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

#-------------------------------------------------------------------------------

=head1	makedisklessnode

	Description: This script is executed after the boot of a diskless
	node from its diskless boot image. In the /etc/inittab of the diskless 
	boot image, an entry will call this script for each boot of the diskless 
	node.

	It will perform tasks related to CSM features and will call the 
	makenode command.

	Exit codes:
		0 - success
		1 - error

=cut

#-------------------------------------------------------------------------------

use strict;

# BEGIN is executed first, regardless of the loading order of
# other program modules, such as NodeUtils.pm.

BEGIN
{
    use File::Basename;    # The path of the command
    ($::Bin) = dirname($0);    # Assumes msgmaps are in same dir as application
         # This can be meaningful for using csm.core code like
         # runcmd, or using messaging and logging from /csminstall
      # this enables us to redirect where it looks for other CSM files during development
    $::csmroot = $ENV{'CSM_ROOT'} ? $ENV{'CSM_ROOT'} : '/opt/csm';
    $::csmpm   = "$::csmroot/pm";
    $::csmbin  = "$::csmroot/bin";

    # setup messaging globals
    $::MSGCAT = 'csmInstall.cat';

    #$::MSGMAPPATH = $::Bin;
    $::MSGMAPPATH = "$::csmroot/msgmaps";
    $::MSGSET     = 'csminstall';

    #NodeUtils should use the msgmap files in the current directory
    $NodeUtils::MSGMAPPATH = $::MSGMAPPATH;
}

use lib "$::Bin";
use lib $::csmpm;

#use Getopt::Std;
use NodeUtils;
use CSMDefs;
use ServerUtils;
use NetworkUtils;

#-------------------------------------------------------------------------------

=head3	initialize	

	init the global variables

        Notes:

=cut

#-------------------------------------------------------------------------------

sub initialize
{

    $::command_line;

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

    # setup the global defs
    ServerUtils->get_OSDefs($::PLTFRM);

    $::csm_server   = "";    # the long hostname of the install server
    $::akb_nodename = "";    # the long hostname of this node as known by
                             # the management server

    $::OPTCSMINSTALL   = "/opt/csm/install";
    $::CFGINFOFILE     = "$::OPTCSMINSTALL/configinfo";
    $::LOCALCSMINSTDIR = "$::CSMCLIENTMNTDIR/csm";      #"/var/log/csm/mnt/csm";

    $::LOCAL_DISKLESSBOOT_DIR = "$::CSMCLIENTMNTDIR/csm/scripts/disklessboot";
    $::inittab                = "/etc/inittab";
    $::tmpinittab             = "/etc/inittab.tmp";
    $::mounted                = 0;
    $::GLOBAL_EXIT            = 0;
    $::CSMINSTALL_ATFTP       = "$::LOCALCSMINSTDIR/atftp";

    @::disklessboot_scriptlist = ();    #  list of user-provided scripts to run

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

    # make OSDEP INST directories for the MS and the nodes:
    my $msPrefixDir   = "/csminstall";
    my $nodePrefixDir = $::CSMCLIENTMNTDIR;
    my $suffixDir     = "";

    if    ($::PLTFRM eq "Linux") { $suffixDir = "Linux"; }
    elsif ($::PLTFRM eq "AIX")   { $suffixDir = "AIX/csm"; }

    $::CSMOSDEPINSTDIR      = "$msPrefixDir/$suffixDir";
    $::LOCALCSMOSDEPINSTDIR = "$nodePrefixDir/$suffixDir";

    $::OSDEPmounted = 0;
    $::tmpetchosts  = "/tmp/etchosts";
    $::etchosts     = "/etc/hosts";
    $::ETC_HOSTS_MS;    # the "ip longhost shorthost" of the management server
    $::MNTdir = "";     # directory to mount from install server
    %::ISinfo = ();     # hash of install server info

    $::CSMINSTDIR  = "/csminstall/csm";     # this may be replaced in getargs
    $::CSMLINUXDIR = "/csminstall/Linux";
    $::CSMCFGDIR = "$::LOCALCSMINSTDIR/config";

    #$::CAT             = "/bin/cat";
    $::MKDIR = "/bin/mkdir";
    $::COPY  = "/bin/cp";

    #$::MKITAB          = "/usr/sbin/mkitab";
    #$::LSITAB          = "/usr/sbin/lsitab";
    #$::GREP            = "/bin/grep";
    $::CHMOD    = "/bin/chmod";
    $::HOSTNAME = "/bin/hostname";
    if ($::PLTFRM eq "AIX")
    {
        $::MOUNT  = "/usr/sbin/mount";
        $::UMOUNT = "/usr/sbin/umount";
    }
    else
    {
        $::MOUNT  = "/bin/mount";
        $::UMOUNT = "/bin/umount";
    }

}

