#!/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.50   src/rsct/rmc/cli/bin/runact.perl, rmccli, rsct_rady, rady2035a 11/12/15 16:30:56"
######################################################################
#                                                                    #
# Module: runact                                                     #
#                                                                    #
# Purpose:                                                           #
#   runact - Run / invokes an action on a resource or resource class.#
#                                                                    #
# Syntax:                                                            #
#   runact [-h] -s "Selection_string" [-f Resource_data_file]        #
#          [-l|-t|-d|-D Delimiter] [-x] [-T] [-V] Resource_class     #
#          Action [In_Element_0=value In_Element_1=value ...]        #
#          [Rsp_Element...]                                          #
#                                                                    #
#   runact [-h] -r [-f Resource_data_file]                           #
#          [-l|-t|-d|-D Delimiter] [-x] [-T] [-V] Resource_handle    #
#          Action [In_Element_0_value In_Element_1_value ...]        #
#          [Rsp_Element...]                                          #
#                                                                    #
#   runact [-h] -c [-f Resource_data_file] [-n Node_name]            #
#          [-l|-t|-d|-D Delimiter] [-x] [-T] [-V] Resource_class     #
#          Action [In_Element_0=value In_Element_1=value ...]        #
#          [Rsp_Element...]                                          #
#                                                                    #
#   runact [-h] -C Peer_domain_names [-f Resource_data_file]         #
#          [-l|-t|-d|-D Delimiter] [-x] [-T] [-V] Resource_class     #
#          Action [In_Element_0=value In_Element_1=value ...]        #
#          [Rsp_Element...]                                          #
#                                                                    #
# Flags:                                                             #
#   -h      Help. Writes this command's usage statement to stdout.   #
#   -c      Class. Invoke the action on the resource class instead   #
#           of on the resource. By default the action is invoked on  #
#           the resource.                                            #
#   -C Peer_domain_names  Class. Invoke the action on the resource   #
#           class instead of on the resource. The class must be a    #
#           globalized class of a peer domain that exists in a       #
#           management domain.  Peer_domain_names is a list of one   #
#           or more peer domains on which to run the class action.   #
#   -n Node_name  The name of the node on which to run the class     #
#           action.  The -n flag is only allowed with the -c flag.   #
#   -f Resource_data_input_file File input. Specifies the name of    #
#           the file which contains resource or resource class       #
#           input elements. For example:                             #
#           ResourceAction::                                         #
#                  element1 = value                                  #
#                  element2 = value                                  #
#                  ...                                               #
#           - or -                                                   #
#           ResourceClassAction::                                    #
#                  element1 = value                                  #
#                  element2 = value                                  #
#                  ...                                               #
#           Use the lsactdef command with the -i flag to generate a  #
#           template for this input file.                            #
#   -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.                                                  #
#   -r      Resource Handle. Invoke the action on the specific       #
#           resource that matches the specified resource handle.     #
#   -l      Long formatted output. Each element is displayed on a    #
#           separate line. This is the default display format.       #
#   -t      Tabular formatted output. Each element is displayed      #
#           in a separate column, one response per line.             #
#   -d      Delimiter-formatted output. The default delimiter is     #
#           a colon (:). Use the -D flag if you wish to change       #
#           the default delimiter.                                   #
#   -D Delimiter Delimiter formatted output using the specified      #
#           delimiter. Use this flag to specify something other than #
#           the default colon (:). An example is when the data to be #
#           displayed contains colons. Use this flag to specify a    #
#           delimiter of one or more characters.                     #
#   -x      Exclude header. Suppress header printing.                #
#   -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 name of the resource class that we want to   #
#                   invoke the action against.                       #
#                                                                    #
#   Action          The name of the action that we want to invoke.   #
#                                                                    #
#   In_Element=value Enter all of the Action input elements and      #
#                   values. If the -f flag is specified, In_Element= #
#                   value pair operands should not be entered on the #
#                   command line. There should be one In_Element=    #
#                   value pair for each of the defined SD input      #
#                   elements for the specified action.               #
#                   Run lsactdef -i Resource Action to generate a    #
#                   template of the required SD input elements for   #
#                   this action.                                     #
#                                                                    #
#   In_Element      Action input element name.                       #
#                   Run lsactdef -si Resource Action to see the      #
#                   action input element names for this Action.      #
#                                                                    #
#   value           The value for this action input element, the     #
#                   value data type must match the definition of     #
#                   this elements data type.                         #
#                   Run lsactdef -si Resource Action to determine    #
#                   the data type.                                   #
#                                                                    #
#   Response_Element Zero or more of the action response element     #
#                   names may be specified. If zero element names    #
#                   are specified, all the elements are displayed.   #
#                   If one or more element names are specified, only #
#                   those elements and their values are displayed    #
#                   in the specified order.                          #
#                                                                    #
# Description:                                                       #
#   The runact command requests the RMC subsystem to run (invoke)    #
#   the specified action on the resource or resource class.          #
#                                                                    #
#   Prior to running runact you should run the lsactdef command      #
#   to determine the action name and action input structured data    #
#   elements that must be specified when invoking an action.         #
#                                                                    #
# 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:                                                          #
#   runact -s 'Name == "c175n05"' IBM.Foo TestResourceAction Int32=99#
#   runact -f IBM.Foo.runact1 -s 'Name == "c175n05"'                 #
#      IBM.Foo TestResourceAction                                    #
#      Note: IBM.Foo.runact1 input file would contain the 2 lines:   #
#          ResourceAction::                                          #
#               Int32 = 99                                           #
#   runact -s 'Name ?= "*"' IBM.Foo ExecuteCommand                   #
#      Command=hostname User=root ExitCode Stdout                    #
#                                                                    #
# Man Page:                                                          #
#   For the most current detailed description of this command see    #
#   the runact man page in /opt/rsct/man.                       #
#                                                                    #
#--------------------------------------------------------------------#
# Inputs:                                                            #
#   /opt/rsct/msgmaps/mccli.runact.map - message mapping        #
#   /opt/rsct/msgmaps/mccli.mccil.map - message mapping         #
#                                                                    #
# Outputs:                                                           #
#   stdout - display of Action output response.                      #
#   stderr - any error message.                                      #
#                                                                    #
# External Ref:                                                      #
#   Commands: ctdspmsg                                               #
#   Modules:  MC_cli_utils.pm, MC_cli_display_utils.pm, MC_cli_rc.pm #
#             CT_cli_utils.pm, CT_cli_data_type_utils,               #
#             CT_cli_input_utils.pm, CT_cli_display_utils.pm.        #
#   Extensions:  CT::MC, CT::MCerr, CT::CT, CT::CU                   #
#   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:                                                   #
#   000517 SAB 64351: Initial design & write.                        #
#   001120 GTM 67900: Add response element, resource handle support. #
#   010311 SAB 63852: Prepared for GA.                               #
#   010406 SAB 71892: Support new MC_CLI_NO_RSRC_FOUND return code.  #
#   011216 JAC 77349: Add -n flag, node_name for class action (1).   #
#   011217 JAC 79061: Remove using a default for nodenamelist.       #
#   020925 JAC 87393: Change CT_cli_display_utils to .._displayext.. #
#   030123 JAC 91151: Fixes for extensionless version.               #
#   030205 JAC 91360: Escape inner quotes in select strings.         #
#   030318 JAC 92966: Fix for no args and bad action name.           #
#   030402 JAC 93181: Fix for some arg types not passed correctly.   #
#   030404 JAC 92787: Don't allow -s "" for selection string.        #
#   030709 JAC 96745: Add delimiter to call to remove_api_error.     #
#   040111 JAC 100165: Add -C flag for peer domains in DM scope.     #
#   040116 JAC 103144: Fix for typo introduced by 100165.            #
#   040407 JAC 105863: Use escape_chars for "\" searches.            #
#   080521 JAC 150491: Don't assume all actions have input and out.  #
#   080630 JAC 152000: repeat substitution for binary array output.  #
#   080723 JAC 151272: make the display multipass if large output.   #
#   080910 JAC 153444: Fix reseting of variable in display routine.  #
######################################################################

