root/lib/pacemaker/pcmk_output.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. colocations_header
  2. colocations_xml_node
  3. do_locations_list_xml
  4. PCMK__OUTPUT_ARGS
  5. PCMK__OUTPUT_ARGS
  6. PCMK__OUTPUT_ARGS
  7. PCMK__OUTPUT_ARGS
  8. PCMK__OUTPUT_ARGS
  9. PCMK__OUTPUT_ARGS
  10. PCMK__OUTPUT_ARGS
  11. PCMK__OUTPUT_ARGS
  12. PCMK__OUTPUT_ARGS
  13. PCMK__OUTPUT_ARGS
  14. PCMK__OUTPUT_ARGS
  15. PCMK__OUTPUT_ARGS
  16. PCMK__OUTPUT_ARGS
  17. PCMK__OUTPUT_ARGS
  18. PCMK__OUTPUT_ARGS
  19. PCMK__OUTPUT_ARGS
  20. PCMK__OUTPUT_ARGS
  21. PCMK__OUTPUT_ARGS
  22. PCMK__OUTPUT_ARGS
  23. PCMK__OUTPUT_ARGS
  24. PCMK__OUTPUT_ARGS
  25. PCMK__OUTPUT_ARGS
  26. PCMK__OUTPUT_ARGS
  27. PCMK__OUTPUT_ARGS
  28. PCMK__OUTPUT_ARGS
  29. PCMK__OUTPUT_ARGS
  30. add_digest_xml
  31. PCMK__OUTPUT_ARGS
  32. PCMK__OUTPUT_ARGS
  33. PCMK__OUTPUT_ARGS
  34. PCMK__OUTPUT_ARGS
  35. PCMK__OUTPUT_ARGS
  36. PCMK__OUTPUT_ARGS
  37. PCMK__OUTPUT_ARGS
  38. PCMK__OUTPUT_ARGS
  39. PCMK__OUTPUT_ARGS
  40. PCMK__OUTPUT_ARGS
  41. PCMK__OUTPUT_ARGS
  42. PCMK__OUTPUT_ARGS
  43. PCMK__OUTPUT_ARGS
  44. PCMK__OUTPUT_ARGS
  45. PCMK__OUTPUT_ARGS
  46. PCMK__OUTPUT_ARGS
  47. PCMK__OUTPUT_ARGS
  48. PCMK__OUTPUT_ARGS
  49. PCMK__OUTPUT_ARGS
  50. PCMK__OUTPUT_ARGS
  51. PCMK__OUTPUT_ARGS
  52. PCMK__OUTPUT_ARGS
  53. PCMK__OUTPUT_ARGS
  54. PCMK__OUTPUT_ARGS
  55. PCMK__OUTPUT_ARGS
  56. PCMK__OUTPUT_ARGS
  57. PCMK__OUTPUT_ARGS
  58. PCMK__OUTPUT_ARGS
  59. PCMK__OUTPUT_ARGS
  60. PCMK__OUTPUT_ARGS
  61. PCMK__OUTPUT_ARGS
  62. PCMK__OUTPUT_ARGS
  63. PCMK__OUTPUT_ARGS
  64. PCMK__OUTPUT_ARGS
  65. pcmk__register_lib_messages

   1 /*
   2  * Copyright 2019-2023 the Pacemaker project contributors
   3  *
   4  * The version control history for this file may have further details.
   5  *
   6  * This source code is licensed under the GNU General Public License version 2
   7  * or later (GPLv2+) WITHOUT ANY WARRANTY.
   8  */
   9 
  10 #include <crm_internal.h>
  11 #include <crm/common/output.h>
  12 #include <crm/common/results.h>
  13 #include <crm/msg_xml.h>
  14 #include <crm/stonith-ng.h>
  15 #include <crm/fencing/internal.h>
  16 #include <crm/pengine/internal.h>
  17 #include <libxml/tree.h>
  18 #include <pacemaker-internal.h>
  19 
  20 #include <inttypes.h>
  21 #include <stdint.h>
  22 
  23 static char *
  24 colocations_header(pcmk_resource_t *rsc, pcmk__colocation_t *cons,
     /* [previous][next][first][last][top][bottom][index][help] */
  25                    bool dependents) {
  26     char *retval = NULL;
  27 
  28     if (cons->primary_role > pcmk_role_started) {
  29         retval = crm_strdup_printf("%s (score=%s, %s role=%s, id=%s)",
  30                                    rsc->id, pcmk_readable_score(cons->score),
  31                                    (dependents? "needs" : "with"),
  32                                    role2text(cons->primary_role), cons->id);
  33     } else {
  34         retval = crm_strdup_printf("%s (score=%s, id=%s)",
  35                                    rsc->id, pcmk_readable_score(cons->score),
  36                                    cons->id);
  37     }
  38     return retval;
  39 }
  40 
  41 static void
  42 colocations_xml_node(pcmk__output_t *out, pcmk_resource_t *rsc,
     /* [previous][next][first][last][top][bottom][index][help] */
  43                      pcmk__colocation_t *cons) {
  44     xmlNodePtr node = NULL;
  45 
  46     node = pcmk__output_create_xml_node(out, XML_CONS_TAG_RSC_DEPEND,
  47                                         "id", cons->id,
  48                                         "rsc", cons->dependent->id,
  49                                         "with-rsc", cons->primary->id,
  50                                         "score",
  51                                         pcmk_readable_score(cons->score),
  52                                         NULL);
  53 
  54     if (cons->node_attribute) {
  55         xmlSetProp(node, (pcmkXmlStr) "node-attribute",
  56                    (pcmkXmlStr) cons->node_attribute);
  57     }
  58 
  59     if (cons->dependent_role != pcmk_role_unknown) {
  60         xmlSetProp(node, (pcmkXmlStr) "rsc-role",
  61                    (pcmkXmlStr) role2text(cons->dependent_role));
  62     }
  63 
  64     if (cons->primary_role != pcmk_role_unknown) {
  65         xmlSetProp(node, (pcmkXmlStr) "with-rsc-role",
  66                    (pcmkXmlStr) role2text(cons->primary_role));
  67     }
  68 }
  69 
  70 static int
  71 do_locations_list_xml(pcmk__output_t *out, pcmk_resource_t *rsc,
     /* [previous][next][first][last][top][bottom][index][help] */
  72                       bool add_header)
  73 {
  74     GList *lpc = NULL;
  75     GList *list = rsc->rsc_location;
  76     int rc = pcmk_rc_no_output;
  77 
  78     for (lpc = list; lpc != NULL; lpc = lpc->next) {
  79         pe__location_t *cons = lpc->data;
  80 
  81         GList *lpc2 = NULL;
  82 
  83         for (lpc2 = cons->node_list_rh; lpc2 != NULL; lpc2 = lpc2->next) {
  84             pcmk_node_t *node = (pcmk_node_t *) lpc2->data;
  85 
  86             if (add_header) {
  87                 PCMK__OUTPUT_LIST_HEADER(out, false, rc, "locations");
  88             }
  89 
  90             pcmk__output_create_xml_node(out, XML_CONS_TAG_RSC_LOCATION,
  91                                          "node", node->details->uname,
  92                                          "rsc", rsc->id,
  93                                          "id", cons->id,
  94                                          "score",
  95                                          pcmk_readable_score(node->weight),
  96                                          NULL);
  97         }
  98     }
  99 
 100     if (add_header) {
 101         PCMK__OUTPUT_LIST_FOOTER(out, rc);
 102     }
 103 
 104     return rc;
 105 }
 106 
 107 PCMK__OUTPUT_ARGS("rsc-action-item", "const char *", "pcmk_resource_t *",
     /* [previous][next][first][last][top][bottom][index][help] */
 108                   "pcmk_node_t *", "pcmk_node_t *", "pcmk_action_t *",
 109                   "pcmk_action_t *")
 110 static int
 111 rsc_action_item(pcmk__output_t *out, va_list args)
 112 {
 113     const char *change = va_arg(args, const char *);
 114     pcmk_resource_t *rsc = va_arg(args, pcmk_resource_t *);
 115     pcmk_node_t *origin = va_arg(args, pcmk_node_t *);
 116     pcmk_node_t *destination = va_arg(args, pcmk_node_t *);
 117     pcmk_action_t *action = va_arg(args, pcmk_action_t *);
 118     pcmk_action_t *source = va_arg(args, pcmk_action_t *);
 119 
 120     int len = 0;
 121     char *reason = NULL;
 122     char *details = NULL;
 123     bool same_host = false;
 124     bool same_role = false;
 125     bool need_role = false;
 126 
 127     static int rsc_width = 5;
 128     static int detail_width = 5;
 129 
 130     CRM_ASSERT(action);
 131     CRM_ASSERT(destination != NULL || origin != NULL);
 132 
 133     if (source == NULL) {
 134         source = action;
 135     }
 136 
 137     len = strlen(rsc->id);
 138     if (len > rsc_width) {
 139         rsc_width = len + 2;
 140     }
 141 
 142     if ((rsc->role > pcmk_role_started)
 143         || (rsc->next_role > pcmk_role_unpromoted)) {
 144         need_role = true;
 145     }
 146 
 147     if (pe__same_node(origin, destination)) {
 148         same_host = true;
 149     }
 150 
 151     if (rsc->role == rsc->next_role) {
 152         same_role = true;
 153     }
 154 
 155     if (need_role && (origin == NULL)) {
 156         /* Starting and promoting a promotable clone instance */
 157         details = crm_strdup_printf("%s -> %s %s", role2text(rsc->role),
 158                                     role2text(rsc->next_role),
 159                                     pe__node_name(destination));
 160 
 161     } else if (origin == NULL) {
 162         /* Starting a resource */
 163         details = crm_strdup_printf("%s", pe__node_name(destination));
 164 
 165     } else if (need_role && (destination == NULL)) {
 166         /* Stopping a promotable clone instance */
 167         details = crm_strdup_printf("%s %s", role2text(rsc->role),
 168                                     pe__node_name(origin));
 169 
 170     } else if (destination == NULL) {
 171         /* Stopping a resource */
 172         details = crm_strdup_printf("%s", pe__node_name(origin));
 173 
 174     } else if (need_role && same_role && same_host) {
 175         /* Recovering, restarting or re-promoting a promotable clone instance */
 176         details = crm_strdup_printf("%s %s", role2text(rsc->role),
 177                                     pe__node_name(origin));
 178 
 179     } else if (same_role && same_host) {
 180         /* Recovering or Restarting a normal resource */
 181         details = crm_strdup_printf("%s", pe__node_name(origin));
 182 
 183     } else if (need_role && same_role) {
 184         /* Moving a promotable clone instance */
 185         details = crm_strdup_printf("%s -> %s %s", pe__node_name(origin),
 186                                     pe__node_name(destination),
 187                                     role2text(rsc->role));
 188 
 189     } else if (same_role) {
 190         /* Moving a normal resource */
 191         details = crm_strdup_printf("%s -> %s", pe__node_name(origin),
 192                                     pe__node_name(destination));
 193 
 194     } else if (same_host) {
 195         /* Promoting or demoting a promotable clone instance */
 196         details = crm_strdup_printf("%s -> %s %s", role2text(rsc->role),
 197                                     role2text(rsc->next_role),
 198                                     pe__node_name(origin));
 199 
 200     } else {
 201         /* Moving and promoting/demoting */
 202         details = crm_strdup_printf("%s %s -> %s %s", role2text(rsc->role),
 203                                     pe__node_name(origin),
 204                                     role2text(rsc->next_role),
 205                                     pe__node_name(destination));
 206     }
 207 
 208     len = strlen(details);
 209     if (len > detail_width) {
 210         detail_width = len;
 211     }
 212 
 213     if ((source->reason != NULL)
 214         && !pcmk_is_set(action->flags, pcmk_action_runnable)) {
 215         reason = crm_strdup_printf("due to %s (blocked)", source->reason);
 216 
 217     } else if (source->reason) {
 218         reason = crm_strdup_printf("due to %s", source->reason);
 219 
 220     } else if (!pcmk_is_set(action->flags, pcmk_action_runnable)) {
 221         reason = strdup("blocked");
 222 
 223     }
 224 
 225     out->list_item(out, NULL, "%-8s   %-*s   ( %*s )%s%s",
 226                    change, rsc_width, rsc->id, detail_width, details,
 227                    ((reason == NULL)? "" : "  "), pcmk__s(reason, ""));
 228 
 229     free(details);
 230     free(reason);
 231     return pcmk_rc_ok;
 232 }
 233 
 234 PCMK__OUTPUT_ARGS("rsc-action-item", "const char *", "pcmk_resource_t *",
     /* [previous][next][first][last][top][bottom][index][help] */
 235                   "pcmk_node_t *", "pcmk_node_t *", "pcmk_action_t *",
 236                   "pcmk_action_t *")
 237 static int
 238 rsc_action_item_xml(pcmk__output_t *out, va_list args)
 239 {
 240     const char *change = va_arg(args, const char *);
 241     pcmk_resource_t *rsc = va_arg(args, pcmk_resource_t *);
 242     pcmk_node_t *origin = va_arg(args, pcmk_node_t *);
 243     pcmk_node_t *destination = va_arg(args, pcmk_node_t *);
 244     pcmk_action_t *action = va_arg(args, pcmk_action_t *);
 245     pcmk_action_t *source = va_arg(args, pcmk_action_t *);
 246 
 247     char *change_str = NULL;
 248 
 249     bool same_host = false;
 250     bool same_role = false;
 251     bool need_role = false;
 252     xmlNode *xml = NULL;
 253 
 254     CRM_ASSERT(action);
 255     CRM_ASSERT(destination != NULL || origin != NULL);
 256 
 257     if (source == NULL) {
 258         source = action;
 259     }
 260 
 261     if ((rsc->role > pcmk_role_started)
 262         || (rsc->next_role > pcmk_role_unpromoted)) {
 263         need_role = true;
 264     }
 265 
 266     if (pe__same_node(origin, destination)) {
 267         same_host = true;
 268     }
 269 
 270     if (rsc->role == rsc->next_role) {
 271         same_role = true;
 272     }
 273 
 274     change_str = g_ascii_strdown(change, -1);
 275     xml = pcmk__output_create_xml_node(out, "rsc_action",
 276                                        "action", change_str,
 277                                        "resource", rsc->id,
 278                                        NULL);
 279     g_free(change_str);
 280 
 281     if (need_role && (origin == NULL)) {
 282         /* Starting and promoting a promotable clone instance */
 283         pcmk__xe_set_props(xml,
 284                            "role", role2text(rsc->role),
 285                            "next-role", role2text(rsc->next_role),
 286                            "dest", destination->details->uname,
 287                            NULL);
 288 
 289     } else if (origin == NULL) {
 290         /* Starting a resource */
 291         crm_xml_add(xml, "node", destination->details->uname);
 292 
 293     } else if (need_role && (destination == NULL)) {
 294         /* Stopping a promotable clone instance */
 295         pcmk__xe_set_props(xml,
 296                            "role", role2text(rsc->role),
 297                            "node", origin->details->uname,
 298                            NULL);
 299 
 300     } else if (destination == NULL) {
 301         /* Stopping a resource */
 302         crm_xml_add(xml, "node", origin->details->uname);
 303 
 304     } else if (need_role && same_role && same_host) {
 305         /* Recovering, restarting or re-promoting a promotable clone instance */
 306         pcmk__xe_set_props(xml,
 307                            "role", role2text(rsc->role),
 308                            "source", origin->details->uname,
 309                            NULL);
 310 
 311     } else if (same_role && same_host) {
 312         /* Recovering or Restarting a normal resource */
 313         crm_xml_add(xml, "source", origin->details->uname);
 314 
 315     } else if (need_role && same_role) {
 316         /* Moving a promotable clone instance */
 317         pcmk__xe_set_props(xml,
 318                            "source", origin->details->uname,
 319                            "dest", destination->details->uname,
 320                            "role", role2text(rsc->role),
 321                            NULL);
 322 
 323     } else if (same_role) {
 324         /* Moving a normal resource */
 325         pcmk__xe_set_props(xml,
 326                            "source", origin->details->uname,
 327                            "dest", destination->details->uname,
 328                            NULL);
 329 
 330     } else if (same_host) {
 331         /* Promoting or demoting a promotable clone instance */
 332         pcmk__xe_set_props(xml,
 333                            "role", role2text(rsc->role),
 334                            "next-role", role2text(rsc->next_role),
 335                            "source", origin->details->uname,
 336                            NULL);
 337 
 338     } else {
 339         /* Moving and promoting/demoting */
 340         pcmk__xe_set_props(xml,
 341                            "role", role2text(rsc->role),
 342                            "source", origin->details->uname,
 343                            "next-role", role2text(rsc->next_role),
 344                            "dest", destination->details->uname,
 345                            NULL);
 346     }
 347 
 348     if ((source->reason != NULL)
 349         && !pcmk_is_set(action->flags, pcmk_action_runnable)) {
 350         pcmk__xe_set_props(xml,
 351                            "reason", source->reason,
 352                            "blocked", "true",
 353                            NULL);
 354 
 355     } else if (source->reason != NULL) {
 356         crm_xml_add(xml, "reason", source->reason);
 357 
 358     } else if (!pcmk_is_set(action->flags, pcmk_action_runnable)) {
 359         pcmk__xe_set_bool_attr(xml, "blocked", true);
 360 
 361     }
 362 
 363     return pcmk_rc_ok;
 364 }
 365 
 366 PCMK__OUTPUT_ARGS("rsc-is-colocated-with-list", "pcmk_resource_t *", "bool")
     /* [previous][next][first][last][top][bottom][index][help] */
 367 static int
 368 rsc_is_colocated_with_list(pcmk__output_t *out, va_list args) {
 369     pcmk_resource_t *rsc = va_arg(args, pcmk_resource_t *);
 370     bool recursive = va_arg(args, int);
 371 
 372     int rc = pcmk_rc_no_output;
 373 
 374     if (pcmk_is_set(rsc->flags, pcmk_rsc_detect_loop)) {
 375         return rc;
 376     }
 377 
 378     /* We're listing constraints explicitly involving rsc, so use rsc->rsc_cons
 379      * directly rather than rsc->cmds->this_with_colocations().
 380      */
 381     pe__set_resource_flags(rsc, pcmk_rsc_detect_loop);
 382     for (GList *lpc = rsc->rsc_cons; lpc != NULL; lpc = lpc->next) {
 383         pcmk__colocation_t *cons = (pcmk__colocation_t *) lpc->data;
 384         char *hdr = NULL;
 385 
 386         PCMK__OUTPUT_LIST_HEADER(out, false, rc,
 387                                  "Resources %s is colocated with", rsc->id);
 388 
 389         if (pcmk_is_set(cons->primary->flags, pcmk_rsc_detect_loop)) {
 390             out->list_item(out, NULL, "%s (id=%s - loop)",
 391                            cons->primary->id, cons->id);
 392             continue;
 393         }
 394 
 395         hdr = colocations_header(cons->primary, cons, false);
 396         out->list_item(out, NULL, "%s", hdr);
 397         free(hdr);
 398 
 399         // Empty list header for indentation of information about this resource
 400         out->begin_list(out, NULL, NULL, NULL);
 401 
 402         out->message(out, "locations-list", cons->primary);
 403         if (recursive) {
 404             out->message(out, "rsc-is-colocated-with-list",
 405                          cons->primary, recursive);
 406         }
 407 
 408         out->end_list(out);
 409     }
 410 
 411     PCMK__OUTPUT_LIST_FOOTER(out, rc);
 412     return rc;
 413 }
 414 
 415 PCMK__OUTPUT_ARGS("rsc-is-colocated-with-list", "pcmk_resource_t *", "bool")
     /* [previous][next][first][last][top][bottom][index][help] */
 416 static int
 417 rsc_is_colocated_with_list_xml(pcmk__output_t *out, va_list args) {
 418     pcmk_resource_t *rsc = va_arg(args, pcmk_resource_t *);
 419     bool recursive = va_arg(args, int);
 420 
 421     int rc = pcmk_rc_no_output;
 422 
 423     if (pcmk_is_set(rsc->flags, pcmk_rsc_detect_loop)) {
 424         return rc;
 425     }
 426 
 427     /* We're listing constraints explicitly involving rsc, so use rsc->rsc_cons
 428      * directly rather than rsc->cmds->this_with_colocations().
 429      */
 430     pe__set_resource_flags(rsc, pcmk_rsc_detect_loop);
 431     for (GList *lpc = rsc->rsc_cons; lpc != NULL; lpc = lpc->next) {
 432         pcmk__colocation_t *cons = (pcmk__colocation_t *) lpc->data;
 433 
 434         if (pcmk_is_set(cons->primary->flags, pcmk_rsc_detect_loop)) {
 435             colocations_xml_node(out, cons->primary, cons);
 436             continue;
 437         }
 438 
 439         colocations_xml_node(out, cons->primary, cons);
 440         do_locations_list_xml(out, cons->primary, false);
 441 
 442         if (recursive) {
 443             out->message(out, "rsc-is-colocated-with-list",
 444                          cons->primary, recursive);
 445         }
 446     }
 447 
 448     return rc;
 449 }
 450 
 451 PCMK__OUTPUT_ARGS("rscs-colocated-with-list", "pcmk_resource_t *", "bool")
     /* [previous][next][first][last][top][bottom][index][help] */
 452 static int
 453 rscs_colocated_with_list(pcmk__output_t *out, va_list args) {
 454     pcmk_resource_t *rsc = va_arg(args, pcmk_resource_t *);
 455     bool recursive = va_arg(args, int);
 456 
 457     int rc = pcmk_rc_no_output;
 458 
 459     if (pcmk_is_set(rsc->flags, pcmk_rsc_detect_loop)) {
 460         return rc;
 461     }
 462 
 463     /* We're listing constraints explicitly involving rsc, so use
 464      * rsc->rsc_cons_lhs directly rather than
 465      * rsc->cmds->with_this_colocations().
 466      */
 467     pe__set_resource_flags(rsc, pcmk_rsc_detect_loop);
 468     for (GList *lpc = rsc->rsc_cons_lhs; lpc != NULL; lpc = lpc->next) {
 469         pcmk__colocation_t *cons = (pcmk__colocation_t *) lpc->data;
 470         char *hdr = NULL;
 471 
 472         PCMK__OUTPUT_LIST_HEADER(out, false, rc, "Resources colocated with %s",
 473                                  rsc->id);
 474 
 475         if (pcmk_is_set(cons->dependent->flags, pcmk_rsc_detect_loop)) {
 476             out->list_item(out, NULL, "%s (id=%s - loop)",
 477                            cons->dependent->id, cons->id);
 478             continue;
 479         }
 480 
 481         hdr = colocations_header(cons->dependent, cons, true);
 482         out->list_item(out, NULL, "%s", hdr);
 483         free(hdr);
 484 
 485         // Empty list header for indentation of information about this resource
 486         out->begin_list(out, NULL, NULL, NULL);
 487 
 488         out->message(out, "locations-list", cons->dependent);
 489         if (recursive) {
 490             out->message(out, "rscs-colocated-with-list",
 491                          cons->dependent, recursive);
 492         }
 493 
 494         out->end_list(out);
 495     }
 496 
 497     PCMK__OUTPUT_LIST_FOOTER(out, rc);
 498     return rc;
 499 }
 500 
 501 PCMK__OUTPUT_ARGS("rscs-colocated-with-list", "pcmk_resource_t *", "bool")
     /* [previous][next][first][last][top][bottom][index][help] */
 502 static int
 503 rscs_colocated_with_list_xml(pcmk__output_t *out, va_list args) {
 504     pcmk_resource_t *rsc = va_arg(args, pcmk_resource_t *);
 505     bool recursive = va_arg(args, int);
 506 
 507     int rc = pcmk_rc_no_output;
 508 
 509     if (pcmk_is_set(rsc->flags, pcmk_rsc_detect_loop)) {
 510         return rc;
 511     }
 512 
 513     /* We're listing constraints explicitly involving rsc, so use
 514      * rsc->rsc_cons_lhs directly rather than
 515      * rsc->cmds->with_this_colocations().
 516      */
 517     pe__set_resource_flags(rsc, pcmk_rsc_detect_loop);
 518     for (GList *lpc = rsc->rsc_cons_lhs; lpc != NULL; lpc = lpc->next) {
 519         pcmk__colocation_t *cons = (pcmk__colocation_t *) lpc->data;
 520 
 521         if (pcmk_is_set(cons->dependent->flags, pcmk_rsc_detect_loop)) {
 522             colocations_xml_node(out, cons->dependent, cons);
 523             continue;
 524         }
 525 
 526         colocations_xml_node(out, cons->dependent, cons);
 527         do_locations_list_xml(out, cons->dependent, false);
 528 
 529         if (recursive) {
 530             out->message(out, "rscs-colocated-with-list",
 531                          cons->dependent, recursive);
 532         }
 533     }
 534 
 535     return rc;
 536 }
 537 
 538 PCMK__OUTPUT_ARGS("locations-list", "pcmk_resource_t *")
     /* [previous][next][first][last][top][bottom][index][help] */
 539 static int
 540 locations_list(pcmk__output_t *out, va_list args) {
 541     pcmk_resource_t *rsc = va_arg(args, pcmk_resource_t *);
 542 
 543     GList *lpc = NULL;
 544     GList *list = rsc->rsc_location;
 545     int rc = pcmk_rc_no_output;
 546 
 547     for (lpc = list; lpc != NULL; lpc = lpc->next) {
 548         pe__location_t *cons = lpc->data;
 549 
 550         GList *lpc2 = NULL;
 551 
 552         for (lpc2 = cons->node_list_rh; lpc2 != NULL; lpc2 = lpc2->next) {
 553             pcmk_node_t *node = (pcmk_node_t *) lpc2->data;
 554 
 555             PCMK__OUTPUT_LIST_HEADER(out, false, rc, "Locations");
 556             out->list_item(out, NULL, "Node %s (score=%s, id=%s, rsc=%s)",
 557                            pe__node_name(node),
 558                            pcmk_readable_score(node->weight), cons->id,
 559                            rsc->id);
 560         }
 561     }
 562 
 563     PCMK__OUTPUT_LIST_FOOTER(out, rc);
 564     return rc;
 565 }
 566 
 567 PCMK__OUTPUT_ARGS("locations-list", "pcmk_resource_t *")
     /* [previous][next][first][last][top][bottom][index][help] */
 568 static int
 569 locations_list_xml(pcmk__output_t *out, va_list args) {
 570     pcmk_resource_t *rsc = va_arg(args, pcmk_resource_t *);
 571     return do_locations_list_xml(out, rsc, true);
 572 }
 573 
 574 PCMK__OUTPUT_ARGS("locations-and-colocations", "pcmk_resource_t *",
     /* [previous][next][first][last][top][bottom][index][help] */
 575                   "bool", "bool")
 576 static int
 577 locations_and_colocations(pcmk__output_t *out, va_list args)
 578 {
 579     pcmk_resource_t *rsc = va_arg(args, pcmk_resource_t *);
 580     bool recursive = va_arg(args, int);
 581     bool force = va_arg(args, int);
 582 
 583     pcmk__unpack_constraints(rsc->cluster);
 584 
 585     // Constraints apply to group/clone, not member/instance
 586     if (!force) {
 587         rsc = uber_parent(rsc);
 588     }
 589 
 590     out->message(out, "locations-list", rsc);
 591 
 592     pe__clear_resource_flags_on_all(rsc->cluster, pcmk_rsc_detect_loop);
 593     out->message(out, "rscs-colocated-with-list", rsc, recursive);
 594 
 595     pe__clear_resource_flags_on_all(rsc->cluster, pcmk_rsc_detect_loop);
 596     out->message(out, "rsc-is-colocated-with-list", rsc, recursive);
 597     return pcmk_rc_ok;
 598 }
 599 
 600 PCMK__OUTPUT_ARGS("locations-and-colocations", "pcmk_resource_t *",
     /* [previous][next][first][last][top][bottom][index][help] */
 601                   "bool", "bool")
 602 static int
 603 locations_and_colocations_xml(pcmk__output_t *out, va_list args)
 604 {
 605     pcmk_resource_t *rsc = va_arg(args, pcmk_resource_t *);
 606     bool recursive = va_arg(args, int);
 607     bool force = va_arg(args, int);
 608 
 609     pcmk__unpack_constraints(rsc->cluster);
 610 
 611     // Constraints apply to group/clone, not member/instance
 612     if (!force) {
 613         rsc = uber_parent(rsc);
 614     }
 615 
 616     pcmk__output_xml_create_parent(out, "constraints", NULL);
 617     do_locations_list_xml(out, rsc, false);
 618 
 619     pe__clear_resource_flags_on_all(rsc->cluster, pcmk_rsc_detect_loop);
 620     out->message(out, "rscs-colocated-with-list", rsc, recursive);
 621 
 622     pe__clear_resource_flags_on_all(rsc->cluster, pcmk_rsc_detect_loop);
 623     out->message(out, "rsc-is-colocated-with-list", rsc, recursive);
 624 
 625     pcmk__output_xml_pop_parent(out);
 626     return pcmk_rc_ok;
 627 }
 628 
 629 PCMK__OUTPUT_ARGS("health", "const char *", "const char *", "const char *",
     /* [previous][next][first][last][top][bottom][index][help] */
 630                   "const char *")
 631 static int
 632 health(pcmk__output_t *out, va_list args)
 633 {
 634     const char *sys_from G_GNUC_UNUSED = va_arg(args, const char *);
 635     const char *host_from = va_arg(args, const char *);
 636     const char *fsa_state = va_arg(args, const char *);
 637     const char *result = va_arg(args, const char *);
 638 
 639     return out->info(out, "Controller on %s in state %s: %s",
 640                      pcmk__s(host_from, "unknown node"),
 641                      pcmk__s(fsa_state, "unknown"),
 642                      pcmk__s(result, "unknown result"));
 643 }
 644 
 645 PCMK__OUTPUT_ARGS("health", "const char *", "const char *", "const char *",
     /* [previous][next][first][last][top][bottom][index][help] */
 646                   "const char *")
 647 static int
 648 health_text(pcmk__output_t *out, va_list args)
 649 {
 650     if (!out->is_quiet(out)) {
 651         return health(out, args);
 652     } else {
 653         const char *sys_from G_GNUC_UNUSED = va_arg(args, const char *);
 654         const char *host_from G_GNUC_UNUSED = va_arg(args, const char *);
 655         const char *fsa_state = va_arg(args, const char *);
 656         const char *result G_GNUC_UNUSED = va_arg(args, const char *);
 657 
 658         if (fsa_state != NULL) {
 659             pcmk__formatted_printf(out, "%s\n", fsa_state);
 660             return pcmk_rc_ok;
 661         }
 662     }
 663 
 664     return pcmk_rc_no_output;
 665 }
 666 
 667 PCMK__OUTPUT_ARGS("health", "const char *", "const char *", "const char *",
     /* [previous][next][first][last][top][bottom][index][help] */
 668                   "const char *")
 669 static int
 670 health_xml(pcmk__output_t *out, va_list args)
 671 {
 672     const char *sys_from = va_arg(args, const char *);
 673     const char *host_from = va_arg(args, const char *);
 674     const char *fsa_state = va_arg(args, const char *);
 675     const char *result = va_arg(args, const char *);
 676 
 677     pcmk__output_create_xml_node(out, pcmk__s(sys_from, ""),
 678                                  "node_name", pcmk__s(host_from, ""),
 679                                  "state", pcmk__s(fsa_state, ""),
 680                                  "result", pcmk__s(result, ""),
 681                                  NULL);
 682     return pcmk_rc_ok;
 683 }
 684 
 685 PCMK__OUTPUT_ARGS("pacemakerd-health", "const char *",
     /* [previous][next][first][last][top][bottom][index][help] */
 686                   "enum pcmk_pacemakerd_state", "const char *", "time_t")
 687 static int
 688 pacemakerd_health(pcmk__output_t *out, va_list args)
 689 {
 690     const char *sys_from = va_arg(args, const char *);
 691     enum pcmk_pacemakerd_state state =
 692         (enum pcmk_pacemakerd_state) va_arg(args, int);
 693     const char *state_s = va_arg(args, const char *);
 694     time_t last_updated = va_arg(args, time_t);
 695 
 696     char *last_updated_s = NULL;
 697     int rc = pcmk_rc_ok;
 698 
 699     if (sys_from == NULL) {
 700         if (state == pcmk_pacemakerd_state_remote) {
 701             sys_from = "pacemaker-remoted";
 702         } else {
 703             sys_from = CRM_SYSTEM_MCP;
 704         }
 705     }
 706 
 707     if (state_s == NULL) {
 708         state_s = pcmk__pcmkd_state_enum2friendly(state);
 709     }
 710 
 711     if (last_updated != 0) {
 712         last_updated_s = pcmk__epoch2str(&last_updated,
 713                                          crm_time_log_date
 714                                          |crm_time_log_timeofday
 715                                          |crm_time_log_with_timezone);
 716     }
 717 
 718     rc = out->info(out, "Status of %s: '%s' (last updated %s)",
 719                    sys_from, state_s,
 720                    pcmk__s(last_updated_s, "at unknown time"));
 721 
 722     free(last_updated_s);
 723     return rc;
 724 }
 725 
 726 PCMK__OUTPUT_ARGS("pacemakerd-health", "const char *",
     /* [previous][next][first][last][top][bottom][index][help] */
 727                   "enum pcmk_pacemakerd_state", "const char *", "time_t")
 728 static int
 729 pacemakerd_health_html(pcmk__output_t *out, va_list args)
 730 {
 731     const char *sys_from = va_arg(args, const char *);
 732     enum pcmk_pacemakerd_state state =
 733         (enum pcmk_pacemakerd_state) va_arg(args, int);
 734     const char *state_s = va_arg(args, const char *);
 735     time_t last_updated = va_arg(args, time_t);
 736 
 737     char *last_updated_s = NULL;
 738     char *msg = NULL;
 739 
 740     if (sys_from == NULL) {
 741         if (state == pcmk_pacemakerd_state_remote) {
 742             sys_from = "pacemaker-remoted";
 743         } else {
 744             sys_from = CRM_SYSTEM_MCP;
 745         }
 746     }
 747 
 748     if (state_s == NULL) {
 749         state_s = pcmk__pcmkd_state_enum2friendly(state);
 750     }
 751 
 752     if (last_updated != 0) {
 753         last_updated_s = pcmk__epoch2str(&last_updated,
 754                                          crm_time_log_date
 755                                          |crm_time_log_timeofday
 756                                          |crm_time_log_with_timezone);
 757     }
 758 
 759     msg = crm_strdup_printf("Status of %s: '%s' (last updated %s)",
 760                             sys_from, state_s,
 761                             pcmk__s(last_updated_s, "at unknown time"));
 762     pcmk__output_create_html_node(out, "li", NULL, NULL, msg);
 763 
 764     free(msg);
 765     free(last_updated_s);
 766     return pcmk_rc_ok;
 767 }
 768 
 769 PCMK__OUTPUT_ARGS("pacemakerd-health", "const char *",
     /* [previous][next][first][last][top][bottom][index][help] */
 770                   "enum pcmk_pacemakerd_state", "const char *", "time_t")
 771 static int
 772 pacemakerd_health_text(pcmk__output_t *out, va_list args)
 773 {
 774     if (!out->is_quiet(out)) {
 775         return pacemakerd_health(out, args);
 776     } else {
 777         const char *sys_from G_GNUC_UNUSED = va_arg(args, const char *);
 778         enum pcmk_pacemakerd_state state =
 779             (enum pcmk_pacemakerd_state) va_arg(args, int);
 780         const char *state_s = va_arg(args, const char *);
 781         time_t last_updated G_GNUC_UNUSED = va_arg(args, time_t);
 782 
 783         if (state_s == NULL) {
 784             state_s = pcmk_pacemakerd_api_daemon_state_enum2text(state);
 785         }
 786         pcmk__formatted_printf(out, "%s\n", state_s);
 787         return pcmk_rc_ok;
 788     }
 789 }
 790 
 791 PCMK__OUTPUT_ARGS("pacemakerd-health", "const char *",
     /* [previous][next][first][last][top][bottom][index][help] */
 792                   "enum pcmk_pacemakerd_state", "const char *", "time_t")
 793 static int
 794 pacemakerd_health_xml(pcmk__output_t *out, va_list args)
 795 {
 796     const char *sys_from = va_arg(args, const char *);
 797     enum pcmk_pacemakerd_state state =
 798         (enum pcmk_pacemakerd_state) va_arg(args, int);
 799     const char *state_s = va_arg(args, const char *);
 800     time_t last_updated = va_arg(args, time_t);
 801 
 802     char *last_updated_s = NULL;
 803 
 804     if (sys_from == NULL) {
 805         if (state == pcmk_pacemakerd_state_remote) {
 806             sys_from = "pacemaker-remoted";
 807         } else {
 808             sys_from = CRM_SYSTEM_MCP;
 809         }
 810     }
 811 
 812     if (state_s == NULL) {
 813         state_s = pcmk_pacemakerd_api_daemon_state_enum2text(state);
 814     }
 815 
 816     if (last_updated != 0) {
 817         last_updated_s = pcmk__epoch2str(&last_updated,
 818                                          crm_time_log_date
 819                                          |crm_time_log_timeofday
 820                                          |crm_time_log_with_timezone);
 821     }
 822 
 823     pcmk__output_create_xml_node(out, "pacemakerd",
 824                                  "sys_from", sys_from,
 825                                  "state", state_s,
 826                                  "last_updated", last_updated_s,
 827                                  NULL);
 828     free(last_updated_s);
 829     return pcmk_rc_ok;
 830 }
 831 
 832 PCMK__OUTPUT_ARGS("profile", "const char *", "clock_t", "clock_t")
     /* [previous][next][first][last][top][bottom][index][help] */
 833 static int
 834 profile_default(pcmk__output_t *out, va_list args) {
 835     const char *xml_file = va_arg(args, const char *);
 836     clock_t start = va_arg(args, clock_t);
 837     clock_t end = va_arg(args, clock_t);
 838 
 839     out->list_item(out, NULL, "Testing %s ... %.2f secs", xml_file,
 840                    (end - start) / (float) CLOCKS_PER_SEC);
 841 
 842     return pcmk_rc_ok;
 843 }
 844 
 845 PCMK__OUTPUT_ARGS("profile", "const char *", "clock_t", "clock_t")
     /* [previous][next][first][last][top][bottom][index][help] */
 846 static int
 847 profile_xml(pcmk__output_t *out, va_list args) {
 848     const char *xml_file = va_arg(args, const char *);
 849     clock_t start = va_arg(args, clock_t);
 850     clock_t end = va_arg(args, clock_t);
 851 
 852     char *duration = pcmk__ftoa((end - start) / (float) CLOCKS_PER_SEC);
 853 
 854     pcmk__output_create_xml_node(out, "timing",
 855                                  "file", xml_file,
 856                                  "duration", duration,
 857                                  NULL);
 858 
 859     free(duration);
 860     return pcmk_rc_ok;
 861 }
 862 
 863 PCMK__OUTPUT_ARGS("dc", "const char *")
     /* [previous][next][first][last][top][bottom][index][help] */
 864 static int
 865 dc(pcmk__output_t *out, va_list args)
 866 {
 867     const char *dc = va_arg(args, const char *);
 868 
 869     return out->info(out, "Designated Controller is: %s",
 870                      pcmk__s(dc, "not yet elected"));
 871 }
 872 
 873 PCMK__OUTPUT_ARGS("dc", "const char *")
     /* [previous][next][first][last][top][bottom][index][help] */
 874 static int
 875 dc_text(pcmk__output_t *out, va_list args)
 876 {
 877     if (!out->is_quiet(out)) {
 878         return dc(out, args);
 879     } else {
 880         const char *dc = va_arg(args, const char *);
 881 
 882         if (dc != NULL) {
 883             pcmk__formatted_printf(out, "%s\n", pcmk__s(dc, ""));
 884             return pcmk_rc_ok;
 885         }
 886     }
 887 
 888     return pcmk_rc_no_output;
 889 }
 890 
 891 PCMK__OUTPUT_ARGS("dc", "const char *")
     /* [previous][next][first][last][top][bottom][index][help] */
 892 static int
 893 dc_xml(pcmk__output_t *out, va_list args)
 894 {
 895     const char *dc = va_arg(args, const char *);
 896 
 897     pcmk__output_create_xml_node(out, "dc",
 898                                  "node_name", pcmk__s(dc, ""),
 899                                  NULL);
 900     return pcmk_rc_ok;
 901 }
 902 
 903 PCMK__OUTPUT_ARGS("crmadmin-node", "const char *", "const char *",
     /* [previous][next][first][last][top][bottom][index][help] */
 904                   "const char *", "bool")
 905 static int
 906 crmadmin_node(pcmk__output_t *out, va_list args)
 907 {
 908     const char *type = va_arg(args, const char *);
 909     const char *name = va_arg(args, const char *);
 910     const char *id = va_arg(args, const char *);
 911     bool bash_export = va_arg(args, int);
 912 
 913     if (bash_export) {
 914         return out->info(out, "export %s=%s",
 915                          pcmk__s(name, "<null>"), pcmk__s(id, ""));
 916     } else {
 917         return out->info(out, "%s node: %s (%s)", type ? type : "cluster",
 918                          pcmk__s(name, "<null>"), pcmk__s(id, "<null>"));
 919     }
 920 }
 921 
 922 PCMK__OUTPUT_ARGS("crmadmin-node", "const char *", "const char *",
     /* [previous][next][first][last][top][bottom][index][help] */
 923                   "const char *", "bool")
 924 static int
 925 crmadmin_node_text(pcmk__output_t *out, va_list args)
 926 {
 927     if (!out->is_quiet(out)) {
 928         return crmadmin_node(out, args);
 929     } else {
 930         const char *type G_GNUC_UNUSED = va_arg(args, const char *);
 931         const char *name = va_arg(args, const char *);
 932         const char *id G_GNUC_UNUSED = va_arg(args, const char *);
 933         bool bash_export G_GNUC_UNUSED = va_arg(args, int);
 934 
 935         pcmk__formatted_printf(out, "%s\n", pcmk__s(name, "<null>"));
 936         return pcmk_rc_ok;
 937     }
 938 }
 939 
 940 PCMK__OUTPUT_ARGS("crmadmin-node", "const char *", "const char *",
     /* [previous][next][first][last][top][bottom][index][help] */
 941                   "const char *", "bool")
 942 static int
 943 crmadmin_node_xml(pcmk__output_t *out, va_list args)
 944 {
 945     const char *type = va_arg(args, const char *);
 946     const char *name = va_arg(args, const char *);
 947     const char *id = va_arg(args, const char *);
 948     bool bash_export G_GNUC_UNUSED = va_arg(args, int);
 949 
 950     pcmk__output_create_xml_node(out, "node",
 951                                  "type", type ? type : "cluster",
 952                                  "name", pcmk__s(name, ""),
 953                                  "id", pcmk__s(id, ""),
 954                                  NULL);
 955     return pcmk_rc_ok;
 956 }
 957 
 958 PCMK__OUTPUT_ARGS("digests", "const pcmk_resource_t *", "const pcmk_node_t *",
     /* [previous][next][first][last][top][bottom][index][help] */
 959                   "const char *", "guint", "const op_digest_cache_t *")
 960 static int
 961 digests_text(pcmk__output_t *out, va_list args)
 962 {
 963     const pcmk_resource_t *rsc = va_arg(args, const pcmk_resource_t *);
 964     const pcmk_node_t *node = va_arg(args, const pcmk_node_t *);
 965     const char *task = va_arg(args, const char *);
 966     guint interval_ms = va_arg(args, guint);
 967     const op_digest_cache_t *digests = va_arg(args, const op_digest_cache_t *);
 968 
 969     char *action_desc = NULL;
 970     const char *rsc_desc = "unknown resource";
 971     const char *node_desc = "unknown node";
 972 
 973     if (interval_ms != 0) {
 974         action_desc = crm_strdup_printf("%ums-interval %s action", interval_ms,
 975                                         ((task == NULL)? "unknown" : task));
 976     } else if (pcmk__str_eq(task, PCMK_ACTION_MONITOR, pcmk__str_none)) {
 977         action_desc = strdup("probe action");
 978     } else {
 979         action_desc = crm_strdup_printf("%s action",
 980                                         ((task == NULL)? "unknown" : task));
 981     }
 982     if ((rsc != NULL) && (rsc->id != NULL)) {
 983         rsc_desc = rsc->id;
 984     }
 985     if ((node != NULL) && (node->details->uname != NULL)) {
 986         node_desc = node->details->uname;
 987     }
 988     out->begin_list(out, NULL, NULL, "Digests for %s %s on %s",
 989                     rsc_desc, action_desc, node_desc);
 990     free(action_desc);
 991 
 992     if (digests == NULL) {
 993         out->list_item(out, NULL, "none");
 994         out->end_list(out);
 995         return pcmk_rc_ok;
 996     }
 997     if (digests->digest_all_calc != NULL) {
 998         out->list_item(out, NULL, "%s (all parameters)",
 999                        digests->digest_all_calc);
1000     }
1001     if (digests->digest_secure_calc != NULL) {
1002         out->list_item(out, NULL, "%s (non-private parameters)",
1003                        digests->digest_secure_calc);
1004     }
1005     if (digests->digest_restart_calc != NULL) {
1006         out->list_item(out, NULL, "%s (non-reloadable parameters)",
1007                        digests->digest_restart_calc);
1008     }
1009     out->end_list(out);
1010     return pcmk_rc_ok;
1011 }
1012 
1013 static void
1014 add_digest_xml(xmlNode *parent, const char *type, const char *digest,
     /* [previous][next][first][last][top][bottom][index][help] */
1015                xmlNode *digest_source)
1016 {
1017     if (digest != NULL) {
1018         xmlNodePtr digest_xml = create_xml_node(parent, "digest");
1019 
1020         crm_xml_add(digest_xml, "type", ((type == NULL)? "unspecified" : type));
1021         crm_xml_add(digest_xml, "hash", digest);
1022         if (digest_source != NULL) {
1023             add_node_copy(digest_xml, digest_source);
1024         }
1025     }
1026 }
1027 
1028 PCMK__OUTPUT_ARGS("digests", "const pcmk_resource_t *", "const pcmk_node_t *",
     /* [previous][next][first][last][top][bottom][index][help] */
1029                   "const char *", "guint", "const op_digest_cache_t *")
1030 static int
1031 digests_xml(pcmk__output_t *out, va_list args)
1032 {
1033     const pcmk_resource_t *rsc = va_arg(args, const pcmk_resource_t *);
1034     const pcmk_node_t *node = va_arg(args, const pcmk_node_t *);
1035     const char *task = va_arg(args, const char *);
1036     guint interval_ms = va_arg(args, guint);
1037     const op_digest_cache_t *digests = va_arg(args, const op_digest_cache_t *);
1038 
1039     char *interval_s = crm_strdup_printf("%ums", interval_ms);
1040     xmlNode *xml = NULL;
1041 
1042     xml = pcmk__output_create_xml_node(out, "digests",
1043                                        "resource", pcmk__s(rsc->id, ""),
1044                                        "node",
1045                                        pcmk__s(node->details->uname, ""),
1046                                        "task", pcmk__s(task, ""),
1047                                        "interval", interval_s,
1048                                        NULL);
1049     free(interval_s);
1050     if (digests != NULL) {
1051         add_digest_xml(xml, "all", digests->digest_all_calc,
1052                        digests->params_all);
1053         add_digest_xml(xml, "nonprivate", digests->digest_secure_calc,
1054                        digests->params_secure);
1055         add_digest_xml(xml, "nonreloadable", digests->digest_restart_calc,
1056                        digests->params_restart);
1057     }
1058     return pcmk_rc_ok;
1059 }
1060 
1061 #define STOP_SANITY_ASSERT(lineno) do {                                 \
1062         if ((current != NULL) && current->details->unclean) {           \
1063             /* It will be a pseudo op */                                \
1064         } else if (stop == NULL) {                                      \
1065             crm_err("%s:%d: No stop action exists for %s",              \
1066                     __func__, lineno, rsc->id);                         \
1067             CRM_ASSERT(stop != NULL);                                   \
1068         } else if (pcmk_is_set(stop->flags, pcmk_action_optional)) {    \
1069             crm_err("%s:%d: Action %s is still optional",               \
1070                     __func__, lineno, stop->uuid);                      \
1071             CRM_ASSERT(!pcmk_is_set(stop->flags, pcmk_action_optional));\
1072         }                                                               \
1073     } while (0)
1074 
1075 PCMK__OUTPUT_ARGS("rsc-action", "pcmk_resource_t *", "pcmk_node_t *",
     /* [previous][next][first][last][top][bottom][index][help] */
1076                   "pcmk_node_t *")
1077 static int
1078 rsc_action_default(pcmk__output_t *out, va_list args)
1079 {
1080     pcmk_resource_t *rsc = va_arg(args, pcmk_resource_t *);
1081     pcmk_node_t *current = va_arg(args, pcmk_node_t *);
1082     pcmk_node_t *next = va_arg(args, pcmk_node_t *);
1083 
1084     GList *possible_matches = NULL;
1085     char *key = NULL;
1086     int rc = pcmk_rc_no_output;
1087     bool moving = false;
1088 
1089     pcmk_node_t *start_node = NULL;
1090     pcmk_action_t *start = NULL;
1091     pcmk_action_t *stop = NULL;
1092     pcmk_action_t *promote = NULL;
1093     pcmk_action_t *demote = NULL;
1094     pcmk_action_t *reason_op = NULL;
1095 
1096     if (!pcmk_is_set(rsc->flags, pcmk_rsc_managed)
1097         || (current == NULL && next == NULL)) {
1098         const bool managed = pcmk_is_set(rsc->flags, pcmk_rsc_managed);
1099 
1100         pe_rsc_info(rsc, "Leave   %s\t(%s%s)",
1101                     rsc->id, role2text(rsc->role),
1102                     (managed? "" : " unmanaged"));
1103         return rc;
1104     }
1105 
1106     moving = (current != NULL) && (next != NULL)
1107              && !pe__same_node(current, next);
1108 
1109     possible_matches = pe__resource_actions(rsc, next, PCMK_ACTION_START,
1110                                             false);
1111     if (possible_matches) {
1112         start = possible_matches->data;
1113         g_list_free(possible_matches);
1114     }
1115 
1116     if ((start == NULL)
1117         || !pcmk_is_set(start->flags, pcmk_action_runnable)) {
1118         start_node = NULL;
1119     } else {
1120         start_node = current;
1121     }
1122     possible_matches = pe__resource_actions(rsc, start_node, PCMK_ACTION_STOP,
1123                                             false);
1124     if (possible_matches) {
1125         stop = possible_matches->data;
1126         g_list_free(possible_matches);
1127     } else if (pcmk_is_set(rsc->flags, pcmk_rsc_stop_unexpected)) {
1128         /* The resource is multiply active with multiple-active set to
1129          * stop_unexpected, and not stopping on its current node, but it should
1130          * be stopping elsewhere.
1131          */
1132         possible_matches = pe__resource_actions(rsc, NULL, PCMK_ACTION_STOP,
1133                                                 false);
1134         if (possible_matches != NULL) {
1135             stop = possible_matches->data;
1136             g_list_free(possible_matches);
1137         }
1138     }
1139 
1140     possible_matches = pe__resource_actions(rsc, next, PCMK_ACTION_PROMOTE,
1141                                             false);
1142     if (possible_matches) {
1143         promote = possible_matches->data;
1144         g_list_free(possible_matches);
1145     }
1146 
1147     possible_matches = pe__resource_actions(rsc, next, PCMK_ACTION_DEMOTE,
1148                                             false);
1149     if (possible_matches) {
1150         demote = possible_matches->data;
1151         g_list_free(possible_matches);
1152     }
1153 
1154     if (rsc->role == rsc->next_role) {
1155         pcmk_action_t *migrate_op = NULL;
1156 
1157         CRM_CHECK(next != NULL, return rc);
1158 
1159         possible_matches = pe__resource_actions(rsc, next,
1160                                                 PCMK_ACTION_MIGRATE_FROM,
1161                                                 false);
1162         if (possible_matches) {
1163             migrate_op = possible_matches->data;
1164         }
1165 
1166         if ((migrate_op != NULL) && (current != NULL)
1167             && pcmk_is_set(migrate_op->flags, pcmk_action_runnable)) {
1168             rc = out->message(out, "rsc-action-item", "Migrate", rsc, current,
1169                               next, start, NULL);
1170 
1171         } else if (pcmk_is_set(rsc->flags, pcmk_rsc_reload)) {
1172             rc = out->message(out, "rsc-action-item", "Reload", rsc, current,
1173                               next, start, NULL);
1174 
1175         } else if ((start == NULL)
1176                    || pcmk_is_set(start->flags, pcmk_action_optional)) {
1177             if ((demote != NULL) && (promote != NULL)
1178                 && !pcmk_is_set(demote->flags, pcmk_action_optional)
1179                 && !pcmk_is_set(promote->flags, pcmk_action_optional)) {
1180                 rc = out->message(out, "rsc-action-item", "Re-promote", rsc,
1181                                   current, next, promote, demote);
1182             } else {
1183                 pe_rsc_info(rsc, "Leave   %s\t(%s %s)", rsc->id,
1184                             role2text(rsc->role), pe__node_name(next));
1185             }
1186 
1187         } else if (!pcmk_is_set(start->flags, pcmk_action_runnable)) {
1188             if ((stop == NULL) || (stop->reason == NULL)) {
1189                 reason_op = start;
1190             } else {
1191                 reason_op = stop;
1192             }
1193             rc = out->message(out, "rsc-action-item", "Stop", rsc, current,
1194                               NULL, stop, reason_op);
1195             STOP_SANITY_ASSERT(__LINE__);
1196 
1197         } else if (moving && current) {
1198             const bool failed = pcmk_is_set(rsc->flags, pcmk_rsc_failed);
1199 
1200             rc = out->message(out, "rsc-action-item",
1201                               (failed? "Recover" : "Move"), rsc, current, next,
1202                               stop, NULL);
1203 
1204         } else if (pcmk_is_set(rsc->flags, pcmk_rsc_failed)) {
1205             rc = out->message(out, "rsc-action-item", "Recover", rsc, current,
1206                               NULL, stop, NULL);
1207             STOP_SANITY_ASSERT(__LINE__);
1208 
1209         } else {
1210             rc = out->message(out, "rsc-action-item", "Restart", rsc, current,
1211                               next, start, NULL);
1212 #if 0
1213             /* @TODO This can be reached in situations that should really be
1214              * "Start" (see for example the migrate-fail-7 regression test)
1215              */
1216             STOP_SANITY_ASSERT(__LINE__);
1217 #endif
1218         }
1219 
1220         g_list_free(possible_matches);
1221         return rc;
1222     }
1223 
1224     if ((stop != NULL)
1225         && ((rsc->next_role == pcmk_role_stopped)
1226             || ((start != NULL)
1227                 && !pcmk_is_set(start->flags, pcmk_action_runnable)))) {
1228 
1229         key = stop_key(rsc);
1230         for (GList *iter = rsc->running_on; iter != NULL; iter = iter->next) {
1231             pcmk_node_t *node = iter->data;
1232             pcmk_action_t *stop_op = NULL;
1233 
1234             reason_op = start;
1235             possible_matches = find_actions(rsc->actions, key, node);
1236             if (possible_matches) {
1237                 stop_op = possible_matches->data;
1238                 g_list_free(possible_matches);
1239             }
1240 
1241             if (stop_op != NULL) {
1242                 if (pcmk_is_set(stop_op->flags, pcmk_action_runnable)) {
1243                     STOP_SANITY_ASSERT(__LINE__);
1244                 }
1245                 if (stop_op->reason != NULL) {
1246                     reason_op = stop_op;
1247                 }
1248             }
1249 
1250             if (out->message(out, "rsc-action-item", "Stop", rsc, node, NULL,
1251                              stop_op, reason_op) == pcmk_rc_ok) {
1252                 rc = pcmk_rc_ok;
1253             }
1254         }
1255 
1256         free(key);
1257 
1258     } else if ((stop != NULL)
1259                && pcmk_all_flags_set(rsc->flags,
1260                                      pcmk_rsc_failed|pcmk_rsc_stop_if_failed)) {
1261         /* 'stop' may be NULL if the failure was ignored */
1262         rc = out->message(out, "rsc-action-item", "Recover", rsc, current,
1263                           next, stop, start);
1264         STOP_SANITY_ASSERT(__LINE__);
1265 
1266     } else if (moving) {
1267         rc = out->message(out, "rsc-action-item", "Move", rsc, current, next,
1268                           stop, NULL);
1269         STOP_SANITY_ASSERT(__LINE__);
1270 
1271     } else if (pcmk_is_set(rsc->flags, pcmk_rsc_reload)) {
1272         rc = out->message(out, "rsc-action-item", "Reload", rsc, current, next,
1273                           start, NULL);
1274 
1275     } else if ((stop != NULL)
1276                && !pcmk_is_set(stop->flags, pcmk_action_optional)) {
1277         rc = out->message(out, "rsc-action-item", "Restart", rsc, current,
1278                           next, start, NULL);
1279         STOP_SANITY_ASSERT(__LINE__);
1280 
1281     } else if (rsc->role == pcmk_role_promoted) {
1282         CRM_LOG_ASSERT(current != NULL);
1283         rc = out->message(out, "rsc-action-item", "Demote", rsc, current,
1284                           next, demote, NULL);
1285 
1286     } else if (rsc->next_role == pcmk_role_promoted) {
1287         CRM_LOG_ASSERT(next);
1288         rc = out->message(out, "rsc-action-item", "Promote", rsc, current,
1289                           next, promote, NULL);
1290 
1291     } else if ((rsc->role == pcmk_role_stopped)
1292                && (rsc->next_role > pcmk_role_stopped)) {
1293         rc = out->message(out, "rsc-action-item", "Start", rsc, current, next,
1294                           start, NULL);
1295     }
1296 
1297     return rc;
1298 }
1299 
1300 PCMK__OUTPUT_ARGS("node-action", "const char *", "const char *", "const char *")
     /* [previous][next][first][last][top][bottom][index][help] */
