MINI MINI MANI MO

Path : /opt/oracle/product/18c/dbhomeXE/bin/
File Upload :
Current File : //opt/oracle/product/18c/dbhomeXE/bin/CommonSetup.pm

# 
# $Header: install/utl/scripts/db/CommonSetup.pm.pp /st_install_18.0/4 2018/08/31 12:22:26 poosrini Exp $
#
# CommonSetup.pm
# 
# Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
#
#    NAME
#      CommonSetup.pm - Common Setup perl module
#
#    DESCRIPTION
#      Contains the common code to launch the setup scripts.
#
#    MODIFIED   (MM/DD/YY)
#    poosrini    08/28/18 - Backport rfgonzal_dicdi2508 from main
#    rfgonzal    07/13/18 - DICDI2508 - Move rootPreCheck after getImageInfo
#    davjimen    12/07/17 - support orch tool launch
#    lorajan     09/15/17 - Adding mgmtua.jar in the classpath for mgmtua
#                           downgrade support.
#    rfgonzal    09/13/17 - bug 26788168 - rootpre.sh is not required for DB in
#                           Solaris
#    rfgonzal    08/30/17 - add image info
#    davjimen    08/23/17 - remove multiple slashes from oracle home path
#    davjimen    08/17/17 - remove destinationHome message
#    poosrini    08/01/17 - oraclepki
#    davjimen    07/10/17 - clear quotes from expansible args and set ours
#    davjimen    07/06/17 - support applyRU and applyRUR to apply PSU
#    davjimen    06/26/17 - bug 26351914 - create method to calculate 
#                           the temp log directory
#    davjimen    06/22/17 - add quotes to some args to not expand
#    davjimen    06/15/17 - lrg 20368653 - set oui library location
#    rtattuku    06/12/17 - Library version change from 12 to 18
#    vansoni     06/12/17 - -version support removed
#    davjimen    05/16/17 - add mgmtca and clscred jars to the classpath
#    apperuma    04/20/17 - Set printtime option if its passed
#    lorajan     03/22/17 - Adding pilot jar in the classpath.
#    davjimen    01/06/17 - Creation
# 
use Cwd qw(abs_path);
use File::Basename;
use File::Path qw(make_path remove_tree);
use File::Copy qw(cp mv);
use File::Find;
use Time::Piece;

package CommonSetup;
	
sub new {
	my $class = shift;
	my %params = @_;
	my $self = {
		"TYPE" => $params{"TYPE"},
		"PRODUCT_DESCRIPTION" => $params{"PRODUCT_DESCRIPTION"},
		"PRODUCT_JAR_NAME" => $params{"PRODUCT_JAR_NAME"},
		"SETUP_SCRIPTS" => $params{"SETUP_SCRIPTS"},
		"LOG_DIR_PREFIX" => $params{"LOG_DIR_PREFIX"},
		"MAIN_CLASS" => $params{"MAIN_CLASS"},
	};
	bless $self, $class;
	return $self;
}

# The current platform
my $PLATFORM=$^O;

# The architecture and the platform directory name
my ($ARCH,$PLATFORM_DIRECTORY_NAME) = &determinePlatformDirName();

# The ID of the user
my $ID = exists($ENV{ID}) ? $ENV{ID} : '/usr/bin/id';

# The user name
my $user;

# Flag to determine if the current platform is Windows
my $isWindows = ($PLATFORM =~ /.*MSWin.*/) ? 1 : 0;

# The directory separator
my $dirSep = '';

# The classpath separator
my $pathSep;

# The Oracle home path
my $ORACLE_HOME = "";

# The scratch path
my $scratchPath = "";

# The timestamp
my $timestamp = "";

# The temporary location
my $tmpLoc = "";

# The temporary log directory
my $tempLogDir = "";
	
# Path to the OUI platform directory
my $OUI_LIBRARY_LOCATION = "";

# Determine the classpath
my $classPath = "";

# Generic arguments
my $printTimeArg = "-printtime";
my $noWaitArg = "-nowait";
my $debugArg = "-debug";
my $javaDebugArg = "-javadebug";

# Pilot variables
my $launchPilot = "false";
my $pluginArg = "-plugin";

# Generic variables
my $printtime="-printtime";
my $noWait="false";
my $debug="false";
my $debugOpts='';
my $javadebug="false";
my $javadebugOpts='';
my $JAVA64FLAG='-d64';

# JRE location variables
my $JRELOC = "";
my $customJRE = 'false';
my $jreLocArg = '-jreLoc';

# define the patching variables
# PSU variables
my $patchTypePSU = '-applyPSU';
my $patchTypeRU = '-applyRU';
my $patchTypeRUR = '-applyRUR';
my $applyingPSU = 'false';
# OneOffs variables
my $patchTypeOneOffs = '-applyOneOffs';
my $applyingOneOffs = 'false';
# OPatch variables
my $updatingOpatch = 'false';
my $opatchLocArg = '-opatchLocation';
my $skipOpatchVersionArg = '-skipOpatchVersionCheck';
# Generic patch variables
my $patching = 'false'; # To deterine if a patch will be applied
my @patchArgs; # To carry all the patch related arguments passed.
my $applyInstallerUpdatesArg = "-applyInstallerUpdates";
my $applyingInstallerUpdates = 'false';
my $revertArg = "-revert";
my $revertingInstallerUpdate = 'false';
my $skipPatchStatusCheckArg = "-skipPatchStatusCheck";
my $skipPatchStatusCheck = 'false';

# bug 18154139 - support -J option (-J-m -J-D properties)
my @javaOptions;
my @remainingArgs;
my $javaOptionsSize = @ARGV;

# The destination oracle home path
my $dstoraclehome = "";
my $destinationHomeArg = "-destinationHome";

# The java binary
my $JAVACMD = "";

# bug 21613196 - wa for jdk bug 8060036
my $jdkBug8060036WA = ' -XX:-OmitStackTraceInFastThrow -XX:CompileCommand=quiet -XX:CompileCommand=exclude,javax/swing/text/GlyphView,getBreakSpot ';	

# The wizard command
my $wizardCmd = "";

# Image info variables
my $printImageInfoArg = "-printImageInfo";
my $printImageInfo = 'false';

# Exit code of the module
return 1;

