root/lib/fencing/st_output.c

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

DEFINITIONS

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

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

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