1301 static int
1302 node_action(pcmk__output_t *out, va_list args)
1303 {
1304     const char *task = va_arg(args, const char *);
1305     const char *node_name = va_arg(args, const char *);
1306     const char *reason = va_arg(args, const char *);
1307 
1308     if (task == NULL) {
1309         return pcmk_rc_no_output;
1310     } else if (reason) {
1311         out->list_item(out, NULL, "%s %s '%s'", task, node_name, reason);
1312     } else {
1313         crm_notice(" * %s %s", task, node_name);
1314     }
1315 
1316     return pcmk_rc_ok;
1317 }
1318 
1319 PCMK__OUTPUT_ARGS("node-action", "const char *", "const char *", "const char *")
     /* [previous][next][first][last][top][bottom][index][help] */
1320 static int
1321 node_action_xml(pcmk__output_t *out, va_list args)
1322 {
1323     const char *task = va_arg(args, const char *);
1324     const char *node_name = va_arg(args, const char *);
1325     const char *reason = va_arg(args, const char *);
1326 
1327     if (task == NULL) {
1328         return pcmk_rc_no_output;
1329     } else if (reason) {
1330         pcmk__output_create_xml_node(out, "node_action",
1331                                      "task", task,
1332                                      "node", node_name,
1333                                      "reason", reason,
1334                                      NULL);
1335     } else {
1336         crm_notice(" * %s %s", task, node_name);
1337     }
1338 
1339     return pcmk_rc_ok;
1340 }
1341 
1342 PCMK__OUTPUT_ARGS("node-info", "uint32_t", "const char *", "const char *",
     /* [previous][next][first][last][top][bottom][index][help] */
1343                   "const char *", "bool", "bool")
1344 static int
1345 node_info_default(pcmk__output_t *out, va_list args)
1346 {
1347     uint32_t node_id = va_arg(args, uint32_t);
1348     const char *node_name = va_arg(args, const char *);
1349     const char *uuid = va_arg(args, const char *);
1350     const char *state = va_arg(args, const char *);
1351     bool have_quorum = (bool) va_arg(args, int);
1352     bool is_remote = (bool) va_arg(args, int);
1353 
1354     return out->info(out,
1355                      "Node %" PRIu32 ": %s "
1356                      "(uuid=%s, state=%s, have_quorum=%s, is_remote=%s)",
1357                      node_id, pcmk__s(node_name, "unknown"),
1358                      pcmk__s(uuid, "unknown"), pcmk__s(state, "unknown"),
1359                      pcmk__btoa(have_quorum), pcmk__btoa(is_remote));
1360 }
1361 
1362 PCMK__OUTPUT_ARGS("node-info", "uint32_t", "const char *", "const char *",
     /* [previous][next][first][last][top][bottom][index][help] */
1363                   "const char *", "bool", "bool")
1364 static int
1365 node_info_xml(pcmk__output_t *out, va_list args)
1366 {
1367     uint32_t node_id = va_arg(args, uint32_t);
1368     const char *node_name = va_arg(args, const char *);
1369     const char *uuid = va_arg(args, const char *);
1370     const char *state = va_arg(args, const char *);
1371     bool have_quorum = (bool) va_arg(args, int);
1372     bool is_remote = (bool) va_arg(args, int);
1373 
1374     char *id_s = crm_strdup_printf("%" PRIu32, node_id);
1375 
1376     pcmk__output_create_xml_node(out, "node-info",
1377                                  "nodeid", id_s,
1378                                  XML_ATTR_UNAME, node_name,
1379                                  XML_ATTR_ID, uuid,
1380                                  PCMK__XA_CRMD, state,
1381                                  XML_ATTR_HAVE_QUORUM, pcmk__btoa(have_quorum),
1382                                  XML_NODE_IS_REMOTE, pcmk__btoa(is_remote),
1383                                  NULL);
1384     free(id_s);
1385     return pcmk_rc_ok;
1386 }
1387 
1388 PCMK__OUTPUT_ARGS("inject-cluster-action", "const char *", "const char *",
     /* [previous][next][first][last][top][bottom][index][help] */
1389                   "xmlNodePtr")
1390 static int
1391 inject_cluster_action(pcmk__output_t *out, va_list args)
1392 {
1393     const char *node = va_arg(args, const char *);
1394     const char *task = va_arg(args, const char *);
1395     xmlNodePtr rsc = va_arg(args, xmlNodePtr);
1396 
1397     if (out->is_quiet(out)) {
1398         return pcmk_rc_no_output;
1399     }
1400 
1401     if (rsc != NULL) {
1402         out->list_item(out, NULL, "Cluster action:  %s for %s on %s",
1403                        task, ID(rsc), node);
1404     } else {
1405         out->list_item(out, NULL, "Cluster action:  %s on %s", task, node);
1406     }
1407 
1408     return pcmk_rc_ok;
1409 }
1410 
1411 PCMK__OUTPUT_ARGS("inject-cluster-action", "const char *", "const char *",
     /* [previous][next][first][last][top][bottom][index][help] */
1412                   "xmlNodePtr")
1413 static int
1414 inject_cluster_action_xml(pcmk__output_t *out, va_list args)
1415 {
1416     const char *node = va_arg(args, const char *);
1417     const char *task = va_arg(args, const char *);
1418     xmlNodePtr rsc = va_arg(args, xmlNodePtr);
1419 
1420     xmlNodePtr xml_node = NULL;
1421 
1422     if (out->is_quiet(out)) {
1423         return pcmk_rc_no_output;
1424     }
1425 
1426     xml_node = pcmk__output_create_xml_node(out, "cluster_action",
1427                                             "task", task,
1428                                             "node", node,
1429                                             NULL);
1430 
1431     if (rsc) {
1432         crm_xml_add(xml_node, "id", ID(rsc));
1433     }
1434 
1435     return pcmk_rc_ok;
1436 }
1437 
1438 PCMK__OUTPUT_ARGS("inject-fencing-action", "const char *", "const char *")
     /* [previous][next][first][last][top][bottom][index][help] */
