#!/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 = "@(#)80   1.15.1.14   src/rsct/rm/ER/cli/bin/stopcondresp.perl, errmcli, rsct_rady, rady2035a 11/12/15 16:39:05"
######################################################################
#                                                                    #
# Module: stopcondresp                                               #
#                                                                    #
# Purpose:                                                           #
#   stopcondresp - stop monitoring a condition that has a response   # 
#                                                                    #
# Syntax:                                                            #
#   stopcondresp [-h] [-q] [-TV] Condition[:Node_name] [Response     #
#                [Response ...]]                                     #
#                                                                    #
#   stopcondresp [-h] -U|-L [-TV] Condition[:Node_name] Response     #
#                                                                    #
# Flags:                                                             #
#   -h      help - writes this command's usage statement to stdout   #
#   -q      Does not return an error when either condition or        #
#           response does not exist or when the condition linked     #
#           to the response is not being monitored.                  #
#   -L      Lock. Lock the link between a condition and response so  #
#           that the monitoring state cannot be changed using the    #
#           startcondresp or stopcondresp command or the link        #
#           between the condition and response be removed using the  #
#           rmcondresp command.                                      #
#   -U      Unlock. Unlock the link between a condition and response #
#           so that the monitoring state can be changed using the    #
#           startcondresp or stopcondresp command or the link        #
#           between the condition and response removed using the     #
#           rmcondresp command.                                      #
#   -T      Trace. IBM Support Center use only.                      #
#   -V      Verbose.                                                 #
#                                                                    #
# Operands:                                                          #
#   Condition    The condition that is linked to a response.  The    #
#                condition is always specified first. Node_name      #
#                specifies where the condition is defined.           #
#   Response     The response that is linked to a condition.  If more#
#                than one response is specified, all of the responses#
#                are linked to the same condition.                   #
#                                                                    #
# Description:                                                       #
#   The stopcondresp command stops monitoring of a condition that    #
#   has a linked response.  If no response is specified, all of the  #
#   linked responses for the condition are stopped.  If more than    #
#   one response is specified, only those linked responses are       #
#   stopped.  When the condition occurs, the response is not run.    #
#   If no responses are active for a condition, the condition is     #
#   no longer monitored.                                             #
#                                                                    #
# Exit Values:                                                       #
#   0  ERRM_CLI_SUCCESS      Command completed successfully.         #
#   1  ERRM_CLI_RMC_ERROR    Command terminated due to an underlying #
#                            RMC error.                              #
#   2  ERRM_CLI_ERROR        Command terminated due to an underlying #
#                            error in the command script.            #
#   3  ERRM_CLI_BAD_FLAG     Command terminated due to user          #
#                            specifying an invalid flag.             #
#   4  ERRM_CLI_BAD_OPERAND  Command terminated due to user          #
#                            specifying a bad operand.               #
#   5  ERRM_CLI_USER_ERROR   Command terminated due to a user error. #
#                            For example specifying a name that      #
#                            already exists.                         #
#                                                                    #
# Examples:                                                          #
#   1. Stop monitoring the condition "JFS space used" with the       #
#      response "Broadcast event on-shift":                          #
#      stopcondresp "JFS space used"  "Broadcast event on-shift"     #
#   2. Stop monitoring the condition "JFS space used" for all of     #
#      its linked responses:                                         #
#      stopcondresp "JFS space used"                                 #
#                                                                    #
# Man Page:                                                          #
#   For the most current detailed description of this command see    #
#   the stopcondresp man page in /opt/rsct/man.                 #
#                                                                    #
#--------------------------------------------------------------------#
# Inputs:                                                            #
#   /opt/rsct/msgmaps/errmcli.stopcondresp.map - msg mapping    #
#                                                                    #
# Outputs:                                                           #
#   stdout - display information on the condition.                   #
#   stderr - any error message.                                      #
#                                                                    #
# External Ref:                                                      #
#   Commands: ctdspmsg                                               #
#   Modules:  ERRM_cli_utils.pm, ERRM_cli_rc.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:                                                   #
#   001106 JAC 67469: Initial design & write.                        #
#   010119 JAC 67471: Completed stopcondresp command.                #
#   010306 JAC 72063: Message EMsgstopcondrespCondNotInAssoc is not  #
#                     in msgcat. Comment and use print for now.      # 
#   010306 JAC 72065: Continue to process responses even if a        #
#                     response is not found.                         #
#   010330 JAC 71287: Update runact call due to syntax change        #
#   010403 JAC 72894: Eliminate extra call to lsrsrc to get handle   #
#   010412 JAC 73148: Enclose ActiveFlags in quotes on runact.       #
#   010501 JAC 73619: Do not send any RMC CLI std err to garbage.    #
#   010507 JAC 73620: Check for RMC CLI user error (rc=5) and        #
#                     return ERRM user error for this case.          #
#   011120 JAC 77597: Add distributed RMC changes                    #
#   020128 JAC 79559: Change how destination/locator node is used.   #
#   020214 JAC 77600: Add node name to runact call if not local.     #
#   020416 JAC 81754: Fix exit code checking.                        #
#   020606 JAC 83872: Use runact-api instead of runact.              #
#   020719 JAC 84931: Modify quoting in runact-api call.             #
#   020719 JAC 84425: Add $rc to process_api_error call.             #
#   020729 JAC 85061: Use 4 (DM/SR/local) for scope if locator used  #
#                     and scope not set.                             #
#   030610 JAC 95615: Add support for locked attribute.              #
#   030620 JAC 96060: Add -U|-L for Locked attribute.                #
#   030630 JAC 96546: Define subroutine change_locked_attr.          #
#   071026 JAC 146726: set delimiter for calls to -api commands.     #
######################################################################