sub main {
	my ($self, @args) = @_;
  
	# The directory separator
	$dirSep = $self->getDirSep();

	# The classpath separator
	if ($isWindows)  {
		$pathSep = ';';
	} else {
		$pathSep = ':';
	}

	# Determine the ORACLE_HOME
	$ORACLE_HOME = $self->determineOracleHome();

	# Root and Administrator user check
	$self->rootAndAdminUserCheck();

	# Parse the arguments
	$self->parseArgs();

	# Check if pilot is to be launched
	$self->checkPilotLaunch();

	# Check if its a change destination home action
	$self->changeDestinationHome();
	
	# Perform home ownership checks
	$self->homeOwnershipChecks();
	
	# The timestamp
	$timestamp = $self->calculateTimestamp();
	
	# The temporary location
	$tmpLoc = $self->calculateTempLoc();

	# The temporary log directory
	$tempLogDir = $self->calculateTempLogDir();
	
	# Create temporary log directory
	$self->createTempDirectory();
	
	# Get the JRE location
	$JRELOC = $ORACLE_HOME.$dirSep.'jdk'.$dirSep.'jre';

	# Path to the OUI platform directory
	$OUI_LIBRARY_LOCATION=$ORACLE_HOME.$dirSep.'oui'.$dirSep.'lib'.$dirSep.$PLATFORM_DIRECTORY_NAME;
	
	# Determine the classpath
	$classPath = $self->getClassPath();
	
	# Set env variables and library path
	$self->setLdLibraryPath($ORACLE_HOME);
	
	# bug 21020114 - add java memory options
	push(@javaOptions, "-Xms150m");
	# bug 21297469 - change memory to 2GB
	push(@javaOptions, "-Xmx2048m");
	
	# Get the java binary for the java command
	$JAVACMD = $self->getJavaCmd();
	
	# Print image info
	$self->getImageInfo();

	# Check the patch actions
	$self->checkPatchActions();
	
	# Unsetting ORA_CRS_HOME Env Variable.
	delete $ENV{ORA_CRS_HOME};

        # Root pre check
        $self->rootPreCheck();
	
	# Set the wizard command
	$wizardCmd = $self->setWizardCmd($self->{"MAIN_CLASS"});
	
	# Run the wizard command
	$self->runWizardCmd();
}

sub launchPilot() {
	my $self = shift;
	my $oracleHome = $ENV{ORACLE_HOME};
	
	my $pilotCmd = $oracleHome.$dirSep."install".$dirSep."pilot"." ".join(' ',@ARGV);
	my $pilotCode = $self->runCommand($pilotCmd);
	$self->terminate($pilotCode);
}

sub checkPilotLaunch() {
	my $self = shift;

	if($launchPilot eq "true") {
		$self->launchPilot();
	}
}

sub determineOracleHome() {
	my $self = shift;
	my $oracleHome = $ENV{ORACLE_HOME};
	
	# bug 26098267 - Remove multiple slashes in a row
	$oracleHome =~ s/[\/]+/\//g;
	
	# Re-set the ORACLE_HOME env variable
	$ENV{ORACLE_HOME} = $oracleHome;

	return $oracleHome;
}

sub calculateTempLogDir() {
	my $self = shift;
	return $tmpLoc.$dirSep.$self->{"LOG_DIR_PREFIX"}.$timestamp;
}

sub createTempDirectory() {
	mkdir($tempLogDir);
}

sub getDirSep() {
	my ($self, @args) = @_;
	my $sep = '';
	if ($isWindows)  {
		$sep = '\\';
	} else {
		$sep = '/';
	}
	return $sep;
}

sub determinePlatformDirName() {
	if($PLATFORM=~/.*hpux.*/) {
		$ARCH=`uname -m`;
		if($ARCH=~/.*ia64.*/) {
			$PLATFORM_DIRECTORY_NAME="hpia64";
		} else {
			$PLATFORM_DIRECTORY_NAME="hpunix";
		}
	} elsif($PLATFORM=~/.*aix.*/) {
		$PLATFORM_DIRECTORY_NAME="aix";
	} elsif($PLATFORM=~/.*linux.*/) {
		$ARCH=`uname -m`;
		if($ARCH=~/.*x86_64.*/) {
			$PLATFORM_DIRECTORY_NAME="linux64";
		} elsif($ARCH=~/.*ppc64.*/) {
			$PLATFORM_DIRECTORY_NAME="linuxppc64";
		} elsif($ARCH=~/.*s390x.*/) {
			$PLATFORM_DIRECTORY_NAME="linuxS390";
		} else {
			$PLATFORM_DIRECTORY_NAME="linux";
		}
	} elsif($PLATFORM=~/.*solaris.*/) {
		# bug 20399971 - use uname -p to get solaris architecture
		$ARCH=`uname -p`;
		if($ARCH=~/.*sparc.*/) {
			$PLATFORM_DIRECTORY_NAME="solaris";
		} else {
			$PLATFORM_DIRECTORY_NAME="intelsolaris";
		}
	} elsif($PLATFORM=~/.*MSWin.*/) {
		$PLATFORM_DIRECTORY_NAME="win64";
	}
	
	return($ARCH, $PLATFORM_DIRECTORY_NAME)
}

sub calculateTempLoc() {
	my $tmpLoc = $ENV{TEMP};
	if(! defined $tmpLoc or "$tmpLoc" eq "") {
		$tmpLoc = $ENV{TMP};
		if(! defined $tmpLoc or "$tmpLoc" eq "") {
			$tmpLoc = $ENV{TMPDIR};
			if(! defined $tmpLoc or "$tmpLoc" eq "") {
				if($PLATFORM=~/.*MSWin.*/) {
					$tmpLoc = 'C:'.$dirSep.'temp';
					} else {
					$tmpLoc = "/tmp";
				}
			}
		}
	}
	return $tmpLoc;
}

sub rootAndAdminUserCheck() {
	
	# Check is not root user
	if (! $isWindows) {
		my $id = `$ID`;
		$id =~ /.*?\((\w+)\).*/;
		$user = $1;
		
		# check for non-root user
		if ($user eq 'root') {
			print "\nERROR: You must not be logged in as root to run this tool.\n";
			exit 1;
		}
	}

	# check in windows if user is non-admin
	if ($isWindows) {
		require Win32;
		if(! Win32::IsAdminUser()) {
			print "\nERROR: You must be logged in as an Administrator user to run this tool.\n";
			exit 1;
		}
	}
}

sub getVersion() {
	my ($self, @args) = @_;

	my $jarName = $self->{"PRODUCT_JAR_NAME"};
	
	if($jarName) {
		# check all args and if -version or -v is there then show the version and exit immediately
		# don't proceed further
		my $versionExists = "false";
		for(my $cntval = 0; $cntval < @ARGV; $cntval++) {
			if(lc($ARGV[$cntval]) eq "-version" || lc($ARGV[$cntval]) eq "-v") {
				$versionExists ="true";
			}
		}
		if($versionExists eq "true") {
			# check for instcrs jar
			my $crs_jar_loc = $ENV{ORACLE_HOME}.$dirSep.'install'.$dirSep.'jlib'.$dirSep.$jarName;
			if (-f $crs_jar_loc){	
				my $unzip_loc = "";	 
				if ($isWindows)  {
					$unzip_loc = $ENV{ORACLE_HOME}.$dirSep.'bin'.$dirSep.'unzip.exe';
				} else {
					$unzip_loc = $ENV{ORACLE_HOME}.$dirSep.'bin'.$dirSep.'unzip';
				}
				
				my $manifestDir = 'META-INF'.$dirSep.'MANIFEST.MF';   
				my $jarManifestInfo = `$unzip_loc -p $crs_jar_loc $manifestDir`;
				
				# check for status of last executed cmd
				if(($? == -1) || ($jarManifestInfo eq '') || (not defined $jarManifestInfo) || ($jarManifestInfo =~ /^ *$/) || (
				$jarManifestInfo =~ /^\s*$/) ){
					print "\nERROR: Failed to retrive version info.\n";
					exit 1;
				} else {
					# remove unwanted new lines
					chomp($jarManifestInfo);
					
					# When we create a JAR file,
						# The manifest's entries take the form of "header: value" pairs.
					# The name of a header is separated from its value by a colon.
					my @values = split(':', $jarManifestInfo);
					
					# jarManifest value array not empty
					# the product version header is always be the last value
					if(@values){
						print "$values[-1]\n";
					}
					exit;
				}
			}
		}
	}
}