1439 static int
1440 inject_fencing_action(pcmk__output_t *out, va_list args)
1441 {
1442     const char *target = va_arg(args, const char *);
1443     const char *op = va_arg(args, const char *);
1444 
1445     if (out->is_quiet(out)) {
1446         return pcmk_rc_no_output;
1447     }
1448 
1449     out->list_item(out, NULL, "Fencing %s (%s)", target, op);
1450     return pcmk_rc_ok;
1451 }
1452 
1453 PCMK__OUTPUT_ARGS("inject-fencing-action", "const char *", "const char *")
     /* [previous][next][first][last][top][bottom][index][help] */
1454 static int
1455 inject_fencing_action_xml(pcmk__output_t *out, va_list args)
1456 {
1457     const char *target = va_arg(args, const char *);
1458     const char *op = va_arg(args, const char *);
1459 
1460     if (out->is_quiet(out)) {
1461         return pcmk_rc_no_output;
1462     }
1463 
1464     pcmk__output_create_xml_node(out, "fencing_action",
1465                                  "target", target,
1466                                  "op", op,
1467                                  NULL);
1468     return pcmk_rc_ok;
1469 }
1470 
1471 PCMK__OUTPUT_ARGS("inject-attr", "const char *", "const char *", "xmlNodePtr")
     /* [previous][next][first][last][top][bottom][index][help] */
