#!/usr/bin/perl
# IBM_PROLOG_BEGIN_TAG 
# This is an automatically generated prolog. 
#  
#  
#  
# Licensed Materials - Property of IBM 
#  
# (C) COPYRIGHT International Business Machines Corp. 2000,2019 
# All Rights Reserved 
#  
# US Government Users Restricted Rights - Use, duplication or 
# disclosure restricted by GSA ADP Schedule Contract with IBM Corp. 
#  
# IBM_PROLOG_END_TAG 
# sccsid = "@(#)06   1.33   src/rsct/rmc/cli/bin/rmrsrc.perl, rmccli, rsct_rady, rady2035a 11/12/15 16:30:49"
######################################################################
#                                                                    #
# Module: rmrsrc                                                     #
#                                                                    #
# Purpose:                                                           #
#   rmrsrc - Removes (undefines) a defined resource.                 #
#                                                                    #
# Syntax:                                                            #
#   To remove one or more resources, using data entered on the       #
#   command line:                                                    #
#   rmrsrc [-h] -s "Selection_string" [-a] [-T] [-V]                 #
#          Resource_class [Arg=value...]                             #
#   rmrsrc [-h] -r [-a] [-T] [-V]                                    #
#          Resource_handle [Arg=value...]                            #
#                                                                    #
#   To remove one or more resources using command arguments          #
#   predefined in an input file:                                     #
#   rmrsrc [-h] -f Resource_data_input_file -s "Selection_string"    #
#          [-a] [-T] [-V] Resource_class                             #
#   rmrsrc [-h] -f Resource_data_input_file -r [-a]                  #
#          [-T] [-V] Resource_handle                                 #
#                                                                    #
#   To list the required command arguments names and data types:     #
#   rmrsrc [-h] -l [-T] [-V] Resource_class                          #
#                                                                    #
# Flags:                                                             #
#   -h      Help. Writes the command's usage statement to stdout.    #
#   -f Resource_data_input_file File input. Specifies the name of    #
#           the file which contains resource argument information.   #
#           PersistentResourceArguments::                            #
#               argument1 = value                                    #
#               argument2 = value                                    #
#           TODO: If must specify the selection string on the        #
#           command line with -s flag, does it make sense to have    #
#           more than one set of command arguments here?             #
#           Similar issue in runact, startrsrc, stoprsrc, resetrsrc. #
#   -a      All nodes. The rmrsrc command applies to all nodes in    #
#           the cluster. The cluster scope is determined by the      #
#           environment variable CT_MANAGEMENT_SCOPE. If it is not   #
#           set, first the management domain scope is used, then     #
#           peer domain scope, and then local scope is used until    #
#           the scope is a valid scope for the command. The command  #
#           will run once for the first valid scope found.           #
#   -l      List command arguments and data types. Some Resource     #
#           managers accept additional arguments passed to the       #
#           undefine request. Use the -l flag to list any defined    #
#           command arguments and the data type of the command       #
#           argument values.                                         #
#   -r      Specifies that a resource handle is specified as the     #
#           operand. Resource associated with this resource handle   #
#           will be removed.                                         #
#   -s "Selection string" Specifies the selection string. All        #
#           selection strings must be enclosed within either double  #
#           or single quotation marks. If the selection string       #
#           contains double quotation marks, enclose the entire      #
#           selection string in single quotation marks. For example: #
#           -s 'Name == "testing"'                                   #
#           -s 'Name ?= "test"'                                      #
#           Only persistent attributes can be listed in a selection  #
#           string.                                                  #
#   -T      Trace. Writes the command's trace messages to standard   #
#           error. For your software-service organization use only.  #
#   -V      Verbose. Writes this command's verbose messages to       #
#           standard output.                                         #
#                                                                    #
# Operands:                                                          #
#   Resource_class  The resource class name. The resource instances  #
#                   that match the selection string criteria for     #
#                   this resource class, will be removed.            #
#                                                                    #
#   Resource_handle A resource handle. The resource handle must be   #
#                   specified using the format:                      #
#                   "0x#### 0x#### 0x######## 0x######## 0x########  #
#                    0x########", where # is any valid hexadecimal   #
#                   digit. The resource handle uniquely identifies   #
#                   a particular resousrce that should be removed.   #
#                                                                    #
#   Arg=value       Enter the command arguments names and values.    #
#                   Command arguments are optional.                  #
#                   If any Arg=value pairs are entered then there    #
#                   should be one Arg=value pair for each of the     #
#                   the command arguments defined for the undefine   #
#                   function for the specified resource class.       #
#                   Use rmrsrc -l to get the list of command         #
#                   arguments names and data types for the specific  #
#                   resource class.                                  #
#                   Use the lscmdargdef command to view the command  #
#                   arguments definition.                            #
#   Arg             The argument name.                               #
#   value           The value for this argument, the value data type #
#                   must match the definition of arguments data type.#
#                                                                    #
# Description:                                                       #
#   The rmrsrc command removes (undefines) the specified resource    #
#   instance or resource instances. The rmrsrc command makes a       #
#   request to the RMC subsystem to undefine a specific resource     #
#   instance. The resource manager of the resource will actually do  #
#   the removal.                                                     #
#                                                                    #
#   The first format of this command requires a resource class name  #
#   operand and a selection string specified using the -s flag. All  #
#   resources in the specified resource class that match the         #
#   specified selection string are removed. If the selection string  #
#   identifies more than one resource to be removed, it is the same  #
#   as running this command once for each resource that matches the  #
#   selection string.                                                #
#                                                                    #
#   The second format of this command allows the actual resource     #
#   handle which uniquely identifies a specific resource to be       #
#   specified as the operand. It is expected that this form of the   #
#   command would be more likely used within a script. Use the       #
#   lsrsrc command to get a list of resource handles.                #
#                                                                    #
#   Invoke rmrsrc with the -l flag to determine if any command       #
#   arguments are defined for the specific resource class.           #
#   TODO: (Update next sentence).                                    #
#   Prior to running rmrsrc you should run the lscmdargdef           #
#   command to determine if the specified resource class accepts     #
#   any additional arguments.                                        #
#                                                                    #
# Exit Values:                                                       #
#   0  MC_CLI_SUCCESS        Command completed successfully.         #
#   1  MC_CLI_RMC_ERROR      Command terminated due to an underlying #
#                            RMC error.                              #
#   2  MC_CLI_ERROR          Command terminated due to an underlying #
#                            error in the command script.            #
#   3  MC_CLI_BAD_FLAG       Command terminated due to user          #
#                            specifying an invalid flag.             #
#   4  MC_CLI_BAD_OPERAND    Command terminated due to user          #
#                            specifying a bad operand.               #
#   5  MC_CLI_USER_ERROR     Command terminated due to a user error. #
#                            For example specifying an undefined     #
#                            Resource name as the Resource operand.  #
#   6  MC_CLI_NO_RSRC_FOUND  No resources were found that matched    #
#                            the specified selection string.         #
#                                                                    #
# Examples:                                                          #
#  rmrsrc -s 'Name ?= "c175"' IBM.Foo                                #
#  rmrsrc -s "*" IBM.Foo        # WARNING - this will remove all!    #
#  rmrsrc -r "0x400a 0x0001 0x00000000 0x0069684c 0x0d3a434b         #
#             0x8e245cee"                                            #
#                                                                    #
# Man Page:                                                          #
#   For the most current detailed description of this command see    #
#   the rmrsrc man page in /opt/rsct/man.                       #
#                                                                    #
#--------------------------------------------------------------------#
# Inputs:                                                            #
#   /opt/rsct/msgmaps/mccli.rmrsrc.map - message mapping        #
#   /opt/rsct/msgmaps/mccli.mccli.map - message mapping         #
#                                                                    #
# Outputs:                                                           #
#   stdout - any verbose messages.                                   #
#   stderr - any error message.                                      #
#                                                                    #
# External Ref:                                                      #
#   Commands: ctdspmsg                                               #
#   Modules:  MC_cli_utils.pm, MC_cli_rc.pm                          #
#             CT_cli_utils.pm, CT_cli_input_utils.pm,                #
#             CT_cli_display_utils.pm                                #
#   Extensions:  CT::MC, CT::MCerr, CT::CT                           #
#   Perl library routines: Getopt::Long                              #
#                                                                    #
# Tab Settings:                                                      #
#   4 and tabs should be expanded to spaces before saving this file. #
#   in vi:  (:set ts=4  and   :%!expand -4)                          #
#                                                                    #
# Change Activity:                                                   #
#   000316 SAB 60909: Initial design & write.                        #
#   010311 SAB 63852: Prepared for GA.                               #
#   010406 SAB 71892: Support new MC_CLI_NO_RSRC_FOUND return code.  #
#   010804 SAB 75111: Support -f, -l, and command arguments.         #
#   020107 JAC 79315: Fix passing cmd args to undefine function.     #
#   020716 JAC 84819: Add -a to mean remove from all nodes in cluster#
#   020925 JAC 87393: Change CT_cli_display_utils to .._displayext.. #
#   021126 JAC 88084: Change to use rmrsrc-api instead of ext.       #
#   021203 JAC 88085: Move get_class_from_rsrc_hndl_api to utils.    #
#   030404 JAC 92787: Don't allow -s "" for selection string.        #
#   040407 JAC 105863: Use escape_chars for "\" searches.            #
#   050419 JAC 120003: For -r, get class name only if SD input.      #
#   071015 JAC 146726: Use input/output delimiter for -api calls.    #
######################################################################

