MINI MINI MANI MO

Path : /proc/self/root/opt/oracle/product/18c/dbhomeXE/bin/
File Upload :
Current File : //proc/self/root/opt/oracle/product/18c/dbhomeXE/bin/asmcmdcore

#!$ORACLE_HOME/perl/bin/perl -w
#
# Copyright (c) 2004, 2018, Oracle and/or its affiliates. All rights reserved.
#
#    NAME
#      asmcmdcore - ASM CoMmanD line interface (Driver Program)
#
#    DESCRIPTION
#      ASMCMD is a Perl utility that provides easy nagivation of files within
#      ASM diskgroups.  Simple UNIX shell-like commands allow directory
#      traversal, directory creation and deletion, user alias creation and
#      deletion, and file deletion capabilities, among other features.
#      We implement this utility as a wrapper around existing SQL statements,
#      and we use the Perl DBI Module to connect to an ASM instance and to
#      issue these SQL statements.
#
#    NOTES
#      usage: asmcmdcore [-V] [--nocp] [--privilege <sysasm|sysdba>]
#                        [-v {errors | warnings | normal | info | debug}]
#                        [--inst <instance_name>] [-p] [command]
#
#    MODIFIED  (MM/DD/YY)
#    apfwkr     07/02/18 - Backport prabbala_bgpipe_dir_28218832 from main
#    apfwkr     06/15/18 - Backport apfwkr_blr_backport_27303785_18.0.0.0.0
#                          from st_rdbms_18.0
#    apfwkr     06/04/18 - Backport prabbala_acmdpip_27948050 from main
#    prabbala   06/26/18 - 28218832: set tempdir to /tmp/.oracle in AIX/HPUX
#    prabbala   05/31/18 - 27948050: move tempdir to /var/tmp/.oracle
#    apfwkr     06/05/18 - Backport sanselva_bug-27303785 from main
#    sanselva   02/13/18 - 27303785: use orabase to find out ORACLE_BASE
#    sanselva   11/28/17 - RTI#20772974: change asmcmd trace path
#    anovelo    10/05/17 - 26927584: Updating directory for oraversion
#    anovelo    09/21/17 - 26734430: Remove hard-coded version from code.
#    bhshanmu   05/05/17 - bhshanmu_bug-26003322_linux
#    diguzman   09/22/16 - 11736372: Filter semicolon from user's input
#    diguzman   05/30/16 - 19654070: Connect to ASM only when it is needed
#    anovelo    01/07/16 - Bug#21182361: Fixed path if system cmd is used 
#    dacavazo   12/07/15 - 22223809: undef function before dl_find_symbol
#    anovelo    12/01/15 - Bug#21500055: Don't append $PATH if env is unset
#    dacavazo   11/27/15 - 20766180: Make bg pipe filename contain its pid
#    byyang     06/04/15 - Bug#21204705: Do not corrupt ARGV in foreground
#    dacavazo   03/04/15 - Redirected daemon's STDERR to /dev/null
#    prabbala   01/30/15 - log more info on pipe write failure
#    anovelo    10/22/14 - 19783114: List commands with error ASMCMD-8022
#    dacavazo   10/15/14 - 19445832: BG pipe will be opened only when needed
#    anovelo    08/22/14 - Added ASM version pull from C
#    dacavazo   07/25/14 - 19234907: strip single quotes from arguments
#    shlian     05/20/14 - Bug#18355789: check if user-entered cmd was valid
#    dacavazo   05/15/14 - Added support for multiple concurrent FG processes
#    pvenkatr   01/23/14 - Bug #18113228 Added check for SYSASM req0uirment
#    pvenkatr   01/15/14 - Bug # 18080252 - remove the check to allow only to
#                          ASM instance.
#    pvenkatr   11/06/13 - #17395893 - Added discover flag for ASMCMD
#    pvenkatr   04/30/13 - Fixed LRG #8953219 -restting iostat "running" flag
#                          added more traces.
#    pvenkatr   04/17/13 - Fix for Bug# 15952019 - setting owner/group/
#                          permission for log/diag/asmcmd/ dir for tracing.
#    shmubeen   02/15/13 - Fix for bug# 16384206 /Lrg #8710957 - FG ensures
#                          that background process is in wait mode before
#                          sending SIGUSR1
#    pvenkatr   02/01/13 - Skip printing blank line in show_commands if empty.
#    mchimang   12/24/12 - XbranchMerge mchimang_bug-15895228_2 from
#                          st_rdbms_12.1.0.1
#    sanselva   12/05/12 - use ORACLE_BASE if set for tracing
#    moreddy    11/22/12 - 14142633: asmcmd needs to reconnect for flex asm
#    shmubeen   11/20/12 - bug fix# 15859633, close STDOUT in child(bg) process
#    mchimang   11/02/12 - bug14631873: Fix the path
#    shmubeen   10/16/12 - Fix for 14184571 - Fix for  CPU spin on
#                          background pipe's read
#    pvenkatr   10/05/12 - 14195852 - Register Daemon for canshutdown
#    skiyer     05/28/12 - 13952494:set exit return status for asmcmd commands
#    adileepk   03/30/12 - Fix for Connection Pooling rogue output issue.
#    adileepk   12/21/11 - Fix for bug-13106171.
#    adileepk   11/23/11 - Fix for bug-13412679.
#    pvenkatr   10/07/11 - removed noinstance, flags
#    adileepk   10/03/11 - Fix fr lrg-5705736.
#    adileepk   09/12/11 - Fix for bug 12970899. Adding option to opt out of
#                          connection pooling.
#    adileepk   08/22/11 - Fix for lrg 5840040. Solution for race condition in
#                          Connection Pooling.
#    adileepk   06/19/11 - Connection Pooling.
#    moreddy    05/26/11 - fix bug 12555747 help for invalid command
#    adileepk   11/30/10 - Changes made to integrate parser module with asmcmd.
#    moreddy    08/23/10 - bug 6969662 improve rm command performance
#    shmubeen   08/19/10 - bugfix# 9703627, get the current logged in user
#    canuprem   07/16/10 - bug 9499720 : Load module that are existent
#    moreddy    05/06/10 - bug 8667038 NLS for error messages
#    shmubeen   04/27/10 - fix of 7193021 for windows
#    amitroy    04/29/10 - BUG 8933243 - USE DIFFERENT CHARACTER IN ASMCMD TO
#                          "HIDE COLUMN DETAILS" INSTEAD OF -H; REPLACE -a
#                           TO --privilege FOR asmcmd
#    pvenkatr   03/31/10 - Syntax, Description, Example - all from XML
#    shmubeen   03/30/10 - fix for #7193021
#    moreddy    03/22/10 - Adding more tracing
#    moreddy    03/23/10 - fixed bug 9412680
#    moreddy    03/22/10 - Adding more tracing
#    sanselva   03/15/10 - clean up asmcmdbase_connect, get rid of
#                          unused asmcmdglobal_hash variables
#    mchimang   02/23/10 - Made change to handle CNTRL-C in Noninteractive Mode
#    moreddy    01/08/10 - Adding tracing infrastructure
#    danagara   08/06/09 - Cntrl + C handled properly bug-8646861
#    lajain     07/24/09 - Fix dsset --profile -f
#    gayavenk   06/11/09 - reconnect after dsset
#    sanselva   06/04/09 - Enable consistencychk when 'c' option used
#    heyuen     04/20/09 - add spbackup
#    heyuen     12/03/08 - reconnect after spmove
#    heyuen     11/10/08 - fix asmcmd prompt in windows
#    heyuen     10/14/08 - use dynamic modules
#    heyuen     08/02/08 - add verbose
#    heyuen     07/28/08 - rewrite asmcmdcore to use getopt
#    heyuen     06/16/08 - force disk scan during startup
#    heyuen     05/14/08 - reconnect after spcopy
#    heyuen     04/15/08 - bug 6957288
#    heyuen     03/26/08 - reconnect at instance startup
#    heyuen     03/21/08 - enable lsdsk in non connected mode
#    heyuen     02/15/08 - add history
#    hqian      11/29/07 - #5661841, #5629952: enable ASMCMD for RDBMS instance
#    heyuen     09/20/07 - flush error messages as well as pending messages
#                          before the prompt
#    heyuen     08/09/07 - refresh from main
#    heyuen     07/24/07 - add error message for connection failure
#    hqian      07/06/07 - #6174647: set $ENV{'PATH'} to include
#                          $ENV{'ORACLE_HOME'}/bin
#    hqian      06/25/07 - Reset $ENV{'PATH'} for security reasons
#    heyuen     04/02/07 - remove error message when issuing asmcmd help-
#                          and not being able to connect to ASM
#    hqian      03/09/07 - Notify user when failed to connect to ASM
#    hqian      03/02/07 - add asmcmdcore_get_asm_version
#    jilim      02/19/07 - fix for invalid $dbh after the cp
#    hqian      11/21/06 - fix signal_handler
#    jilim      09/27/06 - bug-5402303: added passing arg, contype,
#                          for asmcmdbase_connect()
#    averhuls   07/06/06 -
#    hqian      07/12/06 - 11gR1: enable AMBR, disk repair, and other features
#    hqian      06/26/06 - disable asmcmddisk and asmcmdambr for initial merge
#    hqian      06/15/06 - add asmcmddisk module
#    msharang   03/28/06 - Add asmcmdambr
#    hqian      01/26/06 - rename asmcmdbase_global to asmcmdglobal_hash
#    hqian      01/24/06 - #4939032: split off callback defs into asmcmdglobal
#    hqian      01/20/06 - #4939032: rename bad_cmd() to show_commands()
#    hqian      01/18/06 - #4939032: support additional modules
#    hqian      01/18/06 - #4939032: keep only main() and shell()
#    hqian      01/18/06 - #4939032: split up asmcmd into modules
#    hqian      07/19/05 - Remove RCS header
#    hqian      06/23/05 - #4450221: support wildcards for CD
#    hqian      05/18/05 - Mention 'missing view attributes' in help ls
#    hqian      05/03/05 - #4329688: improve SQL efficiency
#    hqian      04/13/05 - ls_get_file_info() -> ls_process_file()
#    hqian      04/08/05 - Improve implementation of ls
#    hqian      04/08/05 - Improve help documentation
#    hqian      04/07/05 - LRG 1843355: include seconds in mod-time
#    hqian      04/01/05 - #4261342: use asmcmd messages for certain errors
#    hqian      02/28/05 - #4204122: change NLS date format for minute to 'MI'
#    hqian      10/27/04 - hqian_asmcmd_13306_linux_3
#    hqian      10/19/04 - Rename asmcmd0 to asmcmdcore
#    hqian      08/03/04 - hqian_asmcmd_13306_linux_2
#    hqian      07/28/04 - Add % as wildcard char in addition to *.
#    hqian      07/13/04 - Add implementation of find [-t <type>].
#    hqian      06/30/04 - Make code that uses BigInt work for both Perl 5.6.1
#                          and Perl 5.8.3; take out -c <connect_string>
#                          functionality.
#    hqian      06/29/04 - Fix 10gR1 compatibility issues; fix alias name
#                          case-sensitive bug, should be case insensitive
#                          but case retentive.
#    hqian      06/25/04 - Rename the main program from asmcmd to asmcmd0, so
#                          that we can name the wrapper script asmcmd; rename
#                          global constants, global variables, and function
#                          names so that they are prefixed by 'asmcmd0_',
#                          as per coding style standards; fix ORA-15128 bug.
#    hqian      06/23/04 - Inaccurate error message bug: add error message
#                          8004, do not print error when '*' matches nothing;
#                          fix rm -rf * double error message bug; fix find
#                          diskgroup bug; fix print header in empty directory
#                          bug; fix space in alias name bug.
#    hqian      06/22/04 - Give the option to turn off the functionality of
#                          the -c flag; add constants for better code design.
#    hqian      06/09/04 - Fix bugs; improve comments.
#    hqian      06/07/04 - Organize code for better maintenance; code review
#                          changes (suggested by Dave Friedman).
#    hqian      06/01/04 - Fix some bugs.
#    hqian      05/24/04 - Implement rm [-rf] and rm *; some code review fixes.
#    hqian      05/20/04 - Implement help, instance_type security check,
#                        - connection error checks, and debug mode.
#    hqian      05/18/04 - Implement ls flags and lsct.
#    hqian      05/14/04 - hqian_asmcmd_13306
#    hqian      04/21/04 - Creation
#
#
#
#############################################################################
#
############################ Functions List #################################
#
# Top Level Routines
#   asmcmdcore_main
#   asmcmdcore_shell
#   asmcmdcore_parse_asmcmd_args
#   asmcmdcore_module_driver
#   asmcmdcore_process_help
#   asmcmdcore_show_commands
#   asmcmdcore_is_cmd
#   asmcmdcore_check_global_callbacks
#   asmcmdcore_syntax_error
#############################################################################

