# # $Header: usm/src/cmds/acfslib/acfslib.pm /st_usm_11.2/14 2011/07/25 13:22:33 averhuls Exp $ # # osdsacfslib.pm # # Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved. # # # NAME # acfslib.pm - Common (non platform specific) functions used by # the install/runtime scripts. # # DESCRIPTION # Purpose # See above. # # 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/25/11 - XbranchMerge averhuls_install_from_load from main # averhuls 07/25/11 - Pass $COMMAND in lib_osds_usm_drivers(). # averhuls 07/21/11 - XbranchMerge averhuls_crs_modify_and_more from main # averhuls 07/15/11 - Add usm_resource_exists(), # modify_usm_{registry,drivers}_resource(). # averhuls 07/11/11 - Minor rework of when USM_REBOOT_RECOMMENDED is # issued. # gsanders 06/30/11 - Backport gsanders_bug-12692110 from main # averhuls 06/20/11 - Test lib_osds_unload_driver() return for # USM_SUCCESS. # gsanders 05/11/11 - Backport gsanders_bug-12387330 from main # gsanders 04/04/11 - Backport gsanders_bug-11871207 from main # anjiwaji 03/24/11 - Backport anjiwaji_bug-11872430 from main # anjiwaji 03/23/11 - Add a VERBOSE flag to wrap message 9155. # mcarrell 03/21/11 - Backport mcarrell_bug-11874601 from main # anjiwaji 02/25/11 - Add debugging statements for loading and verifying # driver installation. # anjiwaji 02/17/11 - Backport anjiwaji_bug-11744565 from main # anjiwaji 01/20/11 - Add subroutine to print header for system error # messages. # gsanders 01/10/11 - XbranchMerge gsanders_bug-10229980 from main # gsanders 01/10/11 - spelling miss-match -> mismatch # aime 12/09/10 - XbranchMerge aime_w3 from main # rvadraha 11/30/10 - Bug9925648 Add lib_count_drivers_loaded() # mcarrell 11/19/10 - Change lib_recover_stale_mounts to only recover # mount points in the registry when called from # acfsregistrymount. # agraves 09/30/10 - Add option to not mount mount points if a nomounts # file is present. # gsanders 09/17/10 - Remove temp debug statement # gsanders 08/20/10 - change reg res group rwx # gsanders 07/21/10 - lib_is_mount_available() strip backslash # gsanders 07/07/10 - add lib_create_mount_point() # plancian 07/06/10 - Skip lines from acfsutil that produce ACFS-# # messages, instead of reading these errors as # mountpoints # jinjche 07/06/10 - Fix a bug that DBHOME ACFS resource does not # start # gsanders 06/22/10 - add lib_get_drive_info() # bonelso 01/21/10 - Stop trying to unload drivers if error encountered. # jinjche 06/02/10 - Add 7 functions for reregistering and unregistering # ACFS resources # gsanders 05/20/10 - Add time stamps to logged output from clsecho # gsanders 04/30/10 - Merge forward 11.2.0.1 work # averhuls 04/28/10 - Errors will now go to the CRS user - if invoked by # CRS and not just the logs. # jinjche 04/21/10 - Fix bug that $COMMAND was not initialized. Set it to # "No Command Specified" as suggested by the reviewers. # agraves 04/19/10 - Fix message 9111 to not have Stale in it. # agraves 04/14/10 - Add missing comma on line 713 # agraves 04/10/10 - Change stale to offline in message 9139. # agraves 04/08/10 - Add some extra error checking to # lib_is_mount_available for cases when acfsutil info # fs fails to run. This will get around perl throwing # an exception to the CRS stack. # averhuls 03/22/10 - Improve debug output if the -s (silent) option is # used. # averhuls 03/17/10 - Add USM_NOT_SUPPORTED. # averhuls 03/15/10 - change verify_message() to convert the incoming # message ID to the acfsus.msg 5 char format. # averhuls 02/26/10 - lib_load_usm_drivers(): separate the detect and # load steps into two phases - bug 9345437. # anjiwaji 02/10/10 - Add function to check if any drivers are installed. # agraves 01/19/09 - Remove 2>&1 output redirection for execution from # the srvctl environment. Apparently on Windows # the redirection fails, and the execution dies. # certan 11/24/09 - Add optional argument to lib_unload_usm_drivers # that specifies the location of new install files. # Utilities inside of new install files may be used # to unload drivers if old utilities cannot be found # averhuls 11/18/09 - if asm_connect() fails, chech that the gis is # correct. # averhuls 09/21/09 - Report error if osdbagrp returns NULL. # agraves 07/28/09 - Remove is_db_home function. # averhuls 07/15/09 - Add time stamp to the check_in_progress file. # averhuls 07/02/09 - Change SQL select to improve performance. # Remove unused lib_asm_create_volume() and # lib_asm_delete_volume(). # averhuls 06/23/09 - Allow lib_check_in_progress() to handle multi-level # directories. # averhuls 06/01/09 - Add lib_check_in_progress(). # agraves 05/15/09 - Add function lib_is_db_home heuristic check. # averhuls 05/07/09 - Unformatted messages go thru clsecho too. # averhuls 05/01/09 - Delete lib_verify_resource_online. # averhuls 04/30/09 - Get clsecho from ORA_CRS_HOME. # agraves 04/29/09 - Update the messages in this file to go hand in hand # with the messages in the mesg file, following Bill # Manry's review of them. # averhuls 03/31/09 - make lib_verify_ora_asm_online() generic. # averhuls 03/23/09 - Add CLSAGFW_ return codes. # averhuls 03/13/09 - Pass the nodename to crsctl stat - not the # hostname. # averhuls 02/19/09 - Export constants from osds_acfslib. # averhuls 02/17/09 - Fix format for msg 9101. # averhuls 02/11/09 - Add lib_verify_ora_asm_online. # Use acfsutil info fs -o mountpoints,isavailable # to check for stale mounts. # averhuls 01/29/09 - rename usm_lib to acfslib. # agraves 01/28/09 - Add lib_is_mount_available to see if device is # available, not offline or otherwise on vacation. # averhuls 12/22/08 - convert to use message catalog. # averhuls 11/03/08 - Creation # use strict; package acfslib; require Exporter; our @ISA = qw(Exporter); our @EXPORT = qw( lib_am_root lib_asm_connect lib_asm_disconnect lib_asm_enable_volume lib_asm_mount_diskgroup lib_check_drivers_installed lib_check_any_driver_installed lib_check_drivers_loaded lib_count_drivers_loaded lib_check_loaded_drivers_mismatch lib_check_in_progress lib_control_devices_accessible lib_create_mount_point lib_device_from_mountpoint lib_end_check_in_progress lib_error_print lib_get_advm_mounts lib_get_asm_admin_name lib_get_asm_user lib_get_drive_info lib_inform_print lib_is_mounted lib_is_mount_available lib_load_usm_drivers lib_mount lib_mountpoint_descriptors lib_recover_stale_mounts lib_run_as_user lib_run_func lib_unload_usm_drivers lib_unmount lib_usm_supported lib_verify_usm_devices lib_is_abs_path lib_print_cmd_header trim $COMMAND $SILENT $VERBOSE $ACFSUTIL AVD_IDX OFS_IDX OKS_IDX OPT_CHR CHECK_IN_PROGRESS_NO CHECK_IN_PROGRESS_YES CHECK_IN_PROGRESS_TIMEOUT CLSAGFW_AE_SUCCESS CLSAGFW_AE_FAIL CLSAGFW_ONLINE CLSAGFW_UNPLANNED_OFFLINE CLSAGFW_PLANNED_OFFLINE CLSAGFW_UNKNOWN CLSAGFW_PARTIAL CLSAGFW_FAILED USM_FAIL USM_TRANSIENT_FAIL USM_SUCCESS USM_NOT_SUPPORTED USM_REBOOT_RECOMMENDED add_acfs_registry delete_acfs_registry start_acfs_registry stop_acfs_registry add_usm_drivers_resource usm_resource_exists modify_usm_registry_resource modify_usm_drivers_resource delete_usm_drivers_resource start_usm_drivers_resource ); use DBI; use osds_acfslib; use File::Spec::Functions; our ($SILENT) = 0; # input option (-s) our ($VERBOSE) = 0; # input option (-v) our ($COMMAND) = "No Command Specified"; # currently executing command my ($ADE_VIEW_ROOT) = $ENV{ADE_VIEW_ROOT}; my ($ORACLE_HOME) = $ENV{ORACLE_HOME}; my ($ORA_CRS_HOME) = $ENV{ORA_CRS_HOME}; my ($CRS) = $ENV{_ORA_AGENT_ACTION}; # defined if invoked via CRS my ($CACHED_ASMADMIN); # avoid calling osdbagrp -a repeatedly # '-l' = write to CRS alert log my ($CLSECHO) = catfile($ORA_CRS_HOME, "bin", "clsecho") . " -p usm -f acfs -l"; # CRS check function return codes from crs/agentfw/include/clsagfw.h use constant CLSAGFW_ONLINE => 0; use constant CLSAGFW_UNPLANNED_OFFLINE => 1; use constant CLSAGFW_PLANNED_OFFLINE => 2; use constant CLSAGFW_UNKNOWN => 3; use constant CLSAGFW_PARTIAL => 4; use constant CLSAGFW_FAILED => 5; # CRS return codes for functions other than check() use constant CLSAGFW_AE_SUCCESS => 0; use constant CLSAGFW_AE_FAIL => 1; use constant PRINT_INFORM => 0; use constant PRINT_ERROR => 1; use Config; my ($OSNAME) = $Config{osname}; chomp($OSNAME); # lib_am_root # # call into lib_osds_am_root # sub lib_am_root { return lib_osds_am_root(); } # end lib_am_root # # connect to the ASM instance # sub lib_asm_connect { my ($dbh); my (%session_mode); my ($driver) = 'dbi:Oracle:'; my ($usr) = ''; my ($pswd) = ''; # $session_mode{'ora_session_mode'} = 2; # sysdba $session_mode{'ora_session_mode'} = 32768; # sysasm $session_mode{'PrintError'} = 0; $dbh = DBI->connect($driver, $usr, $pswd, \%session_mode); warn "$DBI::errstr\n" unless defined ($dbh); if (!defined ($dbh)) { if (defined($ENV{ADE_VIEW_ROOT})) { # On non-Linux platforms, ADE changes your gid when you enter a view. # This program is called as root, which then does a "su " in # order to perform the ASM functions. The "su" command will revert # your gid back to the original gid. This means that you can no longer # "talk" to ASM. The -no_newgid option on your "ade useview " # command will prevent the gid switch. my ($my_gid_list) = $(; my ($asm_user, $asm_gid) = lib_get_asm_user(); my (@array) = split(/ /, $my_gid_list); my ($my_gid) = $array[0]; # On NT, $asm_gid comes back as 0 from lib_get_asm_user(). if (($my_gid != $asm_gid) && $asm_gid) { # No internationalization of the message because this is devlopment lib_error_print(9999, "\nASM/user gid mismatch ($asm_gid/$my_gid)."); lib_error_print(9999, "You may need the -no_newgrp option on the ade useview command."); } } return USM_FAIL; } return $dbh; } # # connect to the ASM instance # sub lib_asm_disconnect { my ($dbh); if (defined($dbh)) { $dbh->disconnect(); } } # end_lib_asm_disconnect # lib_asm_enable_volume # # If the specified volume is not ASM enabled - enable it. # # The caller must have verified that the diskgroup is mounted. # sub lib_asm_enable_volume { my ($dbh, $diskgroup, $volume) = @_; my ($diskgroup_uc, $volume_uc); my ($qry); # SQL query my ($dg_state); # ASM state of the diskgroup my ($sth); # SQL statement handle my ($row); # SQL table row my ($found_diskgroup) = 0; my ($found_volume) = 0; my ($return_val) = USM_SUCCESS; # ASM returns select data in upper case and so our comparisons have to # match case. $diskgroup_uc = uc($diskgroup); $volume_uc = uc($volume); # Now see if the volume exists. Enable it if needed. $qry = "select NAME, VOLUME_NAME, x.STATE from V\$ASM_VOLUME x join V\$ASM_DISKGROUP_STAT on x.GROUP_NUMBER = V\$ASM_DISKGROUP_STAT.GROUP_NUMBER"; $sth = asm_select_stmt($dbh, $qry); while (defined ($row = asm_fetch_row($sth))) { if (($row->{'NAME'} eq $diskgroup_uc) && ($row->{'VOLUME_NAME'} eq $volume_uc)) { $found_volume = 1; if ($row->{'STATE'} ne 'ENABLED') { # enable the volume lib_inform_print(9103, "Enabling volume '%s' on diskgroup '%s'.", $volume, $diskgroup); $qry = "alter diskgroup $diskgroup enable volume $volume"; $return_val = asm_do_stmt($dbh, $qry); if ($return_val == USM_FAIL) { lib_error_print(9104, "Enable of volume '%s' failed.", $volume); } } last; } } eval { $sth->finish(); }; if (! $found_volume) { lib_error_print(9105, "Volume '%s' not found in '%s'.", $volume, $diskgroup); $return_val = USM_FAIL; } return $return_val } # end asm_enable_volume # lib_asm_mount_diskgroup # # If the specified diskgroup is not ASM mounted - mount it. # sub lib_asm_mount_diskgroup { my ($dbh, $diskgroup) = @_; my ($diskgroup_uc); my ($qry); # SQL query my ($dg_state); # ASM state of the diskgroup my ($sth); # SQL statement handle my ($row); # SQL table row my ($found_diskgroup) = 0; my ($return_val); # ASM returns select data in upper case and so our comparisons have to # match case. $diskgroup_uc = uc($diskgroup); $return_val = USM_SUCCESS; # see if the diskgroup exists $qry= "select name,state from v\$asm_diskgroup"; $sth = asm_select_stmt($dbh, $qry); while (defined ($row = asm_fetch_row($sth))) { if ($row->{'NAME'} eq $diskgroup_uc) { $dg_state = $row->{'STATE'}; $found_diskgroup = 1; last; } } eval { $sth->finish(); }; if (! $found_diskgroup) { lib_error_print(9106, "Diskgroup '%s' not found.", $diskgroup); return USM_FAIL; } if ($dg_state eq 'DISMOUNTED') { lib_inform_print(9107, "ASM mounting diskgroup '%s'.", $diskgroup); $qry = "alter diskgroup $diskgroup mount"; $return_val = asm_do_stmt($dbh, $qry); if ($return_val == USM_FAIL) { lib_error_print(9108, "ASM mount of diskgroup '%s' failed.", $diskgroup); return USM_FAIL; } } return $return_val; } # end lib_asm_mount_and_enable # lib_check_drivers_installed # sub lib_check_drivers_installed { my ($driver); my ($num_drivers_installed) = 0; foreach $driver ($DRIVER_COMPONENTS[OKS_IDX], $DRIVER_COMPONENTS[AVD_IDX], $DRIVER_COMPONENTS[OFS_IDX]) { if($VERBOSE) { lib_inform_print(9155, "Checking for existing '%s' driver " . "installation.", $driver); } if (lib_osds_check_driver_installed($driver)) { $num_drivers_installed++; } } if ($num_drivers_installed != 3) { return 0; } return 1; } # end lib_check_drivers_installed # lib_check_any_driver_installed # sub lib_check_any_driver_installed { my ($driver); foreach $driver ($DRIVER_COMPONENTS[OKS_IDX], $DRIVER_COMPONENTS[AVD_IDX], $DRIVER_COMPONENTS[OFS_IDX]) { if($VERBOSE) { lib_inform_print(9155, "Checking for existing '%s' driver " . "installation.", $driver); } if (lib_osds_check_driver_installed($driver)) { return 1; } } return 0; } # end lib_check_any_driver_installed # lib_count_drivers_loaded # sub lib_count_drivers_loaded { my ($driver); my ($num_drivers_loaded) = 0; foreach $driver ($DRIVER_COMPONENTS[OKS_IDX], $DRIVER_COMPONENTS[AVD_IDX], $DRIVER_COMPONENTS[OFS_IDX]) { if (lib_osds_check_driver_loaded($driver)) { $num_drivers_loaded++; } } return $num_drivers_loaded; } # end lib_osds_count_drivers_loaded # lib_check_drivers_loaded # sub lib_check_drivers_loaded { my ($num_drivers_loaded) = 0; my ($return_val); $num_drivers_loaded = lib_count_drivers_loaded(); if ($num_drivers_loaded != 3) { $return_val = 0; } else { $return_val = 1; } return $return_val; } # end lib_osds_check_drivers_loaded # lib_check_loaded_drivers_mismatch # # Determine whether or not the installed drivers match the drivers that # are loaded in the kernel. This can happen during Solaris which # doesn't reliably unload drivers. sub lib_check_loaded_drivers_mismatch { return lib_osds_check_loaded_drivers_mismatch(); } use constant CHECK_IN_PROGRESS_NO => 0; use constant CHECK_IN_PROGRESS_YES => 1; use constant CHECK_IN_PROGRESS_TIMEOUT => 2; # lib_check_in_progress # # Use a temp file to mark a check being in progress # # Returns: # CHECK_IN_PROGRESS_NO - no previous check currently in progress # CHECK_IN_PROGRESS_YES - previous check currently in progress # CHECK_IN_PROGRESS_TIMEOUT - previous check in progress timeout exceeded # # We return a CHECK_IN_PROGRESS_NO even if the directory or the file creation # fails. This, effectively, disables the function because the caller will # think that there is no check in progress and so the check proceeds normally. # This is better than returning a 1, which would make the caller think that # is a check in progress - even if there isn't one. # sub lib_check_in_progress { my ($fname) = @_; # temp file name my ($pname); # full path name for temp file name my ($retcode) = CHECK_IN_PROGRESS_NO; # return value my ($time_stamp) = get_day_time_in_seconds(); if (! -d $TMPDIR) { mkdir $TMPDIR,0777 or warn ("failed to create $TMPDIR: $!"), $retcode = 1; if ($retcode eq 1) { return CHECK_IN_PROGRESS_NO; } } $pname = build_check_filename($TMPDIR, $fname); if (-e $pname) { # A check for this $pname is already in progress. my ($time_stamp); my ($time_limit) = $ENV{_ORA_CHECK_TIMEOUT}; # If the $pname creation timestamp is greater than the check timeout value, # we return CHECK_IN_PROGRESS_TIMEOUT. open FILE, "<$pname" or warn ("failed to open $pname: $!"), $retcode = CHECK_IN_PROGRESS_YES; if ($retcode ne CHECK_IN_PROGRESS_NO) { # We could not open the file to read the time stamp. We're root # and we can't open a file that we created.... hmmm. # Well, there is a small race between the exist check and the open. # Remove the file (if it still exists). It will be created on next check. unlink $pname; return $retcode; } $time_stamp = ; if(!defined($time_stamp)) { # Apparently the file got damaged. delete the file and return # CHECK_IN_PROGRESS_YES. The file will be recreated on the next check. unlink $pname; return CHECK_IN_PROGRESS_YES; } chomp($time_stamp); close(FILE); if (!defined($time_limit)) { # We could not get the _ORA_SCRIPT_TIMEOUT from the environment. # use the default falue from ./has/crs/template/registry.acfs.type. $time_limit = 300; } if (time_limit_exceeded($time_stamp, $time_limit)) { $retcode = CHECK_IN_PROGRESS_TIMEOUT; } else { $retcode = CHECK_IN_PROGRESS_YES; } } else { # Marking check in progress. open FILE, ">$pname" or warn ("failed to create $pname: $!"), $retcode = 1; if ($retcode eq 0) { printf FILE "%05s\n", $time_stamp; close FILE; } $retcode = CHECK_IN_PROGRESS_NO; } return $retcode; } # end lib_check_in_progress # lib_end_check_in_progress # # returns 0 (success) or 1 (failed to remove existing tmp file) # # This is also called from start() when no temp file exists (should exist) # to guarantee a "clean slate". # sub lib_end_check_in_progress { my ($fname) = @_; # temp file name my ($pname); # full path name for temp file name my ($retcode) = 0; # return value $pname = build_check_filename($TMPDIR, $fname); if (-e $pname) { unlink $pname or warn ("failed to remove $pname: $!"), $retcode = 1; } return $retcode; } # end lib_end_check_in_progress # lib_control_devices_accessible # # call into control_devices_accessible # sub lib_control_devices_accessible { return lib_osds_control_devices_accessible(); } # end lib_control_devices_accessible # lib_get_asm_admin_name # # Get the group name of the ASM administrator # NOTE: not called from Windows # This is not really OSD code - but it's not (yet) needed on Windows # and is not installed there. # sub lib_get_asm_admin_name { if (defined($CACHED_ASMADMIN)) { return $CACHED_ASMADMIN; } my ($asmadmin) = 'dba'; # get the current system ASM admin group name if ((defined($ORACLE_HOME)) && (-e "$ORACLE_HOME/bin/osdbagrp")) { open (ASMADMIN, "$ORACLE_HOME/bin/osdbagrp -a |"); $asmadmin = ; close (ASMADMIN); if (!defined($asmadmin)) { lib_error_print(9115, "The command '%s' returned an unexpected value.", "$ORACLE_HOME/bin/osdbagrp -a"); lib_error_print(9135, "%s installation aborted.", $COMMAND); # This is unrecoverable - fail. Unfortunately, there's no graceful way # of failing without major redesign - and this is a VERY rare event. exit USM_FAIL; } } $CACHED_ASMADMIN = $asmadmin; return $CACHED_ASMADMIN; } # end lib_get_asm_admin_name # lib_get_advm_mounts # # call into lib_osds_get_advm_mounts # sub lib_get_advm_mounts { return lib_osds_get_advm_mounts(); } # end lib_get_advm_mounts # lib_get_asm_user # # call into lib_osds_get_asm_user # sub lib_get_asm_user { return lib_osds_get_asm_user(); } # end lib_get_asm_user # lib_get_drive_info # # call into lib_osds_get_drive_info # sub lib_get_drive_info { return lib_osds_get_drive_info(@_); } # end lib_get_drive_info # lib_load_usm_drivers # # Load the drivers if not already loaded. Silently ignore if a driver is loaded # # We do this in two phases because we found that on Solaris, sometimes the # oracleacfs driver got loaded when the advm driver got loaded by devfsadm(1M). # Then the next time through the loop, lib_osds_check_driver_loaded(oracleacfs) # would not get called. This prevented /dev/ofsctl was from being created. # sub lib_load_usm_drivers { my ($driver); my (@loaded); my ($idx); # determine which drivers are already loaded (if any). foreach $idx (OKS_IDX, AVD_IDX, OFS_IDX) { $driver = $DRIVER_COMPONENTS[$idx]; $loaded[$idx] = 0; if (lib_osds_check_driver_loaded($driver)) { $loaded[$idx] = 1; } } # Load the not already loaded drivers. # The order is important - OKS must be first. foreach $idx (OKS_IDX, AVD_IDX, OFS_IDX) { if (!$loaded[$idx]) { my ($return_val); $driver = $DRIVER_COMPONENTS[$idx]; lib_inform_print(9154, "Loading '%s' driver.", $driver); $return_val = lib_osds_load_driver($driver, $COMMAND); if ($return_val == USM_FAIL) { lib_error_print(9109, "%s driver failed to load.", $driver); return USM_FAIL; } } } return USM_SUCCESS; } # end lib_load_usm_drivers # lib_mount # # call into lib_osds_mount # sub lib_mount { my ($device, $mount_point, $options) = @_; # The following nomounts file can be used to prevent # automatic resources from mounting file systems # that may need to be fsck'd - resulting in a panic. my $nomounts = "" ; if (defined($ENV{'TEMP'}) && (-f "$ENV{'TEMP'}/oracle_nomounts" )) { $nomounts = "$ENV{'TEMP'}/oracle_nomounts"; } elsif (defined($ENV{'TMP'}) && (-f "$ENV{'TMP'}/oracle_nomounts" )) { $nomounts = "$ENV{'TMP'}/oracle_nomounts"; } elsif (-f "/tmp/oracle_nomounts" ) { $nomounts = "/tmp/oracle_nomounts"; } if ( $nomounts ne "" ) { lib_inform_print(9151, "Ignoring request to mount due to existence of \"oracle_nomounts\" file: %s", $nomounts); return USM_FAIL; } return lib_osds_mount($device, $mount_point, $options); } # end lib_mount # lib_mountpoint_descriptors # # call into lib_osds_mountpoint_descriptors # sub lib_mountpoint_descriptors { my ($mount_point, $action) = @_; return lib_osds_mountpoint_descriptors($mount_point, $action); } # end lib_mountpoint_descriptors # lib_recover_stale_mounts # # call acfsutil info fs and look for mountpoints marked Offline. # Attempt to unmount the mount point. # # An acfsutil info fs -o mountpoints,isavailable entry looks like this: # /mnt # 1 # sub lib_recover_stale_mounts { my ($recover_specific_mountpoint) = @_; # set by usm_singlefs_mount only my ($offline) = 0; my ($recovered_list) = ""; my ($line) = ""; my ($device); my ($mountpoint); my ($ret_val); my ($acfsutil_info_fs) = "$ACFSUTIL info fs " . OPT_CHR . "o mountpoints,isavailable"; my ($switch) = 0; # TODO: test the failure case. # this used to have a 2>&1 here. Windows in CRS env does not seem to # like this sort of redirection, so it got booted. # # Do we need to check the error stream for -03036? Or can we just # assume that there are no file systems if there is no output? # There doesn't seem to be any checks for other errors. open(INFO , "$acfsutil_info_fs $REDIRECT |") or die "acfsutil info fs failed: $!"; while ($line = ) { chomp($line); if ($line =~ /ACFS-03036/) { # no mounted file systems last; } if ($line =~/^\s*acfsutil info fs: (ACFS|CLSU)-\d{5}/) { # any ACFS-# error message lib_error_print(9150, "Unexpected output from 'acfsutil info fs': '%s'.", $line); next; } if ($switch == 0) { $mountpoint = $line; $switch = 1; next; } else { $switch = 0; if ($line eq 1) { #online next; } } $device = lib_osds_device_from_mountpoint($mountpoint); if (!defined($device)) { lib_error_print(9122, "ADVM device not determined from mount point '%s'.", $mountpoint); return USM_FAIL; } # usm_mount wants to recover all stale mounts (if any) and will # not pass an argument. usm_singlefs_mount wants to recover only # the mount point it is interested in (so as not to confuse # usm_mount and its state file). if (defined($recover_specific_mountpoint)) { if ($recover_specific_mountpoint ne $mountpoint) { # looking for a specific mountpoint and this isn't it. next; } } else { # # Recover any stale mount points in the registry. # my $cmd_out = ""; my $acfsutil_registry = "$ACFSUTIL registry " . OPT_CHR . "l $mountpoint"; open(REGISTRY, "$acfsutil_registry $REDIRECT |") or do { lib_error_print(9999, "executing $acfsutil_registry failed: $!"); next; }; $cmd_out = ; close(REGISTRY); if ( ! defined ( $cmd_out ) ) { next; } if ($cmd_out =~ /ACFS-03135/) { # called from acfsregistrymount and mount point isn't in the registry so # so we don't want to recover it. next; } if ($cmd_out =~ /ACFS-/) { # Unexpected error from acfsutil lib_error_print(9999, "Unexpected error from $acfsutil_registry. err=$cmd_out"); next; } my $mountpointQM = quotemeta ( $mountpoint ); # for Windows if ( $cmd_out !~ /Mount Point\s+:\s+$mountpointQM\s+:/i ) { # We probably shouldn't get here. Our check for ACFS-03135 # should have caught this condition. At any rate we don't see # the mount point in the acfsutil registry output so it isn't # registered (or there's some other problem). lib_error_print(9999, "Unexpected output from $acfsutil_registry. err=$cmd_out"); next; } } lib_inform_print(9139, "Attempting recovery of offline mount point '%s'", $mountpoint); $ret_val = lib_osds_unmount($mountpoint); if ($ret_val == 0) { # The unmount succeeded! Remove the mount point from the temp file # so it will simply be treated as a new mount in check(). lib_inform_print(9110, "Offline mount point '%s' was dismounted for recovery.", $mountpoint); $recovered_list .= "$device "; } else { # The unmount failed. # Find and report the open references on the mountpoint my ($refs) = lib_osds_mountpoint_descriptors($mountpoint, 0); lib_error_print (9112, "The following process IDs have open references on mount point '%s':", $mountpoint); lib_error_print(9999, $refs); # message 9999 is not formatted lib_error_print(9113, "These processes will now be terminated."); # terminate any open descriptors $ret_val = lib_osds_mountpoint_descriptors($mountpoint, 1); lib_error_print(9114, "completed"); if ($ret_val == USM_SUCCESS) { # OK try the unmount again $ret_val = lib_osds_unmount($mountpoint); } if ($ret_val == USM_SUCCESS) { # The unmount succeeded! Remove the mount point from the temp file # so it will simply be treated as a new mount in check(). lib_inform_print(9110, "Offline mount point '%s' was dismounted for recovery.", $mountpoint); $recovered_list .= "$device "; } else { # should never get here......... but...... lib_error_print (9116, "Offline mount point '%s' was not recovered.", $mountpoint); lib_error_print(9117, "Manual intervention is required."); } } } close (INFO); return $recovered_list; } # end lib_recover_stale mounts # lib_run_as_user # # call into lib_osds_run_as_user # sub lib_run_as_user { my ($user_name, $cmd) = @_; return lib_osds_run_as_user($user_name, $cmd); } # end lib_run_as_user # lib_unmount # # call into lib_osds_unmount # sub lib_unmount { my ($mount_point) = @_; return lib_osds_unmount($mount_point); } # end lib_unmount # lib_unload_usm_drivers # # Unload the USM drivers. Return error if any driver fails to unload. # sub lib_unload_usm_drivers { # Optional argument: location of new install files. Utilities from new # install files may be used to unload drivers if old utilities cannot be # found my ($install_files_loc) = @_; my ($driver); my ($return_val) = USM_SUCCESS; foreach $driver ($DRIVER_COMPONENTS[OFS_IDX], $DRIVER_COMPONENTS[AVD_IDX], $DRIVER_COMPONENTS[OKS_IDX]) { # nothing to do if the driver is not loaded if (lib_osds_check_driver_loaded($driver)) { # test to see that the driver is not being used if (lib_osds_check_driver_inuse($driver)) { lib_error_print (9118, "%s driver in use - cannot unload.", $driver); $return_val = USM_SUCCESS; last; } $return_val = lib_osds_unload_driver($driver, $install_files_loc); if ($return_val != USM_SUCCESS) { lib_error_print(9119, "%s driver failed to unload.", $driver); $return_val = USM_REBOOT_RECOMMENDED; last; } } } return $return_val; } # end lib_unload_usm_drivers # lib_usm_supported # # call into lib_osds_usm_supported # sub lib_usm_supported { return lib_osds_usm_supported(); } # end lib_usm_supported # lib_usm_supported # # call into lib_osds_usm_supported # sub lib_verify_usm_devices { return lib_osds_verify_usm_devices(); } # end lib_verify_usm_devices # lib_inform_print # If $silent is set, messages are not displayed. # sub lib_inform_print { my (@arg_array) = @_; common_print(PRINT_INFORM, @arg_array); return USM_SUCCESS; } # lib_create_mount_point # # call into lib_osds_create_mount_point # sub lib_create_mount_point { my $mount_point = shift; return lib_osds_create_mount_point($mount_point); } # end lib_create_mount_point # lib_device_from_mountpoint # # call into lib_osds_device_from_mountpoint # sub lib_device_from_mountpoint { my ($mount_point) = @_; return lib_osds_device_from_mountpoint($mount_point); } # end lib_device_from_mountpoint sub lib_error_print { my (@arg_array) = @_; common_print(PRINT_ERROR, @arg_array); return USM_SUCCESS; } # lib_is_mounted # # call into lib_osds_is_mounted # sub lib_is_mounted { my ($mount_point) = @_; return lib_osds_is_mounted($mount_point); } # end lib_is_mounted # # Check if a file system is offline or otherwise # unavailable. (0 , not available, 1, available, -1, other error) # sub lib_is_mount_available { my ($mount_point) = @_; # mount point to test my ($avail) = 0; # assume not available my ($cmd_out); # Capture output of acfsutil command. # # On windows performing acfsutil against a drive letter # specification which includes a trailing backslash (e.g. "p:\") # when the filesystem is stale will yield a bunch of errors rather # than returning the availability state. Strip the trailing # backslash if any. This code is harmless on non-Windows. # $mount_point = substr ($mount_point,0,2) if ( length($mount_point) == 3 && substr($mount_point,1,2) eq ":\\" ); # ACFSUTIL defined in lib_osds_usm.pm my $cmd = "$ACFSUTIL info fs " . OPT_CHR . "o isavailable $mount_point "; $cmd_out= `$cmd`; if (!defined($cmd_out)) { $cmd_out=""; } if ($? == 0) { # Execution successful, cmd_out will hold 0 or 1. if ($cmd_out != 1 ) { $avail = 0; } else { #mount is available. $avail = 1; } } else { # We had an error running acfsutil. # Probable error: Not an acfs file system # Probable error #2: Mount point no longer exists. lib_error_print(9138, "command '%s' completed with an error: %s", $cmd, $cmd_out); $avail=-1; } return $avail; } ########################################### ######## Local only static routines ####### ########################################### # common_print # # common print routine shared by lib_inform_print() and lib_error_print # sub common_print { my ($message_type) = shift(@_); # PRINT_ERROR, PRINT_INFORM my ($message_id) = shift(@_); my ($message) = shift(@_); my (@message_args) = @_; my ($debug) = $ENV{'ACFS_DEBUG'}; if (defined($debug)) { my (@args) = @message_args; my ($msg) = $message; open DBG, ">>/tmp/acfs_debug" or warn "/tmp/acfs_debug: $!"; while (@args) { my ($arg) = shift(@args); $msg =~ s/\%s/$arg/; } print DBG "$COMMAND: $msg\n"; close DBG; } if ($SILENT && ($message_type == PRINT_INFORM)) { # do not print if the message is not an error and the -s option is used. return USM_SUCCESS; } # special case: message 9999 is not formatted # The message may be a list of PIDs, for instance, or an error message # from another command that may already have been I18N'ed. if ($message_id == 9999) { # TODO - disable until bug 9664524 gets fixed. undef $CRS; # end TODO if (($message_type == PRINT_ERROR) && (defined($CRS))) { $message = "CRS_ERROR:" . $message; } system("$CLSECHO \"$message\""); return; } if (defined($ADE_VIEW_ROOT)) { # If we are in a devlopment environment, we compare the message # in the program to the message in acfsus.msg and flag a mis-match. verify_message($message_id, $message); } my ($arg_list) = ""; # process message arguments while (@message_args) { my ($arg) = shift(@message_args); $arg_list .= "\"$arg\" "; } # Create the clsecho options string my ($echo_string) = "-m $message_id "; # Set the severity level (-c option) if ($message_type == PRINT_ERROR) { # TODO - disable until bug 9664524 gets fixed. undef $CRS; # end TODO if (defined($CRS)) { # Force errors to go to the terminal, not just the logs. # Normally, the messages would just go to the logs, but when AGFW # sees the "CRS_ERROR:" "decoration string", it strips that off and # sends the remaining string to the terminal and the logs. See # ./has/src/crs/agentfw/framework/clsAgfwScript.cpp. # # See has/include/clsem.h for "decoration string" guidelines. For example, # if the string, anywhere, contains 'f', it will be converted into the # "one digit fractional secs." - what you see may not be what you get. $echo_string .= "-c err -d 'CRS_ERROR: ' "; } else { # We're called interactively. $echo_string .= "-c err "; } } else { # lib_inform_print() $echo_string .= "-c info "; } # timestamp user message $echo_string .= "-t "; # write to log and console, with timestamps in log but not on console. $echo_string .= "-z "; # finally append the message values arg_list $echo_string .= $arg_list; # Send the message system ("$CLSECHO $echo_string"); } # end common_print # verify_message # # Verify that the message in the print statement matches the message catalog. # # Called only when ADE_VIEW_ROOT is set in the environment # sub verify_message { my ($message_id, $message) = @_; # verify that the message matches the (acfsus.msg) catalog open CATALOG, "<$ORACLE_HOME/usm/mesg/acfsus.msg" or die "can't open msg file: $!"; my ($line); while ($line = ) { my ($len) = length $message_id; # Convert the incoming msg id to the acfsus.msg 5 character format - if # needed. If the msg id is 5 chars (or more, [future]), no work is needed. if ($len < 5) { $message_id = sprintf("%05s", $message_id); } if ($line =~ /^$message_id/) { # the "split" separates the message in the file from what # preceeds it (e.g., 1234, 0, ") my (@acfsus_msg) = split(/"/, $line); chomp($acfsus_msg[1]); # lose the trailing quote $acfsus_msg[1] =~ s/"$//; if ($acfsus_msg[1] ne $message) { print "message $message_id format mismatch:\n"; print "acfsus.msg:\t>$acfsus_msg[1]<\n"; print "$COMMAND:\t>$message<\n"; } last; } } close (CATALOG); } # end verify_message # # used for "sql alter diskgroup.... # sub asm_do_stmt { my ($dbh, $qry) = @_; my ($sth); my ($rv) = USM_SUCCESS; $rv = $dbh->do($qry); warn "$DBI::errstr\n" unless defined ($rv); if (!defined ($rv)) { $rv = USM_FAIL; } return ($rv); } # # used for sql select # sub asm_select_stmt { my ($dbh, $qry) = @_; my ($sth); my ($rv); eval { $sth = $dbh->prepare($qry); }; if (!defined ($sth)) { return USM_FAIL; } eval { $rv = $sth->execute(); }; warn "$DBI::errstr\n" unless defined ($rv); if (!defined($rv)) { return USM_FAIL; } return ($sth); } # # Fetch the next row on the table # sub asm_fetch_row { my $sth = shift; my $row; return undef unless(defined $sth); eval { $row = $sth->fetchrow_hashref; }; if ( $@ ) { # We can't talk to the data base. Maybe ASM died. undef $row; } return $row; } # build_check_filename # # Return the name of the check_in_progress file name - # Input: # $tmp_dir - typically /tmp or \temp. # $name of the file - this could include directories. # # Remove any semblance of directory structure in $name. So, on Unix, a # name of /one/two/three will return /tmp/_one_two_three_check. # sub build_check_filename { my ($tmp_dir, $name) = @_; $name =~ s/\//_/g; $name =~ s/\\/_/g; my ($full_file_name) = catfile($tmp_dir, $name . "_check"); return $full_file_name; } # end build_check_filename # time stamp ops use constant SECONDS_PER_DAY => 86400; # get_day_time_in_seconds # # Return number of seconds since local midnight. # sub get_day_time_in_seconds { my ($sec, $min, $hour) = localtime(time); my ($seconds) = ($hour * 3600) + ($min * 60) + $sec; return $seconds; } # end get_day_time_in_seconds # time_limit_exceeded # # The main reason for a separate function is to handle time wrapping. # sub time_limit_exceeded { my ($time_stamp, $time_limit) = @_; my ($current_time) = get_day_time_in_seconds(); my ($time_diff); if ($current_time>= $time_stamp) { $time_diff= $current_time - $time_stamp; } else { # the timer has wrapped $time_diff= (SECONDS_PER_DAY - $time_stamp) + $current_time; } if ($time_diff< $time_limit) { # time limit not exceeded return 0; } return 1; } # end time_limit_exceeded sub trim($) { my $string=shift; $string =~ s/^\s+//; $string =~ s/\s+$//; return $string; } # # ACFS resource utility functions # # Add the ACFS registry resource and its type sub add_acfs_registry { my $owner = "root"; my $asmgrp = getParam("ORA_ASM_GROUP"); chomp $asmgrp; my $crsctl = File::Spec->catfile($ORACLE_HOME, "bin", "crsctl"); if ($asmgrp eq "") { # getParam failed. lib_error_print(9367, "Adding ACFS registry resource failed."); return USM_FAIL; } if ($OSNAME eq "Windows_NT" || $OSNAME eq "MSWin32") { $owner = "NT AUTHORITY\\SYSTEM"; } # Add the ora.registry.acfs.type type my @cmd = ($crsctl, 'add', 'type', 'ora.registry.acfs.type', '-basetype', 'ora.local_resource.type', '-file', "$ORACLE_HOME/crs/template/registry.acfs.type"); my $ret1 = system(@cmd); # Add the ora.registry.acfs resource @cmd = ($crsctl, "add", "resource", "ora.registry.acfs", "-attr", "ACL='owner:$owner:rwx,pgrp:$asmgrp:rwx,other::r--'", "-type", "ora.registry.acfs.type", "-f"); my $ret = system(@cmd); if ($ret != 0) { lib_error_print(9367, "Adding ACFS registry resource failed."); return USM_FAIL; } else { lib_inform_print(9368, "Adding ACFS registry resource succeeded."); return USM_SUCCESS; } } # Delete the ACFS registry resource and its type sub delete_acfs_registry { my $crsctl = File::Spec->catfile($ORACLE_HOME, "bin", "crsctl"); my @cmd = ($crsctl, "delete", "resource", "ora.registry.acfs", "-f"); my $ret1 = system(@cmd); @cmd = ($crsctl, 'delete', 'type', 'ora.registry.acfs.type'); my $ret = system(@cmd); if ($ret != 0) { lib_error_print(9369, "Deleting ACFS registry resource failed."); return USM_FAIL; } else { lib_inform_print(9370, "Deleting ACFS registry resource succeeded."); return USM_SUCCESS; } } # Start the ACFS registry resource sub start_acfs_registry { my $crsctl = File::Spec->catfile($ORACLE_HOME, "bin", "crsctl"); my @cmd = ($crsctl, 'start', 'res', 'ora.registry.acfs'); my $ret = system(@cmd); if ($ret != 0) { lib_error_print(9371, "Starting ACFS registry resource failed."); return USM_FAIL; } else { lib_inform_print(9372, "Starting ACFS registry resource succeeded."); return USM_SUCCESS; } } # Stop the ACFS registry resource sub stop_acfs_registry { my $crsctl = File::Spec->catfile($ORACLE_HOME, "bin", "crsctl"); my @cmd = ($crsctl, 'stop', 'res', 'ora.registry.acfs'); my $ret = system(@cmd); if ($ret != 0) { lib_error_print(9373, "Stopping ACFS registry resource failed."); return USM_FAIL; } else { lib_inform_print(9374, "Stopping ACFS registry resource succeeded."); return USM_SUCCESS; } } # Add the USM drivers resource. sub add_usm_drivers_resource { my $crsctl = File::Spec->catfile($ORACLE_HOME, "bin", "crsctl"); my $asmgrp = getParam("ORA_ASM_GROUP"); chomp $asmgrp; my $owner = "root"; my $CRSDUSER = getParam("ORACLE_OWNER"); chomp $CRSDUSER; if (($CRSDUSER eq "") || ($asmgrp eq "")) { # getParam failed. lib_error_print(9375, "Adding ADVM/ACFS drivers resource failed."); return USM_FAIL; } if ($OSNAME eq "Windows_NT" || $OSNAME eq "MSWin32") { $owner = "NT AUTHORITY\\SYSTEM"; } my $ret = system($crsctl, "add", "resource", "ora.drivers.acfs", "-attr", "ACL='owner:$owner:rwx,pgrp:$asmgrp:r-x,other::r--,user:$CRSDUSER:r-x'", "-type", "ora.drivers.acfs.type","-init"); if ($ret != 0) { lib_error_print(9375, "Adding ADVM/ACFS drivers resource failed."); return USM_FAIL; } else { lib_inform_print(9376, "Adding ADVM/ACFS drivers resource succeeded."); return USM_SUCCESS; } } # Delete the USM drivers resource. sub delete_usm_drivers_resource { my $crsctl = File::Spec->catfile($ORACLE_HOME, "bin", "crsctl"); my @cmd = ($crsctl, "delete", "resource", "ora.drivers.acfs", "-f", "-init"); my $ret = system(@cmd); if ($ret != 0) { lib_error_print(9377, "Deleting ADVM/ACFS drivers resource failed."); return USM_FAIL; } else { lib_inform_print(9378, "Deleting ADVM/ACFS drivers resource succeeded."); return USM_SUCCESS; } } # Start the USM drivers resource. sub start_usm_drivers_resource { my $crsctl = File::Spec->catfile($ORACLE_HOME, "bin", "crsctl"); my @cmd = ($crsctl, "start", "resource", "ora.drivers.acfs", "-init"); my $ret = system(@cmd); if ($ret != 0) { lib_error_print(9379, "Starting ADVM/ACFS drivers resource failed."); return USM_FAIL; } else { lib_inform_print(9380, "Starting ADVM/ACFS drivers resource succeeded."); return USM_SUCCESS; } } # usm_resource_exists # returns USM_SUCCESS if the specified resource exists. # returns USM_FAIL if the specified resource does not exist. # returns USM_FAIL if en error is encountered. # sub usm_resource_exists { my ($resource) = @_; my ($which); my ($opt) = ""; my ($ret) = USM_SUCCESS; if ($resource eq "registry") { $which = "ora.registry.acfs"; } elsif ($resource eq "drivers") { $which = "ora.drivers.acfs"; $opt = "-init"; } else { lib_error_print(532, "invalid option: %s", $resource); $ret = USM_FAIL; } if ($ret == USM_SUCCESS) { open CRSCTL, "$ORACLE_HOME/bin/crsctl stat res $which $opt |"; if ($?) { $ret = USM_FAIL; } else { while () { if (/CRS-2613/) { # "Could not find resource '%s'." $ret = USM_FAIL; last; } } close CRSCTL; } } return $ret; } sub modify_usm_drivers_resource { my $crsctl = File::Spec->catfile($ORACLE_HOME, "bin", "crsctl"); my $asmgrp = getParam("ORA_ASM_GROUP"); my $owner = "root"; my $CRSDUSER = getParam("ORACLE_OWNER"); chomp $CRSDUSER; chomp $asmgrp; my @cmd; my $ret; my $ret1 = 0; if (($CRSDUSER eq "") || ($asmgrp eq "")) { # getParam failed. lib_error_print(9381, "Modification of ADVM/ACFS drivers resource failed."); return USM_FAIL; } if ($OSNAME eq "Windows_NT" || $OSNAME eq "MSWin32") { $owner = "NT AUTHORITY\\SYSTEM"; } @cmd = ($crsctl, "modify", "resource", "ora.drivers.acfs", "-attr", "ACL='owner:$owner:r-x,pgrp:$asmgrp:r-x,user:$CRSDUSER:r-x,other::r--'", "-init"); $ret = system(@cmd); $ret1 = ($ret) ? 1 : $ret1; if ($ret1 != 0) { lib_error_print(9381, "Modification of ADVM/ACFS drivers resource failed."); return USM_FAIL; } lib_inform_print(9382, "Modification of ADVM/ACFS drivers resource succeeded."); return USM_SUCCESS; } sub modify_usm_registry_resource { my $owner = "root"; my $crsctl = File::Spec->catfile($ORACLE_HOME, "bin", "crsctl"); my $asmgrp = getParam("ORA_ASM_GROUP"); chomp $asmgrp; my @cmd; my $ret; my $ret1 = 0; if ($asmgrp eq "") { # getParam failed. lib_error_print(9397, "Modification of ADVM/ACFS registry resource failed."); return USM_FAIL; } if ($OSNAME eq "Windows_NT" || $OSNAME eq "MSWin32") { $owner = "NT AUTHORITY\\SYSTEM"; } @cmd = ($crsctl, "modify", "resource", "ora.registry.acfs", "-attr", "ACL='owner:$owner:rwx,pgrp:$asmgrp:rwx,other::r--'"); $ret = system(@cmd); $ret1 = ($ret) ? 1 : $ret1; # Modify the ora.registry.acfs resource @cmd = ($crsctl, "modify", "resource", "ora.registry.acfs", "-attr", "TYPE=ora.registry.acfs.type"); $ret = system(@cmd); $ret1 = ($ret) ? 1 : $ret1; @cmd = ($crsctl, 'modify', 'resource', 'ora.registry.acfs', '-attr', 'SCRIPT_TIMEOUT=120'); $ret = system(@cmd); $ret1 = ($ret) ? 1 : $ret1; @cmd = ($crsctl, 'modify', 'resource', 'ora.registry.acfs', '-attr', 'START_TIMEOUT=180'); $ret = system(@cmd); $ret1 = ($ret) ? 1 : $ret1; @cmd = ($crsctl, 'modify', 'resource', 'ora.registry.acfs', '-attr', 'STOP_TIMEOUT=900'); $ret = system(@cmd); $ret1 = ($ret) ? 1 : $ret1; @cmd = ($crsctl, 'modify', 'resource', 'ora.registry.acfs', '-attr', 'CHECK_TIMEOUT=600'); $ret = system(@cmd); $ret1 = ($ret) ? 1 : $ret1; if ($ret1 != 0) { lib_error_print(9397, "Modification of ADVM/ACFS registry resource failed."); return USM_FAIL; } lib_inform_print(9398, "Modification of ADVM/ACFS registry resource succeeded."); return USM_SUCCESS; } sub getParam { my $var = $_[0]; my $paramFhdl; my ($paramfile) = File::Spec->catfile($ORACLE_HOME, "crs", "install", "crsconfig_params"); if (! -e $paramfile) { lib_error_print(10285, "Pathname '%s' does not exist.", $paramfile); return ""; } open ( $paramFhdl, "<$paramfile" ); while ( my $line = <$paramFhdl> ) { chomp $line; if ( $line =~ /^\s*$var/i ) { my $param = $line; $param =~ s/^\s*($var)\s*=.*/$1/i; my $val = $line; $val =~ s/.*=\s*(.*)\s*/$1/i; close ( $paramFhdl ); return $val; } } close ( $paramFhdl ); return ""; } sub lib_is_abs_path { return lib_osds_is_abs_path(@_); } # # Subroutine to print a warning header for a command # sub lib_print_cmd_header { my ($cmd) = @_; $cmd=~ s/"/'/g; lib_inform_print (9390, "The command '%s' returned unexpected output that" . " may be important for system configuration:", $cmd); } # end lib_print_cmd_header # # lib_run_func - Run specified library function # # This function exposes library functions to the command line so that # they may be called by programs outside of the usm/src/cmds framework. # This function itself is currently exposed from acfsroot.pl and is # accessed as follows. # # acfsroot lib_run_func [args ...] # # For example # # acfsroot lib_run_func lib_is_mounted /my_mount # # This function is useful for things like the USM CRS agents which are # written in C++ but can benefit from the functions in this Perl # library. When used with UsmUtils::execCmd, execCmdRead, and # execCmdClose, the agents have a reasonably seamless interface into # the functions in this library. The first use of this interface (and # hence the only current example) is UsmUtils::CheckLoadedDriversMismatch. # # Note that lib_run_func can be made to expose functions in the command # libraries (e.e. acfsload.pm) by putting a call out to it (see # the call to this function in acfsroot.pl for an example) and # prefixing the function name with the library name. E.g. # osds_acfslog::osds_verify_correct_driver_version(). # sub lib_run_func { my $fName = shift; # name of library function to execute my $fP; # pointer to function # Make sure a function name is specified if ( ! $fName ) { lib_error_print(9999, "ERROR: Internal error: lib_run_func function name not specified"); return -1; } # Get a pointer to the function $fP = \&$fName; # Make sure the function is defined if ( ! defined ( &$fP ) ) { lib_error_print(9999, "ERROR: Internal error: " . "Unknown lib_run_func function: $fName "); return -1; } # Call the function specifying the remaining arguments and returning # its return value return $fP->( @_ ); } 1;