#!/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 = "@(#)17   1.24   src/rsct/rm/ConfigRM/cli/bin/chcomg.perl, configrmcli, rsct_rady, rady2035a 11/12/15 16:41:10"
######################################################################
#                                                                    #
# Module: chcomg                                                     #
#                                                                    #
# Purpose:                                                           #
#   chcomg - changes a previously defined communication group for a  #
#            cluster                                                 #
#                                                                    #
# Syntax:                                                            #
#   To change attributes of a communication group:                   #
#   chcomg  [-h] [-s Sensitivity] [-p Period] [-t Priority]          #
#           [-b] [-r] [-x br] [-e NIM_path] [-m NIM_parameters]      #
#	    [-N UseForNodeMembership]				     #
#           [-TV] Communication_group                                #
#                                                                    #
#   To change the membership of a communication group:               #
#   chcomg  [-h] [-i n:Network_interface_name:[Node_name][,Network_- #
#           interface_name:[Node_name],...] |-S n:"Network_interface-#
#           _selection_string"] [-TV] Communication_group            #
#                                                                    #
# Flags:                                                             #
#   -h      Help. Writes the command's usage statement to standard   #
#           output.                                                  #
#   -s Sensitivity   The sensitivity number. This is the number of   #
#           missed heartbeats that constitute a failure.  The        #
#           sensitivity value is an integer greater than or equal to #
#           2.                                                       #
#   -p Period        The period number. This is the number of seconds#
#           between heartbeats.   The value of  period is in seconds,#
#           can be an integer or floating point number, and is       #
#           significant to milliseconds.                             #
#   -g grace_period  Specifies the grace period used when heartbeats #
#           are no longer received. When a heartbeat is missed, an   #
#           echo packet is sent to the failed node. If the echo is   #
#           returned, then the grace period is initiated. The value  #
#           of grace_period is in seconds, can be an integer or      #
#           floating point number that is significant to             #
#           milliseconds, or can be one of the following values:     #
#            0          The grace period is disabled.                #
#            -1 or "d"  The default mode where Topology Services     #
#                       controls the grace period.                   #
#   -t Priority      The priority number.  The priority indicates    #
#           the importance of this communication group with respect  #
#           to others.  It is used to order the heartbeat rings. The #
#           lower the number the higher the priority.  The highest   #
#           priority is 1.                                           #
#   -b      Broadcast.  Use broadcast if the underlying media        #
#           support it.                                              #
#   -r      Source routing.  Use source routing if the underlying    #
#           media support it.                                        #
#   -x      Exclude control for heartbeat mechanism.  This indicates #
#           that one or more controls for heartbeat mechanisms       #
#           should not be used even if the underlying media support  #
#           it.                                                      #
#           The following can be excluded:                           #
#           b   This specifies that broadcast should not be used     #
#               even if the underlying media support it.             #
#           r   This specifies that source routing should not be     #
#               used even if the underlying media support it.        #
#           Excluding more than one control is specified by listing  #
#           the feature option letters consecutively (-x br).        #
#   -i      Assigns this communication group to one or more          #
#           interfaces by resource name.  The -i flag cannot be used #
#           with the -S flag.                                        #
#           n:Network_interface_name:[Node_name]   Assign this       #
#              communication group to the network interface with the #
#              resource name Network_interface_name on node          #
#              Node_name.  More than one can be specified, separated #
#              by commas.  If Node_name is not specified, the local  #
#              node is used.                                         #
#   -S      Assigns this communication group to one or more          #
#           interfaces by selection string.  The -S flag cannot be   #
#           used with the -i flag.                                   #
#           n:"Network_interface_selection_string"  The selection    #
#              string applies to the network interface class.  The   #
#              network interfaces found as a result of the selection #
#              string will use this communication group.             #
#   -T      Trace. Writes the command's trace messages to standard   #
#           error. For your software-service organization's use only.#
#   -V      Verbose. Writes the command's verbose messages to        #
#           standard output.                                         #
#   -6      use IPv6 interfaces in new CGs.  Default use IPv4.	     #
#   -N	    specify UseForNodeMembership value			     #
#                                                                    #
# Operands:                                                          #
#   Communication_group   The name of an existing communication      #
#           group to be changed in the cluster.                      #
#                                                                    #
# Description:                                                       #
#   The chcomg command changes an existing communication group       #
#   definition with the name specified by the Communication_group    #
#   operand for the online cluster. The communication group is used  #
#   to define heartbeat rings for use by HATS and to define the      #
#   tunables for each heartbeat ring.                                #
#                                                                    #
#   The chcomg command must be run on a node which is currently      #
#   online in the cluster where the communication group is defined.  #
#                                                                    #
# Exit Values:                                                       #
#   0  CRM_CLI_SUCCESS       Command completed successfully.         #
#   1  CRM_CLI_RMC_ERROR     Command terminated due to an underlying #
#                            RMC error.                              #
#   2  CRM_CLI_ERROR         Command terminated due to an underlying #
#                            error in the command script.            #
#   3  CRM_CLI_BAD_FLAG      Command terminated due to user          #
#                            specifying an invalid flag.             #
#   4  CRM_CLI_BAD_OPERAND   Command terminated due to user          #
#                            specifying a bad operand.               #
#   5  CRM_CLI_USER_ERROR    Command terminated due to a user error, #
#                            for example specifying a name that      #
#                            already exists.                         #
#   6  CRM_CLI_COMG_NOT_FOUND   Communication group definition does  #
#                            not exist.                              #
#                                                                    #
# Examples:                                                          #
#   1. To change the communication group ComGrp1 for the cluster     #
#      ApplCluster to a sensitivity of 1 and a period of 3, and      #
#      nodeA is defined and online to ApplCluster, run the following #
#      command on nodeA:                                             #
#      chcomg -s 1 -p 3 ComGrp1                                      #
#                                                                    #
#   2. To change the communication group ComGrp1 for the cluster     #
#      ApplCluster, to use broadcast, and nodeA is defined and       #
#      online to ApplCluster, run the following command on nodeA:    #
#      chcomg -b ComGrp1                                             #
#                                                                    #
#   3. To change the communication group ComGrp1 for the cluster     #
#      ApplCluster, to not use source routing, and nodeA is defined  #
#      and online to ApplCluster, run the following command on       #
#      nodeA:                                                        #
#      chcomg -x r ComGrp1                                           #
#                                                                    #
# Man Page:                                                          #
#   For the most current detailed description of this command see    #
#   the chcomg man page in /opt/rsct/man.                       #
#                                                                    #
#--------------------------------------------------------------------#
# Inputs:                                                            #
#   /opt/rsct/msgmaps/configrmcli.chcomg.map -                  # 
#       message mapping                                              #
#                                                                    #
# Outputs:                                                           #
#   stdout - none.                                                   #
#   stderr - any error message.                                      #
#                                                                    #
# External Ref:                                                      #
#   Commands: ctdspmsg                                               #
#   Modules:  CRM_cli_utils.pm, CRM_cli_rc.pm,                       #
#             CRM_cli_include.pm, CT_cli_utils.pm                    #
#   Perl library routines: Getopt::Std                               #
#                                                                    #
# Tab Settings:                                                      #
#   4 and tabs should be expanded to spaces before saving this file. #
#   in vi:  (:set ts=4  and   :%!expand -4)                          #
#                                                                    #
# Change Activity:                                                   #
#   010827 JAC 75436: Initial design & write.                        #
#   011207 JAC 77315: Final version of comg commands.                #
#   011219 JAC 78807: Don't resolve node names or check if in cluster#
#   020205 JAC 80023: Use chrsrc-api instead of chrsrc.              #
#   020207 JAC 80121: Make printing of c-api results a trace msg.    #
#   020424 JAC 82359: Fix typos in message calls.                    #
#   020428 JAC 82316: Call process_exit_code to check $rc.           #
#   020501 JAC 82546: Let -m,-n pass "" to chrsrc-api.               #
#   020503 JAC 82564: Set peer domain scope before calling chrsrc-api#
#   020724 JAC 85045: Change -n to -e for command consistency.       #
#   040407 JAC 105863: Use escape_chars for "\" searches.            #
#   050406 JAC 119510: Add rc when calling process_api_error.        #
#   071210 JAC 147147: Use PeriodMillSec and add Grace option.       #
#   080404 JAC 150569: Use Period when -p is integer.                #
######################################################################