1472 static int
1473 inject_attr(pcmk__output_t *out, va_list args)
1474 {
1475     const char *name = va_arg(args, const char *);
1476     const char *value = va_arg(args, const char *);
1477     xmlNodePtr cib_node = va_arg(args, xmlNodePtr);
1478 
1479     xmlChar *node_path = NULL;
1480 
1481     if (out->is_quiet(out)) {
1482         return pcmk_rc_no_output;
1483     }
1484 
1485     node_path = xmlGetNodePath(cib_node);
1486 
1487     out->list_item(out, NULL, "Injecting attribute %s=%s into %s '%s'",
1488                    name, value, node_path, ID(cib_node));
1489 
1490     free(node_path);
1491     return pcmk_rc_ok;
1492 }
1493 
1494 PCMK__OUTPUT_ARGS("inject-attr", "const char *", "const char *", "xmlNodePtr")
     /* [previous][next][first][last][top][bottom][index][help] */
1495 static int
1496 inject_attr_xml(pcmk__output_t *out, va_list args)
1497 {
1498     const char *name = va_arg(args, const char *);
1499     const char *value = va_arg(args, const char *);
1500     xmlNodePtr cib_node = va_arg(args, xmlNodePtr);
1501 
1502     xmlChar *node_path = NULL;
1503 
1504     if (out->is_quiet(out)) {
1505         return pcmk_rc_no_output;
1506     }
1507 
1508     node_path = xmlGetNodePath(cib_node);
1509 
1510     pcmk__output_create_xml_node(out, "inject_attr",
1511                                  "name", name,
1512                                  "value", value,
1513                                  "node_path", node_path,
1514                                  "cib_node", ID(cib_node),
1515                                  NULL);
1516     free(node_path);
1517     return pcmk_rc_ok;
1518 }
1519 
1520 PCMK__OUTPUT_ARGS("inject-spec", "const char *")
     /* [previous][next][first][last][top][bottom][index][help] */
