# IBM_PROLOG_BEGIN_TAG 
# This is an automatically generated prolog. 
#  
#  
#  
# Licensed Materials - Property of IBM 
#  
# (C) COPYRIGHT International Business Machines Corp. 1997,2007 
# 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 
#*======================================================================
#*
#* Module Name:  hagsp
#*
#* Description:
#*      Script to start the Group Services Daemon as an SRC subsystem.
#*
#*      This file is formatted with tabstops of 4.
#*======================================================================

# sccsid = "@(#)54   1.64         src/rsct/pgs/cmds/aix/hagsp.pl, gsctrl, rsct_relgh, relghs001a 11/9/06 18:52:21"

unshift(@INC, '/usr/sbin/rsct/bin');

#
require "hagsSetup.pkg";

$OSname = `/bin/uname -s`;
chomp($OSname);

if ("Linux" eq $OSname) {
    $ENV{'PATH'} = $ENV{'PATH'} . ":/bin";
}

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

&TSprint( TRACE_FYI, "$0 $#ARGV $[ $subsys input arguments: @ARGV\n" );

sub Usage {
    warn "Usage: $progname -s <subsystem_name> -p <domain_name> [-i <cluster_id>] [-d <default_log_name>]\n";
    exit -1;
}


# Too many arguments?
if (8 <= $#ARGV) {
    &Usage;
}
# Avoid getopts, to remove dependencies on Perl libraries...
while (@ARGV) {
    $arg = shift @ARGV;
    if ("-s" eq $arg) {
        $subsys = shift @ARGV;
    } elsif ("-p" eq $arg) {
        $DomainName = shift @ARGV;
    } elsif ("-i" eq $arg) {
	$ClusterID = shift @ARGV;
    } elsif ("-d" eq $arg) {
        $DefaultLogName = shift @ARGV;
    } else {
        &Usage;
    }
}

#
# Note: PGSD_RELEASE_LEVEL must be to the proper daemon level here.
# PGSD_RELEASE_LEVEL ensures the proper behaviour of daemons, esp. in the
#   mixed environment.

# Current Release Level
$CURRENT_RELEASE_LEVEL = 13;		# current level
$SUPPORTED_RELEASE_LEVEL_FOR_HAES = 5;	# supported level for HAES
$MAX_RELEASE_LEVEL_FOR_HAES = 5;

#
$PGSD_RELEASE_LEVEL = &GSCurrentReleaseLevel();
&TSprint( TRACE_FYI, "PGSD_RELEASE_LEVEL=$PGSD_RELEASE_LEVEL\n");


$Perl = $ENV{'PGSD_PERL'};

$domainType = $ENV{'HA_DOMAIN_TYPE'};

$daemon = $ENV{'PGSD_DAEMON'};
if (!defined $ENV{'PGSD_DAEMON'}) {
    $daemon = "${subsys}d";
}

if($domainType eq "CLUSTER") {
	&TSprint( TRACE_FYI, 
	  	  "domainType=$domainType, subsys=$subsys, ".
		  "DomainName=$DomainName, ".
		  "ClusterID=$ClusterID, ".
		  "DefaultLogName=$DefaultLogName, Perl=$Perl\n" );
} else {
	&TSprint( TRACE_FYI,
	          "domainType=$domainType, subsys=$subsys, ".
	          "DomainName=$DomainName, ".
	          "DefaultLogName=$DefaultLogName, Perl=$Perl\n" );
}

if (!defined $ENV{'PGSD_TID_DIR'}) {
    if( $domainType eq "CLUSTER" ) {
	$TidDir = "/var/ct/$ClusterID/lck/$subsys/$subsys.tid.$DomainName";
    } else {
	$TidDir = "/var/ha/lck/$subsys.tid.$DomainName";
    }
    $ENV{'PGSD_TID_DIR'} = $TidDir;
} else {
    $TidDir = $ENV{'PGSD_TID_DIR'};
}

if(! -d $TidDir) {
    eval `mkdir -p $TidDir`;
    if ($? != 0) {
        local($msg) = " cannot create directory $TidDir.";
        &TSprint( TRACE_FYI, "$msg\n");
        printf STDERR "$msg\n";
        &fcstart_error(__LINE__,$msg);
        exit 3;
    }
    eval `chmod 0750 $TidDir`;
}

&TSprint( TRACE_FYI, "PGSD_TID_DIR=$ENV{'PGSD_TID_DIR'}\n" );
&TSprint( TRACE_FYI, "PATH=$ENV{'PATH'}\n" );

# Set the env variable HA_DOMAIN_NAME to our partition name so that
# heartbeat will see it.  For now, also set HA_SYSPAR_NAME.
$ENV{'HA_SYSPAR_NAME'}	= $DomainName;
$ENV{'HA_DOMAIN_NAME'}	= $DomainName;
$ENV{'SP_NAME'}		= $DomainName;

if($domainType eq "CLUSTER") {
	# Set CT_DOMAIN, CT_CLUSTER_ID, and CT_CLUSTER_NAME
	$ENV{'CT_DOMAIN'} = 1;
}


#
# Get the node number
$NodeNumber = $ENV{'PGSD_NODE_NUMBER'};
&TSprint( TRACE_FYI, "NodeNumber=$NodeNumber\n" );
&TSprint( TRACE_FYI, "PGSD_NODE_NUMBER=$ENV{'PGSD_NODE_NUMBER'}\n" );

# Declare the variables for Cluster
local(%ct_gs_node_level);	# node level(RSCT) for each node
local($ct_gs_global_logLength);	
local($ct_gs_global_logDirSize);	
local(%ct_gs_local_level);	# per node
local(%ct_gs_local_logLength);	# per node
local(%ct_gs_local_logDirSize);	# per node
local($ct_gs_pri_fixed, $ct_gs_pri_value);