#--------------------------------------------------------------------#
# General Program Flow/Logic:                                        #
#                                                                    #
# 1. Parse command line flags and operands, determine which flavor   #
#    of this command we are actually invoking.                       #
#    This command allows a user to stop monitoring a condition-      #
#    response association.                                           #
# 2. Print usage if -h specified.                                    #
# 3. Make sure one and only one condition is specified and it exists #
# 4. Make sure any responses specified exist.                        #
# 5. If there are no responses, find all associations for the        #
#    condition and save the resource handles.                        #
# 6. If there are responses, for each response,                      #
#    see if the condition - response association exists.  If it does,#
#    save the resource handle.                                       #
# 7. Call RMC command runact using the action SetActiveFlags with    #
#    the array of association handles and a matching array of 0's.   #
#    Also pass along -VT if necessary.                               #
# 8. Return back any errors.                                         #
#                                                                    #
#--------------------------------------------------------------------#

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

use CT_cli_utils qw(printIMsg
                    printEMsg);

use ERRM_cli_rc qw(ERRM_CLI_SUCCESS ERRM_CLI_RMC_ERROR
                   ERRM_CLI_ERROR ERRM_CLI_BAD_FLAG
                   ERRM_CLI_BAD_OPERAND ERRM_CLI_USER_ERROR);
use ERRM_cli_utils qw(error_exit
                    printCIMsg
                    printCEMsg
                    get_source_node get_locator_node
                    find_resource_name get_handle get_assoc_handles
                    find_names_from_assoc change_locked_attr
                    set_orig_rmc_scope process_exit_code
                    process_api_error check_set_cluster_scope
                    $DELIMITERO $DELIMITERI
                    $CTDIR $CTBINDIR $STOPMON
                    $LSNOTFND $MKRSRC $TRUE $FALSE
                    $RMC_CLI_USER_ERROR $RMC_LOCAL_SCOPE
                    $RUNACT $LSRSRC $RSCASSC $RSCCOND $RSCEVRS);


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

$Trace = $FALSE;                        # default - trace off
$Verbose = $FALSE;                      # default - verbose turned off
$Quiet_req = $FALSE;                    # is -q requested for quiet?

$Scope_orig_set = $FALSE;               # default - no CT_MANAGEMENT_SCOPE
$Scope_orig_value = 0;                  # default - scope value
$Opt_Lock = $FALSE;                     # default - no set lock
$Opt_Unlock = $FALSE;                   # default - no set unlock

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