#-------------------------------------------------------------------------------

=head3	get_configinfo

	figure out the name of the management server, the hostname of this node
	as known by the management server, the CSM Version, etc. 

	return 0 or 1

        Notes:

=cut

#-------------------------------------------------------------------------------

sub get_configinfo
{

    my ($attr, $value);
    my $match_svr         = 0;
    my $match_node        = 0;
    my $match_csmver      = 0;
    my $match_csmosname   = 0;
    my $match_rshell      = 0;
    my $match_setuprshell = 0;
    my $match_powermethod = 0;

    # get info from the config_info file
    if (-f $::CFGINFOFILE)
    {
        unless (open(CFGINFO, "<$::CFGINFOFILE"))
        {

            # Could not open $::CFGINFOFILE.
            MessageUtils->message('E', 'EMsgCANT_READ_FILE', $::CFGINFOFILE);
            return $::NOK;
        }

        while (<CFGINFO>)
        {
            ($attr, $value) = split('=');

            if ($attr eq "ManagementServerIP")
            {
                $match_svr++;
                $::csm_server = $value;
                chomp $::csm_server;
            }
            if ($attr eq "Hostname")
            {
                $match_node++;
                $::akb_nodename = $value;
                chomp $::akb_nodename;
            }
            if ($attr eq "InstallCSMVersion")
            {
                $match_csmver++;
                $::csm_version = $value;
                chomp $::csm_version;
            }
            if ($attr eq "InstallOSName")
            {
                $match_csmosname++;
                $::csm_osname = $value;
                chomp $::csm_osname;
            }
            if ($attr eq "RemoteShell")
            {
                $match_rshell++;
                $::csm_rshell = $value;
                chomp $::csm_rshell;
            }
            if ($attr eq "SetupRemoteShell")
            {
                $match_setuprshell++;
                $::csm_setuprshell = $value;
                chomp $::csm_setuprshell;
            }
            if ($attr eq "InstallServer")
            {
                $::InstallServer = $value;
                chomp $::InstallServer;
            }
            if ($attr eq "InstallServerAKBNode")
            {
                $::InstallServerAKBNode = $value;
                chomp $::InstallServerAKBNode;
            }
            if ($attr eq "InstallServerIsGroup")
            {
                my $isgroup = $value;
                chomp $value;
                if ($value eq "yes") { $::ISGrp = 1; }
            }
            if ($attr eq "NFSServer")
            {
                $::NFSServer = $value;
                chomp $::NFSServer;
            }
            if ($attr eq "InstallMsgServer")
            {
                $::MSGServer = $value;
                chomp $::MSGServer;
            }

            if ($attr eq "PowerMethod")
            {
                $match_powermethod++;
                $::csm_powermethod = $value;
                chomp $::csm_powermethod;
            }

            if ($attr eq "DISKLESSBOOTSCRIPTS")
            {
                @::disklessboot_scriptlist = split(" ", $value);
            }
            if ($attr eq "Mode")
            {
                $::Mode = $value;
                chomp $::Mode;
            }
            if ($attr eq "InActiveMSAttr")
            {
                $::InActiveMSAttr = $value;
                chomp $::InActiveMSAttr;
            }
            if ($attr eq "ETCHOSTSMS")
            {
                $::ETC_HOSTS_MS = $value;
                chomp $::ETC_HOSTS_MS;
            }
            if ($attr eq "UPDATESCRIPTS")
            {
                @::updatescriptlist = split(" ", $value);
            }
        }
        if (!$match_svr || !$match_node)
        {

            # Could not find attribute values in the config_info file.
            MessageUtils->message('E', 'EMsgNO_Attr_Values');
            return $::NOK;
        }
        close(CFGINFO);
    }
    else
    {

        # Could not find $::CFGINFOFILE file.
        MessageUtils->message('E', 'EMsgNO_FIND', $::CFGINFOFILE);
        return $::NOK;
    }

    return $::OK;
}

#--------------------------------------------------------------------------------

=head3	write_status 

	Write a line to the status file on the management server.

        Notes:

=cut

#--------------------------------------------------------------------------------

sub write_status
{
    my ($msg, $status) = @_;
    my ($cmd, $rc);

    chomp $msg;

    my ($statusflag) = "";
    $statusflag = "-s $status" if ($status);

    my $write_status = "$::LOCALCSMINSTDIR/nodestatus.client";

    $cmd =
      "$write_status -S $::MSGServer -n $::akb_nodename $statusflag -M \"$msg\"";
    $rc = system("$cmd");
    if ($rc >> 8)
    {

        #  Could not execute the write_status command.
        MessageUtils->message('E', 'EMsgNO_RunCmd', $cmd);
        $::GLOBAL_EXIT = 1;
        exit;
    }
}

