#!/usr/bin/perl
# IBM_PROLOG_BEGIN_TAG 
# This is an automatically generated prolog. 
#  
#  
#  
# Licensed Materials - Property of IBM 
#  
# (C) COPYRIGHT International Business Machines Corp. 2001,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 = "@(#)59   1.19   src/rsct/rmc/cli/bin/startrsrc.perl, rmccli, rsct_rady, rady2035a 11/12/15 16:30:53"
######################################################################
#                                                                    #
# Module: startrsrc                                                  #
#                                                                    #
# Purpose:                                                           #
#   startrsrc - Starts (brings on-line) a defined resource.          #
#                                                                    #
# Syntax:                                                            #
#   To start one or more resources, using data entered on the        #
#   command line:                                                    #
#   startrsrc [-h] -s "Selection_string" [-n Node_name] [-T] [-V]    #
#          Resource_class [Arg=value...]                             #
#   startrsrc [-h] -r [-n Node_name] [-T] [-V]                       #
#          Resource_handle [Arg=value...]                            #
#                                                                    #
#   To start one or more resources using command arguments           #
#   predefined in an input file:                                     #
#   startrsrc [-h] -f Resource_data_input_file -s "Selection_string" #
#             [-n Node_name] [-T] [-V] Resource_class                #
#   startrsrc [-h] -f Resource_data_input_file -r                    #
#             [-n Node_name] [-T] [-V] Resource_handle               #
#                                                                    #
#   To list the required command arguments names and data types:     #
#   startrsrc [-h] -l [-T] [-V] Resource_class                       #
#                                                                    #
#                                                                    #
# Flags:                                                             #
#   -h      Help. Writes this command's usage statement to stdout.   #
#   -f Resource_data_input_file File input. Specifies the name of    #
#           the file which contains resource attribute 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.                                 #
#   -l      List command arguments and data types. Some Resource     #
#           managers accept additional arguments passed to the       #
#           online request. Use the -l flag to list any defined      #
#           command arguments and the data type of the command       #
#           argument values.                                         #
#   -n Node_name  The node name of the node where the resource is to #
#           be brought on-line. Do not specify this flag if you wish #
#           for the resource to be brought on-line on the node where #
#           it is known. Use this flag to bring a floating resource  #
#           on-line on a different node when the node where it had   #
#           been on-line may be down. The node name is one of the    #
#           names contained in the NodeNameList attribute.           #
#           TODO: May need to decide that this should become a       #
#           Nodelist, a comma separated list of hostnames.           #
#   -r      Resource Handle. Brings on-line the specific             #
#           resource that matches the specified resource handle.     #
#   -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 name of the resource class whose resources   #
#                   we are selecting to bring on-line.               #
#                                                                    #
#   Resource_handle Brings on-line the resource that corresponds to  #
#                   this resource handle.                            #
#                                                                    #
#   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 online     #
#                   function for the specified resource class.       #
#                   Use startrsrc -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.#
#                   Run lscmdargdef -o Resource_class to determine   #
#                   the data type.                                   #
#                                                                    #
# Description:                                                       #
#   The startrsrc command requests the RMC subsystem to bring        #
#   on-line one or more resources. The request is actually performed #
#   by the appropriate resource manager.                             #
#                                                                    #
#   To start one or more resources use the -s flag to bring on-line  #
#   all the resources that match the specified "Selection_string".   #
#   To start one specific resource use the -r flag to specify the    #
#   Resource_handle that represents that specific resource.          #
#                                                                    #
#   The successfull completion of this command does not guarantee    #
#   that the resource is on-line. Only that the resource manager     #
#   successfully received the request to bring this resource on-line.#
#   The resources OpState attribute should be monitored to determine #
#   when the resource is actually brought on-line. Register an event #
#   for the resource, specifying the OpState attribute, to know when #
#   the resource is actually on-line. Or intermittently run lsrsrc   #
#   until you see the resource is on-line.                           #
#                                                                    #
#   Prior to running startrsrc, run the lscmdargdef command to       #
#   determine if the specified resource class accepts any additional #
#   arguments on the startrsrc command.                              #
#                                                                    #
# 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:                                                          #
#   startrsrc -s 'Name == "c175n05"' IBM.Foo  TODO add args.         #
#   startrsrc -r "0x406b 0x0001 0x00000000 0x0069564c 0x0dc1f272     #
#                 0xb9de145e"  TODO add args...                      #
#                                                                    #
# Man Page:                                                          #
#   For the most current detailed description of this command see    #
#   the startrsrc man page in /opt/rsct/man.                    #
#                                                                    #
#--------------------------------------------------------------------#
# Inputs:                                                            #
#   /opt/rsct/msgmaps/mccli.mccli.map - message mapping         #
#   /opt/rsct/msgmaps/mccli.startrsrc.map - message mapping     #
#                                                                    #
# Outputs:                                                           #
#   stdout - optionally the required command arguments and data      #
#            types for the specified resource.                       #
#   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:                                                   #
#   010615 SAB 75111: Initial design & write.                        #
#   011214 JAC 77349: Change nodeid to nodename (but just 1)         #
#   011217 JAC 79061: Remove using a default for nodenamelist.       #
#   020307 JAC 80897: Update prolog and point to new help message.   #
#   020925 JAC 87393: Change CT_cli_display_utils to .._displayext.. #
#   030108 JAC 88089: Remove perl extensions.                        #
#   030404 JAC 92787: Don't allow -s "" for selection string.        #
#   040312 JAC 105726: Remove braces around node name for -n.        #
#   040407 JAC 105863: Use escape_chars for "\" searches.            #
######################################################################