#--------------------------------------------------------------------#
# Variables                                                          #
#--------------------------------------------------------------------#
my $condition = "";                     # condition to use
my @responses = ();                     # responses to use
my $Cond_handle = "";                   # handle for condition
my $Resp_handle = "";                   # handle for response
my $handle_ref = 0;                     # reference for handle array
my $flag_ref = 0;                       # reference for flag array
my $passopts = "";                      # options to pass to RMC
my $i = 0;                              # loop counter
my $handle_comma = "";                  # for building handle string
my $flag_comma = "";                    # for building flag string
my $handle_str = "";                    # string of handles to process
my $flag_str = "";                      # string of flag settings
my $num_handles = -1;                   # number of handles to process
my $temp_name = "";                     # holds condition name
my $locator = "";                       # locator
my $other_opts = "";                    # command parameters
my @cmd_out = ();                       # xxx-api command output
my @action_resp = ();                   # action response
my @locked_assocrh = ();                # locked assoc handles
my $line = "";                          # action response line
my $cond_names = "";                    # name reference
my $resp_names = "";                    # name reference
my $j = 0;                              # loop counter
my $lock_val = 0;                       # Locked attr value


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

# save original rmc management scope value, in case it's changed later
if (defined $ENV{CT_MANAGEMENT_SCOPE}) {
   $Scope_orig_set = $TRUE;
   $Scope_orig_value = $ENV{CT_MANAGEMENT_SCOPE};
}

# parse the command line, exit if there are errors
($rc, $condition, @responses) = &parse_cmd_line;
($rc == 0) || error_exit($rc);

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

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

# extract the locator from condition, if it exists
($temp_name, $locator) = get_locator_node($condition);
# put back condition name without locator
if ($locator ne "") {
   $condition = $temp_name;
}

# make sure the condition already exists and get handle
($rc, $Cond_handle) = get_handle($condition, $RSCCOND,$locator);
if ($rc != 0) {                        # condition name not found
    # if get_handle failed due to RMC CLI user error   73620
    # set ERRM CLI user error and exit
    if ($rc == $RMC_CLI_USER_ERROR) {
       exit(ERRM_CLI_USER_ERROR);
       }
    if ($Quiet_req) {                  # don't care about it
       exit(0);
       }
    printEMsg("EMsgstopcondrespConditionNotFound",$condition);
    exit(ERRM_CLI_USER_ERROR);
    }

# if there are no responses, find all associations for the condition
if ($#responses <0) {                   # no responses

   # get all associations for the condition handle, if any
   # get back references to array of handles, flags
   ($rc, $handle_ref, $flag_ref) = get_assoc_handles($Cond_handle,"",$locator);

   # if no associations are found for this condition, error and exit
   if ($rc != 0) {
      # if get_assoc_handles failed due to RMC CLI user error   73620
      # set ERRM CLI user error and exit
      if ($rc == $RMC_CLI_USER_ERROR) {
         exit(ERRM_CLI_USER_ERROR);
         }
      if ($Quiet_req) {                # don't care about it
          exit(0);
          }
      printEMsg("EMsgstopcondrespCondNotInAssoc",$condition);
      exit(ERRM_CLI_USER_ERROR);
      }

   # if there are associations, save the handles
   else {
      if ($Verbose) { printIMsg("IMsgstopcondrespStartNoResp",$condition);}
      for ($i=0;$i<=$#$handle_ref;$i++) {
         $$handle_ref[$i] =~ s/^\"//;
         $$handle_ref[$i] =~ s/\"$//;
         $handle_str = $handle_str . $handle_comma . $$handle_ref[$i];
         $handle_comma = ",";
         $num_handles++;
         }
      }
   }                                    # end of if no responses