use strict;

# load global modules
use asmcmdglobal;
use asmcmdshare;
use asmcmdparser;

use Getopt::Long qw(:config no_ignore_case bundling);
use Term::ReadLine;
use File::Path;
use Sys::Hostname;
use POSIX;

use List::Util qw[min max];
use Fcntl qw[:flock];
require DynaLoader;

#find all the modules that exist, and include them
my (%asm_modules);
my @staleMods;

foreach (@INC)
{
  if (-d $_)
  {
    my ($dir)   = $_;
    my (@files) = ();

    opendir (MODDIR, $dir);
    @files = readdir(MODDIR);
    foreach (@files)
    {
      if ( $_ =~ /^asmcmd/ && $_ =~ /pm$/ )
      {
        # Load the modules only if the symlinks(if there are any) are
        # not stale.
        if (defined(open(TMPFILE  , "$dir/$_")))
        {
          close(TMPFILE);

          my (@temp) = (split(/\./, $_))[0];
          $asm_modules{$temp[0]} = $dir . '/' . $_;
        }
        else
        {
          push(@staleMods, "$dir/$_");
        }
      }
    }
    closedir(MODDIR);
  }
}

delete($asm_modules{'asmcmdglobal'});
delete($asm_modules{'asmcmdshare'});


# If the module does not belong to asmcmd, remove it
my @not_mod = ();
my ($module);
foreach $module(keys %asm_modules)
{
  require "$module.pm";
  my ($is_asm) = $module. "::is_asmcmd()";

  eval ($is_asm);
  push (@not_mod, $module) if ($@);
}

foreach (@not_mod)
{
  delete ($asm_modules{$_});
}

# import modules
foreach $module(sort(keys %asm_modules))
{
  $module->import;
}

#$$$$$$$$---CHANGE THIS TO ORACLE/LIB WHEN THE SYMLINK IS CREATED #
my $file;

# clear the array to prevent loading asmperl from unknown locations
@DynaLoader::dl_library_path = ();

#26734430: Obtain latest ASM version number from oraversion. This will be used
#          to obtain the library number.
my $ver = `$ENV{ORACLE_HOME}/bin/oraversion -majorVersion`;
chomp($ver);

if ($^O eq "MSWin32")
{
  push(@DynaLoader::dl_library_path, $ENV{ORACLE_HOME}."/bin");
  push(@DynaLoader::dl_library_path, $ENV{ORACLE_HOME}."/rdbms/bin");
  $file = "oraasmperl".$ver.".dll";
}
else
{
  push(@DynaLoader::dl_library_path, $ENV{ORACLE_HOME}."/lib");
  push(@DynaLoader::dl_library_path, $ENV{ORACLE_HOME}."/rdbms/lib");
  $file = "libasmperl".$ver.".so";
}

