#!/usr/bin/perl
# IBM_PROLOG_BEGIN_TAG 
# This is an automatically generated prolog. 
#  
#  
#  
# Licensed Materials - Property of IBM 
#  
# (C) COPYRIGHT International Business Machines Corp. 2004,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 

$::DEBUG = 1;
#####################################################################
#                                                                   #
# Command: osprereboot                                              #
#                                                                   #
#-------------------------------------------------------------------#
#                                                                   #
# Description: This command is executed just before the first       #
#              reboot of a node after the operating system has been #
#              installed. It copies files from the management server#
#              and adds an entry for osfirstboot to the             #
#              /etc/inittab file.                                   #
#                                                                   #
#                                                                   #
# Command Syntax:  osprereboot [ -n node_hostname]                  #
#                                                                   #
#                                                                   #
# Exit codes:                                                       #
#     0 - All was successful.                                       #
#     1 - An error occured.                                         #
#                                                                   #
#                                                                   #
#####################################################################
# @(#)05   1.28.1.2   src/csm/install/osprereboot.perl, setup, csm_rfish, rfishs001b 3/15/07 21:46:05

use strict;

BEGIN
{
	use File::Basename;    # - this gives us the path of the command
	($::Bin) = dirname($0);    # - for this command we assume the modules and
	                           #   message maps are in the same place
}
use lib "$::Bin";
use Getopt::Std;

#	Note:	this script is meant to be standalone
#		it should not require other modules or message files.

#-------------------------------------------------------------------#
#   MAIN Main main section of code
#-------------------------------------------------------------------#
#-------------------------------------------------------------------#
# Global Variables                                                  #
#-------------------------------------------------------------------#
$::progname        = "osprereboot";
$::install_mounted = 0;             # /csminstall/csm directory mounted
$::csm_server      = "";            # the long hostname of the install server
$::MNTdir          = "";            # directory to mount from install server
%::ISinfo          = ();            # hash of install server info
$::akb_nodename    = "";            # the long hostname of this node as known by
                                    #    the install server
$::csmversion      = "";            # the version of CSM to install on
                                    #    this node
$::foundakbname    = 0;             # indicate that we have the hostname as
                                    #    known by the install server
$::mounted         = 0;
$::mounted_linux   = 0;
$::FLAG            = 0;
$::CSMCLIENTMNTDIR = "/var/opt/csm/mnt";
$::inittab         = "/etc/inittab";
$::NIMINFO         = "/etc/niminfo";
$::CSMINSTDIR      = "/csminstall/csm";        # this may be replaced in getargs
$::CSMLINUXDIR     = "/csminstall/Linux";
$::CSM_MOUNT       = "$::CSMCLIENTMNTDIR/csm";
$::CSM_MOUNT_LINUX = "$::CSMCLIENTMNTDIR/Linux";
$::OPTCSMINSTALL   = "/opt/csm/install";
# Don't hard code PREINSTALLDIR, get PREREBOOT_SCRIPT_DIR from config_info
#$::PREINSTALLDIR   = "$::CSM_MOUNT/scripts/installprereboot"; 
$::CSMCFGDIR       = "$::CSM_MOUNT/config";
$::CAT             = "/bin/cat";
$::MKDIR           = "/bin/mkdir";
$::COPY            = "/bin/cp";
$::MKITAB          = "/usr/sbin/mkitab";
$::LSITAB          = "/usr/sbin/lsitab";
$::NOK             = 1;
$::OK              = 0;
$::GREP            = "/bin/grep";
$::CSMLOG          = "/var/log/csm";
$::INSTALL_LOG     = "/var/log/csm/install.log";
$::GLOBAL_EXIT     = 0;
$::logging         = 0;

$::command_line;
$::macaddr = "";

# get the platform and architecture
$::PLTFRM = `uname`;
chomp $::PLTFRM;

$::arch = `uname -m`;
chomp($::arch);

if ($::PLTFRM eq "AIX")
{
	$::MOUNT  = "/usr/sbin/mount";
	$::UMOUNT = "/usr/sbin/umount";
}
else
{
	$::MOUNT  = "/bin/mount";
	$::UMOUNT = "/bin/umount";
}

my ($cmd, $rc);

#
#  check the command line
#
print "Running osprereboot script\n" if $::DEBUG;
&parse_args;

#   IMBEDDEDTZINFO   -  Start imbedded time zone information
#   End imbedded time zone info

#   EMBEDDEDNODEINFO   -  Start embedded node information (ipaddr->hostname map)
#   End embedded node info

#
# start logging
#
print "$0: start logging\n" if $::DEBUG;
if ($::PLTFRM eq "AIX")
{
	&start_logging($::INSTALL_LOG);
	$::logging++;
}
elsif ($::PLTFRM eq "Linux")
{
	&append_logging($::INSTALL_LOG);
	$::logging++;
}

#
# if the node hostname was not
#      provided on the command line then look for it in
#      the /etc/niminfo file, or in the embedded NODEINFO hash.
if (!$::foundakbname)
{
	if ($::PLTFRM eq "AIX")
	{    # we have a different way to get the info
		if (&get_niminfo != 0)
		{
			print
			  "$::progname:  2653-102 Could not get required information from \"$::NIMINFO\".\n";
			print $::LOG_FILE_HANDLE
			  "$::progname:  2653-102 Could not get required information from \"$::NIMINFO\".\n";
			$::GLOBAL_EXIT = 1;
			exit;
		}
	}
	else
	{
		if (&get_akbname_from_NODEINFO != 0) # Set $::akb_nodename if possible
		{
				print "$::progname:  2653-103 Could not determine this node's hostname as known by the management server.\n";
				print $::LOG_FILE_HANDLE
				  "$::progname: 2653-103 Could not determine this node's hostname as known by the management server.\n";
				$::GLOBAL_EXIT = 1;
				exit;
		}
	}
}