#--------------------------------------------------------------------#
# General Program Flow/Logic:                                        #
#                                                                    #
# A. Parse command line flags and operands, determine which flavor   #
#    of this command we are actually invoking.                       #
#       * Invoke a resource class action.                            #
#       * Invoke a resource action.                                  #
# B. Initialize a session with RMC.                                  #
# C. If a resource handle was specified we need to determine which   #
#    resource class it belongs to. So we can get the data types.     #
# D. If a selection string and resource class were specified we need #
#    to get the resource handles associated with the resources that  #
#    match the selection string for the specified class.             #
# E. Query the definition of the action input.                       #
# F. Query the definition of the action response (output).           #
# G. Parse the element = value pairs from the command line or        #
#    from the input file.                                            #
# H. Invoke the action on each of the resource handles.              #
# E. Display the Action response.                                    #
# F. Cleanup.                                                        #
#--------------------------------------------------------------------#

#--------------------------------------------------------------------#
# 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(
    error_exit
    build_HoAttr
    printCEMsg
    get_class_from_rsrc_hndl_api
    convert_input_value_api
    process_api_error
    process_exit_code
    remove_api_error
    read_from_Stdin
);
use autouse MC_cli_display_utils => qw(
    display_resource_data_api3
);


#--------------------------------------------------------------------#
# 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 output, attribute name value pairs should be entered
# via the command line.  Attr=value   e.g. Name=c175n06 NodeNumber=1
$Opt_RSRC_Class = $FALSE;               # default - see -c (class)
$Opt_RSRC_Class_DM = $FALSE;            # default - see -C (class)
$Opt_Class = $FALSE;                    # either -C or -c 
$Opt_File_Input = $FALSE;               # default - see -f (file form)
$Opt_RSRC_Handle = $FALSE;              # default - see -r (rsrc hndl)
$Opt_Select_Str = $FALSE;               # default - see -s (selectstr)
$Opt_Long_Format = $TRUE;               # default - see -l (long form)
$Opt_Table_Format = $FALSE;             # default - see -t (tabular)
$Opt_Delm_Format = $FALSE;              # default - see -d (delimiter)
$Opt_Delm_Str = ":";                    # default - see -D (colon :)
$Opt_No_HDR = $FALSE;                   # default - see -x
$Opt_Node_File= $FALSE;                 # default - see -N
$Opt_Stdin= $FALSE;                     # default - see -N with Stdin

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

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

