MINI MINI MANI MO

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

# Copyright (c) 2004, 2018, Oracle and/or its affiliates. All rights reserved.
#
#    NAME
#      asmcmdpasswd - ASM CoMmanD line interface for shared password file 
#                     operations
#
#    DESCRIPTION
#      This module handles the shared password file operations like create, 
#      move, copy, delete the password file, get and set the password 
#      file location.y
#
#    MODIFIED (MM/DD/YY)
#    apfwkr    03/28/18 - Backport moreddy_bug-27688692 from main
#    moreddy   03/19/18 - 27688692: modify pwcreate
#    prabbala  07/25/17 - 26485972: Fix value of dest_DG in _normalized_files
#    anovelo   01/17/17 - 21159907: Disallow duplicate password files
#    anovelo   10/27/16 - 19261460: Ensure CRS is updated in pwmove
#    anovelo   10/24/16 - 24706236: Update calls to asmcmdshare_get_subdirs
#    prabbala  09/15/16 - bug19777340: send dbuniquename to KFPKG in pwcopy
#    yilhu     07/19/16 - 24309216: Add anchor for start of line when parsing
#    diguzman  05/30/16 - 19654070: Little change at _no_instance_cmd routine
#    moreddy   05/30/16 - 21168520: fix pwdelete --dbuniquename
#    anovelo   03/08/16 - 21894027: Update format for orapwd
#    dacavazo  01/18/16 - 22458930: fix undefined array value in pwdelete
#    dacavazo  12/07/15 - 22223809: undef function before dl_find_symbol
#    bhshanmu  07/26/15 - bhshanmu_perl_522_changes_for_rdbms
#    prabbala  01/30/15 - 20101171: use asmcmdshare_runcmd to capture cmd o/p
#    prabbala  11/25/14 - bug19512500: use asmcmdshare_runcmd to capture shell
#                         command output
#    pvenkatr  07/05/13 - Bug 14014671: Reverse lookup API integration.
#    pvenkatr  02/01/13 - using asmcmdshare_filter_invisible_cmds
#    adileepk  05/08/12 - Fix for bug-14000743.
#    adileepk  04/18/12 - Fix for bug-13964420.
#    adileepk  03/15/12 - Fix for bug-13827285.
#    ssonawan  03/08/12 - Bug 13050833: replace 'extended' by 'format'
#    adileepk  01/31/12 - Fix for bug-13574607.
#    adileepk  12/01/11 - Fix for bug-13450576. Adding pwget & pwset
#                         commands.
#    adileepk  01/10/11 - Creation
#
#############################################################################
#
############################ Functions List #################################
#
# Top Level Command Processing Routines
#   asmcmdpasswd_init
#   asmcmdpasswd_process_cmd
#   asmcmdpasswd_process_pwcreate
#   asmcmdpasswd_process_pwcopy
#   asmcmdpasswd_process_pwdelete
#   asmcmdpasswd_process_pwmove
#   asmcmdpasswd_process_pwset
#   asmcmdpasswd_process_pwget
#   asmcmdpasswd_process_help
#
# Error Routines
#   asmcmdpasswd_syntax_error
#
# Help Routines
#   asmcmdpasswd_get_asmcmd_cmds
#
# Misc Utility Routines
#   asmcmdpasswd_get_res_list
#############################################################################

package asmcmdpasswd;
require Exporter;
our @ISA    = qw(Exporter);
our @EXPORT = qw(asmcmdpasswd_init
                 );

use strict;
use Getopt::Std;
use asmcmdglobal;
use asmcmdshare;
use asmcmdparser;
use asmcmdbase;

####################### ASMCMDPASSWD Global Constants ######################



####################### ASMCMDPASSWD Global Variables ######################
my (%asmcmdpasswd_cmds) = (pwcreate    => { },
                           pwcopy      => { },
                           pwmove      => { },
                           pwdelete    => { },
                           pwset       => { },
                           pwget       => { },
                          );

my ($PLSQL_NUMBER)      = 22;
my ($PLSQL_PWFILE)      = 28;

sub is_asmcmd
{
  return 1;
}

########
# NAME
#   asmcmdpasswd_init
#
# DESCRIPTION
#   This function initializes the asmcmdpasswd 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, \&asmcmdpasswd_process_cmd);
  push (@asmcmdglobal_help_callbacks, \&asmcmdpasswd_process_help);
  push (@asmcmdglobal_command_list_callbacks, \&asmcmdpasswd_get_asmcmd_cmds);
  push (@asmcmdglobal_is_command_callbacks, \&asmcmdpasswd_is_cmd);
  push (@asmcmdglobal_is_wildcard_callbacks, \&asmcmdpasswd_is_wildcard_cmd);
  push (@asmcmdglobal_syntax_error_callbacks, \&asmcmdpasswd_syntax_error);
  push (@asmcmdglobal_no_instance_callbacks, \&asmcmdpasswd_is_no_instance_cmd);
  %asmcmdglobal_cmds = (%asmcmdglobal_cmds, %asmcmdpasswd_cmds);

  #Perform ASMCMD consistency check if enabled
  if ($asmcmdglobal_hash{'consistchk'} eq 'y')
  {
    if (!asmcmdshare_check_option_consistency(%asmcmdpasswd_cmds))
    {
      exit 1;
    }
  }
}

########
# NAME
#   asmcmdpasswd_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 asmcmdpasswd module; 0 if not.
#
# NOTES
#   Only asmcmdcore_shell() calls this routine.
########
sub asmcmdpasswd_process_cmd 
{
  my ($dbh) = @_;
  my ($succ) = 0;
  my ($result);
  # Get current command from global value, which is set by 
  # asmcmdpasswd_parse_asmcmd_args()and by asmcmdcore_shell().
  my ($cmd) = $asmcmdglobal_hash{'cmd'};

  # Declare and initialize hash of function pointers, each designating a 
  # routine that processes an ASMCMDTEMPLATE command.
  my (%cmdhash) = ( pwcreate => \&asmcmdpasswd_process_pwcreate, 
                    pwcopy   => \&asmcmdpasswd_process_pwcopy,
                    pwmove   => \&asmcmdpasswd_process_pwmove,
                    pwdelete => \&asmcmdpasswd_process_pwdelete,
                    pwset    => \&asmcmdpasswd_process_pwset,
                    pwget    => \&asmcmdpasswd_process_pwget,
                  );

  if (defined ( $cmdhash{ $cmd } ))
  {    # If user specifies a known command, then call routine to process it. #
    $result = $cmdhash{ $cmd }->($dbh);
    $succ = 1;
  }

  return $succ;
}