#--------------------------------------------------------------------#
# General Program Flow/Logic:                                        #
#                                                                    #
# A. Parse command line flags and operands, determine which flavor   #
#    of this command we are actually invoking.                       #
#    This command allows a user to remove (undefine) resources.      #
# B. Initialize a session with RMC.                                  #
# C. If the -s flag was specified then a selection string and        #
#    resource class name were provided as input to this command.     #
#    Call the MC_cli_utils::enumerate_resources utility which calls  #
#    the CT::MC::RMC function mc_enumerate_resources_bp to get a     #
#    list of resource handles that match the selection criteria that #
#    was specified by the user.                                      #
# D. If the -r flag was specified then the user is specifying the    #
#    actual resource handles on the command line and wants the       #
#    resources associated with these resource handles removed.       #
#    Convert the string format of these resource handles into an     #
#    array of references to resource handles (the same format that   #
#    we get back from enumerate_resources).                          #
# E. Call mc_undefine_resource_bp for each resource handle listed    #
#    in the array of resource handles.                               #
# F. Cleanup - remove responses and terminate the session with RMC.  #
#--------------------------------------------------------------------#

#--------------------------------------------------------------------#
# Included Libraries and Extensions                                  #
#--------------------------------------------------------------------#
use lib "/opt/rsct/pm";
use locale;
use Getopt::Long; 