#
# In PSSP/Cluster, Update the release level as early as possible
if($domainType eq "CLUSTER") {
   # 
   # Update the release level and build the registry information
   &Update_CodeLevel_And_Build_Cluster_Table($NodeNumber, $PGSD_RELEASE_LEVEL);

} elsif($domainType eq "PSSP") {
   &Query_And_Update_My_CodeLevel($NodeNumber, $PGSD_RELEASE_LEVEL);
}

#
# Handling for Markfile is now changed.
# In principal, every node will have a markfile and it will be updated
# whenever the state of daemon is changed. The daemon will also update
# the content of the markfile at the time of death.
# The daemon will read the file, compute the time how much the daemon
# has been down, and call hb_simulate_death with the time length
# if it was LNN or NS. Otherwise it call the function to stop SD.
# Note: if the markfile does not exist, the time length will be zero.
#
# A new environment will be passed so that the daemon knows whether
# SD is enabled(PSSP,CLUSTER) or disabled(under HAES)
#	PGSD_ALLOW_SIMULATE_DEATH
# If this environment is not defined, it is assumed as enabled.
#
# After the change of SD, PGSD_STEP_ON_HATS will be obsolete
# although it will still be passed for awhile.
#
#
$MarkFile = "$TidDir/${subsys}.status.$DomainName";
$ENV{'PGSD_MARKFILE'} = $MarkFile;
&TSprint( TRACE_FYI, "PGSD_MARKFILE=$ENV{'PGSD_MARKFILE'}\n" );

#
if ($domainType eq "HAES") {
   #simulate death will be disabled
   $ENV{'PGSD_ALLOW_SIMULATE_DEATH'} = "no";
   $ENV{'PGSD_STEP_ON_HATS'} = "no";
} else  {
   #simulate death will be enabled
   $ENV{'PGSD_ALLOW_SIMULATE_DEATH'} = "yes";
   if ( ! -e $MarkFile ) {
	&TSprint( TRACE_FYI, "No Markfile $MarkFile found.\n" );
	$ENV{'PGSD_STEP_ON_HATS'} = "no";
   } else {
	&TSprint( TRACE_FYI, "Markfile $MarkFile found.\n");
	$ENV{'PGSD_STEP_ON_HATS'} = "yes";
   }
}

&TSprint( TRACE_FYI, "SimulateDeath is set to $ENV{'PGSD_ALLOW_SIMULATE_DEATH'}\n");
&TSprint( TRACE_FYI, "(Obsolete) Step On Hats value = $ENV{'PGSD_STEP_ON_HATS'}\n");

$NodeNumber = $ENV{'PGSD_NODE_NUMBER'};

&TSprint( TRACE_FYI, "NodeNumber=$NodeNumber\n" );
&TSprint( TRACE_FYI, "PGSD_NODE_NUMBER=$ENV{'PGSD_NODE_NUMBER'}\n" );

#
#
$IncarnationNumber = &GetInstance( $TidDir, "${subsys}d" );
$ENV{'PGSD_INCARNATION_NUMBER'} = $IncarnationNumber;
&TSprint( TRACE_FYI, "PGSD_INCARNATION_NUMBER=$ENV{'PGSD_INCARNATION_NUMBER'}\n" );

#
if($domainType eq "CLUSTER") {
        $daemonName = $subsys;
} else {
        $daemonName = (0 == $NodeNumber) ? "$subsys.$DomainName" : $subsys;
}                                                              
#
#
# set PGSD_LOGFILE
local($LogDir) = $ENV{'PGSD_LOGDIR'};
if(!defined($LogDir)) {
    if($domainType eq "CLUSTER") {
	$LogDir = "/var/ct/$ClusterID/log/$subsys";
    } else {
	$LogDir = "/var/ha/log";
    }
    $ENV{'PGSD_LOGDIR'} = $LogDir;
}

if (!defined( $ENV{'PGSD_LOGFILE'} ) ) {
    $ENV{'PGSD_LOGFILE'} =
        "$LogDir/${daemonName}_${NodeNumber}_$IncarnationNumber.$DomainName";
}
if(! -d $LogDir) {
    eval `mkdir -p $LogDir`;
    if ($? != 0) {
        local($msg) = " cannot create directory $LogDir.";
        &TSprint( TRACE_FYI, "$msg\n");
        printf STDERR "$msg\n";
        &fcstart_error(__LINE__,$msg);
        exit 3;
    }
    eval `chmod 0750 $LogDir`;
}

&TSprint( TRACE_FYI, "PGSD_LOGFILE=$ENV{'PGSD_LOGFILE'}, ",
                     "PGSD_LOGDIR=$ENV{'PGSD_LOGDIR'}\n" );

#
#Set run dir
if (!defined $ENV{'PGSD_RUN_DIR'}) {
    if($domainType eq "CLUSTER") {
        $RunDir = "/var/ct/$ClusterID/run/$subsys";
    } else {
        $RunDir = "/var/ha/run/$subsys.$DomainName";
    }
    $ENV{'PGSD_RUN_DIR'} = $RunDir;
} else {
    $RunDir = $ENV{'PGSD_RUN_DIR'};
}
if(! -d $RunDir) {
    eval `mkdir -p $RunDir`;
    if ($? != 0) {
        local($msg) = " cannot create directory $RunDir.";
        &TSprint( TRACE_FYI, "$msg\n");
        printf STDERR "$msg\n";
        &fcstart_error(__LINE__,$msg);
        exit 3;
    }
    eval `chmod 0750 $RunDir`;
}
&TSprint( TRACE_FYI, "PGSD_RUN_DIR=$ENV{'PGSD_RUN_DIR'}\n" );


# hagsreap is a perl script which will trim the amount of space that
# hags logs and cores occupies.  We fire it off, and then just let it
# go, and check back on it later.

# hagsreap will remove hags logs and core files so that they consume
# no more than sizeLimit bytes.
$Command=$ENV{'PGSD_REAP_CMD'};
$sizeLimit=$ENV{'PGSD_REAP_SIZE'};

