MINI MINI MANI MO

Path : /opt/oracle/product/18c/dbhomeXE/lib/
File Upload :
Current File : //opt/oracle/product/18c/dbhomeXE/lib/osds_acfsroot.pm

#)
#
# osds_acfsroot.pm
# 
# Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
#
#
#    NAME
#      osds_acfsroot.pm - Linux OSD component of acfsroot.
#
#    DESCRIPTION
#      Purpose
#          Install/uninstall USM components.
#
#    NOTES
#      All user visible output should be done in the common code.
#      this will ensure a consistent look and feel across all platforms.
#
#

use strict;
package osds_acfsroot;
require Exporter;
our @ISA = qw(Exporter);
our @EXPORT = qw(
                 osds_fix_wrapper_scripts
                 osds_get_kernel_version
                 osds_initialize
                 osds_install_from_distribution_files
                 osds_is_kabi_compatible
                 osds_search_for_distribution_files
                 osds_load_and_verify_usm_state
                 osds_usm_uninstall
                 osds_patch_verify
                 get_install_home_from_base
                 machine_is_supported_linux
                 machine_is_supported
                 machine_is_RH
                 machine_is_SLES
                 osds_symvers_exists
                 $MEDIA_FOUND
                 $ORACLE_HOME
                 $USM_DFLT_DRV_LOC
                 $USM_DFLT_CMD_LOC
                 $USM_TUNE_OS_DIR
                 $USM_TUNE_ORA_DIR
                 @OH_BIN_COMPONENTS
                 @OH_LIB_COMPONENTS
                 @SBIN_COMPONENTS
                 @USM_PUB_COMPONENTS
                 @MESG_COMPONENTS
                );

use osds_acfslib;
use acfslib;

our ($ORACLE_HOME) = $ENV{ORACLE_HOME};

# This file is used by other commands, like acfsdriverstate. These commands can
# be run by a user, using a perl location in the db home. When this is done,
# ORACLE_HOME points to the dbhome, not crs home. However, to run other
# commands, we need access to the crs home - the acfs modules exist there.
# So, if ORACLE_HOME points to the db home (no usm/install dir), point it to the
# CRS_HOME. Both ORACLE_HOME and ORA_CRS_HOME are set in the wrapper scripts for
# the individual commands.
$ORACLE_HOME = $ENV{ORA_CRS_HOME} if (!(-e "$ORACLE_HOME/usm/install"));

my  ($SHIPHOME_BASE_DIR) = "$ORACLE_HOME/usm/install";
our ($USM_DFLT_CMD_LOC)  = "$SHIPHOME_BASE_DIR/cmds/bin";      # cmds media loc
our ($USM_DFLT_DRV_LOC);                        # location of the drivers media
my  ($MINUS_L_DRIVER_LOC);
our ($MEDIA_FOUND) = '';                        # path name to media
                                                # used for version_check
use constant UID  => 4;
use constant GID  => 5;
use constant KABI_NOT_SUPPORTED => "KABI_NOT_SUPPORTED";
 
my ($ARCH)    = `uname -i`;                     # Machine architecture - i386
chomp($ARCH);
my ($UNAME_R) = `uname -r`;
chomp($UNAME_R);
my ($no_init) = "";
$no_init = `/sbin/weak-modules -h | grep ^'--no-init'` if machine_is_RH();
chomp($no_init);

# We do not install/uninstall the commands destined for ORACLE_HOME - that
# is now done by the mapfiles during Oracle install/uninstall. We use
# <XXX>_COMPONENTS only to verify that the commands exist in their
# installed location.
# The exception are the commands destined to live in /sbin. Since OUI
# won't have permissions to copy these commands directly, we do it here.

my ($SBIN_DIR)         = "/sbin";
my ($OH_BIN_DIR)       = "$ORACLE_HOME/bin"; 
my ($OH_LIB_DIR)       = "$ORACLE_HOME/lib"; 
my ($MESG_DST_DIR)     = "$ORACLE_HOME/usm/mesg";
my ($USM_PUB_DST_DIR)  = "$ORACLE_HOME/usm/public"; 
my ($CMDS_SRC_DIR)     = "$SHIPHOME_BASE_DIR/cmds/bin"; 
my ($MESG_SRC_DIR)     = "$SHIPHOME_BASE_DIR/../mesg"; 
my ($USM_LIB_SRC_DIR)  = "$SHIPHOME_BASE_DIR/../lib"; 
my ($USM_PUB_SRC_DIR)  = "$SHIPHOME_BASE_DIR/../public"; 

our ($USM_TUNE_OS_DIR)  = "/etc/sysconfig";
our ($USM_TUNE_ORA_DIR) = "$ORACLE_HOME/acfs/tunables";

# ACFS library name.
my ($LIBACFS)          = "libacfs18.so";

# Default ACFS library install directory 
my ($LIBACFS_DIR)      = "/opt/oracle/extapi/64/acfs/orcl/1/";

# Bug 21518337
# tsc tkfvinfolink12 in which we extract the content of these elements.
our (@SBIN_COMPONENTS) = (
     "advmutil",                         "advmutil.bin",
     "fsck.acfs",                        "fsck.acfs.bin",
     "mkfs.acfs",                        "mkfs.acfs.bin",
     "mount.acfs",                       "mount.acfs.bin",
     "acfsdbg",                          "acfsdbg.bin",
     "acfsutil",                         "acfsutil.bin",
     "umount.acfs",                      "umount.acfs.bin",
     "acfssihamount",
);

our (@OH_BIN_COMPONENTS) = (
     "$OH_BIN_DIR/acfsdriverstate",      "$OH_BIN_DIR/acfsload",
     "$OH_BIN_DIR/acfsregistrymount",    "$OH_BIN_DIR/acfsroot",
     "$OH_BIN_DIR/acfsrepl_apply",       "$OH_BIN_DIR/acfsrepl_apply.bin",
     "$OH_BIN_DIR/acfsrepl_monitor",     "$OH_BIN_DIR/acfsreplcrs",          
     "$OH_BIN_DIR/acfsrepl_preapply",    "$OH_BIN_DIR/acfsrepl_transport",
     "$OH_BIN_DIR/acfsrepl_initializer", "$OH_BIN_DIR/acfssinglefsmount",
     "$OH_BIN_DIR/acfsrepl_dupd",        "$OH_BIN_DIR/acfsrepl_dupd.bin",
     "$OH_BIN_DIR/acfshanfs",            "$OH_BIN_DIR/acfsrm",
     "$OH_BIN_DIR/acfsremote",           "$OH_BIN_DIR/acfscm",
     "$OH_BIN_DIR/acfsiob",              "$OH_BIN_DIR/acfsrd",
);

our (@OH_LIB_COMPONENTS) = (
     "$OH_LIB_DIR/acfsdriverstate.pl",   "$OH_LIB_DIR/acfslib.pm",
     "$OH_LIB_DIR/acfsload.pl",          "$OH_LIB_DIR/acfsregistrymount.pl",
     "$OH_LIB_DIR/acfstoolsdriver.sh",   "$OH_LIB_DIR/osds_acfsdriverstate.pm",
     "$OH_LIB_DIR/osds_acfslib.pm",      "$OH_LIB_DIR/osds_acfsload.pm",
     "$OH_LIB_DIR/acfsroot.pl",          "$OH_LIB_DIR/acfssinglefsmount.pl",
     "$OH_LIB_DIR/osds_acfsroot.pm",     "$OH_LIB_DIR/acfsreplcrs.pl",
     "$OH_LIB_DIR/osds_acfsregistrymount.pm",
     "$OH_LIB_DIR/osds_acfssinglefsmount.pm",
     "$OH_LIB_DIR/osds_unix_linux_acfslib.pm",
     "$OH_LIB_DIR/$LIBACFS",             "$OH_LIB_DIR/osds_acfsremote.pm",
     "$OH_LIB_DIR/acfshanfs.pl",         "$OH_LIB_DIR/acfsremote.pl", 
     "$OH_LIB_DIR/acfsr_member",         
     "$OH_LIB_DIR/65-usm-acfsr-member.rules",
);

our (@USM_PUB_COMPONENTS) = (
     "$USM_PUB_DST_DIR/acfslib.h",
);

our (@MESG_COMPONENTS) = (
     "$MESG_DST_DIR/acfsus.msb",
     "$MESG_DST_DIR/acfsus.msg",
);

my (@OH_COMPONENTS) = (@OH_BIN_COMPONENTS, @OH_LIB_COMPONENTS);

my ($DRIVER_DIR);              # installed driver location 
my ($minus_l_specified) = 0;   # Alternate install location specified by user.

# set by osds_search_for_distribution_files() and
# consumed by osds_install_from_distribution_files() 
my ($OIP_PATH, $GPL_PATH);

# make sure that /sbin is in the PATH - that's where modprobe lives
$ENV{PATH} .= ':/sbin';

my ($ASMADMIN);                          # ASM admin group name
my ($KVER);                              # kernel version being installed

# osds_symvers_exists
#
# /sbin/weak-modules depends on /boot being accessible and the 
# symvers-<kernel_version> file being present.
sub osds_symvers_exists
{
  my ($kver) = @_;
  if ($osds_acfslib::configuration{symvers})
  {
    if ($osds_acfslib::configuration{symvers} eq "no")
    {
      return 0;
    }
    else
    {
      return 1;
    }
  }
  if (!$kver)
  {
    $kver = $UNAME_R;
  }

  if (machine_is_RH())
  {
    my ($symvers_file) = "symvers-" . $kver . ".gz";
    $osds_acfslib::configuration{symversfile} = $symvers_file;
    if (! -r "/boot/$symvers_file")
    {
      lib_error_print(9213,
        "Configuration file '%s' in the /boot directory does not exist or cannot be read.",
         $symvers_file);
      $osds_acfslib::configuration{symvers} = "no";
      return 0;
    }
  }
  $osds_acfslib::configuration{symvers} = "yes";
  return 1;
}

