MINI MINI MANI MO

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

# Copyright (c) 2004, 2018, Oracle and/or its affiliates. All rights reserved.
#
#    NAME
#      asmcmdafd - ASM CoMmanD line interface (AFD Module)
#
#    DESCRIPTION
#      This module contains all the AFD(ASM Filter Driver) related commands.
#
#    NOTES
#      usage: asmcmdcore [-p] [command]
#
#    MODIFIED  (MM/DD/YY)
#    apfwkr     06/11/18 - Backport ssprasad_bug-28074713 from main
#    ssprasad   05/25/18 - 28074713: fix in asmcmdafd_isSUSELinux
#    wanhlee    08/02/17 - 26564508: Verify afd/acfsdriverstate return result.
#    csusarre   04/28/17 - fix afddriverstate and afdroot extensions on Windows
#                          OS, changed to .bat
#    ssprasad   04/27/17 - 25902425: asmcmd/afd-udev to set same permissions
#    prabbala   03/27/17 - 25825910: use asmcmdshare_runcmd in sub _isSUSELinux
#    siyarlag   01/10/17 - 25117436: check for mc after GI is setup
#    siyarlag   07/12/16 - 23700550: no member cluster check if --init
#    siyarlag   06/21/16 - 23616155: check state of afd before command exec
#    siyarlag   05/31/16 - 23495544: trim domain from hostname
#    diguzman   05/30/16 - 19654070 Little change at _no_instance_cmd routine
#    siyarlag   05/16/16 - 23288546: setup log dirs
#    siyarlag   05/10/16 - 23129577: let afd_dsset run as root
#    ssprasad   04/13/16 - Bug/23100725 - Report AFD driver mismatch in afdstate
#    siyarlag   03/14/16 - disallow label operations on member cluster
#    siyarlag   02/15/16 - Bug/22472825 - run afd_dsset as GI user
#    jochoa     12/13/15 - Bug22238113: Make $dskpath have complete argument
#                          without splitting on comma 
#    siyarlag   12/18/15 - add -init option for label set/clear
#    siyarlag   11/09/15 - Bug/21511801: add afd_refresh and change owner
#    siyarlag   10/05/15 - afd_deconfigure with force
#    siyarlag   08/20/15 - Bug/21663398: sles fixes
#    siyarlag   08/03/15 - Bug/21544924: fix command mismatch
#    siyarlag   07/21/15 - Bug/21482687: fix afdconfigure
#    siyarlag   06/30/15 - Bug/21244596: miscellaneous fixes
#    ssprasad   06/22/15 - #21206502: DI not supported msg for Solaris
#    siyarlag   06/08/15 - srge dif issue - retrun true
#    siyarlag   05/20/15 - creation
#    siyarlag   05/11/15 - Bug/21116936: fix label set, disallow afd on exadata
#    siyarlag   04/02/15 - Bug/19700132: make afd commands clusterwide
#    ssprasad   03/09/15 - Change afd.conf to oracleafd.conf
#    siyarlag   01/08/15 - Bug/20307737: print msg based on return code
#    siyarlag   12/04/14 - Bug/18838998: display if no device to label
#    siyarlag   07/30/14 - Bug/19326908: use HAS commands for SIHA
#    alolau     06/10/14 - Add afd_di
#    siyarlag   06/24/14 - Bug/19035573: use afdtool always to update afd conf
#    siyarlag   05/29/14 - Bug/18865657: add afd_scan
#    pvenkatr   01/22/14 - Bug # 18136383 Added afd commands
#    siyarlag   05/21/14 - Bug/18812974: add afd_filter afd_lsdsk
#    siyarlag   04/16/14 - Bug/18430406: add afd_configure afd_deconfigure
#                          afd_state
#    pvenkatr   01/22/14 - Bug # 18136383 Added AFD commands
#                                afd_dsget/afd_dsset/afd_label/afd_unlabel
#
############################################################################
#
############################ Functions List #################################
#
#############################################################################

package asmcmdafd;
require Exporter;
our @ISA    = qw(Exporter);
our @EXPORT = qw(asmcmdafd_init
                 %asmcmdafd_cmds
                 );

use strict;
use DBI qw(:sql_types);
use Getopt::Long qw(:config no_ignore_case bundling);
use asmcmdglobal;
use asmcmdshare;
use asmcmdparser;
use asmcmdbase;

use List::Util qw[min max];
use File::Find;
use File::Spec;
use File::Spec::Functions;
use File::Copy;
use Sys::Hostname;

####################### ASMCMDAFD Global Constants ######################
our ($ASMCMDAFD_SQLPLUS) = "$ENV{'ORACLE_HOME'}/bin/sqlplus -S / as sysasm";

# SQLPLUS command with appropriage roles.
our ($ASMCMDAFD_SQLPLUS_SYSASM)  =
                 "$ENV{'ORACLE_HOME'}/bin/sqlplus -S / as sysasm";
our ($ASMCMDAFD_SQLPLUS_SYSDBA)  = 
                 "$ENV{'ORACLE_HOME'}/bin/sqlplus -S / as sysdba";
our ($ASMCMDAFD_SQLPLUS_SYSOPER) = 
                 "$ENV{'ORACLE_HOME'}/bin/sqlplus -S / as sysoper" ;


####################### ASMCMDAFD Global Variables ######################
our (%asmcmdafd_cmds) = (afd_configure   => {},
                         afd_deconfigure => {},
                         afd_dsset       => {},
                         afd_dsget       => {},
                         afd_filter      => {},
                         afd_label       => {},
                         afd_lsdsk       => {},
                         afd_lslbl       => {},
                         afd_refresh     => {},
                         afd_scan        => {},
                         afd_unlabel     => {},
                         afd_state       => {},
                         afd_di          => {}
                         );

# init script constants
our  $INITD;
our  $RCSDIR;
our  $RCKDIR;
our  $RCALLDIR;
our  $RC_START;
our  $RC_KILL;
our  $RC_KILL_OLD;
our  $RC_KILL_OLD2;
our  $IT;
our  $INIT;
our  $OCRLOC;
our  $AFDDISKLOC;
our  $SU;

if ($^O =~ /linux/i)
{
  $INITD = "/etc/init.d";
  $RCSDIR = "/etc/rc.d/rc3.d /etc/rc.d/rc5.d";
  $RCKDIR = "/etc/rc.d/rc0.d /etc/rc.d/rc1.d /etc/rc.d/rc2.d /etc/rc.d/rc4.d";
  $RCKDIR = $RCKDIR . " /etc/rc.d/rc6.d";
  $RCALLDIR ="/etc/rc.d/rc0.d /etc/rc.d/rc1.d /etc/rc.d/rc2.d /etc/rc.d/rc3.d";
  $RCALLDIR = $RCALLDIR . " /etc/rc.d/rc4.d /etc/rc.d/rc5.d /etc/rc.d/rc6.d";
  $RC_START = "S96";
  $RC_KILL = "K15";
  $RC_KILL_OLD  = "K96";
  $RC_KILL_OLD2 = "K19";
  $IT = "/etc/inittab";
  $INIT = "/usr/sbin/init";
  $OCRLOC = "/etc/oracle/ocr.loc";
  $AFDDISKLOC = "/dev/oracleafd/disks";
  $SU = "/bin/su";
}
elsif ($^O =~ /solaris/i)
{
  $INITD = "/etc/init.d";
  $RCSDIR = "/etc/rc3.d";
  $RCKDIR = "/etc/rc0.d /etc/rc1.d /etc/rc2.d /etc/rcS.d";
  $RCALLDIR ="/etc/rc.d/rc0.d /etc/rc.d/rc1.d /etc/rc.d/rc2.d /etc/rc.d/rc3.d";
  $RCALLDIR = $RCALLDIR ." /etc/rc.d/rcS.d";
  $RC_START = "S96";
  $RC_KILL = "K19";
  $RC_KILL_OLD = "K96";
  $IT = "/etc/inittab";
  $INIT = "/sbin/init";
  $OCRLOC = "/var/opt/oracle/ocr.loc";
  $AFDDISKLOC = "/var/opt/oracle/oracleafd/disks";
  $SU = "/usr/bin/su";
}
elsif ($^O =~ /aix/i)
{
  $INITD = "/etc";
  $RCSDIR = "/etc/rc.d/rc2.d";
  $RCKDIR = "/etc/rc.d/rc2.d";
  $RCALLDIR = "/etc/rc.d/rc2.d";
  $RC_START = "S96";
  $RC_KILL = "K19";
  $RC_KILL_OLD = "K96";
  $IT = "/etc/inittab";
  $INIT = "/usr/sbin/init";
  $OCRLOC = "/var/opt/oracle/ocr.loc";
  $AFDDISKLOC = "/var/opt/oracle/oracleafd/disks";
  $SU = "/bin/su";
}
elsif(!($^O =~ /win/i))
{
  $AFDDISKLOC = "\\\\.\\ORACLEAFD";
}

sub is_asmcmd
{
  return 1;
}

