# $Header: ecmPatchOneOff.pl 31-jan-2005.05:29:53 shgangul Exp $
#
# Copyright (c) 2001, 2005, Oracle. All rights reserved.  
#
#    DESCRIPTION
#      ECM script to patch Oracle RDBMS server using ST one-off patches
#
#    USAGE
#      ecmPatchOneOff.pl <OPERATION> <PATCH_ID> <ORACLE_HOME> <ORACLE_SID>
#                           <PATCH_PATH> <PATCH_FILE>
#
#    NOTES
#      <other useful comments,qualifications,etc>
#
#    MODIFIED     (MM/DD/YY)
#       shgangul   01/31/05 - bug 3845819: MAC OS port 
#       mbhoopat   03/10/04 - linux port 
#       nsharma    01/21/04 - Change nawk to awk on linux
#       xxu        06/25/02 - remove /usr/local/bin/perl
#       mgoodric   11/09/01 - Create a new PatchOneOff job type
#       mgoodric   11/09/01 - Create a new PatchOneOff job type
#
#

# --- Set up necessary variables for proper running of this environment ---
use strict;
use FileHandle;
use File::Basename;
use Config;

my $OSNAME = $Config{'osname'};
my $IsWin32 = ($OSNAME eq 'MSWin32');

# ------ Initialize global variables -------------------------------------
my $EMDROOT     = $ENV{EMDROOT};
my $OPERATION   = $ARGV[0]; # checkTarget | installPatch
my $PATCH_ID    = $ARGV[1]; # 1390304
my $ORACLE_HOME = $ARGV[2]; # /private/OraHome1
my $ORACLE_SID  = $ARGV[3]; # mjgdb817
my $PATCH_PATH  = $ARGV[4]; # ecmdepot/patches/1390304
my $PATCH_FILE  = $ARGV[5]; # p1390304_8170_SOLARIS.zip

# --------------------- Subroutines -------------------------------------
#
# err <ERROR_NUMBER> <ERROR_TEXT>
#
# Display a formatted error message
#
sub err {
  my ($ERROR_NUMBER,$ERROR_TEXT) = @_;
  printf "---------- Error Message ----------\n";
  printf "PAT-%03d:\n",$ERROR_NUMBER;
  printf "%s\n",$ERROR_TEXT;
  printf "----------- End Message -----------\n";
}

#
# err <WARNING_NUMBER> <WARNING_TEXT>
#
# Display a formatted warning message
#
sub warn {
  my ($WARNING_NUMBER,$WARNING_TEXT) = @_;
  printf "--------- Warning Message ---------\n";
  printf "PAT-%03d:\n",$WARNING_NUMBER;
  printf "%s\n",$WARNING_TEXT;
  printf "----------- End Message -----------\n";
}

#
# abort <NUMBER> <TEXT>
#
# Display a formatted error and exit with error status
#
sub abort {
  my ($NUMBER,$TEXT) = @_;
  if ($NUMBER == 0) { $NUMBER = 1; }
  err($NUMBER,$TEXT);
  printf "\n$OPERATION command failed\n";
  exit $NUMBER;
}

#
# checkTarget <PATCH_ID> <PATCH_PATH>
#
# - Verify ORACLE_HOME
# - Create depot directory to store patch
#
sub checkTarget {
  my ($PATCH_ID,$PATCH_PATH) = @_;
  my $_status_ = -1;
  my $ORACLE_HOME = $ENV{'ORACLE_HOME'};
  my $ORACLE_SID = $ENV{'ORACLE_SID'};
  chdir $ORACLE_HOME
    or abort($? >>8,"Could not cd to >$ORACLE_HOME<: $!");
  my $dir = "$ORACLE_HOME/$PATCH_PATH";
  if (! -e $dir)
  {
    system("/bin/mkdir -p $dir") == 0
      or abort($? >>8,"Could not mkdir >$dir<: $!");
  }
  chdir $dir
    or abort($? >>8,"Could not cd to >$dir<: $!");
  system('/bin/ls -1R | /bin/egrep -s \'^undo_pre[0-9]*\\.sh$\'') != 0
    or abort(1,"$PATCH_ID already applied");
  my $_tempfile_ = '_test_';
  open (OUTPUT,'>',$_tempfile_)
    or abort($? >>8,"Could not open file $_tempfile_ to write: $!");
  close (OUTPUT);
  unlink $_tempfile_;
}

