# Copyright (c) 2004, 2009, Oracle and/or its affiliates. All rights reserved. # # NAME # asmcmdtmpl - ASM CoMmanD line interface TEMPLATE operations # # DESCRIPTION # This module contains the code for ASMCMD/ASM template-related # operations, such as listing the contents of v$asm_template. # # NOTES # usage: asmcmdcore [-p] [command] # # MODIFIED (MM/DD/YY) # sanselva 06/17/09 - correct check for --primary and --secondary # sanselva 04/06/09 - ASMCMD long options and consistency # heyuen 10/14/08 - use dynamic modules # heyuen 07/28/08 - use command properties array # heyuen 05/27/08 - remove entry_number field # heyuen 04/15/08 - rename zones to regions # heyuen 07/23/07 - creation # ############################################################################# # ############################ Functions List ################################# # asmcmdtmpl_init # asmcmdtmpl_error_msg # asmcmdtmpl_display_msg # asmcmdtmpl_signal_exception # asmcmdtmpl_process_cmd # asmcmdtmpl_process_lstmpl # asmcmdtmpl_process_mktmpl # asmcmdtmpl_process_chtmpl # asmcmdtmpl_process_rmtmpl # asmcmdtmpl_is_cmd # asmcmdtmpl_is_no_instance_cmd # asmcmdtmpl_parse_int_args # asmcmdtmpl_syntax_error # asmcmdtmpl_get_cmd_syntax # asmcmdtmpl_process_help # asmcmdtmpl_get_asmcmd_cmds ############################################################################# package asmcmdtmpl; require Exporter; our @ISA = qw(Exporter); our @EXPORT = qw(asmcmdtmpl_init %asmcmdtmpl_cmds ); use strict; use Getopt::Long qw(:config no_ignore_case bundling); use asmcmdglobal; use asmcmdshare; use List::Util qw[min max]; ####################### ASMCMDTMPL Global Constants ###################### # ASMCMD Column Header Names: # Below are the names of the column headers for lstmpl. our (%asmcmdtmpl_lstmpl_header) = ('inst_id' , 'Inst_Id', 'group_name' , 'Group_Name', 'name' , 'Name', 'stripe' , 'Stripe', 'system' , 'Sys', 'redundancy' , 'Redund', 'group_number' , 'Group_Num', 'primary_region' , 'PriReg', 'mirror_region' , 'MirrReg' ); our (%asmcmdtmpl_cmds) = (lstmpl => {wildcard => 'True', no_instance => 'True', flags => {'l'=>'longListing', 'G=s'=>'diskGroup', 'H'=>'supressHeaders'} }, mktmpl => {no_instance => 'True', flags => {'G=s'=>'diskGroup', 'striping=s'=> 'diskStriping', 'redundancy=s'=> 'redundancyType', 'primary=s'=> 'primaryRegion', 'secondary=s'=> 'secondaryRegion'} }, chtmpl => {no_instance => 'True', flags => {'G=s'=>'diskGroup', 'striping=s'=> 'diskStriping', 'redundancy=s'=> 'redundancyType', 'primary=s'=> 'primaryRegion', 'secondary=s'=> 'secondaryRegion'} }, rmtmpl => {no_instance => 'True', flags => {'G=s'=>'diskGroup'} } ); ####################### ASMCMDTMPL Global Variables ###################### sub is_asmcmd { return 1; } ######## # NAME # asmcmdtmpl_init # # DESCRIPTION # This function initializes the asmcmdtmpl 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 { push (@asmcmdglobal_command_callbacks, \&asmcmdtmpl_process_cmd); push (@asmcmdglobal_help_callbacks, \&asmcmdtmpl_process_help); push (@asmcmdglobal_command_list_callbacks, \&asmcmdtmpl_get_asmcmd_cmds); push (@asmcmdglobal_is_command_callbacks, \&asmcmdtmpl_is_cmd); push (@asmcmdglobal_is_wildcard_callbacks, \&asmcmdtmpl_is_wildcard_cmd); push (@asmcmdglobal_syntax_error_callbacks, \&asmcmdtmpl_syntax_error); push (@asmcmdglobal_no_instance_callbacks, \&asmcmdtmpl_is_no_instance_cmd); push (@asmcmdglobal_error_message_callbacks, \&asmcmdtmpl_error_msg); push (@asmcmdglobal_signal_exception_callbacks, \&asmcmdtmpl_signal_exception); %asmcmdglobal_cmds = (%asmcmdglobal_cmds, %asmcmdtmpl_cmds); #Perform ASMCMD consistency check if enabled if($asmcmdglobal_hash{'consistchk'} eq 'y') { if(!asmcmdshare_check_option_consistency(%asmcmdtmpl_cmds)) { exit 1; } } } ######## # NAME # asmcmdtmpl_error_msg # # DESCRIPTION # This function is a wrapper around asmcmdtmpl_display_msg(), the # function responsible for displaying error messages for the asmcmdtmpl # 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 asmcmdtmpl module; 0 # otherwise. # # NOTES # Only asmcmdshare_error_message should call this function. *Do not* # call this function directly; call asmcmdshare_error_message, # instead. ######## sub asmcmdtmpl_error_msg { my ($err_num, $args_ref) = @_; my ($succ) = 0; my (@eargs); # Assert that $err_num is not within 8000-9400, inclusive. @eargs = ("asmcmdtmpl_error_msg_05", $err_num); asmcmdshare_assert( (($err_num > 8000) || ($err_num < 9400)) , \@eargs); $succ = asmcmdtmpl_display_msg($err_num, $args_ref); return $succ; } ######## # NAME # asmcmdtmpl_display_msg # # DESCRIPTION # This routine prints error and exception messages to STDERR for the # asmcmdtmpl 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 asmcmdtmpl. # # If an error is found, this function prints the error message. ######### sub asmcmdtmpl_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. # # Define a hash of error messages that exist for this module. # 8351-8400 my (%error_messages) = ( ); $errmsg = $error_messages{$err_num}; # 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 # asmcmdtmpl_signal_exception # # DESCRIPTION # This function is a wrapper around asmcmdtmpl_display_msg(), the # function responsible for displaying error messages for the asmcmdtmpl # 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 asmcmdtmpl 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 asmcmdtmpl_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: [asmcmdtmpl_signal_exception_05] " . "[$exception_num]\n"; } $succ = asmcmdtmpl_display_msg($exception_num, $args_ref); return $succ; } ######## # NAME # asmcmdtmpl_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 asmcmdtmpl_get_cmd_desc { my ($cmd) = shift; my (%cmd_desc); # Hash storing the description for each internal command. # $cmd_desc{'lstmpl'} = ' Lists ASM templates in a disk group. [-G dgname] shows the templates that belong to a certain disk group. [-l] shows detailed information about the templates. [-H] supress headers. [pattern] filter out template names that match a given pattern. '; $cmd_desc{'mktmpl'} = ' Create a template in a disk group. -G disk group to place the'. 'template in [--striping ] striping (Coarse|Fine) [--redundancy ] redundancy'. ' (Unprotected|Mirror|High) [--primary ] primary region (Hot|Cold) [--secondary ] secondary region (Hot|Cold) name of the template '; $cmd_desc{'chtmpl'} = ' Change attributes of an existing template. -G disk group to place the'. ' template in [--striping ] striping (Coarse|Fine) [--redundancy ] redundancy'. ' (Unprotected|Mirror|High) [--primary ] primary region (Hot|Cold) [--secondary ] secondary region (Hot|Cold) name name of the template '; $cmd_desc{'rmtmpl'} = ' Drop a template from a disk group. <-G dgname> disk group where the template is name name of the template '; return $cmd_desc{$cmd}; } ######## # NAME # asmcmdtmpl_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 asmcmdtmpl module; 0 if not. # # NOTES # Only asmcmdcore_shell() calls this routine. ######## sub asmcmdtmpl_process_cmd { my ($dbh) = @_; my ($succ) = 0; # Get current command from global value, which is set by # asmcmdtemplate_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 ASMCMDTEMPLATE command. my (%cmdhash) = ( lstmpl => \&asmcmdtmpl_process_lstmpl, mktmpl => \&asmcmdtmpl_process_mktmpl, chtmpl => \&asmcmdtmpl_process_chtmpl, rmtmpl => \&asmcmdtmpl_process_rmtmpl ); if (defined ( $cmdhash{ $cmd } )) { # If user specifies a known command, then call routine to process it. # $cmdhash{ $cmd }->($dbh); $succ = 1; } return $succ; } ######## # NAME # asmcmdtmpl_process_lstmpl # # DESCRIPTION # This function processes the asmcmd command lstmpl. # # PARAMETERS # dbh (IN) - initialized database handle, must be non-null. # # RETURNS # Null. # # NOTES # Only asmcmdtmpl_process_cmd() calls this function. ######## sub asmcmdtmpl_process_lstmpl { my ($dbh) = shift; my (%args); my ($qry, $ret); my (@what , @from, $sth, @where, @order); my (@cols, @dgroups, %dgnmap); my ($dgname, $dgnum, $meta, $vals); my ($header, $pattern); my (%as); my (@tmpl_list); my ($row, $k, $v, $h); my (%min_col_wid, $print_format, $printf_code, @what_print); # Get option parameters, if any. $ret = asmcmdtmpl_parse_int_args($asmcmdglobal_hash{'cmd'}, \%args); return unless defined ($ret); # get disk group names @dgroups = asmcmdshare_get_dg($dbh); foreach (@dgroups) { $dgnmap{$_->{'group_number'}} = $_->{'name'}; } # if disk group is specified, filter out if (defined($args{'G'})) { $dgname = $args{'G'}; $dgname =~ tr/[a-z]/[A-Z]/; $dgnum = asmcmdshare_get_gnum_from_gname($dbh, $dgname); } # check if -l is specified $vals = defined($args{'l'}); # check if pattern is specified if (defined($ARGV[0])) { $pattern= $ARGV[0]; $pattern =~ s,$ASMCMDGLOBAL_WCARD_CHARS,\%,g; } push (@what, 'group_number'); push (@what, 'name'); push (@order, 'group_number'); push (@order, 'name'); # add extra columns if specified if ($vals) { push (@what, 'stripe'); push (@what, 'system'); push (@what, 'redundancy'); push (@what, 'primary_region'); push (@what, 'mirror_region'); } # filter out template name if ($pattern) { $pattern =~ tr/[a-z]/[A-Z]/; push (@where, 'name LIKE \'%' . $pattern . '%\' '); } # filter out diskgroup if (defined($dgnum)) { push (@where, 'group_number = \'' . $dgnum . '\' '); } push (@from, 'v$asm_template'); $sth = asmcmdshare_do_construct_select($dbh, \@what, \@from, \@where, \@order); warn "$DBI::errstr\n" unless defined ($sth); #initialize the min_col_wid array foreach(@what) { $min_col_wid{$_} = 0; } $min_col_wid{'group_name'} = 0; #get the rows while (defined($row = asmcmdshare_fetch($sth))) { my(%tmpl_info) = (); while(($k, $v) = each(%{$row})) { $k =~ tr/[A-Z]/[a-z]/; $tmpl_info{$k} = $v; $min_col_wid{$k} = max($min_col_wid{$k}, length($v)); } if (defined($tmpl_info{'group_number'})) { $tmpl_info{'group_name'} = $dgnmap{$tmpl_info{'group_number'}}; $min_col_wid{'group_name'} = max( $min_col_wid{'group_name'}, length($tmpl_info{'group_name'})); } push (@tmpl_list, \%tmpl_info); } asmcmdshare_finish($sth); # add the group_name column at the beginning, we do this because it was not # part of the query unshift @what, "group_name"; #get the header length foreach (@what) { $min_col_wid{$_} = max($min_col_wid{$_}, length($asmcmdtmpl_lstmpl_header{$_})); } #create print format $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, "\'" . $asmcmdtmpl_lstmpl_header{$_} . "\'"); } $printf_code .= "(" . join (", ", @what_print) . ")"; eval $printf_code; } #print rows foreach $h (@tmpl_list) { $printf_code = "printf \"$print_format\", "; @what_print = (); foreach (@what) { push (@what_print, "\'" . $h->{$_} . "\'"); } $printf_code .= "(" . join (", ", @what_print) . ")"; eval $printf_code; } } ######## # NAME # asmcmdtmpl_process_mktmpl # # DESCRIPTION # This function processes the asmcmd command mktmpl. # # PARAMETERS # dbh (IN) - initialized database handle, must be non-null. # # RETURNS # Null. # # NOTES # Only asmcmdtmpl_process_cmd() calls this function. ######## sub asmcmdtmpl_process_mktmpl { my ($dbh) = shift; my (%args); my ($qry, $ret); my ($redun, $pri_zn, $sec_zn, $dgname); my ($name); my (@attrs); # Get option parameters, if any. $ret = asmcmdtmpl_parse_int_args($asmcmdglobal_hash{'cmd'}, \%args); return unless defined ($ret); if (!defined($args{'G'})) { asmcmdtmpl_syntax_error($asmcmdglobal_hash{'cmd'}); return; } $dgname = $args{'G'}; if (!defined($ARGV[0])) { asmcmdtmpl_syntax_error($asmcmdglobal_hash{'cmd'}); return; } $name = $ARGV[0]; #striping if (defined($args{'striping'})) { push(@ARGV,"--".$args{'striping'}); GetOptions (\%args, 'coarse','fine'); pop(@ARGV); if(defined($args{'coarse'}) ^ defined($args{'fine'})) { push (@attrs, 'COARSE') if (defined($args{'coarse'})); push (@attrs, 'FINE') if (defined($args{'fine'})); } else { asmcmdtmpl_syntax_error($asmcmdglobal_hash{'cmd'}); return; } } #redundancy if (defined($args{'redundancy'})) { $redun = $args{'redundancy'}; push(@ARGV,"--".$args{'redundancy'}); GetOptions (\%args, 'unprotected','mirror','high'); pop(@ARGV); # (A XOR B XOR C) && !(A AND B AND C) if((defined($args{'unprotected'}) ^ defined($args{'mirror'}) ^ defined($args{'high'})) && !(defined($args{'unprotected'}) && defined($args{'mirror'}) && defined($args{'high'}))) { push (@attrs, 'UNPROTECTED') if (defined($args{'unprotected'})); push (@attrs, 'MIRROR') if (defined($args{'mirror'})); push (@attrs, 'HIGH') if (defined($args{'high'})); } else { asmcmdtmpl_syntax_error($asmcmdglobal_hash{'cmd'}); return; } } #pri-zone if (defined($args{'primary'})) { $pri_zn = $args{'primary'}; push(@ARGV,"--".$args{'primary'}); GetOptions (\%args, 'hot','cold'); pop(@ARGV); if(defined($args{'hot'}) ^ defined($args{'cold'})) { if(defined($args{'hot'})) { push (@attrs, 'HOT'); delete($args{'hot'}); } elsif(defined($args{'cold'})) { push (@attrs, 'COLD'); delete($args{'cold'}); } } else { asmcmdtmpl_syntax_error($asmcmdglobal_hash{'cmd'}); return; } } #sec zone if (defined($args{'secondary'})) { $sec_zn = $args{'secondary'}; push(@ARGV,"--".$args{'secondary'}); GetOptions (\%args, 'hot','cold'); if(defined($args{'hot'}) ^ defined($args{'cold'})) { if(defined($args{'hot'})) { push (@attrs, 'MIRRORHOT'); delete($args{'hot'}); } elsif(defined($args{'cold'})) { push (@attrs, 'MIRRORCOLD'); delete($args{'cold'}); } } else { asmcmdtmpl_syntax_error($asmcmdglobal_hash{'cmd'}); return; } } $qry = "ALTER DISKGROUP " . $dgname . " ADD TEMPLATE " . $name; if (@attrs) { $qry .= ' ATTRIBUTES(' .join(' ', @attrs) . ')'; } $ret= asmcmdshare_do_stmt($dbh, $qry); warn "$DBI::errstr\n" unless defined ($ret); } ######## # NAME # asmcmdtmpl_process_chtmpl # # DESCRIPTION # This function processes the asmcmd command chtmpl. # # PARAMETERS # dbh (IN) - initialized database handle, must be non-null. # # RETURNS # Null. # # NOTES # Only asmcmdtmpl_process_cmd() calls this function. ######## sub asmcmdtmpl_process_chtmpl { my ($dbh) = @_; my (%args); my ($qry, $ret); my ($redun, $pri_zn, $sec_zn, $dgname); my ($name); my (@attrs); # Get option parameters, if any. $ret = asmcmdtmpl_parse_int_args($asmcmdglobal_hash{'cmd'}, \%args); return unless defined ($ret); # get the diskgroup name if (!defined($args{'G'})) { asmcmdtmpl_syntax_error($asmcmdglobal_hash{'cmd'}); return; } $dgname = $args{'G'}; # get the template name if (!defined($ARGV[0])) { asmcmdtmpl_syntax_error($asmcmdglobal_hash{'cmd'}); return; } $name = $ARGV[0]; $qry = "ALTER DISKGROUP " . $dgname . " MODIFY TEMPLATE " . $name; #striping if (defined($args{'striping'})) { push(@ARGV,"--".$args{'striping'}); GetOptions (\%args, 'coarse','fine'); pop(@ARGV); if(defined($args{'coarse'}) ^ defined($args{'fine'})) { push (@attrs, 'COARSE') if (defined($args{'coarse'})); push (@attrs, 'FINE') if (defined($args{'fine'})); } else { asmcmdtmpl_syntax_error($asmcmdglobal_hash{'cmd'}); return; } } #redundancy if (defined($args{'redundancy'})) { $redun = $args{'redundancy'}; push(@ARGV,"--".$args{'redundancy'}); GetOptions (\%args, 'unprotected','mirror','high'); pop(@ARGV); # (A XOR B XOR C) && !(A AND B AND C) if((defined($args{'unprotected'}) ^ defined($args{'mirror'}) ^ defined($args{'high'})) && !(defined($args{'unprotected'}) && defined($args{'mirror'}) && defined($args{'high'}))) { push (@attrs, 'UNPROTECTED') if (defined($args{'unprotected'})); push (@attrs, 'MIRROR') if (defined($args{'mirror'})); push (@attrs, 'HIGH') if (defined($args{'high'})); } else { asmcmdtmpl_syntax_error($asmcmdglobal_hash{'cmd'}); return; } } #pri-zone if (defined($args{'primary'})) { $pri_zn = $args{'primary'}; push(@ARGV,"--".$args{'primary'}); GetOptions (\%args, 'hot','cold'); if(defined($args{'hot'}) ^ defined($args{'cold'})) { if(defined($args{'hot'})) { push (@attrs, 'HOT'); delete($args{'hot'}); } elsif(defined($args{'cold'})) { push (@attrs, 'COLD'); delete($args{'cold'}); } } else { asmcmdtmpl_syntax_error($asmcmdglobal_hash{'cmd'}); return; } } #sec zone if (defined($args{'secondary'})) { $sec_zn = $args{'secondary'}; push(@ARGV,"--".$args{'secondary'}); GetOptions (\%args, 'hot','cold'); if(defined($args{'hot'}) ^ defined($args{'cold'})) { if(defined($args{'hot'})) { push (@attrs, 'MIRRORHOT'); delete($args{'hot'}); } elsif(defined($args{'cold'})) { push (@attrs, 'MIRRORCOLD'); delete($args{'cold'}); } } else { asmcmdtmpl_syntax_error($asmcmdglobal_hash{'cmd'}); return; } } if (@attrs) { $qry .= ' ATTRIBUTES(' .join(' ', @attrs) . ')'; } $ret= asmcmdshare_do_stmt($dbh, $qry); warn "$DBI::errstr\n" unless defined ($ret); } ######## # NAME # asmcmdtmpl_process_rmtmpl # # DESCRIPTION # This function processes the asmcmd command rmtmpl. # # PARAMETERS # dbh (IN) - initialized database handle, must be non-null. # # RETURNS # Null. # # NOTES # Only asmcmdtmpl_process_cmd() calls this function. ######## sub asmcmdtmpl_process_rmtmpl { my ($dbh) = shift; my (%args); my ($qry, $ret); my ($dgname, $name); # Get option parameters, if any. $ret = asmcmdtmpl_parse_int_args($asmcmdglobal_hash{'cmd'}, \%args); return unless defined ($ret); # get the diskgroup name if (!defined($args{'G'})) { asmcmdtmpl_syntax_error($asmcmdglobal_hash{'cmd'}); return; } $dgname = $args{'G'}; # get the template name if (!defined($ARGV[0])) { asmcmdtmpl_syntax_error($asmcmdglobal_hash{'cmd'}); return; } $name = $ARGV[0]; $qry = "ALTER DISKGROUP " . $dgname . " DROP TEMPLATE " . $name; $ret= asmcmdshare_do_stmt($dbh, $qry); warn "$DBI::errstr\n" unless defined ($ret); } ######## # NAME # asmcmdtmpl_is_cmd # # DESCRIPTION # This routine checks if a user-entered command is one of the known # ASMCMD internal commands that belong to the ASMCMDTMPL module. # # PARAMETERS # arg (IN) - user-entered command name string. # # RETURNS # True if $arg is one of the known commands, false otherwise. ######## sub asmcmdtmpl_is_cmd { my ($arg) = shift; return defined ( $asmcmdtmpl_cmds{ $arg } ); } ######## # NAME # asmcmdtmpl_is_wildcard_cmd # # DESCRIPTION # This routine determines if an ASMCMDTMPL 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 asmcmdtmpl_is_wildcard_cmd { my ($arg) = shift; return defined ($asmcmdtmpl_cmds{ $arg }) && defined ($asmcmdtmpl_cmds{ $arg }{ wildcard }); } ######## # NAME # asmcmdtmpl_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 asmcmdtmpl module currently supports only the help as a command # that does not require an ASM instance. ######## sub asmcmdtmpl_is_no_instance_cmd { my ($arg) = shift; return !defined ($asmcmdtmpl_cmds{ $arg }) || !defined ($asmcmdtmpl_cmds{ $arg }{ no_instance }); } ######## # NAME # asmcmdtmpl_parse_int_args # # DESCRIPTION # This routine parses the arguments for flag options for ASMCMD 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 ASMCMD internal command. ######## sub asmcmdtmpl_parse_int_args { my ($cmd, $args_ref) = @_; my @string; my $key; #build the list of options to parse using GetOptions if($asmcmdtmpl_cmds{ $cmd }{ flags }) { foreach $key(keys %{$asmcmdtmpl_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. # asmcmdtmpl_syntax_error($cmd); return undef; } return 0; } ######## # NAME # asmcmdtmpl_syntax_error # # DESCRIPTION # This routine prints the correct syntax for a command to STDERR, used # when there is a syntax error. If the command with bad syntax is asmcmd # itself, then asmcmdbase_syntax_error also calls exit() to quit out. # # PARAMETERS # cmd (IN) - user-entered command name string. # # RETURNS # Exits if cmd is "asmcmd" or "asmcmd_no_conn_str"; 1 if another command # that 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. Thus, even if exit() is called, the exit value is # zero. ######## sub asmcmdtmpl_syntax_error { my ($cmd) = shift; my ($cmd_syntax); # Correct syntax for $cmd. # my ($succ) = 0; $cmd_syntax = asmcmdtmpl_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 # asmcmdtmpl_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 asmcmdtmpl_get_cmd_syntax { my ($cmd) = shift; my (%cmd_syntax); # Hash storing the syntax for each internal command. # $cmd_syntax{'lstmpl'} = 'lstmpl [-Hl] [-G dgname] [pattern]'; $cmd_syntax{'mktmpl'} = 'mktmpl <-G dgname> [--striping ] '. '[--redundancy ] '. '[--primary ] [--secondary ]'. ' name'; $cmd_syntax{'chtmpl'} = 'chtmpl <-G dgname> [--striping ] ' . '[--redundancy ] '. '[--primary ] [--secondary ]'. ' name'; $cmd_syntax{'rmtmpl'} = 'rmtmpl <-G dgname> name'; return $cmd_syntax{$cmd}; } ######## # NAME # asmcmdtmpl_process_help # # DESCRIPTION # This function is the help function for the asmcmdtmpl module. # # PARAMETERS # command (IN) - display the help message for this command. # # RETURNS # 1 if command found; 0 otherwise. ######## sub asmcmdtmpl_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 (asmcmdtmpl_is_cmd ($command)) { # User specified a command name to look up. # $syntax = asmcmdtmpl_get_cmd_syntax($command); $desc = asmcmdtmpl_get_cmd_desc($command); print " $syntax\n" . "$desc\n"; $succ = 1; } return $succ; } ######## # NAME # asmcmdtmpl_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. ######## sub asmcmdtmpl_get_asmcmd_cmds { my ($asmcmd_cmds) = " chtmpl, lstmpl, mktmpl, rmtmpl\n" ; return ($asmcmd_cmds); } 1;