#!$ORACLE_HOME/perl/bin/perl -w # # Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved. # # NAME # asmcmdcore - ASM CoMmanD line interface (Driver Program) # # DESCRIPTION # ASMCMD is a Perl utility that provides easy nagivation of files within # ASM diskgroups. Simple UNIX shell-like commands allow directory # traversal, directory creation and deletion, user alias creation and # deletion, and file deletion capabilities, among other features. # We implement this utility as a wrapper around existing SQL statements, # and we use the Perl DBI Module to connect to an ASM instance and to # issue these SQL statements. # # NOTES # usage: asmcmdcore [-v] [--privilege ] [-p] [command] # # MODIFIED (MM/DD/YY) # moreddy 01/13/11 - Backport moreddy_bug-8667038 from main # moreddy 01/12/11 - Backport moreddy_bug-6969662 from main # shmubeen 04/27/10 - fix of 7193021 for windows # amitroy 04/29/10 - BUG 8933243 - USE DIFFERENT CHARACTER IN ASMCMD TO # "HIDE COLUMN DETAILS" INSTEAD OF -H; REPLACE -a # TO --privilege FOR asmcmd # pvenkatr 03/31/10 - Syntax, Description, Example - all from XML # shmubeen 03/30/10 - fix for #7193021 # moreddy 03/22/10 - Adding more tracing # moreddy 03/23/10 - fixed bug 9412680 # moreddy 03/22/10 - Adding more tracing # sanselva 03/15/10 - clean up asmcmdbase_connect, get rid of # unused asmcmdglobal_hash variables # mchimang 02/23/10 - Made change to handle CNTRL-C in Noninteractive Mode # moreddy 01/08/10 - Adding tracing infrastructure # danagara 08/06/09 - Cntrl + C handled properly bug-8646861 # lajain 07/24/09 - Fix dsset --profile -f # gayavenk 06/11/09 - reconnect after dsset # sanselva 06/04/09 - Enable consistencychk when 'c' option used # heyuen 04/20/09 - add spbackup # heyuen 12/03/08 - reconnect after spmove # heyuen 11/10/08 - fix asmcmd prompt in windows # heyuen 10/14/08 - use dynamic modules # heyuen 08/02/08 - add verbose # heyuen 07/28/08 - rewrite asmcmdcore to use getopt # heyuen 06/16/08 - force disk scan during startup # heyuen 05/14/08 - reconnect after spcopy # heyuen 04/15/08 - bug 6957288 # heyuen 03/26/08 - reconnect at instance startup # heyuen 03/21/08 - enable lsdsk in non connected mode # heyuen 02/15/08 - add history # hqian 11/29/07 - #5661841, #5629952: enable ASMCMD for RDBMS instance # heyuen 09/20/07 - flush error messages as well as pending messages # before the prompt # heyuen 08/09/07 - refresh from main # heyuen 07/24/07 - add error message for connection failure # hqian 07/06/07 - #6174647: set $ENV{'PATH'} to include # $ENV{'ORACLE_HOME'}/bin # hqian 06/25/07 - Reset $ENV{'PATH'} for security reasons # heyuen 04/02/07 - remove error message when issuing asmcmd help- # and not being able to connect to ASM # hqian 03/09/07 - Notify user when failed to connect to ASM # hqian 03/02/07 - add asmcmdcore_get_asm_version # jilim 02/19/07 - fix for invalid $dbh after the cp # hqian 11/21/06 - fix signal_handler # jilim 09/27/06 - bug-5402303: added passing arg, contype, # for asmcmdbase_connect() # averhuls 07/06/06 - # hqian 07/12/06 - 11gR1: enable AMBR, disk repair, and other features # hqian 06/26/06 - disable asmcmddisk and asmcmdambr for initial merge # hqian 06/15/06 - add asmcmddisk module # msharang 03/28/06 - Add asmcmdambr # hqian 01/26/06 - rename asmcmdbase_global to asmcmdglobal_hash # hqian 01/24/06 - #4939032: split off callback defs into asmcmdglobal # hqian 01/20/06 - #4939032: rename bad_cmd() to show_commands() # hqian 01/18/06 - #4939032: support additional modules # hqian 01/18/06 - #4939032: keep only main() and shell() # hqian 01/18/06 - #4939032: split up asmcmd into modules # hqian 07/19/05 - Remove RCS header # hqian 06/23/05 - #4450221: support wildcards for CD # hqian 05/18/05 - Mention 'missing view attributes' in help ls # hqian 05/03/05 - #4329688: improve SQL efficiency # hqian 04/13/05 - ls_get_file_info() -> ls_process_file() # hqian 04/08/05 - Improve implementation of ls # hqian 04/08/05 - Improve help documentation # hqian 04/07/05 - LRG 1843355: include seconds in mod-time # hqian 04/01/05 - #4261342: use asmcmd messages for certain errors # hqian 02/28/05 - #4204122: change NLS date format for minute to 'MI' # hqian 10/27/04 - hqian_asmcmd_13306_linux_3 # hqian 10/19/04 - Rename asmcmd0 to asmcmdcore # hqian 08/03/04 - hqian_asmcmd_13306_linux_2 # hqian 07/28/04 - Add % as wildcard char in addition to *. # hqian 07/13/04 - Add implementation of find [-t ]. # hqian 06/30/04 - Make code that uses BigInt work for both Perl 5.6.1 # and Perl 5.8.3; take out -c # functionality. # hqian 06/29/04 - Fix 10gR1 compatibility issues; fix alias name # case-sensitive bug, should be case insensitive # but case retentive. # hqian 06/25/04 - Rename the main program from asmcmd to asmcmd0, so # that we can name the wrapper script asmcmd; rename # global constants, global variables, and function # names so that they are prefixed by 'asmcmd0_', # as per coding style standards; fix ORA-15128 bug. # hqian 06/23/04 - Inaccurate error message bug: add error message # 8004, do not print error when '*' matches nothing; # fix rm -rf * double error message bug; fix find # diskgroup bug; fix print header in empty directory # bug; fix space in alias name bug. # hqian 06/22/04 - Give the option to turn off the functionality of # the -c flag; add constants for better code design. # hqian 06/09/04 - Fix bugs; improve comments. # hqian 06/07/04 - Organize code for better maintenance; code review # changes (suggested by Dave Friedman). # hqian 06/01/04 - Fix some bugs. # hqian 05/24/04 - Implement rm [-rf] and rm *; some code review fixes. # hqian 05/20/04 - Implement help, instance_type security check, # - connection error checks, and debug mode. # hqian 05/18/04 - Implement ls flags and lsct. # hqian 05/14/04 - hqian_asmcmd_13306 # hqian 04/21/04 - Creation # # # ############################################################################# # ############################ Functions List ################################# # # Top Level Routines # asmcmdcore_main # asmcmdcore_shell # asmcmdcore_parse_asmcmd_args # asmcmdcore_module_driver # asmcmdcore_process_help # asmcmdcore_show_commands # asmcmdcore_is_cmd # asmcmdcore_check_global_callbacks # asmcmdcore_syntax_error ############################################################################# use strict; # load global modules use asmcmdglobal; use asmcmdshare; use Getopt::Long qw(:config no_ignore_case bundling); use Term::ReadLine; use File::Path; use Sys::Hostname; use List::Util qw[min max]; #find all the modules that exist, and include them my (%asm_modules); foreach (@INC) { if (-d $_) { my ($dir) = $_; my (@files) = (); opendir (MODDIR, $dir); @files = readdir(MODDIR); foreach (@files) { if ( $_ =~ /^asmcmd/ && $_ =~ /pm$/ ) { my (@temp) = (split(/\./, $_))[0]; $asm_modules{$temp[0]} = $dir . '/' . $_; } } closedir(MODDIR); } } delete($asm_modules{'asmcmdglobal'}); delete($asm_modules{'asmcmdshare'}); # If the module does not belong to asmcmd, remove it my @not_mod = (); my ($module); foreach $module(keys %asm_modules) { require "$module.pm"; my ($is_asm) = $module. "::is_asmcmd()"; eval ($is_asm); push (@not_mod, $module) if ($@); } foreach (@not_mod) { delete ($asm_modules{$_}); } # import modules foreach $module(sort(keys %asm_modules)) { $module->import; } ######################## ASMCMDCORE Global Variables ######################## # # # Each module needs to specify its initialization function here. my (@asmcmdcore_init_modules) = (); foreach $module(sort(keys %asm_modules)) { push (@asmcmdcore_init_modules, $module . "::init()"); } our (%asmcmdcore_cmds) = (asmcmd => {no_instance =>'False', flags => {'V'=>'version', 'v=s'=>'tracingLevel', 'privilege=s'=> 'systemPrivilege', 'p'=>'commandHistory' } } ); %asmcmdglobal_cmds = (%asmcmdglobal_cmds, %asmcmdcore_cmds); ############################ Top Level Routines ############################## # # Routines that calls exit(): # asmcmdcore_main - exit 0 # asmcmdcore_syntax_error - exit 0 # asmcmdbase_show_commands - exit 0 # asmcmdbase_check_insttype - exit 0 # asmcmdshare_signal_exception - exit 1 # asmcmdcore_shell - exit -1 # asmcmddisk_process_lsdsk - exit -1 0 1 2 ######## # NAME # asmcmdcore_main # # DESCRIPTION # This function is the main function of ASMCMD. It is the first # function that is called. # # PARAMETERS # None. # # RETURNS # Null. # ######## sub asmcmdcore_main { my ($dbh); my ($module); my ($mypath); $mypath = $ENV{'PATH'}; # $ORACLE_HOME/bin is appended for NT compatibility. # NT has the necessary dll's in that directory. $ENV{'PATH'} = "$ENV{'ORACLE_HOME'}/bin"; # Parse for consistency check option before calling init_modules asmcmdcore_consistency_check(); asmcmdcore_trace(); # Initialize modules. for $module (@asmcmdcore_init_modules) { eval($module); } # Check to see if all the modules have initialized the global callbacks # correctly. asmcmdcore_check_global_callbacks(); asmcmdcore_parse_asmcmd_args(); asmcmdcore_get_system_endian(); # If we're in non-interactive mode, and command is help, then there is # no need to attempt a network connection. Just run help and exit. # if (($asmcmdglobal_hash{'mode'} eq 'n') && # $asmcmdglobal_hash{'cmd'} eq 'help') # { # asmcmdcore_process_help(); # exit 0; # } # Now run the shell to process command(s). $dbh = asmcmdcore_shell($mypath); asmcmdbase_disconnect($dbh) if defined ($dbh); # Always exit zero here. Exiting non-zero is done only from exception # routine. See asmcmdcore_signal_exception(). exit 0; } asmcmdcore_main(); ######## # NAME # asmcmdcore_get_system_endian # # DESCRIPTION # This routine gets the system's endianness and stores it in a global # variable. # # PARAMETERS # None. # # RETURNS # Null. # # NOTES ######## sub asmcmdcore_get_system_endian { # The first bit of a little endian system is 1, and that of big endian # system is 0. if (unpack("b*", pack("s", 1)) =~ /^1/) { # System is little endian. $asmcmdglobal_hash{'endn'} = 1; } else { # System is big endian. $asmcmdglobal_hash{'endn'} = 0; } } ######## # NAME # asmcmdcore_connect # # DESCRIPTION # This routine initiates a conneciton to the ASM instance. Calls # asmcmdbase_connect(). # # PARAMETERS # None. # # RETURNS # Null. # # NOTES ######## sub asmcmdcore_connect { my ($dbh); # Connect to ASM instance first $dbh = asmcmdbase_connect(undef); if (defined ($dbh)) { my ($qry, $sth, $row); # Bugs 5661841 and 5629952: now that these bugs are fixed, ASMCMD # can work on both ASM and RDBMS instances. No need to check instance # type, anymore. # Initialize global variables, including getting group_number and name # of the first diskgroup. asmcmdbase_init_global($dbh); } return $dbh; } ######## # NAME # asmcmdcore_shell # # DESCRIPTION # This routine contains the top-level shell loop that prompts the user for # for commands and calls other routines to process them. # # PARAMETERS # dbh (IN) - initialized database handle, must be non-null. # # RETURNS # Null. # # NOTES # Should call asmcmdcore_connect to initialize $dbh before calling this # routine. ######## sub asmcmdcore_shell { my ($dbh); my ($line); # One line of input from user. # my ($prompt) = 'ASMCMD> '; # ASMCMD user prompt value. # my ($term); my (@eargs); my ($lastflag) = 0; #Flag to indicate last iteration of while loop my ($mypath) = shift; # This is the right place for registering the signal handler. Initially it # was registered when the modules where loaded in global scope. Handling # sthe ctrl-C ignal before connecting to the ASM instance (and starting # ASM command prompt) $SIG{INT} = \&asmcmdshare_signal_handler;# Signal handler for asmcmd # # Try to connect to ASM if the command is different from help if ($asmcmdglobal_hash{'cmd'} ne 'help') { $dbh = asmcmdcore_connect(); if (defined($dbh)) { $asmcmdglobal_hash{'ver'} = asmcmdshare_get_asm_version($dbh); # $$$ In order to test different version numbers of ASM and their # relative behaviors on ASMCMD, comment out the line above and # uncomment the line below. Set the version number to the one # that's to be tested. Note that this testing method works only # # $asmcmdglobal_hash{'ver'} = '11.1.0.3.0'; } else { # Inform user that connection to ASM failed, except when the issued # command is help, startup, shutdown, or lsdsk asmcmdshare_trace(5, $DBI::errstr, 'y', 'y'); @eargs = ($ENV{'ORACLE_SID'}) if defined($ENV{'ORACLE_SID'}); if ($asmcmdglobal_hash{'verbose'} eq 'debug') { asmcmdshare_error_msg (8103, \@eargs); } asmcmdshare_trace(3, "Connected to an idle instance.", 'y', 'y'); } } # If non-interactive mode, process command and return. if ($asmcmdglobal_hash{'mode'} eq 'n') { if (!defined ($dbh) && asmcmdshare_is_no_instance_cmd($asmcmdglobal_hash{'cmd'}) != 1) { # Connection failed, and command requires ASM instance; record error. # asmcmdshare_error_msg (8102, undef); } else { asmcmdcore_module_driver($dbh); } exit $asmcmdglobal_hash{'e'}; } $asmcmdglobal_hash{'cwdnm'} = '+'; if (-e "/dev/tty") { $term = new Term::ReadLine("", \*STDIN, \*STDOUT); } else { $term = new Term::ReadLine("CON", \*STDIN, \*STDOUT); } if ($term->Features->{ornaments}) { local $Term::ReadLine::termcap_nowarn = 1; $term->ornaments(0); } while (1) { if ($lastflag == 1) { $lastflag = 0; #Reset flag (which is reduandant as of now) last; } eval { my (@token);# Need fresh array of parsed tokens of arguments from $line. # # Prepare prompt, if long version of prompt is needed. if ($asmcmdglobal_hash{'lprmt'} eq 'y') { $prompt = 'ASMCMD [' . $asmcmdglobal_hash{'cwdnm'} . '] > '; } select STDERR; $|++; select STDOUT; $|++; $line = $term->readline($prompt); if (defined($line)) { chomp($line); # Remove newline character. # $line =~ s,^\s+,,g; # Remove initial spaces. # $line =~ s,\s+$,,g; # Remove trailing spaces. # } # Terminate if EOF or 'exit'. if (! defined($line)) { $line = 'exit'; print "exit\n"; } #last if ($line eq 'exit'); #last if ($line eq 'quit'); if ($line eq 'exit' || $line eq 'quit') { $lastflag = 1; die; } if ( $line =~ /^!/ ) { $ENV{'PATH'} = $mypath; $line =~ s/^!//; my $cmd; my $os = $^O; if($os eq "MSWin32") { $cmd = "$line"; } else { $cmd="$line 1>&1"; } system($cmd); # NT has the necessary dll's in that directory. $ENV{'PATH'} = "$ENV{'ORACLE_HOME'}/bin"; } else { # Parse $line into an array of arguments. if (asmcmdbase_parse_int_cmd_line($line, \@token)) { # asmcmdcore_parse_int_cmd_line() returned error. # asmcmdshare_error_msg(8007, undef); #next; # Error, so done with this command, move on to next comand. # die; } die if ($token[0] eq ''); # Empty line, so skip command. # $asmcmdglobal_hash{'cmd'} = shift(@token); # Save command name. # @ARGV = @token; # Save in global @ARGV for internal command parsing. # if (!defined ($dbh) && asmcmdshare_is_no_instance_cmd($asmcmdglobal_hash{'cmd'}) != 1) { # Connection failed, and command requires ASM instance; record error. # asmcmdshare_error_msg (8102, undef); } else { asmcmdcore_module_driver($dbh); } $term->addhistory($line); if ($asmcmdglobal_hash{'cmd'} eq 'cp' || $asmcmdglobal_hash{'cmd'} eq 'spcopy' || $asmcmdglobal_hash{'cmd'} eq 'spmove' || $asmcmdglobal_hash{'cmd'} eq 'spset' || $asmcmdglobal_hash{'cmd'} eq 'spbackup' || $asmcmdglobal_hash{'cmd'} eq 'dsset' || $asmcmdglobal_hash{'cmd'} eq 'rm') { # re-connect to asm instance after the cp # # this must be done since $dbh is now invalidated by the cp # # and it was orginally set at this module level # asmcmdbase_disconnect($dbh) if defined ($dbh); $dbh = asmcmdbase_connect(undef); } # re-connect if we startup/shutdown an instance # if we cannot get a $dbh, that means there is no instance # but this is not a reason to signal error since we can # try startup again if ($asmcmdglobal_hash{'cmd'} eq 'startup' || $asmcmdglobal_hash{'cmd'} eq 'shutdown') { asmcmdbase_disconnect($dbh) if defined ($dbh); $dbh = asmcmdbase_connect(undef); if (!defined($dbh)) { asmcmdshare_trace(5, $DBI::errstr, 'y', 'y'); @eargs = ($ENV{'ORACLE_SID'}) if defined($ENV{'ORACLE_SID'}); if ($asmcmdglobal_hash{'verbose'} eq 'debug') { asmcmdshare_error_msg (8103, \@eargs); } asmcmdshare_trace(3, "Connected to an idle instance.", 'y', 'y'); } } } }; } return $dbh; } ######## # NAME # asmcmdcore_consistency_check # # DESCRIPTION # This routine parses command line arguments only for consistency check option # not anyother the arguments related to ASMCMD or commands internal to ASMCMD. # # PARAMETERS # GLOBAL: @ARGV (IN/OUT) - list of all command line arguments for asmcmd. # # RETURNS # Null. # # Note also that this routine removes the consistency check option if found in # ARGV ######## sub asmcmdcore_consistency_check { my $i; for ($i = 0; $i < $#ARGV+1; $i++) { if ($ARGV[$i] eq '-check') { #remove the option from ARGV array if found splice(@ARGV,$i,1); #set the global to denote that consistency check is ON #later used in init() function in all perl modules $asmcmdglobal_hash{'consistchk'} = 'y'; print STDERR "WARNING: ASMCMD consistency check enabled\n"; last; } } return; } ######## # NAME # asmcmdcore_trace # # DESCRIPTION # This routine parses command line arguments only for verbose option -v and # not anyother the arguments related to ASMCMD or commands internal to ASMCMD. # # PARAMETERS # GLOBAL: @ARGV (IN/OUT) - list of all command line arguments for asmcmd. # # RETURNS # Null. # # Note also that this routine removes the verbose option -v and trace level # value if found in ARGV ######## sub asmcmdcore_trace { my ($i, $user, $host); $user = getlogin || getpwuid($<); $host = hostname(); $asmcmdglobal_trace_path = "$ENV{'ORACLE_HOME'}/log/diag/asmcmd/user_$user/$host"; if (!-d $asmcmdglobal_trace_path) { $asmcmdglobal_trace_path =~ /([^\n^\r^\t]+)/; $asmcmdglobal_trace_path =$1; eval { mkpath ("$asmcmdglobal_trace_path/alert") }; if ($@) { print STDERR "Can not create path $asmcmdglobal_trace_path/alert \n"; } eval { mkpath ("$asmcmdglobal_trace_path/trace") }; if ($@) { print STDERR "Can not create path $asmcmdglobal_trace_path/trace \n"; } } for ($i = 0; $i < $#ARGV+1; $i++) { if ($ARGV[$i] eq '-v') { #remove the option from ARGV array if found splice(@ARGV,$i,1); if (defined($ARGV[$i])) { if (defined($asmcmdshare_trace_levels{$ARGV[$i]})) { $asmcmdglobal_hash{'verbose'} =$ARGV[$i]; } else { print STDERR "WARNING: Specified tracing level '$ARGV[$i]' does". " not exist.\n"; $asmcmdglobal_hash{'verbose'} ='normal'; print STDERR "Default level of tracing is enabled.\n"; } #remove the value of trace level from ARGV array if found splice(@ARGV,$i,1); } else { print STDERR "WARNING: Tracing level not specified\n"; $asmcmdglobal_hash{'verbose'} ='normal'; print STDERR "Default level of tracing is enabled.\n"; } last; } } return; } ######## # NAME # asmcmdcore_parse_asmcmd_args # # DESCRIPTION # This routine parses the command line arguments for ASMCMD. These are # not the arguments for commands internal to ASMCMD. # asmcmdbase_parse_int_args() handles the latter cases. # # PARAMETERS # GLOBAL: @ARGV (IN/OUT) - list of all command line arguments for asmcmd. # # RETURNS # Null. # # Note also that this routine *modifies* @ARGV; all parsed arguments are # removed from this array. ######## sub asmcmdcore_parse_asmcmd_args { my ($args_ref); my (%args) = (); my ($i, $len); my (@asmcmd_arg) = (); my (@cmd_arg) = (); my ($cmd) = 'asmcmd'; my (@string); my ($key); # chop off the @ARGV array, so we process asmcmd arguments for ($i = 0; $i < $#ARGV+1; $i++) { if (defined ($asmcmdglobal_cmds{$ARGV[$i]})) { last; } } $len = $#ARGV; @asmcmd_arg = @ARGV[0..$i-1] if (defined(@ARGV[0..$i-1])); @cmd_arg = @ARGV[$i..$len] if (defined(@ARGV[$i..$len])); @ARGV = @asmcmd_arg; #build the list of options to parse using GetOptions if($asmcmdcore_cmds{ $cmd }{ flags }) { foreach $key(keys %{$asmcmdcore_cmds{ $cmd }{ flags }}) { push(@string, $key); } } #include deprecated options if any if($asmcmdglobal_deprecated_options{ $cmd }) { foreach my $key(keys %{$asmcmdglobal_deprecated_options{ $cmd }}) { push(@string, $asmcmdglobal_deprecated_options{$cmd}{$key}[0]); } } # Use GetOptions() from the Getopt::Long package to parse arguments for # internal commands. These arguments are stored in @ARGV. if ( (!GetOptions(\%args,@string)) || (@ARGV > 0) ) { # Print command list if unknown arguement # Print correct command format if syntax error. # if(@ARGV > 0) { asmcmdcore_show_commands('exit', \*STDERR); } else { asmcmdcore_syntax_error($cmd); } return; } #Set the correct options if deprecated options were used and print WARNING. #asmcmdshare_handle_deprecation($asmcmdglobal_hash{ 'cmd'},\%args); asmcmdshare_handle_deprecation($cmd, \%args); # reconstruct @ARGV for the command arguments @ARGV = @cmd_arg; # if a command is passed, check that it is a valid one if (defined($ARGV[0])) { if (!defined($asmcmdglobal_cmds{$ARGV[0]})) { asmcmdcore_show_commands('exit', \*STDERR); return; } } if (defined($args{'V'})) { print 'asmcmd version ' . $asmcmdglobal_hash{'acver'}. "\n"; exit 0; } #default is sysasm $asmcmdglobal_hash{'contyp'} = 'sysasm'; if (defined($args{'privilege'})) { if (($args{'privilege'} =~ /^sysasm$/i) || ($args{'privilege'} =~ /^sysdba$/i)) { $asmcmdglobal_hash{'contyp'} = $args{'privilege'}; } else { asmcmdcore_syntax_error('asmcmd'); return; } } if (defined($args{'p'})) { $asmcmdglobal_hash{'lprmt'} = 'y'; } if (defined($ARGV[0])) { $asmcmdglobal_hash{'mode'} = 'n'; if (asmcmdcore_is_cmd($ARGV[0])) { $asmcmdglobal_hash{'cmd'} = $ARGV[0]; shift(@ARGV); return; } else { asmcmdcore_show_commands('exit', \*STDERR); } } return; } ######## # NAME # asmcmdcore_module_driver # # DESCRIPTION # This function calls in each module the respective function that # processes commands responsible by the said module. All ASMCMD # commands must pass through this function before being processed # by the modules. # # PARAMETERS # dbh (IN) - initialized database handle, must be non-null. # # RETURNS # Null. # ######## sub asmcmdcore_module_driver { my ($dbh) = shift; my ($succ) = 0; my ($module); my (@eargs); # Array of error arguments. # foreach $module (@asmcmdglobal_command_callbacks) { if ($module->($dbh)) { # Assert that we find only one occurrence of this command in # the modules. @eargs = ("asmcmdcore_module_driver_05", $asmcmdglobal_hash{'cmd'}); asmcmdshare_assert(($succ == 0), \@eargs); $succ = 1; } } if ($asmcmdglobal_hash{'cmd'} eq 'help') { # Assert that we find only one occurrence of this command in # the modules. @eargs = ("asmcmdcore_module_driver_10", $asmcmdglobal_hash{'cmd'}); asmcmdshare_assert(($succ == 0), \@eargs); asmcmdcore_process_help(); $succ = 1; } if (! $succ) { asmcmdcore_show_commands(undef, \*STDERR); } return; } ######## # NAME # asmcmdcore_process_help # # DESCRIPTION # This top-level routine processes the help command. # # PARAMETERS # None. # # RETURNS # Null. # ######## sub asmcmdcore_process_help { my (%args); # Argument hash used by getopts(). # my ($ret); # asmcmdbase_parse_int_args() return value. # my ($cmd); # User-specified command-name argument; show help on $cmd. # my ($syntax); # Command syntax for $cmd. # my ($desc); # Command description for $cmd. # my ($module); # A module's help function. # my ($succ) = 0; # 1 if command exists, 0 otherwise. # my (@eargs); # Array of error arguments. # # Get option parameters, if any. $ret = asmcmdbase_parse_int_args($asmcmdglobal_hash{'cmd'}, \%args); return unless defined ($ret); # Check if number of non-option parameters are correct. if (@ARGV > 1) { asmcmdcore_syntax_error($asmcmdglobal_hash{'cmd'}); return; } $cmd = shift (@ARGV); if (defined ($cmd)) { # Search each module for the command's help message. foreach $module (@asmcmdglobal_help_callbacks) { if ($module->($cmd) == 1) { # Assert that we find only one occurrence of this command in # the modules. @eargs = ("asmcmdcore_process_help_05", $cmd); asmcmdshare_assert(($succ == 0), \@eargs); # We found the command's help message. $succ = 1; } } } if (! defined ($cmd) || ($succ == 0)) { # No command name specified, or command not found; # # show help on asmcmd and list all commands. # $syntax = ""; if ($ASMCMDGLOBAL_USE_CONN_STR) { $syntax = asmcmdshare_get_help_syntax ('asmcmd'); $desc = asmcmdshare_get_help_desc('asmcmd'); $desc = asmcmdshare_trim_str ($desc); } else { # If -c is deprecated, then use syntax without -c option. # $syntax = asmcmdshare_get_help_syntax('asmcmd_no_conn_str') ; $desc = asmcmdshare_get_help_desc('asmcmd_no_conn_str'); $desc = asmcmdshare_trim_str ($desc); } print " $syntax\n"; print "$desc\n\n"; asmcmdcore_show_commands(undef, \*STDOUT); # Print list of all commands. # } return; } ######## # NAME # asmcmdcore_show_commands # # DESCRIPTION # This routine prints a list of all valid internal commands, used # as an error message when the user has entered an invalid command name. # If $exit is set to 'exit', then also call exit(0). This option is to # accommodate the non-interactive option, when quitting asmcmd is necessary. # The caller can specify whether he wants to direct the output to # STDOUT or STDERR. # # PARAMETERS # exit (IN) - flag: causes asmcmdbase_show_commands() to call exit() # iff value is 'exit'. # IO_handle (IN) - handle where to print output: STDOUT or STDERR. # # RETURNS # Null. # ######## sub asmcmdcore_show_commands { my ($exit, $output_handle) = @_; my ($asmcmd_cmds) = ''; my ($module); print $output_handle " commands:\n"; print $output_handle " --------\n\n"; foreach $module (@asmcmdglobal_command_list_callbacks) { $asmcmd_cmds .= $module->() . "\n"; } print $output_handle $asmcmd_cmds; exit 0 if (defined($exit) && ($exit eq 'exit')); return; } ######## # NAME # asmcmdcore_is_cmd # # DESCRIPTION # This routine checks if a user-entered command is one of the known ASMCMD # internal commands. # # PARAMETERS # arg (IN) - user-entered command name string. # # RETURNS # 1 if $arg is one of the known commands, 0 otherwise. # # NOTES # This routine calls the callbacks from each module to check if $arg # belongs to any of the modules. It asserts that the command is found # in only one module. ######## sub asmcmdcore_is_cmd { my ($command) = shift; my ($module); my ($succ) = 0; my ($count) = 0; my (@eargs); # Array of error arguments. # foreach $module (@asmcmdglobal_is_command_callbacks) { if ($module->($command)) { $succ = 1; $count++; } } # Assert that $count is at most 1 and at least 0. @eargs = ("asmcmdcore_is_cmd_05", $asmcmdglobal_hash{'cmd'}, $count); asmcmdshare_assert( (($count == 1) || ($count == 0)), \@eargs); return $succ; } ######## # NAME # asmcmdcore_check_global_callbacks # # DESCRIPTION # This function checks to see if the global callback arrays have been # initialized correctly. # # PARAMETERS # None # # RETURNS # Null if the assertion passes; signals exception otherwise. # # NOTES # This function asserts that all the callback arrays, including # asmcmdcore_init_modules, have the same number of elements. ######## sub asmcmdcore_check_global_callbacks { my (@eargs); # Error arguments for the assert. # my ($temp); @eargs = ("asmcmdcore_check_global_callbacks_05", scalar(@asmcmdcore_init_modules), scalar(@asmcmdglobal_command_callbacks), scalar(@asmcmdglobal_help_callbacks), scalar(@asmcmdglobal_command_list_callbacks), scalar(@asmcmdglobal_is_command_callbacks), scalar(@asmcmdglobal_is_wildcard_callbacks), scalar(@asmcmdglobal_syntax_error_callbacks), scalar(@asmcmdglobal_no_instance_callbacks)); $temp = scalar(@asmcmdcore_init_modules); asmcmdshare_assert(((scalar(@asmcmdglobal_command_callbacks) == $temp) && (scalar(@asmcmdglobal_help_callbacks) == $temp) && (scalar(@asmcmdglobal_command_list_callbacks) == $temp) && (scalar(@asmcmdglobal_is_command_callbacks) == $temp) && (scalar(@asmcmdglobal_is_wildcard_callbacks) == $temp) && (scalar(@asmcmdglobal_syntax_error_callbacks) == $temp) && (scalar(@asmcmdglobal_no_instance_callbacks) == $temp)), \@eargs); return; } ######## # NAME # asmcmdcore_syntax_error # # DESCRIPTION # This function calls into each module to display the correct syntax # for a given ASMCMD command. # # PARAMETERS # command (IN) - the user-specified ASMCMD command # # RETURNS # Null. # # NOTES # This routine calls the callbacks from each module to display the # correct syntax for $command. ######## sub asmcmdcore_syntax_error { my ($command) = shift; my ($module); my ($count) = 0; my (@eargs); # Array of error arguments. # foreach $module (@asmcmdglobal_syntax_error_callbacks) { if ($module->($command)) { $count++; } } # Assert that $count is at most 1 and at least 0. @eargs = ("asmcmdcore_syntax_error_05", $asmcmdglobal_hash{'cmd'}, $count); asmcmdshare_assert( (($count == 1) || ($count == 0)), \@eargs); return; } ##############################################################################