#--------------------------------------------------------------------#
# Variables                                                          #
#--------------------------------------------------------------------#
my %HoSDInDef = ();                     # Action input SD Definition
my %HoSDRspDef = ();                    # Action response SD Def
my %HoClassNames = ();
my @LoSDIn = ();                        # Action input SD
my @resource_handles = ();
my $rsp_elements;                       # Reference to array of 
                                        # response element names. 
my $in_elements;                        # Reference to array of 
                                        # In_Element=value pairs
my $rc = 0, $badrc = 0;
my $rsrc_class_id = 0;
my $rHoSD;

my $node_names = "";                    # -n node names
my $peer_domain_names = "";             # -C peer domain names
my @node_name_list = ();                # node names in an array
my $name_count;                         # number of nodes in list 
                                        # (only allow 1 today)
my $node_file_name;                     # to hold node filename
my @lsr_out = ();                       # lsrsrcdef-api output
my @run_out = ();                       # runact-api output
my $cmdstr = "";                        # runact-api parameters
my $cmdstr_tmp = "";                    # runact-api parameters
$DELIMITER = "tvrtvrtvr";               # delimiter for runact-api

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

# set the quote string environment variable, if necessary
if (!defined $ENV{CT_CLI_QUOTE_STRING}){
   $ENV{CT_CLI_QUOTE_STRING} = 1;
}

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

# if - N was specified, make sure CT_MANAGEMENT_SCOPE
# is set.  If it isn't, set it to 4, DM/SR/Local 
if ($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_RSRC_Handle) {
    $r_rsrc_handle = $resource;
    ($rc, $resource) = get_class_from_rsrc_hndl_api($r_rsrc_handle);
    ($rc == 0) || error_exit($rc);

    push @resource_handles, $r_rsrc_handle;
}

# set $Opt_Class if either -c or -C used
if ($Opt_RSRC_Class || $Opt_RSRC_Class_DM) {
   $Opt_Class = $TRUE;
}

# Call lsrsrcdef-api to get the input and response elements
# for the action
if ($Trace) { print STDERR "$PROGNAME: calling lsrsrcdef-api\n";}

# set up flags for resource action
my $flg1 = " -tx";
my $flg2 = " -ty";
my $flg3 = " -a";

# change the flags if it's a class action
if ($Opt_Class) {
   $flg1 = " -tX";
   $flg2 = " -tY";
   $flg3 = " -A";
}

@lsr_out = `$CTBINDIR/lsrsrcdef-api $flg3 ${resource}::${action} $flg1 ${resource}::${action} $flg2 ${resource}::${action} 2>&1`;

# capture the return code from lsrsrcdef-api
$rc = $?;
$rc = process_exit_code($rc);

if ($Trace) { print STDERR "lsrsrcdef-api results:\n";
          print STDERR "@lsr_out";
          print STDERR "$PROGNAME: lsrsrcdef-api returned $rc\n";}

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

# remove any error messages from the output to display
@lsr_out = remove_api_error("::",@lsr_out);

# exit user error if nothing came back from lsrsrcdef-api
# must be action not found
if ($#lsr_out < 0) {
   printCEMsg("EMsgMCcliUndefinedActionName", $resource);
   exit (MC_CLI_USER_ERROR);
}

# remove the action def from @lsr_out[0]
shift @lsr_out;

# form the input and response SD definitionas from the
# lsrsrcdef-api output
format_sd_element_defs ($resource, \@lsr_out, 
         \%HoSDInDef, \%HoSDRspDef);

# Get the SD element=value pairs to construct the action input SD 
# from either the command line (@$in_elements) or input file.
($rc, $rLoRsrcData) = process_input($Opt_File_Input, $filename, 
    $Opt_Class, $in_elements);
($rc == 0) || error_exit($rc);

# if there are no arguments for this action, build the
# command without them
if ($#$rLoRsrcData <0) {
   $cmdstr = build_action_input_no_sd($resource, $action,
        $r_rsrc_handle, $select_str, $node_names, $peer_domain_names);
}

else {
   # Merge the attr=value pairs you got from the user with the 
   # resources actual attribute definitions to build a Hash of 
   # Persistent Attributes which contains the equivalent data as 
   # the mc_attribute_t structure ({at_name} {at_dtype} {at_value}) 
   # The data you need to actually define the resource - also 
   # check that the user supplied values for all the required 
   # attributes
   foreach $new_action (@$rLoRsrcData) {
       ($rc, $cmdstr_temp) = build_action_input_sd($resource, $action,
           $r_rsrc_handle, $select_str, $node_names, $peer_domain_names,
           $new_action, \%HoSDInDef); 
       if ($rc != 0) {
           if (!$badrc) { $badrc = $rc; }
           next;
       }
       # add it to the final command
       $cmdstr .= " " . $cmdstr_temp;
   }   # end foreach $new_action
}

# call runact-api 
if ($Trace) { 
   print STDERR "$PROGNAME: calling runact-api\n";
   print STDERR "$PROGNAME: calling runact-api with $cmdstr\n";
}

@run_out = `$CTBINDIR/runact-api -D $DELIMITER -I $DELIMITER $cmdstr 2>&1`;

# remove temp node file if from STDIN
if ($Opt_Stdin)
{
    unlink($node_file_name);
}

