LCOV - code coverage report
Current view: top level - common - output_xml.c (source / functions) Hit Total Coverage
Test: Pacemaker code coverage Lines: 0 292 0.0 %
Date: 2024-05-07 11:09:47 Functions: 0 30 0.0 %

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

Generated by: LCOV version 1.14