#--------------------------------------------------------------------#
# General Program Flow/Logic:                                        #
#                                                                    #
# 1. Parse command line flags and operands.                          #
# 2. Print usage if -h specified                                     #
# 3. Make sure the node is online in the cluster.                    #
# 4. Check and translate the sensitivity, period, broadcast,         #
#    source routing, and exclude options for chrsrc.                 #
# 5. Call RMC command chrsrc. Also pass along -VT if necessary.      #
# 6. Return not found if the communication group didn't exist.       #
# 7. Return back any other errors.                                   #
#                                                                    #
#--------------------------------------------------------------------#

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

use CT_cli_utils qw(printIMsg
                    printEMsg);
use CT_cli_input_utils qw(escape_chars);
use CRM_cli_rc qw(CRM_CLI_SUCCESS CRM_CLI_RMC_ERROR
                  CRM_CLI_ERROR CRM_CLI_BAD_FLAG
                  CRM_CLI_BAD_OPERAND CRM_CLI_USER_ERROR
                  CRM_CLI_COMG_NOT_FOUND);
use CRM_cli_utils qw(error_exit
                     printCIMsg
                     printCEMsg
                     process_exit_code
                     process_api_error
                     get_locator_node
		     get_IPv6Support);
use CRM_cli_include qw($TRUE $FALSE
                       $RMC_CLI_USER_ERROR
                       $RSCOMG $PEER_DOMAIN_SCOPE
                       $RSNETI $RSHBI $PRIORITY_LOW
                       $SENSITIVITY_LOW $PERIOD_LOW
                       $BROADCAST $SRCROUTING
                       $RMC_CLI_RSRC_NOT_FOUND
                       $CTBINDIR $CTDIR
		       $IPVerV4 $IPVerV6);