# capture the return code from runact-api
$rc = $?;
$rc = process_exit_code($rc);

if ($Trace) { print STDERR "runact-api results:\n";
          print STDERR "@run_out";
          print STDERR "$PROGNAME: runact-api returned $rc\n";}

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

# remove any error messages from the output to display
@run_out = remove_api_error($DELIMITER,@run_out);

# Display the action's response
$rc = format_and_display_SD(\@run_out, $rsp_elements, 
      \%HoSDRspDef);
($rc == 0) || error_exit($rc);

($badrc == 0) || 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.   #
#         SR_CLI_BAD_FLAG    Command line contained a bad flag.      #
#   $resource                Resource Class Name.                    #
#   $r_rsrc_handle           Reference to a resource handle.         #
#   $action                  Action Name.                            #
#   $rsrc_file               Name of file that contains rsrc data    #
#   $select_str              Selection string.                       #
#   $node_names              node name for class action              #
#   @in_elements             Reference to an array of                #
#                            Input element = value pairs.            #
#   @out_elements            Reference to an array of the            #
#                            Output element names to be displayed.   #
#                                                                    #
# Global Variables Modified:                                         #
#   $Opt_RSRC_Class    output   True (-c), invoke action on resource #
#                               class.                               #
#   $Opt_RSRC_Class_DM output   True (-C), invoke action on resource #
#                               class on peer domains in DM scope.   #
#   $Opt_Select_Str    output   True (-s select_string), invoke      #
#                               action on resources that match       #
#                               specified selection string.          #
#   $Opt_RSRC_Handle   output   True (-r), invoke action on this     #
#                               resource handle specified as operand.#
#   $Opt_File_Input    output   True (-f) read rsrc data from file.  #
#   $Opt_Long_Format   output   True (-l) print one entry per line   #
#   $Opt_Table_Format  output   True (-t) print in table format.     #
#   $Opt_Delm_Format   output   True (-d|-D) print delimitter        #
#                               separated output.                    #
#   $Opt_Delm_Str      output   the string to use as the delimitter, #
#                               default is colon (:).                #
#   $Opt_No_HDR        output   True (-x) print without header       #
#   $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 $action = "";
my $rsrc_file = ""; 
my $select_str = "";
my @in_elements = ();
my @out_elements = ();
my $node_names = "";
my $peer_domain_names = "";
my $node_file_name= "";
my $rc;
my %opts = ();

# Process the command line...
if (!GetOptions(\%opts,
                'h|help|version' ,
                'c' ,
                'd' ,
                'l' ,
                'r' ,
                't' ,
                'T' ,
                'V' ,
                'x' ,
                'C=s' ,
                'D=s' ,
                'f=s' ,
                'n=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
    if ($#ARGV >= 0) {
        $action = shift @ARGV;          # user specified action
    }
    else {
        printCEMsg("EMsgMCcliMissingAction");
        &print_usage;
        return MC_CLI_BAD_OPERAND;          # return bad rc - bad operand
    }
}
else {
    (defined $opts{s}) && printCEMsg("EMsgMCcliMissingRsrcClass");
    (defined $opts{r}) && printCEMsg("EMsgMCcliMissingRsrcHandle");
    &print_usage;
    return MC_CLI_BAD_OPERAND;          # return bad rc - bad operand
}

                                        # need to handle sd input and
# Grab all of the In_Element=value pairs that must come before the
# Out_Element operands. The regular expression sees if 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++) {
        if ($ARGV[0] =~ /(\w+)\s*=\s*(.*?)\s*/) { # arg keyword=value
            push @in_elements, shift @ARGV;
        }
        else {  
            last; 
        }
    }
}           

# The remaining arguments / operands are the Out_Elements
# The Action output response element names that should be displayed
if ($#ARGV >= 0) {
    @out_elements = @ARGV;
}

# See which options/flags were used...

if (defined $opts{c}) {                 # -c, invoke act on rsrc class
    $Opt_RSRC_Class = $TRUE;
    if (defined $opts{s}) {
        printCEMsg("EMsgMCcliImproperUsageCombination", "-c", "-s");
        &print_usage;
        return MC_CLI_BAD_FLAG;
    }

    # check for -n node_names option
    if (defined $opts{n}) {
        $node_names = $opts{n};
    }
}

if (defined $opts{C}) {                 # -C, invoke act on rsrc class
    $Opt_RSRC_Class_DM = $TRUE;
    $peer_domain_names = $opts{C};
    if (defined $opts{s}) {
        printCEMsg("EMsgMCcliImproperUsageCombination", "-C", "-s");
        &print_usage;
        return MC_CLI_BAD_FLAG;
    }
    if (defined $opts{c}) {
        printCEMsg("EMsgMCcliImproperUsageCombination", "-C", "-c");
        &print_usage;
        return MC_CLI_BAD_FLAG;
    }
    if (defined $opts{n}) {
        printCEMsg("EMsgMCcliImproperUsageCombination", "-C", "-n");
        &print_usage;
        return MC_CLI_BAD_FLAG;
    }
}

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