#
# installPatch <PATCH_ID> <PATCH_PATH> <PATCH_FILE>
#
# - Unzip the patch
# - Stop the database if running
# - run the patch.sh script
# - restart the database if it was running
#
sub installPatch {
  my ($PATCH_ID,$PATCH_PATH,$PATCH_FILE) = @_;
  my $_status_ = -1;
  my $ORACLE_HOME = $ENV{'ORACLE_HOME'};
  my $ORACLE_SID = $ENV{'ORACLE_SID'};
  my $dir = "$ORACLE_HOME/$PATCH_PATH";
  chdir $dir
    or abort($? >>8,"Could not cd to >$dir<: $!");
  my $unziputil = "/bin/unzip";
  if ($^O eq "darwin")
  {
    $unziputil = "/usr/bin/unzip";
  }
  system("$unziputil -o $PATCH_FILE") == 0
    or abort($? >>8,"Could not unzip $PATCH_FILE");
  my $awkutil = "/bin/nawk";
  if ($^O eq "linux")
  {
    $awkutil = "/bin/awk";
  }
  elsif ($^O eq "darwin")
  {
    $awkutil = "/usr/bin/awk";
  }
  my $_patchhome_ = `/bin/ls -1p | $awkutil '{if (substr(\$0,length(\$0)) == "/") {printf "%s",\$0; exit}}'`;
  chdir $_patchhome_
    or abort($? >>8,"Could not cd to >$_patchhome_<: $!");
  my $_tempfile_ = '';
  system("/bin/ps -ef | /bin/egrep -s \' ora_pmon_$ORACLE_SID\$\'");
  if ($? == 0)
  {
    $_tempfile_ = "/tmp/$ENV{'LOGNAME'}_sqlplus_$$.sql";
    open (OUTPUT,'>',$_tempfile_)
      or abort($? >>8,"Could not open file $_tempfile_ to write: $!");
    print OUTPUT "CONNECT / AS SYSDBA;\n";
    print OUTPUT "SHUTDOWN IMMEDIATE\n";
    print OUTPUT "EXIT\n";
    close (OUTPUT);
    my $_errstatus_ = system("$ORACLE_HOME/bin/sqlplus /nolog \@$_tempfile_");
    unlink $_tempfile_;
    ($_errstatus_ == 0) or abort($_errstatus_ >>8,"Could not shutdown database");
    system("/bin/ps -ef | /bin/egrep -s \' ora_pmon_$ORACLE_SID\$\'") != 0
      or abort(1,"Could not shutdown database");
  }
  my $_orapatch_ = 'patch.sh';
  if (! -e $_orapatch_)
  {
    chmod 0777,$_orapatch_
      or abort($? >>8,"Could not chmod >$_orapatch_<: $!");
  }
  $_status_ = system("./$_orapatch_ </dev/null");
  if ($_tempfile_ ne '')
  {
    open (OUTPUT,'>',$_tempfile_)
      or abort($? >>8,"Could not open file $_tempfile_ to write: $!");
    print OUTPUT "CONNECT / AS SYSDBA;\n";
    print OUTPUT "STARTUP FORCE\n";
    print OUTPUT "EXIT\n";
    close (OUTPUT);
    my $_errstatus_ = system("$ORACLE_HOME/bin/sqlplus /nolog \@$_tempfile_");
    unlink $_tempfile_;
    ($_errstatus_ == 0)
      or abort($_errstatus_ >>8,"Could not startup database");

    system("/bin/ps -ef | /bin/egrep -s \' ora_pmon_$ORACLE_SID\$\'") == 0
     or abort(1,"Could not startup database");
  }
  ($_status_ == 0) or abort($_status_ >>8,"Patch failed");
}

# --------------------- Main program -------------------------------------
$| = 1; # set OUTPUT_AUTOFLUSH

printf "Running: '$0' - #ARGV: $#ARGV\n";
printf "Perl version = $]\n";
printf "Hostname = %s",`hostname`;
printf "Operating system = $^O\n";
printf "Time = %s\n\n",scalar(localtime());

#
# Set ORACLE_HOME environment if present
#
if ($#ARGV >= 3)
{
  if ($ENV{'ORACLE_HOME'} ne $ORACLE_HOME)
  {
    $ENV{'ORACLE_HOME'} = $ORACLE_HOME;
    $ENV{'ORACLE_SID'} = $ORACLE_SID;
    $ENV{'PATH'} = "$ORACLE_HOME/bin:/usr/bin:/usr/ccs/bin:/usr/ucb:$ENV{'PATH'}";
    $ENV{'LD_LIBRARY_PATH'} = "$ORACLE_HOME/lib:$ENV{'LD_LIBRARY_PATH'}";
  }
}

#
# Execute the operation requested
#
if ($OPERATION eq 'checkTarget')
{
  if ($#ARGV < 4)
  {
    abort(3,"Missing args: $#ARGV < 4");
  }
  checkTarget($PATCH_ID,$PATCH_PATH);
}
elsif ($OPERATION eq 'installPatch')
{
  if ($#ARGV < 5)
  {
    abort(3,"Missing args: $#ARGV < 5");
  }
  installPatch($PATCH_ID,$PATCH_PATH,$PATCH_FILE);
}
else
{
  abort(5,"Unrecognized operation: $OPERATION");
}

#
# Indicate a successful operation exit with success status
#
printf "\n$OPERATION command successful\n";
exit 0;
