#!/usr/bin/perl
# IBM_PROLOG_BEGIN_TAG 
# This is an automatically generated prolog. 
#  
#  
#  
# Licensed Materials - Property of IBM 
#  
# (C) COPYRIGHT International Business Machines Corp. 2000,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 
#
# @(#)13   1.67.3.1   src/csm/install/copycsmpkgs.perl, setup, csm_rfish, rfishs001b 3/5/07 00:53:18

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

=head1    copycsmpkgs

	Platform independent install of /csminstall on Linux and AIX managment servers.

        Example:

         copycsmpkgs -p . InstallCSMVersion=1.3.2 InstallDistributionName=SLES \
                          InstallDistributionVersion=8.1 InstallOSName=Linux \
                          InstallPkgArchitecture=i386 
	Notes:  

=cut

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

=head3	file header

        the use statements and $ENV stuff


=cut

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

use strict;
BEGIN { $::csmpm = $ENV{'CSM_PM'} ? $ENV{'CSM_PM'} : '/opt/csm/pm'; }
use lib $::csmpm;
use File::Path;

# Provides mkpath();
use FindBin qw($Bin);
use lib "$Bin";

use Getopt::Long;
use NodeUtils;
use CSMDefs;
require ArchiveUtils;
require ServerUtils;

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

=head3	initialize

	sets @::COPY_VALID_ATTRS and $::MSGCAT globals

=cut

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

sub initialize
{

	$::MSGCAT     = 'csmInstall.cat';
	$::MSGMAPPATH =
	  $ENV{'CSM_MSGMAPS'} ? $ENV{'CSM_MSGMAPS'} : '/opt/csm/msgmaps';
	$::MSGSET = 'csminstall';

	@::COPY_VALID_ATTRS = (
						   "InstallCSMVersion",
						   "InstallOSName",
						   "InstallDistributionName",
						   "InstallDistributionVersion",
						   "InstallPkgArchitecture",
						   "InstallServiceLevel"
						  );
	@::osTypeVersion;

	$::PLTFRM = `uname`;
	chomp($::PLTFRM);

	# read in the OSDefs, but don't set gobals?
	my %OSDefs = ServerUtils->get_OSDefs();

	# override $::RPMCMD if going to suppress signature warning.
	ArchiveUtils->suppressRpmSigWarning();

}

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

=head3	usage

        Notes:


=cut

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

sub usage
{
	MessageUtils->message('I', 'IMsgcopycsmpkgsUsage');
	exit 1;
}

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

=head3	getArgs

        Notes:

=cut

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