#   IMBEDDEDISINFO   -  Start imbedded install server information
#   End imbedded install server info

#  set the install server name and directory to mount from the imbedded
#      info - split name and dir

($::csm_server, $::MNTdir) = split(/:/, $::ISinfo{$::akb_nodename});
$::csm_server =~ s/^\s*//;    # delete leading white space
$::csm_server =~ s/\s*$//;    # delete trailing spaces
chomp $::csm_server;

print "osprereboot: InstallServer $::csm_server\n";    # if $::DEBUG;

# set $::CSMINSTDIR  and $::CSMLINUXDIR
chomp $::MNTdir;

if ($::MNTdir eq "")
{

	# if MNTdir is blank then set the default
	$::MNTdir      = "/csmserver";
	$::CSMINSTDIR  = "/csmserver/csm";
	$::CSMLINUXDIR = "/csmserver/Linux";

}
else
{

	# make sure we have a valid dir path, and strip off ending "/" if any
	my $num = length($::MNTdir);
	my $temp = rindex($::MNTdir, "/");
	if ($temp >= 0)
	{
		if (($temp + 1) == $num)
		{

			# get rid os the "/" at the end
			chop($::MNTdir);
		}

		$::CSMINSTDIR  = $::MNTdir . "/csm";
		$::CSMLINUXDIR = $::MNTdir . "/Linux";
	}
	else
	{
		print "Error: $::MNTdir is not a valid path name.\n";
	}
}

#
# mount $::MNTdir/csm and $::MNTdir/Linux if not already mounted
#    (default- /csminstall/csm & /csminstall/Linux )
#
if (&mount_csminstall($::CSMINSTDIR, $::CSM_MOUNT) != 0)
{
	$::GLOBAL_EXIT = 1;
	exit;
}
else
{
	if ($::FLAG)
	{
		$::mounted++;
	}
}

#
# get info from the config_info file
#
if (&get_config_info != 0)
{
	print
	  "$::progname: 2653-104 Could not get node attribute values from config_info file.\n";
	print $::LOG_FILE_HANDLE
	  "$::progname: 2653-104 Could not get node attribute values from config_info file.\n";
	$::GLOBAL_EXIT = 1;
	exit;
}

if ($::PLTFRM eq "Linux" and 
	($::InstallMethod ne "you" and $::InstallMethod ne "kickstart-upgrade"))
{
	&config_network;
}

if ($::PLTFRM eq "Linux")
{
	if (&mount_csminstall($::CSMLINUXDIR, $::CSM_MOUNT_LINUX) != 0)
	{
		$::GLOBAL_EXIT = 1;
		exit;
	}
	else
	{
		if ($::FLAG)
		{
			$::mounted_linux++;
		}
	}
}

#
# copy files to /opt/csm/install directory on the node
#
if (&copy_files != 0)
{
	print
	  "$::progname: 2653-105 An error occured when copying files to \"$::OPTCSMINSTALL\".\n";
	print $::LOG_FILE_HANDLE
	  "$::progname: 2653-105 An error occured when copying files to \"$::OPTCSMINSTALL\".\n";
	$::GLOBAL_EXIT = 1;
	exit;
}

#
# Add lines to /etc/lilo.conf and /etc/inittab to allow
# remote console support for this node once the node reboots.
#

if ($::PLTFRM eq "Linux")
{
	if ($::arch ne "ppc64")
	{
		my $cmd = "$::CSM_MOUNT/setupconsole 2>&1";
		print $::LOG_FILE_HANDLE "$::progname: Running $cmd\n";
		print $::LOG_FILE_HANDLE `$cmd`;
		print $::LOG_FILE_HANDLE "$::progname: Return Code from command = $?\n";
	}
	else
	{
		#/dev/console does not work on RHEL5 by default, setup the console manually 
		if (($::distribution_name =~ /RedHatEL/) && ($::distribution_version >= 5))
		{
			`/bin/sed -i 's/console=ttyS[0-9]/console=hvc0/g' /boot/etc/yaboot.conf`;
			if ($::InstallMethod ne "kickstart-upgrade")
			{
				`echo  "hvc0:1235:respawn:/sbin/agetty -L 9600 hvc0 vt320" >>/etc/inittab`;
				`echo "hvc0" >>/etc/securetty`;
			}
		}
	}
}

# Add csmgrabport script into runlevel 3  script.
# During an install(RedHat), there is a possibility that certain services 
# (rpc.statd, rpc.mounted, nfsd, biod and even yp) can highjack the RMC reserve port 657.
# In order to avoid it, we use this script to preemptively grab port 657 firstly and
# release port 657 once osfirstboot runs to make sure port 657 available for RSCT.
#    Note: regarding RedHat upgrade scenario, RSCT has been installed on the node, 
#          and we don't need to grab port for it.
if (  ($::PLTFRM eq "Linux")
   && ( -f "/etc/redhat-release")
   && !($::mode =~ /DCInstall/ || $::mode =~ /MinManaged/)
   && ($::InstallMethod ne "kickstart-upgrade")
   ) 
{
    &generate_csmgrabport();

}

#
# add an entry for osfirstboot to the /etc/inittab file
#
if (&update_inittab != 0)
{

	# print "$::progname:  2653-036 Could not update \"$::inittab\".\n";
	# print $::LOG_FILE_HANDLE  "$::progname:  2653-036 Could not update \"$::inittab\".\n";
	$::GLOBAL_EXIT = 1;
	exit;
}

#
##		Run  csmprereboot
#

##		Run customer provided scripts

#	Set some environment variables for the cust scripts to use

#   The name of this node as it is known by the CSM
#   management server

$ENV{'CSMNODENAME'} = "$::akb_nodename";

#	The mount point for CSM on the node is equivalent
#	to /csminstall on the management server

