#
#
# Copyright (c) 2003, 2023, Oracle and/or its affiliates. 
#
#    NAME
#      PatchCmds.pm - Patch Repository Perl Module
#
#    DESCRIPTION
#      Integrates EM Repository Patching with EMCTL
#      Supports cmds:
#           emctl applypatch repos -patchHome "location of unzipped patch" 
#           emctl rollbackpatch repos -patchHome "location of unzipped patch"
#
#    NOTES
#      Usecase - EM Repository Patching.
#

package PatchCmds;
use EmctlCommon;
use IPC::Open3;
use File::Spec; 
use Getopt::Long;
use FileHandle;
use IO::Handle;
use File::Copy;
use File::Path qw(mkpath);

my $NT = 0;
if ("$IS_WINDOWS" eq 'TRUE')
{
    $NT = 1;
}

my %emgcProps = &EMomsCmds::getEmgcProps();
my $oracleHome = $emgcProps{"ORACLE_HOME"};
my $commonOracleHome = $emgcProps{"COMMON_ORACLE_HOME"};
my $rcuHome = $commonOracleHome;
my $reposConnectDesc = $emgcProps{"EM_REPOS_CONNECTDESCRIPTOR"} =~ s/\s//gr;
my $reposUser = $emgcProps{"EM_REPOS_USER"};
#my $dbUser = "ADMIN";
my $emPatchComponentXml = File::Spec->catfile($oracleHome,'sysman','emdrep','config','patch','emPatchComponentInfo.xml');
my $emStorageXml = File::Spec->catfile($oracleHome,'sysman','emdrep','config','rcu','EMStorage.xml'); 
my $patchHome ="";
my $pluginHome = "";
my $isPlatform = "false";
my $emSqlRoot = "";
my $patchId ="";
my $rcuLogHome="";
my $rcuLogFileName ="";
my $rcuCoreLogFileName ="";
my $rcuCoreLog ="";
my $timestamp ="";
my $cloneHome="";
my $rpuFlag="";
my $cloneHomeFlag = 0;
my $em_edition_name = "";
my $trustStore ="";
my $dbUser="";
my $trustStoreType ="";
my $keyStore ="";
my $keyStoreType ="";
my $serverDnMatchForApply="false";
my $serverDnMatchForRollback="false";
my $DB_USER="";
sub new {
  my $classname = shift;
  my $self = { };
  bless ( $self, $classname);
  return $self;
}

sub doIT {
   my $classname = shift;
   my $rargs = shift;
   my $result = $EMCTL_UNK_CMD;
   my $argCount  = @$rargs;

   # If POSIXLY_CORRECT environment variable is set, the GetOptions call below returns
   # empty strings, and the overall script fails (see Bug 17046212)
   # This is why explicit configation of GetOptions is done
   Getopt::Long::Configure ("permute");

   if ($argCount >= 4  && $rargs->[0] eq "applypatch" &&  $rargs->[1] eq "repos") 
    {  
       GetOptions('patchHome=s' => \$patchHome, 'pluginHome=s' => \$pluginHome, 'rpu=s' => \$rpuFlag, 'trustStore=s' => \$trustStore,'trustStoreType=s' => \$trustStoreType, 'keyStore=s' => \$keyStore, 'keyStoreType=s' => \$keyStoreType, 'dbUser=s' => \$dbUser);       
       checkPrereqs("true");   
       doCommon("true");
       $result = applyPatchRepos($rargs);
    }
    elsif ($argCount >= 4  && $rargs->[0] eq "rollbackpatch" && $rargs->[1] eq "repos")
    {
      GetOptions('patchHome=s' => \$patchHome, 'pluginHome=s' => \$pluginHome,'rpu=s' => \$rpuFlag, 'trustStore=s' => \$trustStore,'trustStoreType=s' => \$trustStoreType, 'keyStore=s' => \$keyStore, 'keyStoreType=s' => \$keyStoreType,'dbUser=s' => \$dbUser);       
       checkPrereqs("false");   
       doCommon("false");
       $result = rollbackPatchRepos($rargs);
    }  
    elsif ($argCount >= 1 && ($rargs->[0] eq "applypatch" || $rargs->[0] eq "rollbackpatch"))
    {
       GetOptions( 'trustStore=s' => \$trustStore,'trustStoreType=s' => \$trustStoreType, 'keyStore=s' => \$keyStore, 'keyStoreType=s' => \$keyStoreType,'dbUser=s' => \$dbUser);

       usage();
       $result = $EMCTL_DONE;       
    }
   return $result;
}

sub usage
{
    print "\nPatch Repository Usage: \n";
    print "\n";
    print "emctl applypatch repos [-patchHome <patch home directory> -pluginHome <plugin home directory>] Specify directory where patch has been unzipped\n";
    print "emctl rollbackpatch repos [-patchHome <patch home directory> -pluginHome <plugin home directory>] Specify directory where patch has been unzipped\n";
    print "\n";
}

sub DESTROY {
    my $self = shift;
}