# determine PGSD_REAP_SIZE in CLUSTERS
if(($domainType eq "CLUSTER") && !defined($sizeLimit)) {
	# CLUSTER and No PGSD_REAP_SIZE defined
	$sizeLimit = $ct_gs_local_logDirSize{$NodeNumber};
	if(!defined($sizeLimit) || ($sizeLimit == 0)) {
		$sizeLimit = $ct_gs_global_logDirSize;
	}
	if(!defined($sizeLimit) || ($sizeLimit == 0)) {
		$sizeLimit = 5;	# in MB
	}
	$sizeLimit = $sizeLimit * 1024 * 1024;	# in Bytes
} elsif(!defined($sizeLimit)) {
	$sizeLimit=(5 * 1024 * 1024); # default size is 5M
}


$DefaultLogNameParameter = ("" ne $DefaultLogName) ? "-d $DefaultLogName" : "";
    
$cmd = "$Perl -S hagsreap  $DefaultLogNameParameter  $subsys $DomainName ".
       " $Command   $sizeLimit $NodeNumber " .
       "  $ENV{'PGSD_LOGDIR'}   $ENV{'PGSD_RUN_DIR'}";


select STDOUT; $|=1;	# to flush output
&TSprint( TRACE_FYI, "cmd = $cmd.\n" );

if (0 == ($kidPid = fork)) {
    exec $cmd;
    die "Couldn't exec hagsreap: $!\n";
}

select STDOUT; $|=0;	# enable buffering again

#
# Remove the client socket directory 
# (/var/ha/soc/<subsys>.clients[.<partition>]) on HAES and PSSP
# (/var/ct/<cluster_id>/soc/ctgrpsvcs/clients.<cluster_name>) on CLUSTER
#
if($domainType eq "CLUSTER") {
    $client_dir = "/var/ct/$ClusterID/soc/$subsys/$subsys.clients";
} else {
    $client_dir = "/var/ha/soc/$subsys.clients";
}
if( defined($DomainName) ) {
    $client_dir = "$client_dir.$DomainName";
}

#
select STDOUT; $|=1;	# disable buffering

# 1. Fork another process that will remove the client socket files
if( 0 == ($client_rm_pid = fork) ) {
	# create the client dir
        eval `mkdir -p $client_dir`;
        eval `chmod 1777 $client_dir`;

        # child process. delete the socket files and directory
        eval `rm -rf $client_dir/*`;
        exit(0);
}

#
select STDOUT; $|=0;	# enable buffering again

#
#

# note that MoveToRunDir should probably be called BEFORE hagsreap,
# so that the core file is found and renamed before we calculate how
# much disk space we are using, otherwise it's not counted.
# It will be counted the next time we restart, however.
# If we move it, we lose some parallelism, as we'd have to determine
# our incarnation number first.

&MoveToRunDir( $RunDir, $NodeNumber, $IncarnationNumber );


if ("" ne $DefaultLogName) {
    # We want to save the messages in the default log.
    # so, we rename it to the log name, and daemon appends to the log!
    local($newDefaultLogName) = "$DefaultLogName.${NodeNumber}_$IncarnationNumber";
    &TSprint(TRACE_FYI, "rename $DefaultLogName to $newDefaultLogName\n");
    rename($DefaultLogName, $newDefaultLogName) || warn "rename of $DefaultLogName to $newDefaultLogName failed!: $!\n";
    eval `chmod 0644 $newDefaultLogName`;
}

# Set the fixed priority value of the daemon.  If not set, it won't setpri
# to this value.  If PGSD_TSCONFIG set, use it.  If not, if PSSP, use SDR,
# if HAES, use odm, if CLUSTER, use Registry.

if (defined $ENV{'PGSD_TSCONFIG'}) {
    &TSprint( TRACE_FYI, "PGSD_TSCONFIG=$ENV{'PGSD_TSCONFIG'}\n" );
    ($fixFlag, $TSpriority, $GSLogLength) = split(':',$ENV{'PGSD_TSCONFIG'});
    $GSpriority = (38 < $TSpriority) ? 1 + $TSpriority : 39;
} elsif ($domainType eq "PSSP") {
    $cmd = "SDRGetObjects -x TS_Config Run_FixPri FixPri_Value Frequency Sensitivity Log_Length |";
    &TSprint( TRACE_FYI, "$cmd\n" );
    if (open(TSCONFIG, $cmd)) {
        ($fixFlag, $TSpriority, $TSfrequency, $TSsensitivity, $TSLogLength) = split(' ', <TSCONFIG>);
        close TSCONFIG;
    } else {
        warn "Can't get TS_Config from SDR: $cmd: $!\n";
        warn "Setting some default values.\n";
        # need some default values
        $fixFlag = 0;
        $TSpriority = 39;
        $TSLogLength = 5100;
    }
    $GSLogLength = $TSLogLength;
    $GSpriority = (38 < $TSpriority) ? 1 + $TSpriority : 39;
} elsif ($domainType eq "HAES") {
    # save the ODMDIR
    $saved_odmdir=$ENV{'ODMDIR'};
    # set the ODMDIR in preperation for the odmget
    $ENV{'ODMDIR'} = "/etc/es/objrepos";

    $odmcmd = "odmget HACMPtopsvcs | awk '/runFixedPri/ {runFixedPri=\$3} /fixedPriLevel/ {fixedPriLevel=\$3} /gsLogLength/ {gsLogLen=\$3} END { printf(\"%d:%d:%d\", runFixedPri, fixedPriLevel, gsLogLen)}'|";
    &TSprint( TRACE_FYI, "odmcmd = $odmcmd.\n" );
    if (open(TSCONFIG, $odmcmd)) {
        ($fixFlag, $TSpriority, $GSLogLength) = split(':',<TSCONFIG>);
        close TSCONFIG;
	if( !defined($GSLogLength) || int($GSLogLength) < 5000 ) {
		# force the length at a minimum of 5000
		$GSLogLength = 5000;
	}
    } else {
        $fixFlag = 0;
        $TSpriority = 38;
        $GSLogLength = 5200;
    }
    # restore the ODMDIR to original
    $ENV{'ODMDIR'} = $saved_odmdir;
    $GSpriority = (38 < $TSpriority) ? 1 + $TSpriority : 39;

} elsif ($domainType eq "CLUSTER") {
    # Cluster. Read SR /IBM/GroupServices/GS_GlobalConfig and GS_LocalConfig
    $fixFlag = $ct_gs_pri_fixed;
    $GSpriority = $ct_gs_pri_value;
    $GSLogLength = $ct_gs_global_logLength;
} else {
    # Unknown environment, and no PGSD_TSCONFIG.  Use some defaults.
    $fixFlag = 0;
    $TSpriority = 38;
    $GSLogLength = 6000;
    $GSpriority = (38 < $TSpriority) ? 1 + $TSpriority : 39;
}