sub getArgs
{
	my $pkgpath = "";

	$Getopt::Long::ignorecase = 0;
	Getopt::Long::Configure("bundling");
	Getopt::Long::Configure("pass_through");
	if (
		!GetOptions(
				'h'  => \$::opt_h,
				'c'  => \$::opt_c,
				'p=s' => \$::opt_p,
				'v' => \$::opt_v,
				'V'  => \$::opt_V,
				'A' => \$::opt_A,
				'n=s' => \$::opt_n,
				'N=s' => \$::opt_N,
				'noprompt' => \$::NO_MOUNT_CD,
			   )
	   )
	  {
		$::GLOBAL_EXIT = 1;
		&usage;
		exit $::GLOBAL_EXIT;
	  }

	$::command_line = $0;

	if ($::opt_h) { &usage }
	if (NodeUtils->isHMC() && ($ENV{'DC_ENVIRONMENT'} ne 1))
	{
		MessageUtils->messageFromCat(
			$::MSGCAT,
			$::MSGMAPPATH,
                        $::MSGSET,
			'E1',
                        'EMsgDisabledCmdOnHMC',
                        'copycsmpkgs'
		);
	}

	# check for valid args
	if (ServerUtils->check_invalid_options(\@ARGV))
	{
		&usage;
	}

	# -n and -N options can't be used together
	if (($::opt_n) && ($::opt_N))
	{
		MessageUtils->messageFromCat('csmInstall.cat', $::MSGMAPPATH,
									 'csminstall', 'I', 'IMsgCopycdsWrongN');
		$::GLOBAL_EXIT = 0;
		&usage;
		exit $::GLOBAL_EXIT;
	}

	$::COPY_OPT_FLAG = $::opt_c;
	if ($::opt_v || $::opt_V)
	{
		if ($::opt_v) { $::VERBOSE = $::opt_v; }
		if ($::opt_V) { $::VERBOSE = $::opt_V; }

	}
	if ($::opt_p)
	{
		# Packages path
		$pkgpath = $::opt_p;
        foreach my $dir ( split(":", $pkgpath))
        {
		    if (! -d $dir)
		    {
			    MessageUtils->messageFromCat('csmInstall.cat', $::MSGMAPPATH, 'csminstall', 
					    'I', 'IMsgDIRECTORY_NOT_FOUND', $dir);
			    exit 1;
		    }
        }
	} else 
	{
		&usage; 
	}

	# Handle attr=value arguments
	if (scalar(@ARGV) > 0)
	{
		foreach my $a (@ARGV)
		{

			# Note:  we allow a null value
			my ($attr, $value) = $a =~ /^\s*(\S+?)\s*=\s*(\S*.*)$/;

			# mkrsrc-api needs something for the value
			if (!length($value))
			{
				$value = "''";
			}
			if (!defined($attr))
			{
				MessageUtils->message('W', 'EMsgBAD_ATTR_VAL_FORM');
				&usage;
			}
			else
			{
				if ($::opt_n || $::opt_N)
				{
					MessageUtils->messageFromCat('csmInstall.cat',
											   $::MSGMAPPATH, 'csminstall', 'I',
											   'IMsgCopycdsWrongList');
					$::GLOBAL_EXIT = 0;
					&usage;
					exit $::GLOBAL_EXIT;
				}

			}

			my $found = 0;
			foreach my $va (@::COPY_VALID_ATTRS)
			{
				if ($attr eq $va)
				{

					# Put quotes around the value to protect spaces
					# or weird chars

					$::ATTRS{$va} = $value;
					$found = 1;
				}
			}
			if (!$found) { MessageUtils->message('E1', 'EMsgBAD_ATTR', $attr); }
		}
	}

	#  Get the list of nodes
	@ARGV = ($::opt_n);
	my ($ref_DestNode, $ref_lsnode_info, $ref_DestNodeHash) =
	  NodeUtils->get_target_nodes(\@ARGV, $::opt_N);
	@::NODELIST    = @$ref_DestNode;
	@::LSNODE_INFO = @$ref_lsnode_info;
	%::NODEHASH    = %$ref_DestNodeHash;

	# Only a single node is allowed to be listed, since the command
	# can only be run for one distro/service level at a time.
	if ($::opt_n)
	{
		if (scalar(@::NODELIST) > 1)
		{
			MessageUtils->messageFromCat('csmInstall.cat', $::MSGMAPPATH,
									'csminstall', 'I', 'IMsgCopycdsSingleNode');
			$::GLOBAL_EXIT = 0;
			&usage;
			exit $::GLOBAL_EXIT;
		}
	}

	if (@::NODELIST)
	{

		# Read in the Install* attributes from the node
		&get_common_install_attrs();
	}

	# verify the correctness of the attributes
	&checkattrs;

	@::PKGPATH = split(":", $pkgpath);

	foreach my $p (split(":", $pkgpath))
	{

		#gather the subdirectories too
		push @::PKGPATH, (ServerUtils->returnSubdirectory($p));
	}
}

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

=head3  get_common_install_attrs

        Notes:
            Read attribute from node. If -N is used, all nodes in the group
            must have the same attribute values or the command will fail.
=cut