#-------------------------------------------------------------------------------

=head3	mount_csminstall

	mount the /csminstall/csm directory to $::CSMCLIENTMNTDIR

	returns 0 - good  or 1 - bad 

        Notes:

=cut

#-------------------------------------------------------------------------------

sub mount_csminstall
{
    my ($src_dir, $dest_dir) = @_;
    my ($cmd, $rc, $server, $dir);

    # if there is an install server value and a directory to use
    #      then set it as the src_dir
    if ($::InstallServer)
    {
        ($server, $dir) = split ':', $::InstallServer;
        if ($::InstallServerAKBNode && !$::ISGrp)
        {
            $server = $::InstallServerAKBNode;
        }
    }
    elsif ($::NFSServer)
    {
        ($server, $dir) = split ':', $::NFSServer;
    }    #only look at install server if not on AIX

    if ($server && $server ne $::csm_server)
    {
        if ($dir)
        {
            $src_dir =~ s/\/csminstall/$dir/;
        }
        else
        {
            $src_dir =~ s/\/csminstall/$::SERVER_DIRECTORY/;
        }
    }
    else
    {
        $server = $::csm_server;
    }

    if (!-d $dest_dir)
    {

        # create a local directory
        $cmd = "$::MKDIR -p $dest_dir";
        $rc  = system("$cmd");
        if ($rc >> 8)
        {

            # Could not create $::CSMINSTDIR directory.
            MessageUtils->message('E', 'EMsgNO_CreateDir', $dest_dir);
            return $::NOK;
        }
    }

    #  Mount the filesystem
    $cmd = "$::MOUNT -o ro $server:$src_dir $dest_dir";

    #The NIC may not be so stable after the node just boot up.
    #So, here, try 3 times, and sleep 30 in between each time;
    my $times      = 3;
    my $sleep_time = 30;
    my $mounted    = 0;
    my $failed     = 0;

    while (($times > 0) && ($mounted == 0))
    {
        $times--;
        if ($failed)
        {
            sleep $sleep_time;
        }
        $rc = system("$cmd");
        if ($rc >> 8)
        {
            $failed = 1;
        }
        else
        {
            $mounted = 1;    #
        }
    }
    if (!$mounted)
    {

        #  Could not mount $srcdir.
        MessageUtils->message('E', 'EMsgNO_MOUNT', $server . ":" . $src_dir);
        return $::NOK;
    }
    return $::OK;
}

#-------------------------------------------------------------------------------

=head3	setup_remote_shell

	Set up either rsh or ssh on the node.

	return 1 or 0

        Notes:

=cut

#-------------------------------------------------------------------------------

sub setup_remote_shell
{

    my $rc = 0;

    # Only set up a remote shell if SetupRemoteShell was set to 1 in configinfo
    if ($::csm_setuprshell)
    {
        if ($::PLTFRM eq "Linux")
        {
            &write_status("Configuring remote shell $::csm_rshell");
        }

        (my $rshell_basename = $::csm_rshell) =~ s:^.*/::;

        # Set up RSH
        if ($rshell_basename eq "rsh")
        {
            if ($::csm_osname eq "Linux")
            {
                NetworkUtils->setupLinuxRSH($::csm_server, $::InActiveMSAttr);
            }
            elsif ($::csm_osname eq "AIX")
            {
                NetworkUtils->setupAIXRSH($::csm_server, $::InActiveMSAttr);
            }
        }

        # Set up SSH
        elsif ($rshell_basename eq "ssh")
        {
            my $authorized_keys =
              "$::LOCALCSMINSTDIR/config/.ssh/authorized_keys";
            my $authorized_keys2 =
              "$::LOCALCSMINSTDIR/config/.ssh/authorized_keys2";
            NetworkUtils->installSSHFiles($authorized_keys, $authorized_keys2);
        }

        # Unknown remote shell
        else
        {

            # Nothing to install
        }
    }

    return $rc;
}

#-------------------------------------------------------------------------------

=head3	unmount_csminstall

	unmount the /csminstall/csm directory                #

	return 0 or 1

        Notes:

=cut

#-------------------------------------------------------------------------------

sub unmount_csminstall
{

    my ($unmnt_dir, undef) = @_;
    my ($rc,        $cmd);

    $cmd = "$::UNMOUNT $unmnt_dir";
    $rc  = system("$cmd");
    if ($rc >> 8)
    {

        # Internal call to unmount was not successful.
        MessageUtils->message('E', 'EMsgNO_INTERNAL_CALL', $::UMOUNT);
        return $::NOK;
    }
    return $::OK;
}

#-------------------------------------------------------------------------------

=head3	set_tty

	add the clocal attribute to tty0 definition (SP Nodes only)

        Notes:

=cut

#-------------------------------------------------------------------------------