# osds_is_kabi_compatible
#
# Predict the success to load ACFS Drivers on not supported kernels, 
# without loading the drivers. 
# Compare checksum symbols in the driver versus checksum symbols in the kernel.
# Checking for unknown symbols and disagree about version of symbols.
# Using weak-modules command
#
sub osds_is_kabi_compatible
{
  my ($base_directory, $kver) = @_;
  my $compatible = "is compatible";
  my $not_compatible = "is not compatible";
  my $weak_modules = "/sbin/weak-modules";
  # if weak-modules does not exist or it is not executable,
  # We can not check kabi compatibility
  if (!-e $weak_modules || 
      !-X $weak_modules)
  {
    lib_error_print(9551, "Command file '/sbin/weak-modules' does not exist " .
                          "or it is not an executable.");
    return 0;
  }

  # We need to uncompress driver files first
  lib_uncompress_all_driver_files($base_directory);
  
  # In EL5 --no-initrd Do not generate an initrd.
  # In EL6 --no-initramfs Do not generate an initramfs.
  # Both cases, we don't want to generate.
  # 
  # Output for weak-modules looks like:
  # Module oracleoks.ko from kernel 2.6.18-164.0.0.0.1.el5 is compatible 
  #                     with kernel 2.6.18-238.0.0.0.1.el5
  # or
  # Module oracleoks.ko from kernel 2.6.18-164.0.0.0.1.el5 is not compatible   
  #                     with kernel 2.6.18-238.0.0.0.1.el5xen
  # "from kernel" is the kernel used for compiling ACFS Drivers
  # "with kernel" is the installed kernel
  # We want to filter "with kernel"

  #First, We check compatibility for OKS Driver.
  my $command = "ls $base_directory/$DRIVER_COMPONENTS[OKS_IDX] | " .
                "/sbin/weak-modules --verbose --dry-run $no_init --add-modules 2>&1 | " .
                "grep -w 'with kernel $kver' | grep -v 'with kernel $kver.debug' | " .
                "grep -v ksplice";
  my $output = `$command`;
  # We check return code for any error, check for empty output
  # or check for compatible message
  if (($? != 0) ||
      (!$output) ||
      (index($output, $compatible) == -1))
  {
    lib_error_print(9999, "Command Output: $output.");
    #if weak-modules failed we send a message asking to run the command manually 
    #for checking issues
    lib_error_print(9552,
           "Command '/sbin/weak-modules' returned a potential " .
           "compatibility issue. For more details execute the command '%s'.",
           "$command");
    $osds_acfslib::configuration{okskabi} = "no";
    return 0;
  }
  # Second, if OKS Driver is compatible. We need to check compatibility
  # for ACFS and ADVM Drivers. For these cases we can get "is not compatible".
  # But it can be because ACFS and ADVM Drivers need the OKS symbols and these 
  # symbols are not loading in the Kernel Symbol Table.
  # We need to filter out OKS Drivers and determine if the drivers are compatible or not.

  # Getting OKS Symbols
  my $oks_symbols = `/usr/bin/nm --defined-only $base_directory/$DRIVER_COMPONENTS[OKS_IDX]`;

  foreach my $module ($DRIVER_COMPONENTS[AVD_IDX], $DRIVER_COMPONENTS[OFS_IDX])
  {  
    # Checking for ACFS/ADVM Driver
    $command = "ls $base_directory/$module | " .
               "/sbin/weak-modules --verbose --dry-run $no_init --add-modules 2>&1 | " .
               "grep -w 'with kernel $kver' | grep -v 'with kernel $kver.debug' | " .
               "grep -v ksplice";

    $output = `$command`;

    # We need to check, whether ACFS/ADVM is compatible or not
    # If ACFS/ADVM is compatible, we don't need to check for OKS Symbols 
    if ($? != 0 ||
        !$output)
    {
      lib_error_print(9999, "Command Output: $output.");
      #if weak-modules failed we send a message asking to run the command manually 
      #for checking issues
      lib_error_print(9552,
             "Command '/sbin/weak-modules' returned a potential " .
             "compatibility issue. For more details execute the command '%s'.",
             "$command");
      if ($module eq "oracleadvm.ko")
      {
        $osds_acfslib::configuration{advmkabi} = "no";
      }
      else
      {
        $osds_acfslib::configuration{acfskabi} = "no";
      }
      return 0;
    }
    elsif ($output =~ $not_compatible) {
      #We need to split for getting the missing symbols
      my ($header, $symbols) = split(/\:/, $output);
      #remove leading spaces
      $symbols =~ s/^\s+//; 
      #remove trailing spaces    
      $symbols =~ s/\s+$//;    
    
      #Splitting ACFS/ADVM missing symbols
      my @missing_symbols = split(/\s+/, $symbols);
      #Have an array to store confirmed missing symbols 
      my @confirmed_missing_symbols= ();
      foreach my $wrong_symbol (@missing_symbols) 
      {
        #We try to find the symbol in OKS Symbols
        if (!($oks_symbols =~ $wrong_symbol)) 
        {
          push @confirmed_missing_symbols, $wrong_symbol;
        }
      }
      if (@confirmed_missing_symbols)
      {
        if ($module eq "oracleadvm.ko")
        {
          $osds_acfslib::configuration{advmkabi} = "no";
        }
        else
        {
          $osds_acfslib::configuration{acfskabi} = "no";
        }
        lib_error_print(9460, "Missing symbols: '%s'", join ' ', @confirmed_missing_symbols);
        #if weak-modules failed we send a message asking to run the command manually 
        #for checking issues
        lib_error_print(9552,
             "Command '/sbin/weak-modules' returned a potential " .
             "compatibility issue. For more details execute the command '%s'.",
             "$command");
        return 0;
      }
    }
  }
  $osds_acfslib::configuration{driverskabi} = "yes";
  return 1;
}

# osds_initialize
#
# Perform OSD initialization.
#   Set USM_DFLT_DRV_LOC - the location of the USM installation driver media.
#   We deduce the location of the other components from there.
#
sub osds_initialize
{
  my ($install_kver, $sub_command, $install_location, $option_l_used,
      $test_mode, $test_os, $test_unamer, $test_patchlevel, $test_arch) = @_;
  my ($vendor);
  my ($type);
  my (@test_params);
  my ($test_release);

  if (!defined($install_kver))
  {
    # use the current kernel version
    $KVER = $UNAME_R;
  }
  else
  {
    # use the specified kernel version
    # TODO we'll want to do some sanity checking here.
    $KVER = $install_kver;
  }

  if ($test_mode)
  {
    if ($test_os eq "EL5")
    {
      $test_release = "redhat-release-5";
    }
    elsif($test_os eq "EL6")
    {
      $test_release = "redhat-release-6";
    }
    elsif($test_os eq "EL7")
    {
      $test_release = "redhat-release-7";
    }
    elsif($test_os eq "RHEL6")
    {
      $test_release = "redhat-release-server-6";
    }
    elsif($test_os eq "RHEL7")
    {
      $test_release = "redhat-release-server-7";
    }
    elsif($test_os eq "SLES10")
    {
      $test_release = "sles-release-10";
    }
    elsif($test_os eq "SLES11")
    {
      $test_release = "sles-release-11";
    }
    elsif($test_os eq "SLES12")
    {
      $test_release = "sles-release-12";
    }
    push(@test_params, $test_mode);
    push(@test_params, $test_release);
    push(@test_params, $test_unamer);
    push(@test_params, $test_patchlevel);
    push(@test_params, $test_arch);
    $KVER = $test_unamer;
  }
  # we have already verified that we have a valid Linux type
  $type = lib_osds_get_os_type(@test_params);

  $vendor = lib_osds_get_linux_vendor(@test_params);

  # For "acfsdriverstate supported" command, we don't need to know
  # asmadmin name, and we can get some errors running the command
  # We skip this part for supported
  if ($sub_command ne "supported")
  {
    # Get the name of the ASM adminisrator
    $ASMADMIN = lib_get_asm_admin_name();
  }

  if (!((defined($ORACLE_HOME)) &&
        (-e "$ORACLE_HOME/lib/acfsroot.pl") &&
        (-e "$SHIPHOME_BASE_DIR")))
  {
    lib_error_print(9389,
    "ORACLE_HOME is not set to the location of the Grid Infrastructure home.");
    return USM_TRANSIENT_FAIL;
  }

  # ADVM/ACFS is not supported in a LXC environment
  # LXC is sharing the Kernel with the Host OS
  # Inserting new modules is not allowed
  if (lib_is_local_container())
  {
    return USM_NOT_SUPPORTED;
  }
  
  # /sbin/weak-modules depends on /boot being accessible and the 
  # symvers-<kernel_version> file being present.
  if (!$test_mode && !osds_symvers_exists($KVER))
  {
    my ($symvers_file) = "symvers-" . $KVER . ".gz";

    if (! -e "/boot/$symvers_file")
    {
      lib_error_print(9305,
        "ADVM/ACFS installation cannot proceed:");
      lib_error_print(9158,
        "Configuration file '%s' in the /boot directory does not exist.",
        $symvers_file);
      return USM_TRANSIENT_FAIL;
    }
  }

  # default media location - over-ride with the -l option
  my ($base) = $SHIPHOME_BASE_DIR;
  my ($run_install_dir_verification) = 0;

  #Alternative location
  if ($option_l_used)
  {
    $base = $install_location;
    $USM_DFLT_DRV_LOC = get_install_home_from_base($base, $type, $ARCH, $KVER,
                            $run_install_dir_verification, @test_params);
  }
  else
  {
    $run_install_dir_verification = 1;
    $USM_DFLT_DRV_LOC = get_install_home_from_base($base, $type, $ARCH, $KVER,
                            $run_install_dir_verification, @test_params);
  }
  
  if (!$USM_DFLT_DRV_LOC || ($USM_DFLT_DRV_LOC eq KABI_NOT_SUPPORTED)) {
    return USM_NOT_SUPPORTED;	
  }

  return USM_SUCCESS;
}

