#!/usr/bin/perl
# IBM_PROLOG_BEGIN_TAG 
# This is an automatically generated prolog. 
#  
#  
#  
# Licensed Materials - Property of IBM 
#  
# (C) COPYRIGHT International Business Machines Corp. 2001,2019 
# All Rights Reserved 
#  
# US Government Users Restricted Rights - Use, duplication or 
# disclosure restricted by GSA ADP Schedule Contract with IBM Corp. 
#  
# IBM_PROLOG_END_TAG 
#
# sccsid = "@(#)12   1.15   src/rsct/cfg_access/cfgmgr/ct_hats_info.perl, cfg.access, rsct_rady, rady2035a 11/12/15 16:43:42"
#
# Usage: ct_hats_info [-l] [-w]
#    -l  to get the data from the local repository (no-use)
#    -w  to set the data to the repository (input from stdin)
# This will give the hats subsystem information
#       REALM		CLUSTER
#       FIXED_PRI       <value>
#       PIN             <value>
#       LOGFILELEN      <value>
#
use Getopt::Std;

# set peer domain scope
$ENV{CT_MANAGEMENT_SCOPE} = 2;

my %opts = ();
&getopts(':lw',\%opts);
my $mmsetting=(defined($opts{w}) ? 1 : 0);

$SUBSYS_PREFIX = "cthats";
$RSCTBIN="/opt/rsct/bin";

($dir,$progname) = $0 =~ /(.*\/)?(.*)/; # get basename of $0

# ValidKeys: list of all acceptable keys (either canset or not).
# In other words, the input keys must be in the list.
# Otherwise, an error will be issued.

$NON_SETTABLE = 0;
$SETTABLE = 1;

%ValidKeys = (
    "ENVIRONMENT"       => $NON_SETTABLE,
    "START_AT_BOOT"      => $NON_SETTABLE,
    "RESTART_BY_SRC"      => $NON_SETTABLE,
    "REALM"             => $NON_SETTABLE,
    "PORT"              => $NON_SETTABLE,
    "FIXED_PRI"         => $SETTABLE,
    "LOGFILELEN"        => $SETTABLE,
    "PIN"               => $SETTABLE,
    # Feature 134905
    # If CCSKEnabled is meant to be settable, changes will
    # need to be made immediately following this comment,
    # as well as to set_data_to_repository.
    "CSSK_ENABLED"      => $NON_SETTABLE
);

$NO_PIN_VALUE = 256;  # Value for TSPinnedRegions that means "don't pin"

$TSFixPri = -1;
$TSPin = "DEFAULT";
$TSDirSize = -1;
$CSSKEnabled = 0;

# main starts here
if($mmsetting) {
    #write the data to the repository
    &set_data_to_repository();
} else {
    my $outcnt = &get_data_from_repository();
    if($outcnt == 0) {
	# No output
        &print_errmsg("EMSG107 $progname");
	exit(1);
    }
}
exit(0);

#-------- functions -----------------------------------
# print_dbgmsg(list)
sub print_dbgmsg
{
  my @args = @_;
  if(!defined($ccal_log_inited)) {
	my $outfile = $ENV{"HA_CCAL_LOG"};
	$ccal_log_inited = 0;
	if(defined($outfile) && open(LOGOUT, ">>$outfile")) {
	    $ccal_log_inited = 1;
	    select LOGOUT;
	    $| = 1; # unbuffered
	    select STDOUT;
	}
  }
  if($ccal_log_inited) {
	my $dstr = scalar(localtime);
	my $msg = "$dstr $progname: " . join(" ", @args);
	print LOGOUT $msg, "\n" ;
  }
}

sub print_errmsg
{
   $msgcmd = "$RSCTBIN/hadspmsg cfgaccess ha_com.cat ". join(" ",@_);
   system($msgcmd);
}
#-----------------------------------------------------

# GET DATA from the repository
sub get_data_from_repository
{
   # print REALM
   print "REALM         CLUSTER\n";

   # show the environment and AutoStart flags
   print "ENVIRONMENT    cfgmgr\n";
   print "START_AT_BOOT  0\n";
   print "RESTART_BY_SRC 0\n";

   #
   if( ! -e "$RSCTBIN/ct_clusterinfo" ) {
   	# No ${RSCTBIN}/ct_clusterinfo found.
        &print_errmsg("EMSG104 $progname ${RSCTBIN}/ct_clusterinfo");
	exit(1);
   }

   $CLSTNAME = `$RSCTBIN/ct_clusterinfo -c`;
   chomp($CLSTNAME);
   if( !defined($CLSTNAME) || $CLSTNAME eq "" ) {
	# No cluster name found.
        &print_errmsg("EMSG105 $progname $CLSTNAME");
	exit(1);
   }

   $TSLogSize = -1;
   $TSFixPri = -1;
   $TSPin = "DEFAULT";

   # Obtain tunables
   $machines_lst = "/var/ct/$CLSTNAME/cfg/machines.lst";
   &get_tunables_from_machines_lst($machines_lst);


   # Copy from the rsct.params
   $RSCTPARAMS = $ENV{"CT_RSCT_PARAMS"};
   if( !defined($RSCTPARAMS) ) {
        $RSCTPARAMS = "/var/ct/$CLSTNAME/cfg/rsct.params";
   }
   if(open(PARMFP, "<$RSCTPARAMS")) {
        while( <PARMFP> ) {
            chomp($_);       # Remove trailing '\n'
            # 2 simple s/// are faster than one complex s///.
            s/^[ \t\n]*//;   # Remove possible leading spaces
            s/#.*$//;       # Remove possible trailing comments
            ($keyword, $keyvalue) = split(/=/, $_, 2);
            if($keyword =~ "TSLogSize") {
                $TSLogSize = $keyvalue;
            } elsif($keyword =~ "TSFixedPriority") {
                $TSFixPri = $keyvalue;
            } elsif($keyword =~ "TSPinnedRegions") {
		$TSPin = "";
		if($keyvalue == $NO_PIN_VALUE) {
			$TSPin = "NONE";
                }
		else {
			if( ($keyvalue & 0x0001) != 0 ) {
				$TSPin = "$TSPin TEXT";
			}
			if( ($keyvalue & 0x0002) != 0 ) {
				$TSPin = "$TSPin DATA";
			}
			if( ($keyvalue & 0x0004) != 0 ) {
				$TSPin = "$TSPin STACK";
			}
			if ($TSPin eq "") {
				$TSPin = "DEFAULT";
			}
		}
            } elsif ($keyword =~ "CSSKEnabled") {
                $CSSKEnabled = $keyvalue;
            }
        }
        close PARAMFP;
   }

   if(defined($PORT) && ($PORT != 0)) {
	print "PORT         $PORT\n";
   }
   print "FIXED_PRI  $TSFixPri\n";
   print "PIN        $TSPin\n";
   print "LOGFILELEN $TSLogSize\n";
   print "CSSK_ENABLED $CSSKEnabled\n";
   return 5;	# 5 lines of output
}