use autouse CT_cli_utils => qw(
    printIMsg
    printEMsg
);
use autouse CT_cli_input_utils => qw (
    process_input_file
    process_cmdline_input
    string_to_rsrc_handle
    escape_chars
    check_input_file
);

use MC_cli_rc qw(:return_codes); 
use autouse MC_cli_utils => qw(
    get_arg_defs_api
    build_cmd_arg_sd_api
    error_exit
    printCEMsg
    process_exit_code
    process_api_error
    remove_api_error
    get_class_from_rsrc_hndl_api
    read_from_Stdin
);


#--------------------------------------------------------------------#
# Global Variables                                                   #
#--------------------------------------------------------------------#
Getopt::Long::Configure ("bundling", "no_auto_abbrev", 
                         "no_ignore_case", "require_order",
                         "prefix_pattern=(--|-)");
$TRUE = 1;
$FALSE = 0;

$Verbose = $FALSE;                      # default - verbose turned off

# By default we expect a selection string and resource name 
$Opt_RM_RSRC_Handles = $FALSE;          # default - see -r
$Opt_RM_Select = $FALSE;                # default - see -s
$Opt_Ls_Cmd_Args = $FALSE;              # default - see -l (list args)
$Opt_File_Input = $FALSE;               # -f not supported in rmrsrc
$Opt_Cmd_Cluster = $FALSE;              # -a all nodes
$Opt_Node_File= $FALSE;                 # default - see -N
$Opt_Stdin= $FALSE;                     # default - see -N with Stdin

$PROGNAME = "rmrsrc";                   # Program Name for messages
$MSGCAT = "mccli.cat";                  # msg catalogue for this cmd

$CTDIR = "/opt/rsct";              # RSCT root directory
$CTBINDIR = "$CTDIR/bin";               # Cluster Bin directory 
$LSMSG = "$CTBINDIR/ctdspmsg";          # list / display message rtn.
$ENV{'MSGMAPPATH'} = "$CTDIR/msgmaps";  # msg maps for $LSMSG

