# Copyright (c) 2004, 2009, Oracle and/or its affiliates. All rights reserved. # # NAME # asmcmdsys - ASM CoMmanD line interface (Sample Module) # # DESCRIPTION # This module is a dummy/sample module that provides a working # template for module additions. # # NOTES # usage: asmcmdcore [-p] [command] # # MODIFIED (MM/DD/YY) # sanselva 12/29/09 - XbranchMerge sanselva_lrg-4067759 from main # sanselva 12/17/09 - XbranchMerge sanselva_bug-8683273 from main # sanselva 11/30/09 - XbranchMerge sanselva_lrg-4226821 from main # sanselva 06/24/09 - correct syntax for command startup # canuprem 06/18/09 - options for dsset should be mutually exclusive. # gayavenk 06/11/09 - Fix pathname issue in dsset # shagarw 06/11/09 - add param to setds to ignore the input ds. # canuprem 05/29/09 - modify dsset and dsget # sanselva 05/14/09 - spbackup,spmove,spcopy issue when target directory # heyuen 04/17/09 - add dsset dsget help # heyuen 04/20/09 - add spbackup # sanselva 04/12/09 - ASMCMD long options and consistency # heyuen 04/06/09 - update spmove to use asmcmdsys_dualget # heyuen 03/23/09 - remove iostat # heyuen 01/30/09 - update offline commands # heyuen 02/09/09 - fix asmcmd_spset # heyuen 12/03/08 - add spmove, spset, spget # heyuen 10/24/08 - change zones to regions # heyuen 10/14/08 - use dynamic modules # heyuen 09/19/08 - fix ctrl-c in iostat # heyuen 09/17/08 - complete path for spcopy # heyuen 08/02/08 - fix startup/shutdown msgs # heyuen 07/28/08 - use command properties array # heyuen 07/17/08 - fix messages, rewrite iostat # heyuen 05/14/08 - add spcopy # heyuen 05/19/08 - startup restricted # heyuen 05/12/08 - enable iostat continuously # heyuen 04/15/08 - bug 6935431, reorder help # heyuen 03/26/08 - bug 6753856: fix shutdown hang # heyuen 03/17/08 - enable -g for iostat # heyuen 02/21/08 - disable iostat for non mounted disks # heyuen 09/20/07 - creation # ############################################################################ # ############################ Functions List ################################# # ############################################################################# package asmcmdsys; require Exporter; our @ISA = qw(Exporter); our @EXPORT = qw(asmcmdsys_init %asmcmdsys_cmds ); use strict; use Getopt::Long qw(:config no_ignore_case bundling); use asmcmdglobal; use asmcmdshare; use asmcmdbase; use List::Util qw[min max]; use File::Find; ####################### ASMCMDSYS Global Constants ###################### our ($ASMCMDSYS_SQLPLUS) = "$ENV{'ORACLE_HOME'}/bin/sqlplus -S / as sysasm"; ####################### ASMCMDSYS Global Variables ###################### our (%asmcmdsys_lsop_header) = ('name' ,'Group_Name', 'operation' ,'Dsk_Num', 'state' ,'State', 'power' ,'Power', ); our (%asmcmdsys_cmds) = (lsop => {no_instance => 'True' }, shutdown => {flags => {'abort'=>'abortOperations', 'immediate'=>'immediate'} }, spcopy => {no_instance => 'True', flags => {'u'=>'updateGPnP'} }, spmove => {no_instance => 'True' }, startup => {flags => {'nomount'=>'noMount', 'restrict'=>'restrictedMode', 'pfile=s'=>'parameterFile'} }, spset => {no_instance => 'True' }, spget => {no_instance => 'True' }, dsset => {flags => {'normal'=>'scopeBoth', 'profile'=>'scopeGPnP', 'f' =>'force', 'parameter'=>'scopeASMInstance'} }, dsget => {flags => {'normal'=>'scopeBoth', 'profile'=>'scopeGPnP', 'f' =>'force', 'parameter'=>'scopeASMInstance'} }, spbackup => {no_instance => 'True' } ); # PLSQL constants my ($PLSQL_NUMBER) = 22; sub is_asmcmd { return 1; } ######## # NAME # asmcmdsys_init # # DESCRIPTION # This function initializes the asmcmdsys module. For now it simply # registers its callbacks with the asmcmdglobal module. # # PARAMETERS # None # # RETURNS # Null # # NOTES # Only asmcmdcore_main() calls this routine. ######## sub init { # All of the arrays defined in the asmcmdglobal module must be # initialized here. Otherwise, an internal error will result. push (@asmcmdglobal_command_callbacks, \&asmcmdsys_process_cmd); push (@asmcmdglobal_help_callbacks, \&asmcmdsys_process_help); push (@asmcmdglobal_command_list_callbacks, \&asmcmdsys_get_asmcmd_cmds); push (@asmcmdglobal_is_command_callbacks, \&asmcmdsys_is_cmd); push (@asmcmdglobal_is_wildcard_callbacks, \&asmcmdsys_is_wildcard_cmd); push (@asmcmdglobal_syntax_error_callbacks, \&asmcmdsys_syntax_error); push (@asmcmdglobal_no_instance_callbacks, \&asmcmdsys_is_no_instance_cmd); push (@asmcmdglobal_error_message_callbacks, \&asmcmdsys_error_msg); push (@asmcmdglobal_signal_exception_callbacks, \&asmcmdsys_signal_exception); %asmcmdglobal_cmds = (%asmcmdglobal_cmds, %asmcmdsys_cmds); #Perform ASMCMD consistency check if enabled if($asmcmdglobal_hash{'consistchk'} eq 'y') { if(!asmcmdshare_check_option_consistency(%asmcmdsys_cmds)) { exit 1; } } } ######## # NAME # asmcmdsys_process_cmd # # DESCRIPTION # This routine calls the appropriate routine to process the command # specified by $asmcmdglobal_hash{'cmd'}. # # PARAMETERS # dbh (IN) - initialized database handle, must be non-null. # # RETURNS # 1 if command is found in the asmcmdsys module; 0 if not. # # NOTES # Only asmcmdcore_shell() calls this routine. ######## sub asmcmdsys_process_cmd { my ($dbh) = @_; my ($succ) = 0; # Get current command from global value, which is set by # asmcmdsys_parse_asmcmd_args()and by asmcmdcore_shell(). my ($cmd) = $asmcmdglobal_hash{'cmd'}; # Declare and initialize hash of function pointers, each designating a # routine that processes an ASMCMDSYS command. my (%cmdhash) = ( startup => \&asmcmdsys_process_startup , shutdown => \&asmcmdsys_process_shutdown , lsop => \&asmcmdsys_process_lsop, spcopy => \&asmcmdsys_process_spcopy, spmove => \&asmcmdsys_process_spmove, spset => \&asmcmdsys_process_spset, spget => \&asmcmdsys_process_spget, dsset => \&asmcmdsys_process_dsset, dsget => \&asmcmdsys_process_dsget, spbackup => \&asmcmdsys_process_spbackup); if (defined ( $cmdhash{ $cmd } )) { # If user specifies a known command, then call routine to process it. # $cmdhash{ $cmd }->($dbh); $succ = 1; } return $succ; } ######## # NAME # asmcmdsys_process_startup # # DESCRIPTION # This function processes the asmcmd command startup. # # PARAMETERS # dbh (IN) - initialized database handle, must be non-null. # # RETURNS # Null. # # NOTES # Only asmcmdsys_process_cmd() calls this function. ######## sub asmcmdsys_process_startup { my (%args); my ($ret); my ($qry); my ($pfile); my ($sqlplus_stmt); # Get option parameters, if any. $ret = asmcmdsys_parse_int_args($asmcmdglobal_hash{'cmd'}, \%args); return unless defined ($ret); #bug 6994980 delete $ENV{'ENV'} if (defined($ENV{'ENV'})); $sqlplus_stmt = "$ASMCMDSYS_SQLPLUS"; $qry = "startup"; #nomount if (defined($args{'nomount'})) { $qry .= " nomount "; } if (defined($args{'restrict'})) { $qry .= " restrict "; } if (defined($args{'pfile'})) { $qry .= " pfile=" . $args{'pfile'}; } # untaint sqlplus $sqlplus_stmt =~ m/(.*)/; $sqlplus_stmt = $1; open SQLPLUS, "| $sqlplus_stmt"; print SQLPLUS $qry; close SQLPLUS; return; } ######## # NAME # asmcmdsys_process_shutdown # # DESCRIPTION # This function processes the asmcmd command shutdown. # # PARAMETERS # dbh (IN) - initialized database handle, must be non-null. # # RETURNS # Null. # # NOTES # Only asmcmdsys_process_cmd() calls this function. ######## sub asmcmdsys_process_shutdown { my ($dbh) = shift; my (%args); # Argument hash used by getopts(). # my ($ret); # asmcmdsys_parse_int_args() return value. # my ($qry); # SQL query statement. # my ($sqlplus_stmt); # Get option parameters, if any. $ret = asmcmdsys_parse_int_args($asmcmdglobal_hash{'cmd'}, \%args); return unless defined ($ret); #bug 6994980 delete $ENV{'ENV'} if (defined($ENV{'ENV'})); $sqlplus_stmt = "$ASMCMDSYS_SQLPLUS"; $qry = "SHUTDOWN "; if (defined($args{'immediate'})) { $qry .= "IMMEDIATE "; } if (defined($args{'abort'})) { $qry .= "ABORT "; } # untaint sqlplus $sqlplus_stmt =~ m/(.*)/; $sqlplus_stmt = $1; if (defined($dbh)) { asmcmdbase_disconnect($dbh); } open SQLPLUS, "| $sqlplus_stmt"; print SQLPLUS $qry; close SQLPLUS; return; } ######## # NAME # asmcmdsys_process_lsop # # DESCRIPTION # This function processes the asmcmd command lsop. # # PARAMETERS # dbh (IN) - initialized database handle, must be non-null. # # RETURNS # Null. # # NOTES # Only asmcmdsys_process_cmd() calls this function. ######## sub asmcmdsys_process_lsop { my ($dbh) = shift; my (@what , @from, $sth, @where, @order); my (%min_col_wid, $print_format, $printf_code, @what_print); my ($k, $v, @op_list, $h); my ($row); my (%args); my (@tmp_cols); push (@what, 'v$asm_diskgroup_stat.name as name'); push (@what, 'v$asm_operation.operation as operation'); push (@what, 'v$asm_operation.state as state'); push (@what, 'v$asm_operation.power as power'); push (@from, 'v$asm_operation'); push (@from, 'v$asm_diskgroup_stat'); push (@where, 'v$asm_operation.group_number = v$asm_diskgroup_stat.group_number'); $sth = asmcmdshare_do_construct_select($dbh, \@what, \@from, \@where, \@order); warn "$DBI::errstr\n" unless defined ($sth); @tmp_cols = @{$sth->{NAME}}; @what = (); foreach (@tmp_cols) { push (@what, "\L$_"); } #initialize the min_col_wid array foreach(@what) { $min_col_wid{$_} = 0; } while (defined($row = asmcmdshare_fetch($sth))) { my(%op_info) = (); while(($k, $v) = each(%{$row})) { $k =~ tr/[A-Z]/[a-z]/; $op_info{$k} = $v; $min_col_wid{$k} = max($min_col_wid{$k}, length($v)); } push (@op_list, \%op_info); } #get header length foreach (@what) { $min_col_wid{$_} = max($min_col_wid{$_}, length($asmcmdsys_lsop_header{$_})); } $print_format = ''; foreach (@what) { $print_format .= "%-$min_col_wid{$_}s "; } $print_format .= "\\n"; #print header if (!defined ($args{'H'}) ) { $printf_code = "printf \"$print_format\", "; @what_print = (); foreach (@what) { push (@what_print, "\'" . $asmcmdsys_lsop_header{$_} . "\'"); } $printf_code .= "(" . join (", ", @what_print) . ")"; eval $printf_code; } #print rows foreach $h (@op_list) { $printf_code = "printf \"$print_format\", "; @what_print = (); foreach (@what) { push (@what_print, "\'" . $h->{$_} . "\'"); } $printf_code .= "(" . join (", ", @what_print) . ")"; eval $printf_code; } return; } ######## # NAME # asmcmdsys_process_spcopy # # DESCRIPTION # This function processes the asmcmd command spcopy. # # PARAMETERS # dbh (IN) - initialized database handle, must be non-null. # # RETURNS # Null. # # NOTES # Only asmcmdsys_process_cmd() calls this function. ######## sub asmcmdsys_process_spcopy { my ($dbh) = shift; my ($src_path, $dst_path, $src_name, $dst_name); my ($sth); my ($hdl, $pblk, $fname, $ftyp, $blksz, $openmode); my (%norm, $ret); my ($update_gpnp) = 0; my ($pl_sql_number) = 22; my ($spfile_number) = 253; my (%args); my ($fileType, $blkSz, $fileSz); my ($client_mode) = 0; my (@eargs); # Get option parameters, if any. $ret = asmcmdsys_parse_int_args($asmcmdglobal_hash{'cmd'}, \%args); return unless defined ($ret); if (!defined($ARGV[0]) || !defined($ARGV[1])) { asmcmdsys_syntax_error($asmcmdglobal_hash{'cmd'}); return; } $src_path = $ARGV[0]; $src_path =~ /(.*)/; $src_path = $1; $src_name = $src_path; #Match the last part in the src_path which is source file name #seperator is '/' for linux path and '\' for NT $src_name =~ s,(.*/|.*\\)(.*)$,$2,; $dst_path = $ARGV[1]; # complete relative paths # paths begining with "/"(linux) or containing ":\" (NT) are OS paths if ($src_path !~ m':\\' and $src_path !~ m'^/') { $src_path = asmcmdshare_make_absolute($src_path); } if ($dst_path !~ m':\\' and $dst_path !~ m'^/') { # Target is ASM asmcmdsys_get_target_name($dbh,$src_name,$dst_path,\$dst_name); } else { # target is OS # if path exists it must be a directory if ( -d $dst_path ) { $dst_name = $dst_path . '/' . $src_name; } else { $dst_name = $dst_path; } } return if (!defined $src_path || !defined $dst_name); $update_gpnp = 1 if defined($args{'u'}); $update_gpnp = 0 if ($dst_name !~ m,^\+,); #do not update gpnp if #destination file is not in asm diskgroup $sth = $dbh->prepare(q{ begin dbms_diskgroup.getfileattr(:src_path, :fileType, :fileSz, :blkSz); end; }); # bind input params # $sth->bind_param( ":src_path", $src_path); # bind output params # $sth->bind_param_inout( ":fileType", \$fileType, $PLSQL_NUMBER); $sth->bind_param_inout( ":fileSz", \$fileSz, $PLSQL_NUMBER); $sth->bind_param_inout( ":blkSz", \$blkSz, $PLSQL_NUMBER); $ret = $sth->execute(); if (!defined $fileType || !defined $fileSz || !defined $blkSz) { @eargs = ( $src_path ); asmcmdshare_error_msg(8303, \@eargs); warn "$DBI::errstr\n"; return; } # reconnect asmcmdbase_disconnect($dbh) if defined ($dbh); $dbh = asmcmdbase_connect($asmcmdglobal_hash{'usr'}, $asmcmdglobal_hash{'pswd'}, $asmcmdglobal_hash{'ident'}, $asmcmdglobal_hash{'contyp'}); $sth = $dbh->prepare(q{ begin dbms_diskgroup.asmcopy(:src_path, :dst_name, :spfile_number, :fileType, :blkSz, :spfile_number2, :spfile_type, :client_mode); exception when others then raise; end; }); $sth->bind_param( ":src_path", $src_path); $sth->bind_param( ":dst_name", $dst_name); $sth->bind_param( ":spfile_number", $spfile_number); $sth->bind_param( ":fileType", $fileType); $sth->bind_param( ":blkSz", $blkSz); $sth->bind_param( ":spfile_number2", $spfile_number); $sth->bind_param( ":spfile_type", $fileType); $sth->bind_param( ":client_mode", $client_mode); $ret = $sth->execute(); if (!defined($ret)) { warn "$DBI::errstr\n"; return; } if ($update_gpnp) { $ret = asmcmdsys_spset($dbh, $dst_name); if (!defined($ret)) { warn "$DBI::errstr\n"; return; } } return; } ######## # NAME # asmcmdsys_process_spmove # # DESCRIPTION # This function processes the asmcmd command spmove. # # PARAMETERS # dbh (IN) - initialized database handle, must be non-null. # # RETURNS # Null. # # NOTES # Only asmcmdsys_process_cmd() calls this function. ######## sub asmcmdsys_process_spmove { my ($dbh) = shift; my ($attr, $val); my ($sth); my ($src_path, $dst_path, $src_name, $dst_name,$spfile); my (%norm, $ret); my ($update_gpnp) = 0; my ($pl_sql_number) = 22; my ($spfile_number) = 253; my (%args); my ($fileType, $blkSz, $fileSz); my ($client_mode) = 0; my ($gname); my (@eargs); # Get option parameters, if any. $ret = asmcmdsys_parse_int_args($asmcmdglobal_hash{'cmd'}, \%args); return unless defined ($ret); if (!defined($ARGV[0]) || !defined($ARGV[1])) { asmcmdsys_syntax_error($asmcmdglobal_hash{'cmd'}); return; } $src_path = $ARGV[0]; $src_path =~ /(.*)/; $src_path = $1; $src_name = $src_path; #Match the last part in the src_path which is source file name #seperator is '/' for linux path and '\' for NT $src_name =~ s,(.*/|.*\\)(.*)$,$2,; $dst_path = $ARGV[1]; # complete relative paths # paths begining with "/"(linux) or containing ":\" (NT) are OS paths if($src_path !~ m':\\' and $src_path !~ m'^/') { $src_path = asmcmdshare_make_absolute($src_path); } if($dst_path !~ m':\\' and $dst_path !~ m'^/') { # Target is ASM asmcmdsys_get_target_name($dbh,$src_name,$dst_path,\$dst_name); } else { # target is OS # if path exists it must be a directory if ( -d $dst_path ) { $dst_name = $dst_path . '/' . $src_name; } else { $dst_name = $dst_path; } } return if (!defined $src_path || !defined $dst_name); $sth = $dbh->prepare(q{ begin dbms_diskgroup.getfileattr(:src_path, :fileType, :fileSz, :blkSz); end; }); # bind input params # $sth->bind_param( ":src_path", $src_path); # bind output params # $sth->bind_param_inout( ":fileType", \$fileType, $PLSQL_NUMBER); $sth->bind_param_inout( ":fileSz", \$fileSz, $PLSQL_NUMBER); $sth->bind_param_inout( ":blkSz", \$blkSz, $PLSQL_NUMBER); $ret = $sth->execute(); if (!defined $fileType || !defined $fileSz || !defined $blkSz) { @eargs = ( $src_path ); asmcmdshare_error_msg(8303, \@eargs); warn "$DBI::errstr\n"; return; } # reconnect asmcmdbase_disconnect($dbh) if defined ($dbh); $dbh = asmcmdbase_connect($asmcmdglobal_hash{'usr'}, $asmcmdglobal_hash{'pswd'}, $asmcmdglobal_hash{'ident'}, $asmcmdglobal_hash{'contyp'}); $sth = $dbh->prepare(q{ begin dbms_diskgroup.asmcopy(:src_path, :dst_name, :spfile_number, :fileType, :blkSz, :spfile_number2, :spfile_type, :client_mode); exception when others then raise; end; }); $sth->bind_param( ":src_path", $src_path); $sth->bind_param( ":dst_name", $dst_name); $sth->bind_param( ":spfile_number", $spfile_number); $sth->bind_param( ":fileType", $fileType); $sth->bind_param( ":blkSz", $blkSz); $sth->bind_param( ":spfile_number2", $spfile_number); $sth->bind_param( ":spfile_type", $fileType); $sth->bind_param( ":client_mode", $client_mode); $ret = $sth->execute(); if (!defined($ret)) { warn "$DBI::errstr\n"; return; } # if the current spfile is the active one, update gpnp $spfile = asmcmdsys_dualget($dbh, 'asm_spfile'); if (!defined($spfile) or $spfile ne $dst_name) { $ret = asmcmdsys_spset($dbh, $dst_name); if (!defined($ret)) { warn "$DBI::errstr\n"; # UNDO the move if GPnP update is not successful if($dst_name =~ m'^\+') { %norm = asmcmdshare_normalize_path($dbh, $src_path, 0, \$ret); $gname = asmcmdshare_get_gname_from_gnum ($dbh, $norm{'gnum'}->[0]); asmcmdbase_rm_sql($dbh, $gname, $norm{'path'}->[0], 0); } else { #os File #Untaint $dst_name =~ m/(.*)/; $dst_name = $1; unlink("$dst_name"); } return; } } asmcmdbase_disconnect($dbh) if defined ($dbh); $dbh = asmcmdbase_connect($asmcmdglobal_hash{'usr'}, $asmcmdglobal_hash{'pswd'}, $asmcmdglobal_hash{'ident'}, $asmcmdglobal_hash{'contyp'}); #delete the source file if ($src_path =~ m'^\+') { # asm spfile %norm = asmcmdshare_normalize_path($dbh, $src_path, 0, \$ret); $gname = asmcmdshare_get_gname_from_gnum ($dbh, $norm{'gnum'}->[0]); asmcmdbase_rm_sql($dbh, $gname, $norm{'path'}->[0], 0); } else { #os spfile unlink($src_path); } } ######## # NAME # asmcmdsys_process_spbackup # # DESCRIPTION # This function processes the asmcmd command spbackup. # # PARAMETERS # dbh (IN) - initialized database handle, must be non-null. # # RETURNS # Null. # # NOTES # Only asmcmdsys_process_cmd() calls this function. ######## sub asmcmdsys_process_spbackup { my ($dbh) = shift; my (%args, $ret); my ($src_path, $dst_path,$src_name,$dst_name); my ($sth, $fileType, $fileSz, $blkSz); my ($spfile_type) = 31; my ($spbackup_type) = 33; my ($client_mode) = 1; my (@eargs); # Get option parameters, if any. $ret = asmcmdsys_parse_int_args($asmcmdglobal_hash{'cmd'}, \%args); return unless defined ($ret); if (!defined($ARGV[0]) || !defined($ARGV[1])) { asmcmdsys_syntax_error($asmcmdglobal_hash{'cmd'}); return; } $src_path = $ARGV[0]; $src_path =~ /(.*)/; $src_path = $1; $src_name = $src_path; #Match the last part in the src_path which is source file name #seperator is '/' for linux path and '\' for NT $src_name =~ s,(.*/|.*\\)(.*)$,$2,; $dst_path = $ARGV[1]; # complete relative paths # paths begining with "/"(linux) or containing ":\" (NT) are OS paths if($src_path !~ m':\\' and $src_path !~ m'^/') { $src_path = asmcmdshare_make_absolute($src_path); } if($dst_path !~ m':\\' and $dst_path !~ m'^/') { asmcmdsys_get_target_name($dbh,$src_name,$dst_path,\$dst_name); } else { # target is OS # if path exists it must be a directory if ( -d $dst_path ) { $dst_name = $dst_path . '/' . $src_name; } else { $dst_name = $dst_path; } } return if (!defined $src_path || !defined $dst_name); $sth = $dbh->prepare(q{ begin dbms_diskgroup.getfileattr(:src_path, :fileType, :fileSz, :blkSz); end; }); # bind input params # $sth->bind_param( ":src_path", $src_path); # bind output params # $sth->bind_param_inout( ":fileType", \$fileType, $PLSQL_NUMBER); $sth->bind_param_inout( ":fileSz", \$fileSz, $PLSQL_NUMBER); $sth->bind_param_inout( ":blkSz", \$blkSz, $PLSQL_NUMBER); $ret = $sth->execute(); if (!defined $fileType || !defined $fileSz || !defined $blkSz || $fileType != $spfile_type) { @eargs = ( $src_path ); asmcmdshare_error_msg(8303, \@eargs); warn "$DBI::errstr\n" if(defined($DBI::errstr)); return; } # reconnect asmcmdbase_disconnect($dbh) if defined ($dbh); $dbh = asmcmdbase_connect($asmcmdglobal_hash{'usr'}, $asmcmdglobal_hash{'pswd'}, $asmcmdglobal_hash{'ident'}, $asmcmdglobal_hash{'contyp'}); $sth = $dbh->prepare(q{ begin dbms_diskgroup.asmcopy(:src_path, :dst_name, :spfile_number, :fileType, :blkSz, :dst_fnum, :dst_ftype, :client_mode); exception when others then raise; end; }); $sth->bind_param(":src_path", $src_path); $sth->bind_param(":dst_name", $dst_name); $sth->bind_param(":spfile_number", 0); $sth->bind_param(":fileType", $fileType); $sth->bind_param(":blkSz", $blkSz); $sth->bind_param(":dst_fnum", 0); $sth->bind_param(":dst_ftype", $spbackup_type); $sth->bind_param(":client_mode", $client_mode); $ret = $sth->execute(); if (!defined($ret)) { warn "$DBI::errstr\n"; return; } asmcmdbase_disconnect($dbh) if defined ($dbh); $dbh = asmcmdbase_connect($asmcmdglobal_hash{'usr'}, $asmcmdglobal_hash{'pswd'}, $asmcmdglobal_hash{'ident'}, $asmcmdglobal_hash{'contyp'}); } ######## # NAME # asmcmdsys_get_target_name # # DESCRIPTION # This function gets the complete target file name when the # destination is a directory or diskgroup for spcopy/spmove/spbackup. # # PARAMETERS # dbh (IN) - initialized database handle, must be non-null. # src_name (IN) - spfile name # dst_path (IN) - destination path # dst_name (IN/OUT) - destination pathname # # RETURNS # Null. # # NOTES # ######## sub asmcmdsys_get_target_name { my ($dbh,$src_name,$dst_path,$dst_name) = @_; my (@paths, @ref_ids, @par_ids, @dg_nums, @entry_list, $name ,$ret); my (%norm); my (@eargs); # target is ASM # if target is a relative path, complete it to be a valid ASM path %norm = asmcmdshare_normalize_path($dbh, $dst_path, 1, \$ret); # path exists, must be a directory, and need to complete it with # the source name if ( $ret == 0 ) { # complete the path $dst_path = $norm{'path'}->[0]; @paths = @{ $norm{'path'} }; @ref_ids = @{ $norm{'ref_id'} }; @par_ids = @{ $norm{'par_id'} }; @dg_nums = @{ $norm{'gnum'} }; $name = $paths[0]; $name =~ s,.*/(.*)$,$1,; if($ref_ids[0] == -1) { @eargs = ($dst_path); asmcmdshare_error_msg(8014, \@eargs); return; } asmcmdshare_get_subdirs($dbh, \@entry_list, $dg_nums[0], $ref_ids[0], $par_ids[0], $name, undef, 0, 1); # if the directory is a diskgroup or a directory if ( ($ref_ids[0] != -1) && (($ref_ids[0] == $dg_nums[0] << 24 ) || ($entry_list[0]->{'alias_directory'} eq 'Y'))) { $$dst_name = $dst_path . '/' . $src_name; } elsif($entry_list[0]->{'alias_directory'} eq 'N') { $$dst_name = $dst_path; } else { @eargs = ($dst_path); asmcmdshare_error_msg(8014, \@eargs); return; } } else { $$dst_name = $dst_path; } } ######## # NAME # asmcmdsys_process_spget # # DESCRIPTION # This function processes the asmcmd command spget. # # PARAMETERS # dbh (IN) - initialized database handle, must be non-null. # # RETURNS # Null. # # NOTES # Only asmcmdsys_process_cmd() calls this function. ######## sub asmcmdsys_process_spget { my ($dbh) = shift; my ($spfile); $spfile = asmcmdsys_dualget($dbh, 'asm_spfile'); if (defined($spfile)) { print $spfile ."\n"; } } ######## # NAME # asmcmdsys_process_dsset # # DESCRIPTION # This function processes the asmcmd command dsset. # # USAGE # dsset [--normal] [--parameter] [--profile [-f]] pathname # # PARAMETERS # dbh (IN) - initialized database handle, must be non-null. # # RETURNS # Null. # # NOTES # second arg to gpnpsetds is false so that user supplied diskstring # gets pushed to gpnp profile. ######### sub asmcmdsys_process_dsset { my ($dbh) = @_; my ($ret, %args, $sth); my ($forced); my ($qry); my ($gpnptool); my ($gpnp_sign); my ($gpnp_edit); my ($gpnp_seq); my ($prof_path); my ($peer_path); my ($seq_num); my ($buf); my ($normal); my ($num); my ($test); my ($crs_home); my ($crsctl); my ($path) = 0; my (@buff_arr); # Problem: If dsset is used multiple times in a asmcmd session # pathname gets messed up. Reason being, the buffer cache used for # storing pathname in SQL is not cleared on every call. # This workaround could be removed if the PL/SQL buffer problem is # fixed. # reconnect asmcmdbase_disconnect($dbh) if defined ($dbh); $dbh = asmcmdbase_connect($asmcmdglobal_hash{'usr'}, $asmcmdglobal_hash{'pswd'}, $asmcmdglobal_hash{'ident'}, $asmcmdglobal_hash{'contyp'}); $ret = asmcmdsys_parse_int_args($asmcmdglobal_hash{'cmd'}, \%args); return unless defined ($ret); #path should be specified if (!defined($ARGV[0])) { asmcmdsys_syntax_error($asmcmdglobal_hash{'cmd'}); return; } $num = keys(%args); $forced = 0; $normal = 0; #dsset is executed in normal mode, if no option is specified if($num == 0) { $normal = 1; } if(defined($args{'normal'})) { $normal = 1; } if(defined($args{'f'})) { $forced = 1; } $path = $ARGV[0]; $path =~ s/,/','/g; #ASM instance is required for all the options other than '--profile -f' if(!defined($dbh)) { if(!(defined($args{'profile'}) && $forced == 1)) { asmcmdshare_error_msg(8311, undef); return; } } if($normal == 1) { #force option is not supported with normal optoin if($num > 1) { asmcmdsys_syntax_error($asmcmdglobal_hash{'cmd'}); return; } $qry = "alter system set asm_diskstring='" . $path . "' SCOPE=BOTH"; $ret = asmcmdshare_do_stmt($dbh,$qry); if (!defined ($ret)) { warn "$DBI::errstr\n"; } return; } if(defined($args{'profile'})) { # the only option allowed with profile is -f if($num > 2 || ($num == 2 && $forced != 1)) { asmcmdsys_syntax_error($asmcmdglobal_hash{'cmd'}); return; } if($forced == 1) { $crsctl = "$ENV{'ORACLE_HOME'}/bin/crsctl"; # The path in WIN is $ENV{'ORACLE_HOME'}/bin/crsctl.exe $crsctl .= ".exe" if($^O =~ /win/i); # Make sure the crsctl binary exists and can be executed. if (! -x $crsctl) { #If not, try at a second locaction. $crsctl = "$ENV{'ORACLE_HOME'}/rdbms/bin/crsctl"; # The path in WIN is $ENV{'ORACLE_HOME'}/bin/crsctl.exe $crsctl .= ".exe" if($^O =~ /win/i); if (! -x $crsctl) { asmcmdshare_error_msg(8313, \$crsctl); return; } } #untaint crsctl $crsctl =~ /([^\n^\r^\t]+)/; $crsctl = $1; my $css = "$crsctl check css"; eval { $buf = `$css`; }; if($@ ne '') { asmcmdshare_error_msg(8309, undef); return; } # Check for the number at CRS-xxxx in the output. if($buf =~ /([^\d]+)([^:]+)/) { my $status = $2; if(defined($status)) { if($status == 4529) { #output is CRS-4529: Cluster Synchronization Services is online asmcmdshare_error_msg(8308, undef); return; } } else { asmcmdshare_error_msg(8309, undef); return; } } else { asmcmdshare_error_msg(8309, undef); return; } $gpnptool = "$ENV{'ORA_CRS_HOME'}/bin/gpnptool"; #Adjust path for WIN $gpnptool .= ".exe" if($^O =~ /win/i); # Make sure the gpnptool binary exists and can be executed. if (! -x $gpnptool) { #If not, try at a second locaction. $gpnptool = "$ENV{'ORA_CRS_HOME'}/has/bin/gpnptool"; #Adjust path for WIN $gpnptool .= ".exe" if($^O =~ /win/i); if (! -x $gpnptool) { asmcmdshare_error_msg(8305, \$gpnptool); return; } } # The location of profile.xml is different for production and # dev environment now. The current environment is being determined by # checking whethe ADE_VIEW_ROOT is set or not. Bug 8579922 is filed # for this issue. $test = "$ENV{'ADE_VIEW_ROOT'}"; if($test eq '') { $crs_home = "$ENV{'ORA_CRS_HOME'}"; } else { $crs_home = "$ENV{'ORA_CRS_HOME'}/has_work"; } $prof_path = "$crs_home/gpnp/$ENV{'HOSTNAME'}/" . "profiles/peer/profile.xml"; #untaint prof_path $prof_path =~ /([^\n^\r^\t]+)/; $prof_path = $1; $peer_path = "$crs_home/gpnp/$ENV{'HOSTNAME'}/wallets/peer"; #untaint peer_path $peer_path =~ /([^\n^\r^\t]+)/; $peer_path = $1; # get the sequence number of the profile. $gpnp_seq = "$gpnptool getpval -p=$prof_path -prf_sq -o-"; #untaint gpnp_seq $gpnp_seq =~ /([^\n^\r^\t]+)/; $gpnp_seq = $1; eval { $seq_num = `$gpnp_seq`; }; if($@ ne '') { asmcmdshare_error_msg(8310, undef); } $seq_num = $seq_num + 3; $gpnp_edit = "$gpnptool edit -p=$prof_path -o=$prof_path -ovr " . "-asm_dis=$path -prf_sq=$seq_num"; #untaint gpnp_edit $gpnp_edit =~ /([^\n^\r^\t]+)/; $gpnp_edit = $1; eval { $buf = `$gpnp_edit 2>&1`; }; #check whether gpnp_edit succeeded. if ($@ ne '') { asmcmdshare_error_msg(8306, undef); return; } $gpnp_sign = "$gpnptool sign -p=$prof_path -o=$prof_path -ovr " . "-w=file:$peer_path"; #untaint gpnp_sign $gpnp_sign =~ /([^\n^\r^\t]+)/; $gpnp_sign = $1; # sign the gpnp profile once its edited. eval { @buff_arr = `$gpnp_sign 2>&1`; }; #check whether gpnp_sign succeeded. if ($@ ne '') { asmcmdshare_error_msg(8307, undef); return; } } else { $sth = $dbh->prepare(q{ begin dbms_diskgroup.gpnpsetds(:ds_path,0); exception when others then raise; end; }); $sth->bind_param(":ds_path", $path); $ret = $sth->execute(); if (!defined ($ret)) { warn "$DBI::errstr\n"; } } return; } #parameter option. if(defined($args{'parameter'})) { #no other option should be given when parameter option is suuplied. if($num != 1) { asmcmdsys_syntax_error($asmcmdglobal_hash{'cmd'}); return; } $qry = "alter system set asm_diskstring='" . $path . "' SCOPE=MEMORY"; $ret = asmcmdshare_do_stmt($dbh,$qry); if (!defined ($ret)) { warn "$DBI::errstr\n"; } return; } } ######## # NAME # asmcmdsys_process_dsget # # DESCRIPTION # This function processes the asmcmd command dsget. # # USAGE # dsget [[--normal] [--profile [-f]] [--parameter]] # # PARAMETERS # dbh (IN) - initialized database handle, must be non-null. # # RETURNS # Null. # ######### sub asmcmdsys_process_dsget { my ($dbh) = shift; my ($diskstring, $sth, $ret, $row, $val); my (@what, @from, @where); my ($num); my ($buf); my ($test); my ($parameter); my ($profile); my ($forced); my (%args); my ($gpnptool); my ($gpnp_exec); my ($prof_path); my ($crs_home); my ($crsctl); $ret = asmcmdsys_parse_int_args($asmcmdglobal_hash{'cmd'}, \%args); return unless defined ($ret); $num = keys(%args); $forced = 0; $parameter = 0; $profile = 0; if(defined($args{'f'})) { $forced = 1; } # normal mode should return both profile and parameter settings. # normal is the default option if(defined($args{'normal'}) || $num == 0) { if($num > 1) { asmcmdsys_syntax_error($asmcmdglobal_hash{'cmd'}); return; } $parameter = 1; $profile = 1; } if(defined($args{'profile'})) { $profile = 1; } if(defined($args{'parameter'})) { $parameter = 1; } #ASM instance is required for all the options other than '--profile -f' if(!defined($dbh)) { if(!(defined($args{'profile'}) && $forced == 1)) { asmcmdshare_error_msg(8311, undef); return; } } if($parameter == 1) { #force option should error out when used with parameter if($num > 1) { asmcmdsys_syntax_error($asmcmdglobal_hash{'cmd'}); return; } push(@what, 'value'); push(@from, 'v$parameter'); push(@where, 'name=\'asm_diskstring\''); $sth = asmcmdshare_do_construct_select($dbh, \@what, \@from, \@where); warn "$DBI::errstr\n" unless defined ($sth); $row = asmcmdshare_fetch($sth); $val = $row->{VALUE}; if(defined($val)) { print "parameter:" . $val . "\n"; } } if($profile == 1) { # The only option allowed with profile is -f. if($num > 2 || ($num == 2 && $forced != 1)) { asmcmdsys_syntax_error($asmcmdglobal_hash{'cmd'}); return; } # force with profile option. if($forced == 1) { $crsctl = "$ENV{'ORACLE_HOME'}/bin/crsctl"; # The path in WIN is $ENV{'ORACLE_HOME'}/bin/crsctl.exe $crsctl .= ".exe" if($^O =~ /win/i); # Make sure the crsctl binary exists and can be executed. if (! -x $crsctl) { #If not, try at a second locaction. $crsctl = "$ENV{'ORACLE_HOME'}/rdbms/bin/crsctl"; # The path in WIN is $ENV{'ORACLE_HOME'}/bin/crsctl.exe $crsctl .= ".exe" if($^O =~ /win/i); if (! -x $crsctl) { asmcmdshare_error_msg(8313, \$crsctl); return; } } #untaint crsctl $crsctl =~ /([^\n^\r^\t]+)/; $crsctl = $1; my $css = "$crsctl check css"; eval { $buf = `$css`; }; if($@ ne '') { asmcmdshare_error_msg(8309, undef); return; } # Check for the number at CRS-xxxx in the output. # Could not check cluster status if anything fails. if($buf =~ /([^\d]+)([^:]+)/) { my $status = $2; if(defined($status)) { if($status == 4529) { # CRS-4529: Cluster Synchronization Services is online asmcmdshare_error_msg(8308, undef); return; } } else { asmcmdshare_error_msg(8309, undef); return; } } else { asmcmdshare_error_msg(8309, undef); return; } $gpnptool = "$ENV{'ORA_CRS_HOME'}/bin/gpnptool"; #Adjust path for WIN $gpnptool .= ".exe" if($^O =~ /win/i); # Make sure the gpnptool binary exists and can be executed. if (! -x $gpnptool) { #If not, try at a second locaction. $gpnptool = "$ENV{'ORA_CRS_HOME'}/has/bin/gpnptool"; #Adjust path for WIN $gpnptool .= ".exe" if($^O =~ /win/i); if (! -x $gpnptool) { asmcmdshare_error_msg(8305, \$gpnptool); return; } } # The location of profile.xml is different for production and # dev environment now. The current environment is being determined by # checking whethe ADE_VIEW_ROOT is set or not. Bug 8579922 is filed # for this issue. $test = "$ENV{'ADE_VIEW_ROOT'}"; if($test eq '') { $crs_home = "$ENV{'ORA_CRS_HOME'}"; } else { $crs_home = "$ENV{'ORA_CRS_HOME'}/has_work"; } #untaint gpnptool $gpnptool =~ /([^\n^\r^\t]+)/; $gpnptool = $1; $prof_path = "$crs_home/gpnp/$ENV{'HOSTNAME'}/" . "profiles/peer/profile.xml"; #untaint prof_path $prof_path =~ /([^\n^\r^\t]+)/; $prof_path = $1; $gpnp_exec = "$gpnptool getpval -p=$prof_path -asm_dis -o-"; $gpnp_exec =~ /([^\n^\r^\t]+)/; $gpnp_exec = $1; eval { $buf = `$gpnp_exec`; }; if($@ ne '') { asmcmdshare_error_msg(8307); return; } if(defined($buf)) { print "profile:" . $buf . "\n"; } } else { $diskstring = asmcmdsys_dualget($dbh, 'asm_diskstring'); if(defined($diskstring)) { print "profile:" . $diskstring ."\n"; } } return; } } ######## # NAME # asmcmdsys_dualget # # DESCRIPTION # This function returns the requested valure from sys_cluster_properties. # # USAGE # # PARAMETERS # dbh (IN) - initialized database handle, must be non-null. # $what (IN) - property/value requested # $val (OUT) - # # RETURNS # Requested value querying from sys_context # ######### sub asmcmdsys_dualget { my ($dbh, $what) = @_; my ($stmt, $ret, $val, $row); =pod We use 4000 because asm_diskstring can be more than the default max(256) The default maximum size can be overriden by specifying the optional length parameter, which must be a NUMBER or a value that can be implicitly converted to NUMBER.The valid range of values is 1 to 4000 bytes. If you specify an invalid value, then Oracle Database ignores it and uses the default.For more details see SYS_CONTEXT in SQL Reference. =cut $stmt="select sys_context('sys_cluster_properties','" . $what . "',4000) ". "as val from dual"; $ret = asmcmdshare_do_select($dbh, $stmt); if (!defined($ret)) { warn "$DBI::errstr\n"; return; } $row = asmcmdshare_fetch($ret); $val = $row->{VAL}; return $val; } ######## # NAME # asmcmdsys_spset # # DESCRIPTION # This function sets the spfile location in the gPnP profile. # # PARAMETERS # dbh (IN) - initialized database handle, must be non-null. # spfile(IN) - spfile path. # # RETURNS # Path of the spfile. # # NOTES # The caller is responsible to check that the file exists. # ######## sub asmcmdsys_spset { my ($dbh, $path) = @_; my ($ret, $sth); $sth = $dbh->prepare(q{ begin dbms_diskgroup.gpnpsetsp(:spfile_path); exception when others then raise; end; }); $sth->bind_param( ":spfile_path", $path); $ret = $sth->execute(); return $ret; } ######## # NAME # asmcmdsys_process_spset # # DESCRIPTION # This function processes the asmcmd command spset. # # PARAMETERS # dbh (IN) - initialized database handle, must be non-null. # # RETURNS # Null. # # NOTES # Only asmcmdsys_process_cmd() calls this function. ######## sub asmcmdsys_process_spset { my ($dbh) = shift; my ($attr, $val); my ($ret, %args, $sth, $row, $dst_path); my ($spfile); my (@what , @from, @where, @order); $ret = asmcmdsys_parse_int_args($asmcmdglobal_hash{'cmd'}, \%args); return unless defined ($ret); if (!defined($ARGV[0])) { asmcmdsys_syntax_error($asmcmdglobal_hash{'cmd'}); return; } $spfile = $ARGV[0]; $ret = asmcmdsys_spset($dbh, $spfile); if (!defined($ret)) { warn "$DBI::errstr\n"; return; } return; } ######## # NAME # asmcmdsys_is_help # # DESCRIPTION # This function is the help function for the ASMCMDSYS module. # # PARAMETERS # command (IN) - display the help message for this command. # # RETURNS # 1 if command found; 0 otherwise. ######## sub asmcmdsys_process_help { my ($command) = shift; # User-specified argument; show help on $cmd. # my ($syntax); # Command syntax for $cmd. # my ($desc); # Command description for $cmd. # my ($succ) = 0; # 1 if command found, 0 otherwise. # if (asmcmdsys_is_cmd ($command)) { # User specified a command name to look up. # $syntax = asmcmdsys_get_cmd_syntax($command); $desc = asmcmdsys_get_cmd_desc($command); print " $syntax\n" . "$desc\n"; $succ = 1; } return $succ; } ######## # NAME # asmcmdsys_is_cmd # # DESCRIPTION # This routine checks if a user-entered command is one of the known # ASMCMD internal commands that belong to the ASMCMDSYS module. # # PARAMETERS # arg (IN) - user-entered command name string. # # RETURNS # True if $arg is one of the known commands, false otherwise. ######## sub asmcmdsys_is_cmd { my ($arg) = shift; return defined ( $asmcmdsys_cmds{ $arg } ); } ######## # NAME # asmcmdsys_is_wildcard_cmd # # DESCRIPTION # This routine determines if an ASMCMDSYS command allows the use # of wild cards. # # PARAMETERS # arg (IN) - user-entered command name string. # # RETURNS # True if $arg is a command that can take wildcards as part of its argument, # false otherwise. ######## sub asmcmdsys_is_wildcard_cmd { my ($arg) = shift; my (%cmdhash); # Empty hash; no ASMCMDSYS command supports wildcards. # return defined ( $cmdhash{ $arg } ); } ######## # NAME # asmcmdsys_is_no_instance_cmd # # DESCRIPTION # This routine determines if a command can run without an ASM instance. # # PARAMETERS # arg (IN) - user-entered command name string. # # RETURNS # True if $arg is a command that can run without an ASM instance # or does not exist, false otherwise. # # NOTES # The asmcmdsys module currently supports no command that can run # without an ASM instance. ######## sub asmcmdsys_is_no_instance_cmd { my ($arg) = shift; return !defined ($asmcmdsys_cmds{ $arg }) || !defined ($asmcmdsys_cmds{ $arg }{ no_instance }); } ######## # NAME # asmcmdsys_parse_int_args # # DESCRIPTION # This routine parses the arguments for flag options for ASMCMDSYS # internal commands. # # PARAMETERS # cmd (IN) - user-entered command name string. # args_ref (OUT) - hash of user-specified flag options for a command, # populated by getopts(). # # RETURNS # Zero on success; undefined on error. # # NOTES # $cmd must already be verified as a valid ASMCMDSYS internal command. ######## sub asmcmdsys_parse_int_args { my ($cmd, $args_ref) = @_; my ($key); my (@string); #build the list of options to parse using GetOptions if($asmcmdsys_cmds{ $cmd }{ flags }) { foreach $key(keys %{$asmcmdsys_cmds{ $cmd }{ flags }}) { push(@string, $key); } } # Use GetOptions() from the Getopt::Long package to parse arguments for # internal commands. These arguments are stored in @ARGV. if (!GetOptions($args_ref,@string)) { # Print correct command format if syntax error. # asmcmdsys_syntax_error($cmd); return undef; } return 0; } ######## # NAME # asmcmdsys_syntax_error # # DESCRIPTION # This function prints the correct syntax for a command to STDERR, used # when there is a syntax error. This function is responsible for # only ASMCMDSYS commands. # # PARAMETERS # cmd (IN) - user-entered command name string. # # RETURNS # 1 if the command belongs to this module; 0 if command not found. # # NOTES # These errors are user-errors and not internal errors. They are of type # record, not signal. # # N.B. Functions in this module can call this function directly, without # calling the asmcmdshare::asmcmdshare_syntax_error equivalent. The # latter is used only by the asmcmdcore module. ######## sub asmcmdsys_syntax_error { my ($cmd) = shift; my ($cmd_syntax); # Correct syntax for $cmd. # my ($succ) = 0; $cmd_syntax = asmcmdsys_get_cmd_syntax($cmd); # Get syntax for $cmd. # if (defined ($cmd_syntax)) { print STDERR 'usage: ' . $cmd_syntax . "\n"; print STDERR 'help: help ' . $cmd . "\n"; $succ = 1; } return $succ; } ######## # NAME # asmcmdsys_error_msg # # DESCRIPTION # This function is a wrapper around asmcmdsys_display_msg(), the # function responsible for displaying error messages for the asmcmdsys # module. # # This function is called by the general function asmcmdshare_error_msg, # which calls the respective _error_msg function in each module. # # This function records an error but does not signal one. # # PARAMETERS # err_num (IN) - ASMCMD internal error number. # args_ref (IN) - (Optional) Reference to array of error arguments # # RETURNS # 1 if the error number is supported by the asmcmdsys module; 0 # otherwise. # # NOTES # Only asmcmdshare_error_message should call this function. *Do not* # call this function directly; call asmcmdshare_error_message, # instead. ######## sub asmcmdsys_error_msg { my ($err_num, $args_ref) = @_; my ($succ) = 0; my (@eargs); # Assert that $err_num is not within 8200-8299, inclusive. @eargs = ("asmcmdsys_error_msg_05", $err_num); asmcmdshare_assert( (($err_num > 8000) || ($err_num < 9400)) , \@eargs); $succ = asmcmdsys_display_msg($err_num, $args_ref); return $succ; } ######## # NAME # asmcmdsys_display_msg # # DESCRIPTION # This routine prints error and exception messages to STDERR for the # asmcmdsys module. # # PARAMETERS # err_num (IN) - ASMCMD internal error number. # args_ref (IN) - (Optional) Reference to array of error arguments # # RETURNS # 1 if error message is found; 0 otherwise. # # NOTES # This function maintains a hash of error numbers supported by this # module in order to return quickly if the error number is not # supported by asmcmdsys. # # If an error is found, this function prints the error message. ######### sub asmcmdsys_display_msg { my ($err_num, $args_ref) = @_; my ($errmsg) = ''; # Error message from from $DBI::errstr. # my ($succ) = 0; # 1 if error message found, 0 otherwise. # my ($argument); # Argument iterator of the $args_ref array. # my ($arg) = ''; # Define a hash of error messages that exist for this module. # 8300-8350 my (%error_messages) = ( 8301 => q!diskgroup '$arg' does not exist or is not mounted!, 8303 => q!invalid spfile '$arg'!, 8304 => q!diskgroup '$arg' does not contain an spfile!, 8305 => q!gpnptool binary not found at '$arg'!, 8306 => q!could not edit the gpnp profile!, 8307 => q!could not sign the gpnp profile!, 8308 => q!-f option cannot be used when cluster stack is up!, 8309 => q!could not check the status of cluster!, 8310 => q!could not get the gpnp profile sequence number!, 8311 => q!no connection to ASM; command requires ASM to run!, 8312 => q!could not determine the status of ASM!, 8313 => q!crsctl binary not found at'$arg'!, ); $errmsg = $error_messages{$err_num}; if ($err_num == 8301 || $err_num == 8304 || $err_num == 8305 || $err_num == 8313) { $errmsg =~ s,\$arg,$$args_ref,; } if($err_num == 8303) { $arg = $args_ref->[0] if (defined($args_ref) && defined($args_ref->[0])); $errmsg =~ s,\$arg,$arg,; } # Print error only if this module supports this error number. if (defined ($errmsg)) { $succ = 1; print STDERR 'ASMCMD-0' . $err_num . ': ' . $errmsg . "\n"; } return $succ; } ######## # NAME # asmcmdsys_signal_exception # # DESCRIPTION # This function is a wrapper around asmcmdsys_display_msg(), the # function responsible for displaying error messages for the asmcmdsys # module. This function is a callback for asmcmdshare_signal_exception. # # PARAMETERS # exception_num (IN) - ASMCMD internal error/exception number. # args_ref (IN) - (Optional) Reference to array of error arguments # # RETURNS # 1 if the error number is supported by the asmcmdsys module; 0 # otherwise. # # NOTES # Only asmcmdshare_signal_exception should call this function. *Do not* # call this function directly; call asmcmdshare_signal_exception, # instead. The caller of this function always exits 1. ######## sub asmcmdsys_signal_exception { my ($exception_num, $args_ref) = @_; my ($succ) = 0; # Assert that $exception_num is within 8000-9400, inclusive. if (($exception_num < 8000) || ($exception_num > 9400)) { die "asmcmd: 8202 internal error: [asmcmdsys_signal_exception_05] " . "[$exception_num]\n"; } $succ = asmcmdsys_display_msg($exception_num, $args_ref); return $succ; } ######## # NAME # asmcmdsys_get_cmd_desc # # DESCRIPTION # This routine returns the help description of the command specified by $cmd. # # PARAMETERS # cmd (IN) - the name of the command of which we're looking up the # description. # # RETURNS # The description paragraph(s) for command $cmd; undefined if $cmd does not # exist. # # NOTES # IMPORTANT: the commands descriptions must be preceded by eight (8) spaces # of indention! This formatting is mandatory. ######## sub asmcmdsys_get_cmd_desc { my ($cmd) = shift; my (%cmd_desc); # Hash storing the description for each internal command. # $cmd_desc{'startup'} = ' Start the ASM instance. [--nomount] specifies the nomount option. [--restrict] start the instance in restricted mode. [--pfile ] specifies the location of the pfile. '; $cmd_desc{'shutdown'} = ' Shut down an ASM instance. [--immediate] Performs shutdown immediate. [--abort] Abort all existing operations. '; $cmd_desc{'lsop'} = ' List pending operations. '; $cmd_desc{'spcopy'} = ' Copy spfile from source to destination. [-u] Update gPnP profile. Source spfile. Destination of spfile. '; $cmd_desc{'spset'} = ' Sets the spfile into the gPnP profile. NOTE: there is no validation done on the spfile value. Path of the spfile. '; $cmd_desc{'spmove'} = ' Move spfile from source to destination. '; $cmd_desc{'spget'} = ' Retrieve the location of the spfile from the gPnP profile. '; $cmd_desc{'dsget'} = ' Retrieve the diskstring value from the ASM server and gPnP profile; [--normal] gets the diskstring from gPnP profile and ASM instance. [--profile] retrieves the diskstring from gPnP profile. [-f] retrieves the diskstring from local gPnP profile. used only with --profile cluster stack should not be up while using this option [--parameter] Retrieves the ASM_DISKSTRING parameter from ASM instance. '; $cmd_desc{'dsset'} = ' Sets the diskstring value into the server,gPnP profile. NOTE: there is no validation done on the diskstring. [--normal] sets the diskstring in gPnP profile and in ASM server [--profile] pushes the diskstring into gPnP profile without validating [-f] pushes the diskstring into local gPnP profile. used only with --profile cluster stack should not be up while using this option [--parameter] updates the diskstring in memory Path of the diskstring. '; $cmd_desc{'spbackup'} = ' Backup an spfile from to Source spfile to backup. Destination spfile backup. '; return $cmd_desc{$cmd}; } ######## # NAME # asmcmdsys_get_cmd_syntax # # DESCRIPTION # This routine returns the help syntax of the command specified by $cmd. # # PARAMETERS # cmd (IN) - the name of the command of which we're looking up the # syntax. # # RETURNS # The syntax for command $cmd; undefined if $cmd does not exist. ######## sub asmcmdsys_get_cmd_syntax { my ($cmd) = shift; my (%cmd_syntax); # Hash storing the syntax for each internal command. # $cmd_syntax{'startup'} = 'startup [--nomount] [--restrict] '. '[--pfile ]'; $cmd_syntax{'shutdown'} = 'shutdown [--immediate] [--abort]'; $cmd_syntax{'lsop'} = 'lsop'; $cmd_syntax{'spcopy'} = 'spcopy [-u] '; $cmd_syntax{'spmove'} = 'spmove '; $cmd_syntax{'spget'} = 'spget'; $cmd_syntax{'spset'} = 'spset '; $cmd_syntax{'dsget'} = 'dsget [--normal|--parameter|--profile [-f]]'; $cmd_syntax{'dsset'} = 'dsset [--normal|--parameter|--profile [-f]]'. ' '; $cmd_syntax{'spbackup'} = 'spbackup '; return $cmd_syntax{$cmd}; } ######## # NAME # asmcmdsys_get_asmcmd_cmds # # DESCRIPTION # This routine constructs a string that contains a list of the names of all # ASMCMD internal commands and returns this string. # # PARAMETERS # None. # # RETURNS # A string contain a list of the names of all ASMCMD internal commands. # # NOTES # Used by the help command and by the error command when the user enters # an invalid internal command. # # IMPORTANT: the commands names must be preceded by eight (8) spaces of # indention! This formatting is mandatory. ######## sub asmcmdsys_get_asmcmd_cmds { return asmcmdshare_print_cmds(sort(keys %asmcmdsys_cmds)); } 1;