root/lib/fencing/st_output.c

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

DEFINITIONS

This source file includes following definitions.
  1. time_t_string
  2. state_str
  3. stonith__history_description
  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. stonith__register_messages

   1 /*
   2  * Copyright 2019-2022 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 Lesser General Public License
   7  * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
   8  */
   9 
  10 #include <crm_internal.h>
  11 #include <stdarg.h>
  12 #include <stdint.h>
  13 
  14 #include <crm/stonith-ng.h>
  15 #include <crm/msg_xml.h>
  16 #include <crm/common/iso8601.h>
  17 #include <crm/common/util.h>
  18 #include <crm/common/xml.h>
  19 #include <crm/common/output.h>
  20 #include <crm/common/output_internal.h>
  21 #include <crm/common/xml_internal.h>
  22 #include <crm/fencing/internal.h>
  23 #include <crm/pengine/internal.h>
  24 
  25 static char *
  26 time_t_string(time_t when) {
     /* [previous][next][first][last][top][bottom][index][help] */
  27     crm_time_t *crm_when = crm_time_new(NULL);
  28     char *buf = NULL;
  29 
  30     crm_time_set_timet(crm_when, &when);
  31     buf = crm_time_as_string(crm_when, crm_time_log_date | crm_time_log_timeofday | crm_time_log_with_timezone);
  32     crm_time_free(crm_when);
  33     return buf;
  34 }
  35 
  36 /*!
  37  * \internal
  38  * \brief Return a status-friendly description of fence history entry state
  39  *
  40  * \param[in] history  Fence history entry to describe
  41  *
  42  * \return One-word description of history entry state
  43  * \note This is similar to stonith_op_state_str() except user-oriented (i.e.
  44  *       for cluster status) instead of developer-oriented (for debug logs).
  45  */
  46 static const char *
  47 state_str(stonith_history_t *history)
     /* [previous][next][first][last][top][bottom][index][help] */
  48 {
  49     switch (history->state) {
  50         case st_failed: return "failed";
  51         case st_done:   return "successful";
  52         default:        return "pending";
  53     }
  54 }
  55 
  56 /*!
  57  * \internal
  58  * \brief Create a description of a fencing history entry for status displays
  59  *
  60  * \param[in] history          Fencing history entry to describe
  61  * \param[in] full_history     Whether this is for full or condensed history
  62  * \param[in] later_succeeded  Node that a later equivalent attempt succeeded
  63  *                             from, or NULL if none
  64  * \param[in] show_opts        Flag group of pcmk_show_opt_e
  65  *
  66  * \return Newly created string with fencing history entry description
  67  *
  68  * \note The caller is responsible for freeing the return value with g_free().
  69  * \note This is similar to stonith__event_description(), except this is used
  70  *       for history entries (stonith_history_t) in status displays rather than
  71  *       event notifications (stonith_event_t) in log messages.
  72  */
  73 gchar *
  74 stonith__history_description(stonith_history_t *history, bool full_history,
     /* [previous][next][first][last][top][bottom][index][help] */
  75                              const char *later_succeeded, uint32_t show_opts)
  76 {
  77     GString *str = g_string_sized_new(256); // Generous starting size
  78     char *completed_time = NULL;
  79 
  80     if ((history->state == st_failed) || (history->state == st_done)) {
  81         completed_time = time_t_string(history->completed);
  82     }
  83 
  84     pcmk__g_strcat(str,
  85                    stonith_action_str(history->action), " of ", history->target,
  86                    NULL);
  87 
  88     if (!pcmk_is_set(show_opts, pcmk_show_failed_detail)) {
  89         // More human-friendly
  90         if (((history->state == st_failed) || (history->state == st_done))
  91             && (history->delegate != NULL)) {
  92 
  93             pcmk__g_strcat(str, " by ", history->delegate, NULL);
  94         }
  95         pcmk__g_strcat(str, " for ", history->client, "@", history->origin,
  96                        NULL);
  97         if (!full_history) {
  98             g_string_append(str, " last"); // For example, "last failed at ..."
  99         }
 100     }
 101 
 102     pcmk__add_word(&str, 0, state_str(history));
 103 
 104     // For failed actions, add exit reason if available
 105     if ((history->state == st_failed) && (history->exit_reason != NULL)) {
 106         pcmk__g_strcat(str, " (", history->exit_reason, ")", NULL);
 107     }
 108 
 109     if (pcmk_is_set(show_opts, pcmk_show_failed_detail)) {
 110         // More technical
 111         g_string_append(str, ": ");
 112 
 113         // For completed actions, add delegate if available
 114         if (((history->state == st_failed) || (history->state == st_done))
 115             && (history->delegate != NULL)) {
 116 
 117             pcmk__g_strcat(str, "delegate=", history->delegate, ", ", NULL);
 118         }
 119 
 120         // Add information about originator
 121         pcmk__g_strcat(str,
 122                        "client=", history->client, ", origin=", history->origin,
 123                        NULL);
 124 
 125         // For completed actions, add completion time
 126         if (completed_time != NULL) {
 127             if (full_history) {
 128                 g_string_append(str, ", completed");
 129             } else if (history->state == st_failed) {
 130                 g_string_append(str, ", last-failed");
 131             } else {
 132                 g_string_append(str, ", last-successful");
 133             }
 134             pcmk__g_strcat(str, "='", completed_time, "'", NULL);
 135         }
 136     } else { // More human-friendly
 137         if (completed_time != NULL) {
 138             pcmk__g_strcat(str, " at ", completed_time, NULL);
 139         }
 140     }
 141 
 142     if ((history->state == st_failed) && (later_succeeded != NULL)) {
 143         pcmk__g_strcat(str,
 144                        " (a later attempt from ", later_succeeded,
 145                        " succeeded)", NULL);
 146     }
 147 
 148     free(completed_time);
 149     return g_string_free(str, FALSE);
 150 }
 151 
 152 PCMK__OUTPUT_ARGS("failed-fencing-list", "stonith_history_t *", "GList *",
     /* [previous][next][first][last][top][bottom][index][help] */
 153                   "uint32_t", "uint32_t", "bool")
 154 static int
 155 failed_history(pcmk__output_t *out, va_list args)
 156 {
 157     stonith_history_t *history = va_arg(args, stonith_history_t *);
 158     GList *only_node = va_arg(args, GList *);
 159     uint32_t section_opts = va_arg(args, uint32_t);
 160     uint32_t show_opts = va_arg(args, uint32_t);
 161     bool print_spacer = va_arg(args, int);
 162 
 163     int rc = pcmk_rc_no_output;
 164 
 165     for (stonith_history_t *hp = history; hp; hp = hp->next) {
 166         if (hp->state != st_failed) {
 167             continue;
 168         }
 169 
 170         if (!pcmk__str_in_list(hp->target, only_node, pcmk__str_star_matches|pcmk__str_casei)) {
 171             continue;
 172         }
 173 
 174         PCMK__OUTPUT_LIST_HEADER(out, print_spacer, rc, "Failed Fencing Actions");
 175         out->message(out, "stonith-event", hp,
 176                      pcmk_all_flags_set(section_opts, pcmk_section_fencing_all),
 177                      false, stonith__later_succeeded(hp, history), show_opts);
 178         out->increment_list(out);
 179     }
 180 
 181     PCMK__OUTPUT_LIST_FOOTER(out, rc);
 182     return rc;
 183 }
 184 
 185 PCMK__OUTPUT_ARGS("fencing-list", "stonith_history_t *", "GList *", "uint32_t",
     /* [previous][next][first][last][top][bottom][index][help] */
 186                   "uint32_t", "bool")
 187 static int
 188 stonith_history(pcmk__output_t *out, va_list args)
 189 {
 190     stonith_history_t *history = va_arg(args, stonith_history_t *);
 191     GList *only_node = va_arg(args, GList *);
 192     uint32_t section_opts = va_arg(args, uint32_t);
 193     uint32_t show_opts = va_arg(args, uint32_t);
 194     bool print_spacer = va_arg(args, int);
 195 
 196     int rc = pcmk_rc_no_output;
 197 
 198     for (stonith_history_t *hp = history; hp; hp = hp->next) {
 199         if (!pcmk__str_in_list(hp->target, only_node, pcmk__str_star_matches|pcmk__str_casei)) {
 200             continue;
 201         }
 202 
 203         if (hp->state != st_failed) {
 204             PCMK__OUTPUT_LIST_HEADER(out, print_spacer, rc, "Fencing History");
 205             out->message(out, "stonith-event", hp,
 206                          pcmk_all_flags_set(section_opts,
 207                                             pcmk_section_fencing_all),
 208                          false, stonith__later_succeeded(hp, history), show_opts);
 209             out->increment_list(out);
 210         }
 211     }
 212 
 213     PCMK__OUTPUT_LIST_FOOTER(out, rc);
 214     return rc;
 215 }
 216 
 217 PCMK__OUTPUT_ARGS("full-fencing-list", "crm_exit_t", "stonith_history_t *",
     /* [previous][next][first][last][top][bottom][index][help] */
 218                   "GList *", "uint32_t", "uint32_t", "bool")
 219 static int
 220 full_history(pcmk__output_t *out, va_list args)
 221 {
 222     crm_exit_t history_rc G_GNUC_UNUSED = va_arg(args, crm_exit_t);
 223     stonith_history_t *history = va_arg(args, stonith_history_t *);
 224     GList *only_node = va_arg(args, GList *);
 225     uint32_t section_opts = va_arg(args, uint32_t);
 226     uint32_t show_opts = va_arg(args, uint32_t);
 227     bool print_spacer = va_arg(args, int);
 228 
 229     int rc = pcmk_rc_no_output;
 230 
 231     for (stonith_history_t *hp = history; hp; hp = hp->next) {
 232         if (!pcmk__str_in_list(hp->target, only_node, pcmk__str_star_matches|pcmk__str_casei)) {
 233             continue;
 234         }
 235 
 236         PCMK__OUTPUT_LIST_HEADER(out, print_spacer, rc, "Fencing History");
 237         out->message(out, "stonith-event", hp,
 238                      pcmk_all_flags_set(section_opts, pcmk_section_fencing_all),
 239                      false, stonith__later_succeeded(hp, history), show_opts);
 240         out->increment_list(out);
 241     }
 242 
 243     PCMK__OUTPUT_LIST_FOOTER(out, rc);
 244     return rc;
 245 }
 246 
 247 PCMK__OUTPUT_ARGS("full-fencing-list", "crm_exit_t", "stonith_history_t *",
     /* [previous][next][first][last][top][bottom][index][help] */
 248                   "GList *", "uint32_t", "uint32_t", "bool")
 249 static int
 250 full_history_xml(pcmk__output_t *out, va_list args)
 251 {
 252     crm_exit_t history_rc = va_arg(args, crm_exit_t);
 253     stonith_history_t *history = va_arg(args, stonith_history_t *);
 254     GList *only_node = va_arg(args, GList *);
 255     uint32_t section_opts = va_arg(args, uint32_t);
 256     uint32_t show_opts = va_arg(args, uint32_t);
 257     bool print_spacer G_GNUC_UNUSED = va_arg(args, int);
 258 
 259     int rc = pcmk_rc_no_output;
 260 
 261     if (history_rc == 0) {
 262         for (stonith_history_t *hp = history; hp; hp = hp->next) {
 263             if (!pcmk__str_in_list(hp->target, only_node, pcmk__str_star_matches|pcmk__str_casei)) {
 264                 continue;
 265             }
 266 
 267             PCMK__OUTPUT_LIST_HEADER(out, false, rc, "Fencing History");
 268             out->message(out, "stonith-event", hp,
 269                          pcmk_all_flags_set(section_opts,
 270                                             pcmk_section_fencing_all),
 271                          false, stonith__later_succeeded(hp, history), show_opts);
 272             out->increment_list(out);
 273         }
 274 
 275         PCMK__OUTPUT_LIST_FOOTER(out, rc);
 276     } else {
 277         char *rc_s = pcmk__itoa(history_rc);
 278 
 279         pcmk__output_create_xml_node(out, "fence_history",
 280                                      "status", rc_s,
 281                                      NULL);
 282         free(rc_s);
 283 
 284         rc = pcmk_rc_ok;
 285     }
 286 
 287     return rc;
 288 }
 289 
 290 PCMK__OUTPUT_ARGS("last-fenced", "const char *", "time_t")
     /* [previous][next][first][last][top][bottom][index][help] */
 291 static int
 292 last_fenced_html(pcmk__output_t *out, va_list args) {
 293     const char *target = va_arg(args, const char *);
 294     time_t when = va_arg(args, time_t);
 295 
 296     if (when) {
 297         char *buf = crm_strdup_printf("Node %s last fenced at: %s", target, ctime(&when));
 298         pcmk__output_create_html_node(out, "div", NULL, NULL, buf);
 299         free(buf);
 300         return pcmk_rc_ok;
 301     } else {
 302         return pcmk_rc_no_output;
 303     }
 304 }
 305 
 306 PCMK__OUTPUT_ARGS("last-fenced", "const char *", "time_t")
     /* [previous][next][first][last][top][bottom][index][help] */
 307 static int
 308 last_fenced_text(pcmk__output_t *out, va_list args) {
 309     const char *target = va_arg(args, const char *);
 310     time_t when = va_arg(args, time_t);
 311 
 312     if (when) {
 313         pcmk__indented_printf(out, "Node %s last fenced at: %s", target, ctime(&when));
 314     } else {
 315         pcmk__indented_printf(out, "Node %s has never been fenced\n", target);
 316     }
 317 
 318     return pcmk_rc_ok;
 319 }
 320 
 321 PCMK__OUTPUT_ARGS("last-fenced", "const char *", "time_t")
     /* [previous][next][first][last][top][bottom][index][help] */
 322 static int
 323 last_fenced_xml(pcmk__output_t *out, va_list args) {
 324     const char *target = va_arg(args, const char *);
 325     time_t when = va_arg(args, time_t);
 326 
 327     if (when) {
 328         char *buf = time_t_string(when);
 329 
 330         pcmk__output_create_xml_node(out, "last-fenced",
 331                                      "target", target,
 332                                      "when", buf,
 333                                      NULL);
 334 
 335         free(buf);
 336         return pcmk_rc_ok;
 337     } else {
 338         return pcmk_rc_no_output;
 339     }
 340 }
 341 
 342 PCMK__OUTPUT_ARGS("pending-fencing-list", "stonith_history_t *", "GList *",
     /* [previous][next][first][last][top][bottom][index][help] */
 343                   "uint32_t", "uint32_t", "bool")
 344 static int
 345 pending_actions(pcmk__output_t *out, va_list args)
 346 {
 347     stonith_history_t *history = va_arg(args, stonith_history_t *);
 348     GList *only_node = va_arg(args, GList *);
 349     uint32_t section_opts = va_arg(args, uint32_t);
 350     uint32_t show_opts = va_arg(args, uint32_t);
 351     bool print_spacer = va_arg(args, int);
 352 
 353     int rc = pcmk_rc_no_output;
 354 
 355     for (stonith_history_t *hp = history; hp; hp = hp->next) {
 356         if (!pcmk__str_in_list(hp->target, only_node, pcmk__str_star_matches|pcmk__str_casei)) {
 357             continue;
 358         }
 359 
 360         /* Skip the rest of the history after we see a failed/done action */
 361         if ((hp->state == st_failed) || (hp->state == st_done)) {
 362             break;
 363         }
 364 
 365         PCMK__OUTPUT_LIST_HEADER(out, print_spacer, rc, "Pending Fencing Actions");
 366         out->message(out, "stonith-event", hp,
 367                      pcmk_all_flags_set(section_opts, pcmk_section_fencing_all),
 368                      false, stonith__later_succeeded(hp, history), show_opts);
 369         out->increment_list(out);
 370     }
 371 
 372     PCMK__OUTPUT_LIST_FOOTER(out, rc);
 373     return rc;
 374 }
 375 
 376 PCMK__OUTPUT_ARGS("stonith-event", "stonith_history_t *", "bool", "bool",
     /* [previous][next][first][last][top][bottom][index][help] */
 377                   "const char *", "uint32_t")
 378 static int
 379 stonith_event_html(pcmk__output_t *out, va_list args)
 380 {
 381     stonith_history_t *event = va_arg(args, stonith_history_t *);
 382     bool full_history = va_arg(args, int);
 383     bool completed_only G_GNUC_UNUSED = va_arg(args, int);
 384     const char *succeeded = va_arg(args, const char *);
 385     uint32_t show_opts = va_arg(args, uint32_t);
 386 
 387     gchar *desc = stonith__history_description(event, full_history, succeeded,
 388                                                show_opts);
 389 
 390     switch(event->state) {
 391         case st_done:
 392             out->list_item(out, "successful-stonith-event", "%s", desc);
 393             break;
 394 
 395         case st_failed:
 396             out->list_item(out, "failed-stonith-event", "%s", desc);
 397             break;
 398 
 399         default:
 400             out->list_item(out, "pending-stonith-event", "%s", desc);
 401             break;
 402     }
 403     g_free(desc);
 404     return pcmk_rc_ok;
 405 }
 406 
 407 PCMK__OUTPUT_ARGS("stonith-event", "stonith_history_t *", "bool", "bool",
     /* [previous][next][first][last][top][bottom][index][help] */
 408                   "const char *", "uint32_t")
 409 static int
 410 stonith_event_text(pcmk__output_t *out, va_list args)
 411 {
 412     stonith_history_t *event = va_arg(args, stonith_history_t *);
 413     bool full_history = va_arg(args, int);
 414     bool completed_only = va_arg(args, int);
 415     const char *succeeded = va_arg(args, const char *);
 416     uint32_t show_opts = va_arg(args, uint32_t);
 417 
 418     if (completed_only) {
 419         pcmk__formatted_printf(out, "%lld\n", (long long) event->completed);
 420     } else {
 421         gchar *desc = stonith__history_description(event, full_history, succeeded,
 422                                                    show_opts);
 423 
 424         pcmk__indented_printf(out, "%s\n", desc);
 425         g_free(desc);
 426     }
 427 
 428     return pcmk_rc_ok;
 429 }
 430 
 431 PCMK__OUTPUT_ARGS("stonith-event", "stonith_history_t *", "bool", "bool",
     /* [previous][next][first][last][top][bottom][index][help] */
 432                   "const char *", "uint32_t")
 433 static int
 434 stonith_event_xml(pcmk__output_t *out, va_list args)
 435 {
 436     stonith_history_t *event = va_arg(args, stonith_history_t *);
 437     bool full_history G_GNUC_UNUSED = va_arg(args, int);
 438     bool completed_only G_GNUC_UNUSED = va_arg(args, int);
 439     const char *succeeded G_GNUC_UNUSED = va_arg(args, const char *);
 440     uint32_t show_opts G_GNUC_UNUSED = va_arg(args, uint32_t);
 441 
 442     char *buf = NULL;
 443 
 444     xmlNodePtr node = pcmk__output_create_xml_node(out, "fence_event",
 445                                                    "action", event->action,
 446                                                    "target", event->target,
 447                                                    "client", event->client,
 448                                                    "origin", event->origin,
 449                                                    NULL);
 450 
 451     switch (event->state) {
 452         case st_failed:
 453             pcmk__xe_set_props(node, "status", "failed",
 454                                XML_LRM_ATTR_EXIT_REASON, event->exit_reason,
 455                                NULL);
 456             break;
 457 
 458         case st_done:
 459             crm_xml_add(node, "status", "success");
 460             break;
 461 
 462         default: {
 463             char *state = pcmk__itoa(event->state);
 464             pcmk__xe_set_props(node, "status", "pending",
 465                                "extended-status", state,
 466                                NULL);
 467             free(state);
 468             break;
 469         }
 470     }
 471 
 472     if (event->delegate != NULL) {
 473         crm_xml_add(node, "delegate", event->delegate);
 474     }
 475 
 476     if (event->state == st_failed || event->state == st_done) {
 477         buf = time_t_string(event->completed);
 478         crm_xml_add(node, "completed", buf);
 479         free(buf);
 480     }
 481 
 482     return pcmk_rc_ok;
 483 }
 484 
 485 PCMK__OUTPUT_ARGS("validate", "const char *", "const char *", "char *", "char *", "int")
     /* [previous][next][first][last][top][bottom][index][help] */
 486 static int
 487 validate_agent_html(pcmk__output_t *out, va_list args) {
 488     const char *agent = va_arg(args, const char *);
 489     const char *device = va_arg(args, const char *);
 490     char *output = va_arg(args, char *);
 491     char *error_output = va_arg(args, char *);
 492     int rc = va_arg(args, int);
 493 
 494     if (device) {
 495         char *buf = crm_strdup_printf("Validation of %s on %s %s", agent, device,
 496                                       rc ? "failed" : "succeeded");
 497         pcmk__output_create_html_node(out, "div", NULL, NULL, buf);
 498         free(buf);
 499     } else {
 500         char *buf = crm_strdup_printf("Validation of %s %s", agent,
 501                                       rc ? "failed" : "succeeded");
 502         pcmk__output_create_html_node(out, "div", NULL, NULL, buf);
 503         free(buf);
 504     }
 505 
 506     out->subprocess_output(out, rc, output, error_output);
 507     return rc;
 508 }
 509 
 510 PCMK__OUTPUT_ARGS("validate", "const char *", "const char *", "char *", "char *", "int")
     /* [previous][next][first][last][top][bottom][index][help] */
 511 static int
 512 validate_agent_text(pcmk__output_t *out, va_list args) {
 513     const char *agent = va_arg(args, const char *);
 514     const char *device = va_arg(args, const char *);
 515     char *output = va_arg(args, char *);
 516     char *error_output = va_arg(args, char *);
 517     int rc = va_arg(args, int);
 518 
 519     if (device) {
 520         pcmk__indented_printf(out, "Validation of %s on %s %s\n", agent, device,
 521                               rc ? "failed" : "succeeded");
 522     } else {
 523         pcmk__indented_printf(out, "Validation of %s %s\n", agent,
 524                               rc ? "failed" : "succeeded");
 525     }
 526 
 527     out->subprocess_output(out, rc, output, error_output);
 528     return rc;
 529 }
 530 
 531 PCMK__OUTPUT_ARGS("validate", "const char *", "const char *", "char *", "char *", "int")
     /* [previous][next][first][last][top][bottom][index][help] */
 532 static int
 533 validate_agent_xml(pcmk__output_t *out, va_list args) {
 534     const char *agent = va_arg(args, const char *);
 535     const char *device = va_arg(args, const char *);
 536     char *output = va_arg(args, char *);
 537     char *error_output = va_arg(args, char *);
 538     int rc = va_arg(args, int);
 539 
 540     xmlNodePtr node = pcmk__output_create_xml_node(
 541         out, "validate", "agent", agent, "valid", pcmk__btoa(rc == pcmk_ok),
 542         NULL);
 543 
 544     if (device != NULL) {
 545         crm_xml_add(node, "device", device);
 546     }
 547 
 548     pcmk__output_xml_push_parent(out, node);
 549     out->subprocess_output(out, rc, output, error_output);
 550     pcmk__output_xml_pop_parent(out);
 551 
 552     return rc;
 553 }
 554 
 555 static pcmk__message_entry_t fmt_functions[] = {
 556     { "failed-fencing-list", "default", failed_history },
 557     { "fencing-list", "default", stonith_history },
 558     { "full-fencing-list", "default", full_history },
 559     { "full-fencing-list", "xml", full_history_xml },
 560     { "last-fenced", "html", last_fenced_html },
 561     { "last-fenced", "log", last_fenced_text },
 562     { "last-fenced", "text", last_fenced_text },
 563     { "last-fenced", "xml", last_fenced_xml },
 564     { "pending-fencing-list", "default", pending_actions },
 565     { "stonith-event", "html", stonith_event_html },
 566     { "stonith-event", "log", stonith_event_text },
 567     { "stonith-event", "text", stonith_event_text },
 568     { "stonith-event", "xml", stonith_event_xml },
 569     { "validate", "html", validate_agent_html },
 570     { "validate", "log", validate_agent_text },
 571     { "validate", "text", validate_agent_text },
 572     { "validate", "xml", validate_agent_xml },
 573 
 574     { NULL, NULL, NULL }
 575 };
 576 
 577 void
 578 stonith__register_messages(pcmk__output_t *out) {
     /* [previous][next][first][last][top][bottom][index][help] */
 579     pcmk__register_messages(out, fmt_functions);
 580 }

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