#--------------------------------------------------------------------#
# Variables                                                          #
#--------------------------------------------------------------------#
my %HoSDArgDefs = ();                   # Hash of Command SD Arguments
                                        # element definitions
my @LoSDArgNames = ();                  # List of SD Arg Names, sorted
                                        # by element id.
my @LoSDArgs = ();                      # Array of SD Cmd Arg Elements
                                        # (type, value) ordered by
                                        # element id.

my @resource_handles = ();              # array of resource handle
my $resource;                           # resource class name
my $r_rsrc_handle;                      # reference to rsrc handle
my $select_str;                         # -s selection string
my $filename;                           # -f filename, input file
my $cmdline_args;                       # Reference to array of
                                        # Cmd_Args=value pairs
my $node_file_name;                     # to hold node filename
my @rm_out = ();

my $rc = 0, $badrc = 0;
$DELIMITER = "tvrtvrtvr";               # delimiter for rmrsrc-api

#--------------------------------------------------------------------#
# Main Code                                                          #
#--------------------------------------------------------------------#

# parse the command line, exit if there are errors 
($rc, $resource, $select_str, $r_rsrc_handle, $filename,
    $node_file_name, $cmdline_args) = &parse_cmd_line;
($rc == 0) || error_exit($rc);

# if -a or -N was specified, make sure CT_MANAGEMENT_SCOPE
# is set.  If it isn't, set it to 4, DM/SR/Local
if (($Opt_Cmd_Cluster  || $Opt_Node_File) && !defined $ENV{CT_MANAGEMENT_SCOPE}) {
   $ENV{CT_MANAGEMENT_SCOPE} = 4;
}

# If the -r flag was specified then the user is specifying the
# actual resource handle on the command line and wants the
# resource associated with this resource handle removed.
# Determine which resource class this resource handle is associated.
if ($Opt_RM_RSRC_Handles) {
    $r_rsrc_handle = $resource;

    # if command args are present, need class name for this RH (120003)
    if (scalar @$cmdline_args > 0 || $Opt_File_Input || $Opt_Ls_Cmd_Args) {
       ($rc, $resource) = get_class_from_rsrc_hndl_api($r_rsrc_handle);
       ($rc == 0) || error_exit($rc);
    }
}

# Command arguments are optional - but if any were provided on 
# the command line or in an input file - then all of the defined 
# command arguments must have been provided.
if (scalar @$cmdline_args > 0 || $Opt_File_Input || 
    $Opt_Ls_Cmd_Args) {
    # Get the undefine command SD argument definitions for this 
    # resource class. SD element names are key to the level 1 hash.
    $rc = get_arg_defs_api($resource, "", "undefine", 1, \%HoSDArgDefs,
                           \@LoSDArgNames);
    ($rc == 0) || error_exit($rc);

    # If there are no cmd arguments defined as being required for this
    # resource class - then none should have been
    # entered on the command line.
    if ((scalar @LoSDArgNames == 0) && !$Opt_Ls_Cmd_Args) {
        printCEMsg(EMsgMCcliNoArgsRequired, $resource);
        error_exit(MC_CLI_USER_ERROR);
    }
}