$ENV{'CSMMOUNTPOINT'} = "/var/opt/csm/mnt";

#	The data directory where additional user provided scripts
#	and data files will be located.

$ENV{'SCRIPTDATAPATH'} = "/var/opt/csm/mnt/csm/scripts/data";

##	Run each user script
#   The script list and script directory are different for different 
#   install methods
my @scriptlist;
my $scriptdir;
if ($::InstallMethod eq "you" || $::InstallMethod eq "kickstart-upgrade")
{
	@scriptlist = @::preosupgradescripts;
	$scriptdir  = $::OSUPGRADE_PREREBOOT_SCRIPT_DIR
}
else
{
	@scriptlist = @::preinstscripts;
	$scriptdir  = $::PREREBOOT_SCRIPT_DIR
}
foreach my $name (@scriptlist)
{

	#	cd to the directory of the customer's script in case they
	#	use a relative path to get to the data directory.

	my $cmd = "cd $scriptdir; ./$name";
	print $::LOG_FILE_HANDLE
	  "$::progname: 2653-144 Beginning Customer Script: $cmd. Reported $rc.\n";

	&stop_logging(1);

	my $output = `$cmd 2>&1`;
	chomp($output);
	$rc = $? >> 8;

	&append_logging($::INSTALL_LOG, 1);

	if ($rc != 0)
	{
		print
		  "$::progname: 2653-144 Error running command $cmd. Reported $rc.\n";
		print $::LOG_FILE_HANDLE
		  "$::progname: 2653-144 Error running command $cmd. Reported $rc.\n";
	}
	else
	{
		print $::LOG_FILE_HANDLE
		  "$::progname: 2653-144 Completed Customer Script $cmd. Reported $rc.\n";
	}
}

#
##		Finish up and exit
#

END
{

	#
	# unmount /csminstall/csm  and /csminstall/Linux - if we mounted it
	#
	if ($::mounted)
	{
		if (&unmount_csminstall($::CSM_MOUNT) != 0)
		{
			$::GLOBAL_EXIT = 1;
			exit;
		}
	}
	if ($::mounted_linux)
	{
		if (&unmount_csminstall($::CSM_MOUNT_LINUX) != 0)
		{
			$::GLOBAL_EXIT = 1;
			exit;
		}
	}

	if ($::logging)
	{
		&stop_logging();
	}

	#Determine exit code
	if ($::GLOBAL_EXIT > $?)
	{
		$? = $::GLOBAL_EXIT;
	}
}

exit;    # end of Main

#
#-------------------------------------------------------------------------#
# parse_args - Parse the command line for options and operands.           #
#--------------------------------------#----------------------------------#
sub parse_args
{

	my @command_line = ();
	@command_line   = @ARGV;
	$::command_line = $0 . " " . join(" ", @command_line);

	#
	# Process the command line...
	#
	if (!getopts('n:'))
	{    # Gather options
		exit 1;
	}

	if ($::opt_n ne "")
	{
		$::akb_nodename = $::opt_n;
		$::akb_nodename =~ s/^\s*//;
		$::akb_nodename =~ s/\s*$//;
		chomp $::akb_nodename;
		print "csmprereboot: Node name is $::akb_nodename\n" if $::DEBUG;
		$::foundakbname++;
	}
	return $::OK;
}

#
#-------------------------------------------------------------------------#
#  get_niminfo  - Get the hostname from the /etc/niminfo file.            #
#                                                                         #
#   Note: This assumes that the NIM master is always defined on the       #
#         install server.                                                 #
#                                                                         #
#   Return Codes: 0 - All was successful.                                 #
#                 1 - An error occured.                                   #
#--------------------------------------#----------------------------------#
sub get_niminfo
{
	my ($junk, $line, $server_long_hostname, $node_long_hostname);

	if (-f $::NIMINFO)
	{
		$line = `$::CAT $::NIMINFO | grep "NIM_HOSTNAME"`;
		($junk, $node_long_hostname) = split(/=/, $line);
		$node_long_hostname =~ s/^\s*//;    # delete leading white space
		$::akb_nodename = $node_long_hostname;
		chomp $::akb_nodename;
	}
	else
	{
		print "$::progname:  2653-035 Could not find \"$::NIMINFO\" file.\n";
		print $::LOG_FILE_HANDLE
		  "$::progname: 2653-035 Could not find \"$::NIMINFO\" file.\n";
		return $::NOK;
	}
	return $::OK;
}
#
#-------------------------------------------------------------------------#
#  get_akbname_from_NODEINFO - Get the node hostname from the NODEINFO    #
#         Hash that was embedded in osprereboot.  The hostname is the     #
#         name as known by the management server.  Get all this node's IP #
#         Addresses using ifconfig, and find one that matches an entry in #
#         %::NODEINFO. Sets $::akb_nodename to the matching hostname.     #
#                                                                         #
#   Global Variables:  $::NODEINFO                                        #
#                      $::akb_nodename                                    #
#                      $::foundakbname                                    #
#                                                                         #
#   Return Codes: 0 - All was successful.                                 #
#                 1 - An error occured.                                   #
#--------------------------------------#----------------------------------#
sub get_akbname_from_NODEINFO
{
	my $hostname = '';
    my @IPS = 
		`ifconfig | grep Bcast | awk '{print \$2}' | awk -F: '{print \$2}'`;
	foreach my $ip (@IPS)
	{
		chomp $ip;
		if ($::NODEINFO{$ip})
		{
			$hostname = $::NODEINFO{$ip};
		}
	}
	if ($hostname)
	{
		$::akb_nodename = $hostname;
		$::foundakbname++;
	}
	else
	{
		print "$::progname:  None of this node's IP addresses (" .
			join (", ", @IPS) .
			") match a node known by the management server.\n";
		print $::LOG_FILE_HANDLE
			"$::progname:  None of this node's IP addresses (" .
			join (", ", @IPS) .
			") match a node known by the management server.\n";
		return $::NOK;
	}
	return $::OK;
}