sub changeDestinationHome() {
	my ($self, @args) = @_;
	
	my $setupScripts = $self->{"SETUP_SCRIPTS"};
	
	if($setupScripts) {
		if($dstoraclehome) {

			my $setupScript;
			if($isWindows) {
				$setupScript = $dstoraclehome.$dirSep.(split(',', $setupScripts))[1];
			} else {
				$setupScript = $dstoraclehome.$dirSep.(split(',', $setupScripts))[0];
			}

			$|++; #autoflush stdout
			my $ohDir=$ENV{ORACLE_HOME};
			
			# Check that all the files from the source home are readable by the current user
			if(! $isWindows) {
				my $readAll=$self->areAllFilesReadable($ohDir);
				if("$readAll" eq "false") {
					print "ERROR: Unable to copy the software to the specified location ($dstoraclehome). Ensure user ($user) has read access over the source software home ($ohDir).\n";
					exit(-1);
				}
			}
			
			my $filecnt=0;
			if(-f $dstoraclehome){
				print "ERROR: Target location ($dstoraclehome) should not be a file.\n";
				exit(-1);
			}
			if(! -d $dstoraclehome) {
				File::Path::make_path($dstoraclehome) or die "mkdir failed: $!";
			} else{
				opendir(DIR, "$dstoraclehome") or die "Cant open $dstoraclehome: $!\n";
				my @files = readdir(DIR);
				closedir(DIR);
				if(@files){
					foreach (@files) {
						if( ("$_" ne ".") and ("$_" ne "..") ) {
							print "ERROR: Target location ($dstoraclehome) should be an empty directory.\n";
							exit(-1);
						}
					}
				}
			}
			
			# Check that the destinationHome is writable
			if(! -w "$dstoraclehome") {
				print "ERROR: Target location ($dstoraclehome) should be writable by user ($user).\n";
				exit(-1);
			}
			
			print "Copying files to $dstoraclehome...";
			File::Find::find(sub{
				# create all dirs
				my $dirpath=substr($File::Find::dir,length($ohDir)+1);
				if(! -d "$dstoraclehome/$dirpath"){
					File::Path::make_path("$dstoraclehome/$dirpath") or die "mkdir failed: $!\n";
				}
			},"$ohDir");
			File::Find::find(sub{
				#create links
				if( -l $File::Find::name ){
					my $rellinkpath=substr($File::Find::name,length($ohDir)+1);
					my $linkpath=readlink($File::Find::name);
					symlink($linkpath,"$dstoraclehome/$rellinkpath")or die "create symlink $dstoraclehome/$rellinkpath -> $linkpath failed: $!\n";
				} elsif( -f $File::Find::name ){
					# copy all files
					my $filepath=substr($File::Find::name,length($ohDir)+1);
					File::Copy::cp($File::Find::name,"$dstoraclehome/$filepath") or die "Copy of $File::Find::name to $dstoraclehome/$filepath failed: $!\n";
					$filecnt++;
					if($filecnt == 1000){
						print "."; # print a progress dot for every thousand files
						$filecnt=0; # reset counter
					}
				} elsif( -d $File::Find::name ) {
					# create left out empty dirs
					my $reldirpath=substr($File::Find::name,length($ohDir)+1);
					if(!-d "$dstoraclehome/$reldirpath"){
						File::Path::make_path("$dstoraclehome/$reldirpath") or die "mkdir of $dstoraclehome/$reldirpath failed: $!\n";
					}
				}
			},"$ohDir");
			print "\n"; # next line
			my $argcnt = @ARGV;
			my @newcmd;
			push(@newcmd,"$setupScript");

			for(my $cnt = 0; $cnt < $argcnt; $cnt++) {
				my $myarg = $ARGV[$cnt];
				if($myarg ne "-destinationHome") {
					#include for new cmd
					push(@newcmd,$myarg);
				} else{
					# ignore for new cmd
					if($cnt+1 < $argcnt and substr($ARGV[$cnt+1],0,1) ne "-"){
						$cnt++;
					}
				}
			}
			$SIG{CHLD} = 'IGNORE';
			unless ( fork() ) {
				#spawn setup
				print "Executing $newcmd[0]\n";
				exec(@newcmd);
				exit(0);
			}
			exit(0);
		}
	}
}

sub homeOwnershipChecks() {
	my ($self, @args) = @_;
	
	my $productDescription = $self->{"PRODUCT_DESCRIPTION"};
	
	if($productDescription) {
		# Home ownership checks
		if (! $isWindows) {
			# check current user owns OH
			# bug 20400258 - only allow home owner user to run the tool
			my $ohDir=$ENV{ORACLE_HOME};
			# check that OH path is a directory
			if(! -d $ohDir) {
				$self->showOwnerErrorAndExit();
			}  
			my $ohDirOwner='';
			# get the owner of the OH dir
			($ohDirOwner=getpwuid((stat($ohDir))[4])) or $self->showOwnerErrorAndExit();
			# check that owner of OH was set
			if($ohDirOwner eq '') {
				$self->showOwnerErrorAndExit();
			} 
			# check if the home owner is not root, which would be the case
			# if a cluster is already configured in it.
			if($ohDirOwner ne 'root') {
				# check that current user is owner of OH  
				if($user ne $ohDirOwner) {
					print "\nERROR: Unable to run the setup script as user ($user). Run the setup script from a location where the $productDescription software image is owned by user ($user).\n";
					exit 1;
				}
			} else {
				# case the OH is owned by root
				
				# bug 20802525 - if home already configured, check ownership of OH/oraInst.loc file
				my $oraInstloc="$ohDir/oraInst.loc";
				
				# check if the OH/oraInst.loc file exist
				if(! -e $oraInstloc) {
					# if it does not exist, the goldimage might have been unzipped with root
					print "\nERROR: Ensure that the $productDescription software image files at ($ohDir) are not owned by root.\n";
					exit 1;    
				}
				
				my $oraInstlocOwner='';
				# get the owner of the OH/oraInst.loc file
				($oraInstlocOwner=getpwuid((stat($oraInstloc))[4])) or $self->showOwnerErrorAndExit();
				# check that owner of OH/oraInst.loc was set
				if($oraInstlocOwner eq '') {
					$self->showOwnerErrorAndExit();
				}
				
				# check that current user is owner of OH/oraInst.loc 
				if($oraInstlocOwner ne 'root') {
					if($user ne $oraInstlocOwner) {
						print "\nERROR: You must be logged in as user ($oraInstlocOwner) to run this tool.\n";
						exit 1;
					}
				} else {
					$self->showOwnerErrorAndExit();
				}
			}
		}
	}
}
	