# else there is a condition and one or more responses
else {
   # loop for each response:
   # make sure it exists, get handle, find association
   for ($i=0;$i<=$#responses;$i++) {

      # make sure it exists and get handle
      ($rc, $Resp_handle) = get_handle($responses[$i], $RSCEVRS, $locator);
      if ($rc != 0) {                     # response does not exist
          # if get_handle failed due to RMC CLI user error   73620
          # set ERRM CLI user error and go to next response
          if ($rc == $RMC_CLI_USER_ERROR) {
             $errmcli_rc = ERRM_CLI_USER_ERROR;
             }
          else {
             if (!$Quiet_req) {
                printEMsg("EMsgstopcondrespResponseNotFound",$responses[$i]);
                $errmcli_rc = ERRM_CLI_USER_ERROR;
                }
             }
             $rc = 0;                        # reset rc 
          }
      else {          # response found 

         # get the association handle for the condition-response
         # get back references to array of handles, flags
         ($rc, $handle_ref, $flag_ref) = get_assoc_handles($Cond_handle,$Resp_handle,$locator);

         # if get_assoc_handles failed due to RMC CLI user error   73620
         # set ERRM CLI user error and go to next response
         if ($rc == $RMC_CLI_USER_ERROR) {
            $errmcli_rc = ERRM_CLI_USER_ERROR;
            next;
            }

         # if there's no association, skip over this response
         # but set return code if not in quiet mode
         if ($rc != 0) {
            if (!$Quiet_req) {
               printEMsg("EMsgstopcondrespCondRespNotFound",$condition,$responses[$i]);
               $errmcli_rc = ERRM_CLI_USER_ERROR;
               }
            }

         else {     # association exists

            # if only changing Locked attribute, do it and leave
            if ($Opt_Lock || $Opt_Unlock) {

               # set lock value
               if ($Opt_Lock) { $lock_val = 1;}
               if ($Opt_Unlock) { $lock_val = 0;}

               # call function to change Locked attribute
               $rc = change_locked_attr($lock_val,$locator,$RSCASSC,$$handle_ref[0]);

               if ($Verbose) { printIMsg("IMsgstopcondrespEnd");}
               exit($rc);
            }

            # see if it's already deactived
            if ($$flag_ref[0] == $STOPMON) {      # active flag is off
               if (!$Quiet_req) {
                  printEMsg("EMsgstopcondrespAlreadyStopped",$condition,$responses[$i]);
                  $errmcli_rc = ERRM_CLI_USER_ERROR;
                  }
               }

            # if it's active, add the association handle to the handle array
            else {
               if ($Verbose) { printIMsg("IMsgstopcondrespStart",$condition,$responses[$i]);}
               $$handle_ref[0] =~ s/^\"//;
               $$handle_ref[0] =~ s/\"$//;
               $handle_str = $handle_str . $handle_comma . $$handle_ref[0];
               $handle_comma = ",";
               $num_handles++;
               }
            }       # end of else association exists
         }          # end response exists
      }             # end of for loop
   }                # end of else there is a condition and response(s)

# make a string of 0's to use in the runact command for off-flags
for ($i=0;$i<=$num_handles;$i++) {
   $flag_str = $flag_str . $flag_comma . "$STOPMON";
   $flag_comma = ",";
   }