#--------------------------------------------------------------------#
# Global Variables                                                   #
#--------------------------------------------------------------------#
$Trace = $FALSE;                        # default - trace off
$Verbose = $FALSE;                      # default - verbose turned off

$Opt_Sensitivity = $FALSE;              # default - no Sensitivity 
$Opt_Period = $FALSE;                   # default - no Period
$Opt_Grace  = $FALSE;                   # default - no Grace 
$Opt_Priority = $FALSE;                 # default - no Priority
$Opt_Broadcast = $FALSE;                # default - no UseBroadcast
$Opt_SourceRouting = $FALSE;            # default - no UseSourceRouting
$Opt_Exclude = $FALSE;                  # default - exclude comm ftr
$Opt_NIMpath = $FALSE;                  # default - no NIM path name
$Opt_NIMparms = $FALSE;                 # default - no NIM parameters
$Opt_iSelect = $FALSE;                  # default - no interface sel str
$Opt_Interface = $FALSE;                # default - no interface flag -i
$Opts_change_comg = $FALSE;             # default - no change to comg
$Use_IPv6 = $FALSE;			# default - no -6 IPv6 select
$Opt_NodeMembership = $FALSE;           # default - no change

$PROGNAME = "chcomg";                   # Program Name for messages
$LSMSG = "$CTBINDIR/ctdspmsg";          # list / display message rtn
$MSGCAT = "configrmcli.cat";            # msg catalogue for this cmd
$ENV{'MSGMAPPATH'} = "$CTDIR/msgmaps";  # msg maps used by $LSMSG

#--------------------------------------------------------------------#
# Variables                                                          #
#--------------------------------------------------------------------#
my $comg_name = "";                     # communication group to change
my $new_comg_name = "";                 # new communication group name
my $sensitivity = 0;                    # sensitivity for -s
my $period = 0;                         # period for -p
my $grace  = 0;                         # period for -g
my $priority = 0;                       # priority for -t
my $exclude = "";                       # no broadcast, no source routing
my $i = 0;                              # counter
my $NIMpathname = "";                   # NIM path name
my $NIMparms = "";                      # NIM start parameters
my $INames = "";                        # interface names from -i
my $SelString = "";                     # select string from -S
my $name_exists = $FALSE;               # boolean
my $found = $FALSE;                     # boolean
my $exclude_cnt = 0;                    # count how many to exclude
my $iname = "";                         # an interface name
my $locator = "";                       # an interface node for a name
my $inames = "";                        # interface name/node
my @inames_a = ();                      # interface name/node array
my $resource = "";                      # an interface name/node
my $inter_class = "";                   # interface resource class
my @cmd_out = ();                       # for mkrsrc output