sub set_tty
{

    my ($sw_console);
    my ($rc);
    my ($run_modes);
    my ($log_modes);
    my ($cons_dev);
    my ($cons_itab);
    my ($mkitab_cmd);
    my (@itab_list);
    my (@ps_list);
    my ($prev_itab);
    my ($itab);
    my ($ps);

    $sw_console = 0;

    # In order to successfully change the tty params, we need to free up
    # the device.  We'll switch the console output to a temporary file,
    # then remove references to the console from inittab
    #
    # First, see where the console output is currently directed
    #
    $cons_dev = NodeUtils->runcmd("/usr/sbin/lscons", -1);

    # lscons rc 0, 1, or 2 are ok, 3 or 4 indicate error
    #
    if ($::RUNCMD_RC > 2)
    {
        return 1;
    }

    if ($cons_dev =~ /\/dev\/tty0/)
    {

        # Console output is on /dev/tty0, so we need to switch it
        # with the swcons command
        #
        NodeUtils->runcmd("/usr/sbin/swcons /tmp/tmp.console", 0);

        if ($::RUNCMD_RC != 0)
        {
            return 1;
        }

        $sw_console = 1;
    }

    # Next, see if there's a console entry in initab
    #
    $cons_itab = NodeUtils->runcmd("/usr/sbin/lsitab cons", 0);
    if ($::RUNCMD_RC == 0)
    {

        # We have a cons entry, traverse the entries and find
        # the entry that preceeds cons, and save it.  Next, remove
        # the cons entry from /etc/inittab and
        # refresh the init daemon (this should clear the running
        # getty process on /dev/tty0)
        #
        @itab_list = NodeUtils->runcmd("/usr/sbin/lsitab -a", 0);
        foreach $itab (@itab_list)
        {
            my ($itab_id, $dummy) = split /:/, $itab, 2;
            if ($itab_id eq "cons")
            {
                last;
            }
            else
            {
                $prev_itab = $itab_id;
            }
        }
        NodeUtils->runcmd("/usr/sbin/rmitab cons", 0);
        NodeUtils->runcmd("/usr/sbin/telinit q",   0);
    }

    # Kill the getty process if it's still running
    #
    sleep 5;

    @ps_list =
      NodeUtils->runcmd("ps -ef\|grep \"/usr/sbin/getty /dev/console\"", -2);

    foreach $ps (@ps_list)
    {
        $ps =~ s/^\s+//;    # strip any leading spaces
        my ($uid, $pid, $ppid, $junk) = split /\s+/, $ps;

        # differentiate the getty from the grep by checking
        # the ppid.  since getty was started by the init process,
        # it will have a ppid of 1
        #
        if ($ppid == 1)
        {
            NodeUtils->runcmd("kill -9 $pid", 0);
        }
    }

    @ps_list =
      NodeUtils->runcmd("ps -ef\|grep \"/usr/sbin/getty /dev/tty0\"", 0);

    foreach $ps (@ps_list)
    {
        $ps =~ s/^\s+//;    # strip any leading spaces
        my ($uid, $pid, $ppid, $junk) = split /\s+/, $ps;

        # differentiate the getty from the grep by checking
        # the ppid.  since getty was started by the init process,
        # it will have a ppid of 1
        #
        if ($ppid == 1)
        {
            NodeUtils->runcmd("kill -9 $pid", 0);
        }
    }

    # Next, check the current run modes, see if clocal is present
    #
    $run_modes =
      NodeUtils->runcmd("/usr/sbin/lsattr -E -a runmodes -F'value' -l tty0", 0);
    if ($run_modes !~ /clocal/)
    {

        # The clocal runmode is not present.  Use chdev to add it
        #
        $run_modes = $run_modes . ",clocal";
        NodeUtils->runcmd("chdev -l tty0 -a runmodes=$run_modes", 0);
    }

    # Next, check the current log modes, see if clocal is present
    #
    $log_modes =
      NodeUtils->runcmd("/usr/sbin/lsattr -E -a logmodes -F'value' -l tty0", 0);
    if ($log_modes !~ /clocal/)
    {

        # The clocal logmode is not present.  Use chdev to add it
        #
        $log_modes = $log_modes . ",clocal";
        NodeUtils->runcmd("chdev -l tty0 -a logmodes=$log_modes", 0);
    }

    # If the console was switched, switch it back
    #
    if ($sw_console)
    {
        NodeUtils->runcmd("swcons /dev/tty0", 0);
    }

    # If we removed an entry from inittab, replace it, and refresh init
    #
    if (defined($cons_itab))
    {
        $mkitab_cmd = qq/\/usr\/sbin\/mkitab -i $prev_itab \"$cons_itab\"/;
        NodeUtils->runcmd("$mkitab_cmd",         0);
        NodeUtils->runcmd("/usr/sbin/telinit q", 0);
    }

    return $::OK;
}

