#  $Header: emcore/sysman/admin/scripts/osm/ecmCloneHome.pl /st_emcore_10.2.0.4.3db11.2.0.2/1 2010/06/07 22:38:56 kbodkhe Exp $
#
# Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. 
#
#    DESCRIPTION
#      perl routines used by CloneInstallation job
#
#    NOTES
#
#
#    MODIFIED   (MM/DD/YY)
#     kbodkhe    09/24/09 - Handling hybrid java invocations on Solaris x64
#     kbodkhe    05/29/10 - XbranchMerge kbodkhe_bug8903874_sol_hybrid_java
#                           from st_emcore_10.2.0.4.2db11.2
#     amani      01/10/08 - Backport amani_coregen from main
#     kkhanuja   09/11/07 - 
#     shnavane   05/18/07 - Fix bug #6024894
#     shnavane   09/02/07  - Backport shnavane_bug-6024894 from main
#     amani      08/09/07  - Added overloaded method preparesourceHomeEx, for enabling to use 
#			     zip utility. HP POC requirement.
#     amani      08/08/06 - Backport amani_fix_5374094 from main
#     amani      07/13/06 - For bug fix 5374094 
#     amani      05/25/06 - Adding additional options for update
#     amani      05/25/06 - Adding additional options for update
#     amani      05/25/06 - Adding additional options for update
#     amani      05/25/06 - Adding additional options for update
#     amani      08/01/06 - Backport amani_bug-5075347 from main
#     amani      07/31/06 - Backport amani_bug-4870299 from main
#     amani    05/03/06 - For adding options to dcmJoincluster, changing code for addtoOUI
#     amani      04/24/06 - To add Prereq check for windows.Bug fix 5053879.
#     makarapu   02/28/06 - Exit code issue with addnode
#     audupi     01/18/06 - Backport audupi_bug-4870686 from main 
#     audupi     12/27/05 - 4906869 - 10.1.3 Integration 
#     audupi     12/14/05 - Backport audupi_bug-4870686 from main 
#     audupi     12/13/05 - Adding sub-routine to register home with 
#                           OUIinventories.add 
#     audupi     09/15/05 - 4609384 - Adding -nowait to clone parameters
#     anusharm   08/25/05 - making checkDestPrereqs compatible with 10.1GC
#     audupi     08/23/05 - 4568252 - Win CRS create cluster changes
#     anusharm   08/22/05 - unsetting EMSTATE for AS Cloning 
#     anusharm   08/08/05 - win32 CRS parameters 
#     audupi     08/03/05 - Removing braces for cluster-nodes for attachRACHome
#     anusharm   08/01/05 - clearing CONSOLE_CFG for ias clone
#     anusharm   07/15/05 - windows crs support 
#     anusharm   07/15/05 - windows crs support
#     anusharm   07/12/05 - adding ORACLE_HOSTNAME for CRS 
#     anusharm   06/14/05 - removing unnecessary params from prepareCRS 
#     anusharm   05/31/05 - making prepare_clone.pl optional for prepareAS 
#     anusharm   05/24/05 - correcting crs extend case
#     anusharm   04/28/05 - correcting prepareASHome params, adding prepareCRSHome
#     anusharm   04/14/05 - removing extra escape chars 
#     gpalrech   04/06/05 - attachHome method for RAC 
#     anusharm   04/04/05 - adding checkDestPrereqs to job
#     anusharm   03/28/05 - cleaning up rac job 
#     anusharm   02/03/05 - cloning for crs 
#     mgoodric   01/31/05 - fix ambiguous warn subroutine 
#     anusharm   01/24/05 - clean up updateHome classpath
#     anusharm   12/28/04 - dcmJoinCluster, dcm whichCluster
#     anusharm   12/01/04 - adding local_node, calling clone.pl in 
#                           updateBuiltInClonable, calling prepare_clone.pl 
#                           for db homes, adding emCfg.jar to classpath 
#     anusharm   11/10/04 - ignoring exit status 2 for linux while tar, 
#                           take care of homes with space while setting invptrloc
#     anusharm   09/28/04 - adding 10gr2 enhancements
#     mnosseir   09/16/04 - add getFreeSpace() and dirPermission() to remove
#                           dependency on db_common.pl
#     mnosseir   09/16/04 - #(3872357) set oracle.install.oui_loc in
#                            updateBuiltInClonable()
#     anusharm   09/01/04 -  merging ple changes
#     djoly      08/18/04 - Break up cemd
#     skumar     08/13/04 - HP, AIX, Tru64, MAC OS X, HPI and L64 changes
#     anusharm   06/18/04 - bug 3427734 
#     anusharm   06/17/04 - bug 3235500
#     djoly      05/14/04 - Update core reference 
#     mnosseir   04/09/04 - #(3488792) typecast the return value of 
#                           getFreeSpace to int 
#     mbhoopat   03/10/04 - linux port 
#     nsharma    01/21/04 - change solaris to linux 
#     jmansur    12/21/03 - bug 3238183 - testing shows oui bug prevents oui
#                           using oui_loc when updateHome() is called, so
#                           set LD_LIBRARY_PATH for that as before.
#     jmansur    12/17/03 - bug 3238183 - set oui_loc when check dest pre-reqs
#                           (and when updateHome for platform-independence)
#     jmansur    01/12/04 - fix bug 3368647 - in updateBuiltInClonable(), if
#                           status file is present, treat update as successful
#     jmansur    12/09/03 - bug 3307527 - handle Locale with no country piece
#     jmansur    12/05/03 - bug 3278299 - use csh for piped commands so overall
#                           command fails if the 1st command in pipeline fails
#     jmansur    11/20/03 - bug 3271279 - fix copySourceHome so it doesn't try
#                           to recursively copy a home to under itself
#     jmansur    11/14/03 - bug 3238101 - do preClone check in
#                           updateBuiltInClonable(); if preClone check fails,
#                           assume preClone not needed so job can continue
#     jmansur    11/13/03 - bug 3252975 - get zipped+expanded size of home's
#                           ClonerStage(s) in checkSourcePrereqs()
#     jmansur    11/05/03 - bug 3238183 - handle space in new home's homeName,
#                           so we can let oui tell us it's an invalid homeName
#     jmansur    10/22/03 - use /bin/find and /bin/ftp, so don't rely on path
#                         - add other oui jars to classpath when updateHome()
#                         - fix LD_LIBRARY_PATH when run oui's updateHome()
#     jmansur    09/25/03 - ClonerStage now (oui 2.3.0.9.0) returns an error
#                           rather than a warning code if prereq-checks fail,
#                           so go back to only warning for warning codes
#     jmansur    10/19/03 - add ftpGet - for bug 3200203
#     jmansur    10/14/03 - use status-file when updateHome - for bug 3123996
#     jmansur    10/14/03 - fix home-is-readable result; true/false, not 1/0
#     jmansur    10/08/03 - check if home is readable in checkSourcePrereqs()
#     jmansur    10/02/03 - move more of prepareSource step from job to here
#     jmansur    09/23/03 - do case-blind search for excluded files on windows,
#                           since windows has, e.g., .DBF, .log and .LOG files
#     jmansur    09/20/03 - use ' instead of ? as delimiter for search & subst,
#                           since ?? only matches once between reset calls
#     jmansur    09/19/03 - handle embedded spaces in agent home location
#     jmansur    09/16/03 - handle embedded spaces in file paths; move more
#                           perl here from job definition
#     jmansur    09/15/03 - jmansur_ecm-030912-clone-home-nt
#     jmansur    09/12/03 - creation
# 
#

use strict;
use Config;
use File::Basename;
use File::Copy;
use File::Path;
use File::Spec;
use Net::Domain qw(hostfqdn);
use Sys::Hostname;
require "emd_common.pl";
require "$ENV{EMDROOT}/sysman/admin/scripts/osm/ecmCommon.pl";
use vars qw($DF $DELIMITER);

#
# some platform-specific commands
#
my $FIND = '/usr/bin/find';
my $FTP = '';
my $TAR = '';
if (onWindows())
{
  $FTP = 'ftp';
}
else
{
  $FTP = '/usr/bin/ftp';
}
if ($^O eq "darwin")
{
  $TAR = '/usr/bin/gnutar';
}
else
{
  $TAR = '/bin/tar';
}
my $CSH = '/bin/csh';

#### GLOBAL Platform-specific flags for all EM OSs ####
if($^O =~ /solaris/i){
  $DF = "/bin/df -k"
}
elsif($^O =~ /aix/i){
  $DF = "/bin/df -Pk"
}
elsif($^O =~ /linux/i){
  $DF = "/bin/df -k"
}
elsif($^O =~ /hpux/i){
  $DF = "/usr/bin/bdf"
}
## Operating system unknown (probably Unix)
else{
  $DF = "/bin/df -k"
}

## The delimiter is used to separate paramters passed in perl routines from Java
## code.  In most cases, it is used to separate file names.
$DELIMITER = ":::";


#
# check oui-style status returned from system().  oui-style status is:
# 0 for success, 1 for ok with warnings, or -1 for failure
#
sub checkOuiStatus($$)
{
  my ($systemStatus, # status from external call, e.g., from system()
      $operation     # operation that failed, e.g., "update"
      ) = @_;

  my $warningText =
    "$operation completed successfully but there were some warnings";

  my $exitStatus = $systemStatus / 256;

  if ($exitStatus == 1)
  {
    # use ecmCommon's warn subroutine
    main::warning($exitStatus, "$warningText");
  }
  elsif ($exitStatus)
  {
    abort($operation, $exitStatus, "$systemStatus / 256");
  }
}

#
# check pre-requisite info at the clone dest
#
sub checkDestPrereqs()
{
  (@ARGV) = @_;
  my $size = @ARGV;
  my $oms102 = "false";

  #get type of OMS from number of arguments.
  if($size eq 5)
  {
    $oms102 = "true";
  }

  if($oms102 eq "true")
  {
	my $homeLocation = $ARGV[0];
	my $homeName = $ARGV[1];
	my $scratchLocation = $ARGV[2];
	my $homeArchSpaceReq = $ARGV[3];
	my $homeSpaceReq = $ARGV[4];

	#called only for pre-reqs step in the job
    checkDestPrereqsFor102($homeLocation, $homeName, $scratchLocation, $homeArchSpaceReq, $homeSpaceReq);
  }
  else
  {
	  #for wizard validation, only for 10.1 GC
	  my ($homeLocation,   # dest home dir, e.g., /private/ora10gClone
		  $homeName,       # dest home name, e.g., ora10gClone
		  $scratchLocation # scratch dir, e.g., /tmp/oemchd123
		  ) = @_;

	  my $scratchIsRw;
	  if (dirPermission($scratchLocation) eq "OK")
	  {
		$scratchIsRw='true';
	  }
	  else
	  {
		$scratchIsRw='false';
	  }
	  my $scratchFreeKB = int(getFreeSpace($scratchLocation));
	  my $homeFreeKB = int(getFreeSpace($homeLocation));
	  print("$scratchIsRw, $scratchFreeKB, $homeFreeKB");
	  # invoke code that uses oui then prints homeNameOK & ouiInvIsRw 
	  my $oracleHome = $ENV{ORACLE_HOME};
	  my $javaHome = $ENV{JAVA_HOME};
	  my $emdroot = $ENV{EMDROOT};
	  my $pathSep = "\":\"";
	  if (onWindows())
	  {
		$pathSep = "\";\"";
	  }
	  my $d64_opt;
          if(is64BitHybridJava($ENV{EMDROOT}))
          {
             $d64_opt = "-d64";
          }

	  # same as emd.properties hostConfigClasspath
	  my $classPath = "\"$oracleHome/oui/jlib/xmlparserv2.jar$pathSep$oracleHome/oui/jlib/OraInstaller.jar$pathSep$oracleHome/oui/jlib/srvm.jar$pathSep$oracleHome/oui/jlib/share.jar$pathSep$emdroot/sysman/jlib/emd_java.jar$pathSep$emdroot/sysman/jlib/emcoreAgent.jar$pathSep$emdroot/sysman/jlib/emagentSDK.jar$pathSep$emdroot/sysman/jlib/log4j-core.jar\"";
	  chdir($javaHome)
		or abort("cd to '$javaHome'", $!, "$!");
	  system(getDirPath("bin", "java") . "  $d64_opt -cp $classPath -Doracle.installer.oui_loc=\"$oracleHome/oui\" oracle.sysman.emd.ecm.clone.DestEnvironment -validate \"$homeName\" \"$homeLocation\"");
	  exit ($? >> 8);
  }
}