1521 static int
1522 inject_spec(pcmk__output_t *out, va_list args)
1523 {
1524     const char *spec = va_arg(args, const char *);
1525 
1526     if (out->is_quiet(out)) {
1527         return pcmk_rc_no_output;
1528     }
1529 
1530     out->list_item(out, NULL, "Injecting %s into the configuration", spec);
1531     return pcmk_rc_ok;
1532 }
1533 
1534 PCMK__OUTPUT_ARGS("inject-spec", "const char *")
     /* [previous][next][first][last][top][bottom][index][help] */
1535 static int
1536 inject_spec_xml(pcmk__output_t *out, va_list args)
1537 {
1538     const char *spec = va_arg(args, const char *);
1539 
1540     if (out->is_quiet(out)) {
1541         return pcmk_rc_no_output;
1542     }
1543 
1544     pcmk__output_create_xml_node(out, "inject_spec",
1545                                  "spec", spec,
1546                                  NULL);
1547     return pcmk_rc_ok;
1548 }
1549 
1550 PCMK__OUTPUT_ARGS("inject-modify-config", "const char *", "const char *")
     /* [previous][next][first][last][top][bottom][index][help] */
1551 static int
1552 inject_modify_config(pcmk__output_t *out, va_list args)
1553 {
1554     const char *quorum = va_arg(args, const char *);
1555     const char *watchdog = va_arg(args, const char *);
1556 
1557     if (out->is_quiet(out)) {
1558         return pcmk_rc_no_output;
1559     }
1560 
1561     out->begin_list(out, NULL, NULL, "Performing Requested Modifications");
1562 
1563     if (quorum) {
1564         out->list_item(out, NULL, "Setting quorum: %s", quorum);
1565     }
1566 
1567     if (watchdog) {
1568         out->list_item(out, NULL, "Setting watchdog: %s", watchdog);
1569     }
1570 
1571     return pcmk_rc_ok;
1572 }
1573 
1574 PCMK__OUTPUT_ARGS("inject-modify-config", "const char *", "const char *")
     /* [previous][next][first][last][top][bottom][index][help] */
