diff --git a/lib/pacemaker/pcmk_output.c b/lib/pacemaker/pcmk_output.c
index 50578142be..d402f841c8 100644
--- a/lib/pacemaker/pcmk_output.c
+++ b/lib/pacemaker/pcmk_output.c
@@ -1,2372 +1,2374 @@
 /*
  * Copyright 2019-2023 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/common/output.h>
 #include <crm/common/results.h>
 #include <crm/msg_xml.h>
 #include <crm/stonith-ng.h>
 #include <crm/fencing/internal.h>
 #include <crm/pengine/internal.h>
 #include <libxml/tree.h>
 #include <pacemaker-internal.h>
 
 #include <inttypes.h>
 #include <stdint.h>
 
 static char *
 colocations_header(pe_resource_t *rsc, pcmk__colocation_t *cons,
                    bool dependents) {
     char *retval = NULL;
 
     if (cons->primary_role > RSC_ROLE_STARTED) {
         retval = crm_strdup_printf("%s (score=%s, %s role=%s, id=%s)",
                                    rsc->id, pcmk_readable_score(cons->score),
                                    (dependents? "needs" : "with"),
                                    role2text(cons->primary_role), cons->id);
     } else {
         retval = crm_strdup_printf("%s (score=%s, id=%s)",
                                    rsc->id, pcmk_readable_score(cons->score),
                                    cons->id);
     }
     return retval;
 }
 
 static void
 colocations_xml_node(pcmk__output_t *out, pe_resource_t *rsc,
                      pcmk__colocation_t *cons) {
     xmlNodePtr node = NULL;
 
     node = pcmk__output_create_xml_node(out, XML_CONS_TAG_RSC_DEPEND,
                                         "id", cons->id,
                                         "rsc", cons->dependent->id,
                                         "with-rsc", cons->primary->id,
                                         "score",
                                         pcmk_readable_score(cons->score),
                                         NULL);
 
     if (cons->node_attribute) {
         xmlSetProp(node, (pcmkXmlStr) "node-attribute",
                    (pcmkXmlStr) cons->node_attribute);
     }
 
     if (cons->dependent_role != RSC_ROLE_UNKNOWN) {
         xmlSetProp(node, (pcmkXmlStr) "rsc-role",
                    (pcmkXmlStr) role2text(cons->dependent_role));
     }
 
     if (cons->primary_role != RSC_ROLE_UNKNOWN) {
         xmlSetProp(node, (pcmkXmlStr) "with-rsc-role",
                    (pcmkXmlStr) role2text(cons->primary_role));
     }
 }
 
 static int
 do_locations_list_xml(pcmk__output_t *out, pe_resource_t *rsc, bool add_header)
 {
     GList *lpc = NULL;
     GList *list = rsc->rsc_location;
     int rc = pcmk_rc_no_output;
 
     for (lpc = list; lpc != NULL; lpc = lpc->next) {
         pe__location_t *cons = lpc->data;
 
         GList *lpc2 = NULL;
 
         for (lpc2 = cons->node_list_rh; lpc2 != NULL; lpc2 = lpc2->next) {
             pe_node_t *node = (pe_node_t *) lpc2->data;
 
             if (add_header) {
                 PCMK__OUTPUT_LIST_HEADER(out, false, rc, "locations");
             }
 
             pcmk__output_create_xml_node(out, XML_CONS_TAG_RSC_LOCATION,
                                          "node", node->details->uname,
                                          "rsc", rsc->id,
                                          "id", cons->id,
                                          "score",
                                          pcmk_readable_score(node->weight),
                                          NULL);
         }
     }
 
     if (add_header) {
         PCMK__OUTPUT_LIST_FOOTER(out, rc);
     }
 
     return rc;
 }
 
 PCMK__OUTPUT_ARGS("rsc-action-item", "const char *", "pe_resource_t *",
                   "pe_node_t *", "pe_node_t *", "pe_action_t *",
                   "pe_action_t *")
 static int
 rsc_action_item(pcmk__output_t *out, va_list args)
 {
     const char *change = va_arg(args, const char *);
     pe_resource_t *rsc = va_arg(args, pe_resource_t *);
     pe_node_t *origin = va_arg(args, pe_node_t *);
     pe_node_t *destination = va_arg(args, pe_node_t *);
     pe_action_t *action = va_arg(args, pe_action_t *);
     pe_action_t *source = va_arg(args, pe_action_t *);
 
     int len = 0;
     char *reason = NULL;
     char *details = NULL;
     bool same_host = false;
     bool same_role = false;
     bool need_role = false;
 
     static int rsc_width = 5;
     static int detail_width = 5;
 
     CRM_ASSERT(action);
     CRM_ASSERT(destination != NULL || origin != NULL);
 
-    if(source == NULL) {
+    if (source == NULL) {
         source = action;
     }
 
     len = strlen(rsc->id);
-    if(len > rsc_width) {
+    if (len > rsc_width) {
         rsc_width = len + 2;
     }
 
     if ((rsc->role > RSC_ROLE_STARTED)
         || (rsc->next_role > RSC_ROLE_UNPROMOTED)) {
         need_role = true;
     }
 
     if (pe__same_node(origin, destination)) {
         same_host = true;
     }
 
-    if(rsc->role == rsc->next_role) {
+    if (rsc->role == rsc->next_role) {
         same_role = true;
     }
 
     if (need_role && (origin == NULL)) {
         /* Starting and promoting a promotable clone instance */
         details = crm_strdup_printf("%s -> %s %s", role2text(rsc->role),
                                     role2text(rsc->next_role),
                                     pe__node_name(destination));
 
     } else if (origin == NULL) {
         /* Starting a resource */
         details = crm_strdup_printf("%s", pe__node_name(destination));
 
     } else if (need_role && (destination == NULL)) {
         /* Stopping a promotable clone instance */
         details = crm_strdup_printf("%s %s", role2text(rsc->role),
                                     pe__node_name(origin));
 
     } else if (destination == NULL) {
         /* Stopping a resource */
         details = crm_strdup_printf("%s", pe__node_name(origin));
 
     } else if (need_role && same_role && same_host) {
         /* Recovering, restarting or re-promoting a promotable clone instance */
         details = crm_strdup_printf("%s %s", role2text(rsc->role),
                                     pe__node_name(origin));
 
     } else if (same_role && same_host) {
         /* Recovering or Restarting a normal resource */
         details = crm_strdup_printf("%s", pe__node_name(origin));
 
     } else if (need_role && same_role) {
         /* Moving a promotable clone instance */
         details = crm_strdup_printf("%s -> %s %s", pe__node_name(origin),
                                     pe__node_name(destination),
                                     role2text(rsc->role));
 
     } else if (same_role) {
         /* Moving a normal resource */
         details = crm_strdup_printf("%s -> %s", pe__node_name(origin),
                                     pe__node_name(destination));
 
     } else if (same_host) {
         /* Promoting or demoting a promotable clone instance */
         details = crm_strdup_printf("%s -> %s %s", role2text(rsc->role),
                                     role2text(rsc->next_role),
                                     pe__node_name(origin));
 
     } else {
         /* Moving and promoting/demoting */
         details = crm_strdup_printf("%s %s -> %s %s", role2text(rsc->role),
                                     pe__node_name(origin),
                                     role2text(rsc->next_role),
                                     pe__node_name(destination));
     }
 
     len = strlen(details);