my $passopts = "";                      # TV options to pass to RMC CLI
my $other_opts = "";                    # parameters to pass to RMC CLI
my $delimiter = "#:#";

my $IPVerSel = "";			# IP version select stuff

#--------------------------------------------------------------------#
# Main Code                                                          #
#--------------------------------------------------------------------#
my $rc = 0;

# set peer domain scope
$ENV{CT_MANAGEMENT_SCOPE} = $PEER_DOMAIN_SCOPE;

# parse the command line, exit if there are errors 
($rc, $sensitivity, $period, $grace, $priority, $exclude, $NIMpathname,
      $NIMparms, $INames, $SelString, $comg_name) = &parse_cmd_line;
($rc == 0) || error_exit($rc);

if ($Verbose) { printIMsg("IMsgchcomgStart",$comg_name); }

if ($Trace) { $passopts = $passopts." -T"; }
if ($Verbose) { $passopts = $passopts." -V"; }

# Do some escaping on strings.  Do the escape character first
# for anything that's a string, escape any inner \
#$comg_name =~ s/\\/\\\\/g;
#$NIMpathname =~ s/\\/\\\\/g;
#$NIMparms =~ s/\\/\\\\/g;

# for anything that's a string, escape any inner double quotes
#$comg_name =~ s/\"/\\\"/g;
#$NIMpathname =~ s/\"/\\\"/g;
#$NIMparms =~ s/\"/\\\"/g;

$comg_name = escape_chars($comg_name);
$NIMpathname = escape_chars($NIMpathname);
$NIMparms = escape_chars($NIMparms);

# if IPv6 interfaces were selected, check if IPv6 is supported
if ( $Use_IPv6 ) {
   if ( get_IPv6Support() == $FALSE ) {
      printEMsg( "EMsgchcomgNoIPv6" );
      exit( CRM_CLI_USER_ERROR );
   } else {
      # now build a useful select substring for use below
      $IPVerSel="IPVersion=$IPVerV6";
   }
} else {
   $IPVerSel="IPVersion=$IPVerV4";
}

# pass in Sensitivity if specified
if ($Opt_Sensitivity) {                 # -s used for sensitivity
      # is it a valid value
      if (($sensitivity < $SENSITIVITY_LOW) || 
          ($sensitivity != int($sensitivity))) {
         printEMsg("EMsgchcomgInvalidSensitivity",$sensitivity);
         exit(CRM_CLI_USER_ERROR);
      }
      $other_opts = $other_opts."${delimiter}Sensitivity${delimiter}$sensitivity";
}

# pass in Period if specified
if ($Opt_Period) {                      # -p used for period
      # is it a numeric value
      if ($period !~ /^[0-9]*\.?[0-9]*$/) {
         printEMsg("EMsgchcomgInvalidPeriod",$period);
         exit(CRM_CLI_USER_ERROR);
      }

      # if period is an integer, set the Period attribute
      if ( $period == int($period) ) {
         $period = int ($period);
         $other_opts = $other_opts."${delimiter}Period${delimiter}$period";
      }

      else {
         # multiply by 1000 to get milliseconds and round up if not 0
         if ($period != 0) {
            $period = int ($period * 1000 + 0.5);
         }

         $other_opts = $other_opts."${delimiter}PeriodMilliSec${delimiter}$period";
      }
}

# pass in Grace if specified
if ($Opt_Grace) {                      # -g used for period

      # if grace is a "d", then set a -1
      if ($grace =~ /^d$/) {
         $grace = -1;
      }

      # is it a numeric value (or -1)
      if ( ($grace !~ /^-?[0-9]*\.?[0-9]*$/) || 
           ($grace < -1) ) {
         printEMsg("EMsgchcomgInvalidGrace",$grace);
         exit(CRM_CLI_USER_ERROR);
      }

      # multiply by 1000 to get milliseconds and round up if not 0 or -1
      if ( $grace != 0 && $grace != -1 ) {
         $grace = int ($grace * 1000 + 0.5);
      }

      $other_opts = $other_opts."${delimiter}PingGracePeriodMilliSec${delimiter}$grace";
}