sub checkDestPrereqsFor102()
{
  my ($homeLocation,   # dest home dir, e.g., /private/ora10gClone
      $homeName,       # dest home name, e.g., ora10gClone
      $scratchLocation, # scratch dir, e.g., /tmp/oemchd123
  	  $homeArchSpaceReq, # home archive space required
  	  $homeSpaceReq # home space required
      ) = @_;

  #For bug fix 5374094
  $homeSpaceReq *= 2;
  $homeArchSpaceReq = $homeSpaceReq;
  print "Oracle Home Location:--$homeLocation--\n";
  print "Oracle Home Name:--$homeName--\n";
  print "Space required in working directory:$homeArchSpaceReq KB\n";
  print "Space required for Oracle Home:$homeSpaceReq KB\n";
  my $preReqFailures = "";
  my $preReqWarnings = "";
  
  my $scratchIsRw;
  if (dirPermission($scratchLocation) eq "OK")
  {
    $scratchIsRw='true';
  }
  else
  {
    $scratchIsRw='false';
	$preReqFailures = $preReqFailures."\nFailed >> Read/Write check failed for Working Directory:$scratchLocation\n";
  }
  
  my $scratchFreeKB = int(getFreeSpace($scratchLocation));
  if($scratchFreeKB eq "0")
  {
	$preReqWarnings = $preReqWarnings."\nWarning >> Could not find available space in the working directory.\n";
  }
  elsif($scratchFreeKB < $homeArchSpaceReq)
  {
	$preReqFailures = $preReqFailures."\nFailed >> Not enough space in working directory($scratchFreeKB) for home archive($homeArchSpaceReq)\n";
  }

  my $homeFreeKB = int(getFreeSpace($homeLocation));
  if($homeFreeKB eq "0")
  {
	$preReqWarnings = $preReqWarnings."\nWarning >> Could not check available space in the volume.\n";
  }
  elsif($homeFreeKB < $homeSpaceReq)
  {
	$preReqFailures = $preReqFailures."\nFailed >> Not enough space on the volume($homeFreeKB) selected for the Oracle Home($homeSpaceReq)\n";
  }

  #On windows if the the drive is same, then the free space required must be greater than the (homeSpace+ArchSpace)
  if(onWindows()){
  	my $volOH = &getDriveName($homeLocation);
  	my $volScratch = &getDriveName($scratchLocation);

  	if($volOH eq $volScratch){
  		my $myTotReqdSpace = $homeSpaceReq + $homeArchSpaceReq;

  		if($homeFreeKB < $myTotReqdSpace){
			print "\n Space available for OracleHome:$homeFreeKB KB\n";
			print "\n Space available for Working Directory:$scratchFreeKB KB\n";
  			$preReqFailures = $preReqFailures."\nFailed >> Total available space on the volume($homeFreeKB) for selected Oracle Home($homeSpaceReq) and Working Directory($homeArchSpaceReq) is not sufficient to support Clone operation\n";
  		}
  	}
  }
  else
  {
	my $fileSyVal = &checkForSameFileSys($homeLocation,$scratchLocation );
	if($fileSyVal eq "true")
	{
		my $totReqSpace = $homeSpaceReq + $homeArchSpaceReq;
		if($homeFreeKB < $totReqSpace){
			print "\n Space available for OracleHome:$homeFreeKB KB\n";
			print "\n Space available for Working Directory:$scratchFreeKB KB\n";
  			$preReqFailures = $preReqFailures."\nFailed >> Total available space on the system($homeFreeKB) for selected Oracle Home($homeSpaceReq) and Working Directory($homeArchSpaceReq) is not sufficient to support Clone operation\n";
  		}
	}
  }

  # invoke code that uses oui then prints homeNameOK & ouiInvIsRw
  my $oracleHome = $ENV{ORACLE_HOME};
  my $javaHome = $ENV{JAVA_HOME};
  my $emdroot = $ENV{EMDROOT};
  my $pathSep = "\":\"";
  if (onWindows())
  {
    $pathSep = "\";\"";
  }
  my $d64_opt;
  if(is64BitHybridJava($ENV{EMDROOT}))
  {
     $d64_opt = "-d64";
  }

  # same as emd.properties hostConfigClasspath
  my $classPath = "\"$oracleHome/oui/jlib/xmlparserv2.jar$pathSep$oracleHome/oui/jlib/OraInstaller.jar$pathSep$oracleHome/jlib/emCfg.jar$pathSep$oracleHome/oui/jlib/srvm.jar$pathSep$oracleHome/oui/jlib/share.jar$pathSep$emdroot/sysman/jlib/emd_java.jar$pathSep$emdroot/sysman/jlib/emagentSDK.jar$pathSep$emdroot/sysman/jlib/emcoreAgent.jar$pathSep$emdroot/sysman/jlib/log4j-core.jar\"";
  chdir($javaHome)
    or abort("cd to '$javaHome'", $!, "$!");
  my $cmd = getDirPath("bin", "java") . " $d64_opt -cp $classPath -Doracle.installer.oui_loc=\"$oracleHome/oui\" oracle.sysman.emd.ecm.clone.DestEnvironment -validate \"$homeName\" \"$homeLocation\"";

  open(READ, " $cmd |");
  my @array=<READ>;
  close(READ);
  my $status = $?;

  if($status ne 0)
  {
	  abort("checkDestPrereqs", $status >> 8, "could not execute destination validation");
  }
  my $x = "";
  my $homeOK = "";
  my $locStatus = "";
  my $ouiInvRw = "";
  ($x, $homeOK, $locStatus, $ouiInvRw) = split(", ", $array[0], 4);
    
  if(uc($ouiInvRw) eq "FALSE")
  {
	$preReqFailures = $preReqFailures."\nFailed >> The central OUI inventory on this host is not read-writable or it is locked by another process. This directory must be read-writable before you submit the clone job.\n";
  }

  if(uc($homeOK) eq "FALSE")
  {
	$preReqFailures = $preReqFailures."\nFailed >> Oracle Home Name is not valid.\n";
  }
  
  if(($locStatus ne 1) && ($locStatus ne 2))
  {
	  if($locStatus eq -2)#is file
	  {
		  $preReqFailures = $preReqFailures."\nFailed >> Invalid Oracle Home Location. A file already exists by this name.\n";
	  }
	  elsif($locStatus eq -3)#cannot create
	  {
		  $preReqFailures = $preReqFailures."\nFailed >> Invalid Oracle Home Location. Failed to create the new directory. The parent directory must be set as read-writable for the user specified in the Select Destination table for this host.\n";
	  }
	  elsif($locStatus eq -4)#not empty
	  {
		  $preReqFailures = $preReqFailures."\nFailed >> Invalid Oracle Home Location. The existing directory is not empty.\n";
	  }
	  elsif($locStatus eq -5)#not rw
	  {
		  $preReqFailures = $preReqFailures."\nFailed >> Invalid Oracle Home Location. Can not read-write into the existing directory. The directory location must be set as read-writable.\n";
	  }
  }

  #warnings
  if(length($preReqWarnings) ne 0)
  {
	  print($preReqWarnings);
  }

  #failures
  if(length($preReqFailures) eq 0)
  {
	  print("\n-----------------All pre-requisites succeeded-----------------\n");
	  exit;
  }
  else
  {
	  #print("$preReqFailures\n");
	  abort("prerequisites", 1 , "$preReqFailures\n");
  }
}