if (defined($fixFlag) && 0 != $fixFlag) {
   if(!defined($GSpriority)) {
	$GSpriority = 39;
   }
   $ENV{'PGSD_FIXED_PRIORITY'} = $GSpriority;
}

if(!defined($GSLogLength) || ($GSLogLength < 5000) ) {
   # make the logLength at least 5000
   $GSLogLength = 5000;
}

&TSprint( TRACE_FYI, "TS_Config data: Run_FixPri=$fixFlag, ",
                         "GSFixPri_Value=$GSpriority, ",
                         "LogLength=$GSLogLength.\n" );
&TSprint( TRACE_FYI, "PGSD_FIXED_PRIORITY=$ENV{'PGSD_FIXED_PRIORITY'}\n" );
$ENV{'PGSD_LOGSIZE'} = $GSLogLength;

if (!defined( $ENV{'PGSD_PRM_SOCK'} ) ) {
    if ($domainType eq "HAES") {
        if (!defined($ENV{"PGSD_HAESLEVEL"})) {
            # Assume HACMP/ES 4.3
            $ENV{'PGSD_PRM_SOCK'} = "$subsys";
        } else {
            $haesLevel = $ENV{"PGSD_HAESLEVEL"};
            if ($haesLevel eq "42") {
                &TSprint( TRACE_FYI, "Assuming HAES level 42.\n");
                $ENV{'PGSD_PRM_SOCK'} = "$subsys.$DomainName";
            } else {
                $ENV{'PGSD_PRM_SOCK'} = "$subsys";
            }
        }
    } elsif($domainType eq "CLUSTER") {
        $ENV{'PGSD_PRM_SOCK'} = "$subsys";
    } else {
        $ENV{'PGSD_PRM_SOCK'} = "$subsys.$DomainName";
    }
}
&TSprint( TRACE_FYI, "PGSD_PRM_SOCK=$ENV{'PGSD_PRM_SOCK'}\n");

if (!defined( $ENV{'PGSD_SUPP_SOCK'} ) ) {
    if($domainType eq "CLUSTER") {
    	$ENV{'PGSD_SUPP_SOCK'} = "/var/ct/$ClusterID/soc/${subsys}/${subsys}dsocket.$DomainName";
    } else {
	$ENV{'PGSD_SUPP_SOCK'} = "/var/ha/soc/${subsys}dsocket.$DomainName";
    }
}

&TSprint( TRACE_FYI, "PGSD_SUPP_SOCK=$ENV{'PGSD_SUPP_SOCK'}\n");

# remove pgsd socket (so that client can get errno=ENO rather ECONNREFUSED)
if( -e $ENV{'PGSD_SUPP_SOCK'} ) {
   eval `rm -f $ENV{'PGSD_SUPP_SOCK'}`;
}

# If in HAES/CLUSTER, worry about setting our hats socket pointer.
if (!defined( $ENV{'HB_SERVER_SOCKET'} ) ) {
    if ($domainType eq "HAES") {
        $ENV{'HB_SERVER_SOCKET'} = "/var/ha/soc/topsvcs/server_socket";
    } elsif($domainType eq "CLUSTER") {
	$ENV{'HB_SERVER_SOCKET'} = "/var/ct/$ClusterID/soc/cttopsvcs/server_socket";
    }
}
&TSprint( TRACE_FYI, "HB_SERVER_SOCKET=$ENV{HB_SERVER_SOCKET}\n");

# Allowing new function differs between HAES and PSSP, since HAES has
# no SDR to give us the lowest common denominator.

if ($domainType eq "HAES") {
    $ENV{'PGSD_NEW_FUNCTION'} = "unsafe";    
} else {
    if (!defined( $ENV{'PGSD_NEW_FUNCTION'} ) ) {
        $ENV{'PGSD_NEW_FUNCTION'} = "safe";
    }
}
&TSprint( TRACE_FYI, "PGSD_NEW_FUNCTION=$ENV{'PGSD_NEW_FUNCTION'}\n" );

$| = 1; #flush and unbuffer stdout to get next messages asap.

# Allow hagsreap to finish, if it hasn't already.
if (0 != $kidPid) {
    local($startedWaiting) = time;
    waitpid( $kidPid, 0 );
    if ( 0 < ($waited = time - $startedWaiting) ) {
        &TSprint( TRACE_FYI, "We waited $waited seconds for hagsreap.\n" );
    }
}

#
# Wait the child process that is removing the client socket files
#
waitpid($client_rm_pid, 0);
#
#if ( ! -d $client_dir ) {
#    # create the client directory
#    mkdir($client_dir, 0777) || die "Can't make $client_dir: $!";
#}

# make sure the filemode (rwxrwxrwt) of the client socket directory
eval `chmod 1777 $client_dir`;
&TSprint( TRACE_FYI, "Client socket directory = $client_dir\n" );