#-------------------------------------------------------------------------#
#   mount_csminstall - mount the /csminstall/csm and /csminstall/Linux    #
#		       directories                                                #
#                                                                         #
#   Return Codes: 0 - All was successful.                                 #
#                 1 - An error occured.                                   #
#--------------------------------------#----------------------------------#
sub mount_csminstall
{
	my ($src_dir, $dest_dir) = @_;
	my $cmd;
	my $rc;
	my $srcdir;
	my $output;

	$cmd = "$::MOUNT | $::GREP $dest_dir >/dev/null 2>&1";
	$rc  = system("$cmd");
	if ($rc >> 8)
	{
		print $::LOG_FILE_HANDLE
		  "$0: mounting $::csm_server:$src_dir to $dest_dir\n"
		  if $::DEBUG;
		$srcdir = "$::csm_server:$src_dir";
		chomp $srcdir;
		if (!-d $dest_dir)
		{

			# create a local directory
			$cmd = "$::MKDIR -m 755 -p $dest_dir";
			$rc  = system("$cmd");
			if ($rc >> 8)
			{
				print
				  "$::progname:  2653-158 Could not create \"$dest_dir\" directory.\n";
				print $::LOG_FILE_HANDLE
				  "$::progname: 2653-158 Could not create \"$dest_dir\" directory.\n";
				return $::NOK;
			}
		}

		#  Mount the /<install server dir>/csm filesystem
		$cmd = "$::MOUNT -o nolock $srcdir $dest_dir";
		my @output = `$cmd 2>&1`;
		if ($?>>8)
		{
			if(grep /already mounted/, @output)
			{
				print $::LOG_FILE_HANDLE "\"$srcdir\" has already been mounted.\n";
				print "$::progname: \"$srcdir\" has already been mounted.\n";
				#$::FLAG = 1;
			}
			else
			{
				print "$::progname:  2653-032 Could not mount \"$srcdir\".\n";
				print $::LOG_FILE_HANDLE
				  "$::progname: 2653-032 Could not mount \"$srcdir\".\n";
				return $::NOK;  
			}
		}
		else
		{
			print $::LOG_FILE_HANDLE "\"$srcdir\" is mounted now.\n";
			print "$::progname: \"$srcdir\" is mounted now.\n";
			$::FLAG = 1;
		}
	}
	else
	{
		print "$::progname:  \"$dest_dir\" is already mounted.\n";
		print $::LOG_FILE_HANDLE
		  "$::progname: \"$dest_dir\" is already mounted.\n";
	}
	return $::OK;
}

#-------------------------------------------------------------------------#
#   get_config_info - Get required information out of the config_info     #
#                     file. This file contains attributes and values for  #
#                     the node we are running on.                         #
#                                                                         #
#   Return Codes: 0 - All was successful.                                 #
#                 1 - An error occured.                                   #
#--------------------------------------#----------------------------------#

sub get_config_info
{

	my ($attr, $value);
	my $cfg_file   = "$::CSMCFGDIR/$::akb_nodename.config_info";
	my $match_vers = 0;

	if (!-f $cfg_file)
	{
		$cfg_file = "/mnt" . $cfg_file;
	}
	if (-f $cfg_file)
	{
		unless (open(CFGINFO, "<$cfg_file"))
		{
			print
			  "$::progname: 2653-142 Cannot open file \"$cfg_file\" for reading.\n";
			print $::LOG_FILE_HANDLE
			  "$::progname: 2653-142 Cannot open file \"$cfg_file\" for reading.\n";
			return $::NOK;
		}
		while (<CFGINFO>)
		{
			($attr, $value) = split('=');
			if (defined($attr) && defined($value))
			{
				if ($attr eq "InstallCSMVersion")
				{
					$match_vers++;
					$::csmversion = $value;
					chomp $::csmversion;
				}

				if ($attr eq "PREREBOOT_SCRIPT_DIR")
				{
					$::PREREBOOT_SCRIPT_DIR = $value;
					chomp $::PREREBOOT_SCRIPT_DIR;
				}

				if ($attr eq "OSUPGRADE_PREREBOOT_SCRIPT_DIR")
				{
					$::OSUPGRADE_PREREBOOT_SCRIPT_DIR = $value;
					chomp $::OSUPGRADE_PREREBOOT_SCRIPT_DIR;
				}

				if ($attr eq "PREINSTSCRIPTS")
				{
					@::preinstscripts = split(" ", $value);
				}

				if ($attr eq "PREOSUPGRADESCRIPTS")
				{
					@::preosupgradescripts = split(" ", $value);
				}

				if ($attr eq "InstallAdapterMacaddr")
				{
                    			$::macaddr = lc($value);
					chop($::macaddr);

				}

				if ($attr eq "InstallDistributionName")
				{
					$::distribution_name = $value;
					chomp $::distribution_name;
				}

				if ($attr eq "InstallDistributionVersion")
				{
					$::distribution_version = $value;
					chomp $::distribution_version;
				}

				if ($attr eq "Mode")
				{
					$::mode = $value;
					chomp $::mode;
				}

				if ($attr eq "InstallMethod")
				{
					$::InstallMethod = $value;
					chomp $::InstallMethod;
				}
				if ($attr eq "ManagementServer")
				{
					$::ManagementServer = $value;
					chomp $::ManagementServer;
				}
			}
		}
		if (!$match_vers)
		{
			print
			  "$::progname:  2653-174 Could not find attribute values in \"$cfg_file\" file.\n";
			print $::LOG_FILE_HANDLE
			  "$::progname: 2653-174 Could not find attribute values in \"$cfg_file\" file.\n";
			return $::NOK;
		}
		close(CFGINFO);
	}
	else
	{
		print "$::progname: 2653-023 \"$cfg_file\" does not exist.\n";
		print $::LOG_FILE_HANDLE
		  "$::progname: 2653-023 \"$cfg_file\" does not exist.\n";
		return $::NOK;
	}
	return $::OK;
}

