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