$rc = 0;
# make sure there's something to stop 
if ($num_handles>=0) {

   # set CT_MANAGEMENT_SCOPE to original setting, in case it was used
   set_orig_rmc_scope;

   # if the destination node was not specified, make a local association.
   # Make sure rmc scope is set to local scope.
   if ($locator eq "") {
      $ENV{CT_MANAGEMENT_SCOPE} = $RMC_LOCAL_SCOPE;
#     $other_opts = "";
   }
#  # a locator was specified, use it for NodeNameList
#  else {
#     $other_opts = " -n $locator ";
#  }

   else {
      # use DM/SR/Local scope if scope not set and there's a locator
      check_set_cluster_scope;
   }

   # call runact to stop monitoring
   if ($Trace) { print STDERR "$PROGNAME: calling runact-api\n";}
   #`$CTBINDIR/$RUNACT $passopts -c $other_opts $RSCASSC SetActiveFlags ActiveFlags='{$flag_str}' AssoRHs='{$handle_str}'`;

   @cmd_out = `$CTBINDIR/runact-api -I $DELIMITERI -D $DELIMITERO -c "${RSCASSC}${DELIMITERI}${locator}${DELIMITERI}SetActiveFlags${DELIMITERI}ActiveFlags${DELIMITERI}{$flag_str}${DELIMITERI}AssoRHs${DELIMITERI}{$handle_str}" 2>&1`;

   $rc = $?;

   $rc = process_exit_code($rc);

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

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

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

   # if runact command failed due to RMC CLI user error   73620
   # set ERRM CLI user error and go to next condition/response
   if ($rc == $RMC_CLI_USER_ERROR) {
      $errmcli_rc = ERRM_CLI_USER_ERROR;
      }  
   else {
      # if runact command failed, print RMC error message and exit
      if ($rc != 0) {
         #printCEMsg("EMsgERRMcliUnExpectRMCrc",$rc);
         exit(ERRM_CLI_RMC_ERROR);
         }
      }

   # check for locked attribute
   if ($#cmd_out >= 0) {

      # see if locked rc is set (=2)
      foreach $line (@cmd_out) {
         @action_resp = split(/$DELIMITERO/, $line);
         if ($action_resp[2] == 2) {
            push @locked_assocrh, $action_resp[$#action_resp];
         }
      }

      # get condition and response names for the associations
      ($rc, $cond_names, $resp_names) = find_names_from_assoc($locator, @locked_assocrh);

      # print error messages for locked resource
      for ($j=0; $j<=$#$cond_names;$j++) {
         printEMsg("EMsgstopcondrespAssocLocked",$$cond_names[$j],$$resp_names[$j]);
         $errmcli_rc = ERRM_CLI_USER_ERROR;
      }
   }
}

if ($Verbose) { printIMsg("IMsgstopcondrespEnd");}

if ($errmcli_rc == 0) { exit($rc);}
else { exit($errmcli_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.   #
#         ERRM_CLI_BAD_FLAG  Command line contained a bad flag.      #
#   $resource                Name of resource to be removed.         #
#                                                                    #
# Global Variables Modified:                                         #
#   $Verbose           output   True (-V) turn Verbose mode on.      #
#   $Trace             output   True (-T) turn Trace mode on.        #
#   $Quiet_req         output   True (-q) quiet mode on              #
#   $Opt_Lock          output   True (-U) lock specified             #
#   $Opt_Unlock        output   True (-U) unlock specified           #
#--------------------------------------------------------------------#
sub parse_cmd_line
{
my(@original_argv) = @ARGV;
my $condition_name = "";                # condition name
my @responses = ();                     # array of response names
my $i = 0;                              # simple counter
my $rc = 0;                             # return code
my %opts = ();
my $lock_flag = "";                     # for invalid flag message
my $lock_flag2 = "";                    # for invalid flag messag

# Process the command line...
if (!GetOptions(\%opts,
		'h' ,
		'q' ,
		'U' ,
		'L' ,
		'V' ,
		'T')) {      # Gather options;
                                        # if errors
    &print_usage;                       # display proper usage
    return ERRM_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!
}

# process q flag
if (defined $opts{q}) {                 # -q, quiet request
    $Quiet_req = $TRUE                  # set quiet flag
    }

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:  Condition [Response [Response ...]]
if ($#ARGV >= 0) {                      # must have at least 1

   # first one is Condition name
   $condition_name = shift @ARGV;

   # the rest are responses
   @responses = @ARGV;
   }                                   # end of processing valid operands
else {
   # not enough operands
   printCEMsg("EMsgERRMcliInvalidNumberOfOperands");
   &print_usage;
   return ERRM_CLI_BAD_OPERAND;
   }

# check for lock/unlock flags
if ((defined $opts{L}) || (defined $opts{U})) { # -U,-L for unlock,lock

   # set global flag
   if ( defined $opts{L} ) {
      $Opt_Lock = $TRUE;
      $lock_flag = "L";
   }
   if ( defined $opts{U} ) {
      $Opt_Unlock = $TRUE;
      $lock_flag = "U";
   }

   # these flags are not allowed together or with the other flags (qr)
   if ( $Opt_Lock && $Opt_Unlock ) {
      $lock_flag = "L";
      $lock_flag2 = "U";
   }

   if (defined $opts{r}) { $lock_flag2 = "r";}

   if ( $lock_flag2 ne "" ) {
      printCEMsg("EMsgERRMcliImproperUsageCombination",$lock_flag,$lock_flag2);
      &print_usage;
      return ERRM_CLI_BAD_FLAG;
      }

   # must have 1 condition and 1 response
   if (  ($condition_name eq "") || ($#responses != 0) ) {
      printCEMsg("EMsgERRMcliInvalidNumberOfOperands");
      &print_usage;
      return ERRM_CLI_BAD_OPERAND;
   }
}

return(0, $condition_name, @responses); # success
}   # end parse_cmd_line


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