#-------------------------------------------------------------------------#
#   copy_files  - copy files to the node from the management server       #
#                                                                         #
#-------------------------------------------------------------------------#
#   Return Codes: 0 - All was successful.                                 #
#                 1 - An error occured.                                   #
#--------------------------------------#----------------------------------#
sub copy_files
{

	my ($rc, $cmd, $src);
	my $dest     = "/opt/csm/install";
	my $cfg_file = "/opt/csm/install/configinfo";
	my $srcdir   = "$::CSM_MOUNT";
	my @csm_files = (
					 'csmfirstboot',              'Rpm',
					 'NodeUtils.pm',              'ArchiveUtils.pm',
					 'MessageUtils.pm',           'NetworkUtils.pm',
					 'ServerUtils.pm',            'CSMDefs.pm',
					 'csmInstall.csminstall.map', 'nodecmds.NodeUtils.map',
					 'defs',                      'pkgdefs',
					 'osfirstboot',               'csmprereboot'
					);

	# if this is ppc linux, then add setbootdisk
	if ($::arch eq "ppc64")
	{
		push @csm_files, 'setbootdisk';
	}
	if($::mode ne "DCInstall")
	{
		push @csm_files,'makenode';
	}
	# create directory for files that will be copied
	if (!-e $dest)
	{
		$cmd = "$::MKDIR -m 755 -p $dest";
		$rc  = system("$cmd");
		if ($rc >> 8)
		{
			print
			  "$::progname:  2653-158 Could not create \"$dest\" directory.\n";
			print $::LOG_FILE_HANDLE
			  "$::progname: 2653-158 Could not create \"$dest\" directory.\n";
			return $::NOK;
		}
	}

	#
	# copy the config_info file
	#

	$src = "$::CSMCFGDIR/$::akb_nodename.config_info";
	$cmd = "$::COPY $src $cfg_file";
	$rc  = system("$cmd");
	if ($rc >> 8)
	{
		print
		  "$::progname: 2653-159 Could not copy \"$src\" to \"$cfg_file\".\n";
		print $::LOG_FILE_HANDLE
		  "$::progname: 2653-159 Could not copy the \"$src\" file to \"$cfg_file\".\n";
		return $::NOK;
	}

	#
	# copy the rest of the files
	#
	foreach my $file (@csm_files)
	{
		$src = "$srcdir/$file";
		$cmd = "$::COPY -r $src $dest";
		$rc  = system("$cmd");
		if ($rc >> 8)
		{
			print
			  "$::progname: 2653-159 Could not copy \"$src\" to \"$dest\".\n";
			print $::LOG_FILE_HANDLE
			  "$::progname: 2653-159 Could not copy the \"$src\" file to \"$dest\".\n";
			return $::NOK;
		}
	}
	return $::OK;
}

#-------------------------------------------------------------------------#
#   update_inittab  - add an entry for osfirstboot to the /etc/inittab    #
#                     file                                                #
#                                                                         #
#   Description:  This function updates the /etc/inittab file.  It        #
#                 places an entry for osfirstboot after rctcpip in        #
#                 in /etc/inittab so that it is run on the next (first)   #
#                 boot after installation.                                #
#                                                                         #
#   Arguments:    None.                                                   #
#                                                                         #
#   Return Codes: 0 - All was successful.                                 #
#                 1 - An error occured.                                   #
#--------------------------------------#----------------------------------#
sub update_inittab
{

	my ($cmd, $rc, $entry);

	#
	# Add entry for osfirstboot to the end of /etc/inittab
	#
	if ($::PLTFRM eq "AIX")
	{
		$entry = "csm:2:wait:/opt/csm/install/osfirstboot";

		# see if it is already there
		$cmd = "$::LSITAB $entry >/dev/null 2>&1";
		$rc  = system("$cmd");
		if ($rc >> 8)
		{    #  entry does not exist
			$cmd = "$::MKITAB $entry >/dev/null 2>&1";
			$rc  = system("$cmd");
			if ($rc >> 8)
			{
				print
				  "$::progname: 2653-036 Could not update  \"$::inittab\".\n";
				print $::LOG_FILE_HANDLE
				  "$::progname: 2653-036 Could not update \"$::inittab\".\n";
				return $::NOK;
			}
		}
	}
	elsif ($::PLTFRM eq "Linux")
	{
		# Add a line to inittab, but only if it doesn't already exist
		my $inittab_line = "csm:345:wait:/opt/csm/install/osfirstboot";

		my $grepout = `grep $inittab_line $::inittab`;
		if (! $grepout)
		{
			unless (open(INITTAB, ">>$::inittab"))
			{
				print "$::progname: 2653-106 Could not open \"$::inittab\".\n";
				print $::LOG_FILE_HANDLE
				  "$::progname: 2653-106 Could not open \"$::inittab\".\n";
				return $::NOK;
			}
			print INITTAB "$inittab_line\n";
			close(INITTAB);
		}

	}
	else
	{
		print "$::progname: 2653-036 Could not update  \"$::inittab\".\n";
		print $::LOG_FILE_HANDLE
		  "$::progname: 2653-036 Could not update \"$::inittab\".\n";
		return $::NOK;
	}
	return $::OK;
}