#-------------------------------------------------------------------------------

=head3	copy_configinfo_file
   copy_files  - copy files to the node from the management server    
                                                                         
   Return Codes: 0 - All was successful.                                 
                 1 - An error occured.                                   
=cut

#-------------------------------------------------------------------------------

sub copy_files
{

    my ($rc, $cmd, $src);
    my $dest     = $::OPTCSMINSTALL;
    my $cfg_file = $::CFGINFOFILE;
    my $srcdir   = $::LOCALCSMINSTDIR;
    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)
        {
            MessageUtils->message('E', 'EMsgNO_CreateDir', $dest);
            return $::NOK;
        }
    }

    #
    # copy the config_info file
    #

    $src = "$::CSMCFGDIR/$::akb_nodename.config_info";
    $cmd = "$::COPY $src $cfg_file";
    $rc  = system("$cmd");
    if ($rc >> 8)
    {
        MessageUtils->message('E', 'EMsgNO_CopyFile', $src, $cfg_file);
        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)
        {
            MessageUtils->message('E', 'EMsgNO_CopyFile', $src, $dest);
            return $::NOK;
        }
    }
    return $::OK;
}

#-------------------------------------------------------------------------------

=head3	run_rpm_scriptlet
   run_rpm_scriptlet run designated rpm scripts in a rpm packages. These 
   scripts include: preinstall scriptlet, postinstall scriptlet, 
   preuninstall scriptlet and postuninstall scriptlet.

   Inputs: rpm_name - name of a rpm
           $scriptlet_name - name of the scriptlet need to run. The name can
		                     be one of the following:
							 "preinstall scriptlet"
							 "postinstall scriptlet"
							 "preuninstall scriptlet"
							 "postuninstall scriptlet"
           $mode - The value of $1 in the rpm scriptlet.
		           If you want run RPM scriptlet same as when the RPM is:
				   Installed (rpm -i)
				      run preinstall scriptlet, $mode = 1.
					  run postinstal scriptlet, $mode = 1.
				   Updated (rpm -U)
				      run preinstall scriptlet, $mode = 2.
					  run postinstall scriptlet, $mode = 2.
					  rum preuninstall scriptlet, $mode = 1.
					  run postuninstall scriptlet, $mode = 1.
				   Ereased (rpm -e)
				      run preuninstall scriptlet, $mode = 0.
					  run postuninstall scriptlet, $mode = 0.


   Return Codes: 0 - All was successful.                                 
                 1 - An error occured.                                   
   Example: run_rpm_scriptlet("csm.client", "postinstall scriptlet");
=cut

#-------------------------------------------------------------------------------
sub run_rpm_scriptlet
{
    my ($rpm_name, $scriptlet_name, $mode) = @_;
    my $rc = 0;
    my $cmd;

    my $ext = $scriptlet_name;
    $ext =~ s/\s+/-/g;

    my $scriptlet_file    = "/tmp/$rpm_name.$ext";
    my $scriptlet_sh_file = "$::OPTCSMINSTALL/$rpm_name.$ext.sh";

    $cmd = "rpm -q --scripts $rpm_name > $scriptlet_file";
    NodeUtils->runcmd($cmd, 0);
    $rc = 1 if ($::RUNCMD_RC);

    unless (open(SCRIPTLET, "<$scriptlet_file"))
    {
        MessageUtils->message('E', 'EMsgCANT_READ_FILE', $scriptlet_file);
    }
    unless (open(SCRIPTLET_SH, ">$scriptlet_sh_file"))
    {
        MessageUtils->message('E', 'EMsgCANT_WRITE_FILE', $scriptlet_sh_file);
    }

    my $start_mark  = "";
    my $stop_mark_1 = "";
    my $stop_mark_2 = "";
    my $stop_mark_3 = "";

    if ($scriptlet_name =~ /^preinstall scriptlet/)
    {
        $start_mark  = "preinstall scriptlet";
        $stop_mark_1 = "postinstall scriptlet";
        $stop_mark_2 = "preuninstall scriptlet";
        $stop_mark_3 = "postuninstall scriptlet";
    }
    elsif ($scriptlet_name =~ /^postinstall scriptlet/)
    {
        $start_mark  = "postinstall scriptlet";
        $stop_mark_1 = "preinstall scriptlet";
        $stop_mark_2 = "preuninstall scriptlet";
        $stop_mark_3 = "postuninstall scriptlet";
    }
    elsif ($scriptlet_name =~ /^preuninstall scriptlet/)
    {
        $start_mark  = "preuninstall scriptlet";
        $stop_mark_1 = "preinstall scriptlet";
        $stop_mark_2 = "postinstall scriptlet";
        $stop_mark_3 = "postuninstall scriptlet";
    }
    else
    {
        $start_mark  = "postuninstall scriptlet";
        $stop_mark_1 = "preinstall scriptlet";
        $stop_mark_2 = "postinstall scriptlet";
        $stop_mark_3 = "preuninstall scriptlet";
    }

    # Read scriptlet file
    my $scriptlet_start = 0;
    my $scripts         = "";

    print SCRIPTLET_SH "#!/bin/sh\n";

    while (my $line = <SCRIPTLET>)
    {
        if ($line =~ /^$start_mark/)
        {
            $scriptlet_start = 1;
            next;
        }
        if (   ($line =~ /^$stop_mark_1/)
            || ($line =~ /^$stop_mark_2/)
            || ($line =~ /^$stop_mark_3/))
        {
            $scriptlet_start = 0;
            next;
        }

        next if ($scriptlet_start == 0);

        print SCRIPTLET_SH $line;
    }

    close SCRIPTLET;
    close SCRIPTLET_SH;

    # Run the scriptlet
    $cmd = "$::CHMOD 755 $scriptlet_sh_file";
    NodeUtils->runcmd($cmd, 0);
    $rc = 1 if ($::RUNCMD_RC);

    $cmd = "$scriptlet_sh_file $mode";
    NodeUtils->runcmd($cmd, 0);
    $rc = 1 if ($::RUNCMD_RC);

    return $rc;
}