# List the required command arguments and data types
# when the -l flag was specified on the command line
if ($Opt_Ls_Cmd_Args) {
    ls_cmd_args($resource, \@LoSDArgNames, \%HoSDArgDefs);
}
else { 
    # Remove the resources

    # Get the SD Arg=value pairs to construct the cmd args SD
    # from either the command line (@$cmd_args) or input file.
    my $rLoCmdData = ();
    if (scalar @LoSDArgNames > 0) {
        ($rc, $rLoCmdData) = process_input($Opt_File_Input, $filename,
            0, $cmdline_args);
        ($rc == 0) || error_exit($rc);
    }

    # Merge the Args=value pairs you got from the user with the
    # resources actual command argument definitions to build a Hash
    # of Command Arguments which contains the equivalent data as
    # the ct_structured_data_t structure ({sd_dtype} {sd_value})
    # The data you need to actually undefine the resource - also
    # check that the user supplied values for all the required
    # cmd arguments.
    my $new_cmd_args;
    # TODO: does it make sense to allow more than one resource set of 
    # arguments here. If specify -s Selection_string on command line 
    # then probably only makes sense to allow one set of command 
    # arguments here.
    foreach $new_cmd_args (@$rLoCmdData) {
        ($rc, @LoSDArgs) = build_cmd_arg_sd_api($resource,
            $new_cmd_args, \%HoSDArgDefs);
        if ($rc != 0) {
            if (!$badrc) { $badrc = $rc; }
            next;
        }
    }   # end foreach $new_cmd_args

    ($badrc == 0) || error_exit($badrc);

    my $comma = "";
    my $cmd_opts = "";
    my $tmpparms = "";
    # process any command options (arguments)
    if ($#LoSDArgs >=0) {
       # use double delimiters to show args next
       for (my $j=0; $j<=$#LoSDArgs; $j++) {
          if ( ${LoSDArgs[$j]}{type} =~ /ARRAY/ ) {
             $tmpparms = "{";
             $i = scalar (@{$LoSDArgs[$j]->{value}});
             for (my $k=0; $k<$i; $k++){
                $tmpparms .= $comma . ${$LoSDArgs[$j]->{value}}[$k];
                $comma = ",";
             }
             $comma = "";
             $tmpparms .= "}";

             $cmd_opts .= $DELIMITER . $LoSDArgs[$j]->{name} . $DELIMITER . $tmpparms;

          }
          else {
            $cmd_opts .= $DELIMITER . $LoSDArgs[$j]->{name} . $DELIMITER . $LoSDArgs[$j]->{value};
          }
       }
    }

    if ($Trace) { print STDERR "Calling rmrsrc-api:\n"; }

    $cmd_opts = escape_chars($cmd_opts);

    # make call to rmrsrc-api
    if ($Opt_RM_RSRC_Handles) {
       @rm_out = `$CTBINDIR/rmrsrc-api  -I $DELIMITER -D $DELIMITER -r "${r_rsrc_handle}${cmd_opts}" 2>&1`;
    }
    elsif ($Opt_RM_Select) {
       $select_str = escape_chars($select_str);
       if ($Opt_Node_File)
       {
           # create temp file based on Stdin input
           if ($Opt_Stdin)
           {
               $node_file_name= read_from_Stdin();
           }
           
           @rm_out = `$CTBINDIR/rmrsrc-api -I $DELIMITER -D $DELIMITER -w "${resource}${DELIMITER}${select_str}${DELIMITER}${node_file_name}${cmd_opts}" 2>&1`;
           
           # remove temp node file if from STDIN
           if ($Opt_Stdin)
           {
               unlink($node_file_name);
           }
       }
       else
       {
           @rm_out = `$CTBINDIR/rmrsrc-api -I $DELIMITER -D $DELIMITER -s "${resource}${DELIMITER}${select_str}${cmd_opts}" 2>&1`;
       }
    }
   
    # capture the return code from rmrsrc-api
    $rc = $?;
    $rc = process_exit_code($rc);

    if ($Trace) { print STDERR "rmrsrc-api results:\n";
      print STDERR "rmrsrc-api returned $rc \n";
      print STDERR "@rm_out";
      print STDERR "Return from rmrsrc-api\n";
   }

    # show any errors if there was a bad rc
    if ($rc != 0) {
       process_api_error($DELIMITER,$rc,@rm_out);
    }



}   # end if (!$Opt_Ls_Cmd_Args) 

# Exit with error if one of the undefine resources failed 
($badrc == 0) || error_exit($badrc);

exit $rc;


#--------------------------------------------------------------------#
# End Main Code                                                      #
#--------------------------------------------------------------------#