########
# NAME
#   asmcmdpasswd_process_help
#
# DESCRIPTION
#   This function is the help function for the ASMCMDPASSWD module.
#
# PARAMETERS
#   command     (IN) - display the help message for this command.
#
# RETURNS
#   1 if command found; 0 otherwise.
########
sub asmcmdpasswd_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 (asmcmdpasswd_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
#   asmcmdpasswd_is_cmd
#
# DESCRIPTION
#   This routine checks if a user-entered command is one of the known
#   ASMCMD internal commands that belong to the ASMCMDPASSWD module.
#
# PARAMETERS
#   arg   (IN) - user-entered command name string.
#
# RETURNS
#   True if $arg is one of the known commands, false otherwise.
########
sub asmcmdpasswd_is_cmd 
{
  my ($arg) = shift;
  return defined ( $asmcmdpasswd_cmds{ $arg } );
}

########
# NAME
#   asmcmdpasswd_is_wildcard_cmd
#
# DESCRIPTION
#   This routine determines if an ASMCMDPASSWD 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 asmcmdpasswd_is_wildcard_cmd 
{
  my ($arg) = shift;

  return defined ($asmcmdpasswd_cmds{ $arg }) &&
         (asmcmdshare_get_cmd_wildcard($arg) eq "true" ) ;
}

########
# NAME
#   asmcmdpasswd_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 asmcmdpasswd module currently supports no command that can run 
#   without an ASM instance.
########
sub asmcmdpasswd_is_no_instance_cmd 
{
  my ($arg) = shift;
  my ($rc);

  return 1 unless defined($asmcmdpasswd_cmds{$arg});

  $rc = asmcmdshare_get_cmd_noinst($arg);
  if ($rc eq "true")
  {
    return 1;
  }
  elsif ($rc eq "undef")
  {
    return -1;
  }

  return 0;
}

########
# NAME
#   asmcmdpasswd_parse_int_args
#
# DESCRIPTION
#   This routine parses the arguments for flag options for ASMCMDPASSWD 
#   internal commands.  
#
# PARAMETERS
#   cmd      (IN)  - user-entered command name string.
#   args_ref (OUT) - hash of user-specified flag options for a command, 
#                    populated by asmcmdparser.
#
# RETURNS
#   Zero on success; undefined on error.
#
# NOTES
#   $cmd must already be verified as a valid ASMCMDPASSWD internal command.
########
sub asmcmdpasswd_parse_int_args 
{
  my ($cmd, $args_ref) = @_;
  my (@string);
  my ($key);

  #include deprecated options if any
  if ($asmcmdglobal_deprecated_options{ $cmd })
  {
    foreach my $key(keys %{$asmcmdglobal_deprecated_options{ $cmd }})
    {
      push(@string, $asmcmdglobal_deprecated_options{$cmd}{$key}[0]);
    }
  }

  # 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. #
    asmcmdpasswd_syntax_error($cmd);
    return undef;
  }
  return 0;
}

