#!/usr/local/bin/perl
# 
# $Header: has/install/crsconfig/s_crsconfig_lib.pm /st_has_11.2.0/35 2011/08/29 19:34:07 minzhu Exp $
#
# s_crsconfig_lib.pm
# 
# Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved. 
#
#    NAME
#      s_crsconfig_lib.pm - <one-line expansion of the name>
#
#    DESCRIPTION
#      <short description of component this file declares/defines>
#
#    NOTES
#      <other useful comments, qualifications, etc.>
#
#    MODIFIED   (MM/DD/YY)
#    minzhu      08/18/11 - 12857064 if 5.11 & upgrade, disable HAIP
#    xyuan       07/14/11 - Fix bug 12698968,12728939
#    jchandar    07/07/11 - bug 12574874, set LC_ALL to C
#    rdasari     06/28/11 - add EXTSHM=OFF for aix
#    gmaldona    06/09/11 - add run_as_user3 function.
#    xyuan       05/25/11 - Fix bug 12576508
#    smatpadi    05/23/11 - Bug/12582737
#    smatpadi    05/03/11 - Bug/12410027
#    rdasari     04/29/11 - downgrade
#    smatpadi    04/04/11 - Backport smatpadi_bug-11071429 from main
#    shullur     01/31/11 - XbranchMerge shullur_bug-11675864 from main
#    ahabbas     01/28/11 - Backport ahabbas_bug-11077756 from main
#    ksviswan    01/20/11 - Backport ksviswan_janbugs2 from main
#    dpham       01/19/11 - Backport dpham_bug-10189035 from st_has_11.2.0
#    dpham       01/19/11 - Backport dpham_bug-10306520 from st_has_11.2.0
#    dpham       01/06/11 - Backport dpham_bug-10073372 from main
#    ahabbas     12/14/10 - Backport ahabbas_bug-10260251 from main
#    minzhu      12/14/10 - Backport minzhu_bug-10375649 from main
#    dpham       11/29/10 - Fix bug 10074540
#    ahabbas     08/26/10 - bug#10053985 - check for solaris 11 and ipmp
#    dpham       08/10/10 - Fix bug 10011430
#    dpham       08/09/10 - Fix bug 9962532
#    ahabbas     08/06/10 - bug#9930739 - disable zeroconf on linux
#    ksviswan    08/03/10 - Fix Bugs 9962938,9963005,9962532
#    ksviswan    08/01/10 - fix s_SetParentDirOwner
#    dpham       07/22/10 - Fix bug 9931050
#    ankkhand    07/21/10 - Backport ankkhand_bug-9860018 from main
#    dpham       07/15/10 - Fix bug 9879090
#    dpham       07/14/10 - Fix bug 9133502
#    jchandar    07/14/10 - support 1GB per node space for 11.2
#    jchandar    07/12/10 - XbranchMerge jchandar_bug-9440492 from main
#    jchandar    07/05/10 - support not-english LANG while using system command
#    minzhu      06/23/10 - not install HAIP if sun cluster
#    rdasari     06/14/10 - check the status of system cmds
#    fjlee       06/11/10 - bug9391709 add /etc/rc.d/rc3.d/K15ohasd and change
#                           K19ohasd to K15ohasd
#    ksviswan    06/03/10 - Fix Bugs 9732945,9737629,9773975,9723851 and 9785215
#    dpham       06/01/10 - Fix bug 9648820
#    dpham       05/20/10 - Not to remove oratab during deinstall if SIHA (8680498
#    ksviswan    05/14/10 - Fix bug 9409199
#    dpham       04/27/10 - Fix bug 9559013 & 9446443
#    dpham       04/05/10 - Fix bug 9541617
#    dpham       04/05/10 - Fix bug 9496702
#    spavan      03/22/10 - fix bug 9454517
#    dpham       03/17/10 - Get TZ variable from param file (9462081
#    sukumar     03/17/10 - Enable Solaris.
#    dpham       01/07/09 - Fix security bug (8275055
#    dpham       02/12/10 - Fix s_validate_olrconfig() to set olr to 0644
#    ksviswan    02/11/10 - Fix Bug 8666579
#    dpham       02/03/10 - Capture command output in s_stop_OldCrsStack()
#    ksviswan    01/28/10 - Fix Bug 8563348
#    dpham       01/25/10 - Fix s_copyOCRLoc() function to always return TRUE
#			  - Remove oratab and lastgasp when deconfig
#    dpham       01/07/09 - Fix security bug (8275055
#    dpham       01/07/10 - Add strict
#    dpham       01/04/10 - Check if $SCRBASE dir exists (8732192)
#    sujkumar    12/26/09 - Remove shared filesytem check from bdb checks
#    ksviswan    12/18/09 - Fix Bug 8680498. 
#    jachang     12/02/09 - Add RT_GRQ into envvar file for AIX
#    dpham       11/17/09 - Not trace '*** not exists' during deconfig (8942028)
#    dpham       11/24/09 - XbranchMerge dpham_bug-9067738 from st_has_11.2.0.1.0
#    sujkumar    11/17/09 - Change BDB check loc ERROR messages to INFO
#                           messages
#    ksviswan    11/11/09 - Fix Bug 8739716,8565910
#    dpham       10/12/09 - Add s_getAbsLink (9004597
#    sujkumar    09/22/09 - Add IPD/OS related changes
#    dpham       09/14/09 - XbranchMerge dpham_bug-8484319 from
#                           st_has_11.2.0.1.0
#    dpham       09/04/09 - /etc/oracle is removed only if it's empty (8798767)
#    hchau       08/21/09 - Bug 8716580, 8276914. Unset TNS_ADMIN and
#                           ORACLE_BASE env vars in the ENV file.
#    dpham       08/21/09 - XbranchMerge dpham_bug-8776078 from
#                           st_has_11.2.0.1.0
#    dpham       08/19/09 - XbranchMerge dpham_bug-8395346 from main
#    dpham       08/19/09 - XbranchMerge dpham_bug-8726265 from
#                           st_has_11.2.0.1.0
#    hchau       08/17/09 - Sync comment on ENV VAR file syntax from
#                           crswrapexec.pl
#    dpham       08/17/09 - Add 'return' to no-op functions
#    dpham       08/10/09 - XbranchMerge dpham_bug8762050 from
#                           st_has_11.2.0.1.0
#    dpham       08/04/09 - Fix 'signal 2' issue (bug 8762050
#    dpham       07/31/09 - Fix bug 8395346
#    dpham       07/15/09 - XbranchMerge dpham_bug-8664938 from main
#    dpham       07/09/09 - 'crs_stat' should be used to check if it's runnnig in 10.1
#    dpham       07/08/09 - zero out ocr device only if it's not on ASM
#			  - Add new blank line before add daemon in inittab
#    hchau       07/07/09 - Bug 8657323. Fix TZ not retrieved correctly from
#                           ORACLE_OWNER
#    dpham       06/30/09 - Print error in s_copyOCRLoc() only if it failed to copy
#    ksviswan    06/24/09 - Fix Bug 8626827 and 8630938
#    dpham       06/22/09 - Capture error output from cluutil.
#			  - Remove extra 'print' statement from s_run_as_user2
#    dpham       06/17/09 - Add logic to remove /etc/oratab
#    vmanivel    06/16/09 - Bug 8582457
#    dpham       06/16/09 - Remove 'set ocrconfig_loc to srvconfig_loc' in 
#			    s_validateOCR for 9i
#    dpham       06/15/09 - Add ocrconfig_loc3 and ocrconfig_loc4 check in s_validateOCR
#    dpham       06/01/09 - 'cluutil' should be run as oracle owner
#			  - s_removeGPnPprofile() should only remove contents
#    dpham       05/31/09 - Change msg in s_isRAC_appropriate()
#    nvira       05/28/09 - specify --allmatches option to cvuqdisk rpm -e
#                           command
#    jgrout      05/22/09 - Fix bug 8540887
#    dpham       05/20/09 - Add s_copyOCRLoc & s_removeGPnPprofile
#    jgrout      05/11/09 - Use "crsctl start has" instead of "ohasd reboot &"
#    dpham       05/11/09 - Add s_is92ConfigExists
#    dpham       04/27/09 - Add s_houseCleaning
#                         - Add an arguement to s_remove_itab
#    spavan      04/22/09 - fix bug8424504 - Mask old RPM removal error
#    dpham       04/15/09 - Add s_createLocalOnlyOCR
#    ksviswan    04/15/09 - XbranchMerge ksviswan_rootmisc_fixes from
#                           st_has_11.2beta2
#    ksviswan    04/13/09 - Remove ocr.loc on lastnode for all storage type
#    dpham       04/08/09 - XbranchMerge dpham_bug-8412144 from main
#    dpham       04/07/09 - XbranchMerge dpham_bug-8400917 from main
#    dpham       04/07/09 - Fix s_crsconfig_$HOST_env file.
#    dpham       04/02/09 - Check OldCrsStack for 10.1
#    dpham       03/27/09 - Add comments in s_createConfigEnvFile
#    spavan      03/25/09 - fix bug7700245
#    dpham       03/20/09 - Return to caller if failed in s_validateOCR
#    dpham       03/15/09 - Do not remove contents from OCR device if it's on ASM
#			  - Fix /tmp/.oracle & /var/tmp/.oracle
#    dpham       02/23/09 - Remove /etc/oracle if it's empty
#    dpham       02/22/09 - Modify s_get_olr_file to eccept arguement
#    dpham       02/04/09 - Add s_isRAC_appropriate to check for rac_on/rac_off
#    dpham       01/09/09 - Rename s_setParentDir2Root to s_setParentDirOwner
#                         - Change its functionality so that it should be able
#                           to handle any dir and any owner.
#    dpham       01/05/09 - Remove single quote from LANGUAGE_ID
#    ksviswan    12/29/08 - Add s_check_OldCrsStack
#    hchau       12/12/08 - Add 'DO NOT TOUCH' comment in config env file
#                         - Fix config env file name
#    ksviswan    11/19/08 - Add s_ResetOLR for SIHA
#    dpham       11/14/08 - Add s_checkOracleCM
#                         - Add s_createConfigEnvFile for Time Zone
#    dpham       10/23/08 - Add s_start_ocfs_driver
#    dpham       10/14/08 - Add s_ResetVotedisks
#    jleys       08/17/08 - Start OHASD as user for SIHA
#    jleys       10/02/08 - Add leading 0 to chmod in s_Reset_OCR
#    dpham       08/28/08 - add s_setParentDir2Root  
#    khsingh     08/04/08 - add API to change owners on CRS files
#    khsingh     07/31/08 - fix s_clean_rcdirs
#    jleys       06/01/08 - Do not start ohasd using s_run_as_user
#    jgrout      05/21/08 - Restore explicit OHASD fork to avoid
#                           security issues in crsctl start has
#    hkanchar    05/04/08 - Fix getOldCrsHome
#    dpham       04/28/08 - Add new subroutines for root deconfig 
#    ysharoni    04/22/08 - rc fix for run_as_user2
#    jgrout      04/04/08 - Fix bug 6897603
#    hkanchar    03/30/08 - Move somepart of upgrade code to OSDS
#    srisanka    03/25/08 - bug 6915812: replace check for file/dir with check
#                           for existence of path
#    jgrout      03/21/08 - Create OHASD autostart and run files
#    srisanka    03/18/08 - handle stdout/stderr
#    ysharoni    02/21/08 - add run_as_user2
#    jtellez     02/17/08 - check for inittab exitance
#    jtellez     02/17/08 - bug 6822192: fix perms on init files
#    srisanka    02/14/08 - add OSD setup APIs
#    srisanka    01/31/08 - add s_isLink() API
#    srisanka    01/28/08 - use s_get_config_key()
#    srisanka    01/09/08 - Creation
#
use strict;
use English;
use File::Copy;
use Fcntl ':mode';
use POSIX qw(tmpnam);
use Cwd;
use crsconfig_lib;

use constant TRUE       =>  "1";
use constant FALSE	=>  "0";

my @ns_dir    = ("/var/tmp/.oracle","/tmp/.oracle");
my $dev_null  = "/dev/null";
my $FSSEP     = "/";
my ($ARCHIVE, $INITD, $ENVMT);

my $oelNetworkConfig  = "/etc/sysconfig/network";
my $suseNetworkConfig = "/etc/sysconfig/network/config";

my $checkNetworkTemp = ".orcl.tmp.$$";
my $checkNetworkSave = ".orcl.$$";

# Linux Upstart definitions and globals
my $UPSTART_OHASD_SERVICE   = "oracle-ohasd";
my $UPSTART_OHASD_CONF_FILE = "oracle-ohasd.conf";
my $RESTORECON              = "/sbin/restorecon";
my $UPSTART_USED            = -1;

if ($OSNAME eq 'linux') {
   $INITD   = '/etc/init.d';
   $ARCHIVE = '/usr/bin/ar';
   $ENVMT   = '/usr/bin/env';
} elsif ($OSNAME eq 'solaris') {
   $INITD   = '/etc/init.d';
   $ARCHIVE = '/usr/ccs/bin/ar';
   $ENVMT   = '/usr/bin/env';
} elsif ($OSNAME eq 'hpux') {
   $INITD   = '/sbin/init.d';
   $ARCHIVE = '/usr/ccs/bin/ar';
   $ENVMT   = "/bin/env";
} elsif ($OSNAME eq 'aix') {
   $INITD   = '/etc';
   $ARCHIVE = '/usr/ccs/bin/ar -X64';
   $ENVMT   = '/usr/bin/env';
} elsif ($OSNAME eq 'dec_osf') {
   $INITD   = '/sbin/init.d';
   $ARCHIVE = '/usr/bin/ar';
   $ENVMT   = '/usr/bin/env';
}

sub system {
  return system_cmd(@_);
}

####---------------------------------------------------------
#### Function for checking and returning Super User name
# ARGS : 0
sub s_check_SuperUser
{
    my $superUser = "root";
    my $program   = "this script";

    # get user-name
    my $usrname = getpwuid ($<);
    if ($usrname ne $superUser) {
        error ("You must be logged in as $superUser to run $program.");
        error ("Log in as $superUser and rerun $program.");
        return "";
    }

    return $superUser;
}