########
# NAME
#   asmcmdafd_init
#
# DESCRIPTION
#   This function initializes the asmcmdafd module.  For now it simply 
#   registers its callbacks with the asmcmdglobal module.
#
# PARAMETERS
#   None
#
# RETURNS
#   Null
#
# NOTES
#   Only asmcmdcore_main() calls this routine.
########
sub init
{
  # All of the arrays defined in the asmcmdglobal module must be 
  # initialized here.  Otherwise, an internal error will result.
  push (@asmcmdglobal_command_callbacks, \&asmcmdafd_process_cmd);
  push (@asmcmdglobal_help_callbacks, \&asmcmdafd_process_help);
  push (@asmcmdglobal_command_list_callbacks, \&asmcmdafd_get_asmcmd_cmds);
  push (@asmcmdglobal_is_command_callbacks, \&asmcmdafd_is_cmd);
  push (@asmcmdglobal_is_wildcard_callbacks, \&asmcmdafd_is_wildcard_cmd);
  push (@asmcmdglobal_syntax_error_callbacks, \&asmcmdafd_syntax_error);
  push (@asmcmdglobal_no_instance_callbacks, \&asmcmdafd_is_no_instance_cmd);
  %asmcmdglobal_cmds = (%asmcmdglobal_cmds, %asmcmdafd_cmds);

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


########
# NAME
#   asmcmdafd_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 asmcmdafd module; 0 if not.
#
# NOTES
#   Only asmcmdcore_shell() calls this routine.
########
sub asmcmdafd_process_cmd 
{
  my ($dbh) = @_;
  my ($succ) = 0;

  # Get current command from global value, which is set by 
  # asmcmdafd_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 ASMCMDAFD command.
  my (%cmdhash) = ( afd_configure    => \&asmcmdafd_process_afdconfigure,
                    afd_deconfigure  => \&asmcmdafd_process_afddeconfigure,
                    afd_dsset        => \&asmcmdafd_process_afddsset,
                    afd_dsget        => \&asmcmdafd_process_afddsget,
                    afd_filter       => \&asmcmdafd_process_afdfilter,
                    afd_label        => \&asmcmdafd_process_afdsetlabel,
                    afd_lsdsk        => \&asmcmdafd_process_afdlsdsk,
                    afd_lslbl        => \&asmcmdafd_process_afdlslbl,
                    afd_refresh      => \&asmcmdafd_process_afdrefresh,
                    afd_scan         => \&asmcmdafd_process_afdscan,
                    afd_unlabel      => \&asmcmdafd_process_afdclrlabel,
                    afd_state        => \&asmcmdafd_process_afdstate,
                    afd_di           => \&asmcmdafd_process_afddi);

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

########
# NAME
#   asmcmdafd_process_afdconfigure
#
# DESCRIPTION
#   To configure AFD on the local node
#
# PARAMETER
#   -d      -  disable AFD filtering mode
#   -e      -  enable  AFD filtering mode
#   -f      -  force   AFD configuration
#
# RETURNS
#   NULL.
#
# NOTES
#   Only asmcmdafd_process_cmd() calls this function.
########
sub asmcmdafd_process_afdconfigure
{
  my ($dbh) = @_;
  my ($path);
  my ($ret);
  my (%args);
  my (@eargs);
  my ($buf);
  my ($asmlib);
  my ($asmlibexists) = 0;
  my ($efilter) = 0;
  my ($dfilter) = 0;
  my ($force) = 0;

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

  $efilter = $args{'e'};
  $dfilter = $args{'d'};
  $force  = $args{'f'};
  if ($force)
  {
    asmcmdshare_trace(3, "NOTE: afd_configure 'force' option used", 'y', 'n');
  }

  # Bug 21058846: AFD is not supported on Exadata
  if (asmcmdafd_is_exadata())
  {
    #9520-"AFD is not '%s'"
    @eargs = "supported";
    asmcmdshare_error_msg(9520, \@eargs);
    return;
  }

  # 0. Check for ASMLIB presence on Linux
  if (($^O =~ /linux/i))
  {
    my $dir = "/opt/oracle/extapi";
    if (-e "$dir")
    {
      open (ASMLIB, "find /opt/oracle/extapi/ | grep libasm.so |");
      while ($asmlib = <ASMLIB>)
      {
        $asmlibexists = 1;
      }
      close(ASMLIB);
    }
    open (ASMLIB, "/sbin/lsmod | grep oracleasm |");
    while ($asmlib = <ASMLIB>)
    {
      $asmlibexists = 1;
    }
    close(ASMLIB);
    if ($asmlibexists)
    {
      my $asm_dis;
      $asm_dis = asmcmdafd_get_asmdiskstr_fromprofile();

      # Bug 24939841: don't need empty asm_diskstring if not using ASMLib disks
      if (($asm_dis) && (($asm_dis =~ /ORCL:/) || ($asm_dis =~ /oracleasm/)))
      {
        asmcmdshare_trace(3, "NOTE: ASMLib present; asm diskstring : $asm_dis",
                          'y', 'n');
        #9519-"ASMLib is present; command requires blank ASM disk string"
        @eargs = ($asm_dis);
        asmcmdshare_error_msg(9519, \@eargs);
        return;
      }
    }
  }

  # 1. Check if AFD is supported and not loaded.
  #    Skipping is_afd_supported on a system with asmlib exists.
  if ((!$asmlibexists) && (!asmcmdafd_is_afd("supported")))
  {
    #9520-"AFD is not '%s'"
    @eargs = "supported";
    asmcmdshare_error_msg(9520, \@eargs);
    return;
  }

  # 2. Verify that the command is run as 'root' and clusterware is down
  if (!asmcmdafd_am_root())
  {
    #9522-"command requires Root access"
    asmcmdshare_error_msg(9522);
    return;
  }
  if (!asmcmdafd_is_cluster_down())
  {
    #9523-"command cannot be used when Oracle Clusterware stack is up"
    asmcmdshare_error_msg(9523);
    return;
  }

  if ((!$force) && (asmcmdafd_is_afd("loaded")))
  {
    # start OHASD
    if (!asmcmdafd_ohasd("start"))
    {
      #9524-"AFD configuration failed"
      @eargs = "ERROR: OHASD start failed";
      asmcmdshare_error_msg(9524, \@eargs);
      return;
    }
    # Even if AFD is loaded on the node, check if its resource is present.
    if (asmcmdafd_afd_resource("status"))
    {
      #9527-"AFD is loaded, but resource ora.driver.afd does not exist"
      asmcmdshare_error_msg(9527);
    }
    else
    {
      #9521-"AFD is already configured"
      asmcmdshare_error_msg(9521);
    }
    # stop OHASD
    if (!asmcmdafd_ohasd("stop"))
    {
      #9524-"AFD configuration failed"
      @eargs = "ERROR: OHASD stop failed";
      asmcmdshare_error_msg(9524, \@eargs);
      return;
    }
    return;
  }

  # 3. Handle ASMLib if configured.
  $asmlibexists = asmcmdafd_handle_asmlib();
  if ($asmlibexists == 2)
  {
    #9524-"AFD configuration failed"
    @eargs = "ERROR: ASMLib deconfiguration failed";
    asmcmdshare_error_msg(9524, \@eargs);
    return;
  }

  # 4. Install AFD
  if (!asmcmdafd_afdroot("install"))
  {
    #9524-"AFD configuration failed"
    @eargs = "ERROR: afdroot install failed";
    asmcmdshare_error_msg(9524, \@eargs);
    return;
  }

  # 5. - Update oracleafd.conf using kfod op=GPNP
  if (!asmcmdafd_update_afd_conf())
  {
    #9524-"AFD configuration failed"
    @eargs = "ERROR: update of oracleafd.conf file failed";
    asmcmdshare_error_msg(9524, \@eargs);
    return;
  }
  else
  {
    # Enable filtering if "-e"
    if ($efilter)
    {
      asmcmdafd_afdfilter("enable", "");
    }
    # Disable filtering if "-d"
    if ($dfilter)
    {
      asmcmdafd_afdfilter("disable", "");
    }
  }

  # 6. If ASMLib was present in the system and we removed it before installing
  #   AFD, then perform a rescan of the system for any ASMLib disks to be
  #   be managed by AFD.
  if ($asmlibexists)
  {
    my ($dfltstr) = "/dev/sd*";
    asmcmdafd_rescan_afd("$dfltstr");
  }
  else
  {
    asmcmdafd_rescan_afd();
  }

  # 7. - create init scripts
  if(!($^O =~ /win/i))
  {
    if (!asmcmdafd_copy_afdinit())
    {
      #9524-"AFD configuration failed"
      @eargs = "ERROR: copying afd init scripts to init directory failed";
      asmcmdshare_error_msg(9524, \@eargs);
      return;
    }
  }

  asmcmdshare_print("Modifying resource dependencies".
                    " - this may take some time.\n");
  # 8. start OHASD with -noautostart option. This starts only the OHASD.
  if (!asmcmdafd_ohasd("start"))
  {
    #9524-"AFD configuration failed"
    @eargs = "ERROR: OHASD start failed";
    asmcmdshare_error_msg(9524, \@eargs);
    return;
  }
  # 9. check and create ora.driver.afd OHASD resource
  if (!asmcmdafd_afd_resource("add"))
  {
    #9524-"AFD configuration failed"
    @eargs = "ERROR: AFD resource add failed";
    asmcmdshare_error_msg(9524, \@eargs);
    return;
  }
  # 10. Add a START dependency. Modify ora.cssd resource attributes.
  if (!asmcmdafd_modify_resource("add"))
  {
    #9524-"AFD configuration failed"
    @eargs = "ERROR: AFD resource modify failed";
    asmcmdshare_error_msg(9524, \@eargs);
    return;
  }
  # 11. stop OHASD
  if (!asmcmdafd_ohasd("stop"))
  {
    #9524-"AFD configuration failed"
    @eargs = "ERROR: OHASD stop failed";
    asmcmdshare_error_msg(9524, \@eargs);
    return;
  }
}

########
# NAME
#   asmcmdafd_process_afddeconfigure
#
# DESCRIPTION
#   To deconfigure AFD from the local node
#
# PARAMETER
#   NONE
#
# RETURNS
#   NULL.
#
# NOTES
#   Only asmcmdafd_process_cmd() calls this function.
########
sub asmcmdafd_process_afddeconfigure
{
  my ($dbh) = @_;
  my ($path);
  my ($ret);
  my (%args);
  my (@eargs);
  my $afd_conf = "/etc/oracleafd.conf";
  my ($force) = 0;

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

  $force  = $args{'f'};
  if ($force)
  {
    asmcmdshare_trace(3,"NOTE: afd_deconfigure 'force' option used", 'y', 'n');
  }

  if($^O =~ /win/i)
  {
    ($afd_conf) = "$ENV{SYSTEMROOT}\\system32\\drivers\\oracleafd.conf";
  }

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

  # 0. Bug 21058846: AFD is not supported on Exadata
  if (asmcmdafd_is_exadata())
  {
    #9520-"AFD is not '%s'"
    @eargs = "supported";
    asmcmdshare_error_msg(9520, \@eargs);
    return;
  }

  # 1. is supported check 
  if (!asmcmdafd_is_afd("supported"))
  {
    #9520-"AFD is not '%s'"
    @eargs = "Supported";
    asmcmdshare_error_msg(9520, \@eargs);
    return;
  }

  # 2. Verify that the command is run as 'root', clusterware is down and 
  # AFD is configured.
  if (!asmcmdafd_am_root())
  {
    #9522-"command requires Root access"
    asmcmdshare_error_msg(9522);
    return;
  }

  # 3. check if AFD is installed on the node
  if ((!$force) && (!asmcmdafd_is_afd("installed")))
  {
    #9520-"AFD is not '%s'"
    @eargs = "installed";
    asmcmdshare_error_msg(9520, \@eargs);
    return;
  }

  # 4. Check if cluster stack is down and ACFS driver is not loaded
  if (!asmcmdafd_is_cluster_down())
  {
    #9523-"command cannot be used when Oracle Clusterware stack is up"
    asmcmdshare_error_msg(9523);
    return;
  }
  # if acfs driver is in loaded state we can't uninstall AFD
  if (asmcmdafd_is_acfs("loaded"))
  {
    #9525-"AFD deconfiguration failed"
    @eargs = "ERROR: acfs driver is loaded";
    asmcmdshare_error_msg(9525, \@eargs);
    return;
  }

  # 5. uninstall AFD driver
  if (!asmcmdafd_afdroot("uninstall"))
  {
    #9525-"AFD deconfiguration failed"
    @eargs = "ERROR: afdroot uninstall failed";
    asmcmdshare_error_msg(9525, \@eargs);
    return;
  }

  # 6. remove oracleafd.conf file
  if (-e "$afd_conf")
  {
    unlink("$afd_conf");
  }

  # 7. remove init scripts
  if(!($^O =~ /win/i))
  {
    asmcmdafd_rm_afdinit_init();
    asmcmdafd_rm_afdinit_rclevel();
  }
  asmcmdshare_print("Modifying resource dependencies".
                    " - this may take some time.\n");
  # 8. start OHASD with -noautostart option. This starts only the OHASD.
  if (!asmcmdafd_ohasd("start"))
  {
    #9525-"AFD deconfiguration failed"
    @eargs = "ERROR: OHASD start failed";
    asmcmdshare_error_msg(9525, \@eargs);
    return;
  }
  # 9. delete ora.driver.afd dependency in ora.cssd resource
  if ((!asmcmdafd_modify_resource("delete")) && (!$force))
  {
    #9525-"AFD deconfiguration failed"
    @eargs = "ERROR: AFD resource modify failed";
    asmcmdshare_error_msg(9525, \@eargs);
    return;
  }

  # 10. delete ora.driver.afd resource
  if ((!asmcmdafd_afd_resource("delete")) && (!$force))
  {
    #9525-"AFD deconfiguration failed"
    @eargs = "ERROR: AFD resource delete failed";
    asmcmdshare_error_msg(9525, \@eargs);
    return;
  }
  # 11. stop OHASD
  if (!asmcmdafd_ohasd("stop"))
  {
    #9525-"AFD deconfiguration failed"
    @eargs = "ERROR: OHASD stop failed";
    asmcmdshare_error_msg(9525, \@eargs);
    return;
  }
}

########
# NAME
#   asmcmdafd_process_afddsset
#
# DESCRIPTION
#   To set the AFD Discovery Disksstring
#
# PARAMETER
#   $dbh   (IN)  - initiatized database handle, must be non-null.
#   <--all>      - Set clusterwide AFD discovery diskstring.
#
# RETURNS
#   NULL.
#
# NOTES
#   Only asmcmdafd_process_cmd() calls this function.
########
sub asmcmdafd_process_afddsset
{
  my ($dbh) = @_;
  my ($path);
  my ($ret);
  my (%args);
  my (@eargs);
  my (@buf);
  my ($afdtool);
  my ($afdtoolafdds);
  my ($line);
  my ($giusr) = "";
  my ($oraclebin) = "$ENV{'ORACLE_HOME'}/bin/oracle";

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

  # Get the AFD Discovery diskstring
  $path = join(',', @{$args{'afd_dsset'}});

  # is AFD supported check 
  if (!asmcmdafd_is_afd("supported"))
  {
    #9520-"AFD is not '%s'"
    @eargs = "Supported";
    asmcmdshare_error_msg(9520, \@eargs);
    return;
  }

  if ($args{'all'})
  {
    # if AFD diskstring set requested on all the cluster nodes
    if (asmcmdafd_request_action("afdtool", "all",
        "KEYWORD=\'-afdds\' ARG1=\'update\' ARG2=\'$path\' NARGS=2", \@buf))
    {
      foreach (@buf)
      {
        # print output - node '<nodenam>':
        $line = $_;
        if ($line =~ /(CRS-4413:.*)/)
        {
          if ($line =~ /(.*)from (.*)/)
          {
            asmcmdshare_print("$2\n");
          }
        }
        else
        {
          asmcmdshare_print("$_");
        }
      }
    }
    return;
  }

  # if afd disksting set on local node
  $afdtool = "$ENV{'ORACLE_HOME'}/bin/afdtool";
  #The path in WIN is ORACLE_HOME/bin/afdtool.exe
  $afdtool .= ".exe" if($^O =~ /win/i);
  # Make sure the afdtool binary exists and can be executed. 
  if (! -x $afdtool)
  {
    @eargs = ($afdtool);
    asmcmdshare_error_msg(9516, \@eargs);
    return 0;
  }

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

  asmcmdshare_trace(3, "NOTE: afdtool -afdds update '$path'", 'y', 'n');
  $afdtoolafdds = "$afdtool -afdds update '$path'";

  $ret = asmcmdshare_runcmd($afdtoolafdds, \@buf, 0, 0);
  if ($ret)
  {
    if (@buf)
    {
      asmcmdshare_trace(3, "FAIL: " . join('', @buf), 'y', 'n');
      asmcmdshare_print(join('', @buf));
    }
    asmcmdshare_error_msg (9512, undef);
  }
  return;
}

########
# NAME
#   asmcmdafd_process_afddsget
#
# DESCRIPTION
#   To obtain the current AFD Discovery diskstring
#
# PARAMETERS
#   $dbh   (IN)  - initialized database handle, must be non-null.
#   <--all>      - Get clusterwide AFD discovery diskstring.
#
# RETURNS
#   NULL.
#
# NOTES
#   Only asmcmdafd_process_cmd() calls this function.
########
sub asmcmdafd_process_afddsget
{
  my ($dbh) = shift;
  my ($ret, $val, $row);
  my (%args);
  my (@eargs);
  my (@buf);
  my ($afdtool);
  my ($afdtoolafdds);
  my ($line);
  my ($giusr) = "";
  my ($oraclebin) = "$ENV{'ORACLE_HOME'}/bin/oracle";

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

  # if AFD diskstring get requested from all the cluster nodes
  if ($args{'all'})
  {
    if (asmcmdafd_request_action("afdtool", "all",
        "KEYWORD=\'-afdds\' ARG1=\'query\' NARGS=1", \@buf))
    {
      foreach (@buf)
      {
        # print output - node '<nodenam>':
        $line = $_;
        if ($line =~ /(CRS-4413:.*)/)
        {
          if ($line =~ /(.*)from (.*)/)
          {
            asmcmdshare_print("$2\n");
          }
        }
        else
        {
          asmcmdshare_print("$_");
        }
      }
    }
    return;
  }

  # if afd disksting get on local node
  $afdtool = "$ENV{'ORACLE_HOME'}/bin/afdtool";
  #The path in WIN is ORACLE_HOME/bin/afdtool.exe
  $afdtool .= ".exe" if($^O =~ /win/i);
  # Make sure the afdtool binary exists and can be executed. 
  if (! -x $afdtool)
  {
    @eargs = ($afdtool);
    asmcmdshare_error_msg(9516, \@eargs);
    return 0;
  }

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

  asmcmdshare_trace(3, "NOTE: afdtool -afdds query", 'y', 'n');
  $afdtoolafdds = "$afdtool -afdds query";

  if (asmcmdafd_am_root())
  {
    if ($oraclebin)
    {
      $giusr = getpwuid((stat($oraclebin))[4]);
    }
    $ret = asmcmdafd_runcmd_as_user($afdtoolafdds, $giusr, \@buf);
  }
  else
  {
    $ret = asmcmdshare_runcmd($afdtoolafdds, \@buf, 1, 0);
  }

  if (!$ret)
  {
    if (@buf)
    {
      # command succeeded
      asmcmdshare_trace(3, "NOTE: " . join('', @buf), 'y', 'n');
      ($val) = grep { /AFD discovery/i } @buf;
      if ($val)
      {
        asmcmdshare_print ("$val");
        return;
      }
    }
  }
  # command failed
  asmcmdshare_error_msg (9511, undef);
  return;
}

########
# NAME
#   asmcmdafd_process_afdfilter
#
# DESCRIPTION
#   To enable or disable AFD filtering mode.
#   If the command is executed without specifying a disk path then
#   filtering is set at node level.
#
# PARAMETERS
#   $dbh   (IN)  - initialized database handle, must be non-null.
#
#    -e          -  enable  AFD filtering mode
#    -d          -  disable AFD filtering mode
#    <disk-path> -  OS disk path to set the AFD filtering mode on.
#   <--all>      -  set Clusterwide AFD fitlering mode.
# RETURNS
#   NULL.
#
# NOTES
#   Only asmcmdafd_process_cmd() calls this function.
########
sub asmcmdafd_process_afdfilter
{
  my ($dbh) = shift;
  my ($ret, $val, $row);
  my (%args);
  my (@eargs);
  my ($filter);
  my ($diskpath);
  my (@buf);

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

  if ($args{'e'})
  {
    $filter  = "enable";
  }
  if ($args{'d'})
  {
    $filter  = "disable";
  }

  $diskpath = shift(@{$args{'afd_filter'}});
  if ($diskpath)
  {
    # verify that OS disk path exists
    if (! -e $diskpath)
    {
      #9528-"disk '%s' does not exist"
      @eargs = $diskpath;
      asmcmdshare_error_msg(9528, \@eargs);
      return;
    }
  }
  else
  {
    $diskpath = "";
  }

  if ($args{'all'})
  {
    if ($diskpath eq "")
    {
      asmcmdafd_request_action("afdtool", "all",
                               "KEYWORD=\'-filter\' ARG1=\'$filter\' NARGS=1",
                               \@buf);
    }
    else
    {
      asmcmdafd_request_action("afdtool", "all",
                               "KEYWORD=\'-filter\' ARG1=\'$filter\' \
                                ARG2=\'$diskpath\' NARGS=2", \@buf);
    }
  }

  # is AFD loaded check 
  if (!asmcmdafd_is_afd("loaded"))
  {
    #9520-"AFD is not '%s'"
    @eargs = "Loaded";
    asmcmdshare_error_msg(9520, \@eargs);
    return;
  }

  # execute the command
  asmcmdafd_afdfilter($filter, $diskpath);
}

########
# NAME
#   asmcmdafd_process_afdsetlabel
#
# DESCRIPTION
#   To associate a AFD label to a disk
#
# PARAMETERS
#   $dbh   (IN)  - initialized database handle, must be non-null.
#   label        - label for the disk
#   disk         - disk path
#   --rename     - to relabel a disk that was labeled earlier
#   --migrate    - to label a disk that was provisioned for ASM
#   --init       - to initialize a disk by labelling for AFD (zipinstall)
#
# RETURNS
#   NULL.
#
# NOTES
#   Only asmcmdafd_process_cmd() calls this function.
########
sub asmcmdafd_process_afdsetlabel
{
  my ($dbh) = @_;
  my ($label, $dskpath);
  my ($ret);
  my (%args);
  my (@eargs);
  my ($labeloption) = "";
  my ($afdtool); 
  my ($afdtooladd); 
  my (@buf); 
  my ($val);
  my ($force) = 0; 
  my ($init) = 0;
  my ($initoption) = "";
  my ($afdloaded) = 1;
  my ($dskpath_num_elements) = 0;

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

  if (defined($args{'init'}))
  {
    $initoption = "-init";
    $init = 1; 
  }

  # is AFD loaded check 
  $afdloaded = asmcmdafd_is_afd("loaded");

  if ((!$afdloaded) && (!$init))
  {
    #9520-"AFD is not '%s'"
    @eargs = "Loaded";
    asmcmdshare_error_msg(9520, \@eargs);
    return;
  }

  # init option is not allowed if AFD is loaded
  if (($afdloaded) && ($init))
  {
    #9521-"AFD is already configured"
    asmcmdshare_error_msg(9521);
    return;
  }

  if (($afdloaded) && asmcmdafd_is_member_cluster())
  {
    #9544-"The command is not supported on a member cluster."
    asmcmdshare_error_msg(9544);
    return;
  }

  $dskpath_num_elements = scalar @{$args{'afd_label'}};
  $label = @{$args{'afd_label'}}[0];
  $dskpath = join ',', @{$args{'afd_label'}}[1..$dskpath_num_elements-1]; 

  if (defined($args{'rename'}))
  {
    $labeloption = "RENAME";
    $force = 1; 
  }

  if (defined($args{'migrate'}))
  {
    $labeloption = "MIGRATE";
    $force = 1; 
  }

  $afdtool = "$ENV{'ORACLE_HOME'}/bin/afdtool";
  #The path in WIN is ORACLE_HOME/bin/afdtool.exe
  $afdtool .= ".exe" if($^O =~ /win/i);
  # Make sure the afdtool binary exists and can be executed. 
  if (! -x $afdtool)
  {
    @eargs = ($afdtool);
    asmcmdshare_error_msg(9516, \@eargs);
    return 0;
  }

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

  if ($init)
  {
    if (asmcmdafd_am_root())
    {
      asmcmdafd_create_afddisks();
    }
  }

  if ($initoption)
  {
    asmcmdafd_create_logdir();
  }

  if ($force)
  {
    asmcmdshare_trace(3,
                     "NOTE: afdtool -add -f '$dskpath' '$label' $initoption",
                     'y', 'n');
    $afdtooladd = "$afdtool -add -f '$dskpath' '$label' $initoption";
  }
  else
  {
    asmcmdshare_trace(3,
                     "NOTE: afdtool -add '$dskpath' '$label' $initoption",
                     'y', 'n');
    $afdtooladd = "$afdtool -add '$dskpath' '$label' $initoption";
  }

  if (!asmcmdshare_runcmd($afdtooladd, \@buf, 1, 0))
  {
    if ($init)
    {
      asmcmdshare_trace(3, "NOTE: Labeled device '$dskpath' with '$label'",
                        'y', 'n');
      if (asmcmdafd_am_root())
      {
        asmcmdafd_update_afddisks();
      }
      return;
    }

    if (@buf)
    {
      # command succeeded
      asmcmdshare_trace(3, "NOTE: " . join('', @buf), 'y', 'n');
      ($val) = grep { /labeled with/ } @buf;
      if (asmcmdafd_am_root())
      {
        asmcmdafd_update_afddisks();
      }
      return if ($val);
    }
  }
  # Failed to label the device.
  if (@buf)
  {
    asmcmdshare_trace(3, "FAIL: Failed to label an AFD device: @buf",
                      'y', 'n');
    asmcmdshare_print(join('', @buf));
  }
  asmcmdshare_error_msg (9513);
  return;
}

########
# NAME
#   asmcmdafd_process_afdlsdsk
#
# DESCRIPTION
#   To list AFD disks.
#
# PARAMETERS
#   $dbh   (IN)  - initialized database handle, must be non-null.
#   <--all>      - list of AFD disks from all the cluster nodes.
#
# RETURNS
#   NULL.
#
# NOTES
#   Only asmcmdafd_process_cmd() calls this function.
########
sub asmcmdafd_process_afdlsdsk
{
  my ($dbh) = @_;
  my ($ret);
  my (%args);
  my (@eargs);
  my ($afdtool);
  my ($afdlsdsk);
  my (@buf);
  my ($line);

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

  # is AFD loaded check 
  if (!asmcmdafd_is_afd("loaded"))
  {
    #9520-"AFD is not '%s'"
    @eargs = "Loaded";
    asmcmdshare_error_msg(9520, \@eargs);
    return;
  }

  if ($args{'all'})
  {
    # if AFD disk list requested from all the cluster nodes
    if (asmcmdafd_request_action("afdtool", "all",
                             "KEYWORD=\'-getdevlist\' ARG1=\'-mode\' NARGS=1",
                             \@buf))
    {
      foreach (@buf)
      {
        # print output - node '<nodenam>': AFD disk list
        $line = $_;
        if ($line =~ /(CRS-4413:.*)/)
        {
          if ($line =~ /(.*)from (.*)/)
          {
            asmcmdshare_print("$2\n");
          }
        }
        else
        {
          asmcmdshare_print("$_");
        }
      }
    }
    return;
  }

  # if AFD disk list is requested from local node
  $afdtool = "$ENV{'ORACLE_HOME'}/bin/afdtool";
  #The path in WIN is ORACLE_HOME/bin/afdtool.exe
  $afdtool .= ".exe" if($^O =~ /win/i);
  # Make sure the afdtool binary exists and can be executed. 
  if (! -x $afdtool)
  {
    @eargs = ($afdtool);
    asmcmdshare_error_msg(9516, \@eargs);
    return 0;
  }

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

  $afdlsdsk = "$afdtool -getdevlist '\*' -mode";

  asmcmdshare_runcmd($afdlsdsk, \@buf, 1, 0);
  if (@buf)
  {
    asmcmdshare_print(join('', @buf));
  }

  return 0;
}

########
# NAME
#   asmcmdafd_process_afdlslbl
#
# DESCRIPTION
#   To list AFD disks containing labels.
#
# PARAMETERS
#   $dbh   (IN)  - initialized database handle, must be non-null.
#
# RETURNS
#   NULL.
#
# NOTES
#   Only asmcmdafd_process_cmd() calls this function.
########
sub asmcmdafd_process_afdlslbl
{
  my ($dbh) = @_;
  my ($ret);
  my (%args);
  my (@eargs);
  my ($afdtool);
  my ($afdlslbl);
  my (@buf);
  my ($diskpath);

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

  $diskpath = shift @{$args{'afd_lslbl'}};
  if(!defined($diskpath))
  {
    $diskpath = "";
  }

  # if AFD label list is requested from local node
  $afdtool = "$ENV{'ORACLE_HOME'}/bin/afdtool";
  #The path in WIN is ORACLE_HOME/bin/afdtool.exe
  $afdtool .= ".exe" if($^O =~ /win/i);
  # Make sure the afdtool binary exists and can be executed. 
  if (! -x $afdtool)
  {
    @eargs = ($afdtool);
    asmcmdshare_error_msg(9516, \@eargs);
    return 0;
  }

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

  asmcmdafd_create_logdir();

  if ($diskpath)
  {
    $afdlslbl = "$afdtool -listall '$diskpath'";
  }
  else
  {
    $afdlslbl = "$afdtool -listall";
  }

  asmcmdshare_runcmd($afdlslbl, \@buf, 1, 0);
  if (@buf)
  {
    asmcmdshare_print(join('', @buf));
  }

  return 0;
}
########
# NAME
#   asmcmdafd_process_afdrefresh
#
# DESCRIPTION
#   To refresh AFD disks.
#   The command is executed without specifying a disk string, so
#   afd_diskstring value in oracleafd.conf file is used.
#
# PARAMETERS
#   $dbh   (IN)   - initialized database handle, must be non-null.
#   <--all>       -  refresh AFD disks on all cluster nodes.
#
# RETURNS
#   NULL.
#
# NOTES
#   Only asmcmdafd_process_cmd() calls this function.
########
sub asmcmdafd_process_afdrefresh
{
  my ($dbh) = shift;
  my ($ret, $val, $row);
  my (%args);
  my (@eargs);
  my (@buf);

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

  # is AFD loaded check 
  if (!asmcmdafd_is_afd("loaded"))
  {
    #9520-"AFD is not '%s'"
    @eargs = "Loaded";
    asmcmdshare_error_msg(9520, \@eargs);
    return;
  }

  asmcmdshare_trace(3, "NOTE: Refresh AFD disks", 'y', 'n');
  if ($args{'all'})
  {
    # if refresh AFD disks is requested on all nodes
    asmcmdafd_request_action("afdtool", "all", "KEYWORD=\'-refresh\'", \@buf);
    if (asmcmdafd_am_root())
    {
      asmcmdafd_update_afddisks();
    }
    return;
  }

  # if scan is requested on local node
  # execute the command
  asmcmdafd_refresh_afd();
}

########
# NAME
#   asmcmdafd_process_afdscan
#
# DESCRIPTION
#   To scan for AFD disks.
#   If the command is executed without specifying a disk string then
#   afd_diskstring value in oracleafd.conf file is used.
#
# PARAMETERS
#   $dbh   (IN)   - initialized database handle, must be non-null.
#   <disk-string> -  OS disk string to scan the AFD disks.
#   <--all>       -  scan for AFD disks on all cluster nodes.
#
# RETURNS
#   NULL.
#
# NOTES
#   Only asmcmdafd_process_cmd() calls this function.
########
sub asmcmdafd_process_afdscan
{
  my ($dbh) = shift;
  my ($ret, $val, $row);
  my (%args);
  my (@eargs);
  my (@buf);
  my ($diskpath);

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

  $diskpath = shift @{$args{'afd_scan'}};
  if(!defined($diskpath))
  {
    $diskpath = "";
  }

  # is AFD loaded check 
  if (!asmcmdafd_is_afd("loaded"))
  {
    #9520-"AFD is not '%s'"
    @eargs = "Loaded";
    asmcmdshare_error_msg(9520, \@eargs);
    return;
  }

  if ($args{'all'})
  {
    # if scan of AFD requested on all nodes
    asmcmdafd_request_action("afdscan", "all", "ARG1=\'$diskpath\'", \@buf);
    if (asmcmdafd_am_root())
    {
      asmcmdafd_update_afddisks();
    }
    return;
  }

  # if scan is requested on local node
  # execute the command
  asmcmdshare_trace(3, "NOTE: AFD Scan on '$diskpath'", 'y', 'n');
  asmcmdafd_rescan_afd("$diskpath");
}

########
# NAME
#   asmcmdafd_process_afddi
#
# DESCRIPTION
#   To manipulate the data integrity mode in the AFD driver.
#
# PARAMETERS
#   $dbh  (IN)  - initialized database handle, must be non-null.
#   -e          - enable  AFD data integrity mode
#   -d          - disable AFD data integrity mode
#   -q          - query   AFD data integrity mode
#
# RETURNS
#   NULL.
#
# NOTES
#   Only asmcmdafd_process_cmd() calls this function.
########
sub asmcmdafd_process_afddi
{
  my ($dbh) = shift;
  my ($ret);
  my (%args);
  my (@eargs);
  my ($di);

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

  if ($args{'e'})
  {
    $di  = "enable";
  }
  elsif ($args{'d'})
  {
    $di  = "disable";
  }
  elsif ($args{'q'})
  {
    $di  = "query";
  }
  else
  {
    @eargs = ("Unknown DI command");
    asmcmdshare_error_msg(9520, \@eargs);
    return;
  }

  # is AFD loaded check 
  if (!asmcmdafd_is_afd("loaded"))
  {
    #9520-"AFD is not '%s'"
    @eargs = ("Loaded");
    asmcmdshare_error_msg(9520, \@eargs);
    return;
  }

  # execute the command
  asmcmdafd_afddi($di);
}

########
# NAME
#   asmcmdafd_process_afdclrlabel
#
# DESCRIPTION
#   To clear an existing label (which is associated with a disk).
#
# PARAMETERS
#   $dbh   (IN)  - initialized database handle, must be non-null.
#   label        - label to clear
#   -f           - force clear the label and drain all I/Os 
#
# RETURNS
#   NULL.
#
# NOTES
#   Only asmcmdafd_process_cmd() calls this function.
########
sub asmcmdafd_process_afdclrlabel
{
  my ($dbh) = @_;
  my ($label);
  my ($ret);
  my (%args);
  my (@eargs);
  my ($afdtool);
  my ($afdtooldel);
  my (@buf);
  my ($val);
  my ($force);
  my ($init) = 0;
  my ($initoption) = "";
  my ($afdloaded) = 1;

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

  $force  = $args{'f'};

  if (defined($args{'init'}))
  {
    $initoption = "-init";
    $init = 1; 
  }

  if ((!$init) && asmcmdafd_is_member_cluster())
  {
    #9544-"The command is not supported on a member cluster."
    asmcmdshare_error_msg(9544);
    return;
  }

  # is AFD loaded check 
  $afdloaded = asmcmdafd_is_afd("loaded");

  if ((!$afdloaded) && (!$init))
  {
    #9520-"AFD is not '%s'"
    @eargs = "Loaded";
    asmcmdshare_error_msg(9520, \@eargs);
    return;
  }
  # init option is not allowed if AFD is loaded
  if (($afdloaded) && ($init))
  {
    #9521-"AFD is already configured"
    asmcmdshare_error_msg(9521);
    return;
  }

  ($label) = shift(@{$args{'afd_unlabel'}});

  $afdtool = "$ENV{'ORACLE_HOME'}/bin/afdtool";
  #The path in WIN is ORACLE_HOME/bin/afdtool.exe
  $afdtool .= ".exe" if($^O =~ /win/i);
  # Make sure the afdtool binary exists and can be executed. 
  if (! -x $afdtool)
  {
    @eargs = ($afdtool);
    asmcmdshare_error_msg(9516, \@eargs);
    return 0;
  }

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

  if ($initoption)
  {
    asmcmdafd_create_logdir();
  }

  if ($force)
  {
    asmcmdshare_trace(3, "NOTE: afdtool -delete -f '$label' $initoption",
                      'y', 'n');
    $afdtooldel = "$afdtool -delete -f '$label' $initoption";
  }
  else
  {
    asmcmdshare_trace(3, "NOTE: afdtool -delete '$label' $initoption",
                      'y', 'n');
    $afdtooldel = "$afdtool -delete '$label' $initoption";
  }

  if (!asmcmdshare_runcmd($afdtooldel, \@buf, 1, 0))
  {
    if ($init)
    {
      asmcmdshare_trace(3, "NOTE: Unlabeled device $label", 'y', 'n');
      return;
    }

    if (@buf)
    {
      # command succeeded
      asmcmdshare_trace(3, "NOTE: " . join('', @buf), 'y', 'n');
      ($val) = grep { /Unlabeled/ } @buf;
      return if ($val);
    }
  }
  asmcmdshare_trace(3, "FAIL: Failed to unlabel an AFD device: @buf",'y', 'n');
  asmcmdshare_print(join('', @buf));
  asmcmdshare_error_msg (9514);
  return;
}

########
# NAME
#   asmcmdafd_request_action
#
# DESCRIPTION
#   Execute the CRSCTL requested action on ora.driver.afd resource
#
# PARAMETER
#   action_name (IN)  - action name.
#   nodearg     (IN)  - comma separated node names where to execute the action
#                        OR 'all' to execute on all nodes of the cluster.
#   env         (IN)  - action attribute's env key values; this can be NULL.
#   buf_ref     (OUT) - output buffer of the command for caller to consume.
#
# RETURNS
#   1 - Successfully executed the requested action
#   0 - Failure
#
# NOTES
#   
########
sub asmcmdafd_request_action
{
  my ($crsctlcmd);
  my ($crsctl);
  my (@eargs);
  my (@buf);
  my ($nodes) = "";
  my ($afdres) = "ora.driver.afd";
  my ($action_name, $nodearg, $env, $buf_ref) = @_;

  if ($nodearg eq "")
  {
    # invalid input nodes
    return 0;
  }

  if ($nodearg eq "all")
  {
    $nodes = "-all";
  }
  else
  {
    $nodes = "-n \'$nodearg\'";
  }

  $crsctl = "$ENV{'ORACLE_HOME'}/bin/crsctl";
  #The path in WIN is ORACLE_HOME/bin/crsctl.exe
  $crsctl .= ".exe" if($^O =~ /win/i);

  # Make sure the crsctl binary exists and can be executed. 
  if (! -x $crsctl)
  {
    @eargs = ($crsctl);
    asmcmdshare_error_msg(8313, \@eargs);
    return 0;
  }

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

  # execute requested action on ora.driver.afd resource
  $crsctlcmd  = "$crsctl request action ";
  $crsctlcmd .= "$action_name -r $afdres -env \"$env\"\ $nodes -init";

  # To run an action on a resource, OHASD is required. That means clusterware
  # stack needs to be up.
  if (!asmcmdafd_ohasd("check"))
  {
    #9532-"command cannot be used when Oracle Clusterware stack is down"
    asmcmdshare_error_msg(9532);
    return 0;
  }
  # check if AFD resource is present.
  if (asmcmdafd_afd_resource("status"))
  {
    #9533-"resource ora.driver.afd does not exist"
    asmcmdshare_error_msg(9533);
    return 0;
  }

  asmcmdshare_runcmd($crsctlcmd, \@buf, 1, 0);
  # store the command output to the OUT buffer
  @{$buf_ref} = @buf;

  asmcmdshare_trace(3, "NOTE: command: $crsctlcmd\n @buf", 'y', 'n');

  return 1;
}

########
# NAME
#   asmcmdafd_process_afdstate
#
# DESCRIPTION
#   To query the state of AFD
#
# PARAMETER
#   NONE
#
# RETURNS
#   NULL.
#
# NOTES
#   Only asmcmdafd_process_cmd() calls this function.
########
sub asmcmdafd_process_afdstate
{
  my ($ret);
  my (%args);
  my (@eargs);
  my ($host) = hostname;
  my ($state) = "";
  my ($filter) = "DEFAULT";
  my ($afdtool);
  my ($afdfilter);
  my (@buf);
  my ($line);

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

  if ($args{'all'})
  {
    # if state of AFD requested from all nodes
    if (asmcmdafd_request_action("afdstate", "all", "", \@buf))
    {
      foreach (@buf)
      {
        # print output like :
        # node '<nodenam>': State of AFD: LOADED and Filtering Status: DISABLED
        $line = $_;
        if ($line =~ /(CRS-4413:.*)/)
        { 
          chomp($line);
          if ($line =~ /(.*)from (.*)/)
          {
            asmcmdshare_print("$2");
          }
        }
        else
        {
          asmcmdshare_print(" $_");
        }
      }
    }
    return;
  }

  # if state of AFD requested from local node
  if (!asmcmdafd_is_afd("supported"))
  {
    # AFD may be installed on a supported kernel/O.S and later the system
    # may have been moved to an unsupported kernel/O.S. In those cases,
    # AFD drivers are installed but are not compatible with current
    # running kernel/O.S.
    if (asmcmdafd_is_afd("installed"))
    {
      asmcmdshare_error_msg(9545);
    }
    else
    {
      $state = "NOT SUPPORTED";
      @eargs = ($state);
      asmcmdshare_error_msg(9530, \@eargs);
    }
  }
  elsif (asmcmdafd_is_afd("loaded"))
  {
    $state = "LOADED";
    $afdtool = "$ENV{'ORACLE_HOME'}/bin/afdtool";
    #The path in WIN is ORACLE_HOME/bin/afdtool.exe
    $afdtool .= ".exe" if($^O =~ /win/i);
    # Make sure the afdtool binary exists and can be executed. 
    if (! -x $afdtool)
    {
      @eargs = ($afdtool);
      asmcmdshare_error_msg(9516, \@eargs);
      return 0;
    }

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

    $afdfilter = "$afdtool -filter query";

    if (!asmcmdshare_runcmd($afdfilter, \@buf, 1, 0))
    {
      if (@buf)
      {
        # command succeeded
        if ($buf[0] =~ /Filtering Status: (.*)/)
        {
          $filter = $1;
        }
      }
    }
    @eargs = ($state, $filter , $host);
    asmcmdshare_error_msg(9526, \@eargs);
  }
  elsif (asmcmdafd_is_afd("installed"))
  {
    $state = "INSTALLED";
    @eargs = ($state);
    asmcmdshare_error_msg(9530, \@eargs);
  }
  else
  {
    $state = "NOT INSTALLED";
    @eargs = ($state);
    asmcmdshare_error_msg(9530, \@eargs);
  }

  return;
}

########
# NAME
#   asmcmdafd_afdfilter
#
# DESCRIPTION
#   To enable or disable filtering mode in AFD
#
# PARAMETER
#   enable  - enable filtering
#   disable - disable filtering
#
# RETURNS
#   1 if successfully enabled or disabled AFD filtering ; 0 otherwise.
#
# NOTES
########
sub asmcmdafd_afdfilter
{
  my ($action, $diskpath) = @_;
  my ($ret);
  my (%args);
  my (@eargs);
  my ($afdtool);
  my ($afdfilter);
  my (@buf);

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

  asmcmdshare_trace(3, "NOTE: $action AFD Filtering on '$diskpath'", 'y', 'n');
  $afdtool = "$ENV{'ORACLE_HOME'}/bin/afdtool";
  #The path in WIN is ORACLE_HOME/bin/afdtool.exe
  $afdtool .= ".exe" if($^O =~ /win/i);
  # Make sure the afdtool binary exists and can be executed. 
  if (! -x $afdtool)
  {
    @eargs = ($afdtool);
    asmcmdshare_error_msg(9516, \@eargs);
    return 0;
  }

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

  if ($diskpath eq "")
  {
    $afdfilter = "$afdtool -filter $action";
  }
  else
  {
    $afdfilter = "$afdtool -filter $action '$diskpath'";
  }

  if (asmcmdshare_runcmd("$afdfilter", \@buf, 1, 1))
  {
    asmcmdshare_trace(3, "NOTE: command: $afdfilter\n @buf", 'y', 'n');
    asmcmdshare_print(join('', @buf));
  }
  else
  {
    if ($diskpath eq "")
    {
      asmcmdshare_trace(3, "NOTE: AFD Filtering $action"."d on 'Node Level'",
                        'y', 'n');
    }
    else
    {
      asmcmdshare_trace(3, "NOTE: AFD Filtering $action"."d on '$diskpath'",
                        'y', 'n');
    }
    return 1;
  }

  return 0;
}

########
# NAME
#   asmcmdafd_afddi
#
# DESCRIPTION
#   To enable, disable, or query data integrity mode in AFD
#
# PARAMETER
#   enable  - enable integrity
#   disable - disable integrity
#   query   - query data integrity
#
# RETURNS
#   1 - No error on data integrity operation - enabled, disabled, or query
#   0 - afdtool command returned an error
#
# NOTES
########
sub asmcmdafd_afddi
{
  my ($action) = @_;
  my ($ret);
  my ($rc);
  my (%args);
  my (@eargs);
  my ($afdtool);
  my ($cmdout);
  my (@buf);

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

  $afdtool = "$ENV{'ORACLE_HOME'}/bin/afdtool";
  #The path in WIN is ORACLE_HOME/bin/afdtool.exe
  $afdtool .= ".exe" if($^O =~ /win/i);
  # Make sure the afdtool binary exists and can be executed. 
  if (! -x $afdtool)
  {
    @eargs = ($afdtool);
    asmcmdshare_error_msg(9516, \@eargs);
    return 0;
  }

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

  $rc  = asmcmdshare_runcmd("$afdtool -di $action", \@buf, 1, 0);
  if (@buf)
  {
    ($cmdout) = grep { /Data Integrity/ } @buf;
  }

  if (defined($cmdout))
  {
    asmcmdshare_print("$cmdout");
  }

  # asmcmdshare_runcmd & asmcmdafd_afddi interpret success differently
  $ret = ($rc == 0) ? 1 : 0;
  return $ret;
}

########
# NAME
#   asmcmdafd_ohasd
#
# DESCRIPTION
#   This function will start OHASD without starting the rest of the stack
#    or stop OHASD or check OHASD status.
#
# PARAMETERS
#   start - start OHASD
#   stop  - stop  OHASD
#   check - check OHASD
#
# RETURNS
#   1 if successfully started or stopped ohasd OR ohasd is online; 0 otherwise.
########
sub asmcmdafd_ohasd
{
  my ($action) = @_;
  my (@eargs);
  my $crsctlcmd;
  my $crsctl;
  my ($buf);
  my ($line);
  my (@lines);
  my ($cmdout);
  my ($status);
  my ($issiha);
  my ($crsmode);

  $crsctl = "$ENV{'ORACLE_HOME'}/bin/crsctl";
  #The path in WIN is ORACLE_HOME/bin/crsctl.exe
  $crsctl .= ".exe" if($^O =~ /win/i);

  # Make sure the crsctl binary exists and can be executed. 
  if (! -x $crsctl)
  {
    @eargs = ($crsctl);
    asmcmdshare_error_msg(8313, \@eargs);
    return 0;
  }

  #untaint crsctl
  $crsctl =~ /([^\n^\r^\t]+)/;
  $crsctl = $1;
     
  # Verify if the env is either GI or SIHA
  $issiha = asmcmdafd_is_siha();

  if ($issiha)
  {
    $crsmode = "has";
  }
  else
  {
    $crsmode = "crs";
  }

  if ($action eq "start")
  {
    # start OHASD 
    $crsctlcmd = "$crsctl start $crsmode -noautostart";
    asmcmdshare_trace(3, "NOTE: Starting OHASD... ", 'y', 'n');
    $cmdout = 4123;
  }
  if ($action eq "stop")
  {
    # stop OHASD 
    $crsctlcmd = "$crsctl stop $crsmode -f";
    asmcmdshare_trace(3, "NOTE: Stopping OHASD... ", 'y', 'n');
    $cmdout = 4133;
  }
  if ($action eq "check")
  {
    # check OHASD 
    asmcmdshare_trace(3, "NOTE: Checking the cluster status.. ", 'y', 'n');
    $crsctlcmd = "$crsctl check has";
    $cmdout = 4638;
  }

  asmcmdshare_runcmd($crsctlcmd, \@lines, 1, 0);
  
  foreach $line (@lines)
  {
    if($line =~ /([^\d]+)([^:]+)/)
    { 
      $status = $2;
      if(defined($status))
      {
        # CRS-4123: Oracle High Availability Services has been started.
        # CRS-4133: Oracle High Availability Services has been stopped.
        # CRS-4638: Oracle High Availability Services is online
        if($status eq $cmdout)
        {
          # Successfully started or stopped OHASD OR OHASD is online.
          return 1;
        }
      }
    }
  }
  # Failed to start or stop OHASD
  asmcmdshare_trace(3, "FAIL: Failed to $action OHASD", 'y', 'n');
  asmcmdshare_trace(3, "$status", 'y', 'n');
  return 0;
}

########
# NAME
#   asmcmdafd_modify_resource
#
# DESCRIPTION
#   This function will modify the dependencies of CSSD resources
#   ora.cssd and ora.cssdmonitor
#   SIHA - ora.cssd(START and STOP)
#   GI   - ora.cssd(STOP) and ora.cssdmonitor(START)
#
# PARAMETERS
#   add    - add ora.driver.afd dependency in cssd resource
#   delete - delete ora.driver.afd dependency from cssd resource
#
# RETURNS
#   1 if successfully modified ; 0 otherwise.
########
sub asmcmdafd_modify_resource
{
  my ($action) = @_;
  my (@eargs);
  my $notExist = 0;
  my $status;
  my $crsctlcmd;
  my (@cssdlines);
  my (@cssdmonlines);
  my ($line);
  my (@buf);
  my ($attr) = "";
  my ($resName) = "ora.driver.afd";
  my $issiha;

  my $crsctl = "$ENV{'ORACLE_HOME'}/bin/crsctl";
  #The path in WIN is ORACLE_HOME/bin/crsctl.exe
  $crsctl .= ".exe" if($^O =~ /win/i);

  # Make sure the crsctl binary exists and can be executed. 
  if (! -x $crsctl)
  {
    @eargs = ($crsctl);
    asmcmdshare_error_msg(8313, \@eargs);
    return 0;
  }

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

  # Verify if the env is either GI or SIHA
  $issiha = asmcmdafd_is_siha();

  # First read the resource dependencies
  $crsctlcmd = "$crsctl stat res ora.cssd -init -f";

  asmcmdshare_runcmd($crsctlcmd, \@cssdlines, 1, 0);
  if (!$issiha)
  {
    $crsctlcmd = "$crsctl stat res ora.cssdmonitor -init -f";
    asmcmdshare_runcmd($crsctlcmd, \@cssdmonlines, 1, 0);
  }
  
  if ($issiha)
  {
    # incase of SIHA modify ora.cssd resource
    foreach $line (@cssdlines)
    {
      if (($line =~ /START_DEPENDENCIES/) || ($line =~ /STOP_DEPENDENCIES/))
      {
        my $hard = "";
        my $weak = "";
        my $pullup = "";
        if ($line =~ /(.*)(hard\(.*?\))(.*)/)
        {
          $hard = $2;
        }
        if ($line =~ /(.*)(weak?\(.*?\))(.*)/)
        {
          $weak = $2;
        }
        if ($line =~ /(.*)(pullup?\(.*?\))(.*)/)
        {
          $pullup = $2;
        }
  
        if ($action eq "add")
        {
          if ($line =~ /START_DEPENDENCIES/)
          {
            if ($hard)
            {
              $hard =~ s/\)/,ora.driver.afd\)/;
            }
            else
            {
              $hard = "hard(ora.driver.afd)";
            }
            $attr = ("\"START_DEPENDENCIES=\'".$weak.$hard.$pullup . "\'\"");
          }
          if ($line =~ /STOP_DEPENDENCIES/)
          {
            $hard =~ s/\)/,shutdown:ora.driver.afd\)/;
            $attr = ("\"STOP_DEPENDENCIES=\'".$weak.$hard.$pullup . "\'\"");
          }
          # Now, update the resource attribute
          if ($attr)
          {
            $crsctlcmd = "$crsctl modify res ora.cssd -attr ".$attr." -init";
            asmcmdshare_trace(3, "cssd res modify command : $crsctlcmd",
                              'y', 'n');
            asmcmdshare_runcmd($crsctlcmd, \@buf, 1, 0);
            if (@buf)
            {
              asmcmdshare_trace(3, "FAIL: Failed to modify ora.cssd resource" .
                                " attribute: " . join('', @buf), 'y', 'n');
              return 0;
            }
          }
        }
        elsif ($action eq "delete")
        {
          my $tmpattr;
          if ($line =~ /START_DEPENDENCIES/)
          {
            if ($hard)
            {
              $hard =~ s/\,?ora.driver.afd//g;
              if ($hard =~ /hard\(\)/)
              {
                $hard = "";
              }
            }
            $line =~ s/\,?ora.driver.afd//g;
            if ($line =~ /START_DEPENDENCIES=(.*)/)
            {
              $tmpattr = $1;
            }
            $attr = ("\"START_DEPENDENCIES=\'".$weak.$hard.$pullup . "\'\"");
          }
          if ($line =~ /STOP_DEPENDENCIES/)
          {
            $line =~ s/\,?shutdown:ora.driver.afd//g;
            if ($line =~ /STOP_DEPENDENCIES=(.*)/)
            {
              $tmpattr = $1;
            }
            $attr = ("\"STOP_DEPENDENCIES=\'".$tmpattr . "\'\"");
          }
          # Now, update the resource attribute
          if ($attr)
          {
            $crsctlcmd = "$crsctl modify res ora.cssd -attr ".$attr." -init";
            asmcmdshare_trace(3, "cssd res modify command : $crsctlcmd",
                              'y', 'n');

            asmcmdshare_runcmd($crsctlcmd, \@buf, 0, 0);
            if (@buf)
            {
              asmcmdshare_trace(3, "FAIL: Failed to modify ora.cssd resource".
                                " attribute: " . join('', @buf), 'y', 'n');
              return 0;
            }
          }
        }
      }
    }
    asmcmdshare_trace(3, "NOTE: Modified ora.cssd res attributes", 'y', 'n');
  }
  else
  {
    # incase of GI modify ora.cssd and ora.cssdmonitor resources
    foreach $line (@cssdlines)
    {
      if ($line =~ /STOP_DEPENDENCIES/)
      {
        my $hard = "";
        my $weak = "";
        my $pullup = "";
        if ($line =~ /(.*)(hard\(.*?\))(.*)/)
        {
          $hard = $2;
        }
        if ($line =~ /(.*)(weak?\(.*?\))(.*)/)
        {
          $weak = $2;
        }
        if ($line =~ /(.*)(pullup?\(.*?\))(.*)/)
        {
          $pullup = $2;
        }

        if ($action eq "add")
        {
          $hard =~ s/\)/,shutdown:ora.driver.afd\)/;
          $attr = ("\"STOP_DEPENDENCIES=\'".$weak.$hard.$pullup . "\'\"");
          # Now, update the resource attribute
          if ($attr)
          {
            $crsctlcmd = "$crsctl modify res ora.cssd -attr ".$attr." -init";
            asmcmdshare_trace(3, "cssd res modify command : $crsctlcmd",
                              'y', 'n');

            asmcmdshare_runcmd($crsctlcmd, \@buf, 0, 0);
            if (@buf)
            {
              asmcmdshare_trace(3, "FAIL: Failed to modify ora.cssd resource" .
                                " attribute: " . join('', @buf), 'y', 'n');
              return 0;
            }
          }
        }
        elsif ($action eq "delete")
        {
          my $tmpattr;
          if ($line =~ /STOP_DEPENDENCIES/)
          {
            $line =~ s/\,?shutdown:ora.driver.afd//g;
            if ($line =~ /STOP_DEPENDENCIES=(.*)/)
            {
              $tmpattr = $1;
            }
            $attr = ("\"STOP_DEPENDENCIES=\'".$tmpattr . "\'\"");
          }
          # Now, update the resource attribute
          if ($attr)
          {
            $crsctlcmd = "$crsctl modify res ora.cssd -attr ".$attr." -init";
            asmcmdshare_trace(3, "cssd res modify command : $crsctlcmd",
                              'y', 'n');

            asmcmdshare_runcmd($crsctlcmd, \@buf, 0, 0);
            if (@buf)
            {
              asmcmdshare_trace(3, "FAIL: Failed to modify ora.cssd resource".
                                " attribute: " . join('', @buf), 'y', 'n');
              return 0;
            }
          }
        }
        last;
      }
    }
    foreach $line (@cssdmonlines)
    {
      if ($line =~ /START_DEPENDENCIES/)
      {
        my $hard = "";
        my $weak = "";
        my $pullup = "";
        if ($line =~ /(.*)(hard\(.*?\))(.*)/)
        {
          $hard = $2;
        }
        if ($line =~ /(.*)(weak?\(.*?\))(.*)/)
        {
          $weak = $2;
        }
        if ($line =~ /(.*)(pullup?\(.*?\))(.*)/)
        {
          $pullup = $2;
        }

        if ($action eq "add")
        {
          $hard =~ s/\)/,ora.driver.afd\)/;
          if (!$hard)
          {
            $hard = "hard(ora.driver.afd)";
          }
          $attr = ("\"START_DEPENDENCIES=\'".$weak.$hard.$pullup . "\'\"");
          # Now, update the resource attribute
          if ($attr)
          {
            $crsctlcmd = "$crsctl modify res ora.cssdmonitor -attr ".$attr.
                          " -init";
            asmcmdshare_trace(3, "cssdmonitor res modify command : $crsctlcmd",
                              'y', 'n');

            asmcmdshare_runcmd($crsctlcmd, \@buf, 0, 0);
            if (@buf)
            {
              asmcmdshare_trace(3, "FAIL: Failed to modify ora.cssdmonitor " .
                                "resource attribute: " . join('', @buf), 
                                'y', 'n');
              return 0;
            }
          }
        }
        elsif ($action eq "delete")
        {
          my $tmpattr;
          if ($line =~ /START_DEPENDENCIES/)
          {
            $line =~ s/\,?ora.driver.afd//g;
            if ($line =~ /START_DEPENDENCIES=.*\(\)/)
            {
              $attr = ("\"START_DEPENDENCIES=\"");
            }
            elsif ($line =~ /START_DEPENDENCIES=(.*)/)
            {
              $tmpattr = $1;
              $attr = ("\"START_DEPENDENCIES=\'".$tmpattr . "\'\"");
            }
          }
          # Now, update the resource attribute
          if ($attr)
          {
            $crsctlcmd = "$crsctl modify res ora.cssdmonitor -attr ".$attr.
                          " -init";
            asmcmdshare_trace(3, "cssdmonitor res modify command : $crsctlcmd",
                              'y', 'n');
            asmcmdshare_runcmd($crsctlcmd, \@buf, 0, 0);
            if (@buf)
            {
              asmcmdshare_trace(3, "FAIL: Failed to modify ora.cssdmonitor ".
                                "resource attribute: " . join('', @buf), 
                                'y', 'n');
              return 0;
            }
          }
        }
        last;
      }
    }
    asmcmdshare_trace(3, "NOTE: Modified ora.cssd and ora.cssdmonitor".
                      " resource attributes", 'y', 'n');
  }
  return 1;
}