1575 static int
1576 inject_modify_config_xml(pcmk__output_t *out, va_list args)
1577 {
1578     const char *quorum = va_arg(args, const char *);
1579     const char *watchdog = va_arg(args, const char *);
1580 
1581     xmlNodePtr node = NULL;
1582 
1583     if (out->is_quiet(out)) {
1584         return pcmk_rc_no_output;
1585     }
1586 
1587     node = pcmk__output_xml_create_parent(out, "modifications", NULL);
1588 
1589     if (quorum) {
1590         crm_xml_add(node, "quorum", quorum);
1591     }
1592 
1593     if (watchdog) {
1594         crm_xml_add(node, "watchdog", watchdog);
1595     }
1596 
1597     return pcmk_rc_ok;
1598 }
1599 
1600 PCMK__OUTPUT_ARGS("inject-modify-node", "const char *", "const char *")
     /* [previous][next][first][last][top][bottom][index][help] */
1601 static int
1602 inject_modify_node(pcmk__output_t *out, va_list args)
1603 {
1604     const char *action = va_arg(args, const char *);
1605     const char *node = va_arg(args, const char *);
1606 
1607     if (out->is_quiet(out)) {
1608         return pcmk_rc_no_output;
1609     }
1610 
1611     if (pcmk__str_eq(action, "Online", pcmk__str_none)) {
1612         out->list_item(out, NULL, "Bringing node %s online", node);
1613         return pcmk_rc_ok;
1614     } else if (pcmk__str_eq(action, "Offline", pcmk__str_none)) {
1615         out->list_item(out, NULL, "Taking node %s offline", node);
1616         return pcmk_rc_ok;
1617     } else if (pcmk__str_eq(action, "Failing", pcmk__str_none)) {
1618         out->list_item(out, NULL, "Failing node %s", node);
1619         return pcmk_rc_ok;
1620     }
1621 
1622     return pcmk_rc_no_output;
1623 }
1624 
1625 PCMK__OUTPUT_ARGS("inject-modify-node", "const char *", "const char *")
     /* [previous][next][first][last][top][bottom][index][help] */
1626 static int
1627 inject_modify_node_xml(pcmk__output_t *out, va_list args)
1628 {
1629     const char *action = va_arg(args, const char *);
1630     const char *node = va_arg(args, const char *);
1631 
1632     if (out->is_quiet(out)) {
1633         return pcmk_rc_no_output;
1634     }
1635 
1636     pcmk__output_create_xml_node(out, "modify_node",
1637                                  "action", action,
1638                                  "node", node,
1639                                  NULL);
1640     return pcmk_rc_ok;
1641 }
1642 
1643 PCMK__OUTPUT_ARGS("inject-modify-ticket", "const char *", "const char *")
     /* [previous][next][first][last][top][bottom][index][help] */
1644 static int
1645 inject_modify_ticket(pcmk__output_t *out, va_list args)
1646 {
1647     const char *action = va_arg(args, const char *);
1648     const char *ticket = va_arg(args, const char *);
1649 
1650     if (out->is_quiet(out)) {
1651         return pcmk_rc_no_output;
1652     }
1653 
1654     if (pcmk__str_eq(action, "Standby", pcmk__str_none)) {
1655         out->list_item(out, NULL, "Making ticket %s standby", ticket);
1656     } else {
1657         out->list_item(out, NULL, "%s ticket %s", action, ticket);
1658     }
1659 
1660     return pcmk_rc_ok;
1661 }
1662 
1663 PCMK__OUTPUT_ARGS("inject-modify-ticket", "const char *", "const char *")
     /* [previous][next][first][last][top][bottom][index][help] */
1664 static int
1665 inject_modify_ticket_xml(pcmk__output_t *out, va_list args)
1666 {
1667     const char *action = va_arg(args, const char *);
1668     const char *ticket = va_arg(args, const char *);
1669 
1670     if (out->is_quiet(out)) {
1671         return pcmk_rc_no_output;
1672     }
1673 
1674     pcmk__output_create_xml_node(out, "modify_ticket",
1675                                  "action", action,
1676                                  "ticket", ticket,
1677                                  NULL);
1678     return pcmk_rc_ok;
1679 }
1680 
1681 PCMK__OUTPUT_ARGS("inject-pseudo-action", "const char *", "const char *")
     /* [previous][next][first][last][top][bottom][index][help] */
1682 static int
1683 inject_pseudo_action(pcmk__output_t *out, va_list args)
1684 {
1685     const char *node = va_arg(args, const char *);
1686     const char *task = va_arg(args, const char *);
1687 
1688     if (out->is_quiet(out)) {
1689         return pcmk_rc_no_output;
1690     }
1691 
1692     out->list_item(out, NULL, "Pseudo action:   %s%s%s",
1693                    task, ((node == NULL)? "" : " on "), pcmk__s(node, ""));
1694     return pcmk_rc_ok;
1695 }
1696 
1697 PCMK__OUTPUT_ARGS("inject-pseudo-action", "const char *", "const char *")
     /* [previous][next][first][last][top][bottom][index][help] */