#--------------------------------------------------------------------------------
sub get_common_install_attrs
{
	my ($osname, $distroname, $distrover, $distroarch, $svclevel, $csmversion);
	my $errors = 0;

	my $InstallOSName;
	my $InstallDistributionName;
	my $InstallDistributionVersion;
	my $InstallPkgArchitecture;
	my $InstallServiceLevel;
	my $InstallCSMVersion;
	my $InstallOSName_Err_Flg              = 0;
	my $InstallDistributionName_Err_Flg    = 0;
	my $InstallDistributionVersion_Err_Flg = 0;
	my $InstallPkgArchitecture_Err_Flg     = 0;
	my $InstallServiceLevel_Err_Flg        = 0;
	my $InstallCSMVersion_Err_Flg          = 0; 

	foreach my $hostname (keys %::NODEHASH)
	{
		$InstallOSName           = $::NODEHASH{$hostname}{'InstallOSName'};
		$InstallDistributionName =
		  $::NODEHASH{$hostname}{'InstallDistributionName'};
		$InstallDistributionVersion =
		  $::NODEHASH{$hostname}{'InstallDistributionVersion'};
		$InstallPkgArchitecture =
		  $::NODEHASH{$hostname}{'InstallPkgArchitecture'};
		$InstallServiceLevel = $::NODEHASH{$hostname}{'InstallServiceLevel'};
		$InstallCSMVersion   = $::NODEHASH{$hostname}{'InstallCSMVersion'};

		if (!$osname)
		{
			$osname = $InstallOSName;
		}
		if (!$distroname)
		{
			$distroname = $InstallDistributionName;
		}
		if (!$distrover)
		{
			$distrover = $InstallDistributionVersion;
		}
		if (!$distroarch)
		{
			$distroarch = $InstallPkgArchitecture;
		}
		if (!$svclevel)
		{
			if ($distrover =~ /\./ && $distroname =~ /RedHatEL/ && !$InstallServiceLevel)
                        {
                                $svclevel = "GA";
                        }else
                        {
                                $svclevel = $InstallServiceLevel;
                        }
		}
		if (!$csmversion)
		{
			$csmversion = $InstallCSMVersion;
		}

		if (    ("$osname" and "$InstallOSName")
			and ($InstallOSName ne $osname))
		{
			$errors++;
			$InstallOSName_Err_Flg++;
		}
		if (    ("$distroname" and "$InstallDistributionName")
			and ($InstallDistributionName ne $distroname))
		{
			$errors++;
			$InstallDistributionName_Err_Flg++;
		}
		if (    ("$distrover" and "$InstallDistributionVersion")
			and ($InstallDistributionVersion ne $distrover))
		{
			$errors++;
			$InstallDistributionVersion_Err_Flg++;
		}

		if (    ("$distroarch" and "$InstallPkgArchitecture")
			and ($InstallPkgArchitecture ne $distroarch))
		{
			$errors++;
			$InstallPkgArchitecture_Err_Flg++;
		}

		if (    ("$svclevel" and "$InstallServiceLevel")
			and ($InstallServiceLevel ne $svclevel))
		{
			$errors++;
			$InstallServiceLevel_Err_Flg++;
		}

		if (    ("$csmversion" and "$InstallCSMVersion")
			and ($InstallCSMVersion ne $csmversion))
		{
			$errors++;
			$InstallCSMVersion_Err_Flg++;
		}
	}
	if ($InstallOSName_Err_Flg > 0)
	{
		MessageUtils->messageFromCat(
									 'csmInstall.cat',     $::MSGMAPPATH,
									 'csminstall',         'E',
									 'EMsgDIFFERENT_ATTR', 'InstallOSName'
									);
	}
	if ($InstallDistributionName_Err_Flg > 0)
	{
		MessageUtils->messageFromCat(
									 'csmInstall.cat',
									 $::MSGMAPPATH,
									 'csminstall',
									 'E',
									 'EMsgDIFFERENT_ATTR',
									 'InstallDistributionName'
									);
	}
	if ($InstallDistributionVersion_Err_Flg > 0)
	{
		MessageUtils->messageFromCat(
									 'csmInstall.cat',
									 $::MSGMAPPATH,
									 'csminstall',
									 'E',
									 'EMsgDIFFERENT_ATTR',
									 'InstallDistributionVersion'
									);
	}
	if ($InstallPkgArchitecture_Err_Flg > 0)
	{
		MessageUtils->messageFromCat(
									 'csmInstall.cat',
									 $::MSGMAPPATH,
									 'csminstall',
									 'E',
									 'EMsgDIFFERENT_ATTR',
									 'InstallPkgArchitecture'
									);
	}
	if ($InstallServiceLevel_Err_Flg > 0)
	{
		MessageUtils->messageFromCat(
									 'csmInstall.cat',
									 $::MSGMAPPATH,
									 'csminstall',
									 'E',
									 'EMsgDIFFERENT_ATTR',
									 'InstallServiceLevel'
									);
	}

	if ($InstallCSMVersion_Err_Flg > 0)
	{
		MessageUtils->messageFromCat(
									 'csmInstall.cat',
									 $::MSGMAPPATH,
									 'csminstall',
									 'E',
									 'EMsgDIFFERENT_ATTR',
									 'InstallCSMVersion'
									);
	}
	exit $errors if ($errors);

	$::ATTRS{"InstallOSName"}              = $osname;
	$::ATTRS{"InstallDistributionName"}    = $distroname;
	$::ATTRS{"InstallDistributionVersion"} = $distrover;
	$::ATTRS{"InstallPkgArchitecture"}     = $distroarch;
	$::ATTRS{"InstallServiceLevel"}        = $svclevel;
	$::ATTRS{"InstallCSMVersion"}          = $csmversion;

}

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