#--------------------------------------------------------------------#
# parse_cmd_line - Parse the command line for options and operands.  #
#   Set appropriate global variables as outlined below, make sure we #
#   have a valid combination of arguments / options.                 #
#                                                                    #
# Return:                                                            #
#   $rc   0                  Command line parsed fine, no problem.   #
#         MC_CLI_BAD_FLAG    Command line contained a bad flag.      #
#   $resource                The resource class name when -s flag    #
#                            was specified.                          #
#   $select_str              Selection string.                       #
#   $r_rsrc_handle           Reference to a resource handle.         #
#   $rsrc_file               Name of file that contains command args.#
#   @cmdline_args            Reference to an array of                #
#                            Command Argument = value pairs.         #
#                                                                    #
# Global Variables:                                                  #
#   $Opt_RM_Select     output   True (-s select_string), remove rsrc #
#                               that match specified selection       #
#   $Opt_RM_RSRC_Handles  output  True (-r), remove specifically the #
#                               resources that have the specified    #
#                               resource handles.                    #
#   $Verbose           output   True (-V) turn Verbose mode on.      #
#   $Trace             output   True (-T) turn Trace mode on.        #
#--------------------------------------------------------------------#
sub parse_cmd_line 
{
my(@original_argv) = @ARGV;
my $resource = "";
my $rsrc_file = "";
my $select_str = "";
my $node_file_name= "";
my $r_rsrc_handle = ();
my $rc;
my @cmdline_args = ();
my %opts = ();

# Process the command line...
if (!GetOptions(\%opts,
                'h|help|version' ,
                'a' ,
                'l' ,
                'r' ,
                'T' ,
                'V' , 
                'f=s' ,
                'N=s' ,
                's=s' )) 
{
    &print_usage;                       # display proper usage
    return MC_CLI_BAD_FLAG;             # return bad rc - bad flag 
}

# Always accept the -h help flag regardless of other flags or operands
if (defined $opts{h}) {                 # -h, help request  
    &print_usage;                       # print usage statement
    exit(0);                            # all done with good return!
}

# An operand is required.
#   When -s flag specified require operand to be a resource class name
#   When -r flag specified require operand to be a resource handle
if ($#ARGV >= 0) {
    # Get the arguments...
    # Operands:  [resource | resource_handle]
    $resource = shift @ARGV;            # user specified resources
}
else {
    (defined $opts{r}) ? printCEMsg("EMsgMCcliMissingRsrcHandle") :
        printCEMsg("EMsgMCcliMissingRsrcClass");
    &print_usage;
    return MC_CLI_BAD_OPERAND;          # return bad rc - bad operand
}

# Grab all of the Arg=value pairs, the command arguments and values, 
# that must come right after the resource class name or rsrc handle.
# The regular expression verifies that the next argument / operand 
# is of the form keyword=value. 
if ($#ARGV >= 0) {
    my $num_elements = $#ARGV + 1;
    for (my $i= 0; $i < $num_elements; $i++) {
        # TODO: add ^^ check and printCEMsg to startrsrc, stoprsrc
        #   resetrsrc, mkrsrc
        # Check if Arg is keyword=value or ^^ (next command args)
        if (($ARGV[0] =~ /(\w+)\s*=\s*(.*?)\s*/) || 
            ($ARGV[0] eq "^^")) { # arg is keyword=value
            push @cmdline_args, shift @ARGV;
        }
        else {
            last;
        }
    }
}

# There should not be any remaining arguments.
if ($#ARGV >= 0) {
    printCEMsg("EMsgMCcliImproperUsageOperand", $ARGV[0]);
    &print_usage;
    return MC_CLI_BAD_OPERAND;
}


# See which options/flags were used...

if (defined $opts{f}) {                 # -f, filename for rsrc data
    $Opt_File_Input = $TRUE;
    $rsrc_file = $opts{f};              # input rsrc file name
    if (scalar @cmdline_args > 0) {
        # Can't use -f with cmdline_args on cmd line
        printCEMsg("EMsgMCcliImproperUsageCombination", "-f", 
            @cmdline_args);
        &print_usage;
        return MC_CLI_BAD_OPERAND;
    } 
}

if (defined $opts{a}) {                 # -a, all nodes 
    $Opt_Cmd_Cluster = $TRUE;
}

# List if any the required cmd_args=data_type pairs for on-line.
if (defined $opts{l}) {
    $Opt_Ls_Cmd_Args = $TRUE;
}

if (defined $opts{r}) {                 # -r, rm using rsrc handles
    if (defined $opts{s}) {
        printCEMsg("EMsgMCcliImproperUsageCombination", "-s", "-r");
        &print_usage;    
        return MC_CLI_BAD_FLAG; 
    }   
    $Opt_RM_RSRC_Handles = $TRUE;
    ($rc, $r_rsrc_handle) = string_to_rsrc_handle($resource);
    if ($rc != 0) {
        printCEMsg("EMsgMCcliBadRsrcHandle", $resource); 
        &print_usage;
        return MC_CLI_BAD_OPERAND; 
    }
}

if (defined $opts{s}) {                 # -s "selection_string"
    $select_str = $opts{s};
    # don't allow empty selection string 
    if ($select_str =~ /^$/) {
        printCEMsg("EMsgMCcliSelectStrError");
        &print_usage;
        return MC_CLI_BAD_OPERAND;
    }
    $Opt_RM_Select = $TRUE;
}
elsif (!defined $opts{r} && !defined $opts{l}) {
    printCEMsg("EMsgMCcliMissingSelectionStr");
    &print_usage;
    return MC_CLI_BAD_FLAG;
}

if (defined $opts{N})
{   
    if (!defined $opts{s})
    {
        # A selection string is required when using -N
        printCEMsg("EMsgMCcliMissingSelectionStr");
        &print_usage;
        return MC_CLI_BAD_FLAG;
    }
    elsif (defined $opts{a}) {
        printCEMsg("EMsgMCcliImproperUsageCombination", "-N", "-a");
        &print_usage;
        return MC_CLI_BAD_FLAG;
    }
    elsif (defined $opts{r}) {
        printCEMsg("EMsgMCcliImproperUsageCombination", "-N", "-r");
        &print_usage;
        return MC_CLI_BAD_FLAG;
    }
    elsif (defined $opts{l}) {
        printCEMsg("EMsgMCcliImproperUsageCombination", "-N", "-l");
        &print_usage;
        return MC_CLI_BAD_FLAG;
    }
    elsif ($opts{N} eq "-")
    {   
        $Opt_Stdin= $TRUE;
    }
    else
    {
        $node_file_name= $opts{N};
        $node_file_name= escape_chars($node_file_name);
        $rc= check_input_file($node_file_name);
        if ($rc)
        {
            return MC_CLI_BAD_OPERAND;
        }
    }
    $Opt_Node_File= $TRUE; 
}

if (defined $opts{T}) {                 # -T, turn tracing on
    $Trace = $TRUE; 
}

if (defined $opts{V}) {                 # -V, turn verbose mode on 
    $Verbose = $TRUE;
}

# success
return(0, $resource, $select_str, $r_rsrc_handle, $rsrc_file, 
    $node_file_name, \@cmdline_args);      
}   # end parse_cmd_line