sub doCommon
{
  # Bug 17432056: unset DISPLAY to make the rcu call more robust
  my $isApply = shift;

  delete $ENV{'DISPLAY'};

# getting the edition name

$cfgFile=File::Spec->catfile($oracleHome,"edition");
  if(-e $cfgFile && $rpuFlag eq 'true'){  
  open(DAT, $cfgFile) || die("Could not open file $propFile! Check if it has read access to the current user");
    @fileContent=<DAT>;
  close(DAT);
	  foreach $data (@fileContent)
	  {
			chomp($data);
			$data=~tr/\015//d;
			$em_edition_name=$data;
	  }
  }

  print "The current edition is --$em_edition_name---";

#getting the clone home
#  $cfgFile=File::Spec->catfile($oracleHome,"preDowntime");
  $cfgFile=File::Spec->catfile($oracleHome,"CloneHome");
  if(-e $cfgFile){
  $cloneHomeFlag = 1;
  open(DAT, $cfgFile) || die("Could not open file $propFile! Check if it has read access to the current user");
    @fileContent=<DAT>;
  close(DAT);
  $string_to_find = "CLONED_HOME_PATH";

  foreach $data (@fileContent)
  {
        chomp($data);
        $data=~tr/\015//d;
        ($key,$value)=split(/\=/,$data);
        if ($key =~ m/$string_to_find/g)
        {
                $value =~ s/\\:/:/g;  #s/$find/$replace/g
                $cloneHome=$value;
		if ($cloneHome eq "") {
 		 $cloneHome = $oracleHome;
		}
                $emSqlRoot = File::Spec->catfile($cloneHome,'sysman', 'admin', 'emdrep', 'sql');
                $ENV{'ORACLE_HOME'} = $cloneHome;
        }
  }
}
else{
	$cloneHome = $oracleHome;
	$emSqlRoot = File::Spec->catfile($cloneHome,'sysman', 'admin', 'emdrep', 'sql');
	$ENV{'ORACLE_HOME'} = $cloneHome;
	#make edition empty
	#$em_edition_name="";
}

#Below is the use case to handle apply_files_predowntime and downtime
if($rpuFlag eq 'true'){
	#update
	if(!$cloneHomeFlag){
		$downtimeApplyFiles = File::Spec->catfile($patchHome,"apply_files_downtime.sql");
		$downtimeApplyFilesBackup = File::Spec->catfile($patchHome,"apply_files_downtime_backup.sql");
		$cumulativeDowntimeSql = File::Spec->catfile($oracleHome,'.omspatcher_storage',"apply_files_downtime_cumulative.sql");
		
		if(-e $cumulativeDowntimeSql){
			print "Renaming $downtimeApplyFiles to $downtimeApplyFilesBackup";
			rename($downtimeApplyFiles, $downtimeApplyFilesBackup);	
			print "Copying $cumulativeDowntimeSql to $downtimeApplyFiles";		
			copy($cumulativeDowntimeSql, $downtimeApplyFiles) or die "Copy failed: $!";
		}
		else{
			print "apply_files_downtime_cumulative.sql does not exist....exiting";
			exit(0);
		}
		
		#unless (-e $downtimeApplyFiles) {
		#	print "apply_files_downtime.sql does not exist....exiting $downtimeApplyFiles";
		#	exit(0);
		#}
	}
	#deploy
	else{
		$predowntimeApplyFiles = File::Spec->catfile($patchHome,"apply_files_predowntime.sql");
		$applyFiles = File::Spec->catfile($patchHome,"apply_files.sql");
		unless (-e $predowntimeApplyFiles) {
			print "apply_files_predowntime.sql does not exist....copying apply_files.sql";
			copy($applyFiles, $predowntimeApplyFiles) or die "Copy failed: $!"; 						
		}		
	}
}
#if ($isApply eq "false") {
#	$cloneHome = $oracleHome;
#	$emSqlRoot = File::Spec->catfile($cloneHome,'sysman', 'admin', 'emdrep', 'sql');
#	$ENV{'ORACLE_HOME'} = $cloneHome;
#}
print "************** clone home is $cloneHome \n";

  $ENV{'RCU_DBMS_OUTPUT_IN_SEPARATE_FILE'} = 'true';
  $ENV{'RCU_TIMESTAMP_LOG_DIR'} = 'false';  
  $ENV{'RCU_PRODUCT_NAME'} = 'Repository_Patching_Utility';
#  $ENV{'ORACLE_HOME'} = $oracleHome;
  $ENV{'COMMON_ORACLE_HOME'} = $commonOracleHome;
  $rcuHome= File::Spec->catfile($cloneHome,'oracle_common');
  $ENV{'RCU_HOME'} = $rcuHome;
  $rcuLogHome = File::Spec->catfile($rcuHome,'rcu', 'log', 'empatch');
  #$rcuLogHome = File::Spec->catfile($oracleHome,'oracle_common','rcu', 'log', 'empatch','logs','logs');
  $ENV{'RCU_LOG_LOCATION'} = $rcuLogHome;
  $rcuCoreLogFileName = "rcu"."_";
  $timeStamp = getTimestamp();
  $rcuCoreLogFileName = $rcuCoreLogFileName.$timeStamp;
  $rcuCoreLogFileName = $rcuCoreLogFileName.".log";  
  $ENV{'RCU_LOG_NAME'} = $rcuCoreLogFileName;
  $rcuCoreLog = File::Spec->catfile($rcuLogHome,'logs',$rcuCoreLogFileName);
  ($volume,$directories,$patchId) = File::Spec->splitpath( $patchHome);       
 # $emSqlRoot = File::Spec->catfile($oracleHome,'sysman', 'admin', 'emdrep', 'sql'); 
  if ($pluginHome ne "")
  {
    $emSqlRoot = File::Spec->catfile($pluginHome,'sql');
  }
#  print "\nPluginHome = $pluginHome\n";
#  print "\nEMSQLRoot = $emSqlRoot\n";
}

sub getTimestamp 
{
   ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
   $mon = $mon + 1;
   if ($mon < 10) { $mon = "0$mon"; }
   if ($hour < 10) { $hour = "0$hour"; }
   if ($min < 10) { $min = "0$min"; }
   if ($sec < 10) { $sec = "0$sec"; }
   $year=$year+1900;
   return $year . '_' . $mon . '_' . $mday . '__' . $hour . '_' . $min . '_' . $sec;
}