#-------------------------------------------------------------------------#
#   unmount_csminstall - unmount the /csminstall/csm and /csminstall/     #
#			 Linux directory                                  #
#                                                                         #
#   Return Codes: 0 - All was successful.                                 #
#                 1 - An error occured.                                   #
#--------------------------------------#----------------------------------#
sub unmount_csminstall
{
	my ($unmnt_dir, undef) = @_;
	my ($rc,        $cmd);

	print "$0: unmounting $unmnt_dir\n";
	$cmd = "$::UMOUNT $unmnt_dir";
	$rc  = system("$cmd");
	if ($rc >> 8)
	{
		print
		  "$::progname: 2653-037 The internal call to \"$::UMOUNT\" was not successful.\n";
		print $::LOG_FILE_HANDLE
		  "$::progname: 2653-037 The internal call to \"$::UMOUNT\" was not successful.\n";
		print "$::progname: 2653-033 Could not unmount \"$unmnt_dir\".\n";
		print $::LOG_FILE_HANDLE
		  "$::progname:  2653-033 Could not unmount \"$unmnt_dir\".\n";
		return $::NOK;
	}
	else
	{
		print $::LOG_FILE_HANDLE "$::progname: \"$unmnt_dir\" is unmounted.\n";
		print "\"$unmnt_dir\" is unmounted.\n";
	}
	return $::OK;
}

#-------------------------------------------------------------------------#
#                                                                         #
#   backup_logfile                                                        #
#                                                                         #
#        Backup the current logfile. Move logfile to logfile.1.           #
#        Shift all other logfiles (logfile.[1-3]) up one number.          #
#        The original logfile.4 is removed.                               #
#                                                                         #
#-------------------------------------------------------------------------#
sub backup_logfile
{
	my ($logfile) = @_;

	my ($logfile1) = $logfile . ".1";
	my ($logfile2) = $logfile . ".2";
	my ($logfile3) = $logfile . ".3";
	my ($logfile4) = $logfile . ".4";

	if (-f $logfile)
	{

		rename($logfile3, $logfile4) if (-f $logfile3);
		rename($logfile2, $logfile3) if (-f $logfile2);
		rename($logfile1, $logfile2) if (-f $logfile1);
		rename($logfile,  $logfile1) if (-f $logfile);
	}
	return $::OK;
}

#-------------------------------------------------------------------------#
#                                                                         #
#    start_logging                                                        #
#                                                                         #
#           Start logging messages to a logfile. Return the log file      #
#           handle so it can be used to close the file when done logging. #
#                                                                         #
#-------------------------------------------------------------------------#
sub start_logging
{
	my ($logfile) = @_;
	my ($cmd, $rc);

	&backup_logfile($logfile);

	# create the log directory if it's not already there
	if (!-d $::CSMLOG)
	{
		$cmd = "$::MKDIR -m 644 -p $::CSMLOG";
		$rc  = system("$cmd");
		if ($rc >> 8)
		{
			print
			  "$::progname: 2653-158 Could not create \"$::CSMLOG\" directory.\n";
			return ($::NOK);
		}
	}

	# open the log file
	unless (open(LOGFILE, ">$logfile"))
	{

		# Cannot open file
		print
		  "$::progname: 2653-141 Cannot open file \"$logfile\" for writing.\n";
		return $::NOK;
	}

	$::LOG_FILE_HANDLE = \*LOGFILE;

	# announce logging and print the date to the top of the logfile
	my $sdate = `/bin/date`;
	chomp $sdate;
	print "Output log is being written to \"$logfile\".\n";
	print $::LOG_FILE_HANDLE
	  "---------------------------------------------------------------------\n";
	print $::LOG_FILE_HANDLE "$::progname: Logging started $sdate.\n";
	print $::LOG_FILE_HANDLE
	  "---------------------------------------------------------------------\n";
	print $::LOG_FILE_HANDLE $::command_line . "\n";

	return ($::LOG_FILE_HANDLE);
}

#-------------------------------------------------------------------------#
#                                                                         #
#    append_logging                                                       #
#                                                                         #
#         Append logging messages to a logfile. Return the log file       #
#           handle so it can be used to close the file when done logging. #
#                                                                         #
#-------------------------------------------------------------------------#
sub append_logging
{
	my ($logfile, $stat) = @_;
	my ($cmd,     $rc);

	# create the log directory if it's not already there
	if (!-d $::CSMLOG)
	{
		$cmd = "$::MKDIR -m 644 -p $::CSMLOG";
		$rc  = system("$cmd");
		if ($rc >> 8)
		{
			print
			  "$::progname: 2653-158 Could not create \"$::CSMLOG\" directory.\n";
			return ($::NOK);
		}
	}

	#
	#  get log file ready
	#
	if (!-e $logfile)
	{    #  create the log file if not already there
		    # open the log file
		unless (open(LOGFILE, ">$logfile"))
		{

			# Cannot open file
			print
			  "$::progname: 2653-141 Cannot open file \"$logfile\" for writing.\n";
			return $::NOK;
		}
	}
	else
	{       # it's there so just append
		unless (open(LOGFILE, ">>$logfile"))
		{
			print "$::progname: 2653-036 Could not update  \"$logfile\".\n";
			return $::NOK;
		}
	}

	$::LOG_FILE_HANDLE = \*LOGFILE;

	if ((defined $stat) && ($stat == 1))
	{
		return ($::LOG_FILE_HANDLE);
	}

	# Print the date to the top of the logfile
	my $sdate = `/bin/date`;
	chomp $sdate;
	print "Output log is being written to \"$logfile\".\n";
	print $::LOG_FILE_HANDLE
	  "---------------------------------------------------------------------\n";
	print $::LOG_FILE_HANDLE "$::progname: Logging started $sdate.\n";
	print $::LOG_FILE_HANDLE
	  "---------------------------------------------------------------------\n";
	print $::LOG_FILE_HANDLE $::command_line . "\n";

	return ($::LOG_FILE_HANDLE);
}