#--------------------------------------------------------------------#
# print_usage : print the usage statement (syntax) to stdout.        #
#   See this command's prologue syntax section for current usage.    #
#--------------------------------------------------------------------#
sub print_usage
{
printIMsg("IMsgrmrsrcUsage4");
}   # end print_usage


#--------------------------------------------------------------------#
# ls_cmd_args - Lists the online arguments and data types if any     #
#   are required for this resource class.                            #
#                                                                    #
# Parameters:                                                        #
#   $resource          in     Name of the resource class.            #
#   @$rLoArgNames      in     Reference to a list (array) of         #
#                             argument names in element order index  #
#                             for all arguments whose definitions    #
#                             are in %$rHoSDDef.                     #
#   %$rHoSDDef         in     Reference to the hash of command       #
#                             SD argument defintitions.              #
#                                                                    #
# Return:                                                            #
#   None.                                                            #
#                                                                    #
# Global References:                                                 #
#   None.                                                            #
#--------------------------------------------------------------------#
sub ls_cmd_args
{
my ($resource, $rLoArgNames, $rHoSDDef) = @_;

my ($arg_name, $data_type, $properties);

print "rmrsrc $resource ";

foreach $arg_name (@$rLoArgNames) {
    $data_type = lc $$rHoSDDef{$arg_name}{sd_dtype};
    $data_type =~ s/^ct_//;
    print "$arg_name=$data_type ";
}

print "\n";

return;
}   # end ls_cmd_args