#given dirs, checks whether they belong to the same file system(unix type filesystem only) and returns true else returns false
sub checkForSameFileSys($$) {
	my ($dir1,
      		$dir2
      ) = @_;

	#get the DF from global variable
	my $df = "$DF .";
	my $row = -1;
	my $filesys1 = "";
	my $filesys2 = "";

	chdir($dir1);
	my @temp1 = `$df`;
	$_ = $temp1[$row];
	my @tokens1 = split;
	$filesys1 = $tokens1[$#tokens1];

	chdir($dir2);
    	my @temp2 = `$df`;
	$_ = $temp2[$row];
	my @tokens2 = split;
	$filesys2 =$tokens2[$#tokens2];

	if($filesys1 eq $filesys2){
		return "true";
	} else {
		return "false";
	}
}

# the vol, dir and file for the given path
  sub getDriveName($){
	my ($myPath) = @_;
	my ($myVoluname,$myDirname,$myFilesname) = File::Spec->splitpath( $myPath );
	return $myVoluname;
  }

#
# check pre-requisite info at the clone source host & home
#
sub checkSourcePrereqs($$)
{
  my ($homeLocation,   # source home dir, e.g., /private/ora10g
      $scratchLocation # scratch dir, e.g., /tmp/oemchs123
      ) = @_;

  my $scratchIsRw;
  if (dirPermission($scratchLocation) eq "OK")
  {
    $scratchIsRw='true';
  }
  else
  {
    $scratchIsRw='false';
  }
  my $scratchFreeKB = int(getFreeSpace($scratchLocation));

  my @clonerStages = getClonerStageList($homeLocation);

  my $clonerStageCount = @clonerStages;

  my $clonerStageKB = 0; # sum of zip + expanded size of home's ClonerStage(s)
  my $clonerStageCountSize = "";
  if (0 != $clonerStageCount)
  {
    foreach my $cs (@clonerStages)
    {
      chomp($cs);
      # assume expanded size = 2 * zip size
      # TBD - should use ClonerStage's getSpaceRequired.pl
      $clonerStageKB += (-s $cs) * 3;
    }
    $clonerStageKB = int(($clonerStageKB + 512) / 1024);
    $clonerStageCountSize = $clonerStageCount . ":" . $clonerStageKB;
  }
  else
  {
    $clonerStageCountSize = $clonerStageCount;
  }

  # bug 3235500, removed install.platform from must-be-readable list.
  my $homeIsReadable = ((-r $homeLocation) &&
      (-r ($homeLocation . '/inventory'))) ? 'true' : 'false';

  print("$scratchIsRw, $scratchFreeKB, $clonerStageCountSize, $homeIsReadable");

  # if OH/oraInst.loc exists, use that to fix inventory associated with this OH, bug 3427734
  my $setInventory = "";
  if( -e ($homeLocation . '/oraInst.loc') )
  {
  	  my $inventoryLoc = getPropertyValue($homeLocation . '/oraInst.loc', "inventory_loc") ;
  	  if( ($inventoryLoc ne "") && ( -r $inventoryLoc ))
  	  {
  		 $setInventory = "-Doracle.installer.invPtrLoc=". "\"$homeLocation" . "/oraInst.loc\"" ;
		 
  	  }
  }
  
  # invoke code that uses oui then prints homeKB & archiveKB, etc.
  my $oracleHome = $ENV{ORACLE_HOME};
  my $javaHome = $ENV{JAVA_HOME};
  my $emdroot = $ENV{EMDROOT};
  my $pathSep = "\":\"";
  if (onWindows())
  {
    $pathSep = "\";\"";
  }
  my $d64_opt;
  if(is64BitHybridJava($ENV{EMDROOT}))
  {
     $d64_opt = "-d64";
  }

  # same as emd.properties hostConfigClasspath
  my $classPath = "\"$oracleHome/oui/jlib/xmlparserv2.jar$pathSep$oracleHome/oui/jlib/OraInstaller.jar$pathSep$oracleHome/jlib/emCfg.jar$pathSep$oracleHome/oui/jlib/srvm.jar$pathSep$oracleHome/oui/jlib/share.jar$pathSep$emdroot/sysman/jlib/emd_java.jar$pathSep$emdroot/sysman/jlib/emagentSDK.jar$pathSep$emdroot/sysman/jlib/emcoreAgent.jar$pathSep$emdroot/sysman/jlib/log4j-core.jar\"";
  chdir($javaHome)
    or abort("cd to '$javaHome'", $!, "$!");
  system(getDirPath("bin", "java") . " $d64_opt $setInventory -cp $classPath -Doracle.installer.oui_loc=\"$oracleHome/oui\" oracle.sysman.emd.ecm.clone.SourceEnvironment -checkPrereqs \"$homeLocation\"");
  exit ($? >> 8);
}

#
# do recursive copy of source home to dest home
#
sub copySourceHome($$$)
{
  my ($sourceHomeLocation, # source home dir, e.g., /private/ora10g
      $destHomeLocation,   # dest home dir, e.g., /private/ora10gClone
      $excludeListFile, # file listing files to exclude, e.g., /tmp/eList.txt
      ) = @_;

  # don't try to recursively copy home to under itself
  my $bsSource = getBackSlashedString($sourceHomeLocation) . "\\";
  my $bsDest = getBackSlashedString($destHomeLocation) . "\\";
  if (substr($bsDest, 0, length($bsSource)) eq $bsSource)
  {
    abort("recursive copy attempt of '$sourceHomeLocation' to under itself: '$destHomeLocation'", 1, "copy loop detected");
  }

  chdir($sourceHomeLocation)
    or abort("cd to '$sourceHomeLocation'", $!, "$!");
  if (onWindows())
  {
    ##### TBD can't seem to make xcopy handle $excludeListFile with embedded
    ##### spaces so in that case, skip excluding files
    ##### double-quoting $excludeListFile fails the xcopy
    if ((`xcopy /?` =~ m'/EXCLUDE:') && !($excludeListFile =~ m' '))
    #####if (`xcopy /?` =~ m'/EXCLUDE:')
    {
      $excludeListFile = getBackSlashedString($excludeListFile);
      echodo("xcopy /r /i /c /h /k /e /y /s /q /EXCLUDE:" .
             $excludeListFile .
             " \"$sourceHomeLocation\" \"$destHomeLocation\"") == 0
        or abort("copySourceHome", $? >> 8, "$!");
    }
    else
    {
      echodo("xcopy /r /i /c /h /k /e /s /q \"$sourceHomeLocation\" \"$destHomeLocation\"") == 0
        or abort("copySourceHome", $? >> 8, "$!");
    }
  }
  else
  {
    if ($^O eq "aix" or $^O eq "hpux" or $^O eq "dec_osf")
    {
      # no -X option
      echodo("$CSH -cf '$TAR cpfh - . | (cd \"$destHomeLocation\"; $TAR xpfh -)'");
    }
    else
    {
      echodo("$CSH -cf '$TAR cpfXh - \"$excludeListFile\" . | (cd \"$destHomeLocation\"; $TAR xpfh -)'");
    }
  
    # treat status 13 as non-error - assume "permission denied" and ignore -
    # assume all cases are like root-owned files that get re-created at dest
    # tbd - there may be other errors that we should swallow or warn about,
    # e.g., if a file changes size while we're tar'ing it
    my $status = $? >> 8; 
    if ($^O eq "dec_osf")
    {
	   # on Tru64, status 1 is warning - assume "permission denied" and ignore
       if ((0 != $status) && (1 != $status))
       {
         abort("copySourceHome", $status, "$!");
       }
    }
	elsif ($^O eq "linux")
	{
	   # on linux, all errors are status 1 or 2 so we ignore them all
	   if ((0 != $status) && (1 != $status) && (2 != $status))
       {
          abort("copySourceHome", $status, "$!");
       }
    }
    elsif ((0 != $status) && (13 != $status))
    {
      abort("copySourceHome", $status, "$!");
    }
  }
}

#
# export home to a COMPRESSed tar file or a zip file
#
sub exportHome($$$$)
{
  my ($homeLocation,    # home location to export, e.g., /private/ora10gHome
      $archiveFilePath, # full path of archive, e.g., /tmp/homeArchive
      $excludeListFile, # file that lists excluded files, e.g., /tmp/eList.txt
      $sourceExcludes   # comma/space-separated patterns, e.g., "*.dbf, *.log"
      ) = @_;

  if (onWindows())
  {
    $excludeListFile = getBackSlashedString($excludeListFile);
    $archiveFilePath = getBackSlashedString($archiveFilePath);
  }
  my $operation = "-export";
  # run the ecmHomePackager.pl in the Oracle home
  # NOTE: future - look for customHomePackager.pl & run that instead
  # since double-quoting the commands in the echodo's fails, get the perl dir
  # then chdir there in case path contains embedded blanks
  my ($perlName, $perlDir, $perlSuffix) = fileparse("$^X", "");
  print("chdir($perlDir)\n");
  chdir($perlDir)
    or abort("cd to '$perlDir'", $!, "$!");
  echodo(getDirPath("$perlName") . " -w \"$ENV{EMDROOT}/sysman/admin/scripts/osm/ecmHomePackager.pl\" $operation \"$archiveFilePath\" \"$homeLocation\" \"$sourceExcludes\" \"$excludeListFile\"");
  exit ($? >> 8);
}

#
# export home to a COMPRESSed tar file or a zip file
#
sub exportHomeEx($$$$$)
{
  my ($homeLocation,    # home location to export, e.g., /private/ora10gHome
      $archiveFilePath, # full path of archive, e.g., /tmp/homeArchive
      $excludeListFile, # file that lists excluded files, e.g., /tmp/eList.txt
      $sourceExcludes,   # comma/space-separated patterns, e.g., "*.dbf, *.log"
      $useZIP			# 
      ) = @_;

  if (onWindows())
  {
    $excludeListFile = getBackSlashedString($excludeListFile);
    $archiveFilePath = getBackSlashedString($archiveFilePath);
  }
  my $operation = "-export";
  # run the ecmHomePackager.pl in the Oracle home
  # NOTE: future - look for customHomePackager.pl & run that instead
  # since double-quoting the commands in the echodo's fails, get the perl dir
  # then chdir there in case path contains embedded blanks
  my ($perlName, $perlDir, $perlSuffix) = fileparse("$^X", "");
  print("chdir($perlDir)\n");
  chdir($perlDir)
    or abort("cd to '$perlDir'", $!, "$!");
  echodo(getDirPath("$perlName") . " -w \"$ENV{EMDROOT}/sysman/admin/scripts/osm/ecmHomePackager.pl\" $operation \"$archiveFilePath\" \"$homeLocation\" \"$sourceExcludes\" \"$excludeListFile\" \"$useZIP\"");
  exit ($? >> 8);
}


#
# use ftp to pull source file from source host to dest file on current host
#
sub ftpGet($$$$$)
{
  my ($sourceHost,      # name host where source file resides
      $sourceFilePath,  # path to file to get, e.g., /tmp/homeArchive
      $destFilePath,    # path to file on current host, e.g., /tmp/homeArchive
      $sourceUsername,  # username that can read source file
      $sourcePassword   # password of user that can read source file
      ) = @_;

  my $systemCommand = "| $FTP -n $sourceHost";
  print("\n$systemCommand\n");
  $! = 0;
  open(FTPIN, "$systemCommand") || abort("fork", $!, "$!");
  local $SIG{PIPE} = sub { abort("pipe", $!, "$!") };
  print FTPIN "user $sourceUsername $sourcePassword\n";
  print FTPIN "binary\n";
  print FTPIN "get \"$sourceFilePath\" \"$destFilePath\"\n";
  print FTPIN "close\n";
  print FTPIN "bye\n";
  my $status = close FTPIN;
  if (!$status)
  {
    if ($!)
    {
      abort("ftp process", $!, "$!");
    }
    else
    {
      $status = $? >> 8;
      if ($status != 0)
      {
        abort("ftp", $? >> 8, "$? >> 8");
      }
    }
  }
  if (! -e $destFilePath)
  {
    abort("ftp of '$sourceFilePath' to '$destFilePath'", $!, "$!");
  }
}

#
# returns a classPath containing the jars in jarDir.  Elements of classPath
# are double-quoted and seprated by a platform-specific separator.  If
# appendEmJars is not 'true',  classPath is terminated with a separator.
#
sub getClassPathWithJars($$)
{
  my ($jarDir,      # dir containing jar files, e.g., /oracle/ora10g/oui/jlib
      $appendEmJars # 'true' asks that em jars (from under $ENV{"EMDROOT"})
                    #   also be added to classPath
      ) = @_;

  my $emdroot = $ENV{EMDROOT};

  my $pathSep = "\":\"";
  if (onWindows())
  {
    $pathSep = "\";\"";
  }

  # add all of this dir's jars to classpath
  my $cp = '"';
  if (!opendir(JAR_DIR, "$jarDir"))
  { 
    abort("open of '$jarDir'", $!, "$!");
  }

  while (my $jar = readdir(JAR_DIR))
  {
    if ($jar =~ m'\.jar$')
    {
      $cp .= "$jarDir/$jar$pathSep";
    }
  }
  closedir(JAR_DIR);

  # get rid of extra trailing double quote, if any
  if (onWindows())
  {
    $cp =~ s';"$';'; # '
  }
  else
  {
    $cp =~ s':"$':'; # '
  }

  if ($appendEmJars eq "true")
  {
    $cp .= "\"$emdroot/sysman/jlib/emd_java.jar$pathSep$emdroot/sysman/jlib/emagentSDK.jar$pathSep$emdroot/sysman/jlib/emcoreAgent.jar$pathSep$emdroot/sysman/jlib/log4j-core.jar$pathSep";
  }
  
  # get rid of extra trailing double quote(pathSep leaves extra quote)
  if (onWindows())
  {
    $cp =~ s';"$';'; # '
  }
  else
  {
    $cp =~ s':"$':'; # '
  }

  return $cp;
}

#
# get user-supplied computeAtClone variables & defaults needed for the clone
#
sub getCloneParams($$$$)
{
  my ($homeLocation,    # source home dir, e.g., /private/ora10g
      $localeLanguage,  # locale.getLanguage() - language of param descriptions
      $localeCountry,   # locale.getCountry()
      $localeVariant    # locale.getVariant()
      ) = @_;

  my $oracleHome = $ENV{ORACLE_HOME};
  my $javaHome = $ENV{JAVA_HOME};
  my $emdroot = $ENV{EMDROOT};
  my $pathSep = "\":\"";
  if (onWindows())
  {
    $pathSep = "\";\"";
  }

  # if OH/oraInst.loc exists, use that to fix inventory associated with this OH, bug 3427734
  my $setInventory = "";
  if( -e ($homeLocation . '/oraInst.loc') )
  {
  	  my $inventoryLoc = getPropertyValue($homeLocation . '/oraInst.loc', "inventory_loc") ;
  	  if( ($inventoryLoc ne "") && ( -r $inventoryLoc ))
  	  {
  		 $setInventory = "-Doracle.installer.invPtrLoc="."\"$homeLocation" . "/oraInst.loc\"" ;
		 
  	  }
  }
  my $d64_opt;
  if(is64BitHybridJava($ENV{EMDROOT}))
  {
     $d64_opt = "-d64";
  }
  # same as emd.properties hostConfigClasspath
  my $classPath = "\"$oracleHome/oui/jlib/xmlparserv2.jar$pathSep$oracleHome/oui/jlib/OraInstaller.jar$pathSep$oracleHome/jlib/emCfg.jar$pathSep$oracleHome/oui/jlib/srvm.jar$pathSep$oracleHome/oui/jlib/share.jar$pathSep$emdroot/sysman/jlib/emd_java.jar$pathSep$emdroot/sysman/jlib/emagentSDK.jar$pathSep$emdroot/sysman/jlib/emcoreAgent.jar$pathSep$emdroot/sysman/jlib/log4j-core.jar\"";
  chdir($javaHome)
    or abort("cd to '$javaHome'", $!, "$!");
  system(getDirPath("bin", "java") . " $d64_opt $setInventory -cp $classPath -Doracle.installer.oui_loc=\"$oracleHome/oui\" oracle.sysman.emd.ecm.clone.SourceEnvironment -getCloneVariables \"$homeLocation\" \"$localeLanguage\" \"$localeCountry\" \"$localeVariant\"");
  exit ($? >> 8);
}

#
# get list of ClonerStages in home
#
sub getClonerStageList($)
{
  my ($homeLocation # home location to search, e.g., /private/ora10gHome
      ) = @_;

  my $csPattern =
    $homeLocation . '/sysman/clonerStage/ClonerStage*.zip';

  my @csList = ();
  if (onWindows())
  {
    $csPattern = getBackSlashedString($csPattern);
    @csList = `dir /b /s "$csPattern" 2> NUL`;
  }
  else
  {
    $csPattern =~ s' '\\ 'g; # '
    @csList = glob($csPattern);
  }

  return @csList;
}

#
# get directory path made up of caller supplied parts, prepended with .
#
sub getDirPath
{
  my $slash = '';

  if (onWindows())
  {
    $slash = '\\';
  }
  else    
  {
    $slash = '/';
  }
  my $fullPath= ".$slash" . join($slash, @_);

  return $fullPath;
}

#
# get version of inputString with all forward slashes replaced by backslashes
#
sub getBackSlashedString($)
{
  my ($inputString # string that may contain forward slashes
      ) = @_;

  my $backSlashedString = $inputString;
  $backSlashedString =~ s'/'\\'g; # ' closing quote fixes text highlighting

  return $backSlashedString;
}

#
# get java home - use home's jre if found, else use JAVA_HOME from env
#
sub getJavaHome($)
{
  my ($homeLocation # home location to search, e.g., /private/ora10gHome
      ) = @_;

  # find dest home's oui's jre & use its jre/bin/java to call oui updateHome()
  my $javaLocation = $ENV{JAVA_HOME};
  my $ouiParamFile = $homeLocation . '/oui/oraparam.ini';
  if (!open(OUI_PARAMS, $ouiParamFile))
  { 
    abort("open of '$ouiParamFile'", $!, "$!");
  }
  while (my $line = <OUI_PARAMS>)
  {
    chomp $line;
    if ($line =~ m/(\S+)=(\S+)/)
    {
      #print("name, value = $1, $2\n");
      if ($1 eq "JRE_LOCATION")
      {
        $javaLocation = $homeLocation . '/oui/bin/' . $2;
        #print("javaLocation=$javaLocation\n");
        last; # TBD - or should we let bottom-most JRE_LOCATION win?
      }
    }
  }
  close(OUI_PARAMS);

  return $javaLocation;
}

#
# get quoted version of command that can be passed to system()
#
# WARNING: each call overwrites the OEM_ECM_CH_COMMAND environment variable
#
sub getQuotedCommand($)
{
  my ($command # the normal looking command, e.g, $^X (the perl exe)
      ) = @_;

  if (!($command =~ m' '))
  {
      return $command;
  }

  my $quotedCommand = '';

  if (onWindows())
  {
    $ENV{'OEM_ECM_CH_COMMAND'} = "\"$command\"";
    print("\n\$ENV\{'OEM_ECM_CH_COMMAND'\}=\"$ENV{'OEM_ECM_CH_COMMAND'}\"\n");
    $quotedCommand = '%OEM_ECM_CH_COMMAND%';
  }
  else
  {
    $quotedCommand = "\"$command\"";
  }

  return $quotedCommand;
}

#
# returns one if home needs preCloning (needs NOH components installed, etc.).
# returns zero otherwise.
#
sub homeNeedsPreCloning($)
{
  my ($homeLocation # home location to examine
      ) = @_;

  my $oracleHome = $ENV{ORACLE_HOME};
  my $javaHome = $ENV{JAVA_HOME};
  my $emdroot = $ENV{"EMDROOT"};
  my $pathSep = "\":\"";
  if (onWindows())
  {
    $pathSep = "\";\"";
  }
  my $d64_opt;   
  if(is64BitHybridJava($ENV{EMDROOT}))
  {
     $d64_opt = "-d64";
  }

  # same as emd.properties hostConfigClasspath
  my $classPath = "\"$oracleHome/oui/jlib/xmlparserv2.jar$pathSep$oracleHome/oui/jlib/OraInstaller.jar$pathSep$oracleHome/jlib/emCfg.jar$pathSep$oracleHome/oui/jlib/srvm.jar$pathSep$oracleHome/oui/jlib/share.jar$pathSep$emdroot/sysman/jlib/emd_java.jar$pathSep$emdroot/sysman/jlib/emagentSDK.jar$pathSep$emdroot/sysman/jlib/emcoreAgent.jar$pathSep$emdroot/sysman/jlib/log4j-core.jar\"";
  print("chdir($javaHome)\n");
  chdir($javaHome)
    or abort("cd to '$javaHome'", $!, "$!");
  my $systemCommand=getDirPath("bin", "java") . " $d64_opt -cp $classPath -Doracle.installer.oui_loc=\"$oracleHome/oui\" oracle.sysman.emd.ecm.clone.DestEnvironment -isPreCloneNeeded \"$homeLocation\" |";
  print("\n$systemCommand\n");
  $! = 0;
  if (!open(CHECKER, "$systemCommand"))
  {
    main::warning($!, "preClone check fork failed: $!");
    return 0;
  }
  local $SIG{PIPE} =
      sub { main::warning($!, "preClone check pipe failed: $!"); return 0; };
  while (my $line = <CHECKER>)
  {
    if (!close CHECKER)
    {
      main::warning($! ? $! : $?,
                 $! ? "preClone check close failed: $!" :
                 "preClone check exited with: $?");
      return 0;
    }
    if ($line =~ /true/)
    {
      return 1;
    }
    else
    {
      return 0;
    }
  }

  main::warning($!, "preClone check failed for '$homeLocation': $!");

  return 0;
}


#
# import/create home from a COMPRESSed tar file or a zip file
#
sub importHome($$)
{
  my ($homeLocation,    # home location to populate, e.g., /private/ora10gClone
      $archiveFilePath  # full path of archive, e.g., /tmp/homeArchive
      ) = @_;

  if (onWindows())
  {
    $archiveFilePath = getBackSlashedString($archiveFilePath);
  }
  my $operation = "-import";
  # run the ecmHomePackager.pl in the Oracle home
  # NOTE: future - look for customHomePackager.pl & run that instead
  my ($perlName, $perlDir, $perlSuffix) = fileparse("$^X", "");
  print("chdir($perlDir)\n");
  chdir($perlDir)
    or abort("cd to '$perlDir'", $!, "$!");
  echodo(getDirPath("$perlName") . " -w \"$ENV{EMDROOT}/sysman/admin/scripts/osm/ecmHomePackager.pl\" $operation \"$archiveFilePath\" \"$homeLocation\"");
  exit ($? >> 8);
}

#
# create a file containing a list of files that tar or xcopy should exclude
# when copying a directory tree
#
sub listExcludedFiles($$$$)
{
  my ($dirLocation,     # dir location to examine, e.g., /private/ora10gHome
      $excludeListDir,  # dir to hold file that will hold list, e.g., /tmp
      $excludeListFile, # file that will hold list, e.g., /tmp/eList.txt
      $sourceExcludes,  # patterns, e.g., "*.dbf, *.log"
      ) = @_;

  my $oracleHome = $ENV{"ORACLE_HOME"};

  my @excludePatterns = split(/[ ,]+/, $sourceExcludes);
  if (!open(EXCLUDE_LIST, "> $excludeListFile"))
  { 
    abort("open of '$excludeListFile'", $!, "$!");
  }
  close(EXCLUDE_LIST);
  my $size = @excludePatterns;
  if($size == 0)
  {
        return;
  }  

  if (!onWindows())
  {
    chdir($dirLocation)
      or abort("cd to '$dirLocation'", $!, "$!");
    foreach my $pattern (@excludePatterns)
    {
      echodo("$FIND . -name \"$pattern\" >> \"$excludeListFile\"") == 0
        or main::warning($!, "find for '$pattern': $!");
    }
  }
  elsif (onWindows() && (`xcopy /?` =~ m'/EXCLUDE:'))
  {
    my $perlLoc = $oracleHome . '/perl';
    chdir($perlLoc)
      or abort("cd to '$perlLoc'", $!, "$!");
    chomp(my $find2Perl = `dir/b/s find2perl.bat`);
    chdir($dirLocation)
      or abort("cd to '$dirLocation'", $!, "$!");
    my $findExcludesScript = $excludeListDir . '/findExcludes.pl';
    $findExcludesScript = getBackSlashedString($findExcludesScript);
    $excludeListFile = getBackSlashedString($excludeListFile);
    foreach my $pattern (@excludePatterns)
    {
      unlink($findExcludesScript);
      #echodo(getQuotedCommand($find2Perl) .
      #       " . -name \"$pattern\" -print | \"$^X\" >> \"$excludeListFile\"") == 0
      echodo(getQuotedCommand($find2Perl) .
             " . -name \"$pattern\" -print  > \"$findExcludesScript\"") == 0
        or abort("'$find2Perl' for '$pattern'", $? >> 8, "$!");
      echodo(getQuotedCommand($^X) .
             "  \"$findExcludesScript\" >> \"$excludeListFile\"") == 0
        or abort("'$findExcludesScript' for '$pattern'", $? >> 8, "$!");

      my $ucPattern = uc($pattern);
      #echodo(getQuotedCommand($find2Perl) .
      #       " . -name \"$ucPattern\" -print | \"$^X\" >> \"$excludeListFile\"") == 0
      unlink($findExcludesScript);
      echodo(getQuotedCommand($find2Perl) .
             " . -name \"$ucPattern\" -print  > \"$findExcludesScript\"") == 0
        or abort("'$find2Perl' for '$ucPattern'", $? >> 8, "$!");
      echodo(getQuotedCommand($^X) .
             "  \"$findExcludesScript\" >> \"$excludeListFile\"") == 0
        or abort("'$findExcludesScript' for '$ucPattern'", $? >> 8, "$!");
    }
    rename("$excludeListFile", "$excludeListFile-ORIG");
    open EXCLUDE_LIST_OLD, "$excludeListFile-ORIG";
    open EXCLUDE_LIST_NEW, "> $excludeListFile";
    while (my $line = <EXCLUDE_LIST_OLD>)
    {
        chomp $line;
        $line =~ s'^\./''; # '
        $line = getBackSlashedString($line);
        print EXCLUDE_LIST_NEW "$line\n";
    }
    close EXCLUDE_LIST_OLD;
    close EXCLUDE_LIST_NEW;
  }
}

#
#
# Make dir or fail if it already exists
#
sub makeNewDir($)
{
  my ($dirName) = @_;

  my @createdDirs = ();
  $!=0;
  if (! -e $dirName)
  {
    #eval {@createdDirs = mkpath($dirName, 0, 0777)};
    @createdDirs = mkpath($dirName, 1, 0777);
    if (! -e $dirName)
    {
        abort("mkdir of '$dirName'", $!, "$!");
    }
  }
  else
  {
    abort("overwrite of '$dirName'", 1, "1");
  }
}

#
# pre-clone built-in-clonable (e.g., db 10g) homes.  pre-cloning installs oui
# non-oracle-home components used by the clone, if needed.
#
sub preCloneHome($$$)
{
  my ($destHomeLocation,    # dest home dir, e.g., /private/ora92Clone
      $destHomeName,        # dest home name, e.g., ora92Clone
      $scratchLocation,     # scratch dir, e.g., /tmp/oemchd123
      ) = @_;

  my $clonerStageName = 'ClonerStage.zip';
  my $scratchClonerStage = $scratchLocation . '/' . $clonerStageName;
  my $oracleHome = $ENV{"ORACLE_HOME"};
  my $clonerStageTop = $scratchLocation . '/ClonerStage';

  my @clonerStages = getClonerStageList($destHomeLocation);

  foreach my $cs (@clonerStages)
  {
    print("\n\n#####\n");
    chomp($cs);
    print("copy($cs, $scratchClonerStage)\n");
    copy($cs, $scratchClonerStage) == 1
      or abort("copying '$cs", $!, "$!");
    processClonerStage($destHomeLocation,
                       $destHomeName,
                       $scratchLocation,
                       $clonerStageName);

    if(!onWindows())
    {
    	addToOUIInv($destHomeLocation);
    }
    chdir($scratchLocation)
      or abort("cd to '$scratchLocation'", $!, "$!");
    removeDirTree($clonerStageTop);
  }
}

#
# prepare source home - make scratch dir, list excluded files, export home
#
sub prepareSourceHomeEx($$$$$$$$)
{
  my ($listExcludedFiles,   # 'true' if must list files to exclude from copy 
      $someDestsRemote,     # 'true' if some clone destinations on other hosts
      $sourceExcludes,      # patterns/files to exclude, e.g., '*.dbf, *.log'
      $scratchPath,         # path of source scratch dir, e.g., /tmp/oemchs123
      $homeLocation,        # source home dir, e.g., /private/ora10g
      $excludeListFile,     # file listing excluded files, e.g., /tmp/eList.txt
      $archiveFilePath,     # full path of home archive, e.g., /tmp/homeArchive
      $useZIP		    # TRUE/FALSE, if true use zip archive
      ) = @_;

  #run prepare_clone.pl only if not ias
  if(($ENV{'HOME_TYPE'} ne "ias") && ($ENV{'HOME_TYPE'} ne "crs") && ( -e File::Spec -> catfile ( $homeLocation, "clone", "bin", "prepare_clone.pl")))
  {
    print("chdir($homeLocation)\n");
    chdir($homeLocation) or abort("cd to '$homeLocation'", $!, "$!");
	echodo(getQuotedCommand($^X) . " " . getDirPath("clone", "bin", "prepare_clone.pl") . " ORACLE_HOME=\"$homeLocation\" 2>&1");
    checkOuiStatus($?, "prepare_clone.pl");
  }

  # if necessary, create temp working dir.  Highly unlikely,
  # but if a dir named this already exists, fail job
  if (($listExcludedFiles eq "true") ||
      ($someDestsRemote eq "true"))
  {
    makeNewDir($scratchPath);
  }

  # list excluded files if necessary
  if ($listExcludedFiles eq "true") 
  {
    listExcludedFiles(
      $homeLocation,
      $scratchPath,
      $excludeListFile,
      $sourceExcludes);
  }

  # export home if necessary
  if ($someDestsRemote eq "true")
  {
    exportHomeEx(
      $homeLocation,
      $archiveFilePath,
      $excludeListFile,
      $sourceExcludes,
      $useZIP);
  }
}

#
# prepare source home - make scratch dir, list excluded files, export home
#
sub prepareSourceHome($$$$$$$)
{
  my ($listExcludedFiles,   # 'true' if must list files to exclude from copy 
      $someDestsRemote,     # 'true' if some clone destinations on other hosts
      $sourceExcludes,      # patterns/files to exclude, e.g., '*.dbf, *.log'
      $scratchPath,         # path of source scratch dir, e.g., /tmp/oemchs123
      $homeLocation,        # source home dir, e.g., /private/ora10g
      $excludeListFile,     # file listing excluded files, e.g., /tmp/eList.txt
      $archiveFilePath      # full path of home archive, e.g., /tmp/homeArchive
      ) = @_;

  #run prepare_clone.pl only if not ias
  if(($ENV{'HOME_TYPE'} ne "ias") && ($ENV{'HOME_TYPE'} ne "crs") && ( -e File::Spec -> catfile ( $homeLocation, "clone", "bin", "prepare_clone.pl")))
  {
    print("chdir($homeLocation)\n");
    chdir($homeLocation) or abort("cd to '$homeLocation'", $!, "$!");
	echodo(getQuotedCommand($^X) . " " . getDirPath("clone", "bin", "prepare_clone.pl") . " ORACLE_HOME=\"$homeLocation\" 2>&1");
    checkOuiStatus($?, "prepare_clone.pl");
  }

  # if necessary, create temp working dir.  Highly unlikely,
  # but if a dir named this already exists, fail job
  if (($listExcludedFiles eq "true") ||
      ($someDestsRemote eq "true"))
  {
    makeNewDir($scratchPath);
  }

  # list excluded files if necessary
  if ($listExcludedFiles eq "true") 
  {
    listExcludedFiles(
      $homeLocation,
      $scratchPath,
      $excludeListFile,
      $sourceExcludes);
  }

  # export home if necessary
  if ($someDestsRemote eq "true")
  {
    exportHome(
      $homeLocation,
      $archiveFilePath,
      $excludeListFile,
      $sourceExcludes);
  }
}

#
# prepare AS source home - prepare_clone.pl, prepareSourceHome
#
sub prepareASSourceHome($$$$$$$$$)
{
  my ($listExcludedFiles,   # 'true' if must list files to exclude from copy 
      $someDestsRemote,     # 'true' if some clone destinations on other hosts
      $sourceExcludes,      # patterns/files to exclude, e.g., '*.dbf, *.log'
      $scratchPath,         # path of source scratch dir, e.g., /tmp/oemchs123
      $homeLocation,        # source home dir, e.g., /private/ora10g
      $oidAdmin,            # oid admin username(cn=orcladmin)
      $oidAdminPassword,    # oid admin password
      $excludeListFile,     # file listing excluded files, e.g., /tmp/eList.txt
      $archiveFilePath      # full path of home archive, e.g., /tmp/homeArchive
      ) = @_;

  if( -e File::Spec -> catfile ( $homeLocation, "clone", "bin", "prepare_clone.pl"))
  {
    # run prepareClone.pl
    # since double-quoting the commands in the echodo's fails, get the unzip dir
    # then chdir there in case path contains embedded blanks
    print("chdir($homeLocation)\n");
    chdir($homeLocation) or abort("cd to '$homeLocation'", $!, "$!");
    my $optional = ($oidAdminPassword ne "") ? "-oid_obf_password $oidAdminPassword -oid_admin $oidAdmin" : "";
    ##### TBD need to test with agent home location containing an embedded space
    echodo(getQuotedCommand($^X) . " " . getDirPath("clone", "bin", "prepare_clone.pl") . " ORACLE_HOME=\"$homeLocation\" $optional 2>&1");
    checkOuiStatus($?, "preparing source AS Home");
  }

  #set this so that prepare_clone not run again in prepareSourceHome
  $ENV{'HOME_TYPE'} = "ias";
  
  #call generic prepareSourceHome
  prepareSourceHome($listExcludedFiles, $someDestsRemote, $sourceExcludes, $scratchPath, $homeLocation, $excludeListFile, $archiveFilePath);
}
#
# prepare CRS source home - prepare_clone.pl, prepareSourceHome
#
sub prepareCRSSourceHomeEx($$$$$$$$)
{
  my ($listExcludedFiles,   # 'true' if must list files to exclude from copy 
      $someDestsRemote,     # 'true' if some clone destinations on other hosts
      $sourceExcludes,      # patterns/files to exclude, e.g., '*.dbf, *.log'
      $scratchPath,         # path of source scratch dir, e.g., /tmp/oemchs123
      $homeLocation,        # source home dir, e.g., /private/ora10g
      $excludeListFile,     # file listing excluded files, e.g., /tmp/eList.txt
      $archiveFilePath,      # full path of home archive, e.g., /tmp/homeArchive
      $useZIP				# TRUE/FALSE
      ) = @_;

  # run prepareClone.pl
  # since double-quoting the commands in the echodo's fails, get the unzip dir
  # then chdir there in case path contains embedded blanks
  print("chdir($homeLocation)\n");
  chdir($homeLocation) or abort("cd to '$homeLocation'", $!, "$!");

  ##### TBD need to test with agent home location containing an embedded space
  if( -e File::Spec -> catfile ( $homeLocation, "clone", "bin", "prepare_clone.pl"))
  {
	echodo(getQuotedCommand($^X) . " " . getDirPath("clone", "bin", "prepare_clone.pl") . " ORACLE_HOME=\"$homeLocation\" 2>&1");
	checkOuiStatus($?, "preparing source CRS Home");
  }

  #set this so that prepare_clone not run again in prepareSourceHome
  $ENV{'HOME_TYPE'} = "crs";
  
  #call generic prepareSourceHome
  prepareSourceHomeEx($listExcludedFiles, $someDestsRemote, $sourceExcludes, $scratchPath, $homeLocation, $excludeListFile, $archiveFilePath, $useZIP);
}

#
# prepare CRS source home - prepare_clone.pl, prepareSourceHome
#
sub prepareCRSSourceHome($$$$$$$)
{
  my ($listExcludedFiles,   # 'true' if must list files to exclude from copy
      $someDestsRemote,     # 'true' if some clone destinations on other hosts
      $sourceExcludes,      # patterns/files to exclude, e.g., '*.dbf, *.log'
      $scratchPath,         # path of source scratch dir, e.g., /tmp/oemchs123
      $homeLocation,        # source home dir, e.g., /private/ora10g
      $excludeListFile,     # file listing excluded files, e.g., /tmp/eList.txt
      $archiveFilePath      # full path of home archive, e.g., /tmp/homeArchive
      ) = @_;

  # run prepareClone.pl
  # since double-quoting the commands in the echodo's fails, get the unzip dir
  # then chdir there in case path contains embedded blanks
  print("chdir($homeLocation)\n");
  chdir($homeLocation) or abort("cd to '$homeLocation'", $!, "$!");

  ##### TBD need to test with agent home location containing an embedded space
  if( -e File::Spec -> catfile ( $homeLocation, "clone", "bin", "prepare_clone.pl"))
  {
	echodo(getQuotedCommand($^X) . " " . getDirPath("clone", "bin", "prepare_clone.pl") . " ORACLE_HOME=\"$homeLocation\" 2>&1");
	checkOuiStatus($?, "preparing source CRS Home");
  }

  #set this so that prepare_clone not run again in prepareSourceHome
  $ENV{'HOME_TYPE'} = "crs";
  
  #call generic prepareSourceHome
  prepareSourceHome($listExcludedFiles, $someDestsRemote, $sourceExcludes, $scratchPath, $homeLocation, $excludeListFile, $archiveFilePath);
}

#
# fix up 10.1.3.* AS homes
#
sub updateAS1013CloneHome($$$$$$)
{
	my ($destHomeLocation,  # dest home dir, e.g., /private/ora1012Clone
	  $destHomeName,        # dest home name, e.g., ora1012Clone
	  $scratchLocation,     # scratch dir, e.g., /tmp/oemchd123
	  $iasInstance,			# instance name
	  $oldOC4JAdminPassword,  # old oc4j admin password
	  $newOC4JAdminPassword  # new oc4j admin password
	) = @_;
  my $optional = "";
  $optional = $optional.(($oldOC4JAdminPassword ne "") ? " -oc4jadmin_obf_old_password $oldOC4JAdminPassword " : "");
  $optional = $optional.(($newOC4JAdminPassword ne "") ? " -oc4jadmin_obf_new_password $newOC4JAdminPassword " : "");

  runUpdateASCloneHomeSteps($destHomeLocation, $destHomeName, $scratchLocation, $iasInstance, $optional);
}

#
# fix up non-10.1.3.* AS homes e.g. Oracle AS 10.1.2
#
sub updateASCloneHome($$$$$$$)
{
	my ($destHomeLocation,  # dest home dir, e.g., /private/ora1012Clone
      $destHomeName,        # dest home name, e.g., ora1012Clone
	  $scratchLocation,     # scratch dir, e.g., /tmp/oemchd123
	  $iasInstance,			# instance name
	  $oldIASAdminPassword,  # old ias admin password
	  $newIASAdminPassword,  # new ias admin password
	  $oidAdminPassword,     # oid admin password
	  $dcmSchemaPassword,    # dcm schema password used for DB-based management of clusters
    ) = @_;
  #-ias_admin_obf_old_pwd oldIASAdminPassword -ias_admin_obf_new_pwd newIASAdminPassword -oid_obf_password oidPassword -dcm_schema_obf_pwd dcmSchemaPassword
  my $optional = "";
  $optional = ($oldIASAdminPassword ne " ") ? "-ias_admin_obf_old_pwd $oldIASAdminPassword " : "";
  $optional = $optional. (($newIASAdminPassword ne " ") ? "-ias_admin_obf_new_pwd $newIASAdminPassword " : "");
  $optional = $optional. (($oidAdminPassword ne "") ? "-oid_obf_password $oidAdminPassword " : "");
  $optional = $optional. (($dcmSchemaPassword ne "") ? "-dcm_schema_obf_pwd $dcmSchemaPassword " : "");

  runUpdateASCloneHomeSteps($destHomeLocation, $destHomeName, $scratchLocation, $iasInstance, $optional);
}

#
# run steps to fix up all kinds of AS homes.
#
sub runUpdateASCloneHomeSteps($$$$$)
{
  my ($destHomeLocation,    # dest home dir, e.g., /private/ora1012Clone
      $destHomeName,        # dest home name, e.g., ora1012Clone
      $scratchLocation,     # scratch dir, e.g., /tmp/oemchd123
      $iasInstance,         # instance name
      $additionalParameters # additional parameters to be passed to clone command line.
  ) = @_;

  # clear CONSOLE_CFG for the benefit of iasconsole
  delete($ENV{'CONSOLE_CFG'});
  delete($ENV{'EMSTATE'});

  # since double-quoting the commands in the echodo's fails, get the unzip dir
  # then chdir there in case path contains embedded blanks
  print("chdir($destHomeLocation)\n");
  chdir($destHomeLocation) or abort("cd to '$$destHomeLocation'", $!, "$!");

  if(onWindows()) {
  echodo(getQuotedCommand($^X). " " .getDirPath("clone", "bin", "clone.pl") . " ORACLE_HOME=\"$destHomeLocation\" ORACLE_HOME_NAME=\"$destHomeName\" -instance $iasInstance $additionalParameters \"-O-noconsole \" 2>&1");
  } 
  else {
  echodo(getQuotedCommand($^X). " " .getDirPath("clone", "bin", "clone.pl") . " ORACLE_HOME=\"$destHomeLocation\" ORACLE_HOME_NAME=\"$destHomeName\" -instance $iasInstance $additionalParameters 2>&1");
  }
  #echodo(getQuotedCommand($^X). " " .getDirPath("clone", "bin", "clone.pl") . " ORACLE_HOME=\"$destHomeLocation\" ORACLE_HOME_NAME=\"$destHomeName\" -instance $iasInstance $additionalParameters 2>&1");
  checkOuiStatus($?, "clone.pl");

  #Add the cloned home to OUIinventories
  if(!onWindows())
  {
	addToOUIInv($destHomeLocation);
  }

  # remove dest temp files
  chdir($destHomeLocation);
  removeDirTree($scratchLocation);
}

#
# fix up cloned RAC homes for DB 10g
#
sub updateRACCloneHome($$$$$$)
{
	my ($destHomeLocation,  # dest home dir, e.g., /private/ora1012Clone
      $destHomeName,        # dest home name, e.g., ora1012Clone
	  $scratchLocation,     # scratch dir, e.g., /tmp/oemchd123
	  $clusterNodes,		# all nodes of the RAC cluster
	  $destParams,        # user-supplied computeAtClone params & values
      $destParamsSecure   # secure user-supplied computeAtClone params & values
    ) = @_;

  #print "ClusterNodes:\{$clusterNodes\}\n";
  # add all the oui jars to classpath in case oui adds others in the future
  my $classPath = getClassPathWithJars("$destHomeLocation/oui/jlib", "true");
  $classPath .= "\"$destHomeLocation/jlib/emCfg.jar\"";
 
  if (!onWindows())
  {
    # NOTE: fix this for non-solaris platforms
    # TBD test embedded spaces in home location
    my $myplatform = "solaris";
    if ($^O eq "linux")
    {
      $myplatform = "linux";
    }
    $ENV{'LD_LIBRARY_PATH'} = "$destHomeLocation/oui/lib/$myplatform:" . "$ENV{'LD_LIBRARY_PATH'}";
    #print("\$ENV{'LD_LIBRARY_PATH'}=$ENV{'LD_LIBRARY_PATH'}\n");
  }

  # find dest home oui's jre and use its jre/bin/java to call oui updateHome()
  my $javaHome = getJavaHome($destHomeLocation);
  print("\nchdir($javaHome)\n");
  chdir($javaHome)
    or abort("cd to '$javaHome'", $!, "$!");
  my $d64_opt;   
  if(is64BitHybridJava($ENV{EMDROOT}))
  {
     $d64_opt = "-d64";
  }

  my $ouiLoc = "$destHomeLocation/oui";
  my $statusFilePath = $scratchLocation . '/updateHomeCompleted.txt';
  my $systemCommand="| " . getDirPath("bin", "java") . " $d64_opt -Doracle.installer.oui_loc=$ouiLoc -cp $classPath oracle.sysman.emd.ecm.clone.DestEnvironment -updateRacHome";
  print("\n$systemCommand\n");
  $! = 0;
  open(UPDATER, "$systemCommand") || abort("fork", $!, "$!");
  local $SIG{PIPE} = sub { abort("pipe", $!, "$!") };
  print UPDATER "$destHomeName\n";
  print UPDATER "$destHomeLocation\n";
  print UPDATER "\{$clusterNodes\}\n";
  print UPDATER "$destParams\n";
  print UPDATER "$destParamsSecure\n";
  print UPDATER "$statusFilePath\n";
  my $status = close UPDATER;
  my $updateStatus = $?;
  if (!$status)
  {
    if ($!)
    {
      #abort("updater process", $!, "$!");
      main::warning($!, "error closing pipe to updater process: $!");
    }
  }

  if (-e $statusFilePath)
  {
    # got through oui's updateHome(), check status from that
    checkOuiStatus($updateStatus, "update of rac home");
  }
  else
  {
    abort("update of home", $updateStatus >> 8, "$updateStatus >> 8");
  }

  #Add the cloned home to OUIinventories
  if(!onWindows())
  {
	addToOUIInv($destHomeLocation);
  }

  # remove dest temp files
  removeDirTree($scratchLocation);
}

#
# fix up cloned RAC homes for DB 10g, not used right now!
#
sub updateRACHome($$$$$$$)
{
	my ($destHomeLocation,  # dest home dir, e.g., /private/ora1012Clone
      $destHomeName,        # dest home name, e.g., ora1012Clone
      $scratchLocation,     # scratch dir, e.g., /tmp/oemchd123
      $clusterNodes,		# all nodes of the RAC cluster
      $localNode,           # local node which OUI uses
      $destParams,        # user-supplied computeAtClone params & values
      $destParamsSecure   # secure user-supplied computeAtClone params & values
    ) = @_;

	my $clonepl = File::Spec -> catfile ( $destHomeLocation, "clone", "bin", "clone.pl" );
	my $oui = "";
	if (!onWindows())
	{
		$oui = "runInstaller";
	}
	else
	{
		$oui = "setup.exe";
	}
	my $runInstaller = File::Spec -> catfile ( $destHomeLocation, "oui", "bin", "$oui" );
	
	#print("\n destParams-->$destParams\n");
  	#print("\n destParamsSecure-->$destParamsSecure\n");
  	#for oracle base bug fix
  	if (isEmpty($destParams)) {
  		$destParams = "";
  	}
  
  	if (isEmpty($destParamsSecure)) {
  		$destParamsSecure = "";
  	}
	
	if( -e $clonepl )
	{	
        #call clone.pl
        my $dir = File::Spec -> catfile ( $destHomeLocation, "clone", "bin");
        print("chdir($dir)\n");
        chdir($dir) or abort("cd to '$$dir'", $!, "$!");
        echodo(getQuotedCommand($^X) . " " . getDirPath("clone.pl") . " -waitForCompletion ORACLE_HOME=\"$destHomeLocation\" ORACLE_HOME_NAME=\"$destHomeName\" \"CLUSTER_NODES={$clusterNodes}\" LOCAL_NODE=$localNode $destParams $destParamsSecure 2>&1");
        checkOuiStatus($?, "clone.pl");
	}
    elsif ( -e $runInstaller )
    {
        my $ouiParams = "-clone -silent -waitForCompletion -noConfig";
        if (onWindows())
        {
            $ouiParams = "$ouiParams -nowait";
        }
        #call runInstaller
        my $dir = File::Spec -> catfile ( $destHomeLocation, "oui", "bin");
        print("chdir($dir)\n");
        chdir($dir) or abort("cd to '$$dir'", $!, "$!");
                
        #need to remove back slashes if calling from runInstaller directly
        $clusterNodes =~ s/\\//g;
        echodo(getDirPath($oui) . " $ouiParams ORACLE_HOME=\"$destHomeLocation\"  ORACLE_HOME_NAME=\"$destHomeName\" \"CLUSTER_NODES={$clusterNodes}\" LOCAL_NODE=$localNode $destParams $destParamsSecure 2>&1");
        checkOuiStatus($?, "$oui clone mode");
    }
    else
    {
        main::err(1, "$oui not found.");
    }
	
    # remove dest temp files
    chdir($destHomeLocation);
    removeDirTree($scratchLocation);
}

#
# method to run attachHome for a RAC Home (gpalrech)
#
sub attachHomeRACHome($$$$$)
{
   my (
      $destHomeLocation,  # dest home dir, e.g., /private/ora1012Clone
      $destHomeName,      # dest home name, e.g., ora1012Clone
      $scratchLocation,   # scratch dir, e.g., /tmp/oemchd123
      $clusterNodes,      # all nodes of the RAC cluster
      $localNode,         # local node which OUI uses
   ) = @_;

   my $oui = "";
   if (!onWindows())
   {
      $oui = "runInstaller";
   }
   else
   {
      $oui = "setup.exe";
   }
   my $runInstaller = File::Spec -> catfile ( $destHomeLocation, "oui", "bin", "$oui" );
	
   if ( -e $runInstaller )
   {
      my $ouiParams = "-attachHome -silent -waitForCompletion";
      if (onWindows())
      {
          $ouiParams = "$ouiParams -nowait";
      }
      #call runInstaller
      my $dir = File::Spec -> catfile ( $destHomeLocation, "oui", "bin");
      print("chdir($dir)\n");
      chdir($dir) or abort("cd to '$$dir'", $!, "$!");

      #need to remove back slashes if calling from runInstaller directly
      $clusterNodes =~ s/\\//g;
      $clusterNodes =~ s/\"//g;

      echodo(getDirPath($oui) . " $ouiParams ORACLE_HOME=\"$destHomeLocation\"  ORACLE_HOME_NAME=\"$destHomeName\" \"CLUSTER_NODES=$clusterNodes\" LOCAL_NODE=$localNode 2>&1");
      checkOuiStatus($?, "$oui clone (attachHome) mode");
  }
  else
  {
      main::err(1, "$oui not found.");
  }

  # remove dest temp files
  chdir($destHomeLocation);
  removeDirTree($scratchLocation);
}

sub getShortHostName()
{
	my $host = hostname;
    my ($short, $remain) = split("\\.", $host, 2);
	return $short;
}

#
# fix up cloned CRS homes for DB 10g
#
sub updateCRSHome($$$$$$$$$$$$$)
{
	my ($destHomeLocation,  # dest home dir, e.g., /private/ora1012Clone
      $destHomeName,        # dest home name, e.g., ora1012Clone
      $scratchLocation,     # scratch dir, e.g., /tmp/oemchd123
	  $extendMode,			# create or extend mode
      $hostnames,   		# all hostnames of the CRS cluster
      $clusterNodes,		# all nodes of the CRS cluster
	  $tableList,			# sl_tableList
	  $clusterName,			# name to register with em
	  $ocrLoc,				# OCR location
	  $vdiskLoc,			# Voting Disk location
      $localNode,           # local node which OUI uses
      $destParams,        # user-supplied computeAtClone params & values
      $destParamsSecure   # secure user-supplied computeAtClone params & values
    ) = @_;

	my $shortHostname = getShortHostName();
	my $createModeParams = "";
	my $extendModeParams = "";
	my $sourceTableList = "";
	if($extendMode eq "false") #create mode
	{
		$createModeParams = "n_storageTypeVDSK=2 n_storagetypeOCR=2 oracle.crs:s_clustername=\"$clusterName\"";
		if(onWindows())
		{ #this param is only required for windows for all nodes except the first.
			my $hostname = hostfqdn();
	                if ($hostnames !~ /^$hostname$/
        	            && $hostnames !~ /^$hostname,/)
                	{ #this node does not occur singly or before a comma.
                        	$createModeParams = "$createModeParams PERFORM_PARTITION_TASKS=FALSE";
                	}
		}
		else
		{ #add ocr/vdisk location for non-windows.
			$createModeParams = "$createModeParams s_ocrpartitionlocation=\"$ocrLoc\" s_votingdisklocation=\"$vdiskLoc\"";
		}
	}
	elsif(($extendMode eq "true") && onWindows())
	{ #this param is only required for windows
		$extendModeParams = "PERFORM_PARTITION_TASKS=FALSE";
	}
	
	if (isEmpty($destParams)) {
  		$destParams = "ORACLE_BASE=".$destHomeLocation;
  	}
  
  	if (isEmpty($destParamsSecure)) {
  		$destParamsSecure = "";
  	}
	
	my $cmdLine = " -waitForCompletion ORACLE_HOME=\"$destHomeLocation\" ORACLE_HOME_NAME=\"$destHomeName\" $createModeParams $extendModeParams \"sl_tableList={$tableList}\" ORACLE_HOSTNAME=$shortHostname $destParams $destParamsSecure -noConfig 2>&1";
	my $clonepl = File::Spec -> catfile ( $destHomeLocation, "clone", "bin", "clone.pl" );
	my $oui = "";
	if (!onWindows())
	{
		$oui = "runInstaller";
	}
	else
	{
		$oui = "setup.exe";
	}
	my $runInstaller = File::Spec -> catfile ( $destHomeLocation, "oui", "bin", "$oui" );
	
	if( -e $clonepl )
	{	
        #call clone.pl
        my $dir = File::Spec -> catfile ( $destHomeLocation, "clone", "bin");
        print("chdir($dir)\n");
        chdir($dir) or abort("cd to '$$dir'", $!, "$!");
        echodo(getQuotedCommand($^X) . " " . getDirPath("clone.pl") .$cmdLine );
        checkOuiStatus($?, "clone.pl");
	}
    elsif ( -e $runInstaller )
    {
        if (onWindows())
        {
            $cmdLine = " -nowait $cmdLine";
        }
        #call runInstaller
        my $dir = File::Spec -> catfile ( $destHomeLocation, "oui", "bin");
        print("chdir($dir)\n");
        chdir($dir) or abort("cd to '$$dir'", $!, "$!");
                
        echodo(getDirPath($oui) . " -clone -silent ". $cmdLine);
        checkOuiStatus($?, "$oui clone mode");
    }
    else
    {
        main::err(1, "$oui not found.");
    }

    #Add the cloned home to OUIinventories
    if(!onWindows())
    {
	     addToOUIInv($destHomeLocation);
    }

    # remove dest temp files
    chdir($destHomeLocation);
    removeDirTree($scratchLocation);
}

#
# updateNodeList on source RAC node to add new nodes to their node list
#
sub updateNodeList($$)
{
	my ($homeLocation,  # dest home dir, e.g., /private/ora1012Clone
        $nodes
    ) = @_;

  my $clonepl = File::Spec -> catfile ( $homeLocation, "clone", "bin", "clone.pl" );
  my $oui = "";
  if (!onWindows())
  {
	  $oui = "runInstaller";
  }
  else
  {
	  $oui = "setup.exe";
  }

  #call runInstaller
  my $dir = File::Spec -> catfile ( $homeLocation, "oui", "bin");
  print("chdir($dir)\n");
  chdir($dir) or abort("cd to '$$dir'", $!, "$!");

  #need to remove back slashes if calling from runInstaller directly
  my $ouiParams = "-updateNodeList -silent -waitForCompletion";
  if (onWindows())
  {
      $ouiParams = "$ouiParams -nowait";
  }
  $nodes =~ s/\\//g;
  echodo(getDirPath("$oui") . " $ouiParams ORACLE_HOME=\"$homeLocation\" \"CLUSTER_NODES={$nodes}\" 2>&1");
  checkOuiStatus($?, "$oui updateNodeList");
  
}

sub addNode($$$$)
{
	my ($homeLocation,
		$newNodes,
		$newPvtNodes,
		$newVips) = @_;

	my $addNode = "";
	my $checkfile = "";
	if (!onWindows())
	{
		$checkfile = File::Spec -> catfile ( $homeLocation, "install", "rootaddnode.sh");
		#Delete rootaddnode.sh if it exists
		unlink $checkfile ||  abort("Delete $checkfile", $!, "Unable to delete $checkfile file") ;
		$addNode = "addNode.sh";
	}
	else
	{
		$checkfile = File::Spec -> catfile ( $homeLocation, "install", "crssetup.add.bat");
		#Delete crssetup.add.bat if it exists
		unlink $checkfile ||  abort("Delete $checkfile", $!, "Unable to delete $checkfile file") ;
		$addNode = "addNode.bat -noRemoteActions -nowait";
	}
	
	#call addNode
	my $dir = File::Spec -> catfile ( $homeLocation, "oui", "bin");
	print("chdir($dir)\n");
	chdir($dir) or abort("cd to '$$dir'", $!, "$!");
	
	my $cmdLine = " -silent -noCopy \"CLUSTER_NEW_NODES={$newNodes}\" \"CLUSTER_NEW_PRIVATE_NODE_NAMES={$newPvtNodes}\" \"CLUSTER_NEW_VIRTUAL_HOSTNAMES={$newVips}\"  ";
	echodo(getDirPath($addNode) . $cmdLine);
	#checkOuiStatus($?, "$addNode"); returning exit status 255 even on success, as of on 18-may-2005

	#Non-existance of checkfile  is an indication of failure.
	abort("$cmdLine", -1, "Add node operation failed.") if (!-e $checkfile);

	#if windows, then run crssetup.add.set(Windows equivalent of rootaddnode.sh)
    if (onWindows())
	{
		$dir = File::Spec -> catfile ( $homeLocation, "install");
		print("chdir($dir)\n");
	    chdir($dir) or abort("cd to '$$dir'", $!, "$!");
		my $crssetup = "crssetup.add.bat";
		echodo(getDirPath($crssetup));
	}
}

#remmove this if not needed, was required to pass LOCAL_NODE to addnode.sh due to a bug which was fixed
sub getLocalNode($)
{
	my ($crsHome) = @_;
	my $localnode ;
	my $OLSNODES_CMD;
	if (onWindows())
	{
		$OLSNODES_CMD = File::Spec->catfile($crsHome, "bin", "olsnodes.exe -l");
	}
	else
	{
        	$OLSNODES_CMD = File::Spec->catfile($crsHome, "bin", "olsnodes -l");
	}
	my $pid = open (READ, " $OLSNODES_CMD |");
	my @array = <READ>;
	close READ;
	my $status = $?;
	if ($status != 0)
    	{
		abort();
    	}
	$localnode = $array[0];
	chomp($localnode);
	return $localnode;
}

#
# expand ClonerStage residing at scratchLocation, then invoke its clone.pl
#
sub processClonerStage($$$$)
{
  my ($destHomeLocation,    # dest home dir, e.g., /private/ora92Clone
      $destHomeName,        # dest home name, e.g., ora92Clone
      $scratchLocation,     # scratch dir, e.g., /tmp/oemchd123
      $clonerStageName      # scratch ClonerStage name, e.g., ClonerStage.zip
      ) = @_;

  my $scratchClonerStage = $scratchLocation . '/' . $clonerStageName;
  my $oracleHome = $ENV{"ORACLE_HOME"};
  my $clonerStageTop = $scratchLocation . '/ClonerStage';

  # since double-quoting the commands in the echodo's fails, get the unzip dir
  # then chdir there in case path contains embedded blanks
  print("chdir($oracleHome)\n");
  chdir($oracleHome)
    or abort("cd to '$oracleHome'", $!, "$!");
  echodo(getDirPath("bin", "unzip") . " -o -q \"$scratchClonerStage\" -d \"$scratchLocation\"") == 0
    or abort("expandClonerStage", $? >> 8, "$!");
  chdir($clonerStageTop)
    or abort("cd to '$clonerStageTop'", $!, "$!");
  ##### TBD need to test with agent home location containing an embedded space
  echodo(getQuotedCommand($^X) . " " . getDirPath("clone.pl") . " ORACLE_HOME=\"$destHomeLocation\" ORACLE_HOME_NAME=\"$destHomeName\" 2>&1");
  checkOuiStatus($?, "ClonerStage clone.pl");
}

#
# remove a directory tree and display count of files deleted
#
sub removeDirTree($)
{
  my ($dirPath, # directory path, e.g., /tmp/oemchd123
      ) = @_;

  print("\nrmtree($dirPath, 0, 0)\n");
  my $deletedCount = rmtree($dirPath, 0, 0);
  print("$deletedCount\n");
}

# Check if the user has read/write permission for the specified directory
# Return OK if the user has read/write permission, otherwise, return NOK.
# dirPermission(dirName)
sub dirPermission
{
  my ($dirName) = @_;
  if(! -r "$dirName")
  {
    EMD_PERL_DEBUG("ecmCloneHome.dirPermission(): UID $> does not have read permission for $dirName");
    return "NOK";
  }
  if(! -w _)
  {
    EMD_PERL_DEBUG("ecmCloneHome.dirPermission(): UID $> does not have write permission for $dirName");
    return "NOK";
  }
  
  EMD_PERL_DEBUG("ecmCloneHome.dirPermission(): UID $> has read/write permission for $dirName");
  
  return "OK";
}

# Check if the user has read/write permission for the multiple directories.
# Return an array containing OK and NOK.
# Flag OK is returned if user has read/write permission, otherwise, NOK is returned.
# dirsPermission(dirNameArray)
sub dirsPermission
{
  my ($dirNameArray) = @_;

  my @dirNames = split /$DELIMITER/, $dirNameArray;
  my $permissionStatus = "";
  my $dirNames;

  foreach $dirNames (@dirNames)
  {
    if(! -r "$dirNames")
    {
      EMD_PERL_DEBUG("ecmCloneHome.dirsPermission(): UID $> does not have read permission for $dirNames");
      $permissionStatus .= "NOK:";
    }
    elsif(! -w "$dirNames")
    {
      EMD_PERL_DEBUG("ecmCloneHome.dirsPermission(): UID $> does not have write permission for $dirNames");
      $permissionStatus .= "NOK:";
    }
    else
    {
      EMD_PERL_DEBUG("ecmCloneHome.dirsPermission(): UID $> has read/write permission for $dirNames");
      $permissionStatus .= "OK:";
    }
  }
  
  return $permissionStatus;
}

# --------- OS platform-specific (for "getFreeSpace" only) -------------

# Run command $df, the free space information shows at $row (usually the last
# row) and $column.  If the unit is K-bytes, $divide = 1, if bytes, $divide = 1024.
# paramForGetFreeSpace()
sub paramForGetFreeSpace
{
  my $df = ""; 
  my $row = "";
  my $column = "";
  my $divide = "";

  if($^O =~ /MSWin32/i)
  {
    EMD_PERL_DEBUG("ecmCloneHome.paramForGetFreeSpace(): OS platform: MSWin32");
    $ENV{dircmd}="";
    my $cmd = $ENV{ComSpec}." /c";
    $df = "$cmd dir /ad /-c";
    $row = -1;

    #For XP, 2000, 2003 etc.
    $column = 2;

    my $winVer= `ver`;
    if(($winVer =~ "NT"))
    {
      $column = 0;
    }
    
    $divide = 1024;
  }
  # This should cover all UNIX variants
  else #may be Unix
  {
    EMD_PERL_DEBUG("ecmCloneHome.paramForGetFreeSpace(): OS platform: UNIX");
    $df = "$DF .";
    $row = -1;
    $column = 3;
    $divide = 1;
  }

  return ($df, $row, $column, $divide);
}
# --------- OS platform-specific (END) -----------------------------------

# Check if a specified directory exists
# Return OK if the directory exists, otherwise, return NOK.
# dirExists(dirName)
sub dirExists
{
  my ($dirName) = @_;
  if(! -e "$dirName")
  {
    EMD_PERL_DEBUG("ecmCloneHome.dirExists(): Directory $dirName does not exist");
    return "NOK";
  }
  elsif(! -d "$dirName")
  {
    EMD_PERL_DEBUG("ecmCloneHome.dirExists(): $dirName is not a directory");
    return "NOK";
  }
  
  EMD_PERL_DEBUG("ecmCloneHome.dirExists(): Directory $dirName exists");
  
  return "OK";
}


# Find the nearest existing parent dir for a given dir.
# Return dir found, otherwise, return "".
# findNearestExistingParentDir(dirName)
sub findNearestExistingParentDir
{
  my ($dirName) = @_;
  EMD_PERL_DEBUG("ecmCloneHome.findNearestExistingParentDir(): Find nearest existing dir for $dirName");
  my $dirExist = &dirExists($dirName);
  if($dirExist eq "OK")
  {
    EMD_PERL_DEBUG("ecmCloneHome.findNearestExistingParentDir(): Directory $dirName already exists");
    return $dirName;
  }

  my($parent) = dirname($dirName);
  if($parent eq "/" || $parent =~ /:$/ || $parent eq "" || $parent eq ".")
  {
    return $parent;
  }
  
  while(! -e "$parent")
  {
    EMD_PERL_DEBUG("ecmCloneHome.findNearestExistingParentDir(): $parent does not exist");
    $parent = dirname($parent);
    if($parent eq "/" || $parent =~ /:$/ || $parent eq "" || $parent eq ".")
    {
      return $parent;
    }
  }

  return $parent;
}


# This method is platform specific, will be dealt with later.
# Get free space (KB) for a given directory
# getFreeSpace(dirName)
sub getFreeSpace
{
  my ($dirName) = @_;
  EMD_PERL_DEBUG("ecmCloneHome.getFreeSpace(): Passed in dir: $dirName");
  $dirName = &findNearestExistingParentDir($dirName);
  EMD_PERL_DEBUG("ecmCloneHome.getFreeSpace(): cd to the nearest existing parent dir: $dirName");
  chdir($dirName)
    or (((EMD_PERL_ERROR("ecmCloneHome.getFreeSpace(): chdir $dirName failed")) && return "-1") || (return "-1"));
  my $freeKB = 0;

  (my $df, my $row, my $column, my $divide) = &paramForGetFreeSpace();
  EMD_PERL_DEBUG("ecmCloneHome.getFreeSpace(): df: $df, row: $row, column: $column, divide: $divide");
  
  my @temp = `$df`;
  $_ = $temp[$row];
  my @tokens = split; 

  if(($^O !~ /MSWin32/i) && (@temp == 3)){
      EMD_PERL_DEBUG("\tdf output on three lines\n");
      $column = 2;
  }

  $freeKB = $tokens[$column]/$divide;
  
  if("$freeKB" eq "")
  {
    EMD_PERL_ERROR("ecmCloneHome.getFreeSpace(): Could not get free space: $!");
    $freeKB = -1;
  }
  
  EMD_PERL_DEBUG("ecmCloneHome.getFreeSpace(): Free space (KB) in $dirName: $freeKB");
  
  return $freeKB;
}

#
# pre-clone and/or fix up an ad-hoc-clonable home, e.g., rdbms 9.2.0.4.0 home
#
# WARNING: deletes the $scratchLocation directory tree.
#
sub updateAdHocClonable($$$$)
{
  my ($destHomeLocation, # dest home dir, e.g., /private/ora92Clone
      $destHomeName,     # dest home name, e.g., ora92Clone
      $scratchLocation,  # scratch dir, e.g., /tmp/oemchd123
      $clonerStageName   # scratch ClonerStage name, e.g., ClonerStage.zip
      ) = @_;

  my $scratchClonerStage = $scratchLocation . '/' . $clonerStageName;
  my $oracleHome = $ENV{"ORACLE_HOME"};
  my $clonerStageTop = $scratchLocation . '/ClonerStage';

  processClonerStage($destHomeLocation,
                     $destHomeName,
                     $scratchLocation,
                     $clonerStageName);

  #Add the cloned home to OUIinventories
  if(!onWindows())
  {
	addToOUIInv($destHomeLocation);
  }
  # remove dest temp files
  chdir($oracleHome);
  removeDirTree($scratchLocation);
}

#
# fix up a built-in-clonable home, e.g., an rdbms 10g home
#
# WARNING: deletes the $scratchLocation directory tree.
#
sub updateBuiltInClonable($$$$$)
{
  my ($destHomeLocation,  # dest home dir, e.g., /private/ora92Clone
      $destHomeName,      # dest home name, e.g., ora92Clone
      $scratchLocation,   # scratch dir, e.g., /tmp/oemchd123
      $clonerStageInHome, # 'true' if home has any ClonerStages
      $destParams,        # user-supplied computeAtClone params & values
      $destParamsSecure   # secure user-supplied computeAtClone params & values
      ) = @_;

  if (homeNeedsPreCloning($destHomeLocation))
  {
    if ($clonerStageInHome )
    {
      preCloneHome($destHomeLocation,
                   $destHomeName,
                   $scratchLocation);
    }
    else
    {
        main::warning(1, "pre-cloning required, but no ClonerStage in home");
    }
  }    
    
  my $clonepl = File::Spec -> catfile ( $destHomeLocation, "clone", "bin", "clone.pl");
  my $oui = "";
  if (!onWindows())
  {
      $oui = "runInstaller";
  }
  else
  {
      $oui = "setup.exe";
  }
  my $runInstaller = File::Spec -> catfile ( $destHomeLocation, "oui", "bin", "$oui");
  
  #print("\n destParams-->$destParams\n");
  #print("\n destParamsSecure-->$destParamsSecure\n");
  #print("\n clonepl-->$clonepl\n");
  #print("\n runInstaller-->$runInstaller\n");
  #for oracle base bug fix
  if (isEmpty($destParams)) {
  	$destParams = "";
  }
  
  if (isEmpty($destParamsSecure)) {
  	$destParamsSecure = "";
  }
  
  if( -e $clonepl )
  {	#call clone.pl
      my $dir = File::Spec -> catfile ( $destHomeLocation, "clone", "bin");
      print("chdir($dir)\n");
      chdir($dir) or abort("cd to '$$dir'", $!, "$!");
      echodo(getQuotedCommand($^X) . " " . getDirPath("clone.pl") . " -waitForCompletion ORACLE_HOME=\"$destHomeLocation\" ORACLE_HOME_NAME=\"$destHomeName\" $destParams $destParamsSecure 2>&1");
      checkOuiStatus($?, "clone.pl");
  }
  elsif ( -e $runInstaller )
  {
      my $ouiParams = "-clone -silent -waitForCompletion";
      if (onWindows())
      {
          $ouiParams = "$ouiParams -nowait";
      }
      #call runInstaller
      my $dir = File::Spec -> catfile ( $destHomeLocation, "oui", "bin");
      print("chdir($dir)\n");
      chdir($dir) or abort("cd to '$$dir'", $!, "$!");
      echodo(getDirPath($oui) . " $ouiParams ORACLE_HOME=\"$destHomeLocation\"  ORACLE_HOME_NAME=\"$destHomeName\" $destParams $destParamsSecure 2>&1");
      checkOuiStatus($?, "$oui clone mode");
  }
  else
  {
      # add all the oui jars to classpath in case oui adds others in the future
	  my $classPath = getClassPathWithJars("$destHomeLocation/oui/jlib", "true");
	  #print("\$classPath=$classPath\n");
      $classPath .= "\"$destHomeLocation/jlib/emCfg.jar\"";

	  if (!onWindows())
	  {
		# NOTE: fix this for non-solaris platforms
		# TBD test embedded spaces in home location
		my $myplatform = "solaris";
		if ($^O eq "linux")
		{
		  $myplatform = "linux";
		  $myplatform = "ia64linux" if ($Config{'archname'} =~ m/ia64-linux/);
		  $myplatform = "linuxS390" if ($Config{'archname'} =~ m/s390x-linux/);
		}
		$myplatform = "decunix" if ($^O eq "dec_osf");

		if ($^O eq "aix")
		{
		  $ENV{'LIBPATH'} = "$destHomeLocation/oui/lib/aix:" . "$ENV{'LIBPATH'}";
		}
		elsif ($^O eq "darwin")
		{
		  $ENV{'DYLD_LIBRARY_PATH'} = "$destHomeLocation/oui/lib/mac_osx:" . "$ENV{'DYLD_LIBRARY_PATH'}";
		}
		elsif ($^O eq "hpux")
		{
		  $myplatform = "hpunix";
		  $myplatform = "ia64hpunix" if ($Config{'archname'} =~ m/IA64/);
		  $ENV{'SHLIB_PATH'} = "$destHomeLocation/oui/lib/$myplatform:" . "$ENV{'SHLIB_PATH'}";
		}
		else
		{
		  $ENV{'LD_LIBRARY_PATH'} = "$destHomeLocation/oui/lib/$myplatform:" . "$ENV{'LD_LIBRARY_PATH'}";
		  #print("\$ENV{'LD_LIBRARY_PATH'}=$ENV{'LD_LIBRARY_PATH'}\n");
		}
	  }

	  # find dest home oui's jre and use its jre/bin/java to call oui updateHome()
	  my $javaHome = getJavaHome($destHomeLocation);
	  print("\nchdir($javaHome)\n");
	  chdir($javaHome)
		or abort("cd to '$javaHome'", $!, "$!");
 	   my $d64_opt;
           if(is64BitHybridJava($ENV{EMDROOT}))
           {
    	      $d64_opt = "-d64";
           }
	  my $statusFilePath = $scratchLocation . '/updateHomeCompleted.txt';
	  my $systemCommand="| " . getDirPath("bin", "java") . " $d64_opt -cp $classPath -Doracle.installer.oui_loc=\"$destHomeLocation/oui\" oracle.sysman.emd.ecm.clone.DestEnvironment -updateHome";
	  print("\n$systemCommand\n");
	  $! = 0;
	  open(UPDATER, "$systemCommand") || abort("fork", $!, "$!");
	  local $SIG{PIPE} = sub { abort("pipe", $!, "$!") };
	  print UPDATER "$destHomeName\n";
	  print UPDATER "$destHomeLocation\n";
	  print UPDATER "$destParams\n";
	  print UPDATER "$destParamsSecure\n";
	  print UPDATER "$statusFilePath\n";
	  my $status = close UPDATER;
	  my $updateStatus = $?;
	  if (!$status)
	  {
		if ($!)
		{
		  #abort("updater process", $!, "$!");
		  main::warning($!, "error closing pipe to updater process: $!");
		}
	  }

	  if (-e $statusFilePath)
	  {
		# got through oui's updateHome(), check status from that
		checkOuiStatus($updateStatus, "update of home");
	  }
	  else
	  {
		abort("update of home", $updateStatus >> 8, "$updateStatus >> 8");
	  }

  }

  #Add the cloned home to OUIinventories
  if(!onWindows())
  {
	addToOUIInv($destHomeLocation);
  }
  
  # remove dest temp files
  removeDirTree($scratchLocation);
}

#
# Get the IAS properties from an AS installation
# 
sub getIASProperties($)
{
	my ($homeLocation) = @_;
	my $iasPropLoc = File::Spec -> catfile ( $homeLocation, "config", "ias.properties" );
	my $properties = "";
	open (IASPROP, $iasPropLoc) || die ("Could not open ias.properties");
	{ 
		local $/;
		undef $/;
		$properties = <IASPROP>; 
	}
	close(IASPROP);
	print $properties;
	print "ClusterName=";
        # if 10.1.3 home, no cluster information can be retrieved since there is no dcmctl.
        if ($properties =~ /Version=10\.1\.3/)
        { # check if clone bits are present in home and return.
                print "\nCloneBitsPresent=";
                if (-f (File::Spec -> catfile ($homeLocation, "clone", "bin", "clone.pl"))
                   && (-f (File::Spec -> catfile ($homeLocation, "clone", "bin", "prepare_clone.pl"))))
                {
                        print "true";
                }
                else
                {
                        print "false";
                }
                return;
        }
	my $dcm = "";
	if(onWindows())
	{
		$dcm = "dcmctl.bat";
	}
	else
	{
		$dcm = "dcmctl";
	}
        system(File::Spec -> catfile ( $homeLocation, "dcm", "bin", "$dcm")." whichcluster");
	if($?)
	{
		main::warning($! ? $! : $?,
                 $! ? "dcm whichcluster failed: $!" :
                 "dcm whichcluster exited with: $?");
	}
}

#
# Execute dcm joinCluster, called from clone job
#
sub dcmJoinCluster($$$)
{
	my ($homeLocation,
		$joinCluster,
		$clusterName) = @_;

	my $dcm = "";
	if($joinCluster eq "true")
	{
		if(onWindows())
		{
			$dcm = "dcmctl.bat";
			echodo(File::Spec -> catfile ( $homeLocation, "dcm", "bin", $dcm)." joinCluster -v -script  $clusterName");
		}
		else
		{
			$dcm = "dcmctl";
		echodo(File::Spec -> catfile ( $homeLocation, "dcm", "bin", $dcm)." joinCluster $clusterName");
		}
		#echodo(File::Spec -> catfile ( $homeLocation, "dcm", "bin", $dcm)." joinCluster $clusterName");
		#return with exit status, so that step fails if command fails 
		exit($? >> 8);
	}
}

sub registerCRSTarget($$)
{
	my ($crsHome,
		$crsTargetName) = @_;
	my $emdroot = $ENV{EMDROOT};
	my $emctlCmd = "emctl";

	my $javaHome = getJavaHome($crsHome);
	print("\nchdir($javaHome)\n");
	chdir($javaHome)
		or abort("cd to '$javaHome'", $!, "$!");

	my $pathSep = "\":\"";
	if (onWindows())
	{
		$pathSep = "\";\"";
		$emctlCmd = "emctl.bat";
	}
	my $d64_opt;
        if(is64BitHybridJava($ENV{EMDROOT}))
        {
              $d64_opt = "-d64";
        }

	my $classpath = "\"".File::Spec -> catfile ( $emdroot, "jlib", "emConfigInstall.jar").$pathSep.File::Spec -> catfile ( $emdroot, "sysman", "jlib", "emcoreAgent.jar")."\"";

	my $regCommand = getDirPath("bin", "java") . " $d64_opt -cp $classpath -DORACLE_HOME=\"$emdroot\" oracle.sysman.emd.ecm.clone.RegCRSCloneTgt AGENT_HOME=\"$emdroot\" CRS_TARGET_NAME=\"$crsTargetName\" CRS_HOME=\"$crsHome\"";
	echodo($regCommand) == 0
        or abort("registerCRSTarget", $? >> 8, "$!");

	chdir($emdroot)
		or abort("cd to '$emdroot'", $!, "$!");

	echodo(getDirPath("bin", "$emctlCmd"). " reload");
	
}

sub addToOUIInv($)
{
   my ($oracleHome) = @_;
   my $oraInstLoc = File::Spec -> catfile ( $oracleHome, "oraInst.loc" );
   my $ouiAdd = "";
   if(-e $oraInstLoc)
   {
		$ouiAdd = File::Spec -> catfile ( $ENV{EMDROOT}, "sysman", "config", "OUIinventories.add" );
   open(OUIINV, ">>".$ouiAdd) || abort("open of '$ouiAdd'", $!, "$!");
   printf(OUIINV "\ninventory: %s\n", $oraInstLoc);
   close(OUIINV);  
   }

}

#is64BitHybridJava returns the following
# 1 in case ARU_ID has a platform which is 64 bit
#   and has a java which is hybrid
# 0 in case ARU_ID is a 32/64 bit which does not have hybrid java
# <0 in case oraclehomeproperties.xml file is not found.
sub is64BitHybridJava()
{
  my $oracleHome = shift;
  my $ohProp = "$oracleHome/inventory/ContentsXML/oraclehomeproperties.xml";

  my $platID;
  if ( open(OHPROP, "<$ohProp") )
  {
    my @arr = (<OHPROP>);
    close OHPROP;
    my $line = join('',@arr);
 
    if ($line =~ m/(.*?\s*\<ARU_ID\>\s*.*?)([^\s]+)(.*?\s*\<\/ARU_ID\>\s*.*?)$/s)
    {
    	$platID = $2;
    }

  }   
  else {
    return(0);
  }   
  # 23 = SOLARIS_SPARC64
  # 59 = HPUX_PARISC64
  # 197 = HPUX_IA64
  # 267 = SOLARIS x86-64
  if(($platID == 23) || ($platID == 59) || ($platID == 197) || ($platID == 267))
  {   
    return 1;
  }   
  else {
    return 0;
  }   
}    

sub updateNodeListDummy()
{
}
1;