# Get the full path of asmperl shared library
my @file_path = DynaLoader::dl_findfile($file);
if ($#file_path < 0)
{
  die "Error: library $file not found\n";
}

#try loading the file using full path
$asmcmdglobal_hash{'asmperl'} = DynaLoader::dl_load_file($file_path[0], 0);
defined($asmcmdglobal_hash{'asmperl'}) or
                    die "Error:\n", DynaLoader::dl_error();

######################## ASMCMDCORE Global Variables ########################
#                                                                           #
# Each module needs to specify its initialization function here.
my (@asmcmdcore_init_modules) = ();
foreach $module(sort(keys %asm_modules))
{
  push (@asmcmdcore_init_modules, $module . "::init()");
}
our (%asmcmdcore_cmds) = (asmcmd  => {}
                         );

  %asmcmdglobal_cmds = (%asmcmdglobal_cmds, %asmcmdcore_cmds);

############################ Top Level Routines ##############################
#
# Routines that calls exit():
#   asmcmdcore_main              - exit 0
#   asmcmdcore_syntax_error      - exit 0
#   asmcmdbase_show_commands     - exit 0
#   asmcmdbase_check_insttype    - exit 0
#   asmcmdshare_signal_exception  - exit 1
#   asmcmdcore_shell             - exit -1
#   asmcmddisk_process_lsdsk     - exit -1 0 1 2
########
# NAME
#   asmcmdcore_main
#
# DESCRIPTION
#   This function is the main function of ASMCMD.  It is the first
#   function that is called.
#
# PARAMETERS
#   None.
#
# RETURNS
#   Null.
#
########
sub asmcmdcore_main
{
  my ($dbh);
  my ($module);
  my ($mypath);
  my ($childpid);
  my ($foreground_success);
  my ($cmd);
  my ($cdet);
  my ($vers);
  my ($lib) = $asmcmdglobal_hash{'asmperl'};

  $mypath = $ENV{'PATH'};
  $asmcmdshare_logheader = "ASMCMD (PID = $$): ";

  # 1. $ORACLE_HOME/bin is appended for NT compatibility.
  # NT has the necessary dll's in that directory.
  # 2. Original path is necessary for finding uname, dirnam in srvctl.
  # (asmcmdpasswd module invokes srvctl. Refer bug14631873
  # 21500055: Check if $PATH is set; if so, append current value.
  if (defined($mypath))
  {
    $ENV{'PATH'} = "$ENV{'ORACLE_HOME'}/bin:" . $mypath;
  }
  else
  {
    $ENV{'PATH'} = "$ENV{'ORACLE_HOME'}/bin";
  }

  # 27948050: Pipes created under /tmp might get deleted erroneously.
  # Let us move it to /var/tmp/.oracle 
  # 28218832: AIX & HPUX uses /tmp/.oracle; not /var/tmp/.oracle
  if ($^O eq "MSWin32")
  {
    $asmcmdglobal_hash{'tempdir'} = File::Spec->tmpdir();
  } 
  elsif (($^O =~ /linux/i) || ($^O =~ /solaris/i))
  {
    $asmcmdglobal_hash{'tempdir'} = "/var/tmp/.oracle";
  }
  else
  {
    $asmcmdglobal_hash{'tempdir'} = "/tmp/.oracle";
  }

  # Parse for consistency check option before calling init_modules
  asmcmdcore_consistency_check();
  asmcmdcore_trace();

  # Print warnings about the stale links
  if (scalar(@staleMods) > 0)
  {
    foreach (@staleMods)
    {
      asmcmdshare_trace(2, "$_ either does not exist or it is a stale link",
                        "Y", "N");
    }
  }

  #28218832: Check the temp directory exists and writable for pipe creation
  if (!(-d $asmcmdglobal_hash{'tempdir'} and -w $asmcmdglobal_hash{'tempdir'}))
  {
    my @eargs = $asmcmdglobal_hash{'tempdir'};

    # Log the dir name in console itself.
    asmcmdshare_trace(0, $eargs[0] . " is missing or not writable.", 'y', 'y');

    # ASMCMD-9463 operation failed due to lack of write permissions
    asmcmdshare_error_msg (9463, \@eargs);
    
    # The dir is needed only for connection pooling. Do not exit; continue with
    # non connection pooling.
    # exit;
  } 
  
  # Initialize modules.
  for $module (@asmcmdcore_init_modules)
  {
    eval($module);
  }

  # Obtain the latest ASM version from C
  undef &ASMCMDGetASMVersion;
  $cdet = DynaLoader::dl_find_symbol($lib, "XS_ASMCMDCLNT_GetASMVersion");
  DynaLoader::dl_install_xsub("ASMCMDGetASMVersion", $cdet);
  $vers = ASMCMDGetASMVersion();
  $asmcmdglobal_hash{'acver'} = $vers;

  # Check to see if all the modules have initialized the global callbacks
  # correctly.
  asmcmdcore_check_global_callbacks();
  asmcmdcore_get_system_endian();
  asmcmdcore_parse_asmcmd_args();

  eval
  {
    $foreground_success = 0;
    $asmcmdshare_foreground_retries = -1;
    $asmcmdshare_started_daemon = 0;
    while (!$foreground_success)
    {
      # Each iteration of this while loop is an attempt by the foreground
      # process to retrieve output from the deamon.
      # $asmcmdshare_foreground_retries keeps track of the number of retrys.
      # The foreground would take an action only if it detects that the pipe
      # used to communicate with the daemon has been removed, in which case
      # it restarts the daemon and resends the command.
      # If the pipe still exists, the foreground process waits one more cycle.
      # The foreground would be unable to detect whether the daemon has
      # abruptly died without cleaning up the pipe.
      $asmcmdshare_foreground_retries++;
      if ($asmcmdshare_foreground_retries > 1)
      {
        asmcmdshare_trace(3, "ASMCMD (PID = $$): Could not connect to ASM " .
                          "using Connection Pooling. Reverting to " .
                          "legacy method after " .
                          "$asmcmdshare_foreground_retries tries.",
                          'y', 'n');
        die $asmcmdshare_disablecp_string;  # If we have attempted twice
                                            # already, then disable
                                            # connection pooling and move
                                            # to legacy method for
                                            # connections
      }
      # Excluding 'cp', 'orapwusr' & 'passwd' from connection pooling
      # since these commands need the user to enter a password which cannot
      # be passed through the pipe in plain text.
      $cmd = $asmcmdglobal_hash{'cmd'};
      $asmcmdglobal_hash{'cwdnm'} = '+';
      if ($^O ne "MSWin32" &&
          $asmcmdglobal_hash{'mode'} eq 'n' &&
          $asmcmdglobal_hash{'nocp'} == 0 &&
          !asmcmdshare_is_no_instance_cmd($asmcmdglobal_hash{'cmd'}) &&
          !defined($asmcmdglobal_cp_excluded_cmds{$cmd}))
      {
        # Anything done between this point and until the fork will be
        # inherited by both the processes (fore and back)
        $asmcmdglobal_hash{'ispooled'} = 1;

        # Backup the STDIN STDOUT STDERR filehandles for both the processes.
        asmcmdshare_backup_stdio() if ($asmcmdshare_foreground_retries == 0);

        # Fork the undivided process if there is no asmcmd daemon running.
        if (!asmcmdcore_is_bg_alive())
        {
          # If the fork is unsuccessful, the exception would be caught by
          # the enclosing eval block.
          $childpid = asmcmdcore_fork_background();
          if ($childpid) # If this is the parent/foreground process.
          {
            $asmcmdshare_started_daemon = 1;
            if ($asmcmdshare_foreground_retries == 0)
            {
              asmcmdshare_trace(3, "ASMCMD Foreground (PID = $$):  " .
                                "Created the ASMCMD Daemon (PID = " .
                                "$childpid)", 'y', 'n');
            }
            else
            {
              asmcmdshare_trace(3, "ASMCMD Foreground (PID = $$):  " .
                                "Restarted the ASMCMD Daemon (PID = " .
                                "$childpid)", 'y', 'n');
            }

          }
          else # If this is the child process/bp
          {
            asmcmdcore_background($mypath);
            return;
          }
        }
        $foreground_success = asmcmdcore_foreground($mypath);

      }# if block
      else
      {
        $foreground_success = 1;
      }
    }# while loop

    # Foreground process clean up and exit.
    if ($asmcmdglobal_hash{'ispooled'})
    {
      exit $asmcmdglobal_hash{'e'};
    }
  }; # eval block
  # If something goes wrong, disable connection pooling and revert to
  # traditional asmcmd connection.
  if ($@)
  {
    $asmcmdglobal_hash{'ispooled'} = 0;
    $asmcmdglobal_hash{'nocp'} = 1;
    $asmcmdshare_started_daemon = 0;
    asmcmdshare_trace(3, "ASMCMD (PID = $$) Could not proceed with " .
                      "connection pooling. Switching to non " .
                      "connection-pooled mode\nException - $@", 'y', 'n');
    asmcmdshare_removefgpipe();
    asmcmdshare_removebgpipe();

    # if connection pooling is forced, error out here.
    my @eargs = ("Connection pooling failed.", $@);
    asmcmdshare_assert(0, \@eargs) if defined($ENV{'ASMCMD_FRC_CONNPOOL'});
  }
  # Now run the appropriate routine to process command(s).
  $dbh = asmcmdcore_shell($mypath) if (!$asmcmdglobal_hash{'ispooled'});

  # End the database connection iff this is an interactive session, ie.
  # iff this is not a pooled session.
  asmcmdbase_disconnect($dbh) if (!$asmcmdglobal_hash{'ispooled'} &&
                                  defined ($dbh));
  asmcmdbase_disconnect($asmcmdglobal_hash{'proxy_dbh'})
                        if (!$asmcmdglobal_hash{'ispooled'} &&
                          defined ($asmcmdglobal_hash{'proxy_dbh'}));

  # Always exit zero here.  Exiting non-zero is done only from exception
  # routine.  See asmcmdcore_signal_exception().
  exit 0;
}
asmcmdcore_main();


########
# NAME
#   asmcmdcore_background
#
# DESCRIPTION
#   This routine is invoked by the asmcmd daemon to process commands and return
#   output to the foreground process through pipes (specified by the
#   user, privilege).
#
# PARAMETERS
#   $mypath (IN) - The path environment variable.
#
# RETURNS
#   Null.
#
########
sub asmcmdcore_background
{
  my ($dbh);
  my ($line);                                 # One line of input from user. #
  my (@eargs);
  my @temp_array = ();
  my @token      = ();
  my ($mypath)   = shift;
  my ($connected_once);
  my ($cmd);
  my ($sth);

  $asmcmdshare_logheader = "ASMCMD Background (PID = $$): ";

  # Sets the process name. This affects the output of the ps command on some
  # platforms, but not all.
  $0 = "asmcmd daemon";

  # Clear the command list. This is useful when asmcmd daemon
  # is respawn where as asmcmdshare_commandlist was populated in
  # the earlier execution.
  undef(@asmcmdshare_commandlist);

  # Redirected background's STDOUT to /dev/null to fix bug# 15859633
  # Background has inherited foreground i.e. parent's STDOUT, hence
  # redirecting it to null
  open(STDOUT, '>', '/dev/null');
  # 19863551: STDERR should also be redirected to /dev/null
  open(STDERR, '>', '/dev/null');

  # Create the background pipe.
  $asmcmdglobal_hash{'bgpipe'} = $asmcmdglobal_hash{'tempdir'} .
                                 "/asmcmd_bg_" . $< . "_" .
                                 $asmcmdglobal_hash{'contyp'} . "_" . $$;
  # If the command is unsuccessful, the exception would be caught by the
  # enclosing eval block.
  mkfifo($asmcmdglobal_hash{'bgpipe'}, 0700) ||
         die "Couldn't create a pipe. Switching to non " .
         "connection-pooled mode\n";
  asmcmdshare_trace(3, "$asmcmdshare_logheader Created the pipe " .
                    $asmcmdglobal_hash{'bgpipe'}, 'y', 'n');

  # This is the right place for registering the signal handler. Initially it
  # was registered when the modules were loaded in global scope. Handling
  # the ctrl-C signal before connecting to the ASM instance (and starting
  # ASM command prompt)

  $SIG{INT} = \&asmcmdshare_signal_handler;# Signal handler for asmcmd daemon #
  $SIG{USR1} = \&asmcmdshare_signal_handler;

  $SIG{ALRM} = sub { die "ALARM" };
  $ENV{'PATH'} = $mypath;
  $connected_once = 0;

  # Bugfix - 14184571:
  # 1. BG process would be waiting in a while loop
  # 2. FG process will send USR1 signal to BG process
  #    2.1: FG to be aware of PID of BG process, PID of BG is saved in the
  #         bgpipe, which is created in temp directory when a BG is spawn.
  #    2.2: bgpipe will be deleted when BG process exits.
  #    2.3: bgpipe has to be deleted manually if BG process has to be killed
  #         manually.
  # 3. BG would proceed to read the bgpipe upon receiving SIGUSR1.
  $asmcmdglobal_hash{'bgpid'}    = $$;
  $asmcmdglobal_hash{'isdaemon'} = 1;
  $asmcmdglobal_hash{'bgpid'} = $$;
  $asmcmdglobal_hash{'fgpid'} = undef;
  $asmcmdshare_pipetoread = \$asmcmdglobal_hash{'bgpipe'};
  $asmcmdshare_pipetowrite = \$asmcmdglobal_hash{'fgpipe'};
  $asmcmdshare_process_status = "RUNNING";

  # NOTE:  The environment variable 'PATH' is not set as in the foreground
  #        process.

  # Wait on the pipe to read more commands. Exit after 5mins of inactivity.
  while (1)
  {
    $asmcmdglobal_hash{'fgpipe'} = undef;
    $asmcmdglobal_hash{'fgpid'} = undef;
    $asmcmdglobal_hash{'cwdnm'} = '+';

    # Read in more commands from the pipe if there are no more commands
    # left to be processed in the array.
    if ($#asmcmdshare_commandlist == -1)
    {
      asmcmdshare_readcommands();
    }
    $line = shift @asmcmdshare_commandlist;
    next if (!$line);
    asmcmdshare_trace(3, "$asmcmdshare_logheader Processing $line", 'y','n');
    # The lines will be of the format: <PID of Foreground process>#<Command>\n
    $line =~ m/(\d+)#(.*)/;
    $asmcmdglobal_hash{'fgpid'} = $1;
    $line = $2;
    chomp $line;
    $asmcmdglobal_hash{'fgpipe'} = $asmcmdglobal_hash{'tempdir'} .
                                   "/asmcmd_fg_" . $asmcmdglobal_hash{'fgpid'};
    unless (-p $asmcmdglobal_hash{'fgpipe'})
    {
      eval
      {
        mkfifo($asmcmdglobal_hash{'fgpipe'}, 0700);

        asmcmdshare_trace(3, "$asmcmdshare_logheader Created pipe " .
                          $asmcmdglobal_hash{'fgpipe'}, 'y', 'n');
        asmcmdshare_openwritepipe();
      };
      if ($@)
      {
        asmcmdshare_trace(3, "$asmcmdshare_logheader Could not " .
                "create the pipe $asmcmdglobal_hash{'fgpipe'}.", 'y', 'n');
        # This information cannot be communicated to the foreground.
        # Hence, nothing further to be done, proceed to next command.
        # Need CRS integration to handle this appropriately. #CRSINTEGRATION
        next;
      }
    }

    # Parse $line into an array of arguments.
    @token = ();
    if (asmcmdbase_parse_int_cmd_line($line, \@token))
    {                      # asmcmdcore_parse_int_cmd_line() returned error. #
      asmcmdshare_error_msg(8007, undef);
      asmcmdshare_print($asmcmdshare_term_string);
      asmcmdshare_closewritepipe();
      next;
    }

    if ($token[0] eq '')                      # Empty line, so skip command. #
    {
      asmcmdshare_print($asmcmdshare_term_string);
      asmcmdshare_closewritepipe();
      next;
    }

    $cmd = $asmcmdglobal_hash{'cmd'} = shift(@token);   # Save command name. #
    @ARGV = @token;     # Save in global @ARGV for internal command parsing. #

    $asmcmdglobal_hash{'e'} = 0;  # Reset exit status to 0 for each command  #
    eval
    {
      if (defined($dbh))
      {
        # We have a defined DB Handle
        if (asmcmdshare_check_dbh_alive($dbh))
        {
          # And the DB Handle is alive (Connected to a live ASM Instance)
          # Proceed with the command
          $asmcmdglobal_hash{'ver'} = asmcmdshare_get_asm_version($dbh);
          # Invoke the module driver to handle the command.
          eval {
            asmcmdcore_module_driver($dbh);
          };

          if (asmcmdexceptions::catch())
          {
            my $err = asmcmdexceptions::getExceptionstring ();
            asmcmdshare_trace(3, "Unhandled Exception valid db conn $err",
                              'y', 'n');
            # Set exit status to -1
            $asmcmdglobal_hash{e} = -1;
          }
        }
        else
        {
          # The DB Handle is stale, probably the ASM instance went down
          # since the execution of the last command
          asmcmdshare_trace(3, "Connected to an idle instance.", 'y', 'y')
                            if($cmd eq 'startup');
          asmcmdshare_trace(3, "$asmcmdshare_logheader Lost " .
                      "connection to ASM. Requesting the Foreground process " .
                      "to restart the ASMCMD Background process and retry.",
                      'y', 'n');
          asmcmdshare_print($asmcmdshare_reconnect_string);
          undef(@asmcmdshare_commandlist);
          exit;
        }
      }
      else
      {
        # The DB Handle is not defined
        asmcmdshare_trace(3, "Connected to an idle instance.", 'y', 'y')
                          if($cmd eq 'startup');
        asmcmdbase_disconnect($dbh) if defined ($dbh);

        $dbh = asmcmdbase_connect(undef);
        if (defined $dbh)
        {
          # register the Background process for later cleanup
          $sth = $dbh->prepare (q{
            begin
            dbms_diskgroup.registeracmdbg;
            end;
            });
          $sth->execute();

          asmcmdshare_trace(3, "Registered Daemon process.", 'y', 'n');

          $connected_once = 1 if (!$connected_once);
          $asmcmdglobal_hash{'ver'} = asmcmdshare_get_asm_version($dbh);
          # Invoke the module driver to handle the command.
          eval {
            asmcmdcore_module_driver($dbh);
          };

          if (asmcmdexceptions::catch())
          {
            my $err = asmcmdexceptions::getExceptionstring ();
            asmcmdshare_trace (3,
                          "Unhandled Exception after daemon registration $err",
                          'y', 'n');
            # Set exit status to -1
            $asmcmdglobal_hash{e} = -1;
          }
        }
        else
        {
          # Log the error so it can be diagnosed if needed.
          asmcmdshare_trace(3, $DBI::errstr, 'y', 'n');
          # The DB Handle is not defined (Connection failed)
          asmcmdshare_trace(3, "$asmcmdshare_logheader Unable to " .
                      "connect to ASM. Requesting the foreground process to " .
                      "retry the command after disabling connection pooling.",
                      'y', 'n');
          asmcmdshare_print($asmcmdshare_disablecp_string);
          asmcmdshare_removebgpipe();
          exit;
        }
      }


      # Send a terminating string to the foreground process to signal end
      # of output from the server.
      asmcmdshare_print ($asmcmdglobal_hash{'e'} . $asmcmdshare_term_string);
      asmcmdshare_closewritepipe();
      undef $asmcmdglobal_hash{'fgpipe'};

      asmcmdshare_trace(3, "$asmcmdshare_logheader Processed command " .
                        "- $line", 'y', 'n');

      if (defined ($asmcmdglobal_reconnect_cmds{$cmd}))
      {
        # disconnect from asm instance after the cp #
        # this must be done since $dbh is now invalidated by the cp #
        asmcmdbase_disconnect($dbh) if defined ($dbh);
        undef $dbh;
      }
      if ($cmd eq 'shutdown')
      {
        asmcmdshare_removebgpipe();
        exit(0);
      }
    };
    if ($@)
    {
      asmcmdshare_trace (3,
                      "(Process=$$) BG unhandled exception before exiting $@",
                      'y', 'n');
      asmcmdshare_removebgpipe();
      exit(0);
    }
  };
  return;
}

########
# NAME
#   asmcmdcore_is_bg_alive
#
# DESCRIPTION
#   Checks whether the background is alive or not.
#
# PARAMETERS
#   None.
#
# RETURNS
#   1 - if bg is alive.
#   0 - if bg is not alive.
#
# NOTES
########
sub asmcmdcore_is_bg_alive
{
  # Get the PID of the background process to send the signal. If bgpid is
  # already defined, try with that because a connection could already be
  # established with it. Calling asmcmdcore_getbg_pid() could change the bgpid
  # if multiple background pipes exist.
  if (!defined($asmcmdglobal_hash{'bgpid'}))
  {
    asmcmdcore_getbg_pid();
    return 0 if (!defined($asmcmdglobal_hash{'bgpid'}));
  }

  # This checks whether the background (background process's pid)
  # process is alive or not.
  my $bgfilename = $asmcmdglobal_hash{'tempdir'} . "/asmcmd_bg_" .
                   $< . "_" . $asmcmdglobal_hash{'contyp'} . "_" .
                   $asmcmdglobal_hash{'bgpid'};
  if (!-e $bgfilename)
  {
    # Getting here means the bgpid has a value, but the pipe is not found.
    # Undefine the pid and call asmcmdcore_is_bg_alive() again; that will force
    # a rescan for the bgpid.
    asmcmdshare_trace(2, "$asmcmdshare_logheader Background pipe " .
                      "'$bgfilename' not found, invalid background PID " .
                      "$asmcmdglobal_hash{'bgpid'}.", 'y', 'n');
    $asmcmdglobal_hash{'bgpid'}  = undef;
    $asmcmdglobal_hash{'bgpipe'} = undef;
    return asmcmdcore_is_bg_alive();
  }

  # If a background pipe file exists, the background must be reachable.
  if (!kill(SIGCHLD, $asmcmdglobal_hash{'bgpid'}))
  {
    $asmcmdshare_logheader = "(PID: $$)" if (!defined($asmcmdshare_logheader));
    asmcmdshare_trace(2, "$asmcmdshare_logheader Background pipe " .
                      "'$bgfilename' found, but process is not responding.",
                      'y', 'n');
    $asmcmdglobal_hash{'bgpipe'} = $bgfilename;
    asmcmdshare_removebgpipe();
    # Try to rescan if there is any other background alive.
    $asmcmdglobal_hash{'bgpid'}  = undef;
    $asmcmdglobal_hash{'bgpipe'} = undef;
    return asmcmdcore_is_bg_alive();
  }
  return 1;
}

########
# NAME
#   asmcmdcore_getbg_pid
#
# DESCRIPTION
#   This routine extracts the PID of the background process which is deposited
#   with the file name in the temp directory. If there are multiple background
#   pipes, it will always get the smallest pid.
#
# PARAMETERS
#   None.
#
# RETURNS
#   Nothing
#
# NOTES
########
sub asmcmdcore_getbg_pid
{
  my ($filename);
  my (@bgpid);
  my (@FILES);
  my ($bgfilename);
  my ($tmpdir);

  $bgfilename = "asmcmd_bg_" . $< . "_" . $asmcmdglobal_hash{'contyp'} . "_";
  $tmpdir = $asmcmdglobal_hash{'tempdir'};
  opendir(DIR, "$tmpdir");
  @FILES= readdir(DIR);

  $asmcmdglobal_hash{'bgpid'} = undef;
  foreach $filename (@FILES)
  {
    if ("$filename" =~ "$bgfilename")
    {
      @bgpid = split("_", $filename);
      # There should always be only one background, but in case others are
      # found we should keep the smallest pid always.
      if (!defined($asmcmdglobal_hash{'bgpid'}) ||
          $bgpid[$#bgpid] < $asmcmdglobal_hash{'bgpid'})
      {
        $asmcmdglobal_hash{'bgpid'} = $bgpid[$#bgpid];
      }
    }
  }
  closedir(DIR);
}

########
# NAME
#   asmcmdcore_fork_background
#
# DESCRIPTION
#   This routine forks the present undivided process, creating a child process
#
# PARAMETERS
#   None.
#
# RETURNS
#   $pid - It returns the pid of the child to the parent and 0 to the child..
#
# NOTES
########
sub asmcmdcore_fork_background
{
   my $pid;
   defined($pid = fork())       || die "can't fork: $!";
   return $pid if $pid;

   # Makes the child process (The asmcmd daemon) a session leader.
   # This prevents it from being automatically killed when the parent porcess
   # (The first foreground process) exits.
   (setsid() != -1)                || die "Can't start a new session: $!";

   return $pid;
}

########
# NAME
#   asmcmdcore_get_system_endian
#
# DESCRIPTION
#   This routine gets the system's endianness and stores it in a global
#   variable.
#
# PARAMETERS
#    None.
#
# RETURNS
#   Null.
#
# NOTES
########
sub asmcmdcore_get_system_endian
{
  # The first bit of a little endian system is 1, and that of big endian
  # system is 0.
  if (unpack("b*", pack("s", 1)) =~ /^1/)
  {
    # System is little endian.
    $asmcmdglobal_hash{'endn'} = 1;
  }
  else
  {
    # System is big endian.
    $asmcmdglobal_hash{'endn'} = 0;
  }
}

########
# NAME
#   asmcmdcore_foreground
#
# DESCRIPTION
#   This routine gets the system's endianness and stores it in a global
#   variable.
#
# PARAMETERS
#   $mypath (IN) - Path to the directory.
#
# RETURNS
#   1 - if run was successful
#   0 - if there were errors, will trigger a retry if necessary
#
# NOTES
########
sub asmcmdcore_foreground
{
  my ($line);                                 # One line of input from user. #
  my (@eargs);
  my ($mypath) = shift;
  my ($moreoutput);
  my ($waittime) = $asmcmdshare_readpipewait + 5; # FG Wait time for

  $SIG{ALRM} = sub { die "ALARM" };
  $asmcmdshare_logheader = "ASMCMD Foreground (PID = $$): ";

  # Set foreground pipe name.
  $asmcmdglobal_hash{'fgpipe'} = $asmcmdglobal_hash{'tempdir'} .
                                 "/asmcmd_fg_" . $$;

  # Wait until background has created the pipe to know its pid.
  if (!asmcmdcore_is_bg_alive())
  {
    asmcmdshare_trace(3, "$asmcmdshare_logheader Waiting for the " .
                      "background process to appear", 'y', 'n');
    eval
    {
      alarm $asmcmdshare_openpipewait;
      while (!asmcmdcore_is_bg_alive())
      {
        # Do nothing, just keep checking until the background is alive.
        # Using select() instead of sleep() because sleep() often uses SIGALRM
        # so it cannot be used alongside alarm.
        select(undef, undef, undef, 0.25);
      }
      alarm 0;
    };
    if ($@)
    {
      asmcmdshare_trace(3, "$asmcmdshare_logheader Could not find the " .
                        "background process, retrying", 'y', 'n');
      return 0;
    }
  }
  asmcmdshare_trace(3, "$asmcmdshare_logheader Background process found " .
                    "with PID = $asmcmdglobal_hash{'bgpid'}", 'y', 'n');
  $asmcmdglobal_hash{'bgpipe'} = $asmcmdglobal_hash{'tempdir'} .
                                 "/asmcmd_bg_" . $< . "_" .
                                 $asmcmdglobal_hash{'contyp'} .
                                 "_" . $asmcmdglobal_hash{'bgpid'};

  # BG to be in wait mode
  $asmcmdshare_pipetoread = \$asmcmdglobal_hash{'fgpipe'};
  $asmcmdshare_pipetowrite = \$asmcmdglobal_hash{'bgpipe'};
  $asmcmdglobal_hash{'fgpid'} = $$;
  $asmcmdglobal_hash{'bgpid'} = undef;
  $asmcmdshare_process_status = "RUNNING";

  if (!$asmcmdshare_foreground_retries || $asmcmdshare_started_daemon)
  {
    # This is the right place for registering the signal handler. Initially it
    # was registered when the modules were loaded in global scope. Handling
    # the ctrl-C signal before connecting to the ASM instance (and starting
    # ASM command prompt)
    $SIG{INT} = \&asmcmdshare_signal_handler;# Signal handler for asmcmd     #
    $SIG{USR1} = \&asmcmdshare_signal_handler;
    $ENV{'PATH'} = $mypath;

    # Construct the command arguments from ARGV and pass the entire command
    # to the asmcmd daemon.
    my ($i,$token);
    # bug#21204705: ARGV should not be corrupted as it can be used in shell
    # if foreground fails
    my (@args) = ();
    for ($i = 0; $i<= $#ARGV; $i++)
    {
      $token = $ARGV[$i];
      if ($token !~ /^-/ && $token =~ /\W/ && $token !~ /'/)
      {
        $args[$i] = "'$token'"; # Put back the single quotes for tokens like
                                # patterns, etc. The quotes are stripped by
                                # the shell.
      }
      else
      {
        $args[$i] = $token;
      }
    }
    $line = join(" ", @args);
    eval
    {
      # 05/24/2012 adileepk_cpbug2
      # Operation: Send command to the background through the pipe
      # pipe_<userid>_<privilege>.
      # Here exceptions can be thrown from two functions
      # 1. asmcmdshare_openwritepipe() - If open fails or times out.
      #    Situation is handled internally by asmcmdshare_alarm_handler()
      #    which logs the situation and attempts to remove the unresponsive
      #    pipe and then throws another exception so that it can be caught
      #    at this level.
      # 2. asmcmdshare_printpipe() - If the background is found to have
      #    died or the filehandle is broken or the pipe has been removed.
      #    Again attempts to remove the unresponsive pipe if it exists
      #    and throws an exception to be caught here.
      #
      # If an exception is caught, then returns 0.
      # A return 0 from this function triggers a retry (with connection
      # pooling enabled). After two such retries, the calling function
      # asmcmdcore_main() would disable connection pooling and proceed with
      # the legacy method.
      my $string_delimiter = "!!!!!";
      asmcmdshare_openwritepipe();

      # Get exclusive lock on background pipe
      if ($asmcmdshare_writehandle)
      {
        flock($asmcmdshare_writehandle, LOCK_EX);
      }

      # Send the command through the pipe
      if ($line)
      {
        asmcmdshare_trace(3, "$asmcmdshare_logheader Given command - ".
                          $asmcmdglobal_hash{'cmd'} . " $line", 'y', 'n')
                          if (!$asmcmdshare_foreground_retries);
        asmcmdshare_printpipe($string_delimiter . $$ . "#" .
                              $asmcmdglobal_hash{'cmd'} . " $line" .
                              $string_delimiter . "\n");
      }
      else
      {
        asmcmdshare_trace(3, "$asmcmdshare_logheader Given command - ".
                          $asmcmdglobal_hash{'cmd'}, 'y', 'n')
                          if (!$asmcmdshare_foreground_retries);
        asmcmdshare_printpipe($string_delimiter . $$ . "#" .
                              $asmcmdglobal_hash{'cmd'} .
                              $string_delimiter . "\n");
      }
      flock($asmcmdshare_writehandle, LOCK_UN);
      asmcmdshare_closewritepipe();
    };
    if ($@)
    {
      # Could not write the command to the pipe.
      # Retry.
      asmcmdshare_trace(3, "$asmcmdshare_logheader Could not write command.\n" .
                        "err:", join('', $@) . " ret:$? err:$! oserr:$^E \n" .
                        "retrying...", 'y', 'n');
      return 0;
    }
  }
  elsif ($asmcmdshare_foreground_retries && $asmcmdshare_started_daemon)
  {
    asmcmdshare_trace(3, "$asmcmdshare_logheader restarted the ASMCMD " .
                      "Background process. Retrying command.", 'y', 'n');
  }

  # Try to open the read pipe for as long as the background is alive. It might
  # be busy with other foregrounds.
  my $success = 0;
  while (!$success)
  {
    # Check if the BG is alive before reading the pipe. If it is not, abort
    # immediately instead of waiting for the timeout. This will disable
    # connection pooling for the foreground and avoid hanging until the
    # timeout.
    if (!asmcmdcore_is_bg_alive())
    {
      asmcmdshare_trace(3, "$asmcmdshare_logheader BG died unexpectedly, ".
                           "retrying", 'y', 'n');
      return 0;
    }

    # Wait for the pipe to appear
    my $i = $asmcmdshare_wait4pipeCrt;
    while ($i-- && !(-p $asmcmdglobal_hash{'fgpipe'}))
    {
      sleep(1);
    }

    eval
    {
      # 05/24/2012 adileepk_cpbug2
      # Open pipe to receive the output from background process.
      # asmcmdshare_openreadpipe() can throw an exception if
      # if anything goes wrong with the pipe 'pipe_<pidOfForeground>'.
      # The situation is logged and the unresponsive pipe is removed if it
      # exists and then throws an exception which is caught here.
      #
      # Return 0 from this function which triggers a retry at the calling
      # function, asmcmdcore_main().
      asmcmdshare_openreadpipe();
      $success = 1;
    };
    if ($@)
    {
      asmcmdshare_trace(3, "$asmcmdshare_logheader Could not read pipe " .
                        "$asmcmdglobal_hash{'fgpipe'}", 'y', 'n');
      return 0;
    }
  }
  my $output_expected = 1;
  while ($output_expected)
  {
    # Check if bg is still alive, otherwise retry immediately
    if (!asmcmdcore_is_bg_alive())
    {
      asmcmdshare_trace(3, "$asmcmdshare_logheader BG died unexpectedly, ".
                        "retrying", 'y', 'n');
      return 0;
    }
    # Read and print the output from the pipe until a terminating string
    # is received.
    eval
    {
      alarm $asmcmdshare_readpipewait;
      $asmcmdshare_process_status = "RECEIVINGOUTPUT";
      $output_expected = asmcmdshare_output($asmcmdglobal_hash{'fgpipe'});
      alarm 0;
    };
    if ($@)
    {
      asmcmdshare_trace(4, "$asmcmdshare_logheader Timeout read output - ".
                        "$asmcmdshare_readpipewait seconds", 'y', 'n');
      # If the background process has requested that connection pooling be
      # disabled then proceed with legacy method.
      if (!asmcmdcore_is_bg_alive())
      {
        asmcmdshare_trace(3, "$asmcmdshare_logheader BG died unexpectedly, ".
                          "retrying", 'y', 'n');
        return 0;
      }
      if ($@ =~ $asmcmdshare_disablecp_string)
      {
        die $asmcmdshare_disablecp_string;
      }
      else
      {
        # 05/24/2012 adileepk_cpbug2
        # Output timed out. Perhaps the Background process exited after
        # the command was sent.
        # If an exception is caught then return 0 from this function which
        # would trigger a retry at the calling function, asmcmdcore_main()
        asmcmdshare_closereadpipe();
        $asmcmdshare_process_status = "RUNNING";
        # Wait until BG process exits in case it's still alive.
        while (asmcmdcore_is_bg_alive())
        {
          sleep(1);
        }
        return 0;
      }
    }
  }
  $asmcmdshare_process_status = "RECEIVEDOUTPUT";
  asmcmdshare_trace(3, "$asmcmdshare_logheader Received the " .
                    "terminating string from ASMCMD Background, exiting.",
                    'y', 'n');
  return 1;
}

########
# NAME
#   asmcmdcore_connect
#
# DESCRIPTION
#   This routine initiates a conneciton to the ASM instance.  Calls
#    asmcmdbase_connect().
#
# PARAMETERS
#    None.
#
# RETURNS
#   Null.
#
# NOTES
########
sub asmcmdcore_connect
{
  my ($dbh);

  # Connect to ASM instance first
  $dbh = asmcmdbase_connect(undef);

  if (defined ($dbh))
  {
    my ($qry, $sth, $row);

    # Bugs 5661841 and 5629952: now that these bugs are fixed, ASMCMD
    # can work on both ASM and RDBMS instances. No need to check instance
    # type, anymore.

    # Initialize global variables, including getting group_number and name
    # of the first diskgroup.
    asmcmdbase_init_global($dbh);
  }

  return $dbh;
}

########
# NAME
#   asmcmdcore_shell
#
# DESCRIPTION
#   This routine contains the top-level shell loop that prompts the user for
#   for commands and calls other routines to process them.
#
# PARAMETERS
#   dbh   (IN) - initialized database handle, must be non-null.
#
# RETURNS
#   Null.
#
# NOTES
#   Should call asmcmdcore_connect to initialize $dbh before calling this
#   routine.
########
sub asmcmdcore_shell
{
  my ($dbh);

  my ($line);                                 # One line of input from user. #
  my ($prompt) = 'ASMCMD> ';                  # ASMCMD user prompt value.    #
  my ($term);
  my (@eargs);
  my ($lastflag) = 0;        #Flag to indicate last iteration of while loop
  my ($mypath) = shift;
  my ($cmd);
  my ($mode);
  my ($no_instance_cmd);

  # This is the right place for registering the signal handler. Initially it
  # was registered when the modules where loaded in global scope. Handling
  # sthe ctrl-C ignal before connecting to the ASM instance (and starting
  # ASM command prompt)

  $SIG{INT} = \&asmcmdshare_signal_handler;# Signal handler for asmcmd       #

  # Try to connect to ASM if the command is different from help or if it needs
  # to connect to ASM instance
  $cmd             = $asmcmdglobal_hash{'cmd'};
  $mode            = $asmcmdglobal_hash{'mode'};
  $no_instance_cmd = asmcmdshare_is_no_instance_cmd($cmd);

  if ($mode eq 'i' or ($cmd ne 'help' and $no_instance_cmd <= 0))
  {
    $dbh = asmcmdcore_connect();

    if (defined($dbh))
    {
      $asmcmdglobal_hash{'ver'} = asmcmdshare_get_asm_version($dbh);

      # $$$ In order to test different version numbers of ASM and their
      # relative behaviors on ASMCMD, comment out the line above and
      # uncomment the line below. Set the version number to the one
      # that's to be tested. Note that this testing method works only
      #
      # $asmcmdglobal_hash{'ver'} = '11.1.0.3.0';
    }
    else
    {
      # Inform user that connection to ASM failed, except when the issued
      # command is help, startup, shutdown, or lsdsk

      asmcmdshare_trace(5, $DBI::errstr, 'y', 'y');
      @eargs = ($ENV{'ORACLE_SID'}) if defined($ENV{'ORACLE_SID'});
      if ($asmcmdglobal_hash{'verbose'} eq 'debug')
      {
        asmcmdshare_error_msg (8103, \@eargs);
      }
      asmcmdshare_trace(3, "Connected to an idle instance.", 'y', 'y');
    }
  }

  # If non-interactive mode, process command and return.
  if ($mode eq 'n')
  {
    asmcmdshare_trace(3, "Connection Pooling has been disabled.",
                      'y', 'n') if ($asmcmdglobal_hash{'nocp'} == 1);
    # Construct the command arguments from ARGV and log it
    my ($i,$token);
    my (@args) = ();

    for ($i = 0; $i<= $#ARGV; $i++)
    {
       $token = $ARGV[$i];
       if ($token !~ /^-/ && $token =~ /\W/ && $token !~ /'/)
       {
          $args[$i] = "'$token'"; # Put back the single quotes for tokens like
                                  # patterns, etc. The quotes are stripped by
                                  # the shell.
       }
       else
       {
          $args[$i] = $token;
       }
    }
    $line = join(" ", @args);
    if ($line)
    {
        asmcmdshare_trace(3, "ASMCMD (PID = $$) Given command - ".
                              $asmcmdglobal_hash{'cmd'} . " $line", 'y', 'n')
    }
    else
    {
        asmcmdshare_trace(3, "ASMCMD (PID = $$) Given command - ".
                              $asmcmdglobal_hash{'cmd'}, 'y', 'n')
    }

    if (!defined ($dbh) && $no_instance_cmd == 0)
    {
      # Connection failed, and command requires ASM instance; record error.
      asmcmdshare_error_msg (8102, undef);
      asmcmdshare_removebgpipe();
    }
    else
    {
      eval
      {
         asmcmdcore_module_driver($dbh);
      };
      if (asmcmdexceptions::catch())
      {
        my $err = asmcmdexceptions::getExceptionstring ();
        asmcmdshare_trace (3,
                           "Unhandled Exception non-interactive mode $err",
                           'y', 'n');
         # Set the exit status to -1
         $asmcmdglobal_hash{'e'} = -1;
      }
    }

    exit $asmcmdglobal_hash{'e'};
  }

  $asmcmdglobal_hash{'cwdnm'} = '+';

  if (-e "/dev/tty")
  {
    $term = new Term::ReadLine("", \*STDIN, \*STDOUT);
  }
  else
  {
    $term = new Term::ReadLine("CON", \*STDIN, \*STDOUT);
  }

  if ($term->Features->{ornaments})
  {
    local $Term::ReadLine::termcap_nowarn = 1;
    $term->ornaments(0);
  }

  while (1)
  {

    if ($lastflag == 1)
    {
      $lastflag = 0;   #Reset flag (which is reduandant as of now)
      last;
    }

    eval
    {
      my (@token);# Need fresh array of parsed tokens of arguments from $line. #

      # Prepare prompt, if long version of prompt is needed.
      if ($asmcmdglobal_hash{'lprmt'} eq 'y')
      {
        $prompt = 'ASMCMD [' . $asmcmdglobal_hash{'cwdnm'} . '] > ';
      }

      select STDERR;
      $|++;
      select STDOUT;
      $|++;

      $line = $term->readline($prompt);

      if (defined($line))
      {
        chomp($line);                           # Remove newline character.    #
        $line =~ s,^\s+,,g;                     # Remove initial spaces.       #
        $line =~ s,\s+$,,g;                     # Remove trailing spaces.      #
        $line =~ s,;+$,,g;                      # Remove trailing semicolon.   #
      }

      # Terminate if EOF or 'exit'.
      if (! defined($line))
      {
        $line = 'exit';
        print "exit\n";
      }
      #last if ($line eq 'exit');
      #last if ($line eq 'quit');
      if ($line eq 'exit' || $line eq 'quit')
      {
        $lastflag = 1;
        die;
      }

      if ($line =~ /^!/)
      {
        $ENV{'PATH'} = $mypath;
        $line =~ s/^!//;

        my $cmd;
        my $os = $^O;

        if ($os eq "MSWin32")
        {
          $cmd = "$line";
        }
        else
        {
          $cmd="$line 1>&1";
        }

        system($cmd);

        # NT has the necessary dll's in that directory.
        # 21182361: Append to original path
        $ENV{'PATH'} = "$ENV{'ORACLE_HOME'}/bin:".$mypath;
      }
      else
      {
        # Parse $line into an array of arguments.
        if (asmcmdbase_parse_int_cmd_line($line, \@token))
        {
          # asmcmdcore_parse_int_cmd_line() returned error. #
          asmcmdshare_error_msg(8007, undef);
          #next;
          # Error, so done with this command, move on to next comand. #
          die;
        }

        die if ($token[0] eq '');           # Empty line, so skip command. #

        # Save command name. #
        $cmd = $asmcmdglobal_hash{'cmd'} = shift(@token);
        @ARGV = @token; # Save in global @ARGV for internal command parsing. #

        if (!defined ($dbh) &&
            asmcmdshare_is_no_instance_cmd($asmcmdglobal_hash{'cmd'}) != 1)
        {
          # Connection failed, and command requires ASM instance;
          # record error. #
          asmcmdshare_error_msg (8102, undef);
          asmcmdshare_removebgpipe();
        }
        else
        {
          # Need to enclose this call to module_driver() in eval block, since
          # an exception could be thrown if any sql query fails.
          # Here, the mode is interactive, hence no need to set exit status.
          # Catch the exception, check if it isn't an asmcmdexceptions
          # exception issue a die statement. (Propogate other exceptions up)
          eval
          {
            asmcmdcore_module_driver($dbh);
          };
          if (asmcmdexceptions::catch())
          {
            my $err = asmcmdexceptions::getExceptionstring();
            asmcmdshare_trace (3, "Unhandled Exception interactive mode $err",
                               'y', 'n');
            die;
          }
        }

        $term->addhistory($line);

        if (defined ($asmcmdglobal_reconnect_cmds{$cmd}))
        {
          # re-connect to asm instance after these commands #
          # this must be done since $dbh is now invalidated #
          # and it was orginally set at this module level   #
          asmcmdbase_disconnect($dbh) if defined ($dbh);

          $dbh = asmcmdbase_connect(undef);
        }

        # re-connect if we startup/shutdown an instance
        # if we cannot get a $dbh, that means there is no instance
        # but this is not a reason to signal error since we can
        # try startup again
        if ($asmcmdglobal_hash{'cmd'} eq 'startup' ||
            $asmcmdglobal_hash{'cmd'} eq 'shutdown')
        {
          asmcmdbase_disconnect($dbh) if defined ($dbh);

          $dbh = asmcmdbase_connect(undef);
          if (!defined($dbh))
          {
            asmcmdshare_trace(5, $DBI::errstr, 'y', 'y');
            @eargs = ($ENV{'ORACLE_SID'}) if defined($ENV{'ORACLE_SID'});
            if ($asmcmdglobal_hash{'verbose'} eq 'debug')
            {
              asmcmdshare_error_msg (8103, \@eargs);
            }
            asmcmdshare_trace(3, "Connected to an idle instance.", 'y', 'y');
          }
        }
      }
    };
  }

  return $dbh;
}

########
# NAME
#  asmcmdcore_consistency_check
#
# DESCRIPTION
#  This routine parses command line arguments only for consistency check option
#  not anyother the arguments  related to ASMCMD or commands internal to ASMCMD.
#
# PARAMETERS
#   GLOBAL: @ARGV (IN/OUT) - list of all command line arguments for asmcmd.
#
# RETURNS
#   Null.
#
#  Note also that this routine removes the consistency check option if found in
#  ARGV
########
sub asmcmdcore_consistency_check
{
  my $i;
  for ($i = 0; $i < $#ARGV+1; $i++)
  {
    if ($ARGV[$i] eq '-check')
    {
      #remove the option from ARGV array if found
      splice(@ARGV,$i,1);

      #set the global to denote that consistency check is ON
      #later used in init() function in all perl modules
      $asmcmdglobal_hash{'consistchk'} = 'y';
      # Connection Pooling would not affect this statement since this routine
      # is called before the fork happens.
      print STDERR "WARNING: ASMCMD consistency check enabled\n";
      last;
    }
  }
  return;
}

########
# NAME
#   asmcmdcore_init_tracebasepath
#
# DESCRIPTION
#   This function creates asmcmd/ directory under
#   $ORACLE_BASE/diag or $ORACLE_HOME/log/diag/ directory if it does not exist.
#   Also sets the owner/group + permissions correctly
#   owner/group same as $ORACLE_HOME/bin/oracle and permission is 0775.
#   This is to allow trace directories to be created under asmcmd for any users
#
# PARAMETERS
#   $basepath   - base directory where asmcmd/ will be created.
#
# RETURNS
#    NULL
#
# NOTE:  $ORACLE_BASE/diag or $ORACLE_HOME/log/diag is assumed to exist
#        only asmcmd/ will be created underneath.
########
sub asmcmdcore_init_tracebasepath
{
  my ($basepath) = shift ;

  if (!-d $basepath)
  {
    eval {mkpath ($basepath)};
    if ($@)
    {
      print STDERR "Can not create path $basepath \n";
    }
  }
  # get ownership/group from $ORACLE_HOME/bin/oracle
  #  This will work only on Unix, so ignore Windows
  if ($^O ne "MSWin32")
  {
    my ($device, $inode, $mode, $nlink, $uid, $gid, $rdev, $size,
            $atime, $mtime, $ctime, $blksize, $blks) ;
    my ($oracle) = "$ENV{'ORACLE_HOME'}/bin/oracle";

    if ( -l $oracle)
    {
      # oracle binary is symbolic link, get details of link
      ($device, $inode, $mode, $nlink, $uid, $gid, $rdev, $size,
            $atime, $mtime, $ctime, $blksize, $blks) =
                                   lstat ("$ENV{'ORACLE_HOME'}/bin/oracle");
    }
    else
    {
      # oracle binary is a file, get details of file
      ($device, $inode, $mode, $nlink, $uid, $gid, $rdev, $size,
            $atime, $mtime, $ctime, $blksize, $blks) =
                                   stat ("$ENV{'ORACLE_HOME'}/bin/oracle");
    }

    if ($mode ne 0775)
    {
      chown $uid, $gid, $basepath ;  # owner/group same as ORACLE binary.
      chmod 0775, $basepath;       # permissions for owner/group.
    }
  }
}

########
# NAME
#  asmcmdcore_trace
#
# DESCRIPTION
#  This routine initializes the tracing - creates trace directory with
#  appropriate owner/group/permission.  Also parses command line arguments
#  for "verbose".  If "verbose", trace-level specified in ARGV, this routine
#  removes it.
#
# PARAMETERS
#   GLOBAL: @ARGV (IN/OUT) - list of all command line arguments for asmcmd.
#
# RETURNS
#   Null.
#
########
sub asmcmdcore_trace
{
  my ($i, $user, $host);
  my ($tracebasepath);
  my $orabase    = "$ENV{'ORACLE_HOME'}/bin/orabase"; 
  my $basepath   = `$orabase`;

  my $os = $^O;

  # This is to get the effective user name
  if ($os eq "MSWin32")
  {
    $user = getlogin;
  }
  else
  {
    $user = getpwuid($>) || getlogin;
  }
  $host = hostname();

  # use ORACLE_BASE if its set to a valid location
  # RTI#20772974: drop "log" in "log/diag/asmcmd" under ORACLE_BASE
  if (exists $ENV{'ORACLE_BASE'} && ($ENV{'ORACLE_BASE'} ne "") &&
      (-d $ENV{'ORACLE_BASE'}))
  {
    $tracebasepath = "$ENV{'ORACLE_BASE'}/diag/asmcmd";
  }
  # 27303785 - use orabase to figure out tracepath if ORACLE_BASE not set
  elsif ($basepath ne "") 
  {
    chomp($basepath);
    $tracebasepath = "$basepath/diag/asmcmd";
  }
  else
  {
    $tracebasepath = "$ENV{'ORACLE_HOME'}/log/diag/asmcmd";
  }

  asmcmdcore_init_tracebasepath ($tracebasepath);
  $asmcmdglobal_trace_path = "$tracebasepath/user_$user/$host";

  if (!-d $asmcmdglobal_trace_path)
  {
    $asmcmdglobal_trace_path =~ /([^\n^\r^\t]+)/;
    $asmcmdglobal_trace_path =$1;

    eval { mkpath ("$asmcmdglobal_trace_path/alert") };
    if ($@)
    {
      print STDERR "Can not create path $asmcmdglobal_trace_path/alert \n";
    }
    eval { mkpath ("$asmcmdglobal_trace_path/trace") };
    if ($@)
    {
      print STDERR "Can not create path $asmcmdglobal_trace_path/trace \n";
    }
  }

  for ($i = 0; $i < $#ARGV+1; $i++)
  {
    if ($ARGV[$i] eq '-v')
    {
      #remove the option from ARGV array if found
      splice(@ARGV,$i,1);
      if (defined($ARGV[$i]))
      {
        if (defined($asmcmdshare_trace_levels{$ARGV[$i]}))
        {
          $asmcmdglobal_hash{'verbose'} =$ARGV[$i];
        }
        else
        {
          print STDERR "WARNING: Specified tracing level '$ARGV[$i]' does".
                                                " not exist.\n";
          $asmcmdglobal_hash{'verbose'} ='normal';
          print STDERR "Default level of tracing is enabled.\n";
        }
        #remove the value  of trace level from ARGV array if found
        splice(@ARGV,$i,1);
      }
      else
      {
        print STDERR "WARNING: Tracing level not specified\n";
        $asmcmdglobal_hash{'verbose'} ='normal';
        print STDERR "Default level of tracing is enabled.\n";
      }
      last;
    }
  }
  return;
}

########
# NAME
#   asmcmdcore_parse_asmcmd_args
#
# DESCRIPTION
#   This routine parses the command line arguments for ASMCMD.  These are
#   not the arguments for commands internal to ASMCMD.
#   asmcmdbase_parse_int_args() handles the latter cases.
#
# PARAMETERS
#   GLOBAL: @ARGV (IN/OUT) - list of all command line arguments for asmcmd.
#
# RETURNS
#   Null.
#
#  Note also that this routine *modifies* @ARGV; all parsed arguments are
#  removed from this array.
########
sub asmcmdcore_parse_asmcmd_args
{
  my ($args_ref);
  my ($i, $len);
  my (@string);
  my ($key);
  my ($argv);
  my (%args)       = ();
  my (@asmcmd_arg) = ();
  my (@cmd_arg)    = ();
  my ($cmd)        = 'asmcmd';

  # Remove trailing semicolon
  $argv = pop(@ARGV);

  if (defined($argv))
  {
    $argv =~ s,;+$,,g;
    push(@ARGV, $argv);
  }

  # chop off the @ARGV array, so we process asmcmd arguments
  for ($i = 0; $i < $#ARGV+1; $i++)
  {
    if (defined ($asmcmdglobal_cmds{$ARGV[$i]}))
    {
      last;
    }
  }
  $len = $#ARGV;
  @asmcmd_arg = @ARGV[0..$i-1] if (defined(@ARGV[0..$i-1]));
  @cmd_arg    = @ARGV[$i..$len] if (defined(@ARGV[$i..$len]));

  @ARGV = @asmcmd_arg;

  # build the list of options to parse using GetOptions
  if ($asmcmdcore_cmds{ $cmd }{ flags })
  {
    foreach $key (keys %{$asmcmdcore_cmds{ $cmd }{ flags }})
    {
      push(@string, $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, \@string))
  {
    # Bug-19783114: If the parse error was caused by an invalid command, 
    #               list all the valid ones.
    if (defined $args{'asmcmd'})
    {
      if (!defined($asmcmdglobal_cmds{${$args{'asmcmd'}}[0]}))
      {
        asmcmdcore_show_commands('exit', \*STDERR);
        return;
      }
    }
    asmcmdcore_syntax_error($cmd);
    return;
  }

  #Set the correct options if deprecated options were used and print WARNING.
  #asmcmdshare_handle_deprecation($asmcmdglobal_hash{ 'cmd'},\%args);
  asmcmdshare_handle_deprecation($cmd, \%args);

  # 19234907: some versions of Windows will not strip the single quotes given
  # through the command line arguments. If they have them, strip them here.
  foreach (@cmd_arg)
  {
    ($_) = $_ =~ /'([^']*)'/ if ($_ =~ /'[^']*'/);
  }

  # reconstruct @ARGV for the command arguments
  @ARGV = @cmd_arg;
  # if a command is passed, check that it is a valid one
  if (defined($ARGV[0]))
  {
    if (!defined($asmcmdglobal_cmds{$ARGV[0]}))
    {
      asmcmdcore_show_commands('exit', \*STDERR);
      return;
    }
  }

  if (defined($args{'V'}))
  {
    print 'asmcmd version ' . $asmcmdglobal_hash{'acver'}. "\n";
    exit 0;
  }

  #default is sysasm
  $asmcmdglobal_hash{'contyp'} = 'sysasm';
  if (defined($args{'privilege'}))
  {
    if (($args{'privilege'} =~ /^sysasm$/i) ||
        ($args{'privilege'} =~ /^sysdba$/i))
    {
      $asmcmdglobal_hash{'contyp'} = $args{'privilege'};
    }
    else
    {
      asmcmdcore_syntax_error('asmcmd');
      return;
    }
  }

  if (defined($args{'nocp'}))
  {
      $asmcmdglobal_hash{'nocp'} = 1;
  }

  if (defined($args{'p'}))
  {
    $asmcmdglobal_hash{'lprmt'} = 'y';
  }

  if (defined($args{'inst'}))
  {
    $asmcmdglobal_hash{'inst'} = $args{'inst'};
  }

  if (defined($ARGV[0]))
  {
    $asmcmdglobal_hash{'mode'} = 'n';

    if (asmcmdcore_is_cmd($ARGV[0]))
    {
      $asmcmdglobal_hash{'cmd'} = shift @ARGV;
      return;
    }
    else
    {
      asmcmdcore_show_commands('exit', \*STDERR);
    }
  }

  if (defined($args{'discover'}))
  {
    $asmcmdglobal_hash{'discover'} = 1;
  }
  else
  {
    $asmcmdglobal_hash{'discover'} = 0;
  }

  return;
}


########
# NAME
#   asmcmdcore_module_driver
#
# DESCRIPTION
#   This function calls in each module the respective function that
#   processes commands responsible by the said module.  All ASMCMD
#   commands must pass through this function before being processed
#   by the modules.
#
# PARAMETERS
#   dbh         (IN) - initialized database handle, must be non-null.
#
# RETURNS
#   Null.
#
########
sub asmcmdcore_module_driver
{
  my ($dbh) = shift;
  my ($succ) = 0;
  my ($module);
  my (@eargs);                                   # Array of error arguments. #

  # Bug#18355789: check if the user-entered command is one of the known 
  # ASMCMD internal commands.
  if (!asmcmdcore_is_cmd($asmcmdglobal_hash{'cmd'}))
  {
    @eargs = $asmcmdglobal_hash{'cmd'};
    asmcmdshare_error_msg(8022, \@eargs);
    return;
  }

  # check to see if the current command can be executed with the privilege
  # provided.
  if (!asmcmdshare_check_reqd_priv())
  {
    @eargs = ( $asmcmdglobal_hash{'cmd'}, $asmcmdglobal_hash{'contyp'});
    asmcmdshare_error_msg(9487, \@eargs);
    return;
  }

  foreach $module (@asmcmdglobal_command_callbacks)
  {
    if ($module->($dbh))
    {
      # Assert that we find only one occurrence of this command in
      # the modules.
      @eargs = ("asmcmdcore_module_driver_05", $asmcmdglobal_hash{'cmd'});
      asmcmdshare_assert(($succ == 0), \@eargs);
      $succ = 1;
    }
  }

  if ($asmcmdglobal_hash{'cmd'} eq 'help')
  {
    # Assert that we find only one occurrence of this command in
    # the modules.
    @eargs = ("asmcmdcore_module_driver_10", $asmcmdglobal_hash{'cmd'});
    asmcmdshare_assert(($succ == 0), \@eargs);
    asmcmdcore_process_help();
    $succ = 1;
  }
  if (! $succ)
  {
    asmcmdcore_show_commands(undef, \*STDERR);
  }

  return;
}

########
# NAME
#   asmcmdcore_process_help
#
# DESCRIPTION
#   This top-level routine processes the help command.
#
# PARAMETERS
#   None.
#
# RETURNS
#   Null.
#
########
sub asmcmdcore_process_help
{
  my (%args);                             # Argument hash used by getopts(). #
  my ($ret);                     # asmcmdbase_parse_int_args() return value. #
  my ($cmd);      # User-specified command-name argument; show help on $cmd. #
  my ($syntax);                                   # Command syntax for $cmd. #
  my ($desc);                                # Command description for $cmd. #
  my ($module);                                  # A module's help function. #
  my ($succ) = 0;                        # 1 if command exists, 0 otherwise. #
  my (@eargs);                                   # Array of error arguments. #

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

  # Check if number of non-option parameters are correct.
  if (@ARGV > 1)
  {
    asmcmdcore_syntax_error($asmcmdglobal_hash{'cmd'});
    return;
  }

  $cmd = shift (@ARGV);

  if (defined ($cmd))
  {
    # Search each module for the command's help message.
    foreach $module (@asmcmdglobal_help_callbacks)
    {
      if ($module->($cmd) == 1)
      {
        # Assert that we find only one occurrence of this command in
        # the modules.
        @eargs = ("asmcmdcore_process_help_05", $cmd);
        asmcmdshare_assert(($succ == 0), \@eargs);

        # We found the command's help message.
        $succ = 1;
      }
    }
  }

  if (! defined ($cmd))
  {                       # No command name specified, or command not found; #
                                # show help on asmcmd and list all commands. #

    $syntax = "";
    $syntax = asmcmdshare_get_help_syntax ('asmcmd');
    $desc = asmcmdshare_get_help_desc('asmcmd');
    $desc = asmcmdshare_trim_str ($desc);

    print "$desc\n\n";
    asmcmdcore_show_commands(undef, \*STDOUT); # Print list of all commands. #
  }
  elsif ($succ == 0)
  {
    @eargs = $cmd;
    asmcmdshare_error_msg(8022, \@eargs);
  }

  return;
}

########
# NAME
#   asmcmdcore_show_commands
#
# DESCRIPTION
#   This routine prints a list of all valid internal commands, used
#   as an error message when the user has entered an invalid command name.
#   If $exit is set to 'exit', then also call exit(0).  This option is to
#   accommodate the non-interactive option, when quitting asmcmd is necessary.
#   The caller can specify whether he wants to direct the output to
#   STDOUT or STDERR.
#
# PARAMETERS
#   exit        (IN) - flag: causes asmcmdbase_show_commands() to call exit()
#                      iff value is 'exit'.
#   IO_handle   (IN) - handle where to print output: STDOUT or STDERR.
#
# RETURNS
#   Null.
#
########
sub asmcmdcore_show_commands
{
  my ($exit, $output_handle) = @_;
  my ($asmcmd_cmds) = '';
  my ($module);

  # Not affected by connection pooling since this function is called before
  # asmcmd determines whether connection pooling can be done or not
  print $output_handle "        commands:\n";
  print $output_handle "        --------\n\n";

  foreach $module (@asmcmdglobal_command_list_callbacks)
  {
    my $out = $module->();

    #in case of invisible commands, we get empty string, ignore it.
    if ($out ne "")
    {
      $asmcmd_cmds .= $out . "\n";
    }
  }

  print $output_handle $asmcmd_cmds;

  exit 0 if (defined($exit) && ($exit eq 'exit'));
  return;
}

########
# NAME
#   asmcmdcore_is_cmd
#
# DESCRIPTION
#   This routine checks if a user-entered command is one of the known ASMCMD
#   internal commands.
#
# PARAMETERS
#   arg   (IN) - user-entered command name string.
#
# RETURNS
#   1 if $arg is one of the known commands, 0 otherwise.
#
# NOTES
#   This routine calls the callbacks from each module to check if $arg
#   belongs to any of the modules.  It asserts that the command is found
#   in only one module.
########
sub asmcmdcore_is_cmd
{
  my ($command) = shift;




  my ($module);
  my ($succ) = 0;
  my ($count) = 0;
  my (@eargs);                                   # Array of error arguments. #



  foreach $module (@asmcmdglobal_is_command_callbacks)
  {
    if ($module->($command))
    {
      $succ = 1;
      $count++;
    }
  }

  # Assert that $count is at most 1 and at least 0.
  @eargs = ("asmcmdcore_is_cmd_05", $asmcmdglobal_hash{'cmd'}, $count);
  asmcmdshare_assert( (($count == 1) || ($count == 0)), \@eargs);

  return $succ;
}

########
# NAME
#   asmcmdcore_check_global_callbacks
#
# DESCRIPTION
#   This function checks to see if the global callback arrays have been
#   initialized correctly.
#
# PARAMETERS
#   None
#
# RETURNS
#   Null if the assertion passes; signals exception otherwise.
#
# NOTES
#   This function asserts that all the callback arrays, including
#   asmcmdcore_init_modules, have the same number of elements.
########
sub asmcmdcore_check_global_callbacks
{
  my (@eargs);                             # Error arguments for the assert. #
  my ($temp);

  @eargs = ("asmcmdcore_check_global_callbacks_05",
            scalar(@asmcmdcore_init_modules),
            scalar(@asmcmdglobal_command_callbacks),
            scalar(@asmcmdglobal_help_callbacks),
            scalar(@asmcmdglobal_command_list_callbacks),
            scalar(@asmcmdglobal_is_command_callbacks),
            scalar(@asmcmdglobal_is_wildcard_callbacks),
            scalar(@asmcmdglobal_syntax_error_callbacks),
            scalar(@asmcmdglobal_no_instance_callbacks));

  $temp = scalar(@asmcmdcore_init_modules);

  asmcmdshare_assert(((scalar(@asmcmdglobal_command_callbacks) == $temp) &&
              (scalar(@asmcmdglobal_help_callbacks) == $temp) &&
              (scalar(@asmcmdglobal_command_list_callbacks) == $temp) &&
              (scalar(@asmcmdglobal_is_command_callbacks) == $temp) &&
              (scalar(@asmcmdglobal_is_wildcard_callbacks) == $temp) &&
              (scalar(@asmcmdglobal_syntax_error_callbacks) == $temp) &&
              (scalar(@asmcmdglobal_no_instance_callbacks) == $temp)),
                                  \@eargs);

  return;
}

########
# NAME
#   asmcmdcore_syntax_error
#
# DESCRIPTION
#   This function calls into each module to display the correct syntax
#   for a given ASMCMD command.
#
# PARAMETERS
#   command     (IN) - the user-specified ASMCMD command
#
# RETURNS
#   Null.
#
# NOTES
#   This routine calls the callbacks from each module to display the
#   correct syntax for $command.
########
sub asmcmdcore_syntax_error
{
  my ($command) = shift;
  my ($module);
  my ($count) = 0;
  my (@eargs);                                   # Array of error arguments. #

  foreach $module (@asmcmdglobal_syntax_error_callbacks)
  {
    if ($module->($command))
    {
      $count++;
    }
  }

  # Assert that $count is at most 1 and at least 0.
  @eargs = ("asmcmdcore_syntax_error_05", $asmcmdglobal_hash{'cmd'}, $count);
  asmcmdshare_assert( (($count == 1) || ($count == 0)), \@eargs);

  return;
}


END
{
  if ($asmcmdglobal_hash{'ispooled'})
  {
    asmcmdshare_closereadpipe();
    asmcmdshare_removereadpipe();
    asmcmdshare_closewritepipe();
    asmcmdshare_trace(3, "$asmcmdshare_logheader Exited (" .
                      $asmcmdglobal_hash{'e'} . ") after removing " .
                      "the pipe " . $$asmcmdshare_pipetoread, 'y', 'n');
    if (defined($asmcmdglobal_hash{'proxy_dbh'}))
    {
      if (asmcmdshare_check_dbh_alive($asmcmdglobal_hash{'proxy_dbh'}))
      {
        asmcmdbase_disconnect($asmcmdglobal_hash{'proxy_dbh'});
      }
    }
    exit $asmcmdglobal_hash{'e'};
  }
}
##############################################################################


OHA YOOOO