diff --git a/daemons/controld/controld_messages.c b/daemons/controld/controld_messages.c
index 8d0e7c3e57..1896686b40 100644
--- a/daemons/controld/controld_messages.c
+++ b/daemons/controld/controld_messages.c
@@ -1,1287 +1,1287 @@
 /*
  * Copyright 2004-2022 the Pacemaker project contributors
  *
  * The version control history for this file may have further details.
  *
  * This source code is licensed under the GNU General Public License version 2
  * or later (GPLv2+) WITHOUT ANY WARRANTY.
  */
 
 #include <crm_internal.h>
 
 #include <sys/param.h>
 #include <string.h>
 #include <time.h>
 
 #include <crm/crm.h>
 #include <crm/msg_xml.h>
 #include <crm/common/xml.h>
 #include <crm/cluster/internal.h>
 #include <crm/cib.h>
 #include <crm/common/ipc_internal.h>
 
 #include <pacemaker-controld.h>
 
 GList *fsa_message_queue = NULL;
 extern void crm_shutdown(int nsig);
 
 static enum crmd_fsa_input handle_message(xmlNode *msg,
                                           enum crmd_fsa_cause cause);
 static void handle_response(xmlNode *stored_msg);
 static enum crmd_fsa_input handle_request(xmlNode *stored_msg,
                                           enum crmd_fsa_cause cause);
 static enum crmd_fsa_input handle_shutdown_request(xmlNode *stored_msg);
 static void send_msg_via_ipc(xmlNode * msg, const char *sys);
 
 /* debug only, can wrap all it likes */
 int last_data_id = 0;
 
 void
 register_fsa_error_adv(enum crmd_fsa_cause cause, enum crmd_fsa_input input,
                        fsa_data_t * cur_data, void *new_data, const char *raised_from)
 {
     /* save the current actions if any */
     if (fsa_actions != A_NOTHING) {
         register_fsa_input_adv(cur_data ? cur_data->fsa_cause : C_FSA_INTERNAL,
                                I_NULL, cur_data ? cur_data->data : NULL,
                                fsa_actions, TRUE, __func__);
     }
 
     /* reset the action list */
     crm_info("Resetting the current action list");
     fsa_dump_actions(fsa_actions, "Drop");
     fsa_actions = A_NOTHING;
 
     /* register the error */
     register_fsa_input_adv(cause, input, new_data, A_NOTHING, TRUE, raised_from);
 }
 
 int
 register_fsa_input_adv(enum crmd_fsa_cause cause, enum crmd_fsa_input input,
                        void *data, uint64_t with_actions,
                        gboolean prepend, const char *raised_from)
 {
     unsigned old_len = g_list_length(fsa_message_queue);
     fsa_data_t *fsa_data = NULL;
 
     if (raised_from == NULL) {
         raised_from = "<unknown>";
     }
 
     if (input == I_NULL && with_actions == A_NOTHING /* && data == NULL */ ) {
         /* no point doing anything */
         crm_err("Cannot add entry to queue: no input and no action");
         return 0;
     }
 
     if (input == I_WAIT_FOR_EVENT) {
         do_fsa_stall = TRUE;
         crm_debug("Stalling the FSA pending further input: source=%s cause=%s data=%p queue=%d",
                   raised_from, fsa_cause2string(cause), data, old_len);
 
         if (old_len > 0) {
             fsa_dump_queue(LOG_TRACE);
             prepend = FALSE;
         }
 
         if (data == NULL) {
             controld_set_fsa_action_flags(with_actions);
             fsa_dump_actions(with_actions, "Restored");
             return 0;
         }
 
         /* Store everything in the new event and reset fsa_actions */
         with_actions |= fsa_actions;
         fsa_actions = A_NOTHING;
     }
 
     last_data_id++;
     crm_trace("%s %s FSA input %d (%s) due to %s, %s data",
               raised_from, (prepend? "prepended" : "appended"), last_data_id,
               fsa_input2string(input), fsa_cause2string(cause),
               (data? "with" : "without"));
 
     fsa_data = calloc(1, sizeof(fsa_data_t));
     fsa_data->id = last_data_id;
     fsa_data->fsa_input = input;
     fsa_data->fsa_cause = cause;
     fsa_data->origin = raised_from;
     fsa_data->data = NULL;
     fsa_data->data_type = fsa_dt_none;
     fsa_data->actions = with_actions;
 
     if (with_actions != A_NOTHING) {
         crm_trace("Adding actions %.16llx to input",
                   (unsigned long long) with_actions);
     }
 
     if (data != NULL) {
         switch (cause) {
             case C_FSA_INTERNAL:
             case C_CRMD_STATUS_CALLBACK:
             case C_IPC_MESSAGE:
             case C_HA_MESSAGE:
                 CRM_CHECK(((ha_msg_input_t *) data)->msg != NULL,
                           crm_err("Bogus data from %s", raised_from));
                 crm_trace("Copying %s data from %s as cluster message data",
                           fsa_cause2string(cause), raised_from);
                 fsa_data->data = copy_ha_msg_input(data);
                 fsa_data->data_type = fsa_dt_ha_msg;
                 break;
 
             case C_LRM_OP_CALLBACK:
                 crm_trace("Copying %s data from %s as lrmd_event_data_t",
                           fsa_cause2string(cause), raised_from);
                 fsa_data->data = lrmd_copy_event((lrmd_event_data_t *) data);
                 fsa_data->data_type = fsa_dt_lrm;
                 break;
 
             case C_TIMER_POPPED:
             case C_SHUTDOWN:
             case C_UNKNOWN:
             case C_STARTUP:
                 crm_crit("Copying %s data (from %s) is not yet implemented",
                          fsa_cause2string(cause), raised_from);
                 crmd_exit(CRM_EX_SOFTWARE);
                 break;
         }
     }
 
     /* make sure to free it properly later */
     if (prepend) {
         fsa_message_queue = g_list_prepend(fsa_message_queue, fsa_data);
     } else {
         fsa_message_queue = g_list_append(fsa_message_queue, fsa_data);
     }
 
     crm_trace("FSA message queue length is %d",
               g_list_length(fsa_message_queue));
 
     /* fsa_dump_queue(LOG_TRACE); */
 
     if (old_len == g_list_length(fsa_message_queue)) {
         crm_err("Couldn't add message to the queue");
     }
 
     if (fsa_source && input != I_WAIT_FOR_EVENT) {
         crm_trace("Triggering FSA");
         mainloop_set_trigger(fsa_source);
     }
     return last_data_id;
 }
 
 void
 fsa_dump_queue(int log_level)
 {
     int offset = 0;
     GList *lpc = NULL;
 
     for (lpc = fsa_message_queue; lpc != NULL; lpc = lpc->next) {
         fsa_data_t *data = (fsa_data_t *) lpc->data;
 
         do_crm_log_unlikely(log_level,
                             "queue[%d.%d]: input %s raised by %s(%p.%d)\t(cause=%s)",
                             offset++, data->id, fsa_input2string(data->fsa_input),
                             data->origin, data->data, data->data_type,
                             fsa_cause2string(data->fsa_cause));
     }
 }
 
 ha_msg_input_t *
 copy_ha_msg_input(ha_msg_input_t * orig)
 {
     ha_msg_input_t *copy = calloc(1, sizeof(ha_msg_input_t));
 
     CRM_ASSERT(copy != NULL);
     copy->msg = (orig && orig->msg)? copy_xml(orig->msg) : NULL;
     copy->xml = get_message_xml(copy->msg, F_CRM_DATA);
     return copy;
 }
 
 void
 delete_fsa_input(fsa_data_t * fsa_data)
 {
     lrmd_event_data_t *op = NULL;
     xmlNode *foo = NULL;
 
     if (fsa_data == NULL) {
         return;
     }
     crm_trace("About to free %s data", fsa_cause2string(fsa_data->fsa_cause));
 
     if (fsa_data->data != NULL) {
         switch (fsa_data->data_type) {
             case fsa_dt_ha_msg:
                 delete_ha_msg_input(fsa_data->data);
                 break;
 
             case fsa_dt_xml:
                 foo = fsa_data->data;
                 free_xml(foo);
                 break;
 
             case fsa_dt_lrm:
                 op = (lrmd_event_data_t *) fsa_data->data;
                 lrmd_free_event(op);
                 break;
 
             case fsa_dt_none:
                 if (fsa_data->data != NULL) {
                     crm_err("Don't know how to free %s data from %s",
                             fsa_cause2string(fsa_data->fsa_cause), fsa_data->origin);
                     crmd_exit(CRM_EX_SOFTWARE);
                 }
                 break;
         }
         crm_trace("%s data freed", fsa_cause2string(fsa_data->fsa_cause));
     }
 
     free(fsa_data);
 }
 
 /* returns the next message */
 fsa_data_t *
 get_message(void)
 {
     fsa_data_t *message = g_list_nth_data(fsa_message_queue, 0);
 
     fsa_message_queue = g_list_remove(fsa_message_queue, message);
     crm_trace("Processing input %d", message->id);
     return message;
 }
 
 void *
 fsa_typed_data_adv(fsa_data_t * fsa_data, enum fsa_data_type a_type, const char *caller)
 {
     void *ret_val = NULL;
 
     if (fsa_data == NULL) {
         crm_err("%s: No FSA data available", caller);
 
     } else if (fsa_data->data == NULL) {
         crm_err("%s: No message data available. Origin: %s", caller, fsa_data->origin);
 
     } else if (fsa_data->data_type != a_type) {
         crm_crit("%s: Message data was the wrong type! %d vs. requested=%d.  Origin: %s",
                  caller, fsa_data->data_type, a_type, fsa_data->origin);
         CRM_ASSERT(fsa_data->data_type == a_type);
     } else {
         ret_val = fsa_data->data;
     }
 
     return ret_val;
 }
 
 /*	A_MSG_ROUTE	*/
 void
 do_msg_route(long long action,
              enum crmd_fsa_cause cause,
              enum crmd_fsa_state cur_state,
              enum crmd_fsa_input current_input, fsa_data_t * msg_data)
 {
     ha_msg_input_t *input = fsa_typed_data(fsa_dt_ha_msg);
 
     route_message(msg_data->fsa_cause, input->msg);
 }
 
 void
 route_message(enum crmd_fsa_cause cause, xmlNode * input)
 {
     ha_msg_input_t fsa_input;
     enum crmd_fsa_input result = I_NULL;
 
     fsa_input.msg = input;
     CRM_CHECK(cause == C_IPC_MESSAGE || cause == C_HA_MESSAGE, return);
 
     /* try passing the buck first */
     if (relay_message(input, cause == C_IPC_MESSAGE)) {
         return;
     }
 
     /* handle locally */
     result = handle_message(input, cause);
 
     /* done or process later? */
     switch (result) {
         case I_NULL:
         case I_CIB_OP:
         case I_ROUTER:
         case I_NODE_JOIN:
         case I_JOIN_REQUEST:
         case I_JOIN_RESULT:
             break;
         default:
             /* Defering local processing of message */
             register_fsa_input_later(cause, result, &fsa_input);
             return;
     }
 
     if (result != I_NULL) {
         /* add to the front of the queue */
         register_fsa_input(cause, result, &fsa_input);
     }
 }
 
 gboolean
 relay_message(xmlNode * msg, gboolean originated_locally)
 {
     int dest = 1;
     bool is_for_dc = false;
     bool is_for_dcib = false;
     bool is_for_te = false;
     bool is_for_crm = false;
     bool is_for_cib = false;
     bool is_local = false;
     const char *host_to = crm_element_value(msg, F_CRM_HOST_TO);
     const char *sys_to = crm_element_value(msg, F_CRM_SYS_TO);
     const char *sys_from = crm_element_value(msg, F_CRM_SYS_FROM);
     const char *type = crm_element_value(msg, F_TYPE);
     const char *task = crm_element_value(msg, F_CRM_TASK);
     const char *ref = crm_element_value(msg, XML_ATTR_REFERENCE);
 
     if (ref == NULL) {
         ref = "without reference ID";
     }
 
     if (msg == NULL) {
         crm_warn("Cannot route empty message");
         return TRUE;
 
     } else if (pcmk__str_eq(task, CRM_OP_HELLO, pcmk__str_casei)) {
         /* quietly ignore */
         crm_trace("No routing needed for hello message %s", ref);
         return TRUE;
 
     } else if (!pcmk__str_eq(type, T_CRM, pcmk__str_casei)) {
         crm_warn("Cannot route message %s: Type is '%s' not '" T_CRM "'",
                  ref, (type? type : "missing"));
         crm_log_xml_warn(msg, "[bad message type]");
         return TRUE;
 
     } else if (sys_to == NULL) {
         crm_warn("Cannot route message %s: No subsystem specified", ref);
         crm_log_xml_warn(msg, "[no subsystem]");
         return TRUE;
     }
 
     is_for_dc = (strcasecmp(CRM_SYSTEM_DC, sys_to) == 0);
     is_for_dcib = (strcasecmp(CRM_SYSTEM_DCIB, sys_to) == 0);
     is_for_te = (strcasecmp(CRM_SYSTEM_TENGINE, sys_to) == 0);
     is_for_cib = (strcasecmp(CRM_SYSTEM_CIB, sys_to) == 0);
     is_for_crm = (strcasecmp(CRM_SYSTEM_CRMD, sys_to) == 0);
 
     is_local = false;
     if (pcmk__str_empty(host_to)) {
         if (is_for_dc || is_for_te) {
             is_local = false;
 
         } else if (is_for_crm) {
             if (pcmk__strcase_any_of(task, CRM_OP_NODE_INFO,
                                      PCMK__CONTROLD_CMD_NODES, NULL)) {
                 /* Node info requests do not specify a host, which is normally
                  * treated as "all hosts", because the whole point is that the
                  * client may not know the local node name. Always handle these
                  * requests locally.
                  */
                 is_local = true;
             } else {
                 is_local = !originated_locally;
             }
 
         } else {
             is_local = true;
         }
 
     } else if (pcmk__str_eq(fsa_our_uname, host_to, pcmk__str_casei)) {
         is_local = true;
     } else if (is_for_crm && pcmk__str_eq(task, CRM_OP_LRM_DELETE, pcmk__str_casei)) {
         xmlNode *msg_data = get_message_xml(msg, F_CRM_DATA);
         const char *mode = crm_element_value(msg_data, PCMK__XA_MODE);
 
         if (pcmk__str_eq(mode, XML_TAG_CIB, pcmk__str_casei)) {
             // Local delete of an offline node's resource history
             is_local = true;
         }
     }
 
     if (is_for_dc || is_for_dcib || is_for_te) {
         if (AM_I_DC && is_for_te) {
             crm_trace("Route message %s locally as transition request", ref);
             send_msg_via_ipc(msg, sys_to);
 
         } else if (AM_I_DC) {
             crm_trace("Route message %s locally as DC request", ref);
             return FALSE; // More to be done by caller
 
         } else if (originated_locally && !pcmk__strcase_any_of(sys_from, CRM_SYSTEM_PENGINE,
                                                                CRM_SYSTEM_TENGINE, NULL)) {
 
 #if SUPPORT_COROSYNC
             if (is_corosync_cluster()) {
                 dest = text2msg_type(sys_to);
             }
 #endif
             crm_trace("Relay message %s to DC", ref);
             send_cluster_message(host_to ? crm_get_peer(0, host_to) : NULL, dest, msg, TRUE);
 
         } else {
             /* Neither the TE nor the scheduler should be sending messages
              * to DCs on other nodes. By definition, if we are no longer the DC,
              * then the scheduler's or TE's data should be discarded.
              */
             crm_trace("Discard message %s because we are not DC", ref);
         }
 
     } else if (is_local && (is_for_crm || is_for_cib)) {
         crm_trace("Route message %s locally as controller request", ref);
         return FALSE; // More to be done by caller
 
     } else if (is_local) {
         crm_trace("Relay message %s locally to %s",
                   ref, (sys_to? sys_to : "unknown client"));
         crm_log_xml_trace(msg, "[IPC relay]");
         send_msg_via_ipc(msg, sys_to);
 
     } else {
         crm_node_t *node_to = NULL;
 
 #if SUPPORT_COROSYNC
         if (is_corosync_cluster()) {
             dest = text2msg_type(sys_to);
 
             if (dest == crm_msg_none || dest > crm_msg_stonith_ng) {
                 dest = crm_msg_crmd;
             }
         }
 #endif
 
         if (host_to) {
             node_to = pcmk__search_cluster_node_cache(0, host_to);
             if (node_to == NULL) {
                 crm_warn("Cannot route message %s: Unknown node %s",
                          ref, host_to);
                 return TRUE;
             }
             crm_trace("Relay message %s to %s",
                       ref, (node_to->uname? node_to->uname : "peer"));
         } else {
             crm_trace("Broadcast message %s to all peers", ref);
         }
         send_cluster_message(host_to ? node_to : NULL, dest, msg, TRUE);
     }
 
     return TRUE; // No further processing of message is needed
 }
 
 // Return true if field contains a positive integer
 static bool
 authorize_version(xmlNode *message_data, const char *field,
                   const char *client_name, const char *ref, const char *uuid)
 {
     const char *version = crm_element_value(message_data, field);
     long long version_num;
 
     if ((pcmk__scan_ll(version, &version_num, -1LL) != pcmk_rc_ok)
         || (version_num < 0LL)) {
 
         crm_warn("Rejected IPC hello from %s: '%s' is not a valid protocol %s "
                  CRM_XS " ref=%s uuid=%s",
                  client_name, ((version == NULL)? "" : version),
                  field, (ref? ref : "none"), uuid);
         return false;
     }
     return true;
 }
 
 /*!
  * \internal
  * \brief Check whether a client IPC message is acceptable
  *
  * If a given client IPC message is a hello, "authorize" it by ensuring it has
  * valid information such as a protocol version, and return false indicating
  * that nothing further needs to be done with the message. If the message is not
  * a hello, just return true to indicate it needs further processing.
  *
  * \param[in] client_msg     XML of IPC message
  * \param[in] curr_client    If IPC is not proxied, client that sent message
  * \param[in] proxy_session  If IPC is proxied, the session ID
  *
  * \return true if message needs further processing, false if it doesn't
  */
 bool
 controld_authorize_ipc_message(xmlNode *client_msg, pcmk__client_t *curr_client,
                                const char *proxy_session)
 {
     xmlNode *message_data = NULL;
     const char *client_name = NULL;
     const char *op = crm_element_value(client_msg, F_CRM_TASK);
     const char *ref = crm_element_value(client_msg, XML_ATTR_REFERENCE);
     const char *uuid = (curr_client? curr_client->id : proxy_session);
 
     if (uuid == NULL) {
         crm_warn("IPC message from client rejected: No client identifier "
                  CRM_XS " ref=%s", (ref? ref : "none"));
         goto rejected;
     }
 
     if (!pcmk__str_eq(CRM_OP_HELLO, op, pcmk__str_casei)) {
         // Only hello messages need to be authorized
         return true;
     }
 
     message_data = get_message_xml(client_msg, F_CRM_DATA);
 
     client_name = crm_element_value(message_data, "client_name");
     if (pcmk__str_empty(client_name)) {
         crm_warn("IPC hello from client rejected: No client name",
                  CRM_XS " ref=%s uuid=%s", (ref? ref : "none"), uuid);
         goto rejected;
     }
     if (!authorize_version(message_data, "major_version", client_name, ref,
                            uuid)) {
         goto rejected;
     }
     if (!authorize_version(message_data, "minor_version", client_name, ref,
                            uuid)) {
         goto rejected;
     }
 
     crm_trace("Validated IPC hello from client %s", client_name);
     if (curr_client) {
         curr_client->userdata = strdup(client_name);
     }
     mainloop_set_trigger(fsa_source);
     return false;
 
 rejected:
     if (curr_client) {
         qb_ipcs_disconnect(curr_client->ipcs);
     }
     return false;
 }
 
 static enum crmd_fsa_input
 handle_message(xmlNode *msg, enum crmd_fsa_cause cause)
 {
     const char *type = NULL;
 
     CRM_CHECK(msg != NULL, return I_NULL);
 
     type = crm_element_value(msg, F_CRM_MSG_TYPE);
     if (pcmk__str_eq(type, XML_ATTR_REQUEST, pcmk__str_none)) {
         return handle_request(msg, cause);
 
     } else if (pcmk__str_eq(type, XML_ATTR_RESPONSE, pcmk__str_none)) {
         handle_response(msg);
         return I_NULL;
     }
 
     crm_err("Unknown message type: %s", type);
     return I_NULL;
 }
 
 static enum crmd_fsa_input
 handle_failcount_op(xmlNode * stored_msg)
 {
     const char *rsc = NULL;
     const char *uname = NULL;
     const char *op = NULL;
     char *interval_spec = NULL;
     guint interval_ms = 0;
     gboolean is_remote_node = FALSE;
     xmlNode *xml_op = get_message_xml(stored_msg, F_CRM_DATA);
 
     if (xml_op) {
         xmlNode *xml_rsc = first_named_child(xml_op, XML_CIB_TAG_RESOURCE);
         xmlNode *xml_attrs = first_named_child(xml_op, XML_TAG_ATTRS);
 
         if (xml_rsc) {
             rsc = ID(xml_rsc);
         }
         if (xml_attrs) {
             op = crm_element_value(xml_attrs,
                                    CRM_META "_" XML_RSC_ATTR_CLEAR_OP);
             crm_element_value_ms(xml_attrs,
                                  CRM_META "_" XML_RSC_ATTR_CLEAR_INTERVAL,
                                  &interval_ms);
         }
     }
     uname = crm_element_value(xml_op, XML_LRM_ATTR_TARGET);
 
     if ((rsc == NULL) || (uname == NULL)) {
         crm_log_xml_warn(stored_msg, "invalid failcount op");
         return I_NULL;
     }
 
     if (crm_element_value(xml_op, XML_LRM_ATTR_ROUTER_NODE)) {
         is_remote_node = TRUE;
     }
 
     if (interval_ms) {
         interval_spec = crm_strdup_printf("%ums", interval_ms);
     }
     update_attrd_clear_failures(uname, rsc, op, interval_spec, is_remote_node);
     free(interval_spec);
 
     lrm_clear_last_failure(rsc, uname, op, interval_ms);
 
     return I_NULL;
 }
 
 static enum crmd_fsa_input
 handle_lrm_delete(xmlNode *stored_msg)
 {
     const char *mode = NULL;
     xmlNode *msg_data = get_message_xml(stored_msg, F_CRM_DATA);
 
     CRM_CHECK(msg_data != NULL, return I_NULL);
 
     /* CRM_OP_LRM_DELETE has two distinct modes. The default behavior is to
      * relay the operation to the affected node, which will unregister the
      * resource from the local executor, clear the resource's history from the
      * CIB, and do some bookkeeping in the controller.
      *
      * However, if the affected node is offline, the client will specify
      * mode="cib" which means the controller receiving the operation should
      * clear the resource's history from the CIB and nothing else. This is used
      * to clear shutdown locks.
      */
     mode = crm_element_value(msg_data, PCMK__XA_MODE);
     if ((mode == NULL) || strcmp(mode, XML_TAG_CIB)) {
         // Relay to affected node
         crm_xml_add(stored_msg, F_CRM_SYS_TO, CRM_SYSTEM_LRMD);
         return I_ROUTER;
 
     } else {
         // Delete CIB history locally (compare with do_lrm_delete())
         const char *from_sys = NULL;
         const char *user_name = NULL;
         const char *rsc_id = NULL;
         const char *node = NULL;
         xmlNode *rsc_xml = NULL;
         int rc = pcmk_rc_ok;
 
         rsc_xml = first_named_child(msg_data, XML_CIB_TAG_RESOURCE);
         CRM_CHECK(rsc_xml != NULL, return I_NULL);
 
         rsc_id = ID(rsc_xml);
         from_sys = crm_element_value(stored_msg, F_CRM_SYS_FROM);
         node = crm_element_value(msg_data, XML_LRM_ATTR_TARGET);
         user_name = pcmk__update_acl_user(stored_msg, F_CRM_USER, NULL);
         crm_debug("Handling " CRM_OP_LRM_DELETE " for %s on %s locally%s%s "
                   "(clearing CIB resource history only)", rsc_id, node,
                   (user_name? " for user " : ""), (user_name? user_name : ""));
         rc = controld_delete_resource_history(rsc_id, node, user_name,
                                               cib_dryrun|cib_sync_call);
         if (rc == pcmk_rc_ok) {
             rc = controld_delete_resource_history(rsc_id, node, user_name,
                                                   crmd_cib_smart_opt());
         }
 
         //Notify client and tengine.(Only notify tengine if mode = "cib" and CRM_OP_LRM_DELETE.)
         if (from_sys) {
             lrmd_event_data_t *op = NULL;
             const char *from_host = crm_element_value(stored_msg,
                                                       F_CRM_HOST_FROM);
             const char *transition;
 
             if (strcmp(from_sys, CRM_SYSTEM_TENGINE)) {
                 transition = crm_element_value(msg_data,
                                                        XML_ATTR_TRANSITION_KEY);
             } else {
                 transition = crm_element_value(stored_msg,
                                                        XML_ATTR_TRANSITION_KEY);
             }
 
             crm_info("Notifying %s on %s that %s was%s deleted",
                      from_sys, (from_host? from_host : "local node"), rsc_id,
                      ((rc == pcmk_rc_ok)? "" : " not"));
             op = lrmd_new_event(rsc_id, CRMD_ACTION_DELETE, 0);
             op->type = lrmd_event_exec_complete;
             op->user_data = strdup(transition? transition : FAKE_TE_ID);
             op->params = pcmk__strkey_table(free, free);
             g_hash_table_insert(op->params, strdup(XML_ATTR_CRM_VERSION),
                                 strdup(CRM_FEATURE_SET));
             controld_rc2event(op, rc);
             controld_ack_event_directly(from_host, from_sys, NULL, op, rsc_id);
             lrmd_free_event(op);
             controld_trigger_delete_refresh(from_sys, rsc_id);
         }
         return I_NULL;
     }
 }
 
 /*!
  * \brief Handle a CRM_OP_REMOTE_STATE message by updating remote peer cache
  *
  * \param[in] msg  Message XML
  *
  * \return Next FSA input
  */
 static enum crmd_fsa_input
 handle_remote_state(xmlNode *msg)
 {
     const char *remote_uname = ID(msg);
     crm_node_t *remote_peer;
     bool remote_is_up = false;
     int rc = pcmk_rc_ok;
 
     rc = pcmk__xe_get_bool_attr(msg, XML_NODE_IN_CLUSTER, &remote_is_up);
 
     CRM_CHECK(remote_uname && rc == pcmk_rc_ok, return I_NULL);
 
     remote_peer = crm_remote_peer_get(remote_uname);
     CRM_CHECK(remote_peer, return I_NULL);
 
     pcmk__update_peer_state(__func__, remote_peer,
                             remote_is_up ? CRM_NODE_MEMBER : CRM_NODE_LOST,
                             0);
     return I_NULL;
 }
 
 /*!
  * \brief Handle a CRM_OP_PING message
  *
  * \param[in] msg  Message XML
  *
  * \return Next FSA input
  */
 static enum crmd_fsa_input
 handle_ping(xmlNode *msg)
 {
     const char *value = NULL;
     xmlNode *ping = NULL;
 
     // Build reply
 
     ping = create_xml_node(NULL, XML_CRM_TAG_PING);
     value = crm_element_value(msg, F_CRM_SYS_TO);
     crm_xml_add(ping, XML_PING_ATTR_SYSFROM, value);
 
     // Add controller state
     value = fsa_state2string(fsa_state);
     crm_xml_add(ping, XML_PING_ATTR_CRMDSTATE, value);
     crm_notice("Current ping state: %s", value); // CTS needs this
 
     // Add controller health
     // @TODO maybe do some checks to determine meaningful status
     crm_xml_add(ping, XML_PING_ATTR_STATUS, "ok");
 
     // Send reply
     msg = create_reply(msg, ping);
     free_xml(ping);
     if (msg) {
         (void) relay_message(msg, TRUE);
         free_xml(msg);
     }
 
     // Nothing further to do
     return I_NULL;
 }
 
 /*!
  * \brief Handle a PCMK__CONTROLD_CMD_NODES message
  *
  * \return Next FSA input
  */
 static enum crmd_fsa_input
 handle_node_list(xmlNode *request)
 {
     GHashTableIter iter;
     crm_node_t *node = NULL;
     xmlNode *reply = NULL;
     xmlNode *reply_data = NULL;
 
     // Create message data for reply
     reply_data = create_xml_node(NULL, XML_CIB_TAG_NODES);
     g_hash_table_iter_init(&iter, crm_peer_cache);
     while (g_hash_table_iter_next(&iter, NULL, (gpointer *) & node)) {
         xmlNode *xml = create_xml_node(reply_data, XML_CIB_TAG_NODE);
 
         crm_xml_add_ll(xml, XML_ATTR_ID, (long long) node->id); // uint32_t
         crm_xml_add(xml, XML_ATTR_UNAME, node->uname);
         crm_xml_add(xml, XML_NODE_IN_CLUSTER, node->state);
     }
 
     // Create and send reply
     reply = create_reply(request, reply_data);
     free_xml(reply_data);
     if (reply) {
         (void) relay_message(reply, TRUE);
         free_xml(reply);
     }
 
     // Nothing further to do
     return I_NULL;
 }
 
 /*!
  * \brief Handle a CRM_OP_NODE_INFO request
  *
  * \param[in] msg  Message XML
  *
  * \return Next FSA input
  */
 static enum crmd_fsa_input
 handle_node_info_request(xmlNode *msg)
 {
     const char *value = NULL;
     crm_node_t *node = NULL;
     int node_id = 0;
     xmlNode *reply = NULL;
 
     // Build reply
 
     reply = create_xml_node(NULL, XML_CIB_TAG_NODE);
     crm_xml_add(reply, XML_PING_ATTR_SYSFROM, CRM_SYSTEM_CRMD);
 
     // Add whether current partition has quorum
     pcmk__xe_set_bool_attr(reply, XML_ATTR_HAVE_QUORUM, fsa_has_quorum);
 
     // Check whether client requested node info by ID and/or name
     crm_element_value_int(msg, XML_ATTR_ID, &node_id);
     if (node_id < 0) {
         node_id = 0;
     }
     value = crm_element_value(msg, XML_ATTR_UNAME);
 
     // Default to local node if none given
     if ((node_id == 0) && (value == NULL)) {
         value = fsa_our_uname;
     }
 
     node = pcmk__search_node_caches(node_id, value, CRM_GET_PEER_ANY);
     if (node) {
         crm_xml_add_int(reply, XML_ATTR_ID, node->id);
         crm_xml_add(reply, XML_ATTR_UUID, node->uuid);
         crm_xml_add(reply, XML_ATTR_UNAME, node->uname);
         crm_xml_add(reply, XML_NODE_IS_PEER, node->state);
         pcmk__xe_set_bool_attr(reply, XML_NODE_IS_REMOTE,
                                pcmk_is_set(node->flags, crm_remote_node));
     }
 
     // Send reply
     msg = create_reply(msg, reply);
     free_xml(reply);
     if (msg) {
         (void) relay_message(msg, TRUE);
         free_xml(msg);
     }
 
     // Nothing further to do
     return I_NULL;
 }
 
 static void
 verify_feature_set(xmlNode *msg)
 {
     const char *dc_version = crm_element_value(msg, XML_ATTR_CRM_VERSION);
 
     if (dc_version == NULL) {
         /* All we really know is that the DC feature set is older than 3.1.0,
          * but that's also all that really matters.
          */
         dc_version = "3.0.14";
     }
 
     if (feature_set_compatible(dc_version, CRM_FEATURE_SET)) {
         crm_trace("Local feature set (%s) is compatible with DC's (%s)",
                   CRM_FEATURE_SET, dc_version);
     } else {
         crm_err("Local feature set (%s) is incompatible with DC's (%s)",
                 CRM_FEATURE_SET, dc_version);
 
         // Nothing is likely to improve without administrator involvement
         controld_set_fsa_input_flags(R_STAYDOWN);
         crmd_exit(CRM_EX_FATAL);
     }
 }
 
 // DC gets own shutdown all-clear
 static enum crmd_fsa_input
 handle_shutdown_self_ack(xmlNode *stored_msg)
 {
     const char *host_from = crm_element_value(stored_msg, F_CRM_HOST_FROM);
 
     if (pcmk_is_set(fsa_input_register, R_SHUTDOWN)) {
         // The expected case -- we initiated own shutdown sequence
         crm_info("Shutting down controller");
         return I_STOP;
     }
 
     if (pcmk__str_eq(host_from, fsa_our_dc, pcmk__str_casei)) {
         // Must be logic error -- DC confirming its own unrequested shutdown
         crm_err("Shutting down controller immediately due to "
                 "unexpected shutdown confirmation");
         return I_TERMINATE;
     }
 
     if (fsa_state != S_STOPPING) {
         // Shouldn't happen -- non-DC confirming unrequested shutdown
         crm_err("Starting new DC election because %s is "
                 "confirming shutdown we did not request",
                 (host_from? host_from : "another node"));
         return I_ELECTION;
     }
 
     // Shouldn't happen, but we are already stopping anyway
     crm_debug("Ignoring unexpected shutdown confirmation from %s",
               (host_from? host_from : "another node"));
     return I_NULL;
 }
 
 // Non-DC gets shutdown all-clear from DC
 static enum crmd_fsa_input
 handle_shutdown_ack(xmlNode *stored_msg)
 {
     const char *host_from = crm_element_value(stored_msg, F_CRM_HOST_FROM);
 
     if (host_from == NULL) {
         crm_warn("Ignoring shutdown request without origin specified");
         return I_NULL;
     }
 
     if ((fsa_our_dc == NULL) || (strcmp(host_from, fsa_our_dc) == 0)) {
 
         if (pcmk_is_set(fsa_input_register, R_SHUTDOWN)) {
             crm_info("Shutting down controller after confirmation from %s",
                      host_from);
         } else {
             crm_err("Shutting down controller after unexpected "
                     "shutdown request from %s", host_from);
             controld_set_fsa_input_flags(R_STAYDOWN);
         }
         return I_STOP;
     }
 
     crm_warn("Ignoring shutdown request from %s because DC is %s",
              host_from, fsa_our_dc);
     return I_NULL;
 }
 
 static enum crmd_fsa_input
 handle_request(xmlNode *stored_msg, enum crmd_fsa_cause cause)
 {
     xmlNode *msg = NULL;
     const char *op = crm_element_value(stored_msg, F_CRM_TASK);
 
     /* Optimize this for the DC - it has the most to do */
 
     if (op == NULL) {
         crm_log_xml_warn(stored_msg, "[request without " F_CRM_TASK "]");
         return I_NULL;
     }
 
     if (strcmp(op, CRM_OP_SHUTDOWN_REQ) == 0) {
         const char *from = crm_element_value(stored_msg, F_CRM_HOST_FROM);
         crm_node_t *node = pcmk__search_cluster_node_cache(0, from);
 
         pcmk__update_peer_expected(__func__, node, CRMD_JOINSTATE_DOWN);
         if(AM_I_DC == FALSE) {
             return I_NULL; /* Done */
         }
     }
 
     /*========== DC-Only Actions ==========*/
     if (AM_I_DC) {
         if (strcmp(op, CRM_OP_JOIN_ANNOUNCE) == 0) {
             return I_NODE_JOIN;
 
         } else if (strcmp(op, CRM_OP_JOIN_REQUEST) == 0) {
             return I_JOIN_REQUEST;
 
         } else if (strcmp(op, CRM_OP_JOIN_CONFIRM) == 0) {
             return I_JOIN_RESULT;
 
         } else if (strcmp(op, CRM_OP_SHUTDOWN) == 0) {
             return handle_shutdown_self_ack(stored_msg);
 
         } else if (strcmp(op, CRM_OP_SHUTDOWN_REQ) == 0) {
             // Another controller wants to shut down its node
             return handle_shutdown_request(stored_msg);
 
         } else if (strcmp(op, CRM_OP_REMOTE_STATE) == 0) {
             /* a remote connection host is letting us know the node state */
             return handle_remote_state(stored_msg);
         }
     }
 
     /*========== common actions ==========*/
     if (strcmp(op, CRM_OP_NOVOTE) == 0) {
         ha_msg_input_t fsa_input;
 
         fsa_input.msg = stored_msg;
         register_fsa_input_adv(C_HA_MESSAGE, I_NULL, &fsa_input,
                                A_ELECTION_COUNT | A_ELECTION_CHECK, FALSE,
                                __func__);
 
     } else if (strcmp(op, CRM_OP_THROTTLE) == 0) {
         throttle_update(stored_msg);
         if (AM_I_DC && transition_graph != NULL) {
-            if (transition_graph->complete == FALSE) {
+            if (!transition_graph->complete) {
                 crm_debug("The throttle changed. Trigger a graph.");
                 trigger_graph();
             }
         }
         return I_NULL;
 
     } else if (strcmp(op, CRM_OP_CLEAR_FAILCOUNT) == 0) {
         return handle_failcount_op(stored_msg);
 
     } else if (strcmp(op, CRM_OP_VOTE) == 0) {
         /* count the vote and decide what to do after that */
         ha_msg_input_t fsa_input;
 
         fsa_input.msg = stored_msg;
         register_fsa_input_adv(C_HA_MESSAGE, I_NULL, &fsa_input,
                                A_ELECTION_COUNT | A_ELECTION_CHECK, FALSE,
                                __func__);
 
         /* Sometimes we _must_ go into S_ELECTION */
         if (fsa_state == S_HALT) {
             crm_debug("Forcing an election from S_HALT");
             return I_ELECTION;
 #if 0
         } else if (AM_I_DC) {
             /* This is the old way of doing things but what is gained? */
             return I_ELECTION;
 #endif
         }
 
     } else if (strcmp(op, CRM_OP_JOIN_OFFER) == 0) {
         verify_feature_set(stored_msg);
         crm_debug("Raising I_JOIN_OFFER: join-%s", crm_element_value(stored_msg, F_CRM_JOIN_ID));
         return I_JOIN_OFFER;
 
     } else if (strcmp(op, CRM_OP_JOIN_ACKNAK) == 0) {
         crm_debug("Raising I_JOIN_RESULT: join-%s", crm_element_value(stored_msg, F_CRM_JOIN_ID));
         return I_JOIN_RESULT;
 
     } else if (strcmp(op, CRM_OP_LRM_DELETE) == 0) {
         return handle_lrm_delete(stored_msg);
 
     } else if ((strcmp(op, CRM_OP_LRM_FAIL) == 0)
                || (strcmp(op, CRM_OP_LRM_REFRESH) == 0)
                || (strcmp(op, CRM_OP_REPROBE) == 0)) {
 
         crm_xml_add(stored_msg, F_CRM_SYS_TO, CRM_SYSTEM_LRMD);
         return I_ROUTER;
 
     } else if (strcmp(op, CRM_OP_NOOP) == 0) {
         return I_NULL;
 
     } else if (strcmp(op, CRM_OP_LOCAL_SHUTDOWN) == 0) {
 
         crm_shutdown(SIGTERM);
         /*return I_SHUTDOWN; */
         return I_NULL;
 
     } else if (strcmp(op, CRM_OP_PING) == 0) {
         return handle_ping(stored_msg);
 
     } else if (strcmp(op, CRM_OP_NODE_INFO) == 0) {
         return handle_node_info_request(stored_msg);
 
     } else if (strcmp(op, CRM_OP_RM_NODE_CACHE) == 0) {
         int id = 0;
         const char *name = NULL;
 
         crm_element_value_int(stored_msg, XML_ATTR_ID, &id);
         name = crm_element_value(stored_msg, XML_ATTR_UNAME);
 
         if(cause == C_IPC_MESSAGE) {
             msg = create_request(CRM_OP_RM_NODE_CACHE, NULL, NULL, CRM_SYSTEM_CRMD, CRM_SYSTEM_CRMD, NULL);
             if (send_cluster_message(NULL, crm_msg_crmd, msg, TRUE) == FALSE) {
                 crm_err("Could not instruct peers to remove references to node %s/%u", name, id);
             } else {
                 crm_notice("Instructing peers to remove references to node %s/%u", name, id);
             }
             free_xml(msg);
 
         } else {
             reap_crm_member(id, name);
 
             /* If we're forgetting this node, also forget any failures to fence
              * it, so we don't carry that over to any node added later with the
              * same name.
              */
             st_fail_count_reset(name);
         }
 
     } else if (strcmp(op, CRM_OP_MAINTENANCE_NODES) == 0) {
         xmlNode *xml = get_message_xml(stored_msg, F_CRM_DATA);
 
         remote_ra_process_maintenance_nodes(xml);
 
     } else if (strcmp(op, PCMK__CONTROLD_CMD_NODES) == 0) {
         return handle_node_list(stored_msg);
 
         /*========== (NOT_DC)-Only Actions ==========*/
     } else if (!AM_I_DC) {
 
         if (strcmp(op, CRM_OP_SHUTDOWN) == 0) {
             return handle_shutdown_ack(stored_msg);
         }
 
     } else {
         crm_err("Unexpected request (%s) sent to %s", op, AM_I_DC ? "the DC" : "non-DC node");
         crm_log_xml_err(stored_msg, "Unexpected");
     }
 
     return I_NULL;
 }
 
 static void
 handle_response(xmlNode *stored_msg)
 {
     const char *op = crm_element_value(stored_msg, F_CRM_TASK);
 
     if (op == NULL) {
         crm_log_xml_err(stored_msg, "Bad message");
 
     } else if (AM_I_DC && strcmp(op, CRM_OP_PECALC) == 0) {
         // Check whether scheduler answer been superseded by subsequent request
         const char *msg_ref = crm_element_value(stored_msg, XML_ATTR_REFERENCE);
 
         if (msg_ref == NULL) {
             crm_err("%s - Ignoring calculation with no reference", op);
 
         } else if (pcmk__str_eq(msg_ref, fsa_pe_ref, pcmk__str_casei)) {
             ha_msg_input_t fsa_input;
 
             controld_stop_sched_timer();
             fsa_input.msg = stored_msg;
             register_fsa_input_later(C_IPC_MESSAGE, I_PE_SUCCESS, &fsa_input);
 
         } else {
             crm_info("%s calculation %s is obsolete", op, msg_ref);
         }
 
     } else if (strcmp(op, CRM_OP_VOTE) == 0
                || strcmp(op, CRM_OP_SHUTDOWN_REQ) == 0 || strcmp(op, CRM_OP_SHUTDOWN) == 0) {
 
     } else {
         const char *host_from = crm_element_value(stored_msg, F_CRM_HOST_FROM);
 
         crm_err("Unexpected response (op=%s, src=%s) sent to the %s",
                 op, host_from, AM_I_DC ? "DC" : "controller");
     }
 }
 
 static enum crmd_fsa_input
 handle_shutdown_request(xmlNode * stored_msg)
 {
     /* handle here to avoid potential version issues
      *   where the shutdown message/procedure may have
      *   been changed in later versions.
      *
      * This way the DC is always in control of the shutdown
      */
 
     char *now_s = NULL;
     const char *host_from = crm_element_value(stored_msg, F_CRM_HOST_FROM);
 
     if (host_from == NULL) {
         /* we're shutting down and the DC */
         host_from = fsa_our_uname;
     }
 
     crm_info("Creating shutdown request for %s (state=%s)", host_from, fsa_state2string(fsa_state));
     crm_log_xml_trace(stored_msg, "message");
 
     now_s = pcmk__ttoa(time(NULL));
     update_attrd(host_from, XML_CIB_ATTR_SHUTDOWN, now_s, NULL, FALSE);
     free(now_s);
 
     /* will be picked up by the TE as long as its running */
     return I_NULL;
 }
 
 /* msg is deleted by the time this returns */
 extern gboolean process_te_message(xmlNode * msg, xmlNode * xml_data);
 
 static void
 send_msg_via_ipc(xmlNode * msg, const char *sys)
 {
     pcmk__client_t *client_channel = pcmk__find_client_by_id(sys);
 
     if (crm_element_value(msg, F_CRM_HOST_FROM) == NULL) {
         crm_xml_add(msg, F_CRM_HOST_FROM, fsa_our_uname);
     }
 
     if (client_channel != NULL) {
         /* Transient clients such as crmadmin */
         pcmk__ipc_send_xml(client_channel, 0, msg, crm_ipc_server_event);
 
     } else if (sys != NULL && strcmp(sys, CRM_SYSTEM_TENGINE) == 0) {
         xmlNode *data = get_message_xml(msg, F_CRM_DATA);
 
         process_te_message(msg, data);
 
     } else if (sys != NULL && strcmp(sys, CRM_SYSTEM_LRMD) == 0) {
         fsa_data_t fsa_data;
         ha_msg_input_t fsa_input;
 
         fsa_input.msg = msg;
         fsa_input.xml = get_message_xml(msg, F_CRM_DATA);
 
         fsa_data.id = 0;
         fsa_data.actions = 0;
         fsa_data.data = &fsa_input;
         fsa_data.fsa_input = I_MESSAGE;
         fsa_data.fsa_cause = C_IPC_MESSAGE;
         fsa_data.origin = __func__;
         fsa_data.data_type = fsa_dt_ha_msg;
 
         do_lrm_invoke(A_LRM_INVOKE, C_IPC_MESSAGE, fsa_state, I_MESSAGE, &fsa_data);
 
     } else if (sys != NULL && crmd_is_proxy_session(sys)) {
         crmd_proxy_send(sys, msg);
 
     } else {
         crm_debug("Ignoring message for unknown subsystem %s",
                   pcmk__s(sys, "<null>"));
     }
 }
 
 void
 delete_ha_msg_input(ha_msg_input_t * orig)
 {
     if (orig == NULL) {
         return;
     }
     free_xml(orig->msg);
     free(orig);
 }
 
 /*!
  * \internal
  * \brief Notify the DC of a remote node state change
  *
  * \param[in] node_name  Node's name
  * \param[in] node_up    TRUE if node is up, FALSE if down
  */
 void
 send_remote_state_message(const char *node_name, gboolean node_up)
 {
     /* If we don't have a DC, or the message fails, we have a failsafe:
      * the DC will eventually pick up the change via the CIB node state.
      * The message allows it to happen sooner if possible.
      */
     if (fsa_our_dc) {
         xmlNode *msg = create_request(CRM_OP_REMOTE_STATE, NULL, fsa_our_dc,
                                       CRM_SYSTEM_DC, CRM_SYSTEM_CRMD, NULL);
 
         crm_info("Notifying DC %s of Pacemaker Remote node %s %s",
                  fsa_our_dc, node_name, (node_up? "coming up" : "going down"));
         crm_xml_add(msg, XML_ATTR_ID, node_name);
         pcmk__xe_set_bool_attr(msg, XML_NODE_IN_CLUSTER, node_up);
         send_cluster_message(crm_get_peer(0, fsa_our_dc), crm_msg_crmd, msg,
                              TRUE);
         free_xml(msg);
     } else {
         crm_debug("No DC to notify of Pacemaker Remote node %s %s",
                   node_name, (node_up? "coming up" : "going down"));
     }
 }
 
diff --git a/daemons/controld/controld_te_actions.c b/daemons/controld/controld_te_actions.c
index 17e4c4b7bf..9ec4a1e425 100644
--- a/daemons/controld/controld_te_actions.c
+++ b/daemons/controld/controld_te_actions.c
@@ -1,687 +1,687 @@
 /*
  * Copyright 2004-2022 the Pacemaker project contributors
  *
  * The version control history for this file may have further details.
  *
  * This source code is licensed under the GNU General Public License version 2
  * or later (GPLv2+) WITHOUT ANY WARRANTY.
  */
 
 #include <crm_internal.h>
 
 #include <sys/param.h>
 #include <crm/crm.h>
 #include <crm/cib.h>
 #include <crm/lrmd.h>               // lrmd_event_data_t, lrmd_free_event()
 #include <crm/msg_xml.h>
 #include <crm/common/xml.h>
 #include <crm/cluster.h>
 
 #include <pacemaker-internal.h>
 #include <pacemaker-controld.h>
 
 char *te_uuid = NULL;
 GHashTable *te_targets = NULL;
 void send_rsc_command(pcmk__graph_action_t *action);
 static void te_update_job_count(pcmk__graph_action_t *action, int offset);
 
 static void
 te_start_action_timer(pcmk__graph_t *graph, pcmk__graph_action_t *action)
 {
     action->timer = g_timeout_add(action->timeout + graph->network_delay,
                                   action_timer_callback, (void *) action);
     CRM_ASSERT(action->timer != 0);
 }
 
 static gboolean
 te_pseudo_action(pcmk__graph_t *graph, pcmk__graph_action_t *pseudo)
 {
     const char *task = crm_element_value(pseudo->xml, XML_LRM_ATTR_TASK);
 
     /* send to peers as well? */
     if (pcmk__str_eq(task, CRM_OP_MAINTENANCE_NODES, pcmk__str_casei)) {
         GHashTableIter iter;
         crm_node_t *node = NULL;
 
         g_hash_table_iter_init(&iter, crm_peer_cache);
         while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &node)) {
             xmlNode *cmd = NULL;
 
             if (pcmk__str_eq(fsa_our_uname, node->uname, pcmk__str_casei)) {
                 continue;
             }
 
             cmd = create_request(task, pseudo->xml, node->uname,
                                  CRM_SYSTEM_CRMD, CRM_SYSTEM_TENGINE, NULL);
             send_cluster_message(node, crm_msg_crmd, cmd, FALSE);
             free_xml(cmd);
         }
 
         remote_ra_process_maintenance_nodes(pseudo->xml);
     } else {
         /* Check action for Pacemaker Remote node side effects */
         remote_ra_process_pseudo(pseudo->xml);
     }
 
     crm_debug("Pseudo-action %d (%s) fired and confirmed", pseudo->id,
               crm_element_value(pseudo->xml, XML_LRM_ATTR_TASK_KEY));
     te_action_confirmed(pseudo, graph);
     return TRUE;
 }
 
 static int
 get_target_rc(pcmk__graph_action_t *action)
 {
     int exit_status;
 
     pcmk__scan_min_int(crm_meta_value(action->params, XML_ATTR_TE_TARGET_RC),
                        &exit_status, 0);
     return exit_status;
 }
 
 static gboolean
 te_crm_command(pcmk__graph_t *graph, pcmk__graph_action_t *action)
 {
     char *counter = NULL;
     xmlNode *cmd = NULL;
     gboolean is_local = FALSE;
 
     const char *id = NULL;
     const char *task = NULL;
     const char *value = NULL;
     const char *on_node = NULL;
     const char *router_node = NULL;
 
     gboolean rc = TRUE;
     gboolean no_wait = FALSE;
 
     id = ID(action->xml);
     task = crm_element_value(action->xml, XML_LRM_ATTR_TASK);
     on_node = crm_element_value(action->xml, XML_LRM_ATTR_TARGET);
     router_node = crm_element_value(action->xml, XML_LRM_ATTR_ROUTER_NODE);
 
     if (!router_node) {
         router_node = on_node;
         if (pcmk__str_eq(task, CRM_OP_LRM_DELETE, pcmk__str_casei)) {
             const char *mode = crm_element_value(action->xml, PCMK__XA_MODE);
 
             if (pcmk__str_eq(mode, XML_TAG_CIB, pcmk__str_casei)) {
                 router_node = fsa_our_uname;
             }
         }
     }
 
     if (pcmk__str_empty(on_node)) {
         crm_err("Corrupted command (id=%s) %s: no node",
                 pcmk__s(id, "<null>"), pcmk__s(task, "without task"));
         return FALSE;
     }
 
     if (pcmk__str_eq(router_node, fsa_our_uname, pcmk__str_casei)) {
         is_local = TRUE;
     }
 
     value = crm_meta_value(action->params, XML_ATTR_TE_NOWAIT);
     if (crm_is_true(value)) {
         no_wait = TRUE;
     }
 
     crm_info("Executing crm-event (%s)%s%s: %s on %s",
              pcmk__s(id, "<null>"), (is_local? " locally" : ""),
              (no_wait? " without waiting" : ""),
              pcmk__s(task, "unspecified task"), on_node);
 
     if (is_local && pcmk__str_eq(task, CRM_OP_SHUTDOWN, pcmk__str_casei)) {
         /* defer until everything else completes */
         crm_info("crm-event (%s) is a local shutdown", pcmk__s(id, "<null>"));
         graph->completion_action = tg_shutdown;
         graph->abort_reason = "local shutdown";
         te_action_confirmed(action, graph);
         return TRUE;
 
     } else if (pcmk__str_eq(task, CRM_OP_SHUTDOWN, pcmk__str_casei)) {
         crm_node_t *peer = crm_get_peer(0, router_node);
 
         pcmk__update_peer_expected(__func__, peer, CRMD_JOINSTATE_DOWN);
     }
 
     cmd = create_request(task, action->xml, router_node, CRM_SYSTEM_CRMD, CRM_SYSTEM_TENGINE, NULL);
 
     counter = pcmk__transition_key(transition_graph->id, action->id,
                                    get_target_rc(action), te_uuid);
     crm_xml_add(cmd, XML_ATTR_TRANSITION_KEY, counter);
 
     rc = send_cluster_message(crm_get_peer(0, router_node), crm_msg_crmd, cmd, TRUE);
     free(counter);
     free_xml(cmd);
 
     if (rc == FALSE) {
         crm_err("Action %d failed: send", action->id);
         return FALSE;
 
     } else if (no_wait) {
         te_action_confirmed(action, graph);
 
     } else {
         if (action->timeout <= 0) {
             crm_err("Action %d: %s on %s had an invalid timeout (%dms).  Using %ums instead",
                     action->id, task, on_node, action->timeout, graph->network_delay);
             action->timeout = (int) graph->network_delay;
         }
         te_start_action_timer(graph, action);
     }
 
     return TRUE;
 }
 
 /*!
  * \internal
  * \brief Synthesize an executor event for a resource action timeout
  *
  * \param[in] action     Resource action that timed out
  * \param[in] target_rc  Expected result of action that timed out
  *
  * Synthesize an executor event for a resource action timeout. (If the executor
  * gets a timeout while waiting for a resource action to complete, that will be
  * reported via the usual callback. This timeout means we didn't hear from the
  * executor itself or the controller that relayed the action to the executor.)
  *
  * \return Newly created executor event for result of \p action
  * \note The caller is responsible for freeing the return value using
  *       lrmd_free_event().
  */
 static lrmd_event_data_t *
 synthesize_timeout_event(pcmk__graph_action_t *action, int target_rc)
 {
     lrmd_event_data_t *op = NULL;
     const char *target = crm_element_value(action->xml, XML_LRM_ATTR_TARGET);
     const char *reason = NULL;
     char *dynamic_reason = NULL;
 
     if (pcmk__str_eq(target, get_local_node_name(), pcmk__str_casei)) {
         reason = "Local executor did not return result in time";
     } else {
         const char *router_node = NULL;
 
         router_node = crm_element_value(action->xml, XML_LRM_ATTR_ROUTER_NODE);
         if (router_node == NULL) {
             router_node = target;
         }
         dynamic_reason = crm_strdup_printf("Controller on %s did not return "
                                            "result in time", router_node);
         reason = dynamic_reason;
     }
 
     op = pcmk__event_from_graph_action(NULL, action, PCMK_EXEC_TIMEOUT,
                                        PCMK_OCF_UNKNOWN_ERROR, reason);
     op->call_id = -1;
     op->user_data = pcmk__transition_key(transition_graph->id, action->id,
                                          target_rc, te_uuid);
     free(dynamic_reason);
     return op;
 }
 
 static void
 controld_record_action_event(pcmk__graph_action_t *action,
                              lrmd_event_data_t *op)
 {
     xmlNode *state = NULL;
     xmlNode *rsc = NULL;
     xmlNode *action_rsc = NULL;
 
     int rc = pcmk_ok;
 
     const char *rsc_id = NULL;
     const char *target = crm_element_value(action->xml, XML_LRM_ATTR_TARGET);
     const char *task_uuid = crm_element_value(action->xml, XML_LRM_ATTR_TASK_KEY);
     const char *target_uuid = crm_element_value(action->xml, XML_LRM_ATTR_TARGET_UUID);
 
     int call_options = cib_quorum_override | cib_scope_local;
     int target_rc = get_target_rc(action);
 
     action_rsc = find_xml_node(action->xml, XML_CIB_TAG_RESOURCE, TRUE);
     if (action_rsc == NULL) {
         return;
     }
 
     rsc_id = ID(action_rsc);
     CRM_CHECK(rsc_id != NULL,
               crm_log_xml_err(action->xml, "Bad:action"); return);
 
 /*
   update the CIB
 
 <node_state id="hadev">
       <lrm>
         <lrm_resources>
           <lrm_resource id="rsc2" last_op="start" op_code="0" target="hadev"/>
 */
 
     state = create_xml_node(NULL, XML_CIB_TAG_STATE);
 
     crm_xml_add(state, XML_ATTR_UUID, target_uuid);
     crm_xml_add(state, XML_ATTR_UNAME, target);
 
     rsc = create_xml_node(state, XML_CIB_TAG_LRM);
     crm_xml_add(rsc, XML_ATTR_ID, target_uuid);
 
     rsc = create_xml_node(rsc, XML_LRM_TAG_RESOURCES);
     rsc = create_xml_node(rsc, XML_LRM_TAG_RESOURCE);
     crm_xml_add(rsc, XML_ATTR_ID, rsc_id);
 
 
     crm_copy_xml_element(action_rsc, rsc, XML_ATTR_TYPE);
     crm_copy_xml_element(action_rsc, rsc, XML_AGENT_ATTR_CLASS);
     crm_copy_xml_element(action_rsc, rsc, XML_AGENT_ATTR_PROVIDER);
 
     pcmk__create_history_xml(rsc, op, CRM_FEATURE_SET, target_rc, target,
                              __func__);
 
     rc = fsa_cib_conn->cmds->update(fsa_cib_conn, XML_CIB_TAG_STATUS, state, call_options);
     fsa_register_cib_callback(rc, FALSE, NULL, cib_action_updated);
     free_xml(state);
 
     crm_trace("Sent CIB update (call ID %d) for synthesized event of action %d (%s on %s)",
               rc, action->id, task_uuid, target);
     pcmk__set_graph_action_flags(action, pcmk__graph_action_sent_update);
 }
 
 void
 controld_record_action_timeout(pcmk__graph_action_t *action)
 {
     lrmd_event_data_t *op = NULL;
 
     const char *target = crm_element_value(action->xml, XML_LRM_ATTR_TARGET);
     const char *task_uuid = crm_element_value(action->xml, XML_LRM_ATTR_TASK_KEY);
 
     int target_rc = get_target_rc(action);
 
     crm_warn("%s %d: %s on %s timed out",
              crm_element_name(action->xml), action->id, task_uuid, target);
 
     op = synthesize_timeout_event(action, target_rc);
     controld_record_action_event(action, op);
     lrmd_free_event(op);
 }
 
 static gboolean
 te_rsc_command(pcmk__graph_t *graph, pcmk__graph_action_t *action)
 {
     /* never overwrite stop actions in the CIB with
      *   anything other than completed results
      *
      * Writing pending stops makes it look like the
      *   resource is running again
      */
     xmlNode *cmd = NULL;
     xmlNode *rsc_op = NULL;
 
     gboolean rc = TRUE;
     gboolean no_wait = FALSE;
     gboolean is_local = FALSE;
 
     char *counter = NULL;
     const char *task = NULL;
     const char *value = NULL;
     const char *on_node = NULL;
     const char *router_node = NULL;
     const char *task_uuid = NULL;
 
     CRM_ASSERT(action != NULL);
     CRM_ASSERT(action->xml != NULL);
 
     pcmk__clear_graph_action_flags(action, pcmk__graph_action_executed);
     on_node = crm_element_value(action->xml, XML_LRM_ATTR_TARGET);
 
     if (pcmk__str_empty(on_node)) {
         crm_err("Corrupted command(id=%s) %s: no node",
                 ID(action->xml), pcmk__s(task, "without task"));
         return FALSE;
     }
 
     rsc_op = action->xml;
     task = crm_element_value(rsc_op, XML_LRM_ATTR_TASK);
     task_uuid = crm_element_value(action->xml, XML_LRM_ATTR_TASK_KEY);
     router_node = crm_element_value(rsc_op, XML_LRM_ATTR_ROUTER_NODE);
 
     if (!router_node) {
         router_node = on_node;
     }
 
     counter = pcmk__transition_key(transition_graph->id, action->id,
                                    get_target_rc(action), te_uuid);
     crm_xml_add(rsc_op, XML_ATTR_TRANSITION_KEY, counter);
 
     if (pcmk__str_eq(router_node, fsa_our_uname, pcmk__str_casei)) {
         is_local = TRUE;
     }
 
     value = crm_meta_value(action->params, XML_ATTR_TE_NOWAIT);
     if (crm_is_true(value)) {
         no_wait = TRUE;
     }
 
     crm_notice("Initiating %s operation %s%s on %s%s "CRM_XS" action %d",
                task, task_uuid, (is_local? " locally" : ""), on_node,
                (no_wait? " without waiting" : ""), action->id);
 
     cmd = create_request(CRM_OP_INVOKE_LRM, rsc_op, router_node,
                          CRM_SYSTEM_LRMD, CRM_SYSTEM_TENGINE, NULL);
 
     if (is_local) {
         /* shortcut local resource commands */
         ha_msg_input_t data = {
             .msg = cmd,
             .xml = rsc_op,
         };
 
         fsa_data_t msg = {
             .id = 0,
             .data = &data,
             .data_type = fsa_dt_ha_msg,
             .fsa_input = I_NULL,
             .fsa_cause = C_FSA_INTERNAL,
             .actions = A_LRM_INVOKE,
             .origin = __func__,
         };
 
         do_lrm_invoke(A_LRM_INVOKE, C_FSA_INTERNAL, fsa_state, I_NULL, &msg);
 
     } else {
         rc = send_cluster_message(crm_get_peer(0, router_node), crm_msg_lrmd, cmd, TRUE);
     }
 
     free(counter);
     free_xml(cmd);
 
     pcmk__set_graph_action_flags(action, pcmk__graph_action_executed);
 
     if (rc == FALSE) {
         crm_err("Action %d failed: send", action->id);
         return FALSE;
 
     } else if (no_wait) {
         /* Just mark confirmed. Don't bump the job count only to immediately
          * decrement it.
          */
         crm_info("Action %d confirmed - no wait", action->id);
         pcmk__set_graph_action_flags(action, pcmk__graph_action_confirmed);
         pcmk__update_graph(transition_graph, action);
         trigger_graph();
 
     } else if (pcmk_is_set(action->flags, pcmk__graph_action_confirmed)) {
         crm_debug("Action %d: %s %s on %s(timeout %dms) was already confirmed.",
                   action->id, task, task_uuid, on_node, action->timeout);
     } else {
         if (action->timeout <= 0) {
             crm_err("Action %d: %s %s on %s had an invalid timeout (%dms).  Using %ums instead",
                     action->id, task, task_uuid, on_node, action->timeout, graph->network_delay);
             action->timeout = (int) graph->network_delay;
         }
         te_update_job_count(action, 1);
         te_start_action_timer(graph, action);
     }
 
     return TRUE;
 }
 
 struct te_peer_s
 {
         char *name;
         int jobs;
         int migrate_jobs;
 };
 
 static void te_peer_free(gpointer p)
 {
     struct te_peer_s *peer = p;
 
     free(peer->name);
     free(peer);
 }
 
 void te_reset_job_counts(void)
 {
     GHashTableIter iter;
     struct te_peer_s *peer = NULL;
 
     if(te_targets == NULL) {
         te_targets = pcmk__strkey_table(NULL, te_peer_free);
     }
 
     g_hash_table_iter_init(&iter, te_targets);
     while (g_hash_table_iter_next(&iter, NULL, (gpointer *) & peer)) {
         peer->jobs = 0;
         peer->migrate_jobs = 0;
     }
 }
 
 static void
 te_update_job_count_on(const char *target, int offset, bool migrate)
 {
     struct te_peer_s *r = NULL;
 
     if(target == NULL || te_targets == NULL) {
         return;
     }
 
     r = g_hash_table_lookup(te_targets, target);
     if(r == NULL) {
         r = calloc(1, sizeof(struct te_peer_s));
         r->name = strdup(target);
         g_hash_table_insert(te_targets, r->name, r);
     }
 
     r->jobs += offset;
     if(migrate) {
         r->migrate_jobs += offset;
     }
     crm_trace("jobs[%s] = %d", target, r->jobs);
 }
 
 static void
 te_update_job_count(pcmk__graph_action_t *action, int offset)
 {
     const char *task = crm_element_value(action->xml, XML_LRM_ATTR_TASK);
     const char *target = crm_element_value(action->xml, XML_LRM_ATTR_TARGET);
 
     if ((action->type != pcmk__rsc_graph_action) || (target == NULL)) {
         /* No limit on these */
         return;
     }
 
     /* if we have a router node, this means the action is performing
      * on a remote node. For now, we count all actions occurring on a
      * remote node against the job list on the cluster node hosting
      * the connection resources */
     target = crm_element_value(action->xml, XML_LRM_ATTR_ROUTER_NODE);
 
     if ((target == NULL) && pcmk__strcase_any_of(task, CRMD_ACTION_MIGRATE,
                                                  CRMD_ACTION_MIGRATED, NULL)) {
 
         const char *t1 = crm_meta_value(action->params, XML_LRM_ATTR_MIGRATE_SOURCE);
         const char *t2 = crm_meta_value(action->params, XML_LRM_ATTR_MIGRATE_TARGET);
 
         te_update_job_count_on(t1, offset, TRUE);
         te_update_job_count_on(t2, offset, TRUE);
         return;
     } else if (target == NULL) {
         target = crm_element_value(action->xml, XML_LRM_ATTR_TARGET);
     }
 
     te_update_job_count_on(target, offset, FALSE);
 }
 
 static gboolean
 te_should_perform_action_on(pcmk__graph_t *graph, pcmk__graph_action_t *action,
                             const char *target)
 {
     int limit = 0;
     struct te_peer_s *r = NULL;
     const char *task = crm_element_value(action->xml, XML_LRM_ATTR_TASK);
     const char *id = crm_element_value(action->xml, XML_LRM_ATTR_TASK_KEY);
 
     if(target == NULL) {
         /* No limit on these */
         return TRUE;
 
     } else if(te_targets == NULL) {
         return FALSE;
     }
 
     r = g_hash_table_lookup(te_targets, target);
     limit = throttle_get_job_limit(target);
 
     if(r == NULL) {
         r = calloc(1, sizeof(struct te_peer_s));
         r->name = strdup(target);
         g_hash_table_insert(te_targets, r->name, r);
     }
 
     if(limit <= r->jobs) {
         crm_trace("Peer %s is over their job limit of %d (%d): deferring %s",
                   target, limit, r->jobs, id);
         return FALSE;
 
     } else if(graph->migration_limit > 0 && r->migrate_jobs >= graph->migration_limit) {
         if (pcmk__strcase_any_of(task, CRMD_ACTION_MIGRATE, CRMD_ACTION_MIGRATED, NULL)) {
             crm_trace("Peer %s is over their migration job limit of %d (%d): deferring %s",
                       target, graph->migration_limit, r->migrate_jobs, id);
             return FALSE;
         }
     }
 
     crm_trace("Peer %s has not hit their limit yet. current jobs = %d limit= %d limit", target, r->jobs, limit);
 
     return TRUE;
 }
 
 static gboolean
 te_should_perform_action(pcmk__graph_t *graph, pcmk__graph_action_t *action)
 {
     const char *target = NULL;
     const char *task = crm_element_value(action->xml, XML_LRM_ATTR_TASK);
 
     if (action->type != pcmk__rsc_graph_action) {
         /* No limit on these */
         return TRUE;
     }
 
     /* if we have a router node, this means the action is performing
      * on a remote node. For now, we count all actions occurring on a
      * remote node against the job list on the cluster node hosting
      * the connection resources */
     target = crm_element_value(action->xml, XML_LRM_ATTR_ROUTER_NODE);
 
     if ((target == NULL) && pcmk__strcase_any_of(task, CRMD_ACTION_MIGRATE,
                                                  CRMD_ACTION_MIGRATED, NULL)) {
         target = crm_meta_value(action->params, XML_LRM_ATTR_MIGRATE_SOURCE);
         if(te_should_perform_action_on(graph, action, target) == FALSE) {
             return FALSE;
         }
 
         target = crm_meta_value(action->params, XML_LRM_ATTR_MIGRATE_TARGET);
 
     } else if (target == NULL) {
         target = crm_element_value(action->xml, XML_LRM_ATTR_TARGET);
     }
 
     return te_should_perform_action_on(graph, action, target);
 }
 
 /*!
  * \brief Confirm a graph action (and optionally update graph)
  *
  * \param[in] action  Action to confirm
  * \param[in] graph   Update and trigger this graph (if non-NULL)
  */
 void
 te_action_confirmed(pcmk__graph_action_t *action, pcmk__graph_t *graph)
 {
     if (!pcmk_is_set(action->flags, pcmk__graph_action_confirmed)) {
         if ((action->type == pcmk__rsc_graph_action)
             && (crm_element_value(action->xml, XML_LRM_ATTR_TARGET) != NULL)) {
             te_update_job_count(action, -1);
         }
         pcmk__set_graph_action_flags(action, pcmk__graph_action_confirmed);
     }
     if (graph) {
         pcmk__update_graph(graph, action);
         trigger_graph();
     }
 }
 
 
 pcmk__graph_functions_t te_graph_fns = {
     te_pseudo_action,
     te_rsc_command,
     te_crm_command,
     te_fence_node,
     te_should_perform_action,
 };
 
 void
 notify_crmd(pcmk__graph_t *graph)
 {
     const char *type = "unknown";
     enum crmd_fsa_input event = I_NULL;
 
     crm_debug("Processing transition completion in state %s", fsa_state2string(fsa_state));
 
-    CRM_CHECK(graph->complete, graph->complete = TRUE);
+    CRM_CHECK(graph->complete, graph->complete = true);
 
     switch (graph->completion_action) {
         case tg_stop:
             type = "stop";
             if (fsa_state == S_TRANSITION_ENGINE) {
                 event = I_TE_SUCCESS;
             }
             break;
         case tg_done:
             type = "done";
             if (fsa_state == S_TRANSITION_ENGINE) {
                 event = I_TE_SUCCESS;
             }
             break;
 
         case tg_restart:
             type = "restart";
             if (fsa_state == S_TRANSITION_ENGINE) {
                 if (transition_timer->period_ms > 0) {
                     controld_stop_timer(transition_timer);
                     controld_start_timer(transition_timer);
                 } else {
                     event = I_PE_CALC;
                 }
 
             } else if (fsa_state == S_POLICY_ENGINE) {
                 controld_set_fsa_action_flags(A_PE_INVOKE);
                 trigger_fsa();
             }
             break;
 
         case tg_shutdown:
             type = "shutdown";
             if (pcmk_is_set(fsa_input_register, R_SHUTDOWN)) {
                 event = I_STOP;
 
             } else {
                 crm_err("We didn't ask to be shut down, yet the scheduler is telling us to");
                 event = I_TERMINATE;
             }
     }
 
     crm_debug("Transition %d status: %s - %s", graph->id, type,
               pcmk__s(graph->abort_reason, "unspecified reason"));
 
     graph->abort_reason = NULL;
     graph->completion_action = tg_done;
     controld_clear_fsa_input_flags(R_IN_TRANSITION);
 
     if (event != I_NULL) {
         register_fsa_input(C_FSA_INTERNAL, event, NULL);
 
     } else if (fsa_source) {
         mainloop_set_trigger(fsa_source);
     }
 }
