#!/usr/bin/perl
# IBM_PROLOG_BEGIN_TAG 
# This is an automatically generated prolog. 
#  
#  
#  
# Licensed Materials - Property of IBM 
#  
# (C) COPYRIGHT International Business Machines Corp. 2002,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 
#
# @(#)42   1.48.3.3   src/csm/install/csmfirstboot.perl, setup, csm_rfish, rfishs001b 2/20/06 23:36:38

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

=head1	csmfirstboot

	Description: This script is executed after the first reboot of a
	node after the operating system has been installed.  It is called 
    by osfirstboot.

	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

	# setup messaging globals
	$::MSGCAT     = 'csmInstall.cat';
	$::MSGMAPPATH = $::Bin;
	$::MSGSET     = 'csminstall';
	#NodeUtils should use the msgmap files in the current directory
	$NodeUtils::MSGMAPPATH = $::MSGMAPPATH;
}

use lib "$::Bin";
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 name of the management server
	$::akb_nodename = "";    # the name of this node as known by
	                         # the management server

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

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

	@::postscriptlist = ();    #  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

}

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

=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 "POSTINSTSCRIPTS")
			{
				@::postscriptlist = 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 (!$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	Main	

        Notes:

=cut

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

{    # main

	# initialize the global data
	&initialize;

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

	#
	# 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;
	}

	#
	#  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);
	}

	#
	# mount /csminstall/csm
	#      the subroutine takes care of the InstallServer case
	#
	if (&mount_csminstall($::MSCSMINSTDIR, $::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($::CSMOSDEPINSTDIR, $::LOCALCSMOSDEPINSTDIR) != 0)
		{

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

	#
	# 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/)
	{

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

		#
		# call makenode
		#
		#$cmd = "/opt/csm/install/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";

	foreach my $name (@::postscriptlist)
	{

		# 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 $::LOCALPOSTINSTALLDIR; ./$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 /opt/csm/install if this is a Lite node
	if ($::Mode =~ /$::CSMLITE/ || $::Mode =~ /DCInstall/)
	{
		my $cmd = "$::RM -rf /opt/csm/install";
		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;

	}

}