#-------------------------------------------------------------------------#
#                                                                         #
#    stop_logging                                                         #
#                                                                         #
#                  Turn off message logging.  (Expects to have a file     #
#                   handle passed in. )                                   #
#                                                                         #
#-------------------------------------------------------------------------#
sub stop_logging
{

	# Print the date at the bottom of the logfile
	my ($stat) = @_;
	my $sdate = `/bin/date`;
	chomp $sdate;
	if ($stat != 1)
	{
		print $::LOG_FILE_HANDLE
		  "---------------------------------------------------------------------\n";
		print $::LOG_FILE_HANDLE "$::progname: Logging stopped $sdate.\n";
		print $::LOG_FILE_HANDLE
		  "---------------------------------------------------------------------\n";
	}

	close($::LOG_FILE_HANDLE);
	$::LOG_FILE_HANDLE = undef;

	return $::OK;
}

#-------------------------------------------------------------------------#
#                                                                         #
#                                                                         #
#  config_network                                                         #
#                                                                         #
#          To configure network using the HW address in config file.      #
#                                                                         #
#                                                                         #
#-------------------------------------------------------------------------#
sub config_network
{
	my ($IP, $BC, $SM, $netdevice);

	$netdevice = `ifconfig | grep -m1 Ethernet | awk '{print \$1}' `;
	chop($netdevice);
	if ($netdevice eq "")
	{
		print $::LOG_FILE_HANDLE
		  "$::progname: Could not find the netdevice for hw address: $::macaddr .\n";
		return $::NOK;
	}

	if ($::macaddr eq "")
	{
		$::macaddr =
		  `ifconfig $netdevice | grep -m1 Ethernet |awk '{print \$5}' `;
		chop($::macaddr);
		$::macaddr=lc($::macaddr);

		if ($::macaddr eq "")
		{
			print $::LOG_FILE_HANDLE
			  "$::progname: Could not config netdevice without hw address .\n";
			return $::NOK;
		}
	}

=head
    #just need ipv4 information, so use Bcast
    $IP =
      `ifconfig $netdevice | grep Bcast | head -n1 | awk '{print \$2}' | awk -F: '{print \$2}'`;
    $BC =
      `ifconfig $netdevice | grep Bcast | head -n1 |  awk '{print \$3}' | awk -F: '{print \$2}'`;
    $SM =
      `ifconfig $netdevice | grep Bcast | head -n1 |  awk '{print \$4}' | awk -F: '{print \$2}'`;
    chop($IP);
    chop($BC);
    chop($SM);
=cut

	$IP = $ENV{NODE_IP};
	$BC = $ENV{NODE_BC};
	if (!$BC)
	{
		$BC =
		  `ifconfig $netdevice | grep Bcast | head -n1 |  awk '{print \$3}' | awk -F: '{print \$2}'`;
		chomp($BC);
	}
	$SM = $ENV{NODE_MASK};
	if (!$SM)
	{
		$SM =
		  `ifconfig $netdevice | grep Bcast | head -n1 |  awk '{print \$4}' | awk -F: '{print \$2}'`;
		chomp($SM);
	}
	chomp $IP;
	chomp $SM;
	my ($ia, $ib, $ic, $id) = split('\.', $IP);
	my ($na, $nb, $nc, $nd) = split('\.', $SM);

	# Convert to integers so the bitwise and (&) works correctly.
	int $ia;
	int $ib;
	int $ic;
	int $id;
	int $na;
	int $nb;
	int $nc;
	int $nd;
	my $sa     = ($ia & $na);
	my $sb     = ($ib & $nb);
	my $sc     = ($ic & $nc);
	my $sd     = ($id & $nd);
	my $subnet = "$sa.$sb.$sc.$sd";

	my $cfg_dir = "/etc/sysconfig/network-scripts";

	my $cfg_dir = "/etc/sysconfig/network-scripts";
	if (!(-d $cfg_dir))
	{
		$cfg_dir = "/etc/sysconfig/network";
	}

	if (($::distribution_name =~ /SLES/) && ($::distribution_version =~ /9/))
	{
		`$::COPY $cfg_dir/ifcfg-eth-id-$::macaddr /tmp/ifcfg-eth-id-$::macaddr.ORIG`;
	}
	else
	{
		`$::COPY $cfg_dir/ifcfg-$netdevice /tmp/ifcfg-$netdevice.ORIG`;
	}

	if (($::distribution_name =~ /SLES/) && ($::distribution_version >= 10))
	{
	    # for sles above 10, the network device configing be moved to 
	    # autoyast configure file
	}
	elsif (($::distribution_name =~ /SLES/) && ($::distribution_version =~ /9/))
	{
		if ($::arch eq "x86_64")
		{
			`echo "BOOTPROTO='static'
BROADCAST='$BC'
IPADDR='$IP'
MTU=''
NETMASK='$SM'
NETWORK='$subnet'
REMOTE_IPADDR=''
STARTMODE='onboot'
HWADDR='$::macaddr'" > $cfg_dir/ifcfg-eth-id-$::macaddr`;
		}
		else
		{
			`echo "BOOTPROTO='static'
BROADCAST='$BC'
IPADDR='$IP'
MTU=''
NETMASK='$SM'
NETWORK='$subnet'
REMOTE_IPADDR=''
STARTMODE='onboot'" > $cfg_dir/ifcfg-eth-id-$::macaddr`;
		}
	}
	elsif (($::distribution_name =~ /SLES/) && ($::distribution_version =~ /8/))
	{
		if ($::arch eq "x86_64")
		{
			`echo "BOOTPROTO='static'
REMOTE_IPADDR=''
STARTMODE='onboot'
BROADCAST='$BC'
IPADDR='$IP'
NETMASK='$SM'
NETWORK='$subnet'
HWADDR='$::macaddr'" > $cfg_dir/ifcfg-$netdevice`;
		}
		else
		{
			`echo "BOOTPROTO='static'
REMOTE_IPADDR=''
STARTMODE='onboot'
BROADCAST='$BC'
IPADDR='$IP'
NETMASK='$SM'
NETWORK='$subnet'" > $cfg_dir/ifcfg-$netdevice`;
		}
	}
	elsif (   ($::distribution_name =~ /RedHatEL/)
		   && ($::distribution_version =~ /4/))
	{
		`echo "DEVICE=$netdevice
BOOTPROTO='static'
REMOTE_IPADDR=''
STARTMODE='onboot'
BROADCAST='$BC'
IPADDR='$IP'
NETMASK='$SM'
NETWORK='$subnet'
HWADDR='$::macaddr'" > $cfg_dir/ifcfg-$netdevice`;
	}
	elsif (($::arch eq "x86_64") && (!($::distribution_name =~ /SLES/)))
	{
		`echo "DEVICE=$netdevice
STARTMODE=onboot
ONBOOT=yes
HWADDR=$::macaddr
IPADDR=$IP
BROADCAST=$BC
NETMASK=$SM" > $cfg_dir/ifcfg-$netdevice`;
	}
	else
	{
		`echo "DEVICE=$netdevice
STARTMODE=onboot
ONBOOT=yes
IPADDR=$IP
BROADCAST=$BC
NETMASK=$SM" > $cfg_dir/ifcfg-$netdevice`;
	}

	return $::OK;
}