########
# NAME
#   asmcmdpasswd_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 ASMCMDPASSWD 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.  
# 
#   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 asmcmdpasswd_syntax_error 
{
  my ($cmd) = shift;
  my ($cmd_syntax);                               # Correct syntax for $cmd. #
  my ($succ) = 0;

  #display syntax only for commands in this module.
  if (asmcmdpasswd_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
#   asmcmdpasswd_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 asmcmdpasswd_get_asmcmd_cmds 
{
  return asmcmdshare_filter_invisible_cmds(%asmcmdpasswd_cmds);
}

########
# NAME
#   asmcmdpasswd_get_res_list
#
# DESCRIPTION
#   To find a list of resources associated with the given password file
#
# PARAMETERS
#   $filepath    -  full path name of password file
#
# RETURNS
#   @reslist     - list of resource names associated with the given passwd file
#
########
sub asmcmdpasswd_get_res_list
{
  my ($filepath) = shift ;
  my (@reslist, $hasres, $ret);
  my ($cdet);
  my ($lib) = $asmcmdglobal_hash{'asmperl'};

  undef &ASMCMDkgfPWFileGetRes;
  $cdet = DynaLoader::dl_find_symbol($lib, "XS_ASMCMDCLNT_kgfPWFileGetRes");
  DynaLoader::dl_install_xsub("ASMCMDkgfPWFileGetRes", $cdet);
  ($ret, $hasres, @reslist) = ASMCMDkgfPWFileGetRes( $filepath, '');
  if ($ret != 0 )
  {
    asmcmdshare_trace (3,
                 "NOTE:Get CRS Resource List failed for $filepath err $ret\n",
                 'n', 'y');
    die "Error: GetResource List failed for $filepath ret $ret\n";
  }

  # if no resources returned make sure the reslist is empty.
  if ($hasres == 0 )
  {
    @reslist = ();   # empty the resource list
  }
  return @reslist;
}



########
# NAME
#   asmcmdpasswd_process_pwcreate
#
# DESCRIPTION
#   This function processes the asmcmd command pwcreate.
#   This function calls orapwd internally to create the pasword file, and uses
#   srvctl to update the CRSD resource.
#
# PARAMETERS
#   dbh   (IN) - initialized database handle, must be non-null.
#
# RETURNS
#   Null.
#
# NOTES
#   Only asmcmdpasswd_process_cmd() calls this function.
#   
########
sub asmcmdpasswd_process_pwcreate
{
  my ($dbh)    = shift;
  my ($format) = undef;
  my ($force)  = 0;
  my (%args); 
  my ($dbuniquename, $asm);
  my ($filepath, $filename, $syspassword);
  my (@eargs);
  my ($alias, %norm);
  my @buf;                              # Buffer to hold command output.

  my $ret = asmcmdpasswd_parse_int_args($asmcmdglobal_hash{'cmd'}, \%args);
  return unless defined ($ret);

  $dbuniquename = $args{'dbuniquename'} if defined $args{'dbuniquename'};
  $asm          = $args{'asm'} if defined $args{'asm'};
  $format       = $args{'format'} if defined $args{'format'};
  $force        = 1 if (defined($args{'f'}));

  ($filepath, $syspassword) = @{$args{'pwcreate'}};
  %norm = asmcmdpasswd_normalized_files(\$dbh, undef, $filepath);
  if (!$norm{'dest_success'})
  {
    asmcmdshare_error_msg(9455, undef);
    return;
  }
  $filepath = $norm{'dest_filepath'};
  if ($filepath !~ m/^\+/)
  {
    #Error, password file should be located on a diskgroup
    # and the name of the disk group should be preceded by a '+' symbol.
    asmcmdshare_error_msg(9455, undef); 
    return;
  }

  if (defined($format) && $format !~ m/^12(.2)?$/)
  {
    asmcmdshare_error_msg(9464, undef);
    return;
  }

  #
  # ORAPWD internally checks for resource name associated with given password
  # file, and multiple resources using the given password file, or if given
  # password file exists, and action based on "force" specified or not.
  #
  my (@patharr) = ("$ENV{'ORACLE_HOME'}/bin/",
                   "$ENV{'ORACLE_HOME'}/rdbms/bin/");

  my ($opt);
  # dbuniquename
  $opt = "file=$filepath dbuniquename=$dbuniquename".
         " password=$syspassword"     if (defined($dbuniquename));

  # asm
  $opt = "file=$filepath asm=y".
         " password=$syspassword" if (defined($asm));

  # force option
  $opt = $opt . " force=y" if ($force == 1);
  # format option
  $opt = $opt . " format=$format" if (defined($format));

  my $errorflag = 'n';

  # send parameter to asmcmdshare_execute_tool to skip tracing
  @buf = asmcmdshare_execute_tool ("orapwd", ".exe", $opt, \@patharr, 0, 1);

  $errorflag = 'y' if ($@ ne '');
  foreach(@buf)
  {
    chomp $_;
    $errorflag = 'y' if ($_ =~ /[A-Z]+-[0-9]+\s*:/); # If an error is detected
    asmcmdshare_trace(3, "$_", 'y', 'y') if ($errorflag eq 'y');
  }
  if ($errorflag eq 'y')
  {
    asmcmdshare_error_msg(9454, undef);
  }
  else
  {
    asmcmdshare_trace(3, "The Password file was created successfuly by " .
                      "ASMCMD through an internal call to orapwd.",'y','n');
  }
  return;
}

########
# NAME
#   asmcmdpasswd_process_pwcopy
#
# DESCRIPTION
#   This top-level routine processes the pwcopy command.
#   This function calls the core function of the ASMCMD cp command
#   to copy the password file from the source to the destination.
#   It then uses srvctl to update the CRSD resource with the new location of
#   the password if and only if the user specifies either the '--asm' or
#   '--dbuniquename' option.
#
# PARAMETERS
#   dbh   (IN) - initialize database handle, must be non-null.
#
# RETURNS
#   Null.
#
# NOTES
#   Only asmcmdpasswd_process_cmd() calls this routine.  
########
sub asmcmdpasswd_process_pwcopy
{
  my ($dbh) = shift;                                   # local auto-variables #
  my (%args);                                                      # cmd args #
  my (@eargs);
  my ($ret);
  my ($copy_success_hash);      # A reference to a hash of src and dest files #
                                              # that were successfully copied #
  my ($copy_success) = 0;             # Flag to indicate whether the copy was #
                                                          # successful or not #
  my (%norm);       # See asmcmdshare_normalize_path() return value comments. #
  my ($force) = 0;
  my ($dbuniquename) = undef;
  my ($asm) = undef;
  my ($src_filepath, $dest_filepath);
  my ($passwordfile_loc) = "";

  $ret = asmcmdbase_parse_int_args($asmcmdglobal_hash{'cmd'}, \%args);
  return unless defined ($ret);

  # check for the force option
  $force = 1 if (defined($args{'f'}));

  # check for the dbuniquename option.
  if (defined($args{'asm'}))
  {
    $dbuniquename = "ASM";
    $asm = 1;
  }
  elsif (defined($args{'dbuniquename'}))
  {
    $dbuniquename = $args{'dbuniquename'};
  }

  ($src_filepath, $dest_filepath) = @{$args{'pwcopy'}};

  %norm = asmcmdpasswd_normalized_files(\$dbh, $src_filepath, $dest_filepath);
  if (!$norm{'src_success'} || !$norm{'dest_success'})
  {
    return;
  }
  $src_filepath  = $norm{'src_filepath'};
  $dest_filepath = $norm{'dest_filepath'};

  ######                          -If OS -> OS-                          ######
  if ($src_filepath !~ m/^\+/ && $dest_filepath !~ m/^\+/)
  {
    #Error out, OS -> OS not supported
    asmcmdshare_error_msg(9458, undef);
    return;
  }

  ######                        -If DG -> same DG-                       ######
  if ($src_filepath =~ m/^\+/ && $dest_filepath =~ m/^\+/ &&
     $norm{'src_DG'} == $norm{'dest_DG'})
  {
    #Error out, DG -> same DG not supported
    asmcmdshare_error_msg(9459, undef);
    return;
  }

  ######    -If destination is OS CRS Resource cannot be updated         ######
  ######    Only if $asm or $dbuniquename specified                      ######
  if ((defined($asm) || defined($dbuniquename)) && ($dest_filepath !~ m/^\+/))
  {
    asmcmdshare_error_msg (9456, undef);
    return;
  }

  if (defined($dbuniquename) || defined($asm))
  {
    $ret = asmcmdpasswd_get_pwfile ($asm, $dbuniquename, \$passwordfile_loc);
    if ($ret && ($passwordfile_loc ne "" ))
    {
      # The resource has already a password file associated with it.
      if ($force == 0)
      {
        push (@eargs, $passwordfile_loc);
        push (@eargs, 'asm') if defined($asm);
        push (@eargs, $dbuniquename) if defined($dbuniquename);
        asmcmdshare_error_msg(8028, \@eargs);
        return;
      }
      else
      {
        $ret = asmcmdpasswd_set_pwfile ($asm, $dbuniquename, "");
      }
    }
  }
   
  ######                    -Copy the password file-                     ######
  ${$args{'pwcopy'}}[0] = $src_filepath;
  ${$args{'pwcopy'}}[1] = $dest_filepath;
  # copy the arguments for pwcopy so asmcmdbase_cp_core will process it 
  # correctly.
  @{$args{'cp'}} = @{$args{'pwcopy'}};

  # set the dbuniquename, if specified
  if (defined($dbuniquename)) 
  { 
    $asmcmdglobal_hash{'dbuniquename'} = $dbuniquename;
    asmcmdshare_trace(3, "dbuniquename is $asmcmdglobal_hash{'dbuniquename'}", 
                      'y', 'n'); 
  }

  # executes the core code of ASMCMD cp command to copy the password file to
  # the destination
  $copy_success_hash = asmcmdbase_cp_core($dbh, %args);

  while ( my ($key, $value) = each(%$copy_success_hash) )
  {
    # get the absolute path of src file and dest file
    $src_filepath = $key;
    $dest_filepath = $value;
    $copy_success++;
  }

   
  ######                   -Check that copy succeeded-                   ######
  if (!$copy_success)
  {
    # Proceed no further. Error message would have been displayed at the cp
    # level.
    return;
  }
  asmcmdshare_trace(3, "The password file $src_filepath was copied " .
                       "successfully by ASMCMD to $dest_filepath", 'y', 'n');

   
  ######              -Update the CRS resource if necessary-             ######
  # Attempt to update the CRS resource with the new location of the password 
  # file if and only if the user specifies either the '--asm' or 
  # '--dbuniquename' option, and the destination file is on an ASM DG.
  if ((defined $args{'asm'} || defined $args{'dbuniquename'}) && 
      $copy_success == 1)
  {
    # The dest_filepath here will be on DG only.
    asmcmdpasswd_set_pwfile ($asm, $dbuniquename, $dest_filepath);
  }
  return;
}

########
# NAME
#   asmcmdpasswd_process_pwmove
#
# DESCRIPTION
#   This top-level routine processes the pwmove command.
#   This function calls the core function of the ASMCMD cp command
#   to copy the password file from the source to the destination.
#   Then deletes the original file from the source path.
#   It then uses srvctl to update the CRSD resource with the new location of
#   the password file.
#
# PARAMETERS
#   dbh   (IN) - initialize database handle, must be non-null.
#
# RETURNS
#   Null.
#
# NOTES
#   Only asmcmdpasswd_process_cmd() calls this routine.  
########
sub asmcmdpasswd_process_pwmove
{
  my ($dbh) = shift;                                   # local auto-variables #
  my (%args);                                                      # cmd args #
  my (@eargs);
  my ($ret);
  my @buf = ();
  my ($copy_success_hash);      # A reference to a hash of src and dest files #
                                              # that were successfully copied #
  my ($copy_success) = 0;             # Flag to indicate whether the copy was #
                                                          # successful or not #
  my (%norm);       # See asmcmdshare_normalize_path() return value comments. #
  my ($alias_path);                     # User-entered raw path for deletion. #
  my ($alias_name);                                   # Alias name of a path. #
  my ($is_dir);           # Flag: 'Y' if alias is a directory; 'N' otherwise. #
  my ($gnum);                                                 # Group number. #
  my ($gname);                                                  # Group name. #
  my ($par_id);                                      # Parent ID of an alias. #
  my ($spprserr) = 0;          # Whether to suppress errors on normalization. #
  my ($i);                              # Iteration variable for for() loops. #
  my (@entries); 

  my ($dbuniquename) = undef;
  my ($asm) = undef;
  my ($force) = 0 ;
  my ($src_filepath, $dest_filepath);
  my ($passwordfile_loc);
  my ($sqlstmt, $sth, $row);
  my (@src_aliases) = ();
  my (@reslist);

  # get option parameters 
  $ret = asmcmdbase_parse_int_args($asmcmdglobal_hash{'cmd'}, \%args);
  return unless defined ($ret);

  $dbuniquename = $args{'dbuniquename'}   if defined $args{'dbuniquename'};
  $asm = 1 if defined $args{'asm'};
  $force = 1 if (defined ($args{'f'}));
  ($src_filepath, $dest_filepath) = @{$args{'pwmove'}};

  if (defined($dbuniquename) || defined ($asm) )
  {
    $ret = asmcmdpasswd_get_pwfile ($asm, $dbuniquename, \$passwordfile_loc);
    if ((defined ($ret) && ($ret == 1)) && 
        (defined ($passwordfile_loc) && (length($passwordfile_loc) > 0 )) &&
        ($force == 0 ))
    {
      push (@eargs, $passwordfile_loc);
      push (@eargs, 'asm') if defined($asm);
      push (@eargs, $dbuniquename) if defined($dbuniquename);
      asmcmdshare_error_msg (8028, \@eargs);
      return;
    }
    elsif ($ret == 0)
    {
      return;
    }
  }

  %norm = asmcmdpasswd_normalized_files(\$dbh, $src_filepath, $dest_filepath);
  # If normalization failed, then return. Errors would have been printed by 
  # normalization routine.
  if (!$norm{'src_success'} || !$norm{'dest_success'})
  {
    return;
  }
  $src_filepath  = $norm{'src_filepath'};
  $dest_filepath = $norm{'dest_filepath'};

  ######-              Find all aliases for this src file              -######
  if ($norm{'src_onDG'})
  {
    $src_filepath =~ m/[\\\/]+([^\\\/]+)$/;
    $alias_name = $1;
    my @info = ();
    my ($file_number);

    #retreive the unique file number given the parent_id,reference_id,
    #group_number and filename
    asmcmdshare_get_subdirs($dbh, \@info, undef, $norm{'src_DG'}, 
                            $norm{'src_reference_index'}, 
                            $norm{'parent_index'}, $alias_name, 
                            undef, 0, 0);
 
    $file_number = $info[0]->{'file_number'};

    # Find the SYS alias.
    $alias_name = asmcmdbase_get_alias_path($dbh, $norm{'src_DG'}, 
                                            $file_number, 'Y');
    push(@src_aliases, $alias_name);
    # Find the USER created alias.
    $alias_name = asmcmdbase_get_alias_path($dbh, $norm{'src_DG'}, 
                                            $file_number, 'N');
    push(@src_aliases, $alias_name);
  }

   
  ######                          -If OS -> OS-                          ######
  if ($src_filepath !~ m/^\+/ && $dest_filepath !~ m/^\+/)
  {
    #Error out, OS -> OS not supported
    asmcmdshare_error_msg(9458, undef);
    return;
  }

  ######                        -If DG -> same DG-                       ######
  if ($src_filepath =~ m/^\+/ && $dest_filepath =~ m/^\+/ &&
      $norm{'src_DG'} == $norm{'dest_DG'})
  {
    #Error out, DG -> same DG not supported
    asmcmdshare_error_msg(9459, undef);
    return;
  }

  ######   If the destination file is on OS, res can not be updated    #######
  ######    Only if $asm or $dbuniquename specified                    #######
  if ((defined($asm) || defined($dbuniquename)) && ($dest_filepath !~ m/^\+/))
  {
    asmcmdshare_error_msg (9456, undef);
    return;
  }

  # get the resource(s) associated with given source password file name
  @reslist = asmcmdpasswd_get_res_list ($src_filepath);

  # if shared by more than one resource - can't move, bail out.
  if ($#reslist > 1)
  {
    @eargs = ($src_filepath);
    asmcmdshare_error_msg (8026, \@eargs);
    return;
  }

  # if only one resource and not matching given res - can't move, bail out
  if (($#reslist == 1) &&
      !((defined($asm) && ($reslist[0] eq "ora.asm")) ||
        (defined($dbuniquename) && ($reslist[0] eq "db.$dbuniquename.db"))))
  {
    @eargs = ($src_filepath);
    asmcmdshare_error_msg (8026, \@eargs);
    return;
  }

  ######                    -Copy the password file-                     ######
  ${$args{'pwmove'}}[0] = $src_filepath;
  ${$args{'pwmove'}}[1] = $dest_filepath;
  # copy the arguments for pwmove so asmcmdbase_cp_core will process it 
  # correctly.
  @{$args{'cp'}} = @{$args{'pwmove'}};
  # executes the core code of ASMCMD cp command to copy the password file to
  # the destination.
  $copy_success_hash = asmcmdbase_cp_core($dbh, %args);
  while ( my ($key, $value) = each(%$copy_success_hash) )
  {
    # get the absolute path of src file and dest file
    $src_filepath = $key;
    $dest_filepath = $value;
    $copy_success++;
  }

  ######                   -Check that copy succeeded-                   ######
  if (!$copy_success)
  {
    # Proceed no further. Error message would have been displayed at the copy
    # level.
    return;
  }

  # Reconnect to instance since dbh handle would become useless after the copy
  asmcmdbase_disconnect($dbh) if defined ($dbh);
  $dbh = asmcmdbase_connect(undef);

  ######                      -Delete the src file-                      ######
  if ($src_filepath =~ m/^\+/) # If the src file was on a DG, use sql query to
                               # drop the file
  {
    $alias_path = $src_filepath;
    %norm = asmcmdshare_normalize_path($dbh, $alias_path, $spprserr, \$ret);

    # Error if normalization failed/ password file does not exist
    if ($ret != 0)
    {
      @eargs = ($alias_path);
      asmcmdshare_error_msg(9452, \@eargs);
      return;
    }

    # Remove one entry at a time, if $alias_path contains '*' and has multiple
    # password file matches.
    for ($i = 0; $i < @{ $norm{'path'} }; $i++) 
    {
      $alias_name = $alias_path = $norm{'path'}->[$i];
      $alias_name =~ s,.*/([^/]+)$,$1,;   # Get last level of path for name.#
      $par_id = $norm{'par_id'}->[$i];
      $gnum = $norm{'gnum'}->[$i];

      # If parent index is -1, then the directory must be a diskgroup or '+';
      # thus we cannot remove it.
      if ($par_id != -1)
      {
        asmcmdshare_get_subdirs($dbh, \@entries, undef, $gnum, undef, $par_id, 
                                $alias_name, undef, 0, 0);
        $is_dir = $entries[$i]->{'alias_directory'};
        $gname = asmcmdshare_get_gname_from_gnum ($dbh, $gnum);

        # Run SQL to remove an entry.     
        asmcmdbase_rm_sql($dbh, $gname, $alias_path, $is_dir);
      }
    }
  }
  else # If the src file is on OS filesystem, use system command to remove it
  {
    $ret = 0;
    eval
    {
      $ret = unlink("$src_filepath");
    };
    if ($@ || !defined($ret) || !$ret)
    {
      # Warn, no need to error out
      asmcmdshare_print("Couldn't delete $src_filepath from OS filesystem\n");
    }
  }

  asmcmdshare_trace(3, "The password file $src_filepath was moved " .
                        "successfuly by ASMCMD to $dest_filepath", 'y', 'n');

  #######           -Now update the CRS resource if necessary-           ######
  # Attempt to update the CRS resource with the new location of the password 
  # file if and only if the user specifies either the '--asm' or 
  # '--dbuniquename' option, and the destination file is on an ASM DG.
  if ((defined $args{'asm'} || defined $args{'dbuniquename'}) && 
      $copy_success == 1)
  {
    # Remove the original resource value.
    asmcmdpasswd_set_pwfile ($asm, $dbuniquename, "");

    # $dest_filepath will be on DG here.
    asmcmdpasswd_set_pwfile ($asm, $dbuniquename, $dest_filepath);
  }
  return;
}

########
# NAME
#   asmcmdpasswd_process_pwdelete
#
# DESCRIPTION
#   This top-level routine processes the pwdelete command.
#   This function removes the password file from the specified location
#   and updates the CRSD resource.
#
# PARAMETERS
#   dbh   (IN) - initialize database handle, must be non-null.
#
# RETURNS
#   Null.
#
# NOTES
#   Only asmcmdpasswd_process_cmd() calls this routine.  
########
sub asmcmdpasswd_process_pwdelete
{
  my ($dbh) = shift;
  my (%args);                           # Argument hash used by asmcmdparser. #
  my (%norm);       # See asmcmdshare_normalize_path() return value comments. #
  my ($ret);                      # asmcmdbase_parse_int_args() return value. #
  my ($dbuniquename);
  my ($asm);
  my ($force) = 0 ;
  my ($alias_name, $filepath, $filetype);
  my @buf;                                   # Buffer to hold command output. #
  my (@eargs);
  my (@reslist);

  $ret = asmcmdpasswd_parse_int_args($asmcmdglobal_hash{'cmd'}, \%args);
  return unless defined ($ret);

  $dbuniquename = $args{'dbuniquename'}   if defined $args{'dbuniquename'};
  $asm = 1 if defined $args{'asm'};
  $force = 1 if defined ($args{'f'});

  ($filepath) = @{$args{'pwdelete'}} if defined $args{'pwdelete'};

  if (defined($args{'dbuniquename'}) || defined ($args{'asm'}))
  {
    $ret = asmcmdpasswd_get_pwfile ($asm, $dbuniquename, \$filepath);
  }
  elsif (defined $filepath)
  {
    %norm = asmcmdpasswd_normalized_files(\$dbh, $filepath, undef);
    if (!$norm{'src_success'})
    {
      return;
    }
    $filepath = $norm{'src_filepath'};
  }
   
  #
  # ORAPWD utility handles the clearing of resource name of given password
  # and checking if more than one resources are using sceanrio.  
  #

  ######-              Find all aliases for this src file              -######
  $filepath = $norm{'src_filepath'};

  ######                        -Delete the file-                        ######
  if (defined $args{'dbuniquename'} || defined $args{'asm'} || 
      (@{$args{'pwdelete'}} && $filepath =~ /^\+/)) 
      # If the src file was on a DG, use orapwd to drop the file
  {
    my (@patharr) = ("$ENV{'ORACLE_HOME'}/bin/",
                     "$ENV{'ORACLE_HOME'}/rdbms/bin/");
    my $opt;

    #dbuniquename
    $opt = "delete=y dbuniquename=$dbuniquename" if (defined($dbuniquename));
    #asm
    $opt = "delete=y asm=y" if (defined($asm));
    # if file name is provided
    $opt = "delete=y file=$filepath" if defined($filepath);
    # force
    $opt = "$opt". " force=y" if ($force == 1);
    my $errorflag = 'n';

    @buf = asmcmdshare_execute_tool ("orapwd", ".exe", $opt, \@patharr);

    $errorflag = 'y' if ($@ ne '');
    foreach(@buf)
    {
      chomp $_;
      $errorflag = 'y' if ($_ =~ /[A-Z]+-[0-9]+\s*:/); # If an error is found
      asmcmdshare_trace(3, "$_", 'y', 'y') if ($errorflag eq 'y');
    }
    if ($errorflag eq 'y')
    {
      asmcmdshare_error_msg(9462, undef);
    }
    else
    {
      asmcmdshare_trace(3, "The Password file was deleted successfuly by " .
                           "ASMCMD through an internal call to orapwd.", 
                            'y', 'n');
    }
  }
  else # If the src file is on OS filesystem, use system command to remove it
  {
    $ret = 0;
    eval
    {
      $ret = unlink("$filepath");
    };
    if ($@ || !defined($ret) || !$ret)
    {
      # Warn, no need to error out
      asmcmdshare_print("Couldn't delete $filepath from OS filesystem\n");
      return;
    }
    else
    {
      asmcmdshare_trace(3, "The password file $filepath was deleted " .
                           "successfuly by ASMCMD", 'y', 'n');
    }
  }

  return;
}

########
# NAME
#   asmcmdpasswd_process_pwset
#
# DESCRIPTION
#   This top-level routine processes the pwset command.
#   This function sets the location of the password file associated with and 
#   ASM or a DB instance on the CRS resource.
#
# PARAMETERS
#   dbh   (IN) - initialize database handle, must be non-null.
#
# RETURNS
#   Null.
#
# NOTES
#   Only asmcmdpasswd_process_cmd() calls this routine.  
########
sub asmcmdpasswd_process_pwset
{
  my $dbh = shift;
  my %args;                            # Argument hash used by asmcmdparser. #
  my $ret;                       # asmcmdbase_parse_int_args() return value. #
  my @eargs;
  my $dbuniquename;
  my $asm;
  my $force = 0 ;
  my %norm;
  my $srvctl;
  my $srvctlcommand;                      # For executing the srvctl command. #
  my @buf = ();                              # Buffer to hold command output. #
  my @reslist;
  my $filepath;

  $ret = asmcmdpasswd_parse_int_args($asmcmdglobal_hash{'cmd'}, \%args);
  return unless defined ($ret);

  $dbuniquename = "";
  $dbuniquename = $args{'dbuniquename'}   if defined $args{'dbuniquename'};
  $asm = 1 if defined $args{'asm'};
  $force = 1 if defined $args{'f'};

  if (defined($dbuniquename) || defined ($asm))
  {
    $ret = asmcmdpasswd_get_pwfile ($asm, $dbuniquename, \$filepath);
    if (defined($ret) && ($ret == 1)  && 
        ($filepath ne "" && $filepath ne $args{'pwset'}))
    {
      if ($force == 0 )
      {
        push (@eargs, $filepath);
        push (@eargs, 'asm') if defined ($asm);
        push (@eargs, $dbuniquename) if defined ($dbuniquename);

        # ASMCMD-8028 "Password file '%s' is associated with '%s' already. Use 
        #              the force option."
        asmcmdshare_error_msg (8028, \@eargs);
        return ;
      }
    }
  }

  ($filepath) = @{$args{'pwset'}};
  if (!defined $filepath || $filepath eq '""' || $filepath eq "''")
  {
    $filepath = "";
  }

  if ($filepath ne "")
  {
    %norm = asmcmdpasswd_normalized_files(\$dbh, $filepath, undef);
    if (!$norm{'src_success'})
    {
      return;
    }
    $filepath = $norm{'src_filepath'};

    if (!($filepath =~ m/^\+/))
    {
      # ASMCMD-9456 "password file should be located on an ASM disk group"
      asmcmdshare_error_msg(9456, undef);
      return;
    }

    # Bug21159907: Check if the password file has been already set for another
    # resource, but only if the force option is not set.
    @reslist = asmcmdpasswd_get_res_list($filepath);
    if (scalar @reslist > 0 && !$force)
    {
      @eargs = $filepath;
      # ASMCMD-8026 Password file '%s' is in use. Use the force option.
      asmcmdshare_error_msg(8026, \@eargs);
      return;
    }
  }
  asmcmdpasswd_set_pwfile($asm, $dbuniquename, $filepath);

  return;
}

########
# NAME
#   asmcmdpasswd_process_pwget
#
# DESCRIPTION
#   This top-level routine processes the pwget command.
#   This function retrieves the location of the password file associated with 
#   and ASM or a DB instance from the CRS resource.
#
# PARAMETERS
#   dbh   (IN) - initialize database handle, must be non-null.
#
# RETURNS
#   Null.
#
# NOTES
#   Only asmcmdpasswd_process_cmd() calls this routine.  
########
sub asmcmdpasswd_process_pwget
{
  my ($dbh) = shift;
  my (%args);                          # Argument hash used by asmcmdparser. #
  my ($ret);                     # asmcmdbase_parse_int_args() return value. #
  my (@eargs);
  my ($dbuniquename,$asm);
  my ($passwordfile_loc) = "";

  $ret = asmcmdpasswd_parse_int_args($asmcmdglobal_hash{'cmd'}, \%args);
  return unless defined ($ret);

  $dbuniquename = $args{'dbuniquename'}   if defined $args{'dbuniquename'};
  $asm = 1 if defined $args{'asm'};

  $ret = asmcmdpasswd_get_pwfile($asm, $dbuniquename, \$passwordfile_loc);

  if ($ret)
  {
    if ($passwordfile_loc eq "")
    {
      if ($asm)
      {
        asmcmdshare_print("Password file location has not been set for " .
                          "ASM instance\n");
      }
      else
      {
        asmcmdshare_print("Password file location has not been set for " .
                          "DB instance\n");
      }
    }
    else
    {
      asmcmdshare_print("$passwordfile_loc\n");
    }
  }

  return;
}

########
# NAME
#   asmcmdpasswd_set_pwfile
#
# DESCRIPTION
#   This function sets the password file location on the corresponding CRS 
#   resource.
#
# PARAMETERS
#   asm              (IN)  - Whether an ASM or a DB resource is to be updated
#   dbuniquename     (IN)  - The dbuniquename, used only if asm is 0
#   passwordfile_loc (IN)  - The new location of the password file
#                            to be set on CRS.
#
# RETURNS
#   0 on failure
#   1 on success
#
# NOTES
#   Assumes $passwordfile_loc is a valid path and the file is on DG
#
########
sub asmcmdpasswd_set_pwfile
{
  my ($asm) = shift;
  my ($dbuniquename) = shift;
  my ($passwordfile_loc) = shift;
  my ($ret) = 0;
  my ($srvctl, $srvctlcommand);
  my (@eargs) = ();
  my ($errorflag) = 'n';
  my (@buf) = ();

  $srvctl = "$ENV{'ORACLE_HOME'}/bin/srvctl";
  #Path in Win is ORACLE_HOME/bin/srvctl.bat
  $srvctl .= ".bat" if ($^O =~ /win/i);

  # Make sure the srvctl binary exists and can be executed. 
  if (! -x $srvctl)
  { 
    #If not, try at a second locaction.
    $srvctl = "$ENV{'ORACLE_HOME'}/srvm/bin/srvctl";
    #path in Win is ORACLE_HOME/bin/srvctl.bat
    $srvctl .= ".bat" if ($^O =~ /win/i);
    if (! -x $srvctl)
    {
      @eargs = ($srvctl);
      asmcmdshare_error_msg(8316, \@eargs);
      return $ret;
    }
  }

  #untaint srvctl
  $srvctl =~ /([^\n^\r^\t]+)/;
  $srvctl = $1; 

  if ($asm)
  {
    $srvctlcommand = "$srvctl modify asm -pwfile $passwordfile_loc";
  }
  else
  {
    $srvctlcommand = "$srvctl modify database " .
                     "-db $dbuniquename " .
                     "-pwfile $passwordfile_loc";
  } 

  if (!asmcmdshare_runcmd("$srvctlcommand", \@buf, 1, 1))
  {
    # command succeeded
    foreach(@buf)
    {
      chomp $_;
      $errorflag = 'y' if ($_ =~ /[A-Z]+-[0-9]+\s*:/);# If an error is detected
      asmcmdshare_trace(3, "$_", 'y', 'y') if ($errorflag eq 'y');
    }
  }
  else 
  {
    $errorflag = 'y';
  }

  if ($errorflag eq 'y')
  {
    asmcmdshare_error_msg(9453, undef);
    return 0;
  }
  return 1;
}

########
# NAME
#   asmcmdpasswd_get_pwfile
#
# DESCRIPTION
#   This function retrieves the password file location from the corresponding 
#   CRS resource.
#
# PARAMETERS
#   asm              (IN)  - Whether the instance is an ASM or a DB
#   dbuniquename     (IN)  - The dbuniquename, used only if asm is 0
#   pfile_loc_ref    (IN)  - Reference to the variable where the retrieved path
#                            is to be stored.
#
# RETURNS
#   0 on failure
#   1 on success
#
# NOTES
#
########
sub asmcmdpasswd_get_pwfile
{
  my $asm = shift;
  my $dbuniquename = shift;
  my $pfile_loc_ref = shift;

  my $srvctl;
  my $srvctlcommand;
  my $errorflag = 'n';
  my @eargs = ();
  my @buf = ();
  my $ret = 0;

  $srvctl = "$ENV{'ORACLE_HOME'}/bin/srvctl";
  #Path in Win is ORACLE_HOME/bin/srvctl.bat
  $srvctl .= ".bat" if ($^O =~ /win/i);

  # Make sure the srvctl binary exists and can be executed. 
  if (! -x $srvctl)
  { 
    #If not, try at a second locaction.
    $srvctl = "$ENV{'ORACLE_HOME'}/srvm/bin/srvctl";
    #path in Win is ORACLE_HOME/bin/srvctl.bat
    $srvctl .= ".bat" if ($^O =~ /win/i);
    if (! -x $srvctl)
    {
      @eargs = ($srvctl);
      asmcmdshare_error_msg(8316, \@eargs);
      return $ret;
    }
  }

  #untaint srvctl
  $srvctl =~ /([^\n^\r^\t]+)/;
  $srvctl = $1; 

  if ($asm)
  {
    $srvctlcommand = "$srvctl config asm";
  }
  else
  {
    $srvctlcommand = "$srvctl config database -db $dbuniquename";
  } 
  if (asmcmdshare_runcmd("$srvctlcommand", \@buf, 1, 1))
  {
    $errorflag = 'y';
  }
  foreach (@buf)
  {
    chomp $_;
    $errorflag = 'y' if ($_ =~ /[A-Z]+-[0-9]+\s*:/ && # If an error is detected
                 $_ !~ /PRCA-1032 : ASM listener LISTENER does not exist/);
    asmcmdshare_trace(3, "$_", 'y', 'y') if ($errorflag eq 'y');
    # Bug 24308847: Add the anchor for start of line to differentiate the lines
    # containing Password file and Backup of Password file when parsing output
    if ($errorflag eq 'n' && $_ =~ /^Password file: (.*)$/)
    {
      if (defined $1)
      {
        $$pfile_loc_ref = $1;
      }
      else
      {
        $$pfile_loc_ref = "";
      }
        $ret = 1;
    }
  }
  if ($errorflag eq 'y')
  {
    asmcmdshare_error_msg(9457, undef);
  }
  else
  {
    $ret = 1;
  }
  return $ret;
}

########
# NAME
#   asmcmdpasswd_file_type
#
# DESCRIPTION
#   This function retrieves the file type for a given file
#
# PARAMETERS
#   dbh_ref      (IN)  - reference to the dbh handle
#   fileName     (IN)  - The complete path to the file for which file type
#                        is to be found out
#   fileType_ref (IN)  - Reference to the variable where the retrived file
#                        type is to be stored.
#
# RETURNS
#   0 on failure
#   1 on success
#
# NOTES
#   Assumes the path is a complete path and file exists.
#  
########
sub asmcmdpasswd_file_type
{
  my ($fileName, $fileType_ref, $fileSz, $blkSz);
  my ($stmt, $dbh, $dbh_ref, $ret);

  my ($return_status) = 0;

  $dbh_ref = shift;
  $dbh = $$dbh_ref;
  $fileName = shift;
  $fileType_ref = shift;

  # get file information, block size, file size, file type
  $stmt = $dbh->prepare(q{
    begin
      dbms_diskgroup.getfileattr(:fileName, :fileType, :fileSz, :blkSz);
    end;
    });

  # Bind input parameters #
  $stmt->bind_param( ":fileName", $fileName );

  # Bind ouput params #
  $stmt->bind_param_inout( ":fileType", $fileType_ref, $PLSQL_NUMBER);
  $stmt->bind_param_inout( ":fileSz", \$fileSz, $PLSQL_NUMBER);
  $stmt->bind_param_inout( ":blkSz", \$blkSz, $PLSQL_NUMBER);
  $ret = $stmt->execute();
  if (!defined ($ret) && ($asmcmdglobal_hash{'mode'} eq 'n'))
  {	
    $asmcmdglobal_hash{'e'} = -1;	
  }	     

  if (!defined $$fileType_ref || $$fileType_ref < 1 )
  {
    my (@eargs) = ($fileName);
    asmcmdshare_error_msg(8012, \@eargs);
    asmcmdshare_trace(1, $DBI::errstr, 'y', 'y') unless defined ($ret);
    asmcmdshare_error_msg(9461, \@eargs);
  }
  else
  {
    # Call was a success;
    $return_status = 1;
  }
  # reconnect
  asmcmdbase_disconnect($dbh) if defined ($dbh);
  #undef since we connect to local asm instance
  $$dbh_ref = asmcmdbase_connect(undef);

  return $return_status;
}

########
# NAME
#   asmcmdpasswd_normalized_files
#
# DESCRIPTION
#   This function returns the full expanded path for a given destination, 
#   OS or on on DG.
#   
# PARAMETERS
#   dbh_ref      (IN/OUT) - Reference to initialized database handle, must be 
#                           non-null.
#   src_filepath (IN)     - src file path to be normalized
#   dest_filepath(IN)     - the dest file path passed to the command by user.
#                           Can be a directory path or partial path or which 
#                           may or may not contain the target filename.
#
# RETURNS
#   %return_hash (OUT)    - Hash of values 
#   $return_hash{'src_filepath'}  = normalized $src_filepath
#   $return_hash{'src_success'}   = status of normalization for src file
#   $return_hash{'src_exists'}    = whether the src file exists
#   $return_hash{'src_onDG'}      = whether the src file is on DG or on OS
#   $return_hash{'src_DG'}        = if the src file is on DG, the DG num
#   $return_hash{'dest_filepath'} = normalized $dest_filepath;
#   $return_hash{'dest_success'}  = status of normalization for dest file
#   $return_hash{'dest_exists'}   = whether the dest directorystructure exists
#   $return_hash{'dest_onDG'}     = whether the dest file is on DG or on OS
#   $return_hash{'dest_DG'}       = if the dest file is on DG, the DG num
#
# NOTES
#   Assumes the reference to dbh handle is a valid and non-null 
#   
########
# Assumes the src_fileapth is a full path containing the filename at the end
sub asmcmdpasswd_normalized_files
{
  my ($dbh_ref) = shift;
  my ($src_filepath) = shift;
  my ($dest_filepath) = shift;
  my ($src_filename, $src_filetype, $ret);
  my ($dir_path, $filename);
  my (@eargs, @paths, @ref_ids, @par_ids, @entry_list, @dg_nums, $name);
  my ($dbh) = $$dbh_ref;

  my %norm;
  my %return_hash;
  $return_hash{'src_reference_index'} = -1;
  $return_hash{'src_parent_index'}    = -1;
  $return_hash{'src_filepath'}        = $src_filepath;
  $return_hash{'src_success'}         = 0;
  $return_hash{'src_exists'}          = 0;
  $return_hash{'src_onDG'}            = 0;
  $return_hash{'src_DG'}              = -1;
  $return_hash{'dest_filepath'}       = $dest_filepath;
  $return_hash{'dest_success'}        = 0;
  $return_hash{'dest_exists'}         = 0; # The directory structure exists
  $return_hash{'dest_onDG'}           = 0;
  $return_hash{'dest_DG'}             = -1;

  if (defined $src_filepath && $src_filepath ne "")
  {
    ######                       -Normalize file-                        ######
    # criteria: if it is an OS file, has to be full path,
    #           otherwise it will be treated as a relative path
    #           in the ASM context

    # if path doesn't start with '/', then it is an ASM relative path
    # every OS path must be absolute.
    if ( ($src_filepath !~ /^[a-z]:/i) && ($src_filepath !~ m'^[/\\\\]'))
    {
      $return_hash{'src_onDG'} = 1;
      # ASM file case
      # if source file name is not an an absolute OS path, assume it is an ASM
      # DG path and complete it
      %norm = asmcmdshare_normalize_path($$dbh_ref, $src_filepath, 0, \$ret);

      if ( $ret != 0 )
      {
        @eargs = ($src_filepath);
        asmcmdshare_error_msg(9452, \@eargs);
      }
      else
      {
        $return_hash{'src_exists'}   = 1;
        $return_hash{'src_filepath'} = $norm{'path'}->[0];
        $return_hash{'src_DG'}       = $norm{'gnum'}->[0];
        $return_hash{'src_parent_index'}       = $norm{'par_id'}->[0];
        $return_hash{'src_reference_index'}       = $norm{'ref_id'}->[0];

        ######          -Check that the file is a password file-         ######
        if (asmcmdpasswd_file_type($dbh_ref, $norm{'path'}->[0], 
                                   \$src_filetype))
        {
          if ($src_filetype == $PLSQL_PWFILE)
          {
            @return_hash{keys %norm} = values %norm;
            $return_hash{'src_success'} = 1;
          }
          else
          {
            # pw* commands can only be used to operate on password file 
            # commands
            @eargs = ($asmcmdglobal_hash{'cmd'});
            asmcmdshare_error_msg(9460, \@eargs);
          }
        }
      }
    }
    else
    {
      # Assume the path is a full path to a file on the OS filesystem
      $return_hash{'src_onDG'}  = 0;
      # If the path is simply a directory
      if (-d $src_filepath)
      {
        @eargs = ($src_filepath);
        asmcmdshare_error_msg(9452, \@eargs);
        $return_hash{'src_exists'} = 1;
        $return_hash{'src_success'}= 0;
      }
      # If the path is an existing filename
      elsif (-e $src_filepath)
      {
        $return_hash{'src_exists'} = 1;
        $return_hash{'src_success'}= 1;
      }
      # Else, the path is invalid
      else
      {
        @eargs = ($src_filepath);
        asmcmdshare_error_msg(9452, \@eargs);
        $return_hash{'src_exists'} = 0;
        $return_hash{'src_success'}= 0;
      }
    }
    return %return_hash if (!$return_hash{'src_success'});
  }

  if (defined $dest_filepath && $dest_filepath ne "")
  {
    $src_filepath = $return_hash{'src_filepath'};
    $src_filepath = "" if (!defined $src_filepath);

    $src_filepath =~ m/[\\\/]+([^\\\/]+)$/;
    $src_filename = $1;


    ######                 -Normalize destination file-                 ######
    if ( ($dest_filepath !~ /^[a-z]:/i) && ($dest_filepath !~ m'^[/\\\\]'))
    {
      $return_hash{'dest_onDG'} = 1;
      $return_hash{'dest_DG'}   = -1;
      # Make the path absolute.
      $dest_filepath = asmcmdshare_make_absolute($dest_filepath);
      # Separate out the filename,if any, and the directory path
      $filename = "";
      $dir_path = $dest_filepath;
      # If the $dest_filepath is of the form +diskgroup/path/to/filename
      if ($dest_filepath =~ m/[\\\/]+([^\\\/]+)$/)
      {
        $filename = $1 if defined $1;
        if ($filename ne "")
        {
          $dest_filepath =~ m/(.*)$filename$/;
          $dir_path = $1;
        }
      }

      # ASM file case
      # if source file name is not an an absolute OS path nor ASM path,
      # assume it is ASM and  complete it
      %norm = asmcmdshare_normalize_path($$dbh_ref, $dest_filepath, 1, \$ret);
      if ( $ret == 0 )
      {
        $dest_filepath = $norm{'path'}->[0];
        @paths   = @{ $norm{'path'} };
        @ref_ids = @{ $norm{'ref_id'} };
        @par_ids = @{ $norm{'par_id'} };
        @dg_nums = @{ $norm{'gnum'} };
        $name = $paths[0];
        $name =~ s,.*/(.*)$,$1,;

        asmcmdshare_get_subdirs($$dbh_ref, \@entry_list, undef, $dg_nums[0],
                                $ref_ids[0], $par_ids[0], $name, undef, 0, 1);

        if ( ($ref_ids[0] == $dg_nums[0] << 24 ) ||
              $entry_list[0]->{'alias_directory'} eq 'Y')
        {
          if ($filename eq "")
          {
            if (defined $src_filename)
            {
              $norm{'path'}->[0] = $norm{'path'}->[0] . '/' . $src_filename;
            }
            else
            {
              $norm{'path'}->[0] = $norm{'path'}->[0] . '/';
            }
          }
          else
          {
            $norm{'path'}->[0] = $norm{'path'}->[0] . '/' . $filename;
          }
          $return_hash{'dest_exists'}   = 1;
          $return_hash{'dest_filepath'} = $norm{'path'}->[0];
          $return_hash{'dest_success'}  = 1;
          $return_hash{'dest_DG'}       = $norm{'gnum'}->[0];
        }
        elsif ( $entry_list[0]->{'alias_directory'} eq 'N' )
        {
          $return_hash{'dest_exists'}   = 1;
          $return_hash{'dest_filepath'} = $norm{'path'}->[0];
          $return_hash{'dest_success'}  = 1;
          $return_hash{'dest_DG'}       = $norm{'gnum'}->[0];
        }
        else
        {
          $return_hash{'dest_exists'}   = 0;
          $return_hash{'dest_success'}  = 0;
          @eargs = ($norm{'path'}->[0]);
          asmcmdshare_error_msg(8014, \@eargs);
        }
      }
      else
      {
        $return_hash{'dest_exists'}   = 0;
        $return_hash{'dest_success'}  = 1;
        # given destination file does not exist, but is not an error
        # in case of pwcreate command.
      }
      asmcmdbase_disconnect($$dbh_ref) if defined ($$dbh_ref);
      $$dbh_ref = asmcmdbase_connect(undef);
    }
    # Path is an OS filesystem path
    else
    {
      $return_hash{'dest_onDG'}    = 0;
      # If the path is a directory
      if ( -d $dest_filepath )
      {
        # Remove trailing '/' or '\'
        $dest_filepath =~ s/[\/\\]$//;
        if (defined $src_filename)
        {
          $return_hash{'dest_filepath'} = $dest_filepath . '/'. $src_filename;
          if ( -e $return_hash{'dest_filepath'}) 
          {
            $return_hash{'dest_exists'}   = 1;
            $return_hash{'dest_success'}  = 1;
          }
        }
        else
        {
          $return_hash{'dest_filepath'} = $dest_filepath . '/';
        }
        $return_hash{'dest_exists'}   = 1;
        $return_hash{'dest_success'}  = 1;
      }
      # If the path is a file
      elsif ( -e $dest_filepath )
      {
        $return_hash{'dest_filepath'} = $dest_filepath;
        $return_hash{'dest_exists'}   = 1;
        $return_hash{'dest_success'}  = 1;
      }
      else  #$dest_filepath is NOT a dir and $dest_filepath does not exist
      {
        $filename = "";
        # Extract the filename from the path - everything after the last 
        # '\' or '/'. Store it in $filename, if there is any filename.
        $dest_filepath =~ m/[\\\/]+([^\\\/]+)$/;
        $filename = $1 if defined $1;
        if ($filename ne "")
        {
          # Extract the parent directory path
          $dest_filepath =~ m/(.*)$filename$/;
          $dir_path = $1;
          # If the parent directory doesn't exist, then path is invalid
          if (-d $dir_path)
          {
            $return_hash{'dest_success'} = 1;
            $return_hash{'dest_exists'}  = 1;
            $return_hash{'dest_filepath'}= $dest_filepath
          }

        }
        @eargs = ($dest_filepath);
        asmcmdshare_error_msg(8005, \@eargs) 
                              if $return_hash{'dest_success'} == 0;
      }
    }
  }
  return %return_hash;
}

1;

OHA YOOOO