sub getTimestampID
{
   ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
   $mon = $mon + 1;
   if ($mon < 10) { $mon = "0$mon"; }
   if ($hour < 10) { $hour = "0$hour"; }
   if ($min < 10) { $min = "0$min"; }
   if ($sec < 10) { $sec = "0$sec"; }
   $year=$year+1900;
   return $year . $mon . $mday . $hour . $min . $sec;
}

sub checkPrereqs
{  
  if($oracleHome eq '') 
  {  
    abort("*** Failed: Unable to get ORACLE_HOME\n"); 
  }
  
  my $isApply = shift;
  my $fileToValidPatchHome = File::Spec->catfile($patchHome, 'etc', 'rcu', 'emPatchApply.xml');  
  if ($isApply eq "false")
  { 
     $fileToValidPatchHome = File::Spec->catfile($patchHome, 'etc', 'rcu', 'emPatchRollback.xml');  
	 $rcuHome = $commonOracleHome;
  }

  unless (-e $fileToValidPatchHome)  
  {
      abort("*** Failed: Patch Home Directory specified is invalid as the required file \"" . $fileToValidPatchHome . "\" is not found from the Patch Home directory.\n"); 
  }
  
  #Check whether rcu binary is present  
  my $RCU = File::Spec->catfile($rcuHome,'bin','rcu'); 
  if($NT)  
  {  
    unless (-e "$RCU.bat")  
    { 
      abort("*** Failed: Required rcu.bat not found in the directory : $rcuHome/bin. Check whether you have set the correct COMMON_ORACLE_HOME\n");  
    }  
  }  
  else  
  {  
    unless( -e $RCU )  
    { 
      abort("*** Failed: Required rcu binary not found in the directory : $rcuHome/bin. Check whether you have set the correct COMMON_ORACLE_HOME\n");  
    } 
  } 
  
  if($reposConnectDesc eq '')    
  {    
    abort("*** Failed: Unable to get Repository Descriptor details\n");    
  }  
  if ($reposUser eq '')
  {    
    abort("*** Failed: Unable to get Repository User details\n");    
  }
    
  return true;  
} 
   
 
sub abort 
{ 
 
  if($_[0] ne '')  
  {  
    print "$_[0]\n";  
  }    
  print " Please correct error and return or contact Oracle Support\n";  
  exit(-1);  
} 
 
sub executePrompt  
{ 
  print "\n";  
  print "In case of multi OMS, you are rqeuired to run this utility to patch\n"; 
  print " repositry only from one OMS. Do you want to continue? [y/n] : ";    
  chomp($runYN = <STDIN>);    
  if ((lc($runYN) ne "y") && (lc($runYN) ne "yes"))    
  {    
    print " *** Aborting on user input ***\n";    
    abort();    
  }  
} 


