# Copyright (c) 2004, 2009, Oracle and/or its affiliates. All rights reserved. # # NAME # asmcmdvol - ASM CoMmanD line interface for VOLume commands # # DESCRIPTION # ASMCMD is a Perl utility that provides easy nagivation of files within # ASM diskgroups. This module contains the functionality for # the ASM volume commands. # # NOTES # usage: asmcmdcore [-p] [command] # # MODIFIED (MM/DD/YY) # sanselva 06/22/09 - volcreate --secondary option not set correctly # sanselva 06/17/09 - correct check for --primary and --secondary # sanselva 04/12/09 - ASMCMD long options and consistency # heyuen 04/06/09 - fix asmcmd_error_msg # bonelso 03/04/09 - OFS -> ACFS and add support for K suffix in resize # heyuen 10/14/08 - use dynamic modules # bonelso 10/09/08 - Add back help text for volstat # gsanders 08/05/08 - fix merge errors from 07/28 version # heyuen 07/28/08 - use command properties array # gsanders 07/10/08 - fix bug 6963383 require -d dgname option # heyuen 04/09/08 - reorder help commands and improve help message. # averhuls 04/01/08 - add to volinfo documentation. # averhuls 03/05/08 - Add -v and -g undocumented switches to volinfo. # josmith 01/05/08 - Put single quotes around list of volumes # josmith 12/13/07 - Don't put single quotes around DG names # josmith 11/21/07 - Bug 6629935 - Need quotes around identifiers # averhuls 11/15/07 - Document volset needing quotes if options contain # spaces # josmith 11/14/07 - Add resize_unit_mb column # averhuls 11/14/07 - Warn users before shrinking a non-ACFS volume. # josmith 11/02/07 - Change volume redundancy # josmith 10/17/07 - Support zones # josmith 06/20/07 - Make columns consistent with v # heyuen 05/25/07 - add return codes for errors # averhuls 04/10/07 - Bug 5958908 and 5958923 fixes # Re-document volset # averhuls 03/01/07 - add asmcmdvol_is_no_instance_cmd # josmith 09/03/06 - Add wildcard subroutine # averhuls 09/01/06 - Add process_help # averhuls 07/18/06 - Undocument volset as it intended as an internal # command. # averhuls 06/23/06 - Created # ############################################################################# # ############################ Functions List ################################# # # asmcmdvol_process_volcreate # asmcmdvol_process_voldelete # asmcmdvol_process_voldisable # asmcmdvol_process_volenable # asmcmdvol_process_volinfo # asmcmdvol_process_volresize # asmcmdvol_process_volset # asmcmdvol_process_volstat # # SQL Routines # asmcmdvol_volcreate_sql # asmcmdvol_voldelete_sql # asmcmdvol_volenable_disable_sql # asmcmdvol_volresize_sql # asmcmdvol_volset_sql # # Help Routines # asmcmdvol_get_cmd_desc # asmcmdvol_get_cmd_syntax # asmcmdvol_get_asmcmd_cmds # # Parameter Parsing Routines # asmcmdvol_is_cmd # asmcmdvol_parse_int_args ############################################################################# package asmcmdvol; require Exporter; our @ISA = qw(Exporter); #our @EXPORT = qw(asmcmdvol_init); use strict; use Getopt::Long qw(:config no_ignore_case bundling); use asmcmdglobal; use asmcmdshare; ####################### ASMCMDVOL Global Variables ######################## our (%asmcmdvol_cmds) = ( volcreate => {no_instance => 'True', flags => {'G=s'=>'diskGroup', 'column=s'=> 'noOfColumns', 'primary=s'=> 'primaryRegion', 'secondary=s'=> 'secondaryRegion', 'redundancy=s'=> 'redundancyType', 's=s'=>'size', 'width=s'=> 'stripeWidth'} }, voldelete => {no_instance => 'True', flags => {'G=s'=>'diskGroup'} }, voldisable => {no_instance => 'True', flags => {'G=s'=>'diskGroup', 'a'=>'all'} }, volenable => {no_instance => 'True', flags => {'G=s'=>'diskGroup', 'a'=>'all'} }, volinfo => {no_instance => 'True', flags => {'G=s'=>'diskGroup', 'a'=>'all', 'show_diskgroup=s'=> 'displayDiskGroupName', 'show_volume=s'=> 'displayVolumeName'} }, volresize => {no_instance => 'True', flags => {'G=s'=>'diskGroup', 'f'=>'force', 's=s'=>'size'} }, volset => {flags => {'G=s'=>'diskGroup', 'primary=s'=> 'primaryRegion', 'secondary=s'=> 'secondaryRegion', 'usagestring=s'=> 'usageString2TagVol', 'mountpath=s'=> 'mountPath'} }, volstat => {flags => {'G=s'=>'diskGroup', 'show_volume'=> 'displayVolumeName'} } ); sub is_asmcmd { return 1; } ######## # NAME # init # # DESCRIPTION # This function initializes the asmcmdvol module. It simply registers # its callbacks with the asmcmdglobal module. Note that you must register # all 8 callbacks - even if the module has no corresponding function. # # 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, \&asmcmdvol_process_cmd); push (@asmcmdglobal_help_callbacks, \&asmcmdvol_process_help); push (@asmcmdglobal_command_list_callbacks, \&asmcmdvol_get_asmcmd_cmds); push (@asmcmdglobal_is_command_callbacks, \&asmcmdvol_is_cmd); push (@asmcmdglobal_is_wildcard_callbacks, \&asmcmdvol_is_wildcard_cmd); push (@asmcmdglobal_syntax_error_callbacks, \&asmcmdvol_syntax_error); push (@asmcmdglobal_no_instance_callbacks, \&asmcmdvol_is_no_instance_cmd); push (@asmcmdglobal_error_message_callbacks, \&asmcmdvol_error_msg); push (@asmcmdglobal_signal_exception_callbacks, \&asmcmdvol_signal_exception); %asmcmdglobal_cmds = (%asmcmdglobal_cmds, %asmcmdvol_cmds); #Perform ASMCMD consistency check if enabled if($asmcmdglobal_hash{'consistchk'} eq 'y') { if(!asmcmdshare_check_option_consistency(%asmcmdvol_cmds)) { exit 1; } } } ######## # NAME # process_cmd # # DESCRIPTION # This routine calls the appropriate routine to process the command # specified by $asmcmdglobal_hash{'cmd'}. # # PARAMETERS # dbh (IN) - initialized datavol handle, must be non-null. # # RETURNS # 1 if command is found in the asmcmdvol module; 0 if not. # # NOTES # Only asmcmdcore_shell() calls this routine. ######## sub asmcmdvol_process_cmd { my ($dbh) = @_; my ($succ) = 0; # Get current command from global value, which is set by # asmcmdvol_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 ASMCMD volume command. my (%cmdhash) = ( volcreate => \&asmcmdvol_process_volcreate, voldelete => \&asmcmdvol_process_voldelete, voldisable => \&asmcmdvol_process_voldisable, volenable => \&asmcmdvol_process_volenable, volinfo => \&asmcmdvol_process_volinfo, volresize => \&asmcmdvol_process_volresize, volset => \&asmcmdvol_process_volset, volstat => \&asmcmdvol_process_volstat, ); if (defined ( $cmdhash{ $cmd } )) { # If user specifies a known command, then call routine to process it. # $cmdhash{ $cmd }->($dbh); $succ = 1; } return $succ; } ######## # NAME # asmcmdvol_process_help # # DESCRIPTION # This function is the help function for the asmcmdvol module. # # PARAMETERS # command (IN) - display the help message for this command. # # RETURNS # 1 if command found; 0 otherwise. ######## sub asmcmdvol_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 (asmcmdvol_is_cmd ($command)) { # User specified a command name to look up. # $syntax = asmcmdvol_get_cmd_syntax($command); $desc = asmcmdvol_get_cmd_desc($command); # The following check prevents an "undefined value" error message for # legal commands that have no help information. if (defined $desc) { print " $syntax\n" . "$desc\n"; $succ = 1; } else { $succ = 0; } } return $succ; } ######## # NAME # asmcmdvol_process_volcreate # # DESCRIPTION # This top-level routine processes the volcreate command. # # PARAMETERS # dbh (IN) - initialized handle, must be non-null. # # RETURNS # Null. # # NOTES # Only asmcmdvol_process_cmd() can call this routine. ######## sub asmcmdvol_process_volcreate { my ($dbh) = shift; my (%args); # Argument hash used by getopts(). # my ($ret); # asmcmdvol_parse_int_args() return value. # my ($volname); # volume name to create (required user parameter) # my ($dgname); # name of mounted diskgroup (required user parameter) # my ($size); # volume size (required user parameter) # my ($stripe_columns); # stripe columns (optional user parameter) # my ($stripe_width); # stripe width (optional user parameter) # my ($redundancy); # redundancy (optional user parameter) # my ($primary_zone); # disk zone for primary extents (optional) # my ($mirror_zone); # disk zone for mirrored extents (optional) # # Check if minimum number of required parameters are correct. # For example "foo bar -s 100M". if (@ARGV < 5) { asmcmdvol_syntax_error($asmcmdglobal_hash{'cmd'}); return; } # parse options $ret = asmcmdvol_parse_int_args($asmcmdglobal_hash{'cmd'}, \%args); return unless defined ($ret); # get and validate diskgroup name (-G required) if (!defined($args{'G'})) { print STDERR "diskgroup name must be specified\n"; return; } $dgname = $args{'G'}; if ($dgname =~ /\W/) { printf (STDERR "invalid diskgroup name \"%s\"\n", $dgname); return; } # get and validate volume name (last arg - required) $volname = pop @ARGV; if ( ! $volname ) { print STDERR "volume name must be specified\n"; return; } if ($volname =~ /\W/) { printf (STDERR "invalid volume name \"%s\"\n", $volname); return; } # validate option parameters - "-s" is required . if (!defined($args{'s'})) { print STDERR "volume size must be specified\n"; return; } else { $size = $args{'s'}; } # initialize optional parameters $redundancy = 'default'; $stripe_columns = 'default'; $stripe_width = 'default'; if (defined($args{'redundancy'})) # Get redundancy. # { # user can specifiy in upper or lower case $redundancy = $args{'redundancy'}; tr/a-z/A-Z/ for $redundancy; # normally I would let SQL field this error but the SQL error message # is just awful. if (($redundancy ne 'UNPROTECTED') && ($redundancy ne 'MIRROR') && ($redundancy ne 'HIGH')) { printf (STDERR "invalid redundancy type \"%s\" specified\n", $redundancy); return; } } if (defined($args{'column'})) # Get stripe columns. # { $stripe_columns = $args{'column'}; } if (defined($args{'width'})) # Get stripe width. # { $stripe_width = $args{'width'}; } if (defined($args{'primary'})) # Get primary zone # { #Run GetOpts on the value to support first unique chars for option push(@ARGV,"--".$args{'primary'}); GetOptions (\%args, 'hot','cold'); pop(@ARGV); if(defined($args{'hot'}) ^ defined($args{'cold'})) { if(defined($args{'hot'})) { $primary_zone = 'HOT'; delete($args{'hot'}); } elsif(defined($args{'cold'})) { $primary_zone = 'COLD'; delete($args{'cold'}); } } else { # part of the user input could not be parsed asmcmdvol_syntax_error($asmcmdglobal_hash{'cmd'}); return; } } if (defined($args{'secondary'})) # Get secondary zone # { #Run GetOpts on the value to support first unique chars for option push(@ARGV,"--".$args{'secondary'}); GetOptions (\%args, 'hot','cold'); pop(@ARGV); if(defined($args{'hot'}) ^ defined($args{'cold'})) { if(defined($args{'hot'})) { $mirror_zone = 'MIRRORHOT'; delete($args{'hot'}); } elsif(defined($args{'cold'})) { $mirror_zone = 'MIRRORCOLD'; delete($args{'cold'}); } } else { # part of the user input could not be parsed asmcmdvol_syntax_error($asmcmdglobal_hash{'cmd'}); return; } } if (@ARGV != 0) { # part of the user input could not be parsed asmcmdvol_syntax_error($asmcmdglobal_hash{'cmd'}); return; } # Run SQL to create the volume. asmcmdvol_volcreate_sql ($dbh, $dgname, $volname, $size, $redundancy, $stripe_columns, $stripe_width, $primary_zone, $mirror_zone); } ######## # NAME # asmcmdvol_process_voldelete # # DESCRIPTION # This top-level routine processes the voldelete command. # # PARAMETERS # dbh (IN) - initialized handle, must be non-null. # # RETURNS # Null. # # NOTES # Only asmcmdvol_process_cmd() can call this routine. ######## sub asmcmdvol_process_voldelete { my ($dbh) = shift; my (%args); # Argument hash used by getopts(). # my ($ret); # asmcmdvol_parse_int_args() return value. # my ($volname); # volume name to delete # my ($dgname); # name of mounted diskgroup # # the diskgroup name option and volume name must be specified if (@ARGV != 3) { asmcmdvol_syntax_error($asmcmdglobal_hash{'cmd'}); return; } # parse options $ret = asmcmdvol_parse_int_args($asmcmdglobal_hash{'cmd'}, \%args); return unless defined ($ret); # get and validate diskgroup name (-d required) if (!defined($args{'G'})) { print STDERR "diskgroup name must be specified\n"; return; } $dgname = $args{'G'}; if ($dgname =~ /\W/) { printf (STDERR "invalid diskgroup name \"%s\"\n", $dgname); return; } # Get the volume name. $volname = pop(@ARGV); if ( ! $volname ) { print STDERR "volume name must be specified\n"; return; } if ($volname =~ /\W/) { printf (STDERR "invalid volume name \"%s\"\n", $volname); return; } # Run SQL to delete the volume. asmcmdvol_voldelete_sql ($dbh, $dgname, $volname); } ######## # NAME # asmcmdvol_process_volenable # asmcmdvol_process_voldisable # # DESCRIPTION # This top-level routine processes the volenable command. # This top-level routine processes the voldisable command. # # PARAMETERS # dbh (IN) - initialized datavol handle, must be non-null. # # RETURNS # Null. # # NOTES # Only asmcmdvol_process_cmd() can call asmcmdvol_process_voldisable # and asmcmdvol_process_volenable. # # Since the volenable and voldisable commands have the same arguments, # it makes sense to have the commands as a front end to a common function. # The only difference is whether "enable" or "disable" is sent to SQL. ######## sub asmcmdvol_process_voldisable { # add the "disable" command onto the front of the argument stack # The common routine will parse this. unshift @ARGV, 'disable'; asmcmdvol_process_volenable_disable(@_); } sub asmcmdvol_process_volenable { # add the "enable" command onto the front of the argument stack # The common routine will parse this. unshift @ARGV, 'enable'; asmcmdvol_process_volenable_disable(@_); } # The common function for volenable and voldisable. sub asmcmdvol_process_volenable_disable { my ($dbh) = shift; my (%args); # Argument hash used by getopts(). # my ($ret); # asmcmdvol_parse_int_args() return value. # my ($cmd_name); # SQL "enable" or "disable" statement # my ($volname); # volume name to enable/disable # my ($dgname); # name of mounted diskgroup # my ($validargs); # Is argument list valid? # # "enable" or "disable" - NOT user supplied $cmd_name = shift(@ARGV); # initialize required parameters. if the user does not specify, # all diskgroups and/or all volumes are enabled/disabled. $dgname = 'all'; $volname = 'all'; # validate parameters, if any. since this routine is NOT called directly # from asmcmdvol_process_cmd(), we have to play some games to get the # user supplied command name. $ret = asmcmdvol_parse_int_args('vol' . $cmd_name, \%args); return unless defined ($ret); # Verify valid set of arguments. $validargs = ( (!defined($args{'a'}) && defined($args{'G'}) && @ARGV == 1) || (defined($args{'a'}) && @ARGV == 0) ); if (!$validargs) { asmcmdvol_syntax_error($asmcmdglobal_hash{'cmd'}); return; } if (defined($args{'G'})) # Get diskgroup name. # { $dgname = $args{'G'}; } else { $dgname = 'all'; } if (defined($args{'a'})) # Get volume name. # { $volname = 'all'; } else { $volname = shift(@ARGV); # Put single quotes around the volume name for SQL $volname = "'$volname'"; } # Run SQL to enable/disable the volume. asmcmdvol_volenable_disable_sql ($dbh, $cmd_name, $dgname, $volname); } ######## # NAME # asmcmdvol_process_volinfo # # DESCRIPTION # This top-level routine processes the volinfo command. # # PARAMETERS # dbh (IN) - initialized handle, must be non-null. # # RETURNS # Null. # # NOTES # Only asmcmdvol_process_cmd() can call this routine. ######## sub asmcmdvol_process_volinfo { my ($dbh) = shift; my (%args); # Argument hash used by getopts(). # my ($ret); # asmcmdvol_parse_int_args() return value. # my ($sql); #SQL select command # my ($sth); # SQL statement handle. # my ($row); # One row results returned from the SQL execution. # my ($dgname); #diskgroup name # my ($volname); # volume name # my ($cur_dgname); # determines when to print dg # my ($report); # set when data is printed - used for error reporting # my ($device_name); # used only to report volume name or diskgroup name # my ($validargs); # Is argument list valid? # # validate option parameters, if any. $ret = asmcmdvol_parse_int_args($asmcmdglobal_hash{'cmd'}, \%args); return unless defined ($ret); # Verify valid set of arguments. $validargs = ( (!defined($args{'a'}) && defined($args{'G'}) && @ARGV == 1) || (defined($args{'show_diskgroup'}) && @ARGV == 0) || (defined($args{'show_volume'}) && @ARGV == 0) || (defined($args{'a'}) && @ARGV == 0) ); if (!$validargs) { asmcmdvol_syntax_error($asmcmdglobal_hash{'cmd'}); return; } if (defined($args{'G'})) # Get diskgroup name. # { $dgname = $args{'G'}; } else { $dgname = 'all'; } if (defined($args{'a'})) # Get volume name. # { $volname = 'all'; } else { $volname = shift(@ARGV); } # The --show_diskgroup and --show_volume options are for internal use only # and are not documented in "usage" or "help". if (defined($args{'show_diskgroup'})) # output ONLY the diskgroup name { $device_name = $args{'show_diskgroup'}; } if (defined($args{'show_volume'})) # output ONLY the volume name { $device_name = $args{'show_volume'}; } # if a diskgroup is specified, does it exist? if (defined($args{'G'})) { my ($dg_uc) = uc($dgname); $sql = "select * from V\$ASM_DISKGROUP_STAT where name = '$dg_uc'"; # perform the SQL select $sth = asmcmdshare_do_select($dbh, $sql); return undef if (! defined ($sth)); $row = asmcmdshare_fetch($sth); if (!defined($row)) { print "diskgroup $dgname is not mounted or does not exist\n"; return; } } # Note1: All that we want from V$ASM_DISKGROUP is the diskgroup name. # Note2: it looks like diskgroups are sorted in dg number order - which is # what we want. But, just to be sure, we enforce sort order here. In # addition, we also sort by volume name within the diskgroup. # Note3: The order of the fixed views is important! Both V$ASM_DISKGROUP # and V$ASM_VOLUME have a STATE column. The order below ensures that we get # the V$ASM_VOLUME state and not the V$ASM_DISKGROUP state. $sql = "select * from V\$ASM_DISKGROUP_STAT join V\$ASM_VOLUME on V\$ASM_VOLUME.GROUP_NUMBER = V\$ASM_DISKGROUP_STAT.GROUP_NUMBER order by V\$ASM_DISKGROUP_STAT.GROUP_NUMBER, V\$ASM_VOLUME.VOLUME_NAME"; # perform the SQL select $sth = asmcmdshare_do_select($dbh, $sql); return undef if (! defined ($sth)); # process the volumes $cur_dgname = 'none'; $report = 0; while (defined ($row = asmcmdshare_fetch($sth))) { if (defined($args{'G'}) && (uc($dgname) ne $row->{'NAME'})) { # a dgname was specified on the cmd line and this row isn't it - continue next; } if ((defined($args{'show_diskgroup'})) || (defined($args{'show_volume'}))) { if ($device_name ne $row->{'VOLUME_DEVICE'}) { # We're looking for a specific device and this isn't it - continue. next; } } elsif ((!defined($args{'a'})) && (uc($volname) ne $row->{'VOLUME_NAME'})) { # a volname was specified on the cmd line and this row isn't it - continue next; } if (defined($device_name)) { # We have already verified that this is the device we are looking for. # # We are printing either the diskgroup name or the volume name # and NOTHING else. if (defined($args{'show_diskgroup'})) { # output only the diskgroup name printf("%s\n", lc($row->{'NAME'})); } elsif (defined($args{'show_volume'})) { # output only the volume name printf("%s\n", lc($row->{'VOLUME_NAME'})); } asmcmdshare_finish ($sth); return; } if ($cur_dgname ne $row->{'NAME'}) { my($dgnum, $dgnam); # This is the first time that we've seen this disk group, so # print the dg number and name - remember that this list is sorted. # Perl complains if the printf line wraps. $dgnum = $row->{'GROUP_NUMBER'}; $dgnam = $row->{'NAME'}; printf "Diskgroup Name: $dgnam\n\n"; # Indicate that we've seen this diskgroup. $cur_dgname = $dgnam; } $report = 1; # we found information to print # Format and print the volume information. printf "\t Volume Name: $row->{'VOLUME_NAME'}\n"; printf "\t Volume Device: $row->{'VOLUME_DEVICE'}\n"; printf "\t State: $row->{'STATE'}\n"; printf "\t Size (MB): $row->{'SIZE_MB'}\n"; printf "\t Resize Unit (MB): $row->{'RESIZE_UNIT_MB'}\n"; printf "\t Redundancy: $row->{'REDUNDANCY'}\n"; printf "\t Stripe Columns: $row->{'STRIPE_COLUMNS'}\n"; printf "\t Stripe Width (K): $row->{'STRIPE_WIDTH_K'}\n"; printf "\t Usage: "; if (defined($row->{'USAGE'})) { printf "$row->{'USAGE'}"; } printf "\n"; printf "\t Mountpath: "; if (defined($row->{'MOUNTPATH'})) { printf ("%s ", $row->{'MOUNTPATH'}); } print "\n"; print "\n"; } if (!$report) { if (defined($args{'G'}) && !defined($args{'a'})) { printf("volume %s not found in diskgroup %s\n", $volname, $dgname); } elsif (defined($args{'G'})) { printf("diskgroup %s has no volumes or is not mounted\n", $dgname); } elsif ((defined($args{'show_diskgroup'})) || (defined($args{'show_volume'}))) { printf("no device name \"%s\" found\n", $device_name); } else { printf("no volumes found\n"); } } asmcmdshare_finish ($sth); } ######## # NAME # asmcmdvol_process_volresize # # DESCRIPTION # This top-level routine processes the volresize command. # # PARAMETERS # dbh (IN) - initialized datavol handle, must be non-null. # # RETURNS # Null. # # NOTES # Only asmcmdvol_process_cmd() can call this routine. ######## sub asmcmdvol_process_volresize { my ($dbh) = shift; my (%args); # Argument hash used by getopts(). # my ($ret); # asmcmdvol_parse_int_args() return value. # my ($volname); # volume name to resize # my ($dgname); # name of mounted diskgroup # my ($newsize); # new size of volume # my ($cursize); # current size of volume # my ($usage); # usage string of volume # my ($force); # force option # my ($sql); # SQL select statement # my ($sth); # SQL statement handle # my ($row); # One row results returned from the SQL execution # if (!((@ARGV == 5) || (@ARGV == 6))) { # must have dgname, volname, and -s newsize asmcmdvol_syntax_error($asmcmdglobal_hash{'cmd'}); return; } # parse options $ret = asmcmdvol_parse_int_args($asmcmdglobal_hash{'cmd'}, \%args); return unless defined ($ret); # get and validate diskgroup name (-G required) if (!defined($args{'G'})) { print STDERR "diskgroup name must be specified\n"; return; } $dgname = $args{'G'}; if ($dgname =~ /\W/) { printf (STDERR "invalid diskgroup name \"%s\"\n", $dgname); return; } # get and validate volume name (last arg - required) $volname = pop(@ARGV); if ( ! $volname ) { print STDERR "volume name must be specified\n"; return; } if ($volname =~ /\W/) { printf (STDERR "invalid volume name \"%s\"\n", $volname); return; } # get required -s parameter. $ret = asmcmdvol_parse_int_args($asmcmdglobal_hash{'cmd'}, \%args); return unless defined ($ret); # we will not have gotten here if -s was not specified $newsize = $args{'s'}; # force option if (defined($args{'f'})) { $force = 1; } # check to see if this is a non ACFS volume. # If so and the new size is less than the current size, warn the user. $sql = "select * from V\$ASM_VOLUME join V\$ASM_DISKGROUP on V\$ASM_DISKGROUP.GROUP_NUMBER = V\$ASM_VOLUME.GROUP_NUMBER"; # perform the SQL select $sth = asmcmdshare_do_select($dbh, $sql); return undef if (! defined ($sth)); # process the volumes while (defined ($row = asmcmdshare_fetch($sth))) { tr/a-z/A-Z/ for $dgname; tr/a-z/A-Z/ for $volname; if (($dgname eq $row->{'NAME'}) && ($volname eq $row->{'VOLUME_NAME'})) { $cursize = $row->{'SIZE_MB'}; if (defined($row->{'USAGE'})) { $usage = $row->{'USAGE'}; } else { $usage = "not defined"; } last; } } # did we find the volume? if (!defined($cursize)) { printf (STDERR "diskgroup \"%s\" " , $dgname); printf (STDERR "volume \"%s\" not found\n", $volname); return; } # newsize must be in MB for the size test if (($newsize =~ m/k/) || ($newsize =~ m/K/)) { $newsize =~ s/k//; $newsize =~ s/K//; if($newsize != 0) { $newsize = int (($newsize+1023) / 1024); } } elsif (($newsize =~ m/m/) || ($newsize =~ m/M/)) { $newsize =~ s/m//; $newsize =~ s/M//; } elsif (($newsize =~ m/g/) || ($newsize =~ m/G/)) { $newsize =~ s/g//; $newsize =~ s/G//; $newsize *= 1024; } elsif (($newsize =~ m/t/) || ($newsize =~ m/T/)) { $newsize =~ s/t//; $newsize =~ s/T//; $newsize *= (1024 * 1024); } else { print "invalid size multiplier specified\n"; return; } if (($newsize < $cursize) && ($usage ne "ACFS")) { my ($response) = 'x'; print "The volume is not ACFS and the requested size "; print "is smaller than the current size.\n"; print "Data corruption may occur.\n"; if (!defined($force)) { while (($response ne 'y') && ($response ne 'n')) { print "Are you sure? [y/n]: "; $response = ; chomp ($response); } if ($response eq 'n') { return; } } } # tell SQL that the size is in MB $newsize = $newsize . "m"; # Run SQL to resize the volume. asmcmdvol_volresize_sql ($dbh, $dgname, $volname, $newsize); } ######## # NAME # asmcmdvol_process_volset # # DESCRIPTION # This top-level routine processes the volset command. # # PARAMETERS # dbh (IN) - initialized datavol handle, must be non-null. # # RETURNS # Null. # # NOTES # Only asmcmdvol_process_cmd() can call this routine. ######## sub asmcmdvol_process_volset { my ($dbh) = shift; my (%args); # Argument hash used by getopts(). # my ($ret); # asmcmdvol_parse_int_args() return value. # my ($dgname); # name of mounted diskgroup # my ($volname); # target volume name # my ($usage_string); # usage string to add to volume name # my ($mountpath); # mount path string to add to volume name # my ($primary_zone); # disk zone for primary extents (optional) # my ($mirror_zone); # disk zone for mirrored extents (optional) # # Check if number of non-option parameters are correct. if (@ARGV < 3) { asmcmdvol_syntax_error($asmcmdglobal_hash{'cmd'}); return; } # parse options $ret = asmcmdvol_parse_int_args($asmcmdglobal_hash{'cmd'}, \%args); return unless defined ($ret); # get and validate diskgroup name (-G required) if (!defined($args{'G'})) { print STDERR "diskgroup name must be specified\n"; return; } $dgname = $args{'G'}; if ($dgname =~ /\W/) { printf (STDERR "invalid diskgroup name \"%s\"\n", $dgname); return; } # get and validate volume name (last arg - required) $volname = pop(@ARGV); if ( ! $volname ) { print STDERR "volume name must be specified\n"; return; } if ($volname =~ /\W/) { printf (STDERR "invalid volume name \"%s\"\n", $volname); return; } if (defined($args{'mountpath'})) { $mountpath = $args{'mountpath'}; } if (defined($args{'usagestring'})) { $usage_string = $args{'usagestring'}; } if (defined($args{'primary'})) # Get primary zone # { #Run GetOpts on the value to support first unique chars for option push(@ARGV,"--".$args{'primary'}); GetOptions (\%args, 'hot','cold'); pop(@ARGV); if(defined($args{'hot'}) ^ defined($args{'cold'})) { if(defined($args{'hot'})) { $primary_zone = 'HOT'; delete($args{'hot'}); } elsif(defined($args{'cold'})) { $primary_zone = 'COLD'; delete($args{'cold'}); } } else { # part of the user input could not be parsed asmcmdvol_syntax_error($asmcmdglobal_hash{'cmd'}); return; } } if (defined($args{'secondary'})) # Get secondary zone # { #Run GetOpts on the value to support first unique chars for option push(@ARGV,"--".$args{'secondary'}); GetOptions (\%args, 'hot','cold'); pop(@ARGV); if(defined($args{'hot'}) ^ defined($args{'cold'})) { if(defined($args{'hot'})) { $mirror_zone = 'MIRRORHOT'; delete($args{'hot'}); } elsif(defined($args{'cold'})) { $mirror_zone = 'MIRRORCOLD'; delete($args{'cold'}); } } else { # part of the user input could not be parsed asmcmdvol_syntax_error($asmcmdglobal_hash{'cmd'}); return; } } if (!defined($usage_string) && !defined($mountpath) && !defined($mirror_zone) && !defined($primary_zone)) { asmcmdvol_process_help($asmcmdglobal_hash{'cmd'}); return; } # Run SQL to add mountpath/usage string to the volume. asmcmdvol_volset_sql ($dbh, $dgname, $volname, $usage_string, $mountpath, $primary_zone, $mirror_zone); } ######## # NAME # asmcmdvol_process_volstat # # DESCRIPTION # This top-level routine processes the volstat command. # # PARAMETERS # dbh (IN) - initialized datavol handle, must be non-null. # # RETURNS # Null. # # NOTES # Only asmcmdvol_process_cmd() can call this routine. ######## sub asmcmdvol_process_volstat { my ($dbh) = shift; my (%args); # Argument hash used by getopts(). # my ($ret); # asmcmdvol_parse_int_args() return value. # my ($sql); #SQL select command # my ($sth); # SQL statement handle. # my ($row); # One row results returned from the SQL execution. # my ($dgname); #diskgroup name # my ($volname); # volume name # my ($cur_dgname); # determines when to print dg # my ($report); # set when data is printed - used for error reporting # # validate option parameters, if any. $ret = asmcmdvol_parse_int_args($asmcmdglobal_hash{'cmd'}, \%args); return unless defined ($ret); $dgname = 'UNSPECIFIED'; if (defined($args{'G'})) # Get diskgroup name. # { $dgname = $args{'G'}; tr/a-z/A-Z/ for $dgname; # must be upper case # } # Get optional volume name $volname = 'UNSPECIFIED'; if (@ARGV != 0) { $volname = pop(@ARGV); tr/a-z/A-Z/ for $volname; # must be upper case # } if (@ARGV != 0) { # part of the user input could not be parsed asmcmdvol_syntax_error($asmcmdglobal_hash{'cmd'}); return; } # Note: it looks like diskgroups are sorted in dg number order - which is # what we want. But, just to be sure, we enforce sort order here. In # addition, we also sort by volume name within the diskgroup. $sql = "select * from V\$ASM_DISKGROUP_STAT join V\$ASM_VOLUME_STAT on V\$ASM_DISKGROUP_STAT.GROUP_NUMBER = V\$ASM_VOLUME_STAT.GROUP_NUMBER order by V\$ASM_VOLUME_STAT.GROUP_NUMBER, V\$ASM_VOLUME_STAT.VOLUME_NAME"; # perform the SQL select $sth = asmcmdshare_do_select($dbh, $sql); return undef if (! defined ($sth)); # process the volumes $cur_dgname = 'none'; $report = 0; while (defined ($row = asmcmdshare_fetch($sth))) { if (($dgname ne 'UNSPECIFIED') && ($dgname ne $row->{'NAME'})) { # a dgname was specified on the cmd line and this row isn't it - continue next; } if (($volname ne 'UNSPECIFIED') && ($volname ne $row->{'VOLUME_NAME'})) { # a volname was specified on the cmd line and this row isn't it - continue next; } if ($cur_dgname ne $row->{'NAME'}) { my($dgnum, $dgnam); # This is the first time that we've seen this disk group, so # print the dg number and name - remember that this list is sorted. # Perl complains if the printf line wraps. $dgnum = $row->{'GROUP_NUMBER'}; $dgnam = $row->{'NAME'}; printf ("\nDISKGROUP NUMBER / NAME: %d / %s\n", $dgnum, $dgnam); print "---------------------------------------\n"; # Indicate that we've seen this diskgroup. $cur_dgname = $dgnam; # Now print the volume header - one per diskgroup. printf " VOLUME_NAME\n"; printf " %-16s%-16s%-16s%-16s\n", "READS","BYTES_READ","READ_TIME","READ_ERRS"; printf " %-16s%-16s%-16s%-16s\n", "WRITES","BYTES_WRITTEN","WRITE_TIME","WRITE_ERRS"; print " -------------------------------------------------------------\n"; } $report = 1; # we found information to print # Format and print the volume statistics. print " "; printf ("%s\n", $row->{'VOLUME_NAME'}); print " "; printf ("%-16s", $row->{'READS'}); printf ("%-16s", $row->{'BYTES_READ'}); printf ("%-16s", $row->{'READ_TIME'}); printf ("%-16s", $row->{'READ_ERRS'}); print "\n"; print " "; printf ("%-16s", $row->{'WRITES'}); printf ("%-16s", $row->{'BYTES_WRITTEN'}); printf ("%-16s", $row->{'WRITE_TIME'}); printf ("%-16s", $row->{'WRITE_ERRS'}); print "\n"; } if (!$report) { if (defined($args{'G'}) && defined($args{'show_volume'})) { printf("volume %s not found in diskgroup %s\n", $args{'show_volume'}, $args{'G'}); } elsif (defined($args{'G'})) { printf("diskgroup %s has no volumes or is not mounted\n", $args{'G'}); } elsif (defined($args{'show_volume'})) { printf("no volumes \"%s\" found in any mounted diskgroup\n", $args{'show_volume'}); } else { printf("no volumes found\n"); } } asmcmdshare_finish ($sth); } ######## # NAME # asmcmdvol_volcreate_sql # # DESCRIPTION # This routine constructs the SQL used to create an ASM volume. # It calls asmcmdshare_do_stmt() to execute it. # # PARAMETERS # dbh (IN) - initialized datavol handle, must be non-null. # dgname (IN) - name of diskgroup in which to create the volume. # volname (IN) - name of volume to be created within the diskgroup. # size (IN) - size of the volume. # redundancy (IN) - redundancy type of the volume. # size (IN) - size of the stripe width. # size (IN) - number of stripe columns. # # RETURNS # Null. ######## sub asmcmdvol_volcreate_sql { my ($dbh, $dgname, $volname, $size, $redundancy, $stripe_columns, $stripe_width, $primary_zone, $mirror_zone) = @_; my ($ret, $qry); # The minimum required of statements to the SQL command $qry = "alter diskgroup $dgname add volume '$volname' size $size"; # Optional SQL statements follow # if redundancy is not specified, you get the diskgroup default if ($redundancy ne 'default') { $qry = $qry . " $redundancy"; } # if the stripe width is not specified, you get the AVD default if ($stripe_width ne 'default') { $qry = $qry . " stripe_width $stripe_width"; } # if the stripe columns are not specified, you get the AVD default if ($stripe_columns ne 'default') { $qry = $qry . " stripe_columns $stripe_columns"; } # Add disk zone attributes, if any. if (defined($primary_zone) or defined($mirror_zone)) { $qry = $qry . " ATTRIBUTE("; if (defined($primary_zone)) { $qry = $qry . " $primary_zone"; } if (defined($mirror_zone)) { $qry = $qry . " $mirror_zone"; } $qry = $qry . ")"; } # execute the SQL statement $ret = asmcmdshare_do_stmt($dbh, $qry); warn "$DBI::errstr\n" unless defined ($ret); } ######## # NAME # asmcmdvol_volenable_disable_sql # # DESCRIPTION # This routine constructs the SQL used to enable/disable an ASM volume. # It calls asmcmdshare_do_stmt() to execute it. # # PARAMETERS # dbh (IN) - initialized datavol handle, must be non-null. # cmd_name (IN) - "enable" or "disable". # dgname (IN) - name of diskgroup or "all". # volname (IN) - name of volume or "all". # # RETURNS # Null. ######## sub asmcmdvol_volenable_disable_sql { my ($dbh, $cmd_name, $dgname, $volname) = @_; my ($ret, $qry); $qry = "alter diskgroup $dgname $cmd_name volume $volname"; # execute the SQL statement $ret = asmcmdshare_do_stmt($dbh, $qry); warn "$DBI::errstr\n" unless defined ($ret); } ######## # NAME # asmcmdvol_volresize_sql # # DESCRIPTION # This routine constructs the SQL used to resize an ASM volume. # It calls asmcmdshare_do_stmt() to execute it. # # PARAMETERS # dbh (IN) - initialized datavol handle, must be non-null. # dgname (IN) - name of diskgroup in which to resize the volume. # volname (IN) - name of volume within the diskgroup to be resized. # newsize (IN) - new size of volume. # # RETURNS # Null. ######## sub asmcmdvol_volresize_sql { my ($dbh, $dgname, $volname, $newsize) = @_; my ($ret, $qry); $qry = "alter diskgroup $dgname resize volume '$volname' size $newsize"; # execute the SQL statement $ret = asmcmdshare_do_stmt($dbh, $qry); warn "$DBI::errstr\n" unless defined ($ret); } ######## # NAME # asmcmdvol_voldelete_sql # # DESCRIPTION # This routine constructs the SQL used to delete an ASM volume. # It calls asmcmdshare_do_stmt() to execute it. # # PARAMETERS # dbh (IN) - initialized datavol handle, must be non-null. # dgname (IN) - name of diskgroup containing the volume. # volname (IN) - name of the volume to be deleted. # # RETURNS # Null. ######## sub asmcmdvol_voldelete_sql { my ($dbh, $dgname, $volname) = @_; my ($ret, $qry); $qry = "alter diskgroup $dgname drop volume '$volname'"; # execute the SQL statement $ret = asmcmdshare_do_stmt($dbh, $qry); warn "$DBI::errstr\n" unless defined ($ret); } ######## # NAME # asmcmdvol_volset_sql # # DESCRIPTION # This routine constructs the SQL used to add a usage string and/or a # mountpath to an ASM volume. It calls asmcmdshare_do_stmt() to execute it. # # PARAMETERS # dbh (IN) - initialized datavol handle, must be non-null. # dgname (IN) - name of diskgroup containing the volume. # volname (IN) - name of the volume to add the usage string to. # usage_string (IN) - usage string to add to the volume. # primary_zone (IN) - zone for the primary extents (hot|cold) # mirror_zone (IN) - zone for the mirrored extents (hot|cold) # # RETURNS # Null. ######## sub asmcmdvol_volset_sql { my ($dbh, $dgname, $volname, $usage_string, $mountpath, $primary_zone, $mirror_zone) = @_; my ($ret, $qry); $qry = "alter diskgroup $dgname modify volume '$volname'"; # Add disk zone attributes, if any. if (defined($primary_zone) or defined($mirror_zone)) { $qry = $qry . " ATTRIBUTE("; if (defined($primary_zone)) { $qry = $qry . " $primary_zone"; } if (defined($mirror_zone)) { $qry = $qry . " $mirror_zone"; } $qry = $qry . ")"; } if (defined($mountpath)) { $qry = $qry . " mountpath '$mountpath'"; } if (defined($usage_string)) { $qry = $qry . " usage '$usage_string'"; } # execute the SQL statement $ret = asmcmdshare_do_stmt($dbh, $qry); warn "$DBI::errstr\n" unless defined ($ret); } ######## # NAME # asmcmdvol_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 ASMCMD volume 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 asmcmdvol_syntax_error { my ($cmd) = shift; my ($cmd_syntax); # Correct syntax for $cmd. # my ($succ) = 0; $cmd_syntax = asmcmdvol_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; } if ($asmcmdglobal_hash{'mode'} eq 'n') { $asmcmdglobal_hash{'e'} = -1; } return $succ; } ######## # NAME # asmcmdvol_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 hash list contains asmcmd volume functions that* DO* require that # an ASM instance be running - all volume commands. ######## sub asmcmdvol_is_no_instance_cmd { my ($arg) = shift; return !defined ($asmcmdvol_cmds{ $arg }) || !defined ($asmcmdvol_cmds{ $arg }{ no_instance }); } ######## # NAME # asmcmdvol_error_msg # # DESCRIPTION # This function is a wrapper around asmcmdvol_display_msg(), the # function responsible for displaying error messages for the asmcmdvol # 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 asmcmdvol module; 0 # otherwise. # # NOTES # Only asmcmdshare_error_message should call this function. *Do not* # call this function directly; call asmcmdshare_error_message, # instead. ######## sub asmcmdvol_error_msg { my ($err_num, $args_ref) = @_; my ($succ) = 0; my (@eargs); # Assert that $err_num is not within 8200-8299, inclusive. @eargs = ("asmcmdvol_error_msg_05", $err_num); asmcmdshare_assert( (($err_num < 8200) || ($err_num > 8299)) , \@eargs); $succ = asmcmdvol_display_msg($err_num, $args_ref); return $succ; } ######## # NAME # asmcmdvol_display_msg # # DESCRIPTION # This routine prints error and exception messages to STDERR for the # asmcmdvol 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 asmcmdvol. # # If an error is found, this function prints the error message. ######### sub asmcmdvol_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. my (%error_messages) = ( ); $errmsg = $error_messages{$err_num}; # Process error arguments for errors that support them. #if ($err_num == 9345) #{ # Substitute the string '$arg' with the value of $args_ref->[0] # $errmsg =~ s,\$arg,$args_ref->[0],; #} # Print error only if this module supports this error number. if (defined ($errmsg)) { $succ = 1; print STDERR $errmsg . "\n"; } return $succ; } ######## # NAME # asmcmdvol_signal_exception # # DESCRIPTION # This function is a wrapper around asmcmdvol_display_msg(), the # function responsible for displaying error messages for the asmcmdvol # 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 asmcmdvol 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 asmcmdvol_signal_exception { my ($exception_num, $args_ref) = @_; my ($succ) = 0; # Assert that $exception_num is within 8200-8299, inclusive. if (($exception_num < 8200) || ($exception_num > 8299)) { die "asmcmd: 8202 internal error: [asmcmdvol_signal_exception_05] " . "[$exception_num]\n"; } $succ = asmcmdvol_display_msg($exception_num, $args_ref); return $succ; } ######## # NAME # asmcmdvol_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 asmcmdvol_get_cmd_desc { my ($cmd) = shift; my (%cmd_desc); # Hash storing the description for each internal command. # $cmd_desc{'volcreate'} = ' Create the volume in the specified diskgroup. The diskgroup must be mounted. The volume size must be specified and must contain the "size multiplier" K, M, G, or T. The following options may be specified: --redundancy - "unprotected", "mirror", or "high" --width - 4K to 1M at power of 2 intervals '. '(default = 128K) --column - between 1 and 8 (inclusive) (default = 4) --primary primary region - "hot", or "cold" --secondary mirrored region- "hot", or "cold"'; $cmd_desc{'voldelete'} = ' Delete the volume from the diskgroup specified. The diskgroup must be mounted. '; $cmd_desc{'voldisable'} = " Disable one or more volumes. * If the '-a' and '-G dgname' options are specified, all volumes in the specified diskgroup will be disabled. * If the '-a' option is specified and no diskgroup name is specified then all volumes in all diskgroups will be disabled. If specified, the diskgroup must be mounted "; $cmd_desc{'volenable'} = " Enable one or more volumes. * If the '-a' and '-G dgname' options are specified, all volumes in the specified diskgroup will be enabled. * If the '-a' option is specified and no diskgroup name is specified then all volumes in all diskgroups will be enabled. If specified, the diskgroup must be mounted "; $cmd_desc{'volinfo'} = " Display volume information. * If the '-a' and '-G dgname' options are specified, info for all volumes in the specified diskgroup will be displayed. * If the '-a' option is specified and no diskgroup name is specified then info for all volumes in all diskgroups will be displayed. * The --show_diskgroup and --show_volume switches require a". "volume device name argument. These switches display only the diskgroup name or the volume name, respectively. If specified, the diskgroup must be mounted "; $cmd_desc{'volresize'} = ' Resize the volume in the diskgroup specified. The diskgroup must be mounted and the volume must exist. If the volume is not ACFS and the new size is smaller than current, the user will be warned of possible data corruption. Unless the -f (force) option is specified, the user will be asked if it is OK to continue. '; $cmd_desc{'volset'} = ' Change existing volume attributes. The diskgroup must be mounted and the volume must exist. * Add a "usage" and/or "mount path" message to the specified volume. These strings are user informational only and are not used by ASM. * Change the region for the volume\'s primary or mirrored storage.'; $cmd_desc{'volstat'} = ' Report volume I/O statistics. * If the optional diskgroup name is omitted, all mounted diskgroups are searched and, if found, volume(s) are displayed. * If the optional volume name is omitted, all volumes are displayed on the named diskgroup. * If both the diskgroup name and the volume name are omitted, all volumes on all diskgroups are displayed. * If specified, the diskgroup must be mounted '; return $cmd_desc{$cmd}; } ######## # NAME # asmcmdvol_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 asmcmdvol_get_cmd_syntax { my ($cmd) = shift; my (%cmd_syntax); # Hash storing the syntax for each internal command. # $cmd_syntax{'volcreate'} = 'volcreate -G -s ' . '[--redundancy ] [--width '. '] [--column ] '. '[--primary ] [-secondary ]'. ' '; $cmd_syntax{'voldelete'} = 'voldelete -G '; $cmd_syntax{'voldisable'} = 'voldisable ' . '[-G | -G -a | -a]'; $cmd_syntax{'volenable'} = 'volenable ' . '[-G | -G -a | -a]'; $cmd_syntax{'volinfo'} = 'volinfo [-G | '. '-G -a | -a] | [--show_diskgroup |'. ' --show_volume] '; $cmd_syntax{'volresize'} = 'volresize -G -s [-f] '. ''; $cmd_syntax{'volset'} = 'volset -G [--usagestring'. ' ] [--mountpath ]'. ' [--primary ] ' . '[--secondary ] '; $cmd_syntax{'volstat'} = 'volstat [-G ] [--show_volume'. ' ]'; return $cmd_syntax{$cmd}; } ######## # NAME # asmcmdvol_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 asmcmdvol_get_asmcmd_cmds { return asmcmdshare_print_cmds(sort(keys %asmcmdvol_cmds)); } ######## # NAME # asmcmdvol_is_cmd # # DESCRIPTION # This routine checks if a user-entered command is one of the known ASMCMD # internal commands that belong to the vol module. # # PARAMETERS # arg (IN) - user-entered command name string. # # RETURNS # True if $arg is one of the known commands, false otherwise. ######## sub asmcmdvol_is_cmd { my ($arg) = shift; return defined ( $asmcmdvol_cmds{ $arg } ); } ######## # NAME # asmcmdvol_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 asmcmdvol_parse_int_args { my ($cmd, $args_ref) = @_; my (@string); my ($key); #build the list of options to parse using GetOptions if($asmcmdvol_cmds{ $cmd }{ flags }) { foreach $key(keys %{$asmcmdvol_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. # asmcmdvol_syntax_error($cmd); return undef; } return 0; } ######### # NAME # asmcmdvol_is_wildcard_cmd # # DESCRIPTION # This routine determines if an ASMCMDVOL 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 asmcmdvol_is_wildcard_cmd { my ($arg) = shift; return 0; } 1;