#--------------------------------------------------------------------#
# General Program Flow/Logic:                                        #
#                                                                    #
# TODO: Update this section.                                         #
# 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 define command arguments for this   #
#    resource class. There may not be any defined.                   #
# G. Parse the cmd_arg = value pairs from the command line or        #
#    from the input file.                                            #
# H. Invoke the on-line 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
    printCEMsg
    get_class_from_rsrc_hndl_api
    process_exit_code
    process_api_error
    remove_api_error
    build_cmd_arg_sd_api
    get_arg_defs_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 output, attribute name value pairs should be entered
# via the command line.  Attr=value   e.g. Name=c175n06 NodeNumber=1
$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_Ls_Cmd_Args = $FALSE;              # default - see -l (list args)
$Opt_Node = $FALSE;                     # default - see -n (start node)
$Opt_Node_File= $FALSE;                 # default - see -N
$Opt_Stdin= $FALSE;                     # default - see -N with Stdin

$PROGNAME = "startrsrc";                # 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 
$DELIMITER = "tvrtvrtvr";

#--------------------------------------------------------------------#
# 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 = ();
my $resource;                           # resource class name
my $r_rsrc_handle;                      # reference to rsrc handle
my $filename;                           # -f filename, input file
my $node_name = "";                     # -n node, node where rsrc 
                                        # will be brought on-line.
my @node_name_list = ();                # list of node names
my $number_names;                       # number is list of node names
my $select_str;                         # -s selection string
my $cmdline_args;                       # Reference to array of 
                                        # Cmd_Args=value pairs

my @start_out = ();                     # startrsrc-api result
my $rc = 0, $badrc = 0;
my $rsrc_class_id = 0;
my $node_file_name;                     # to hold node filename

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

# parse the command line, exit if there are errors 
($rc, $resource, $r_rsrc_handle, $filename, $node_name, $select_str,
    $node_file_name, $cmdline_args) = &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 brought on-line.
# 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) || 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 online command SD argument definitions for this 
    # resource class. SD element name are key to level 1 hash. 
    $rc = get_arg_defs_api($resource, "", "online",
         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);
}

