MINI MINI MANI MO
# Copyright (c) 2004, 2017, 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)
# wanhlee 02/09/17 - 22895947: Handle new kfod getclstype return value
# averhuls 08/27/16 - Code coverage improvement - no functional change.
# jochoa 08/15/16 - 24344967: Do not proceed further when volume
# resize request is 0
# diguzman 05/30/16 - 19654070: Little change at _no_instance_cmd routine
# mnollen 08/13/15 - #21569440 - export asmcmdvol_volcreate_sql
# ykatada 10/03/14 - #19617921: use bind_param for strings in WHERE
# manuegar 07/04/13 - Bug12991117 Remove all duplicate forward slashes
# from $device_name in asmcmdvol_process_volinfo().
# manuegar 05/08/13 - Bug13951456 Support bind parameters
# averhuls 03/01/13 - Fix volresize to generate error if vol < 1M.
# averhuls 02/13/13 - volinfo perl fix if modules not loaded (bug
# 16263194)
# averhuls 01/04/13 - Tighten size parsing in volresize - bug 16043884.
# Fix Windows hostname case issue - bug 16043579.
# bonelso 01/02/13 - Remobed some erroneous/redundant syntax checks.
# mchimang 12/01/12 - 14142633: handle proxy connection in remote asm
# averhuls 11/08/12 - Rename ora,proxy_asm to ora.proxy_advm.
# pvenkatr 09/08/12 - 14321350: process volenable/disable multiple vols
# bonelso 07/12/12 - Fix volcreate when using zones.
# averhuls 05/31/12 - Enable/disable/stat volumes via proxy if remote ASM.
# pvenkatr 08/24/11 - Removed flags hash table - using from XML
# adileepk 06/20/11 - Connection Pooling.
# moreddy 04/01/11 - 12312348 missing msg when resize invalid volume
# adileepk 02/13/11 - Fix for HAS SRG issue, volinfo bug.
# adileepk 11/09/10 - Adding changes to integrate the parser module with
# asmcmd.
# moreddy 05/06/10 - bug 8667038 NLS for error messages
# bonelso 04/17/10 - Fix asmcmdvol_error_msg() and the warning message
# in volresize when shrinking a volume.
# Bugs 94561723 and 9466091
# bonelso 03/30/10 - Fix for LRG4522067
# pvenkatr 03/25/10 - Syntax, command description, example all from XML
# moreddy 03/22/10 - Adding more tracing
# bonelso 03/17/10 - Fix asmcmdvol_error_msg() and the warning message
# in volresize when shrinking a volume.
# Bugs 94561723 and 9466091
# moreddy 01/18/10 - Adding tracing messages
# pvenkatr 09/03/09 - Help message from xml file
# 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 03/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_asmcmd_cmds
#
# Parameter Parsing Routines
# asmcmdvol_is_cmd
# asmcmdvol_parse_int_args
#############################################################################
package asmcmdvol;
require Exporter;
our @ISA = qw(Exporter);
our @EXPORT = qw(asmcmdvol_volcreate_sql);
use strict;
use DBI qw(:sql_types);
use Getopt::Long qw(:config no_ignore_case bundling);
use Scalar::Util qw(looks_like_number);
use Sys::Hostname;
use asmcmdglobal;
use asmcmdshare;
use asmcmdparser;
use asmcmdbase;
####################### ASMCMDVOL Global Variables ########################
our (%asmcmdvol_cmds) = ( volcreate => {},
voldelete => {},
voldisable => {},
volenable => {},
volinfo => {},
volresize => {},
volset => {},
volstat => {},
);
my $PROXY_RESOURCE = "ora.proxy_advm";
my $CRSCTL = "$ENV{ORACLE_HOME}/bin/crsctl";
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);
%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 $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. #
$desc = asmcmdshare_get_help_desc($command);
# The following check prevents an "undefined value" error message for
# legal commands that have no help information.
if (defined $desc)
{
asmcmdshare_print "$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) #
# parse options
$ret = asmcmdvol_parse_int_args($asmcmdglobal_hash{'cmd'}, \%args);
return unless defined ($ret);
# get and validate diskgroup name (-G required)
$dgname = $args{'G'};
# get and validate volume name (last arg - required)
$volname = pop @{$args{'volcreate'}};
$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;
}
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 #
{
$primary_zone = $args{'primary'};
tr/a-z/A-Z/ for $primary_zone;
}
if (defined($args{'secondary'})) # Get secondary zone #
{
$mirror_zone = "MIRROR" . $args{'secondary'};
tr/a-z/A-Z/ for $mirror_zone;
}
# 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 #
# parse options
$ret = asmcmdvol_parse_int_args($asmcmdglobal_hash{'cmd'}, \%args);
return unless defined ($ret);
# get and validate diskgroup name (-d required)
$dgname = $args{'G'};
# Get the volume name.
($volname) = @{$args{'voldelete'}};
# 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 $vname; # each volume name in loop #
my $dgname; # name of mounted diskgroup #
my $have_proxy; # Set if node has a proxy instance #
my $proxy_online; # Set if the proxy instance is online #
my $switched_to_asm_proxy = 0; # Set if we connect to the ASM proxy #
my @eargs; # asmcmdshare_error_msg() arguments #
# "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);
if (defined($args{'G'})) # Get diskgroup name. #
{
# multiple diskgroups can be specified. Make a list - comma separated.
$dgname = "" ;
foreach (@{$args{'G'}})
{
if ($dgname eq "" )
{
$dgname = $_ ;
}
else
{
$dgname = $dgname . "," . $_ ;
}
}
}
if (defined($args{'a'})) # Get volume name. #
{
$volname = 'all';
}
elsif(defined($args{'vol' . $cmd_name}))
{
# multiple volumes can be specified, across diskgroups too.
# make a comma separated list
$volname = "";
foreach ((@{$args{'vol'.$cmd_name}}))
{
$vname = $_ ;
if ( $volname eq "" )
{
$volname = $vname ;
}
else
{
$volname = $volname . "," . $vname;
}
}
}
($have_proxy, $proxy_online) = get_asm_proxy_state();
if ($have_proxy && !$proxy_online)
{
@eargs = ('');
# 9470 - "ASM proxy instance unavailable."
asmcmdshare_error_msg(9470, \@eargs);
# 9471 - "Cannot enable/disable volumes."
asmcmdshare_error_msg(9471, \@eargs);
return;
}
# If there is an online proxy AND our ORACLE_SID is that of the
# proxy, we simply use SQL. If our ORACLE_SID is NOT that of the proxy
# instance, we connect to the proxy and use SQL.
if ($proxy_online)
{
($switched_to_asm_proxy, $dbh) = connect_to_asm_proxy($dbh);
if (!defined($dbh))
{
@eargs = ('');
# 9472 - "Failed to connect to the ASM proxy."
asmcmdshare_error_msg(9472, \@eargs);
return;
}
}
asmcmdvol_volenable_disable_sql ($dbh, $cmd_name, $dgname, $volname);
if ($switched_to_asm_proxy)
{
# Disconnect from the proxy and restore original state
asmcmdbase_disconnect($dbh);
}
}
########
# 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 @eargs; # asmcmdshare_error_msg() arguments #
my $print_string;
my $have_proxy; # Set if node has a proxy instance #
my $proxy_online; # Set if the proxy instance is online #
my $switched_to_asm_proxy = 0; # Set if node has a proxy instance #
# validate option parameters, if any.
$ret = asmcmdvol_parse_int_args($asmcmdglobal_hash{'cmd'}, \%args);
return unless defined ($ret);
if(defined($args{'all'}))
{
$dgname = 'all';
$volname = 'all';
}
elsif (defined($args{'G'})) # Get diskgroup name. #
{
$dgname = $args{'G'};
if (defined($args{'a'})) # Get volume name. #
{
$volname = 'all';
}
elsif(defined($args{'volinfo'}))
{
($volname) = @{$args{'volinfo'}};
}
}
if(defined($args{'volinfo'}))
{
($volname) = @{$args{'volinfo'}};
}
if (defined($args{'show_diskgroup'}) || defined($args{'show_volume'})) # output ONLY the diskgroup name
{
$device_name = $args{'show_diskgroup'} if defined $args{'show_diskgroup'};
$device_name = $args{'show_volume'} if defined $args{'show_volume'};
# Bug12991117 Remove all duplicate forward slashes from $device_name
$device_name =~ s/\/{2,}/\//g;
}
($have_proxy, $proxy_online) = get_asm_proxy_state();
if ($have_proxy && !$proxy_online)
{
@eargs = ('');
# 9470 - "ASM proxy instance unavailable."
asmcmdshare_error_msg(9470, \@eargs);
# 9473 - "Volume STATE will show as REMOTE."
asmcmdshare_error_msg(9473, \@eargs);
# Continue to do what we can on the current instance.
}
# If there is an online proxy AND our ORACLE_SID is that of the
# proxy, we simply use SQL. If our ORACLE_SID is NOT that of the proxy
# instance, we connect to the proxy and use SQL.
if ($proxy_online)
{
($switched_to_asm_proxy, $dbh) = connect_to_asm_proxy($dbh);
if (!defined($dbh))
{
@eargs = ('');
# 9472 - "Failed to connect to the ASM proxy."
asmcmdshare_error_msg(9472, \@eargs);
return;
}
}
# 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 = ?";
# perform the SQL select
$sth = asmcmdshare_do_prepare($dbh, $sql);
$sth->bind_param(1,$dg_uc,SQL_VARCHAR);
asmcmdshare_do_execute($sth);
goto done if (! defined ($sth));
$row = asmcmdshare_fetch($sth);
asmcmdshare_finish($sth);
if (!defined($row))
{
@eargs = ($dgname);
asmcmdshare_error_msg(8001, \@eargs);
goto done;
}
}
# 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);
goto done 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{'all'})) && (!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
$print_string = sprintf("%s\n", lc($row->{'NAME'}));
asmcmdshare_print($print_string);
}
elsif (defined($args{'show_volume'}))
{
# output only the volume name
$print_string = sprintf("%s\n", lc($row->{'VOLUME_NAME'}));
asmcmdshare_print($print_string);
}
asmcmdshare_finish ($sth);
goto done;
}
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'};
$print_string = sprintf "Diskgroup Name: $dgnam\n\n";
asmcmdshare_print($print_string);
# Indicate that we've seen this diskgroup.
$cur_dgname = $dgnam;
}
$report = 1; # we found information to print
# Format and print the volume information.
# The 'VOLUME_DEVICE' is the only field that can possibly be NULL. This
# can happen if the drivers are not loaded or if there is no libskvol
# or if the ADVM device control files have the wrong permissions.
my $vol_dev;
$vol_dev = ($row->{'VOLUME_DEVICE'}) ? $row->{'VOLUME_DEVICE'} : "UNKNOWN";
asmcmdshare_print "\t Volume Name: " . $row->{'VOLUME_NAME'} . "\n";
asmcmdshare_print "\t Volume Device: " . $vol_dev . "\n";
asmcmdshare_print "\t State: " . $row->{'STATE'} . "\n";
asmcmdshare_print "\t Size (MB): " . $row->{'SIZE_MB'} . "\n";
asmcmdshare_print "\t Resize Unit (MB): " . $row->{'RESIZE_UNIT_MB'} . "\n";
asmcmdshare_print "\t Redundancy: " . $row->{'REDUNDANCY'} . "\n";
asmcmdshare_print "\t Stripe Columns: " . $row->{'STRIPE_COLUMNS'} . "\n";
asmcmdshare_print "\t Stripe Width (K): " . $row->{'STRIPE_WIDTH_K'} . "\n";
$print_string = "\t Usage: ";
if (defined($row->{'USAGE'}))
{
$print_string .= $row->{'USAGE'};
}
asmcmdshare_print($print_string . "\n");
$print_string = "\t Mountpath: ";
if (defined($row->{'MOUNTPATH'}))
{
$print_string .= $row->{'MOUNTPATH'} . " ";
}
asmcmdshare_print($print_string . "\n");
asmcmdshare_print " \n";
}
if (!$report)
{
if (defined($args{'G'}) && !defined($args{'a'}))
{
$print_string = sprintf("volume %s not found in diskgroup %s\n", $volname, $dgname);
asmcmdshare_print($print_string);
}
elsif (defined($args{'G'}))
{
$print_string = sprintf("diskgroup %s has no volumes or is not mounted\n", $dgname);
asmcmdshare_print($print_string);
}
elsif ((defined($args{'show_diskgroup'})) || (defined($args{'show_volume'})))
{
$print_string = sprintf("no device name \"%s\" found\n", $device_name);
asmcmdshare_print($print_string);
}
else
{
asmcmdshare_print("no volumes found\n");
}
}
done:
if ($switched_to_asm_proxy)
{
# Disconnect from the proxy and restore original state
asmcmdbase_disconnect($dbh);
}
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 $testsize; # test against cursize to check for reduced size #
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 #
my @eargs;
# parse options
$ret = asmcmdvol_parse_int_args($asmcmdglobal_hash{'cmd'}, \%args);
return unless defined ($ret);
# get and validate diskgroup name (-G required)
$dgname = $args{'G'};
# get and validate volume name (last arg - required)
$volname = pop(@{$args{'volresize'}});
$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);
# 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;
}
}
asmcmdshare_finish($sth);
# did we find the volume?
if (!defined($cursize))
{
@eargs = ($dgname, $volname);
asmcmdshare_error_msg(8557, \@eargs);
return;
}
# convert SQL returned cursize from MB to KB.
# We later compare the current size to the new size and issue a warning
# if the new size is smaller.
$cursize *= 1024;
$newsize = uc $newsize;
if ($newsize =~ m/K$/)
{
$newsize =~ s/K$//;
if (!looks_like_number($newsize))
{
# "valid size modifier but invalid numeric size specified\n"
asmcmdshare_error_msg(8559, \@eargs);
return;
}
$testsize = $newsize;
$newsize .= 'K';
}
elsif ($newsize =~ m/M$/)
{
$newsize =~ s/M$//;
if (!looks_like_number($newsize))
{
# "valid size modifier but invalid numeric size specified\n"
asmcmdshare_error_msg(8559, \@eargs);
return;
}
$testsize = $newsize * 1024;
$newsize .= 'M';
}
elsif ($newsize =~ m/G$/)
{
$newsize =~ s/G$//;
if (!looks_like_number($newsize))
{
# "valid size modifier but invalid numeric size specified\n"
asmcmdshare_error_msg(8559, \@eargs);
return;
}
$testsize = $newsize * 1024 * 1024;
$newsize .= 'G';
}
elsif ($newsize =~ m/T$/)
{
$newsize =~ s/T$//;
if (!looks_like_number($newsize))
{
# "valid size modifier but invalid numeric size specified\n"
asmcmdshare_error_msg(8559, \@eargs);
return;
}
$testsize = $newsize * 1024 * 1024 * 1024;
$newsize .= 'T';
}
else
{
# "invalid size modifier specified"
asmcmdshare_error_msg(8558, \@eargs);
return;
}
if ($testsize == 0)
{
# "invalid numeric size specified"
asmcmdshare_error_msg(8559, \@eargs);
return;
}
if (($testsize < $cursize) && ($usage ne "ACFS"))
{
my $response = 'x';
if (!defined($force))
{
while (($response ne 'y') && ($response ne 'n'))
{
asmcmdshare_print "The requested size is smaller than the current size.\n";
asmcmdshare_print "Data corruption may occur.\n";
asmcmdshare_printprompt "Are you sure? [y/n]: ";
$response = asmcmdshare_readstdin();
chomp ($response);
}
if ($response eq 'n')
{
return;
}
}
}
# 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) #
# parse options
$ret = asmcmdvol_parse_int_args($asmcmdglobal_hash{'cmd'}, \%args);
return unless defined ($ret);
# get and validate diskgroup name (-G required)
$dgname = $args{'G'};
# get and validate volume name (last arg - required)
$volname = pop(@{$args{'volset'}});
if (defined($args{'mountpath'}))
{
$mountpath = $args{'mountpath'};
}
if (defined($args{'usagestring'}))
{
$usage_string = $args{'usagestring'};
}
if (defined($args{'primary'})) # Get primary zone #
{
$primary_zone = $args{'primary'};
tr/a-z/A-Z/ for $primary_zone;
}
if (defined($args{'secondary'})) # Get secondary zone #
{
$mirror_zone = "MIRROR" . $args{'secondary'};
tr/a-z/A-Z/ for $mirror_zone;
}
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 #
my $print_string;
my $have_proxy; # Set if node has a proxy instance #
my $proxy_online; # Set if the proxy instance is online #
my $switched_to_asm_proxy = 0; # Set if node has a proxy instance #
my @eargs; # asmcmdshare_error_msg() arguments #
# 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 (defined($args{'volstat'}))
{
$volname = pop(@{$args{'volstat'}});
tr/a-z/A-Z/ for $volname; # must be upper case #
}
# 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";
($have_proxy, $proxy_online) = get_asm_proxy_state();
if ($have_proxy && !$proxy_online)
{
@eargs = ('');
# 9470 - "ASM proxy instance unavailable.
asmcmdshare_error_msg(9470, \@eargs);
# 9474 - "Volume statistics cannot be queried.
asmcmdshare_error_print(9474, \@eargs);
return;
}
# If there is an online proxy AND our ORACLE_SID is that of the
# proxy, we simply use SQL. If our ORACLE_SID is NOT that of the proxy
# instance, we connect to the proxy and use SQL.
if ($proxy_online)
{
($switched_to_asm_proxy, $dbh) = connect_to_asm_proxy($dbh);
if (!defined($dbh))
{
@eargs = ('');
# 9472 - "Failed to connect to the ASM proxy."
asmcmdshare_error_msg(9472, \@eargs);
return;
}
}
# perform the SQL select
$sth = asmcmdshare_do_select($dbh, $sql);
# 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'};
$print_string = sprintf ("\nDISKGROUP NUMBER / NAME: %d / %s\n", $dgnum, $dgnam);
asmcmdshare_print($print_string);
asmcmdshare_print("---------------------------------------\n");
# Indicate that we've seen this diskgroup.
$cur_dgname = $dgnam;
# Now print the volume header - one per diskgroup.
asmcmdshare_print(" VOLUME_NAME\n");
$print_string = sprintf(" %-16s%-16s%-16s%-16s\n",
"READS","BYTES_READ","READ_TIME","READ_ERRS");
asmcmdshare_print($print_string);
$print_string = sprintf(" %-16s%-16s%-16s%-16s\n",
"WRITES","BYTES_WRITTEN","WRITE_TIME","WRITE_ERRS");
asmcmdshare_print($print_string);
asmcmdshare_print(" -------------------------------------------------------------\n");
}
$report = 1; # we found information to print
# Format and print the volume statistics.
$print_string = sprintf (" %s\n", $row->{'VOLUME_NAME'});
asmcmdshare_print($print_string);
$print_string = sprintf (" %-16s", $row->{'READS'});
$print_string .= sprintf ("%-16s", $row->{'BYTES_READ'});
$print_string .= sprintf ("%-16s", $row->{'READ_TIME'});
$print_string .= sprintf ("%-16s\n", $row->{'READ_ERRS'});
asmcmdshare_print($print_string);
$print_string = sprintf (" %-16s", $row->{'WRITES'});
$print_string .= sprintf ("%-16s", $row->{'BYTES_WRITTEN'});
$print_string .= sprintf ("%-16s", $row->{'WRITE_TIME'});
$print_string .= sprintf ("%-16s\n", $row->{'WRITE_ERRS'});
asmcmdshare_print($print_string);
}
if (!$report)
{
if (defined($args{'G'}) && defined($args{'show_volume'}))
{
$print_string = sprintf("volume %s not found in diskgroup %s\n",
$args{'show_volume'}, $args{'G'});
asmcmdshare_print($print_string);
}
elsif (defined($args{'G'}))
{
$print_string = sprintf("diskgroup %s has no volumes or is not mounted\n",
$args{'G'});
asmcmdshare_print($print_string);
}
elsif (defined($args{'show_volume'}))
{
$print_string = sprintf("no volumes \"%s\" found in any mounted diskgroup\n",
$args{'show_volume'});
asmcmdshare_print($print_string);
}
else
{
asmcmdshare_print("no volumes found\n");
}
}
if ($switched_to_asm_proxy)
{
# Disconnect from the proxy and restore original state
asmcmdbase_disconnect($dbh);
}
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, $retqry) = @_;
my $ret;
my $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 . ")";
}
# Return query if requested
return $qry if ($retqry);
# execute the SQL statement
$ret = asmcmdshare_do_stmt($dbh, $qry);
}
########
# 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;
my $qry;
$qry = "alter diskgroup $dgname $cmd_name volume $volname";
# execute the SQL statement
$ret = asmcmdshare_do_stmt($dbh, $qry);
}
########
# 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;
my $qry;
$qry = "alter diskgroup $dgname resize volume '$volname' size $newsize";
# execute the SQL statement
$ret = asmcmdshare_do_stmt($dbh, $qry);
}
########
# 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;
my $qry;
$qry = "alter diskgroup $dgname drop volume '$volname'";
# execute the SQL statement
$ret = asmcmdshare_do_stmt($dbh, $qry);
}
########
# 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;
my $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);
}
########
# 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;
#display syntax only for commands from this module
if(asmcmdvol_is_cmd($cmd))
{
$cmd_syntax = asmcmdshare_get_help_syntax($cmd); # Get syntax for $cmd. #
$cmd_syntax = asmcmdshare_trim_str ($cmd_syntax); # Trim blank spaces #
if (defined ($cmd_syntax))
{
asmcmdshare_printstderr 'usage: ' . $cmd_syntax . "\n";
asmcmdshare_printstderr '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
# 1 if $arg is a command that can run without an ASM instance or it does not
# belong to this module
# 0 if $arg is a command that needs to connect to an ASM instance
# -1 if $arg is a command that may use an ASM instance.
#
# 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;
my ($rc);
return 1 unless defined($asmcmdvol_cmds{$arg});
$rc = asmcmdshare_get_cmd_noinst($arg);
if ($rc eq "true")
{
return 1;
}
elsif ($rc eq "undef")
{
return -1;
}
return 0;
}
########
# 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_filter_invisible_cmds(%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;
# Use asmcmdparser_parse_issued_command() from the asmcmdparser package to parse arguments for
# internal commands. These arguments are stored in @ARGV.
if (!asmcmdparser_parse_issued_command($cmd, $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;
}
#########
# NAME
# get_asm_proxy_state
#
# DESCRIPTION
# Get the state of the ASM proxy resource.
#
# PARAMETERS
# arg (IN) - None.
#
# RETURNS
# 2 values - proxy exists / proxy is (or not) online.
########
sub get_asm_proxy_state
{
my $have_proxy = 0;
my $proxy_online = 0;
my $hostname = get_hostname();
# The CRSCTL line below is functionally equivalent to
# $CRSCTL status resource $PROXY_RESOUCE -n $hostname
# with the exception that the command is now insensitive to the $hostname
# case. That '-n' is sensitive to the host name case is bug 16080860.
open PROXY, "$CRSCTL status resource -w \"(NAME = $PROXY_RESOURCE) AND (LAST_SERVER eqi $hostname)\" |";
while (<PROXY>)
{
if ($_ =~ /CRS-/)
{
# Could not find resource (CRS-2613).
# No Oracle Clusterware components configured (CRS-4047).
# etc.
$have_proxy = 0;
$proxy_online = 0;
last;
}
elsif ($_ =~ /^STATE=ONLINE/)
{
# on line.
$have_proxy = 1;
$proxy_online = 1;
last;
}
elsif ($_ =~ /^STATE=/)
{
# STATE could be OFFLINE, UNKNOWN, etc.
# Unless ONLINE, treat all other states as OFFLINE
$have_proxy = 1;
$proxy_online = 0;
last;
}
}
close (PROXY);
return ($have_proxy, $proxy_online);
}
#########
# NAME
# get_asm_proxy_sid
#
# DESCRIPTION
# Get the SID of the ASM proxy instance.
#
# PARAMETERS
# arg (IN) - None.
#
# RETURNS
# proxy SID.
########
sub get_asm_proxy_sid
{
my $proxy_sid;
my $hostname = get_hostname();
# The CRSCTL line below is functionally equivalent to
# $CRSCTL status resource $PROXY_RESOUCE -n $hostname
# with the exception that the command is now insensitive to the $hostname
# case. That '-n' is sensitive to the host name case is bug 16080860.
open SID, "$CRSCTL status resource -p -w \"(NAME = $PROXY_RESOURCE) AND (LAST_SERVER eqi $hostname)\" |";
while (<SID>)
{
if ($_ =~ /^GEN_USR_ORA_INST_NAME/)
{
my (@array) = split /=/, $_;
$proxy_sid = $array[-1];
chomp $proxy_sid;
last;
}
}
close SID;
return $proxy_sid;
}
#########
# NAME
# get_hostname
#
# DESCRIPTION
# Get the hostname of the system
#
# PARAMETERS
# arg (IN) - None.
#
# RETURNS
# hostname.
########
sub get_hostname
{
my $hostname = hostname();
#remove domain name from hostname (if any).
my @array = split /\./, $hostname;
$hostname = $array[0];
return $hostname;
}
#########
# NAME
# connect_to_asm_proxy
#
# DESCRIPTION
# Connect to the ASM proxy (if required).
#
# PARAMETERS
# arg (IN) - ASM dbh.
#
# RETURNS
# switched_to_proxy dbh
# ---------------------------
# case: switched to the proxy 1 proxy
# case: failed to connect to the proxy 0 undef
# case: already connected to proxy 0 original
# case: failed to detect the proxy SID 0 original
########
sub connect_to_asm_proxy
{
my ($dbh) = @_;
my $orig_sid = $ENV{ORACLE_SID}; # SID in effect when called #
my $proxy_sid;
my $switched_to_proxy = 0;
my $flex_cluster = 0;
my $clus_mode; # Cluster mode #
my $stor_access; # Storage Access Mode #
# Environment variable 'ORACLE_HOME' will be set, otherwise
# ASMCMD init code will bail out.
# directories in which kfod can be found.
my (@patharr) =("$ENV{'ORACLE_HOME'}/bin/",
"$ENV{'ORACLE_HOME'}/rdbms/bin/");
my (@buf) = asmcmdshare_execute_tool ("kfod",
".exe",
"op=getclstype",
\@patharr);
# only one line output.
chomp($buf[0]); # Remove the newline character at the end of the string #
# split the "[cluster mode] - [storage access mode]" information
($clus_mode, $stor_access) = split / - /, $buf[0];
if ($clus_mode eq 'ASM cluster : Flex mode enabled')
{
$flex_cluster = 1;
}
if ($flex_cluster)
{
if (defined($asmcmdglobal_hash{'proxy_dbh'}) &&
asmcmdshare_check_dbh_alive($asmcmdglobal_hash{'proxy_dbh'}))
{
# let $switched_to_proxy = 0, since we cache the proxy connection
# in the flex cluster. This is released during shutdown
return ($switched_to_proxy, $asmcmdglobal_hash{'proxy_dbh'});
}
}
$proxy_sid = get_asm_proxy_sid();
if (!defined($proxy_sid))
{
my @eargs = ('');
# 9475 - "ASM proxy SID not found\n");
asmcmdshare_error_msg (9475, \@eargs);
return $switched_to_proxy, $dbh;
}
# 1. In case of flex cluster regardless of whether the SID is equal to proxy
# instance SID or not, the connection established in asmcmdbase_connect is
# always to the ASM instance.
# Hence in flex cluster, we have to establish connection to the proxy
# instance
# 2. In case of classic clusters, if sid is equal to proxy sid, the earlier
# connection established in asmcmdbase_connect would be to Proxy instance.
# Hence no need to connect again.
if ($flex_cluster)
{
$ENV{ORACLE_SID} = $proxy_sid;
$dbh = asmcmdvol_proxy_connect();
$ENV{ORACLE_SID} = $orig_sid;
}
elsif ($proxy_sid ne $orig_sid)
{
$ENV{ORACLE_SID} = $proxy_sid;
$dbh = asmcmdbase_connect(undef);
if (defined($dbh))
{
$switched_to_proxy = 1;
}
$ENV{ORACLE_SID} = $orig_sid;
}
return $switched_to_proxy, $dbh;
}
########
# NAME
# asmcmdvol_proxy_connect
#
# DESCRIPTION
# The user who wants to connect to local ASM proxy instance should set the
# value of ORACLE_SID environment variable to the ASM proxy instance SID. The
# ORACLE_SID value and ORACLE_HOME value would be used to establish the
# connection to the local ASM proxy instance.
#
# PARAMETERS
# None.
#
# RETURNS
# DBI Handle to the local ASM proxy instance
#
# NOTES
#
########
sub asmcmdvol_proxy_connect
{
my $usr;
my $pswd;
my $contype;
my $driver;
my %session_mode;
$contype = $asmcmdglobal_hash{'contyp'};
# Verify connection admin type, sysdba or sysasm, and assign proper ora #
# session mode. (sysasm = 32768 or sysdba = 2) #
if (($contype =~ /^sysdba$/i))
{
$session_mode{'ora_session_mode'} = 2;
}
else
{
$session_mode{'ora_session_mode'} = 32768;
}
$session_mode{'PrintError'} = 0;
$driver = 'dbi:Oracle:';
$asmcmdglobal_hash{'proxy_dbh'} = DBI->connect($driver, $usr, $pswd,
\%session_mode);
if(!defined($asmcmdglobal_hash{'proxy_dbh'}))
{
# 9470 - failed to connect to the ASM proxy instance
asmcmdshare_error_msg(9472, undef);
asmcmdshare_trace(3, $DBI::errstr, 'y', 'n');
return undef;
}
else
{
my $instance_name =
asmcmdshare_get_instance_name($asmcmdglobal_hash{'proxy_dbh'});
asmcmdshare_trace(3, "Successfully connected to ASM PROXY instance "
."$instance_name", 'y', 'n');
}
return $asmcmdglobal_hash{'proxy_dbh'};
}
OHA YOOOO