root/lib/common/output_xml.c

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

DEFINITIONS

This source file includes following definitions.
  1. has_root_node
  2. add_root_node
  3. xml_free_priv
  4. xml_init
  5. add_error_node
  6. xml_finish
  7. xml_reset
  8. xml_subprocess_output
  9. xml_version
  10. G_GNUC_PRINTF
  11. G_GNUC_PRINTF
  12. xml_output_xml
  13. G_GNUC_PRINTF
  14. G_GNUC_PRINTF
  15. xml_increment_list
  16. xml_end_list
  17. xml_is_quiet
  18. xml_spacer
  19. xml_progress
  20. pcmk__mk_xml_output
  21. pcmk__output_xml_create_parent
  22. pcmk__output_xml_add_node_copy
  23. pcmk__output_create_xml_node
  24. pcmk__output_create_xml_text_node
  25. pcmk__output_xml_push_parent
  26. pcmk__output_xml_pop_parent
  27. pcmk__output_xml_peek_parent
  28. pcmk__output_get_legacy_xml
  29. pcmk__output_set_legacy_xml
  30. pcmk__output_enable_list_element

   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 
  12 #include <ctype.h>
  13 #include <stdarg.h>
  14 #include <stdlib.h>
  15 #include <stdio.h>
  16 #include <crm/crm.h>
  17 
  18 #include <glib.h>
  19 #include <libxml/tree.h>                    // xmlNode
  20 #include <libxml/xmlstring.h>               // xmlChar
  21 
  22 #include <crm/common/cmdline_internal.h>
  23 #include <crm/common/output.h>
  24 #include <crm/common/xml.h>
  25 #include <crm/common/xml_internal.h>    // pcmk__xml2fd
  26 
  27 typedef struct subst_s {
  28     const char *from;
  29     const char *to;
  30 } subst_t;
  31 
  32 static const subst_t substitutions[] = {
  33     { "Active Resources",
  34       PCMK_XE_RESOURCES, },
  35     { "Assignment Scores",
  36       PCMK_XE_ALLOCATIONS, },
  37     { "Assignment Scores and Utilization Information",
  38       PCMK_XE_ALLOCATIONS_UTILIZATIONS, },
  39     { "Cluster Summary",
  40       PCMK_XE_SUMMARY, },
  41     { "Current cluster status",
  42       PCMK_XE_CLUSTER_STATUS, },
  43     { "Executing Cluster Transition",
  44       PCMK_XE_TRANSITION, },
  45     { "Failed Resource Actions",
  46       PCMK_XE_FAILURES, },
  47     { "Fencing History",
  48       PCMK_XE_FENCE_HISTORY, },
  49     { "Full List of Resources",
  50       PCMK_XE_RESOURCES, },
  51     { "Inactive Resources",
  52       PCMK_XE_RESOURCES, },
  53     { "Migration Summary",
  54       PCMK_XE_NODE_HISTORY, },
  55     { "Negative Location Constraints",
  56       PCMK_XE_BANS, },
  57     { "Node Attributes",
  58       PCMK_XE_NODE_ATTRIBUTES, },
  59     { "Operations",
  60       PCMK_XE_NODE_HISTORY, },
  61     { "Resource Config",
  62       PCMK_XE_RESOURCE_CONFIG, },
  63     { "Resource Operations",
  64       PCMK_XE_OPERATIONS, },
  65     { "Revised Cluster Status",
  66       PCMK_XE_REVISED_CLUSTER_STATUS, },
  67     { "Timings",
  68       PCMK_XE_TIMINGS, },
  69     { "Transition Summary",
  70       PCMK_XE_ACTIONS, },
  71     { "Utilization Information",
  72       PCMK_XE_UTILIZATIONS, },
  73 
  74     { NULL, NULL }
  75 };
  76 
  77 /* The first several elements of this struct must be the same as the first
  78  * several elements of private_data_s in lib/common/output_html.c.  That
  79  * struct gets passed to a bunch of the pcmk__output_xml_* functions which
  80  * assume an XML private_data_s.  Keeping them laid out the same means this
  81  * still works.
  82  */
  83 typedef struct private_data_s {
  84     /* Begin members that must match the HTML version */
  85     xmlNode *root;
  86     GQueue *parent_q;
  87     GSList *errors;
  88     /* End members that must match the HTML version */
  89     bool legacy_xml;
  90     bool list_element;
  91 } private_data_t;
  92 
  93 static bool
  94 has_root_node(pcmk__output_t *out)
     /* [previous][next][first][last][top][bottom][index][help] */
  95 {
  96     private_data_t *priv = NULL;
  97 
  98     pcmk__assert(out != NULL);
  99 
 100     priv = out->priv;
 101     return priv != NULL && priv->root != NULL;
 102 }
 103 
 104 static void
 105 add_root_node(pcmk__output_t *out)
     /* [previous][next][first][last][top][bottom][index][help] */
 106 {
 107     private_data_t *priv = NULL;
 108 
 109     /* has_root_node will assert if out is NULL, so no need to do it here */
 110     if (has_root_node(out)) {
 111         return;
 112     }
 113 
 114     priv = out->priv;
 115 
 116     if (priv->legacy_xml) {
 117         priv->root = pcmk__xe_create(NULL, PCMK_XE_CRM_MON);
 118         crm_xml_add(priv->root, PCMK_XA_VERSION, PACEMAKER_VERSION);
 119     } else {
 120         priv->root = pcmk__xe_create(NULL, PCMK_XE_PACEMAKER_RESULT);
 121         crm_xml_add(priv->root, PCMK_XA_API_VERSION, PCMK__API_VERSION);
 122         crm_xml_add(priv->root, PCMK_XA_REQUEST,
 123                     pcmk__s(out->request, "libpacemaker"));
 124     }
 125 
 126     priv->parent_q = g_queue_new();
 127     g_queue_push_tail(priv->parent_q, priv->root);
 128 }
 129 
 130 static void
 131 xml_free_priv(pcmk__output_t *out) {
     /* [previous][next][first][last][top][bottom][index][help] */
 132     private_data_t *priv = NULL;
 133 
 134     if (out == NULL || out->priv == NULL) {
 135         return;
 136     }
 137 
 138     priv = out->priv;
 139 
 140     if (has_root_node(out)) {
 141         pcmk__xml_free(priv->root);
 142         /* The elements of parent_q are xmlNodes that are a part of the
 143          * priv->root document, so the above line already frees them.  Don't
 144          * call g_queue_free_full here.
 145          */
 146         g_queue_free(priv->parent_q);
 147     }
 148 
 149     g_slist_free_full(priv->errors, free);
 150     free(priv);
 151     out->priv = NULL;
 152 }
 153 
 154 static bool
 155 xml_init(pcmk__output_t *out) {
     /* [previous][next][first][last][top][bottom][index][help] */
 156     private_data_t *priv = NULL;
 157 
 158     pcmk__assert(out != NULL);
 159 
 160     /* If xml_init was previously called on this output struct, just return. */
 161     if (out->priv != NULL) {
 162         return true;
 163     } else {
 164         out->priv = calloc(1, sizeof(private_data_t));
 165         if (out->priv == NULL) {
 166             return false;
 167         }
 168 
 169         priv = out->priv;
 170     }
 171 
 172     priv->errors = NULL;
 173 
 174     return true;
 175 }
 176 
 177 static void
 178 add_error_node(gpointer data, gpointer user_data) {
     /* [previous][next][first][last][top][bottom][index][help] */
 179     const char *str = (const char *) data;
 180     xmlNodePtr node = (xmlNodePtr) user_data;
 181 
 182     node = pcmk__xe_create(node, PCMK_XE_ERROR);
 183     pcmk__xe_set_content(node, "%s", str);
 184 }
 185 
 186 static void
 187 xml_finish(pcmk__output_t *out, crm_exit_t exit_status, bool print, void **copy_dest) {
     /* [previous][next][first][last][top][bottom][index][help] */
 188     private_data_t *priv = NULL;
 189     xmlNodePtr node;
 190 
 191     pcmk__assert(out != NULL);
 192     priv = out->priv;
 193 
 194     if (priv == NULL) {
 195         return;
 196     }
 197 
 198     add_root_node(out);
 199 
 200     if (priv->legacy_xml) {
 201         GSList *node = priv->errors;
 202 
 203         if (exit_status != CRM_EX_OK) {
 204             fprintf(stderr, "%s\n", crm_exit_str(exit_status));
 205         }
 206 
 207         while (node != NULL) {
 208             fprintf(stderr, "%s\n", (char *) node->data);
 209             node = node->next;
 210         }
 211     } else {
 212         char *rc_as_str = pcmk__itoa(exit_status);
 213 
 214         node = pcmk__xe_create(priv->root, PCMK_XE_STATUS);
 215         pcmk__xe_set_props(node,
 216                            PCMK_XA_CODE, rc_as_str,
 217                            PCMK_XA_MESSAGE, crm_exit_str(exit_status),
 218                            NULL);
 219 
 220         if (g_slist_length(priv->errors) > 0) {
 221             xmlNodePtr errors_node = pcmk__xe_create(node, PCMK_XE_ERRORS);
 222             g_slist_foreach(priv->errors, add_error_node, (gpointer) errors_node);
 223         }
 224 
 225         free(rc_as_str);
 226     }
 227 
 228     if (print) {
 229         pcmk__xml2fd(fileno(out->dest), priv->root);
 230     }
 231 
 232     if (copy_dest != NULL) {
 233         *copy_dest = pcmk__xml_copy(NULL, priv->root);
 234     }
 235 }
 236 
 237 static void
 238 xml_reset(pcmk__output_t *out) {
     /* [previous][next][first][last][top][bottom][index][help] */
 239     pcmk__assert(out != NULL);
 240 
 241     out->dest = freopen(NULL, "w", out->dest);
 242     pcmk__assert(out->dest != NULL);
 243 
 244     xml_free_priv(out);
 245     xml_init(out);
 246 }
 247 
 248 static void
 249 xml_subprocess_output(pcmk__output_t *out, int exit_status,
     /* [previous][next][first][last][top][bottom][index][help] */
 250                       const char *proc_stdout, const char *proc_stderr) {
 251     xmlNodePtr node, child_node;
 252     char *rc_as_str = NULL;
 253 
 254     pcmk__assert(out != NULL);
 255 
 256     rc_as_str = pcmk__itoa(exit_status);
 257 
 258     node = pcmk__output_xml_create_parent(out, PCMK_XE_COMMAND,
 259                                           PCMK_XA_CODE, rc_as_str,
 260                                           NULL);
 261 
 262     if (proc_stdout != NULL) {
 263         child_node = pcmk__xe_create(node, PCMK_XE_OUTPUT);
 264         pcmk__xe_set_content(child_node, "%s", proc_stdout);
 265         crm_xml_add(child_node, PCMK_XA_SOURCE, "stdout");
 266     }
 267 
 268     if (proc_stderr != NULL) {
 269         child_node = pcmk__xe_create(node, PCMK_XE_OUTPUT);
 270         pcmk__xe_set_content(child_node, "%s", proc_stderr);
 271         crm_xml_add(child_node, PCMK_XA_SOURCE, "stderr");
 272     }
 273 
 274     free(rc_as_str);
 275 }
 276 
 277 static void
 278 xml_version(pcmk__output_t *out, bool extended) {
     /* [previous][next][first][last][top][bottom][index][help] */
 279     const char *author = "Andrew Beekhof and the Pacemaker project "
 280                          "contributors";
 281     pcmk__assert(out != NULL);
 282 
 283     pcmk__output_create_xml_node(out, PCMK_XE_VERSION,
 284                                  PCMK_XA_PROGRAM, "Pacemaker",
 285                                  PCMK_XA_VERSION, PACEMAKER_VERSION,
 286                                  PCMK_XA_AUTHOR, author,
 287                                  PCMK_XA_BUILD, BUILD_VERSION,
 288                                  PCMK_XA_FEATURES, CRM_FEATURES,
 289                                  NULL);
 290 }
 291 
 292 G_GNUC_PRINTF(2, 3)
     /* [previous][next][first][last][top][bottom][index][help] */
 293 static void
 294 xml_err(pcmk__output_t *out, const char *format, ...) {
 295     private_data_t *priv = NULL;
 296     int len = 0;
 297     char *buf = NULL;
 298     va_list ap;
 299 
 300     pcmk__assert((out != NULL) && (out->priv != NULL));
 301     priv = out->priv;
 302 
 303     add_root_node(out);
 304 
 305     va_start(ap, format);
 306     len = vasprintf(&buf, format, ap);
 307     pcmk__assert(len > 0);
 308     va_end(ap);
 309 
 310     priv->errors = g_slist_append(priv->errors, buf);
 311 }
 312 
 313 G_GNUC_PRINTF(2, 3)
     /* [previous][next][first][last][top][bottom][index][help] */
 314 static int
 315 xml_info(pcmk__output_t *out, const char *format, ...) {
 316     return pcmk_rc_no_output;
 317 }
 318 
 319 static void
 320 xml_output_xml(pcmk__output_t *out, const char *name, const char *buf) {
     /* [previous][next][first][last][top][bottom][index][help] */
 321     xmlNodePtr parent = NULL;
 322     xmlNodePtr cdata_node = NULL;
 323 
 324     pcmk__assert(out != NULL);
 325 
 326     parent = pcmk__output_create_xml_node(out, name, NULL);
 327     if (parent == NULL) {
 328         return;
 329     }
 330     cdata_node = xmlNewCDataBlock(parent->doc, (const xmlChar *) buf,
 331                                   strlen(buf));
 332     xmlAddChild(parent, cdata_node);
 333 }
 334 
 335 G_GNUC_PRINTF(4, 5)
     /* [previous][next][first][last][top][bottom][index][help] */
 336 static void
 337 xml_begin_list(pcmk__output_t *out, const char *singular_noun, const char *plural_noun,
 338                const char *format, ...) {
 339     va_list ap;
 340     char *name = NULL;
 341     char *buf = NULL;
 342     int len;
 343     private_data_t *priv = NULL;
 344 
 345     pcmk__assert((out != NULL) && (out->priv != NULL));
 346     priv = out->priv;
 347 
 348     va_start(ap, format);
 349     len = vasprintf(&buf, format, ap);
 350     pcmk__assert(len >= 0);
 351     va_end(ap);
 352 
 353     for (const subst_t *s = substitutions; s->from != NULL; s++) {
 354         if (strcmp(s->from, buf) == 0) {
 355             name = g_strdup(s->to);
 356             break;
 357         }
 358     }
 359 
 360     if (name == NULL) {
 361         name = g_ascii_strdown(buf, -1);
 362     }
 363 
 364     if (priv->list_element) {
 365         pcmk__output_xml_create_parent(out, PCMK_XE_LIST,
 366                                        PCMK_XA_NAME, name,
 367                                        NULL);
 368     } else {
 369         pcmk__output_xml_create_parent(out, name, NULL);
 370     }
 371 
 372     g_free(name);
 373     free(buf);
 374 }
 375 
 376 G_GNUC_PRINTF(3, 4)
     /* [previous][next][first][last][top][bottom][index][help] */
 377 static void
 378 xml_list_item(pcmk__output_t *out, const char *name, const char *format, ...) {
 379     xmlNodePtr item_node = NULL;
 380     va_list ap;
 381     char *buf = NULL;
 382     int len;
 383 
 384     pcmk__assert(out != NULL);
 385 
 386     va_start(ap, format);
 387     len = vasprintf(&buf, format, ap);
 388     pcmk__assert(len >= 0);
 389     va_end(ap);
 390 
 391     item_node = pcmk__output_create_xml_text_node(out, PCMK_XE_ITEM, buf);
 392 
 393     if (name != NULL) {
 394         crm_xml_add(item_node, PCMK_XA_NAME, name);
 395     }
 396 
 397     free(buf);
 398 }
 399 
 400 static void
 401 xml_increment_list(pcmk__output_t *out) {
     /* [previous][next][first][last][top][bottom][index][help] */
 402     /* This function intentially left blank */
 403 }
 404 
 405 static void
 406 xml_end_list(pcmk__output_t *out) {
     /* [previous][next][first][last][top][bottom][index][help] */
 407     private_data_t *priv = NULL;
 408 
 409     pcmk__assert((out != NULL) && (out->priv != NULL));
 410     priv = out->priv;
 411 
 412     if (priv->list_element) {
 413         char *buf = NULL;
 414         xmlNodePtr node;
 415 
 416         /* Do not free node here - it's still part of the document */
 417         node = g_queue_pop_tail(priv->parent_q);
 418         buf = crm_strdup_printf("%lu", xmlChildElementCount(node));
 419         crm_xml_add(node, PCMK_XA_COUNT, buf);
 420         free(buf);
 421     } else {
 422         /* Do not free this result - it's still part of the document */
 423         g_queue_pop_tail(priv->parent_q);
 424     }
 425 }
 426 
 427 static bool
 428 xml_is_quiet(pcmk__output_t *out) {
     /* [previous][next][first][last][top][bottom][index][help] */
 429     return false;
 430 }
 431 
 432 static void
 433 xml_spacer(pcmk__output_t *out) {
     /* [previous][next][first][last][top][bottom][index][help] */
 434     /* This function intentionally left blank */
 435 }
 436 
 437 static void
 438 xml_progress(pcmk__output_t *out, bool end) {
     /* [previous][next][first][last][top][bottom][index][help] */
 439     /* This function intentionally left blank */
 440 }
 441 
 442 pcmk__output_t *
 443 pcmk__mk_xml_output(char **argv) {
     /* [previous][next][first][last][top][bottom][index][help] */
 444     pcmk__output_t *retval = calloc(1, sizeof(pcmk__output_t));
 445 
 446     if (retval == NULL) {
 447         return NULL;
 448     }
 449 
 450     retval->fmt_name = "xml";
 451     retval->request = pcmk__quote_cmdline(argv);
 452 
 453     retval->init = xml_init;
 454     retval->free_priv = xml_free_priv;
 455     retval->finish = xml_finish;
 456     retval->reset = xml_reset;
 457 
 458     retval->register_message = pcmk__register_message;
 459     retval->message = pcmk__call_message;
 460 
 461     retval->subprocess_output = xml_subprocess_output;
 462     retval->version = xml_version;
 463     retval->info = xml_info;
 464     retval->transient = xml_info;
 465     retval->err = xml_err;
 466     retval->output_xml = xml_output_xml;
 467 
 468     retval->begin_list = xml_begin_list;
 469     retval->list_item = xml_list_item;
 470     retval->increment_list = xml_increment_list;
 471     retval->end_list = xml_end_list;
 472 
 473     retval->is_quiet = xml_is_quiet;
 474     retval->spacer = xml_spacer;
 475     retval->progress = xml_progress;
 476     retval->prompt = pcmk__text_prompt;
 477 
 478     return retval;
 479 }
 480 
 481 xmlNodePtr
 482 pcmk__output_xml_create_parent(pcmk__output_t *out, const char *name, ...) {
     /* [previous][next][first][last][top][bottom][index][help] */
 483     va_list args;
 484     xmlNodePtr node = NULL;
 485 
 486     pcmk__assert(out != NULL);
 487     CRM_CHECK(pcmk__str_any_of(out->fmt_name, "xml", "html", NULL), return NULL);
 488 
 489     node = pcmk__output_create_xml_node(out, name, NULL);
 490 
 491     va_start(args, name);
 492     pcmk__xe_set_propv(node, args);
 493     va_end(args);
 494 
 495     pcmk__output_xml_push_parent(out, node);
 496     return node;
 497 }
 498 
 499 void
 500 pcmk__output_xml_add_node_copy(pcmk__output_t *out, xmlNodePtr node) {
     /* [previous][next][first][last][top][bottom][index][help] */
 501     private_data_t *priv = NULL;
 502     xmlNodePtr parent = NULL;
 503 
 504     pcmk__assert((out != NULL) && (out->priv != NULL) && (node != NULL));
 505     CRM_CHECK(pcmk__str_any_of(out->fmt_name, "xml", "html", NULL), return);
 506 
 507     add_root_node(out);
 508 
 509     priv = out->priv;
 510     parent = g_queue_peek_tail(priv->parent_q);
 511 
 512     // Shouldn't happen unless the caller popped priv->root
 513     CRM_CHECK(parent != NULL, return);
 514 
 515     pcmk__xml_copy(parent, node);
 516 }
 517 
 518 xmlNodePtr
 519 pcmk__output_create_xml_node(pcmk__output_t *out, const char *name, ...) {
     /* [previous][next][first][last][top][bottom][index][help] */
 520     xmlNodePtr node = NULL;
 521     private_data_t *priv = NULL;
 522     va_list args;
 523 
 524     pcmk__assert((out != NULL) && (out->priv != NULL));
 525     CRM_CHECK(pcmk__str_any_of(out->fmt_name, "xml", "html", NULL), return NULL);
 526 
 527     add_root_node(out);
 528 
 529     priv = out->priv;
 530 
 531     node = pcmk__xe_create(g_queue_peek_tail(priv->parent_q), name);
 532     va_start(args, name);
 533     pcmk__xe_set_propv(node, args);
 534     va_end(args);
 535 
 536     return node;
 537 }
 538 
 539 xmlNodePtr
 540 pcmk__output_create_xml_text_node(pcmk__output_t *out, const char *name, const char *content) {
     /* [previous][next][first][last][top][bottom][index][help] */
 541     xmlNodePtr node = NULL;
 542 
 543     pcmk__assert(out != NULL);
 544     CRM_CHECK(pcmk__str_any_of(out->fmt_name, "xml", "html", NULL), return NULL);
 545 
 546     node = pcmk__output_create_xml_node(out, name, NULL);
 547     pcmk__xe_set_content(node, "%s", content);
 548     return node;
 549 }
 550 
 551 void
 552 pcmk__output_xml_push_parent(pcmk__output_t *out, xmlNodePtr parent) {
     /* [previous][next][first][last][top][bottom][index][help] */
 553     private_data_t *priv = NULL;
 554 
 555     pcmk__assert((out != NULL) && (out->priv != NULL) && (parent != NULL));
 556     CRM_CHECK(pcmk__str_any_of(out->fmt_name, "xml", "html", NULL), return);
 557 
 558     add_root_node(out);
 559 
 560     priv = out->priv;
 561 
 562     g_queue_push_tail(priv->parent_q, parent);
 563 }
 564 
 565 void
 566 pcmk__output_xml_pop_parent(pcmk__output_t *out) {
     /* [previous][next][first][last][top][bottom][index][help] */
 567     private_data_t *priv = NULL;
 568 
 569     pcmk__assert((out != NULL) && (out->priv != NULL));
 570     CRM_CHECK(pcmk__str_any_of(out->fmt_name, "xml", "html", NULL), return);
 571 
 572     add_root_node(out);
 573 
 574     priv = out->priv;
 575 
 576     pcmk__assert(g_queue_get_length(priv->parent_q) > 0);
 577     /* Do not free this result - it's still part of the document */
 578     g_queue_pop_tail(priv->parent_q);
 579 }
 580 
 581 xmlNodePtr
 582 pcmk__output_xml_peek_parent(pcmk__output_t *out) {
     /* [previous][next][first][last][top][bottom][index][help] */
 583     private_data_t *priv = NULL;
 584 
 585     pcmk__assert((out != NULL) && (out->priv != NULL));
 586     CRM_CHECK(pcmk__str_any_of(out->fmt_name, "xml", "html", NULL), return NULL);
 587 
 588     add_root_node(out);
 589 
 590     priv = out->priv;
 591 
 592     /* If queue is empty NULL will be returned */
 593     return g_queue_peek_tail(priv->parent_q);
 594 }
 595 
 596 bool
 597 pcmk__output_get_legacy_xml(pcmk__output_t *out)
     /* [previous][next][first][last][top][bottom][index][help] */
 598 {
 599     private_data_t *priv = NULL;
 600 
 601     pcmk__assert(out != NULL);
 602 
 603     if (!pcmk__str_eq(out->fmt_name, "xml", pcmk__str_none)) {
 604         return false;
 605     }
 606 
 607     pcmk__assert(out->priv != NULL);
 608 
 609     priv = out->priv;
 610     return priv->legacy_xml;
 611 }
 612 
 613 void
 614 pcmk__output_set_legacy_xml(pcmk__output_t *out)
     /* [previous][next][first][last][top][bottom][index][help] */
 615 {
 616     private_data_t *priv = NULL;
 617 
 618     pcmk__assert(out != NULL);
 619 
 620     if (!pcmk__str_eq(out->fmt_name, "xml", pcmk__str_none)) {
 621         return;
 622     }
 623 
 624     pcmk__assert(out->priv != NULL);
 625 
 626     priv = out->priv;
 627     priv->legacy_xml = true;
 628 }
 629 
 630 void
 631 pcmk__output_enable_list_element(pcmk__output_t *out)
     /* [previous][next][first][last][top][bottom][index][help] */
 632 {
 633     private_data_t *priv = NULL;
 634 
 635     pcmk__assert(out != NULL);
 636 
 637     if (!pcmk__str_eq(out->fmt_name, "xml", pcmk__str_none)) {
 638         return;
 639     }
 640 
 641     pcmk__assert(out->priv != NULL);
 642 
 643     priv = out->priv;
 644     priv->list_element = true;
 645 }

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