=head3	checkattrs

        Notes:

=cut

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

sub checkattrs
{

	#check if all the attributes are there, if not defined then get the
	#default from Management Server
	$::ATTRS{'InstallOSName'} ||= 'Linux';
	my $IsInterOp = $::ATTRS{'InstallOSName'} eq $::PLTFRM ? 0 : 1;

	#target is Linux
	if ($::ATTRS{'InstallOSName'} eq 'Linux')
	{

		# get default value
		$::ATTRS{'InstallCSMVersion'} ||=
		  NodeUtils->get_CSMVersion("csm\.core");
		if (!$::ATTRS{'InstallDistributionName'})
		{
			$::ATTRS{'InstallDistributionName'} =
			  NodeUtils->get_DistributionName
			  if !$IsInterOp;
			MessageUtils->message('E1', 'EMsgNoDistributionName') if $IsInterOp;
		}
		if (!$::ATTRS{'InstallDistributionVersion'})
		{
			$::ATTRS{'InstallDistributionVersion'} =
			  NodeUtils->get_DistributionVersion
			  if !$IsInterOp;
			MessageUtils->message('E1', 'EMsgNoDistributionVersion')
			  if $IsInterOp;
		}
		if (!$::ATTRS{'InstallPkgArchitecture'})
		{
			$::ATTRS{'InstallPkgArchitecture'} =
			  ArchiveUtils->get_PkgArchitecture
			  if !$IsInterOp;
			MessageUtils->message('E1', 'EMsgNoArch') if $IsInterOp;
		}
		if (   $::ATTRS{"InstallServiceLevel"}
			&& $::ATTRS{"InstallServiceLevel"} ne '\'\'')
		{

			# When user uses lower-case pre-defined service level such as qu* and sp*,
			# a warning message will be given and no action will take in place.
			if (
				NodeUtils->checkServiceLevelCase(            $::ATTRS{"InstallServiceLevel"}
												)
			   )
			{
				MessageUtils->messageFromCat('csmInstall.cat', $::MSGMAPPATH,
									   'csminstall', 'E', "ESvcLevelCaseWrong");
				$::ATTRS{"InstallServiceLevel"} =
				  uc($::ATTRS{"InstallServiceLevel"});
			}
		}
		else
		{
			# Default the ISL to the value of management server or GA.
			my $isl = 'GA';

			if ($::PLTFRM eq "Linux")
			{
				my $ms_distro     = NodeUtils->get_DistributionName();
				my $ms_distro_ver = NodeUtils->get_DistributionVersion();
				my $ms_arch       = NodeUtils->get_PkgArchitecture();
				if ($ms_distro eq $::ATTRS{'InstallDistributionName'})
				{
					%::pkgdefs =
					  ServerUtils->get_pkgdefs($::PLTFRM, $ms_distro,
											   $ms_distro_ver, $ms_arch);
					$isl = NodeUtils->get_ServiceLevel;
					$isl = "GA" if (!$isl);
				}
			}

			$::ATTRS{"InstallServiceLevel"} = $isl;
		}

		# check for the valid attributes
		MessageUtils->message('E2', 'EMsgNO_CORE_COPY')
		  if !$::ATTRS{'InstallCSMVersion'};
		$::ATTRS{'InstallPkgArchitecture'} = "i386"
		  if $::ATTRS{'InstallPkgArchitecture'} =~ /i.86/;
		my $temp_distro =
		    $::ATTRS{'InstallDistributionName'} . " "
		  . $::ATTRS{'InstallDistributionVersion'};
        my %pkgdefs =
              ServerUtils->get_pkgdefs(
                                       $::ATTRS{'InstallOSName'},
                                       $::ATTRS{'InstallDistributionName'},
                                       $::ATTRS{'InstallDistributionVersion'},
                                       $::ATTRS{'InstallPkgArchitecture'}
                                      );
        my $location = "MgdNode";
		if (!grep(/^$location$/, @{$pkgdefs{'where_supported'}}))
		{
			my $officially_supported = 1;	
			my %supported_distro = NodeUtils->getSupportedDistro($officially_supported);
			MessageUtils->message(         'E1', 'EMsgUNSUPPORTED_DISTRO',
								  $temp_distro, $supported_distro{$location});
		}
		else
		{
			MessageUtils->message('V', 'IMsgDETECTED_DISTRO', $temp_distro);
		}
		if (!grep(/^$::ATTRS{'InstallCSMVersion'}$/, @::VALID_CSM_DISTROS))
		{
			MessageUtils->message(
								  'E5',
								  'EMsgUNSUPPORTED_CSM_DISTRO',
								  "CSM" . $::ATTRS{'InstallCSMVersion'},
								  join(', ', @::VALID_CSM_DISTROS)
								 );
		}
		else
		{
			MessageUtils->message(
								  'V',
								  'IMsgDETECTED_CSM_DISTRO',
								  "CSM" . $::ATTRS{'InstallCSMVersion'}
								 );
		}
		$::DISTRO = $temp_distro;
	}

	#target is AIX
	elsif ($::ATTRS{'InstallOSName'} eq 'AIX')
	{
		MessageUtils->message('E2', 'EMsgCopyingAIXpkgs');
	}

	#target is others
	else
	{
		MessageUtils->message("E2", 'EMsgINVALID_OSTYPE');
	}

}

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