#-------------------------------------------------------------------------#
#                                                                         #
#                                                                         #
#  generate_csmgrabporta                                                  #
#                                                                         #
#          add csmgrabport script into /etc/rc.d/rc3.d/S13csmgrabport.    #
#                                                                         #
#                                                                         #
#-------------------------------------------------------------------------#

sub generate_csmgrabport
{
    # Hardcode csmgrabport script and put it into /etc/rc.d/rc3.d/S13csmgrabport.
    my $src_script = <<'EOF_SCRIPT';
#!/usr/bin/perl
use IO::Socket;
use Getopt::Long;
$::PIDFILE = '/var/lock/csm/csmgrabport.pid';
$::LOGFILE = '/var/log/csm/install.log';
$::progname  = "csmgrabport";
$::PORT      = 657;
$::CSMLOG    = "/var/log/csm";
$::CSMLOCK   = "/var/lock/csm";
$::NOK       = 1;
$::OK        = 0;
$::MKDIR       = "/bin/mkdir";

# create the log directory if it's not already there

my $cmd,$rc;
if (!-d $::CSMLOG)
{
        $cmd = "$::MKDIR -m 644 -p $::CSMLOG";
        $rc  = system("$cmd");
        if ($rc >> 8)
        {
                print
                  "$::progname: 2653-158 Could not create \"$::CSMLOG\" directory.\n";
                return ($::NOK);
        }
}
if (!-d $::CSMLOCK)
{
        $cmd = "$::MKDIR -m 644 -p $::CSMLOCK";
        $rc  = system("$cmd");
        if ($rc >> 8)
        {
                print
                  "$::progname: 2653-158 Could not create \"$::CSMLOCK\" directory.\n";
                return ($::NOK);
        }
}

system("echo 'Running $::progname to preemptively grab port $::PORT' >> $::LOGFILE");

if ( -f $::PIDFILE ) {
   print "CSM grab port daemon already running!\n";
   open(PID, $::PIDFILE);
   $pid = <PID>;
   close PID;
   print "PID=$pid\n";
   exit 1;
}

open(STDIN, "/dev/null");
open(STDOUT, ">/dev/null");
open(STDERR, ">/dev/null");
# Fork child process as a daemon.
my $child = fork();
if(!defined $child) {
	system("echo '2653-339 Could not fork child process' >> $::LOGFILE");
	exit 1;
}
if ($child !=0 )
{
    # Parent process exit
    exit 0;
}

$pid = $$;
unless (open(PID, "> $::PIDFILE"))
{ 
    system("echo 'Could not create PID file at: $::PIDFILE\n' >> $::LOGFILE");
    exit 1;
}
print PID $pid;
close PID;

$SIG{PIPE} = 'IGNORE';
$SIG{HUP} = sub {
   unlink($::PIDFILE); 
   return('1');
};
$SIG{TERM} = sub {
   unlink($::PIDFILE);
   exit 1;
};
$SIG{INT} = sub {
   warn "-Cought Signal Interrupt, exiting...\n";
   unlink($::PIDFILE);
   exit 1;
};

system("echo 'Listening UDP socket at port $::PORT' >> $::LOGFILE");
my $udp_socket = IO::Socket::INET->new(Proto     => 'udp',
                              LocalPort => $::PORT,
                              Type      => SOCK_DGRAM,
                              );
if (!$udp_socket)
{
    system("echo 'can't make udp socket on port $::PORT: $!\n' >> $::LOGFILE");
    exit 1;
}

system("echo 'Listening TCP socket at port $::PORT' >> $::LOGFILE");
my $tcp_socket = IO::Socket::INET->new(Proto     => 'tcp',
                              LocalPort => $::PORT,
                              Listen    => 1,
                              Reuse     => 1,
                              );

if (!$tcp_socket)
{
    system("echo 'can't make tcp socket on port $::PORT: $!\n' >> $::LOGFILE");
    exit 1;
}

system("echo \"The pid of csmgrabport daemon is :`cat $::PIDFILE` \" >> $::LOGFILE");
while (1) {};       

END { unlink $::PIDFILE if $$ == $pid; }   
EOF_SCRIPT

    my $S13z = "/etc/rc.d/rc3.d/S13csmgrabport";
    unless (open (S13, ">$S13z")) {
        print 
        "$::progname: 2653-106 Could not open $S13z.\n";
        print $::LOG_FILE_HANDLE
        "$::progname: 2653-106 Could not open $S13z.\n";
        return $::NOK;
    }
    
    print S13 $src_script; 
    close S13;
    chmod 0755, $S13z;
}