sub rootPreCheck() {
	my ($self, @args) = @_;

	# add rootpre.sh requirement
	if(! $isWindows) {
		# bug 21973856 - use a script to determine if rootpre is required
		# bug 26788168 - rootpre.sh is not required for DB in Solaris
		my $rootPreReqCmd = $ENV{ORACLE_HOME}.$dirSep.'bin'.$dirSep.'rootPreRequired.sh '.$self->{"TYPE"}.' '.join(' ',@ARGV);
		my $showRootPre = `$rootPreReqCmd`;
		chomp($showRootPre); 
		if($showRootPre eq "true") {
			print "\n********************************************************************************\n\n";
			print "Your platform requires the root user to perform certain pre-installation\n";
			print "OS preparation.  The root user should run the shell script 'rootpre.sh' before\n";
			print "you proceed with Oracle installation. The rootpre.sh script can be found at:\n";
			print $ENV{ORACLE_HOME}.$dirSep.'clone'.$dirSep.'rootpre.sh';
			print "\n\nAnswer 'y' if root has run 'rootpre.sh' so you can proceed with Oracle\n";
			print "installation.\n";
			print "Answer 'n' to abort installation and then ask root to run 'rootpre.sh'.\n";
			print "\n********************************************************************************\n\n";
			print "Has 'rootpre.sh' been run by root in this machine? [y/n] (n)\n";
			# read user input
			my $userInput = <STDIN>;
			# remove leading new line char
			chomp($userInput);
			# trim blank spaces
			$userInput =~ s/^\s+//;
			$userInput =~ s/\s+$//;
			if ( !(lc($userInput) eq "y") ) {
				print "Installation stopped to run 'rootpre.sh' by root.\n";
				exit 1;
			}
		}
	}
}	

sub calculateTimestamp() {
	# Calculate the timestamp, temp dir and templogdir location
	my $timestamp = Time::Piece::localtime->strftime('%Y-%m-%d_%H-%M-%S');
	# Get the 24 hr format string (00 - 23)
	my $hour = substr($timestamp, 11, 2);
	my $AMPM = 'PM';
	# If the hr starts with 0 or is 10 or 11, its AM
	if(substr($hour, 0, 1) eq '0' or $hour eq '10' or $hour eq '11') {
		$AMPM = 'AM';
	} else {
		# For PM case, we need to convert the 24 hr string into 12 hr format (00-12), for this
		# we keep the hr string if it is already 12, for any other case we get the modulo 12
		if($hour ne '12') {
			$hour = ($hour % 12);
		}
		# If the hr string ends up with one char after the modulo operation, add a 0 in front  
		if(length($hour) == 1) {
			$hour = '0'.$hour;
		}
	}
	# Reconstruct the timestamp by replacing the hour string and appending the AM/PM
	$timestamp = substr($timestamp,0,11).$hour.substr($timestamp, 13).$AMPM;
	return $timestamp;
}

sub getClassPath() {
	my ($self, @args) = @_;
	
	# Path to the OUI Scripts directory
	my $OUI_Scripts=$ORACLE_HOME.$dirSep.'inventory'.$dirSep.'Scripts';
	
	# Path to the OUI Scripts ext jlib directory
	my $extjlib_dir=$OUI_Scripts.$dirSep.'ext'.$dirSep.'jlib'.$dirSep;
	
	# set scratchPath as OH/inventory/Scripts
	$scratchPath=$OUI_Scripts;

	# include jars in classpath
	my @INSTALL_JARS_LIST=($ORACLE_HOME.$dirSep.'install'.$dirSep.'jlib'.$dirSep.'installcommons_1.0.0b.jar',
	$ORACLE_HOME.$dirSep.'install'.$dirSep.'jlib'.$dirSep.'instcommon.jar', 
	$ORACLE_HOME.$dirSep.'install'.$dirSep.'jlib'.$dirSep.'instcrs.jar',
	$ORACLE_HOME.$dirSep.'install'.$dirSep.'jlib'.$dirSep.'pilot_1.0.0b.jar',
	$ORACLE_HOME.$dirSep.'install'.$dirSep.'jlib'.$dirSep.'instdb.jar');
	
	# Check if the install jars exist
	my @INSTALL_JARS;
	for my $installJar (@INSTALL_JARS_LIST) {
		if(-e $installJar) {
			push(@INSTALL_JARS, $installJar);
		}
	}

	# bug 21277531 - include srvmhas.jar and gns.jar into the classpath
	# bug 20676526 - load srvm.jar from OH/jlib
	my @EXT_JARS=($ORACLE_HOME.$dirSep.'jlib'.$dirSep.'cvu.jar',
	$ORACLE_HOME.$dirSep.'jlib'.$dirSep.'srvmhas.jar',
	$ORACLE_HOME.$dirSep.'jlib'.$dirSep.'srvmasm.jar',
	$ORACLE_HOME.$dirSep.'jlib'.$dirSep.'gns.jar',
	$ORACLE_HOME.$dirSep.'jlib'.$dirSep.'srvm.jar',
	$ORACLE_HOME.$dirSep.'jlib'.$dirSep.'oraclepki.jar',
        $ORACLE_HOME.$dirSep.'jlib'.$dirSep.'mgmtca.jar',
        $ORACLE_HOME.$dirSep.'jlib'.$dirSep.'mgmtua.jar',
        $ORACLE_HOME.$dirSep.'jlib'.$dirSep.'clscred.jar',
	$ORACLE_HOME.$dirSep.'jlib'.$dirSep.'oracle.dbtools-common.jar',
	$ORACLE_HOME.$dirSep.'jlib'.$dirSep.'wsclient_extended.jar',
	$ORACLE_HOME.$dirSep.'jlib'.$dirSep.'adf-share-ca.jar',
	$ORACLE_HOME.$dirSep.'jlib'.$dirSep.'jmxspi.jar',
	$ORACLE_HOME.$dirSep.'jlib'.$dirSep.'emca.jar',
	$ORACLE_HOME.$dirSep.'jlib'.$dirSep.'entityManager_proxy.jar',
	$ORACLE_HOME.$dirSep.'jlib'.$dirSep.'javax.security.jacc_1.0.0.0_1-1.jar',
	$ORACLE_HOME.$dirSep.'jlib'.$dirSep.'orai18n-mapping.jar',
	$ORACLE_HOME.$dirSep.'jlib'.$dirSep.'orai18n-utility.jar',
	$ORACLE_HOME.$dirSep.'jdbc'.$dirSep.'lib'.$dirSep.'ojdbc8.jar',
	$ORACLE_HOME.$dirSep.'OPatch'.$dirSep.'jlib'.$dirSep.'opatchsdk.jar',
	$ORACLE_HOME.$dirSep.'OPatch'.$dirSep.'jlib'.$dirSep.'opatch.jar',
	$ORACLE_HOME.$dirSep.'oui'.$dirSep.'jlib'.$dirSep.'OraPrereqChecks.jar',
	$ORACLE_HOME.$dirSep.'oui'.$dirSep.'jlib'.$dirSep.'prov_fixup.jar',
	$ORACLE_HOME.$dirSep.'oui'.$dirSep.'jlib'.$dirSep.'ssh.jar',
	$ORACLE_HOME.$dirSep.'oui'.$dirSep.'jlib'.$dirSep.'jsch.jar',
	$ORACLE_HOME.$dirSep.'oui'.$dirSep.'jlib'.$dirSep.'remoteinterfaces.jar',
	$ORACLE_HOME.$dirSep.'oui'.$dirSep.'jlib'.$dirSep.'OraPrereq.jar');
	foreach my $extjar(@EXT_JARS){
		$self->addJarToClassPath($extjar,\@INSTALL_JARS);
	}

	# bug 21822387 - these jars need to be before oui/jlib jars
	# include all jars of inventory/Scripts/ext/jlib in classpath
	opendir(DIR,$extjlib_dir) || die "can't opendir $extjlib_dir: $!";
	foreach my $file(readdir(DIR)){
		if (! -d $file) {
			chomp($file);
			$self->addJarToClassPath($extjlib_dir.$file, \@INSTALL_JARS);
		}
	}
	closedir DIR;

	# include all jars of oui/jlib in classpath
	my $ouijlib_dir=$ORACLE_HOME.$dirSep.'oui'.$dirSep.'jlib'.$dirSep;
	opendir(DIR,$ouijlib_dir) || die "can't opendir $ouijlib_dir: $!";
	foreach my $file(readdir(DIR)){
		if (! -d $file) {
			chomp($file);
			$self->addJarToClassPath($ouijlib_dir.$file, \@INSTALL_JARS);
		}
	}
	close(DIR);

	return join($pathSep,@INSTALL_JARS);
}