diff --git a/daemons/controld/controld_te_callbacks.c b/daemons/controld/controld_te_callbacks.c
index 9f38c57301..c57c0818d5 100644
--- a/daemons/controld/controld_te_callbacks.c
+++ b/daemons/controld/controld_te_callbacks.c
@@ -1,674 +1,673 @@
 /*
  * Copyright 2004-2022 the Pacemaker project contributors
  *
  * The version control history for this file may have further details.
  *
  * This source code is licensed under the GNU General Public License version 2
  * or later (GPLv2+) WITHOUT ANY WARRANTY.
  */
 
 #include <crm_internal.h>
 
 #include <sys/stat.h>
 
 #include <crm/crm.h>
 #include <crm/common/xml.h>
 #include <crm/common/xml_internal.h>
 #include <crm/msg_xml.h>
 #include <crm/cluster.h>        /* For ONLINESTATUS etc */
 
 #include <pacemaker-controld.h>
 
 void te_update_confirm(const char *event, xmlNode * msg);
 
 extern char *te_uuid;
 gboolean shuttingdown = FALSE;
 pcmk__graph_t *transition_graph;
 crm_trigger_t *transition_trigger = NULL;
 
 /* #define RSC_OP_TEMPLATE "//"XML_TAG_DIFF_ADDED"//"XML_TAG_CIB"//"XML_CIB_TAG_STATE"[@uname='%s']"//"XML_LRM_TAG_RSC_OP"[@id='%s]" */
 #define RSC_OP_TEMPLATE "//"XML_TAG_DIFF_ADDED"//"XML_TAG_CIB"//"XML_LRM_TAG_RSC_OP"[@id='%s']"
 
 // An explicit shutdown-lock of 0 means the lock has been cleared
 static bool
 shutdown_lock_cleared(xmlNode *lrm_resource)
 {
     time_t shutdown_lock = 0;
 
     return (crm_element_value_epoch(lrm_resource, XML_CONFIG_ATTR_SHUTDOWN_LOCK,
                                     &shutdown_lock) == pcmk_ok)
            && (shutdown_lock == 0);
 }
 
 static void
 te_update_diff_v1(const char *event, xmlNode *diff)
 {
     int lpc, max;
     xmlXPathObject *xpathObj = NULL;
 
     CRM_CHECK(diff != NULL, return);
 
     xml_log_patchset(LOG_TRACE, __func__, diff);
     if (cib_config_changed(NULL, NULL, &diff)) {
         abort_transition(INFINITY, tg_restart, "Non-status change", diff);
         goto bail;              /* configuration changed */
     }
 
     /* Tickets Attributes - Added/Updated */
     xpathObj =
         xpath_search(diff,
                      "//" F_CIB_UPDATE_RESULT "//" XML_TAG_DIFF_ADDED "//" XML_CIB_TAG_TICKETS);
     if (numXpathResults(xpathObj) > 0) {
         xmlNode *aborted = getXpathResult(xpathObj, 0);
 
         abort_transition(INFINITY, tg_restart, "Ticket attribute: update", aborted);
         goto bail;
 
     }
     freeXpathObject(xpathObj);
 
     /* Tickets Attributes - Removed */
     xpathObj =
         xpath_search(diff,
                      "//" F_CIB_UPDATE_RESULT "//" XML_TAG_DIFF_REMOVED "//" XML_CIB_TAG_TICKETS);
     if (numXpathResults(xpathObj) > 0) {
         xmlNode *aborted = getXpathResult(xpathObj, 0);
 
         abort_transition(INFINITY, tg_restart, "Ticket attribute: removal", aborted);
         goto bail;
     }
     freeXpathObject(xpathObj);
 
     /* Transient Attributes - Removed */
     xpathObj =
         xpath_search(diff,
                      "//" F_CIB_UPDATE_RESULT "//" XML_TAG_DIFF_REMOVED "//"
                      XML_TAG_TRANSIENT_NODEATTRS);
     if (numXpathResults(xpathObj) > 0) {
         xmlNode *aborted = getXpathResult(xpathObj, 0);
 
         abort_transition(INFINITY, tg_restart, "Transient attribute: removal", aborted);
         goto bail;
 
     }
     freeXpathObject(xpathObj);
 
     // Check for lrm_resource entries
     xpathObj = xpath_search(diff,
                             "//" F_CIB_UPDATE_RESULT
                             "//" XML_TAG_DIFF_ADDED
                             "//" XML_LRM_TAG_RESOURCE);
     max = numXpathResults(xpathObj);
 
     /*
      * Updates by, or in response to, graph actions will never affect more than
      * one resource at a time, so such updates indicate an LRM refresh. In that
      * case, start a new transition rather than check each result individually,
      * which can result in _huge_ speedups in large clusters.
      *
      * Unfortunately, we can only do so when there are no pending actions.
      * Otherwise, we could mistakenly throw away those results here, and
      * the cluster will stall waiting for them and time out the operation.
      */
     if ((transition_graph->pending == 0) && (max > 1)) {
         crm_debug("Ignoring resource operation updates due to history refresh of %d resources",
                   max);
         crm_log_xml_trace(diff, "lrm-refresh");
         abort_transition(INFINITY, tg_restart, "History refresh", NULL);
         goto bail;
     }
 
     if (max == 1) {
         xmlNode *lrm_resource = getXpathResult(xpathObj, 0);
 
         if (shutdown_lock_cleared(lrm_resource)) {
             // @TODO would be more efficient to abort once after transition done
             abort_transition(INFINITY, tg_restart, "Shutdown lock cleared",
                              lrm_resource);
             // Still process results, so we stop timers and update failcounts
         }
     }
     freeXpathObject(xpathObj);
 
     /* Process operation updates */
     xpathObj =
         xpath_search(diff,
                      "//" F_CIB_UPDATE_RESULT "//" XML_TAG_DIFF_ADDED "//" XML_LRM_TAG_RSC_OP);
     max = numXpathResults(xpathObj);
     if (max > 0) {
         int lpc = 0;
 
         for (lpc = 0; lpc < max; lpc++) {
             xmlNode *rsc_op = getXpathResult(xpathObj, lpc);
             const char *node = get_node_id(rsc_op);
 
             process_graph_event(rsc_op, node);
         }
     }
     freeXpathObject(xpathObj);
 
     /* Detect deleted (as opposed to replaced or added) actions - eg. crm_resource -C */
     xpathObj = xpath_search(diff, "//" XML_TAG_DIFF_REMOVED "//" XML_LRM_TAG_RSC_OP);
     max = numXpathResults(xpathObj);
     for (lpc = 0; lpc < max; lpc++) {
         int path_max = 0;
         const char *op_id = NULL;
         char *rsc_op_xpath = NULL;
         xmlXPathObject *op_match = NULL;
         xmlNode *match = getXpathResult(xpathObj, lpc);
 
         CRM_LOG_ASSERT(match != NULL);
         if(match == NULL) { continue; };
 
         op_id = ID(match);
 
         path_max = strlen(RSC_OP_TEMPLATE) + strlen(op_id) + 1;
         rsc_op_xpath = calloc(1, path_max);
         snprintf(rsc_op_xpath, path_max, RSC_OP_TEMPLATE, op_id);
 
         op_match = xpath_search(diff, rsc_op_xpath);
         if (numXpathResults(op_match) == 0) {
             /* Prevent false positives by matching cancelations too */
             const char *node = get_node_id(match);
             pcmk__graph_action_t *cancelled = get_cancel_action(op_id, node);
 
             if (cancelled == NULL) {
                 crm_debug("No match for deleted action %s (%s on %s)", rsc_op_xpath, op_id,
                           node);
                 abort_transition(INFINITY, tg_restart, "Resource op removal", match);
                 freeXpathObject(op_match);
                 free(rsc_op_xpath);
                 goto bail;
 
             } else {
                 crm_debug("Deleted lrm_rsc_op %s on %s was for graph event %d",
                           op_id, node, cancelled->id);
             }
         }
 
         freeXpathObject(op_match);
         free(rsc_op_xpath);
     }
 
   bail:
     freeXpathObject(xpathObj);
 }
 
 static void
 process_lrm_resource_diff(xmlNode *lrm_resource, const char *node)
 {
     for (xmlNode *rsc_op = pcmk__xml_first_child(lrm_resource); rsc_op != NULL;
          rsc_op = pcmk__xml_next(rsc_op)) {
         process_graph_event(rsc_op, node);
     }
     if (shutdown_lock_cleared(lrm_resource)) {
         // @TODO would be more efficient to abort once after transition done
         abort_transition(INFINITY, tg_restart, "Shutdown lock cleared",
                          lrm_resource);
     }
 }
 
 static void
 process_resource_updates(const char *node, xmlNode *xml, xmlNode *change,
                          const char *op, const char *xpath)
 {
     xmlNode *rsc = NULL;
 
     if (xml == NULL) {
         return;
     }
 
     if (strcmp(TYPE(xml), XML_CIB_TAG_LRM) == 0) {
         xml = first_named_child(xml, XML_LRM_TAG_RESOURCES);
         CRM_CHECK(xml != NULL, return);
     }
 
     CRM_CHECK(strcmp(TYPE(xml), XML_LRM_TAG_RESOURCES) == 0, return);
 
     /*
      * Updates by, or in response to, TE actions will never contain updates
      * for more than one resource at a time, so such updates indicate an
      * LRM refresh.
      *
      * In that case, start a new transition rather than check each result
      * individually, which can result in _huge_ speedups in large clusters.
      *
      * Unfortunately, we can only do so when there are no pending actions.
      * Otherwise, we could mistakenly throw away those results here, and
      * the cluster will stall waiting for them and time out the operation.
      */
     if ((transition_graph->pending == 0)
         && xml->children && xml->children->next) {
 
         crm_log_xml_trace(change, "lrm-refresh");
         abort_transition(INFINITY, tg_restart, "History refresh", NULL);
         return;
     }
 
     for (rsc = pcmk__xml_first_child(xml); rsc != NULL;
          rsc = pcmk__xml_next(rsc)) {
         crm_trace("Processing %s", ID(rsc));
         process_lrm_resource_diff(rsc, node);
     }
 }
 
 static char *extract_node_uuid(const char *xpath) 
 {
     char *mutable_path = strdup(xpath);
     char *node_uuid = NULL;
     char *search = NULL;
     char *match = NULL;
 
     match = strstr(mutable_path, "node_state[@id=\'");
     if (match == NULL) {
         free(mutable_path);
         return NULL;
     }
     match += strlen("node_state[@id=\'");
 
     search = strchr(match, '\'');
     if (search == NULL) {
         free(mutable_path);
         return NULL;
     }
     search[0] = 0;
 
     node_uuid = strdup(match);
     free(mutable_path);
     return node_uuid;
 }
 
 static void
 abort_unless_down(const char *xpath, const char *op, xmlNode *change,
                   const char *reason)
 {
     char *node_uuid = NULL;
     pcmk__graph_action_t *down = NULL;
 
     if(!pcmk__str_eq(op, "delete", pcmk__str_casei)) {
         abort_transition(INFINITY, tg_restart, reason, change);
         return;
     }
 
     node_uuid = extract_node_uuid(xpath);
     if(node_uuid == NULL) {
         crm_err("Could not extract node ID from %s", xpath);
         abort_transition(INFINITY, tg_restart, reason, change);
         return;
     }
 
     down = match_down_event(node_uuid);
     if (down == NULL) {
         crm_trace("Not expecting %s to be down (%s)", node_uuid, xpath);
         abort_transition(INFINITY, tg_restart, reason, change);
     } else {
         crm_trace("Expecting changes to %s (%s)", node_uuid, xpath);
     }
     free(node_uuid);
 }
 
 static void
 process_op_deletion(const char *xpath, xmlNode *change)
 {
     char *mutable_key = strdup(xpath);
     char *key;
     char *node_uuid;
 
     // Extract the part of xpath between last pair of single quotes
     key = strrchr(mutable_key, '\'');
     if (key != NULL) {
         *key = '\0';
         key = strrchr(mutable_key, '\'');
     }
     if (key == NULL) {
         crm_warn("Ignoring malformed CIB update (resource deletion of %s)",
                  xpath);
         free(mutable_key);
         return;
     }
     ++key;
 
     node_uuid = extract_node_uuid(xpath);
     if (confirm_cancel_action(key, node_uuid) == FALSE) {
         abort_transition(INFINITY, tg_restart, "Resource operation removal",
                          change);
     }
     free(mutable_key);
     free(node_uuid);
 }
 
 static void
 process_delete_diff(const char *xpath, const char *op, xmlNode *change)
 {
     if (strstr(xpath, "/" XML_LRM_TAG_RSC_OP "[")) {
         process_op_deletion(xpath, change);
 
     } else if (strstr(xpath, "/" XML_CIB_TAG_LRM "[")) {
         abort_unless_down(xpath, op, change, "Resource state removal");
 
     } else if (strstr(xpath, "/" XML_CIB_TAG_STATE "[")) {
         abort_unless_down(xpath, op, change, "Node state removal");
 
     } else {
         crm_trace("Ignoring delete of %s", xpath);
     }
 }
 
 static void
 process_node_state_diff(xmlNode *state, xmlNode *change, const char *op,
                         const char *xpath)
 {
     xmlNode *lrm = first_named_child(state, XML_CIB_TAG_LRM);
 
     process_resource_updates(ID(state), lrm, change, op, xpath);
 }
 
 static void
 process_status_diff(xmlNode *status, xmlNode *change, const char *op,
                     const char *xpath)
 {
     for (xmlNode *state = pcmk__xml_first_child(status); state != NULL;
          state = pcmk__xml_next(state)) {
         process_node_state_diff(state, change, op, xpath);
     }
 }
 
 static void
 process_cib_diff(xmlNode *cib, xmlNode *change, const char *op,
                  const char *xpath)
 {
     xmlNode *status = first_named_child(cib, XML_CIB_TAG_STATUS);
     xmlNode *config = first_named_child(cib, XML_CIB_TAG_CONFIGURATION);
 
     if (status) {
         process_status_diff(status, change, op, xpath);
     }
     if (config) {
         abort_transition(INFINITY, tg_restart,
                          "Non-status-only change", change);
     }
 }
 
 static void
 te_update_diff_v2(xmlNode *diff)
 {
     crm_log_xml_trace(diff, "Patch:Raw");
 
     for (xmlNode *change = pcmk__xml_first_child(diff); change != NULL;
          change = pcmk__xml_next(change)) {
 
         xmlNode *match = NULL;
         const char *name = NULL;
         const char *xpath = crm_element_value(change, XML_DIFF_PATH);
 
         // Possible ops: create, modify, delete, move
         const char *op = crm_element_value(change, XML_DIFF_OP);
 
         // Ignore uninteresting updates
         if (op == NULL) {
             continue;
 
         } else if (xpath == NULL) {
             crm_trace("Ignoring %s change for version field", op);
             continue;
 
         } else if (strcmp(op, "move") == 0) {
             crm_trace("Ignoring move change at %s", xpath);
             continue;
         }
 
         // Find the result of create/modify ops
         if (strcmp(op, "create") == 0) {
             match = change->children;
 
         } else if (strcmp(op, "modify") == 0) {
             match = first_named_child(change, XML_DIFF_RESULT);
             if(match) {
                 match = match->children;
             }
 
         } else if (strcmp(op, "delete") != 0) {
             crm_warn("Ignoring malformed CIB update (%s operation on %s is unrecognized)",
                      op, xpath);
             continue;
         }
 
         if (match) {
             if (match->type == XML_COMMENT_NODE) {
                 crm_trace("Ignoring %s operation for comment at %s", op, xpath);
                 continue;
             }
             name = (const char *)match->name;
         }
 
         crm_trace("Handling %s operation for %s%s%s",
                   op, (xpath? xpath : "CIB"),
                   (name? " matched by " : ""), (name? name : ""));
 
         if (strstr(xpath, "/" XML_TAG_CIB "/" XML_CIB_TAG_CONFIGURATION)) {
             abort_transition(INFINITY, tg_restart, "Configuration change",
                              change);
             break; // Won't be packaged with operation results we may be waiting for
 
         } else if (strstr(xpath, "/" XML_CIB_TAG_TICKETS)
                    || pcmk__str_eq(name, XML_CIB_TAG_TICKETS, pcmk__str_casei)) {
             abort_transition(INFINITY, tg_restart, "Ticket attribute change", change);
             break; // Won't be packaged with operation results we may be waiting for
 
         } else if (strstr(xpath, "/" XML_TAG_TRANSIENT_NODEATTRS "[")
                    || pcmk__str_eq(name, XML_TAG_TRANSIENT_NODEATTRS, pcmk__str_casei)) {
             abort_unless_down(xpath, op, change, "Transient attribute change");
             break; // Won't be packaged with operation results we may be waiting for
 
         } else if (strcmp(op, "delete") == 0) {
             process_delete_diff(xpath, op, change);
 
         } else if (name == NULL) {
             crm_warn("Ignoring malformed CIB update (%s at %s has no result)",
                      op, xpath);
 
         } else if (strcmp(name, XML_TAG_CIB) == 0) {
             process_cib_diff(match, change, op, xpath);
 
         } else if (strcmp(name, XML_CIB_TAG_STATUS) == 0) {
             process_status_diff(match, change, op, xpath);
 
         } else if (strcmp(name, XML_CIB_TAG_STATE) == 0) {
             process_node_state_diff(match, change, op, xpath);
 
         } else if (strcmp(name, XML_CIB_TAG_LRM) == 0) {
             process_resource_updates(ID(match), match, change, op, xpath);
 
         } else if (strcmp(name, XML_LRM_TAG_RESOURCES) == 0) {
             char *local_node = pcmk__xpath_node_id(xpath, "lrm");
 
             process_resource_updates(local_node, match, change, op, xpath);
             free(local_node);
 
         } else if (strcmp(name, XML_LRM_TAG_RESOURCE) == 0) {
             char *local_node = pcmk__xpath_node_id(xpath, "lrm");
 
             process_lrm_resource_diff(match, local_node);
             free(local_node);
 
         } else if (strcmp(name, XML_LRM_TAG_RSC_OP) == 0) {
             char *local_node = pcmk__xpath_node_id(xpath, "lrm");
 
             process_graph_event(match, local_node);
             free(local_node);
 
         } else {
             crm_warn("Ignoring malformed CIB update (%s at %s has unrecognized result %s)",
                      op, xpath, name);
         }
     }
 }
 
 void
 te_update_diff(const char *event, xmlNode * msg)
 {
     xmlNode *diff = NULL;
     const char *op = NULL;
     int rc = -EINVAL;
     int format = 1;
     int p_add[] = { 0, 0, 0 };
     int p_del[] = { 0, 0, 0 };
 
     CRM_CHECK(msg != NULL, return);
     crm_element_value_int(msg, F_CIB_RC, &rc);
 
     if (transition_graph == NULL) {
         crm_trace("No graph");
         return;
 
     } else if (rc < pcmk_ok) {
         crm_trace("Filter rc=%d (%s)", rc, pcmk_strerror(rc));
         return;
 
     } else if (transition_graph->complete
                && fsa_state != S_IDLE
                && fsa_state != S_TRANSITION_ENGINE
                && fsa_state != S_POLICY_ENGINE) {
-        crm_trace("Filter state=%s, complete=%d", fsa_state2string(fsa_state),
-                  transition_graph->complete);
+        crm_trace("Filter state=%s (complete)", fsa_state2string(fsa_state));
         return;
     }
 
     op = crm_element_value(msg, F_CIB_OPERATION);
     diff = get_message_xml(msg, F_CIB_UPDATE_RESULT);
 
     xml_patch_versions(diff, p_add, p_del);
     crm_debug("Processing (%s) diff: %d.%d.%d -> %d.%d.%d (%s)", op,
               p_del[0], p_del[1], p_del[2], p_add[0], p_add[1], p_add[2],
               fsa_state2string(fsa_state));
 
     crm_element_value_int(diff, "format", &format);
     switch (format) {
         case 1:
             te_update_diff_v1(event, diff);
             break;
         case 2:
             te_update_diff_v2(diff);
             break;
         default:
             crm_warn("Ignoring malformed CIB update (unknown patch format %d)",
                      format);
     }
 }
 
 gboolean
 process_te_message(xmlNode * msg, xmlNode * xml_data)
 {
     const char *from = crm_element_value(msg, F_ORIG);
     const char *sys_to = crm_element_value(msg, F_CRM_SYS_TO);
     const char *sys_from = crm_element_value(msg, F_CRM_SYS_FROM);
     const char *ref = crm_element_value(msg, F_CRM_REFERENCE);
     const char *op = crm_element_value(msg, F_CRM_TASK);
     const char *type = crm_element_value(msg, F_CRM_MSG_TYPE);
 
     crm_trace("Processing %s (%s) message", op, ref);
     crm_log_xml_trace(msg, "ipc");
 
     if (op == NULL) {
         /* error */
 
     } else if (sys_to == NULL || strcasecmp(sys_to, CRM_SYSTEM_TENGINE) != 0) {
         crm_trace("Bad sys-to: %s", pcmk__s(sys_to, "missing"));
         return FALSE;
 
     } else if (pcmk__str_eq(op, CRM_OP_INVOKE_LRM, pcmk__str_casei)
                && pcmk__str_eq(sys_from, CRM_SYSTEM_LRMD, pcmk__str_casei)
 /* 		  && pcmk__str_eq(type, XML_ATTR_RESPONSE, pcmk__str_casei) */
         ) {
         xmlXPathObject *xpathObj = NULL;
 
         crm_log_xml_trace(msg, "Processing (N)ACK");
         crm_debug("Processing (N)ACK %s from %s", crm_element_value(msg, F_CRM_REFERENCE), from);
 
         xpathObj = xpath_search(xml_data, "//" XML_LRM_TAG_RSC_OP);
         if (numXpathResults(xpathObj)) {
             int lpc = 0, max = numXpathResults(xpathObj);
 
             for (lpc = 0; lpc < max; lpc++) {
                 xmlNode *rsc_op = getXpathResult(xpathObj, lpc);
                 const char *node = get_node_id(rsc_op);
 
                 process_graph_event(rsc_op, node);
             }
             freeXpathObject(xpathObj);
 
         } else {
             crm_log_xml_err(msg, "Invalid (N)ACK");
             freeXpathObject(xpathObj);
             return FALSE;
         }
 
     } else {
         crm_err("Unknown command: %s::%s from %s", type, op, sys_from);
     }
 
     crm_trace("finished processing message");
 
     return TRUE;
 }
 
 void
 cib_action_updated(xmlNode * msg, int call_id, int rc, xmlNode * output, void *user_data)
 {
     if (rc < pcmk_ok) {
         crm_err("Update %d FAILED: %s", call_id, pcmk_strerror(rc));
     }
 }
 
 /*!
  * \brief Handle a timeout in node-to-node communication
  *
  * \param[in] data  Pointer to graph action
  *
  * \return FALSE (indicating that source should be not be re-added)
  */
 gboolean
 action_timer_callback(gpointer data)
 {
     pcmk__graph_action_t *action = (pcmk__graph_action_t *) data;
     const char *task = NULL;
     const char *on_node = NULL;
     const char *via_node = NULL;
 
     CRM_CHECK(data != NULL, return FALSE);
 
     stop_te_timer(action);
 
     task = crm_element_value(action->xml, XML_LRM_ATTR_TASK);
     on_node = crm_element_value(action->xml, XML_LRM_ATTR_TARGET);
     via_node = crm_element_value(action->xml, XML_LRM_ATTR_ROUTER_NODE);
 
     if (transition_graph->complete) {
         crm_notice("Node %s did not send %s result (via %s) within %dms "
                    "(ignoring because transition not in progress)",
                    (on_node? on_node : ""), (task? task : "unknown action"),
                    (via_node? via_node : "controller"), action->timeout);
     } else {
         /* fail the action */
 
         crm_err("Node %s did not send %s result (via %s) within %dms "
                 "(action timeout plus cluster-delay)",
                 (on_node? on_node : ""), (task? task : "unknown action"),
                 (via_node? via_node : "controller"),
                 action->timeout + transition_graph->network_delay);
         pcmk__log_graph_action(LOG_ERR, action);
 
         pcmk__set_graph_action_flags(action, pcmk__graph_action_failed);
 
         te_action_confirmed(action, transition_graph);
         abort_transition(INFINITY, tg_restart, "Action lost", NULL);
 
         // Record timeout in the CIB if appropriate
         if ((action->type == pcmk__rsc_graph_action)
             && controld_action_is_recordable(task)) {
             controld_record_action_timeout(action);
         }
     }
 
     return FALSE;
 }