# GET Tunables from the machines.lst 
# input (machines_lst)
sub get_tunables_from_machines_lst
{

   # get the machines_lst file name
   ($machines_lst) = @_;
   if( ! -e $machines_lst || !open(MACHLST,$machines_lst)) {
	&print_dbgmsg("Error on opening $machines_lst");
	$TSFixPri = -1;
	$TSPin = "DEFAULT";
	$TSLogDir = -1;
        $CSSKEnabled = 0;
	return 1;
   }

   # read TOPOLCFG
   local(@macContents) = <MACHLST>;
   close MACHLST;

   my $fixedPri = -1;
   my $pin = "";
   my $logLen = -1;

   foreach $aLine (@macContents) {
	chomp($aLine);		# chop '\n'
	&print_dbgmsg("$aLine");
	my(@tks) = split("=", $aLine);	# separate '='
	if( $tks[0] eq "TS_FixedPriority" ) {
	    $fixedPri = $tks[1];
	} elsif( $tks[0] eq "TS_LogLength" ) {
	    $logLen = $tks[1];
	} elsif( $tks[0] eq "*!TS_PinText" ) {
	    $pin = "$pin TEXT";
	} elsif( $tks[0] eq "*!TS_PinData" ) {
	    $pin = "$pin DATA";
	} elsif( $tks[0] eq "*!TS_PinStack" ) {
	    $pin = "$pin STACK";
	} else {
	    # ignore
	}
   }

   $TSFixPri = $fixedPri;
   if($pin ne "") {
	$TSPin = $pin;
   } else {
	$TSPin = "DEFAULT";
   }
   $TSLogSize = $logLen;

   return 1;	# many lines
}



# SET DATA to the repository 
sub set_data_to_repository
{
   my $count = 0;
   my %kvFields = ();
   my @fields;
   my ($key, $val, $canset);
   while( <STDIN> ) {
	@fields = split " ";	# split input
	$key = $fields[0];
	$val = join(" ",@fields[1..$#fields]);
	next if(!defined($key) || ($key eq "") || ($key =~ /^#/));
        $key = uc $key;		# upper case
	$canset = $ValidKeys{$key};	
	if(defined($canset)) {
	    # process the field
	    if($canset == $SETTABLE) {
		$kvFields{$key} = $val;
		$count++;
	    } else {
	    	&print_dbgmsg("Unsettable field: $key $val");
	    }
	} else {
	    # not defined...unknown key
	    #Unknown field: $key $val
            &print_errmsg("EMSG106 $progname $key $val");
	}
   }
   
   if($count == 0) {
	#no fields will be updated
	return 0;
   }

   # merge the 'kvFields' as the blank-separated list
   # For example, KA=V1 KB=V2:
   my @mmInList = ();
   my @kvpair;
   my $kvStr;
   while( @kvpair = each %kvFields ) {
        if( $kvpair[0] =~ "FIXED_PRI" ) {
                $kvStr = "TSFixedPriority=$kvpair[1]";
                push @mmInList, ($kvStr);
        } elsif( $kvpair[0] =~ "LOGFILELEN" ) {
                $kvStr = "TSLogSize=$kvpair[1]";
                push @mmInList, ($kvStr);
        } elsif( $kvpair[0] =~ "PIN" ) {
		my (@tks) = split(" ", $kvpair[1]);
		my $pinval = 0;
		foreach $aVal (@tks) {
		    if($aVal eq "NONE") {
			$pinval = $NO_PIN_VALUE;
			last;            # get out of foreach loop
		    }
		    if($aVal eq "TEXT") {
			$pinval = $pinval | 0x0001;
		    } elsif($aVal eq "DATA") {
			$pinval = $pinval | 0x0002;
		    } elsif($aVal eq "STACK") {
			$pinval = $pinval | 0x0004;
		    } elsif($aVal eq "PROC") {
			$pinval = $pinval | 0x0007;
		    }
		}
                $kvStr = "TSPinnedRegions=$pinval";
                push @mmInList, ($kvStr);
        }
   }

   my $mmInStr = join(" ",@mmInList);
   `/opt/rsct/bin/chrsrc -c IBM.RSCTParameters $mmInStr`;
   $rc = $?;
   &print_dbgmsg("Update: $mmInStr RC=$rc");

   if($rc != 0) {  # error in chrsrc (probably no quorum): exit with
                   # error. An error msg will have been produced by
                   # chrsrc.
       exit(1);
   }

   return $count;
}