#
# applyPatchRepos
# Usage : emctl applypatch repos [-patchHome <patch Home directory>]
#
sub applyPatchRepos()
{ 
  $ENV{'RCU_OPERATION1_NAME'} = 'ApplyRepositoryPatch';
  $ENV{'RCU_OPERATION1_CMDLINE'} = 'applyRepositoryPatch';
  if($trustStore ne ""){
    print("Setting rcu_ssl_mode is true in apply\n ");
    $ENV{'RCU_SSL_MODE'}=true;
 }    
  $rcuLogFileName = "em_patch_apply"."_";
  $rcuLogFileName = $rcuLogFileName.$patchId;
  $rcuLogFileName = $rcuLogFileName."_";  
  $rcuLogFileName = $rcuLogFileName.$timeStamp;  

  my $RCU = File::Spec->catfile($rcuHome,'bin','rcu');
  
  my $RCU_COMMAND_ARGS=""; 
   
  $RCU_COMMAND_ARGS=$RCU_COMMAND_ARGS." -silent"; 
   
  $RCU_COMMAND_ARGS=$RCU_COMMAND_ARGS." -applyRepositoryPatch"; 
   
  $RCU_COMMAND_ARGS=$RCU_COMMAND_ARGS." -connectString \"$reposConnectDesc\""; 
   
  $RCU_COMMAND_ARGS=$RCU_COMMAND_ARGS." -databaseType ORACLE"; 
   
   $RCU_COMMAND_ARGS=$RCU_COMMAND_ARGS." -dbUser $dbUser"; 
   
  if(lc($dbUser) eq "sys" ){
	$RCU_COMMAND_ARGS=$RCU_COMMAND_ARGS." -dbRole SYSDBA";
  }
   
  $RCU_COMMAND_ARGS=$RCU_COMMAND_ARGS." -useDBPasswordAsSchemaPassword true"; 
   
  $RCU_COMMAND_ARGS=$RCU_COMMAND_ARGS." -compInfoXMLLocation $emPatchComponentXml"; 
   
  $RCU_COMMAND_ARGS=$RCU_COMMAND_ARGS." -storageXMLLocation $emStorageXml";   
  
  $RCU_COMMAND_ARGS_2=$RCU_COMMAND_ARGS;

  $nzdt_xml_file = File::Spec->catfile($patchHome,'etc', 'rcu','nzdt','emPatchApply.xml');  
  $down_xml_file = File::Spec->catfile($patchHome,'etc', 'rcu','nzdt','emPatchApply_downtime.xml');  
  $xml_file = File::Spec->catfile($patchHome,'etc', 'rcu','emPatchApply.xml');
  $DB_USER=uc($dbUser);
  #Due to limitation of rcu, we cannot send new parameter admin_reposuser to app
 # ly_files.sql,so sending it in pluginHome for core subpatch as a solution to bug 34680616
  if($pluginHome eq ""){
     $isPlatform = "true";
     $pluginHome = uc($dbUser);
   }
 
  if ($em_edition_name ne "") {
	  #copy emPatchApply.xml from omshome	  
	  if($cloneHomeFlag){
		print "copy  $nzdt_xml_file to $xml_file";
		copy($nzdt_xml_file, $xml_file) or die "Copy failed: $!";  
	  }		
	  else{
		  print "copy  $down_xml_file to $xml_file";
		  copy($down_xml_file, $xml_file) or die "Copy failed: $!";
	  }		
	  $RCU_COMMAND_ARGS=$RCU_COMMAND_ARGS." -variables EM_REPOS_USER=$reposUser,DB_USER=$DB_USER,PATCH_HOME=$patchHome,ORACLE_HOME=$cloneHome,PATCH_MODE_SELECT=patchAction,EM_SQL_ROOT=$emSqlRoot,PLUGIN_HOME=$pluginHome,NEW_EDITION_NAME=$em_edition_name,NZDT_MODE=true";
  }
  else{
	  $RCU_COMMAND_ARGS=$RCU_COMMAND_ARGS." -variables EM_REPOS_USER=$reposUser,DB_USER=$DB_USER,PATCH_HOME=$patchHome,ORACLE_HOME=$oracleHome,PATCH_MODE_SELECT=patchAction,EM_SQL_ROOT=$emSqlRoot,PLUGIN_HOME=$pluginHome,NZDT_MODE=false";
  }
 
  if ($isPlatform eq "true") {
	$RCU_COMMAND_ARGS=$RCU_COMMAND_ARGS.",IS_PLATFORM=true";
  }
  else{
	$RCU_COMMAND_ARGS=$RCU_COMMAND_ARGS.",IS_PLATFORM=false";
  }

  $RCU_COMMAND_ARGS=$RCU_COMMAND_ARGS." -component EM_PATCH_APPLY"; 
##Adding ssl params


 if($keyStore ne "") {
      $RCU_COMMAND_ARGS=$RCU_COMMAND_ARGS." -useSSL -sslArgs javax.net.ssl.trustStore=$trustStore,javax.net.ssl.trustStoreType=$trustStoreType,javax.net.ssl.keyStore=$keyStore,javax.net.ssl.keyStoreType=$keyStoreType,oracle.net.ssl_server_dn_match=$serverDnMatchForApply -sslPasswordArgNames javax.net.ssl.keyStorePassword,javax.net.ssl.trustStorePassword -schemaPrefix SSL1 -serverDN CN=server,OU=ST,O=Oracle,ST=California,C=US";
     }
 elsif ( $trustStore ne "") {
       $RCU_COMMAND_ARGS=$RCU_COMMAND_ARGS." -useSSL -sslArgs javax.net.ssl.trustStore=$trustStore,javax.net.ssl.trustStoreType=$trustStoreType,oracle.net.ssl_server_dn_match=$serverDnMatchForApply -sslPasswordArgNames javax.net.ssl.trustStorePassword -schemaPrefix SSL1 -serverDN CN=server,OU=ST,O=Oracle,ST=California,C=US";
       }


  my $cmd = "$RCU $RCU_COMMAND_ARGS";         
  my $child_exit_status1 = 1;
  my $child_exit_status2 = 1;
  my $child_exit_status = 1;

  if($NT)  
  {  
    $cmd =  "$RCU.bat $RCU_COMMAND_ARGS";   
 }       
  
  print "\n***********************************************\n";    
  print "Executing Patch Application Steps.....\n";    
  print "\n$cmd\n";
  print "\n***********************************************\n";    
  my $password;
  my $sysPassword;
  my $keyStorePassword;
  my $trustStorePassword; 
   $sysPassword= EmctlCommon::promptUserPasswd("Enter the $dbUser password:\n");  
   chomp($sysPassword);
   @password=split(" ",$sysPassword); 
   $pwdLen=@password; 
    $sysPassword=$password[0];
  print("pwdLen:$pwdLen" );
###In case of resume sh , all 3 pwd will be passed.
  if($pwdLen > 1){
   if ($keyStore ne "") {
        $keyStorePassword = $password[1];
	    $trustStorePassword = $password[2];
    }  
    else {
        $trustStorePassword = $password[1];
       }
  }
##in case of apply patch all pwd will enter accordingly.
  else{  
      if ($keyStore ne "") {
	$keyStorePassword = EmctlCommon::promptUserPasswd("Enter the keyStore  password:\n");
	chomp($keyStorePassword);
      }
   if ($trustStore ne "") {
        $trustStorePassword = EmctlCommon::promptUserPasswd("Enter the trustStore  password:\n");
        chomp($trustStorePassword);
   }
}
 print ("Patch apply :   trustStore:$trustStore trustStoreType:$trustStoreType keyStore:$keyStore keyStoreType:$keyStoreType in apply \n");

  


  my $fh = IO::Handle->new();
  $pid = open3($fh, '>&STDOUT', '>&STDERR', $cmd);
   if ($keyStorePassword ne "") {
	$fh->print("$keyStorePassword\n");

   }if ($trustStorePassword ne "") {
	$fh->print("$trustStorePassword\n");
    }
	$fh->print("$sysPassword\n");


  $fh->close;  
  waitpid($pid,0);
  $child_exit_status1  = $? >> 8;
  #print "ChildExitStatus 1 = $child_exit_status1";

# Execute post patch cleanup actions

  if ($em_edition_name eq "") {
	  $RCU_COMMAND_ARGS_2=$RCU_COMMAND_ARGS_2." -variables EM_REPOS_USER=$reposUser,PATCH_HOME=$patchHome,ORACLE_HOME=$oracleHome,PATCH_MODE_SELECT=postAction,NZDT_MODE=false";       
  }	
  else{
	  $RCU_COMMAND_ARGS_2=$RCU_COMMAND_ARGS_2." -variables EM_REPOS_USER=$reposUser,PATCH_HOME=$patchHome,ORACLE_HOME=$cloneHome,PATCH_MODE_SELECT=postAction,NEW_EDITION_NAME=$em_edition_name,NZDT_MODE=true";       
  }
#if ($pluginHome eq "") {
#	$RCU_COMMAND_ARGS_2=$RCU_COMMAND_ARGS_2.",IS_PLATFORM=true";
#}
#else{
	$RCU_COMMAND_ARGS_2=$RCU_COMMAND_ARGS_2.",IS_PLATFORM=false";
#}

$RCU_COMMAND_ARGS_2=$RCU_COMMAND_ARGS_2." -component EM_PATCH_APPLY"; 
  
##Adding ssl params
if ($keyStore ne "") {
	$RCU_COMMAND_ARGS_2=$RCU_COMMAND_ARGS_2." -useSSL -sslArgs javax.net.ssl.trustStore=$trustStore,javax.net.ssl.trustStoreType=$trustStoreType,javax.net.ssl.keyStore=$keyStore,javax.net.ssl.keyStoreType=$keyStoreType,oracle.net.ssl_server_dn_match=$serverDnMatchForApply -sslPasswordArgNames javax.net.ssl.keyStorePassword,javax.net.ssl.trustStorePassword -schemaPrefix SSL1 -serverDN CN=server,OU=ST,O=Oracle,ST=California,C=US";
}
 elsif( $trustStore ne "") {
       $RCU_COMMAND_ARGS_2=$RCU_COMMAND_ARGS_2." -useSSL -sslArgs javax.net.ssl.trustStore=$trustStore,javax.net.ssl.trustStoreType=$trustStoreType,oracle.net.ssl_server_dn_match=$serverDnMatchForApply -sslPasswordArgNames javax.net.ssl.trustStorePassword -schemaPrefix SSL1 -serverDN CN=server,OU=ST,O=Oracle,ST=California,C=US";
}


  my $cmd = "$RCU $RCU_COMMAND_ARGS_2";         
  if($NT)  
  {  
    $cmd =  "$RCU.bat $RCU_COMMAND_ARGS_2";   
  }  
$ENV{'ORACLE_HOME'} = $cloneHome;
  #print "$cmd";
  print "\n***********************************************\n";   
  print "Executing Post Patch Action Steps.....\n";    
print "$cmd";
  print "\n***********************************************\n";    
 
 print(" Post Apply patch: trustStore:$trustStore trustStoreType:$trustStoreType keyStore:$keyStore keyStoreType:$keyStoreTy \n");

  my $fh2 = IO::Handle->new();
  $pid = open3($fh2, '>&STDOUT', '>&STDERR', $cmd);


 if ($keyStorePassword ne "") {
        $fh2->print("$keyStorePassword\n");
   }if ($trustStorePassword ne "") {
        $fh2->print("$trustStorePassword\n");
    }
        $fh2->print("$sysPassword\n");
 

$fh2->close;  
  waitpid($pid,0);
  $child_exit_status2  = $? >> 8;
  #print "ChildExitStatus 2 = $child_exit_status2";
# Rename log files

  my $newName;
  my $newName_dbmsOut;
  my $newRcuLogHome = File::Spec->catfile($oracleHome,'oracle_common','rcu', 'log', 'empatch','logs');
	if (! -e $newRcuLogHome) {
	mkpath($newRcuLogHome);
	}

  eval 
  {
    my $oldName = File::Spec->catfile($rcuLogHome,'logs',"em_patch_apply.log");
    $newName = File::Spec->catfile($newRcuLogHome,'', $rcuLogFileName.".log");
    
    print "\nRenaming logfile $oldName to $newName\n";
    
    rename($oldName, $newName);    
    
    my $oldName_dbmsOut = File::Spec->catfile($rcuLogHome,'logs',"em_patch_apply_dbmsOutput.log");  
    $newName_dbmsOut = File::Spec->catfile($newRcuLogHome,$rcuLogFileName."_dbmsOutput.log");
    
    print "\nRenaming logfile $oldName_dbmsOut to $newName_dbmsOut\n";
    
    rename($oldName_dbmsOut, $newName_dbmsOut);          
    
    1;
  }
  or do 
  {
    print "Error renaming log files";
  };
  $child_exit_status = $child_exit_status1 + $child_exit_status2;
  if ($child_exit_status != 0)
  { 
  	print "\n****************************************************************************\n";
  	print "\n****************************************************************************\n";
  	print "\nPATCH APPLICATION HAS FAILED " ;
    print "\n\nPlease review the following log files of Repository Patching Utility to determine error:";
    print "\nPatch Log: $newName";
	  print "\nPatch DbmsOutLog: $newName_dbmsOut";
    print "\nRCU Core Log: $rcuCoreLog";
  	print "\nPATCH APPLICATION HAS FAILED " ;
  	print "\n***************************************************************************\n";
  	print "\n***************************************************************************\n";
  }
  else
  {
   	print "\n****************************************************************************\n";
   	print "\n****************************************************************************\n";
    print "\nPATCH APPLICATION HAS SUCCEEDED ";
    print "\n***************************************************************************\n";
    print "\n***************************************************************************\n";
  }
  
  $cumulativeDowntimeSql = File::Spec->catfile($oracleHome,'.omspatcher_storage',"apply_files_downtime_cumulative.sql");
  
  if($rpuFlag eq 'true' && !$cloneHomeFlag && -e $cumulativeDowntimeSql){
		$downtimeApplyFiles = File::Spec->catfile($patchHome,"apply_files_downtime.sql");
		$downtimeApplyFilesBackup = File::Spec->catfile($patchHome,"apply_files_downtime_backup.sql");
		unlink($downtimeApplyFiles);
		rename($downtimeApplyFilesBackup, $downtimeApplyFiles);	  
  }
  
  exit($child_exit_status);
}