# pass in Priority if specified
if ($Opt_Priority) {                    # -t used for priority
      # is it a valid value
      if (($priority < $PRIORITY_LOW) ||
          ($priority != int($priority))) {
         printEMsg("EMsgchcomgInvalidPriority",$priority);
         exit(CRM_CLI_USER_ERROR);
      }
      $other_opts = $other_opts."${delimiter}Priority${delimiter}$priority";
}

# pass in UseBroadcast if specified
if ($Opt_Broadcast) {                   # -b used for usebroadcast
      $other_opts = $other_opts."${delimiter}UseBroadcast${delimiter}1";
}

# pass in UseSourceRouting if specified
if ($Opt_SourceRouting) {               # -r used for usesourcerouting
      $other_opts = $other_opts."${delimiter}UseSourceRouting${delimiter}1";
}

# pass in No-Broadcast/No-Source Routing if specified
if ($Opt_Exclude) {                     # -x used to exclude
   # count how many to exclude
   $exclude_cnt = 0;
   
   # look for b for (no) broadcast
   if ($exclude =~ /$BROADCAST/) {
      # can't have -b and -x b
      if ($Opt_Broadcast) {
         printCEMsg("EMsgConfigRMcliImproperUsageCombination","-b","-x b");
         exit(CRM_CLI_USER_ERROR);
      }
      $exclude_cnt++;
      $other_opts = $other_opts."${delimiter}UseBroadcast${delimiter}0";
   }

   # look for r for (no) source routing
   if ($exclude =~ /$SRCROUTING/) {
      # can't have -r and -x r
      if ($Opt_SourceRouting) {
         printCEMsg("EMsgConfigRMcliImproperUsageCombination","-r","-x r");
         exit(CRM_CLI_USER_ERROR);
      }
      $exclude_cnt++;
      $other_opts = $other_opts."${delimiter}UseSourceRouting${delimiter}0";
   }

   # anything else?
   if (($exclude_cnt <= 0) || (length($exclude) > $exclude_cnt)) {
      printEMsg("EMsgchcomgInvalidExclude",$exclude);
      exit(CRM_CLI_USER_ERROR);
   }
}

# pass in Node Membership indicator if specified
if ($Opt_NodeMembership) {
      # is it a valid value
      if (($nodemembership != 0) && ($nodemembership != 1)) {
         printEMsg("EMsgchcomgInvalidNodeMembership",$nodemembership);
         exit(CRM_CLI_USER_ERROR);
      }
      $other_opts = $other_opts."${delimiter}UseForNodeMembership${delimiter}$nodemembership";
}

# pass in NIM path name if specified
if ($Opt_NIMpath) {                      # -e used for NIM path
      # check to see if $NIMpathname is null. if specified and null,
      # make sure a null is passed to chrsrc
      if ($NIMpathname =~ /^$/) {
         $NIMpathname = "\\\"\\\"";
      }
      $other_opts = $other_opts."${delimiter}NIMPathName${delimiter}\"$NIMpathname\"";
}

# pass in NIM parameters if specified
if ($Opt_NIMparms) {                     # -m used for NIM parms
      # check to see if $NIMparms is null. if specified and null,
      # make sure a null is passed to chrsrc
      if ($NIMparms =~ /^$/) {
         $NIMparms = "\\\"\\\"";
      }
      $other_opts = $other_opts."${delimiter}NIMParameters${delimiter}\"$NIMparms\"";
}