sub parseArgs() {
	my ($self, @args) = @_;
	
	for(my $count = 0; $count < $javaOptionsSize; $count++) {
		my $javaOption = $ARGV[$count];
		my $firstTwoChars = substr($javaOption, 0, 2);
		if($firstTwoChars eq "-J") {
			push(@javaOptions, substr($javaOption,2));
		} elsif(lc($javaOption) eq lc($pluginArg)) {
			$launchPilot="true";
			last;
		} elsif(lc($javaOption) eq lc($printTimeArg)) {
			$printtime="-printtime";
		} elsif(lc($javaOption) eq lc($noWaitArg)) {
			$noWait="true";
		} elsif(lc($javaOption) eq lc($debugArg)) {
			$debug="true";
			$debugOpts=' -DTRACING.LEVEL=2 -DTRACING.ENABLED=TRUE ';
			push(@remainingArgs, $javaOption);
		} elsif(lc($javaOption) eq lc($javaDebugArg)) {
			$javadebug="true";
			$javadebugOpts = " -Xdebug -agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=8001 ";
		} elsif(lc($javaOption) eq lc($applyInstallerUpdatesArg)){
			if($applyingInstallerUpdates eq 'true') {
				$self->repetitiveArgsError($applyInstallerUpdatesArg);
			}
			$applyingInstallerUpdates = 'true';
			push(@patchArgs, $javaOption);
			$patching = 'true';
			# do not pass -applyInstallerUpdates to java cmd
				# also skip next param only if it doesn't start with "-"
			# i.e. skip if it is a a value and not another param
			if($count+1 < $javaOptionsSize and substr($ARGV[$count+1],0,1) ne "-"){
				$count++;
				push(@patchArgs, $ARGV[$count]);
			}
		} elsif(($javaOption eq $patchTypePSU) or ($javaOption eq $patchTypeRU) or ($javaOption eq $patchTypeRUR)) {
			if($applyingPSU eq 'true') {
				# The argument was already passed
				$self->repetitiveArgsError($patchTypePSU);
			}
			push(@patchArgs, $javaOption);
			# this block takes out the apply arguments from the java cmd
			# set $patching as true
			$patching = 'true';
			$applyingPSU = 'true';
			# get the next arg value as the path with the patch
			if($count+1 < $javaOptionsSize and substr($ARGV[$count+1],0,1) ne "-"){
				$count++;
				push(@patchArgs, $ARGV[$count]);
			}
		} elsif($javaOption eq $patchTypeOneOffs) {
			if($applyingOneOffs eq 'true') {
				# The argument was already passed
				$self->repetitiveArgsError($patchTypeOneOffs);
			}
			push(@patchArgs, $javaOption);
			# this block takes out the apply arguments from the java cmd
			# set $patching as true
			$patching = 'true';
			$applyingOneOffs = 'true';
			# get the next arg value as the path with the patch
			if($count+1 < $javaOptionsSize and substr($ARGV[$count+1],0,1) ne "-"){
				$count++;
				push(@patchArgs, $ARGV[$count]);
			}
		} elsif($javaOption eq "-skipRemoteCopy") {
			# bug 22147365 - enable skipRemoteCopy flag
			push(@remainingArgs, "-noCopy -nolink");
		} elsif(($javaOption =~ /^ORACLE_HOME=/) or ($javaOption =~ /^-ORACLE_HOME$/)) {
			# The ORACLE_HOME argument or option was passed
			my $rightOHCmdline = "true";
			my $OHcmdline = "";
			if($javaOption =~ /^ORACLE_HOME=/) {
				# Option case: 'ORACLE_HOME=value'
				$OHcmdline = (split('=', $javaOption))[1];
			} elsif($javaOption =~ /^-ORACLE_HOME$/) {
				# Argument case: '-ORACLE_HOME value'
				if($count+1 < $javaOptionsSize and substr($ARGV[$count+1],0,1) ne "-"){
					$count++;
					$OHcmdline = $ARGV[$count];
				}
			}
			
			if("$OHcmdline" ne "") {
				if(length($OHcmdline) > 1) {
					# Remove the trailing slash if existent
					if($OHcmdline =~ /$dirSep$/) {
						$OHcmdline = substr($OHcmdline, 0, length($OHcmdline)-1);
					}
				}
				# Check if the OH provided in the cmdline matches the one detected by the Setup script.
				if($OHcmdline ne $ORACLE_HOME) {
					$rightOHCmdline = "false";
				}
			} else {
				$rightOHCmdline = "false";
			}
			
			if($rightOHCmdline eq "false") {
				print("ERROR: The installer has detected that the Oracle home location provided in the command line is not correct. The Oracle home is the location from where setup script is executed.\n\nIt is not required to specify ORACLE_HOME in the command line for the installation.\n");
				exit(1);
			}
		} elsif($javaOption eq $opatchLocArg) {
			if($updatingOpatch eq 'true') {
				# The argument was already passed
				$self->repetitiveArgsError($opatchLocArg);
			}
			push(@patchArgs, $javaOption);
			$patching = 'true';
			$updatingOpatch = 'true';
			# get the next arg value as the opatch location
			if($count+1 < $javaOptionsSize and substr($ARGV[$count+1],0,1) ne "-"){
				$count++;
				push(@patchArgs, $ARGV[$count]);
			}
		} elsif($javaOption eq $skipOpatchVersionArg) {
			push(@patchArgs, $javaOption);
		} elsif($javaOption eq $revertArg) {
			$revertingInstallerUpdate = 'true';
			push(@patchArgs, $javaOption);
		} elsif(lc($javaOption) eq lc($jreLocArg)) {
			# Get the next arg as the custom JRE location
			if($count+1 < $javaOptionsSize and substr($ARGV[$count+1],0,1) ne "-"){
				$customJRE = 'true';
				$count++;
				$JRELOC = $ARGV[$count];
			}
		} elsif(lc($javaOption) eq lc($skipPatchStatusCheckArg)) {
			$skipPatchStatusCheck = 'true';
		} elsif(lc($javaOption) eq lc($destinationHomeArg)) {
			# Get the next arg as the destination home
			if($count+1 < $javaOptionsSize and substr($ARGV[$count+1],0,1) ne "-"){
				$count++;
				$dstoraclehome = $ARGV[$count];
			}
		} elsif($javaOption =~ /\{/ || $javaOption =~ /\*/) {
			# lrg 20441240 - Clear any pre-existing quote
			$javaOption =~ s/'//g;
			$javaOption =~ s/"//g;

			# Add quotes to avoid expansion
			push(@remainingArgs, "'".$javaOption."'");
		} elsif(lc($javaOption) eq lc($printImageInfoArg)) {
                        $printImageInfo = 'true';
		} else {
			push(@remainingArgs, $javaOption);
		}
	}
}

sub getJavaCmd() {
	#Adding the -d64 flag for java command on hybrid unixplatforms.
	if( $PLATFORM=~ /.*solaris.*/ || $PLATFORM=~ /.*hpux.*/ || $PLATFORM=~ /.*aix.*/ ){
		return $JRELOC.$dirSep.'bin'.$dirSep.'java'.' '.$JAVA64FLAG;
	}else{
		return $JRELOC.$dirSep.'bin'.$dirSep.'java';
	}
}

sub getImageInfo() {
	my ($self, @args) = @_;
	
	#Check if image info should be printed out	
	if($printImageInfo eq 'true') {
                my $imageInfoCmd = $JAVACMD.' -cp '.$classPath.' oracle.install.library.util.imageinfo.ImageInfoUtil '.$ORACLE_HOME;
                my $imageInfoOut = qx{$imageInfoCmd};
                my $checkImageInfoStatusCode = $?;
                if($imageInfoOut ne ""){
                        print "\n$imageInfoOut\n";
                }
                $self->terminate($checkImageInfoStatusCode);
        }

}
	
sub checkPatchActions() {
	my ($self, @args) = @_;
	
	# Check for the patch status
	$self->checkPatchStatus();

	# Check patch revert action
	$self->checkPatchRevert();
	
	# Check patch action
	$self->checkPatchAction();
}
	
sub checkPatchStatus() {
	my ($self, @args) = @_;
	
	# Check patch status
	if($skipPatchStatusCheck eq 'false') {
		my $checkPatchStatusCmd = $JAVACMD.' -cp '.$classPath.' '.join(' ',@javaOptions).' oracle.install.ivw.common.driver.InstallerPatchDriver '.$self->{LOG_DIR_PREFIX}.' '.$ORACLE_HOME.' -status -timestamp '.$timestamp.' -tempLocation '.$tempLogDir;
		my $checkPatchStatusOut = qx{$checkPatchStatusCmd};
		my $checkPatchStatusCode = $?;
		if($checkPatchStatusCode ne "0" and $revertingInstallerUpdate eq 'false') {
			print "\n$checkPatchStatusOut\n";
			$self->terminate($checkPatchStatusCode);
		}
	}
}

sub checkPatchRevert() {
	my ($self, @args) = @_;
	
	# Check if its a revert action
	if($revertingInstallerUpdate eq 'true') {
		my ($tempHome, $newJavaBinary,$newClassPath) = $self->bootstrap();
		
		if( $PLATFORM=~ /.*solaris.*/ || $PLATFORM=~ /.*hpux.*/ || $PLATFORM=~ /.*aix.*/ ){
			$newJavaBinary = $newJavaBinary.' '.$JAVA64FLAG;
		}
		
		my $ouiLoc = '-Doracle.installer.oui_loc='.$ORACLE_HOME.$dirSep.'oui';
		
		my $revertInstallerPatchCmd = $newJavaBinary.' -cp '.$newClassPath.$javadebugOpts.' '.join(' ',@javaOptions).' '.$ouiLoc.' -Djava.util.logging.FileHandler.append=true oracle.install.ivw.common.driver.InstallerPatchDriver '.$self->{LOG_DIR_PREFIX}.' '.$ORACLE_HOME.' -revert -timestamp '.$timestamp.' -tempLocation '.$tempLogDir;
		my $revertInstallerPatchCode = $self->runCommand($revertInstallerPatchCmd);
		
		File::Path::remove_tree($tempHome);
		
		$self->terminate($revertInstallerPatchCode);
	}
}

sub checkPatchAction() {
	my ($self, @args) = @_;
	
	# Check if its a patch action
	if($patching eq 'true') {
		
		my ($tempHome, $newJavaBinary,$newClassPath) = $self->bootstrap();
		
		if( $PLATFORM=~ /.*solaris.*/ || $PLATFORM=~ /.*hpux.*/ || $PLATFORM=~ /.*aix.*/ ){
			$newJavaBinary = $newJavaBinary.' '.$JAVA64FLAG;
		}
		
		my $ouiLoc = '-Doracle.installer.oui_loc='.$ORACLE_HOME.$dirSep.'oui';
		
		my $debugFlag = '';
		if($debug) {
			$debugFlag = '-debug';
		}  
		
		my $installerPatchCmd = $newJavaBinary.' -cp '.$newClassPath.$javadebugOpts.' '.join(' ',@javaOptions).' '.$ouiLoc.' -Djava.util.logging.FileHandler.append=true oracle.install.ivw.common.driver.InstallerPatchDriver '.$self->{LOG_DIR_PREFIX}.' '.$ORACLE_HOME.' '.$debugFlag.' -timestamp '.$timestamp.' -tempLocation '.$tempLogDir.' '.join(' ',@patchArgs);
		my $installerPatchCode = $self->runCommand($installerPatchCmd);
		
		File::Path::remove_tree($tempHome);
		
		if($installerPatchCode ne "0") {
			$self->terminate($installerPatchCode);
		}
	}
}

sub setWizardCmd() {
	my $self = shift;
	my $mainClass = shift;
	
	# java cmd to launch
	return $JAVACMD.' -cp '.$classPath.$debugOpts.$javadebugOpts.$jdkBug8060036WA.' -Doracle.installer.library_loc='.$OUI_LIBRARY_LOCATION.' -Djava.io.tmpdir='.$tempLogDir.' -Doracle.installer.timestamp='.$timestamp.' -Doracle.installer.tempLogDir='.$tempLogDir.' -Doracle.installer.scratchPath='.$scratchPath.' -DORACLE_HOME='.$ORACLE_HOME.' '.join(' ',@javaOptions).' -Xdebug '.$self->{"MAIN_CLASS"}.' '.$printtime.' ORACLE_HOME='.$ORACLE_HOME.' '.join(' ',@remainingArgs);
}

sub runWizardCmd() {
	#Check for writability permission for system preference files. (bug #10041861)
	#if files don't have writable permission then add the writable permission.
	#remove added writable permission at the end.
	my $systemLockFilePermissionAdded='0';
	my $systemRootModeFilePermissionAdded='0';
	my $systemLockFile=$JRELOC.$dirSep.'.systemPrefs'.$dirSep.'.system.lock';
	my $systemRootModeFile=$JRELOC.$dirSep.'.systemPrefs'.$dirSep.'.systemRootModFile';
	my $CHMOD='/bin/chmod';
	if($PLATFORM=~ /.*aix.*/){
		if((-e $systemLockFile) && !(-w $systemLockFile)){
			my $chmodcmd=$CHMOD.' u+w '.$systemLockFile;
			system($chmodcmd);
			$systemLockFilePermissionAdded='1';
		}
		if((-e $systemRootModeFile) && !(-w $systemRootModeFile)){
			my $chmodcmd=$CHMOD.' u+w '.$systemRootModeFile;
			system($chmodcmd);
			$systemRootModeFilePermissionAdded='1';
		}
	}

	# Determine the current existent files in the scratch path location
	my @scratchPathFiles;
	File::Find::find(sub{
		push(@scratchPathFiles, $File::Find::name);
	}, $scratchPath);

	# change dir
	chdir $ORACLE_HOME;
	# execute java cmd
	my $retcode=0;
	if($isWindows) {
		# WA for Perl bug 18917 (double execution)
		open(WCMD, "$wizardCmd |");
		while(<WCMD>) {
			print STDOUT $_;
		}
		close(WCMD);
		$retcode=$?;
	} else {
		# if os is unix and -noWait is passed in the command line then launching the SetupWizard in background.
		if($noWait eq "true") {
			$SIG{CHLD} = 'IGNORE';
			unless ( fork() ) {
				# Spawn SetupWizard
				$retcode=exec($wizardCmd);
				exit(0);
			}
		   } else {
			$retcode=system($wizardCmd);
		}
	}

	if( $PLATFORM=~ /.*aix.*/){
		if($systemLockFilePermissionAdded){
			my $chmodcmd=$CHMOD.' u-w '.$systemLockFile;
			system($chmodcmd);
		}
		if($systemRootModeFilePermissionAdded){
			my $chmodcmd=$CHMOD.' u-w '.$systemRootModeFile;
			system($chmodcmd);
		}
	}

	# Remove all the newly created files from the scratch path location
	my @oldScratchPathFiles;
	foreach (@scratchPathFiles) {
		push(@oldScratchPathFiles, $_);
	}
	my @newScratchPathFiles;
	File::Find::find(sub{
		push(@newScratchPathFiles, $File::Find::name);
	}, $scratchPath);
	foreach my $newFile (@newScratchPathFiles) {
		if(-e $newFile) {
			my $isOldFile = 'false';
			my $count = 0;
			foreach my $oldFile (@oldScratchPathFiles) {
				if($oldFile eq $newFile) {
					$isOldFile = 'true';
					
					# Optimize by removing the file from the old scratch path files array
					splice(@oldScratchPathFiles, $count, 1);
					last;
				}
				$count++;
			}
			if($isOldFile eq 'false') {
				if(-d $newFile) {
					File::Path::remove_tree($newFile);
					} else {
					unlink($newFile);
				}
			}
		}
	}

	exit $retcode >> 8;
}
	
sub runCommand() {
	my $self = shift;
	my $command = shift;
	my $exitCode = 0;
	if($isWindows) {
		# WA for Perl bug 18917 (double execution)
		open(WCMD, "$command |");
		while(<WCMD>) {
			print STDOUT $_;
		}
		close(WCMD);
		$exitCode=$?;
	} else {
		$exitCode=system($command);
	}
	return $exitCode;
}

sub setLdLibraryPath() {
	my $self = shift;
	my $oracleHome = shift;
	my $osname=$^O;
	my $LD_LIBRARY_PATH = $oracleHome.$dirSep.'lib'.$pathSep.$OUI_LIBRARY_LOCATION.$pathSep.$oracleHome.$dirSep.'bin';
	$LD_LIBRARY_PATH .= $pathSep.$ENV{LD_LIBRARY_PATH} if (exists($ENV{LD_LIBRARY_PATH}));
	$ENV{LD_LIBRARY_PATH} = $LD_LIBRARY_PATH;
	if ( $osname =~ /.*solaris.*/){
		$ENV{LD_LIBRARY_PATH_64} = $LD_LIBRARY_PATH;
	}
	
	if ($osname =~ /.*HPUX.*/i) {
		my $SHLIB_PATH = $LD_LIBRARY_PATH;
		$SHLIB_PATH .= $pathSep.$ENV{SHLIB_PATH} if (exists($ENV{SHLIB_PATH}));
		$ENV{SHLIB_PATH} = $SHLIB_PATH;
	}
	
	if ($osname =~ /.*AIX.*/i) {
		my $LIBPATH = $LD_LIBRARY_PATH;
		$LIBPATH .= $pathSep.$ENV{LIBPATH} if (exists($ENV{LIBPATH}));
		$ENV{LIBPATH} = $LIBPATH;
	}
}

sub showOwnerErrorAndExit() {
	print "\nERROR: Could not validate ownership of the Oracle home software.\n";
	print "       Verify that the software is not corrupt.\n";
	exit 1;
}

sub addJarToClassPath() {
	my ($self, $newJar, $existentJars) = @_;
	my $newJarName = File::Basename::basename($newJar);
	my $newJarExists = 0;
	# check if the jar is not already in the classpath
	for(my $count = 0; $count < @{$existentJars}; $count++) {
		my $jarName = File::Basename::basename(${$existentJars}[$count]);
		# compare the names of the jars
		if($jarName eq $newJarName) {
			$newJarExists=1;
			last;
		}
	}
	if(! $newJarExists) {
		push(@{$existentJars}, $newJar);
	}
}

###
# To show proper error message when repetitive arguments are passed,
# and it is not supported for such given argument.
###
sub repetitiveArgsError() {
        my $self = shift;
	my $repetitiveArg = shift;
	
	print "\nERROR: Repetition of command line argument is not supported: $repetitiveArg.\n";
	exit 1;
}

###
# To check if all the files from a given file or directory are
# readable by the current user.
# This subroutine is only for unix platforms.
#
# returns "true" if all files from the given directory are readable
# by the current user, "false" otherwise.
###
sub areAllFilesReadable() {
        my $self = shift;
	my $dirPath = shift;
	my $readAll="true";
	my $FIND="/bin/find";
	if(! -f "$FIND") {
		$FIND="/usr/bin/find";
	}
	# This check can only be done if the find binary is available
	if(-f "$FIND") {
		# find command: 'find dirPath ! -readable 2> /dev/null'
		my $allNonReadableFilesCmd=$FIND.' '.$dirPath.' ! -readable 2> /dev/null';
		my @nonReadableFiles=`$allNonReadableFilesCmd`;
		my $exitCodeNonReadFilesCmd=$?;
		if("$exitCodeNonReadFilesCmd" ne "0") {
			# If the find command fails, then some subdirectories are not readable by the current user
			$readAll="false";
		} else {
			# We iterate through the results of the find command to see if any of them is a file
			foreach (@nonReadableFiles) {
				if(-f "$_") {
					$readAll="false";
					last;
				}
			}
		}
	}
	return $readAll;
}

###
# To bootstrap the jdk and some jars into a temporary home in
# the temporary location.
# return The temporary home, the temporary java binary, and the
# temporary classpath.
###
sub bootstrap() {
	my ($self, @args) = @_;
	
	my $tempHome = $tempLogDir.$dirSep."tempHome";
	
	if($isWindows) {
		# bug 24517277 - Bootstrap the required DLLs
		my $dllDir = $tempHome.$dirSep."dlls";
		File::Path::make_path($dllDir);
		
		my @dllFiles;
		my $homeBin = $ORACLE_HOME.$dirSep."bin";
		my $ouiLibWin64 = $ORACLE_HOME.$dirSep."oui".$dirSep."lib".$dirSep."win64";
		push(@dllFiles, $homeBin.$dirSep."orasrvm18.dll");
		push(@dllFiles, $homeBin.$dirSep."orawsec18.dll");
		push(@dllFiles, $homeBin.$dirSep."orauts.dll");
		push(@dllFiles, $ouiLibWin64.$dirSep."oraInstaller.dll");
		foreach my $dll (@dllFiles) {
			my $dllName = File::Basename::basename($dll);
			my $newDllPath = $dllDir.$dirSep.$dllName;
			File::Copy::cp($dll,$newDllPath);
		}
		
		# Pre-append the temp dll dir into the PATH env var
		$ENV{PATH} = $dllDir.$pathSep.$ENV{PATH};
	}
	
	# Only bootstrap the JRE if there was no custom JRE provided
	my $jreDir = $tempHome.$dirSep."jre";
	if($customJRE eq 'false') {  
		File::Path::make_path($jreDir);
		$self->copyAllFiles($ORACLE_HOME.$dirSep."jdk".$dirSep."jre", $jreDir);
	} else {
		$jreDir = $JRELOC;
	}
	
	my $newCP = "";
	my $installJarsPath = $ORACLE_HOME.$dirSep."install".$dirSep."jlib";
	my $ouiJlibJarsPath = $ORACLE_HOME.$dirSep."oui".$dirSep."jlib";
	my $jlibJarsPath = $ORACLE_HOME.$dirSep."jlib";
	my @installJars;
	# Install jars
	push(@installJars, $installJarsPath.$dirSep."installcommons_1.0.0b.jar");
	push(@installJars, $installJarsPath.$dirSep."instcommon.jar");
	push(@installJars, $installJarsPath.$dirSep."instcrs.jar");
	push(@installJars, $installJarsPath.$dirSep."instdb.jar");
	# OUI jars
	push(@installJars, $ouiJlibJarsPath.$dirSep."OraInstaller.jar");
	push(@installJars, $ouiJlibJarsPath.$dirSep."xmlparserv2.jar");
	push(@installJars, $ouiJlibJarsPath.$dirSep."share.jar");
	# SRVM jars
	push(@installJars, $jlibJarsPath.$dirSep."srvm.jar");
	push(@installJars, $jlibJarsPath.$dirSep."cvu.jar");
	
	foreach my $jar (@installJars) {
		my $jarName = File::Basename::basename($jar);
		my $parentPath = File::Basename::dirname($jar);
		my $relPath = substr($parentPath, length($ORACLE_HOME)+1);
		my $newJarPath = $tempHome.$dirSep.$relPath;
		File::Path::make_path($newJarPath);
		
		$self->copyAllFiles($jar, $newJarPath);
		$newCP = $newCP.$newJarPath.$dirSep.$jarName.$pathSep;
	}
	
	if(length($newCP) > 0) {
		$newCP = substr($newCP, 0, length($newCP)-1);
	}
	
	my $javaBinary = $jreDir.$dirSep."bin".$dirSep."java";
	
	return ($tempHome,$javaBinary,$newCP);
}

###
# To copy all the files from a directory, in a recursive way,
# but the subdirectories will not be copied, instead they will
# be created in the destination location.
###
sub copyAllFiles() {
        my $self = shift;
	my $sourceDir = shift;
	my $destDir = shift;
	
	# Make the destination directory if not existent
	if (! -d $destDir) {
		File::Path::make_path("$destDir");
	}
	
	# Remove trailing slash from the sourceDir path
	if(length($sourceDir) > 1) {
		my $lastChar = substr($sourceDir,length($sourceDir)-1);
		while("$lastChar" eq "$dirSep") {
			$sourceDir = substr($sourceDir, 0, length($sourceDir)-1);
			$lastChar = substr($sourceDir,length($sourceDir)-1);
		}
	}
	
	# Copy the files from sourceDir to destDir
	File::Find::find(sub{
		# Get the file name, starting from the end of the sourceDir
		my $filepath=substr($File::Find::name,length($sourceDir));
		# Get the relative path from the file
		my $relparentdir=substr($filepath,0,rindex($filepath,$dirSep));
		# Check if the relative path exists in the destDir, if not, make it
		if(! -d $destDir.$dirSep.$relparentdir) {
			File::Path::make_path($destDir.$dirSep.$relparentdir);
		}
		if(-d $_) {
			# For directories, check if they already exist in the destDir, if not, make them
			if(! -d $destDir.$dirSep.$filepath) {
				File::Path::make_path($destDir.$dirSep.$filepath);
			}
		} else {
			# For files, copy them to the destDir
			File::Copy::cp($File::Find::name,$destDir.$dirSep.$filepath);
		}
	},$sourceDir);
}

###
# To exit the perl execution.
# The temp log dir will be removed if its empty.
###
sub terminate() {
        my $self = shift;
	my $exitCode = shift;
	
	# Remove the temp log dir if its empty
	my @tmpDirFiles;
	File::Find::find(sub{
		my $fileName = $File::Find::name;
		if($fileName ne $tempLogDir) {
			push(@tmpDirFiles, $fileName);
		}
	}, $tempLogDir);
	
	if(!@tmpDirFiles) {
		File::Path::remove_tree($tempLogDir);
	}
	
	exit $exitCode >> 8;
}

OHA YOOOO