#
# rollbackPatchRepos
# Usage : emctl rollbackPatch repos [-patchHome <patch Home directory>]
#
sub rollbackPatchRepos()
{
       print("*************rollbackPatchRepose"); 

  $ENV{'RCU_OPERATION1_NAME'} = 'RollbackRepositoryPatch';
  $ENV{'RCU_OPERATION1_CMDLINE'} = 'rollbackRepositoryPatch';  
  if($trustStore ne ""){
	$ENV{'RCU_SSL_MODE'}=true;
	print ("SSL Mode value is $ENV{'RCU_SSL_MODE'}");
    }

  $DB_USER=uc($dbUser); 
  $rcuLogFileName = "em_patch_rollback"."_";
  $rcuLogFileName = $rcuLogFileName.$patchId;
  $rcuLogFileName = $rcuLogFileName."_";  
  $rcuLogFileName = $rcuLogFileName.$timeStamp;
  
#  my $em_edition_name = "E" . getTimestampID();

  my $RCU = File::Spec->catfile($rcuHome,'bin','rcu'); 
 # my $RCU = File::Spec->catfile($commonOracleHome,'bin','rcu'); 
  my $RCU_COMMAND_ARGS=""; 
   
  $RCU_COMMAND_ARGS=$RCU_COMMAND_ARGS." -silent"; 
   
  $RCU_COMMAND_ARGS=$RCU_COMMAND_ARGS." -rollbackRepositoryPatch"; 
   
  $RCU_COMMAND_ARGS=$RCU_COMMAND_ARGS." -connectString \"$reposConnectDesc\""; 
   
  $RCU_COMMAND_ARGS=$RCU_COMMAND_ARGS." -databaseType ORACLE"; 
   
  $RCU_COMMAND_ARGS=$RCU_COMMAND_ARGS." -dbUser $dbUser"; 
   
 if(lc($dbUser) eq "sys"){
        $RCU_COMMAND_ARGS=$RCU_COMMAND_ARGS." -dbRole SYSDBA";
  }
#  $RCU_COMMAND_ARGS=$RCU_COMMAND_ARGS." -dbRole $dbUserRole"; 
   
  $RCU_COMMAND_ARGS=$RCU_COMMAND_ARGS." -useDBPasswordAsSchemaPassword true"; 
   
  $RCU_COMMAND_ARGS=$RCU_COMMAND_ARGS." -compInfoXMLLocation $emPatchComponentXml"; 
   
  $RCU_COMMAND_ARGS=$RCU_COMMAND_ARGS." -storageXMLLocation $emStorageXml"; 
  
  $RCU_COMMAND_ARGS_2=$RCU_COMMAND_ARGS;

# adding the code to add the rollback code

  $nzdt_xml_file = File::Spec->catfile($patchHome,'etc', 'rcu','nzdt','emPatchRollback.xml');  
  $xml_file = File::Spec->catfile($patchHome,'etc', 'rcu','emPatchRollback.xml');
  
  $predowntimeRollbackFiles = File::Spec->catfile($patchHome,"rollback_files_predowntime.sql");
  $rollbackFiles = File::Spec->catfile($patchHome,"rollback_files.sql");
  $rollbackFilesBackup = File::Spec->catfile($patchHome,"rollback_files_backup.sql");
  
  if($rpuFlag eq 'true' && -e $predowntimeRollbackFiles){
	  print "Renaming $rollbackFiles to $rollbackFilesBackup\n";
	  rename($rollbackFiles, $rollbackFilesBackup);
	  print "Renaming $predowntimeRollbackFiles to $rollbackFiles\n";		
	  rename($predowntimeRollbackFiles, $rollbackFiles);	 
  }
#calling the calculate delta for rollback
  calculateDelta();

  if($pluginHome eq ""){
     $isPlatform = "true";
     $pluginHome=uc($dbUser);
  }
   
  if ($em_edition_name ne "") {
	  #copy emPatchApply.xml from omshome
	  print "copy  $nzdt_xml_file to $xml_file";
	  copy($nzdt_xml_file, $xml_file) or die "Copy failed: $!";
	  $RCU_COMMAND_ARGS=$RCU_COMMAND_ARGS." -variables EM_REPOS_USER=$reposUser,DB_USER=$DB_USER,PATCH_HOME=$patchHome,ORACLE_HOME=$cloneHome,PATCH_MODE_SELECT=patchAction,EM_SQL_ROOT=$emSqlRoot,PLUGIN_HOME=$pluginHome,NEW_EDITION_NAME=$em_edition_name,NZDT_MODE=true";
  }
  else{
	  $RCU_COMMAND_ARGS=$RCU_COMMAND_ARGS." -variables EM_REPOS_USER=$reposUser,DB_USER=$DB_USER,PATCH_HOME=$patchHome,ORACLE_HOME=$oracleHome,PATCH_MODE_SELECT=patchAction,EM_SQL_ROOT=$emSqlRoot,PLUGIN_HOME=$pluginHome,NZDT_MODE=false";    
  }

 if ($isPlatform eq "true") {
       $RCU_COMMAND_ARGS=$RCU_COMMAND_ARGS.",IS_PLATFORM=true";
  }
 else{
       $RCU_COMMAND_ARGS=$RCU_COMMAND_ARGS.",IS_PLATFORM=false";
 }


  $RCU_COMMAND_ARGS=$RCU_COMMAND_ARGS." -component EM_PATCH_ROLLBACK";        
if ($keyStore ne "") {
  $RCU_COMMAND_ARGS=$RCU_COMMAND_ARGS." -useSSL -sslArgs javax.net.ssl.trustStore=$trustStore,javax.net.ssl.trustStoreType=$trustStoreType,javax.net.ssl.keyStore=$keyStore,javax.net.ssl.keyStoreType=$keyStoreType,oracle.net.ssl_server_dn_match=$serverDnMatchForRollback -sslPasswordArgNames javax.net.ssl.keyStorePassword,javax.net.ssl.trustStorePassword -schemaPrefix SSL1  -serverDN CN=server,OU=ST,O=Oracle,ST=California,C=US";
}
elsif($trustStore ne "") {
  $RCU_COMMAND_ARGS=$RCU_COMMAND_ARGS." -useSSL -sslArgs javax.net.ssl.trustStore=$trustStore,javax.net.ssl.trustStoreType=$trustStoreType,oracle.net.ssl_server_dn_match=$serverDnMatchForRollback -sslPasswordArgNames javax.net.ssl.trustStorePassword -schemaPrefix SSL1 -serverDN CN=server,OU=ST,O=Oracle,ST=California,C=US";
}
	
 
  my $cmd = "$RCU $RCU_COMMAND_ARGS";         
  my $child_exit_status1 = 1;
  my $child_exit_status2 = 1;
  my $child_exit_status = 1;
 
  if($NT)  
  {  
    $cmd =  "$RCU.bat $RCU_COMMAND_ARGS";   
  }       
 
  print "\n***********************************************\n";    
  print "Executing Patch Rollback Steps.....\n";    
  print "\n$cmd\n"; 
  print "\n***********************************************\n";    
 

 my $sysPassword;
  my $keyStorePassword;
  my $trustStorePassword;   
        $sysPassword = EmctlCommon::promptUserPasswd("Enter the $dbUser password:\n");   
   chomp($sysPassword);  
my @password=split(" ",$sysPassword);
my $pwdLen=@password; 

print("pwd lenght is $pwdLen\n");

   $sysPassword=$password[0];

###In case of resume sh , all 3 pwd will be passed.
 if($pwdLen > 1){
    if ($keyStore ne "") {
       $keyStorePassword = $password[1];
       $trustStorePassword = $password[2];
    }
   else {
       $trustStorePassword = $password[1];
    }
  }
 ##in case of apply patch all pwd will enter accordingly.
 else{
  if ($keyStore ne "") {
        $keyStorePassword = EmctlCommon::promptUserPasswd("Enter the keyStore  password:\n");
        chomp($keyStorePassword);
  }
  if ($trustStore ne "") {
      $trustStorePassword = EmctlCommon::promptUserPasswd("Enter the trustStore  password:\n");
      chomp($trustStorePassword);
  }
 
}
    print("Rollback: trustStore:$trustStore trustStoreType:$trustStoreType            keyStore:$keyStore keyStoreType:$keyStoreType\n");

  my $fh = IO::Handle->new();
  $pid = open3($fh, '>&STDOUT', '>&STDERR', $cmd);

  if ($keyStorePassword ne "") {
      $fh->print("$keyStorePassword\n");
   }
  if ($trustStorePassword ne "") {
      $fh->print("$trustStorePassword\n");
   }

   $fh->print("$sysPassword\n");
   $fh->close;  
   waitpid($pid,0);
   my $child_exit_status1  = $? >> 8;

 
# Execute post patch cleanup actions
  $RCU_COMMAND_ARGS_2=$RCU_COMMAND_ARGS_2." -variables EM_REPOS_USER=$reposUser,PATCH_HOME=$patchHome,ORACLE_HOME=$oracleHome,PATCH_MODE_SELECT=postAction,NZDT_MODE=false";       
    $RCU_COMMAND_ARGS_2=$RCU_COMMAND_ARGS_2." -component EM_PATCH_ROLLBACK"; 
##Adding ssl params 
if ($keyStore ne "") {
        $RCU_COMMAND_ARGS_2=$RCU_COMMAND_ARGS_2." -useSSL -sslArgs javax.net.ssl.trustStore=$trustStore,javax.net.ssl.trustStoreType=$trustStoreType,javax.net.ssl.keyStore=$keyStore,javax.net.ssl.keyStoreType=$keyStoreType,oracle.net.ssl_server_dn_match=$serverDnMatchForRollback -sslPasswordArgNames javax.net.ssl.keyStorePassword,javax.net.ssl.trustStorePassword -schemaPrefix SSL1  -serverDN CN=server,OU=ST,O=Oracle,ST=California,C=US";
}
elsif ($trustStore ne "") {
        $RCU_COMMAND_ARGS_2=$RCU_COMMAND_ARGS_2." -useSSL -sslArgs javax.net.ssl.trustStore=$trustStore,javax.net.ssl.trustStoreType=$trustStoreType,oracle.net.ssl_server_dn_match=$serverDnMatchForRollback -sslPasswordArgNames javax.net.ssl.trustStorePassword -schemaPrefix SSL1 -serverDN CN=server,OU=ST,O=Oracle,ST=California,C=US";
}

print(" Post rollbacksysPwd:trustStore:$trustStore trustStoreType:$trustStoreType                keyStore:$keyStore keyStoreType:$keyStoreType");


  my $cmd = "$RCU $RCU_COMMAND_ARGS_2";         
  if($NT)  
  {  
    $cmd =  "$RCU.bat $RCU_COMMAND_ARGS_2";   
  }  
  #print "\n$cmd\n";
  print "\n***********************************************\n";    
  print "Executing Post Patch Action Steps.....\n";    
print "\n$cmd\n";
  print "\n***********************************************\n";    

  my $fh2 = IO::Handle->new();
  $pid = open3($fh2, '>&STDOUT', '>&STDERR', $cmd);
 
 if ($keyStorePassword ne "") {
        $fh2->print("$keyStorePassword\n");
 }if ($trustStorePassword ne "") {
        $fh2->print("$trustStorePassword\n");
   }
        $fh2->print("$sysPassword\n");

 $fh2->close;  
  waitpid($pid,0);
  my $child_exit_status2  = $? >> 8;

  my $newName;
  my $newName_dbmsOut;
  my $newRcuLogHome = File::Spec->catfile($oracleHome,'oracle_common','rcu', 'log', 'empatch','logs');
	if (! -e $newRcuLogHome) {
	mkpath($newRcuLogHome);
	}
  
  # Rename log files
  eval 
  {
    my $oldName = File::Spec->catfile($rcuLogHome,'logs',"em_patch_rollback.log");
    $newName = File::Spec->catfile($newRcuLogHome,$rcuLogFileName.".log");
    
    print "\nRenaming logfile $oldName to $newName\n";
    
    rename($oldName, $newName);        
    
    my $oldName_dbmsOut = File::Spec->catfile($rcuLogHome,'logs',"em_patch_rollback_dbmsOutput.log");  
    $newName_dbmsOut = File::Spec->catfile($newRcuLogHome,$rcuLogFileName."_dbmsOutput.log");
    
    print "\nRenaming logfile $oldName_dbmsOut to $newName_dbmsOut\n";
    
    rename($oldName_dbmsOut, $newName_dbmsOut);          
    
    1;
  }
  or do 
  {
    print "Error renaming log files";
  };

  $child_exit_status = $child_exit_status1 + $child_exit_status2;
  if ($child_exit_status != 0)
  { 
  	 print "\n****************************************************************************\n";
  	 print "\n****************************************************************************\n";
     print "\nPATCH ROLLBACK HAS FAILED" ;
     print "\n\nPlease review the following log files of Repository Patching Utility to determine error:";
     print "\nPatch Log: $newName";
     print "\nPatch DbmsOutLog: $newName_dbmsOut";
     print "\nRCU Core Log: $rcuCoreLog";
     print "\nPATCH ROLLBACK HAS FAILED" ;
  	 print "\n***************************************************************************\n";
     print "\n***************************************************************************\n";
  }
  else
  {
   	print "\n****************************************************************************\n";
   	print "\n****************************************************************************\n";
    print "\nPATCH ROLLBACK HAS SUCCEEDED";
    print "\n***************************************************************************\n";
    print "\n***************************************************************************\n";
  }
  
  if($rpuFlag eq 'true' && -e $rollbackFilesBackup){
	  print "Renaming $rollbackFiles to $predowntimeRollbackFiles\n";
	  rename($rollbackFiles, $predowntimeRollbackFiles);
	  print "Renaming $rollbackFilesBackup to $rollbackFiles\n";
	  rename($rollbackFilesBackup, $rollbackFiles);	 
  }
  exit($child_exit_status);  
}