diff --git a/daemons/controld/controld_te_events.c b/daemons/controld/controld_te_events.c
index fdf1e9bc76..9dfefa614c 100644
--- a/daemons/controld/controld_te_events.c
+++ b/daemons/controld/controld_te_events.c
@@ -1,508 +1,508 @@
 /*
  * Copyright 2004-2022 the Pacemaker project contributors
  *
  * The version control history for this file may have further details.
  *
  * This source code is licensed under the GNU General Public License version 2
  * or later (GPLv2+) WITHOUT ANY WARRANTY.
  */
 
 #include <crm_internal.h>
 
 #include <sys/param.h>
 #include <crm/crm.h>
 #include <crm/cib.h>
 #include <crm/msg_xml.h>
 #include <crm/common/xml.h>
 
 #include <pacemaker-controld.h>
 
 char *failed_stop_offset = NULL;
 char *failed_start_offset = NULL;
 
 gboolean
 fail_incompletable_actions(pcmk__graph_t *graph, const char *down_node)
 {
     const char *target_uuid = NULL;
     const char *router = NULL;
     const char *router_uuid = NULL;
     xmlNode *last_action = NULL;
 
     GList *gIter = NULL;
     GList *gIter2 = NULL;
 
     if (graph == NULL || graph->complete) {
         return FALSE;
     }
 
     gIter = graph->synapses;
     for (; gIter != NULL; gIter = gIter->next) {
         pcmk__graph_synapse_t *synapse = (pcmk__graph_synapse_t *) gIter->data;
 
         if (pcmk_any_flags_set(synapse->flags, pcmk__synapse_confirmed|pcmk__synapse_failed)) {
             /* We've already been here */
             continue;
         }
 
         gIter2 = synapse->actions;
         for (; gIter2 != NULL; gIter2 = gIter2->next) {
             pcmk__graph_action_t *action = (pcmk__graph_action_t *) gIter2->data;
 
             if ((action->type == pcmk__pseudo_graph_action)
                 || pcmk_is_set(action->flags, pcmk__graph_action_confirmed)) {
                 continue;
             } else if (action->type == pcmk__cluster_graph_action) {
                 const char *task = crm_element_value(action->xml, XML_LRM_ATTR_TASK);
 
                 if (pcmk__str_eq(task, CRM_OP_FENCE, pcmk__str_casei)) {
                     continue;
                 }
             }
 
             target_uuid = crm_element_value(action->xml, XML_LRM_ATTR_TARGET_UUID);
             router = crm_element_value(action->xml, XML_LRM_ATTR_ROUTER_NODE);
             if (router) {
                 crm_node_t *node = crm_get_peer(0, router);
                 if (node) {
                     router_uuid = node->uuid;
                 }
             }
 
             if (pcmk__str_eq(target_uuid, down_node, pcmk__str_casei) || pcmk__str_eq(router_uuid, down_node, pcmk__str_casei)) {
                 pcmk__set_graph_action_flags(action, pcmk__graph_action_failed);
                 pcmk__set_synapse_flags(synapse, pcmk__synapse_failed);
                 last_action = action->xml;
                 stop_te_timer(action);
                 pcmk__update_graph(graph, action);
 
                 if (pcmk_is_set(synapse->flags, pcmk__synapse_executed)) {
                     crm_notice("Action %d (%s) was pending on %s (offline)",
                                action->id, crm_element_value(action->xml, XML_LRM_ATTR_TASK_KEY), down_node);
                 } else {
                     crm_info("Action %d (%s) is scheduled for %s (offline)",
                              action->id, crm_element_value(action->xml, XML_LRM_ATTR_TASK_KEY), down_node);
                 }
             }
         }
     }
 
     if (last_action != NULL) {
         crm_info("Node %s shutdown resulted in un-runnable actions", down_node);
         abort_transition(INFINITY, tg_restart, "Node failure", last_action);
         return TRUE;
     }
 
     return FALSE;
 }
 
 /*!
  * \internal
  * \brief Update failure-related node attributes if warranted
  *
  * \param[in] event            XML describing operation that (maybe) failed
  * \param[in] event_node_uuid  Node that event occurred on
  * \param[in] rc               Actual operation return code
  * \param[in] target_rc        Expected operation return code
  * \param[in] do_update        If TRUE, do update regardless of operation type
  * \param[in] ignore_failures  If TRUE, update last failure but not fail count
  *
  * \return TRUE if this was not a direct nack, success or lrm status refresh
  */
 static gboolean
 update_failcount(xmlNode * event, const char *event_node_uuid, int rc,
                  int target_rc, gboolean do_update, gboolean ignore_failures)
 {
     guint interval_ms = 0;
 
     char *task = NULL;
     char *rsc_id = NULL;
 
     const char *value = NULL;
     const char *id = crm_element_value(event, XML_LRM_ATTR_TASK_KEY);
     const char *on_uname = crm_peer_uname(event_node_uuid);
     const char *origin = crm_element_value(event, XML_ATTR_ORIGIN);
 
     // Nothing needs to be done for success or status refresh
     if (rc == target_rc) {
         return FALSE;
     } else if (pcmk__str_eq(origin, "build_active_RAs", pcmk__str_casei)) {
         crm_debug("No update for %s (rc=%d) on %s: Old failure from lrm status refresh",
                   id, rc, on_uname);
         return FALSE;
     }
 
     /* Sanity check */
     CRM_CHECK(on_uname != NULL, return TRUE);
     CRM_CHECK(parse_op_key(id, &rsc_id, &task, &interval_ms),
               crm_err("Couldn't parse: %s", ID(event)); goto bail);
 
     /* Decide whether update is necessary and what value to use */
     if ((interval_ms > 0) || pcmk__str_eq(task, CRMD_ACTION_PROMOTE, pcmk__str_casei)
         || pcmk__str_eq(task, CRMD_ACTION_DEMOTE, pcmk__str_casei)) {
         do_update = TRUE;
 
     } else if (pcmk__str_eq(task, CRMD_ACTION_START, pcmk__str_casei)) {
         do_update = TRUE;
         if (failed_start_offset == NULL) {
             failed_start_offset = strdup(CRM_INFINITY_S);
         }
         value = failed_start_offset;
 
     } else if (pcmk__str_eq(task, CRMD_ACTION_STOP, pcmk__str_casei)) {
         do_update = TRUE;
         if (failed_stop_offset == NULL) {
             failed_stop_offset = strdup(CRM_INFINITY_S);
         }
         value = failed_stop_offset;
     }
 
     /* Fail count will be either incremented or set to infinity */
     if (!pcmk_str_is_infinity(value)) {
         value = XML_NVPAIR_ATTR_VALUE "++";
     }
 
     if (do_update) {
         char *now = pcmk__ttoa(time(NULL));
         char *attr_name = NULL;
         gboolean is_remote_node = FALSE;
 
         if (g_hash_table_lookup(crm_remote_peer_cache, event_node_uuid)) {
             is_remote_node = TRUE;
         }
 
         crm_info("Updating %s for %s on %s after failed %s: rc=%d (update=%s, time=%s)",
                  (ignore_failures? "last failure" : "failcount"),
                  rsc_id, on_uname, task, rc, value, now);
 
         /* Update the fail count, if we're not ignoring failures */
         if (!ignore_failures) {
             attr_name = pcmk__failcount_name(rsc_id, task, interval_ms);
             update_attrd(on_uname, attr_name, value, NULL, is_remote_node);
             free(attr_name);
         }
 
         /* Update the last failure time (even if we're ignoring failures,
          * so that failure can still be detected and shown, e.g. by crm_mon)
          */
         attr_name = pcmk__lastfailure_name(rsc_id, task, interval_ms);
         update_attrd(on_uname, attr_name, now, NULL, is_remote_node);
         free(attr_name);
 
         free(now);
     }
 
   bail:
     free(rsc_id);
     free(task);
     return TRUE;
 }
 
 pcmk__graph_action_t *
 controld_get_action(int id)
 {
     for (GList *item = transition_graph->synapses; item; item = item->next) {
         pcmk__graph_synapse_t *synapse = (pcmk__graph_synapse_t *) item->data;
 
         for (GList *item2 = synapse->actions; item2; item2 = item2->next) {
             pcmk__graph_action_t *action = (pcmk__graph_action_t *) item2->data;
 
             if (action->id == id) {
                 return action;
             }
         }
     }
     return NULL;
 }
 
 pcmk__graph_action_t *
 get_cancel_action(const char *id, const char *node)
 {
     GList *gIter = NULL;
     GList *gIter2 = NULL;
 
     gIter = transition_graph->synapses;
     for (; gIter != NULL; gIter = gIter->next) {
         pcmk__graph_synapse_t *synapse = (pcmk__graph_synapse_t *) gIter->data;
 
         gIter2 = synapse->actions;
         for (; gIter2 != NULL; gIter2 = gIter2->next) {
             const char *task = NULL;
             const char *target = NULL;
             pcmk__graph_action_t *action = (pcmk__graph_action_t *) gIter2->data;
 
             task = crm_element_value(action->xml, XML_LRM_ATTR_TASK);
             if (!pcmk__str_eq(CRMD_ACTION_CANCEL, task, pcmk__str_casei)) {
                 continue;
             }
 
             task = crm_element_value(action->xml, XML_LRM_ATTR_TASK_KEY);
             if (!pcmk__str_eq(task, id, pcmk__str_casei)) {
                 crm_trace("Wrong key %s for %s on %s", task, id, node);
                 continue;
             }
 
             target = crm_element_value(action->xml, XML_LRM_ATTR_TARGET_UUID);
             if (node && !pcmk__str_eq(target, node, pcmk__str_casei)) {
                 crm_trace("Wrong node %s for %s on %s", target, id, node);
                 continue;
             }
 
             crm_trace("Found %s on %s", id, node);
             return action;
         }
     }
 
     return NULL;
 }
 
 bool
 confirm_cancel_action(const char *id, const char *node_id)
 {
     const char *op_key = NULL;
     const char *node_name = NULL;
     pcmk__graph_action_t *cancel = get_cancel_action(id, node_id);
 
     if (cancel == NULL) {
         return FALSE;
     }
     op_key = crm_element_value(cancel->xml, XML_LRM_ATTR_TASK_KEY);
     node_name = crm_element_value(cancel->xml, XML_LRM_ATTR_TARGET);
 
     stop_te_timer(cancel);
     te_action_confirmed(cancel, transition_graph);
 
     crm_info("Cancellation of %s on %s confirmed (action %d)",
              op_key, node_name, cancel->id);
     return TRUE;
 }
 
 /* downed nodes are listed like: <downed> <node id="UUID1" /> ... </downed> */
 #define XPATH_DOWNED "//" XML_GRAPH_TAG_DOWNED \
                      "/" XML_CIB_TAG_NODE "[@" XML_ATTR_UUID "='%s']"
 
 /*!
  * \brief Find a transition event that would have made a specified node down
  *
  * \param[in] target  UUID of node to match
  *
  * \return Matching event if found, NULL otherwise
  */
 pcmk__graph_action_t *
 match_down_event(const char *target)
 {
     pcmk__graph_action_t *match = NULL;
     xmlXPathObjectPtr xpath_ret = NULL;
     GList *gIter, *gIter2;
 
     char *xpath = crm_strdup_printf(XPATH_DOWNED, target);
 
     for (gIter = transition_graph->synapses;
          gIter != NULL && match == NULL;
          gIter = gIter->next) {
 
         for (gIter2 = ((pcmk__graph_synapse_t * ) gIter->data)->actions;
              gIter2 != NULL && match == NULL;
              gIter2 = gIter2->next) {
 
             match = (pcmk__graph_action_t *) gIter2->data;
             if (pcmk_is_set(match->flags, pcmk__graph_action_executed)) {
                 xpath_ret = xpath_search(match->xml, xpath);
                 if (numXpathResults(xpath_ret) < 1) {
                     match = NULL;
                 }
                 freeXpathObject(xpath_ret);
             } else {
                 // Only actions that were actually started can match
                 match = NULL;
             }
         }
     }
 
     free(xpath);
 
     if (match != NULL) {
         crm_debug("Shutdown action %d (%s) found for node %s", match->id,
                   crm_element_value(match->xml, XML_LRM_ATTR_TASK_KEY), target);
     } else {
         crm_debug("No reason to expect node %s to be down", target);
     }
     return match;
 }
 
 void
 process_graph_event(xmlNode *event, const char *event_node)
 {
     int rc = -1;                // Actual result
     int target_rc = -1;         // Expected result
     int status = -1;            // Executor status
     int callid = -1;            // Executor call ID
     int transition_num = -1;    // Transition number
     int action_num = -1;        // Action number within transition
     char *update_te_uuid = NULL;
     bool ignore_failures = FALSE;
     const char *id = NULL;
     const char *desc = NULL;
     const char *magic = NULL;
     const char *uname = NULL;
 
     CRM_ASSERT(event != NULL);
 
 /*
 <lrm_rsc_op id="rsc_east-05_last_0" operation_key="rsc_east-05_monitor_0" operation="monitor" crm-debug-origin="do_update_resource" crm_feature_set="3.0.6" transition-key="9:2:7:be2e97d9-05e2-439d-863e-48f7aecab2aa" transition-magic="0:7;9:2:7:be2e97d9-05e2-439d-863e-48f7aecab2aa" call-id="17" rc-code="7" op-status="0" interval="0" last-rc-change="1355361636" exec-time="128" queue-time="0" op-digest="c81f5f40b1c9e859c992e800b1aa6972"/>
 */
 
     magic = crm_element_value(event, XML_ATTR_TRANSITION_KEY);
     if (magic == NULL) {
         /* non-change */
         return;
     }
 
     crm_element_value_int(event, XML_LRM_ATTR_OPSTATUS, &status);
     if (status == PCMK_EXEC_PENDING) {
         return;
     }
 
     id = crm_element_value(event, XML_LRM_ATTR_TASK_KEY);
     crm_element_value_int(event, XML_LRM_ATTR_RC, &rc);
     crm_element_value_int(event, XML_LRM_ATTR_CALLID, &callid);
 
     rc = pcmk__effective_rc(rc);
 
     if (decode_transition_key(magic, &update_te_uuid, &transition_num,
                               &action_num, &target_rc) == FALSE) {
         // decode_transition_key() already logged the bad key
         crm_err("Can't process action %s result: Incompatible versions? "
                 CRM_XS " call-id=%d", id, callid);
         abort_transition(INFINITY, tg_restart, "Bad event", event);
         return;
     }
 
     if (transition_num == -1) {
         // E.g. crm_resource --fail
         desc = "initiated outside of the cluster";
         abort_transition(INFINITY, tg_restart, "Unexpected event", event);
 
     } else if ((action_num < 0) || !pcmk__str_eq(update_te_uuid, te_uuid, pcmk__str_none)) {
         desc = "initiated by a different DC";
         abort_transition(INFINITY, tg_restart, "Foreign event", event);
 
     } else if ((transition_graph->id != transition_num)
-               || (transition_graph->complete)) {
+               || transition_graph->complete) {
 
         // Action is not from currently active transition
 
         guint interval_ms = 0;
 
         if (parse_op_key(id, NULL, NULL, &interval_ms)
             && (interval_ms != 0)) {
             /* Recurring actions have the transition number they were first
              * scheduled in.
              */
 
             if (status == PCMK_EXEC_CANCELLED) {
                 confirm_cancel_action(id, get_node_id(event));
                 goto bail;
             }
 
             desc = "arrived after initial scheduling";
             abort_transition(INFINITY, tg_restart, "Change in recurring result",
                              event);
 
         } else if (transition_graph->id != transition_num) {
             desc = "arrived really late";
             abort_transition(INFINITY, tg_restart, "Old event", event);
         } else {
             desc = "arrived late";
             abort_transition(INFINITY, tg_restart, "Inactive graph", event);
         }
 
     } else {
         // Event is result of an action from currently active transition
         pcmk__graph_action_t *action = controld_get_action(action_num);
 
         if (action == NULL) {
             // Should never happen
             desc = "unknown";
             abort_transition(INFINITY, tg_restart, "Unknown event", event);
 
         } else if (pcmk_is_set(action->flags, pcmk__graph_action_confirmed)) {
             /* Nothing further needs to be done if the action has already been
              * confirmed. This can happen e.g. when processing both an
              * "xxx_last_0" or "xxx_last_failure_0" record as well as the main
              * history record, which would otherwise result in incorrectly
              * bumping the fail count twice.
              */
             crm_log_xml_debug(event, "Event already confirmed:");
             goto bail;
 
         } else {
             /* An action result needs to be confirmed.
              * (This is the only case where desc == NULL.)
              */
 
             if (pcmk__str_eq(crm_meta_value(action->params, XML_OP_ATTR_ON_FAIL), "ignore", pcmk__str_casei)) {
                 ignore_failures = TRUE;
 
             } else if (rc != target_rc) {
                 pcmk__set_graph_action_flags(action, pcmk__graph_action_failed);
             }
 
             stop_te_timer(action);
             te_action_confirmed(action, transition_graph);
 
             if (pcmk_is_set(action->flags, pcmk__graph_action_failed)) {
                 abort_transition(action->synapse->priority + 1, tg_restart,
                                  "Event failed", event);
             }
         }
     }
 
     if (id == NULL) {
         id = "unknown action";
     }
     uname = crm_element_value(event, XML_LRM_ATTR_TARGET);
     if (uname == NULL) {
         uname = "unknown node";
     }
 
     if (status == PCMK_EXEC_INVALID) {
         // We couldn't attempt the action
         crm_info("Transition %d action %d (%s on %s): %s",
                  transition_num, action_num, id, uname,
                  pcmk_exec_status_str(status));
 
     } else if (desc && update_failcount(event, event_node, rc, target_rc,
                                         (transition_num == -1), FALSE)) {
         crm_notice("Transition %d action %d (%s on %s): expected '%s' but got '%s' "
                    CRM_XS " target-rc=%d rc=%d call-id=%d event='%s'",
                    transition_num, action_num, id, uname,
                    services_ocf_exitcode_str(target_rc),
                    services_ocf_exitcode_str(rc),
                    target_rc, rc, callid, desc);
 
     } else if (desc) {
         crm_info("Transition %d action %d (%s on %s): %s "
                  CRM_XS " rc=%d target-rc=%d call-id=%d",
                  transition_num, action_num, id, uname,
                  desc, rc, target_rc, callid);
 
     } else if (rc == target_rc) {
         crm_info("Transition %d action %d (%s on %s) confirmed: %s "
                  CRM_XS " rc=%d call-id=%d",
                  transition_num, action_num, id, uname,
                  services_ocf_exitcode_str(rc), rc, callid);
 
     } else {
         update_failcount(event, event_node, rc, target_rc,
                          (transition_num == -1), ignore_failures);
         crm_notice("Transition %d action %d (%s on %s): expected '%s' but got '%s' "
                    CRM_XS " target-rc=%d rc=%d call-id=%d",
                    transition_num, action_num, id, uname,
                    services_ocf_exitcode_str(target_rc),
                    services_ocf_exitcode_str(rc),
                    target_rc, rc, callid);
     }
 
   bail:
     free(update_te_uuid);
 }