########
# NAME
#   asmcmdafd_afd_resource_type
#
# DESCRIPTION
#   This function will add or remove or status check AFD OHASD resource type
#   ora.driver.afd.type
#   Keep consistent with oraafd.pm:actionASMDriverResource().
#
# PARAMETERS
#   add    - add the resource type in ohasd
#   delete - remove the resource type from ohasd
#   status - find the status of resource type from ohasd
#
# RETURNS
#   1 if resouce type doesn't exist or is added/removed; 0 otherwise.
########
sub asmcmdafd_afd_resource_type
{
  my ($action) = @_;
  my (@eargs);
  my $ORACLE_HOME = $ENV{'ORACLE_HOME'};
  my $type = "ora.driver.afd.type";
  my $baseType = "ora.daemon.type";
  my $templateFile = "driver.afd.type"; 
  my $CRS_HOME_TEMPLATE = catdir($ORACLE_HOME, "crs", "template");
  my $infile  = catfile($CRS_HOME_TEMPLATE, $templateFile);
  my $restypecmd;
  my @buf;
  my $notExist = 0;
  my $status;

  my $crsctl = "$ENV{'ORACLE_HOME'}/bin/crsctl";
  #The path in WIN is ORACLE_HOME/bin/crsctl.exe
  $crsctl .= ".exe" if($^O =~ /win/i);

  # Make sure the crsctl binary exists and can be executed. 
  if (! -x $crsctl)
  {
    @eargs = ($crsctl);
    asmcmdshare_error_msg(8313, \@eargs);
    return 0;
  }

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

  # First check the status of the resource type
  $restypecmd = "$crsctl stat type $type -init"; 
  asmcmdshare_runcmd($restypecmd, \@buf, 1, 0);

  if (!grep(/TYPE_NAME=ora.driver.afd.type/, @buf))
  { 
    #output: CRS-2560: Resource type 'ora.driver.afd.type' does not exist
    asmcmdshare_trace(3, "NOTE: ora.driver.afd.type res type doesn't exist",
                      'y', 'n');
    $notExist = 1;
  }
  # if action is 'status' then just send the status value
  if ($action eq "status")
  {
    return $notExist; 
  }
  # if resource type does not exist and action is 'add'
  if (scalar($notExist) > 0 && ($action eq "add"))
  {
    asmcmdshare_trace(3, "NOTE: Registering resource type ora.driver.afd.type",
                      'y', 'n');

    $restypecmd = "$crsctl add type $type -basetype $baseType " .
                   "-file $infile -init";

    asmcmdshare_runcmd($restypecmd, \@buf, 0, 0);

    if (@buf)
    {
      asmcmdshare_trace(3, "FAIL: Failed to add resource type".
                        " ora.driver.afd.type: " . join('', @buf), 'y', 'n');
      return 0;
    }
    else
    {
      asmcmdshare_trace(3, "NOTE: added resource type ora.driver.afd.type",
                        'y', 'n');
      return 1;
    }
  }

  # if resource type exist and action is 'delete'
  if ((scalar($notExist) == 0) && ($action eq "delete"))
  {
    asmcmdshare_trace(3, "NOTE: Deleting resource type ora.driver.afd.type",
                      'y', 'n');

    $restypecmd = "$crsctl delete type $type -init";
    asmcmdshare_runcmd($restypecmd, \@buf, 1, 0);

    if (@buf)
    {
      asmcmdshare_trace(3, "FAIL: Failed to delete resource type".
                        " ora.driver.afd.type: " . join('', @buf), 'y', 'n');
      return 0;
    }
    else
    {
      asmcmdshare_trace(3, "NOTE: deleted resource type ora.driver.afd.type",
                        'y', 'n');
      return 1;
    }
  }
  return 1;
}