####---------------------------------------------------------
#### Function for setting user and group on a specified path
# ARGS : 3
# ARG1 : Oracle owner
# ARG2 : Oracle group 
# ARG3 : file
sub s_set_ownergroup
{
    my ($owner, $group, $file) = @_;

    if (!$owner) {
        error ("Null value passed for Oracle owner");
        return $FAILED;
    }

    if (!$group) {
        error ("Null value passed for group name");
        return $FAILED;
    }

    if (!$file) {
        error ("Null value passed for file or directory path");
        return $FAILED;
    }

    if (!(-e $file)) {
        error ("The path \"" . $file . "\" does not exist");
        return $FAILED;
    }

    my $uid = getpwnam ($owner);
    my $gid = getgrnam ($group);
    if ($DEBUG) {
	trace("Setting owner ($owner:$uid) and group ($group:$gid) on file $file");
    }

    if (! chown ($uid, $gid, $file)) {
       error ("Can't change ownership of $file: $!");
       return $FAILED;
    }

    return $SUCCESS;
}

####---------------------------------------------------------
#### Function for resetting owner and permissions of CRS home dirs/files
# ARGS : 4
# ARG1 : Oracle owner
# ARG2 : Oracle group
# ARG3 : perms
# ARG4 : directory path
sub s_reset_crshome
{
    my ($owner, $group, $perms, $basedir) = @_;
    my $exclfile = catfile($CFG->ORA_CRS_HOME, 'crs', 'install', 'install.excl');
    s_reset_crshome1($owner, $group, $perms, $basedir, $exclfile);
}