sub calculateDelta(){
# move the rollback_files.sql to rollback_file.sql_org
my $rollbackFiles = File::Spec->catfile($patchHome,"rollback_files.sql");
my $rollbackOrgFiles = File::Spec->catfile($patchHome,"rollback_files.sql_org");
print "------------ Renaming $rollbackFiles to $rollbackOrgFiles --- \n";
rename($rollbackFiles, $rollbackOrgFiles);

unlink($rollbackFiles);
# read rollback_file.sql_org 
open(FH, '<', $rollbackOrgFiles) or die "File '$rollbackOrgFiles' can't be opened";

# replace the @ORACLE_HOME and @PLUGIN_HOME with the relevant value

$OHfind = "@&ORACLE_HOME";
$OHreplace = $oracleHome;
$PLfind = "@&PLUGIN_HOME";
$PLreplace = $pluginHome;

my $filecontent = "";
# read each entry from rollback_file.sql_org 
while(<FH>)
{
    $line = $_;
    $path = $line;

    if ((index ($path, '@&PATCH_HOME') != -1) || (index ($path, '.sql') == -1)){
        chomp($path);
        print "$path : -- add the file\n";
        $filecontent=$filecontent.$line; #."\n";
    }
    else{
        $path =~ s/$OHfind/$OHreplace/g;
        $path =~ s/$PLfind/$PLreplace/g;
        $index = index ($path, ' ');
        $path = substr($path,0, $index);
        chomp($path);
	
	# if it exist write it into rollback_file.sql else skip
        if (-e $path)
        {
            print "$path : File exist -- add the file\n";
            $filecontent=$filecontent.$line; #."\n";
        }
        else{
            print "$path : File does not exist -- skip adding the file\n";
        }
    }
}
close(FH);

open(FH1, '>', $rollbackFiles) or die $!;
print FH1 $filecontent;
close(FH1); 
}
1;