# The environment PGSD_AUTH_BY_DAEMON to enable the new auth. method
$ENV{"PGSD_AUTH_BY_DAEMON"} = 1;


# If in the HA domain, then no SDR.  Hard code for now!  Otherwise,
# use the SDR to find the LOWEST code level for this partition.
# Also, determine if the domain is, or is not, a single level.  In
# the HAES domain this is important to determine if we allow back-level
# daemons in.

if ($domainType eq "HAES") {
    # See 73167. We'll determine the gs_level based on HACMP level
    # and choose the reasonable minimum gs_level.
    # In this release, the appropripate gs_level is 5.
    # See 73402, In addition, the max. upgradable level is also 5.
    $ENV{'PGSD_CODELEVEL'} = $SUPPORTED_RELEASE_LEVEL_FOR_HAES;
    $ENV{'PGSD_MAX_CODELEVEL'} = $MAX_RELEASE_LEVEL_FOR_HAES;
	# Check for mixed (migrating) domain.
    $ENV{'PGSD_HAES_CODELEVEL'} = `clmixver`;
    $rcMix = $?;
    chomp $ENV{'PGSD_HAES_CODELEVEL'};
    if (0 == $rcMix) {
        &TSprint( TRACE_FYI, "clmixver says the domain is one level.\n");
        $ENV{'PGSD_MIXEDLEVEL'} = "no";
        $allowMixing = "no";
    } else {
        &TSprint( TRACE_FYI, "clmixver says the domain is mixed levels,",
			     " returns an error: $rcMix\n");
        $ENV{'PGSD_MIXEDLEVEL'} = "yes";	# assume most flexible
        $allowMixing = "yes";
    }
    if (!defined( $ENV{'PGSD_ALLOW_MIXING'} ) ) {
        # Override if not set.
        $ENV{'PGSD_ALLOW_MIXING'} = $allowMixing;
    }
    $ENV{'HA_GS_DOMAIN_MASTER_NAME'} = "clstrmgr";
} elsif($domainType eq "CLUSTER") {
    # Determine the working code level from REGISTRY
    # Determine gs_release_level
    local($ext_gs_level) = $ENV{'PGSD_CODELEVEL'};
    local($desired_level);
    $desired_level = &Determine_CodeLevel_For_Cluster($NodeNumber,$ext_gslevel);
    if($desired_level < $PGSD_RELEASE_LEVEL) {
        # There are other old-nodes out there.
        &TSprint( TRACE_FYI, 
	"There are some (old) level nodes with lvl=$desired_level.\n");
        sleep(6);       # WAIT for the other's joining
        $desired_level = &Determine_CodeLevel_For_Cluster( $NodeNumber,$ext_gslevel );
    }

    # ?? remove DCE creds if it was obtained
    # &remove_dce_creds_for_sdr_if_exist();

    #
    # Not needed: Conversion: "int" level -> "str" level
    # $desired_level = &GSLevel_To_RSCT( $desired_level );
    $ENV{'PGSD_CODELEVEL'} = $desired_level;

    # for setting PGSD_MIXEDLEVEL
    # Not needed: local($ourLevel) = &RSCT_To_GSLevel(&GSCurrentReleaseLevel());
    local($ourLevel) = &GSCurrentReleaseLevel();
    if ($ourLevel eq $desired_level) {
        $ENV{'PGSD_MIXEDLEVEL'} = "no";  # All, are at our level.
    } else {
        $ENV{'PGSD_MIXEDLEVEL'} = "yes"; # Yup, we've got mixed levels.
    }
    if (!defined( $ENV{'PGSD_ALLOW_MIXING'} ) ) {
        $ENV{'PGSD_ALLOW_MIXING'} = "yes";
    }

} else {

    #
    # Determine the working code level from SDR and PSSP levels
    #
    # Determine gs_release_level
    local($ext_gs_level) = $ENV{'PGSD_CODELEVEL'};
    local($desired_level) = &Determine_CodeLevel_For_PSSP( $NodeNumber,$ext_gslevel);
    if($desired_level < $PGSD_RELEASE_LEVEL) {
        # There are other old-nodes out there.
        &TSprint( TRACE_FYI, "There are some (old) level nodes lvl=$desired_level.\n");
        sleep(6);       # WAIT for the other's joining
        $desired_level = &Determine_CodeLevel_For_PSSP( $NodeNumber,$ext_gslevel );
    }

    # remove DCE creds if it was obtained
    &remove_dce_creds_for_sdr_if_exist();

    #
    # Not needed: Conversion: "int" level -> "str" level
    # $desired_level = &GSLevel_To_RSCT( $desired_level );
    $ENV{'PGSD_CODELEVEL'} = $desired_level;

    # for setting PGSD_MIXEDLEVEL
    # Not needed: local($ourLevel) = &RSCT_To_GSLevel(&GSCurrentReleaseLevel());
    local($ourLevel) = &GSCurrentReleaseLevel();
    if ($ourLevel eq $desired_level) {
	$ENV{'PGSD_MIXEDLEVEL'} = "no";  # All, are at our level.
    } else {
	$ENV{'PGSD_MIXEDLEVEL'} = "yes"; # Yup, we've got mixed levels.
    }
    if (!defined( $ENV{'PGSD_ALLOW_MIXING'} ) ) {
        $ENV{'PGSD_ALLOW_MIXING'} = "yes";
    }
}

#
# remove the dce/creds if exist
&remove_dce_creds_for_sdr_if_exist();

#

&TSprint( TRACE_FYI, "PGSD_CODELEVEL=$ENV{'PGSD_CODELEVEL'}\n" );
if(defined $ENV{'PGSD_MAX_CODELEVEL'}) {
   &TSprint( TRACE_FYI, "PGSD_MAX_CODELEVEL=$ENV{'PGSD_MAX_CODELEVEL'}\n");
}
&TSprint( TRACE_FYI, "PGSD_MIXEDLEVEL=$ENV{'PGSD_MIXEDLEVEL'}\n" );
&TSprint( TRACE_FYI, "PGSD_ALLOW_MIXING=$ENV{'PGSD_ALLOW_MIXING'}\n" );
#
#  run the daemon
$cmd = "$daemon $daemonName @ARGV";