####-------------------------------------------------------------
####---------------------------------------------------------
#### Function for resetting owner and permissions of CRS home dirs/files
# ARGS : 5
# ARG1 : Oracle owner
# ARG2 : Oracle group
# ARG3 : perms
# ARG4 : directory path
sub s_reset_crshome1
{
    if (is_dev_env()) {
        return $SUCCESS;
    }

    my ($owner, $group, $perms, $basedir, $exclfile) = @_;

    if (!$owner) {
        error ("Null value passed for Oracle owner");
        return $FAILED;
    }

    if (!$group) {
        error ("Null value passed for group name");
        return $FAILED;
    }

    my $userid   = getpwnam ($owner);
    my $groupid  = getgrnam ($group);

    my @excl_dir = ();

    if (-e $exclfile) 
    {
      @excl_dir = read_file ($exclfile); 
    }

    # reset owner/group of basedir and its parent dir to ORACLE_OWNER/DBA
    finddepth (\&reset_perms, $basedir);

    sub reset_perms
    {
      #Just give write permissions to grid owner for all files
      #during reset and exclude links .
      if (! -l $_) {
         my ($dev,$ino,$mode) = lstat($_);
         $perms = S_IMODE($mode);
         my $origperm = sprintf "%04o", $perms;
         $perms = $perms | 128;
         my $newperm = sprintf "%04o", $perms;

         if (SetPerms()) {
           if ($DEBUG) {
              trace("orig perm for $_ is $origperm, setting file perm to $newperm");
           }

	 chown ($userid, $groupid, $_);
	 chmod (oct ($newperm), $_);
         }
      }
    }

    sub SetPerms
    {
       if (! $CFG->UNLOCK) {
          return TRUE;
       }

       # if UNLOCK, bypass files that are in exclude dir
       my $setperms = TRUE;
       foreach my $dir (@excl_dir) {
          chomp ($dir);
          next if ($dir =~ /^#|^\s*$/);  # skip blanks and comments

	  # do not set perms if file is on execluded dir
          if ($File::Find::dir =~ /$dir/) {
              $setperms = FALSE;
          }
       }

       return $setperms;
    }

    return $SUCCESS;
}

####---------------------------------------------------------
#### Function for setting permissions on a specified path
# ARGS : 2
# ARG1 : permissions
# ARG3 : file/dir
sub s_set_perms
{
    my ($perms, $file) = @_;

    if (!$perms) {
        error ("Null value passed for permissions");
        return $FAILED;
    }

    if (!$file) {
        error ("Null value passed for file or directory path");
        return $FAILED;
    }

    if (!(-e $file)) {
        error ("The path \"" . $file . "\" does not exist");
        return "$FAILED";
    }

   if ($DEBUG) { trace ("Setting permissions ($perms) on file/dir $file"); }

   if ($CFG->IS_SIHA) {
      if (is_dev_env()) {
         if (! chmod (oct($perms), $file)) {
            error ("Can't change permissions of $file: $!");
            return $FAILED;
         }
      }
      elsif (! chmod (((oct($perms)) & oct(4770)), $file)) {
         error ("Can't change permissions of $file: $!");
         return $FAILED;
      }
   }
   elsif (! chmod (oct($perms), $file)) {
      error ("Can't change permissions of $file: $!");
      return $FAILED;
   }

   return $SUCCESS;
}

####---------------------------------------------------------
#### Functions for copying script to init directory
# ARGS : 2
# ARG1 : init script name
# ARG2 : destination file
sub s_copy_to_initdir
{
    my $sourcefile = $_[0];
    my $destfile = $_[1];

    if (!$sourcefile) {
        error ("The init script file name passed is null");
        return $FAILED;
    }

    if (!(-f $sourcefile)) {
        error ("The init script file \"" . $sourcefile . "\" does not exist");
        return $FAILED;
    }

    trace ("init file = " . $sourcefile);

    trace ("Copying file " . $sourcefile . " to " . $ID . " directory");
    copy ($sourcefile, catfile ($ID, $destfile)) or return $FAILED;

    trace ("Setting " . $destfile . " permission in " . $ID . " directory");
    s_set_perms ("0755", catfile ($ID, $destfile)) or return $FAILED;
    return $SUCCESS;
}

####---------------------------------------------------------
#### Functions for copying script to init directory
# ARGS : 1
# ARG1 : init script name
# ARG1 : dest name
sub s_copy_to_rcdirs
{
    my $sourcefile = $_[0];
    my $destfile = $_[1];

    if (!$sourcefile) {
        error ("The init script file name passed is null");
        return $FAILED;
    }

    if (!(-f $sourcefile)) {
        error ("The init script file \"" . $sourcefile . "\" does not exist");
        return $FAILED;
    }

    trace ("init file = " . $sourcefile);

    # Copy to init dir
    trace ("Copying file " . $sourcefile . " to " . $ID . " directory");
    copy ($sourcefile, catfile ($ID, $destfile)) or return $FAILED;
    trace ("Setting " . $destfile . " permission in " . $ID . " directory");
    s_set_perms ("0755", catfile ($ID, $destfile)) or return $FAILED;

    if (s_isSUSELinux()) {
       # for SUSE Linux, do not create link to the file in the init dir
       return $SUCCESS;
    }

    # Create a link to the file in the init dir
    my @RCSDIRLIST = split (/ /, $RCSDIR);
    foreach my $rc (@RCSDIRLIST) {
        trace ("Removing \"" . $rc . "/" . $RC_START . $destfile . "\"");
        s_remove_file ("$rc/$RC_START$destfile");
        trace ("Creating a link \"" . catfile ($rc, "$RC_START$destfile") .
               "\" pointing to " . catfile ($ID, $destfile));
        symlink (catfile ($ID, $destfile), catfile($rc, "$RC_START$destfile"))
            or return $FAILED;
    }

    my @RCKDIRLIST = split (/ /, $RCKDIR);
    foreach my $rc (@RCKDIRLIST) {
        trace ("Removing \"" . $rc . "/" . $RC_KILL . $destfile . "\"");
        s_remove_file ("$rc/$RC_KILL$destfile");
        trace ("Creating a link \"" . catfile ($rc, "$RC_KILL$destfile") .
               "\" pointing to " . catfile ($ID, $destfile));
        symlink (catfile ($ID, $destfile), catfile ($rc, "$RC_KILL$destfile"))
            or return $FAILED;
    }

    trace ("The file " . $destfile .
           " has been successfully linked to the RC directories");

    return $SUCCESS;
}

####---------------------------------------------------------
#### Functions for removing script from rc directories
# ARGS : 1
# ARG1 : init script name
sub s_clean_rcdirs
{
    my $file = $_[0];

    if (!$file) {
        error ("Null value passed for init script file name");
        return $FAILED;
    }

    trace ("Init file = " . $file);
    trace ("Removing \"" . $file . "\" from RC dirs");

    #remove old ones
    if ($RCALLDIR) {
        my ($rc, $rcStartFile, $rcKillFile, $rcKillOldFile, $rcKillOld2File);
        my @RCALLDIRLIST = split (/ /, $RCALLDIR);

        foreach $rc (@RCALLDIRLIST) {
            if ($RC_START) {
                $rcStartFile = catfile ($rc, "$RC_START$file");
                s_remove_file ("$rcStartFile");
            }

            if ($RC_KILL) {
                $rcKillFile = catfile ($rc, "$RC_KILL$file");
                s_remove_file ("$rcKillFile");
            }

            if ($RC_KILL_OLD) {
                $rcKillOldFile = catfile ($rc, "$RC_KILL_OLD$file");
                s_remove_file ("$rcKillOldFile");
            }
            if ($RC_KILL_OLD2) {
                $rcKillOld2File = catfile ($rc, "$RC_KILL_OLD2$file");
                s_remove_file ("$rcKillOld2File");
            }
        }
    }
}

####---------------------------------------------------------
#### Function for adding CRS entries to inittab
# ARGS : 0
sub s_add_itab
{
    # If upstart is being used, then add the upstart conf file.
    if (s_is_Linux_Upstart())
    {
      return (s_add_upstart_conf());
    }

    my $INITTAB_CH = catfile ($ORA_CRS_HOME, "crs", "install", "inittab");
    if (-e $INITTAB_CH) {

        unless (open (ITAB, "<$IT")) {
            error ("Can't open $IT for reading: $!");
            return $FAILED;
        }
        unless (open (ITABNOCRS, ">$IT.no_crs")) {
            error ("Can't open $IT.no_crs for writing: $!");
            return $FAILED;
        }

        # Remove ohasd from inittab
        while (<ITAB>) {
            if (!($_ =~ /init.ohasd/)) {
                print ITABNOCRS "$_";
            }
        }
        close (ITABNOCRS);
        close (ITAB);
        trace("Created backup $IT.no_crs");

        unless (copy ("$IT.no_crs", "$IT.tmp")) {
            error ("Can't copy $IT.no_crs to $IT.tmp: $!");
            return $FAILED;
        }

        unless (open (CRSITAB, "<$INITTAB_CH")) {
            error ("Can't open $INITTAB_CH for reading: $!");
            return $FAILED;
        }

        unless (open (ITABTMP, ">>$IT.tmp")) {
            error ("Can't open $IT.tmp for append: $!");
            return $FAILED;
        }

        trace ("Appending to $IT.tmp:");
        while (<CRSITAB>) {
            print ITABTMP "\n";
            print ITABTMP "$_";
            trace ("$_");
        }
        close (ITABTMP);
        close (CRSITAB);
        trace ("Done updating $IT.tmp");

        unless (copy ("$IT.tmp", "$IT.crs")) {
            error("Can't copy $IT.tmp to $IT.crs: $!");
            return $FAILED;
        }
        trace("Saved $IT.crs");

        unless (move ("$IT.tmp", $IT)) {
            error("Can't move $IT.tmp to $IT: $!");
            return $FAILED;
        }
        trace("Installed new $IT");
    } else {
        error("$INITTAB_CH does not exist.");
        return $FAILED;
    }

    return $SUCCESS;
}

####---------------------------------------------------------
#### Function for removing CRS entries from inittab
# ARGS : 1 - match pattern for inittab entries
sub s_remove_itab
{
    my $match_pattern = $_[0];
    trace ("itab entries=$match_pattern");

    # If upstart is being used, then remove the conf files
    if (s_is_Linux_Upstart())
    {
       return (s_remove_upstart_conf($match_pattern));
    }

    unless (open (ITAB, "<$IT")) {
        print "Can't open $IT for reading: $!";
        return $FAILED;
    }
    unless (open (ITABTMP, ">$IT.tmp")) {
        print "Can't open $IT.tmp for writing: $!";
        return $FAILED;
    }

    while (<ITAB>) {
        if (!($_ =~ /init.($match_pattern)/)) {
            print ITABTMP "$_";
        }
    }
    close (ITABTMP);
    close (ITAB);

    unless (copy ("$IT.tmp", "$IT.no_crs")) {
        print "Can't copy $IT.tmp to $IT.no_crs: $!";
        return $FAILED;
    }

    unless (move ("$IT.tmp", $IT)) {
        print "Can't move $IT.tmp to $IT: $!";
        return $FAILED;
    }

    return $SUCCESS;
}
#
####-----------------------------------------------------------------------
#### Function for performing clusterwide one-time setup
# ARGS: 0
sub s_first_node_tasks
{
    # no-op on Linux
    return $SUCCESS;
}

####-----------------------------------------------------------------------
#### Function for performing Linux-specific setup
# ARGS: 0
sub s_osd_setup
{
    # no-op on Linux
    return $SUCCESS;
}

####-----------------------------------------------------------------------
#### Function for checking if CRS is already configured
# ARGS: 2
# ARG1: hostname
# ARG2: crs user
sub s_check_CRSConfig
{
    my $hostname = $_[0];
    my $crsuser = $_[1];

    my $SCRDIR = catfile ($SCRBASE, $hostname);
    my $FATALFILE = catfile ($SCRDIR, $crsuser, "cssfatal");
    if ((-f $FATALFILE) && (-f $OCRCONFIG)) {
        trace ("Oracle CRS stack is already configured and will be " .
               "running under init \(1M\)");
        return TRUE;
    } else {
        trace ("Oracle CRS stack is not configured yet");
        return FALSE;
    }
}

####-----------------------------------------------------------------------
#### Function for validating olr.loc file and creating it if does not exist
# ARGS: 2
# ARG1 : Complete path of OLR location
# ARG2 : CRS Home
sub s_validate_olrconfig
{
    my $olrlocation = $_[0];
    my $crshome     = $_[1];

    trace ("Validating " . $OLRCONFIG .
           " file for OLR location " . $olrlocation);

    ## @todo Check existing olr.loc file. If it exists, then check value of
    #  olrconfig_loc property. If it's same as the one passed on the call
    #  then go ahead. Else, throw an error msg and quit the installation.
    if (-f $OLRCONFIG) {
        trace ("$OLRCONFIG already exists. Backing up " . $OLRCONFIG .
               " to " . $OLRCONFIG . ".orig");
        # Need to remove this once the @todo is implemented.
        copy ($OLRCONFIG, $OLRCONFIG . ".orig") or return $FAILED;
    }

    open (OLRCFGFILE, ">$OLRCONFIG") or return $FAILED;
    print OLRCFGFILE "olrconfig_loc=$olrlocation\n";
    print OLRCFGFILE "crs_home=$crshome\n";
    close (OLRCFGFILE);

    #FIXME: This should be moved to add_olr_ocr_vdisks_locs
    if (is_dev_env()) {
       s_set_ownergroup ($ORACLE_OWNER, $ORA_DBA_GROUP, $OLRCONFIG);
    } 
    else {
       s_set_ownergroup ($SUPERUSER, $ORA_DBA_GROUP, $OLRCONFIG);
    }

    s_set_perms ("0644", $OLRCONFIG);

    trace("Done setting permissions on file $OLRCONFIG");

    return $SUCCESS;
}

sub s_get_olr_file
#-------------------------------------------------------------------------------
# Function:  Get key from olr.loc
# Args    :  1 - key
# Returns :  Key's value
#-------------------------------------------------------------------------------
{
    my $key = $_[0];
    my $ret = "";

    if (!(-r $OLRCONFIG)) {
        error ("Either " . $OLRCONFIG . " does not exist or is not readable");
        error ("Make sure the file exists and it has read and execute access");
        return $ret;
    }

    open (OLRCFGFILE, "<$OLRCONFIG") or return $ret;
    while (<OLRCFGFILE>) {
        if (/^$key=(\S+)/) {
            $ret = $1;
            last;
        }
    }
    close (OLRCFGFILE);

    return $ret;
}

####---------------------------------------------------------
#### Function for validating ocr.loc file
# ARGS: 2
# ARG1 : ocrlocations
# ARG2 : isHas
sub s_validate_ocrconfig
{
    my $ocrlocations = $_[0];
    my $isHas        = $_[1];

    trace ("Validating OCR locations in " . $OCRCONFIG);

    trace ("Checking for existence of " . $OCRCONFIG);
    if (-f $OCRCONFIG) {
        trace ("Backing up " . $OCRCONFIG . " to " . $OCRCONFIG . ".orig");
        copy ($OCRCONFIG, $OCRCONFIG . ".orig") or return $FAILED;
    }

    my ($ocrlocation,
        $ocrmirrorlocation,
        $ocrlocation3,
        $ocrlocation4,
        $ocrlocation5) = split (/\s*,\s*/, $ocrlocations);

    open (OCRCFGFILE, ">$OCRCONFIG") or return $FAILED;

    trace ("Setting ocr location " . $ocrlocation);
    print OCRCFGFILE "ocrconfig_loc=$ocrlocation\n";

    if ($ocrmirrorlocation) {
        trace ("Setting ocr mirror location " . $ocrmirrorlocation);
        print OCRCFGFILE "ocrmirrorconfig_loc=$ocrmirrorlocation\n";
    }

    if ($ocrlocation3) {
        trace ("Setting ocr location3 " . $ocrlocation3);
        print OCRCFGFILE "ocrconfig_loc3=$ocrlocation3\n";
    }

    if ($ocrlocation4) {
        trace ("Setting ocr location4 " . $ocrlocation4);
        print OCRCFGFILE "ocrconfig_loc4=$ocrlocation4\n";
    }

    if ($ocrlocation5) {
        trace ("Setting ocr location5 " . $ocrlocation5);
        print OCRCFGFILE "ocrconfig_loc5=$ocrlocation5\n";
    }

    if ($isHas) {
        print OCRCFGFILE "local_only=TRUE\n";
    } else {
        print OCRCFGFILE "local_only=FALSE\n";
    }

    close (OCRCFGFILE);

    return $SUCCESS;
}

####---------------------------------------------------------
#### Function for retrieving OCR location from ocr.loc
# ARGS: 0
sub s_get_ocrdisk
{
    my $ret = "";

    if (!(-r $OCRCONFIG)) {
        error ("Either " . $OCRCONFIG . " does not exist or is not readable");
        error ("Make sure the file exists and it has read and execute access");
        return $ret;
    }

    $ret = s_get_config_key ("ocr", "ocrconfig_loc");

    return $ret;
}

####---------------------------------------------------------
#### Function for returning OCR mirror location from ocr.loc
# ARGS: 0
sub s_get_ocrmirrordisk
{
    my $ret = "";

    if (!(-r $OCRCONFIG)) {
        error ("Either " . $OCRCONFIG . " does not exist or is not readable");
        error ("Make sure the file exists and it has read and execute access");
        return $ret;
    }

    $ret = s_get_config_key ("ocr", "ocrmirrorconfig_loc");

    return $ret;
}

####---------------------------------------------------------
#### Validating OCR locations based on existing ocr settings
# ARGS: 3
# ARG1 : Path for Oracle CRS home
# ARG2 : Cluster name
# ARG3 : Comma separated OCR locations
sub s_validateOCR
{
    my $crshome        = $_[0];
    my $clustername    = $_[1];
    my $ocrlocations   = $_[2];
    my $status         = $SUCCESS;
    my $OCR_SYNC_FILE  = catfile ($crshome, "srvm", "admin", $OCRLOC);
    my $OCR_CDATA_DIR  = catfile ($crshome, "cdata");
    my $OCR_BACKUP_DIR = catfile ($crshome, "cdata", $clustername);

    my $SRVCONFIG_LOC = "";
    if (-f $SRVCONFIG) {
        trace ("Checking repository used for 9i installations");

        # srvConfig.loc file exists and repository location is
        $SRVCONFIG_LOC = s_get_config_key ("srv", "srvconfig_loc");

        if ($SRVCONFIG_LOC eq "/dev/null") {
            # 9.x srvconfig_loc is already invalidated. So ignore it
            # # take the location entered by user to populate ocr.loc
            $SRVCONFIG_LOC = "";
        }
    }

    ##Checking the OCR locations used by 10gR1 or previous 10gR2
    #installations
    my $OCRCONFIG_LOC = "";
    my $OCRMIRRORCONFIG_LOC = "";
    my $OCRCONFIG_LOC3 = "";
    my $OCRCONFIG_LOC4 = "";
    my $OCRCONFIG_LOC5 = "";

    if (-f $OCRCONFIG) {
        trace ("Retrieving OCR location used by previous installations");
        # ocr.loc file exists and ocr location set here is
        $OCRCONFIG_LOC       = s_get_config_key ("ocr", "ocrconfig_loc");
        $OCRMIRRORCONFIG_LOC = s_get_config_key ("ocr", "ocrmirrorconfig_loc");
        $OCRCONFIG_LOC3      = s_get_config_key ("ocr", "ocrconfig_loc3");
        $OCRCONFIG_LOC4      = s_get_config_key ("ocr", "ocrconfig_loc4");
        $OCRCONFIG_LOC5      = s_get_config_key ("ocr", "ocrconfig_loc5");
    }

    my $OCRFILE = $OCRCONFIG;

    trace ("Checking if OCR sync file exists");

    if (-f $OCR_SYNC_FILE) {
        trace ("$OCR_SYNC_FILE exists");
        ##Checking the OCR locations used by existing nodes in the cluster
        my $NEW_OCR_FILE = "";
        my $NEW_OCRMIRROR_FILE = "";
        my $NEW_OCRMIRROR_LOC3 = "";
        my $NEW_OCRMIRROR_LOC4 = "";
        my $NEW_OCRMIRROR_LOC5 = "";

        open (OCRSYNCFILE, "<$OCR_SYNC_FILE");

        while (<OCRSYNCFILE>) {
            if (/^ocrconfig_loc=(\S+)/) {
                $NEW_OCR_FILE = $1;
            }
            if (/^ocrmirrorconfig_loc=(\S+)/) {
                $NEW_OCRMIRROR_FILE = $1;
            }
            if (/^ocrconfig_loc3=(\S+)/) {
                $NEW_OCRMIRROR_LOC3 = $1;
            }
            if (/^ocrconfig_loc4=(\S+)/) {
                $NEW_OCRMIRROR_LOC4 = $1;
            }
            if (/^ocrconfig_loc5=(\S+)/) {
                $NEW_OCRMIRROR_LOC5 = $1;
            }
        }
        close (OCRSYNCFILE);

        trace ("NEW_OCR_FILE=$NEW_OCR_FILE");
        trace ("NEW_OCRMIRROR_FILE=$NEW_OCRMIRROR_FILE");
        trace ("NEW_OCRMIRROR_LOC3=$NEW_OCRMIRROR_LOC3");
        trace ("NEW_OCRMIRROR_LOC4=$NEW_OCRMIRROR_LOC4");
        trace ("NEW_OCRMIRROR_LOC5=$NEW_OCRMIRROR_LOC5");

        $ocrlocations = $NEW_OCR_FILE;

        if ($NEW_OCRMIRROR_FILE) {
            $ocrlocations = "$ocrlocations,$NEW_OCRMIRROR_FILE";
        }
        if ($NEW_OCRMIRROR_LOC3) {
            $ocrlocations = "$ocrlocations,$NEW_OCRMIRROR_LOC3";
        }
        if ($NEW_OCRMIRROR_LOC4) {
            $ocrlocations = "$ocrlocations,$NEW_OCRMIRROR_LOC4";
        }
        if ($NEW_OCRMIRROR_LOC5) {
            $ocrlocations = "$ocrlocations,$NEW_OCRMIRROR_LOC5";
        }

        trace ("OCR locations (obtained from $OCR_SYNC_FILE) = $ocrlocations");
    } else {
        ##Syncing of OCR disks is not required
        trace ("No need to sync OCR file");
    }

    my ($OCR_LOCATION,$OCR_MIRROR_LOCATION,$OCR_MIRROR_LOC3,
	$OCR_MIRROR_LOC4,$OCR_MIRROR_LOC5) = split (/\s*,\s*/, $ocrlocations);

    trace ("OCR_LOCATION=$OCR_LOCATION");
    trace ("OCR_MIRROR_LOCATION=$OCR_MIRROR_LOCATION");
    trace ("OCR_MIRROR_LOC3=$OCR_MIRROR_LOC3");
    trace ("OCR_MIRROR_LOC4=$OCR_MIRROR_LOC4");
    trace ("OCR_MIRROR_LOC5=$OCR_MIRROR_LOC5");
    trace ("Current OCR location= $OCRCONFIG_LOC");
    trace ("Current OCR mirror location= $OCRMIRRORCONFIG_LOC");
    trace ("Current OCR mirror loc3=$OCRCONFIG_LOC3");
    trace ("Current OCR mirror loc4=$OCRCONFIG_LOC4");
    trace ("Current OCR mirror loc5=$OCRCONFIG_LOC5");
    trace ("Verifying current OCR settings with user entered values");

    if ($OCRCONFIG_LOC) {
        if ($OCR_LOCATION ne $OCRCONFIG_LOC) {
            error ("Current Oracle Cluster Registry location " .
                   "\"$OCRCONFIG_LOC\" in \"$OCRFILE\" and " .
                   "\"$OCR_LOCATION\" do not match");
            error ("Update either \"$OCRFILE\" to use \"$OCR_LOCATION\" or " .
                   "variable OCR_LOCATIONS property set in " .
                   catfile ($crshome, "crs", "install", "crsconfig_params") .
                "with \"$OCRCONFIG_LOC\" then rerun this script");
            return $FAILED;
        }
    } else {
        #set ocrconfig_loc = OCR_LOCATION
        $OCRCONFIG_LOC = $OCR_LOCATION;
    }

    if ($OCRMIRRORCONFIG_LOC) {
        if ($OCR_MIRROR_LOCATION ne $OCRMIRRORCONFIG_LOC) {
            error ("Current Oracle Cluster Registry mirror location " .
                   "\"$OCRMIRRORCONFIG_LOC\" in \"$OCRFILE\" and " .
                   "\"$OCR_MIRROR_LOCATION\" do not match");
            error ("Update either \"$OCRFILE\" to use " .
                   "\"$OCR_MIRROR_LOCATION\" or variable OCR_LOCATIONS " .
                   "property set in " .
                   catfile ($crshome, "crs" . "install" . "crsconfig_params") .
                   " with \"$OCRMIRRORCONFIG_LOC\" then rerun this script");
            return $FAILED;
        }
    } else {
        #set the mirror location=user entered value for OCR_MIRROR_LOCATION
        $OCRMIRRORCONFIG_LOC = $OCR_MIRROR_LOCATION;
    }

    if ($OCRCONFIG_LOC3) {
        if ($OCR_MIRROR_LOC3 ne $OCRCONFIG_LOC3) {
            error ("Current Oracle Cluster Registry mirror location " .
                   "\"$OCRCONFIG_LOC3\" in \"$OCRFILE\" and " .
                   "\"$OCR_MIRROR_LOC3\" do not match");
            error ("Update either \"$OCRFILE\" to use " .
                   "\"$OCR_MIRROR_LOC3\" or variable OCR_LOCATIONS " .
                   "property set in " .
                   catfile ($crshome, "crs" . "install" . "crsconfig_params") .
                   " with \"$OCRCONFIG_LOC3\" then rerun this script");
            return $FAILED;
        }
    } else {
        #set the mirror location=user entered value for OCR_MIRROR_LOCATION
        $OCRCONFIG_LOC3 = $OCR_MIRROR_LOC3;
    }

    if ($OCRCONFIG_LOC4) {
        if ($OCR_MIRROR_LOC4 ne $OCRCONFIG_LOC4) {
            error ("Current Oracle Cluster Registry mirror location " .
                   "\"$OCRCONFIG_LOC4\" in \"$OCRFILE\" and " .
                   "\"$OCR_MIRROR_LOC4\" do not match");
            error ("Update either \"$OCRFILE\" to use " .
                   "\"$OCR_MIRROR_LOC4\" or variable OCR_LOCATIONS " .
                   "property set in " .
                   catfile ($crshome, "crs" . "install" . "crsconfig_params") .
                   " with \"$OCRCONFIG_LOC4\" then rerun this script");
            return $FAILED;
        }
    } else {
        #set the mirror location=user entered value for OCR_MIRROR_LOCATION
        $OCRCONFIG_LOC4 = $OCR_MIRROR_LOC4;
    }

    if ($OCRCONFIG_LOC5) {
        if ($OCR_MIRROR_LOC5 ne $OCRCONFIG_LOC5) {
            error ("Current Oracle Cluster Registry mirror location " .
                   "\"$OCRCONFIG_LOC5\" in \"$OCRFILE\" and " .
                   "\"$OCR_MIRROR_LOC5\" do not match");
            error ("Update either \"$OCRFILE\" to use " .
                   "\"$OCR_MIRROR_LOC5\" or variable OCR_LOCATIONS " .
                   "property set in " .
                   catfile ($crshome, "crs" . "install" . "crsconfig_params") .
                   " with \"$OCRCONFIG_LOC5\" then rerun this script");
            return $FAILED;
        }
    } else {
        #set the mirror location=user entered value for OCR_MIRROR_LOCATION
        $OCRCONFIG_LOC5 = $OCR_MIRROR_LOC5;
    }

    trace ("Setting OCR locations in $OCRCONFIG");
    s_validate_ocrconfig ($ocrlocations, 0) or (return $FAILED);

    if (-f $OCR_SYNC_FILE) {
        trace ("Removing OCR sync file: $OCR_SYNC_FILE");
        s_remove_file ("$OCR_SYNC_FILE");
    }

    return $status;
}

####---------------------------------------------------------
#### Function for invalidating srvconfig_loc in srvconfig.loc file
sub s_reset_srvconfig
{
    trace ("Invalidating repository location for Oracle 9i deployments");
    ##Invalidate the existing srvConfig.loc file if it was existing 
    if (-f $SRVCONFIG) {
        open (SRVCFGFILE, ">$SRVCONFIG") or return $FAILED;
        print SRVCFGFILE "srvconfig_loc=/dev/null\n";
        close (SRVCFGFILE);
        s_set_ownergroup ($SUPERUSER, $ORA_DBA_GROUP, $SRVCONFIG)
            or return $FAILED;
        s_set_perms ("0644", $SRVCONFIG) or return $FAILED;
    }

    return $SUCCESS;
}

####---------------------------------------------------------
#### Function for registering daemon/service with init
# ARGS: 1
# ARG1: daemon to be registered
sub s_register_service
{
    my $srv = $_[0];
    my $INITDIR_SRV;
    # Setup init scripts
    my $INITDIR = catfile ($ORACLE_HOME, "crs", "init");
    my $INITDIR_INITSRV = catfile ($INITDIR, "init.$srv");
    #if SUSE linux, copy the ohasd.sles to the rcdirs
    if (! s_isSUSELinux()) {
       $INITDIR_SRV = catfile ($INITDIR, $srv);
    } else {
       $INITDIR_SRV = catfile ($INITDIR, "$srv.sles");
    }
    s_copy_to_initdir ($INITDIR_INITSRV, "init.$srv") or return $FAILED;
    s_copy_to_rcdirs ($INITDIR_SRV, $srv) or return $FAILED;
   
    return $SUCCESS;
}

####---------------------------------------------------------
#### Function for unregistering daemon/service
# ARGS: 1
# ARG1: daemon to be unregistered
sub s_unregister_service
{
    # TBD

    return $SUCCESS;
}

####---------------------------------------------------------
#### Function for starting daemon/service
# ARGS: 3
# ARG1: daemon to be started
# ARG2: user under whom daemon/service needs to be started
sub s_start_service
{
    my $srv  = $_[0];
    my $user = $_[1];
    my $status;
    my @output;
    my $grep_val;
    my @cmdout;

    # Check to see if the service is OHASD
    if (($srv eq "ohasd") || ($srv eq "crsexcl")) {
	# Create the autorun file and its directory
        my $dir = catdir ($SCRBASE, $HOST, $HAS_USER);
        create_dir($dir);
        my $AUTORUNFILE = catfile ($dir, "ohasdrun");
        open (AUTORUN, ">$AUTORUNFILE")
            or die "Can't open $AUTORUNFILE for write: $!";
        print AUTORUN "stop\n";
        close (AUTORUN);

        s_set_ownergroup ($HAS_USER, $HAS_GROUP, $AUTORUNFILE)
	    or die "Can't change ownership of $AUTORUNFILE";
        s_set_perms ("0644", $AUTORUNFILE)
            or die "Can't change permissions of $AUTORUNFILE";

        my $INIT_FILE="inittab";
        if (s_is_Linux_Upstart())
        {   
           $INIT_FILE="upstart";
        }
	# Add OHASD to inittab
        if ($CFG->DOWNGRADE) { 
           print "Removing Clusterware entries in $INIT_FILE\n";
        } 
        elsif($CFG->UPGRADE) {
           print "Replacing Clusterware entries in $INIT_FILE\n";
        }
        else {
           print "Adding Clusterware entries to $INIT_FILE\n";
        }

        s_remove_itab ("cssd|evmd|crsd|ohasd") or return $FAILED;
        if ( ! s_is_Linux_Upstart())
        {
          $status = system ("$INIT q");
          if (0 != $status)
          {
            error ("Failed in reading inittab, error: $!");
            return $FAILED;
          }
        }
        sleep (5);
        s_add_itab () or return $FAILED;

        if (s_is_Linux_Upstart())
        {
            my $INITCTL = $CFG->params('INITCTL');
            ($status, @output) = system_cmd_capture ("$INITCTL start $UPSTART_OHASD_SERVICE");
            if (0 != $status)
            {
              error ("Failed to start $UPSTART_OHASD_SERVICE, error: $!");
              return $FAILED;
            }
        }
        else
        {
           $status = system ("$INIT q");
           if (0 != $status)
           {
             error ("Failed in reading inittab, error: $!");
             return $FAILED;
           }
        }
        if ($srv eq "ohasd") {

	   # Start OHASD
           $grep_val = "4640";
	   @output = system_cmd_capture ("$CRSCTL start has");
           $status = shift @output;

           # call $ID/ohasd install (bug 9133502)
           if (! is_dev_env()) {
              my @cmd = (catfile($ID, 'ohasd'), 'install');
              system (@cmd);
	   }
	}
	else {
	   # Start CRS if it's crsexcl
	   @output = system_cmd_capture ("$CRSCTL start crs -excl");
           $status = shift @output;
	}
    } 
    else {
        my $SRVBIN = catfile ($ORACLE_HOME, "bin", $srv);
	$status = s_run_as_user ("$SRVBIN &", $user);
    }

    if ($grep_val) { @cmdout = grep(/$grep_val/, @output); } # for OHASD

    if (0 == $status) {
        trace ("$srv is starting");
    } elsif ($grep_val && scalar(@cmdout) > 0) {
        trace("$srv is already active");
    } else {
        error ("$srv failed to start");
        trace ("$srv failed to start");
        my $host = tolower_host();
        my $alertlog = catfile ($ORACLE_HOME, "log", $host, "alert${host}.log");
        trace ("Alert log is $alertlog");
        print "Failed to start the Clusterware. Last 20 lines of the alert " .
              "log follow: \n";
        if (-e $alertlog)
        {
          open(ALERTLOG, "< $alertlog");
          my @lines = reverse <ALERTLOG>;
          my @reversed_lines = reverse(@lines[0..19]);
          my $line;
          foreach $line (@reversed_lines)
          {
            print $line;
          }
        }
        print "\n";
        return $FAILED;
    }

    return $SUCCESS;
}

####---------------------------------------------------------
#### Function for stopping daemon/service
# ARGS: 2
# ARG1: daemon to be stopped
# ARG2: user under whom daemon/service needs to be stopped
sub s_stop_service
{
    # TBD

    return $SUCCESS;
}
#
####---------------------------------------------------------
#### Function for checking daemon
# ARGS: 2
# ARG1: daemon to be checked
# ARG2: is daemon running?
sub s_check_service
{
    my ($srv, $isRunning) = @_;
    if (($srv eq "ohasd") && ($isRunning) && (-e $SCRBASE)) {
        my $AUTOSTARTFILE = catfile ($SCRBASE, $HOST, $HAS_USER, "ohasdstr");
        open (AUTOSTART, ">$AUTOSTARTFILE")
            or die "Can't open $AUTOSTARTFILE for write: $!";
        print AUTOSTART "enable\n";
        close (AUTOSTART);
        s_set_ownergroup ($HAS_USER, $HAS_GROUP, $AUTOSTARTFILE)
	    or die "Can't change ownership of $AUTOSTARTFILE";
        s_set_perms ("0644", $AUTOSTARTFILE)
            or die "Can't change permissions of $AUTOSTARTFILE";
    }
}

####---------------------------------------------------------
#### Function for initializing SCR settings
# Note: this function will be a no-op on NT
# ARGS: 0
sub s_init_scr
{
    my $status = system ("$CRSCTL create scr $ORACLE_OWNER");
    if (0 != $status) {
        print "Failure initializing entries in " .
        catfile ($SCRBASE, $HOST) . "\n";
        exit 1;
    }
}

####---------------------------------------------------------
#### Function for running a command as given user
# ARGS: 2
# ARG1: cmd to be executed
# ARG2: user name
sub s_run_as_user
{
    my $user = $_[1];
    my $cmd;

    if ($user) {
        my $SU = "/bin/su";
        $cmd = "$SU $user -c \"$_[0]\"";
        trace ("  Invoking \"$_[0]\" as user \"$user\"");
    } else {
        $cmd = $_[0];
        trace ("  Invoking \"$_[0]\"");
    }

    return system_cmd($cmd);
}

####---------------------------------------------------------
#### Function for running a command as given user, returning back 
#### stdout/stderra output
# ARGS: 3
# ARG1: ref to cmdlist argv list to be executed
# ARG2: user name, can be undef
# ARG3: ref to resulting array of stderr/out, can be undef
sub s_run_as_user2
{
    my $cmdlistref = $_[0];
    my $user = $_[1]; 
    my $capoutref = $_[2];
    my $rc = -1;
    my $SU = "/bin/su";
    
    my @cmdlist;
    if ($user)
    {
      @cmdlist = ( $SU, $user, '-c \'',  @{$cmdlistref}, '\'' );
    }
    else
    {
      @cmdlist = @{$cmdlistref};
    }
    my $cmd = join( ' ', @cmdlist );
    
    # capture stdout/stderr, if requested
    if (defined($capoutref))
    {
      @{$capoutref} = ();
      my $cmdout = tmpnam();

      trace ("s_run_as_user2: Running $cmd");

      # system() with stdout/stderr capture. 
      # Note that this is a portable notation in perl
      # see http://perldoc.perl.org/perlfaq8.html
      # see also
      # http://www.perlmonks.org/?node_id=597613
      open (CMDEXE, "$cmd 2>&1 |" ) 
            or die "Can't open \"$cmd\" output: $!";
      open (CMDOUT, ">>$cmdout" ) 
            or die "Can't open \"$cmd\" tee: $!";
      while (<CMDEXE>) { 
	 push( @{$capoutref}, $_ ); 
	 print CMDOUT $_; 
      }
      close (CMDEXE);  # to get $?
      $rc = $?;
      close (CMDOUT);
      s_remove_file ("$cmdout");
    }
    else  # regular system() call
    {
      $rc = s_run_as_user( $cmd, $user );
    }

    if ($rc == 0) {
        trace ("$cmdlist[0] successfully executed\n");
    }
    elsif ($rc == -1) {
        trace ("$cmdlist[0] failed to execute\n");
    }
    elsif ($rc & 127) {
        my $sig = $rc & 127;
        my $core = ($rc & 128) ? 'with' : 'without';
        trace ("$cmdlist[0]  died with signal $sig, $core coredump\n");
    }
    else {
        my $retCode = $rc >> 8;
        trace ("$cmdlist[0] exited with rc=$retCode\n");
    }
    return $rc;
}

####---------------------------------------------------------
#### Function for running a command as given user and inject
#### one value into stdin
# ARGS: 2
# ARG1: cmd to be executed
# ARG2: user name
# ARG3: value to be injected into stdin
sub s_run_as_user3
{
   # read parameters
   my $user  = $_[0];
   my $cmd   = $_[1];
   my $param = $_[2];

   my $SU    = "/bin/su";
   my $cmd2;
   my $cmdout = tmpnam();
   # create final command
   if ($user) {
      $cmd2 = join (" ", "|" , $SU, $user, "-c", "\"", @{$cmd}, "\"",
                    ">>$cmdout");
      trace ("s_run_as_user3  Invoking \"$cmd2\" as user \"$user\"");
   } else {
      $cmd2 = join (" ", "|", @{$cmd}, ">>$cmdout");
      trace ("s_run_as_user3  Invoking \"$cmd2\"");
   }
   # execute the command
   open(COMMAND, $cmd2);
   # inject the parameter
   print COMMAND $param;
   # close the stream
   close COMMAND;
   my $rc = $?;
   # read output and delete temp file
   open(COMMAND_OUT, "$cmdout");
   my @out = (<COMMAND_OUT>);
   close COMMAND_OUT;
   s_remove_file("$cmdout");
   # join result of command and output
   return ($rc,@out);
}

####---------------------------------------------------------
#### Function for getting value corresponding to a key in ocr.loc or olr.loc
# ARGS: 2
# ARG1: ocr/olr
# ARG2: key
sub s_get_config_key
{
   my $src = $_[0];
   my $key = $_[1];
   $src    =~ tr/a-z/A-Z/;
   my ($val, $cfgfile);

   if ($src eq 'OCR') {
      $cfgfile = $OCRCONFIG;
   }
   elsif ($src eq 'OLR') {
      $cfgfile = $OLRCONFIG;
   }
   elsif ($src eq 'SRV') {
      $cfgfile = $SRVCONFIG;
   }

   # open OCRCONFIG/OLRCONFIG/SRVCONFIG as appropriate
   trace("Opening file $cfgfile");
   open (CFGFL, "<$cfgfile") or return $val;
   while (<CFGFL>) {
      if (/^$key=(\S+)/) {
         $val = $1;
         last;
      }
   }

   close (CFGFL);

   trace("Value ($val) is set for key=$key");
   return $val;
}

####---------------------------------------------------------
#### Function for getting platform family
# ARGS: 0
sub s_get_platform_family
{
    return "unix";
}

####---------------------------------------------------------
#### Function for checking if a path is a symlink, and if so, return the
#### target path
# ARGS: 1
# ARG1: file/dir path
sub s_isLink
{
    my $path = $_[0];
    my $target = "";

    if (-l $path) {
        $target = readlink ($path) or die "readlink failed: $!";
    }

    return $target;
}

####--------------------------------
#### Function for redirecting output
# ARGS: 1
# ARG1: file to redirect to 
sub s_redirect_souterr
{
    # no-op on Linux as we don't want to redirect output
   return $SUCCESS;
}

####---------------------------------------------------------
#### Function for restoring output
# ARGS: 0
sub s_restore_souterr
{
    # no-op on Linux
   return $SUCCESS;
}

####---------------------------------------------------------
#### Function for getting the old CRS Home
# ARGS:  0
sub s_getOldCrsHome
{
  my ($oldHome, $Name);
  my $CRS_HOME_ENV  = "ORA_CRS_HOME";
  my $INITD 	    = s_getInitd();
  my $OLD_INIT_CSSD = catfile ($INITD, "init.cssd");

  open(FOHM, $OLD_INIT_CSSD) ||
    die "Could not open old init.cssd\n";
  my @buffer = grep(/$CRS_HOME_ENV/, (<FOHM>));
  close FOHM;

  chomp @buffer;
  if (scalar(@buffer) != 0) {
      ($Name, $oldHome) = split(/=/, $buffer[0]);
  }

  return $oldHome;
}

####---------------------------------------------------------
#### Function to check if  the stack is up  from Pre 11.2 CrsHome
# ARGS:  1
# ARG1:  Old CRS Home Location
sub s_check_OldCrsStack
{
   trace("check old crs stack");
   my $old_crshome = $_[0];
   my @old_version = @{$CFG->oldconfig('ORA_CRS_VERSION')};
   my $crsctl      = catfile ($old_crshome, 'bin', 'crsctl');
   my $crs_stat    = catfile ($old_crshome, 'bin', 'crs_stat');

   if ($old_version[0] eq "10" &&
       $old_version[1] eq "1") {
      my @output = system_cmd_capture($crs_stat);
      my $rc     = shift @output;
      my @cmdout = grep(/CRS-0184/, @output);
      trace("rc=$rc output=@output");

      if ($rc == 0 && scalar(@cmdout) == 0) {
         return $SUCCESS;
      }
   } else {
      my $status_cssd = system_cmd($crsctl, 'check', 'cssd');
      my $status_evmd = system_cmd($crsctl, 'check', 'evmd');
      my $status_crsd = system_cmd($crsctl, 'check', 'crsd');
      if ((! $status_cssd) &&
          (! $status_evmd) &&
          (! $status_crsd)) {
         return $SUCCESS;
      }
   }

   return $FAILED;
}

####---------------------------------------------------------
####---------------------------------------------------------
#### Function for stopping the services from OldCrsHome
# ARGS:  1

sub s_stop_OldCrsStack
{
   my $initd 	    = s_getInitd();
   my $old_init_crs = catfile ($initd, "init.crs");
   my @output	    = system_cmd_capture($old_init_crs, 'stop');
   my $status	    = shift @output;
   trace ("status=$status output=@output");

   return $status;
}

####---------------------------------------------------------
#### Function for getting the Initd locations
# ARGS:  0

sub s_getInitd
{
  return $INITD;
}

sub s_RemoveInitResources
#-------------------------------------------------------------------------------
# Function: Removing init resources
# Args    : 0
#-------------------------------------------------------------------------------
{
   trace ("Remove init resources");
   my @crs_init_scripts = ('init.evmd', 'init.crsd', 'init.cssd',
			   'init.crs', 'init.ohasd');

   s_remove_itab ("cssd|evmd|crsd|ohasd");
   if ( ! s_is_Linux_Upstart() )
   {
     system ("$INIT q");
     sleep (5);
   }
   trace ("Removing script for Oracle Cluster Ready services");

   my ($file, $serv);
   foreach $serv (@crs_init_scripts) {
     trace ("Removing $ID/$serv file");
     $file = catfile($ID,$serv);
     s_remove_file ("$file");
   }

   s_clean_rcdirs ("ohasd");
   s_clean_rcdirs ("init.crs");

} #endsub


sub s_ResetOLR
#---------------------------------------------------------------------
# Function: Reset OLR
# Args    : 0
#--------------------------------------------------------------------
{
   trace ("Reset OLR");
   my $bin_dd = "/bin/dd";

   my $olr_file = s_get_olr_file("olrconfig_loc");

   if (-f $olr_file) {
      trace("Removing OLR file: $olr_file");
      s_remove_file ("$olr_file");
   }
   else {
      trace ("Removing contents from OLR file: $olr_file");
      system ("$bin_dd if=/dev/zero skip=25 bs=4k count=2560 of=$olr_file > $dev_null");
   }

   s_remove_file ("$OLRCONFIG");
}

sub s_ResetOCR
#---------------------------------------------------------------------
# Function: Reset OCR
# Args    : 0
#--------------------------------------------------------------------
{
   trace ("Reset OCR");
   my $bin_dd = "/bin/dd";
   my ($ocr_loc, @mirror_loc, $loc);

   if ($g_downgrade)
   {
      if ($g_version eq "9.2")
      {
         DowngradeTo9i ();
      } else {
         DowngradeTo10or11i ();
      }

      return $SUCCESS;
   }

   my $olr_file = s_get_olr_file("olrconfig_loc");

   if (-f $olr_file) {
      trace("Removing OLR file: $olr_file");
      s_remove_file ("$olr_file");
   }
   else {
      trace ("Removing contents from OLR file: $olr_file");
      system ("$bin_dd if=/dev/zero skip=25 bs=4k count=2560 of=$olr_file > $dev_null");
   }

   s_remove_file ("$OLRCONFIG");

   if (! $g_lastnode) 
   {
      s_remove_file ("$OCRCONFIG");
      return $SUCCESS;
   }

   if (! -f $OCRCONFIG) 
   {
      # ocr.loc file does not exist. Take ocr location of srvconfig.loc for setting
      # file permissions
      if (-f $SRVCONFIG) 
      {
         $ocr_loc =  get_srvdisk ();
      }
   } 
   else {
      $ocr_loc = get_ocrdisk();
      push @mirror_loc, get_ocrmirrordisk();
      push @mirror_loc, get_ocrloc3disk();
      push @mirror_loc, get_ocrloc4disk();
      push @mirror_loc, get_ocrloc5disk();
   }

   my $loc;
   foreach $loc (@mirror_loc) {
      if (($loc) && ($loc ne $dev_null)) {
	 if (-f $loc) {
	    # OCR mirror device is specified and enabled
	    trace("Removing OCR mirror device: $loc");
	    s_remove_file ($loc);
	 }
	 elsif (! isPathonASM($loc)) {
	    trace ("Removing contents from OCR mirror device: $loc");
	    system ("$bin_dd if=/dev/zero skip=25 bs=4k count=2560 of=$loc > $dev_null");
	 }
      }
   }

   # reset OCR device if it's not on ASM
   if (($g_lastnode)    &&
       (! $g_downgrade) &&
       (! $CFG->ASM_STORAGE_USED)) {
      trace ("Removing contents from OCR device");

      if (-f $ocr_loc) {
         trace("Removing OCR device: $ocr_loc");
         s_remove_file ("$ocr_loc");
      }
      elsif (!isPathonASM($ocr_loc)) {
         trace ("Removing contents from OCR device: $ocr_loc");
         system ("$bin_dd if=/dev/zero skip=25 bs=4k count=2560 of=$ocr_loc > $dev_null");
      }
   }

   #remove the ocr.loc in the lastnode in case of ASM storage as well
   if ($g_lastnode) {
      s_remove_file ("$OCRCONFIG");
   }
   
   # reset permissions of ocr_loc files
   if (-f $ocr_loc) {
      chmod(0644, $ocr_loc);

      if (isOwnerGroupValid()) {
         chown ($ORACLE_OWNER, $ORA_DBA_GROUP, $ocr_loc);
      }
   }

   foreach $loc (@mirror_loc) {
      if ((not -z $loc) && (-f $loc)) {
	 chmod(0644, $loc);

	 if (isOwnerGroupValid()) {
            chown ($ORACLE_OWNER, $ORA_DBA_GROUP, $loc);
	 }
      }
   }
}

sub s_setParentDirOwner
#-------------------------------------------------------------------------------
# Function: Set $current_dir and its parent directories to $owner/DBA
#
# Args    : [0] Owner
#           [1] Directory
#-------------------------------------------------------------------------------
{
   my $current_owner = $_[0];
   my $current_dir   = $_[1];

   my $dir = dirname($current_dir);
   
   if ((-c $current_dir) || (-b $current_dir))
   {
     trace("The '$dir' is parent directory of a character/block device. Skip the action ...");
     return;
   }

   #Save the existing ACLs for parent dir
   trace("saving current owner/permisssios of  parent dir of $dir\n");
   s_saveParentDirinfo($dir);

   while ($dir ne "/" && $dir ne ".") {
      s_set_ownergroup ($current_owner, $ORA_DBA_GROUP, $dir)
           or die "Can't change ownership on $dir";
      s_set_perms ("0755", $dir);
      $dir = dirname($dir);
   }
}

sub s_resetParentDirOwner
#-------------------------------------------------------------------------------
# Function: Set $current_dir and its parent directories to $owner/DBA
# Args    : [0] Directory
#-------------------------------------------------------------------------------
{
   my $current_dir = $_[0];
   my $dir = dirname($current_dir);
   my $savepermfile = catfile ($CFG->ORA_CRS_HOME, "crs", "install", 
			       "ParentDirPerm_$HOST.txt");

   if (-e $savepermfile) {
      trace("reset ACLs  of parent dir of grid home\n");
      my ($fname, $fuser, $fgroup, $fperm);
      open (PFILE, $savepermfile) or
	   error("Can't open $savepermfile to read permisisons: $!");
      while(<PFILE>) {
	 ($fname, $fuser, $fgroup, $fperm) = split(/:/, $_);
         trace("Got $fname:$fuser:$fgroup:$fperm from $savepermfile");
	 s_set_ownergroup ($fuser, $fgroup, $fname);
	 s_set_perms ($fperm, $fname);
      }

      close (PFILE);

      s_remove_file($savepermfile);
   }
}

sub s_start_ocfs_driver
{
    # no-op on Linux
    return $SUCCESS;
}
sub s_ResetVotedisks
#-------------------------------------------------------------------------------
# Function: Reset voting disks
#
# Args    : [0] list of voting disks
#-------------------------------------------------------------------------------
{
   trace ("Reset voting disks");
   my @votedisk_list = @_;
   trace ("CRS_STORAGE_OPTION is $CRS_STORAGE_OPTION");
   foreach my $vdisk (@votedisk_list) {
      if ($CRS_STORAGE_OPTION != 1) {
         # OCFS
         if (-f $vdisk) {
            trace("Removing voting disk: $vdisk");
            s_remove_file ("$vdisk");
         }
         else {
            trace ("Removing contents from voting disk: $vdisk");
            my $bin_dd = "/bin/dd";
            system ("$bin_dd if=/dev/zero skip=25 bs=4k count=2560 of=$vdisk > $dev_null");
         }
      }
   }
}

sub s_CleanTempFiles
#-------------------------------------------------------------------------------
# Function: Remove misc files and directories
# Args    : none
#-------------------------------------------------------------------------------
{
   my ($dir, $file);

   # call $ID/ohasd deinstall (bug 9133502)
   if (! is_dev_env()) {
      my @cmd = (catfile($ID, 'ohasd'), 'deinstall');
      system (@cmd);
   }

   # remove /etc/init.d/ohasd
   my $initd = s_getInitd();
   $file  = (catfile ($initd, "ohasd"));
   s_remove_file ("$file");

   # remove /var/tmp/.oracle
   $dir = catdir ("/var", "tmp", ".oracle");
   if (-e $dir) {
      trace ("Remove $dir");
      rmtree ($dir);
   }

   # remove /ect/inittab.crs
   $file = catfile ("/etc", "inittab.crs");
   s_remove_file ("$file");

   # remove /tmp/.oracle
   $dir = catdir ("/tmp", ".oracle");
   if (-e $dir) {
      trace ("Remove $dir");
      rmtree ($dir);
   }

   # remove /ect/oracle/lastgasp
   if ($CFG->defined_param('OLASTGASPDIR')) {
      $dir = $CFG->params('OLASTGASPDIR');
      if (-e $dir) {
         trace ("Remove $dir");
         rmtree ($dir);
      }
   }

   # remove /ect/oratab
   if (! $CFG->IS_SIHA) {
      if ($CFG->defined_param('HOME_TYPE')) {
         $file = catfile ("/etc", "oratab");
         s_remove_file ("$file");
      }
   }

   # remove /etc/oracle if empty
   if (-e $OCRCONFIGDIR) {
      # remove backup ocr.loc.orig and olr.loc.orig files
      $file  = ($OCRCONFIG . ".orig");
      s_remove_file ("$file");
      $file  = ($OLRCONFIG . ".orig");
      s_remove_file ("$file");

      # check if it's empty
      opendir (DIR, $OCRCONFIGDIR);
      my @files = readdir(DIR);
      close DIR;

      if (scalar(@files) == 2) {
         trace ("Remove $OCRCONFIGDIR");
         rmtree $OCRCONFIGDIR;
      }
   }
}

sub s_checkOracleCM
#-------------------------------------------------------------------------------
# Function: Check for OracleCM by checking libskgxn on unix.
#
# Args    : none
#
# Return  : TRUE - if found
#-------------------------------------------------------------------------------
{
   my $false = 0;
   my $true  = 1;
   my $libskgxnBase_lib = catfile('/etc', 'ORCLcluster', 'oracm', 'lib', 'libskgxn2.so');
   my $libskgxn_lib = catfile('/opt', 'ORCLcluster', 'lib', 'libskgxn2.so');

   trace("libskgxnBase_lib = $libskgxnBase_lib");
   trace("libskgxn_lib = $libskgxn_lib");
   if ((-e $libskgxn_lib) || (-e $libskgxnBase_lib)) {
      # no SKGXN;
      trace("SKGXN library file exists");
      return $true;
   }

   trace("SKGXN library file does not exists");
   return $false;
}

sub s_createConfigEnvFile
#---------------------------------------------------------------------
# Function: Create s_crsconfig_$HOST_env.txt file for Time Zone
# Args    : none
# Notes   : Valid <env_file> format
#           (Please keep this in sync with has/utl/crswrapexec.pl)
#             * Empty lines: lines with all white space
#             * Comments: line starts with #.
#             * <key>=<value>
#             * <key> is all non-whitespace characters on the left of the
#               first "=" character.
#             * <value> is everything on the right of the first "=" character
#               (including whitespaces).
#             * Surrounding double-quote (") won't be stripped.
#             * Key with blank <value> ('') will be undefined.
#               (e.g: Hello=, Hello will be undefined)
#---------------------------------------------------------------------
{
   my $env_file = catfile($ORA_CRS_HOME, 'crs', 'install',
                          's_crsconfig_' . $HOST . '_env.txt');

   open (ENVFILE, ">$env_file") or die "Can't create $env_file: $!";

   print ENVFILE "### This file can be used to modify the NLS_LANG environment"
               . " variable, which determines the charset to be used for messages.\n"
               . "### For example, a new charset can be configured by setting"
               . " NLS_LANG=JAPANESE_JAPAN.UTF8 \n"
               . "### Do not modify this file except to change NLS_LANG,"
               . " or under the direction of Oracle Support Services\n\n";

   # get TZ
   if ($CFG->defined_param('TZ')) {
      my $tz = $CFG->params('TZ');
      $tz    =~ s/'//g; # remove single quotes
      print ENVFILE "TZ=" . $tz . "\n";
   }

   # get NLS_LANG
   if ($CFG->defined_param('LANGUAGE_ID')) {
      my $nls_lang = $CFG->params('LANGUAGE_ID');
      $nls_lang =~ s/'//g; # remove single quotes
      print ENVFILE "NLS_LANG=" . $nls_lang . "\n";
   }

   # Set RT_GRQ to force real-time processes onto global run-queue for AIX
   # NOTE - ONLY FOR AIX, DOES NOT MAKE SENSE FOR OTHER PLATFORMS
   #        See IBM AIX documentation on RT_GRQ parameter for more information
   if ($OSNAME eq 'aix') {
     print ENVFILE "RT_GRQ=ON\n";
     print ENVFILE "EXTSHM=OFF\n";
   }

   # Make sure that env var TNS_ADMIN and ORACLE_BASE will be unset.
   print ENVFILE "TNS_ADMIN=\n";
   print ENVFILE "ORACLE_BASE=\n";

   close (ENVFILE);

   s_set_ownergroup ($SUPERUSER, $ORA_DBA_GROUP, $env_file)
                or die "Can't set ownership on $env_file";
   s_set_perms ("0750", $env_file);
}

sub s_isRAC_appropriate
#-------------------------------------------------------------------------------
# Function:  Check if rac_on/rac_off on Unix
# Args    :  none
# Returns :  TRUE  if rac_on/rac_off     needs to be set
#            FALSE if rac_on/rac_off not needs to be set
#-------------------------------------------------------------------------------
{
   my $rdbms_lib = catfile($CFG->ORA_CRS_HOME, "rdbms", "lib");
   my $success   = TRUE;

   # save current dir
   my $save_dir = getcwd;

   # check for rac_on
   chdir $rdbms_lib;

   my $cmd = "$ARCHIVE -tv libknlopt.a | grep kcsm";

   open ON, "$cmd |";
   my @kcsm = (<ON>);
   close ON;

   if (scalar(@kcsm) == 0) {
      if (! $CFG->IS_SIHA) {
         $success = FALSE;
         print " \n";
         print "The oracle binary is currently linked with RAC disabled.\n";
         print "Please execute the following steps to relink oracle binary\n";
         print "and rerun the command with RAC enabled: \n";
         print "   setenv ORACLE_HOME <crshome> \n";
         print "   cd <crshome>/rdbms/lib \n";
         print "   make -f ins_rdbms.mk rac_on ioracle \n";
      }
   }
   elsif ($CFG->IS_SIHA) {
      $success = FALSE;
      print " \n";
      print "The oracle binary is currently linked with RAC enabled.\n";
      print "Please execute the following steps to relink oracle binary\n";
      print "and rerun the command with RAC disabled: \n";
      print "   setenv ORACLE_HOME <oracle_restart_home> \n";
      print "   cd <oracle_restart_home>/rdbms/lib \n";
      print "   make -f ins_rdbms.mk rac_off ioracle \n";
   }

   # restore save_dir
   chdir $save_dir;

   return $success;
}

sub s_configureCvuRpm
#------------------------------------------------------------------------------
# Function:  Install cvuqdisk rpm on Linux
# Args    :  none
#-------------------------------------------------------------------------------
{
    my $uname =`uname`;
    chomp($uname);

    if ($uname=~/Linux/)
    {
       trace ("Install cvuqdisk rpm on Linux...");
       my $rmpexe = "/bin/rpm";
       my $install_cvuqdisk=FALSE;
       my $rpm_pkg_dir;
       my $rpm_file;

       if (is_dev_env())
       {
          $rpm_pkg_dir=catfile($ORA_CRS_HOME,'opsm','cv','remenv');
       }
       else
       {
          $rpm_pkg_dir=catfile($ORA_CRS_HOME,'cv', 'rpm');
       }

       opendir (DIR, $rpm_pkg_dir);
       foreach (sort grep(/cvuqdisk/,readdir(DIR)))
       {
           $rpm_file = $_;
       }
       closedir DIR;

       my $new_rpm_file = $rpm_pkg_dir . "/" . $rpm_file;
       trace ("New package to install is $new_rpm_file");

       trace ("Invoking \"$rmpexe -q cvuqdisk\" command");
       my $curr_rpm_version = `$rmpexe -q cvuqdisk --queryformat '%{VERSION}'`;
       my $status = $?;

       if ($status == 0) 
       {
          my $curr_rpm_release = `$rmpexe -q cvuqdisk --queryformat '%{RELEASE}'`;

          trace ("Invoking \"$rmpexe -qp $new_rpm_file\" command");
          my $new_rpm_version = `$rmpexe -qp $new_rpm_file --queryformat '%{VERSION}'`;
          my $new_rpm_release = `$rmpexe -qp $new_rpm_file --queryformat '%{RELEASE}'`;

          chomp ($curr_rpm_version);
          chomp ($new_rpm_version);
          chomp ($curr_rpm_release);
          chomp ($new_rpm_release);

          if ($curr_rpm_version eq "package cvuqdisk is not installed")
          {
              trace ("package is not installed");
              $install_cvuqdisk = TRUE;
          }
          else
          {
              trace ("check package versions new = [$new_rpm_version];old=[$curr_rpm_version] ");
              my $i;
              my @currPkgArr = split(/\./, $curr_rpm_version);
              my @newPkgArr = split(/\./, $new_rpm_version);
              my $loopMax = (scalar @currPkgArr <= scalar @newPkgArr)?scalar @currPkgArr:scalar @newPkgArr;
              my $currentConfigGood = FALSE;

              for ($i=0;$i<$loopMax;$i++) {
                 if ($currPkgArr[$i] == $newPkgArr[$i])
                 {
                    next;
                 }
                 if ($currPkgArr[$i]  > $newPkgArr[$i])
                 {
                    $currentConfigGood = TRUE;
                    last;
                 }
                 trace ("install new package for version");
                 $install_cvuqdisk = TRUE;
                 last;
              }

              if (!$currentConfigGood && !$install_cvuqdisk && ($curr_rpm_release lt $new_rpm_release))
              {
                  trace ("install new package for release");
                  $install_cvuqdisk = TRUE;
              }
          }
       }
       else
       {
           trace ("no existing cvuqdisk found");
           $install_cvuqdisk = TRUE;
       }

       if ($install_cvuqdisk)
       {
          my $orauser  = $CFG->params('ORACLE_OWNER');
          my $CVUQDISK_GRP=`id -gn $orauser`;
          chomp($CVUQDISK_GRP);
          $ENV{'CVUQDISK_GRP'} = $CVUQDISK_GRP;

          trace ("removing old rpm");
          my @args = ($rmpexe, "-e", "--allmatches", "cvuqdisk");
          my @out = system_cmd_capture (@args);
          my $rc  = shift @out;

          if ( $rc == 1)
          {
              trace ("Older version cvuqdisk not uninstalled");
          }

          trace ("installing/upgrading new rpm");
          system ("$rmpexe -Uv $new_rpm_file");
       }
    }
    return TRUE;
}

sub s_removeCvuRpm
#---------------------------------------------------------------------
# Function: Remove cvuqdisk rpm
# Args    : None
#---------------------------------------------------------------------
{
    my $uname =`uname`;
    chomp($uname);

    if ($uname=~/Linux/)
    {
       trace ("removing cvuqdisk rpm");
       system ("/bin/rpm -e --allmatches cvuqdisk");
    }
    return TRUE;
}

sub s_createLocalOnlyOCR
#-------------------------------------------------------------------------------
# Function:  Create local-only OCR
# Args    :  none
#-------------------------------------------------------------------------------
{
   trace ("create Local Only OCR on Linux...");

   my $owner      = $CFG->params('ORACLE_OWNER');
   my $dba_group  = $CFG->params('ORA_DBA_GROUP');
   my $ocr_config = $CFG->params('OCRCONFIG');

   # create ocr.loc w/ local_only=TRUE and set ownergroup
   open (FILEHDL, ">$ocr_config") or die "Unable to open $ocr_config: $!";
   print FILEHDL "local_only=TRUE\n";
   close (FILEHDL);
   s_set_ownergroup ($owner, $dba_group, $ocr_config)
                or die "Can't change ownership on $ocr_config";
   s_set_perms ("0640", $ocr_config)
    		or die "Can't set permissions on $ocr_config";
}

sub s_houseCleaning
#-------------------------------------------------------------------------------
# Function:  Remove entries from inittab and misc files
# Args    :  none
#-------------------------------------------------------------------------------
{
   # remove cssd/evmd/crsd entries from inittab
   s_remove_itab ("cssd|evmd|crsd");

   # remove /etc/init.d/init.crs
   my $file = catfile ($CFG->params("ID"), 'init.crs');
   if (-f $file) {
      trace ("remove $file");
      s_remove_file ("$file");
   }

   # remove /etc/init.d/init.crsd
   $file = catfile ($CFG->params("ID"), 'init.crsd');
   if (-f $file) {
      trace ("remove $file");
      s_remove_file ("$file");
   }

   # remove /etc/init.d/init.cssd
   $file = catfile ($CFG->params("ID"), 'init.cssd');
   if (-f $file) {
      trace ("remove $file");
      s_remove_file ("$file");
   }

   # remove /etc/init.d/init.evmd
   $file = catfile ($CFG->params("ID"), 'init.evmd');
   if (-f $file) {
      trace ("remove $file");
      s_remove_file ("$file");
   }

   # remove S96init.crs files
   my $search_dir = catdir ('/etc', 'rc.d');
   my $delete_file = "s96init.crs";

   finddepth (\&remove_file, $search_dir);

   # remove K96init.crs files
   $delete_file = "k96init.crs";

   finddepth (\&remove_file, $search_dir);

   # remove K19init.crs files
   $delete_file = "k19init.crs";

   finddepth (\&remove_file, $search_dir);

   sub remove_file {
      if (/\b$delete_file\b/i) {
         trace ("remove $File::Find::name");
         s_remove_file ("$_");
      }
   }
}

sub s_is92ConfigExists
#-------------------------------------------------------------------------------
# Function: Check if config exists in 9.2
# Args    : none
# Returns : TRUE  if     exists
# 	    FALSE if not exists
#-------------------------------------------------------------------------------
{
   my $srvconfig_loc;

   trace("SRVCONFIG=$SRVCONFIG");

   if (-f $SRVCONFIG) {
      trace ("Checking repository used for 9i installations");
      $srvconfig_loc = s_get_config_key ("srv", "srvconfig_loc");

      trace("srvconfig location=<$srvconfig_loc>");

      if ($srvconfig_loc eq '/dev/null') {
          trace("srvconfig location=<$srvconfig_loc>");
          trace("Oracle 92 configuration and SKGXN library does exists");
          return TRUE;
      }
   }

   trace("Oracle 92 configuration and SKGXN library does not exists");

   return FALSE;
}

sub s_copyOCRLoc
#-------------------------------------------------------------------------------
# NOTES: OCR handles the ocr.loc updates on its own, and this is kept around 
#	 as a fallback
#-------------------------------------------------------------------------------
{
   my $cluutil 	   = catfile ($CFG->ORA_CRS_HOME, 'bin', 'cluutil');
   my $ocrloc_temp = catfile ($CFG->ORA_CRS_HOME, 'srvm', 'admin', 'ocrloc.tmp');
   my $ocrloc_file = catfile ($CFG->ORA_CRS_HOME, 'srvm', 'admin', $OCRLOC);
   my @node_list   = getCurrentNodenameList();
   my $success	   = FALSE;
   my @capout	   = ();
   my @cmd;
   my $rc;

   if (! (-e $cluutil)) {
      trace("$cluutil not found");
      trace("Unable to copy OCR locations");
      return FALSE;
   }

   foreach my $node (@node_list) {
      if ($node !~ /\b$HOST\b/i) {
         @cmd = ("$cluutil", '-sourcefile', $OCRCONFIG, '-sourcenode', $node,
              '-destfile', $ocrloc_temp, '-nodelist', $node);
         $rc = run_as_user2($CFG->params('ORACLE_OWNER'), \@capout, @cmd);

         if ($rc == 0) {
            trace("@cmd ... passed");
	    $success = TRUE;
	    last;
         }
         else {
            trace("@cmd ... failed");
	    if (scalar(@capout) > 0) {
	    trace("capout=@capout");
 	    }
         }
      }
      else {
         trace("Avoiding self copy of ocr.loc on node: $node");
      }
   }

   if ($success) {
      rename ($ocrloc_temp, $ocrloc_file);
   } else {
      trace("@cmd ... failed");
      s_remove_file ("$ocrloc_temp");
   }

   return TRUE;
}

sub s_removeGPnPprofile
#-------------------------------------------------------------------------------
# Function: Remove all contents under $crshome/gpnp dir
# Args    : none
#-------------------------------------------------------------------------------
{
   my $dir = catdir($CFG->ORA_CRS_HOME, 'gpnp');

   # read dir contents
   opendir (DIR, $dir);
   my @files = readdir(DIR);
   close DIR;

   my $file;
   foreach $file (@files) {
      if ($file eq '.' || $file eq '..') {
         next;
      }
      elsif (-f "$dir/$file") {
         trace ("remove file=$dir/$file");
         s_remove_file ("$dir/$file");
      }
      elsif (-d "$dir/$file") {
         trace ("rmtree dir=$dir/$file");
         rmtree ("$dir/$file");
      }
   }
}

sub s_remove_file
{
   my $remfile = $_[0];

   if (-e $remfile || -l $remfile) {
      my @args = ("rm", $remfile);

      trace("Removing file $remfile");
      my @out = s_system_cmd_capture2(@args);
      my $rc  = shift @out;

      if ($rc == 0) {
         trace("Successfully removed file: $remfile");
      }
      else {
         trace("Failed to remove file: $remfile");
         return $FAILED;
      }
   }

   return $SUCCESS;
}

sub s_system_cmd_capture2 {

  my $rc = 0;
  my @output;

  @output = `@_ 2>&1`;
  $rc = $? >> 8;

  if (($rc != 1) && ($rc & 127)) {
    # program returned error code
    my $sig = $rc & 127;
    trace("Failure with return code $sig from command: @_");
  }
  elsif ($rc) { 
    trace("Failure with return code $rc from command @_"); 
  }

  if ($DEBUG) { trace("@output"); }

  return ($rc, @output);
}

sub s_getAbsLink
#-------------------------------------------------------------------------------
# Function: Get absolute link
# Args    : file_loc
# Returns : link_loc
#-------------------------------------------------------------------------------
{
   my $file_loc = $_[0];
   my $link_loc = readlink($file_loc);
   my $count    = 0;

   $count++ while ($link_loc =~ /\.\./g);

   if ($count > 0) {
      trace("symbolic link is not absolute link: $link_loc");
      my @ocr_dir       = split(/\//, $file_loc);
      my @link_dir      = split(/\.\./, $link_loc);
      my $ocr_dir_cntr  = scalar @ocr_dir;
      my $abs_link      = '/';
      my $limit         = $ocr_dir_cntr - $count - 1;
      my $i;

      for ($i = 0; $i < $limit; $i++) {
          $abs_link = catdir($abs_link, $ocr_dir[$i]);
      }

      $link_loc = catfile($abs_link, $link_dir[$count]);
      trace("absolute link is $link_loc");
   }

   return $link_loc;
}

sub s_crf_check_bdbloc
{
  my $bdbloc = $_[0];

  trace("CHM/OS repository location checks: $bdbloc");

  # check for existence first
  if (! -d $bdbloc)
  {
    trace("INFO: CHM/OS repository path $bdbloc does not exist. Creating...\n");
    mkpath($bdbloc);
  }

  if (! -w $bdbloc)
  {
    trace("INFO: CHM/OS repository path $bdbloc is not writable, changing ");
    trace("permissions on it...\n");
    s_set_perms ("0755", $bdbloc);
  }

  # check for space now. df -k reports 1K blocks on linux/solaris.
  # Check for 2GB per node.
  my $rqrd;
  my $nodelist = $_[1];
  my $df;

  # For storing the df -k/bdf index as it is same on Linux, Solaris, 
  # HPUX but different on AIX. In AIX it is 3rd column for available 
  # space where as in others it is 4
  my $avail_index;
  
  if ($^O =~ /aix/i)
  {
    $avail_index = 2;
  }
  else
  {
    $avail_index = 3;
  } 
  
  # Linux and Solaris has df command but HPUX doesn't have it.
  # For fixing Bug 11675864. HPUX uses bdf comand.
  
  if ($^O =~ /hpux/i)
  {
    $df =  "/usr/bin/bdf";
  }
  else
  {
    $df = "/bin/df -k";
  }

  chomp($nodelist);
  my @hosts    = split(/[,]+/, $nodelist);
  my $tlang    = $ENV{LANG};
  my $tlcall   = $ENV{LC_ALL};
  $ENV{LANG}   = "";
  $ENV{LC_ALL} = "";

  $rqrd = 1024*1024;

  if (open(DFH, "$df $bdbloc 2>/dev/null |"))
  {
    $ENV{LANG} = $tlang;
    $ENV{LC_ALL} = $tlcall;
    my $fulline="";
    while (<DFH>)
    {
      chomp();
      if (!($_ =~ m/Filesystem.*/i))
      {
        $fulline .= $_;
      }
    }
    close DFH;
    my @parts = split(/[ \n]+/, $fulline);
    my $avl = $parts[$avail_index];
    if ($avl < $rqrd)
    {
      error("Insufficient free space available in CHM/OS repository $bdbloc;" .
            "required space is $rqrd KB and available space is $avl KB;" .
            " run 'oclumon manage -repos reploc <new_path>' command to change" .
            " CHM/OS"); 
      return 12; #correct error code for out of space.
    }
    $rqrd += $rqrd/3;
    if ($avl < $rqrd)
    {
      trace("WARNING: File system hosting the CHM/OS repository $bdbloc is");
      trace(" running low on disk space. Available disk space=$avl KB. ");
    }
  }
  $ENV{LANG} = $tlang;
  $ENV{LC_ALL} = $tlcall;
}

sub s_crf_remove_itab
{
  trace("Removing /etc/init.d/init.crfd");
  unlink("/etc/init.d/init.crfd");

  if ( ! s_is_Linux_Upstart())
  {
    # cleanup from the auto startup configuration
    s_remove_itab ("crfd");
    system ("$INIT q");
  }
}

sub s_is_primeCluster
{
    my $status;
    my $checksc = "/usr/bin/cftool";
    if (! (-e $checksc)) {
      trace ("$checksc not found");
      return FALSE;
    }
    $status = system("$checksc -l");
    if ($status == 0) {
        return TRUE;
    } else {
        return FALSE;
    }
}

sub s_is_sunCluster
{
    my $status;
    my $checksc = "/usr/sbin/clinfo";
    if (! (-e $checksc)) {
      trace ("$checksc not found");
      return FALSE;
    }
    $status = system("$checksc");
    if ($status == 0) {
        return TRUE;
    } else {
        return FALSE;
    }
}

# we cannot support solaris 5.11 ipmp interfaces
sub s_is_sun_ipmp
{
  my $ifconfig = "/usr/sbin/ifconfig";
  my ($net, $inf, $sub, $type, $tmp, $rc, @out);

  #  if(Solaris 11) && (Upgrade to 11.2.0.3) then return true (disable HAIP)
  if($UPGRADE && isVersionLT11203($CFG->oldconfig('ORA_CRS_VERSION')))
  {
    my $cmd = "/sbin/uname -r";

    ($rc, @out) = system_cmd_capture($cmd);
    if ( $rc != 0) {
      trace ("$cmd returns $rc");
      return TRUE;
    }
    if ( $out[0] eq "5.11") {
      trace ("this is solaris 511");
      return TRUE;
    }
    trace ("this is solaris $out[0]");
  }

  # split apart the network keys and search
  foreach $net (split(/,/, $CFG->params('NETWORKS')))
  {
    ($inf, $tmp)  = split(/\//, $net);
    ($sub, $type) = split(/:/, $tmp);
    
    # we only care about cluster_interconnect keys
    next if( $type !~ /cluster_interconnect/ );

    # lets call ifconfig to figure out information about this interface
    ($rc, @out) = system_cmd_capture($ifconfig, $inf);

    # skip any interfaces on which we had errors
    next if( $rc != 0 );

    # if we find any cluster_interconnect keys that have IPMP flag set
    # on their interface description, then we are done
    if( $out[0] =~ /IPMP/ )
    {
      return TRUE;
    }
  }

  # made it all the way out without finding any IPMP private
  return FALSE;
}

# we only create the HAIP resources for CRS installs and for now only on
# linux, hpux, solaris, aix but eventually this should be for all unix.
# NO HAIP if this is sun cluster or solaris 5.11 with IPMP as private
sub s_is_HAIP_supported
{
  if(($OSNAME eq "linux") || ($OSNAME eq "hpux") || ($OSNAME eq "aix") ||
     (($OSNAME eq "solaris") && (!s_is_sunCluster()) && (!s_is_primeCluster())
      && (!s_is_sun_ipmp())))
  {
    return TRUE;
  }
  else {
    return FALSE;
  }
}

# On some platforms we will install the HAIP resource, but we won't worry
# about it's failure to come up but continue on regardless
sub s_is_HAIP_NonFatal
{
  if( ($OSNAME eq "hpux") || ($OSNAME eq "aix") )
  {
    return TRUE;
  }
  else 
  {
    return FALSE;
  }
}

# In Linux, there are two startup mechanisms. SysVInit and the newer upstart.
# This routine will check if upstart is being used or not.
# returns TRUE if upstart is being used for the init

sub s_is_Linux_Upstart
{
  # Check not cached, check if it is upstart
  if ( $UPSTART_USED == -1 ) {
     if ($OSNAME eq 'linux')
     {
        my $rpm = '/bin/rpm';
        my @cmd = ($rpm, '-qf',  '/sbin/init');
        my ($rc, @grepout, @cmdout);

       # Check if rpm is present
       if (! (-e $rpm)) {
         error ("$rpm not found\n");
         return FALSE;
       }

       # Run the rpm command
       ($rc, @cmdout) = system_cmd_capture(@cmd);
       if ( $rc != 0) { return FALSE; }

       # check for upstart in rpm output
       @grepout = grep(/^UPSTART-/i, @cmdout);
       if (scalar(@grepout) > 0) { $UPSTART_USED=TRUE; return TRUE; }
     }
     # Non-Linux
     $UPSTART_USED=FALSE;
     return FALSE;
  }
  # return the cached value
  return $UPSTART_USED;
}

# Add the oracle-ohasd conf file from CRSHOME to /etc/init
sub s_add_upstart_conf
{
   my ($status, @output);
   my $UPSTART_INIT_DIR = $CFG->params('UPSTART_INIT_DIR');
   my $UPSTART_OHASD_CONF_CH = catfile ($CFG->ORA_CRS_HOME, 'crs', 'install', $UPSTART_OHASD_CONF_FILE);
   my $UPSTART_OHASD_CONF = catfile ($UPSTART_INIT_DIR, $UPSTART_OHASD_CONF_FILE);

   if ( -e $UPSTART_OHASD_CONF_CH ) {
       # Copy $UPSTART_OHASD_CONF_CH to /etc/init/
       unless (copy ("$UPSTART_OHASD_CONF_CH", "$UPSTART_OHASD_CONF")) {
       error ("Can't copy $UPSTART_OHASD_CONF_CH to $UPSTART_OHASD_CONF: $!");
       return $FAILED;
       }
   }
   else {
        error("$UPSTART_OHASD_CONF_CH does not exist.");
        return $FAILED;
   }

   # Restore the default SELinux security context
   if ( -e $RESTORECON ) {
      ($status, @output) = system_cmd_capture ("$RESTORECON -iF $UPSTART_OHASD_CONF");
   }
   return $SUCCESS;
}



#### Function for removing the Oracle conf files from /etc/init
#  ARGS : 1 - match pattern for the Oracle conf file pattern
#  NOTE : Oracle conf files will be of the format : oracle-{name}.conf like oracle-ohasd.conf
sub s_remove_upstart_conf
{
   my ($status, @output, @initctl_list, @file_list, $file, $service, $service_name);
   my $match_pattern = $_[0];
   my $INITCTL = $CFG->params('INITCTL');
   my $UPSTART_INIT_DIR = $CFG->params('UPSTART_INIT_DIR');

   #
   # Construct service and then stop it
   #

   # Get list of registered services in the system
   ($status, @output) = system_cmd_capture ("$INITCTL list");
   if(0 != $status)
   {
     error ("Failed to list INITCTL, error: $!");
     return $FAILED;
   }

   # Filter the pattern of services interested from the initctl list
   @initctl_list = grep(/$match_pattern/i, @output);

   # Stop any running services from the list
   foreach $service(@initctl_list)
   {
       # Check if it is in running state and stop it
       if (scalar(grep(/running/,$service) > 0))
       {
           ($service_name)  = split(/ /, $service);
           trace("Service [$service_name] running.\n");
           ($status, @output) = system_cmd_capture ("$INITCTL stop $service_name");
           if(0 != $status)
           {
             error ("Failed to stop service $service_name, error: $!\n");
             return $FAILED;
           }
       }
   }

   #
   # Remove the corresponding conf files
   #


   # Construct the file path pattern for the upstart conf files
   #
   for ($match_pattern) {
      # Replace the | with space of the match_pattern
      s-\|- -g;
      # Convert pattern "ohasd cssd" to "/etc/init/oracle-*ohasd*.conf /etc/init/oracle-*cssd*.conf "
      s-^-${UPSTART_INIT_DIR}/oracle\-*-g;
      s- - ${UPSTART_INIT_DIR}/oracle\-*-g;
      s- -*.conf -g;
      s-$-*.conf -g;
   }

   # Get the file list for the pattern
   (@file_list) = glob ($match_pattern);
   trace ("Glob file list = @file_list");

   # Remove the conf file
   foreach $file(@file_list) {
     s_remove_file("$file");
   }

   return $SUCCESS;
}


sub s_getfileinfo
{
  my $file = $_[0];
  my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,$blksize
,$blocks);
  my $user;
  my $group;
  my $permissions;

  trace("Getting file permissions for $file\n");
  if (($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,$blksize,$blocks) = lstat($file)) {
        $user = getpwuid($uid);
        $group = getgrgid($gid);
        $permissions = sprintf "%04o", S_IMODE($mode);

        return($file, $user , $group, $permissions);
  }
}

sub s_saveParentDirinfo
#-------------------------------------------------------------------------------
# Function: save $current_dir and its parent directories ACL
#
# Args    : [0] Directory
#-------------------------------------------------------------------------------
{
   my $dir = $_[0];
   my $savepermfile = catfile ($CFG->ORA_CRS_HOME, "crs", "install",
                               "ParentDirPerm_$HOST.txt");
   my ($fname, $fuser, $fgroup, $fperm, @perm_table);
   trace("saving parent dir ACLs in $savepermfile\n");

   if (-e $savepermfile) {
      # load into @perm_table
      trace("loading... $savepermfile\n");
      @perm_table = read_file ($savepermfile);
   }

   my $save_entries = scalar(@perm_table);
   while ($dir ne "/" && $dir ne ".") {
      ($fname, $fuser, $fgroup, $fperm) = s_getfileinfo($dir);
      my $text = "$fname:$fuser:$fgroup:$fperm";
      my $search_str = $fname . ':';

      # check if it exists
      my $found = FALSE;
      foreach my $rec (@perm_table) {
         chomp($rec);
         if ($rec =~ m/^$search_str/) {
            $found = TRUE;
          }
      }

      if (! $found) {
         push @perm_table, $text;
      }

      $dir = dirname($dir);
   }

   # if new record is added to the @perm_table, create new perm file
   if (scalar(@perm_table) != $save_entries) {
      if (s_remove_file($savepermfile)) {
         open (SFILE, ">$savepermfile") or
            error("Can't open $savepermfile to write permisisons: $!");

         foreach my $dir (@perm_table) {
            trace("writing $dir to $savepermfile");
            print SFILE "$dir\n";
         }

         close SFILE;
      }
   }

   s_set_ownergroup ($SUPERUSER, $ORA_DBA_GROUP, $savepermfile);
   s_set_perms ("0644", $savepermfile) ;
}

sub s_install_initd
{
   if (s_isSUSELinux()) {
      my $ohasd  = catfile($ID, 'ohasd');
      my $initd  = catfile('/usr', 'lib', 'lsb', 'install_initd');
      my @out    = system_cmd_capture($initd, $ohasd);
      my $status = shift @out;

      if ($status != 0) {
         error ("Failed to install ohasd startup script, error: $!");
         return $FAILED;
      }
   }

   return $SUCCESS;
}

sub s_remove_initd
{
   # remove initd if it's SUSE Linux
   if (s_isSUSELinux()) {
      my $ohasd  = catfile($ID, 'ohasd');
      my $initd  = catfile('/usr', 'lib', 'lsb', 'remove_initd');
      my @out    = system_cmd_capture($initd, $ohasd);
      my $status = shift @out;

      if ($status != 0) {
         trace ("Failed to remove initd");
      }
   }
}

sub s_isSUSELinux
{
   # return FALSE if ade environment
   if (is_dev_env()) {
      return FALSE;
   }

   my $rpm = catfile('/bin', 'rpm');
   if (!(-e $rpm)) {
      trace("$rpm command does not exist");
      return FALSE;
   }

   my @cmd = ($rpm, '-q', 'sles-release');
   my @out  = system_cmd_capture ("@cmd");
   my $rc = shift @out;

   if ($rc == 0) {
      return TRUE;
   }
   else {
      return FALSE;
   }
}

#------------------------------------------------------------------------------
# Function: check if network configuration files need to be updated to 
#           disable 169.254/16 route usage (ZEROCONF)
#------------------------------------------------------------------------------
sub s_CheckNetworkConfig
{
  my $fixed = TRUE;
  my $base;
  my $temp;
  my $save;

  # network configuration modifications only valid for linux
  if( !($OSNAME eq "linux") )
  {
    return;
  }

  if( is_dev_env() ) 
  {
    trace("Skipping network configuration checks due to DEV env");
    return;
  }

  if ( -e $suseNetworkConfig && -f $suseNetworkConfig )
  {
    $base  = $suseNetworkConfig;
    $fixed = s_suseCheckNetworkConfig($base);
  }
  elsif( -e $oelNetworkConfig && -f $oelNetworkConfig )
  {
    $base  = $oelNetworkConfig;
    $fixed = s_oelCheckNetworkConfig($base);
  }

  # if we dont need to do any more work then just leave
  if( ! $fixed )
  {
    return;
  }

  # otherwise lets swap the temporary files with the new ones
  $save = $base . $checkNetworkSave;
  $temp = $base . $checkNetworkTemp;

  # cleanup any original files
  unlink $save;

  # move the original base file to a temporary name
  rename $base, $save;

  # then move the temporary file to this new name
  rename $temp, $base;

  # and let the world know what we have done
  trace("Disabled LinkLocal Address manipulation");
}

#------------------------------------------------------------------------------
# Function: check if network configuration files need to be updated to 
#           disable 169.254/16 route usage (ZEROCONF)
#
# Args    : [0]  Base path to OEL configuration files
#------------------------------------------------------------------------------
sub s_oelCheckNetworkConfig
{
  my $baseFile = $_[0];
  my $tempFile = $_[0] . $checkNetworkTemp;
  my $numFound = 0;
  my $found    = FALSE;
  my $line;

  unlink $tempFile;

  open BASEFILE, "<$baseFile";
  open TEMPFILE, ">$tempFile";

  foreach $line (<BASEFILE>)
  {
    chomp $line;
    if ( $line !~ /NOZEROCONF=\S*/ || $line =~ /^\s*#/ )
    {
      print TEMPFILE "$line\n";
      next;
    }

    # track that we found at least one occurrence
    # but dont output it to the file yet
    $numFound++;
  }

  # if we found exactly one occurrence then we are fine
  if( 1 == $numFound )
  {
    $found = TRUE;
  }
  # if we didnt find any or we found more than one then force just one
  else
  {
    $found = FALSE;
    
    # and output the one good line to the end of the file
    print TEMPFILE "NOZEROCONF=yes\n";
  }
  close BASEFILE;
  close TEMPFILE;

  # if we found the setting, then we can just throw away this temp file
  if( $found )
  {
    unlink $tempFile;
  }

  return ! $found;
}

#------------------------------------------------------------------------------
# Function: check if network configuration files need to be updated to 
#           disable 169.254/16 route usage (ZEROCONF)
#
# Args    : [0]  Base path to suse network configuration files
#------------------------------------------------------------------------------
sub s_suseCheckNetworkConfig
{
  my $found    = FALSE;
  my $baseFile = $_[0];
  my $tempFile = $_[0] . $checkNetworkTemp;
  my $line;

  unlink $tempFile;

  open BASEFILE, "<$baseFile";
  open TEMPFILE, ">$tempFile";

  foreach $line (<BASEFILE>)
  {
    chomp $line;
    if ( $line !~ /LINKLOCAL_INTERFACES=\S*/ || $line =~ /^\s*#/ )
    {
      print TEMPFILE "$line\n";
      next;
    }

    # output to the file the same line but stick a comment '#' at the front
    print TEMPFILE "#${line}\n";

    # track that we found at least one occurrence
    # but dont output it to the file yet
    $found = TRUE;
  }

  # if we did not find any broken lines, then we throw away this temp file
  if( ! $found )
  {
    unlink $tempFile;
  }

  return $found;
}

sub s_restoreInitScripts
{
  my $oldcrshome = $_[0];
  trace("restore init scripts");

  my $initOhasd = 'init.ohasd';
  my $ohasd = 'ohasd';
  my $oldInitOhasd  = catfile ($oldcrshome, 'crs', 'init', $initOhasd);
  my $oldOhasd  = catfile ($oldcrshome, 'crs', 'init', $ohasd);

  my $newInitOhasd  = catfile ($ID, $initOhasd);
  my $newOhasd  = catfile ($ID, $ohasd);

  # restore the init scripts from the old home
  copy_file($oldInitOhasd, $newInitOhasd);
  copy_file($oldOhasd, $newOhasd);
}

sub s_restoreolrloc
{
  my $oldolr = catfile ($OCRCONFIGDIR, 'olr.loc');
  my $oldolrbkp = catfile ($OCRCONFIGDIR, 'olr.loc.bkp');

  trace("restore old olr.loc file");
  return copy_file($oldolrbkp, $oldolr);
}

sub s_checkolrbackup
{
  my $oldolrbkp = catfile($OCRCONFIGDIR, 'olr.loc.bkp');

  if (! (-e $oldolrbkp))
  {
    error("Could not find OLR backup");
    return FAILED;
  }

  return SUCCESS;
}

#-------------------------------------------------------------------------------
# Function: checks if the user running the upgrade matches with the owner
# of the old crs home.
# Args    : none
# Returns : TRUE or FALSE
#-------------------------------------------------------------------------------
sub s_checkOldCrsOwner
{
  my $ch = $CFG->OLD_CRS_HOME;
  my $cssd_bin = "$ch/bin/ocssd.bin";
  my $ch_owner = $CFG->params('ORACLE_OWNER');
  my $old_ch_owner;

  if (-x $cssd_bin)
  {
    my ($dev, $ino, $mode, $nlink, $uid, $gid, $rdev, $size, $atime, $mtime, $ctime,
         $blksize, $blocks) = stat($cssd_bin);

    my ($name, $passwd, $uuid, $ugid, $quota, $comment, $gcos, $dir, $shell)
       = getpwuid( $uid );
    $old_ch_owner = $name;

    trace( "Owner of executable '$cssd_bin': $old_ch_owner" );

  }
  else
  {
    error("Unable to get owner information for the executable '$cssd_bin'");
    return FALSE;
  }

  trace("new CH owner = $ch_owner");
  trace("old CH owner = $old_ch_owner");

  if ($old_ch_owner !~ $ch_owner)
  {
    error("Owner '$old_ch_owner' of the old crs home does not match with owner '$ch_owner' of the new crs home");
    return FALSE;
  }

  return TRUE;
}


####---------------------------------------------------------
#### Function for restoring ASM files during the downgrade
#### from 11203 to 11201/2
# ARGS : 0
sub s_restoreASMFiles
{
  my $optorcldir = $CFG->params('EXTERNAL_ORACLE');
  my $optorclbindir = $CFG->params('EXTERNAL_ORACLE_BIN');
  my $asmgidfile = catfile($optorclbindir, 'setasmgid');
  my $asmgidorg = catfile($CFG->OLD_CRS_HOME, 'bin', 'setasmgid');
  my $ORA_DBA_GROUP = $CFG->params('ORA_DBA_GROUP');

  trace("Re-creating the directory '$optorclbindir'");
  if (-d $optorcldir)
  {
    mkpath($optorclbindir);
  }

  if (!(-d $optorclbindir))
  {
    error("Failed to re-create $optorclbindir");
    return FAILED;
  }
  else
  {
    if (FAILED == s_set_ownergroup($CFG->SUPERUSER, $ORA_DBA_GROUP,
                                    $optorclbindir))
    {
      error("Failed to change the ownership of $optorclbindir");
      return FAILED;
    }

    if (FAILED == s_set_perms("0750", $optorclbindir))
    {
      error("Failed to change the permissions of $optorclbindir");
      return FAILED;
    }
  }

  trace("Restoring $asmgidfile");
  if (FAILED == copy_file($asmgidorg, $asmgidfile,
                           $CFG->SUPERUSER, $ORA_DBA_GROUP))
  {
    error("Failed to restore $asmgidfile");
    return FAILED;
  }

  if (FAILED == s_set_perms("4710", $asmgidfile))
  {
    error("Failed to change permissions on $asmgidfile");
    return FAILED;
  }

  trace("Setting the ownership and permissions of $optorcldir "
       ."to the original");
  if (-d $optorcldir)
  {
    s_set_ownergroup($CFG->SUPERUSER, $ORA_DBA_GROUP, $optorcldir);
    s_set_perms("0750", $optorcldir);
  }

  # Remove /etc/oracle/setasmgid from higher version
  my $file = catfile($CFG->params('OCRCONFIGDIR'), 'setasmgid');
  if (-f $file)
  {
    trace("Remove $file");
    s_remove_file("$file");
  }

  return SUCCESS;
}


####---------------------------------------------------------
#### Function for removing ASM files during the upgrade from
#### 11201/2 to 11203
# ARGS : 0
sub s_cleanASMFiles
{
  my $optorcldir = $CFG->params('EXTERNAL_ORACLE');
  my $optorclbindir = $CFG->params('EXTERNAL_ORACLE_BIN');
  my $ORACLE_OWNER = $CFG->params('ORACLE_OWNER');
  my $ORA_DBA_GROUP = $CFG->params('ORA_DBA_GROUP');

  if (-d $optorclbindir)
  {
    my @res;

    opendir(DIR, $optorclbindir);
    my @files = readdir(DIR);
    close DIR;

    foreach my $file (@files)
    {
      if ($file =~ /^setasmgid/)
      {
        s_remove_file("$optorclbindir/$file");
      }
      else
      {
        push(@res, $file);
      }
    }

    my $noEmpty = 0;
    foreach my $file (@res)
    {
      if (($file eq '.') || ($file eq '..'))
      {
        next;
      }

      $noEmpty = 1; 
    }

    if (0 == $noEmpty)
    {
      trace("Removing $optorclbindir");
      rmtree($optorclbindir);
    }
  }

  # We don't want to fail the upgrade if the clean fails, so 
  # we just trace it and move forward.
  if (-d $optorclbindir)
  {
    trace("Could not reomve the directory '$optorclbindir'");
  }

  if (-d $optorcldir)
  {
    trace("Change the owner of $optorcldir to $ORACLE_OWNER");
    if (FAILED == s_set_ownergroup($ORACLE_OWNER,
                                    $ORA_DBA_GROUP, $optorcldir))
    {
      trace("Could not change ownership on $optorcldir");
    }

    trace("Change the permissons of $optorcldir");
    if (FAILED == s_set_perms("0775", $optorcldir))
    {
      trace("Could not change permissions on $optorcldir");
    }
  }
}

####-----------------------------------------------------------------------
#### Synchronizes a file's in-memory state with that on the physical medium
# ARGS: 1
# ARG1: The full path of given file
# @returns SUCCESS or FAILED
sub s_syncToPhysicalDisk
{
   my $filename = $_[0];
   my $fh;

   trace("Sync '$filename' to the physical disk");
   if (!(-e $filename))
   {
     trace("'$filename' does not exist. Skipping ...");
     return SUCCESS;
   }

   if (open($fh, '>>', $filename))
   {
     $fh->sync;
     close($fh);
   }
   else
   {
     error("Could not open file '$filename' : $!");
     return FAILED;
   }

   return SUCCESS;
}



1;