# osds_get_kernel_version
#
sub osds_get_kernel_version
{
  if (machine_is_supported_linux())
  { 
    return $KVER;
  }

  lib_error_print(9319,"Unknown OS kernel version '%s' detected.",$KVER);
  return USM_FAIL;
} # end osds_get_kernel_version

# osds_install_from_distribution_files
#
# Install the USM components from the specified distribution files
# The files have already been validated by the time we get here
# by osds_search_for_distribution_files(). Also, any previous USM installation
# will have been removed.
#
use File::Path;
sub osds_install_from_distribution_files
{
  my ($component);                 # curent component being installed
  my ($command);                   # current command being executed by system()
  my ($ret) = 0;                   # return of individual copy commands
  my ($return_code) = USM_SUCCESS;

  # install drivers
  # the drivers have been verified to exist so the copy will not fail

  if (! -d $DRIVER_DIR)
  {
    mkpath($DRIVER_DIR, 0, 0755);
  }

  # Print the location of the driver files
  lib_verbose_print (9503, "ADVM and ACFS driver media location is '%s'", 
                     $OIP_PATH);

  foreach $component (@DRIVER_COMPONENTS)
  {
    my ($source) = "$OIP_PATH/$component";
    my ($target) = "$DRIVER_DIR/$component";

    if ($component eq "oracleadvm.ko")
    {
      $source = "$GPL_PATH/$component";
    }

    lib_verbose_print_noalert (9504, "Copying file '%s' to the path '%s'", 
                       $source,
                       $target);

    $command = "cp $source $target";
    if ( ! acfslib::lib_are_same_file($source, $target) )
    {
      $ret = system ($command);
      $return_code = USM_FAIL if $ret;
    }
    else
    { 
      acfslib::lib_inform_print(9506,
               "The files '%s' and '%s' are the same, not copying.",
               $source, $target);
    }
  }

  foreach $component (@SBIN_COMPONENTS)
  {
    my (@array) = split /\//, $component;
    my ($file) = $array[-1];
    my ($source) = "$CMDS_SRC_DIR/$component";
    my ($target) = "$SBIN_DIR/$file";

    $source = "$CMDS_SRC_DIR/$component";

    lib_verbose_print_noalert (9504, "Copying file '%s' to the path '%s'", 
                          $source,
                          $target);

    if ( ! acfslib::lib_are_same_file($source, $target) )
    {
      if($component =~ /acfssihamount/)
      {
        # Check if this is SIHA
        if(lib_osds_is_siha())
        {
          $target = "/etc/init.d/$file";
          $ret =  system ("cp $source $target");
          $ret += system ("/sbin/chkconfig --add $file");
          $ret += system ("/sbin/chkconfig --level 5 $file on");
        }
        else
        {
          # Skip if it isn't.
          next;
        }
      }
      else
      {
        $ret = system ("cp $source $target");
      }
      lib_verbose_print_noalert (9504, "Copying file '%s' to the path '%s'", 
                                        $source,
                                        $target);
      $return_code = USM_FAIL if $ret;
    }
    else
    { 
      acfslib::lib_inform_print(9506,
               "The files '%s' and '%s' are the same, not copying.",
               $source, $target);
    }
    # if I cam write the file, I can change the mode - no need to check return
    system("chmod 0755 $target");
  }

  if ($minus_l_specified)
  {
    # Normally, the ORACLE_HOME/{bin,lib} components are installed via the
    # mapfiles. But, when the user specifies an alternate location via the
    # '-l' option on the command line, we need to install the alternate 
    # OH/{bin,lib} files also. The OH commands are, conveniently located
    # with the sbin commands.
    #
    # If we are replacing existing files, we want to preserve the original
    # file attributes.

    foreach $component (@OH_COMPONENTS) 
    {
      my (@array) = split /\//, $component;
      my ($file) = $array[-1];
      my ($target) = "$component";
      my ($source);
      my ($have_orig);
      my ($uid, $gid);
      $ret = 0;

      if ($component =~ /$LIBACFS/)
      {
        # Special case libusmacfs as it lives apart from the other commands.
        $source = "$USM_LIB_SRC_DIR/$file";
      }
      else
      {
        $source = "$CMDS_SRC_DIR/$file";
      }
      
      $have_orig = 0;

      if (-e $target)
      {
        $have_orig = 1;

        # get the owner/group of the original file
        ($uid, $gid) = (stat($target))[UID,GID];
      }

      if ( ! acfslib::lib_are_same_file($source, $target) )
      {
        lib_verbose_print_noalert (9504, "Copying file '%s' to the path '%s'", 
                           $source, $target);

	unlink ("${target}/${LIBACFS}") if ($component =~ /$LIBACFS/ && 
                                            -e "${target}/${LIBACFS}");
        $ret = system ("cp $source $target");
        $return_code = USM_FAIL if $ret;
      }
      else
      { 
        acfslib::lib_inform_print(9506,
                 "The files '%s' and '%s' are the same, not copying.",
                 $source, $target);
      }
      # For lib directory, we only have two files with mode 0755. If we need to
      # add more files to lib with different mode. Maybe we need to think
      # in change this validation.
      if (($target =~ /\/bin\//) || 
          ($component =~ /acfstoolsdriver.sh/) ||
          ($component =~ /acfsr_member/) ||
          ($component =~ /acfsreplcrs.pl/))
      {
        system("chmod 0755 $target");
      }
      else # lib
      {
        system("chmod 0644 $target");
      }

      if ($have_orig)
      {
        chown $uid, $gid, $target;
      }
    }

    foreach $component (@MESG_COMPONENTS) 
    {
      my (@array) = split /\//, $component;
      my ($file) = $array[-1];
      my ($target) = $component;
      my ($source) = "$MESG_SRC_DIR/$file";
      
      if ( ! acfslib::lib_are_same_file($source, $target) )
      {
        lib_verbose_print_noalert (9504, "Copying file '%s' to the path '%s'", 
                           $source, $target);

        $ret = system ("cp $source $target");
        $return_code = USM_FAIL if $ret;
      }
      else
      { 
        acfslib::lib_inform_print(9506,
                 "The files '%s' and '%s' are the same, not copying.",
                 $source, $target);
      }
    }

    foreach $component (@USM_PUB_COMPONENTS) 
    {
      my (@array) = split /\//, $component;
      my ($file) = $array[-1];
      my ($target) = $component;
      my ($source) = "$USM_PUB_SRC_DIR/$file";

      if ( ! acfslib::lib_are_same_file($source, $target) )
      {
        lib_verbose_print_noalert (9504, "Copying file '%s' to the path '%s'", 
                           $source, $target);

        $ret = system ("cp $source $target");
        $return_code = USM_FAIL if $ret;
      }
      else
      { 
        acfslib::lib_inform_print(9506,
                 "The files '%s' and '%s' are the same, not copying.",
                 $source, $target);
      }
    }

    #If we are using '-l' location, maybe the default location doesn't exist
    if (! -d $USM_DFLT_DRV_LOC)
    {
      mkpath($USM_DFLT_DRV_LOC, 0, 0644);
    }

    # Copy the drivers and system commands to the install area so that
    # subsequent "acfsroot install"s will get the patched bits should
    # the user forget to use the -l option. It also allows us to compare
    # checksums on the drivers in the "install" area to the "installed"
    # area at load time. This will catch situations where users installed
    # new bits but did run "acfsroot install".

    foreach $component (@DRIVER_COMPONENTS) 
    {
      my (@array) = split /\//, $component;
      my ($file) = $array[-1];
      my ($source) = "$MINUS_L_DRIVER_LOC/$component";
      my ($target) = "$USM_DFLT_DRV_LOC/$file";
      
      if ( ! acfslib::lib_are_same_file($source, $target) )
      {
        lib_verbose_print_noalert (9504, "Copying file '%s' to the path '%s'", 
                           $source, $target);

        $ret = system ("cp $source $target");
        $return_code = USM_FAIL if $ret;
      }
      else
      { 
        acfslib::lib_inform_print(9506,
                 "The files '%s' and '%s' are the same, not copying.",
                 $source, $target);
      }
    }

    foreach $component (@SBIN_COMPONENTS) 
    {
      my ($cmd_install_area) = "$ORACLE_HOME/usm/install/cmds/bin";
      my (@array) = split /\//, $component;
      my ($file) = $array[-1];
      my ($source) = "$CMDS_SRC_DIR/$component";
      my ($target) = "$cmd_install_area/$file";
      my ($uid, $gid);


      ($uid, $gid) = (stat($target))[UID,GID];

      if ( ! acfslib::lib_are_same_file($source, $target) )
      {
        if($component =~ /acfssihamount/)
        {
          # Check if this is SIHA
          if(lib_osds_is_siha())
          {
            $target = "/etc/init.d/$file";
            $ret =  system ("cp $source $target");
            $ret += system ("/sbin/chkconfig --add $file");
            $ret += system ("/sbin/chkconfig --level 5 $file on");
          }
          else
          {
            # Skip if it isn't.
            next;
          }
        }
        else
        {
          $ret = system ("cp $source $target");
        }
        lib_verbose_print_noalert (9504, "Copying file '%s' to the path '%s'", 
                                          $source,
                                          $target);
        $return_code = USM_FAIL if $ret;
      }
      else
      { 
        acfslib::lib_inform_print(9506,
                 "The files '%s' and '%s' are the same, not copying.",
                 $source, $target);
      }

      $ret = chmod 0755, $target;
      if ($ret != 1)
      {
        # Warn only
        lib_inform_print(9347, "Unable to set permission bits (%s) on: '%s'.",
                                0755, $target);
      }

      $ret = chown $uid, $gid, $target;
      if ($ret != 1)
      {
        # Warn only
        lib_inform_print(9426,
                    "Unable to set the file attributes for file %s.", $target);
      }
    }
  }

  # Copy ACFS library to the vendor specific location
  $ret = osds_install_acfslib();
  if($ret != USM_SUCCESS)
  {
    $return_code = USM_FAIL;
  }


  # check if the -m flag was set
  if( $osds_acfslib::DOM >= 0)
  {
    my $result;
    my $filename = "/etc/sysconfig/advmtunables";
    my $asm_acfsr_mode = $osds_acfslib::DOM;

    my $asm_acfsr_mode_line = "asm_acfsr_mode=";
    if ( -e $filename )
    {
        lib_trace("9999", "Setting asm_acfsr_mode=$asm_acfsr_mode");
        
        my $fh;
        open ($fh,"<$filename") || return USM_FAIL;
        my @lines = <$fh>;
        close $fh;

        my $overwrite = 0;

        open ($fh,">$filename") || return USM_FAIL;
        for (@lines)
        {
            my $line = $_;
            if($line =~ /^$asm_acfsr_mode_line\d$/)
            {
                $overwrite = 1;
                $line = "$asm_acfsr_mode_line$asm_acfsr_mode\n";
            }
            print $fh $line;
        }

        close $fh;
        
        # The file will technically always exist. The tunable, however, 
        # may not be written in it. There's a chance the above loop never 
        # wrote the asm_acfsr_mode tunable.

        if($overwrite eq 0)
        {
            open ($fh,">>$filename") || return USM_FAIL;
            print $fh "$asm_acfsr_mode_line$asm_acfsr_mode\n";
            close $fh;
        }

    }
    else
    {
        # write mode to file and check for operation failure
        # create file and check for operation failure
        lib_trace("9999", "No advmtunables file found. Creating new one.");
        $result = system("> $filename");
        if($result != 0)
        {
          lib_error_print(5017,"cannot create file: %s",$filename);
        }
        # set permissions and check for operation failure
        my $permissions = "660";
        $result = system("chmod $permissions $filename");
        if($result != 0)
        {
          lib_error_print(9347, "Unable to set permission bits (%s) on: '%s'", 
                          $permissions, $filename);
        }
        
        lib_trace("9999", "Setting asm_acfsr_mode=$asm_acfsr_mode");
        my $writeCmd = "echo \"$asm_acfsr_mode_line$asm_acfsr_mode\"";
        $writeCmd = $writeCmd . " > /etc/sysconfig/advmtunables";
        $result = system($writeCmd);
        if($result != 0)
        {
          lib_error_print(3098, 
                          "error writing to configuration file %s",
                          $filename);
          $return_code = $result;
        }
        
    }

  }

  return $return_code;
} # end osds_install_from_distribution_files



# osds_search_for_distribution_files
#
# Search the media location(s) specified by the user for valid components
#
sub osds_search_for_distribution_files

{
  my ($kernel_install_files_loc) = shift;
  # -l option specified (we know that the path is fully qualified).
  $minus_l_specified = shift;
  my (@install_loc_array);
  my ($cur_loc);              # current location (directory) being examined
  my ($component);            # current component (cmd/driver) being examined
  my ($components_found) = "";# list of components detected
  my ($components_missing) = 0; # set if one or more components are AWOL
  my ($ret_code) = USM_SUCCESS;

  # $kernel_install_files_loc is where the drivers and drivers related files
  # live. - as of 11.2.0.3 and later, the commands are shipped in a separate
  # directory.

  if (!defined($kernel_install_files_loc))
  {
     return USM_FAIL;
  }

  # Look to see if an alternate location for the distribution was specified.
  if ($minus_l_specified)
  {
    # $kernel_install_files_loc is a misnomer for -l within this 'if clause',
    # where it's really the the directory path up to and including "install" -
    # but, what the heck. Once out of this clause, it really will mean the
    # location of the kernel drivers.

    # We use "install" as our starting point for finding our bits
    # so it had better be there.
    if (!($kernel_install_files_loc =~ /install$/))
    {
      # Error message generated by caller
      return USM_TRANSIENT_FAIL;
    }

    # We have the "base" path, up to "install".
    # It's time to find where the drivers are relative to that base.

    my (@path_array) = split ("/", $USM_DFLT_DRV_LOC);
    my ($last_element) = $#path_array;
    my ($driver_relative_path) = "";
    my ($i);
 
    for ($i = 1; $i <= $last_element; $i++)
    {
      # strip off all array elements of out default "base" location. What's 
      # left will be the parts of the driver relative path.
      my ($element) = shift(@path_array);
      if ($element eq "install")
      {
        last;
      }
    }
  
    # Now assemble the driver relative path.
    $last_element = $#path_array;
    for ($i = 0; $i <= $last_element; $i++)
    {
      $driver_relative_path .= "$path_array[$i]/";
    }
    # We now know where the drivers and commands live in the '-l' location.
    $CMDS_SRC_DIR = "$kernel_install_files_loc/cmds/bin";
    $MESG_SRC_DIR = "$kernel_install_files_loc/../mesg";
    $USM_LIB_SRC_DIR = "$kernel_install_files_loc/../lib";
    $USM_PUB_SRC_DIR = "$kernel_install_files_loc/../public";
    $MINUS_L_DRIVER_LOC = "$kernel_install_files_loc/$driver_relative_path";
    $kernel_install_files_loc = $MINUS_L_DRIVER_LOC;
    #We need to update USM_DFLT_DRV_LOC, now is pointing to '-l' location.
    $USM_DFLT_DRV_LOC = "$SHIPHOME_BASE_DIR/$driver_relative_path";
  }

  @install_loc_array = split(/,/, $kernel_install_files_loc);

  # We need to uncompress driver files first
  lib_uncompress_all_driver_files($kernel_install_files_loc);

  foreach $cur_loc (@install_loc_array)
  {
    if (! -d $cur_loc)
    {
      # location (directory) does not exist
      next;
    }
    # test that all of our expected components exist in the distribution

    # The GPL / no GPL decision will be made later
    # search for GPL components
    if (-e "$cur_loc/$DRIVER_COMPONENTS[AVD_IDX]")
    {
      $GPL_PATH = $cur_loc;
      $components_found .= $DRIVER_COMPONENTS[AVD_IDX];
#     if (! ($MEDIA_FOUND =~ m/GPL/))
#     {
#       # $MEDIA_FOUND is used by the check_version sub-command
#       $MEDIA_FOUND .= "GPL components: $GPL_PATH\n";
#     }
    }
  
    # search for OIP components
    foreach $component ($DRIVER_COMPONENTS[OKS_IDX],
                        $DRIVER_COMPONENTS[OFS_IDX],
                       )
    {
      my ($target) = $cur_loc . "/" . $component;
      if (-e $target)
      {
        $components_found .= " $component";
        $OIP_PATH = $cur_loc;
#       if (! ($MEDIA_FOUND =~ m/OIP/))
#       {
#         # $MEDIA_FOUND is used by the version_check sub-command
#         $MEDIA_FOUND .= "OIP components: $OIP_PATH\n";
#       }
      }
      else
      {
        lib_error_print(9320, "Missing file: '%s'.", $target);
        $components_missing = 1;
      }
    }
  }

  if (defined($OIP_PATH))
  {
    $MEDIA_FOUND = "$OIP_PATH\n";
  }
  else
  {
    $MEDIA_FOUND = "";
  }

  # verify that we have all that we need
  if ($components_missing)
  {
    return USM_FAIL;
  }

  foreach $component (@DRIVER_COMPONENTS)
  {
    if (!($components_found =~ m/$component/))
    {
      lib_error_print(9320, "Missing file: '%s'.", $component);
      $ret_code = USM_FAIL;
    }
  }

  if (!defined($OIP_PATH))
  {
    return USM_FAIL;
  }

  # We found drivers, now find where they will be installed.
  $DRIVER_DIR = get_usm_driver_dir($OIP_PATH);

  foreach $component (@SBIN_COMPONENTS)
  {
    if (! -e "$CMDS_SRC_DIR/$component") 
    {
      lib_error_print(9320, "Missing file: '%s'.", "$CMDS_SRC_DIR/$component");
      $ret_code = USM_FAIL;
    }
  }

  foreach $component (@OH_COMPONENTS, @MESG_COMPONENTS, @USM_PUB_COMPONENTS)
  {
    my ($source);

    if ($minus_l_specified)
    {
      my (@array) = split /\//, $component;
      my ($file) = $array[-1];
      $source = "$CMDS_SRC_DIR/$file";
      my ($end) = 'bg'; #End of message file(msb or msg).

      if ($component =~ /$LIBACFS/)
      {
        # Special case libacfs as it lives apart from the other commands.
        $source = "$USM_LIB_SRC_DIR/$file";
      }
      elsif ($component =~ /ms[$end]$/)
      {
        # Special case msg files as it lives apart from the other commands.
        $source = "$MESG_SRC_DIR/$file";
      }
      elsif ($component =~ /lib.h$/)
      {
        # Special case header files as it lives apart from the other commands.
        $source = "$USM_PUB_DST_DIR/$file";
      }
    }
    else
    {
      $source = $component;
    }

    if (! -e $source) 
    {
      lib_error_print(9320, "Missing file: '%s'.", $source);
      $ret_code = USM_FAIL;
    }
  }

  return $ret_code;
} # end osds_search_for_distribution_files

# osds_load_and_verify_usm_state
#
# We unconditionally create the USM udev permissions file
# If the install was for the current kernel version, we load the drivers
# and test to see that the expected /dev entries get created.
#
use File::Copy;
sub osds_load_and_verify_usm_state
{
  my ($no_load) = @_;
  my ($driver);                            # currently loaded driver
  my ($return_val);
  my ($udev_perm_file);

  lib_inform_print (9321, "Creating udev for ADVM/ACFS.");
  lib_osds_create_udev($ASMADMIN);

  # Make sure that all drivers are in place and can be loaded
  my ($component);
  my ($fail) = USM_SUCCESS;
  my ($result);

  foreach $component (@DRIVER_COMPONENTS)
  {
    if (! -e "$DRIVER_DIR/$component")
    {
      lib_error_print(9320, "Missing file: '%s'.", "$DRIVER_DIR/$component");
      $fail = USM_FAIL;
    }
  }
 
  if ($fail != USM_SUCCESS)
  {
     return $fail;
  }
  # create the driver dependencies
  lib_inform_print(9323,
                   "Creating module dependencies - this may take some time.");
  if (machine_is_RH() || machine_is_SLES())
  {
    my ($moved_dep) = 0;
    my ($driver_list);
    foreach $component (@DRIVER_COMPONENTS)
    {
      $driver_list .= "$DRIVER_DIR/$component\n";
    }
    if (-e "/lib/modules/$KVER/modules.dep")
    {
      move("/lib/modules/$KVER/modules.dep", "/tmp/modules.dep");
      $moved_dep = 1;
    }
    $return_val = system("depmod -v $KVER > /dev/null");
    if (($return_val != 0) && $moved_dep)
    {
      # depmod failed - restore the original
      move("/tmp/modules.dep", "/lib/modules/$KVER/modules.dep");
    }

    if (machine_is_RH())
    {
      my ($print_header) = 1;
      my ($cmd) = "echo \"$driver_list\" | /sbin/weak-modules $no_init" . 
                  " --add-modules $KVER 2>&1 |";
      open (MOD, $cmd);
      while (<MOD>)
      {
        if ($_ =~ /^WARNING:/)
        {
          next;
        }
	if ($print_header)
	{
	  lib_print_cmd_header($cmd);
	  $print_header = 0;
        }
        lib_inform_print (9999, "$_");
      }
      close (MOD);
    }
  }

  if ($no_load)
  {
    # We're installing USM for another kernel version - do not attempt to
    # load the drivers. The presumed scenario is that the user wants to
    # install USM for an about to be upgraded kernel. This way, USM can
    # be up and running upon reboot. Dunno if anyone will ever use this.
    lib_inform_print(9324, "Alternate drivers installed.");
    lib_inform_print(9325, "    OS kernel version = %s.", $UNAME_R);
    lib_inform_print(9326, "    installed driver version = %s.", $KVER);
  }
  else
  {
    if (defined($ENV{ACFSPATCH_SYNC}))
    {
      # if ACFSPATCH_SYNC is defined, run sync o.s.
      system("sync;sync;sync");
    }
    # Load the USM drivers
    $return_val = lib_load_usm_drivers();
    if ($return_val != USM_SUCCESS)
    {
      # load_usm_drivers() will print the specific error(s), if any;
      return $return_val;
    }

    # Make sure that the proper /dev files get created by udevd
    lib_inform_print(9327, "Verifying ADVM/ACFS devices.");
    $return_val = lib_verify_usm_devices();
    if ($return_val != USM_SUCCESS)
    {
      # osds_verify_usm_devices() will print the specific error(s), if any;
      return $return_val;
    }
  }

  # see comments at the head of the routine
  lib_trace( 9999, "Resolve ORA_CRS_HOME in the command wrapper scripts.");
  osds_fix_wrapper_scripts();

  # We leave the drivers running because if ASM is started early, because OH
  # or the voting disk reside on ACFS, the drivers must be running as they
  # won't have been started by ora.drivers.acfs (CRS is not yet running).

  return USM_SUCCESS;
} # end osds_load_and_verify_usm_state

# osds_usm_uninstall
#
# remove the USM components.
#
# 
use File::Basename;
use File::Find;
sub osds_usm_uninstall
{
  my (undef, $preserve) = @_;
  my ($return_code) = USM_SUCCESS;       # Assume success
  my ($ret);
  my ($component);
  my ($usm_perm_file);

  if(lib_osds_is_siha())
  {
    # Remove the acfssihamount service
    $ret =  system("/sbin/service stop acfssihamount");
    $ret += system("/sbin/chkconfig --del acfssihamount");
    unlink ("/etc/init.d/acfssihamount");
  }

  if (!$preserve)
  {
    # Names MUST match the ASM_OSD_TUNABLE_FILE_NAME define in asmdefs.h
    # and OFS_OSD_TUNABLE_FILE_NAME in ofslintunables.h
    my ($advm_tunables) = "/etc/sysconfig/advmtunables";
    my ($acfs_tunables) = "/etc/sysconfig/acfstunables";

    if (-e $advm_tunables)
    {
      if (! unlink $advm_tunables)
      {
        lib_inform_print(9348, "Unable to remove '%s'.", $advm_tunables);
        $return_code = USM_TRANSIENT_FAIL;
      }
    }
    if (-e $acfs_tunables)
    {
      if (! unlink $acfs_tunables)
      {
        lib_inform_print(9348, "Unable to remove '%s'.", $acfs_tunables);
        $return_code = USM_TRANSIENT_FAIL;
      }
    }
  } 

  # SLES udev rules work the same as RH5
  if (machine_is_RH() || machine_is_SLES())
  {
    $usm_perm_file = lib_osds_get_usm_udev_rules_file();
    # remove the udev USM premissions file
    if (-e $usm_perm_file)
    {
      if (! unlink $usm_perm_file)
      {
        lib_inform_print(9348, "Unable to remove '%s'.", $usm_perm_file);
        $return_code = USM_TRANSIENT_FAIL;
      }
    }
  }

  if( -e $osds_acfslib::udev_script_location)
  {
    if(! unlink ($osds_acfslib::udev_script_location))
    {
        lib_inform_print(9348, "Unable to remove '%s'.", 
                         $osds_acfslib::udev_script_location);
    }
  }

  if( -e $osds_acfslib::udev_rules_location)
  {
    if(! unlink ($osds_acfslib::udev_rules_location))
    {
        lib_inform_print(9348, "Unable to remove '%s'.", 
                         $osds_acfslib::udev_rules_location);
    }
  }

  # Guarantee that we're not in one of the usm directories about to be nuked.
  chdir "/";
  # Remove USM drivers from and any *empty* sub-directories we would have 
  # created at install time (e.g., /lib/modules/2.6.18-8.el5/extra/usm)
  
  # Attempt to use /bin/find first
  my $find_command = "";

  if( -e "/bin/find")
  {
    $find_command = "/bin/find";
  }
  elsif( -e "/usr/bin/find")
  {
    # no? try /usr/bin/find
    $find_command = "/usr/bin/find";
  }
  else
  {
    # no luck, use 'which'
    $find_command = `which find 2>/dev/null`;

    if( $find_command eq "")
    {
      # Should not happen, too bad
      lib_error_print( 9999, "'find' command not found");
      $return_code = USM_TRANSIENT_FAIL;
      return $return_code;
    }
  }

  # found, chomp, look for files and store output
  chomp( $find_command);
  $find_command .= " /lib/modules 2> /dev/null |";

  open (CHECK, $find_command);
  while (<CHECK>)
  {
    my ($driver) = split;

    if (($driver =~ m/\/usm\/oracleoks.ko/) ||
        ($driver =~ m/\/usm\/oracleacfs.ko/) ||
        ($driver =~ m/\/usm\/oracleadvm.ko/))
    {
      # Remove the driver
      if (! unlink $driver)
      {
        lib_inform_print(9348, "Unable to remove '%s'.", $driver);
        $return_code = USM_TRANSIENT_FAIL;
      }

      # Remove any directories we created - such as the base dirs (if empty).
      # <Base>/weak-updates and <Base>/extra should persist if we did not 
      # create them (that is, they are owned by an rpm).
      my (undef, $lib, $modules, $kver) = split (/\//, $driver);
      my ($subdir)  = "/$lib/$modules/$kver";
      my ($rpm_cmd) = "";
      my ($extra_weakupdates) = "";

      # Bug 27016503
      # We will remove only dirs not owned by any rpm
      #
      # 1. remove /usm/ from /lib/modules/<kernel>/extra/usm/ if not owned by
      #    any rpm
      #    remove /usm/ from /lib/modules/<kernel>//weak-updates/usm/ if not 
      #    owned by any rpm
      #
      # 2. remove /extra/ from /lib/modules/<kernel>/extra/ if not owned by
      #    any rpm
      #    remove /weak-updates/ from /lib/modules/<kernel>/weak-updates/ if
      #    not owned by any rpm
      eval {
        finddepth(
          sub {
            # Revmoving only /usm/ dir where ACFS modules exists
            # Stop the finddepth loop with 'die' once we are in the /usm/ dir 
            # otherwise all the path will be removed.
            #
            # $subdir:
            #  must be the complete path for ACFS modules:
            #  /lib/modules/3.10.0-693.el7.x86_64/
            #  /lib/modules/3.10.0-693.1.1.el7.x86_64/
            #
            # $extra_weakupdates:
            #  must be the last directory like /usm/
            if( ($_ =~ s/usm$//g) )
            {
              $extra_weakupdates = $File::Find::name;
              die "";
            }
          }, $subdir);
      };

      # Remove /usm/ only if not owned by any rpm, otherwise leave and move.
      # $rpm_cmd should have this form:
      # file /lib/modules/<kernel>/extra/usm is not owned by any package
      # file /lib/modules/<kernel>/weak-updates/usm is not owned by any package
      $rpm_cmd = `/bin/rpm -qf $extra_weakupdates`;
      if ($rpm_cmd =~ s/file//g)
      {
        rmdir($extra_weakupdates);
      }

      # Remove if exists /lib/modules/<kernel>/extra/
      # we want to remove dirs not owned by any rpm, $rpm_cmd should have this
      # form:
      # file /lib/modules/<kernel>/extra/usm is not owned by any package
      # file /lib/modules/<kernel>/weak-updates/usm is not owned by any package
      $rpm_cmd = `/bin/rpm -qf $subdir`; 
      if ($rpm_cmd =~ s/file//g)
      {
        # Move outside current directory
        chdir "/";
        # Removing /extra/ or /weak-updates/ directory not owned by any rpm
        finddepth(sub{rmdir}, $subdir);

        # Removing parent dir only if empty, otherwise leave and move
        if (! osds_check_dir_empty($subdir))
        {
          rmdir($subdir);
        }
      }
    }
  }
  close(CHECK);

  system("depmod  > /dev/null");

  foreach $component (@SBIN_COMPONENTS)
  {
    my ($command) = "$SBIN_DIR/$component";

    # This could be a newly added command so if it doesn't exist on the
    # current system, we ignore it. Ideally, you want to uninstall with the
    # old acfsroot and re-install with the new. In practice, this often
    # doesn't happen.
    if ((-e $command) && (! unlink $command))
    {
      lib_inform_print(9348, "Unable to remove '%s'.", $command);
      $return_code = USM_TRANSIENT_FAIL;
    }
  }

  # Remove ACFS library from the vendor specific location
  $ret = osds_uninstall_acfslib();
  if($ret != USM_SUCCESS)
  {
    $return_code = USM_TRANSIENT_FAIL;
  }

  return $return_code;
} # end osds_usm_uninstall

###############################
# internal "static" functions #
###############################

# returns true of the machine is a RHEL system
#
sub machine_is_RH
{
  my ($type) = lib_osds_get_os_type(@_);

  if ($type =~ /EL5/ || 
      $type =~ /EL6/ || 
      $type =~ /EL7/)
  {
    return 1;
  }
  return 0;
}

sub machine_is_SLES
{
  my ($type) = lib_osds_get_os_type(@_);

  if ($type =~ /SLES/)
  {
    return 1;
  }
  return 0;
}

sub machine_is_supported_linux
{
  return (machine_is_SLES() || machine_is_RH());
}

# machine_is_supported
#  
#  Returns if the machine is RH
sub machine_is_supported
{
  my ($type) = lib_osds_get_os_type();
  if ($type !~ /EL6/ && $type !~ /EL7/)
  {
     return 0;
  } 
  return (machine_is_RH());
}

# get_usm_driver_dir
#
# return the directory where the USM drivers will be installed.
#
sub get_usm_driver_dir
{
  my ($path) = @_;

  if (machine_is_RH() || machine_is_SLES())
  {
    my ($driver_build_version); # version that the driver was linked for.
    my ($vermagic);
    my (@tmp_array);

    # pick the oks driver - any USM driver would do.
    open MODINFO , "modinfo $path/$DRIVER_COMPONENTS[OKS_IDX] |";

    while (<MODINFO>)
    {
      if ($_ =~ /^vermagic/)
      {
        $vermagic = $_;
      }
    }
    close (MODINFO);

    if (defined($vermagic))
    {
      # Get the version number from the modinfo vermagic line. It looks like:
      # vermagic:   2.6.18-8.el5PAE SMP mod_unload 686 REGPARM 4KSTACKS gcc-4.1
      $vermagic =~ s/vermagic://;
      $vermagic =~ s/^\s+//g;
      @tmp_array = split(/ /, $vermagic);
      $driver_build_version = $tmp_array[0];
    }
    else
    {
      # Use the current kernel version if we can't get vermagic
      lib_inform_print(9343, "Unable to retrieve OS kernel version from " .
                             "module %s.", "$path/$DRIVER_COMPONENTS[OKS_IDX]");
      $driver_build_version = $UNAME_R;
    }

    return "/lib/modules/$driver_build_version/extra/usm";
  }
} #end get_usm_driver_dir

# osds_fix_wrapper_scripts
#
# We need to resolve %ORA_CRS_HOME% in the command wrapper scripts.
#
sub osds_fix_wrapper_scripts
{
  lib_trace( 9176, "Entering '%s'", "fix wrp scripts");
  my (@progs) = (
      "$SBIN_DIR/advmutil",              "$SBIN_DIR/fsck.acfs",              
      "$SBIN_DIR/mkfs.acfs",             "$SBIN_DIR/mount.acfs",             
      "$SBIN_DIR/umount.acfs",           "$SBIN_DIR/acfsdbg ",               
      "$SBIN_DIR/acfsutil",              "/etc/init.d/acfssihamount",
      "$OH_BIN_DIR/acfsregistrymount",   "$OH_BIN_DIR/acfsdriverstate",      
      "$OH_BIN_DIR/acfssinglefsmount",   "$OH_BIN_DIR/acfsrepl_apply",       
      "$OH_BIN_DIR/acfsreplcrs",         "$OH_BIN_DIR/acfsrepl_dupd",        
      "$OH_BIN_DIR/acfshanfs",           "$OH_BIN_DIR/acfsload",          
                );

  my ($prog); 
  my ($line);
  my (@buffer);
  my ($oracle_base) = acfslib::getParam("ORACLE_BASE");

  foreach $prog (@progs)
  {
    my ($read_index, $write_index);

    $read_index = 0;
    lib_trace( 9999, "Fixing $prog wrapper script.");
    if (open(READ, "<$prog"))
    {
      while ($line = <READ>)
      { 
        if ($line =~ m/^ORA_CRS_HOME/)
        {
          chomp($line);
          lib_trace( 9999, "Old line: $line");
          $line = "ORA_CRS_HOME=$ORACLE_HOME";
          lib_trace( 9999, "New line: $line");
          $line .= "\n";
        }
        if ($line =~ m/^ORACLE_BASE/)
        {
          chomp($line);
          lib_trace( 9999, "Old line: $line");
          $line = "ORACLE_BASE=$oracle_base";
          lib_trace( 9999, "New line: $line");
          $line .= "\n";         
        }
        $buffer[$read_index++] = $line;
      }
      close (READ);
    
      $write_index = 0;
      if (open(WRITE, ">$prog"))
      {
        while($write_index < $read_index)
        {
          print WRITE "$buffer[$write_index++]";
        }
        close (WRITE);
      }
      else
      {
        lib_trace( 9999, "Could not open file '$prog' for writing.");
      }
    }
    else
    {
      lib_trace( 9999, "Could not open file '$prog' for reading.");
    }
  }
  lib_trace( 9177, "Return from '%s'", "fix wrp scripts");
}
# end osds_fix_wrapper_scripts

# get_install_home_from_base
#
# Get the kernel version to use for the install. The heuristic is:
# If we have drivers for kernel version 1, 5, and 9, and our kernel
# version is 7, choose version 5 - the closest without going beyond.
# Higher driver versions may have symbols not in the current kernel.
#
sub get_install_home_from_base
{
  my ($base, $type, $ARCH, $KVER, $runverification, $test_mode) = @_;
  my ($subdir);
  my ($lastdir) = "0";
  my (@var);
  my ($variation);
  my ($minor);
  my (@kver_bydash) = split(/\-/, $KVER);
  my (@kver_bydot) = split(/\./, $KVER);
  my @subdir_bydash;
  my @subdir_bydot;
  my @lastdir_bydash;
  my @subkver_bydash;
  my $subdirstr;
  my $major;
  my $midver;
  my $valid_variation;
  my $kverstr = $KVER;
  my $km;
  my $km_complete;
  my $i = 0;
  my @dir_list;
  my @test_args;
  my @kms = (
    "oracleadvm.ko",
    "oracleacfs.ko",
    "oracleoks.ko"
  );
  my @el7_paths = ( "3.10.0-123", "3.10.0-229", "3.10.0-327",
                    "3.10.0-514", "3.10.0-693", "3.10.0-862");
  my @el7uek_paths = ( "3.8.13-35", "4.1.12", "4.1.12-94.8.2", "4.1.12-103",
                       "4.1.12-112", "4.1.12-112.16.4" );
  my @el6_paths = ( "2.6.32-71", "2.6.32-220", "2.6.32-279", "2.6.32-573",
                     "2.6.32-696"); 
  my @el6uek_paths = ( "2.6.39-100", "2.6.39-200", "2.6.39-300", "2.6.39-400",
    "3.8.13-13", "4.1.12", "4.1.12-94.8.2", "4.1.12-112", "4.1.12-112.16.4" );
  my @sles12sp0 = ( "3.12.28-4" );
  my @sles12sp1 = ( "3.12.49-11" );
  my @sles12sp2 = ( "4.4.21-69" );
  my @sles12sp3 = ( "4.4.73-5", "4.4.120-94.17" );

  if (!$base || !(-d $base))
  {
    lib_error_print( 9544, "Invalid files or directories found: '%s'", $base);
  }

  if( !defined( $runverification))
  {
    $runverification = 0;
  }

  if (defined($test_mode))
  {
    if ($test_mode == 1)
    { # Will probably send uname -r instead of kernel version
      @test_args   = @_[5..9];
      # We can't use KVER for 2.6.18, we look for el5 at the end.
      @kver_bydash = split(/\-/, $test_args[2]);
      @kver_bydot  = split(/\./, $test_args[2]);
      #$test_args[2] = $KVER;
    }
  }

  if ( machine_is_RH(@test_args) )
  {
    $base .= "/Oracle";
    #We check if this is a uek kernel
    if ($KVER =~ /uek/) {    	
        $type .= "UEK";
    }

    if (-d "$base/$type/$ARCH")
    {
      if( $type eq "EL6"){
        @dir_list = @el6_paths; 
      }elsif( $type eq "EL6UEK"){
        @dir_list = @el6uek_paths; 
      }elsif( $type eq "EL7"){
        @dir_list = @el7_paths;
      }elsif( $type eq "EL7UEK"){
        @dir_list = @el7uek_paths;
      }

      $i = 0;
      open (LS, "ls -v $base/$type/$ARCH |");
      while ($subdir = <LS>)
      {
        chomp($subdir);
        @subdir_bydot = split(/\./, $subdir);

        if( $runverification != 0)
        {
          if ( ($subdir ne $dir_list[$i]) &&
               ($dir_list[$i] eq  "4.1.12-112") )
          {
            # Skipping 4.1.12-112 directory.
            $i++;
          }

          #Check if directories found matches with valid directories list
          if( $subdir ne $dir_list[$i])
          {
            lib_error_print( 9544, 
            "Invalid files or directories found: '%s'",
            $subdir);
            return;
          }
          $i++;
        }

        $subdirstr = $subdir; 
        if ($subdirstr eq $kverstr)
        {
          $lastdir = $subdir;
          last;
        }

        @subdir_bydash = split(/\-/, $subdir);
        #Compare dir names, which are kernel versions, and kver  numerically
        if ((osds_unix_linux_acfslib::lib_osds_krncmp($subdirstr, $kverstr) <= 0) &&
            (osds_unix_linux_acfslib::lib_osds_krncmp($subdir, $lastdir) >=0))
        {
          $lastdir = $subdir;
        }
      }
      close(LS);
    }

    if ($lastdir eq "0")
    {
      # no error because the user may have supplied -l (location)
      #  which over-rides.
      return;
    }
   
    # Set the global kernel version
    ($variation) = $kver_bydot[$#kver_bydot];    # el5 or el5PAE, etc.
    chomp($variation);
    #Sometimes you got the arch instead the type in the latest position.
    #Sample: 2.6.32-71.el6.x86_64
    if ($variation eq $ARCH) {
    	($variation) = $kver_bydot[$#kver_bydot - 1];    # el5 or el5PAE, etc.
    	chomp($variation);
    }

    #Try to find variation by matching any of el,uek,xmp,xen
    #If we have 2.6.32-71.el6.x86_64, we pop x86_64 and then match el6.
    #TODO[AG] - Consider replacing the above gymnastics with this simple 
    #piece of code to get the variation
    my @kcp = @kver_bydot;
    while($kcp[$#kcp] !~ /el/  &&   
          $kcp[$#kcp] !~ /uek/ && 
          $kcp[$#kcp] !~ /smp/ && 
          $kcp[$#kcp] !~ /xen/ &&
          $#kcp > 3) {
      pop  @kcp;
    }
    if($#kcp > 3){
      #We don't want to take major, minor, mid versions [3]
      $variation = $kcp[$#kcp];
    }

    ($major)  = $kver_bydot[0];
    ($midver) = $kver_bydot[1];
    ($minor)  = $kver_bydot[2];


    # We currently build kernels for variations ending in "el5", "el5PAE",
    # "el5xen", and "el6". We also build 2.6.32-100. 
    # If the variation/minor here is none of the above, we need to
    # either build additional drivers or massage the variation here. In either
    # case, it's an internal error that should have been caught before we got
    # here and so we just bail. We don't want to fail the entire oracle install
    # and so return USM_NOT_SUPPORTED so that OUI can complete sans USM.
    $valid_variation = 0;

    if($major eq "2")
    {
       if($midver eq "6")
       {
          if(($minor eq "32-100")  || ($minor eq "32-71") ||
            ($variation eq 'el5') || ($variation eq 'el5PAE') ||
            ($variation eq 'el5xen') || ($variation eq 'el6') ||
            ($minor eq "32-200") || ($minor eq "32-300") ||
            ($minor eq "32-400") ||
            ($minor eq "39-100") || ($minor eq "39-200") ||
            ($minor eq "39-300") || ($minor eq "39-400")
            )
          {
              $valid_variation = 1;
          }
       }  
    }
    elsif ($major eq "3")
    {
      if($midver eq "8")
      {
        #We have support for 3.8.13 for el6uek and el7uek
        if(($minor =~ /^13/) || 
           ($variation eq "el6uek") || 
           ($variation eq "el7uek"))
        {
          $valid_variation = 1;
        }
      }
      elsif ($midver eq "10")
      {
        #We have support for 3.10 for el7
        if($variation eq "el7")
        {
          $valid_variation = 1;
        }
      }
    }
    elsif ($major eq "4")
    {
      if($midver eq "1")
      {
        #We have support for 4.1.12 for el6uek and el7uek
        if(($minor =~ /^12/) ||
           ($variation eq "el6uek") ||
           ($variation eq "el7uek"))
        {
          $valid_variation = 1;
        }
      }
    }



    # Do we got a valid_variation?
    if( $valid_variation == 0) 
    {
      my $print = $variation; #Do we print the minor or the variation?
                              # For non-rhel kernels, the variation is useless.
      if ($variation =~ /uek/ )
      {  
        $print = $minor;
      }

      if ($acfslib::USM_CURRENT_PROD eq "prod_afd")
      {
        lib_error_print(9384, 
                    "Invalid operating system kernel variation '%s'.", $print);
        lib_error_print(9508, "AFD installation aborted (component %s).",
                        $COMMAND);
      }
      else
      {
        lib_error_print(9384, "Invalid OS kernel variation '%s'.", $print);
        lib_error_print(9508, "ACFS installation aborted (component %s).",
                        $COMMAND);
      }
      exit USM_NOT_SUPPORTED unless defined($test_mode);
    }


    # Now create a base directory to look for the adequate modules
    if($major eq "4")
    {
      if($midver eq "1")
      {
        # If we are here, we have a 4.1 kernel as supported.
        # We don't need to check for minor version
        # osds_is_kabi_compatible function will check for
        # any different minor version
        $base .= "/$type/$ARCH/$lastdir/$lastdir";
      }
    } #end if($major eq "4")
    elsif($major eq "3")
    {
      if($midver eq "8"  ||
         $midver eq "10")
      {
        # If we are here, we have a 3.8 or 3.10 kernel as supported.
        # We don't need to check for minor version
        # osds_is_kabi_compatible function will check for
        # any different minor version
        $base .= "/$type/$ARCH/$lastdir/$lastdir"; 
      }
    } #end if($major eq "3")
    elsif($major eq "2")
    {
      if($midver eq "6")
      { 
        if (
            ($minor eq "32-100") || ($minor eq "32-200") || 
            ($minor eq "32-300") || ($minor eq "32-400") ||
            ($minor eq "39-100") || ($minor eq "39-200") || 
            ($minor eq "39-300") || ($minor eq "39-400")
           )
        {
          # "32-100" has no variation (el5PAE, for example).
          $base .= "/$type/$ARCH/$lastdir/$lastdir";
          if (!($variation =~ /uek/)) # Unless it's RedHat
          {
            $base .= ".$variation";
          }
        }
        else
        {
          $base .= "/$type/$ARCH/$lastdir/$lastdir.$variation";
        }
      } #if($midver eq "6")
    } #end elsif($major eq "2")

    if ($ARCH eq "x86_64")
    {
      $base .= "-x86_64/bin";
    }
    else
    {
      $base .= "-i686/bin";
    }

  }# end if (machine_is_RH())
  elsif ( machine_is_SLES(@test_args) )
  {
    my ($line);
    my ($SPnumber) = 0;
    $base .= "/Novell";


    #We add the PATCH LEVEL
    if ($test_mode)
    {
      $SPnumber = $test_args[3];
    }
    else
    {
      if (-e "/etc/SuSE-release")
      {
        open (RELEASE, "/etc/SuSE-release");
        while ($line = <RELEASE>)
        {
          if ($line =~ /PATCHLEVEL/)
          {
            # format: "PATCHLEVEL = 3"
            my ($patchlevel, $equals, $number) = split(/ /, $line);
            chomp ($number);
            $SPnumber = $number;
            last;
          }
        }
        close (RELEASE);
      }
      elsif (-e "/etc/os-release")
      {
        open (RELEASE, "/etc/os-release");
        while ($line = <RELEASE>)
        {
          if ($line =~ /VERSION_ID/)
          {
            # format: VERSION_ID="12"
            my ($version_id, $number) = split(/=/, $line);
            chomp ($number);
            $number =~ s/\"//g;
            my ($nversion, $patchnumber) = split(/\./, $number);
            if (defined($patchnumber))
            {
              $SPnumber = $number;
            }
            last;
          }
        }
        close (RELEASE);
      }
    }

    if( $SPnumber eq "0"){
      @dir_list = @sles12sp0;
    }elsif( $SPnumber eq "1"){
      @dir_list = @sles12sp1;
    }elsif( $SPnumber eq "2"){
      @dir_list = @sles12sp2;
    }elsif( $SPnumber eq "3"){
      @dir_list = @sles12sp3;
    }

    open (LS, "ls -v $base/$type/$ARCH/SP$SPnumber |");
    $i = 0;
    while ($subdir = <LS>)
    {
      @subdir_bydash = split(/\-/, $subdir);

      chomp($subdir);
      @subdir_bydot = split(/\./, $subdir);
      $subdirstr =  "$subdir_bydot[0]".".".
                    "$subdir_bydot[1]".".".
                    "$subdir_bydot[2]";

      if( $runverification != 0)
      {
        #Check if directories found matches with valid directories list
        if( $subdir ne $dir_list[$i])
        {
          lib_error_print( 9544,
          "Invalid files or directories found: '%s'",
          $subdir);
          return;
        }
        $i++;
      }
        
      #Compare dir names, which are kernel versions, and kver  numerically
      if ((osds_unix_linux_acfslib::lib_osds_krncmp($subdirstr, $kverstr) <= 0) &&
          (osds_unix_linux_acfslib::lib_osds_krncmp($subdir, $lastdir) >=0))
      {
        $lastdir = $subdir;
      }
    }
    close(LS);

    if ($lastdir eq "0")
    {
      # no error because the user may have supplied '-l' (location)
      # which over-rides.
      return;
    }


    ($variation) = $kver_bydash[$#kver_bydash];
    # smp, xen, or default
    if ($variation =~ /smp/)
    {
      $base .= "/$type/$ARCH/SP$SPnumber/$lastdir/smp/bin";
    }
    elsif ($variation =~ /xen/)
    {
      $base .= "/$type/$ARCH/SP$SPnumber/$lastdir/xen/bin";
    }
    else
    {
      $base .= "/$type/$ARCH/SP$SPnumber/$lastdir/default/bin";
    }
  }
  elsif (defined($test_mode))
  {
    # Make sure base is illegal since we measure success just by checking
    # if the install directory exists.
    undef $base;
  }
  
  # In this point, we have the base directory, the complete path with the
  # drivers to install. We'll do a couple of extra validations.
  if (!$base ||
      !(-d $base))
  {
    lib_error_print( 9544, "Invalid files or directories found: '%s'", $base);
    exit USM_NOT_SUPPORTED;
  }
  $osds_acfslib::configuration{path} = $base;

  # First, Match kernel version in the driver using vermagic modinfo vs the
  # path, we don't want that the customer copy drivers for other path version.
  # Second check if drivers are kABI-Compatible, avoiding mismatch between
  # Kernel Symbols vs Drivers Symbols.

  # Check for ORA_ACFSROOT_TEST Variable.
  my $do_check = 1;
  if (defined($ENV{ADE_VIEW_ROOT}) && 
      defined($ENV{_ORA_ACFSROOT_TEST}))
  {
    if (($ENV{_ORA_ACFSROOT_TEST}) == 8)
    {
      # Don't run 
      $do_check = 0;
    }
  }
  
  if ($do_check && !defined($test_mode))
  {
    lib_uncompress_all_driver_files($base);

    my $km_verify = "";
    my $cmd = "";

    foreach $km (@kms)
    {
      $km_complete = $base . "/" . $km;
      $cmd = "/sbin/modinfo $km_complete|egrep 'vermagic.*$lastdir'|wc -l";
      $km_verify = `$cmd`;
      chomp( $km_verify);
      if ($lastdir eq "4.1.12-112")
      {
         #Validation is not working in this case
         $km_verify = "1";
      }

      if( $km_verify ne "1")
      {
        lib_error_print( 9545,
            "Verification error: kernel module '%(1)s' is incompatible with " .
            "the installed kernel version '%(3)s'. It is compatible with " .
            "kernel version '%(2)s'.",
        $km_complete, $lastdir, $UNAME_R);
        return;
      }
    }
  }

  # We'll check if the drivers are kABI-compatible
  if (!defined($test_mode) &&
      machine_is_RH(@test_args))
  { # Will fail in $test_mode most of the time
    if (!osds_is_kabi_compatible($base, $UNAME_R))
    {
      $base = KABI_NOT_SUPPORTED;
      if ($acfslib::USM_CURRENT_PROD eq "prod_afd")
      {
        acfslib::lib_error_print_noalert(620,
          "AFD is not supported on this operating system version: '%s'",
          $KVER);
      }
      else
      {
        acfslib::lib_error_print_noalert(9459,
          "ADVM/ACFS is not supported on this OS version: '%s'",
          $KVER);
      }
    }
  } #end KABI Validation 

  return $base;
} # end get_install_home_from_base

sub osds_patch_verify
{
  my ($component);                 # curent component being verified
  my ($return_code) = USM_SUCCESS;
  
  foreach $component (@DRIVER_COMPONENTS)
  {
    my ($source) = "$OIP_PATH/$component";
    my ($target) = "$DRIVER_DIR/$component";

    if ($component eq "oracleadvm.ko")
    {
      $source = "$GPL_PATH/$component";
    }
    
    if(md5compare($source,$target) == USM_FAIL)
    {
        lib_inform_print (9999, "$source");
        lib_inform_print (9999,"\tFAIL");
        $return_code = USM_FAIL;
    }
    else
    {
        lib_verbose_print (9999, "$source");
        lib_verbose_print (9999, "\tPASS");
    }
  }

  foreach $component (@SBIN_COMPONENTS)
  {
    my ($target) = "$SBIN_DIR/$component";
    my ($source) = "$CMDS_SRC_DIR/$component";

    if(md5compare($source,$target) == USM_FAIL)
    {
        lib_inform_print (9999, "$source");
        lib_inform_print (9999,"\tFAIL");
        $return_code = USM_FAIL;
    }
    else
    {
        lib_verbose_print (9999, "$source");
        lib_verbose_print (9999, "\tPASS");
    }
  }
  return $return_code;
}

# osds_install_acfslib
#
# Installs the ACFS shared libary into a vendor specific location.
# This allows DB homes to use ACFS functions without needing to know
# the location of the current GI home.
# Called during 'acfsroot install'.
sub osds_install_acfslib
{
  my ($source);
  my ($uid);
  my ($gid);
  my ($libpath);
  my ($ret);
  my ($target) = $ENV{_vendor_lib_loc};
  my ($return_code) = USM_SUCCESS;
  my ($asmadmin) = lib_get_asm_admin_name();
  my ($user) = acfslib::getParam("ORACLE_OWNER"); 

  if(!defined($target))
  {
    # Target should be of the type
    # /opt/oracle/extapi/[32,64]/{API}/{VENDOR}/{VERSION}/lib<apiname>.<ext>
    #
    $target = $LIBACFS_DIR;
  }

  # libacfsXX.so goes to /opt/oracle/extapi/64/acfs/orcl/...
  $source = "$ORACLE_HOME/lib/$LIBACFS";
  $libpath = $target.$LIBACFS; 

  # Get Owner and group of source
  # get the owner/group of the original file
  ($uid, $gid) = (stat($source))[UID,GID];

  if($user)
  {
    $uid = getpwnam($user);
  }
  $gid = getgrnam($asmadmin);

  if(!(-e $target))
  {
    `mkdir -m 755 -p $target`;
     if ($?)
     {
       lib_error_print(9345, "Unable to create directory: '%s'.", $target);
       return USM_FAIL;
     }
  }

  lib_verbose_print_noalert (9504, "Copying file '%s' to the path '%s'",
                     $source, $target);

  unlink ("${target}/${LIBACFS}") if (-e "${target}/${LIBACFS}");
  $ret = system ("cp -f $source $target");
  $return_code = USM_FAIL if $ret;
  if($return_code == USM_SUCCESS)
  {
     system("chmod 755 $libpath");
     $ret = chown $uid, $gid, $libpath;
     if($ret != 1)
     {
       lib_error_print(9426,"unable to set the file attributes for file '%s'",
                       $libpath);
       return USM_FAIL;
     } 
  } 
  return $return_code;
} # end osds_install_acfslib

# osds_uninstall_acfslib
#
# Removes the ACFS library from the vendor specific location.
# Called during 'acfsroot uninstall'
sub osds_uninstall_acfslib
{
  my ($return_code) = USM_SUCCESS;
  my ($libpath);
  my ($target) = $ENV{_vendor_lib_loc};

  if(!defined($target))
  {
    # Target should be of the type
    # /opt/oracle/extapi/[32,64]/{API}/{VENDOR}/{VERSION}/lib<apiname>.<ext>
    #
    $target = $LIBACFS_DIR;
  }

  $libpath = $target.$LIBACFS; 

  if(-e $libpath)
  {
    if (! unlink $libpath)
    {
      lib_inform_print(9348, "Unable to remove '%s'.", $libpath);
      $return_code = USM_FAIL;
    } 
  }
  return $return_code;
} # end osds_uninstall_acfslib

# osds_check_dir_empty 
#
# Check if passed directory is empty
# Called during 'acfsroot uninstall'
#
# Recive:
#  dir name to check
#
# Return:
#  0: if empty
#  1: if non empty
sub osds_check_dir_empty
{
  my ($dir) = $_[0];
  opendir(DIR, $dir) || return 1;
  my (@dir_cont) = readdir(DIR);
  close(DIR);

  if( grep(/\w/, @dir_cont) )
  {
    # dir non empty
    return 1;
  }
  else
  {
    # dir empty
    return 0;
  }
} # end osds_check_dir_empty


1;

OHA YOOOO