#-------------------------------------------------------------------------------

=head3	Main	

        Notes:

=cut

#-------------------------------------------------------------------------------

{    # main

    # initialize the global data
    &initialize;

    #
    # start logging
    #
    MessageUtils->append_logging($::INSTALL_LOG);

    #
    # Get configinfo file from install server. This file wil not only
    # be used in this scripts, but also be used in other scripts. So this
    # need to be copied to the local node.
    #

    # get node's hostname
    #$::akb_nodename =`$::HOSTNAME`;
    $::akb_nodename = NodeUtils->runcmd("$::HOSTNAME", 0);
    if ($::RUNCMD_RC == 0)
    {
        chomp $::akb_nodename;
    }
    else
    {
        MessageUtils->message('E', 'EMsgNO_AKB_Hostname');
        $::GLOBAL_EXIT = 1;
        exit;
    }

    #
    # Get install server and mount directories
    #
    #   IMBEDDEDISINFO   -  Start imbedded install server information
    #   Here is the format:
    #   $::ISinfo{"akb_nodename"}="csm_server_ip:csm_server_dir";
    #   the akb_nodename has to be same as the node name used in the
    #   /etc/warewulf/nodes/node_group/nodename.
    #   Here is an example:
    #   $::ISinfo{"f1csmn06"}="176.60.12.20:/csminstall";
    #   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 "makedisklessnode: 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 of the "/" at the end
                chop($::MNTdir);
            }

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

    #
    # mount /csminstall/csm
    #      the subroutine takes care of the InstallServer case
    #
    if (&mount_csminstall($::CSMINSTDIR, $::LOCALCSMINSTDIR) != 0)
    {

        #  Could not mount $::CSMINSTDIR.
        $::GLOBAL_EXIT = 1;
        exit;
    }
    else
    {
        $::mounted++;
    }
    if ($::PLTFRM eq "Linux")
    {

        # Since CSM does not install AIX packages, only do this if the node is
        # running Linux

        if (&mount_csminstall($::CSMLINUXDIR, $::LOCALCSMOSDEPINSTDIR) != 0)
        {

            #  Could not mount $::CSMOSDEPINSTDIR.
            $::GLOBAL_EXIT = 1;
            exit;
        }
        else
        {
            $::OSDEPmounted++;
        }
    }

    #
    # copy files to $::OPTCSMINSTALL directory on the node
    #
    if (&copy_files != 0)
    {
        MessageUtils->message('E', 'EMsgNO_FILECOPY', $::OPTCSMINSTALL);
        $::GLOBAL_EXIT = 1;
        exit;
    }
    #
    # Add lines to  /etc/inittab to allow
    # remote console support for this node once the node reboots.
    # But the "telinit -q" need be run
    # in order to tell init to read inittab again.

    if ($::PLTFRM eq "Linux")
    {
        if ($::arch ne "ppc64")
        {
            my $cmd = "$::csmbin/setupconsole 2>&1";
            NodeUtils->runcmd("$cmd",-1);
            NodeUtils->runcmd("/sbin/telinit q",-1);
            $cmd = "cat $::CFGINFOFILE | grep ConsoleSerialDevice | cut -d \"=\" -f 2";
            my $output = NodeUtils->runcmd("$cmd",-1);
            if ($::RUNCMD_RC)
            {
                MessageUtils->message('E', 'EMsgCANT_RUN', $cmd, $::RUNCMD_RC);
            }
            chomp($output);
            # In default, set ttyS0
            if ($output eq "")
            {
                $output = "ttyS0";
            }
            NodeUtils->runcmd("echo \"$output\"       >> /etc/securetty");

        }
    }

    #
    # get the management server name and hostname for this node from
    #    the configinfo file
    #
    if (&get_configinfo != 0)
    {

        # Could not get node attribute values from the configinfo file.
        MessageUtils->message('E', 'EMsgNO_Attr_Values');
        $::GLOBAL_EXIT = 1;
        exit;
    }

    #
    # Run rpm scriptlets
    # Diskless node boots from diskless boot images. Some RPMs in the
    # the images are installed without or with partially runing the RPM
    # scriptlets. Therefore, we are re-run these scriptlet at this time.
    # But if disklessnode is MinManaged, rsct and csm rpms are not installed.
	# So, there is no need to run these scriptlets.
	if ($::Mode !~ /MinManaged/)
	{
    	&run_rpm_scriptlet("src", "preinstall scriptlet",  1);
    	&run_rpm_scriptlet("src", "postinstall scriptlet", 1);

    	&run_rpm_scriptlet("rsct.core.utils", "preinstall scriptlet",  1);
   	 	&run_rpm_scriptlet("rsct.core.utils", "postinstall scriptlet", 1);

    	&run_rpm_scriptlet("rsct.core", "preinstall scriptlet",  1);
    	&run_rpm_scriptlet("rsct.core", "postinstall scriptlet", 1);

    	&run_rpm_scriptlet("rsct.core.cimrm", "preinstall scriptlet",  1);
    	&run_rpm_scriptlet("rsct.core.cimrm", "postinstall scriptlet", 1);

    	&run_rpm_scriptlet("csm.client", "preinstall scriptlet",  1);
    	&run_rpm_scriptlet("csm.client", "postinstall scriptlet", 1);
	}

    #
    #  Put the management server "ip longhost shorthost" in /etc/hosts
    #
    if ($::PLTFRM eq "AIX")
    {

        my $found  = 0;
        my $skipit = 0;
        my ($string, $line);
        my ($ipaddr, $junk) = split(/\s+/, $::ETC_HOSTS_MS);

        # open /etc/hosts & /tmp/etchosts
        unless (open(ETCHOSTS_FILE, "<$::etchosts"))
        {
            MessageUtils->message('W', 'EMsgCANT_READ_FILE', $::etchosts);
            $skipit = 1;
        }
        unless (open(TMPETCHOSTS_FILE, ">$::tmpetchosts"))
        {
            MessageUtils->message('W', 'EMsgCANT_WRITEtoFILE', $::tmpetchosts);
            $skipit = 1;
        }

        if (!$skipit)
        {

            #  read the /etc/hosts file and create the /tmp/etchosts file
            while ($line = <ETCHOSTS_FILE>)
            {
                ($string, $junk) = split(/\s+/, $line);

                # check the existing file to see if the entry is there
                if ($string eq $ipaddr)
                {

                    # write the new line to the file
                    print TMPETCHOSTS_FILE $::ETC_HOSTS_MS . "\n";
                    $found = 1;
                    next;    # don't write the old line
                }

                # write the line to the new file
                print TMPETCHOSTS_FILE $line;
            }
            if (!$found)
            {    # add it to the end if the IP addr wasn't already there
                print TMPETCHOSTS_FILE $::ETC_HOSTS_MS . "\n";
            }

            close(TMPETCHOSTS_FILE);
            close(ETCHOSTS_FILE);

            # move the new file to /etc/hosts
            my $cmd = "$::MV -f $::tmpetchosts $::etchosts";
            MessageUtils->message('V', 'IMsgCMD', $cmd);
            my $rc = system($cmd) >> 8;
            if ($rc)
            {
                MessageUtils->message('E', 'EMsgCANT_RUN', $cmd, $rc);
            }
        }
    }

    if ($::PLTFRM eq "Linux" and $::arch ne "ppc64")
    {
        my $cmd = "/etc/init.d/network restart";
        #system($cmd);
        #MessageUtils->message('V', 'IMsgCMD', $cmd);
        sleep(5);
    }

    #
    # Set up the remote shell
    #
    if (&setup_remote_shell != 0)
    {

        # Could not set up the remote shell
        $::GLOBAL_EXIT = 1;
    }

    if ($::Mode !~ /$::CSMLITE/ && $::Mode !~ /DCInstall/  && $::Mode !~ /MinManaged/)
    {

        #
        # report makenode starting status to the management server
        #
        if ($::PLTFRM eq "Linux")
        {
            &write_status("Starting makenode to install CSM RPMs");
        }

        # All the diskless nodes will have the same RSCT nodeid,
        # need to refresh the nodeid.
        NodeUtils->runcmd("/usr/sbin/rsct/bin/mknodeid -f", -1);
        NodeUtils->runcmd("/usr/sbin/rsct/install/bin/uncfgct", -1);
        NodeUtils->runcmd("/usr/sbin/rsct/install/bin/cfgct", -1);

        #
        # call makenode
        #
        #$cmd = "$::OPTCSMINSTALL/makenode -m $::csm_server -n $::akb_nodename";
        my $cmd =
          "FIRSTBOOT=1 $::LOCALCSMINSTDIR/makenode -k -m $::csm_server -n $::akb_nodename";
        print "calling makenode..\n" if $::DEBUG;
        my $rc = system("$cmd");
        if ($rc >> 8)
        {

            #  Could not execute the makenode command.
            MessageUtils->message('E', 'EMsgERROR_RUNNING_COMMAND', $cmd);
            $::GLOBAL_EXIT = 1;
        }

        #
        # report makenode ending status to the management server
        #
        if ($::PLTFRM eq "Linux")
        {
            &write_status("makenode complete", $rc);
        }
    }

    #
    # for SP nodes, modify the tty0 parameters
    #
    if ($::csm_powermethod eq "csp")
    {
        &set_tty;
    }

    # run customer provided scripts

    # first set some environment variables for the user to access
    #    from their scripts
    #
    # The mount point for CSM on the node - equivalent to /csminstall
    #    on the management server
    $ENV{'CSMMOUNTPOINT'} = "$::CSMCLIENTMNTDIR";

    #  The data directory where additional user provided scripts
    #    and data files will be located.
    $ENV{'SCRIPTDATAPATH'} = "$::CSMCLIENTMNTDIR/csm/scripts/data";

    $ENV{'CSMNODENAME'} = $::akb_nodename;
    foreach my $name (@::disklessboot_scriptlist)
    {

        # cd to the directory of the users cust script in case they
        #   use a relative path to get to the data directory.
        my $cmd = "cd $::LOCAL_DISKLESSBOOT_DIR; ./$name";
        my $output = NodeUtils->runcmd($cmd, 0);
        if ($::RUNCMD_RC)
        {
            MessageUtils->message('E', 'EMsgCANT_RUN', $cmd, $::RUNCMD_RC);
        }
        else
        {
            MessageUtils->message('I', 'IMsgShow_Output', $output);
        }
    }


    # clean up $::OPTCSMINSTALL if this is a Lite node
    if ($::Mode =~ /$::CSMLITE/ || $::Mode =~ /DCInstall/ || $::Mode =~ /MinManaged/)
    {
        my $cmd = "$::RM -rf $::csmroot";
        NodeUtils->runcmd($cmd, 0);
    }

    #
    # finish up and exit
    #
    END
    {

        # report completion status to the management server
        if ($::PLTFRM eq "Linux")
        {
            if ($::GLOBAL_EXIT > 0)
            {
                &write_status("Install Failed", $::GLOBAL_EXIT);
            }
            else
            {
                &write_status("Installed");
            }
        }

        # Create a file on the management server that signifies that the "Lite"
        # install is complete.  The management server watches for this file.
        # The filename is /tftpboot/status/MinManaged/<nodename> .
        if ($::Mode =~ /$::CSMLITE/)
        {
            my $write_status = "$::LOCALCSMINSTDIR/nodestatus.client";

            my $cmd = "$write_status -S $::MSGServer -n $::akb_nodename -m";
            my $rc  = system("$cmd");
            if ($rc >> 8)
            {

                #  Could not execute the write_status command.
                MessageUtils->message('E', 'EMsgNO_RunCmd', $cmd);
                $::GLOBAL_EXIT = 1;
                exit;
            }
        }

        #
        # unmount $::LOCALCSMINSTDIR  - if we mounted it
        #
        if ($::mounted)
        {

            # unmount /csminstall/csm
            if (&unmount_csminstall($::LOCALCSMINSTDIR) != 0)
            {

                #  Unmount of $::CSMINSTDIR failed.
                MessageUtils->message('E', 'EMsgNO_UNMOUNT',
                                      $::LOCALCSMINSTDIR);
                $::GLOBAL_EXIT = 1;
            }
        }

        if ($::OSDEPmounted)
        {

            # unmount
            if (&unmount_csminstall($::LOCALCSMOSDEPINSTDIR) != 0)
            {

                #  Unmount of $::CSMINSTDIR failed.
                MessageUtils->message('E', 'EMsgNO_UNMOUNT',
                                      $::LOCALCSMOSDEPINSTDIR);
                $::GLOBAL_EXIT = 1;
            }
        }

        MessageUtils->stop_logging();

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

        #Always exit 0 so the install doesn't completely fail
        $? = 0;

    }

}