# if -i specified, determine class to use and selection string
if ($Opt_Interface) {
   if (substr($INames,0,2) eq "n:") {
      $inter_class = $RSNETI;     # set class to NetworkInterface
   } elsif (substr($INames,0,2) eq "h:") {
      $inter_class = $RSHBI;      # set class to HeartbeatInterface
   } else {
      printEMsg("EMsgchcomgInvalidInterfaceFlg",substr($INames,0,1),"i");
      exit(CRM_CLI_USER_ERROR);
   }

   # get the names/nodes
   $inames = substr($INames,2);

   # make it an array of names/nodes
   @inames_a = split /,/,$inames;

   # initialize the select string being built
   $SelString = "";

   # add each resource to select string
   foreach $resource (@inames_a) {

      # get locator, if present
      ($iname,$locator) = get_locator_node($resource);

      # add to select string
      # 1st add OR if not the first one in select string
      if ($SelString ne "") { $SelString .= " || ";}

      # add name/node to select string
      # 160039: allow for intfX:Y suffix, user must specify only
      # base name
      my $INamePat="(Name==\\\"$iname\\\" || Name LIKE \\\"${iname}:%\\\")";
      if ($locator eq "") {
	 $SelString .= $INamePat;
      } else {
	 $SelString .= "($INamePat && NodeNameList|<{\\\"$locator\\\"})";
      }
   }
}       # end -i