&TSprint( TRACE_FYI, "cmd = $cmd\n" );

exec $cmd;

die "exec $cmd failed!: $!\n";


#-----------------------------------------------------------------
#
# Determination Steps:
# Precondition:
#    SDR (GS_Config) for my node was already updated.
# Brief procedure:
# 1. If desired level is known, return and use it.
# 2. Build a hash (spversions{}) for "splst_versions -t" that includes 
#     all nodes except CWS(node 0) in the current partition.
# 3. Read GS_Config and build two hash tables;
#	gsreleases{} for the nodes in spversions{},
#       and gonenodes{} for unknown nodes(i.e., unknown
# 4. On CWS, delete GS_Config entries for gonenodes{}
# 5. Walk through spversions():
#   	Add the node to gsreleases{} if it is not in gsreleases{}.
# NOTE: table gsreleases{} will have information for all nodes.
# 6. Choose the lowest release_level from the gsreleases{}.
# Note: This function will exit if it hits any error situations.

# prototype: Determine_CodeLevel_For_PSSP(NodeNumber, desired_level)

sub Determine_CodeLevel_For_PSSP
{
    local($NodeNumber, $desired_level) = @_;

    # 1. If desired_level is known, return it with the level
    #
    if( defined($desired_level) ) {
    	# If $desired level is not "int", convert it to number
	if(!($desired_level =~ /^[0-9]/)) {
		$desired_level = &RSCT_To_GSLevel($desired_level);
	}
	return $desired_level;
    }

    # Local variables
    local(%gsreleases);		# for gs_config
    local(%gonenodes);		# unknown(deleted) nodes
    local($a_line, $nodenum, $pssp_level, $gs_level, $sdr_level);
    local(@pair);

    # 2. Build a hash table (spversions) from 'splst_versions -t'
    #  note: splst_verisons -t does NOT give you the version of the CWS
    #  note: splst_verisons -n 0 DOES give you the version of the CWS
    if( !defined(%spversions) || !defined($Already_SPLST_Found) ) {
	$Already_SPLST_Found = 1;
	%spversions = &Build_SP_Versions();
    }

    # 3. Read GS_Config and build tables(%gsreleases, %gonenodes)
    local(@rel_pairs)=`SDRGetObjects -x GS_Config node_number gs_release_level`;
    if( $? != 0 ) {
	local($msg) = "Unable to retrieve SDR GS_Config. $!";
	&TSprint( TRACE_FYI, "$msg\n");
	#&print_message("EMsg_Cannot_get_dce_creds", "hagsd");
	printf STDERR "$msg\n";
        &fcstart_error(__LINE__,$msg);
	exit 1;
    }
    foreach $a_line (@rel_pairs) { 
        chop($a_line);              # trim new-line on each line...
	($nodenum, $gs_level) = split(' ',$a_line);
	if( $nodenum == 0 || defined($spversions{$nodenum}) ) {
		# node in the partition
		$gsreleases{$nodenum} = $gs_level;
	} else {
		# unknown or deleted node
		$gonenodes{$nodenum} = $gs_level;
	}
    }

    # 4. On CWS, delete GS_Config entries in %gonenodes
    if( $NodeNumber == 0  && !defined($Already_GSCFG_Removed) ) {
	$Already_GSCFG_Removed = 1;	# To prevent second removals
        while( @pair = each %gonenodes ) {
	    $nodenum = $pair[0];
	    &get_dce_creds_for_sdr_if_first();  # obtain DCE creds
            `SDRDeleteObjects GS_Config node_number==$nodenum`;
	}
    }

    # 5. Walk through spversions and complete gsreleases
    while( @pair = each %spversions ) {
	($nodenum, $pssp_level) = @pair;
	if( !defined($gsreleases{$nodenum}) ) {
		# node is in "splst" but not in "gs_config". Add it
		$gsreleases{$nodenum} = &RSCT_To_GSLevel($pssp_level);
	}
    }

    # 6. Choose the lowest levels from %gsreleases
    $desired_level = &GSCurrentReleaseLevel();
    while( @pair = each %gsreleases ) {
	$gs_level = $pair[1];
	if($gs_level < $desired_level) { $desired_level = $gs_level; }
    }

    # "int" level
    return $desired_level;
}

# This will update SDR with my release level
# Query_And_Update_My_CodeLevel(NodeNumber, release_level)
# return 1 if it is upgraded

sub Query_And_Update_My_CodeLevel
{
    local($NodeNumber, $pgsd_release_level) = @_;

    # Get the SDR
    local($my_level)=`SDRGetObjects -q -x GS_Config gs_release_level node_number==$NodeNumber`;

    if( $? == 0 && defined($my_level) ) {
        chop($my_level);        # chop newline
        if($my_level == $pgsd_release_level) {
                # SDR already has my release level. Nothing to do
                return 0;
        }
        # Time to change the SDR entry
	&get_dce_creds_for_sdr_if_first();  # obtain DCE creds
    	local($new_attr_arg)="gs_release_level=$pgsd_release_level";
        `SDRChangeAttrValues GS_Config node_number==$NodeNumber $new_attr_arg`;
    } else {
        # Time to add an SDR entry
	&get_dce_creds_for_sdr_if_first();  # obtain DCE creds
        local($new_attr_arg)="gs_release_level=$pgsd_release_level";
        `SDRCreateObjects GS_Config node_number=$NodeNumber $new_attr_arg`;
    }

    return 1;
}

