MINI MINI MANI MO
#
#
# osdsacfslib.pm
#
# Copyright (c) 2007, 2017, 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;
use Cwd;
use Cwd qw(chdir);
use Cwd 'abs_path';
use File::Basename;
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
lib_get_oracle_home
lib_oracle_drivers_conf
lib_get_drivers_version
trim
$COMMAND
$SILENT
$VERBOSE
$_ORA_USM_TRACE_ENABLED
$_ORA_USM_TRACE_LEVEL
$ACFSUTIL
$USM_CURRENT_PROD
$_ORACLE_HOME
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
lib_uncompress_all_driver_files
);
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 ($_ORACLE_HOME) = "";
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";
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_get_oracle_home(); # Define _ORACLE_HOME variable
# 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) = '/'; # According to perl DBI and DBD docs, this allows for
# connecting to Oracle as the local OS authenticated user.
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 <user>" 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 <view>"
# 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.
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 = <FILE>;
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 test user* 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 = <ASMADMIN>;
close (ASMADMIN);
if ((!defined($asmadmin)) || ($asmadmin eq ""))
{
if( defined($ADE_VIEW_ROOT)){
# We 're in a view, solve this cleanly.
# This code should run in all platforms.
$asmadmin = getgrgid((getpwuid( $<))[3]);
if( (!defined( $asmadmin)) || ( $asmadmin eq "")){
lib_error_print( 10610, "Failed to get current user information.");
lib_trace( 9178, "Return code = %s", "USM_FAIL");
lib_trace( 9177, "Return from '%s'", "ga admin name");
exit USM_FAIL;
}
}else{
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 = <INFO>)
{
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 = <REGISTRY>;
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) = @_;
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 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
{
if (lib_check_kernel(@_) &&
lib_check_config())
{
return 1;
}
return 0;
} # 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="<No Error Text Returned>";
}
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;
}
if ((! -e $CLSECHO) || ($SILENT))
{
common_print_noclsecho($message_id, $message, @message_args);
return;
}
# 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";
}
}
# Print error to console if wrapper clsecho is
# not present or SILENT flag is set.
# Bug 24682019: In Clone scenarios, clsecho may be present
# but with incorrect ORACLE_HOME. In such cases, OUI will
# invoke AFD commands with silent option. If silent flag
# is set, print to console directly instead of using clsecho.
#
elsif ($USM_CURRENT_PROD eq USM_PROD_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)
{
common_print_noclsecho($message_id, $message, @message_args);
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: <cmd>: 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
# common_print_noclsecho
sub common_print_noclsecho
{
my $message_id = shift(@_);
my $message = shift(@_);
my @message_args = @_;
my $arg;
foreach $arg (@message_args)
{
#Replace any '%s' with the actual argument.
$arg =~ s/"//g;
$message =~ s/%s/$arg/;
}
if ($USM_CURRENT_PROD eq USM_PROD_OKA)
{
print "OKA-$message_id: $message\n";
}
elsif ($USM_CURRENT_PROD eq USM_PROD_AFD)
{
print "AFD-$message_id: $message\n";
}
elsif ($USM_CURRENT_PROD eq USM_PROD_OLFS)
{
print "OLFS-$message_id: $message\n";
}
else
{
print "ACFS-$message_id: $message\n";
}
} # end common_print_noclsecho
# 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 = <CATALOG>)
{
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:
#<DOMAIN>\<USER>: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:<DOMAIN>\<USER>:rw-,pgrp::rw-,other::r--,user:<DOMAIN>\<USER>: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 (<CRSCTL>)
{
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:<DOMAIN>\<USER>: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:<DOMAIN>\<USER>:rw-,pgrp::rw-,other::r--,user:<DOMAIN>\
#<USER>: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)
{
$paramfile = File::Spec->catfile
($ORACLE_HOME, "has_work", "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 <acfslib::function()> [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
{
if ($configuration{islocal})
{
if ($configuration{islocal} eq "yes")
{
return 1;
}
else
{
return 0;
}
}
my $result = lib_osds_is_local_container();
if ($result)
{
$configuration{islocal} = "yes";
}
else
{
$configuration{islocal} = "no";
}
return $result;
}
# 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");
$class = uc $class;
if ($class eq "" || $class ne "DOMAINSERVICES")
{
return 0;
}
else
{
return 1;
}
}
sub isMemberClass
{
my $class = getParam("CLUSTER_CLASS");
$class = uc $class;
if ($class eq "" || $class ne "MEMBER")
{
return 0;
}
else
{
return 1;
}
}
sub isSHMI
{
my $class = getParam("CLUSTER_CLASS");
$class = uc $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 osds_acfsr_supported(@_);
}
sub lib_acfs_remote_installed
{
return osds_acfsr_installed(@_);
}
sub lib_acfs_remote_loaded
{
return osds_acfsr_loaded(@_);
}
#Uncompress all products' driver files in the passed in path
#(e.g. USM/AFD/OLFS/OKA etc.)
sub lib_uncompress_all_driver_files
{
lib_osds_uncompress_driver_files(@_);
}
# There are 3 different ways of getting ORACLE_HOME:
# 1) From the environment. This may be set by rootcrs or the user.
# 2) From the current location of the command.
# 3) From the crsconfig_params file.
# deinstall tree - Oracle provides a package of software
# that contains all the tools necessary to remove the
# Oracle software - this is called the deinstall.
# In the event that you remove the Grid Home from
# your system, this is the standalone deinstall,
# although it currently doesn't work. Our deinstall
# is part of this throught the deinstall mapfiles.
# There are 5 different uses of the env ORACLE_HOME:
# 1) From the deinstall tree - if the Grid Home that is being removed
# is gone, it will point to non-existent Grid Home.
# 2) From the deinstall tree, pointing to the Grid Home to remove.
# 3) From the rootcrs.pl during install.
# 4) From the rootcrs.pl during deinstall, but not from the deinstall tree.
# 5) And the final one, manually during our patching procedures.
# In all cases, we don't fully trust the passed in ORACLE_HOME, as the
# user may have incorrectly set it. We also don't really want to force
# the user to set it, except in certain situations.
# So, we rely on a heuristic, which should catch all cases:
# 1) Find out where we are running from. In most cases, acfsroot.pl
# will run from ORACLE_HOME/lib. (The only case this isn't true for
# is an ACFS only patch or a command line manual install.)
# 2) Find out what the passed in ORACLE_HOME is.
# 3) See if either discovered or passed in ORACLE_HOME has a crsconfig_params
# file.
# 4) Get ORACLE_HOME from the params file.
# 5) Use the param file ORACLE_HOME for comparison if it exists, or the env
# if it doesn't.
# 6) Convert both the passed in or params ORACLE_HOME (if it exists) and the
# discovered "ORACLE_HOME" to an absolute path, which will
# correctly dereference all symlinks in the path. Compare these
# two values. If they match, then use the passed in\params ORACLE_HOME,
# and assume that it is correct (most times it will be coming from
# rootcrs). This will cover most normal installs, and will
# catch symlinks.
# 7) If they do not match, then use the discovered value. This is
# because during deinstall, one of two things can happen:
# a) We are running from the deinstall tree, and the ORACLE_HOME
# that is passed in is not valid. We want to use our tools out
# of the deinstall tree.
# b) We are running from the deinstall tree, and the ORACLE_HOME
# that is passed in is valid, but it doesn't matter to us,
# we still use our tools out of the deinstall tree.
# And during install, one of 3 things can happen:
# a) We are running from rootcrs, and the value matches.
# b) We are running from the command line during a manual patch\install
# and the user has the incorrect ORACLE_HOME specified. In
# this case, assume we are running from the GridHome. (However,
# this case will be covered by getting it from the params file.)
# Bug 11833948 was a bug where the OH was a symlink, yet we used the
# real path of the directory. This resulted in not being able to contact
# the ASM instance for some reason. Changing the OH to the symlinked
# path made things work again.
sub lib_get_oracle_home
{
my ($dir) = $0; # $0 is built in acfstoolsdriver.{sh,bat}
my $discovered_ORACLE_HOME; # the ORACLE_HOME from bin location.
my $param_ORACLE_HOME; # the ORACLE_HOME in the param file.
my $env_ORACLE_HOME; # the ORACLE_HOME in the env.
my $compare_ORACLE_HOME; # the final choice we are comparing against.
my $paramfile = ""; # The location of the parameter file.
lib_trace( 9176, "Entering '%s'", "get ora home");
if ((defined($ENV{SRCHOME})) && ($ENV{SRCHOME} ne ""))
{
# We're in a development environment, we'll use that $ORACLE_HOME.
$_ORACLE_HOME = $ENV{ORACLE_HOME};
lib_trace( 9182, "Variable '%s' has value '%s'", "ORACLE_HOME",
"$_ORACLE_HOME");
return;
}
# We're in a production environment.
# This file lives in $ORACLE_HOME/lib - drop the trailing /lib
$dir =~ s/\/lib$//;
# This is where we are running from.
$discovered_ORACLE_HOME = $dir;
# Remove any trailing '\n's.
chomp($discovered_ORACLE_HOME);
# Now the env location, for safety.
if (defined($ENV{ORACLE_HOME}))
{
$env_ORACLE_HOME = $ENV{ORACLE_HOME};
chomp($env_ORACLE_HOME);
}
# Now we try to get the information from the params file,
# just in case it matches somewhere else.
# We use this param file in a few places now... should we
# have a function to access it and get info?
# Most times we are running out of the grid home, or a place with
# a crsconfig_params.
$paramfile = $discovered_ORACLE_HOME . "crs/install/crsconfig_params";
if ( ! -e $paramfile )
{
# Try the location of the env ORACLE_HOME for kicks.
$paramfile = $env_ORACLE_HOME . "/crs/install/crsconfig_params";
}
if ( -e $paramfile )
{
open PARAMS, $paramfile;
while (<PARAMS>)
{
if (m/^ORACLE_HOME/)
{
my @LINE = split /=/;
$param_ORACLE_HOME = $LINE[$#LINE];
# Remove any trailing '\n's
chomp($param_ORACLE_HOME);
last;
}
}
close (PARAMS);
}
# Now, compare the env and the param file. If they are different, use
# the param file (assuming it is not null).
# If they are the same, use the param file.
# If we couldn't get to the param file, use the env location.
if (defined($param_ORACLE_HOME) )
{
$compare_ORACLE_HOME = $param_ORACLE_HOME;
lib_verbose_print(9500, "Location of Oracle Home is '%s' " .
"as determined from the internal configuration data",
$compare_ORACLE_HOME);
}
else #param is not defined.
{
if (defined($env_ORACLE_HOME))
{
$compare_ORACLE_HOME = $env_ORACLE_HOME;
lib_verbose_print(9501, "Location of Oracle Home is '%s' " .
"as determined from the ORACLE_HOME " .
"environment variable",
$compare_ORACLE_HOME);
}
}
# Now, compare the abs_path of all dirs found and use the one we trust.
if ((lib_is_abs_path($compare_ORACLE_HOME)) eq
(lib_is_abs_path($discovered_ORACLE_HOME)))
{
# This will take into account symlinks.
$ENV{ORACLE_HOME} = $compare_ORACLE_HOME;
}
else
{
# They differed (after abs_path), so assume the user
# had something wrong somewhere, and use what we know
# to be true.
# Or the user is running deinstall, where ORACLE_HOME can point
# to some invalid location not consistent with where we are
# running out of.
# This is okay - the system location of our files won't
# change, and that's where we want to remove things from.
# OUI can handle cleaning up the ORACLE_HOME, wherever it is.
$ENV{ORACLE_HOME} = $discovered_ORACLE_HOME;
lib_verbose_print(9502, "Location of Oracle Home is '%s' " .
"as determined from the location of the Oracle " .
"library files",
$discovered_ORACLE_HOME);
}
$_ORACLE_HOME = $ENV{ORACLE_HOME};
lib_trace(9182,"Variable '%s' has value '%s'", "ORACLE_HOME", "$_ORACLE_HOME");
lib_trace(9177,"Return from '%s'", "get ora home");
}
# During a driver load oracledrivers.conf file will be created with
# the version of the driver
#
# Eg: [<Driver>]
# <Driver>InstalledVersion = XXYY
# <Driver>AvailableVersion = XXYY
# <Driver>InstalledRelease = XXYY
# <Driver>AvailableRelease = XXYY
# <Driver>InstalledBugList = XXYY,YYXX
# <Driver>AvailableBugList = XXYY,YYXX
# <Driver>InstalledBugHash = XXYY
# <Driver>AvailableBugHash = XXYY
#
# NOTE: This file will be cleaned up on GI uninstall
sub lib_oracle_drivers_conf
{
my $clean = @_; # 0 write confpath, 1 delete driver data
my $driver;
my $confpath = "/etc/"; # Sol, AIX
my $ref = lib_get_drivers_version();
my %drvdata;
my $fhandle;
my $prevdata = "";
my @drvlist = ("oka","afd","olfs","acfs");
my $drvls;
if (!defined $ref)
{
if ($clean == 0)
{
return USM_FAIL;
}
}
else
{
%drvdata = %{$ref};
}
if ($USM_CURRENT_PROD eq USM_PROD_OKA)
{
$driver = "oka";
@drvlist = ("afd","olfs","acfs");
}
elsif ($USM_CURRENT_PROD eq USM_PROD_AFD)
{
$driver = "afd";
@drvlist = ("oka","olfs","acfs");
}
elsif ($USM_CURRENT_PROD eq USM_PROD_OLFS)
{
$driver = "olfs";
@drvlist = ("oka","afd","acfs");
}
else
{
$driver = "acfs";
@drvlist = ("oka","afd","olfs");
}
# Get configuration file path
if ($Config{osname} =~ /Win/)
{
$confpath = "C:\\WINDOWS\\system32\\drivers\\";
}
elsif ($Config{osname} =~ /lin/)
{
$confpath .= "sysconfig/";
}
# else /etc
if (!-d $confpath)
{
lib_inform_print(9295, "failed to open file %s",$confpath);
return USM_FAIL;
}
# Include output to /etc/sysconfig/oracledrivers.conf
$confpath .= "oracledrivers.conf";
$driver = uc ($driver); #uppercase
if (-e $confpath)
{
open ($fhandle,"<",$confpath) or do
{
lib_error_print(9295,"failed to open file %s",$confpath);
return USM_FAIL;
};
# Remove $driver data and re-write.
foreach (<$fhandle>)
{
next if ($_ =~ /$driver/ || $_ =~ /^\s*$/);
foreach $drvls (@drvlist)
{
# Save only other oracle drivers data
# This will make sure other trash data is removed
$drvls = uc($drvls);
chomp($_);
$prevdata .= $_ . "\n" if ($_ =~ /^$drvls/ || $_ eq "[${drvls}]");
}
}
}
lib_inform_print (9294,"updating file %s",$confpath);
open ($fhandle,">",$confpath) or do
{
lib_error_print(9295,"failed to open file %s",$confpath);
return USM_FAIL;
};
print $fhandle "$prevdata";
if ($clean)
{
# This is the action triggered by *root uninstall
# We just want to delete the driver data being uninstalled
close ($fhandle);
unlink ($confpath) if (-z $confpath);
return USM_SUCCESS;
}
if (%drvdata)
{
print $fhandle ("[${driver}]\n");
print $fhandle ($driver."InstalledBuildNo = $drvdata{Installed}{BuildNo}\n");
print $fhandle ($driver."AvailableBuildNo = $drvdata{Available}{BuildNo}\n");
print $fhandle ($driver."InstalledVersion = $drvdata{Installed}{Version}\n");
print $fhandle ($driver."AvailableVersion = $drvdata{Available}{Version}\n");
print $fhandle ($driver."InstalledBugList = $drvdata{Installed}{BugList}\n");
print $fhandle ($driver."AvailableBugList = $drvdata{Available}{BugList}\n");
print $fhandle ($driver."InstalledBugHash = $drvdata{Installed}{BugHash}\n");
print $fhandle ($driver."AvailableBugHash = $drvdata{Available}{BugHash}\n");
print $fhandle ($driver."InstalledKModule = $drvdata{Installed}{KERNVERS}\n");
print $fhandle ($driver."AvailableKModule = $drvdata{Available}{KERNVERS}\n");
print $fhandle ($driver."OS_KernelVersion = $drvdata{OS}{KERNVERS}\n");
}
close ($fhandle);
return USM_SUCCESS;
}
# lib_get_drivers_version
#
# Get the currently installed and the oracle_home version
# Return:
# Failure = Undefined
# Success = Hash of driver data
#
# Hash example
#
sub lib_get_drivers_version
{
my %drvdata; # (Version,Release,BugList,BugHash,KERNELVERS)
my @array;
my $kernelvers;
my $oskvers;
my @drvpath; # (/lib/modules,ORACLE_HOME/install...)
my $prod; # Product Eg: oks, afd, etc.
my $fhandle;
my $grepstr = "";
my $findstr = "";
my $driver = ""; # Driver to parse
my $type = "Installed";
if ($USM_CURRENT_PROD eq USM_PROD_OKA)
{
$prod = "oracka";
}
elsif ($USM_CURRENT_PROD eq USM_PROD_AFD)
{
$prod = "oracleafd";
}
elsif ($USM_CURRENT_PROD eq USM_PROD_OLFS)
{
$prod = "oracleolfs";
}
else
{
$prod = "oracleoks";
}
# OSD handling
if ($Config{osname} =~ /Win/)
{
return (lib_osds_get_drivers_version);
}
elsif ($Config{osname} =~ /aix/)
{
$kernelvers = `oslevel -s`;
$oskvers = $kernelvers;
chomp($kernelvers);
$driver = $prod.".ext ";
$drvpath[0]= "/usr/lib/drivers/".$driver;
$drvpath[1] = lib_osds_get_home_driver_path($_ORACLE_HOME."/usm".
"/install", lib_osds_get_os_type(undef), `uname -p`);
}
elsif ($Config{osname} =~ /sol/)
{
my ($kver) = `uname -s`;
chomp($kver);
$oskvers = `uname -r`;
$kernelvers = $kver . " " . $oskvers;
chomp($kernelvers);
$driver = $prod;
open($fhandle, "find /usr/kernel/drv/`isainfo -k`/ | grep $driver |");
$drvpath[0]= <$fhandle>;
close($fhandle);
$drvpath[1] = lib_osds_get_home_driver_path ($_ORACLE_HOME."/usm".
"/install", `uname -r`, `isainfo -k`);
}
else
{
$oskvers = `uname -r`;
$driver = $prod.".ko";
open($fhandle, "find /lib/modules/ | grep $driver |");
$drvpath[0] = <$fhandle>;
close($fhandle);
$drvpath[1] = lib_osds_get_home_driver_path ("${_ORACLE_HOME}/usm/install",
lib_osds_get_os_type(undef), `uname -i`, $oskvers, undef);
}
# Uncompress oracle_home driver files
lib_uncompress_all_driver_files($drvpath[1]);
$drvpath[1] .= "/$driver";
chomp ($drvpath[1]);
if (defined $kernelvers)
{
$drvdata{$type}{"KERNVERS"} = $kernelvers;
$drvdata{"Available"}{"KERNVERS"} = $kernelvers;
}
if (defined $oskvers)
{
$drvdata{"OS"}{"KERNVERS"} = $oskvers;
}
return undef if (! defined $drvpath[0] || ! defined $drvpath[1] ||
! defined $driver);
foreach $driver (@drvpath)
{
open ($fhandle, "strings $driver |");
foreach (<$fhandle>)
{
if ($_ =~ /vermagic/ && $Config{osname} =~ /lin/)
{
# vermagic=2.6.18-8.el5 SMP mod_unload 686 REGPARM 4KSTACKS gcc-4.1
$drvdata{$type}{"KERNVERS"} = (split(/ /, $_))[0];
$drvdata{$type}{"KERNVERS"} =~ s/vermagic=//;
}
elsif ($_ =~ /USM BUILD LABEL: (\S+)/)
{
# The usm_label_info[] global contains:
# usm_ade_label_info_make_header.pl: USM BUILD LABEL: USM_MAIN_LINUX.X64
# We don't want to export to the user the label info so we strip
# that from the driver_version, leaving only the date.
# so, USM_MAIN_LINUX_090112 becomes 090112.
@array = split (/_/, $1);
$drvdata{$type}{"BuildNo"} = $array[3];
# Returning release version
$drvdata{$type}{"Version"} = $array[1];
# Check if the label is patched
if ($drvdata{$type}{"Version"} =~ /^((\d+\.){3}\d+)(\.\d*(.*))$/) {
# It is, strip the patch number
# 11.2.0.4.0ACFSPSU becomes 11.2.0.4 (ACFSPSU)
# untouched otherwise
$drvdata{$type}{"Version"} = "$1 ($4).";
}
}
elsif ($_ =~ /TXN BUGS:/)
{
# usm_ade_label_info_make_header.pl: TXN BUGS: 1345543,14579183
$drvdata{$type}{"BugList"} = (split(": ",$_))[-1];
chomp ($drvdata{$type}{"BugList"});
if ($drvdata{$type}{"BugList"} =~ /BUGS/)
{
$drvdata{$type}{"BugList"} = "NoTransactionInformation";
}
}
elsif ($_ =~ /TXN BUGS HASH:/)
{
# usm_ade_label_info_make_header.pl: TXN BUGS HASH: 1345579183
$drvdata{$type}{"BugHash"} = (split(": ",$_))[-1];
chomp ($drvdata{$type}{"BugHash"});
}
# got all of our info?
if (defined($drvdata{$type}{"BuildNo"}) &&
defined($drvdata{$type}{"Version"}) &&
defined($drvdata{$type}{"BugList"}) &&
defined($drvdata{$type}{"BugHash"}) &&
defined($drvdata{$type}{"KERNVERS"}))
{
last; # Go to next driver
}
}
close($fhandle);
$type = "Available";
}
# Return an undefined variable if we don't have all of our info.
# That signals failure to the caller.
return undef if (!defined($drvdata{"Installed"}{"KERNVERS"})||
!defined($drvdata{"Installed"}{"BuildNo"}) ||
!defined($drvdata{"Installed"}{"Version"}) ||
!defined($drvdata{"Installed"}{"BugList"}) ||
!defined($drvdata{"Installed"}{"BugHash"}) ||
!defined($drvdata{"Available"}{"BuildNo"}) ||
!defined($drvdata{"Available"}{"Version"}) ||
!defined($drvdata{"Available"}{"BugList"}) ||
!defined($drvdata{"Available"}{"BugHash"}) ||
!defined($drvdata{"OS"}{"KERNVERS"}));
return (\%drvdata);
}
# Check if configuration machine is ready to install and load ACFS/ADVM drivers
# return true or false
sub lib_check_config()
{
if (lib_is_local_container())
{
lib_inform_print_noalert(9559, "Running in a local container: '%s'", "yes");
return 0;
}
if (!lib_osds_check_config())
{
return 0;
}
return 1;
}
# Check if machine supports ACFS/ADVM drivers
# return true or false
sub lib_check_kernel()
{
if (!lib_osds_usm_supported() ||
!lib_osds_check_kernel())
{
return 0;
}
return 1;
}
1;
OHA YOOOO