-    if(len > detail_width) {
+    if (len > detail_width) {
         detail_width = len;
     }
 
-    if(source->reason && !pcmk_is_set(action->flags, pe_action_runnable)) {
+    if ((source->reason != NULL)
+        && !pcmk_is_set(action->flags, pe_action_runnable)) {
         reason = crm_strdup_printf("due to %s (blocked)", source->reason);
 
-    } else if(source->reason) {
+    } else if (source->reason) {
         reason = crm_strdup_printf("due to %s", source->reason);
 
     } else if (!pcmk_is_set(action->flags, pe_action_runnable)) {
         reason = strdup("blocked");
 
     }
 
     out->list_item(out, NULL, "%-8s   %-*s   ( %*s )%s%s",
                    change, rsc_width, rsc->id, detail_width, details,
                    ((reason == NULL)? "" : "  "), pcmk__s(reason, ""));
 
     free(details);
     free(reason);
     return pcmk_rc_ok;
 }
 
 PCMK__OUTPUT_ARGS("rsc-action-item", "const char *", "pe_resource_t *",
                   "pe_node_t *", "pe_node_t *", "pe_action_t *",
                   "pe_action_t *")
 static int
 rsc_action_item_xml(pcmk__output_t *out, va_list args)
 {
     const char *change = va_arg(args, const char *);
     pe_resource_t *rsc = va_arg(args, pe_resource_t *);
     pe_node_t *origin = va_arg(args, pe_node_t *);
     pe_node_t *destination = va_arg(args, pe_node_t *);
     pe_action_t *action = va_arg(args, pe_action_t *);
     pe_action_t *source = va_arg(args, pe_action_t *);
 
     char *change_str = NULL;
 
     bool same_host = false;
     bool same_role = false;
     bool need_role = false;
     xmlNode *xml = NULL;
 
     CRM_ASSERT(action);
     CRM_ASSERT(destination != NULL || origin != NULL);
 
     if (source == NULL) {
         source = action;
     }
 
     if ((rsc->role > RSC_ROLE_STARTED)
         || (rsc->next_role > RSC_ROLE_UNPROMOTED)) {
         need_role = true;
     }
 
     if (pe__same_node(origin, destination)) {
         same_host = true;
     }
 
-    if(rsc->role == rsc->next_role) {
+    if (rsc->role == rsc->next_role) {
         same_role = true;
     }
 
     change_str = g_ascii_strdown(change, -1);
     xml = pcmk__output_create_xml_node(out, "rsc_action",
                                        "action", change_str,
                                        "resource", rsc->id,
                                        NULL);
     g_free(change_str);
 
     if (need_role && (origin == NULL)) {
         /* Starting and promoting a promotable clone instance */
         pcmk__xe_set_props(xml,
                            "role", role2text(rsc->role),
                            "next-role", role2text(rsc->next_role),
                            "dest", destination->details->uname,
                            NULL);
 
     } else if (origin == NULL) {
         /* Starting a resource */
         crm_xml_add(xml, "node", destination->details->uname);
 
     } else if (need_role && (destination == NULL)) {
         /* Stopping a promotable clone instance */
         pcmk__xe_set_props(xml,
                            "role", role2text(rsc->role),
                            "node", origin->details->uname,
                            NULL);
 
     } else if (destination == NULL) {
         /* Stopping a resource */
         crm_xml_add(xml, "node", origin->details->uname);
 
     } else if (need_role && same_role && same_host) {
         /* Recovering, restarting or re-promoting a promotable clone instance */
         pcmk__xe_set_props(xml,
                            "role", role2text(rsc->role),
                            "source", origin->details->uname,
                            NULL);
 
     } else if (same_role && same_host) {
         /* Recovering or Restarting a normal resource */
         crm_xml_add(xml, "source", origin->details->uname);
 
     } else if (need_role && same_role) {
         /* Moving a promotable clone instance */
         pcmk__xe_set_props(xml,
                            "source", origin->details->uname,
                            "dest", destination->details->uname,
                            "role", role2text(rsc->role),
                            NULL);
 
     } else if (same_role) {
         /* Moving a normal resource */
         pcmk__xe_set_props(xml,
                            "source", origin->details->uname,
                            "dest", destination->details->uname,
                            NULL);
 
     } else if (same_host) {
         /* Promoting or demoting a promotable clone instance */
         pcmk__xe_set_props(xml,
                            "role", role2text(rsc->role),
                            "next-role", role2text(rsc->next_role),
                            "source", origin->details->uname,
                            NULL);
 
     } else {
         /* Moving and promoting/demoting */
         pcmk__xe_set_props(xml,
                            "role", role2text(rsc->role),
                            "source", origin->details->uname,
                            "next-role", role2text(rsc->next_role),
                            "dest", destination->details->uname,
                            NULL);
     }
 
     if (source->reason && !pcmk_is_set(action->flags, pe_action_runnable)) {
         pcmk__xe_set_props(xml,
                            "reason", source->reason,
                            "blocked", "true",
                            NULL);
 
-    } else if(source->reason) {
+    } else if (source->reason != NULL) {
         crm_xml_add(xml, "reason", source->reason);
 
     } else if (!pcmk_is_set(action->flags, pe_action_runnable)) {
         pcmk__xe_set_bool_attr(xml, "blocked", true);
 
     }
 
     return pcmk_rc_ok;
 }
 
 PCMK__OUTPUT_ARGS("rsc-is-colocated-with-list", "pe_resource_t *", "bool")
 static int
 rsc_is_colocated_with_list(pcmk__output_t *out, va_list args) {
     pe_resource_t *rsc = va_arg(args, pe_resource_t *);
     bool recursive = va_arg(args, int);
 
     int rc = pcmk_rc_no_output;
 
     if (pcmk_is_set(rsc->flags, pe_rsc_detect_loop)) {
         return rc;
     }
 
     /* We're listing constraints explicitly involving rsc, so use rsc->rsc_cons
      * directly rather than rsc->cmds->this_with_colocations().
      */
     pe__set_resource_flags(rsc, pe_rsc_detect_loop);
     for (GList *lpc = rsc->rsc_cons; lpc != NULL; lpc = lpc->next) {
         pcmk__colocation_t *cons = (pcmk__colocation_t *) lpc->data;
         char *hdr = NULL;
 
         PCMK__OUTPUT_LIST_HEADER(out, false, rc,
                                  "Resources %s is colocated with", rsc->id);
 
         if (pcmk_is_set(cons->primary->flags, pe_rsc_detect_loop)) {
             out->list_item(out, NULL, "%s (id=%s - loop)",
                            cons->primary->id, cons->id);
             continue;
         }
 
         hdr = colocations_header(cons->primary, cons, false);
         out->list_item(out, NULL, "%s", hdr);
         free(hdr);
 
         // Empty list header for indentation of information about this resource
         out->begin_list(out, NULL, NULL, NULL);
 
         out->message(out, "locations-list", cons->primary);
         if (recursive) {
             out->message(out, "rsc-is-colocated-with-list",
                          cons->primary, recursive);
         }
 
         out->end_list(out);
     }
 
     PCMK__OUTPUT_LIST_FOOTER(out, rc);
     return rc;
 }
 
 PCMK__OUTPUT_ARGS("rsc-is-colocated-with-list", "pe_resource_t *", "bool")
 static int
 rsc_is_colocated_with_list_xml(pcmk__output_t *out, va_list args) {
     pe_resource_t *rsc = va_arg(args, pe_resource_t *);
     bool recursive = va_arg(args, int);
 
     int rc = pcmk_rc_no_output;
 
     if (pcmk_is_set(rsc->flags, pe_rsc_detect_loop)) {
         return rc;
     }
 
     /* We're listing constraints explicitly involving rsc, so use rsc->rsc_cons
      * directly rather than rsc->cmds->this_with_colocations().
      */
     pe__set_resource_flags(rsc, pe_rsc_detect_loop);
     for (GList *lpc = rsc->rsc_cons; lpc != NULL; lpc = lpc->next) {
         pcmk__colocation_t *cons = (pcmk__colocation_t *) lpc->data;
 
         if (pcmk_is_set(cons->primary->flags, pe_rsc_detect_loop)) {
             colocations_xml_node(out, cons->primary, cons);
             continue;
         }
 
         colocations_xml_node(out, cons->primary, cons);
         do_locations_list_xml(out, cons->primary, false);
 
         if (recursive) {
             out->message(out, "rsc-is-colocated-with-list",
                          cons->primary, recursive);
         }
     }
 
     return rc;
 }
 
 PCMK__OUTPUT_ARGS("rscs-colocated-with-list", "pe_resource_t *", "bool")
 static int
 rscs_colocated_with_list(pcmk__output_t *out, va_list args) {
     pe_resource_t *rsc = va_arg(args, pe_resource_t *);
     bool recursive = va_arg(args, int);
 
     int rc = pcmk_rc_no_output;
 
     if (pcmk_is_set(rsc->flags, pe_rsc_detect_loop)) {
         return rc;
     }
 
     /* We're listing constraints explicitly involving rsc, so use
      * rsc->rsc_cons_lhs directly rather than
      * rsc->cmds->with_this_colocations().
      */
     pe__set_resource_flags(rsc, pe_rsc_detect_loop);
     for (GList *lpc = rsc->rsc_cons_lhs; lpc != NULL; lpc = lpc->next) {
         pcmk__colocation_t *cons = (pcmk__colocation_t *) lpc->data;
         char *hdr = NULL;
 
         PCMK__OUTPUT_LIST_HEADER(out, false, rc, "Resources colocated with %s",
                                  rsc->id);
 
         if (pcmk_is_set(cons->dependent->flags, pe_rsc_detect_loop)) {
             out->list_item(out, NULL, "%s (id=%s - loop)",
                            cons->dependent->id, cons->id);
             continue;
         }
 
         hdr = colocations_header(cons->dependent, cons, true);
         out->list_item(out, NULL, "%s", hdr);
         free(hdr);
 
         // Empty list header for indentation of information about this resource
         out->begin_list(out, NULL, NULL, NULL);
 
         out->message(out, "locations-list", cons->dependent);
         if (recursive) {
             out->message(out, "rscs-colocated-with-list",
                          cons->dependent, recursive);
         }
 
         out->end_list(out);
     }
 
     PCMK__OUTPUT_LIST_FOOTER(out, rc);
     return rc;
 }
 
 PCMK__OUTPUT_ARGS("rscs-colocated-with-list", "pe_resource_t *", "bool")
 static int
 rscs_colocated_with_list_xml(pcmk__output_t *out, va_list args) {
     pe_resource_t *rsc = va_arg(args, pe_resource_t *);
     bool recursive = va_arg(args, int);
 
     int rc = pcmk_rc_no_output;
 
     if (pcmk_is_set(rsc->flags, pe_rsc_detect_loop)) {
         return rc;
     }
 
     /* We're listing constraints explicitly involving rsc, so use
      * rsc->rsc_cons_lhs directly rather than
      * rsc->cmds->with_this_colocations().
      */
     pe__set_resource_flags(rsc, pe_rsc_detect_loop);
     for (GList *lpc = rsc->rsc_cons_lhs; lpc != NULL; lpc = lpc->next) {
         pcmk__colocation_t *cons = (pcmk__colocation_t *) lpc->data;
 
         if (pcmk_is_set(cons->dependent->flags, pe_rsc_detect_loop)) {
             colocations_xml_node(out, cons->dependent, cons);
             continue;
         }
 
         colocations_xml_node(out, cons->dependent, cons);
         do_locations_list_xml(out, cons->dependent, false);
 
         if (recursive) {
             out->message(out, "rscs-colocated-with-list",
                          cons->dependent, recursive);
         }
     }
 
     return rc;
 }
 
 PCMK__OUTPUT_ARGS("locations-list", "pe_resource_t *")
 static int
 locations_list(pcmk__output_t *out, va_list args) {
     pe_resource_t *rsc = va_arg(args, pe_resource_t *);
 
     GList *lpc = NULL;
     GList *list = rsc->rsc_location;
     int rc = pcmk_rc_no_output;
 
     for (lpc = list; lpc != NULL; lpc = lpc->next) {
         pe__location_t *cons = lpc->data;
 
         GList *lpc2 = NULL;
 
         for (lpc2 = cons->node_list_rh; lpc2 != NULL; lpc2 = lpc2->next) {
             pe_node_t *node = (pe_node_t *) lpc2->data;
 
             PCMK__OUTPUT_LIST_HEADER(out, false, rc, "Locations");
             out->list_item(out, NULL, "Node %s (score=%s, id=%s, rsc=%s)",
                            pe__node_name(node),
                            pcmk_readable_score(node->weight), cons->id,
                            rsc->id);
         }
     }
 
     PCMK__OUTPUT_LIST_FOOTER(out, rc);
     return rc;
 }
 
 PCMK__OUTPUT_ARGS("locations-list", "pe_resource_t *")
 static int
 locations_list_xml(pcmk__output_t *out, va_list args) {
     pe_resource_t *rsc = va_arg(args, pe_resource_t *);
     return do_locations_list_xml(out, rsc, true);
 }
 
 PCMK__OUTPUT_ARGS("locations-and-colocations", "pe_resource_t *",
                   "bool", "bool")
 static int
 locations_and_colocations(pcmk__output_t *out, va_list args)
 {
     pe_resource_t *rsc = va_arg(args, pe_resource_t *);
     bool recursive = va_arg(args, int);
     bool force = va_arg(args, int);
 
     pcmk__unpack_constraints(rsc->cluster);
 
     // Constraints apply to group/clone, not member/instance
     if (!force) {
         rsc = uber_parent(rsc);
     }
 
     out->message(out, "locations-list", rsc);
 
     pe__clear_resource_flags_on_all(rsc->cluster, pe_rsc_detect_loop);
     out->message(out, "rscs-colocated-with-list", rsc, recursive);
 
     pe__clear_resource_flags_on_all(rsc->cluster, pe_rsc_detect_loop);
     out->message(out, "rsc-is-colocated-with-list", rsc, recursive);
     return pcmk_rc_ok;
 }
 
 PCMK__OUTPUT_ARGS("locations-and-colocations", "pe_resource_t *",
                   "bool", "bool")
 static int
 locations_and_colocations_xml(pcmk__output_t *out, va_list args)
 {
     pe_resource_t *rsc = va_arg(args, pe_resource_t *);
     bool recursive = va_arg(args, int);
     bool force = va_arg(args, int);
 
     pcmk__unpack_constraints(rsc->cluster);
 
     // Constraints apply to group/clone, not member/instance
     if (!force) {
         rsc = uber_parent(rsc);
     }
 
     pcmk__output_xml_create_parent(out, "constraints", NULL);
     do_locations_list_xml(out, rsc, false);
 
     pe__clear_resource_flags_on_all(rsc->cluster, pe_rsc_detect_loop);
     out->message(out, "rscs-colocated-with-list", rsc, recursive);
 
     pe__clear_resource_flags_on_all(rsc->cluster, pe_rsc_detect_loop);
     out->message(out, "rsc-is-colocated-with-list", rsc, recursive);
 
     pcmk__output_xml_pop_parent(out);
     return pcmk_rc_ok;
 }
 
 PCMK__OUTPUT_ARGS("health", "const char *", "const char *", "const char *",
                   "const char *")
 static int
 health(pcmk__output_t *out, va_list args)
 {
     const char *sys_from G_GNUC_UNUSED = va_arg(args, const char *);
     const char *host_from = va_arg(args, const char *);
     const char *fsa_state = va_arg(args, const char *);
     const char *result = va_arg(args, const char *);
 
     return out->info(out, "Controller on %s in state %s: %s",
                      pcmk__s(host_from, "unknown node"),
                      pcmk__s(fsa_state, "unknown"),
                      pcmk__s(result, "unknown result"));
 }
 
 PCMK__OUTPUT_ARGS("health", "const char *", "const char *", "const char *",
                   "const char *")
 static int
 health_text(pcmk__output_t *out, va_list args)
 {
     if (!out->is_quiet(out)) {
         return health(out, args);
     } else {
         const char *sys_from G_GNUC_UNUSED = va_arg(args, const char *);
         const char *host_from G_GNUC_UNUSED = va_arg(args, const char *);
         const char *fsa_state = va_arg(args, const char *);
         const char *result G_GNUC_UNUSED = va_arg(args, const char *);
 
         if (fsa_state != NULL) {
             pcmk__formatted_printf(out, "%s\n", fsa_state);
             return pcmk_rc_ok;
         }
     }
 
     return pcmk_rc_no_output;
 }
 
 PCMK__OUTPUT_ARGS("health", "const char *", "const char *", "const char *",
                   "const char *")
 static int
 health_xml(pcmk__output_t *out, va_list args)
 {
     const char *sys_from = va_arg(args, const char *);
     const char *host_from = va_arg(args, const char *);
     const char *fsa_state = va_arg(args, const char *);
     const char *result = va_arg(args, const char *);
 
     pcmk__output_create_xml_node(out, pcmk__s(sys_from, ""),
                                  "node_name", pcmk__s(host_from, ""),
                                  "state", pcmk__s(fsa_state, ""),
                                  "result", pcmk__s(result, ""),
                                  NULL);
     return pcmk_rc_ok;
 }
 
 PCMK__OUTPUT_ARGS("pacemakerd-health", "const char *",
                   "enum pcmk_pacemakerd_state", "const char *", "time_t")
 static int
 pacemakerd_health(pcmk__output_t *out, va_list args)
 {
     const char *sys_from = va_arg(args, const char *);
     enum pcmk_pacemakerd_state state =
         (enum pcmk_pacemakerd_state) va_arg(args, int);
     const char *state_s = va_arg(args, const char *);
     time_t last_updated = va_arg(args, time_t);
 
     char *last_updated_s = NULL;
     int rc = pcmk_rc_ok;
 
     if (sys_from == NULL) {
         if (state == pcmk_pacemakerd_state_remote) {
             sys_from = "pacemaker-remoted";
         } else {
             sys_from = CRM_SYSTEM_MCP;
         }
     }
 
     if (state_s == NULL) {
         state_s = pcmk__pcmkd_state_enum2friendly(state);
     }
 
     if (last_updated != 0) {
         last_updated_s = pcmk__epoch2str(&last_updated,
                                          crm_time_log_date
                                          |crm_time_log_timeofday
                                          |crm_time_log_with_timezone);
     }
 
     rc = out->info(out, "Status of %s: '%s' (last updated %s)",
                    sys_from, state_s,
                    pcmk__s(last_updated_s, "at unknown time"));
 
     free(last_updated_s);
     return rc;
 }
 
 PCMK__OUTPUT_ARGS("pacemakerd-health", "const char *",
                   "enum pcmk_pacemakerd_state", "const char *", "time_t")
 static int
 pacemakerd_health_html(pcmk__output_t *out, va_list args)
 {
     const char *sys_from = va_arg(args, const char *);
     enum pcmk_pacemakerd_state state =
         (enum pcmk_pacemakerd_state) va_arg(args, int);
     const char *state_s = va_arg(args, const char *);
     time_t last_updated = va_arg(args, time_t);
 
     char *last_updated_s = NULL;
     char *msg = NULL;
 
     if (sys_from == NULL) {
         if (state == pcmk_pacemakerd_state_remote) {
             sys_from = "pacemaker-remoted";
         } else {
             sys_from = CRM_SYSTEM_MCP;
         }
     }
 
     if (state_s == NULL) {
         state_s = pcmk__pcmkd_state_enum2friendly(state);
     }
 
     if (last_updated != 0) {
         last_updated_s = pcmk__epoch2str(&last_updated,
                                          crm_time_log_date
                                          |crm_time_log_timeofday
                                          |crm_time_log_with_timezone);
     }
 
     msg = crm_strdup_printf("Status of %s: '%s' (last updated %s)",
                             sys_from, state_s,
                             pcmk__s(last_updated_s, "at unknown time"));
     pcmk__output_create_html_node(out, "li", NULL, NULL, msg);
 
     free(msg);
     free(last_updated_s);
     return pcmk_rc_ok;
 }
 
 PCMK__OUTPUT_ARGS("pacemakerd-health", "const char *",
                   "enum pcmk_pacemakerd_state", "const char *", "time_t")
 static int
 pacemakerd_health_text(pcmk__output_t *out, va_list args)
 {
     if (!out->is_quiet(out)) {
         return pacemakerd_health(out, args);
     } else {
         const char *sys_from G_GNUC_UNUSED = va_arg(args, const char *);
         enum pcmk_pacemakerd_state state =
             (enum pcmk_pacemakerd_state) va_arg(args, int);
         const char *state_s = va_arg(args, const char *);
         time_t last_updated G_GNUC_UNUSED = va_arg(args, time_t);
 
         if (state_s == NULL) {
             state_s = pcmk_pacemakerd_api_daemon_state_enum2text(state);
         }
         pcmk__formatted_printf(out, "%s\n", state_s);
         return pcmk_rc_ok;
     }
 }
 
 PCMK__OUTPUT_ARGS("pacemakerd-health", "const char *",
                   "enum pcmk_pacemakerd_state", "const char *", "time_t")
 static int
 pacemakerd_health_xml(pcmk__output_t *out, va_list args)
 {
     const char *sys_from = va_arg(args, const char *);
     enum pcmk_pacemakerd_state state =
         (enum pcmk_pacemakerd_state) va_arg(args, int);
     const char *state_s = va_arg(args, const char *);
     time_t last_updated = va_arg(args, time_t);
 
     char *last_updated_s = NULL;
 
     if (sys_from == NULL) {
         if (state == pcmk_pacemakerd_state_remote) {
             sys_from = "pacemaker-remoted";
         } else {
             sys_from = CRM_SYSTEM_MCP;
         }
     }
 
     if (state_s == NULL) {
         state_s = pcmk_pacemakerd_api_daemon_state_enum2text(state);
     }
 
     if (last_updated != 0) {
         last_updated_s = pcmk__epoch2str(&last_updated,
                                          crm_time_log_date
                                          |crm_time_log_timeofday
                                          |crm_time_log_with_timezone);
     }
 
     pcmk__output_create_xml_node(out, "pacemakerd",
                                  "sys_from", sys_from,
                                  "state", state_s,
                                  "last_updated", last_updated_s,
                                  NULL);
     free(last_updated_s);
     return pcmk_rc_ok;
 }
 
 PCMK__OUTPUT_ARGS("profile", "const char *", "clock_t", "clock_t")
 static int
 profile_default(pcmk__output_t *out, va_list args) {
     const char *xml_file = va_arg(args, const char *);
     clock_t start = va_arg(args, clock_t);
     clock_t end = va_arg(args, clock_t);
 
     out->list_item(out, NULL, "Testing %s ... %.2f secs", xml_file,
                    (end - start) / (float) CLOCKS_PER_SEC);
 
     return pcmk_rc_ok;
 }
 
 PCMK__OUTPUT_ARGS("profile", "const char *", "clock_t", "clock_t")
 static int
 profile_xml(pcmk__output_t *out, va_list args) {
     const char *xml_file = va_arg(args, const char *);
     clock_t start = va_arg(args, clock_t);
     clock_t end = va_arg(args, clock_t);
 
     char *duration = pcmk__ftoa((end - start) / (float) CLOCKS_PER_SEC);
 
     pcmk__output_create_xml_node(out, "timing",
                                  "file", xml_file,
                                  "duration", duration,
                                  NULL);
 
     free(duration);
     return pcmk_rc_ok;
 }
 
 PCMK__OUTPUT_ARGS("dc", "const char *")
 static int
 dc(pcmk__output_t *out, va_list args)
 {
     const char *dc = va_arg(args, const char *);
 
     return out->info(out, "Designated Controller is: %s",
                      pcmk__s(dc, "not yet elected"));
 }
 
 PCMK__OUTPUT_ARGS("dc", "const char *")
 static int
 dc_text(pcmk__output_t *out, va_list args)
 {
     if (!out->is_quiet(out)) {
         return dc(out, args);
     } else {
         const char *dc = va_arg(args, const char *);
 
         if (dc != NULL) {
             pcmk__formatted_printf(out, "%s\n", pcmk__s(dc, ""));
             return pcmk_rc_ok;
         }
     }
 
     return pcmk_rc_no_output;
 }
 
 PCMK__OUTPUT_ARGS("dc", "const char *")
 static int
 dc_xml(pcmk__output_t *out, va_list args)
 {
     const char *dc = va_arg(args, const char *);
 
     pcmk__output_create_xml_node(out, "dc",
                                  "node_name", pcmk__s(dc, ""),
                                  NULL);
     return pcmk_rc_ok;
 }
 
 PCMK__OUTPUT_ARGS("crmadmin-node", "const char *", "const char *",
                   "const char *", "bool")
 static int
 crmadmin_node(pcmk__output_t *out, va_list args)
 {
     const char *type = va_arg(args, const char *);
     const char *name = va_arg(args, const char *);
     const char *id = va_arg(args, const char *);
     bool bash_export = va_arg(args, int);
 
     if (bash_export) {
         return out->info(out, "export %s=%s",
                          pcmk__s(name, "<null>"), pcmk__s(id, ""));
     } else {
         return out->info(out, "%s node: %s (%s)", type ? type : "cluster",
                          pcmk__s(name, "<null>"), pcmk__s(id, "<null>"));
     }
 }
 
 PCMK__OUTPUT_ARGS("crmadmin-node", "const char *", "const char *",
                   "const char *", "bool")
 static int
 crmadmin_node_text(pcmk__output_t *out, va_list args)
 {
     if (!out->is_quiet(out)) {
         return crmadmin_node(out, args);
     } else {
         const char *type G_GNUC_UNUSED = va_arg(args, const char *);
         const char *name = va_arg(args, const char *);
         const char *id G_GNUC_UNUSED = va_arg(args, const char *);
         bool bash_export G_GNUC_UNUSED = va_arg(args, int);
 
         pcmk__formatted_printf(out, "%s\n", pcmk__s(name, "<null>"));
         return pcmk_rc_ok;
     }
 }
 
 PCMK__OUTPUT_ARGS("crmadmin-node", "const char *", "const char *",
                   "const char *", "bool")
 static int
 crmadmin_node_xml(pcmk__output_t *out, va_list args)
 {
     const char *type = va_arg(args, const char *);
     const char *name = va_arg(args, const char *);
     const char *id = va_arg(args, const char *);
     bool bash_export G_GNUC_UNUSED = va_arg(args, int);
 
     pcmk__output_create_xml_node(out, "node",
                                  "type", type ? type : "cluster",
                                  "name", pcmk__s(name, ""),
                                  "id", pcmk__s(id, ""),
                                  NULL);
     return pcmk_rc_ok;
 }
 
 PCMK__OUTPUT_ARGS("digests", "const pe_resource_t *", "const pe_node_t *",
                   "const char *", "guint", "const op_digest_cache_t *")
 static int
 digests_text(pcmk__output_t *out, va_list args)
 {
     const pe_resource_t *rsc = va_arg(args, const pe_resource_t *);
     const pe_node_t *node = va_arg(args, const pe_node_t *);
     const char *task = va_arg(args, const char *);
     guint interval_ms = va_arg(args, guint);
     const op_digest_cache_t *digests = va_arg(args, const op_digest_cache_t *);
 
     char *action_desc = NULL;
     const char *rsc_desc = "unknown resource";
     const char *node_desc = "unknown node";
 
     if (interval_ms != 0) {
         action_desc = crm_strdup_printf("%ums-interval %s action", interval_ms,
                                         ((task == NULL)? "unknown" : task));
     } else if (pcmk__str_eq(task, "monitor", pcmk__str_none)) {
         action_desc = strdup("probe action");
     } else {
         action_desc = crm_strdup_printf("%s action",
                                         ((task == NULL)? "unknown" : task));
     }
     if ((rsc != NULL) && (rsc->id != NULL)) {
         rsc_desc = rsc->id;
     }
     if ((node != NULL) && (node->details->uname != NULL)) {
         node_desc = node->details->uname;
     }
     out->begin_list(out, NULL, NULL, "Digests for %s %s on %s",
                     rsc_desc, action_desc, node_desc);
     free(action_desc);
 
     if (digests == NULL) {
         out->list_item(out, NULL, "none");
         out->end_list(out);
         return pcmk_rc_ok;
     }
     if (digests->digest_all_calc != NULL) {
         out->list_item(out, NULL, "%s (all parameters)",
                        digests->digest_all_calc);
     }
     if (digests->digest_secure_calc != NULL) {
         out->list_item(out, NULL, "%s (non-private parameters)",
                        digests->digest_secure_calc);
     }
     if (digests->digest_restart_calc != NULL) {
         out->list_item(out, NULL, "%s (non-reloadable parameters)",
                        digests->digest_restart_calc);
     }
     out->end_list(out);
     return pcmk_rc_ok;
 }
 
 static void
 add_digest_xml(xmlNode *parent, const char *type, const char *digest,
                xmlNode *digest_source)
 {
     if (digest != NULL) {
         xmlNodePtr digest_xml = create_xml_node(parent, "digest");
 
         crm_xml_add(digest_xml, "type", ((type == NULL)? "unspecified" : type));
         crm_xml_add(digest_xml, "hash", digest);
         if (digest_source != NULL) {
             add_node_copy(digest_xml, digest_source);
         }
     }
 }
 
 PCMK__OUTPUT_ARGS("digests", "const pe_resource_t *", "const pe_node_t *",
                   "const char *", "guint", "const op_digest_cache_t *")
 static int
 digests_xml(pcmk__output_t *out, va_list args)
 {
     const pe_resource_t *rsc = va_arg(args, const pe_resource_t *);
     const pe_node_t *node = va_arg(args, const pe_node_t *);
     const char *task = va_arg(args, const char *);
     guint interval_ms = va_arg(args, guint);
     const op_digest_cache_t *digests = va_arg(args, const op_digest_cache_t *);
 
     char *interval_s = crm_strdup_printf("%ums", interval_ms);
     xmlNode *xml = NULL;
 
     xml = pcmk__output_create_xml_node(out, "digests",
                                        "resource", pcmk__s(rsc->id, ""),
                                        "node",
                                        pcmk__s(node->details->uname, ""),
                                        "task", pcmk__s(task, ""),
                                        "interval", interval_s,
                                        NULL);
     free(interval_s);
     if (digests != NULL) {
         add_digest_xml(xml, "all", digests->digest_all_calc,
                        digests->params_all);
         add_digest_xml(xml, "nonprivate", digests->digest_secure_calc,
                        digests->params_secure);
         add_digest_xml(xml, "nonreloadable", digests->digest_restart_calc,
                        digests->params_restart);
     }
     return pcmk_rc_ok;
 }
 
 #define STOP_SANITY_ASSERT(lineno) do {                                 \
-        if(current && current->details->unclean) {                      \
+        if ((current != NULL) && current->details->unclean) {           \
             /* It will be a pseudo op */                                \
-        } else if(stop == NULL) {                                       \
+        } else if (stop == NULL) {                                      \
             crm_err("%s:%d: No stop action exists for %s",              \
                     __func__, lineno, rsc->id);                         \
             CRM_ASSERT(stop != NULL);                                   \
         } else if (pcmk_is_set(stop->flags, pe_action_optional)) {      \
             crm_err("%s:%d: Action %s is still optional",               \
                     __func__, lineno, stop->uuid);                      \
             CRM_ASSERT(!pcmk_is_set(stop->flags, pe_action_optional));  \
         }                                                               \
-    } while(0)
+    } while (0)
 
 PCMK__OUTPUT_ARGS("rsc-action", "pe_resource_t *", "pe_node_t *", "pe_node_t *")
 static int
 rsc_action_default(pcmk__output_t *out, va_list args)
 {
     pe_resource_t *rsc = va_arg(args, pe_resource_t *);
     pe_node_t *current = va_arg(args, pe_node_t *);
     pe_node_t *next = va_arg(args, pe_node_t *);
 
     GList *possible_matches = NULL;
     char *key = NULL;
     int rc = pcmk_rc_no_output;
     bool moving = false;
 
     pe_node_t *start_node = NULL;
     pe_action_t *start = NULL;
     pe_action_t *stop = NULL;
     pe_action_t *promote = NULL;
     pe_action_t *demote = NULL;
 
     if (!pcmk_is_set(rsc->flags, pe_rsc_managed)
         || (current == NULL && next == NULL)) {
         pe_rsc_info(rsc, "Leave   %s\t(%s%s)",
                     rsc->id, role2text(rsc->role),
                     !pcmk_is_set(rsc->flags, pe_rsc_managed)? " unmanaged" : "");
         return rc;
     }
 
     moving = (current != NULL) && (next != NULL)
              && !pe__same_node(current, next);
 
     possible_matches = pe__resource_actions(rsc, next, RSC_START, false);
     if (possible_matches) {
         start = possible_matches->data;
         g_list_free(possible_matches);
     }
 
     if ((start == NULL) || !pcmk_is_set(start->flags, pe_action_runnable)) {
         start_node = NULL;
     } else {
         start_node = current;
     }
     possible_matches = pe__resource_actions(rsc, start_node, RSC_STOP, false);
     if (possible_matches) {
         stop = possible_matches->data;
         g_list_free(possible_matches);
     } else if (pcmk_is_set(rsc->flags, pe_rsc_stop_unexpected)) {
         /* The resource is multiply active with multiple-active set to
          * stop_unexpected, and not stopping on its current node, but it should
          * be stopping elsewhere.
          */
         possible_matches = pe__resource_actions(rsc, NULL, RSC_STOP, false);
         if (possible_matches != NULL) {
             stop = possible_matches->data;
             g_list_free(possible_matches);
         }
     }
 
     possible_matches = pe__resource_actions(rsc, next, RSC_PROMOTE, false);
     if (possible_matches) {
         promote = possible_matches->data;
         g_list_free(possible_matches);
     }
 
     possible_matches = pe__resource_actions(rsc, next, RSC_DEMOTE, false);
     if (possible_matches) {
         demote = possible_matches->data;
         g_list_free(possible_matches);
     }
 
     if (rsc->role == rsc->next_role) {
         pe_action_t *migrate_op = NULL;
 
         CRM_CHECK(next != NULL, return rc);
 
         possible_matches = pe__resource_actions(rsc, next, RSC_MIGRATED, false);
         if (possible_matches) {
             migrate_op = possible_matches->data;
         }
 
         if ((migrate_op != NULL) && (current != NULL)
                    && pcmk_is_set(migrate_op->flags, pe_action_runnable)) {
             rc = out->message(out, "rsc-action-item", "Migrate", rsc, current,
                               next, start, NULL);
 
         } else if (pcmk_is_set(rsc->flags, pe_rsc_reload)) {
             rc = out->message(out, "rsc-action-item", "Reload", rsc, current,
                               next, start, NULL);
 
         } else if ((start == NULL)
                    || pcmk_is_set(start->flags, pe_action_optional)) {
             if ((demote != NULL) && (promote != NULL)
                 && !pcmk_is_set(demote->flags, pe_action_optional)
                 && !pcmk_is_set(promote->flags, pe_action_optional)) {
                 rc = out->message(out, "rsc-action-item", "Re-promote", rsc,
                                   current, next, promote, demote);
             } else {
                 pe_rsc_info(rsc, "Leave   %s\t(%s %s)", rsc->id,
                             role2text(rsc->role), pe__node_name(next));
             }
 
         } else if (!pcmk_is_set(start->flags, pe_action_runnable)) {
             rc = out->message(out, "rsc-action-item", "Stop", rsc, current,
                               NULL, stop, (stop && stop->reason)? stop : start);
             STOP_SANITY_ASSERT(__LINE__);
 
         } else if (moving && current) {
             rc = out->message(out, "rsc-action-item",
                               pcmk_is_set(rsc->flags, pe_rsc_failed)? "Recover" : "Move",
                               rsc, current, next, stop, NULL);
 
         } else if (pcmk_is_set(rsc->flags, pe_rsc_failed)) {
             rc = out->message(out, "rsc-action-item", "Recover", rsc, current,
                               NULL, stop, NULL);
             STOP_SANITY_ASSERT(__LINE__);
 
         } else {
             rc = out->message(out, "rsc-action-item", "Restart", rsc, current,
                               next, start, NULL);
 #if 0
             /* @TODO This can be reached in situations that should really be
              * "Start" (see for example the migrate-fail-7 regression test)
              */
             STOP_SANITY_ASSERT(__LINE__);
 #endif
         }
 
         g_list_free(possible_matches);
         return rc;
     }
 
-    if(stop
-       && (rsc->next_role == RSC_ROLE_STOPPED
-           || (start && !pcmk_is_set(start->flags, pe_action_runnable)))) {
+    if ((stop != NULL)
+        && ((rsc->next_role == RSC_ROLE_STOPPED)
+            || ((start != NULL)
+                && !pcmk_is_set(start->flags, pe_action_runnable)))) {
 
         key = stop_key(rsc);
         for (GList *iter = rsc->running_on; iter != NULL; iter = iter->next) {
             pe_node_t *node = iter->data;
             pe_action_t *stop_op = NULL;
 
             possible_matches = find_actions(rsc->actions, key, node);
             if (possible_matches) {
                 stop_op = possible_matches->data;
                 g_list_free(possible_matches);
             }
 
             if (stop_op && (stop_op->flags & pe_action_runnable)) {
                 STOP_SANITY_ASSERT(__LINE__);
             }
 
             if (out->message(out, "rsc-action-item", "Stop", rsc, node, NULL,
                              stop_op,
                              (stop_op && stop_op->reason)? stop_op : start) == pcmk_rc_ok) {
                 rc = pcmk_rc_ok;
             }
         }
 
         free(key);
 
     } else if ((stop != NULL)
                && pcmk_all_flags_set(rsc->flags, pe_rsc_failed|pe_rsc_stop)) {
         /* 'stop' may be NULL if the failure was ignored */
         rc = out->message(out, "rsc-action-item", "Recover", rsc, current,
                           next, stop, start);
         STOP_SANITY_ASSERT(__LINE__);
 
     } else if (moving) {
         rc = out->message(out, "rsc-action-item", "Move", rsc, current, next,
                           stop, NULL);
         STOP_SANITY_ASSERT(__LINE__);
 
     } else if (pcmk_is_set(rsc->flags, pe_rsc_reload)) {
         rc = out->message(out, "rsc-action-item", "Reload", rsc, current, next,
                           start, NULL);
 
     } else if (stop != NULL && !pcmk_is_set(stop->flags, pe_action_optional)) {
         rc = out->message(out, "rsc-action-item", "Restart", rsc, current,
                           next, start, NULL);
         STOP_SANITY_ASSERT(__LINE__);
 
     } else if (rsc->role == RSC_ROLE_PROMOTED) {
         CRM_LOG_ASSERT(current != NULL);
         rc = out->message(out, "rsc-action-item", "Demote", rsc, current,
                           next, demote, NULL);
 
     } else if (rsc->next_role == RSC_ROLE_PROMOTED) {
         CRM_LOG_ASSERT(next);
         rc = out->message(out, "rsc-action-item", "Promote", rsc, current,
                           next, promote, NULL);
 
     } else if ((rsc->role == RSC_ROLE_STOPPED)
                && (rsc->next_role > RSC_ROLE_STOPPED)) {
         rc = out->message(out, "rsc-action-item", "Start", rsc, current, next,
                           start, NULL);
     }
 
     return rc;
 }
 
 PCMK__OUTPUT_ARGS("node-action", "const char *", "const char *", "const char *")
 static int
 node_action(pcmk__output_t *out, va_list args)
 {
     const char *task = va_arg(args, const char *);
     const char *node_name = va_arg(args, const char *);
     const char *reason = va_arg(args, const char *);
 
     if (task == NULL) {
         return pcmk_rc_no_output;
     } else if (reason) {
         out->list_item(out, NULL, "%s %s '%s'", task, node_name, reason);
     } else {
         crm_notice(" * %s %s", task, node_name);
     }
 
     return pcmk_rc_ok;
 }
 
 PCMK__OUTPUT_ARGS("node-action", "const char *", "const char *", "const char *")
 static int
 node_action_xml(pcmk__output_t *out, va_list args)
 {
     const char *task = va_arg(args, const char *);
     const char *node_name = va_arg(args, const char *);
     const char *reason = va_arg(args, const char *);
 
     if (task == NULL) {
         return pcmk_rc_no_output;
     } else if (reason) {
         pcmk__output_create_xml_node(out, "node_action",
                                      "task", task,
                                      "node", node_name,
                                      "reason", reason,
                                      NULL);
     } else {
         crm_notice(" * %s %s", task, node_name);
     }
 
     return pcmk_rc_ok;
 }
 
 PCMK__OUTPUT_ARGS("node-info", "int", "const char *", "const char *",
                   "const char *", "bool", "bool")
 static int
 node_info_default(pcmk__output_t *out, va_list args)
 {
     int node_id = va_arg(args, int);
     const char *node_name = va_arg(args, const char *);
     const char *uuid = va_arg(args, const char *);
     const char *state = va_arg(args, const char *);
     bool have_quorum = (bool) va_arg(args, int);
     bool is_remote = (bool) va_arg(args, int);
 
     return out->info(out,
                      "Node %d: %s "
                      "(uuid=%s, state=%s, have_quorum=%s, is_remote=%s)",
                      node_id, pcmk__s(node_name, "unknown"),
                      pcmk__s(uuid, "unknown"), pcmk__s(state, "unknown"),
                      pcmk__btoa(have_quorum), pcmk__btoa(is_remote));
 }
 
 PCMK__OUTPUT_ARGS("node-info", "int", "const char *", "const char *",
                   "const char *", "bool", "bool")
 static int
 node_info_xml(pcmk__output_t *out, va_list args)
 {
     int node_id = va_arg(args, int);
     const char *node_name = va_arg(args, const char *);
     const char *uuid = va_arg(args, const char *);
     const char *state = va_arg(args, const char *);
     bool have_quorum = (bool) va_arg(args, int);
     bool is_remote = (bool) va_arg(args, int);
 
     char *id_s = crm_strdup_printf("%d", node_id);
 
     pcmk__output_create_xml_node(out, "node-info",
                                  "nodeid", id_s,
                                  XML_ATTR_UNAME, node_name,
                                  XML_ATTR_ID, uuid,
                                  XML_NODE_IS_PEER, state,
                                  XML_ATTR_HAVE_QUORUM, pcmk__btoa(have_quorum),
                                  XML_NODE_IS_REMOTE, pcmk__btoa(is_remote),
                                  NULL);
     free(id_s);
     return pcmk_rc_ok;
 }
 
 PCMK__OUTPUT_ARGS("inject-cluster-action", "const char *", "const char *",
                   "xmlNodePtr")
 static int
 inject_cluster_action(pcmk__output_t *out, va_list args)
 {
     const char *node = va_arg(args, const char *);
     const char *task = va_arg(args, const char *);
     xmlNodePtr rsc = va_arg(args, xmlNodePtr);
 
     if (out->is_quiet(out)) {
         return pcmk_rc_no_output;
     }
 
-    if(rsc) {
+    if (rsc != NULL) {
         out->list_item(out, NULL, "Cluster action:  %s for %s on %s",
                        task, ID(rsc), node);
     } else {
         out->list_item(out, NULL, "Cluster action:  %s on %s", task, node);
     }
 
     return pcmk_rc_ok;
 }
 
 PCMK__OUTPUT_ARGS("inject-cluster-action", "const char *", "const char *",
                   "xmlNodePtr")
 static int
 inject_cluster_action_xml(pcmk__output_t *out, va_list args)
 {
     const char *node = va_arg(args, const char *);
     const char *task = va_arg(args, const char *);
     xmlNodePtr rsc = va_arg(args, xmlNodePtr);
 
     xmlNodePtr xml_node = NULL;
 
     if (out->is_quiet(out)) {
         return pcmk_rc_no_output;
     }
 
     xml_node = pcmk__output_create_xml_node(out, "cluster_action",
                                             "task", task,
                                             "node", node,
                                             NULL);
 
     if (rsc) {
         crm_xml_add(xml_node, "id", ID(rsc));
     }
 
     return pcmk_rc_ok;
 }
 
 PCMK__OUTPUT_ARGS("inject-fencing-action", "const char *", "const char *")
 static int
 inject_fencing_action(pcmk__output_t *out, va_list args)
 {
     const char *target = va_arg(args, const char *);
     const char *op = va_arg(args, const char *);
 
     if (out->is_quiet(out)) {
         return pcmk_rc_no_output;
     }
 
     out->list_item(out, NULL, "Fencing %s (%s)", target, op);
     return pcmk_rc_ok;
 }
 
 PCMK__OUTPUT_ARGS("inject-fencing-action", "const char *", "const char *")
 static int
 inject_fencing_action_xml(pcmk__output_t *out, va_list args)
 {
     const char *target = va_arg(args, const char *);
     const char *op = va_arg(args, const char *);
 
     if (out->is_quiet(out)) {
         return pcmk_rc_no_output;
     }
 
     pcmk__output_create_xml_node(out, "fencing_action",
                                  "target", target,
                                  "op", op,
                                  NULL);
     return pcmk_rc_ok;
 }
 
 PCMK__OUTPUT_ARGS("inject-attr", "const char *", "const char *", "xmlNodePtr")
 static int
 inject_attr(pcmk__output_t *out, va_list args)
 {
     const char *name = va_arg(args, const char *);
     const char *value = va_arg(args, const char *);
     xmlNodePtr cib_node = va_arg(args, xmlNodePtr);
 
     xmlChar *node_path = NULL;
 
     if (out->is_quiet(out)) {
         return pcmk_rc_no_output;
     }
 
     node_path = xmlGetNodePath(cib_node);
 
     out->list_item(out, NULL, "Injecting attribute %s=%s into %s '%s'",
                    name, value, node_path, ID(cib_node));
 
     free(node_path);
     return pcmk_rc_ok;
 }
 
 PCMK__OUTPUT_ARGS("inject-attr", "const char *", "const char *", "xmlNodePtr")
 static int
 inject_attr_xml(pcmk__output_t *out, va_list args)
 {
     const char *name = va_arg(args, const char *);
     const char *value = va_arg(args, const char *);
     xmlNodePtr cib_node = va_arg(args, xmlNodePtr);
 
     xmlChar *node_path = NULL;
 
     if (out->is_quiet(out)) {
         return pcmk_rc_no_output;
     }
 
     node_path = xmlGetNodePath(cib_node);
 
     pcmk__output_create_xml_node(out, "inject_attr",
                                  "name", name,
                                  "value", value,
                                  "node_path", node_path,
                                  "cib_node", ID(cib_node),
                                  NULL);
     free(node_path);
     return pcmk_rc_ok;
 }
 
 PCMK__OUTPUT_ARGS("inject-spec", "const char *")
 static int
 inject_spec(pcmk__output_t *out, va_list args)
 {
     const char *spec = va_arg(args, const char *);
 
     if (out->is_quiet(out)) {
         return pcmk_rc_no_output;
     }
 
     out->list_item(out, NULL, "Injecting %s into the configuration", spec);
     return pcmk_rc_ok;
 }
 
 PCMK__OUTPUT_ARGS("inject-spec", "const char *")
 static int
 inject_spec_xml(pcmk__output_t *out, va_list args)
 {
     const char *spec = va_arg(args, const char *);
 
     if (out->is_quiet(out)) {
         return pcmk_rc_no_output;
     }
 
     pcmk__output_create_xml_node(out, "inject_spec",
                                  "spec", spec,
                                  NULL);
     return pcmk_rc_ok;
 }
 
 PCMK__OUTPUT_ARGS("inject-modify-config", "const char *", "const char *")
 static int
 inject_modify_config(pcmk__output_t *out, va_list args)
 {
     const char *quorum = va_arg(args, const char *);
     const char *watchdog = va_arg(args, const char *);
 
     if (out->is_quiet(out)) {
         return pcmk_rc_no_output;
     }
 
     out->begin_list(out, NULL, NULL, "Performing Requested Modifications");
 
     if (quorum) {
         out->list_item(out, NULL, "Setting quorum: %s", quorum);
     }
 
     if (watchdog) {
         out->list_item(out, NULL, "Setting watchdog: %s", watchdog);
     }
 
     return pcmk_rc_ok;
 }
 
 PCMK__OUTPUT_ARGS("inject-modify-config", "const char *", "const char *")
 static int
 inject_modify_config_xml(pcmk__output_t *out, va_list args)
 {
     const char *quorum = va_arg(args, const char *);
     const char *watchdog = va_arg(args, const char *);
 
     xmlNodePtr node = NULL;
 
     if (out->is_quiet(out)) {
         return pcmk_rc_no_output;
     }
 
     node = pcmk__output_xml_create_parent(out, "modifications", NULL);
 
     if (quorum) {
         crm_xml_add(node, "quorum", quorum);
     }
 
     if (watchdog) {
         crm_xml_add(node, "watchdog", watchdog);
     }
 
     return pcmk_rc_ok;
 }
 
 PCMK__OUTPUT_ARGS("inject-modify-node", "const char *", "const char *")
 static int
 inject_modify_node(pcmk__output_t *out, va_list args)
 {
     const char *action = va_arg(args, const char *);
     const char *node = va_arg(args, const char *);
 
     if (out->is_quiet(out)) {
         return pcmk_rc_no_output;
     }
 
     if (pcmk__str_eq(action, "Online", pcmk__str_none)) {
         out->list_item(out, NULL, "Bringing node %s online", node);
         return pcmk_rc_ok;
     } else if (pcmk__str_eq(action, "Offline", pcmk__str_none)) {
         out->list_item(out, NULL, "Taking node %s offline", node);
         return pcmk_rc_ok;
     } else if (pcmk__str_eq(action, "Failing", pcmk__str_none)) {
         out->list_item(out, NULL, "Failing node %s", node);
         return pcmk_rc_ok;
     }
 
     return pcmk_rc_no_output;
 }
 
 PCMK__OUTPUT_ARGS("inject-modify-node", "const char *", "const char *")
 static int
 inject_modify_node_xml(pcmk__output_t *out, va_list args)
 {
     const char *action = va_arg(args, const char *);
     const char *node = va_arg(args, const char *);
 
     if (out->is_quiet(out)) {
         return pcmk_rc_no_output;
     }
 
     pcmk__output_create_xml_node(out, "modify_node",
                                  "action", action,
                                  "node", node,
                                  NULL);
     return pcmk_rc_ok;
 }
 
 PCMK__OUTPUT_ARGS("inject-modify-ticket", "const char *", "const char *")
 static int
 inject_modify_ticket(pcmk__output_t *out, va_list args)
 {
     const char *action = va_arg(args, const char *);
     const char *ticket = va_arg(args, const char *);
 
     if (out->is_quiet(out)) {
         return pcmk_rc_no_output;
     }
 
     if (pcmk__str_eq(action, "Standby", pcmk__str_none)) {
         out->list_item(out, NULL, "Making ticket %s standby", ticket);
     } else {
         out->list_item(out, NULL, "%s ticket %s", action, ticket);
     }
 
     return pcmk_rc_ok;
 }
 
 PCMK__OUTPUT_ARGS("inject-modify-ticket", "const char *", "const char *")
 static int
 inject_modify_ticket_xml(pcmk__output_t *out, va_list args)
 {
     const char *action = va_arg(args, const char *);
     const char *ticket = va_arg(args, const char *);
 
     if (out->is_quiet(out)) {
         return pcmk_rc_no_output;
     }
 
     pcmk__output_create_xml_node(out, "modify_ticket",
                                  "action", action,
                                  "ticket", ticket,
                                  NULL);
     return pcmk_rc_ok;
 }
 
 PCMK__OUTPUT_ARGS("inject-pseudo-action", "const char *", "const char *")
 static int
 inject_pseudo_action(pcmk__output_t *out, va_list args)
 {
     const char *node = va_arg(args, const char *);
     const char *task = va_arg(args, const char *);
 
     if (out->is_quiet(out)) {
         return pcmk_rc_no_output;
     }
 
     out->list_item(out, NULL, "Pseudo action:   %s%s%s",
                    task, ((node == NULL)? "" : " on "), pcmk__s(node, ""));
     return pcmk_rc_ok;
 }
 
 PCMK__OUTPUT_ARGS("inject-pseudo-action", "const char *", "const char *")
 static int
 inject_pseudo_action_xml(pcmk__output_t *out, va_list args)
 {
     const char *node = va_arg(args, const char *);
     const char *task = va_arg(args, const char *);
 
     xmlNodePtr xml_node = NULL;
 
     if (out->is_quiet(out)) {
         return pcmk_rc_no_output;
     }
 
     xml_node = pcmk__output_create_xml_node(out, "pseudo_action",
                                             "task", task,
                                             NULL);
     if (node) {
         crm_xml_add(xml_node, "node", node);
     }
 
     return pcmk_rc_ok;
 }
 
 PCMK__OUTPUT_ARGS("inject-rsc-action", "const char *", "const char *",
                   "const char *", "guint")
 static int
 inject_rsc_action(pcmk__output_t *out, va_list args)
 {
     const char *rsc = va_arg(args, const char *);
     const char *operation = va_arg(args, const char *);
     const char *node = va_arg(args, const char *);
     guint interval_ms = va_arg(args, guint);
 
     if (out->is_quiet(out)) {
         return pcmk_rc_no_output;
     }
 
     if (interval_ms) {
         out->list_item(out, NULL, "Resource action: %-15s %s=%u on %s",
                        rsc, operation, interval_ms, node);
     } else {
         out->list_item(out, NULL, "Resource action: %-15s %s on %s",
                        rsc, operation, node);
     }
 
     return pcmk_rc_ok;
 }
 
 PCMK__OUTPUT_ARGS("inject-rsc-action", "const char *", "const char *",
                   "const char *", "guint")
 static int
 inject_rsc_action_xml(pcmk__output_t *out, va_list args)
 {
     const char *rsc = va_arg(args, const char *);
     const char *operation = va_arg(args, const char *);
     const char *node = va_arg(args, const char *);
     guint interval_ms = va_arg(args, guint);
 
     xmlNodePtr xml_node = NULL;
 
     if (out->is_quiet(out)) {
         return pcmk_rc_no_output;
     }
 
     xml_node = pcmk__output_create_xml_node(out, "rsc_action",
                                             "resource", rsc,
                                             "op", operation,
                                             "node", node,
                                             NULL);
 
     if (interval_ms) {
         char *interval_s = pcmk__itoa(interval_ms);
 
         crm_xml_add(xml_node, "interval", interval_s);
         free(interval_s);
     }
 
     return pcmk_rc_ok;
 }
 
 #define CHECK_RC(retcode, retval)   \
     if (retval == pcmk_rc_ok) {     \
         retcode = pcmk_rc_ok;       \
     }
 
 PCMK__OUTPUT_ARGS("cluster-status", "pe_working_set_t *",
                   "enum pcmk_pacemakerd_state", "crm_exit_t",
                   "stonith_history_t *", "enum pcmk__fence_history", "uint32_t",
                   "uint32_t", "const char *", "GList *", "GList *")
 int
 pcmk__cluster_status_text(pcmk__output_t *out, va_list args)
 {
     pe_working_set_t *data_set = va_arg(args, pe_working_set_t *);
     enum pcmk_pacemakerd_state pcmkd_state =
         (enum pcmk_pacemakerd_state) va_arg(args, int);
     crm_exit_t history_rc = va_arg(args, crm_exit_t);
     stonith_history_t *stonith_history = va_arg(args, stonith_history_t *);
     enum pcmk__fence_history fence_history = va_arg(args, int);
     uint32_t section_opts = va_arg(args, uint32_t);
     uint32_t show_opts = va_arg(args, uint32_t);
     const char *prefix = va_arg(args, const char *);
     GList *unames = va_arg(args, GList *);
     GList *resources = va_arg(args, GList *);
 
     int rc = pcmk_rc_no_output;
     bool already_printed_failure = false;
 
     CHECK_RC(rc, out->message(out, "cluster-summary", data_set, pcmkd_state,
                               section_opts, show_opts));
 
     if (pcmk_is_set(section_opts, pcmk_section_nodes) && unames) {
         CHECK_RC(rc, out->message(out, "node-list", data_set->nodes, unames,
                                   resources, show_opts, rc == pcmk_rc_ok));
     }
 
     /* Print resources section, if needed */
     if (pcmk_is_set(section_opts, pcmk_section_resources)) {
         CHECK_RC(rc, out->message(out, "resource-list", data_set, show_opts,
                                   true, unames, resources, rc == pcmk_rc_ok));
     }
 
     /* print Node Attributes section if requested */
     if (pcmk_is_set(section_opts, pcmk_section_attributes)) {
         CHECK_RC(rc, out->message(out, "node-attribute-list", data_set,
                                   show_opts, (rc == pcmk_rc_ok), unames,
                                   resources));
     }
 
     /* If requested, print resource operations (which includes failcounts)
      * or just failcounts
      */
     if (pcmk_any_flags_set(section_opts,
                            pcmk_section_operations|pcmk_section_failcounts)) {
         CHECK_RC(rc, out->message(out, "node-summary", data_set, unames,
                                   resources, section_opts, show_opts,
                                   (rc == pcmk_rc_ok)));
     }
 
     /* If there were any failed actions, print them */
     if (pcmk_is_set(section_opts, pcmk_section_failures)
         && xml_has_children(data_set->failed)) {
 
         CHECK_RC(rc, out->message(out, "failed-action-list", data_set, unames,
                                   resources, show_opts, rc == pcmk_rc_ok));
     }
 
     /* Print failed stonith actions */
     if (pcmk_is_set(section_opts, pcmk_section_fence_failed) &&
         fence_history != pcmk__fence_history_none) {
         if (history_rc == 0) {
             stonith_history_t *hp = NULL;
 
             hp = stonith__first_matching_event(stonith_history,
                                                stonith__event_state_eq,
                                                GINT_TO_POINTER(st_failed));
             if (hp) {
                 CHECK_RC(rc, out->message(out, "failed-fencing-list",
                                           stonith_history, unames, section_opts,
                                           show_opts, rc == pcmk_rc_ok));
             }
         } else {
             PCMK__OUTPUT_SPACER_IF(out, rc == pcmk_rc_ok);
             out->begin_list(out, NULL, NULL, "Failed Fencing Actions");
             out->list_item(out, NULL, "Failed to get fencing history: %s",
                            crm_exit_str(history_rc));
             out->end_list(out);
 
             already_printed_failure = true;
         }
     }
 
     /* Print tickets if requested */
     if (pcmk_is_set(section_opts, pcmk_section_tickets)) {
         CHECK_RC(rc, out->message(out, "ticket-list", data_set,
                                   (rc == pcmk_rc_ok)));
     }
 
     /* Print negative location constraints if requested */
     if (pcmk_is_set(section_opts, pcmk_section_bans)) {
         CHECK_RC(rc, out->message(out, "ban-list", data_set, prefix, resources,
                                   show_opts, rc == pcmk_rc_ok));
     }
 
     /* Print stonith history */
     if (pcmk_any_flags_set(section_opts, pcmk_section_fencing_all) &&
         fence_history != pcmk__fence_history_none) {
         if (history_rc != 0) {
             if (!already_printed_failure) {
                 PCMK__OUTPUT_SPACER_IF(out, rc == pcmk_rc_ok);
                 out->begin_list(out, NULL, NULL, "Failed Fencing Actions");
                 out->list_item(out, NULL, "Failed to get fencing history: %s",
                                crm_exit_str(history_rc));
                 out->end_list(out);
             }
         } else if (pcmk_is_set(section_opts, pcmk_section_fence_worked)) {
             stonith_history_t *hp = NULL;
 
             hp = stonith__first_matching_event(stonith_history,
                                                stonith__event_state_neq,
                                                GINT_TO_POINTER(st_failed));
             if (hp) {
                 CHECK_RC(rc, out->message(out, "fencing-list", hp, unames,
                                           section_opts, show_opts,
                                           rc == pcmk_rc_ok));
             }
         } else if (pcmk_is_set(section_opts, pcmk_section_fence_pending)) {
             stonith_history_t *hp = NULL;
 
             hp = stonith__first_matching_event(stonith_history,
                                                stonith__event_state_pending,
                                                NULL);
             if (hp) {
                 CHECK_RC(rc, out->message(out, "pending-fencing-list", hp,
                                           unames, section_opts, show_opts,
                                           rc == pcmk_rc_ok));
             }
         }
     }
 
     return rc;
 }
 
 PCMK__OUTPUT_ARGS("cluster-status", "pe_working_set_t *",
                   "enum pcmk_pacemakerd_state", "crm_exit_t",
                   "stonith_history_t *", "enum pcmk__fence_history", "uint32_t",
                   "uint32_t", "const char *", "GList *", "GList *")
 static int
 cluster_status_xml(pcmk__output_t *out, va_list args)
 {
     pe_working_set_t *data_set = va_arg(args, pe_working_set_t *);
     enum pcmk_pacemakerd_state pcmkd_state =
         (enum pcmk_pacemakerd_state) va_arg(args, int);
     crm_exit_t history_rc = va_arg(args, crm_exit_t);
     stonith_history_t *stonith_history = va_arg(args, stonith_history_t *);
     enum pcmk__fence_history fence_history = va_arg(args, int);
     uint32_t section_opts = va_arg(args, uint32_t);
     uint32_t show_opts = va_arg(args, uint32_t);
     const char *prefix = va_arg(args, const char *);
     GList *unames = va_arg(args, GList *);
     GList *resources = va_arg(args, GList *);
 
     out->message(out, "cluster-summary", data_set, pcmkd_state, section_opts,
                  show_opts);
 
     /*** NODES ***/
     if (pcmk_is_set(section_opts, pcmk_section_nodes)) {
         out->message(out, "node-list", data_set->nodes, unames, resources,
                      show_opts, false);
     }
 
     /* Print resources section, if needed */
     if (pcmk_is_set(section_opts, pcmk_section_resources)) {
         /* XML output always displays full details. */
         uint32_t full_show_opts = show_opts & ~pcmk_show_brief;
 
         out->message(out, "resource-list", data_set, full_show_opts,
                      false, unames, resources, false);
     }
 
     /* print Node Attributes section if requested */
     if (pcmk_is_set(section_opts, pcmk_section_attributes)) {
         out->message(out, "node-attribute-list", data_set, show_opts, false,
                      unames, resources);
     }
 
     /* If requested, print resource operations (which includes failcounts)
      * or just failcounts
      */
     if (pcmk_any_flags_set(section_opts,
                            pcmk_section_operations|pcmk_section_failcounts)) {
         out->message(out, "node-summary", data_set, unames,
                      resources, section_opts, show_opts, false);
     }
 
     /* If there were any failed actions, print them */
     if (pcmk_is_set(section_opts, pcmk_section_failures)
         && xml_has_children(data_set->failed)) {
 
         out->message(out, "failed-action-list", data_set, unames, resources,
                      show_opts, false);
     }
 
     /* Print stonith history */
     if (pcmk_is_set(section_opts, pcmk_section_fencing_all) &&
         fence_history != pcmk__fence_history_none) {
         out->message(out, "full-fencing-list", history_rc, stonith_history,
                      unames, section_opts, show_opts, false);
     }
 
     /* Print tickets if requested */
     if (pcmk_is_set(section_opts, pcmk_section_tickets)) {
         out->message(out, "ticket-list", data_set, false);
     }
 
     /* Print negative location constraints if requested */
     if (pcmk_is_set(section_opts, pcmk_section_bans)) {
         out->message(out, "ban-list", data_set, prefix, resources, show_opts,
                      false);
     }
 
     return pcmk_rc_ok;
 }
 
 PCMK__OUTPUT_ARGS("cluster-status", "pe_working_set_t *",
                   "enum pcmk_pacemakerd_state", "crm_exit_t",
                   "stonith_history_t *", "enum pcmk__fence_history", "uint32_t",
                   "uint32_t", "const char *", "GList *", "GList *")
 static int
 cluster_status_html(pcmk__output_t *out, va_list args)
 {
     pe_working_set_t *data_set = va_arg(args, pe_working_set_t *);
     enum pcmk_pacemakerd_state pcmkd_state =
         (enum pcmk_pacemakerd_state) va_arg(args, int);
     crm_exit_t history_rc = va_arg(args, crm_exit_t);
     stonith_history_t *stonith_history = va_arg(args, stonith_history_t *);
     enum pcmk__fence_history fence_history = va_arg(args, int);
     uint32_t section_opts = va_arg(args, uint32_t);
     uint32_t show_opts = va_arg(args, uint32_t);
     const char *prefix = va_arg(args, const char *);
     GList *unames = va_arg(args, GList *);
     GList *resources = va_arg(args, GList *);
     bool already_printed_failure = false;
 
     out->message(out, "cluster-summary", data_set, pcmkd_state, section_opts,
                  show_opts);
 
     /*** NODE LIST ***/
     if (pcmk_is_set(section_opts, pcmk_section_nodes) && unames) {
         out->message(out, "node-list", data_set->nodes, unames, resources,
                      show_opts, false);
     }
 
     /* Print resources section, if needed */
     if (pcmk_is_set(section_opts, pcmk_section_resources)) {
         out->message(out, "resource-list", data_set, show_opts, true, unames,
                      resources, false);
     }
 
     /* print Node Attributes section if requested */
     if (pcmk_is_set(section_opts, pcmk_section_attributes)) {
         out->message(out, "node-attribute-list", data_set, show_opts, false,
                      unames, resources);
     }
 
     /* If requested, print resource operations (which includes failcounts)
      * or just failcounts
      */
     if (pcmk_any_flags_set(section_opts,
                            pcmk_section_operations|pcmk_section_failcounts)) {
         out->message(out, "node-summary", data_set, unames,
                      resources, section_opts, show_opts, false);
     }
 
     /* If there were any failed actions, print them */
     if (pcmk_is_set(section_opts, pcmk_section_failures)
         && xml_has_children(data_set->failed)) {
 
         out->message(out, "failed-action-list", data_set, unames, resources,
                      show_opts, false);
     }
 
     /* Print failed stonith actions */
     if (pcmk_is_set(section_opts, pcmk_section_fence_failed) &&
         fence_history != pcmk__fence_history_none) {
         if (history_rc == 0) {
             stonith_history_t *hp = NULL;
 
             hp = stonith__first_matching_event(stonith_history,
                                                stonith__event_state_eq,
                                                GINT_TO_POINTER(st_failed));
             if (hp) {
                 out->message(out, "failed-fencing-list", stonith_history,
                              unames, section_opts, show_opts, false);
             }
         } else {
             out->begin_list(out, NULL, NULL, "Failed Fencing Actions");
             out->list_item(out, NULL, "Failed to get fencing history: %s",
                            crm_exit_str(history_rc));
             out->end_list(out);
         }
     }
 
     /* Print stonith history */
     if (pcmk_any_flags_set(section_opts, pcmk_section_fencing_all) &&
         fence_history != pcmk__fence_history_none) {
         if (history_rc != 0) {
             if (!already_printed_failure) {
                 out->begin_list(out, NULL, NULL, "Failed Fencing Actions");
                 out->list_item(out, NULL, "Failed to get fencing history: %s",
                                crm_exit_str(history_rc));
                 out->end_list(out);
             }
         } else if (pcmk_is_set(section_opts, pcmk_section_fence_worked)) {
             stonith_history_t *hp = NULL;
 
             hp = stonith__first_matching_event(stonith_history,
                                                stonith__event_state_neq,
                                                GINT_TO_POINTER(st_failed));
             if (hp) {
                 out->message(out, "fencing-list", hp, unames, section_opts,
                              show_opts, false);
             }
         } else if (pcmk_is_set(section_opts, pcmk_section_fence_pending)) {
             stonith_history_t *hp = NULL;
 
             hp = stonith__first_matching_event(stonith_history,
                                                stonith__event_state_pending,
                                                NULL);
             if (hp) {
                 out->message(out, "pending-fencing-list", hp, unames,
                              section_opts, show_opts, false);
             }
         }
     }
 
     /* Print tickets if requested */
     if (pcmk_is_set(section_opts, pcmk_section_tickets)) {
         out->message(out, "ticket-list", data_set, false);
     }
 
     /* Print negative location constraints if requested */
     if (pcmk_is_set(section_opts, pcmk_section_bans)) {
         out->message(out, "ban-list", data_set, prefix, resources, show_opts,
                      false);
     }
 
     return pcmk_rc_ok;
 }
 
 PCMK__OUTPUT_ARGS("attribute", "const char *", "const char *", "const char *",
                   "const char *", "const char *")
 static int
 attribute_default(pcmk__output_t *out, va_list args)
 {
     const char *scope = va_arg(args, const char *);
     const char *instance = va_arg(args, const char *);
     const char *name = va_arg(args, const char *);
     const char *value = va_arg(args, const char *);
     const char *host = va_arg(args, const char *);
 
     GString *s = g_string_sized_new(50);
 
     if (!pcmk__str_empty(scope)) {
         pcmk__g_strcat(s, "scope=\"", scope, "\" ", NULL);
     }
 
     if (!pcmk__str_empty(instance)) {
         pcmk__g_strcat(s, "id=\"", instance, "\" ", NULL);
     }
 
     pcmk__g_strcat(s, "name=\"", pcmk__s(name, ""), "\" ", NULL);
 
     if (!pcmk__str_empty(host)) {
         pcmk__g_strcat(s, "host=\"", host, "\" ", NULL);
     }
 
     pcmk__g_strcat(s, "value=\"", pcmk__s(value, ""), "\"", NULL);
 
     out->info(out, "%s", s->str);
     g_string_free(s, TRUE);
 
     return pcmk_rc_ok;
 }
 
 PCMK__OUTPUT_ARGS("attribute", "const char *", "const char *", "const char *",
                   "const char *", "const char *")
 static int
 attribute_xml(pcmk__output_t *out, va_list args)
 {
     const char *scope = va_arg(args, const char *);
     const char *instance = va_arg(args, const char *);
     const char *name = va_arg(args, const char *);
     const char *value = va_arg(args, const char *);
     const char *host = va_arg(args, const char *);
 
     xmlNodePtr node = NULL;
 
     node = pcmk__output_create_xml_node(out, "attribute",
                                         "name", name,
                                         "value", value ? value : "",
                                         NULL);
 
     if (!pcmk__str_empty(scope)) {
         crm_xml_add(node, "scope", scope);
     }
 
     if (!pcmk__str_empty(instance)) {
         crm_xml_add(node, "id", instance);
     }
 
     if (!pcmk__str_empty(host)) {
         crm_xml_add(node, "host", host);
     }
 
     return pcmk_rc_ok;
 }
 
 PCMK__OUTPUT_ARGS("rule-check", "const char *", "int", "const char *")
 static int
 rule_check_default(pcmk__output_t *out, va_list args)
 {
     const char *rule_id = va_arg(args, const char *);
     int result = va_arg(args, int);
     const char *error = va_arg(args, const char *);
 
     switch (result) {
         case pcmk_rc_within_range:
             return out->info(out, "Rule %s is still in effect", rule_id);
         case pcmk_rc_ok:
             return out->info(out, "Rule %s satisfies conditions", rule_id);
         case pcmk_rc_after_range:
             return out->info(out, "Rule %s is expired", rule_id);
         case pcmk_rc_before_range:
             return out->info(out, "Rule %s has not yet taken effect", rule_id);
         case pcmk_rc_op_unsatisfied:
             return out->info(out, "Rule %s does not satisfy conditions",
                              rule_id);
         default:
             out->err(out,
                      "Could not determine whether rule %s is in effect: %s",
                      rule_id, ((error != NULL)? error : "unexpected error"));
             return pcmk_rc_ok;
     }
 }
 
 PCMK__OUTPUT_ARGS("rule-check", "const char *", "int", "const char *")
 static int
 rule_check_xml(pcmk__output_t *out, va_list args)
 {
     const char *rule_id = va_arg(args, const char *);
     int result = va_arg(args, int);
     const char *error = va_arg(args, const char *);
 
     char *rc_str = pcmk__itoa(pcmk_rc2exitc(result));
 
     pcmk__output_create_xml_node(out, "rule-check",
                                  "rule-id", rule_id,
                                  "rc", rc_str,
                                  NULL);
     free(rc_str);
 
     switch (result) {
         case pcmk_rc_within_range:
         case pcmk_rc_ok:
         case pcmk_rc_after_range:
         case pcmk_rc_before_range:
         case pcmk_rc_op_unsatisfied:
             return pcmk_rc_ok;
         default:
             out->err(out,
                     "Could not determine whether rule %s is in effect: %s",
                     rule_id, ((error != NULL)? error : "unexpected error"));
             return pcmk_rc_ok;
     }
 }
 
 PCMK__OUTPUT_ARGS("result-code", "int", "const char *", "const char *")
 static int
 result_code_none(pcmk__output_t *out, va_list args)
 {
     return pcmk_rc_no_output;
 }
 
 PCMK__OUTPUT_ARGS("result-code", "int", "const char *", "const char *")
 static int
 result_code_text(pcmk__output_t *out, va_list args)
 {
     int code = va_arg(args, int);
     const char *name = va_arg(args, const char *);
     const char *desc = va_arg(args, const char *);
 
     static int code_width = 0;
 
     if (out->is_quiet(out)) {
         /* If out->is_quiet(), don't print the code. Print name and/or desc in a
          * compact format for text output, or print nothing at all for none-type
          * output.
          */
         if ((name != NULL) && (desc != NULL)) {
             pcmk__formatted_printf(out, "%s - %s\n", name, desc);
 
         } else if ((name != NULL) || (desc != NULL)) {
             pcmk__formatted_printf(out, "%s\n", ((name != NULL)? name : desc));
         }
         return pcmk_rc_ok;
     }
 
     /* Get length of longest (most negative) standard Pacemaker return code
      * This should be longer than all the values of any other type of return
      * code.
      */
     if (code_width == 0) {
         long long most_negative = pcmk_rc_error - (long long) pcmk__n_rc + 1;
         code_width = (int) snprintf(NULL, 0, "%lld", most_negative);
     }
 
     if ((name != NULL) && (desc != NULL)) {
         static int name_width = 0;
 
         if (name_width == 0) {
             // Get length of longest standard Pacemaker return code name
             for (int lpc = 0; lpc < pcmk__n_rc; lpc++) {
                 int len = (int) strlen(pcmk_rc_name(pcmk_rc_error - lpc));
                 name_width = QB_MAX(name_width, len);
             }
         }
         return out->info(out, "% *d: %-*s  %s", code_width, code, name_width,
                          name, desc);
     }
 
     if ((name != NULL) || (desc != NULL)) {
         return out->info(out, "% *d: %s", code_width, code,
                          ((name != NULL)? name : desc));
     }
 
     return out->info(out, "% *d", code_width, code);
 }
 
 PCMK__OUTPUT_ARGS("result-code", "int", "const char *", "const char *")
 static int
 result_code_xml(pcmk__output_t *out, va_list args)
 {
     int code = va_arg(args, int);
     const char *name = va_arg(args, const char *);
     const char *desc = va_arg(args, const char *);
 
     char *code_str = pcmk__itoa(code);
 
     pcmk__output_create_xml_node(out, "result-code",
                                  "code", code_str,
                                  XML_ATTR_NAME, name,
                                  XML_ATTR_DESC, desc,
                                  NULL);
     free(code_str);
     return pcmk_rc_ok;
 }
 
 static pcmk__message_entry_t fmt_functions[] = {
     { "attribute", "default", attribute_default },
     { "attribute", "xml", attribute_xml },
     { "cluster-status", "default", pcmk__cluster_status_text },
     { "cluster-status", "html", cluster_status_html },
     { "cluster-status", "xml", cluster_status_xml },
     { "crmadmin-node", "default", crmadmin_node },
     { "crmadmin-node", "text", crmadmin_node_text },
     { "crmadmin-node", "xml", crmadmin_node_xml },
     { "dc", "default", dc },
     { "dc", "text", dc_text },
     { "dc", "xml", dc_xml },
     { "digests", "default", digests_text },
     { "digests", "xml", digests_xml },
     { "health", "default", health },
     { "health", "text", health_text },
     { "health", "xml", health_xml },
     { "inject-attr", "default", inject_attr },
     { "inject-attr", "xml", inject_attr_xml },
     { "inject-cluster-action", "default", inject_cluster_action },
     { "inject-cluster-action", "xml", inject_cluster_action_xml },
     { "inject-fencing-action", "default", inject_fencing_action },
     { "inject-fencing-action", "xml", inject_fencing_action_xml },
     { "inject-modify-config", "default", inject_modify_config },
     { "inject-modify-config", "xml", inject_modify_config_xml },
     { "inject-modify-node", "default", inject_modify_node },
     { "inject-modify-node", "xml", inject_modify_node_xml },
     { "inject-modify-ticket", "default", inject_modify_ticket },
     { "inject-modify-ticket", "xml", inject_modify_ticket_xml },
     { "inject-pseudo-action", "default", inject_pseudo_action },
     { "inject-pseudo-action", "xml", inject_pseudo_action_xml },
     { "inject-rsc-action", "default", inject_rsc_action },
     { "inject-rsc-action", "xml", inject_rsc_action_xml },
     { "inject-spec", "default", inject_spec },
     { "inject-spec", "xml", inject_spec_xml },
     { "locations-list", "default", locations_list },
     { "locations-list", "xml", locations_list_xml },
     { "node-action", "default", node_action },
     { "node-action", "xml", node_action_xml },
     { "node-info", "default", node_info_default },
     { "node-info", "xml", node_info_xml },
     { "pacemakerd-health", "default", pacemakerd_health },
     { "pacemakerd-health", "html", pacemakerd_health_html },
     { "pacemakerd-health", "text", pacemakerd_health_text },
     { "pacemakerd-health", "xml", pacemakerd_health_xml },
     { "profile", "default", profile_default, },
     { "profile", "xml", profile_xml },
     { "result-code", "none", result_code_none },
     { "result-code", "text", result_code_text },
     { "result-code", "xml", result_code_xml },
     { "rsc-action", "default", rsc_action_default },
     { "rsc-action-item", "default", rsc_action_item },
     { "rsc-action-item", "xml", rsc_action_item_xml },
     { "rsc-is-colocated-with-list", "default", rsc_is_colocated_with_list },
     { "rsc-is-colocated-with-list", "xml", rsc_is_colocated_with_list_xml },
     { "rscs-colocated-with-list", "default", rscs_colocated_with_list },
     { "rscs-colocated-with-list", "xml", rscs_colocated_with_list_xml },
     { "rule-check", "default", rule_check_default },
     { "rule-check", "xml", rule_check_xml },
     { "locations-and-colocations", "default", locations_and_colocations },
     { "locations-and-colocations", "xml", locations_and_colocations_xml },
 
     { NULL, NULL, NULL }
 };
 
 void
 pcmk__register_lib_messages(pcmk__output_t *out) {
     pcmk__register_messages(out, fmt_functions);
 }
diff --git a/lib/pacemaker/pcmk_sched_constraints.c b/lib/pacemaker/pcmk_sched_constraints.c
index 7056cefade..67f226cde6 100644
--- a/lib/pacemaker/pcmk_sched_constraints.c
+++ b/lib/pacemaker/pcmk_sched_constraints.c
@@ -1,426 +1,426 @@
 /*
  * Copyright 2004-2023 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 <sys/types.h>
 #include <stdbool.h>
 #include <regex.h>
 #include <glib.h>
 
 #include <crm/crm.h>
 #include <crm/cib.h>
 #include <crm/msg_xml.h>
 #include <crm/common/xml.h>
 #include <crm/common/xml_internal.h>
 #include <crm/common/iso8601.h>
 #include <crm/pengine/status.h>
 #include <crm/pengine/internal.h>
 #include <crm/pengine/rules.h>
 #include <pacemaker-internal.h>
 #include "libpacemaker_private.h"
 
 static bool
 evaluate_lifetime(xmlNode *lifetime, pe_working_set_t *data_set)
 {
     bool result = FALSE;
     crm_time_t *next_change = crm_time_new_undefined();
 
     result = pe_evaluate_rules(lifetime, NULL, data_set->now, next_change);
     if (crm_time_is_defined(next_change)) {
         time_t recheck = (time_t) crm_time_get_seconds_since_epoch(next_change);
 
         pe__update_recheck_time(recheck, data_set);
     }
     crm_time_free(next_change);
     return result;
 }
 
 /*!
  * \internal
  * \brief Unpack constraints from XML
  *
  * Given a cluster working set, unpack all constraints from its input XML into
  * data structures.
  *
  * \param[in,out] data_set  Cluster working set
  */
 void
 pcmk__unpack_constraints(pe_working_set_t *data_set)
 {
     xmlNode *xml_constraints = pcmk_find_cib_element(data_set->input,
                                                      XML_CIB_TAG_CONSTRAINTS);
 
     for (xmlNode *xml_obj = pcmk__xe_first_child(xml_constraints);
          xml_obj != NULL; xml_obj = pcmk__xe_next(xml_obj)) {
 
         xmlNode *lifetime = NULL;
         const char *id = crm_element_value(xml_obj, XML_ATTR_ID);
         const char *tag = crm_element_name(xml_obj);
 
         if (id == NULL) {
             pcmk__config_err("Ignoring <%s> constraint without "
                              XML_ATTR_ID, tag);
             continue;
         }
 
         crm_trace("Unpacking %s constraint '%s'", tag, id);
 
         lifetime = first_named_child(xml_obj, "lifetime");
         if (lifetime != NULL) {
             pcmk__config_warn("Support for 'lifetime' attribute (in %s) is "
                               "deprecated (the rules it contains should "
                               "instead be direct descendants of the "
                               "constraint object)", id);
         }
 
         if ((lifetime != NULL) && !evaluate_lifetime(lifetime, data_set)) {
             crm_info("Constraint %s %s is not active", tag, id);
 
         } else if (pcmk__str_eq(XML_CONS_TAG_RSC_ORDER, tag, pcmk__str_casei)) {
             pcmk__unpack_ordering(xml_obj, data_set);
 
         } else if (pcmk__str_eq(XML_CONS_TAG_RSC_DEPEND, tag,
                                 pcmk__str_casei)) {
             pcmk__unpack_colocation(xml_obj, data_set);
 
         } else if (pcmk__str_eq(XML_CONS_TAG_RSC_LOCATION, tag,
                                 pcmk__str_casei)) {
             pcmk__unpack_location(xml_obj, data_set);
 
         } else if (pcmk__str_eq(XML_CONS_TAG_RSC_TICKET, tag,
                                 pcmk__str_casei)) {
             pcmk__unpack_rsc_ticket(xml_obj, data_set);
 
         } else {
             pe_err("Unsupported constraint type: %s", tag);
         }
     }
 }
 
 pe_resource_t *
 pcmk__find_constraint_resource(GList *rsc_list, const char *id)
 {
     if (id == NULL) {
         return NULL;
     }
     for (GList *iter = rsc_list; iter != NULL; iter = iter->next) {
         pe_resource_t *parent = iter->data;
         pe_resource_t *match = parent->fns->find_rsc(parent, id, NULL,
                                                      pe_find_renamed);
 
         if (match != NULL) {
-            if(!pcmk__str_eq(match->id, id, pcmk__str_casei)) {
+            if (!pcmk__str_eq(match->id, id, pcmk__str_casei)) {
                 /* We found an instance of a clone instead */
                 match = uber_parent(match);
                 crm_debug("Found %s for %s", match->id, id);
             }
             return match;
         }
     }
     crm_trace("No match for %s", id);
     return NULL;
 }
 
 /*!
  * \internal
  * \brief Check whether an ID references a resource tag
  *
  * \param[in]  data_set  Cluster working set
  * \param[in]  id        Tag ID to search for
  * \param[out] tag       Where to store tag, if found
  *
  * \return true if ID refers to a tagged resource or resource set template,
  *         otherwise false
  */
 static bool
 find_constraint_tag(const pe_working_set_t *data_set, const char *id,
                     pe_tag_t **tag)
 {
     *tag = NULL;
 
     // Check whether id refers to a resource set template
     if (g_hash_table_lookup_extended(data_set->template_rsc_sets, id,
                                      NULL, (gpointer *) tag)) {
         if (*tag == NULL) {
             crm_warn("No resource is derived from template '%s'", id);
             return false;
         }
         return true;
     }
 
     // If not, check whether id refers to a tag
     if (g_hash_table_lookup_extended(data_set->tags, id,
                                      NULL, (gpointer *) tag)) {
         if (*tag == NULL) {
             crm_warn("No resource is tagged with '%s'", id);
             return false;
         }
         return true;
     }
 
     crm_warn("No template or tag named '%s'", id);
     return false;
 }
 
 /*!
  * \brief
  * \internal Check whether an ID refers to a valid resource or tag
  *
  * \param[in]  data_set Cluster working set
  * \param[in]  id       ID to search for
  * \param[out] rsc      Where to store resource, if found (or NULL to skip
  *                      searching resources)
  * \param[out] tag      Where to store tag, if found (or NULL to skip searching
  *                      tags)
  *
  * \return true if id refers to a resource (possibly indirectly via a tag)
  */
 bool
 pcmk__valid_resource_or_tag(const pe_working_set_t *data_set, const char *id,
                             pe_resource_t **rsc, pe_tag_t **tag)
 {
     if (rsc != NULL) {
         *rsc = pcmk__find_constraint_resource(data_set->resources, id);
         if (*rsc != NULL) {
             return true;
         }
     }
 
     if ((tag != NULL) && find_constraint_tag(data_set, id, tag)) {
         return true;
     }
 
     return false;
 }
 
 /*!
  * \internal
  * \brief Replace any resource tags with equivalent resource_ref entries
  *
  * If a given constraint has resource sets, check each set for resource_ref
  * entries that list tags rather than resource IDs, and replace any found with
  * resource_ref entries for the corresponding resource IDs.
  *
  * \param[in,out] xml_obj   Constraint XML
  * \param[in]     data_set  Cluster working set
  *
  * \return Equivalent XML with resource tags replaced (or NULL if none)
  * \note It is the caller's responsibility to free the result with free_xml().
  */
 xmlNode *
 pcmk__expand_tags_in_sets(xmlNode *xml_obj, const pe_working_set_t *data_set)
 {
     xmlNode *new_xml = NULL;
     bool any_refs = false;
 
     // Short-circuit if there are no sets
     if (first_named_child(xml_obj, XML_CONS_TAG_RSC_SET) == NULL) {
         return NULL;
     }
 
     new_xml = copy_xml(xml_obj);
 
     for (xmlNode *set = first_named_child(new_xml, XML_CONS_TAG_RSC_SET);
          set != NULL; set = crm_next_same_xml(set)) {
 
         GList *tag_refs = NULL;
         GList *iter = NULL;
 
         for (xmlNode *xml_rsc = first_named_child(set, XML_TAG_RESOURCE_REF);
              xml_rsc != NULL; xml_rsc = crm_next_same_xml(xml_rsc)) {
 
             pe_resource_t *rsc = NULL;
             pe_tag_t *tag = NULL;
 
             if (!pcmk__valid_resource_or_tag(data_set, ID(xml_rsc), &rsc,
                                              &tag)) {
                 pcmk__config_err("Ignoring resource sets for constraint '%s' "
                                  "because '%s' is not a valid resource or tag",
                                  ID(xml_obj), ID(xml_rsc));
                 free_xml(new_xml);
                 return NULL;
 
             } else if (rsc) {
                 continue;
 
             } else if (tag) {
                 // resource_ref under resource_set references template or tag
                 xmlNode *last_ref = xml_rsc;
 
                 /* For example, given the original XML:
                  *
                  *   <resource_set id="tag1-colocation-0" sequential="true">
                  *     <resource_ref id="rsc1"/>
                  *     <resource_ref id="tag1"/>
                  *     <resource_ref id="rsc4"/>
                  *   </resource_set>
                  *
                  * If rsc2 and rsc3 are tagged with tag1, we add them after it:
                  *
                  *   <resource_set id="tag1-colocation-0" sequential="true">
                  *     <resource_ref id="rsc1"/>
                  *     <resource_ref id="tag1"/>
                  *     <resource_ref id="rsc2"/>
                  *     <resource_ref id="rsc3"/>
                  *     <resource_ref id="rsc4"/>
                  *   </resource_set>
                  */
 
                 for (iter = tag->refs; iter != NULL; iter = iter->next) {
                     const char *obj_ref = iter->data;
                     xmlNode *new_rsc_ref = NULL;
 
                     new_rsc_ref = xmlNewDocRawNode(getDocPtr(set), NULL,
                                                    (pcmkXmlStr)
                                                    XML_TAG_RESOURCE_REF,
                                                    NULL);
                     crm_xml_add(new_rsc_ref, XML_ATTR_ID, obj_ref);
                     xmlAddNextSibling(last_ref, new_rsc_ref);
 
                     last_ref = new_rsc_ref;
                 }
 
                 any_refs = true;
 
                 /* Freeing the resource_ref now would break the XML child
                  * iteration, so just remember it for freeing later.
                  */
                 tag_refs = g_list_append(tag_refs, xml_rsc);
             }
         }
 
         /* Now free '<resource_ref id="tag1"/>', and finally get:
 
            <resource_set id="tag1-colocation-0" sequential="true">
              <resource_ref id="rsc1"/>
              <resource_ref id="rsc2"/>
              <resource_ref id="rsc3"/>
              <resource_ref id="rsc4"/>
            </resource_set>
 
          */
         for (iter = tag_refs; iter != NULL; iter = iter->next) {
             xmlNode *tag_ref = iter->data;
 
             free_xml(tag_ref);
         }
         g_list_free(tag_refs);
     }
 
     if (!any_refs) {
         free_xml(new_xml);
         new_xml = NULL;
     }
     return new_xml;
 }
 
 /*!
  * \internal
  * \brief Convert a tag into a resource set of tagged resources
  *
  * \param[in,out] xml_obj      Constraint XML
  * \param[out]    rsc_set      Where to store resource set XML
  * \param[in]     attr         Name of XML attribute with resource or tag ID
  * \param[in]     convert_rsc  If true, convert to set even if \p attr
  *                             references a resource
  * \param[in]     data_set     Cluster working set
  */
 bool
 pcmk__tag_to_set(xmlNode *xml_obj, xmlNode **rsc_set, const char *attr,
                  bool convert_rsc, const pe_working_set_t *data_set)
 {
     const char *cons_id = NULL;
     const char *id = NULL;
 
     pe_resource_t *rsc = NULL;
     pe_tag_t *tag = NULL;
 
     *rsc_set = NULL;
 
     CRM_CHECK((xml_obj != NULL) && (attr != NULL), return false);
 
     cons_id = ID(xml_obj);
     if (cons_id == NULL) {
         pcmk__config_err("Ignoring <%s> constraint without " XML_ATTR_ID,
                          crm_element_name(xml_obj));
         return false;
     }
 
     id = crm_element_value(xml_obj, attr);
     if (id == NULL) {
         return true;
     }
 
     if (!pcmk__valid_resource_or_tag(data_set, id, &rsc, &tag)) {
         pcmk__config_err("Ignoring constraint '%s' because '%s' is not a "
                          "valid resource or tag", cons_id, id);
         return false;
 
     } else if (tag) {
         /* The "attr" attribute (for a resource in a constraint) specifies a
          * template or tag. Add the corresponding resource_set containing the
          * resources derived from or tagged with it.
          */
         *rsc_set = create_xml_node(xml_obj, XML_CONS_TAG_RSC_SET);
         crm_xml_add(*rsc_set, XML_ATTR_ID, id);
 
         for (GList *iter = tag->refs; iter != NULL; iter = iter->next) {
             const char *obj_ref = iter->data;
             xmlNode *rsc_ref = NULL;
 
             rsc_ref = create_xml_node(*rsc_set, XML_TAG_RESOURCE_REF);
             crm_xml_add(rsc_ref, XML_ATTR_ID, obj_ref);
         }
 
         /* Set sequential="false" for the resource_set */
         pcmk__xe_set_bool_attr(*rsc_set, "sequential", false);
 
     } else if ((rsc != NULL) && convert_rsc) {
         /* Even if a regular resource is referenced by "attr", convert it into a
          * resource_set, because the other resource reference in the constraint
          * could be a template or tag.
          */
         xmlNode *rsc_ref = NULL;
 
         *rsc_set = create_xml_node(xml_obj, XML_CONS_TAG_RSC_SET);
         crm_xml_add(*rsc_set, XML_ATTR_ID, id);
 
         rsc_ref = create_xml_node(*rsc_set, XML_TAG_RESOURCE_REF);
         crm_xml_add(rsc_ref, XML_ATTR_ID, id);
 
     } else {
         return true;
     }
 
     /* Remove the "attr" attribute referencing the template/tag */
     if (*rsc_set != NULL) {
         xml_remove_prop(xml_obj, attr);
     }
 
     return true;
 }
 
 /*!
  * \internal
  * \brief Create constraints inherent to resource types
  *
  * \param[in,out] data_set  Cluster working set
  */
 void
 pcmk__create_internal_constraints(pe_working_set_t *data_set)
 {
     crm_trace("Create internal constraints");
     for (GList *iter = data_set->resources; iter != NULL; iter = iter->next) {
         pe_resource_t *rsc = (pe_resource_t *) iter->data;
 
         rsc->cmds->internal_constraints(rsc);
     }
 }
diff --git a/lib/pacemaker/pcmk_sched_location.c b/lib/pacemaker/pcmk_sched_location.c
index 89b913c9b9..01bf5d8bd6 100644
--- a/lib/pacemaker/pcmk_sched_location.c
+++ b/lib/pacemaker/pcmk_sched_location.c
@@ -1,672 +1,672 @@
 /*
  * Copyright 2004-2023 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 <stdbool.h>
 #include <glib.h>
 
 #include <crm/crm.h>
 #include <crm/pengine/status.h>
 #include <crm/pengine/rules.h>
 #include <pacemaker-internal.h>
 
 #include "libpacemaker_private.h"
 
 static int
 get_node_score(const char *rule, const char *score, bool raw,
                pe_node_t *node, pe_resource_t *rsc)
 {
     int score_f = 0;
 
     if (score == NULL) {
         pe_err("Rule %s: no score specified.  Assuming 0.", rule);
 
     } else if (raw) {
         score_f = char2score(score);
 
     } else {
         const char *attr_score = NULL;
 
         attr_score = pe_node_attribute_calculated(node, score, rsc,
                                                   pe__rsc_node_current);
 
         if (attr_score == NULL) {
             crm_debug("Rule %s: %s did not have a value for %s",
                       rule, pe__node_name(node), score);
             score_f = -INFINITY;
 
         } else {
             crm_debug("Rule %s: %s had value %s for %s",
                       rule, pe__node_name(node), attr_score, score);
             score_f = char2score(attr_score);
         }
     }
     return score_f;
 }
 
 static pe__location_t *
 generate_location_rule(pe_resource_t *rsc, xmlNode *rule_xml,
                        const char *discovery, crm_time_t *next_change,
                        pe_re_match_data_t *re_match_data)
 {
     const char *rule_id = NULL;
     const char *score = NULL;
     const char *boolean = NULL;
     const char *role = NULL;
 
     GList *iter = NULL;
     GList *nodes = NULL;
 
     bool do_and = true;
     bool accept = true;
     bool raw_score = true;
     bool score_allocated = false;
 
     pe__location_t *location_rule = NULL;
 
     rule_xml = expand_idref(rule_xml, rsc->cluster->input);
     if (rule_xml == NULL) {
         return NULL;
     }
 
     rule_id = crm_element_value(rule_xml, XML_ATTR_ID);
     boolean = crm_element_value(rule_xml, XML_RULE_ATTR_BOOLEAN_OP);
     role = crm_element_value(rule_xml, XML_RULE_ATTR_ROLE);
 
     crm_trace("Processing rule: %s", rule_id);
 
     if ((role != NULL) && (text2role(role) == RSC_ROLE_UNKNOWN)) {
         pe_err("Bad role specified for %s: %s", rule_id, role);
         return NULL;
     }
 
     score = crm_element_value(rule_xml, XML_RULE_ATTR_SCORE);
     if (score == NULL) {
         score = crm_element_value(rule_xml, XML_RULE_ATTR_SCORE_ATTRIBUTE);
         if (score != NULL) {
             raw_score = false;
         }
     }
     if (pcmk__str_eq(boolean, "or", pcmk__str_casei)) {
         do_and = false;
     }
 
     location_rule = pcmk__new_location(rule_id, rsc, 0, discovery, NULL);
 
     if (location_rule == NULL) {
         return NULL;
     }
 
     if ((re_match_data != NULL) && (re_match_data->nregs > 0)
         && (re_match_data->pmatch[0].rm_so != -1) && !raw_score) {
 
         char *result = pe_expand_re_matches(score, re_match_data);
 
         if (result != NULL) {
             score = result;
             score_allocated = true;
         }
     }
 
     if (role != NULL) {
         crm_trace("Setting role filter: %s", role);
         location_rule->role_filter = text2role(role);
         if (location_rule->role_filter == RSC_ROLE_UNPROMOTED) {
             /* Any promotable clone cannot be promoted without being in the
              * unpromoted role first. Ergo, any constraint for the unpromoted
              * role applies to every role.
              */
             location_rule->role_filter = RSC_ROLE_UNKNOWN;
         }
     }
     if (do_and) {
         nodes = pcmk__copy_node_list(rsc->cluster->nodes, true);
         for (iter = nodes; iter != NULL; iter = iter->next) {
             pe_node_t *node = iter->data;
 
             node->weight = get_node_score(rule_id, score, raw_score, node, rsc);
         }
     }
 
     for (iter = rsc->cluster->nodes; iter != NULL; iter = iter->next) {
         int score_f = 0;
         pe_node_t *node = iter->data;
         pe_match_data_t match_data = {
             .re = re_match_data,
             .params = pe_rsc_params(rsc, node, rsc->cluster),
             .meta = rsc->meta,
         };
 
         accept = pe_test_rule(rule_xml, node->details->attrs, RSC_ROLE_UNKNOWN,
                               rsc->cluster->now, next_change, &match_data);
 
         crm_trace("Rule %s %s on %s", ID(rule_xml), accept? "passed" : "failed",
                   pe__node_name(node));
 
         score_f = get_node_score(rule_id, score, raw_score, node, rsc);
 
         if (accept) {
             pe_node_t *local = pe_find_node_id(nodes, node->details->id);
 
             if ((local == NULL) && do_and) {
                 continue;
 
             } else if (local == NULL) {
                 local = pe__copy_node(node);
                 nodes = g_list_append(nodes, local);
             }
 
             if (!do_and) {
                 local->weight = pcmk__add_scores(local->weight, score_f);
             }
             crm_trace("%s has score %s after %s", pe__node_name(node),
                       pcmk_readable_score(local->weight), rule_id);
 
         } else if (do_and && !accept) {
             // Remove it
             pe_node_t *delete = pe_find_node_id(nodes, node->details->id);
 
             if (delete != NULL) {
                 nodes = g_list_remove(nodes, delete);
                 crm_trace("%s did not match", pe__node_name(node));
             }
             free(delete);
         }
     }
 
     if (score_allocated) {
         free((char *)score);
     }
 
     location_rule->node_list_rh = nodes;
     if (location_rule->node_list_rh == NULL) {
         crm_trace("No matching nodes for rule %s", rule_id);
         return NULL;
     }
 
     crm_trace("%s: %d nodes matched",
               rule_id, g_list_length(location_rule->node_list_rh));
     return location_rule;
 }
 
 static void
 unpack_rsc_location(xmlNode *xml_obj, pe_resource_t *rsc, const char *role,
                     const char *score, pe_re_match_data_t *re_match_data)
 {
     pe__location_t *location = NULL;
     const char *rsc_id = crm_element_value(xml_obj, XML_LOC_ATTR_SOURCE);
     const char *id = crm_element_value(xml_obj, XML_ATTR_ID);
     const char *node = crm_element_value(xml_obj, XML_CIB_TAG_NODE);
     const char *discovery = crm_element_value(xml_obj,
                                               XML_LOCATION_ATTR_DISCOVERY);
 
     if (rsc == NULL) {
         pcmk__config_warn("Ignoring constraint '%s' because resource '%s' "
                           "does not exist", id, rsc_id);
         return;
     }
 
     if (score == NULL) {
         score = crm_element_value(xml_obj, XML_RULE_ATTR_SCORE);
     }
 
     if ((node != NULL) && (score != NULL)) {
         int score_i = char2score(score);
         pe_node_t *match = pe_find_node(rsc->cluster->nodes, node);
 
         if (!match) {
             return;
         }
         location = pcmk__new_location(id, rsc, score_i, discovery, match);
 
     } else {
         bool empty = true;
         crm_time_t *next_change = crm_time_new_undefined();
 
         /* This loop is logically parallel to pe_evaluate_rules(), except
          * instead of checking whether any rule is active, we set up location
          * constraints for each active rule.
          */
         for (xmlNode *rule_xml = first_named_child(xml_obj, XML_TAG_RULE);
              rule_xml != NULL; rule_xml = crm_next_same_xml(rule_xml)) {
             empty = false;
             crm_trace("Unpacking %s/%s", id, ID(rule_xml));
             generate_location_rule(rsc, rule_xml, discovery, next_change,
                                    re_match_data);
         }
 
         if (empty) {
             pcmk__config_err("Ignoring constraint '%s' because it contains "
                              "no rules", id);
         }
 
         /* If there is a point in the future when the evaluation of a rule will
          * change, make sure the scheduler is re-run by that time.
          */
         if (crm_time_is_defined(next_change)) {
             time_t t = (time_t) crm_time_get_seconds_since_epoch(next_change);
 
             pe__update_recheck_time(t, rsc->cluster);
         }
         crm_time_free(next_change);
         return;
     }
 
     if (role == NULL) {
         role = crm_element_value(xml_obj, XML_RULE_ATTR_ROLE);
     }
 
     if ((location != NULL) && (role != NULL)) {
         if (text2role(role) == RSC_ROLE_UNKNOWN) {
             pe_err("Invalid constraint %s: Bad role %s", id, role);
             return;
 
         } else {
             enum rsc_role_e r = text2role(role);
-            switch(r) {
+            switch (r) {
                 case RSC_ROLE_UNKNOWN:
                 case RSC_ROLE_STARTED:
                 case RSC_ROLE_UNPROMOTED:
                     /* Applies to all */
                     location->role_filter = RSC_ROLE_UNKNOWN;
                     break;
                 default:
                     location->role_filter = r;
                     break;
             }
         }
     }
 }
 
 static void
 unpack_simple_location(xmlNode *xml_obj, pe_working_set_t *data_set)
 {
     const char *id = crm_element_value(xml_obj, XML_ATTR_ID);
     const char *value = crm_element_value(xml_obj, XML_LOC_ATTR_SOURCE);
 
     if (value) {
         pe_resource_t *rsc;
 
         rsc = pcmk__find_constraint_resource(data_set->resources, value);
         unpack_rsc_location(xml_obj, rsc, NULL, NULL, NULL);
     }
 
     value = crm_element_value(xml_obj, XML_LOC_ATTR_SOURCE_PATTERN);
     if (value) {
         regex_t *r_patt = calloc(1, sizeof(regex_t));
         bool invert = false;
 
         if (value[0] == '!') {
             value++;
             invert = true;
         }
 
         if (regcomp(r_patt, value, REG_EXTENDED) != 0) {
             pcmk__config_err("Ignoring constraint '%s' because "
                              XML_LOC_ATTR_SOURCE_PATTERN
                              " has invalid value '%s'", id, value);
             free(r_patt);
             return;
         }
 
         for (GList *iter = data_set->resources; iter; iter = iter->next) {
             pe_resource_t *r = iter->data;
             int nregs = 0;
             regmatch_t *pmatch = NULL;
             int status;
 
-            if(r_patt->re_nsub > 0) {
+            if (r_patt->re_nsub > 0) {
                 nregs = r_patt->re_nsub + 1;
             } else {
                 nregs = 1;
             }
             pmatch = calloc(nregs, sizeof(regmatch_t));
 
             status = regexec(r_patt, r->id, nregs, pmatch, 0);
 
             if (!invert && (status == 0)) {
                 pe_re_match_data_t re_match_data = {
                                                 .string = r->id,
                                                 .nregs = nregs,
                                                 .pmatch = pmatch
                                                };
 
                 crm_debug("'%s' matched '%s' for %s", r->id, value, id);
                 unpack_rsc_location(xml_obj, r, NULL, NULL, &re_match_data);
 
             } else if (invert && (status != 0)) {
                 crm_debug("'%s' is an inverted match of '%s' for %s",
                           r->id, value, id);
                 unpack_rsc_location(xml_obj, r, NULL, NULL, NULL);
 
             } else {
                 crm_trace("'%s' does not match '%s' for %s", r->id, value, id);
             }
 
             free(pmatch);
         }
 
         regfree(r_patt);
         free(r_patt);
     }
 }
 
 // \return Standard Pacemaker return code
 static int
 unpack_location_tags(xmlNode *xml_obj, xmlNode **expanded_xml,
                      pe_working_set_t *data_set)
 {
     const char *id = NULL;
     const char *rsc_id = NULL;
     const char *state = NULL;
     pe_resource_t *rsc = NULL;
     pe_tag_t *tag = NULL;
     xmlNode *rsc_set = NULL;
 
     *expanded_xml = NULL;
 
     CRM_CHECK(xml_obj != NULL, return EINVAL);
 
     id = ID(xml_obj);
     if (id == NULL) {
         pcmk__config_err("Ignoring <%s> constraint without " XML_ATTR_ID,
                          crm_element_name(xml_obj));
         return pcmk_rc_unpack_error;
     }
 
     // Check whether there are any resource sets with template or tag references
     *expanded_xml = pcmk__expand_tags_in_sets(xml_obj, data_set);
     if (*expanded_xml != NULL) {
         crm_log_xml_trace(*expanded_xml, "Expanded rsc_location");
         return pcmk_rc_ok;
     }
 
     rsc_id = crm_element_value(xml_obj, XML_LOC_ATTR_SOURCE);
     if (rsc_id == NULL) {
         return pcmk_rc_ok;
     }
 
     if (!pcmk__valid_resource_or_tag(data_set, rsc_id, &rsc, &tag)) {
         pcmk__config_err("Ignoring constraint '%s' because '%s' is not a "
                          "valid resource or tag", id, rsc_id);
         return pcmk_rc_unpack_error;
 
     } else if (rsc != NULL) {
         // No template is referenced
         return pcmk_rc_ok;
     }
 
     state = crm_element_value(xml_obj, XML_RULE_ATTR_ROLE);
 
     *expanded_xml = copy_xml(xml_obj);
 
     // Convert any template or tag reference into constraint resource_set
     if (!pcmk__tag_to_set(*expanded_xml, &rsc_set, XML_LOC_ATTR_SOURCE,
                           false, data_set)) {
         free_xml(*expanded_xml);
         *expanded_xml = NULL;
         return pcmk_rc_unpack_error;
     }
 
     if (rsc_set != NULL) {
         if (state != NULL) {
             // Move "rsc-role" into converted resource_set as "role" attribute
             crm_xml_add(rsc_set, "role", state);
             xml_remove_prop(*expanded_xml, XML_RULE_ATTR_ROLE);
         }
         crm_log_xml_trace(*expanded_xml, "Expanded rsc_location");
 
     } else {
         // No sets
         free_xml(*expanded_xml);
         *expanded_xml = NULL;
     }
 
     return pcmk_rc_ok;
 }
 
 // \return Standard Pacemaker return code
 static int
 unpack_location_set(xmlNode *location, xmlNode *set, pe_working_set_t *data_set)
 {
     xmlNode *xml_rsc = NULL;
     pe_resource_t *resource = NULL;
     const char *set_id;
     const char *role;
     const char *local_score;
 
     CRM_CHECK(set != NULL, return EINVAL);
 
     set_id = ID(set);
     if (set_id == NULL) {
         pcmk__config_err("Ignoring " XML_CONS_TAG_RSC_SET " without "
                          XML_ATTR_ID " in constraint '%s'",
                          pcmk__s(ID(location), "(missing ID)"));
         return pcmk_rc_unpack_error;
     }
 
     role = crm_element_value(set, "role");
     local_score = crm_element_value(set, XML_RULE_ATTR_SCORE);
 
     for (xml_rsc = first_named_child(set, XML_TAG_RESOURCE_REF);
          xml_rsc != NULL; xml_rsc = crm_next_same_xml(xml_rsc)) {
 
         resource = pcmk__find_constraint_resource(data_set->resources,
                                                   ID(xml_rsc));
         if (resource == NULL) {
             pcmk__config_err("%s: No resource found for %s",
                              set_id, ID(xml_rsc));
             return pcmk_rc_unpack_error;
         }
 
         unpack_rsc_location(location, resource, role, local_score, NULL);
     }
 
     return pcmk_rc_ok;
 }
 
 void
 pcmk__unpack_location(xmlNode *xml_obj, pe_working_set_t *data_set)
 {
     xmlNode *set = NULL;
     bool any_sets = false;
 
     xmlNode *orig_xml = NULL;
     xmlNode *expanded_xml = NULL;
 
     if (unpack_location_tags(xml_obj, &expanded_xml, data_set) != pcmk_rc_ok) {
         return;
     }
 
     if (expanded_xml) {
         orig_xml = xml_obj;
         xml_obj = expanded_xml;
     }
 
     for (set = first_named_child(xml_obj, XML_CONS_TAG_RSC_SET); set != NULL;
          set = crm_next_same_xml(set)) {
 
         any_sets = true;
         set = expand_idref(set, data_set->input);
         if ((set == NULL) // Configuration error, message already logged
             || (unpack_location_set(xml_obj, set, data_set) != pcmk_rc_ok)) {
 
             if (expanded_xml) {
                 free_xml(expanded_xml);
             }
             return;
         }
     }
 
     if (expanded_xml) {
         free_xml(expanded_xml);
         xml_obj = orig_xml;
     }
 
     if (!any_sets) {
         unpack_simple_location(xml_obj, data_set);
     }
 }
 
 /*!
  * \internal
  * \brief Add a new location constraint to a cluster working set
  *
  * \param[in]     id             XML ID of location constraint
  * \param[in,out] rsc            Resource in location constraint
  * \param[in]     node_score     Constraint score
  * \param[in]     discover_mode  Resource discovery option for constraint
  * \param[in]     node           Node in constraint (or NULL if rule-based)
  *
  * \return Newly allocated location constraint
  * \note The result will be added to the cluster (via \p rsc) and should not be
  *       freed separately.
  */
 pe__location_t *
 pcmk__new_location(const char *id, pe_resource_t *rsc,
                    int node_score, const char *discover_mode, pe_node_t *node)
 {
     pe__location_t *new_con = NULL;
 
     if (id == NULL) {
         pe_err("Invalid constraint: no ID specified");
         return NULL;
 
     } else if (rsc == NULL) {
         pe_err("Invalid constraint %s: no resource specified", id);
         return NULL;
 
     } else if (node == NULL) {
         CRM_CHECK(node_score == 0, return NULL);
     }
 
     new_con = calloc(1, sizeof(pe__location_t));
     if (new_con != NULL) {
         new_con->id = strdup(id);
         new_con->rsc_lh = rsc;
         new_con->node_list_rh = NULL;
         new_con->role_filter = RSC_ROLE_UNKNOWN;
 
         if (pcmk__str_eq(discover_mode, "always",
                          pcmk__str_null_matches|pcmk__str_casei)) {
             new_con->discover_mode = pe_discover_always;
 
         } else if (pcmk__str_eq(discover_mode, "never", pcmk__str_casei)) {
             new_con->discover_mode = pe_discover_never;
 
         } else if (pcmk__str_eq(discover_mode, "exclusive", pcmk__str_casei)) {
             new_con->discover_mode = pe_discover_exclusive;
             rsc->exclusive_discover = TRUE;
 
         } else {
             pe_err("Invalid " XML_LOCATION_ATTR_DISCOVERY " value %s "
                    "in location constraint", discover_mode);
         }
 
         if (node != NULL) {
             pe_node_t *copy = pe__copy_node(node);
 
             copy->weight = node_score;
             new_con->node_list_rh = g_list_prepend(NULL, copy);
         }
 
         rsc->cluster->placement_constraints = g_list_prepend(
             rsc->cluster->placement_constraints, new_con);
         rsc->rsc_location = g_list_prepend(rsc->rsc_location, new_con);
     }
 
     return new_con;
 }
 
 /*!
  * \internal
  * \brief Apply all location constraints
  *
  * \param[in,out] data_set       Cluster working set
  */
 void
 pcmk__apply_locations(pe_working_set_t *data_set)
 {
     for (GList *iter = data_set->placement_constraints;
          iter != NULL; iter = iter->next) {
         pe__location_t *location = iter->data;
 
         location->rsc_lh->cmds->apply_location(location->rsc_lh, location);
     }
 }
 
 /*!
  * \internal
  * \brief Apply a location constraint to a resource's allowed node scores
  *
  * \param[in,out] rsc         Resource to apply constraint to
  * \param[in,out] location    Location constraint to apply
  *
  * \note This does not consider the resource's children, so the resource's
  *       apply_location() method should be used instead in most cases.
  */
 void
 pcmk__apply_location(pe_resource_t *rsc, pe__location_t *location)
 {
     bool need_role = false;
 
     CRM_CHECK((rsc != NULL) && (location != NULL), return);
 
     // If a role was specified, ensure constraint is applicable
     need_role = (location->role_filter > RSC_ROLE_UNKNOWN);
     if (need_role && (location->role_filter != rsc->next_role)) {
         pe_rsc_trace(rsc,
                      "Not applying %s to %s because role will be %s not %s",
                      location->id, rsc->id, role2text(rsc->next_role),
                      role2text(location->role_filter));
         return;
     }
 
     if (location->node_list_rh == NULL) {
         pe_rsc_trace(rsc, "Not applying %s to %s because no nodes match",
                      location->id, rsc->id);
         return;
     }
 
     pe_rsc_trace(rsc, "Applying %s%s%s to %s", location->id,
                  (need_role? " for role " : ""),
                  (need_role? role2text(location->role_filter) : ""), rsc->id);
 
     for (GList *iter = location->node_list_rh;
          iter != NULL; iter = iter->next) {
 
         pe_node_t *node = iter->data;
         pe_node_t *allowed_node = NULL;
 
         allowed_node = (pe_node_t *) pe_hash_table_lookup(rsc->allowed_nodes,
                                                           node->details->id);
         if (allowed_node == NULL) {
             pe_rsc_trace(rsc, "* = %d on %s",
                          node->weight, pe__node_name(node));
             allowed_node = pe__copy_node(node);
             g_hash_table_insert(rsc->allowed_nodes,
                                 (gpointer) allowed_node->details->id,
                                 allowed_node);
         } else {
             pe_rsc_trace(rsc, "* + %d on %s",
                          node->weight, pe__node_name(node));
             allowed_node->weight = pcmk__add_scores(allowed_node->weight,
                                                     node->weight);
         }
 
         if (allowed_node->rsc_discover_mode < location->discover_mode) {
             if (location->discover_mode == pe_discover_exclusive) {
                 rsc->exclusive_discover = TRUE;
             }
             /* exclusive > never > always... always is default */
             allowed_node->rsc_discover_mode = location->discover_mode;
         }
     }
 }
diff --git a/lib/pacemaker/pcmk_sched_remote.c b/lib/pacemaker/pcmk_sched_remote.c
index a8ce39ea06..b94b97047b 100644
--- a/lib/pacemaker/pcmk_sched_remote.c
+++ b/lib/pacemaker/pcmk_sched_remote.c
@@ -1,721 +1,721 @@
 /*
  * Copyright 2004-2023 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 <crm/common/xml_internal.h>
 
 #include <glib.h>
 
 #include <crm/pengine/status.h>
 #include <pacemaker-internal.h>
 #include "libpacemaker_private.h"
 
 enum remote_connection_state {
     remote_state_unknown = 0,
     remote_state_alive = 1,
     remote_state_resting = 2,
     remote_state_failed = 3,
     remote_state_stopped = 4
 };
 
 static const char *
 state2text(enum remote_connection_state state)
 {
     switch (state) {
         case remote_state_unknown:
             return "unknown";
         case remote_state_alive:
             return "alive";
         case remote_state_resting:
             return "resting";
         case remote_state_failed:
             return "failed";
         case remote_state_stopped:
             return "stopped";
     }
 
     return "impossible";
 }
 
 /* We always use pe_order_preserve with these convenience functions to exempt
  * internally generated constraints from the prohibition of user constraints
  * involving remote connection resources.
  *
  * The start ordering additionally uses pe_order_runnable_left so that the
  * specified action is not runnable if the start is not runnable.
  */
 
 static inline void
 order_start_then_action(pe_resource_t *first_rsc, pe_action_t *then_action,
                         uint32_t extra)
 {
     if ((first_rsc != NULL) && (then_action != NULL)) {
         pcmk__new_ordering(first_rsc, start_key(first_rsc), NULL,
                            then_action->rsc, NULL, then_action,
                            pe_order_preserve|pe_order_runnable_left|extra,
                            first_rsc->cluster);
     }
 }
 
 static inline void
 order_action_then_stop(pe_action_t *first_action, pe_resource_t *then_rsc,
                        uint32_t extra)
 {
     if ((first_action != NULL) && (then_rsc != NULL)) {
         pcmk__new_ordering(first_action->rsc, NULL, first_action,
                            then_rsc, stop_key(then_rsc), NULL,
                            pe_order_preserve|extra, then_rsc->cluster);
     }
 }
 
 static enum remote_connection_state
 get_remote_node_state(const pe_node_t *node)
 {
     const pe_resource_t *remote_rsc = NULL;
     const pe_node_t *cluster_node = NULL;
 
     CRM_ASSERT(node != NULL);
 
     remote_rsc = node->details->remote_rsc;
     CRM_ASSERT(remote_rsc != NULL);
 
     cluster_node = pe__current_node(remote_rsc);
 
     /* If the cluster node the remote connection resource resides on
      * is unclean or went offline, we can't process any operations
      * on that remote node until after it starts elsewhere.
      */
     if ((remote_rsc->next_role == RSC_ROLE_STOPPED)
         || (remote_rsc->allocated_to == NULL)) {
 
         // The connection resource is not going to run anywhere
 
         if ((cluster_node != NULL) && cluster_node->details->unclean) {
             /* The remote connection is failed because its resource is on a
              * failed node and can't be recovered elsewhere, so we must fence.
              */
             return remote_state_failed;
         }
 
         if (!pcmk_is_set(remote_rsc->flags, pe_rsc_failed)) {
             /* Connection resource is cleanly stopped */
             return remote_state_stopped;
         }
 
         /* Connection resource is failed */
 
         if ((remote_rsc->next_role == RSC_ROLE_STOPPED)
             && remote_rsc->remote_reconnect_ms
             && node->details->remote_was_fenced
             && !pe__shutdown_requested(node)) {
 
             /* We won't know whether the connection is recoverable until the
              * reconnect interval expires and we reattempt connection.
              */
             return remote_state_unknown;
         }
 
         /* The remote connection is in a failed state. If there are any
          * resources known to be active on it (stop) or in an unknown state
          * (probe), we must assume the worst and fence it.
          */
         return remote_state_failed;
 
     } else if (cluster_node == NULL) {
         /* Connection is recoverable but not currently running anywhere, so see
          * if we can recover it first
          */
         return remote_state_unknown;
 
     } else if (cluster_node->details->unclean
                || !(cluster_node->details->online)) {
         // Connection is running on a dead node, see if we can recover it first
         return remote_state_resting;
 
     } else if (pcmk__list_of_multiple(remote_rsc->running_on)
                && (remote_rsc->partial_migration_source != NULL)
                && (remote_rsc->partial_migration_target != NULL)) {
         /* We're in the middle of migrating a connection resource, so wait until
          * after the migration completes before performing any actions.
          */
         return remote_state_resting;
 
     }
     return remote_state_alive;
 }
 
 /*!
  * \internal
  * \brief Order actions on remote node relative to actions for the connection
  *
  * \param[in,out] action    An action scheduled on a Pacemaker Remote node
  */
 static void
 apply_remote_ordering(pe_action_t *action)
 {
     pe_resource_t *remote_rsc = NULL;
     enum action_tasks task = text2task(action->task);
     enum remote_connection_state state = get_remote_node_state(action->node);
 
     uint32_t order_opts = pe_order_none;
 
     if (action->rsc == NULL) {
         return;
     }
 
     CRM_ASSERT(pe__is_guest_or_remote_node(action->node));
 
     remote_rsc = action->node->details->remote_rsc;
     CRM_ASSERT(remote_rsc != NULL);
 
     crm_trace("Order %s action %s relative to %s%s (state: %s)",
               action->task, action->uuid,
               pcmk_is_set(remote_rsc->flags, pe_rsc_failed)? "failed " : "",
               remote_rsc->id, state2text(state));
 
     if (pcmk__strcase_any_of(action->task, CRMD_ACTION_MIGRATE,
                              CRMD_ACTION_MIGRATED, NULL)) {
         /* Migration ops map to "no_action", but we need to apply the same
          * ordering as for stop or demote (see get_router_node()).
          */
         task = stop_rsc;
     }
 
     switch (task) {
         case start_rsc:
         case action_promote:
             order_opts = pe_order_none;
 
             if (state == remote_state_failed) {
                 /* Force recovery, by making this action required */
                 pe__set_order_flags(order_opts, pe_order_implies_then);
             }
 
             /* Ensure connection is up before running this action */
             order_start_then_action(remote_rsc, action, order_opts);
             break;
 
         case stop_rsc:
             if (state == remote_state_alive) {
                 order_action_then_stop(action, remote_rsc,
                                        pe_order_implies_first);
 
             } else if (state == remote_state_failed) {
                 /* The resource is active on the node, but since we don't have a
                  * valid connection, the only way to stop the resource is by
                  * fencing the node. There is no need to order the stop relative
                  * to the remote connection, since the stop will become implied
                  * by the fencing.
                  */
                 pe_fence_node(remote_rsc->cluster, action->node,
                               "resources are active but "
                               "connection is unrecoverable",
                               FALSE);
 
             } else if (remote_rsc->next_role == RSC_ROLE_STOPPED) {
                 /* State must be remote_state_unknown or remote_state_stopped.
                  * Since the connection is not coming back up in this
                  * transition, stop this resource first.
                  */
                 order_action_then_stop(action, remote_rsc,
                                        pe_order_implies_first);
 
             } else {
                 /* The connection is going to be started somewhere else, so
                  * stop this resource after that completes.
                  */
                 order_start_then_action(remote_rsc, action, pe_order_none);
             }
             break;
 
         case action_demote:
             /* Only order this demote relative to the connection start if the
              * connection isn't being torn down. Otherwise, the demote would be
              * blocked because the connection start would not be allowed.
              */
             if ((state == remote_state_resting)
                 || (state == remote_state_unknown)) {
 
                 order_start_then_action(remote_rsc, action, pe_order_none);
             } /* Otherwise we can rely on the stop ordering */
             break;
 
         default:
             /* Wait for the connection resource to be up */
             if (pcmk__action_is_recurring(action)) {
                 /* In case we ever get the recovery logic wrong, force
                  * recurring monitors to be restarted, even if just
                  * the connection was re-established
                  */
                 order_start_then_action(remote_rsc, action,
                                         pe_order_implies_then);
 
             } else {
                 pe_node_t *cluster_node = pe__current_node(remote_rsc);
 
                 if ((task == monitor_rsc) && (state == remote_state_failed)) {
                     /* We would only be here if we do not know the state of the
                      * resource on the remote node. Since we have no way to find
                      * out, it is necessary to fence the node.
                      */
                     pe_fence_node(remote_rsc->cluster, action->node,
                                   "resources are in unknown state "
                                   "and connection is unrecoverable", FALSE);
                 }
 
                 if ((cluster_node != NULL) && (state == remote_state_stopped)) {
                     /* The connection is currently up, but is going down
                      * permanently. Make sure we check services are actually
                      * stopped _before_ we let the connection get closed.
                      */
                     order_action_then_stop(action, remote_rsc,
                                            pe_order_runnable_left);
 
                 } else {
                     order_start_then_action(remote_rsc, action, pe_order_none);
                 }
             }
             break;
     }
 }
 
 static void
 apply_container_ordering(pe_action_t *action)
 {
     /* VMs are also classified as containers for these purposes... in
      * that they both involve a 'thing' running on a real or remote
      * cluster node.
      *
      * This allows us to be smarter about the type and extent of
      * recovery actions required in various scenarios
      */
     pe_resource_t *remote_rsc = NULL;
     pe_resource_t *container = NULL;
     enum action_tasks task = text2task(action->task);
 
     CRM_ASSERT(action->rsc != NULL);
     CRM_ASSERT(action->node != NULL);
     CRM_ASSERT(pe__is_guest_or_remote_node(action->node));
 
     remote_rsc = action->node->details->remote_rsc;
     CRM_ASSERT(remote_rsc != NULL);
 
     container = remote_rsc->container;
     CRM_ASSERT(container != NULL);
 
     if (pcmk_is_set(container->flags, pe_rsc_failed)) {
         pe_fence_node(action->rsc->cluster, action->node, "container failed",
                       FALSE);
     }
 
     crm_trace("Order %s action %s relative to %s%s for %s%s",
               action->task, action->uuid,
               pcmk_is_set(remote_rsc->flags, pe_rsc_failed)? "failed " : "",
               remote_rsc->id,
               pcmk_is_set(container->flags, pe_rsc_failed)? "failed " : "",
               container->id);
 
     if (pcmk__strcase_any_of(action->task, CRMD_ACTION_MIGRATE,
                              CRMD_ACTION_MIGRATED, NULL)) {
         /* Migration ops map to "no_action", but we need to apply the same
          * ordering as for stop or demote (see get_router_node()).
          */
         task = stop_rsc;
     }
 
     switch (task) {
         case start_rsc:
         case action_promote:
             // Force resource recovery if the container is recovered
             order_start_then_action(container, action, pe_order_implies_then);
 
             // Wait for the connection resource to be up, too
             order_start_then_action(remote_rsc, action, pe_order_none);
             break;
 
         case stop_rsc:
         case action_demote:
             if (pcmk_is_set(container->flags, pe_rsc_failed)) {
                 /* When the container representing a guest node fails, any stop
                  * or demote actions for resources running on the guest node
                  * are implied by the container stopping. This is similar to
                  * how fencing operations work for cluster nodes and remote
                  * nodes.
                  */
             } else {
                 /* Ensure the operation happens before the connection is brought
                  * down.
                  *
                  * If we really wanted to, we could order these after the
                  * connection start, IFF the container's current role was
                  * stopped (otherwise we re-introduce an ordering loop when the
                  * connection is restarting).
                  */
                 order_action_then_stop(action, remote_rsc, pe_order_none);
             }
             break;
 
         default:
             /* Wait for the connection resource to be up */
             if (pcmk__action_is_recurring(action)) {
                 /* In case we ever get the recovery logic wrong, force
                  * recurring monitors to be restarted, even if just
                  * the connection was re-established
                  */
-                if(task != no_action) {
+                if (task != no_action) {
                     order_start_then_action(remote_rsc, action,
                                             pe_order_implies_then);
                 }
             } else {
                 order_start_then_action(remote_rsc, action, pe_order_none);
             }
             break;
     }
 }
 
 /*!
  * \internal
  * \brief Order all relevant actions relative to remote connection actions
  *
  * \param[in,out] data_set  Cluster working set
  */
 void
 pcmk__order_remote_connection_actions(pe_working_set_t *data_set)
 {
     if (!pcmk_is_set(data_set->flags, pe_flag_have_remote_nodes)) {
         return;
     }
 
     crm_trace("Creating remote connection orderings");
 
     for (GList *iter = data_set->actions; iter != NULL; iter = iter->next) {
         pe_action_t *action = iter->data;
         pe_resource_t *remote = NULL;
 
         // We are only interested in resource actions
         if (action->rsc == NULL) {
             continue;
         }
 
         /* Special case: If we are clearing the failcount of an actual
          * remote connection resource, then make sure this happens before
          * any start of the resource in this transition.
          */
         if (action->rsc->is_remote_node &&
             pcmk__str_eq(action->task, CRM_OP_CLEAR_FAILCOUNT,
                          pcmk__str_casei)) {
 
             pcmk__new_ordering(action->rsc, NULL, action, action->rsc,
                                pcmk__op_key(action->rsc->id, RSC_START, 0),
                                NULL, pe_order_optional, data_set);
 
             continue;
         }
 
         // We are only interested in actions assigned to a node
         if (action->node == NULL) {
             continue;
         }
 
         if (!pe__is_guest_or_remote_node(action->node)) {
             continue;
         }
 
         /* We are only interested in real actions.
          *
          * @TODO This is probably wrong; pseudo-actions might be converted to
          * real actions and vice versa later in update_actions() at the end of
          * pcmk__apply_orderings().
          */
         if (pcmk_is_set(action->flags, pe_action_pseudo)) {
             continue;
         }
 
         remote = action->node->details->remote_rsc;
         if (remote == NULL) {
             // Orphaned
             continue;
         }
 
         /* Another special case: if a resource is moving to a Pacemaker Remote
          * node, order the stop on the original node after any start of the
          * remote connection. This ensures that if the connection fails to
          * start, we leave the resource running on the original node.
          */
         if (pcmk__str_eq(action->task, RSC_START, pcmk__str_casei)) {
             for (GList *item = action->rsc->actions; item != NULL;
                  item = item->next) {
                 pe_action_t *rsc_action = item->data;
 
                 if (!pe__same_node(rsc_action->node, action->node)
                     && pcmk__str_eq(rsc_action->task, RSC_STOP,
                                     pcmk__str_casei)) {
                     pcmk__new_ordering(remote, start_key(remote), NULL,
                                        action->rsc, NULL, rsc_action,
                                        pe_order_optional, data_set);
                 }
             }
         }
 
         /* The action occurs across a remote connection, so create
          * ordering constraints that guarantee the action occurs while the node
          * is active (after start, before stop ... things like that).
          *
          * This is somewhat brittle in that we need to make sure the results of
          * this ordering are compatible with the result of get_router_node().
          * It would probably be better to add XML_LRM_ATTR_ROUTER_NODE as part
          * of this logic rather than create_graph_action().
          */
         if (remote->container) {
             crm_trace("Container ordering for %s", action->uuid);
             apply_container_ordering(action);
 
         } else {
             crm_trace("Remote ordering for %s", action->uuid);
             apply_remote_ordering(action);
         }
     }
 }
 
 /*!
  * \internal
  * \brief Check whether a node is a failed remote node
  *
  * \param[in] node  Node to check
  *
  * \return true if \p node is a failed remote node, false otherwise
  */
 bool
 pcmk__is_failed_remote_node(const pe_node_t *node)
 {
     return pe__is_remote_node(node) && (node->details->remote_rsc != NULL)
            && (get_remote_node_state(node) == remote_state_failed);
 }
 
 /*!
  * \internal
  * \brief Check whether a given resource corresponds to a given node as guest
  *
  * \param[in] rsc   Resource to check
  * \param[in] node  Node to check
  *
  * \return true if \p node is a guest node and \p rsc is its containing
  *         resource, otherwise false
  */
 bool
 pcmk__rsc_corresponds_to_guest(const pe_resource_t *rsc, const pe_node_t *node)
 {
     return (rsc != NULL) && (rsc->fillers != NULL) && (node != NULL)
             && (node->details->remote_rsc != NULL)
             && (node->details->remote_rsc->container == rsc);
 }
 
 /*!
  * \internal
  * \brief Get proper connection host that a remote action must be routed through
  *
  * A remote connection resource might be starting, stopping, or migrating in the
  * same transition that an action needs to be executed on its Pacemaker Remote
  * node. Determine the proper node that the remote action should be routed
  * through.
  *
  * \param[in] action  (Potentially remote) action to route
  *
  * \return Connection host that action should be routed through if remote,
  *         otherwise NULL
  */
 pe_node_t *
 pcmk__connection_host_for_action(const pe_action_t *action)
 {
     pe_node_t *began_on = NULL;
     pe_node_t *ended_on = NULL;
     bool partial_migration = false;
     const char *task = action->task;
 
     if (pcmk__str_eq(task, CRM_OP_FENCE, pcmk__str_casei)
         || !pe__is_guest_or_remote_node(action->node)) {
         return NULL;
     }
 
     CRM_ASSERT(action->node->details->remote_rsc != NULL);
 
     began_on = pe__current_node(action->node->details->remote_rsc);
     ended_on = action->node->details->remote_rsc->allocated_to;
     if (action->node->details->remote_rsc
         && (action->node->details->remote_rsc->container == NULL)
         && action->node->details->remote_rsc->partial_migration_target) {
         partial_migration = true;
     }
 
     if (began_on == NULL) {
         crm_trace("Routing %s for %s through remote connection's "
                   "next node %s (starting)%s",
                   action->task, (action->rsc? action->rsc->id : "no resource"),
                   (ended_on? ended_on->details->uname : "none"),
                   partial_migration? " (partial migration)" : "");
         return ended_on;
     }
 
     if (ended_on == NULL) {
         crm_trace("Routing %s for %s through remote connection's "
                   "current node %s (stopping)%s",
                   action->task, (action->rsc? action->rsc->id : "no resource"),
                   (began_on? began_on->details->uname : "none"),
                   partial_migration? " (partial migration)" : "");
         return began_on;
     }
 
     if (pe__same_node(began_on, ended_on)) {
         crm_trace("Routing %s for %s through remote connection's "
                   "current node %s (not moving)%s",
                   action->task, (action->rsc? action->rsc->id : "no resource"),
                   (began_on? began_on->details->uname : "none"),
                   partial_migration? " (partial migration)" : "");
         return began_on;
     }
 
     /* If we get here, the remote connection is moving during this transition.
      * This means some actions for resources behind the connection will get
      * routed through the cluster node the connection resource is currently on,
      * and others are routed through the cluster node the connection will end up
      * on.
      */
 
     if (pcmk__str_eq(task, "notify", pcmk__str_casei)) {
         task = g_hash_table_lookup(action->meta, "notify_operation");
     }
 
     /*
      * Stop, demote, and migration actions must occur before the connection can
      * move (these actions are required before the remote resource can stop). In
      * this case, we know these actions have to be routed through the initial
      * cluster node the connection resource lived on before the move takes
      * place.
      *
      * The exception is a partial migration of a (non-guest) remote connection
      * resource; in that case, all actions (even these) will be ordered after
      * the connection's pseudo-start on the migration target, so the target is
      * the router node.
      */
     if (pcmk__strcase_any_of(task, "cancel", "stop", "demote", "migrate_from",
                              "migrate_to", NULL) && !partial_migration) {
         crm_trace("Routing %s for %s through remote connection's "
                   "current node %s (moving)%s",
                   action->task, (action->rsc? action->rsc->id : "no resource"),
                   (began_on? began_on->details->uname : "none"),
                   partial_migration? " (partial migration)" : "");
         return began_on;
     }
 
     /* Everything else (start, promote, monitor, probe, refresh,
      * clear failcount, delete, ...) must occur after the connection starts on
      * the node it is moving to.
      */
     crm_trace("Routing %s for %s through remote connection's "
               "next node %s (moving)%s",
               action->task, (action->rsc? action->rsc->id : "no resource"),
               (ended_on? ended_on->details->uname : "none"),
               partial_migration? " (partial migration)" : "");
     return ended_on;
 }
 
 /*!
  * \internal
  * \brief Replace remote connection's addr="#uname" with actual address
  *
  * REMOTE_CONTAINER_HACK: If a given resource is a remote connection resource
  * with its "addr" parameter set to "#uname", pull the actual value from the
  * parameters evaluated without a node (which was put there earlier in
  * pcmk__create_graph() when the bundle's expand() method was called).
  *
  * \param[in,out] rsc     Resource to check
  * \param[in,out] params  Resource parameters evaluated per node
  */
 void
 pcmk__substitute_remote_addr(pe_resource_t *rsc, GHashTable *params)
 {
     const char *remote_addr = g_hash_table_lookup(params,
                                                   XML_RSC_ATTR_REMOTE_RA_ADDR);
 
     if (pcmk__str_eq(remote_addr, "#uname", pcmk__str_none)) {
         GHashTable *base = pe_rsc_params(rsc, NULL, rsc->cluster);
 
         remote_addr = g_hash_table_lookup(base, XML_RSC_ATTR_REMOTE_RA_ADDR);
         if (remote_addr != NULL) {
             g_hash_table_insert(params, strdup(XML_RSC_ATTR_REMOTE_RA_ADDR),
                                 strdup(remote_addr));
         }
     }
 }
 
 /*!
  * \brief Add special bundle meta-attributes to XML
  *
  * If a given action will be executed on a guest node (including a bundle),
  * add the special bundle meta-attribute "container-attribute-target" and
  * environment variable "physical_host" as XML attributes (using meta-attribute
  * naming).
  *
  * \param[in,out] args_xml  XML to add attributes to
  * \param[in]     action    Action to check
  */
 void
 pcmk__add_bundle_meta_to_xml(xmlNode *args_xml, const pe_action_t *action)
 {
     const pe_node_t *host = NULL;
     enum action_tasks task;
 
     if (!pe__is_guest_node(action->node)) {
         return;
     }
 
     task = text2task(action->task);
     if ((task == action_notify) || (task == action_notified)) {
         task = text2task(g_hash_table_lookup(action->meta, "notify_operation"));
     }
 
     switch (task) {
         case stop_rsc:
         case stopped_rsc:
         case action_demote:
         case action_demoted:
             // "Down" actions take place on guest's current host
             host = pe__current_node(action->node->details->remote_rsc->container);
             break;
 
         case start_rsc:
         case started_rsc:
         case monitor_rsc:
         case action_promote:
         case action_promoted:
             // "Up" actions take place on guest's next host
             host = action->node->details->remote_rsc->container->allocated_to;
             break;
 
         default:
             break;
     }
 
     if (host != NULL) {
         hash2metafield((gpointer) XML_RSC_ATTR_TARGET,
                        (gpointer) g_hash_table_lookup(action->rsc->meta,
                                                       XML_RSC_ATTR_TARGET),
                        (gpointer) args_xml);
         hash2metafield((gpointer) PCMK__ENV_PHYSICAL_HOST,
                        (gpointer) host->details->uname,
                        (gpointer) args_xml);
     }
 }