#
#-----------------------------------------------------------------
#
# Build a hash table (spversions) from 'splst_versions -t'
#  note: splst_verisons -t does NOT give you the version of the CWS
#  note: splst_verisons -n 0 DOES give you the version of the CWS
# returns %spversions{}
sub Build_SP_Versions
{
    local(%spversions);
    local($a_line, $nodenum, $pssp_level);
    local(@Versions) = `splst_versions -t`;
    foreach $a_line (@Versions) {
        chop($a_line);          # trim new-line on each line...
        ($nodenum, $pssp_level) = split(' ',$a_line);
        $spversions{$nodenum} = $pssp_level;
    }
    return %spversions;
}

#
# GS Release Levels:
#   1 for PSSP-2.1 and PSSP-2.2
#   2 for PSSP-2.3 and PSSP-2.4(original)
#   3 for PSSP-2.4 update
#   4 for PSSP-3.1 and RSCT-1.0
#   5 for PSSP-3.2 PSSP-3.2  or RSCT 1.2
#   6-7 skip
#   8 for PSSP-3.4 and RSCT-1.2.1, RSCT-2.1x
#  10 for PSSP-3.5

# GS Current Release level
sub GSCurrentReleaseLevel
{
    return $CURRENT_RELEASE_LEVEL;
}

#
# Conversion: RSCT level to gs_release_level
#
sub RSCT_To_GSLevel
{
   local($pssplvl) = $_[0];
   if( $pssplvl =~ "PSSP-2.1" )   { return 1; }	# LocustGrove
   if( $pssplvl =~ "PSSP-2.2" )   { return 1; }	# LocustGrove
   if( $pssplvl =~ "PSSP-2.3" )   { return 2; }	# Springwood 
   if( $pssplvl =~ "PSSP-2.4" )   { return 2; }	# Opus(Original)
						# 3 for Opus2
   if( $pssplvl =~ "PSSP-3.1" )   { return 4; }   # Troutbeck
   if( $pssplvl =~ "PSSP-3.1.1" ) { return 4; }   # Troutbeck
   if( $pssplvl =~ "RSCT-1.0" )   { return 4; }	  # troutbeck
   if( $pssplvl =~ "RSCT-1.1" )   { return 4; }	  # troutbeck

   if( $pssplvl =~ "RSCT-1.2.1" ) { return 8; }   # after mohonk
   if( $pssplvl =~ "RSCT-1.2.2" ) { return 8; }   # after mohonk

   if( $pssplvl =~ "PSSP-3.2" )   { return 5; }   # Mohonk
   if( $pssplvl =~ "RSCT-1.2" )   { return 5; }   # Mohonk

   if( $pssplvl =~ "PSSP-3.4" )	  { return 8; }   # After Mohonk
   if( $pssplvl =~ "PSSP-3.3" )	  { return 8; }   # After Mohonk
   if( $pssplvl =~ "RSCT-2.1" )	  { return 8; }   # After Mohonk
   if( $pssplvl =~ "RSCT-2.2" )	  { return 8; }   # After Mohonk

   return &GSCurrentReleaseLevel(); # unknown, treated as current level
}

#
# Conversion: PSSP level to gs_release_level
sub PSSP_To_GSLevel
{
   return RSCT_To_GSLevel(@_);
}

#
# Conversion:  GSLevel to PSSP
#
sub GSLevel_To_PSSP
{
   local($gslvl) = int($_[0]);
   if( $gslvl == 1 ) { return "PSSP-2.2"; }
   if( $gslvl == 2 ) { return "PSSP-2.3"; }
   if( $gslvl == 3 ) { return "PSSP-2.4"; }
   if( $gslvl == 4 ) { return "PSSP-3.1"; }
   if( $gslvl == 5 ) { return "PSSP-3.2"; }
   if( $gslvl == 8 ) { return "PSSP-3.4"; }
   return "PSSP-3.4";   # unknown
}

#
# Conversion:  GSLevel to RSCT
#
sub GSLevel_To_RSCT
{
   local($gslvl) = int($_[0]);
   if( $gslvl == 1 ) { return "PSSP-2.2"; }
   if( $gslvl == 2 ) { return "PSSP-2.3"; }
   if( $gslvl == 3 ) { return "PSSP-2.4"; }
   if( $gslvl == 4 ) { return "RSCT-1.0"; }
   if( $gslvl == 5 ) { return "RSCT-1.2"; }
   if( $gslvl == 8 ) { return "RSCT-2.2"; }
   return "RSCT-2.2";   # unknown
}


#
#-----------------------------------------------------------------
#
# Determination for CLUSTER Steps:
# Precondition:
#	%ct_... already exist
# Brief procedure:
# NOTE: Until CLUSTER provides the list of nodes, the following
#       method will be used.
# 1. If desired level is known, return and use it.
# 2. Choose the minimum level from the %ct_gs_local_level
# Note: This function will exit if it hits any error situations.
# prototype: Determine_CodeLevel_For_Cluster(NodeNumber, desired_level)

sub Determine_CodeLevel_For_Cluster
{
    local($NodeNumber, $desired_level) = @_;

    # 1. If desired_level is known, return it with the level
    #
    if( defined($desired_level) ) {
    	# If $desired level is not "int", convert it to number
	if(!($desired_level =~ /^[0-9]/)) {
		$desired_level = &RSCT_To_GSLevel($desired_level);
	}
	return $desired_level;
    }

    # 2. Choose the lowest levels from %ct_gs_local_level
    $desired_level = &GSCurrentReleaseLevel();
    while( @pair = each %ct_gs_local_level ) {
	$gs_level = $pair[1];
	if($gs_level < $desired_level) { $desired_level = $gs_level; }
    }

    # "int" level
    return $desired_level;
}