if (!$Opt_Ls_Cmd_Args) {
    # 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,
            $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 bring the resource online - 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);
  
    # form the command arguments to pass to startrsrc-api
    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};
          }
       }
    }

    # add check for node specified (-n)
    my $st_node_name = "$DELIMITER";
    if ($Opt_Node) {$st_node_name .= "$node_name";}

    # figure out what form of startrsrc-api is needed and call it
    if ($Trace) { print STDERR "Calling startrsrc-api:\n"; }

    $cmd_opts = escape_chars($cmd_opts);

    # make call to startrsrc-api
    if ($Opt_RSRC_Handle) {
       @start_out = `$CTBINDIR/startrsrc-api -I $DELIMITER -D $DELIMITER -r "${r_rsrc_handle}${st_node_name}${cmd_opts}" 2>&1`;
    }
    elsif ($Opt_Select_Str) {
       $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();
           }
       
           @start_out = `$CTBINDIR/startrsrc-api -I $DELIMITER -D $DELIMITER -w "${resource}${DELIMITER}${select_str}${DELIMITER}${node_file_name}${DELIMITER}${st_node_name}${cmd_opts}" 2>&1`;
           
           # remove temp node file if from STDIN
           if ($Opt_Stdin)
           {
               unlink($node_file_name);
           }
       }
       else
       {
           @start_out = `$CTBINDIR/startrsrc-api -I $DELIMITER -D $DELIMITER -s "${resource}${DELIMITER}${select_str}$st_node_name${cmd_opts}" 2>&1`;
       }
    }

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

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

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

}   # end (!$Opt_Ls_Cmd_Args)

($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.   #
#         SR_CLI_BAD_FLAG    Command line contained a bad flag.      #
#   $resource                Resource Class Name.                    #
#   $r_rsrc_handle           Reference to a resource handle.         #
#   $rsrc_file               Name of file that contains cmd args.    #
#   $node_name               Node name where to bring rsrc on-line.  #
#   $select_str              Selection string.                       #
#   @cmdline_args            Reference to an array of                #
#                            Command Argument = value pairs.         #
#                                                                    #
# Global Variables Modified:                                         #
#   $Opt_Select_Str    output   True (-s select_string), bring       #
#                               on-line the resources that match     #
#                               specified selection string.          #
#   $Opt_RSRC_Handle   output   True (-r), bring on-line the         #
#                               resource handle specified as operand.#
#   $Opt_File_Input    output   True (-f) read cmd arg data from file#
#   $Opt_Ls_Cmd_Args   output   True (-l) list command argument      #
#                               names and data types.                #
#   $Opt_Node          output   True (-n) node specified.            #
#   $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 $node_name = "";
my $select_str = "";
my $node_file_name= "";
my @cmdline_args = ();
my $rc;
my %opts = ();

# Process the command line...
if (!GetOptions(\%opts,
                'h|help|version' ,
                'l' ,
                'r' ,
                'T' ,
                'V' , 
                '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
}
else {
    (defined $opts{r}) ? printCEMsg("EMsgMCcliMissingRsrcHandle") : 
        printCEMsg("EMsgMCcliMissingRsrcClass");
    &print_usage;
    return MC_CLI_BAD_OPERAND;          # return bad rc - bad operand
}

                                        # need to handle sd input and
# Grab all of the Cmd_Args=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 @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;
    }       
}

# 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{n}) {                 # -n, node name for on-line
    $Opt_Node = $TRUE;
    $node_name = $opts{n};
}

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_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{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{l} && !defined $opts{r}) {
    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{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, $r_rsrc_handle, $rsrc_file, $node_name,
    $select_str, $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("IMsgstartrsrcUsage2");
}   # 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 "startrsrc $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 #
#   @$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, $r_cmdline) = @_;
my $rc = 0;
my $rLoRsrcData;

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

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

if ($rmc_rc != 0) {
    printEMsg("EMsgstartrsrcStartRsrcError", $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_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;
        }
        # It is possible for Resource Class to have no Cmd Args
        # defined - this is not an error.
        elsif ($err_rc == RMC_ESDNOTDEFINED) {
            $rc = 0;
        }
        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("EMsgstartrsrcStartRsrcError", $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