if (defined $opts{r}) {                 # -r, rm using rsrc handles
    $Opt_RSRC_Handle = $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{c}) {
        printCEMsg("EMsgMCcliImproperUsageCombination", "-c", "-r");
        &print_usage;
        return MC_CLI_BAD_FLAG;
    }
    if (defined $opts{n}) {
        printCEMsg("EMsgMCcliImproperUsageCombination", "-n", "-r");
        &print_usage;
        return MC_CLI_BAD_FLAG;
    }
    if (defined $opts{s}) {
        printCEMsg("EMsgMCcliImproperUsageCombination", "-s", "-r");
        &print_usage;
        return MC_CLI_BAD_FLAG;
    }
    if (defined $opts{C}) {
        printCEMsg("EMsgMCcliImproperUsageCombination", "-C", "-r");
        &print_usage;
        return MC_CLI_BAD_FLAG;
    }
}

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_Select_Str = $TRUE;
}
elsif (!defined $opts{c} && !defined $opts{r} && !defined $opts{C}) {
    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{c})
    {
        printCEMsg("EMsgMCcliImproperUsageCombination", "-N", "-c");
        &print_usage;
        return MC_CLI_BAD_FLAG;
    }
    elsif (defined $opts{C})
    {
        printCEMsg("EMsgMCcliImproperUsageCombination", "-N", "-C");
        &print_usage;
        return MC_CLI_BAD_FLAG;
    }
    elsif (defined $opts{r})
    {
        printCEMsg("EMsgMCcliImproperUsageCombination", "-N", "-r");
        &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;
}

# The -l overrides the -t which overrides the -d which overrides -D
# Long is the default display format 
if (defined $opts{l}) {
    $Opt_Long_Format = $TRUE;
}
elsif (defined $opts{t}) {
    $Opt_Table_Format = $TRUE;          # -t tabular format
    $Opt_Long_Format = $FALSE;
}
elsif (defined $opts{d}) {              # -d delimitter format
    $Opt_Delm_Format = $TRUE;
    $Opt_Long_Format = $FALSE;
}
elsif (defined $opts{D}) {              # -D <delimitter> format
    $Opt_Delm_Format = $TRUE;
    $Opt_Long_Format = $FALSE; 
    $Opt_Delm_Str = $opts{D};
}

if (defined $opts{x}) {                 # -x do not print header
    $Opt_No_HDR = $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, $r_rsrc_handle, $action, $rsrc_file, 
    $select_str, $node_names, $peer_domain_names, $node_file_name,
    \@in_elements, \@out_elements);
}   # 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("IMsgrunactUsage4");
}   # end print_usage