1698 static int
1699 inject_pseudo_action_xml(pcmk__output_t *out, va_list args)
1700 {
1701     const char *node = va_arg(args, const char *);
1702     const char *task = va_arg(args, const char *);
1703 
1704     xmlNodePtr xml_node = NULL;
1705 
1706     if (out->is_quiet(out)) {
1707         return pcmk_rc_no_output;
1708     }
1709 
1710     xml_node = pcmk__output_create_xml_node(out, "pseudo_action",
1711                                             "task", task,
1712                                             NULL);
1713     if (node) {
1714         crm_xml_add(xml_node, "node", node);
1715     }
1716 
1717     return pcmk_rc_ok;
1718 }
1719 
1720 PCMK__OUTPUT_ARGS("inject-rsc-action", "const char *", "const char *",
     /* [previous][next][first][last][top][bottom][index][help] */
1721                   "const char *", "guint")
1722 static int
1723 inject_rsc_action(pcmk__output_t *out, va_list args)
1724 {
1725     const char *rsc = va_arg(args, const char *);
1726     const char *operation = va_arg(args, const char *);
1727     const char *node = va_arg(args, const char *);
1728     guint interval_ms = va_arg(args, guint);
1729 
1730     if (out->is_quiet(out)) {
1731         return pcmk_rc_no_output;
1732     }
1733 
1734     if (interval_ms) {
1735         out->list_item(out, NULL, "Resource action: %-15s %s=%u on %s",
1736                        rsc, operation, interval_ms, node);
1737     } else {
1738         out->list_item(out, NULL, "Resource action: %-15s %s on %s",
1739                        rsc, operation, node);
1740     }
1741 
1742     return pcmk_rc_ok;
1743 }
1744 
1745 PCMK__OUTPUT_ARGS("inject-rsc-action", "const char *", "const char *",
     /* [previous][next][first][last][top][bottom][index][help] */
1746                   "const char *", "guint")
1747 static int
1748 inject_rsc_action_xml(pcmk__output_t *out, va_list args)
1749 {
1750     const char *rsc = va_arg(args, const char *);
1751     const char *operation = va_arg(args, const char *);
1752     const char *node = va_arg(args, const char *);
1753     guint interval_ms = va_arg(args, guint);
1754 
1755     xmlNodePtr xml_node = NULL;
1756 
1757     if (out->is_quiet(out)) {
1758         return pcmk_rc_no_output;
1759     }
1760 
1761     xml_node = pcmk__output_create_xml_node(out, "rsc_action",
1762                                             "resource", rsc,
1763                                             "op", operation,
1764                                             "node", node,
1765                                             NULL);
1766 
1767     if (interval_ms) {
1768         char *interval_s = pcmk__itoa(interval_ms);
1769 
1770         crm_xml_add(xml_node, "interval", interval_s);
1771         free(interval_s);
1772     }
1773 
1774     return pcmk_rc_ok;
1775 }
1776 
1777 #define CHECK_RC(retcode, retval)   \
1778     if (retval == pcmk_rc_ok) {     \
1779         retcode = pcmk_rc_ok;       \
1780     }
1781 
1782 PCMK__OUTPUT_ARGS("cluster-status", "pcmk_scheduler_t *",
     /* [previous][next][first][last][top][bottom][index][help] */
1783                   "enum pcmk_pacemakerd_state", "crm_exit_t",
1784                   "stonith_history_t *", "enum pcmk__fence_history", "uint32_t",
1785                   "uint32_t", "const char *", "GList *", "GList *")
1786 int
1787 pcmk__cluster_status_text(pcmk__output_t *out, va_list args)
1788 {
1789     pcmk_scheduler_t *scheduler = va_arg(args, pcmk_scheduler_t *);
1790     enum pcmk_pacemakerd_state pcmkd_state =
1791         (enum pcmk_pacemakerd_state) va_arg(args, int);
1792     crm_exit_t history_rc = va_arg(args, crm_exit_t);
1793     stonith_history_t *stonith_history = va_arg(args, stonith_history_t *);
1794     enum pcmk__fence_history fence_history = va_arg(args, int);
1795     uint32_t section_opts = va_arg(args, uint32_t);
1796     uint32_t show_opts = va_arg(args, uint32_t);
1797     const char *prefix = va_arg(args, const char *);
1798     GList *unames = va_arg(args, GList *);
1799     GList *resources = va_arg(args, GList *);
1800 
1801     int rc = pcmk_rc_no_output;
1802     bool already_printed_failure = false;
1803 
1804     CHECK_RC(rc, out->message(out, "cluster-summary", scheduler, pcmkd_state,
1805                               section_opts, show_opts));
1806 
1807     if (pcmk_is_set(section_opts, pcmk_section_nodes) && unames) {
1808         CHECK_RC(rc, out->message(out, "node-list", scheduler->nodes, unames,
1809                                   resources, show_opts, rc == pcmk_rc_ok));
1810     }
1811 
1812     /* Print resources section, if needed */
1813     if (pcmk_is_set(section_opts, pcmk_section_resources)) {
1814         CHECK_RC(rc, out->message(out, "resource-list", scheduler, show_opts,
1815                                   true, unames, resources, rc == pcmk_rc_ok));
1816     }
1817 
1818     /* print Node Attributes section if requested */
1819     if (pcmk_is_set(section_opts, pcmk_section_attributes)) {
1820         CHECK_RC(rc, out->message(out, "node-attribute-list", scheduler,
1821                                   show_opts, (rc == pcmk_rc_ok), unames,
1822                                   resources));
1823     }
1824 
1825     /* If requested, print resource operations (which includes failcounts)
1826      * or just failcounts
1827      */
1828     if (pcmk_any_flags_set(section_opts,
1829                            pcmk_section_operations|pcmk_section_failcounts)) {
1830         CHECK_RC(rc, out->message(out, "node-summary", scheduler, unames,
1831                                   resources, section_opts, show_opts,
1832                                   (rc == pcmk_rc_ok)));
1833     }
1834 
1835     /* If there were any failed actions, print them */
1836     if (pcmk_is_set(section_opts, pcmk_section_failures)
1837         && (scheduler->failed != NULL)
1838         && (scheduler->failed->children != NULL)) {
1839 
1840         CHECK_RC(rc, out->message(out, "failed-action-list", scheduler, unames,
1841                                   resources, show_opts, rc == pcmk_rc_ok));
1842     }
1843 
1844     /* Print failed stonith actions */
1845     if (pcmk_is_set(section_opts, pcmk_section_fence_failed) &&
1846         fence_history != pcmk__fence_history_none) {
1847         if (history_rc == 0) {
1848             stonith_history_t *hp = NULL;
1849 
1850             hp = stonith__first_matching_event(stonith_history,
1851                                                stonith__event_state_eq,
1852                                                GINT_TO_POINTER(st_failed));
1853             if (hp) {
1854                 CHECK_RC(rc, out->message(out, "failed-fencing-list",
1855                                           stonith_history, unames, section_opts,
1856                                           show_opts, rc == pcmk_rc_ok));
1857             }
1858         } else {
1859             PCMK__OUTPUT_SPACER_IF(out, rc == pcmk_rc_ok);
1860             out->begin_list(out, NULL, NULL, "Failed Fencing Actions");
1861             out->list_item(out, NULL, "Failed to get fencing history: %s",
1862                            crm_exit_str(history_rc));
1863             out->end_list(out);
1864 
1865             already_printed_failure = true;
1866         }
1867     }
1868 
1869     /* Print tickets if requested */
1870     if (pcmk_is_set(section_opts, pcmk_section_tickets)) {
1871         CHECK_RC(rc, out->message(out, "ticket-list", scheduler,
1872                                   (rc == pcmk_rc_ok)));
1873     }
1874 
1875     /* Print negative location constraints if requested */
1876     if (pcmk_is_set(section_opts, pcmk_section_bans)) {
1877         CHECK_RC(rc, out->message(out, "ban-list", scheduler, prefix, resources,
1878                                   show_opts, rc == pcmk_rc_ok));
1879     }
1880 
1881     /* Print stonith history */
1882     if (pcmk_any_flags_set(section_opts, pcmk_section_fencing_all) &&
1883         fence_history != pcmk__fence_history_none) {
1884         if (history_rc != 0) {
1885             if (!already_printed_failure) {
1886                 PCMK__OUTPUT_SPACER_IF(out, rc == pcmk_rc_ok);
1887                 out->begin_list(out, NULL, NULL, "Failed Fencing Actions");
1888                 out->list_item(out, NULL, "Failed to get fencing history: %s",
1889                                crm_exit_str(history_rc));
1890                 out->end_list(out);
1891             }
1892         } else if (pcmk_is_set(section_opts, pcmk_section_fence_worked)) {
1893             stonith_history_t *hp = NULL;
1894 
1895             hp = stonith__first_matching_event(stonith_history,
1896                                                stonith__event_state_neq,
1897                                                GINT_TO_POINTER(st_failed));
1898             if (hp) {
1899                 CHECK_RC(rc, out->message(out, "fencing-list", hp, unames,
1900                                           section_opts, show_opts,
1901                                           rc == pcmk_rc_ok));
1902             }
1903         } else if (pcmk_is_set(section_opts, pcmk_section_fence_pending)) {
1904             stonith_history_t *hp = NULL;
1905 
1906             hp = stonith__first_matching_event(stonith_history,
1907                                                stonith__event_state_pending,
1908                                                NULL);
1909             if (hp) {
1910                 CHECK_RC(rc, out->message(out, "pending-fencing-list", hp,
1911                                           unames, section_opts, show_opts,
1912                                           rc == pcmk_rc_ok));
1913             }
1914         }
1915     }
1916 
1917     return rc;
1918 }
1919 
1920 PCMK__OUTPUT_ARGS("cluster-status", "pcmk_scheduler_t *",
     /* [previous][next][first][last][top][bottom][index][help] */
1921                   "enum pcmk_pacemakerd_state", "crm_exit_t",
1922                   "stonith_history_t *", "enum pcmk__fence_history", "uint32_t",
1923                   "uint32_t", "const char *", "GList *", "GList *")
1924 static int
1925 cluster_status_xml(pcmk__output_t *out, va_list args)
1926 {
1927     pcmk_scheduler_t *scheduler = va_arg(args, pcmk_scheduler_t *);
1928     enum pcmk_pacemakerd_state pcmkd_state =
1929         (enum pcmk_pacemakerd_state) va_arg(args, int);
1930     crm_exit_t history_rc = va_arg(args, crm_exit_t);
1931     stonith_history_t *stonith_history = va_arg(args, stonith_history_t *);
1932     enum pcmk__fence_history fence_history = va_arg(args, int);
1933     uint32_t section_opts = va_arg(args, uint32_t);
1934     uint32_t show_opts = va_arg(args, uint32_t);
1935     const char *prefix = va_arg(args, const char *);
1936     GList *unames = va_arg(args, GList *);
1937     GList *resources = va_arg(args, GList *);
1938 
1939     out->message(out, "cluster-summary", scheduler, pcmkd_state, section_opts,
1940                  show_opts);
1941 
1942     /*** NODES ***/
1943     if (pcmk_is_set(section_opts, pcmk_section_nodes)) {
1944         out->message(out, "node-list", scheduler->nodes, unames, resources,
1945                      show_opts, false);
1946     }
1947 
1948     /* Print resources section, if needed */
1949     if (pcmk_is_set(section_opts, pcmk_section_resources)) {
1950         /* XML output always displays full details. */
1951         uint32_t full_show_opts = show_opts & ~pcmk_show_brief;
1952 
1953         out->message(out, "resource-list", scheduler, full_show_opts,
1954                      false, unames, resources, false);
1955     }
1956 
1957     /* print Node Attributes section if requested */
1958     if (pcmk_is_set(section_opts, pcmk_section_attributes)) {
1959         out->message(out, "node-attribute-list", scheduler, show_opts, false,
1960                      unames, resources);
1961     }
1962 
1963     /* If requested, print resource operations (which includes failcounts)
1964      * or just failcounts
1965      */
1966     if (pcmk_any_flags_set(section_opts,
1967                            pcmk_section_operations|pcmk_section_failcounts)) {
1968         out->message(out, "node-summary", scheduler, unames,
1969                      resources, section_opts, show_opts, false);
1970     }
1971 
1972     /* If there were any failed actions, print them */
1973     if (pcmk_is_set(section_opts, pcmk_section_failures)
1974         && (scheduler->failed != NULL)
1975         && (scheduler->failed->children != NULL)) {
1976 
1977         out->message(out, "failed-action-list", scheduler, unames, resources,
1978                      show_opts, false);
1979     }
1980 
1981     /* Print stonith history */
1982     if (pcmk_is_set(section_opts, pcmk_section_fencing_all) &&
1983         fence_history != pcmk__fence_history_none) {
1984         out->message(out, "full-fencing-list", history_rc, stonith_history,
1985                      unames, section_opts, show_opts, false);
1986     }
1987 
1988     /* Print tickets if requested */
1989     if (pcmk_is_set(section_opts, pcmk_section_tickets)) {
1990         out->message(out, "ticket-list", scheduler, false);
1991     }
1992 
1993     /* Print negative location constraints if requested */
1994     if (pcmk_is_set(section_opts, pcmk_section_bans)) {
1995         out->message(out, "ban-list", scheduler, prefix, resources, show_opts,
1996                      false);
1997     }
1998 
1999     return pcmk_rc_ok;
2000 }
2001 
2002 PCMK__OUTPUT_ARGS("cluster-status", "pcmk_scheduler_t *",
     /* [previous][next][first][last][top][bottom][index][help] */
2003                   "enum pcmk_pacemakerd_state", "crm_exit_t",
2004                   "stonith_history_t *", "enum pcmk__fence_history", "uint32_t",
2005                   "uint32_t", "const char *", "GList *", "GList *")
2006 static int
2007 cluster_status_html(pcmk__output_t *out, va_list args)
2008 {
2009     pcmk_scheduler_t *scheduler = va_arg(args, pcmk_scheduler_t *);
2010     enum pcmk_pacemakerd_state pcmkd_state =
2011         (enum pcmk_pacemakerd_state) va_arg(args, int);
2012     crm_exit_t history_rc = va_arg(args, crm_exit_t);
2013     stonith_history_t *stonith_history = va_arg(args, stonith_history_t *);
2014     enum pcmk__fence_history fence_history = va_arg(args, int);
2015     uint32_t section_opts = va_arg(args, uint32_t);
2016     uint32_t show_opts = va_arg(args, uint32_t);
2017     const char *prefix = va_arg(args, const char *);
2018     GList *unames = va_arg(args, GList *);
2019     GList *resources = va_arg(args, GList *);
2020     bool already_printed_failure = false;
2021 
2022     out->message(out, "cluster-summary", scheduler, pcmkd_state, section_opts,
2023                  show_opts);
2024 
2025     /*** NODE LIST ***/
2026     if (pcmk_is_set(section_opts, pcmk_section_nodes) && unames) {
2027         out->message(out, "node-list", scheduler->nodes, unames, resources,
2028                      show_opts, false);
2029     }
2030 
2031     /* Print resources section, if needed */
2032     if (pcmk_is_set(section_opts, pcmk_section_resources)) {
2033         out->message(out, "resource-list", scheduler, show_opts, true, unames,
2034                      resources, false);
2035     }
2036 
2037     /* print Node Attributes section if requested */
2038     if (pcmk_is_set(section_opts, pcmk_section_attributes)) {
2039         out->message(out, "node-attribute-list", scheduler, show_opts, false,
2040                      unames, resources);
2041     }
2042 
2043     /* If requested, print resource operations (which includes failcounts)
2044      * or just failcounts
2045      */
2046     if (pcmk_any_flags_set(section_opts,
2047                            pcmk_section_operations|pcmk_section_failcounts)) {
2048         out->message(out, "node-summary", scheduler, unames,
2049                      resources, section_opts, show_opts, false);
2050     }
2051 
2052     /* If there were any failed actions, print them */
2053     if (pcmk_is_set(section_opts, pcmk_section_failures)
2054         && (scheduler->failed != NULL)
2055         && (scheduler->failed->children != NULL)) {
2056 
2057         out->message(out, "failed-action-list", scheduler, unames, resources,
2058                      show_opts, false);
2059     }
2060 
2061     /* Print failed stonith actions */
2062     if (pcmk_is_set(section_opts, pcmk_section_fence_failed) &&
2063         fence_history != pcmk__fence_history_none) {
2064         if (history_rc == 0) {
2065             stonith_history_t *hp = NULL;
2066 
2067             hp = stonith__first_matching_event(stonith_history,
2068                                                stonith__event_state_eq,
2069                                                GINT_TO_POINTER(st_failed));
2070             if (hp) {
2071                 out->message(out, "failed-fencing-list", stonith_history,
2072                              unames, section_opts, show_opts, false);
2073             }
2074         } else {
2075             out->begin_list(out, NULL, NULL, "Failed Fencing Actions");
2076             out->list_item(out, NULL, "Failed to get fencing history: %s",
2077                            crm_exit_str(history_rc));
2078             out->end_list(out);
2079         }
2080     }
2081 
2082     /* Print stonith history */
2083     if (pcmk_any_flags_set(section_opts, pcmk_section_fencing_all) &&
2084         fence_history != pcmk__fence_history_none) {
2085         if (history_rc != 0) {
2086             if (!already_printed_failure) {
2087                 out->begin_list(out, NULL, NULL, "Failed Fencing Actions");
2088                 out->list_item(out, NULL, "Failed to get fencing history: %s",
2089                                crm_exit_str(history_rc));
2090                 out->end_list(out);
2091             }
2092         } else if (pcmk_is_set(section_opts, pcmk_section_fence_worked)) {
2093             stonith_history_t *hp = NULL;
2094 
2095             hp = stonith__first_matching_event(stonith_history,
2096                                                stonith__event_state_neq,
2097                                                GINT_TO_POINTER(st_failed));
2098             if (hp) {
2099                 out->message(out, "fencing-list", hp, unames, section_opts,
2100                              show_opts, false);
2101             }
2102         } else if (pcmk_is_set(section_opts, pcmk_section_fence_pending)) {
2103             stonith_history_t *hp = NULL;
2104 
2105             hp = stonith__first_matching_event(stonith_history,
2106                                                stonith__event_state_pending,
2107                                                NULL);
2108             if (hp) {
2109                 out->message(out, "pending-fencing-list", hp, unames,
2110                              section_opts, show_opts, false);
2111             }
2112         }
2113     }
2114 
2115     /* Print tickets if requested */
2116     if (pcmk_is_set(section_opts, pcmk_section_tickets)) {
2117         out->message(out, "ticket-list", scheduler, false);
2118     }
2119 
2120     /* Print negative location constraints if requested */
2121     if (pcmk_is_set(section_opts, pcmk_section_bans)) {
2122         out->message(out, "ban-list", scheduler, prefix, resources, show_opts,
2123                      false);
2124     }
2125 
2126     return pcmk_rc_ok;
2127 }
2128 
2129 PCMK__OUTPUT_ARGS("attribute", "const char *", "const char *", "const char *",
     /* [previous][next][first][last][top][bottom][index][help] */
2130                   "const char *", "const char *")
2131 static int
2132 attribute_default(pcmk__output_t *out, va_list args)
2133 {
2134     const char *scope = va_arg(args, const char *);
2135     const char *instance = va_arg(args, const char *);
2136     const char *name = va_arg(args, const char *);
2137     const char *value = va_arg(args, const char *);
2138     const char *host = va_arg(args, const char *);
2139 
2140     GString *s = g_string_sized_new(50);
2141 
2142     if (!pcmk__str_empty(scope)) {
2143         pcmk__g_strcat(s, "scope=\"", scope, "\" ", NULL);
2144     }
2145 
2146     if (!pcmk__str_empty(instance)) {
2147         pcmk__g_strcat(s, "id=\"", instance, "\" ", NULL);
2148     }
2149 
2150     pcmk__g_strcat(s, "name=\"", pcmk__s(name, ""), "\" ", NULL);
2151 
2152     if (!pcmk__str_empty(host)) {
2153         pcmk__g_strcat(s, "host=\"", host, "\" ", NULL);
2154     }
2155 
2156     pcmk__g_strcat(s, "value=\"", pcmk__s(value, ""), "\"", NULL);
2157 
2158     out->info(out, "%s", s->str);
2159     g_string_free(s, TRUE);
2160 
2161     return pcmk_rc_ok;
2162 }
2163 
2164 PCMK__OUTPUT_ARGS("attribute", "const char *", "const char *", "const char *",
     /* [previous][next][first][last][top][bottom][index][help] */
2165                   "const char *", "const char *")
2166 static int
2167 attribute_xml(pcmk__output_t *out, va_list args)
2168 {
2169     const char *scope = va_arg(args, const char *);
2170     const char *instance = va_arg(args, const char *);
2171     const char *name = va_arg(args, const char *);
2172     const char *value = va_arg(args, const char *);
2173     const char *host = va_arg(args, const char *);
2174 
2175     xmlNodePtr node = NULL;
2176 
2177     node = pcmk__output_create_xml_node(out, "attribute",
2178                                         "name", name,
2179                                         "value", value ? value : "",
2180                                         NULL);
2181 
2182     if (!pcmk__str_empty(scope)) {
2183         crm_xml_add(node, "scope", scope);
2184     }
2185 
2186     if (!pcmk__str_empty(instance)) {
2187         crm_xml_add(node, "id", instance);
2188     }
2189 
2190     if (!pcmk__str_empty(host)) {
2191         crm_xml_add(node, "host", host);
2192     }
2193 
2194     return pcmk_rc_ok;
2195 }
2196 
2197 PCMK__OUTPUT_ARGS("rule-check", "const char *", "int", "const char *")
     /* [previous][next][first][last][top][bottom][index][help] */
