# # # osds_okaroot.pm # # Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved. # # # NAME # osds_okaroot.pm - Linux OSD component of okaroot. # # DESCRIPTION # Purpose # Install/uninstall OKA 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_okaroot; require Exporter; our @ISA = qw(Exporter); our @EXPORT = qw( osds_fix_oka_wrapper_scripts osds_oka_initialize osds_oka_install_from_distribution_files osds_oka_search_for_distribution_files osds_load_and_verify_oka_state osds_oka_uninstall $MEDIA_FOUND $ORACLE_HOME $OKA_DFLT_DRV_LOC ); use acfslib; use osds_okalib; use osds_unix_linux_okalib; use okalib; use osds_acfslib; use osds_acfsroot; our ($ORACLE_HOME) = $ENV{ORACLE_HOME}; my ($SHIPHOME_BASE_DIR) = "$ORACLE_HOME/usm/install"; our ($USM_DFLT_CMD_LOC) = "$SHIPHOME_BASE_DIR/cmds/bin"; # cmds media loc our ($OKA_DFLT_DRV_LOC); # location of the drivers media my ($MINUS_L_DRIVER_LOC); our ($MEDIA_FOUND) = ''; # path name to media # used for version_check my ($ARCH) = `uname -i`; # Machine architecture - i386 chomp($ARCH); my ($UNAME_R) = `uname -r`; chomp($UNAME_R); # We do not install/uninstall the commands destined for ORACLE_HOME - that # is now done by the mapfiles during Oracle install/uninstall. We use # _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"; my (@OH_BIN_COMPONENTS) = ( "$OH_BIN_DIR/okaroot", "$OH_BIN_DIR/okaload", "$OH_BIN_DIR/okadriverstate", ); my (@OH_LIB_COMPONENTS) = ( "$OH_LIB_DIR/okatoolsdriver.sh", "$OH_LIB_DIR/okalib.pm", "$OH_LIB_DIR/okaroot.pl", "$OH_LIB_DIR/osds_okaroot.pm", "$OH_LIB_DIR/okaload.pl", "$OH_LIB_DIR/osds_okaload.pm", "$OH_LIB_DIR/okadriverstate.pl", "$OH_LIB_DIR/osds_okadriverstate.pm", "$OH_LIB_DIR/osds_okalib.pm", "$OH_LIB_DIR/osds_unix_linux_okalib.pm", ); my (@MESG_COMPONENTS) = ( "$MESG_DST_DIR/okaus.msb", ); 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_oka_search_for_distribution_files() and # consumed by osds_oka_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 ($KVER); # kernel version being installed # osds_oka_initialize # # Perform OSD initialization. # Set OKA_DFLT_DRV_LOC - the location of the OKA installation driver media. # We deduce the location of the other components from there. # sub osds_oka_initialize { my ($install_kver, $sub_command) = @_; my ($vendor); my ($type); 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; } # we have already verified that we have a valid Linix type $type = lib_osds_get_os_type(); $vendor = lib_osds_get_linux_vendor(); if (!((defined($ORACLE_HOME)) && (-e "$ORACLE_HOME/lib/okaroot.pl"))) { lib_error_print_noalert(9389, "ORACLE_HOME is not set to the location of the Grid Infrastructure home."); return USM_TRANSIENT_FAIL; } # default media location - over-ride with the -l option my ($base) = $SHIPHOME_BASE_DIR; $OKA_DFLT_DRV_LOC = get_install_home_from_base($base, $type, $ARCH, $KVER); # /sbin/weak-modules depends on /boot being accessible and the # symvers- file being present. if (($sub_command eq "install") && machine_is_RH()) { my ($symvers_file) = "symvers-" . $KVER . ".gz"; if (! -e "/boot/$symvers_file") { lib_error_print_noalert(625, "OKA installation cannot proceed:"); lib_error_print_noalert(9158, "Configuration file '%s' in the /boot directory does not exist.", $symvers_file); return USM_TRANSIENT_FAIL; } } return USM_SUCCESS; } # osds_oka_install_from_distribution_files # # Install the OKA components from the specified distribution files # The files have already been validated by the time we get here # by osds_oka_search_for_distribution_files(). Also, any previous USM installation # will have been removed. # use File::Path; sub osds_oka_install_from_distribution_files { my ($component); # curent component being installed my ($command); # current command being executed by system() my ($ret); # 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 (626, "OKA driver media location is '%s'", $OIP_PATH); foreach my $component (@OKA_DRIVER_COMPONENTS) { my ($source) = "$OIP_PATH/$component"; my ($target) = "$DRIVER_DIR/$component"; lib_verbose_print (9504, "Copying file '%s' to the path '%s'", $source, $target); $command = "cp $source $target"; $ret = system ($command); $return_code = USM_FAIL if $ret; } 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); $source = "$CMDS_SRC_DIR/$file"; $have_orig = 0; if (-e $target) { use constant UID => 4; use constant GID => 5; $have_orig = 1; # get the owner/group of the original file ($uid, $gid) = (stat($target))[UID,GID]; } lib_verbose_print (9504, "Copying file '%s' to the path '%s'", $source, $target); $ret = system ("cp $source $target"); $return_code = USM_FAIL if $ret; if (($target =~ /\/bin\//) || ($component =~ /okatoolsdriver.sh/)) { 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"; lib_verbose_print (9504, "Copying file '%s' to the path '%s'", $source, $target); $ret = system ("cp $source $target"); $return_code = USM_FAIL if $ret; } # Copy the drivers and system commands to the install area so that # subsequent "okaroot 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 "okaroot install". my ($cmd_install_area) = "$ORACLE_HOME/usm/install/cmds/bin"; foreach $component (@OKA_DRIVER_COMPONENTS) { my (@array) = split /\//, $component; my ($file) = $array[-1]; my ($source) = "$MINUS_L_DRIVER_LOC/$component"; my ($target) = "$OKA_DFLT_DRV_LOC/$file"; lib_verbose_print (9504, "Copying file '%s' to the path '%s'", $source, $target); $ret = system ("cp $source $target"); $return_code = USM_FAIL if $ret; } } return $return_code; } # end osds_oka_install_from_distribution_files # osds_oka_search_for_distribution_files # # Search the media location(s) specified by the user for valid components # sub osds_oka_search_for_distribution_files { my ($kernel_install_files_loc) = @_; 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 ($kernel_install_files_loc ne $OKA_DFLT_DRV_LOC) { # -l option specified (we know that the path is fully qualified). $minus_l_specified = 1; # $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 ("/", $OKA_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; } @install_loc_array = split(/,/, $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 # search for OIP components foreach $component ($OKA_DRIVER_COMPONENTS[OKA_IDX], $OKA_DRIVER_COMPONENTS[OKG_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_noalert(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 (@OKA_DRIVER_COMPONENTS) { if (!($components_found =~ m/$component/)) { lib_error_print_noalert(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_oka_driver_dir($OIP_PATH); foreach $component (@OH_COMPONENTS, @MESG_COMPONENTS) { my ($source); if ($minus_l_specified) { my (@array) = split /\//, $component; my ($file) = $array[-1]; $source = "$CMDS_SRC_DIR/$file"; if ($component =~ /msb$/) { # Special case msg files as it lives apart from the other commands. $source = "$MESG_SRC_DIR/$file"; } } else { $source = $component; } if (! -e $source) { lib_error_print_noalert(9320, "Missing file: '%s'.", $source); $ret_code = USM_FAIL; } } return $ret_code; } # end osds_oka_search_for_distribution_files # osds_load_and_verify_oka_state # # We unconditionally create the OKA 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_oka_state { my ($no_load) = @_; my ($driver); # currently loaded driver my ($return_val); my ($udev_perm_file); my ($okaadmin); # extract the admin name for use $okaadmin = lib_get_oka_admin_name(); lib_inform_print_noalert (9321, "Creating udev for OKA."); lib_osds_oka_create_udev($okaadmin); print ("creating oka node \n"); lib_osds_oka_create_node($okaadmin); # Make sure that all drivers are in place and can be loaded my ($component); my ($fail) = USM_SUCCESS; my ($result); foreach $component (@OKA_DRIVER_COMPONENTS) { if (! -e "$DRIVER_DIR/$component") { lib_error_print_noalert(9320, "Missing file: '%s'.", "$DRIVER_DIR/$component"); $fail = USM_FAIL; } } if ($fail != USM_SUCCESS) { return $fail; } # create the driver dependencies lib_inform_print_noalert(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 (@OKA_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 ($no_initrd) = ""; my ($print_header) = 1; $no_initrd = `/sbin/weak-modules -h | grep ^'--no-initrd\\|--no-initramfs'`; chomp($no_initrd); my ($cmd) = "echo \"$driver_list\" | /sbin/weak-modules $no_initrd" . " --add-modules $KVER 2>&1 |"; open (MOD, $cmd); while () { if ($_ =~ /^WARNING:/) { next; } if ($print_header) { lib_print_cmd_header($cmd); $print_header = 0; } lib_inform_print_noalert (9999, "$_"); } close (MOD); } } if ($no_load) { # We're installing OKA for another kernel version - do not attempt to # load the drivers. The presumed scenario is that the user wants to # install OKA for an about to be upgraded kernel. This way, OKA can # be up and running upon reboot. Dunno if anyone will ever use this. lib_inform_print_noalert(9324, "Alternate drivers installed."); lib_inform_print_noalert(9325, " OS kernel version = %s.", $UNAME_R); lib_inform_print_noalert(9326, " installed driver version = %s.", $KVER); } else { # Load the OKA drivers $return_val = lib_load_oka_drivers(); if ($return_val != USM_SUCCESS) { # lib_load_oka_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_noalert(649, "Verifying OKA devices."); $return_val = lib_verify_oka_devices(); if ($return_val != USM_SUCCESS) { # osds_verify_oka_devices() will print the specific error(s), if any; return $return_val; } } # Fix wrapper scripts to have proper ORACLE_HOME osds_fix_oka_wrapper_scripts(); return USM_SUCCESS; } # end osds_load_and_verify_oka_state # osds_oka_uninstall # # remove the OKA components. # # use File::Basename; use File::Find; sub osds_oka_uninstall { my (undef, $preserve) = @_; my ($return_code) = USM_SUCCESS; # Assume success my ($component); my ($oka_perm_file); if (!$preserve) { my $ret; # TODO-SOMA - do some KA specific action !! # 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_noalert(9348, "Unable to remove '%s'.", $advm_tunables); # $ret = USM_TRANSIENT_FAIL; # } #} #if (-e $acfs_tunables) #{ # if (! unlink $acfs_tunables) # { # lib_inform_print_noalert(9348, "Unable to remove '%s'.", $acfs_tunables); # $ret = USM_TRANSIENT_FAIL; # } #} } # SLES udev rules work the same as RH5 if (machine_is_RH() || machine_is_SLES()) { $oka_perm_file = lib_osds_get_oka_RH5_udev_rules_file(); # remove the udev OKA premissions file if (! unlink $oka_perm_file) { # this is just a comment for the time being as we can still process # the rest of the work lib_inform_print_noalert(9348, "Unable to remove '%s'.", $oka_perm_file); #$return_code = USM_TRANSIENT_FAIL; } } # Guarantee that we're not in one of the usm directories about to be nuked. chdir "/"; # Remove OKA drivers from and any *empty* sub-directories we would have # created at install time (e.g., /lib/modules/2.6.18-8.el5/extra/oracle) open (CHECK, "find /lib/modules 2> /dev/null |"); while () { my ($driver) = split; if (($driver =~ m/\/oracle\/oracka.ko/) || ($driver =~ m/\/oracle\/oracka_mod_kga.ko/)) { # Remove the driver if (! unlink $driver) { lib_inform_print_noalert(9348, "Unable to remove '%s'.", $driver); $return_code = USM_TRANSIENT_FAIL; } # Remove the base directories but only if empty # even if it is not empty, it is removing, so comment it out for now #my (undef, $lib, $modules, $kver) = split (/\//, $driver); #my $subdir = "/$lib/$modules/$kver"; #finddepth(sub{rmdir}, $subdir); } } close(CHECK); system("depmod > /dev/null"); system("rm -f /dev/oka"); return $return_code; } # end osds_oka_uninstall ############################### # internal "static" functions # ############################### # get_oka_driver_dir # # return the directory where the OKA drivers will be installed. # sub get_oka_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 oka driver - any KA driver would do. open MODINFO , "modinfo $path/$OKA_DRIVER_COMPONENTS[OKA_IDX] |"; while () { 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_noalert(9343, "Unable to retrieve OS kernel version from " . "module %s.", "$path/$OKA_DRIVER_COMPONENTS[OKA_IDX]"); $driver_build_version = $UNAME_R; } return "/lib/modules/$driver_build_version/extra/oracle"; } } #end get_oka_driver_dir # osds_fix_oka_wrapper_scripts # # We need to resolve %ORA_CRS_HOME% in the command wrapper scripts. # sub osds_fix_oka_wrapper_scripts { my (@progs) = ( "$OH_BIN_DIR/okaload", "$OH_BIN_DIR/okadriverstate", "$OH_BIN_DIR/okacmd" ); my ($prog); my ($line); my (@buffer); foreach $prog (@progs) { my ($read_index, $write_index); $read_index = 0; open READ, "<$prog" or next; while ($line = ) { if ($line =~ m/^ORA_CRS_HOME/) { $line = "ORA_CRS_HOME=$ORACLE_HOME\n"; } $buffer[$read_index++] = $line; } close (READ); $write_index = 0; open WRITE, ">$prog" or next; while($write_index < $read_index) { print WRITE "$buffer[$write_index++]"; } close (WRITE); } } # end osds_fix_oka_wrapper_scripts 1;