#--------------------------------------------------------------------#
# format_sd_element_defs - formats the structured data elements into #
#   a complex hash of SD element definitions (%rHoSDEleDefs).        #
#   The level 1 hash                                                 #
#     key = element_name data = hash                                 #
#     or                                                             #
#     key = element_index data = hash                                #
#   Typically when processing the SD input def we want the key       #
#   to be the element_name.  But when processing the SD response def #
#   where we want to display the response SD, having the key as      #
#   the SD element index makes more sense.                           #
#   The level 2 hash                                                 #
#     key = (sd_name, sd_dtype, sd_index, sd_value)                  #
#     the values from mc_qdef_sd_bp of those fields                  #
#   Example:                                                         #
#     x $rHoSDEleDefs                                                #
#     0  'Int32'                                                     #
#     1  HASH(0x2045ddd0)                                            #
#        'sd_dtype' => 2                                             #
#        'sd_index' => 0                                             #
#        'sd_name' => 'Int32'                                        #
#        'sd_value' => undefined                                     #
#     or                                                             #
#     0  0                                                           #
#     1  HASH(0x2045ddd0)                                            #
#        'sd_dtype' => 2                                             #
#        'sd_index' => 0                                             #
#        'sd_name' => 'Int32'                                        #
#        'sd_value' => undefined                                     #
#                                                                    #
# Parameters:                                                        #
#   $resource         input   Resource Name                          #
#   $response         input   Reference to array returned by         #
#                             lsrsrcdef-api.                         #
#   %$rHoSDEleDefs    in/out  Reference to the hash of SD element    #
#                             definitions.                           #
#   $hash_by_name     input   TRUE - hash by element_name.           #
#                             FALSE - hash by element_index.         #
#                                                                    #
# Global References:                                                 #
#   None.                                                            #
#--------------------------------------------------------------------#
sub format_sd_element_defs
{
#my($resource, $response, $rHoSDEleDefs, $hash_by_name) = @_;
my($resource, $response, $rHoSDEleDefsIn, $rHoSDEleDefsResp) = @_;

my %elements = ();
my @resp_info = ();
my ($element_name, $element_index, $element_cnt);

# get count of array elements
my $response_cnt = $#$response;

# keep track of if we're processing input or response
my $Input = $TRUE;

# check if there are no input elements 
if ( ($response_cnt >= 0)  &&  ($$response[0] =~ /^.*::\"OUT\"::/) ) {
   $Input = $FALSE;
}

# form the hash
for (my $e = 0; $e <= $response_cnt; $e++) {
    %elements = ();
    chomp($$response[$e]);
    @resp_info = split (/::/, $$response[$e]);
    $element_name = $resp_info[2];
    $element_name =~ s/\"//g;
    $element_index = $resp_info[6];
    $elements{sd_name} =  $element_name;
    $elements{sd_index} = $element_index;
    $elements{sd_dtype} = $resp_info[3];

    # assign to proper structure
    if ($Input) {
        $$rHoSDEleDefsIn{$element_name} = { %elements };
    }
    else {
        $$rHoSDEleDefsResp{$element_name} = { %elements };
    }

    # see if input has ended and responses are next
    if ( ($e < $response_cnt) && ($$response[$e+1] =~ /^.*::\"OUT\"::/) ) {
        $Input = $FALSE;
    } 
}   # end for each response

return;
}   # end of format_sd_element_defs

#--------------------------------------------------------------------#
# 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_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_Class, $r_cmdline) = @_;
my $rc = 0;
my $rLoRsrcData;

if ($Opt_File_Input) {
    my $file_stanza; 
    if ($Opt_Class) {
        $file_stanza = "ResourceClassAction";
    }
    else {
        $file_stanza = "ResourceAction";
    }

    ($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
        printEMsg("EMsgrunactInputFileError", $filename);
        exit(MC_CLI_USER_ERROR);
    }
}
else {
    # set empyt list if no args
    if ($#$r_cmdline < 0) {
       $rLoRsrcData = $r_cmdline;
    }
    # process the args
    else {
       ($rc, $rLoRsrcData) = process_cmdline_input($r_cmdline);
       if ($rc != 0) {
            # Print Command Line Error Attr=value error msg
            printEMsg("EMsgrunactCmdLineError", $r_cmdline);
            exit(MC_CLI_BAD_OPERAND);
       }
    }
}

if ($Verbose) {
    my ($attribute, $value, $entry, $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


#--------------------------------------------------------------------#
# build_action_input_sd - function to build up the parameters for    #
#   the runact-api command.                                          #
#                                                                    #
# Parameters:                                                        #
#   $resource         input   Resource name.                         #
#   $action           input   Action name.                           #
#   $handle           input   Resource handle.                       #
#   $selstr           input   Select string.                         #
#   $node_name        input   Node name.                             #
#   $peer_domain_names input  Peer domain names.                     #
#   $rActionData      input   Reference to array of attr,value pairs.#
#   $rHoSDInDef       input   Reference to hash of the action input  #
#                             SD element definitions for this action.#
#                                                                    #
# Return:                                                            #
#   $rc                       return code.                           #
#   $runcmd                   String containing runact-api parms.    #
#                                                                    #
# Global References:                                                 #
#   Opt_RSRC_Class    input   Class action (-c).                     #
#   Opt_RSRC_Class_DM input   Class action (-C).                     #
#   Opt_RSRC_Handle   input   Resource handle specified (-r).        #
#   Opt_Select_Str    input   Select string specified (-s).          #
#   DELIMITER         input   Input delimiter.                       #
#--------------------------------------------------------------------#
sub build_action_input_sd
{
my ($resource, $action, $handle, $selstr, $node_name, $peer_domain_names,
               $rActionData, $rHoSDInDef) = @_; 

my ($new_element, $data_type);
my $element_list = "";         
my ($element_name, $element_value);
my $badrc = 0;
my $runcmd = "";
my $delim = "";

foreach $new_element (@{$rActionData->[1]}) {
    $element_name = $new_element->[0];

    # first check to make sure this is a valid sd element name
    if (!defined($$rHoSDInDef{$element_name})) {
        printEMsg("EMsgrunactInvalidSDElement", $element_name, 
            $resource, $action, '"' . $rActionData->[0] . '"');
        $badrc = MC_CLI_USER_ERROR;
        next;                   # continue validating rest of input
    }   
    
    # Get the elements value 
    $data_type = $rHoSDInDef->{$element_name}{sd_dtype};
    # An SD cannot contain an SD
    if (($data_type =~ /^CT_SD_PTR$/) || ($data_type =~ /^CT_SD_PTR_ARRAY$/)) {
        printEMsg("EMsgrunactInvalidDataType", $action, $element_name,
            $data_type);
        $rc = MC_CLI_USER_ERROR;
    }
    $element_value = $new_element->[1];

    # get rid of quotes in arrays, but not in string arrays
    if ( ($data_type =~ /ARRAY$/) && ($data_type !~ /^CT_CHAR_PTR_ARRAY$/) ) {
         $element_value =~ s/\"//g;
    }

    $element_list .= $delim . $element_name . $DELIMITER . $element_value;
    $delim = $DELIMITER;
}

# put the command together
# for class, it's -c class::node::
if ($Opt_RSRC_Class)  { 
   $runcmd = "-c \"${resource}${DELIMITER}${node_name}"; 
}

# for class, it's -C class::peer_domain_names::
if ($Opt_RSRC_Class_DM)  { 
   $runcmd = "-C \"${resource}${DELIMITER}${peer_domain_names}"; 
   # set DM scope for -C
   $ENV{CT_MANAGEMENT_SCOPE} = 3;
}

# for resource handle, it's -r handle::
elsif ($Opt_RSRC_Handle) { 
   $runcmd = "-r \"$handle"; 
}

# for select string, it's -s class::select_str
elsif ($Opt_Select_Str)
{ 
   $selstr = escape_chars($selstr);
   
   if ($Opt_Node_File)
   {
       # create temp file based on Stdin input
       if ($Opt_Stdin)
       {
           $node_file_name= read_from_Stdin();
       }
       $runcmd = "-w \"${resource}${DELIMITER}${selstr}${DELIMITER}${node_file_name}";
   }
   else
   {
       $runcmd = "-s \"${resource}${DELIMITER}${selstr}"; 
   }
}

$element_list = escape_chars($element_list);

# add the action and arg/value pairs
$runcmd .= $DELIMITER . $action . $DELIMITER . $element_list . "\"";

return($badrc, $runcmd);
}   # end build_action_input_sd


#--------------------------------------------------------------------#
# build_action_input_no_sd - function to build up the parameters for #
#   the runact-api command when no arguments are used.               #
#                                                                    #
# Parameters:                                                        #
#   $resource         input   Resource name.                         #
#   $action           input   Action name.                           #
#   $handle           input   Resource handle.                       #
#   $selstr           input   Select string.                         #
#   $node_name        input   Node name.                             #
#   $peer_domain_names input  Peer domain names.                     #
#                                                                    #
# Return:                                                            #
#   $runcmd                   String containing runact-api parms.    #
#                                                                    #
# Global References:                                                 #
#   Opt_RSRC_Class    input   Class action (-c).                     #
#   Opt_RSRC_Class_DM input   Class action (-C).                     #
#   Opt_RSRC_Handle   input   Resource handle specified (-r).        #
#   Opt_Select_Str    input   Select string specified (-s).          #
#   DELIMITER         input   Input delimiter.                       #
#--------------------------------------------------------------------#
sub build_action_input_no_sd
{
my ($resource, $action, $handle, $selstr, $node_name, $peer_domain_names) = @_;
my $runcmd = "";
my $delim = "";

# put the command together
# for class, it's -c class::node::
if ($Opt_RSRC_Class)  {
   $runcmd = "-c \"${resource}${DELIMITER}${node_name}";
}

# for class, it's -C class::peer_domain_names::
if ($Opt_RSRC_Class_DM)  {
   $runcmd = "-C \"${resource}${DELIMITER}${peer_domain_names}";
   # set DM scope for -C
   $ENV{CT_MANAGEMENT_SCOPE} = 3;
}

# for resource handle, it's -r handle::
elsif ($Opt_RSRC_Handle) {
   $runcmd = "-r \"$handle";
}

# for select string, it's -s class::select_str
elsif ($Opt_Select_Str)  {

   # escape inner quotes
   $selstr = escape_chars($selstr);
   if ($Opt_Node_File)
   {
       # create temp file based on Stdin input
       if ($Opt_Stdin)
       {
           $node_file_name= read_from_Stdin();
       }
       $runcmd = "-w \"${resource}${DELIMITER}${selstr}${DELIMITER}${node_file_name}";
   }
   else
   {
       $runcmd = "-s \"${resource}${DELIMITER}${selstr}";
   }
}

# add the action and arg/value pairs
$runcmd .= $DELIMITER . $action . "\"";

return($runcmd);
}   # end build_action_input_sd


#--------------------------------------------------------------------#
# format_and_display_SD - formats and displays the action response   #
#   SD elements.                                                     #
#                                                                    #
# Parameters:                                                        #
#   $response         input   Reference to array of runact-api       #
#                             output.                                #
#   $rlo_elements     input   Reference to list of SD element names. #
#                             If empty print all SD elements else    #
#                             print only the ones specified.         #
#   %$rHoSDRspDef     input   Reference to the hash of SD response   #
#                             definition (from get_sd_element_defs)  #
#                             x %$rHoSDRspDef to see format of hash. #
#                                                                    #
# Global References:                                                 #
#   $Opt_Long_Format  input   TRUE if should display one per line.   #
#   $Opt_Table_Format input   TRUE if should display in table form.  #
#   $Opt_Delm_Format  input   TRUE if should display with delimiter. #
#   $Opt_Delm_Str     input   Actual delimiter to display with.      #
#   $Opt_No_HDR       input   TRUE if should not display header.     #
#   $Opt_Class        input   TRUE if -c or -C used.                 #
#--------------------------------------------------------------------#
sub format_and_display_SD
{
my ($response, $rlo_elements, $rHoSDRspDef) = @_;
my @LoElements = ();
my %HoElements = ();
my %elements = ();
my ($element_name, $element_count);
my $TOO_MANY = 100;

my $title_col;
my @title_row;
my $print_format = "long";        
my $delim = "";
my $idcount = 0;
my $start_num = 0;

my $rc = 0;

# Determine if displaying in long, delimiter or tabular/column format.
if ($Opt_Long_Format) {
    $print_format = "long";
}
elsif ($Opt_Table_Format) {
    $print_format = "column";
}
elsif ($Opt_Delm_Format) {
    $print_format = "delim";
    $delim = $Opt_Delm_Str;
}

$title_row = "sd_element";

my @r_info = (); 
my $node_name = "";
my $response_count = $#$response;
my $s = 0;              # number of SDs to be displayed

# if there's alot of data, make this 2 pass by forming the list of element
# names first, and then filling in the hash to display multiple times.
if ($response_count >= $TOO_MANY) {

    for (my $r = 0; $r <= $response_count; $r++) {

       # parse each response
       chomp($$response[$r]);
       @r_info = split (/$DELIMITER/, $$response[$r]);

       # if there is an odd number of array elements, the
       # first is the node name of where it came from
       my $rem = $#r_info % 2;
       if (!$rem) { $node_name = shift @r_info; }

       # format the responses
       for (my $k = 0; $k <= $#r_info; $k=$k+2) {
            $element_name = $r_info[$k];
            if ( (!exists ${$rHoSDRspDef}{$element_name}{sd_dtype}) &&
                 ( $element_name =~ /^\(CT\_/) ) {
               $idcount = $k/2;
               $element_name = "ACT_RSP_ELE_$idcount";
            }

            if (!(exists $HoElements{$element_name})) {
               # add the new attribute to the list of attributes
               push @LoElements, $element_name;

               # Add an empty array for this new attr name
               my @fields = ();
               $HoElements{$element_name} = [ @fields ];
            }
       }
   }   # end for each response
}

# Display the header to the output here since it needs
# to use a catalogued message.
$title_col = "";
if (!$Opt_No_HDR) {
    ($Opt_Class) ?
        printIMsg("IMsgrunactRsrcClassRspHdr", $action) :
        printIMsg("IMsgrunactRsrcActRspHdr", $action);
}

# break up processing the output, if necessary
for (my $ii = 0; $ii < int( ($response_count / $TOO_MANY) +1); $ii++) {
    $s=0;
for (my $r = $ii * $TOO_MANY;
        ($r < ($ii+1)*$TOO_MANY) && ($r <= $response_count);
         $r++) {

    # parse each response 
    chomp($$response[$r]);
    @r_info = split (/$DELIMITER/, $$response[$r]);

    # if there is an odd number of array elements, the 
    # first is the node name of where it came from
    my $rem = $#r_info % 2;
    if (!$rem) { $node_name = shift @r_info; }

#   my @loSDs = $response->data($r);
    # format the responses 
    for (my $k = 0; $k <= $#r_info; $k=$k+2) {
         %elements = ();
         $element_name = $r_info[$k];
         $elements{at_name} = $element_name;
         $elements{at_dtype} = ${$rHoSDRspDef}{$element_name}{sd_dtype};
         if ( (!exists ${$rHoSDRspDef}{$element_name}{sd_dtype}) &&
              ( $element_name =~ /^\(CT\_/) ) {
            $elements{at_dtype} = $element_name;
            $elements{at_dtype} =~ s/^\(//;
            $elements{at_dtype} =~ s/\)$//;
            $idcount = $k/2;
            $element_name = "ACT_RSP_ELE_$idcount";
            $elements{at_name} = $element_name;
         }
         $elements{at_value} = $r_info[$k+1];

         # quote any resource handles and binary values
         if ( ($elements{at_dtype} =~ /^CT_RSRC_HANDLE_PTR$/) ||
              ($elements{at_dtype} =~ /^CT_BINARY_PTR$/) ) {
            $elements{at_value} = "\"" . $elements{at_value} . "\"";
         }
         if ( ($elements{at_dtype} =~ /^CT_RSRC_HANDLE_PTR_ARRAY$/) ||
              ($elements{at_dtype} =~ /^CT_BINARY_PTR_ARRAY$/) ) {
            $elements{at_value} =~ s/\{/\{\"/;
            $elements{at_value} =~ s/\}/\"\}/;
            $elements{at_value} =~ s/,/\",\"/g;
         }

         build_HoAttr($element_name, \@LoElements, \%HoElements,
              \%elements, $s);   
    }
    $s++;     # number of SDs to be displayed
}   # end for each response

# Display the SD elements in the order that they were requested
# on the command line.  If no response element names were specified 
# on the command line display them in the order that RMC returned
# them.

if (scalar(@$rlo_elements) == 0) {
    $rlo_elements = \@LoElements;
}
else {
    # ensure all response elements from cmd line are valid
    foreach $element (@$rlo_elements) {
        if ((!exists ${$rHoSDRspDef}{$element}) && 
            ($element !~/^ACT_RSP_ELE/)) {
            printEMsg("EMsgrunactBadRspElt", $element, $action);
            $rc = MC_CLI_USER_ERROR;
        }
    }
    ($rc == 0) || return $rc;
}

# Only display table header first time display everything from
# one response
$start_num = ($ii * $TOO_MANY)+ 1;
$rc = display_resource_data_api3($print_format, $Opt_No_HDR, $rlo_elements,
        $title_row, \%HoElements, $delim, $title_col, $start_num);

# reset the hash in case we have to do it again for more data
%HoElements = ();
foreach $element (@LoElements) {

          # Add an empty array for this attr name
          my @fields = ();
          $HoElements{$element} = [ @fields ];
}

}

return $rc;
}   # end format_and_display_SD


#--------------------------------------------------------------------#
# 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 resource class name.               #
#   $action           in      The action name.                       #
#   $response         in      RMC response.                          #
#   $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, $action, $response,
    $rmc_rc, $error) = @_;

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

if ($rmc_rc != 0) {
    printEMsg("EMsgrunactRunActError", $action);
    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_ECLASSNOTDEFINED) {
            printCEMsg("EMsgMCcliClassNotDef", $rmc_class);
            $rc = MC_CLI_USER_ERROR;
        }
        elsif ($err_rc == RMC_EBADACTIONNAM) {
            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("EMsgrunactRunActError", $action);
            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