########
# NAME
#   asmcmdafd_afd_resource
#
# DESCRIPTION
#   This function will add or remove or status check AFD OHASD resource
#   ora.driver.afd
#   Keep consistent with oraafd.pm:actionASMDriverResource().
#
# PARAMETERS
#   add    - add the resource 
#   delete - delete the resource 
#   status - find the status of resource
#
# RETURNS
#   1 if resouce doesn't exist or is added or removed; 0 otherwise.
########
sub asmcmdafd_afd_resource
{
  my ($action) = @_;
  my (@eargs);
  my (@lines);
  my (@buf);
  my ($crsctl);
  my ($crsctlcmd);
  my $notExist = 0;
  my $status;
  my $afd_attr;
  my $resName = "ora.driver.afd";
  my $resType = "ora.driver.afd.type";
  my $restypecmd;
  my ($issiha);
  my $ousr;
  my $ogrp;
  my $i;

  # Verify if the env is either GI or SIHA
  $issiha = asmcmdafd_is_siha();

  if (-e "$ENV{'ORACLE_HOME'}/crs/install/crsconfig_params")
  {
    unless (open(FD,"<$ENV{'ORACLE_HOME'}/crs/install/crsconfig_params"))
    {
       return 0;
    }
    @lines = <FD>;
    unless (close(FD))
    {
       return 0;
    }
    for($i = 0; $i<=$#lines; $i++)
    {
      if($lines[$i] =~ "ORACLE_OWNER=")
      {
        $ousr = $lines[$i];
        $ousr =~ /(.*\=)(.*)/i;
        $ousr = $2;
      }
      if($lines[$i] =~ "ORA_ASM_GROUP=")
      {
        $ogrp = $lines[$i];
        $ogrp =~ /(.*\=)(.*)/i;
        $ogrp = $2;
      }
    }
  }
  # if we can't retrieve oracle user and group then we cannot add/remove res.
  if (!$ousr && !$ogrp)
  {
    asmcmdshare_trace(3, "FAIL: Failed to retrieve Oracle owner & group",
                      'y', 'n');
    return 0;
  }

  $crsctl = "$ENV{'ORACLE_HOME'}/bin/crsctl";
  #The path in WIN is ORACLE_HOME/bin/crsctl.exe
  $crsctl .= ".exe" if($^O =~ /win/i);

  # Make sure the crsctl binary exists and can be executed. 
  if (! -x $crsctl)
  {
    @eargs = ($crsctl);
    asmcmdshare_error_msg(8313, \@eargs);
    return 0;
  }

  #untaint crsctl
  $crsctl =~ /([^\n^\r^\t]+)/;
  $crsctl = $1;
     
  # Check the existence of the AFD resource
  $crsctlcmd = "$crsctl stat res ora.driver.afd -init";

  asmcmdshare_trace(3, "NOTE: Checking existence of AFD resource",
                    'y', 'n');
  asmcmdshare_runcmd($crsctlcmd, \@buf, 1, 0);

  #if($buf =~ /([^\d]+)([^:]+)/)
  if (!grep(/NAME=ora.driver.afd/, @buf))
  { 
    #output: CRS-2613: Could not find resource 'ora.driver.afd'.
    asmcmdshare_trace(3, "NOTE: ora.driver.afd resource doesn't exist",
                      'y', 'n');
    $notExist = 1;
  }

  # if resource doesn't exist and action is 'status'
  if ($action eq "status")
  {
    return $notExist;
  }
  # if resource doesn't exist and action is 'add'
  if (($notExist == 1) && ($action eq "add"))
  {
    # add AFD resource type if it does not exist.
    if (!asmcmdafd_afd_resource_type("add"))
    {
      asmcmdshare_trace(3, "FAIL: Failed to add AFD resource type", 'y', 'n');
      return 0;
    }

    if ($issiha)
    {
      $afd_attr = ("ACL=\'owner:$ousr:rwx,pgrp:$ogrp:r-x,other::r--," .
                   "user:$ousr:r-x\',ACTIONS=\'afdscan,user:$ousr ".
                               "afdds,user:$ousr ".
                               "afdtool,user:$ousr ".
                               "afdstate,user:$ousr\'");
    }
    else
    {
      $afd_attr = ("ACL=\'owner:root:rwx,pgrp:$ogrp:r-x,other::r--," .
                   "user:$ousr:r-x\',ACTIONS=\'afdscan,user:$ousr ".
                               "afdds,user:$ousr ".
                               "afdtool,user:$ousr afdstate,user:$ousr\'");
    }

    $crsctlcmd = "$crsctl add resource $resName -attr \"". $afd_attr .
                  "\" -type $resType -init";
    asmcmdshare_runcmd($crsctlcmd, \@buf, 0, 0);

    if (@buf)
    {
      # resource add failed
      asmcmdshare_trace(3, "FAIL: Failed to add AFD resource: " . 
                        join('', @buf), 'y', 'n');
      return 0;
    }
    else
    {
      asmcmdshare_trace(3, "NOTE: Added AFD resource", 'y', 'n');
      return 1;
    }
  }
  # if resource exists and action is 'delete'
  if (($notExist == 0) && ($action eq "delete"))
  {
    my (@lines);
    my ($line);
    # stop AFD resource
    $crsctlcmd = ("$crsctl stop resource $resName -init");

    asmcmdshare_runcmd($crsctlcmd, \@lines, 0, 0);

    foreach $line (@lines)
    {
      if($line =~ /([^\d]+)([^:]+)/)
      { 
        $status = $2;
        if(defined($status))
        {
          #CRS-2677: Stop of 'ora.driver.afd' on 'slc05gkm' succeeded
          #CRS-2500: Cannot stop resource 'ora.driver.afd' as it is not running
          if (($status eq 2677) || ($status eq 2500))
          {
            # Successfully stopped AFD resource or it is not running.
            asmcmdshare_trace(3, "NOTE: AFD resource stopped or not running",
                              'y', 'n');
            $status = 1;
            last;
          }
        }
      }
    }
    if ((defined($status)) && ($status != 1))
    {
      # Failed to stop AFD resource.
      asmcmdshare_trace(3, "FAIL: Failed to stop AFD resource", 'y', 'n');
      return 0;
    }

    $crsctlcmd = ("$crsctl delete resource $resName -init");
    asmcmdshare_runcmd($crsctlcmd, \@buf, 0, 0);

    if (@buf)
    {
      # resource delete failed
      asmcmdshare_trace(3, "FAIL: Failed to delete AFD resource : " . 
                        join('', @buf), 'y', 'n');
      return 0;
    }
    else
    {
      asmcmdshare_trace(3, "NOTE: Deleted AFD resource", 'y', 'n');
      return 1;
    }
    # delete AFD resource type
    if (!asmcmdafd_afd_resource_type("delete"))
    {
      asmcmdshare_trace(3, "FAIL: Failed to delete AFD resource type",
                        'y', 'n');
      return 0;
    }
  }
  return 1;
}

########
# NAME
#   asmcmdafd_is_cluster_down
#
# DESCRIPTION
#   This function checks if clusterware is shutdown on the local system
#
# PARAMETERS
#   NONE 
#
# RETURNS
#   1 if clusterware is down ; 0 otherwise.
########
sub asmcmdafd_is_cluster_down
{
  my ($crsctl);
  my (@buf);
  my ($status);
  my (@eargs);

  $crsctl = "$ENV{'ORACLE_HOME'}/bin/crsctl";
  #The path in WIN is ORACLE_HOME/bin/crsctl.exe
  $crsctl .= ".exe" if($^O =~ /win/i);

  # Make sure the crsctl binary exists and can be executed. 
  if (! -x $crsctl)
  {
    @eargs = ($crsctl);
    asmcmdshare_error_msg(8313, \@eargs);
    return 0;
  }

  #untaint crsctl
  $crsctl =~ /([^\n^\r^\t]+)/;
  $crsctl = $1;
     
  asmcmdshare_runcmd("$crsctl check has", \@buf, 1, 0);

  # Check for the number at CRS-xxxx in the output.
  if((@buf) && ($buf[0] =~ /([^\d]+)([^:]+)/))
  {
    $status = $2;
    if(defined($status))
    {
      if(($status eq 4639) || ($status eq 4047))
      {
        #output: CRS-4639: Could not contact Oracle High Availability Services
        #output: CRS-4047: No Oracle Clusterware components configured.
        asmcmdshare_trace(3, "NOTE: Status of clusterware stack : Not online",
                          'y', 'n');
        return 1;
      }
    }
    else
    {
      asmcmdshare_error_msg(8309, undef);
      return 0;
    }
  }
  return 0;
} # end asmcmdafd_is_cluster_down

########
# NAME
#   asmcmdafd_get_asmdiskstr_fromprofile
#
# DESCRIPTION
#   This function returns asm_diskstring value from gpnp profile.
#
# PARAMETERS
#   NONE 
#
# RETURNS
#   asm_diskstring value if available ; "" otherwise.
########
sub asmcmdafd_get_asmdiskstr_fromprofile
{
  my ($kfod);
  my (@buf);
  my (@eargs);

  # if unable to query, return empty string
  my $asmdiskstr = "";

  my ($asm_discstr) = "";
 
  $kfod = catfile($ENV{'ORACLE_HOME'}, 'bin', 'kfod');
  $kfod .= ".exe" if($^O =~ /win/i);
  # Make sure the kfod binary exists and can be executed. 
  if (! -x $kfod)
  {
    @eargs = ($kfod);
    asmcmdshare_error_msg(9515, \@eargs);
    return;
  }

  asmcmdshare_runcmd("$kfod op=GPNPDSTR nohdr=true", \@buf, 0, 0);
    
  foreach my $line (@buf)
  {
    $asmdiskstr = $line;
  }

  # kfod returns one line o/p for asm_diskstring.
  # Last line contains the asm_diskstring.
  #
  # kfod may return 0 but asm_diskstring may
  # be 'Not Set' or 'Not Available'.
  #
  # If asm_diskstring was never setup at profile creation
  # time or later, the default value in profile.xml is
  # "++no-value-at-profile-creation--never-updated-through-ASM++"
  # This special string also needs to be handled well.
  # For those, return empty string.
  #
  # Empty string is interpreted as default discovery string
  # by afdboot/afdtool.
  #
  chomp($asmdiskstr);
  if( ($asmdiskstr eq "Not Set") ||
      ($asmdiskstr eq "Not Available") ||
      ($asmdiskstr eq "++no-value-at-profile-creation--never-updated-through-ASM++") )
  {
    $asmdiskstr = "";
  }

  asmcmdshare_trace(3, "Retrieved asm disk string from gpnp : \'$asmdiskstr\'",
                    'y', 'n');
  return $asmdiskstr;
} # end asmcmdafd_get_asmdiskstr_fromprofile

########
# NAME
#   asmcmdafd_isSUSELinux
#
# DESCRIPTION
#   This function checks if the node is running SUSE Linux
#
# PARAMETERS
#   NONE 
#
# RETURNS
#   1 if the system is SUSE Linux ; 0 otherwise.
########
sub asmcmdafd_isSUSELinux
{
  my @buf;

  if($^O =~ /linux/i)
  {
    if (!asmcmdshare_runcmd("/bin/rpm -q sles-release", \@buf, 1, 1))
    {
      # rpm command succeeded.
      if (defined($buf[0]) and !($buf[0] =~ /not installed/))
      {
        return 1;
      }
    }
  }
  return 0;
} # end asmcmdafd_isSUSELinux

########
# NAME
#   asmcmdafd_clean_rcdirs
#
# DESCRIPTION
#   This function removed AFD init start or kill scripts from rc directories.
#
# PARAMETERS
#   $file - name of the init script file ("afd" in this case)
#
# RETURNS
#   1 if no error; 0 otherwise.
########
sub asmcmdafd_clean_rcdirs
{
  my $file = $_[0];
  my @cmd;
  my @buf;

  if (!$file)
  {
    return 0;
  }

  #remove old ones
  if ($RCALLDIR)
  {
    my ($rc, $rcStartFile, $rcKillFile, $rcKillOldFile, $rcKillOld2File);
    my @RCALLDIRLIST = split (/ /, $RCALLDIR);

    foreach $rc (@RCALLDIRLIST)
    {
      if ($RC_START)
      {
        $rcStartFile = catfile ($rc, "$RC_START" . "$file");
        @cmd = "rm $rcStartFile 2>&1";
        eval
        {
          @buf = `@cmd`;
        };
      }
      if ($RC_KILL)
      {
        $rcKillFile = catfile ($rc, $RC_KILL . $file);
        @cmd = "rm $rcKillFile 2>&1";
        eval
        {
          @buf = `@cmd`;
        };
      }

      if ($RC_KILL_OLD)
      {
        $rcKillOldFile = catfile ($rc, $RC_KILL_OLD . $file);
        @cmd = "rm $rcKillOldFile 2>&1";
        eval
        {
          @buf = `@cmd`;
        };
      }
      if ($RC_KILL_OLD2)
      {
        $rcKillOldFile = catfile ($rc, $RC_KILL_OLD . $file);
        @cmd = "rm $rcKillOldFile 2>&1";
        eval
        {
          @buf = `@cmd`;
        };
      }
    }
  }
  return 1;
} # end asmcmdafd_clean_rcdirs

########
# NAME
#   asmcmdafd_afd_install_initd
#
# DESCRIPTION
#   This function is used to run install_initd command to create afd links
#   under rc directories. Only for SUSE Linux.
#
# PARAMETERS
#   NONE
#
# RETURNS
#   NONE
########
sub asmcmdafd_afd_install_initd
{
  # call install_initd if it's SUSE Linux
  if (asmcmdafd_isSUSELinux())
  {
    my $afd    = catfile($INITD, "afd");
    my $initd  = catfile('/usr', 'lib', 'lsb', 'install_initd');
    my @buf = "";
    my $cmd;

    $cmd = "$initd $afd";
    # Not checking for the return value
    asmcmdshare_runcmd("$cmd", \@buf, 1, 1);
    for (@buf)
    {
      s/`//g;
    }
    if (@buf)
    {
      asmcmdshare_trace(3, "NOTE: install_initd output : @buf", 'y', 'n');
    }
  }
}

########
# NAME
#   asmcmdafd_afd_remove_initd
#
# DESCRIPTION
#   This function is used to run remove_initd command to remove afd links
#   from rc directories. Only for SUSE Linux.
#
# PARAMETERS
#   NONE
#
# RETURNS
#   NONE
########
sub asmcmdafd_afd_remove_initd
{
  # call remove_initd if it's SUSE Linux
  if (asmcmdafd_isSUSELinux())
  {
    my $afd    = catfile($INITD, "afd");
    my $initd  = catfile('/usr', 'lib', 'lsb', 'remove_initd');
    my @buf = "";
    my $cmd;

    $cmd = "$initd $afd";
    # Not checking for the return value
    asmcmdshare_runcmd("$cmd", \@buf, 1, 1);
    for (@buf)
    {
      s/`//g;
    }
    if (@buf)
    {
      asmcmdshare_trace(3, "NOTE: remove_initd output : @buf", 'y', 'n');
    }
  }
}

########
# NAME
#   asmcmdafd_copy_to_rcdirs
#
# DESCRIPTION
#   This function copies AFD init script to system init directory and also 
#   copies AFD init start or kill scripts from rc directories.
#
# PARAMETERS
#   $sourcefile - init script file to copy (say "GI_home/crs/init/afd")
#   $destfile   - name of the init file to copy as (say "/etc/init.d/afd")
#
# RETURNS
#   1 if no error; 0 otherwise.
########
sub asmcmdafd_copy_to_rcdirs
{
  my $sourcefile = $_[0];
  my $destfile   = $_[1];
  my @buf;
  my @cmd;

  if (!($sourcefile))
  {
    asmcmdshare_trace(3, "FAIL: Failed to copy AFD init scripts; no srcfile",
                      'y', 'n');
    return 0;
  }

  if (! -e $sourcefile)
  {
    asmcmdshare_trace(3, "FAIL: Failed to copy AFD init scripts to rcdirs",
                      'y', 'n');
    return 0;
  }

  # Copy to init dir
  copy ($sourcefile, catfile ($INITD, $destfile)) || return 0;
  @cmd = "chmod 0755 " . catfile($INITD, $destfile);
  eval
  {
    @buf = `@cmd`;
  };

  if (asmcmdafd_isSUSELinux())
  {
    # for SUSE Linux, do not create link to the file in the init dir
    return 1;
  }

  # Create a link to the file in the init dir
  my @RCSDIRLIST = split (/ /, $RCSDIR);
  foreach my $rc (@RCSDIRLIST)
  {
    @cmd = "rm $rc/$RC_START$destfile 2>&1";
    eval
    {
      @buf = `@cmd`;
    };
    symlink (catfile($INITD, $destfile),
             catfile($rc, "$RC_START$destfile")) || return 0;
  }
  my @RCKDIRLIST = split (/ /, $RCKDIR);
  foreach my $rc (@RCKDIRLIST)
  {
    @cmd = "rm $rc/$RC_KILL$destfile 2>&1";
    eval
    {
      @buf = `@cmd`;
    };
    symlink(catfile($INITD, $destfile),
            catfile($rc, "$RC_KILL$destfile")) || return 0;
  }

  asmcmdshare_trace(3, "Copied AFD init scripts to rcdirs", 'y', 'n');
  return 1;
} # end asmcmdafd_copy_to_rcdirs

########
# NAME
#   asmcmdafd_rm_afdinit_init
#
# DESCRIPTION
#   This function removes AFD init file (say "/etc/init.d/afd") from the node.
#
# PARAMETERS
#   NONE
#
# RETURNS
#   NONE
########
sub asmcmdafd_rm_afdinit_init
{
  my $afdfile = catfile($INITD, "afd");
  if(-e $afdfile)
  {
    asmcmdafd_afd_remove_initd();
    unlink($afdfile);
  }
  return;
} # end asmcmdafd_rm_afdinit_init

########
# NAME
#   asmcmdafd_rm_afdinit_rclevel
#
# DESCRIPTION
#   This function is used to clean AFD init files or scripts from the node.
#
# PARAMETERS
#   NONE
#
# RETURNS
#   NONE
########
sub asmcmdafd_rm_afdinit_rclevel
{
  asmcmdafd_clean_rcdirs ("afd");
  return;
} # end asmcmdafd_rm_afdinit_rclevel

########
# NAME
#   asmcmdafd_copy_afdinit
#
# DESCRIPTION
#   This function is used to copy AFD init files or scripts to system dirs.
#
# PARAMETERS
#   NONE
#
# RETURNS
#   1 if no errors; 0 otherwise.
########
sub asmcmdafd_copy_afdinit
{
  my $INITDIR        = catfile ($ENV{'ORACLE_HOME'}, "crs", "init");
  my $srv            = "afd";
  my $INITDIR_SRV    = catfile ($INITDIR, $srv);

  asmcmdshare_trace(3, "Creating AFD init scripts", 'y', 'n');
  #if SUSE linux, copy the afd.sles to the rcdirs
  if (asmcmdafd_isSUSELinux())
  {
    $INITDIR_SRV = catfile ($INITDIR, "$srv.sles");
  }

  asmcmdafd_copy_to_rcdirs ($INITDIR_SRV, "afd") || return 0;
  asmcmdafd_afd_install_initd();
  return 1;
} # end asmcmdafd_copy_afdinit

########
# NAME
#   asmcmdafd_update_afd_conf
#
# DESCRIPTION
#   This function creates oracleafd.conf file in the system directory and adds
#   afd_diskstring parameter and with its value.
#
# PARAMETERS
#   NONE
#
# RETURNS
#   1 if no errors; 0 otherwise.
########
sub asmcmdafd_update_afd_conf
{
  my (@plines);
  my (@lines);
  my ($i);
  my ($line);
  my ($ousr);
  my ($ogrp);
  my ($uid);
  my ($gid);
  my ($afdds);

  asmcmdshare_trace(3, "Updating oracleafd.conf", 'y', 'n');

  if (-e "$ENV{'ORACLE_HOME'}/crs/install/crsconfig_params")
  {
    unless (open(FD,"<$ENV{'ORACLE_HOME'}/crs/install/crsconfig_params"))
    {
      asmcmdshare_trace(3, "FAIL: crsconfig_params file does not exist",
                        'y', 'n');
      return 0;
    }
    @plines = <FD>;
    unless (close(FD))
    {
      return 0;
    }
    for($i = 0; $i<=$#plines; $i++)
    {
      if($plines[$i] =~ "ORACLE_OWNER=")
      {
        $ousr = $plines[$i];
        $ousr =~ /(.*\=)(.*)/i;
        $ousr = $2;
      }
      if($plines[$i] =~ "ORA_ASM_GROUP=")
      {
        $ogrp = $plines[$i];
        $ogrp =~ /(.*\=)(.*)/i;
        $ogrp = $2;
      }
    }
  }

  # Update oracleafd.conf with the default discovery string which is blank ''.
  # "afd_diskstring" is the key in oracleafd.conf .
  my $afd_conf = "/etc/oracleafd.conf";
  if($^O =~ /win/i)
  {
    ($afd_conf) = "$ENV{SYSTEMROOT}\\system32\\drivers\\oracleafd.conf";
  }
  
  # get asm_diskstring and remove AFD:* from it, if present.
  $afdds = asmcmdafd_get_asmdiskstr_fromprofile();
  $afdds =~ s/(^AFD:.*?,)//g;
  $afdds =~ s/(,AFD:.*?,)/,/g;
  $afdds =~ s/(,AFD:.*$)//g;
  if ($afdds =~ /AFD:/)
  {
    $afdds = '';
  }

  if(-e $afd_conf)
  {
    unless (open(FD,"<$afd_conf"))
    {
      return 0;
    }
    @lines = <FD>;
    unless (close(FD))
    {
      return 0;
    }
    for($i = 0; $i<=$#lines; $i++)
    {
      if($lines[$i] =~ /afd_diskstring/)
      {
        $lines[$i] = "afd_diskstring='".$afdds."'\n";
        last;
      }
    }
  }
  else
  {
    $lines[0] = "afd_diskstring='".$afdds."'\n";
  }

  # Write to oracleafd.conf
  unless (open(FD,">$afd_conf"))
  {
    return 0;
  }
  foreach $line (@lines)
  {
    print FD $line;
  }
  unless (close(FD))
  {
    return 0;
  }

  # Set appropriate permissions on /etc/oracleafd.conf file
  if ($ousr && $ogrp)
  {
    $uid = getpwnam ($ousr);
    $gid = getgrnam ($ogrp);

    chown($uid, $gid, "$afd_conf");
  }
  chmod(0664, "$afd_conf");

  asmcmdshare_trace(3, "Created $afd_conf", 'y', 'n');
  return 1;
} # end asmcmdafd_update_afd_conf

########
# NAME
#   asmcmdafd_handle_asmlib
#
# DESCRIPTION
#   This function verifies and removes ASMLib if exists in the system.
#
# PARAMETERS
#   NONE 
#
# RETURNS
#   1 if ASMLib is removed, 2 in case of an error ; 0 otherwise.
########
sub asmcmdafd_handle_asmlib
{
  my ($asmlib);
  my ($asmlibexists) = 0;
  my ($afdtool);
  my (@buf);

  if (!($^O =~ /linux/i))
  {
    return $asmlibexists;
  }

  if (-e "/opt/oracle/extapi")
  {
    open (ASMLIB, "find /opt/oracle/extapi/ | grep libasm.so |");
    while ($asmlib = <ASMLIB>)
    {
      $asmlibexists = 1;
      chomp($asmlib);
      unlink("$asmlib");
    } 
    close(ASMLIB);
  }
  open (ASMLIB, "/sbin/lsmod | grep oracleasm |");
  while ($asmlib = <ASMLIB>)
  {
    $asmlibexists = 1;

    asmcmdshare_runcmd("/sbin/rmmod oracleasm", \@buf, 0, 1);

    if (@buf)
    {
      asmcmdshare_trace(3, "NOTE: unload ASMLIB failed: " . join('', @buf) .
                        "try second way", 'y', 'n');
      if (-e "/etc/init.d/oracleasm")
      {
        asmcmdshare_runcmd("/etc/init.d/oracleasm disable", \@buf, 0, 1);
      }
      if (-e "/usr/sbin/oracleasm")
      {
        asmcmdshare_runcmd("/usr/sbin/oracleasm exit", \@buf, 0, 1);
      }
      if (@buf)
      {
        asmcmdshare_trace(3, "FAIL: Failed to unload ASMLib driver: " . 
                          join('', @buf), 'y', 'n');
        return 2;
      }
    }
    else
    {
      return 1;
    }
  } 
  close(ASMLIB);

  return $asmlibexists;
}

########
# NAME
#   asmcmdafd_rescan_afd
#
# DESCRIPTION
#   This function rescans AFD disks on the local system
#
# PARAMETERS
#   NONE 
#
# RETURNS
#   1 if AFD disks are rescanned; 0 otherwise.
########
sub asmcmdafd_rescan_afd
{
  my ($rescanstr) = @_;
  my (@eargs);
  my (@buf);
  my ($afdtool);
  my ($afdtoolrescan);

  $afdtool = "$ENV{'ORACLE_HOME'}/bin/afdtool";
  #The path in WIN is ORACLE_HOME/bin/afdtool.exe
  $afdtool .= ".exe" if($^O =~ /win/i);
  # Make sure the afdtool binary exists and can be executed. 
  if (! -x $afdtool)
  {
    @eargs = ($afdtool);
    asmcmdshare_error_msg(9516, \@eargs);
    return 0;
  }

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

  if ($rescanstr)
  {
    asmcmdshare_trace(3, "NOTE: Rescanning AFD disks; diskstring:'$rescanstr'",
                    'y', 'n');
    $afdtoolrescan = "$afdtool -rescan '$rescanstr'";
  }
  else
  {
    asmcmdshare_trace(3, "NOTE: Rescanning AFD disks; using afd_diskstring.",
                      'y', 'n');
    $afdtoolrescan = "$afdtool -rescan";
  }

  asmcmdshare_runcmd($afdtoolrescan, \@buf, 1, 0);
  
  if (asmcmdafd_am_root())
  {
    asmcmdafd_update_afddisks();
  }
  if (grep(/Rescanned/i, @buf))
  {
    return 1;
  }
  else
  {
    return 0;
  }
} #end asmcmdafd_rescan_afd

########
# NAME
#   asmcmdafd_refresh_afd
#
# DESCRIPTION
#   This function refreshes AFD disks on the local system
#
# PARAMETERS
#   NONE 
#
# RETURNS
#   1 if AFD disks are refreshed; 0 otherwise.
########
sub asmcmdafd_refresh_afd
{
  my (@eargs);
  my (@buf);
  my ($afdtool);
  my ($afdtoolrefresh);

  $afdtool = "$ENV{'ORACLE_HOME'}/bin/afdtool";
  #The path in WIN is ORACLE_HOME/bin/afdtool.exe
  $afdtool .= ".exe" if($^O =~ /win/i);
  # Make sure the afdtool binary exists and can be executed. 
  if (! -x $afdtool)
  {
    @eargs = ($afdtool);
    asmcmdshare_error_msg(9516, \@eargs);
    return 0;
  }

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

  asmcmdshare_trace(3, "NOTE: Refreshing AFD disks; using afd_diskstring.",
                      'y', 'n');
  $afdtoolrefresh = "$afdtool -refresh";

  asmcmdshare_runcmd($afdtoolrefresh, \@buf, 1, 0);
  
  if (asmcmdafd_am_root())
  {
    asmcmdafd_update_afddisks();
  }
  if (grep(/Refreshed/i, @buf))
  {
    return 1;
  }
  else
  {
    return 0;
  }
} #end asmcmdafd_refresh_afd

########
# NAME
#   asmcmdafd_afdroot
#
# DESCRIPTION
#   This function installs and loads AFD driver on the local system OR
#                 uninstalls AFD from the local system
#
# PARAMETERS
#   $action 
#
# RETURNS
#   1 if AFD is installed and loaded ; 0 otherwise.
########
sub asmcmdafd_afdroot
{
  my ($action) = @_;
  my (@eargs);
  my ($afdroot);
  my (@lines);
  my ($line);
  my ($status);
  my ($cmdout1);
  my ($cmdout2);

  $afdroot = "$ENV{'ORACLE_HOME'}/bin/afdroot";
  #The path in WIN is ORACLE_HOME/bin/afdroot.bat
  $afdroot .= ".bat" if($^O =~ /win/i);
  # Make sure the afdroot binary exists and can be executed. 
  if (! -x $afdroot)
  {
    @eargs = ($afdroot);
    asmcmdshare_error_msg(9517, \@eargs);
    return 0;
  }

  #untaint afdroot
  $afdroot =~ /([^\n^\r^\t]+)/;
  $afdroot = $1;
     
  if ($action eq "install")
  {
    # Install AFD 
    asmcmdshare_trace(3, "NOTE: Installing AFD... ", 'y', 'n');
    # AFD-638: AFD installation correctness verified.
    $cmdout1 = 638;
    # non-existing message
    $cmdout2 = 999;
  }
  if ($action eq "uninstall")
  {
    # uninstall AFD
    asmcmdshare_trace(3, "NOTE: Uninstalling AFD... ", 'y', 'n');
    #AFD-635: Previous AFD components successfully removed.
    $cmdout1 = 635;
    #AFD-633: No AFD installation detected.
    $cmdout2 = 633;
  }

  if (!asmcmdshare_runcmd("$afdroot $action", \@lines, 1, 0))
  {
    foreach $line (@lines)
    {
      print $line;
      if($line =~ /([^\d]+)([^:]+)/)
      { 
        $status = $2;
        if(defined($status))
        {
          if(($status eq $cmdout1) || ($status eq $cmdout2))
          {
            # Successfully installed AFD.
            asmcmdshare_trace(3, "NOTE: Successfully $action". "ed AFD",
                              'y', 'n');
            return 1;
          }
        }
      }
    }
  }
  #asmcmdshare_print("@lines\n");
  asmcmdshare_print(join('', @lines));
  asmcmdshare_trace(3, "FAIL: Failed to $action AFD", 'y', 'n');
  return 0;
} #end asmcmdafd_afdroot

########
# NAME
#   asmcmdafd_create_logdir
#
# DESCRIPTION
#   This function creates log directory $ORACLE_HOME/log/$HOST/client.
#   Call this function only when the command is run as root user.
#
# PARAMETERS
#
# RETURNS
#   1 if successfully created the log directory; 0 otherwise.
########
sub asmcmdafd_create_logdir
{
  my ($oraclebin) = "$ENV{'ORACLE_HOME'}/bin/oracle";
  my ($host) = hostname;
  my ($logdir);
  my ($giusr) = "";
  my ($cmd);
  my ($ret) = 0;
  my (@buf);

  # Windows Oracle always runs in admin mode
  if($^O =~ /win/i)
  {
    return 1;
  }

  # trim domain (ex: .us.oracle.com) from hostname
  $host =~ s/\..*//;
  $logdir = "$ENV{'ORACLE_HOME'}/log/$host/client";

  if(!(-e $logdir))
  {
    if (asmcmdafd_am_root())
    {
      if ($oraclebin)
      {
        $giusr = getpwuid((stat($oraclebin))[4]);
        asmcmdshare_trace(3, "Creating '$logdir' directory as '$giusr'",
                          'y', 'n');

        $cmd = "mkdir -m 755 -p $logdir";
        $ret = asmcmdafd_runcmd_as_user($cmd, $giusr, \@buf);
        return 1;
      }
    }
  }
  else
  {
    asmcmdshare_trace(3, "AFD log directory : $logdir exists", 'y', 'n');
  }
  return 0;
} #end asmcmdafd_create_logdir

########
# NAME
#   asmcmdafd_create_afddisks
#
# DESCRIPTION
#   This function creates AFD disks directory.
#   Call this function only when the command is run as root user.
#
# PARAMETERS
#
# RETURNS
#   1 if successfully created the AFD disks directory; 0 otherwise.
########
sub asmcmdafd_create_afddisks
{
  # Windows Oracle always runs in admin mode
  if($^O =~ /win/i)
  {
    return 1;
  }

  if(!(-e $AFDDISKLOC))
  {
    my ($oraclebin) = "$ENV{'ORACLE_HOME'}/bin/oracle";
    my ($giuid)     = ((stat($oraclebin))[4]);
    my ($gigid)     = ((stat($oraclebin))[5]);
    my ($giusr)     = getpwuid((stat($oraclebin))[4]);
    my ($gigrp)     = getgrgid((stat($oraclebin))[5]);

    asmcmdshare_trace(3, "Creating $AFDDISKLOC directory with $giusr:$gigrp",
                      'y', 'n');

    # asmcmd and AFD (linux) udev rules should set the same permissions.
    # Please see : usm/src/cmds/afdlib/lin/osds*pm
    `mkdir -m 775 -p $AFDDISKLOC`;
    chown $giuid, $gigid, $AFDDISKLOC;
    return 1;
  }
  else
  {
    asmcmdshare_trace(3, "AFD disks directory : $AFDDISKLOC exists", 'y', 'n');
  }
  return 0;
} #end asmcmdafd_create_afddisks

########
# NAME
#   asmcmdafd_update_afddisks
#
# DESCRIPTION
#   This function modifies owership of AFD disks files.
#   Call this function only when the command is run as root user.
#
# PARAMETERS
#
# RETURNS
#   1 if successfully updated the owership of AFD disks; 0 otherwise.
########
sub asmcmdafd_update_afddisks
{
  # Windows Oracle always runs in admin mode
  if($^O =~ /win/i)
  {
    return 1;
  }

  if(-e $AFDDISKLOC)
  {
    my ($oraclebin) = "$ENV{'ORACLE_HOME'}/bin/oracle";
    my ($giuid)     = ((stat($oraclebin))[4]);
    my ($gigid)     = ((stat($oraclebin))[5]);
    my ($giusr)     = getpwuid((stat($oraclebin))[4]);
    my ($gigrp)     = getgrgid((stat($oraclebin))[5]);
    my (@flist)     = glob("$AFDDISKLOC/*");  # expand AFDDISKLOC

    asmcmdshare_trace(3, "Changing owership of $AFDDISKLOC/* to $giusr:$gigrp",
                      'y', 'n');
    asmcmdshare_trace(3, "Label list under $AFDDISKLOC/* : @flist", 'y', 'n');
    if (@flist)
    {
      # asmcmd and AFD (linux) udev rules should set the same permissions.
      # Please see : usm/src/cmds/afdlib/lin/osds*pm
      chown $giuid, $gigid, @flist;
      chmod 0664, @flist;
    }
    return 1;
  }
  asmcmdshare_trace(3, "No AFD disks directory : $AFDDISKLOC", 'y', 'n');
  return 0;
} #end asmcmdafd_update_afddisks

########
# NAME
#   asmcmdafd_is_acfs
#
# DESCRIPTION
#   This function checks if AFD is loaded on the local system
#
# PARAMETERS
#   $state - installed/loaded/supported 
#
# RETURNS
#   1 if ACFS is loaded ; 0 otherwise.
########
sub asmcmdafd_is_acfs
{
  my ($state) = @_;
  my (@eargs);
  my (@buf);
  my ($acfsdriverstate);

  # return not supproted if not any of these platforms.
  if (!($^O =~ /win/i) && !($^O =~ /linux/i) && !($^O =~ /solaris/i) &&
      (!($^O =~ /aix/i)))
  {
    # not supported
    return 0;
  }

  $acfsdriverstate = "$ENV{'ORACLE_HOME'}/bin/acfsdriverstate";
  #The path in WIN is ORACLE_HOME/bin/acfsdriverstate.exe
  $acfsdriverstate .= ".exe" if($^O =~ /win/i);
  # Make sure the acfsdriverstate binary exists and can be executed. 
  if (! -x $acfsdriverstate)
  {
    @eargs = ($acfsdriverstate);
    asmcmdshare_error_msg(9518, \@eargs);
    return;
  }

  #untaint acfsdriverstate
  $acfsdriverstate =~ /([^\n^\r^\t]+)/;
  $acfsdriverstate = $1;
     
  asmcmdshare_runcmd("$acfsdriverstate $state", \@buf, 1, 0);
  
  if ((@buf) &&  
      ((($state =~ /loaded/i) && ($buf[0] =~ /true/i)) ||
       (($state =~ /supported/i) && ($buf[0] =~ /Supported/i)) ||
       (($state =~ /installed/i) && ($buf[0] =~ /true/i))))
  {
    asmcmdshare_trace(3, "NOTE: Verifying ACFS driver state : $state",
                      'y', 'n');
    return 1;
  }
  else
  {
    asmcmdshare_trace(3, "NOTE: Verifying ACFS driver state : Not $state",
                      'y', 'n');
    return 0;
  }
} # end asmcmdafd_is_acfs

########
# NAME
#   asmcmdafd_is_afd
#
# DESCRIPTION
#   This function checks if AFD is loaded on the local system
#
# PARAMETERS
#   $state - installed/loaded/supported 
#
# RETURNS
#   1 if AFD is loaded ; 0 otherwise.
########
sub asmcmdafd_is_afd
{
  my ($state) = @_;
  my (@eargs);
  my (@buf);
  my ($afddriverstate);

  # return not supproted if not any of these platforms.
  if (!($^O =~ /win/i) && !($^O =~ /linux/i) && !($^O =~ /solaris/i) &&
      (!($^O =~ /aix/i)))
  {
    # not supported
    return 0;
  }

  $afddriverstate = "$ENV{'ORACLE_HOME'}/bin/afddriverstate";
  #The path in WIN is ORACLE_HOME/bin/afddriverstate.bat
  $afddriverstate .= ".bat" if($^O =~ /win/i);
  # Make sure the afddriverstate binary exists and can be executed. 
  if (! -x $afddriverstate)
  {
    @eargs = ($afddriverstate);
    asmcmdshare_error_msg(9518, \@eargs);
    return 0;
  }

  #untaint afddriverstate
  $afddriverstate =~ /([^\n^\r^\t]+)/;
  $afddriverstate = $1;
     
  asmcmdshare_runcmd("$afddriverstate $state", \@buf, 1, 0);
  if ((@buf) &&
      ((($state =~ /loaded/i) && ($buf[0] =~ /true/i)) ||
       (($state =~ /supported/i) && ($buf[0] =~ /9200/i)) ||
       (($state =~ /installed/i) && ($buf[0] =~ /true/i))))
  {
    asmcmdshare_trace(3, "NOTE: Verifying AFD driver state : $state",
                      'y', 'n');
    return 1;
  }
  else
  {
    asmcmdshare_trace(3, "Error: " . join('', @buf), 'y', 'n');
    asmcmdshare_trace(3, "NOTE: Verifying AFD driver state : Not $state",
                      'y', 'n');
    return 0;
  }
} # end asmcmdafd_is_afd

########
# NAME
#   asmcmdafd_am_root
#
# DESCRIPTION
#   This function verifies that the command is run as root.
#
# PARAMETERS
#   NONE 
#
# RETURNS
#   1 if root ; 0 otherwise.
########
sub asmcmdafd_am_root
{
  # Windows Oracle always runs in admin mode
  if($^O =~ /win/i)
  {
    return 1;
  }

  if ($>) # get euid
  {
    # not zero (root)
    # If this is AIX, let the grid user in.
    if ($^O =~ /aix/i)
    {
      my $tusr;
      if (-e "$ENV{'ORACLE_HOME'}/crs/install/crsconfig_params")
      {
        $tusr=`grep ORACLE_OWNER $ENV{'ORACLE_HOME'}/crs/install/crsconfig_params|/usr/bin/cut -f2 -d '='`;
      }
      my $me=`/bin/id -un`;
      $tusr =~ s/\s+$//;
      $me =~ s/\s+$//;
      if ($me eq $tusr)
      {
        return 1;
      }
      else
      {
        return 0;
      }
    }

    return 0;
  }

  return 1;
} # end asmcmdafd_am_root

########
# NAME
#   asmcmdafd_is_siha
#
# DESCRIPTION
#   This function verifies that the oracle sw is SIHA.
#
# PARAMETERS
#   NONE 
#
# RETURNS
#   1 if SIHA ; 0 otherwise.
########
sub asmcmdafd_is_siha
{
  my $val = "";
  my $cfgfile = $OCRLOC;
  my $key = "local_only";

  # open OCRCONFIG file
  asmcmdshare_trace(3, "NOTE: asmcmdafd_is_siha Opening $cfgfile", 'y', 'n');
  if (-e $cfgfile)
  {
    open (CFGFL, "<$cfgfile") or return $val;
    while (<CFGFL>) {
       if (/^$key=(\S+)/) {
          $val = $1;
          last;
       }
    }
    close (CFGFL);
    asmcmdshare_trace(3, "NOTE: asmcmdafd_is_siha Value ($val) set for $key",
                      'y', 'n');
  }

  if ($val =~ m/true/i)
  {
    return 1;
  }

  return 0;
}

########
# NAME
#   asmcmdafd_is_exadata
#
# DESCRIPTION
#   This function verifies that the sw env. is Exadata
#
# PARAMETERS
#   NONE 
#
# RETURNS
#   1 if Exadata ; 0 otherwise.
########
sub asmcmdafd_is_exadata
{
  my $checksc = "/etc/oracle/cell/network-config/cellip.ora";
  if (! (-e $checksc))
  {
    asmcmdshare_trace(3, "NOTE: asmcmdafd_is_exadata $checksc not found",
                      'y', 'n');
    return 0;
  }
  return 1;
}

########
# NAME
#   asmcmdafd_runcmd_as_user
#
# DESCRIPTION
#   Function for running a command as given user
#
# PARAMETERS
#  runcmd: cmd to be executed
#    user: user name
# buf_ref: address of the buffer to store the output of the command
#
# RETURNS
#  exit code of the system command execution
########
####---------------------------------------------------------
sub asmcmdafd_runcmd_as_user
{
  my ($runcmd, $user, $buf_ref) = @_;
  my $ret;
  my $cmd;
  my @buf;

  if ($user)
  {
    $cmd = "$SU $user -c \"$runcmd\"";
    asmcmdshare_trace(3, "NOTE: Invoking \"$cmd\" as user \"$user\"",
                      'y', 'n');
  }
  else
  {
    $cmd = $runcmd;
    asmcmdshare_trace(3, "NOTE: Invoking \"$cmd\"", 'y', 'n');
  }
  $ret = asmcmdshare_runcmd($cmd, \@buf, 0, 0);
  @{$buf_ref} = @buf;
  return $ret;
}

########
# NAME
#   asmcmdafd_is_member_cluster
#
# DESCRIPTION
#   Function to verify if the command is run on a member(client) cluster
#
# PARAMETERS
#  NONE
#
# RETURNS
#   1 if member cluster ; 0 otherwise.
########
####---------------------------------------------------------
sub asmcmdafd_is_member_cluster
{
  my ($kfod);
  my (@buf);
  my (@eargs);
  my ($val);
  my ($ret);

  $kfod = catfile($ENV{'ORACLE_HOME'}, 'bin', 'kfod');
  $kfod .= ".exe" if($^O =~ /win/i);
  # Make sure the kfod binary exists and can be executed. 
  if (! -x $kfod)
  {
    @eargs = ($kfod);
    asmcmdshare_error_msg(9515, \@eargs);
    return;
  }

  asmcmdshare_runcmd("$kfod op=getclstype nohdr=true", \@buf, 0, 0);
    
  if (!$ret)
  {
    if (@buf)
    {
      # command succeeded
      asmcmdshare_trace(3, "NOTE: " . join('', @buf), 'y', 'n');
      ($val) = grep { /Client cluster/i } @buf;
      if ($val)
      {
        # Client Cluster
        return 1;
      }
    }
  }
  return 0;
}

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

  return defined ( $asmcmdafd_cmds{ $arg } );
}

########
# NAME
#   asmcmdafd_is_wildcard_cmd
#
# DESCRIPTION
#   This routine determines if an ASMCMDAFD 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 asmcmdafd_is_wildcard_cmd 
{
  my ($arg) = shift;
  my (%cmdhash); # Empty hash; no ASMCMDAFD command supports wildcards. # 

  return (asmcmdshare_get_cmd_wildcard($arg) eq "true");
}

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

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

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

  return 0;
}

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

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

########
# NAME
#   asmcmdafd_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 ASMCMDAFD commands.
#
# PARAMETERS
#   cmd   (IN) - user-entered command name string.
#
# RETURNS
#   1 if the command belongs to this module; 0 if command not found.
#
# NOTES
#   These errors are user-errors and not internal errors.  They are of type
#   record, not signal.  
# 
#   N.B. Functions in this module can call this function directly, without
#   calling the asmcmdshare::asmcmdshare_syntax_error equivalent.  The
#   latter is used only by the asmcmdcore module.
########
sub asmcmdafd_syntax_error 
{
  my ($cmd) = shift;
  my ($cmd_syntax);                               # Correct syntax for $cmd. #
  my ($succ) = 0;
  #display syntax only if the command belongs to this module
  if (asmcmdafd_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;
    }
  }

  return $succ;
}

########
# NAME
#   asmcmdafd_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 asmcmdafd_get_asmcmd_cmds 
{
  return asmcmdshare_filter_invisible_cmds(%asmcmdafd_cmds);
}
1;

OHA YOOOO