=head3	create_directory_structure

        Notes:

=cut

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

sub create_directory_structure
{
	MessageUtils->message('I', 'IMsgCreatingDirectories');
	mkpath($::INSTALLDIR_CSMVRBIN, $::VERBOSE, 0755);
	mkpath($::INSTALLDIR_CSMBIN,   $::VERBOSE, 0755);
	mkpath($::INSTALLDIR_CSMPKG,   $::VERBOSE, 0755);

	if ($::ATTRS{'InstallOSName'} eq "AIX")
	{
		mkpath($::INSTALLDIR_CSMRPM,    $::VERBOSE, 0755);
		mkpath($::INSTALLDIR_CSMINSTLP, $::VERBOSE, 0755);
	}
	elsif ($::ATTRS{'InstallOSName'} eq "Linux")
	{
		ArchiveUtils->createRPMSdir(
									$::ATTRS{'InstallOSName'},
									$::ATTRS{'InstallDistributionName'},
									$::ATTRS{'InstallDistributionVersion'},
									$::ATTRS{'InstallPkgArchitecture'},
									$::ATTRS{'InstallServiceLevel'}
								   );

	}
	else
	{
		MessageUtils->message('E2', 'EMsgINVALID_OSTYPE');
	}
}

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

=head3	Main

=cut

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

{    # main

	# initialize runtime env
	&initialize;

	# Check the arguments
	&getArgs;

	# Start logging
	MessageUtils->start_logging($::COPYCSMPKGS_LOG);

	# get the packege list that needs to be copied
	my $rpmListRef = ArchiveUtils->getPackageList($::opt_A);
							
	#Create the destination directories
	&create_directory_structure;

	# Copy all the appropriate packages to /csminstall.
	ArchiveUtils->update_packages_to_csminstall( 
                    $::ATTRS{'InstallDistributionName'},
                    $::ATTRS{'InstallDistributionVersion'},
					$::ATTRS{'InstallServiceLevel'},
                    $::ATTRS{'InstallPkgArchitecture'},
                    $::ATTRS{'InstallCSMVersion'},
                    $rpmListRef, 
					'/csminstall',
                    $::FALSE, 
                    \%::pkgdefs,
		    $::NO_MOUNT_CD);

	# Copy the 'binaries' needed for install to /csminstall/csm
	# We need to copy the binaries here in copycsmpkgs as well as in installms
	# because in a mixed-architecture Linux cluster (xLinux and pLinux),
	# installms would have only copied the binaries for the management
	# server's architecture.
	MessageUtils->message('I', 'IMsgCOPYING_CSMBINARIES');

	ServerUtils->copyBinaries(
							  $::ATTRS{'InstallOSName'},
							  $::ATTRS{'InstallDistributionName'},
							  $::ATTRS{'InstallDistributionVersion'},
							  $::ATTRS{'InstallPkgArchitecture'},
							  $::ATTRS{'InstallCSMVersion'},
							 );
	MessageUtils->message('I', 'IMsgCOMPLETE_COPYING_CSMBINARIES');

	# Stop logging
	MessageUtils->stop_logging();

	exit 0;

}    # main

