# # # osdsacfslib.pm # # Copyright (c) 2007, 2016, 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. # # 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_disable_volume lib_asm_mount_diskgroup lib_check_drivers_installed lib_check_any_driver_installed lib_check_uninstall_required 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_error_print_noalert lib_get_advm_mounts lib_get_asm_admin_name lib_get_asm_user lib_get_drive_info lib_inform_print lib_inform_print_noalert lib_verbose_print lib_verbose_print_noalert lib_is_local_container 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_trace 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 $_ORA_USM_TRACE_ENABLED $_ORA_USM_TRACE_LEVEL $ACFSUTIL $USM_CURRENT_PROD 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 CRS_ACTION USM_FAIL USM_TRANSIENT_FAIL USM_SUCCESS USM_SUPPORTED USM_NOT_SUPPORTED USM_REBOOT_RECOMMENDED USM_PROD_ACFS USM_PROD_OKA USM_PROD_AFD USM_PROD_OLFS add_usm_drivers_resource usm_resource_exists modify_usm_drivers_resource delete_usm_drivers_resource start_usm_drivers_resource md5compare lib_are_same_file lib_is_number isODA isODADomu isOPCDom0 isOPCDomu isDomainClass isMemberClass isSHMI lib_acfs_remote_supported lib_acfs_remote_installed lib_acfs_remote_loaded ); use DBI; use osds_acfslib; use File::Spec::Functions; use File::Path; use Digest::MD5 qw(md5 md5_hex md5_base64); our ($SILENT) = 0; # input option (-s) our ($VERBOSE) = 0; # input option (-v) our ($_ORA_USM_TRACE_ENABLED) = 0; our ($_ORA_USM_TRACE_LEVEL) = 0; our ($COMMAND) = "No Command Specified"; # currently executing command our (%acfsr) = ( 'ACFS Remote' => 'False', 'iSCSI' => 'False', ); 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 my ($CLSECHO) = catfile($ORA_CRS_HOME, "bin", "clsecho"); # '-l' = write to CRS alert log. Look at common_print() my ($CLSECHO_ACFS) = catfile($ORA_CRS_HOME, "bin", "clsecho") . " -p usm -f acfs"; # if the message to print is from OKA my ($CLSECHO_OKA) = catfile($ORA_CRS_HOME, "bin", "clsecho") . " -p usm -f oka"; # if the message to print is from AFD my ($CLSECHO_AFD) = catfile($ORA_CRS_HOME, "bin", "clsecho") . " -p usm -f afd"; my ($CLSECHO_BIN_AFD) = catfile($ORA_CRS_HOME, "bin", "clsecho.bin") . " -p usm -f afd"; our $CRS_ACTION = ""; # if set, contains "start", "stop", # "check", "clean", etc. # 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 constant PRINT_VERBOSE => 2; use constant PRINT_NOALERTLOG => 0; use constant PRINT_ALERTLOG => 1; # read_or_verify_message use constant MSG_READ => 0; use constant MSG_VERIFY => 1; # Other components may use acfslib modules. # This helps to identify the product we are. use constant USM_PROD_ACFS => "prod_acfs"; use constant USM_PROD_OKA => "prod_oka"; use constant USM_PROD_AFD => "prod_afd"; use constant USM_PROD_OLFS => "prod_olfs"; # to identify the product. Default is ACFS our ($USM_CURRENT_PROD) = USM_PROD_ACFS; 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 sub lib_trace { my ($msg_id) = shift(@_); # PRINT_ERROR, PRINT_INFORM my ($msg) = shift(@_); my (@arg_array) = @_; if( $_ORA_USM_TRACE_ENABLED == 1){ lib_inform_print_noalert( $msg_id, $msg, @arg_array); } return USM_SUCCESS; } # # connect to the ASM instance # sub lib_asm_connect { my ($dbh); my (%session_mode); my ($driver) = 'dbi:Oracle:'; my ($usr) = ''; my ($pswd) = ''; lib_trace( 9176, "Entering '%s'", "la connect"); # $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 development 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."); } } lib_trace( 9178, "Return code = %s", "USM_FAIL"); return USM_FAIL; } lib_trace( 9177, "Return from '%s'", "la connect"); return $dbh; } # # connect to the ASM instance # sub lib_asm_disconnect { my ($dbh); lib_trace( 9176, "Entering '%s'", "la disconnect"); if (defined($dbh)) { $dbh->disconnect(); } lib_trace( 9177, "Return from '%s'", "la 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; lib_trace( 9176, "Entering '%s'", "la enable volume"); # ASM returns select data in upper case and so our comparisons have to # match case. $diskgroup_uc = uc($diskgroup); $volume_uc = uc($volume); $qry = "SELECT NAME_KFVOL,STATE_KFVOL FROM X\$kfvol xvols " . "WHERE xvols.device_kfvol = '$ENV{_ORA_VOLUME_DEVICE}' " . "AND xvols.filenum_kfvol <> 0"; $sth = asm_select_stmt($dbh, $qry); lib_trace( 9183, "Query = '%s'", $qry); while (defined ($row = asm_fetch_row($sth))) { if ( $row->{'NAME_KFVOL'} eq $volume_uc ) { $found_volume = 1; if ($row->{'STATE_KFVOL'} != 1 ) { # 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; } if( $return_val == USM_SUCCESS){ lib_trace( 9178, "Return code = %s", "USM_SUCCESS"); }elsif( $return_val == USM_FAIL){ lib_trace( 9178, "Return code = %s", "USM_FAIL"); }else{ lib_trace( 9178, "Return code = %s", "$return_val"); } lib_trace( 9177, "Return from '%s'", "la enable volume"); return $return_val } # end asm_enable_volume # lib_asm_disable_volume # # If the specified volume is not ASM disabled - disable it. # # The caller must have verified that the diskgroup is mounted. # sub lib_asm_disable_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; lib_trace( 9176, "Entering '%s'", "la disable volume"); # ASM returns select data in upper case and so our comparisons have to # match case. $diskgroup_uc = uc($diskgroup); $volume_uc = uc($volume); $qry = "SELECT NAME_KFVOL,STATE_KFVOL FROM X\$kfvol xvols " . "WHERE xvols.device_kfvol = '$ENV{_ORA_VOLUME_DEVICE}' " . "AND xvols.filenum_kfvol <> 0"; $sth = asm_select_stmt($dbh, $qry); lib_trace( 9183, "Query = '%s'", $qry); while (defined ($row = asm_fetch_row($sth))) { if ( $row->{'NAME_KFVOL'} eq $volume_uc ) { $found_volume = 1; if ($row->{'STATE_KFVOL'} != 0 ) { # disable the volume lib_inform_print(9999, "Disabling volume '$volume' on diskgroup '$diskgroup'." ); $qry = "alter diskgroup $diskgroup disable volume $volume"; $return_val = asm_do_stmt($dbh, $qry); if ($return_val == USM_FAIL) { lib_error_print(9999, "disable of volume '$volume' failed."); } } last; } } eval { $sth->finish(); }; if (! $found_volume) { lib_error_print(9105, "Volume '%s' not found in '%s'.", $volume, $diskgroup); $return_val = USM_FAIL; } if( $return_val == USM_SUCCESS){ lib_trace( 9178, "Return code = %s", "USM_SUCCESS"); }elsif( $return_val == USM_FAIL){ lib_trace( 9178, "Return code = %s", "USM_FAIL"); }else{ lib_trace( 9178, "Return code = %s", "$return_val"); } lib_trace( 9177, "Return from '%s'", "la disable volume"); return $return_val } # end asm_disable_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); lib_trace( 9176, "Entering '%s'", "la mount dg"); # 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"; lib_trace( 9183, "Query = '%s'", $qry); $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); lib_trace( 9178, "Return code = %s", "USM_FAIL"); lib_trace( 9177, "Return from '%s'", "la mount dg"); return USM_FAIL; } if ($dg_state eq 'DISMOUNTED') { lib_inform_print(9107, "ASM mounting diskgroup '%s'.", $diskgroup); $qry = "alter diskgroup $diskgroup mount"; lib_trace( 9183, "Query = '%s'", $qry); $return_val = asm_do_stmt($dbh, $qry); if ($return_val == USM_FAIL) { lib_error_print(9108, "ASM mount of diskgroup '%s' failed.", $diskgroup); lib_trace( 9178, "Return code = %s", "USM_FAIL"); lib_trace( 9177, "Return from '%s'", "la mount dg"); return USM_FAIL; } } if( $return_val == USM_SUCCESS){ lib_trace( 9178, "Return code = %s", "USM_SUCCESS"); }elsif( $return_val == USM_FAIL){ lib_trace( 9178, "Return code = %s", "USM_FAIL"); }else{ lib_trace( 9178, "Return code = %s", "$return_val"); } lib_trace( 9177, "Return from '%s'", "la mount dg"); 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; lib_trace( 9176, "Entering '%s'", "lc drivers installed"); 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) { lib_trace( 9178, "Return code = %s", "0"); lib_trace( 9177, "Return from '%s'", "lc drivers installed"); return 0; } lib_trace( 9178, "Return code = %s", "1"); lib_trace( 9177, "Return from '%s'", "lc drivers installed"); return 1; } # end lib_check_drivers_installed # lib_check_any_driver_installed # sub lib_check_any_driver_installed { my ($driver); lib_trace( 9176, "Entering '%s'", "lc check any 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)) { lib_trace( 9178, "Return code = %s", "1"); lib_trace( 9177, "Return from '%s'", "lc check any driver"); return 1; } } lib_trace( 9178, "Return code = %s", "0"); lib_trace( 9177, "Return from '%s'", "lc check any driver"); return 0; } # end lib_check_any_driver_installed # lib_check_uninstall_required # sub lib_check_uninstall_required { my ($previous_install_detected_msg) = @_; return lib_osds_check_uninstall_required($previous_install_detected_msg); } # end lib_check_uninstall_required # lib_count_drivers_loaded # sub lib_count_drivers_loaded { my ($driver); my ($num_drivers_loaded) = 0; lib_trace( 9176, "Entering '%s'", "count drivers"); foreach $driver ($DRIVER_COMPONENTS[OKS_IDX], $DRIVER_COMPONENTS[AVD_IDX], $DRIVER_COMPONENTS[OFS_IDX]) { if (lib_osds_check_driver_loaded($driver)) { $num_drivers_loaded++; } } lib_trace( 9178, "Return code = %s", "$num_drivers_loaded"); lib_trace( 9177, "Return from '%s'", "count drivers"); 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); lib_trace( 9176, "Entering '%s'", "check drivers loaded"); $num_drivers_loaded = lib_count_drivers_loaded(); if ($num_drivers_loaded != 3) { $return_val = 0; } else { $return_val = 1; } lib_trace( 9178, "Return code = %s", "$return_val"); lib_trace( 9177, "Return from '%s'", "check drivers loaded"); 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(); lib_trace( 9176, "Entering '%s'", "check progress"); if (! -d $TMPDIR) { mkpath ($TMPDIR, 0777) or warn ("failed to create $TMPDIR: $!"), $retcode = 1; if ($retcode eq 1) { lib_trace( 9178, "Return code = %s", "CHECK_IN_PROGRESS_NO"); lib_trace( 9177, "Return from '%s'", "check progress"); return CHECK_IN_PROGRESS_NO; } } lib_trace( 9182, "Variable '%s' has value '%s'", "TMPDIR", "$TMPDIR"); $pname = build_check_filename($TMPDIR, $fname); lib_trace( 9182, "Variable '%s' has value '%s'", "pname", "$pname"); 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; lib_trace( 9178, "Return code = %s", "$retcode"); lib_trace( 9177, "Return from '%s'", "check progress"); 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; lib_trace( 9178, "Return code = %s", "CHECK_IN_PROGRESS_YES"); lib_trace( 9177, "Return from '%s'", "check progress"); 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)) { lib_trace( 9178, "Return code = %s", "CHECK_IN_PROGRESS_TIMEOUT"); $retcode = CHECK_IN_PROGRESS_TIMEOUT; } else { lib_trace( 9178, "Return code = %s", "CHECK_IN_PROGRESS_YES"); $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; } lib_trace( 9178, "Return code = %s", "CHECK_IN_PROGRESS_NO"); $retcode = CHECK_IN_PROGRESS_NO; } lib_trace( 9177, "Return from '%s'", "check progress"); 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 lib_trace( 9176, "Entering '%s'", "lib end check progress"); $pname = build_check_filename($TMPDIR, $fname); lib_trace( 9182, "Variable '%s' has value '%s'", "pname", "$pname"); if (-e $pname) { unlink $pname or warn ("failed to remove $pname: $!"), $retcode = 1; } lib_trace( 9178, "Return code = %s", "$retcode"); lib_trace( 9177, "Return from '%s'", "lib end check progress"); 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 { lib_trace( 9176, "Entering '%s'", "ga admin name"); if (defined($CACHED_ASMADMIN)) { lib_trace( 9178, "Return code = %s", "CACHED_ASMADMIN"); lib_trace( 9177, "Return from '%s'", "ga admin name"); return $CACHED_ASMADMIN; } # In dev env get the ASM group from the install config file because # osdbagrp doesn't return the primary group for aime* on farm machines if ( defined($ENV{ADE_VIEW_ROOT}) ) { my $paramgrp = getParam("ORA_ASM_GROUP"); if ((!$paramgrp eq "") && (lib_osds_validate_asmadmin_group($paramgrp) == USM_SUCCESS)) { $CACHED_ASMADMIN = $paramgrp; lib_trace( 9178, "Return code = %s", "$paramgrp"); lib_trace( 9177, "Return from '%s'", "ga admin name"); return $paramgrp; } } my ($asmadmin) = 'dba'; # AFD 9508 message differs from ACFS my ($err_str_9508) = "ACFS installation aborted (component %s)."; if ($USM_CURRENT_PROD eq USM_PROD_AFD) { $err_str_9508 = "AFD installation aborted (component %s)."; } # 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(9508, "$err_str_9508", $COMMAND); # This is unrecoverable - fail. Unfortunately, there's no graceful way # of failing without major redesign - and this is a VERY rare event. lib_trace( 9178, "Return code = %s", "USM_FAIL"); lib_trace( 9177, "Return from '%s'", "ga admin name"); exit USM_FAIL; } } if (lib_osds_validate_asmadmin_group($asmadmin) == USM_FAIL) { lib_error_print(9190, "User group '%s' does not exist.", $asmadmin); lib_error_print(9508, "$err_str_9508", $COMMAND); lib_trace( 9178, "Return code = %s", "USM_FAIL"); lib_trace( 9177, "Return from '%s'", "ga admin name"); exit USM_FAIL; } $CACHED_ASMADMIN = $asmadmin; lib_trace( 9178, "Return code = %s", "$CACHED_ASMADMIN"); lib_trace( 9177, "Return from '%s'", "ga admin name"); 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); lib_trace( 9176, "Entering '%s'", "ld usm drvs"); # 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); lib_trace( 9178, "Return code = %s", "USM_FAIL"); lib_trace( 9177, "Return from '%s'", "ld usm drvs"); return USM_FAIL; } } } lib_trace( 9177, "Return from '%s'", "ld usm drvs"); lib_trace( 9178, "Return code = %s", "USM_SUCCESS"); 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. lib_trace( 9176, "Entering '%s'", "lmount"); 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); lib_trace( 9178, "Return code = %s", "USM_FAIL"); lib_trace( 9177, "Return from '%s'", "lmount"); return USM_FAIL; } lib_trace( 9177, "Return from '%s'", "lmount"); 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; lib_trace( 9176, "Entering '%s'", "lrec stale mnts"); # 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); lib_trace( 9178, "Return code = %s", "USM_FAIL"); lib_trace( 9177, "Return from '%s'", "lrec stale mnts"); 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); lib_trace( 9178, "Return code = %s", "$recovered_list"); lib_trace( 9177, "Return from '%s'", "lrec stale mnts"); 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, $sub_command) = @_; # This should probably be defined in the osds_ variants for when other # platforms are supported and/if they have other locations for this file. my ($oracleadvmconf_loc) = "/etc/modprobe.d/oracleadvm.conf"; my ($driver); my ($return_val) = USM_SUCCESS; lib_trace( 9176, "Entering '%s'", "uld usm drvs"); 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)) { if ($driver eq $DRIVER_COMPONENTS[AVD_IDX]) { # Check if ACFS Remote mode 3 is setup (SHMI). if ( -e $oracleadvmconf_loc ) { my $mode = `grep asm_acfsr_mode $oracleadvmconf_loc | cut -d= -f2`; if ($mode == 3) { # Execute 'advmutil shim_disconn' if(0 != system("/sbin/advmutil shim_disconn")) { # Something went wrong. $return_val = USM_FAIL; last; } } } } # If this is 'acfsroot install', we pretend to succeed. # This way the new drivers get installed but we exit with # USM_REBOOT_RECOMMENDED. After the reboot, the new drivers are running. if (($COMMAND eq "acfsroot") && ($sub_command eq "install")) { $return_val = USM_SUCCESS; } else { $return_val = USM_FAIL; lib_error_print (9118, "Driver %s in use - cannot unload.", $driver); last; } } $return_val = lib_osds_unload_driver($driver, $install_files_loc); if ($return_val != USM_SUCCESS) { lib_error_print(9119, "Driver %s failed to unload.", $driver); $return_val = USM_REBOOT_RECOMMENDED; last; } } } if( $return_val == USM_SUCCESS){ lib_trace( 9178, "Return code = %s", "USM_SUCCESS"); }elsif( $return_val == USM_FAIL){ lib_trace( 9178, "Return code = %s", "USM_FAIL"); }else{ lib_trace( 9178, "Return code = %s", "$return_val"); } lib_trace( 9177, "Return from '%s'", "uld usm drvs"); 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. # Prints to alert log. # sub lib_inform_print { my (@arg_array) = @_; common_print(PRINT_INFORM, PRINT_ALERTLOG, @arg_array); return USM_SUCCESS; } # Doesn't print to alert logs sub lib_inform_print_noalert { my (@arg_array) = @_; common_print(PRINT_INFORM, PRINT_NOALERTLOG, @arg_array); return USM_SUCCESS; } # lib_verbose_print # If $verbose is set, messages will be displayed. # Prints to alert log. # sub lib_verbose_print { my (@arg_array) = @_; common_print(PRINT_VERBOSE, PRINT_ALERTLOG, @arg_array); return USM_SUCCESS; } # Doesn't print to alert log. sub lib_verbose_print_noalert { my (@arg_array) = @_; common_print(PRINT_VERBOSE, PRINT_NOALERTLOG, @arg_array); return USM_SUCCESS; } # Prints to alert log. sub lib_error_print { my (@arg_array) = @_; common_print(PRINT_ERROR, PRINT_ALERTLOG, @arg_array); return USM_SUCCESS; } # Doesn't print to alert log. sub lib_error_print_noalert { my (@arg_array) = @_; common_print(PRINT_ERROR, PRINT_NOALERTLOG, @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 # 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. # lib_trace( 9176, "Entering '%s'", "lis mnt avail"); $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=""; } lib_trace( 9179, "Command executed: '%s', output = '%s'", "$cmd", "$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; } lib_trace( 9178, "Return code = %s", "$avail"); lib_trace( 9177, "Return from '%s'", "lis mnt avail"); 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 ($alertlog_print) = shift(@_); # PRINT_NOALERTLOG, PRINT_ALERTLOG my ($message_id) = shift(@_); my ($message) = shift(@_); my (@message_args) = @_; my ($debug) = $ENV{'ACFS_DEBUG'}; my ($myclsecho); 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_ERROR)) { # do not print if the message is not an error and the -s option is used. return USM_SUCCESS; } if (!$VERBOSE && ($message_type == PRINT_VERBOSE)) { # do not print verbose message, if -v is not used return USM_SUCCESS; } # clsecho uses '-l' option to print message to alert.log # Based on caller's intent, call clsecho accordingly. # if OKA product, use appropriate message file if ($USM_CURRENT_PROD eq USM_PROD_OKA) { if ($alertlog_print == PRINT_ALERTLOG) { $myclsecho = "$CLSECHO_OKA -l"; } else { $myclsecho = "$CLSECHO_OKA"; } } # if AFD product, use appropriate message file elsif ($USM_CURRENT_PROD eq USM_PROD_AFD) { # If wrapper not present, use clsecho.bin directly. # NOTE: clsecho wrapper is not created for Windows. #if windows use clsecho.exe otherwise use .bin if (!($OSNAME eq "Windows_NT" || $OSNAME eq "MSWin32")) { if (! -e $CLSECHO) { $CLSECHO_AFD = $CLSECHO_BIN_AFD; } } if ($alertlog_print == PRINT_ALERTLOG) { $myclsecho = "$CLSECHO_AFD -l"; } else { $myclsecho = "$CLSECHO_AFD"; } } # Bug 23320181: Printing error to the console in case of OLFS instead of # clsecho as it requires various environment variables to be set. This is # because OLFS is installed when GI stack is not up, so files, like clsecho, # which need instantiation are not ready yet. elsif ($USM_CURRENT_PROD eq USM_PROD_OLFS) { my $arg; foreach $arg (@message_args) { #Replace any '%s' with the actual argument. $arg =~ s/"//g; $message =~ s/%s/$arg/; } print "$message\n"; return; } else { if ($alertlog_print == PRINT_ALERTLOG) { $myclsecho = "$CLSECHO_ACFS -l"; } else { $myclsecho = "$CLSECHO_ACFS"; } } # 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; } # We strip any back ticks from the message. # A single back tick will generate errors: # sh: -c: line 0: unexpected EOF while looking for matching ``' # sh: -c: line 1: syntax error: unexpected end of file # Multiple (even mumber) back ticks will generate errors: # sh: : command not found $message =~ s/`//g; system("$myclsecho \"$message\""); return; } if (defined($ADE_VIEW_ROOT)) { # If we are in a development environment, we compare the message # in the program to the message in acfsus.msg and flag a mis-match. read_or_verify_message($message_id, $message, MSG_VERIFY); } 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 "; } if ($alertlog_print == PRINT_ALERTLOG) { # 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; # Ignore any other argument if any. $echo_string .= " --"; # Send the message # log the error if ($message_type == PRINT_ERROR) { # acfsutil command line option switch. my ($optc); $optc = '-'; $optc = '/' if ($Config{osname} =~ /Win/); my (@array) = split / /, $arg_list; my ($text) = read_or_verify_message($message_id, undef, MSG_READ); my ($arg); foreach $arg (@array) { # Replace any '%s' with the actual argument. $arg =~ s/"//g; $text =~ s/%s/$arg/; } } system ("$myclsecho $echo_string"); } # end common_print # verify_message # # If $which == MSG_VERIFY: # Verify that the message in the print statement matches the message catalog. # Called only when ADE_VIEW_ROOT is set in the environment # # if $which == MSG_READ: # Return the message text to the caller. # Called to log the error to the ACFS command log. # sub read_or_verify_message { my ($message_id, $message, $which) = @_; if ($USM_CURRENT_PROD eq USM_PROD_OKA) { # verify that the message matches the (okaus.msg) catalog open CATALOG, "<$ORACLE_HOME/usm/mesg/okaus.msg" or die "can't open msg file: $!"; } elsif ($USM_CURRENT_PROD eq USM_PROD_AFD) { # verify that the message matches the (afdus.msg) catalog open CATALOG, "<$ORACLE_HOME/usm/mesg/afdus.msg" or die "can't open msg file: $!"; } else { # 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 ($which == MSG_READ) { return $acfsus_msg[1]; } if ($acfsus_msg[1] ne $message) { print "message $message_id format mismatch:\n"; if ($USM_CURRENT_PROD eq USM_PROD_OKA) { print "okaus.msg:\t>$acfsus_msg[1]<\n"; } elsif ($USM_CURRENT_PROD eq USM_PROD_AFD) { print "afdus.msg:\t>$acfsus_msg[1]<\n"; } else { print "acfsus.msg:\t>$acfsus_msg[1]<\n"; } print "$COMMAND:\t>$message<\n"; } last; } } close (CATALOG); } # end read_or_verify_message # # used for "sql alter diskgroup.... # sub asm_do_stmt { my ($dbh, $qry) = @_; my ($sth); my ($rv) = USM_SUCCESS; lib_trace( 9176, "Entering '%s'", "ado stmt"); lib_trace( 9183, "Query = '%s'", $qry); $rv = $dbh->do($qry); warn "$DBI::errstr\n" unless defined ($rv); if (!defined ($rv)) { $rv = USM_FAIL; } if( $rv == USM_SUCCESS){ lib_trace( 9178, "Return code = %s", "USM_SUCCESS"); }elsif( $rv == USM_FAIL){ lib_trace( 9178, "Return code = %s", "USM_FAIL"); }else{ lib_trace( 9178, "Return code = %s", "$rv"); } lib_trace( 9177, "Return from '%s'", "ado stmt"); return ($rv); } # # used for sql select # sub asm_select_stmt { my ($dbh, $qry) = @_; my ($sth); my ($rv); lib_trace( 9176, "Entering '%s'", "asel stmt"); lib_trace( 9183, "Query = '%s'", $qry); eval { $sth = $dbh->prepare($qry); }; if (!defined ($sth)) { lib_trace( 10, "USM_FAIL: sth not defined"); lib_trace( 9178, "Return code = %s", "USM_FAIL"); lib_trace( 9177, "Return from '%s'", "asel stmt"); return USM_FAIL; } eval { $rv = $sth->execute(); }; warn "$DBI::errstr\n" unless defined ($rv); if (!defined($rv)) { lib_trace( 9178, "Return code = %s", "USM_FAIL"); lib_trace( 9177, "Return from '%s'", "asel stmt"); return USM_FAIL; } lib_trace( 9177, "Return from '%s'", "asel stmt"); 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) = @_; lib_trace( 9176, "Entering '%s'", "bldchk fname"); $name =~ s/\//_/g; $name =~ s/\\/_/g; my ($full_file_name) = catfile($tmp_dir, $name . "_check"); lib_trace( 9178, "Return code = %s", "$full_file_name"); lib_trace( 9177, "Return from '%s'", "bldchk fname"); 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 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; lib_trace( 9176, "Entering '%s'", "adusm drvsres"); if ($OSNAME eq "Windows_NT" || $OSNAME eq "MSWin32") { if( $ADE_VIEW_ROOT eq "") { #A shiphome should be using this values for owner and asmgrp. Example: #owner:NT AUTHORITY\SYSTEM:rwx,pgrp:Administrators:r-x,other::r--,user:ST-ADC\aime1:r-x $asmgrp = "Administrators"; $owner = "NT AUTHORITY\\SYSTEM"; } else { #in the other hand, a farm job should have an ACL like the one below: # owner:ST-ADC\aime1:rw-,pgrp::rw-,other::r--,user:ST-ADC\aime1:r-x #So the next values are the correct ones. $asmgrp = ""; $owner = $CRSDUSER; } } if ((($CRSDUSER eq "") || ($asmgrp eq "")) && !($OSNAME eq "Windows_NT" || $OSNAME eq "MSWin32")) { # getParam failed. lib_error_print(9375, "Adding ADVM/ACFS drivers resource failed."); lib_trace( 9178, "Return code = %s", "USM_FAIL"); lib_trace( 9177, "Return from '%s'", "adusm drvsres"); return USM_FAIL; } 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"); lib_trace( 9179, "Command executed: '%s', output = '%s'", "$crsctl", "$ret"); if ($ret != 0) { lib_error_print(9375, "Adding ADVM/ACFS drivers resource failed."); lib_trace( 9178, "Return code = %s", "USM_FAIL"); lib_trace( 9177, "Return from '%s'", "adusm drvsres"); return USM_FAIL; } else { lib_inform_print(9376, "Adding ADVM/ACFS drivers resource succeeded."); lib_trace( 9178, "Return code = %s", "USM_SUCCESS"); lib_trace( 9177, "Return from '%s'", "adusm drvsres"); 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); lib_trace( 9176, "Entering '%s'", "deusm drvsres"); lib_trace( 9179, "Command executed: '%s', output = '%s'", "@cmd", "$ret"); if ($ret != 0) { lib_error_print(9377, "Deleting ADVM/ACFS drivers resource failed."); lib_trace( 9178, "Return code = %s", "USM_FAIL"); lib_trace( 9177, "Return from '%s'", "deusm drvsres"); return USM_FAIL; } else { lib_inform_print(9378, "Deleting ADVM/ACFS drivers resource succeeded."); lib_trace( 9178, "Return code = %s", "USM_SUCCESS"); lib_trace( 9177, "Return from '%s'", "deusm drvsres"); 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); lib_trace( 9176, "Entering '%s'", "stusm drvsres"); lib_trace( 9179, "Command executed: '%s', output = '%s'", "@cmd", "$ret"); if ($ret != 0) { lib_error_print(9379, "Starting ADVM/ACFS drivers resource failed."); lib_trace( 9178, "Return code = %s", "USM_FAIL"); lib_trace( 9177, "Return from '%s'", "stusm drvsres"); return USM_FAIL; } else { lib_inform_print(9380, "Starting ADVM/ACFS drivers resource succeeded."); lib_trace( 9178, "Return code = %s", "USM_SUCCESS"); lib_trace( 9177, "Return from '%s'", "stusm drvsres"); 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; lib_trace( 9176, "Entering '%s'", "ures exists"); lib_trace( 9182, "Variable '%s' has value '%s'", "resource", "$resource"); if ($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; } } if( $ret == USM_SUCCESS){ lib_trace( 9178, "Return code = %s", "USM_SUCCESS"); }elsif( $ret == USM_FAIL){ lib_trace( 9178, "Return code = %s", "USM_FAIL"); }else{ lib_trace( 9178, "Return code = %s", "$ret"); } lib_trace( 9177, "Return from '%s'", "urest exists"); 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; lib_trace( 9176, "Entering '%s'", "modu drvrs res"); lib_trace( 9182, "Variable '%s' has value '%s'", "CRSDUSER", "$CRSDUSER"); lib_trace( 9182, "Variable '%s' has value '%s'", "asmgrp", "$asmgrp"); #if running in Windows if ($OSNAME eq "Windows_NT" || $OSNAME eq "MSWin32") { if( $ADE_VIEW_ROOT eq "") { #A shiphome should be using this values for owner and asmgrp. Example: #owner:NT AUTHORITY\SYSTEM:rwx,pgrp:Administrators:r-x,other::r--,user:ST-ADC\aime1:r-x $asmgrp = "Administrators"; $owner = "NT AUTHORITY\\SYSTEM"; } else { #in the other hand, a farm job should have an ACL like the one below: #owner:ST-ADC\aime1:rw-,pgrp::rw-,other::r--,user:ST-ADC\aime1:r-x #So the next values are the correct ones. $asmgrp = ""; $owner = $CRSDUSER; } } else { #running in a no-windows environment if (($CRSDUSER eq "") || ($asmgrp eq "")) { # getParam failed. lib_error_print(9381, "Modification of ADVM/ACFS drivers resource failed."); lib_trace( 9178, "Return code = %s", "USM_FAIL"); lib_trace( 9177, "Return from '%s'", "modu drvrs res"); return USM_FAIL; } } @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); lib_trace( 9179, "Command executed: '%s', output = '%s'", "@cmd", "$ret"); $ret1 = ($ret) ? 1 : $ret1; if ($ret1 != 0) { lib_error_print(9381, "Modification of ADVM/ACFS drivers resource failed."); lib_trace( 9178, "Return code = %s", "USM_FAIL"); lib_trace( 9177, "Return from '%s'", "modu drvrs res"); return USM_FAIL; } lib_inform_print(9382, "Modification of ADVM/ACFS drivers resource succeeded."); lib_trace( 9178, "Return code = %s", "USM_SUCCESS"); lib_trace( 9177, "Return from '%s'", "modu drvrs res"); return USM_SUCCESS; } sub getParam { my $var = $_[0]; my $paramFhdl; my ($paramfile); lib_trace( 9176, "Entering '%s'", "getparm"); if (!defined($ENV{ADE_VIEW_ROOT})) { $paramfile = File::Spec->catfile ($ORACLE_HOME, "crs", "install", "crsconfig_params"); } else { $paramfile = File::Spec->catfile ($ORACLE_HOME, "has_work_global", "crsconfig_params"); } if (! -e $paramfile) { # Silence this error message in dev env incase someone runs acfsroot # directly without CRS if (!defined($ENV{ADE_VIEW_ROOT})) { lib_error_print(10285, "Pathname '%s' does not exist.", $paramfile); } lib_trace( 9178, "Return code = %s", "(NULL)"); lib_trace( 9177, "Return from '%s'", "getparm"); 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 ); lib_trace( 9178, "Return code = %s", "$val"); lib_trace( 9177, "Return from '%s'", "getparm"); return $val; } } close ( $paramFhdl ); lib_trace( 9178, "Return code = %s", "(NULL)"); lib_trace( 9177, "Return from '%s'", "getparm"); 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 $echoRetVal = 0; my $args = shift; # acfsroot passed args as one string my @args = split ( / /, $args ); my $fName = shift(@args); # name of library function to execute lib_trace( 9176, "Entering '%s'", "lrun func"); lib_trace( 9182, "Variable '%s' has value '%s'", "fName", "$fName"); if ( $fName eq "libRunFuncEchoRetVal" ) { # Enable callers to get values returned by functions. E.g. # lib_get_asm_admin_name returns a string with containing the asm # admin name. By printing the string out the caller (typically # clns*Agent) can slurp it up. $echoRetVal = 1; $fName = shift(@args); # name of library function to execute } my $fP; # pointer to function my $retVal; # Make sure a function name is specified if ( ! $fName ) { lib_error_print(9999, "ERROR: Internal error: lib_run_func function name not specified"); lib_trace( 9178, "Return code = %s", "-1"); lib_trace( 9177, "Return from '%s'", "lrun func"); 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 "); lib_trace( 9178, "Return code = %s", "-1"); lib_trace( 9177, "Return from '%s'", "lrun func"); return -1; } # Call the function specifying the remaining arguments $retVal = $fP->( @args ); # Print the return value? print "libRunFuncRetVal=$retVal\n" if ( $echoRetVal ); # Don't return the called function's return value here. Some of # the functions we call might return strings and things which # wouldn't be well received by our caller who probably wants to # exit with an int. lib_trace( 9178, "Return code = %s", "0"); lib_trace( 9177, "Return from '%s'", "lrun func"); return 0; } # This function is used by 'acfsroot patch_verify' to compare patch # files to installed files. # # Please note that this function ignores certain line changes that occur # during the patching and install process and should not be used for # general file comparison purposes. sub md5compare { my ($source,$target) = @_; my ($return_code) = USM_SUCCESS; my $fh1; #File in source if(!open($fh1, $source)) { lib_inform_print (9999,"Can't open source '$source': $!"); next; } binmode($fh1); my $md51 = Digest::MD5->new; while (<$fh1>) { next if ($_ =~ /^ORA_CRS_HOME=/); next if ($_ =~ /^set CRS_HOME=/); $md51->add($_); } close($fh1); my $digest1 = $md51->b64digest; my $fh2; #File in install if(!open($fh2, "$target")) { lib_inform_print (9999,"Can't open target '$target': $!"); next; } binmode($fh2); my $md52 = Digest::MD5->new; while (<$fh2>) { next if ($_ =~ /^ORA_CRS_HOME=/); next if ($_ =~ /^set CRS_HOME=/); $md52->add($_); } close($fh2); my $digest2 = $md52->b64digest; if ($digest1 ne $digest2) { $return_code = USM_FAIL; } return $return_code; } sub lib_are_same_file { my ($source, $target) = @_; my $return_code = lib_osds_are_same_file( $source, $target); return $return_code; } sub lib_is_number { my ($var) = @_; return ($var eq $var+0); } # lib_is_local_container # # call into lib_osds_is_local_container # sub lib_is_local_container { return lib_osds_is_local_container(); } # isODA # Check for the existence of /opt/oracle/extapi/64/oak/liboak.*.so to determine # if this is an ODA. # In case the Jorge of the future needs to update this, the 'current' version # can be found in has/install/crsconfig/crsutils.pm # sub isODA { my @OAKLIB = glob(catfile("/opt","oracle","extapi","64","oak","liboak.*.so")); if (@OAKLIB) { return 1; } else { return 0; } } # The OPC dom0 is identified by checking for the existence # of the /etc/nimbula_version file. # In case the Jorge of the future needs to update this, the 'current' version # can be found in has/install/crsconfig/crsutils.pm sub isOPCDom0 { my $file = catfile("/etc", "nimbula_version"); if ( -e $file) { return 1; } else { return 0; } } sub isDomainClass { my $class = getParam("CLUSTER_CLASS"); if ($class eq "" || $class ne "DOMAINSERVICES") { return 0; } else { return 1; } } sub isMemberClass { my $class = getParam("CLUSTER_CLASS"); if ($class eq "" || $class ne "MEMBER") { return 0; } else { return 1; } } sub isSHMI { my $class = getParam("CLUSTER_CLASS"); if ($class eq "" || $class ne "SHMI") { return 0; } else { return 1; } } # The crsutils version of this function checks $CFG->params{'ODA_CLUSTER_TYPE'} # I don't see that variable in crsconfig_params.sbs but I am going to assume # it will be there in an ODA setup as the OPC variant is there. sub isODADomu { my $oda_type = getParam("ODA_CLUSTER_TYPE"); if ($oda_type eq "" || $oda_type ne "dom-u") { return 0; } else { return 1; } } # Check OPC_CLUSTER_TYPE sub isOPCDomu { my $opc_type = getParam("OPC_CLUSTER_TYPE"); if ($opc_type eq "" || $opc_type ne "dom-u") { return 0; } else { return 1; } } sub lib_acfs_remote_supported { return lib_osds_acfs_remote_supported(@_); } sub lib_acfs_remote_installed { return lib_osds_acfs_remote_installed(@_); } sub lib_acfs_remote_loaded { return lib_osds_acfs_remote_loaded(@_); } 1;