#-----------------------------------------------------------------
# Update the release level and build the registry information
# Input: NodeNumber, MyReleaseLevel
# Output:
sub Update_CodeLevel_And_Build_Cluster_Table
{
   local($NodeNumber) = $_[0];
   local($MyCodeLevel) = $_[1];
   #
   # use: ctgrpsvcs_sr_process -c -u<node>=<level> -l
   #
   local($cmd) = "/usr/sbin/rsct/bin/ctgrpsvcs_sr_process -c " .
          	 "-u $NodeNumber=$PGSD_RELEASE_LEVEL -l |";

   if(!open(GS_CT_FILE,$cmd)) {
        local($msg) = "Unable to run ctgrpsvcs_sr_process. $!";
        &TSprint( TRACE_FYI, "$msg\n");
        printf STDERR "$msg\n";
        &fcstart_error(__LINE__,$msg);
	exit 1;
   }

   # read the file and parse
   local($line);
   local($tokens);	# tokenized line
   while( $line = <GS_CT_FILE> ) {
	@tokens = split(" ", $line);
	next if !defined(@tokens);	# discard empty line
	next if scalar(@tokens) < 1;	# discard empty line
	next if ($tokens[0] =~ /^#/);	# discard a comment line

	#print "OUTPUT: ", join(" ", @tokens), "\n";

	if($tokens[0] =~ /CLUSTER/) {
		# cluster info
	} elsif($tokens[0] =~ /NODE/ ) {
		# node info: Node Version ...
		$ct_gs_node_level{$tokens[1]} = $tokens[2];
	} elsif($tokens[0] =~ /GS_PRIORITY/) {
		# FixPri, PriVal
		$ct_gs_pri_fixed = $tokens[1];
		$ct_gs_pri_value = $tokens[2];
	} elsif($tokens[0] =~ /GLOBAL_CFG/) {
		# LogLength, LogDirSize
		$ct_gs_global_logLength = $tokens[1];
		$ct_gs_global_logDirSize = $tokens[1];
	} elsif($tokens[0] =~ /LOCAL_CFG/) {
		local($node) = $tokens[1];
		$ct_gs_local_level{$node} = $tokens[2];
		$ct_gs_local_logLength{$node} = $tokens[3];
		$ct_gs_local_logDirSize{$node} = $tokens[4];
	} else {
		# unknown line. Ignore
	}
   }
   close(GS_CT_FILE);
}

#
#
#########################################################################
#                                                                       #
# Function: security_mode                                               #
# Description: Use lsauthpts to determine authentication method used    #
#              in current partition.                                    #
#                                                                       #
#########################################################################
sub get_security_mode
{
   # The "lsauthpts -c" command will return a list of colon delimited
   # methods. Defect 49774, issue number 1.
   local($authpts)=`/usr/lpp/ssp/bin/lsauthpts -c`;
   if($? != 0) {
	return "";		# lsauthpts failed
   } else {
	chomp($authpts);	# truncate '\n'
	return $authpts;
   }
}
#
#
# Get dce credentials - dsrvtgt checks for dce before obtaining creds.
# Use ssp/spbgroot pricipal for write access to SDR.
sub get_dce_creds_for_sdr_if_first
{
   if(defined($Already_DCE_Creds_Obtained) &&
      ($Already_DCE_Creds_Obtained != 0) )  {
	# Already cred obtained
	return;
   }
   if( ! -e "/usr/lpp/ssp/bin/dsrvtgt" ) {
	# 56941 - File not exist. Assume no security
	&TSprint(TRACE_FYI, "/usr/lpp/ssp/bin/dsrvtgt not exist. Assume no security\n");
	return;
   }

   local($authpts) = get_security_mode();




   if( $authpts eq "dce" ) {
   	$old_krb5=$ENV{'KRB5CCNAME'};
	local($tmpname)=`/usr/lpp/ssp/bin/dsrvtgt ssp/spbgroot`;
	local($rc) = $?;
	chomp($tmpname);	# truncate '\n'
   	if( $rc != 0 || $tmpname eq "" ) {
		local($msg)="Unable to get DCE credentials for SDR update. $!";
        	&TSprint( TRACE_FYI, "$msg\n");
		&print_message("EMsg_Cannot_get_dce_creds", "hagsd");
		&fcstart_error(__LINE__,"$msg");
		exit 1;
	} else {
		$Already_DCE_Creds_Obtained = 1;
		$ENV{'KRB5CCNAME'}=$tmpname;
		&TSprint(TRACE_FYI, "KRB5CCNAME=$ENV{'KRB5CCNAME'}\n");
	}
   }
}

# Remove any DCE credentials file we may have obtained.
# Return KRB5CCNAME to original value.
sub remove_dce_creds_for_sdr_if_exist
{
   if(!defined($Already_DCE_Creds_Obtained) ||
      ($Already_DCE_Creds_Obtained == 0) ) {
        # Creds not obtained
        return;
   }

   $Already_DCE_Creds_Obtained = 0;
   `/bin/kdestroy >/dev/null 2>&1`;
   $ENV{'KRB5CCNAME'}=$old_krb5;
}

#
# print_message(list)
sub print_message
{
   local(@args) = @_;
   local($MSGCMD)="/usr/sbin/rsct/bin/hadspmsg hagsctrl ha_gs.cat";
   local($MSGOUT)=`$MSGCMD @args`;
   printf STDERR $MSGOUT;
}

#
# start_error(lineno, msg)
#
sub fcstart_error
{
   local($lineno) = $_[0];
   local($tmsg) = $_[1];
   if(!defined($lineno) || $lineno eq "") { $lineno = "0"; }
   local($cmd) = "/usr/sbin/rsct/bin/fclogerr -x ALPHA -y 100 ".
		 "-d \"$tmsg\" -p $lineno -s $0 -v 1.64 -l RSCT ".
		 "-r $subsys -t ERRID_GS_STARTERR_ER -e FFDC_ERROR ".
                 "-i /usr/sbin/rsct/include/ha_gs.err.S.h ".
		 "-b \"hagsp: $tmsg\"";
   `$cmd`;
}

