MINI MINI MANI MO
# Copyright (c) 2004, 2017, Oracle and/or its affiliates. All rights reserved.
#
# NAME
# asmcmdamdu - ASM CoMmanD AMDU
#
# DESCRIPTION
# This module takes a asm file alias name, finds the file number and
# initiates an AMDU extract for that file.
#
# NOTES
#
#
# MODIFIED (MM/DD/YY)
# anovelo 01/19/17 - 25397936: Allow full path use in amdu_extract
# diguzman 05/31/16 - 19654070: Little change at _no_instance_cmd routine
# gmengel 09/01/15 - LRG 18246299: Make temp file portable
# gmengel 11/11/13 - Bug 17710683: Parsing problem with kfed output.
# gmengel 04/29/13 - Copied from asmcmdtemplate.pm
#
#############################################################################
#
############################ Functions List #################################
#
#############################################################################
package asmcmdamdu;
require Exporter;
our @ISA = qw(Exporter);
our @EXPORT = qw(asmcmdamdu_init
);
use strict;
use Getopt::Long qw(:config no_ignore_case bundling);
use asmcmdglobal;
use asmcmdshare;
use asmcmdparser;
#################### ASMCMDAMDU Global Constants ####################
my (%asmcmdamdu_cmds) = (amdu_extract => {} );
#################### ASMCMDAMDU Global Variables ####################
sub is_asmcmd
{
return 1;
}
########
# NAME
# asmcmdamdu_init
#
# DESCRIPTION
# This function initializes the asmcmdamdu module. For now it
# simply registers its callbacks with the asmcmdglobal module.
#
# PARAMETERS
# None
#
# RETURNS
# Null
#
# NOTES
# Only asmcmdcore_main() calls this routine.
########
sub init
{
# All of the arrays defined in the asmcmdglobal module must be
# initialized here. Otherwise, an internal error will result.
push (@asmcmdglobal_command_callbacks, \&asmcmdamdu_process_cmd);
push (@asmcmdglobal_help_callbacks, \&asmcmdamdu_process_help);
push (@asmcmdglobal_command_list_callbacks, \&asmcmdamdu_get_asmcmd_cmds);
push (@asmcmdglobal_is_command_callbacks, \&asmcmdamdu_is_cmd);
push (@asmcmdglobal_is_wildcard_callbacks, \&asmcmdamdu_is_wildcard_cmd);
push (@asmcmdglobal_syntax_error_callbacks, \&asmcmdamdu_syntax_error);
push (@asmcmdglobal_no_instance_callbacks, \&asmcmdamdu_is_no_instance_cmd);
%asmcmdglobal_cmds = (%asmcmdglobal_cmds, %asmcmdamdu_cmds);
}
########
# NAME
# asmcmdamdu_process_cmd
#
# DESCRIPTION
# This routine calls the appropriate routine to process the command
# specified by $asmcmdglobal_hash{'cmd'}.
#
# PARAMETERS
# dbh (IN) - initialized database handle, must be non-null.
#
# RETURNS
# 1 if command is found in the asmcmdamdu module; 0 if not.
#
# NOTES
# Only asmcmdcore_shell() calls this routine.
########
sub asmcmdamdu_process_cmd
{
my ($dbh) = @_;
my ($succ) = 0;
# Get current command from global value, which is set by
# asmcmdamdu_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 ASMCMDAMDU command.
my (%cmdhash) = ( amdu_extract => \&asmcmdamdu_process_extract );
if (defined ( $cmdhash{ $cmd } ))
{ # If user specifies a known command, then call routine to process it. #
$cmdhash{ $cmd }->($dbh);
$succ = 1;
}
return $succ;
}
########
# NAME
# asmcmdamdu_process_extract
#
# DESCRIPTION
# This function gets the file number associated with an alias name
# and initiates AMDU to extract that file.
#
# PARAMETERS
# dbh (IN) - initialized database handle, must be non-null.
#
# RETURNS
# Null.
#
# NOTES
# Only asmcmdamdu_process_cmd() calls this function.
########
sub asmcmdamdu_process_extract
{
my $dbh = shift;
my %args; # Argument hash used by getopts(). #
my $disk_pattern; # disk pattern and group name. #
my $i;
my $ret;
my $amdu_args;
my $exfile; # the extract specification for the file #
my $fnum; # file number #
my @elements;
my @amduout;
my $fname; # command line argument #
my $gname; # command line argument #
my $ausz; # command line argument #
my $blksz; # command line argument #
my $exdir = $asmcmdglobal_hash{'tempdir'} . "/$$";
my $exout = $asmcmdglobal_hash{'tempdir'} . "/$$/exout";
my %norm; # See asmcmdshare_normalize_path() return value comments. #
my @paths; # Array of normalized paths; $norm{'path'} dereferenced. #
# Get option parameters, if any.
$ret = asmcmdamdu_parse_int_args($asmcmdglobal_hash{'cmd'}, \%args);
return unless defined ($ret);
# Name of disk group for extract
$gname = shift(@{$args{'amdu_extract'}});
# Name of file to be extracted
$fname = shift(@{$args{'amdu_extract'}});
# Discovery disk string
$disk_pattern = shift(@{$args{'amdu_extract'}});
mkdir "$exdir"; # directory for working files
# Substitute any acceptable wild card character with '*', which
# is known to be accepted. This way, any asmcmd wild card
# character can be used.
$disk_pattern =~ s,$ASMCMDGLOBAL_WCARD_CHARS,\*,g;
# directories in which amdu can be found.
my (@patharr) =("$ENV{'ORACLE_HOME'}/bin/",
"$ENV{'ORACLE_HOME'}/rdbms/bin/");
# If --sys_filename option is not being used, user should have provided alias
# file name.
if (!defined ($args{'sys_filename'}))
{
$exfile = "$gname.ALIAS";
$amdu_args = "-diskstring='$disk_pattern' -nodir -noheart -extract $exfile".
" -output $exout";
@amduout = asmcmdshare_execute_tool("amdu", ".exe", $amdu_args, \@patharr);
}
# replace windows style '\\' to Unix style '\/'
$fname =~ s/\\/\//g;
# Is the instance available?
if (defined ($dbh))
{
# See if any entries exist; if so, find all matches for $fname.
%norm = asmcmdshare_normalize_path($dbh, $fname, 0, \$ret);
return unless ($ret == 0);
@paths = @{ $norm{'path'} };
$fname = $paths[0];
}
# No instance: absolute path name must be specified (including '+')
elsif ($fname !~ /^\+/)
{
# ASMCMD-8025 "Invalid file name specified. Absolute path name is required
# when there is no connection to Oracle ASM instance."
asmcmdshare_error_msg(8025, undef);
return;
}
if (defined ($args{'sys_filename'}))
{
my @filepath = split /\./, $fname;
$fnum = $filepath[-2];
if (!defined($fnum) || $fnum !~ m/[\d]+/)
{
my @eargs = "$fname";
# ASMCMD-8038 "invalid path to ASM system file name '%s'"
asmcmdshare_error_msg(8038, \@eargs);
return;
}
}
else
{
# If the --sys_filename option was not used, provided file name is the
# alias. Call asmcmdamdu_get_filenum to obtain the file number.
@elements = split(/\//, $fname);
# call get_filenum recursively to traverse path
$fnum = asmcmdamdu_get_filenum(0, $exout, @elements);
}
if ($fnum > 0 && $fnum < $asmcmdglobal_maxub4)
{
$exfile = "$gname.$fnum";
$amdu_args="-diskstring='$disk_pattern' -noheart -extract $exfile";
@amduout = asmcmdshare_execute_tool("amdu", ".exe", $amdu_args, \@patharr);
asmcmdshare_print @amduout;
}
else
{
my @eargs = "$fname";
# ASMCMD-8024 "file number could not be determined for alias name '%s' "
asmcmdshare_error_msg(8024, \@eargs);
}
return;
}
########
# NAME
# asmcmdamdu_get_filenum
#
# DESCRIPTION
# This function is called recursively to identify the file number for
# a given alias path name (e.g. +datafile/aliasname)
#
# PARAMETERS
# index (IN) - the kfade refer number identifies block of next branch
# ext_file (IN) - the extract file for the alias directory
# levels (IN) - the number of branhes left: levels=1 -> leaf
#
# RETURNS
# file number for file name alias
#
########
sub asmcmdamdu_get_filenum
{
my $index = shift(@_);
my $ext_file = shift(@_);
my @parms = @_;
shift(@parms);
my $branch = $parms[0];
my $levels = @parms;
my ($label, $i);
my ($kfed_args, $kfarefnum, $kfarefnum2, $kfaname, $kfafnum);
my (@kfedout, @fields);
# if branch is null, user probably entered file name in wrong form
if (!defined($branch))
{
return 0;
}
# directories in which kfed can be found.
my (@patharr) =("$ENV{'ORACLE_HOME'}/bin/",
"$ENV{'ORACLE_HOME'}/rdbms/bin/");
# Form the kfed execution line to read the disk header.
$kfed_args = "op=read blknum=$index dev=\'$ext_file\'";
# Execute the kfed command and capture the results.
@kfedout = asmcmdshare_execute_tool("kfed", ".exe", $kfed_args, \@patharr);
# Read the kfed dump containing this
for ($i = 0; $i < @kfedout; $i++)
{
if($kfedout[$i] =~ /\.refer\.number:/)
{
@fields = split ' ', $kfedout[$i];
$kfarefnum = hex($fields[@fields-1]);
if ($kfarefnum == 0)
{
next; # skip over empty kfa entries
}
($label,$kfaname) = split /[:,\s]+/, $kfedout[$i+=2];
($label,$kfafnum) = split ' ', $kfedout[++$i];
if ($kfaname =~/^$branch$/i) # we have a hit
{
if ($levels eq 1) # this is the leaf, we're done
{
return $kfafnum;
}
else # still on branch, recurse to next branch/leaf
{
return asmcmdamdu_get_filenum($kfarefnum, $ext_file, @parms);
}
}
}
}
return $asmcmdglobal_maxub4;
}
########
# NAME
# asmcmdamdu_process_help
#
# DESCRIPTION
# This function is the help function for the ASMCMDAMDU module.
#
# PARAMETERS
# command (IN) - display the help message for this command.
#
# RETURNS
# 1 if command found; 0 otherwise.
########
sub asmcmdamdu_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 (asmcmdamdu_is_cmd ($command))
{ # User specified a command name to look up. #
$desc = asmcmdshare_get_help_desc($command);
asmcmdshare_print "$desc\n";
$succ = 1;
}
return $succ;
}
########
# NAME
# asmcmdamdu_is_cmd
#
# DESCRIPTION
# This routine checks if a user-entered command is one of the known
# ASMCMD internal commands that belong to the ASMCMDAMDU module.
#
# PARAMETERS
# arg (IN) - user-entered command name string.
#
# RETURNS
# True if $arg is one of the known commands, false otherwise.
########
sub asmcmdamdu_is_cmd
{
my ($arg) = shift;
return defined ($asmcmdamdu_cmds {$arg});
}
########
# NAME
# asmcmdamdu_is_wildcard_cmd
#
# DESCRIPTION
# This routine determines if an ASMCMDAMDU 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 asmcmdamdu_is_wildcard_cmd
{
my ($arg) = shift;
return defined ($asmcmdamdu_cmds{ $arg }) &&
(asmcmdshare_get_cmd_wildcard($arg) eq "true" ) ;
}
########
# NAME
# asmcmdamdu_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 asmcmdamdu module currently supports no command that can run
# without an ASM instance.
########
sub asmcmdamdu_is_no_instance_cmd
{
my ($arg) = shift;
my ($rc);
return 1 unless defined($asmcmdamdu_cmds{$arg});
$rc = asmcmdshare_get_cmd_noinst($arg);
if ($rc eq "true")
{
return 1;
}
elsif ($rc eq "undef")
{
return -1;
}
return 0;
}
########
# NAME
# asmcmdamdu_parse_int_args
#
# DESCRIPTION
# This routine parses the arguments for flag options for ASMCMDAMDU
# 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 ASMCMDAMDU internal command.
########
sub asmcmdamdu_parse_int_args
{
my ($cmd, $args_ref) = @_;
my (@string);
# 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. #
asmcmdamdu_syntax_error($cmd);
return undef;
}
return 0;
}
########
# NAME
# asmcmdamdu_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 ASMCMDAMDU 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 asmcmdamdu_syntax_error
{
my ($cmd) = shift;
my ($cmd_syntax); # Correct syntax for $cmd. #
my ($succ) = 0;
#display syntax only for commands in this module.
if (asmcmdamdu_is_cmd($cmd))
{
$cmd_syntax = asmcmdshare_get_help_syntax($cmd); # Get syntax for $cmd. #
$cmd_syntax = asmcmdshare_trim_str ($cmd_syntax); # Trim blank spaces #
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
# asmcmdamdu_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
# 1 if the command is defined; 0 otherwise
########
sub asmcmdamdu_get_cmd_syntax
{
my ($cmd) = shift;
my $cmd_syntax;
my $succ = 0;
if ( asmcmdamdu_is_cmd($cmd))
{
$cmd_syntax = asmcmdshare_get_help_desc($cmd);
if (defined ($cmd_syntax))
{
asmcmdshare_printstderr 'usage: ' . $cmd_syntax . "\n";
asmcmdshare_printstderr 'help: help ' . $cmd . "\n";
$succ = 1;
}
}
return $succ;
}
########
# NAME
# asmcmdamdu_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 asmcmdamdu_get_asmcmd_cmds
{
return asmcmdshare_filter_invisible_cmds(%asmcmdamdu_cmds);
}
OHA YOOOO