#--------------------------------------------------------------------#
# process_input - process the attr=value pairs that are used to      #
#   define this resource and were input by the user on the command   #
#   line or via an input file.                                       #
#                                                                    #
# Parameters:                                                        #
#   $Opt_File_Input   input   True - input should come from file.    #
#                             False - input should come from command #
#                             line.                                  #
#   $filename         input   Name of file if $Opt_File_Input = TRUE #
#   $Opt_RSRC_Class   input   True if invoking action on a resource  #
#                             class instead of a resource.           #
#   @$r_cmdline       input   Reference to attr=value pairs via      #
#                             command line and ARGV.                 #
#                                                                    #
# Return:                                                            #
#   $rc                       return code.                           #
#                                                                    #
# Global References:                                                 #
#   None.                                                            #
#--------------------------------------------------------------------#
sub process_input 
{
my ($Opt_File_Input, $filename, $Opt_RSRC_Class, $r_cmdline) = @_;
my $rc = 0;
my $rLoRsrcData;

# Note: rmrsrc at this time does not accept input from a file
# only from command line.
if ($Opt_File_Input) {
    my $file_stanza = "PersistentResourceArguments"; 

    ($rc, $rLoRsrcData) = process_input_file($filename, $file_stanza);
    if ($rc != 0) {
        # Print Error processing input file msg
        # process_input_file will write a more detailed error message
        printCEMsg("EMsgMCcliInputFileError", $filename);
        exit(MC_CLI_USER_ERROR);
    }
}
else {
    ($rc, $rLoRsrcData) = process_cmdline_input($r_cmdline);
    if ($rc != 0) {
         # Print Command Line Error Attr=value error msg
         printCEMsg("EMsgMCcliCmdLineArgError", $r_cmdline);
         exit(MC_CLI_BAD_OPERAND);
    }
}

if ($Verbose) {
    my ($attribute, $value, $entry, $element, $row_header);
    foreach $entry (@$rLoRsrcData) {
        $row_header = $entry->[0];
        foreach $element (@{$entry->[1]}) {
            $attribute = $element->[0];
            $value = $element->[1];
            print "$attribute = \"$value\"\n";
        }
    }
}

return ($rc, $rLoRsrcData);
}   # end process_input


#--------------------------------------------------------------------#
# error_check - checks the return code from the RMC function and     #
#   the error response return code.  If an error is detected         #
#   appropriate error messages will be displayed.                    #
#                                                                    #
# Parameters:                                                        #
#   $rmc_function     in      Name of the rmc function that was      #
#                             called and whose error code we are     #
#                             checking.                              #
#   $rmc_class        in      The rmc resource class name.           #
#   $rmc_rc           in      The rmc function return code.          #
#   $error            in      The error response.                    #
#                                                                    #
# Return:                                                            #
#   $rc                       return code.                           #
#                                                                    #
# Global References:                                                 #
#   None.                                                            #
#--------------------------------------------------------------------#
sub error_check 
{
my ($rmc_function, $rmc_class, $response, $rmc_rc, $error) = @_;

my $rc = 0;
my $err_rc = $error->errnum();

if ($rmc_rc != 0) {
    printEMsg("EMsgrmrsrcRmRsrcError", $rmc_class);
    my $rmc_rc_hex = sprintf "0x%8.8lx", $rmc_rc;
    printCEMsg("EMsgMCcliMCFunctionFailure", $rmc_function,
        $rmc_rc, $rmc_rc_hex);
    $rc = MC_CLI_RMC_ERROR;
    return $rc;
}

# Check the errnum in each of the RMC responses
for (my $r = 0; $r < $response->array_count; $r++) {
    # get the error that goes with the specific response
    if ($r > 0) {
        $response->error($error, $r);
        $err_rc = $error->errnum();
    }
    if ($err_rc != 0) {
        if ($err_rc == RMC_EBADRSRCHANDLE) {
            printEMsg("EMsgrmrsrcBadRsrcHandle", $rmc_class);
            print STDERR $error->error_msg;
            $rc = MC_CLI_USER_ERROR;
        }
        elsif ($err_rc == RMC_EACCESS) {
            print STDERR $error->error_msg;
            $rc = MC_CLI_USER_ERROR;
        }
        elsif ($err_rc >= 0x60000 && $err_rc <= 0x6ffff) {
            # Selection string errors are in this range
            printCEMsg("EMsgMCcliSelectStrError");
            print STDERR $error->error_msg;
            $rc = MC_CLI_USER_ERROR;
        }
        else {
            printEMsg("EMsgrmrsrcRmRsrcError", $rmc_class);
            my $err_rc_hex = sprintf "0x%8.8lx", $err_rc;
            printCEMsg("EMsgMCcliMCFunctionFailure", $rmc_function, 
                $err_rc, $err_rc_hex);
            print STDERR $error->error_msg; 
            $rc = MC_CLI_RMC_ERROR;
        }
    }   # end if
}   # end for

return $rc;
}   # end error_check