# # $Header: usm/src/cmds/acfslib/unix_linux/osds_unix_linux_acfslib.pm /st_usm_11.2/7 2011/07/22 13:35:26 averhuls Exp $ # # osds_unix_linux_acfslib.pm # # Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved. # # # NAME # osds_unix_linux_acfslib.pm - Linux Unix OSD library components. # # DESCRIPTION # Purpose # Linux Unix OSD library functions for the install/runtime scripts. # # NOTES # All user visible output should be done in the common code. # this will ensure a consistent look and feel across all platforms. # # MODIFIED (MM/DD/YY) # averhuls 07/21/11 - XbranchMerge averhuls_crs_modify_and_more from main # averhuls 07/12/11 - Set USM_TRANSIENT_FAIL to 1. # averhuls 06/30/11 - XbranchMerge averhuls_acfsroot_return_codes from # main # averhuls 06/17/11 - Add return codes. # plancian 05/03/11 - Export get_dev_mntpt_from_mount_line # averhuls 04/26/11 - XbranchMerge averhuls_persistent_log from main # averhuls 04/15/11 - Call acfsutil plogconfig -d to start OKS persistent # logging after driver load. # anjiwaji 04/13/11 - Backport anjiwaji_bug-12347033 from main # anjiwaji 04/13/11 - Fix call to lib_osds_is_mounted. # gsanders 04/06/11 - Backport gsanders_bug_11839415-main from main # gsanders 04/05/11 - Move lib_osds_is_mounted to OSD libraries # anjiwaji 02/25/11 - Add extra debugging when verifying usm drivers. # gsanders 10/25/10 - add CLEAN_DO_NOT_KILL_LIST. Bug fixes. Code cleaning # gsanders 08/20/10 - add lib_osds_is_abs_path # averhuls 07/19/10 - Print PID info from clean when a PID is in use on a # mountpoint. Fix lib_get_pid_info() / # report_pid_info() hash list mismatch. # jinjche 07/13/10 - Fix bug 9879774 - fail to stop USM drivers resource # agraves 07/13/10 - Change fuser to use -a (report all pids) and lsof # to use -b (don't block on system calls). # gsanders 07/07/10 - add lib_osds_create_mount_point # jinjche 06/28/10 - Fix a bug that ora.drivers.acfs resource always # times out on stop in AIX # gsanders 06/24/10 - lib_osds_get_drive_info # jinjche 06/22/10 - Fix a bug that ora.registry.acfs resource does not # start in AIX # averhuls 05/27/10 - Fix race between umount and fuser - bug 9746261. # averhuls 05/18/10 - Remove all text output from fuser leaving only # the pid. bug9722397. # gsanders 10/04/30 - Merge forward 11.2.0.1 work # gsanders 05/05/10 - Move unsupported OS error msg print to osds libs # averhuls 04/28/10 - Use POSIX -c on the fuser command line rather than # -m for compatibility. # jinjche 04/27/10 - Change my original fix to print an error if relative pathname # for a mountpoint is provided to reflect review comments. # jinjche 04/21/10 - Fix bug that causes ACFS DBHOME resource fail to start # with relative mountpoint pathname. Start and stop now work. # agraves 04/14/10 - Change message number so that acfsus.msg builds # again. # agraves 04/12/10 - Massage message 1949 a bit. # agraves 04/09/10 - Convert 9999 messages to real NLS messages. # jinjche 04/01/10 - Fix bug 9536524 # averhuls 03/26/10 - Handle different mount command output formats # lin/sol/aix. # jinjche 03/25/10 - Allow the grid user to run acfsload on AIX # averhuls 03/22/10 - Do not chmod/chgrp after mounting a file system if # the user has changed the mountpoint attributes. # averhuls 03/17/10 - Add USM_NOT_SUPPORTED. # averhuls 02/24/10 - Fix the Solaris ACFSUTIL location. # averhuls 11/17/09 - Solaris additions - different mount switches. # averhuls 11/05/09 - Export AVD_DIR. # agraves 10/01/09 - Cleanup name in header. # abakst 09/28/09 - Add Solaris support # abakst 09/03/09 - Add AIX support # averhuls 08/11/09 - Fix grep'ing when mountoint has trailing slash. # Bug#8786154 # agraves 07/28/09 - Remove osds_db_home function. # averhuls 06/30/09 - Report information when a PID could not be killed. # aime 01/22/10 - Add the use constant redirect here so that unix and # linux variants still have error redirection. # anjiwaji 10/07/09 - Cleanup name in header # averhuls 07/01/09 - Report information when a PID could not be killed. # averhuls 06/10/09 - Handle NFS exported file systems. # averhuls 06/01/09 - Export TMPDIR. # agraves 05/18/09 - Creation of lib_osds_is_db_home for unix # agraves 05/12/09 - Fix for bug 8508861 - Both lsof and fuser should be # used to check for existing processes on a mount # point. # agraves 04/29/09 - Update messages to be consistent with acfsus.msg # after Bill Manry's review. # averhuls 04/02/09 - Remove Linux specific "uname -i", # use Perl $Config{archname}. # averhuls 02/16/09 - Remove debugging leftover. # averhuls 02/04/09 - rename usm_lib to acfslib. # averhuls 02/03/09 - Minor fix that generated a readline error. # agraves 01/28/09 - Add ACFSUTIL variable definition. # averhuls 01/14/09 - lib_osds_get_linux_type(): Fix rpmforge confusion - # bug 7685472. # averhuls 01/13/09 - convert to new driver names - e.g., ofs.ko -> # oracleoks.ko # averhuls 12/22/08 - convert to use message catalog. # averhuls 11/03/09 - Creation # use strict; use File::Path; use acfslib; package osds_unix_linux_acfslib; require Exporter; our @ISA = qw(Exporter); our @EXPORT = qw( lib_osds_am_root lib_osds_control_devices_accessible lib_osds_create_mount_point lib_osds_device_from_mountpoint lib_osds_get_advm_mounts lib_osds_get_asm_user lib_osds_get_drive_info lib_osds_mount lib_osds_mountpoint_descriptors lib_osds_run_as_user lib_osds_unmount lib_osds_usm_supported lib_osds_verify_usm_devices lib_osds_is_db_home lib_osds_is_abs_path get_dev_mntpt_from_mount_line @DRIVER_COMPONENTS $ACFSUTIL $TMPDIR $REDIRECT AVD_DIR AVD_CTL_DEV OFS_CTL_DEV AVD_IDX OFS_IDX OKS_IDX OPT_CHR USM_FAIL USM_SUCCESS USM_NOT_SUPPORTED USM_REBOOT_RECOMMENDED USM_TRANSIENT_FAIL ); use Config; my ($OSNAME) = $Config{osname}; chomp($OSNAME); # return/exit codes # # USM_TRANSIENT_FAILures are those that can be easily filed by the admin. # In the case of "acfsroot install", the admin could fix the error and then # resume a grid install, for example, from the checkpoint. use constant USM_SUCCESS => 0; use constant USM_FAIL => 1; use constant USM_NOT_SUPPORTED => 2; use constant USM_REBOOT_RECOMMENDED => 3; use constant USM_TRANSIENT_FAIL => 1; # failures that can be easily fixed use constant OPT_CHR => "-"; # Linux/Unix option character use constant AVD_DIR => "/dev/asm"; # created when AVD loaded use constant AVD_CTL_DEV => "/dev/asm/.asm_ctl_spec"; # created when AVD loaded use constant OFS_CTL_DEV => "/dev/ofsctl"; # created when OFS loaded use constant AVD_IDX => 0; # index into driver_ccomponents use constant OKS_IDX => 1; # index into driver_ccomponents use constant OFS_IDX => 2; # index into driver_ccomponents # On Windows, in the CRS environment, this # redirection does not work. It fails with # "cannot open file descriptor" or "cannot open pipe NOWAIT". our ($REDIRECT) = "2>&1"; my ($CACHED_INSTALLED_DRIVERS); # saved find /lib/modules output my ($CACHED_LOADED_DRIVERS); # saved find lsmod output our ($ACFSUTIL) = "/sbin/acfsutil"; # Linux $ACFSUTIL = "/sbin/acfsutil" if ($OSNAME eq "aix"); $ACFSUTIL = "/usr/lib/fs/acfs/acfsutil" if ($OSNAME eq "solaris"); our ($TMPDIR) = "/tmp"; # /sbin/fuser ... RH Enterprise Linux # /bin/fuser ... Suse # /usr/sbin/fuser ... AIX, HPUX, Solaris # /usr/sbin/lsof ... RH Enterprise Linux # /sbin/modprobe ... RH Enterprise Linux $ENV{PATH} = $ENV{PATH} . ":/sbin:/bin:/usr/sbin"; # lib_osds_am_root # # verify root access # sub lib_osds_am_root { if ($>) # get euid { # not zero (root) # If this is AIX, let the grid user in. if ($OSNAME eq "aix ") { my $orhome = $ENV{ORACLE_HOME}; my $tusr=`/usr/bin/grep ORACLE_OWNER ${orhome}/crs/install/crsconfig_params|/usr/bin/cut -f2 -d '='`; my $me=`/bin/id -un`; $tusr =~ s/\s+$//; $me =~ s/\s+$//; if ($me eq $tusr) { return 1; } else { return 0; } } return 0; } return 1; } # end lib_osds_am_root # lib_osds_mount # # Mount the specified file system # sub lib_osds_mount { my ($device, $mount_point, $options) = @_; my ($asmadmin); my ($result); my ($fs_switch); if ($OSNAME eq "linux") { $fs_switch = "-t"; } elsif ($OSNAME eq "solaris") { $fs_switch = "-F"; } elsif ($OSNAME eq "aix") { $fs_switch = "-v"; } else { # should never get here if lib_osds_usm_supported() did its job. lib_error_print(9125, "ADVM/ACFS is not supported on this OS: '%s'", $OSNAME); return USM_FAIL; } if ($options ne "none") { $options = "-o " . $options; } else { $options = ""; } $result = system("mount $fs_switch acfs $options $device $mount_point"); if ($result) { return USM_FAIL; } # set mount point attributes if the defaults have not been changed. my ($dev,$ino,$mode,$nlink,$uid,$gid) = stat($mount_point); if (($mode == 040755) && ($uid == 0) && ($gid == 0)) { # The user has not changed the defaults. $asmadmin = acfslib::lib_get_asm_admin_name(); system ("chmod 0770 $mount_point"); system ("chgrp $asmadmin $mount_point"); } # If the mount point is to be exported, do it here. # This will be a no-op if the mount point is not in /etc/exports acfslib::lib_osds_exportfs($mount_point); return USM_SUCCESS; } # end lib_osds_mount # lib_osds_mountpoint_descriptors # # called with action = 1 when the user calls "clean" for force any open file # references to be cleared from a mount point to ensure that the unmount # will succeed. # # called with action = 0 to print open references on the mount point. # sub lib_osds_mountpoint_descriptors { my ($mountpoint, $action) = @_; my ($fuser) = "fuser"; my ($have_fuser) = 1; my ($lsof) = "lsof"; my ($have_lsof) = 1; my ($str); # temp work space my ($descriptor_list) = ""; # returned if action == 0 my ($pid) = ""; my ($retval) = USM_SUCCESS; my ($busyCmd); my @CLEAN_DO_NOT_KILL_LIST = ( '^/\S*/acfs_script.sh', '^asm_.*\+ASM\d$', '^\[asmError0]$', '^\[asmIntervalTime]$', '^\[asmShutdown]$', '^/\S*/crsd', '^/\S*/cssdmonitor', '^/\S*/diskmon', '^/\S*/evmlogger', '^/\S*/evmd', '^/\S*/gipcd', '^/\S*/gpnpd', '^/\S*/mdnsd', '^/\S*/ocssd', '^/\S*/octssd', '^/\S*/ohasd', '^/\S*/ologgerd', '^/\S*/ons', '^/\S*/oraagent', '^/\S*/orarootagent', '^/\S*/osysmond', '^/\S*/tnslsnr', ); # All systems are "supposed" to have fuser (LSB_Core), but who really # knows. Either fuser or lsof can do the job. Let's see what we have. open (WHICH, "which $fuser 2>&1 |"); $str = ; close (WHICH); if ($str =~ /no $fuser in/) { $have_fuser = 0; } open (WHICH, "which $lsof 2>&1 |"); $str = ; close (WHICH); if ($str =~ /no $lsof in/) { $have_lsof = 0; } # for debugging, uncomment the appropriate line below. # $have_fuser = 1; $have_lsof = 0; # $have_fuser = 0; $have_lsof = 1; if (($have_fuser == 0) && ($have_lsof == 0)) { print "This system has neither fuser nor lsof in its command search path\n"; if ($action) { return USM_FAIL; } else { return $descriptor_list; } } # # Search for processes with open files on the target mount point # using fuser. If found, list or kill them. fuser should be on # most operating systems. # if ($have_fuser) { # If the mountpoint got unmounted before we run fuser, we could get all # pids on the system. To avoid this, we run lib_osds_is_mounted() after # fuser completes to ensure that the data is still valid. We used to call # lib_osds_is_mounted() and then fuser - which opened a race condition. # # If fuser gets an error, it will appear on a separate line so we need # to handle that. For example: # Cannot stat file /proc/6318/fd/6: Stale NFS file handle # /mnt1: 14134 # # You won't believe this but on the line: # /mnt1: 14134 # "/mnt1: goes to STDERR and "14134" to STDOUT. So, we can't do # something like "open (FUSER, "$fuser -c $mountpoint 2> /dev/null |");". if ($OSNAME eq "linux") { # Only linux has the -a flag to fuser. open (FUSER, "$fuser -ac $mountpoint 2>&1 |"); } else { open (FUSER, "$fuser -c $mountpoint 2>&1 |"); } my ($fuser_line); while ($fuser_line = ) { my (@fuser_array) = split(/\s+/, $fuser_line); last if (! acfslib::lib_osds_is_mounted($mountpoint) ); EACH_FUSER_PID: foreach $pid (@fuser_array) { if ($pid =~ /$mountpoint/) { # The list begins with ":". Ignore that. next; } my ($first_char) = substr($pid, 0, 1); if ($first_char =~ /\D/) { # non-digit first character # e.g., Cannot stat file /proc/6318/fd/6: Stale NFS file handle next; } # strip non digit characters from (base 10) pid. # # fuser output: : [[n]> # where [n] is one or more of the following: # 'c' current directory symbol # 'e' executable running symbol # 'f' open file symbol # 'F' open for write symbol # 'm' mmap'ed file symbol # 'n' holding non-blocking lock (Solaris) # 'o' open file (Solaris) # 'r' root directory symbol # 's' shared library file (AIX) # 't' text file (Solaris) # 'y' controlling terminal (Solaris) $pid =~ s/[[:alpha:]]+//g; # Does the PID contain non-digits? if ($pid =~ /\D/) { # This is not a PID. Likely an error from fuser. next; } # # This process has a file open on the mount point. Get it's # name and log it. # $busyCmd = qx(ps -p $pid -o args=); next EACH_FUSER_PID if ( ! $busyCmd ); chomp $busyCmd; acfslib::lib_inform_print(9153, "Program '%s' with OS process ID '%s' is using mount point '%s'.", $busyCmd, $pid, $mountpoint ); # # Perform the requested action: list or kill. # if ($action == 1) # clean { # # If process is our "safe list" don't kill it. # foreach my $safe ( @CLEAN_DO_NOT_KILL_LIST ) { if ( $busyCmd =~ /$safe/ ) { # This isn't going to end well ... acfslib::lib_inform_print(9152, "Program '%s' with OS process ID '%s' will not be terminated.", $busyCmd, $pid ); $retval = USM_FAIL; next EACH_FUSER_PID; } } acfslib::lib_inform_print(9126, "Attempting to terminate the program '%s' with OS process ID '%s'.", $busyCmd, $pid); my $killRet = system("kill -9 $pid"); if ( $killRet ) { # The kill command failed. Either the process is already gone # or we can't kill it. my (%info) = lib_get_pid_info($pid); if (defined($info{'PID'})) { # The process is still alive. $retval = USM_FAIL; acfslib::lib_inform_print(9136, "PID %s could not be killed.", $pid); report_pid_info(%info); } } } else { $descriptor_list .= "$pid "; } } } close (FUSER); } # end if have_fuser # # Search for processes with open files on the target mount point # using lsof. If found, list or kill them. lsof isn't found on some # operating system installations. # if ($have_lsof) { my $skipToNextProcess = 0; # # lsof may block. We may want to use the -b option to # avoid kernel calls that might block which can cause hangs # for several minutes. # # Use '-F pn' option to get parsable output (pid, file name) # open (LSOF, "$lsof -b -F pn 2>/dev/null |"); LSOF_LINE: while($str = ) { # If pid line, save it and continue. if ( $str =~ /^p\d+$/ ) { $pid = $str; $pid =~ s/^p//; chomp $pid; $skipToNextProcess = 0; next LSOF_LINE; } # # We should be looking at a file name line. ( "n/abc/def/ghi" ); # # If we've already performed the desired action against the # process, skip to the next process. # next LSOF_LINE if ( $skipToNextProcess == 1 ); # Next if this file is not on the target mount point. next LSOF_LINE if ( $str !~ /^n$mountpoint/ ); # # This process has a file open on the mount point. Get it's name # and log it. # $busyCmd = qx(ps -p $pid -o args=); if ( ! $busyCmd ) { # Maybe it exited between the time lsof found it and now. $skipToNextProcess = 1; next LSOF_LINE; } chomp $busyCmd; acfslib::lib_inform_print(9153, "Program '%s' with OS process ID '%s' is using mount point '%s'.", $busyCmd, $pid, $mountpoint ); # # Perform the requested action: list or kill. # if ($action == 1) # clean { # # Don't kill this process if it's on our "safe list". # foreach my $safe ( @CLEAN_DO_NOT_KILL_LIST ) { if ( $busyCmd =~ /$safe/ ) { # This isn't going to end well ... acfslib::lib_inform_print(9152, "Program '%s' with OS process ID '%s' will not be terminated.", $busyCmd, $pid ); $skipToNextProcess = 1; $retval = USM_FAIL; next LSOF_LINE; } } acfslib::lib_inform_print(9126, "Attempting to terminate the program '%s' " . "with OS process ID '%s'.", $busyCmd, $pid); my $killRet = system("kill -9 $pid"); if ( $killRet ) { # The kill command failed. Either the process is already gone # or we can't kill it. my (%info) = lib_get_pid_info($pid); if (defined($info{'PID'})) { # The process is still alive. $retval = USM_FAIL; acfslib::lib_inform_print(9136, "PID %s could not be killed.", $pid); report_pid_info(%info); } } } else { $descriptor_list .= "$pid "; } # # A process can have multiple files open on the target mount # point. We only want to list or kill the process once. # $skipToNextProcess = 1; } close (LSOF); } # Split the string by spaces. my @words= split / /, $descriptor_list; # New hash. my %newwords; # Put the values in the string as the hash keys, assign a value of 1. # This prevents duplicates as they hash to the same value. for (@words) { $newwords{$_}=1 } # Join the keys back into a list. This effectively removes duplicate # process id's in the string. $descriptor_list = join ' ', keys(%newwords); if ($action) { return $retval; } else { return $descriptor_list; } } # end lib_osds_ mountpoint_descriptors # lib_osds_control_devices_accessible # # We test the USM control device accessibility by opening them # Note that this will work on all Linux/Unix - but not Windows # # return true (1) or false (0) # sub lib_osds_control_devices_accessible { my ($ret) = 1; # assume true open AVD, "<" . AVD_CTL_DEV or $ret = 0; if ($ret) { close AVD; # AVD open worked, now try OFS open OFS, "<" . OFS_CTL_DEV or $ret = 0; if ($ret) { # we can talk to both AVD and OFS control devices - success close OFS; } } return $ret; } # end lib_osds_control_devices_accessible # lib_osds_create_mount_point # # Create the mount point directory. # sub lib_osds_create_mount_point { my $mount_point = shift; acfslib::lib_inform_print(9255, "Creating '%s' mount point.", $mount_point); eval File::Path::mkpath($mount_point); if ($@) { acfslib::lib_error_print(9256, "Failed to create mountpoint '%s'.", $@); return USM_FAIL; } return USM_SUCCESS; } # lib_osds_device_from_mountpoint # # return the device name given a mountpoint # sub lib_osds_device_from_mountpoint { my ($mountpoint) = @_; my ($device) = ""; my ($line); open (MOUNT, "mount |"); while ($line = ) { my ($dev, $mntpt) = get_dev_mntpt_from_mount_line($line); if ($mntpt eq $mountpoint) { $device = $dev; last; } } close (MOUNT); return $device; } # end lib_osds_device_from_mountpoint # lib_osds_get_advm_mounts # # return an doubly dimensioned array of devices and mountpoints # of all currently mounted OFS file systems # array element[0] is the device and array element[1] is the mountpoint # sub lib_osds_get_advm_mounts { my (@array); my ($i) = 0; my ($line); open (MOUNT, "mount |"); while ($line = ) { my ($device, $mount_point) = get_dev_mntpt_from_mount_line($line); if ($device =~ /^\/dev\/asm\//) { push @{$array[$i]}, $device, $mount_point; $i += 1; } } close(MOUNT); return \@array; } #end lib_osds_get_advm_mounts # osds_get_asm_user # # Get the user name and group id that we use to connect to ASM # sub lib_osds_get_asm_user { my (@out_array); my ($group); my ($line); if ($OSNAME eq "solaris") { open(PS, "ps -eo user,gid,comm | grep asm_pmon | grep -v grep |"); } elsif ($OSNAME eq "linux") { open(PS, "ps -eo user,gid,cmd | grep asm_pmon | grep -v grep |"); } elsif ($OSNAME eq "aix") { # On AIX the asm_pmon process shows up as "oracle" whem using -o comm, # but ps -fe works - so we have to do it in 2 steps. open(PS, "ps -fe | grep asm_pmon | grep -v grep |"); my ($psline) = ; if (! $psline) { return (@out_array); } $psline =~ s/^\s+//; # Remove leading whitespace from the line my ($user, $pmon_pid) = split(/ +/, $psline); close(PS); if (defined($pmon_pid) ne "") { open(PS, "ps -eo user,gid,pid | grep $pmon_pid | grep -v grep |"); } else { return (@out_array); } } while ($line = ) { # element 0 is the ASM user name, element 1 is the ASM gid. $line =~ s/^\s+//; # Remove leading whitespace from the line @out_array = split(/\s+/, $line); last; } close(PS); return (@out_array); } # end lib_osds_get_asm_user # lib_osds_run_as_user # # For now, ASM connections require euid of the ASM user - bug 6900692. # sub lib_osds_run_as_user { my ($user_name, $cmd) = @_; my ($return_code); my (@args); ##### special case for usm_dbhome ##### usm_dbhome can be called as non-root - in which case we simmply pass ##### the command on without changing the user ID my ($euid) = $>; my ($asm_user) = lib_osds_get_asm_user(); if (( $euid == 0) || ($user_name ne $asm_user)) { @args = ('su', $user_name, '-c', "$cmd"); } else { @args = $cmd; } $return_code = system(@args); return $return_code; #### once we drop usm_dbhome, the function can revert back to the below ##### @args = ('su', $user_name, '-c', "$cmd"); $return_code = system(@args); return $return_code; } # lib_osds_unmount # # unmount the specified file system # sub lib_osds_unmount { my ($mountpoint) = @_; my ($result); my (@nfs_export_list) = acfslib::lib_osds_remove_exports($mountpoint); $result = system("umount $mountpoint 2> /dev/null"); if ($result) { # The unmount failed. Restore previously existing NFS exports, if any. acfslib::lib_osds_restore_exports(@nfs_export_list); return USM_FAIL; } return USM_SUCCESS; } # end lib_osds_unmount # lib_osds_usm_supported. # # The fact that we got here means that there is some support for # this platform. However, perhaps not all releases are supported. # We make that determination here. # # return true or false # sub lib_osds_usm_supported { my ($arch) = $Config{archname}; # Machine architecture - e.g., i386 chomp($arch); # For the time being, of all the "Unix" versions, # only Linux, AIX, and Solaris are supported if (!(($OSNAME eq "linux") || ($OSNAME eq "aix") || ($OSNAME eq "solaris"))) { # TODO for other operating systems acfslib::lib_error_print(9125, "ADVM/ACFS is not supported on this OS: '%s'.", $OSNAME); return 0; } if (!(($arch =~ /^i686/) || ($arch =~ /^x86_64/) || ($arch =~ /^aix-thread-multi-64all/) || ($arch =~ /^i86pc/) || ($arch =~ /^sun4-solaris/))) { # TODO for other architectures acfslib::lib_error_print(9120, "The '%s' machine architecture is not supported.", $arch); return 0; } # $type is "EL5", for example my ($type) = osds_acfslib::lib_osds_get_os_type(); if ($type =~ /not supported/) { return 0; } return 1; } # end lib_osds_usm_supported # lib_osds_verify_usm_devices # # Verify that the USM drivers are loaded and running by checking the # existence of the device control files for the drivers. # sub lib_osds_verify_usm_devices { my ($ORACLE_HOME) = $ENV{ORACLE_HOME}; my ($asmadmin) = acfslib::lib_get_asm_admin_name(); # Make sure that the proper /dev files get created my ($found) = 0; my ($max_wait_seconds) = 60; my ($device) = AVD_CTL_DEV; acfslib::lib_inform_print(9156, "Detecting control device '%s'.", $device); while (($max_wait_seconds > 0) && (!$found)) { if (! -e $device) { sleep 1; $max_wait_seconds -= 1; } else { $found = 1; } } if (!$found) { acfslib::lib_error_print(9121, "Failed to detect control device '%s'.", $device); return USM_FAIL; } else { # The ADVM driver creates /dev/asm/* and not (directly) /dev/asm. system("chgrp $asmadmin " . AVD_DIR); system("chmod 0770 " . AVD_DIR); } $max_wait_seconds = 60; $found = 0; $device = OFS_CTL_DEV; acfslib::lib_inform_print(9156, "Detecting control device '%s'.", $device); while (($max_wait_seconds > 0) && (!$found)) { if (! -e $device) { sleep 1; $max_wait_seconds -= 1; } else { $found = 1; } } if (!$found) { acfslib::lib_error_print(9121, "Failed to detect control device '%s'.", $device); return USM_FAIL; } # We only warn if persistent logging can't be started. `$ACFSUTIL plogconfig -d $ORACLE_HOME`; if ($?) { acfslib::lib_inform_print(9225, "Failed to start OKS persistent logging."); } } #end lib_osds_verify_usm_devices ###### static routines only after this point ########## # lib_get_pid_info # # Collect and return information, for a given PID. # Returns an undefined %pid_hash if the PID is not found. # # Linux, Solaris, and AIX all support ps -fe and output in the same format. # If a future supported Unix does not, we'll have to make changes. # sub lib_get_pid_info { my ($pid) = @_; # target PID my ($ps_info); # output line from the ps(1) command my (%pid_hash); # return: hashed output from the ps(1) command for $pid open PS, "/bin/ps -fe 2>&1 |" or warn ("Failed to run '/bin/ps -fe': $!"), return %pid_hash; # ps -fe format is: # UID PID PPID C STIME TTY TIME CMD # 0 1 2 3 4 5 6 7 while ($ps_info = ) { my (@array) = split /\s+/, $ps_info; %pid_hash = ( USER => $array[0], PID => $array[1], PPID => $array[2], C => $array[3], STIME => $array[4], TTY => $array[5], TIME => $array[6], CMD => $array[7], ); if ($pid eq $pid_hash{'PID'}) { close(PS); return %pid_hash; } } # Target PID not found. close (PS); undef %pid_hash; return %pid_hash; } # end lib_get_pid_info # 9999 messages are not formatted - WYSIWYG. # sub report_pid_info { my (%info) = @_; acfslib::lib_inform_print(9141, " COMMAND %s", $info{'CMD'}); acfslib::lib_inform_print(9143, " USER %s", $info{'USER'}); acfslib::lib_inform_print(9144, " CPU_TIME %s", $info{'TIME'}); acfslib::lib_inform_print(9142, " STATUS %s", $info{'C'}); } # get_dev_mntpt_from_mount_line # # Get the device and mountpoint from a mount command output line. # # Different Unixs have different mount command output formats. # mount | grep mnt1 # /dev/asm/foo-123 on /mnt1 ... Linux # /dev/asm/foo-123 /mnt1 ... AIX # /mnt1 on /dev/asm/foo-123 ... Solaris # sub get_dev_mntpt_from_mount_line { my ($line) = @_; my ($device, $on, $mountpoint); if ($OSNAME eq "linux") { # /dev/asm/xxx_yyy on /oracle_base/ofsdata/foo type ofs (rw) ($device, $on, $mountpoint) = split(/ /, $line); } elsif ($OSNAME eq "solaris") { # /dev/asm/xxx_yyy on /oracle_base/ofsdata/foo on ($mountpoint, $on, $device) = split(/ /, $line); } elsif ($OSNAME eq "aix") { # /dev/asm/xxx_yyy /oracle_base/ofsdata/foo my ($node); if ($line =~ /^ /) { # if the first char of the line is blank, we don't have a node. $line =~ s/^\s+//; # remove leading spaces $line =~ s/\s+/ /g; # remove extra spaces between fields ($device, $mountpoint) = split(/ /, $line); } else { $line =~ s/\s+/ /g; # remove spaces between fields ($node, $device, $mountpoint) = split(/ /, $line); } } else { # should never get here lib_error_print(9149, "unable to determine device mount status - unsupported OS name '%s'", $OSNAME); } return ($device, $mountpoint); } # end get_dev_mntpt_from_mount_line # This is a Windows function sub lib_osds_get_drive_info { return 0; } # lib_osds_is_abs_path sub lib_osds_is_abs_path { my $path = shift; if ( $path =~ /^\// ) { return 1; } return 0; } # vim:ts=2:expandtab