# if -S specified, determine class to use and selection string
if ($Opt_iSelect) {
   if (substr($SelString,0,2) eq "n:") {
      $inter_class = $RSNETI;     # set class to NetworkInterface
   } elsif (substr($SelString,0,2) eq "h:") {
      $inter_class = $RSHBI;      # set class to HeartbeatInterface
   } else {
      printEMsg("EMsgchcomgInvalidInterface",substr($SelString,0,1));
      exit(CRM_CLI_USER_ERROR);
   }

   # set the actual selection string
   $SelString = substr($SelString,2);

   # escape some things in the select string
   #$SelString =~ s/\\/\\\\/g;
   #$SelString =~ s/\"/\\\"/g;
   $SelString = escape_chars($SelString);

   # now massage it so that we can accomodate Sun IPMP
   my ( $ante, $namePat, $post ) = split /Name=[\'\"](.*)[\'\"]/, $SelString;
   if ( defined $namePat ) {
      $SelString = $ante."(Name == '$namePat' || Name like '$namePat:%')".$post;
   }
}       # end -S

# select IP version if changing network interfaces
if ( $inter_class eq $RSNETI ) {
   $SelString = "$IPVerSel and ( $SelString )";
}
   
# call chrsrc
if ($Trace) { print STDERR "$PROGNAME: calling chrsrc-api\n";}

# Pick which chrsrc to do
# change communication group
if ($Opts_change_comg) {
   @cmd_out=`$CTBINDIR/chrsrc-api -D"$delimiter" -I"$delimiter" -s ${RSCOMG}${delimiter}"Name==\\\"$comg_name\\\""${other_opts} 2>&1`;

   # capture the return code from chrsrc
   $rc = $?;
   $rc = process_exit_code($rc);
} else { # change interface resource
   @cmd_out=`$CTBINDIR/chrsrc-api -D"$delimiter" -I"$delimiter" -s ${inter_class}${delimiter}\"${SelString}\"${delimiter}CommGroup${delimiter}$comg_name 2>&1`;

   # capture the return code from chrsrc
   $rc = $?;
   $rc = process_exit_code($rc);
}

if ($Trace) { print STDERR "chrsrc-api results:\n";
              print STDERR "@cmd_out";}

if ($Trace) { print STDERR "$PROGNAME: chrsrc-api returned $rc\n";}

# return not found error if rmc couldn't find it
if ($rc == $RMC_CLI_RSRC_NOT_FOUND) {
     # communication group not found
     if ($Opts_change_comg) {
        printEMsg("EMsgchcomgComgrpNotFound",$comg_name);
        exit(CRM_CLI_COMG_NOT_FOUND);
     }
     # interface resource not found
     else {
        printEMsg("EMsgchcomgNoInterfaceFound");
        exit(CRM_CLI_USER_ERROR)
     }
}

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

# return ConfigRM CLI user error if it's an RMC CLI user error
if ($rc == $RMC_CLI_USER_ERROR) { exit(CRM_CLI_USER_ERROR);}

# if chrsrc failed for something else, print RMC error message and exit
if ($rc != 0) {
#   printCEMsg("EMsgConfigRMcliUnExpectRMCrc",$rc);
    exit(CRM_CLI_RMC_ERROR);
    }

if ($Verbose) { printIMsg("IMsgchcomgEnd",$comg_name); }

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.   #
#         CRM_CLI_BAD_FLAG   Command line contained a bad flag.      #
#   $comg_name               Name of communication group to change   #
#   $sensitivity             Heartbeat sensitivity                   #
#   $period                  Heartbeat period                        #
#   $priority                Heartbeat priority                      #
#   $exclude                 Exclude communucation feature           #
#   $NIMpathname             NIM path name to start NIM              #
#   $NIMparms                NIM parms to start NIM                  #
#   $INames                  Resource interface names                #
#   $SelString               Resource interface selection string     #
#                                                                    #
# Global Variables Modified:                                         #
#   $Verbose           output   True (-V) turn Verbose mode on.      #
#   $Trace             output   True (-T) turn Trace mode on.        #
#   $Opt_Sensitivity   output   True (-s) Sensitivity specified      #
#   $Opt_Period        output   True (-p) Period specified           #
#   $Opt_Grace         output   True (-g) Grace specified            #
#   $Opt_Priority      output   True (-t) Priority specified         #
#   $Opt_Broadcast     output   True (-b) use broadcast specified    #
#   $Opt_SourceRouting output   True (-r) use source routing spec    #
#   $Opt_Exclude       output   True (-x) Exclude communication ftr  #
#   $Opt_NIMpath       output   True (-e) NIM path name specified    #
#   $Opt_NIMparms      output   True (-m) NIM parameters specified   #
#   $Opt_Interface     output   True (-i) interface name specified   #
#   $Opt_iSelect       output   True (-S) interface select string    #
#   $Opt_NodeMembership output  True (-M) Node Membership indicator  #
#   $Opts_change_comg  output   True      any change comg option     #
#--------------------------------------------------------------------#
sub parse_cmd_line 
{
my(@original_argv) = @ARGV;
my $comg_name = "";                     # communication group name
my $sensitivity = 0;                    # heartbeat sensitivity
my $period = 0;                         # heartbeat period
my $grace  = 0;                         # grace period
my $priority = 0;                       # heartbeat priority
my $exclude = "";                       # heartbeat controls
my $NIMpathname = "";                   # NIM path name
my $NIMparms = "";                      # NIM start parameters
my $INames = "";                        # -i names
my $SelString = "";                     # -S selection string
my $badflag = "";                       # improper usage
my %opts = ();

# Process the command line...
if (!&getopts('hs:p:x:brt:e:m:S:i:g:VT6N:', \%opts)) { # Gather options; 
                                        # if errors
    &print_usage;                       # display proper usage
    return CRM_CLI_BAD_FLAG;            # return bad rc - bad flag 
}

# process h flag
if (defined $opts{h}) {                 # -h, help request
    &print_usage;                       # print usage statement
    exit(0);                            # all done with good return!
}

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

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

# Get the arguments...
# Operands:  communication group
if ($#ARGV == 0) {                      # communication group name
   $comg_name = shift @ARGV;            # get the name
}

else {            
    # communication group name not specified or too many
    printCEMsg("EMsgConfigRMcliInvalidNumberOfOperands");
    &print_usage;
    return CRM_CLI_BAD_OPERAND;
}

if (defined $opts{s}) {                 # -s for sensitivity
    $sensitivity = $opts{s};         
    $Opt_Sensitivity = $TRUE;           # -s flag specified
    $Opts_change_comg = $TRUE;
}

if (defined $opts{p}) {                 # -p for period
    $period = $opts{p}; 
    $Opt_Period = $TRUE;                # -p flag specified
    $Opts_change_comg = $TRUE;
}

if (defined $opts{g}) {                 # -g for grace period
    $grace = $opts{g}; 
    $Opt_Grace = $TRUE;                 # -g flag specified
    $Opts_change_comg = $TRUE;
}

if (defined $opts{t}) {                 # -t for priority
    $priority = $opts{t};
    $Opt_Priority = $TRUE;              # -t flag specified
    $Opts_change_comg = $TRUE;
}

if (defined $opts{b}) {                 # -b for usebroadcast
    $Opt_Broadcast = $TRUE;             # -b flag specified
    $Opts_change_comg = $TRUE;
}

if (defined $opts{r}) {                 # -r for usesourcerouting
    $Opt_SourceRouting = $TRUE;         # -r flag specified
    $Opts_change_comg = $TRUE;
}

if (defined $opts{x}) {                 # -x for exclude com ftr
    $exclude = $opts{x}; 
    $Opt_Exclude = $TRUE;               # -x flag specified
    $Opts_change_comg = $TRUE;
}

if (defined $opts{e}) {                 # -e for NIM path name
    $NIMpathname = $opts{e};
    $Opt_NIMpath = $TRUE;               # -e flag specified
    $Opts_change_comg = $TRUE;
}

if (defined $opts{m}) {                 # -m for NIM parameters
    $NIMparms = $opts{m};
    $Opt_NIMparms = $TRUE;              # -m flag specified
    $Opts_change_comg = $TRUE;
}

if (defined $opts{N}) {                 # -N for "use in Node Membership"
    $nodemembership = $opts{N};
    $Opt_NodeMembership = $TRUE;        # -N flag specified
    $Opts_change_comg = $TRUE;
}

if (defined $opts{i}) {                 # -i for interface name
    # error if -s, -p, -t, -b, -x, -e, -m, -M specified
    if ($Opts_change_comg) {
       if ($Opt_Sensitivity) { $badflag = "-s"; }
       elsif ($Opt_Period) { $badflag = "-p"; }
       elsif ($Opt_Priority) { $badflag = "-t"; }
       elsif ($Opt_Broadcast) { $badflag = "-b"; }
       elsif ($Opt_SourceRouting) { $badflag = "-r"; }
       elsif ($Opt_Exclude) { $badflag = "-x"; }
       elsif ($Opt_SourceRouting) { $badflag = "-r"; }
       elsif ($Opt_NIMpath) { $badflag = "-e"; }
       elsif ($Opt_NIMparms) { $badflag = "-m"; }
       else  { $badflag = "-N"; }  # ($Opt_NodeMembership)
       printCEMsg("EMsgConfigRMcliImproperUsageCombination","-i",$badflag);
       &print_usage;
       return CRM_CLI_BAD_FLAG;
    }
    $INames = $opts{i};
    $Opt_Interface = $TRUE;             # -i flag specified
}

if (defined $opts{S}) {                 # -S for interface selection
    # error if -s, -p, -t, -b, -x, -e, -m, -M specified
    if ($Opts_change_comg) {
       if ($Opt_Sensitivity) { $badflag = "-s"; }
       elsif ($Opt_Period) { $badflag = "-p"; }
       elsif ($Opt_Priority) { $badflag = "-t"; }
       elsif ($Opt_Grace) { $badflag = "-g"; }
       elsif ($Opt_Broadcast) { $badflag = "-b"; }
       elsif ($Opt_SourceRouting) { $badflag = "-r"; }
       elsif ($Opt_Exclude) { $badflag = "-x"; }
       elsif ($Opt_SourceRouting) { $badflag = "-r"; }
       elsif ($Opt_NIMpath) { $badflag = "-e"; }
       elsif ($Opt_NIMparms) { $badflag = "-m"; }
       else  { $badflag = "-N"; }  # ($Opt_NodeMembership)
       printCEMsg("EMsgConfigRMcliImproperUsageCombination","-S",$badflag);
       &print_usage;
       return CRM_CLI_BAD_FLAG;
    }
    # error if -i specified
    if ($Opt_Interface) {
       printCEMsg("EMsgConfigRMcliImproperUsageCombination","-i","-S");
       &print_usage;
       return CRM_CLI_BAD_FLAG;
    }
    $SelString = $opts{S};
    $Opt_iSelect = $TRUE;               # -S flag specified
}

# make sure something was selected
if (!($Opts_change_comg || $Opt_Interface || $Opt_iSelect)) {
    printCEMsg("EMsgConfigRMcliInvalidNumberOfOperands");
    &print_usage;
    return CRM_CLI_BAD_OPERAND;
}

if ( defined $opts{6} ) {		# -6 flag selects IPv6 interfaces
    $Use_IPv6 = $TRUE;
}

return(0, $sensitivity, $period, $grace, $priority, $exclude, $NIMpathname,
          $NIMparms, $INames, $SelString, $comg_name);  # success

}   # end parse_cmd_line


#--------------------------------------------------------------------#
# print_usage : print the usage statement (syntax) to stdout.        #
#--------------------------------------------------------------------#
sub print_usage
{
&printIMsg("IMsgchcomgUsageN");
}   # end print_usage