2198 static int
2199 rule_check_default(pcmk__output_t *out, va_list args)
2200 {
2201     const char *rule_id = va_arg(args, const char *);
2202     int result = va_arg(args, int);
2203     const char *error = va_arg(args, const char *);
2204 
2205     switch (result) {
2206         case pcmk_rc_within_range:
2207             return out->info(out, "Rule %s is still in effect", rule_id);
2208         case pcmk_rc_ok:
2209             return out->info(out, "Rule %s satisfies conditions", rule_id);
2210         case pcmk_rc_after_range:
2211             return out->info(out, "Rule %s is expired", rule_id);
2212         case pcmk_rc_before_range:
2213             return out->info(out, "Rule %s has not yet taken effect", rule_id);
2214         case pcmk_rc_op_unsatisfied:
2215             return out->info(out, "Rule %s does not satisfy conditions",
2216                              rule_id);
2217         default:
2218             out->err(out,
2219                      "Could not determine whether rule %s is in effect: %s",
2220                      rule_id, ((error != NULL)? error : "unexpected error"));
2221             return pcmk_rc_ok;
2222     }
2223 }
2224 
2225 PCMK__OUTPUT_ARGS("rule-check", "const char *", "int", "const char *")
     /* [previous][next][first][last][top][bottom][index][help] */
2226 static int
2227 rule_check_xml(pcmk__output_t *out, va_list args)
2228 {
2229     const char *rule_id = va_arg(args, const char *);
2230     int result = va_arg(args, int);
2231     const char *error = va_arg(args, const char *);
2232 
2233     char *rc_str = pcmk__itoa(pcmk_rc2exitc(result));
2234 
2235     pcmk__output_create_xml_node(out, "rule-check",
2236                                  "rule-id", rule_id,
2237                                  "rc", rc_str,
2238                                  NULL);
2239     free(rc_str);
2240 
2241     switch (result) {
2242         case pcmk_rc_within_range:
2243         case pcmk_rc_ok:
2244         case pcmk_rc_after_range:
2245         case pcmk_rc_before_range:
2246         case pcmk_rc_op_unsatisfied:
2247             return pcmk_rc_ok;
2248         default:
2249             out->err(out,
2250                     "Could not determine whether rule %s is in effect: %s",
2251                     rule_id, ((error != NULL)? error : "unexpected error"));
2252             return pcmk_rc_ok;
2253     }
2254 }
2255 
2256 PCMK__OUTPUT_ARGS("result-code", "int", "const char *", "const char *")
     /* [previous][next][first][last][top][bottom][index][help] */
2257 static int
2258 result_code_none(pcmk__output_t *out, va_list args)
2259 {
2260     return pcmk_rc_no_output;
2261 }
2262 
2263 PCMK__OUTPUT_ARGS("result-code", "int", "const char *", "const char *")
     /* [previous][next][first][last][top][bottom][index][help] */
2264 static int
2265 result_code_text(pcmk__output_t *out, va_list args)
2266 {
2267     int code = va_arg(args, int);
2268     const char *name = va_arg(args, const char *);
2269     const char *desc = va_arg(args, const char *);
2270 
2271     static int code_width = 0;
2272 
2273     if (out->is_quiet(out)) {
2274         /* If out->is_quiet(), don't print the code. Print name and/or desc in a
2275          * compact format for text output, or print nothing at all for none-type
2276          * output.
2277          */
2278         if ((name != NULL) && (desc != NULL)) {
2279             pcmk__formatted_printf(out, "%s - %s\n", name, desc);
2280 
2281         } else if ((name != NULL) || (desc != NULL)) {
2282             pcmk__formatted_printf(out, "%s\n", ((name != NULL)? name : desc));
2283         }
2284         return pcmk_rc_ok;
2285     }
2286 
2287     /* Get length of longest (most negative) standard Pacemaker return code
2288      * This should be longer than all the values of any other type of return
2289      * code.
2290      */
2291     if (code_width == 0) {
2292         long long most_negative = pcmk_rc_error - (long long) pcmk__n_rc + 1;
2293         code_width = (int) snprintf(NULL, 0, "%lld", most_negative);
2294     }
2295 
2296     if ((name != NULL) && (desc != NULL)) {
2297         static int name_width = 0;
2298 
2299         if (name_width == 0) {
2300             // Get length of longest standard Pacemaker return code name
2301             for (int lpc = 0; lpc < pcmk__n_rc; lpc++) {
2302                 int len = (int) strlen(pcmk_rc_name(pcmk_rc_error - lpc));
2303                 name_width = QB_MAX(name_width, len);
2304             }
2305         }
2306         return out->info(out, "% *d: %-*s  %s", code_width, code, name_width,
2307                          name, desc);
2308     }
2309 
2310     if ((name != NULL) || (desc != NULL)) {
2311         return out->info(out, "% *d: %s", code_width, code,
2312                          ((name != NULL)? name : desc));
2313     }
2314 
2315     return out->info(out, "% *d", code_width, code);
2316 }
2317 
2318 PCMK__OUTPUT_ARGS("result-code", "int", "const char *", "const char *")
     /* [previous][next][first][last][top][bottom][index][help] */
2319 static int
2320 result_code_xml(pcmk__output_t *out, va_list args)
2321 {
2322     int code = va_arg(args, int);
2323     const char *name = va_arg(args, const char *);
2324     const char *desc = va_arg(args, const char *);
2325 
2326     char *code_str = pcmk__itoa(code);
2327 
2328     pcmk__output_create_xml_node(out, "result-code",
2329                                  "code", code_str,
2330                                  XML_ATTR_NAME, name,
2331                                  XML_ATTR_DESC, desc,
2332                                  NULL);
2333     free(code_str);
2334     return pcmk_rc_ok;
2335 }
2336 
2337 static pcmk__message_entry_t fmt_functions[] = {
2338     { "attribute", "default", attribute_default },
2339     { "attribute", "xml", attribute_xml },
2340     { "cluster-status", "default", pcmk__cluster_status_text },
2341     { "cluster-status", "html", cluster_status_html },
2342     { "cluster-status", "xml", cluster_status_xml },
2343     { "crmadmin-node", "default", crmadmin_node },
2344     { "crmadmin-node", "text", crmadmin_node_text },
2345     { "crmadmin-node", "xml", crmadmin_node_xml },
2346     { "dc", "default", dc },
2347     { "dc", "text", dc_text },
2348     { "dc", "xml", dc_xml },
2349     { "digests", "default", digests_text },
2350     { "digests", "xml", digests_xml },
2351     { "health", "default", health },
2352     { "health", "text", health_text },
2353     { "health", "xml", health_xml },
2354     { "inject-attr", "default", inject_attr },
2355     { "inject-attr", "xml", inject_attr_xml },
2356     { "inject-cluster-action", "default", inject_cluster_action },
2357     { "inject-cluster-action", "xml", inject_cluster_action_xml },
2358     { "inject-fencing-action", "default", inject_fencing_action },
2359     { "inject-fencing-action", "xml", inject_fencing_action_xml },
2360     { "inject-modify-config", "default", inject_modify_config },
2361     { "inject-modify-config", "xml", inject_modify_config_xml },
2362     { "inject-modify-node", "default", inject_modify_node },
2363     { "inject-modify-node", "xml", inject_modify_node_xml },
2364     { "inject-modify-ticket", "default", inject_modify_ticket },
2365     { "inject-modify-ticket", "xml", inject_modify_ticket_xml },
2366     { "inject-pseudo-action", "default", inject_pseudo_action },
2367     { "inject-pseudo-action", "xml", inject_pseudo_action_xml },
2368     { "inject-rsc-action", "default", inject_rsc_action },
2369     { "inject-rsc-action", "xml", inject_rsc_action_xml },
2370     { "inject-spec", "default", inject_spec },
2371     { "inject-spec", "xml", inject_spec_xml },
2372     { "locations-list", "default", locations_list },
2373     { "locations-list", "xml", locations_list_xml },
2374     { "node-action", "default", node_action },
2375     { "node-action", "xml", node_action_xml },
2376     { "node-info", "default", node_info_default },
2377     { "node-info", "xml", node_info_xml },
2378     { "pacemakerd-health", "default", pacemakerd_health },
2379     { "pacemakerd-health", "html", pacemakerd_health_html },
2380     { "pacemakerd-health", "text", pacemakerd_health_text },
2381     { "pacemakerd-health", "xml", pacemakerd_health_xml },
2382     { "profile", "default", profile_default, },
2383     { "profile", "xml", profile_xml },
2384     { "result-code", "none", result_code_none },
2385     { "result-code", "text", result_code_text },
2386     { "result-code", "xml", result_code_xml },
2387     { "rsc-action", "default", rsc_action_default },
2388     { "rsc-action-item", "default", rsc_action_item },
2389     { "rsc-action-item", "xml", rsc_action_item_xml },
2390     { "rsc-is-colocated-with-list", "default", rsc_is_colocated_with_list },
2391     { "rsc-is-colocated-with-list", "xml", rsc_is_colocated_with_list_xml },
2392     { "rscs-colocated-with-list", "default", rscs_colocated_with_list },
2393     { "rscs-colocated-with-list", "xml", rscs_colocated_with_list_xml },
2394     { "rule-check", "default", rule_check_default },
2395     { "rule-check", "xml", rule_check_xml },
2396     { "locations-and-colocations", "default", locations_and_colocations },
2397     { "locations-and-colocations", "xml", locations_and_colocations_xml },
2398 
2399     { NULL, NULL, NULL }
2400 };
2401 
2402 void
2403 pcmk__register_lib_messages(pcmk__output_t *out) {
     /* [previous][next][first][last][top][bottom][index][help] */
2404     pcmk__register_messages(out, fmt_functions);
2405 }

/* [previous][next][first][last][top][bottom][index][help] */