diff --git a/daemons/controld/controld_te_utils.c b/daemons/controld/controld_te_utils.c
index 23dcff745e..a28bc758dd 100644
--- a/daemons/controld/controld_te_utils.c
+++ b/daemons/controld/controld_te_utils.c
@@ -1,335 +1,336 @@
 /*
  * Copyright 2004-2022 the Pacemaker project contributors
  *
  * The version control history for this file may have further details.
  *
  * This source code is licensed under the GNU General Public License version 2
  * or later (GPLv2+) WITHOUT ANY WARRANTY.
  */
 
 #include <crm_internal.h>
 #include <crm/crm.h>
 #include <crm/msg_xml.h>
 #include <crm/common/xml.h>
 
 #include <pacemaker-controld.h>
 
 gboolean
 stop_te_timer(pcmk__graph_action_t *action)
 {
     if (action == NULL) {
         return FALSE;
     }
     if (action->timer != 0) {
         crm_trace("Stopping action timer");
         g_source_remove(action->timer);
         action->timer = 0;
     } else {
         crm_trace("Action timer was already stopped");
         return FALSE;
     }
     return TRUE;
 }
 
 gboolean
 te_graph_trigger(gpointer user_data)
 {
     if (transition_graph == NULL) {
         crm_debug("Nothing to do");
         return TRUE;
     }
 
     crm_trace("Invoking graph %d in state %s", transition_graph->id, fsa_state2string(fsa_state));
 
     switch (fsa_state) {
         case S_STARTING:
         case S_PENDING:
         case S_NOT_DC:
         case S_HALT:
         case S_ILLEGAL:
         case S_STOPPING:
         case S_TERMINATE:
             return TRUE;
         default:
             break;
     }
 
-    if (transition_graph->complete == FALSE) {
+    if (!transition_graph->complete) {
         enum transition_status graph_rc;
         int limit = transition_graph->batch_limit;
 
         transition_graph->batch_limit = throttle_get_total_job_limit(limit);
         graph_rc = pcmk__execute_graph(transition_graph);
         transition_graph->batch_limit = limit; /* Restore the configured value */
 
         if (graph_rc == transition_active) {
             crm_trace("Transition not yet complete");
             return TRUE;
 
         } else if (graph_rc == transition_pending) {
             crm_trace("Transition not yet complete - no actions fired");
             return TRUE;
         }
 
         if (graph_rc != transition_complete) {
             crm_warn("Transition failed: %s",
                      pcmk__graph_status2text(graph_rc));
             pcmk__log_graph(LOG_NOTICE, transition_graph);
         }
     }
 
     crm_debug("Transition %d is now complete", transition_graph->id);
-    transition_graph->complete = TRUE;
+    transition_graph->complete = true;
     notify_crmd(transition_graph);
 
     return TRUE;
 }
 
 void
 trigger_graph_processing(const char *fn, int line)
 {
     crm_trace("%s:%d - Triggered graph processing", fn, line);
     mainloop_set_trigger(transition_trigger);
 }
 
 static struct abort_timer_s {
     bool aborted;
     guint id;
     int priority;
     enum transition_action action;
     const char *text;
 } abort_timer = { 0, };
 
 static gboolean
 abort_timer_popped(gpointer data)
 {
     if (AM_I_DC && (abort_timer.aborted == FALSE)) {
         abort_transition(abort_timer.priority, abort_timer.action,
                          abort_timer.text, NULL);
     }
     abort_timer.id = 0;
     return FALSE; // do not immediately reschedule timer
 }
 
 /*!
  * \internal
  * \brief Abort transition after delay, if not already aborted in that time
  *
  * \param[in] abort_text  Must be literal string
  */
 void
 abort_after_delay(int abort_priority, enum transition_action abort_action,
                   const char *abort_text, guint delay_ms)
 {
     if (abort_timer.id) {
         // Timer already in progress, stop and reschedule
         g_source_remove(abort_timer.id);
     }
     abort_timer.aborted = FALSE;
     abort_timer.priority = abort_priority;
     abort_timer.action = abort_action;
     abort_timer.text = abort_text;
     abort_timer.id = g_timeout_add(delay_ms, abort_timer_popped, NULL);
 }
 
 static const char *
 abort2text(enum transition_action abort_action)
 {
     switch (abort_action) {
         case tg_done:
             return "done";
         case tg_stop:
             return "stop";
         case tg_restart:
             return "restart";
         case tg_shutdown:
             return "shutdown";
     }
     return "unknown";
 }
 
 static bool
 update_abort_priority(pcmk__graph_t *graph, int priority,
                       enum transition_action action, const char *abort_reason)
 {
     bool change = FALSE;
 
     if (graph == NULL) {
         return change;
     }
 
     if (graph->abort_priority < priority) {
         crm_debug("Abort priority upgraded from %d to %d", graph->abort_priority, priority);
         graph->abort_priority = priority;
         if (graph->abort_reason != NULL) {
             crm_debug("'%s' abort superseded by %s", graph->abort_reason, abort_reason);
         }
         graph->abort_reason = abort_reason;
         change = TRUE;
     }
 
     if (graph->completion_action < action) {
         crm_debug("Abort action %s superseded by %s: %s",
                   abort2text(graph->completion_action), abort2text(action), abort_reason);
         graph->completion_action = action;
         change = TRUE;
     }
 
     return change;
 }
 
 void
 abort_transition_graph(int abort_priority, enum transition_action abort_action,
                        const char *abort_text, xmlNode * reason, const char *fn, int line)
 {
     int add[] = { 0, 0, 0 };
     int del[] = { 0, 0, 0 };
     int level = LOG_INFO;
     xmlNode *diff = NULL;
     xmlNode *change = NULL;
 
     CRM_CHECK(transition_graph != NULL, return);
 
     switch (fsa_state) {
         case S_STARTING:
         case S_PENDING:
         case S_NOT_DC:
         case S_HALT:
         case S_ILLEGAL:
         case S_STOPPING:
         case S_TERMINATE:
-            crm_info("Abort %s suppressed: state=%s (complete=%d)",
-                     abort_text, fsa_state2string(fsa_state), transition_graph->complete);
+            crm_info("Abort %s suppressed: state=%s (%scomplete)",
+                     abort_text, fsa_state2string(fsa_state),
+                     (transition_graph->complete? "" : "in"));
             return;
         default:
             break;
     }
 
     abort_timer.aborted = TRUE;
     controld_expect_sched_reply(NULL);
 
-    if (transition_graph->complete == FALSE) {
+    if (!transition_graph->complete) {
         if(update_abort_priority(transition_graph, abort_priority, abort_action, abort_text)) {
             level = LOG_NOTICE;
         }
     }
 
     if(reason) {
         xmlNode *search = NULL;
 
         for(search = reason; search; search = search->parent) {
             if (pcmk__str_eq(XML_TAG_DIFF, TYPE(search), pcmk__str_casei)) {
                 diff = search;
                 break;
             }
         }
 
         if(diff) {
             xml_patch_versions(diff, add, del);
             for(search = reason; search; search = search->parent) {
                 if (pcmk__str_eq(XML_DIFF_CHANGE, TYPE(search), pcmk__str_casei)) {
                     change = search;
                     break;
                 }
             }
         }
     }
 
     if(reason == NULL) {
         do_crm_log(level, "Transition %d aborted: %s "CRM_XS" source=%s:%d complete=%s",
                    transition_graph->id, abort_text, fn, line,
                    pcmk__btoa(transition_graph->complete));
 
     } else if(change == NULL) {
         char *local_path = xml_get_path(reason);
 
         do_crm_log(level, "Transition %d aborted by %s.%s: %s "
                    CRM_XS " cib=%d.%d.%d source=%s:%d path=%s complete=%s",
                    transition_graph->id, TYPE(reason), ID(reason), abort_text,
                    add[0], add[1], add[2], fn, line, local_path,
                    pcmk__btoa(transition_graph->complete));
         free(local_path);
 
     } else {
         const char *kind = NULL;
         const char *op = crm_element_value(change, XML_DIFF_OP);
         const char *path = crm_element_value(change, XML_DIFF_PATH);
 
         if(change == reason) {
             if(strcmp(op, "create") == 0) {
                 reason = reason->children;
 
             } else if(strcmp(op, "modify") == 0) {
                 reason = first_named_child(reason, XML_DIFF_RESULT);
                 if(reason) {
                     reason = reason->children;
                 }
             }
         }
 
         kind = TYPE(reason);
         if(strcmp(op, "delete") == 0) {
             const char *shortpath = strrchr(path, '/');
 
             do_crm_log(level, "Transition %d aborted by deletion of %s: %s "
                        CRM_XS " cib=%d.%d.%d source=%s:%d path=%s complete=%s",
                        transition_graph->id,
                        (shortpath? (shortpath + 1) : path), abort_text,
                        add[0], add[1], add[2], fn, line, path,
                        pcmk__btoa(transition_graph->complete));
 
         } else if (pcmk__str_eq(XML_CIB_TAG_NVPAIR, kind, pcmk__str_casei)) { 
             do_crm_log(level, "Transition %d aborted by %s doing %s %s=%s: %s "
                        CRM_XS " cib=%d.%d.%d source=%s:%d path=%s complete=%s",
                        transition_graph->id,
                        crm_element_value(reason, XML_ATTR_ID), op,
                        crm_element_value(reason, XML_NVPAIR_ATTR_NAME),
                        crm_element_value(reason, XML_NVPAIR_ATTR_VALUE),
                        abort_text, add[0], add[1], add[2], fn, line, path,
                        pcmk__btoa(transition_graph->complete));
 
         } else if (pcmk__str_eq(XML_LRM_TAG_RSC_OP, kind, pcmk__str_casei)) {
             const char *magic = crm_element_value(reason, XML_ATTR_TRANSITION_MAGIC);
 
             do_crm_log(level, "Transition %d aborted by operation %s '%s' on %s: %s "
                        CRM_XS " magic=%s cib=%d.%d.%d source=%s:%d complete=%s",
                        transition_graph->id,
                        crm_element_value(reason, XML_LRM_ATTR_TASK_KEY), op,
                        crm_element_value(reason, XML_LRM_ATTR_TARGET), abort_text,
                        magic, add[0], add[1], add[2], fn, line,
                        pcmk__btoa(transition_graph->complete));
 
         } else if (pcmk__strcase_any_of(kind, XML_CIB_TAG_STATE, XML_CIB_TAG_NODE, NULL)) {
             const char *uname = crm_peer_uname(ID(reason));
 
             do_crm_log(level, "Transition %d aborted by %s '%s' on %s: %s "
                        CRM_XS " cib=%d.%d.%d source=%s:%d complete=%s",
                        transition_graph->id,
                        kind, op, (uname? uname : ID(reason)), abort_text,
                        add[0], add[1], add[2], fn, line,
                        pcmk__btoa(transition_graph->complete));
 
         } else {
             const char *id = ID(reason);
 
             do_crm_log(level, "Transition %d aborted by %s.%s '%s': %s "
                        CRM_XS " cib=%d.%d.%d source=%s:%d path=%s complete=%s",
                        transition_graph->id,
                        TYPE(reason), (id? id : ""), (op? op : "change"),
                        abort_text, add[0], add[1], add[2], fn, line, path,
                        pcmk__btoa(transition_graph->complete));
         }
     }
 
     if (transition_graph->complete) {
         if (transition_timer->period_ms > 0) {
             controld_stop_timer(transition_timer);
             controld_start_timer(transition_timer);
         } else {
             register_fsa_input(C_FSA_INTERNAL, I_PE_CALC, NULL);
         }
         return;
     }
 
     mainloop_set_trigger(transition_trigger);
 }
diff --git a/daemons/controld/controld_transition.c b/daemons/controld/controld_transition.c
index 60b4eba10c..c8d7f139d0 100644
--- a/daemons/controld/controld_transition.c
+++ b/daemons/controld/controld_transition.c
@@ -1,214 +1,214 @@
 /*
  * Copyright 2004-2022 the Pacemaker project contributors
  *
  * The version control history for this file may have further details.
  *
  * This source code is licensed under the GNU General Public License version 2
  * or later (GPLv2+) WITHOUT ANY WARRANTY.
  */
 
 #include <crm_internal.h>
 
 #include <crm/crm.h>
 #include <crm/msg_xml.h>
 #include <crm/common/xml.h>
 
 #include <pacemaker-controld.h>
 
 extern pcmk__graph_functions_t te_graph_fns;
 
 static void
 global_cib_callback(const xmlNode * msg, int callid, int rc, xmlNode * output)
 {
 }
 
 static pcmk__graph_t *
 create_blank_graph(void)
 {
     pcmk__graph_t *a_graph = pcmk__unpack_graph(NULL, NULL);
 
-    a_graph->complete = TRUE;
+    a_graph->complete = true;
     a_graph->abort_reason = "DC Takeover";
     a_graph->completion_action = tg_restart;
     return a_graph;
 }
 
 /*	 A_TE_START, A_TE_STOP, O_TE_RESTART	*/
 void
 do_te_control(long long action,
               enum crmd_fsa_cause cause,
               enum crmd_fsa_state cur_state,
               enum crmd_fsa_input current_input, fsa_data_t * msg_data)
 {
     gboolean init_ok = TRUE;
 
     if (action & A_TE_STOP) {
         if (transition_graph) {
             pcmk__free_graph(transition_graph);
             transition_graph = NULL;
         }
 
         if (fsa_cib_conn) {
             fsa_cib_conn->cmds->del_notify_callback(fsa_cib_conn, T_CIB_DIFF_NOTIFY,
                                                     te_update_diff);
         }
 
         controld_clear_fsa_input_flags(R_TE_CONNECTED);
         crm_info("Transitioner is now inactive");
     }
 
     if ((action & A_TE_START) == 0) {
         return;
 
     } else if (pcmk_is_set(fsa_input_register, R_TE_CONNECTED)) {
         crm_debug("The transitioner is already active");
         return;
 
     } else if ((action & A_TE_START) && cur_state == S_STOPPING) {
         crm_info("Ignoring request to start the transitioner while shutting down");
         return;
     }
 
     if (te_uuid == NULL) {
         te_uuid = crm_generate_uuid();
         crm_info("Registering TE UUID: %s", te_uuid);
     }
 
     if (fsa_cib_conn == NULL) {
         crm_err("Could not set CIB callbacks");
         init_ok = FALSE;
 
     } else {
 
         if (fsa_cib_conn->cmds->add_notify_callback(fsa_cib_conn,
             T_CIB_DIFF_NOTIFY, te_update_diff) != pcmk_ok) {
 
             crm_err("Could not set CIB notification callback");
             init_ok = FALSE;
         }
 
         if (fsa_cib_conn->cmds->set_op_callback(fsa_cib_conn,
             global_cib_callback) != pcmk_ok) {
 
             crm_err("Could not set CIB global callback");
             init_ok = FALSE;
         }
     }
 
     if (init_ok) {
         pcmk__set_graph_functions(&te_graph_fns);
 
         if (transition_graph) {
             pcmk__free_graph(transition_graph);
         }
 
         /* create a blank one */
         crm_debug("Transitioner is now active");
         transition_graph = create_blank_graph();
         controld_set_fsa_input_flags(R_TE_CONNECTED);
     }
 }
 
 /*	 A_TE_INVOKE, A_TE_CANCEL	*/
 void
 do_te_invoke(long long action,
              enum crmd_fsa_cause cause,
              enum crmd_fsa_state cur_state,
              enum crmd_fsa_input current_input, fsa_data_t * msg_data)
 {
 
     if (AM_I_DC == FALSE || (fsa_state != S_TRANSITION_ENGINE && (action & A_TE_INVOKE))) {
         crm_notice("No need to invoke the TE (%s) in state %s",
                    fsa_action2string(action), fsa_state2string(fsa_state));
         return;
     }
 
     if (action & A_TE_CANCEL) {
         crm_debug("Cancelling the transition: %s",
                   transition_graph->complete ? "inactive" : "active");
         abort_transition(INFINITY, tg_restart, "Peer Cancelled", NULL);
-        if (transition_graph->complete == FALSE) {
+        if (!transition_graph->complete) {
             crmd_fsa_stall(FALSE);
         }
 
     } else if (action & A_TE_HALT) {
         abort_transition(INFINITY, tg_stop, "Peer Halt", NULL);
-        if (transition_graph->complete == FALSE) {
+        if (!transition_graph->complete) {
             crmd_fsa_stall(FALSE);
         }
 
     } else if (action & A_TE_INVOKE) {
         const char *value = NULL;
         xmlNode *graph_data = NULL;
         ha_msg_input_t *input = fsa_typed_data(fsa_dt_ha_msg);
         const char *ref = crm_element_value(input->msg, XML_ATTR_REFERENCE);
         const char *graph_file = crm_element_value(input->msg, F_CRM_TGRAPH);
         const char *graph_input = crm_element_value(input->msg, F_CRM_TGRAPH_INPUT);
 
         if (graph_file == NULL && input->xml == NULL) {
             crm_log_xml_err(input->msg, "Bad command");
             register_fsa_error(C_FSA_INTERNAL, I_FAIL, NULL);
             return;
         }
 
-        if (transition_graph->complete == FALSE) {
+        if (!transition_graph->complete) {
             crm_info("Another transition is already active");
             abort_transition(INFINITY, tg_restart, "Transition Active", NULL);
             return;
         }
 
         if (fsa_pe_ref == NULL || !pcmk__str_eq(fsa_pe_ref, ref, pcmk__str_casei)) {
             crm_info("Transition is redundant: %s vs. %s",
                      pcmk__s(fsa_pe_ref, "<null>"), pcmk__s(ref, "<null>"));
             abort_transition(INFINITY, tg_restart, "Transition Redundant", NULL);
         }
 
         graph_data = input->xml;
 
         if (graph_data == NULL && graph_file != NULL) {
             graph_data = filename2xml(graph_file);
         }
 
         if (is_timer_started(transition_timer)) {
             crm_debug("The transitioner wait for a transition timer");
             return;
         }
 
         CRM_CHECK(graph_data != NULL,
                   crm_err("Input raised by %s is invalid", msg_data->origin);
                   crm_log_xml_err(input->msg, "Bad command");
                   return);
 
         pcmk__free_graph(transition_graph);
         transition_graph = pcmk__unpack_graph(graph_data, graph_input);
         CRM_CHECK(transition_graph != NULL,
                   transition_graph = create_blank_graph(); return);
         crm_info("Processing graph %d (ref=%s) derived from %s", transition_graph->id, ref,
                  graph_input);
 
         te_reset_job_counts();
         value = crm_element_value(graph_data, "failed-stop-offset");
         if (value) {
             free(failed_stop_offset);
             failed_stop_offset = strdup(value);
         }
 
         value = crm_element_value(graph_data, "failed-start-offset");
         if (value) {
             free(failed_start_offset);
             failed_start_offset = strdup(value);
         }
 
         if ((crm_element_value_epoch(graph_data, "recheck-by", &recheck_by)
             != pcmk_ok) || (recheck_by < 0)) {
             recheck_by = 0;
         }
 
         trigger_graph();
         pcmk__log_graph(LOG_TRACE, transition_graph);
 
         if (graph_data != input->xml) {
             free_xml(graph_data);
         }
     }
 }
diff --git a/include/pcmki/pcmki_transition.h b/include/pcmki/pcmki_transition.h
index 7c4f77ad50..d0ebd9f446 100644
--- a/include/pcmki/pcmki_transition.h
+++ b/include/pcmki/pcmki_transition.h
@@ -1,164 +1,164 @@
 /*
  * Copyright 2004-2022 the Pacemaker project contributors
  *
  * The version control history for this file may have further details.
  *
  * This source code is licensed under the GNU Lesser General Public License
  * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
  */
 
 #ifndef PCMK__PCMKI_PCMKI_TRANSITION__H
 #  define PCMK__PCMKI_PCMKI_TRANSITION__H
 
 #  include <glib.h>
 #  include <crm/crm.h>
 #  include <crm/msg_xml.h>
 #  include <crm/common/xml.h>
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
 enum pcmk__graph_action_type {
     pcmk__pseudo_graph_action,
     pcmk__rsc_graph_action,
     pcmk__cluster_graph_action,
 };
 
 enum pcmk__synapse_flags {
     pcmk__synapse_ready       = (1 << 0),
     pcmk__synapse_failed      = (1 << 1),
     pcmk__synapse_executed    = (1 << 2),
     pcmk__synapse_confirmed   = (1 << 3),
 };
 
 typedef struct {
     int id;
     int priority;
 
     uint32_t flags; // Group of pcmk__synapse_flags
 
     GList *actions;           /* pcmk__graph_action_t* */
     GList *inputs;            /* pcmk__graph_action_t* */
 } pcmk__graph_synapse_t;
 
 #define pcmk__set_synapse_flags(synapse, flags_to_set) do {             \
         (synapse)->flags = pcmk__set_flags_as(__func__, __LINE__,       \
             LOG_TRACE,                                                  \
             "Synapse", "synapse",                       \
             (synapse)->flags, (flags_to_set), #flags_to_set);           \
     } while (0)
 
 #define pcmk__clear_synapse_flags(synapse, flags_to_clear) do {         \
         (synapse)->flags = pcmk__clear_flags_as(__func__, __LINE__,     \
             LOG_TRACE,                                                  \
             "Synapse", "synapse",                      \
             (synapse)->flags, (flags_to_clear), #flags_to_clear);       \
     } while (0)
 
 enum pcmk__graph_action_flags {
     pcmk__graph_action_sent_update   = (1 << 0),     /* sent to the CIB */
     pcmk__graph_action_executed      = (1 << 1),     /* sent to the CRM */
     pcmk__graph_action_confirmed     = (1 << 2),
     pcmk__graph_action_failed        = (1 << 3),
     pcmk__graph_action_can_fail      = (1 << 4),     //! \deprecated Will be removed in a future release
 };
 
 typedef struct {
     int id;
     int timeout;
     int timer;
     guint interval_ms;
     GHashTable *params;
     enum pcmk__graph_action_type type;
     pcmk__graph_synapse_t *synapse;
 
     uint32_t flags; // Group of pcmk__graph_action_flags
 
     xmlNode *xml;
 
 } pcmk__graph_action_t;
 
 #define pcmk__set_graph_action_flags(action, flags_to_set) do {       \
         (action)->flags = pcmk__set_flags_as(__func__, __LINE__,      \
             LOG_TRACE,                                                \
             "Action", "action",                                       \
             (action)->flags, (flags_to_set), #flags_to_set);          \
     } while (0)
 
 #define pcmk__clear_graph_action_flags(action, flags_to_clear) do {   \
         (action)->flags = pcmk__clear_flags_as(__func__, __LINE__,    \
             LOG_TRACE,                                                \
             "Action", "action",                                       \
             (action)->flags, (flags_to_clear), #flags_to_clear);      \
     } while (0)
 
 /* order matters here */
 enum transition_action {
     tg_done,
     tg_stop,
     tg_restart,
     tg_shutdown,
 };
 
 typedef struct {
     int id;
     char *source;
     int abort_priority;
 
-    gboolean complete;
+    bool complete;
     const char *abort_reason;
     enum transition_action completion_action;
 
     int num_actions;
     int num_synapses;
 
     int batch_limit;
     guint network_delay;
     guint stonith_timeout;
 
     int fired;
     int pending;
     int skipped;
     int completed;
     int incomplete;
 
     GList *synapses;          /* pcmk__graph_synapse_t* */
 
     int migration_limit;
 } pcmk__graph_t;
 
 
 typedef struct {
     gboolean (*pseudo) (pcmk__graph_t *graph, pcmk__graph_action_t *action);
     gboolean (*rsc) (pcmk__graph_t *graph, pcmk__graph_action_t *action);
     gboolean (*crmd) (pcmk__graph_t *graph, pcmk__graph_action_t *action);
     gboolean (*stonith) (pcmk__graph_t *graph, pcmk__graph_action_t *action);
     gboolean (*allowed) (pcmk__graph_t *graph, pcmk__graph_action_t *action);
 } pcmk__graph_functions_t;
 
 enum transition_status {
     transition_active,
     transition_pending,         /* active but no actions performed this time */
     transition_complete,
     transition_terminated,
 };
 
 void pcmk__set_graph_functions(pcmk__graph_functions_t *fns);
 pcmk__graph_t *pcmk__unpack_graph(xmlNode *xml_graph, const char *reference);
 enum transition_status pcmk__execute_graph(pcmk__graph_t *graph);
 void pcmk__update_graph(pcmk__graph_t *graph, pcmk__graph_action_t *action);
 void pcmk__free_graph(pcmk__graph_t *graph);
 const char *pcmk__graph_status2text(enum transition_status state);
 void pcmk__log_graph(unsigned int log_level, pcmk__graph_t *graph);
 void pcmk__log_graph_action(int log_level, pcmk__graph_action_t *action);
 lrmd_event_data_t *pcmk__event_from_graph_action(xmlNode *resource,
                                                  pcmk__graph_action_t *action,
                                                  int status, int rc,
                                                  const char *exit_reason);
 
 #ifdef __cplusplus
 }
 #endif
 
 #endif
diff --git a/lib/pacemaker/pcmk_graph_consumer.c b/lib/pacemaker/pcmk_graph_consumer.c
index 382932e9da..1a8d587b44 100644
--- a/lib/pacemaker/pcmk_graph_consumer.c
+++ b/lib/pacemaker/pcmk_graph_consumer.c
@@ -1,858 +1,858 @@
 /*
  * Copyright 2004-2022 the Pacemaker project contributors
  *
  * The version control history for this file may have further details.
  *
  * This source code is licensed under the GNU Lesser General Public License
  * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
  */
 
 #include <crm_internal.h>
 
 #include <sys/param.h>
 #include <sys/stat.h>
 
 #include <crm/crm.h>
 #include <crm/msg_xml.h>
 #include <crm/common/xml.h>
 #include <crm/common/xml_internal.h>
 #include <crm/lrmd_internal.h>
 #include <pacemaker-internal.h>
 
 
 /*
  * Functions for updating graph
  */
 
 /*!
  * \internal
  * \brief Update synapse after completed prerequisite
  *
  * A synapse is ready to be executed once all its prerequisite actions (inputs)
  * complete. Given a completed action, check whether it is an input for a given
  * synapse, and if so, mark the input as confirmed, and mark the synapse as
  * ready if appropriate.
  *
  * \param[in] synapse    Transition graph synapse to update
  * \param[in] action_id  ID of an action that completed
  *
  * \note The only substantial effect here is confirming synapse inputs.
  *       should_fire_synapse() will recalculate pcmk__synapse_ready, so the only
  *       thing that uses the pcmk__synapse_ready from here is
  *       synapse_state_str().
  */
 static void
 update_synapse_ready(pcmk__graph_synapse_t *synapse, int action_id)
 {
     if (pcmk_is_set(synapse->flags, pcmk__synapse_ready)) {
         return; // All inputs have already been confirmed
     }
     pcmk__set_synapse_flags(synapse, pcmk__synapse_ready); // Presume ready until proven otherwise
     for (GList *lpc = synapse->inputs; lpc != NULL; lpc = lpc->next) {
         pcmk__graph_action_t *prereq = (pcmk__graph_action_t *) lpc->data;
 
         if (prereq->id == action_id) {
             crm_trace("Confirming input %d of synapse %d",
                       action_id, synapse->id);
             pcmk__set_graph_action_flags(prereq, pcmk__graph_action_confirmed);
 
         } else if (!(pcmk_is_set(prereq->flags, pcmk__graph_action_confirmed))) {
             pcmk__clear_synapse_flags(synapse, pcmk__synapse_ready);
             crm_trace("Synapse %d still not ready after action %d",
                       synapse->id, action_id);
         }
     }
     if (pcmk_is_set(synapse->flags, pcmk__synapse_ready)) {
         crm_trace("Synapse %d is now ready to execute", synapse->id);
     }
 }
 
 /*!
  * \internal
  * \brief Update action and synapse confirmation after action completion
  *
  * \param[in] synapse    Transition graph synapse that action belongs to
  * \param[in] action_id  ID of action that completed
  */
 static void
 update_synapse_confirmed(pcmk__graph_synapse_t *synapse, int action_id)
 {
     bool all_confirmed = true;
 
     for (GList *lpc = synapse->actions; lpc != NULL; lpc = lpc->next) {
         pcmk__graph_action_t *action = (pcmk__graph_action_t *) lpc->data;
 
         if (action->id == action_id) {
             crm_trace("Confirmed action %d of synapse %d",
                       action_id, synapse->id);
             pcmk__set_graph_action_flags(action, pcmk__graph_action_confirmed);
 
         } else if (all_confirmed && !(pcmk_is_set(action->flags, pcmk__graph_action_confirmed))) {
             all_confirmed = false;
             crm_trace("Synapse %d still not confirmed after action %d",
                       synapse->id, action_id);
         }
     }
 
     if (all_confirmed && !(pcmk_is_set(synapse->flags, pcmk__synapse_confirmed))) {
         crm_trace("Confirmed synapse %d", synapse->id);
         pcmk__set_synapse_flags(synapse, pcmk__synapse_confirmed);
     }
 }
 
 /*!
  * \internal
  * \brief Update the transition graph with a completed action result
  *
  * \param[in,out] graph   Transition graph to update
  * \param[in]     action  Action that completed
  */
 void
 pcmk__update_graph(pcmk__graph_t *graph, pcmk__graph_action_t *action)
 {
     for (GList *lpc = graph->synapses; lpc != NULL; lpc = lpc->next) {
         pcmk__graph_synapse_t *synapse = (pcmk__graph_synapse_t *) lpc->data;
 
         if (pcmk_any_flags_set(synapse->flags, pcmk__synapse_confirmed|pcmk__synapse_failed)) {
             continue; // This synapse already completed
 
         } else if (pcmk_is_set(synapse->flags, pcmk__synapse_executed)) {
             update_synapse_confirmed(synapse, action->id);
 
         } else if (!(pcmk_is_set(action->flags, pcmk__graph_action_failed)) || (synapse->priority == INFINITY)) {
             update_synapse_ready(synapse, action->id);
         }
     }
 }
 
 
 /*
  * Functions for executing graph
  */
 
 /* A transition graph consists of various types of actions. The library caller
  * registers execution functions for each action type, which will be stored
  * here.
  */
 static pcmk__graph_functions_t *graph_fns = NULL;
 
 /*!
  * \internal
  * \brief Set transition graph execution functions
  *
  * \param[in]  Execution functions to use
  */
 void
 pcmk__set_graph_functions(pcmk__graph_functions_t *fns)
 {
     crm_debug("Setting custom functions for executing transition graphs");
     graph_fns = fns;
 
     CRM_ASSERT(graph_fns != NULL);
     CRM_ASSERT(graph_fns->rsc != NULL);
     CRM_ASSERT(graph_fns->crmd != NULL);
     CRM_ASSERT(graph_fns->pseudo != NULL);
     CRM_ASSERT(graph_fns->stonith != NULL);
 }
 
 /*!
  * \internal
  * \brief Check whether a graph synapse is ready to be executed
  *
  * \param[in] graph    Transition graph that synapse is part of
  * \param[in] synapse  Synapse to check
  *
  * \return true if synapse is ready, false otherwise
  */
 static bool
 should_fire_synapse(pcmk__graph_t *graph, pcmk__graph_synapse_t *synapse)
 {
     GList *lpc = NULL;
 
     pcmk__set_synapse_flags(synapse, pcmk__synapse_ready);
     for (lpc = synapse->inputs; lpc != NULL; lpc = lpc->next) {
         pcmk__graph_action_t *prereq = (pcmk__graph_action_t *) lpc->data;
 
         if (!(pcmk_is_set(prereq->flags, pcmk__graph_action_confirmed))) {
             crm_trace("Input %d for synapse %d not yet confirmed",
                       prereq->id, synapse->id);
             pcmk__clear_synapse_flags(synapse, pcmk__synapse_ready);
             break;
 
         } else if (pcmk_is_set(prereq->flags, pcmk__graph_action_failed) && !(pcmk_is_set(prereq->flags, pcmk__graph_action_can_fail))) {
             crm_trace("Input %d for synapse %d confirmed but failed",
                       prereq->id, synapse->id);
             pcmk__clear_synapse_flags(synapse, pcmk__synapse_ready);
             break;
         }
     }
     if (pcmk_is_set(synapse->flags, pcmk__synapse_ready)) {
         crm_trace("Synapse %d is ready to execute", synapse->id);
     } else {
         return false;
     }
 
     for (lpc = synapse->actions; lpc != NULL; lpc = lpc->next) {
         pcmk__graph_action_t *a = (pcmk__graph_action_t *) lpc->data;
 
         if (a->type == pcmk__pseudo_graph_action) {
             /* None of the below applies to pseudo ops */
 
         } else if (synapse->priority < graph->abort_priority) {
             crm_trace("Skipping synapse %d: priority %d is less than "
                       "abort priority %d",
                       synapse->id, synapse->priority, graph->abort_priority);
             graph->skipped++;
             return false;
 
         } else if (graph_fns->allowed && !(graph_fns->allowed(graph, a))) {
             crm_trace("Deferring synapse %d: not allowed", synapse->id);
             return false;
         }
     }
 
     return true;
 }
 
 /*!
  * \internal
  * \brief Initiate an action from a transition graph
  *
  * \param[in] graph   Transition graph containing action
  * \param[in] action  Action to execute
  *
  * \return Standard Pacemaker return code
  */
 static int
 initiate_action(pcmk__graph_t *graph, pcmk__graph_action_t *action)
 {
     const char *id = ID(action->xml);
 
     CRM_CHECK(id != NULL, return EINVAL);
     CRM_CHECK(!pcmk_is_set(action->flags, pcmk__graph_action_executed),
               return pcmk_rc_already);
 
     pcmk__set_graph_action_flags(action, pcmk__graph_action_executed);
     switch (action->type) {
         case pcmk__pseudo_graph_action:
             crm_trace("Executing pseudo-action %d (%s)", action->id, id);
             return graph_fns->pseudo(graph, action)? pcmk_rc_ok : pcmk_rc_error;
 
         case pcmk__rsc_graph_action:
             crm_trace("Executing resource action %d (%s)", action->id, id);
             return graph_fns->rsc(graph, action)? pcmk_rc_ok : pcmk_rc_error;
 
         case pcmk__cluster_graph_action:
             if (pcmk__str_eq(crm_element_value(action->xml, XML_LRM_ATTR_TASK),
                              CRM_OP_FENCE, pcmk__str_casei)) {
                 crm_trace("Executing fencing action %d (%s)",
                           action->id, id);
                 return graph_fns->stonith(graph, action)? pcmk_rc_ok : pcmk_rc_error;
             }
             crm_trace("Executing control action %d (%s)", action->id, id);
             return graph_fns->crmd(graph, action)? pcmk_rc_ok : pcmk_rc_error;
 
         default:
             crm_err("Unsupported graph action type <%s id='%s'> (bug?)",
                     crm_element_name(action->xml), id);
             return EINVAL;
     }
 }
 
 /*!
  * \internal
  * \brief Execute a graph synapse
  *
  * \param[in] graph    Transition graph with synapse to execute
  * \param[in] synapse  Synapse to execute
  *
  * \return Standard Pacemaker return value
  */
 static int
 fire_synapse(pcmk__graph_t *graph, pcmk__graph_synapse_t *synapse)
 {
     pcmk__set_synapse_flags(synapse, pcmk__synapse_executed);
     for (GList *lpc = synapse->actions; lpc != NULL; lpc = lpc->next) {
         pcmk__graph_action_t *action = (pcmk__graph_action_t *) lpc->data;
 
         if (initiate_action(graph, action) != pcmk_rc_ok) {
             crm_err("Failed initiating <%s id=%d> in synapse %d",
                     crm_element_name(action->xml), action->id, synapse->id);
             pcmk__set_synapse_flags(synapse, pcmk__synapse_confirmed);
             pcmk__set_graph_action_flags(action,
                                          pcmk__graph_action_confirmed
                                          |pcmk__graph_action_failed);
             return pcmk_rc_error;
         }
     }
     return pcmk_rc_ok;
 }
 
 /*!
  * \internal
  * \brief Dummy graph method that can be used with simulations
  *
  * \param[in] graph   Transition graph containing action
  * \param[in] action  Action to be initiated
  *
  * \retval TRUE   Action initiation was (simulated to be) successful
  * \retval FALSE  Action initiation was (simulated to be) failed (due to the
  *                PE_fail environment variable being set to the action ID)
  */
 static gboolean
 pseudo_action_dummy(pcmk__graph_t * graph, pcmk__graph_action_t *action)
 {
     static int fail = -1;
 
     if (fail < 0) {
         long long fail_ll;
 
         if ((pcmk__scan_ll(getenv("PE_fail"), &fail_ll, 0LL) == pcmk_rc_ok)
             && (fail_ll > 0LL) && (fail_ll <= INT_MAX)) {
             fail = (int) fail_ll;
         } else {
             fail = 0;
         }
     }
 
     if (action->id == fail) {
         crm_err("Dummy event handler: pretending action %d failed", action->id);
         pcmk__set_graph_action_flags(action, pcmk__graph_action_failed);
         graph->abort_priority = INFINITY;
     } else {
         crm_trace("Dummy event handler: action %d initiated", action->id);
     }
     pcmk__set_graph_action_flags(action, pcmk__graph_action_confirmed);
     pcmk__update_graph(graph, action);
     return TRUE;
 }
 
 static pcmk__graph_functions_t default_fns = {
     pseudo_action_dummy,
     pseudo_action_dummy,
     pseudo_action_dummy,
     pseudo_action_dummy
 };
 
 /*!
  * \internal
  * \brief Execute all actions in a transition graph
  *
  * \param[in] graph  Transition graph to execute
  *
  * \return Status of transition after execution
  */
 enum transition_status
 pcmk__execute_graph(pcmk__graph_t *graph)
 {
     GList *lpc = NULL;
     int log_level = LOG_DEBUG;
     enum transition_status pass_result = transition_active;
     const char *status = "In progress";
 
     if (graph_fns == NULL) {
         graph_fns = &default_fns;
     }
     if (graph == NULL) {
         return transition_complete;
     }
 
     graph->fired = 0;
     graph->pending = 0;
     graph->skipped = 0;
     graph->completed = 0;
     graph->incomplete = 0;
 
     // Count completed and in-flight synapses
     for (lpc = graph->synapses; lpc != NULL; lpc = lpc->next) {
         pcmk__graph_synapse_t *synapse = (pcmk__graph_synapse_t *) lpc->data;
 
         if (pcmk_is_set(synapse->flags, pcmk__synapse_confirmed)) {
             graph->completed++;
 
         } else if (!(pcmk_is_set(synapse->flags, pcmk__synapse_failed)) && pcmk_is_set(synapse->flags, pcmk__synapse_executed)) {
             graph->pending++;
         }
     }
     crm_trace("Executing graph %d (%d synapses already completed, %d pending)",
               graph->id, graph->completed, graph->pending);
 
     // Execute any synapses that are ready
     for (lpc = graph->synapses; lpc != NULL; lpc = lpc->next) {
         pcmk__graph_synapse_t *synapse = (pcmk__graph_synapse_t *) lpc->data;
 
         if ((graph->batch_limit > 0)
             && (graph->pending >= graph->batch_limit)) {
 
             crm_debug("Throttling graph execution: batch limit (%d) reached",
                       graph->batch_limit);
             break;
 
         } else if (pcmk_is_set(synapse->flags, pcmk__synapse_failed)) {
             graph->skipped++;
             continue;
 
         } else if (pcmk_any_flags_set(synapse->flags, pcmk__synapse_confirmed|pcmk__synapse_executed)) {
             continue; // Already handled
 
         } else if (should_fire_synapse(graph, synapse)) {
             graph->fired++;
             if (fire_synapse(graph, synapse) != pcmk_rc_ok) {
                 crm_err("Synapse %d failed to fire", synapse->id);
                 log_level = LOG_ERR;
                 graph->abort_priority = INFINITY;
                 graph->incomplete++;
                 graph->fired--;
             }
 
             if (!(pcmk_is_set(synapse->flags, pcmk__synapse_confirmed))) {
                 graph->pending++;
             }
 
         } else {
             crm_trace("Synapse %d cannot fire", synapse->id);
             graph->incomplete++;
         }
     }
 
     if ((graph->pending == 0) && (graph->fired == 0)) {
-        graph->complete = TRUE;
+        graph->complete = true;
 
         if ((graph->incomplete != 0) && (graph->abort_priority <= 0)) {
             log_level = LOG_WARNING;
             pass_result = transition_terminated;
             status = "Terminated";
 
         } else if (graph->skipped != 0) {
             log_level = LOG_NOTICE;
             pass_result = transition_complete;
             status = "Stopped";
 
         } else {
             log_level = LOG_NOTICE;
             pass_result = transition_complete;
             status = "Complete";
         }
 
     } else if (graph->fired == 0) {
         pass_result = transition_pending;
     }
 
     do_crm_log(log_level,
                "Transition %d (Complete=%d, Pending=%d,"
                " Fired=%d, Skipped=%d, Incomplete=%d, Source=%s): %s",
                graph->id, graph->completed, graph->pending, graph->fired,
                graph->skipped, graph->incomplete, graph->source, status);
 
     return pass_result;
 }
 
 
 /*
  * Functions for unpacking transition graph XML into structs
  */
 
 /*!
  * \internal
  * \brief Unpack a transition graph action from XML
  *
  * \param[in] parent      Synapse that action is part of
  * \param[in] xml_action  Action XML to unparse
  *
  * \return Newly allocated action on success, or NULL otherwise
  */
 static pcmk__graph_action_t *
 unpack_action(pcmk__graph_synapse_t *parent, xmlNode *xml_action)
 {
     enum pcmk__graph_action_type action_type;
     pcmk__graph_action_t *action = NULL;
     const char *element = TYPE(xml_action);
     const char *value = ID(xml_action);
 
     if (value == NULL) {
         crm_err("Ignoring transition graph action without id (bug?)");
         crm_log_xml_trace(xml_action, "invalid");
         return NULL;
     }
 
     if (pcmk__str_eq(element, XML_GRAPH_TAG_RSC_OP, pcmk__str_casei)) {
         action_type = pcmk__rsc_graph_action;
 
     } else if (pcmk__str_eq(element, XML_GRAPH_TAG_PSEUDO_EVENT,
                             pcmk__str_casei)) {
         action_type = pcmk__pseudo_graph_action;
 
     } else if (pcmk__str_eq(element, XML_GRAPH_TAG_CRM_EVENT,
                             pcmk__str_casei)) {
         action_type = pcmk__cluster_graph_action;
 
     } else {
         crm_err("Ignoring transition graph action of unknown type '%s' (bug?)",
                 element);
         crm_log_xml_trace(xml_action, "invalid");
         return NULL;
     }
 
     action = calloc(1, sizeof(pcmk__graph_action_t));
     if (action == NULL) {
         crm_perror(LOG_CRIT, "Cannot unpack transition graph action");
         crm_log_xml_trace(xml_action, "lost");
         return NULL;
     }
 
     pcmk__scan_min_int(value, &(action->id), -1);
     action->type = pcmk__rsc_graph_action;
     action->xml = copy_xml(xml_action);
     action->synapse = parent;
     action->type = action_type;
     action->params = xml2list(action->xml);
 
     value = g_hash_table_lookup(action->params, "CRM_meta_timeout");
     pcmk__scan_min_int(value, &(action->timeout), 0);
 
     /* Take start-delay into account for the timeout of the action timer */
     value = g_hash_table_lookup(action->params, "CRM_meta_start_delay");
     {
         int start_delay;
 
         pcmk__scan_min_int(value, &start_delay, 0);
         action->timeout += start_delay;
     }
 
     if (pcmk__guint_from_hash(action->params,
                               CRM_META "_" XML_LRM_ATTR_INTERVAL, 0,
                               &(action->interval_ms)) != pcmk_rc_ok) {
         action->interval_ms = 0;
     }
 
     value = g_hash_table_lookup(action->params, "CRM_meta_can_fail");
     if (value != NULL) {
 
         gboolean can_fail = FALSE;
         crm_str_to_boolean(value, &can_fail);
         if (can_fail) {
             pcmk__set_graph_action_flags(action, pcmk__graph_action_can_fail);
         } else {
             pcmk__clear_graph_action_flags(action, pcmk__graph_action_can_fail);
         }
 
 #ifndef PCMK__COMPAT_2_0
         if (pcmk_is_set(action->flags, pcmk__graph_action_can_fail)) {
             crm_warn("Support for the can_fail meta-attribute is deprecated"
                      " and will be removed in a future release");
         }
 #endif
     }
 
     crm_trace("Action %d has timer set to %dms", action->id, action->timeout);
 
     return action;
 }
 
 /*!
  * \internal
  * \brief Unpack transition graph synapse from XML
  *
  * \param[in] new_graph    Transition graph that synapse is part of
  * \param[in] xml_synapse  Synapse XML
  *
  * \return Newly allocated synapse on success, or NULL otherwise
  */
 static pcmk__graph_synapse_t *
 unpack_synapse(pcmk__graph_t *new_graph, xmlNode *xml_synapse)
 {
     const char *value = NULL;
     xmlNode *action_set = NULL;
     pcmk__graph_synapse_t *new_synapse = NULL;
 
     crm_trace("Unpacking synapse %s", ID(xml_synapse));
 
     new_synapse = calloc(1, sizeof(pcmk__graph_synapse_t));
     if (new_synapse == NULL) {
         return NULL;
     }
 
     pcmk__scan_min_int(ID(xml_synapse), &(new_synapse->id), 0);
 
     value = crm_element_value(xml_synapse, XML_CIB_ATTR_PRIORITY);
     pcmk__scan_min_int(value, &(new_synapse->priority), 0);
 
     CRM_CHECK(new_synapse->id >= 0, free(new_synapse);
                                     return NULL);
 
     new_graph->num_synapses++;
 
     crm_trace("Unpacking synapse %s action sets",
               crm_element_value(xml_synapse, XML_ATTR_ID));
 
     for (action_set = first_named_child(xml_synapse, "action_set");
          action_set != NULL; action_set = crm_next_same_xml(action_set)) {
 
         for (xmlNode *action = pcmk__xml_first_child(action_set);
              action != NULL; action = pcmk__xml_next(action)) {
 
             pcmk__graph_action_t *new_action = unpack_action(new_synapse,
                                                              action);
 
             if (new_action == NULL) {
                 continue;
             }
 
             crm_trace("Adding action %d to synapse %d",
                       new_action->id, new_synapse->id);
             new_graph->num_actions++;
             new_synapse->actions = g_list_append(new_synapse->actions,
                                                  new_action);
         }
     }
 
     crm_trace("Unpacking synapse %s inputs", ID(xml_synapse));
 
     for (xmlNode *inputs = first_named_child(xml_synapse, "inputs");
          inputs != NULL; inputs = crm_next_same_xml(inputs)) {
 
         for (xmlNode *trigger = first_named_child(inputs, "trigger");
              trigger != NULL; trigger = crm_next_same_xml(trigger)) {
 
             for (xmlNode *input = pcmk__xml_first_child(trigger);
                  input != NULL; input = pcmk__xml_next(input)) {
 
                 pcmk__graph_action_t *new_input = unpack_action(new_synapse,
                                                                 input);
 
                 if (new_input == NULL) {
                     continue;
                 }
 
                 crm_trace("Adding input %d to synapse %d",
                            new_input->id, new_synapse->id);
 
                 new_synapse->inputs = g_list_append(new_synapse->inputs,
                                                     new_input);
             }
         }
     }
 
     return new_synapse;
 }
 
 /*!
  * \internal
  * \brief Unpack transition graph XML
  *
  * \param[in] xml_graph  Transition graph XML to unpack
  * \param[in] reference  Where the XML came from (for logging)
  *
  * \return Newly allocated transition graph on success, NULL otherwise
  * \note The caller is responsible for freeing the return value using
  *       pcmk__free_graph().
  * \note The XML is expected to be structured like:
          <transition_graph ...>
            <synapse id="0">
              <action_set>
                <rsc_op id="2" ...>
                ...
              </action_set>
              <inputs>
                  <rsc_op id="1" ...
                  ...
              </inputs>
            </synapse>
            ...
          </transition_graph>
  */
 pcmk__graph_t *
 pcmk__unpack_graph(xmlNode *xml_graph, const char *reference)
 {
     pcmk__graph_t *new_graph = NULL;
     const char *t_id = NULL;
     const char *time = NULL;
 
     new_graph = calloc(1, sizeof(pcmk__graph_t));
     if (new_graph == NULL) {
         return NULL;
     }
 
     new_graph->source = strdup((reference == NULL)? "unknown" : reference);
     if (new_graph->source == NULL) {
         free(new_graph);
         return NULL;
     }
 
     new_graph->id = -1;
     new_graph->abort_priority = 0;
     new_graph->network_delay = 0;
     new_graph->stonith_timeout = 0;
     new_graph->completion_action = tg_done;
 
     // Parse top-level attributes from <transition_graph>
     if (xml_graph != NULL) {
         t_id = crm_element_value(xml_graph, "transition_id");
         CRM_CHECK(t_id != NULL, free(new_graph);
                                 return NULL);
         pcmk__scan_min_int(t_id, &(new_graph->id), -1);
 
         time = crm_element_value(xml_graph, "cluster-delay");
         CRM_CHECK(time != NULL, free(new_graph);
                                 return NULL);
         new_graph->network_delay = crm_parse_interval_spec(time);
 
         time = crm_element_value(xml_graph, "stonith-timeout");
         if (time == NULL) {
             new_graph->stonith_timeout = new_graph->network_delay;
         } else {
             new_graph->stonith_timeout = crm_parse_interval_spec(time);
         }
 
         // Use 0 (dynamic limit) as default/invalid, -1 (no limit) as minimum
         t_id = crm_element_value(xml_graph, "batch-limit");
         if ((t_id == NULL)
             || (pcmk__scan_min_int(t_id, &(new_graph->batch_limit),
                                    -1) != pcmk_rc_ok)) {
             new_graph->batch_limit = 0;
         }
 
         t_id = crm_element_value(xml_graph, "migration-limit");
         pcmk__scan_min_int(t_id, &(new_graph->migration_limit), -1);
     }
 
     // Unpack each child <synapse> element
     for (xmlNode *synapse_xml = first_named_child(xml_graph, "synapse");
          synapse_xml != NULL; synapse_xml = crm_next_same_xml(synapse_xml)) {
 
         pcmk__graph_synapse_t *new_synapse = unpack_synapse(new_graph,
                                                             synapse_xml);
 
         if (new_synapse != NULL) {
             new_graph->synapses = g_list_append(new_graph->synapses,
                                                 new_synapse);
         }
     }
 
     crm_debug("Unpacked transition %d from %s: %d actions in %d synapses",
               new_graph->id, new_graph->source, new_graph->num_actions,
               new_graph->num_synapses);
 
     return new_graph;
 }
 
 
 /*
  * Functions for freeing transition graph objects
  */
 
 /*!
  * \internal
  * \brief Free a transition graph action object
  *
  * \param[in] user_data  Action to free
  */
 static void
 free_graph_action(gpointer user_data)
 {
     pcmk__graph_action_t *action = user_data;
 
     if (action->timer != 0) {
         crm_warn("Cancelling timer for graph action %d", action->id);
         g_source_remove(action->timer);
     }
     if (action->params != NULL) {
         g_hash_table_destroy(action->params);
     }
     free_xml(action->xml);
     free(action);
 }
 
 /*!
  * \internal
  * \brief Free a transition graph synapse object
  *
  * \param[in] user_data  Synapse to free
  */
 static void
 free_graph_synapse(gpointer user_data)
 {
     pcmk__graph_synapse_t *synapse = user_data;
 
     g_list_free_full(synapse->actions, free_graph_action);
     g_list_free_full(synapse->inputs, free_graph_action);
     free(synapse);
 }
 
 /*!
  * \internal
  * \brief Free a transition graph object
  *
  * \param[in] graph  Transition graph to free
  */
 void
 pcmk__free_graph(pcmk__graph_t *graph)
 {
     if (graph != NULL) {
         g_list_free_full(graph->synapses, free_graph_synapse);
         free(graph->source);
         free(graph);
     }
 }
 
 
 /*
  * Other transition graph utilities
  */
 
 /*!
  * \internal
  * \brief Synthesize an executor event from a graph action
  *
  * \param[in] resource     If not NULL, use greater call ID than in this XML
  * \param[in] action       Graph action
  * \param[in] status       What to use as event execution status
  * \param[in] rc           What to use as event exit status
  * \param[in] exit_reason  What to use as event exit reason
  *
  * \return Newly allocated executor event on success, or NULL otherwise
  */
 lrmd_event_data_t *
 pcmk__event_from_graph_action(xmlNode *resource, pcmk__graph_action_t *action,
                               int status, int rc, const char *exit_reason)
 {
     lrmd_event_data_t *op = NULL;
     GHashTableIter iter;
     const char *name = NULL;
     const char *value = NULL;
     xmlNode *action_resource = NULL;
 
     CRM_CHECK(action != NULL, return NULL);
     CRM_CHECK(action->type == pcmk__rsc_graph_action, return NULL);
 
     action_resource = first_named_child(action->xml, XML_CIB_TAG_RESOURCE);
     CRM_CHECK(action_resource != NULL, crm_log_xml_warn(action->xml, "invalid");
                                        return NULL);
 
     op = lrmd_new_event(ID(action_resource),
                         crm_element_value(action->xml, XML_LRM_ATTR_TASK),
                         action->interval_ms);
     lrmd__set_result(op, rc, status, exit_reason);
     op->t_run = time(NULL);
     op->t_rcchange = op->t_run;
     op->params = pcmk__strkey_table(free, free);
 
     g_hash_table_iter_init(&iter, action->params);
     while (g_hash_table_iter_next(&iter, (void **)&name, (void **)&value)) {
         g_hash_table_insert(op->params, strdup(name), strdup(value));
     }
 
     for (xmlNode *xop = pcmk__xml_first_child(resource); xop != NULL;
          xop = pcmk__xml_next(xop)) {
         int tmp = 0;
 
         crm_element_value_int(xop, XML_LRM_ATTR_CALLID, &tmp);
         crm_debug("Got call_id=%d for %s", tmp, ID(resource));
         if (tmp > op->call_id) {
             op->call_id = tmp;
         }
     }
 
     op->call_id++;
     return op;
 }