MINI MINI MANI MO

Path : /opt/oracle/product/18c/dbhomeXE/lib/
File Upload :
Current File : //opt/oracle/product/18c/dbhomeXE/lib/asmcmdamdu.pm

# 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