pacemaker  2.1.9-49aab99839
Scalable High-Availability cluster resource manager
xml_io.c
Go to the documentation of this file.
1 /*
2  * Copyright 2004-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 <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <sys/types.h>
16 
17 #include <bzlib.h>
18 #include <libxml/parser.h>
19 #include <libxml/tree.h>
20 #include <libxml/xmlIO.h> // xmlOutputBuffer*
21 
22 #include <crm/crm.h>
23 #include <crm/common/xml.h>
24 #include <crm/common/xml_io.h>
25 #include "crmcommon_private.h"
26 
27 /* @COMPAT XML_PARSE_RECOVER allows some XML errors to be silently worked around
28  * by libxml2, which is potentially ambiguous and dangerous. We should drop it
29  * when we can break backward compatibility with configurations that might be
30  * relying on it (i.e. pacemaker 3.0.0).
31  */
32 #define PCMK__XML_PARSE_OPTS_WITHOUT_RECOVER (XML_PARSE_NOBLANKS)
33 #define PCMK__XML_PARSE_OPTS_WITH_RECOVER (XML_PARSE_NOBLANKS \
34  |XML_PARSE_RECOVER)
35 
45 static char *
46 read_stdin(void)
47 {
48  char *buf = NULL;
49  size_t length = 0;
50 
51  do {
52  buf = pcmk__realloc(buf, length + PCMK__BUFFER_SIZE + 1);
53  length += fread(buf + length, 1, PCMK__BUFFER_SIZE, stdin);
54  } while ((feof(stdin) == 0) && (ferror(stdin) == 0));
55 
56  if (ferror(stdin) != 0) {
57  crm_err("Error reading input from stdin");
58  free(buf);
59  buf = NULL;
60  } else {
61  buf[length] = '\0';
62  }
63  clearerr(stdin);
64  return buf;
65 }
66 
78 static char *
79 decompress_file(const char *filename)
80 {
81  char *buffer = NULL;
82  int rc = pcmk_rc_ok;
83  size_t length = 0;
84  BZFILE *bz_file = NULL;
85  FILE *input = fopen(filename, "r");
86 
87  if (input == NULL) {
88  crm_perror(LOG_ERR, "Could not open %s for reading", filename);
89  return NULL;
90  }
91 
92  bz_file = BZ2_bzReadOpen(&rc, input, 0, 0, NULL, 0);
93  rc = pcmk__bzlib2rc(rc);
94  if (rc != pcmk_rc_ok) {
95  crm_err("Could not prepare to read compressed %s: %s "
96  CRM_XS " rc=%d", filename, pcmk_rc_str(rc), rc);
97  goto done;
98  }
99 
100  // cppcheck seems not to understand the abort-logic in pcmk__realloc
101  // cppcheck-suppress memleak
102  do {
103  int read_len = 0;
104 
105  buffer = pcmk__realloc(buffer, length + PCMK__BUFFER_SIZE + 1);
106  read_len = BZ2_bzRead(&rc, bz_file, buffer + length, PCMK__BUFFER_SIZE);
107 
108  if ((rc == BZ_OK) || (rc == BZ_STREAM_END)) {
109  crm_trace("Read %ld bytes from file: %d", (long) read_len, rc);
110  length += read_len;
111  }
112  } while (rc == BZ_OK);
113 
114  rc = pcmk__bzlib2rc(rc);
115  if (rc != pcmk_rc_ok) {
116  rc = pcmk__bzlib2rc(rc);
117  crm_err("Could not read compressed %s: %s " CRM_XS " rc=%d",
118  filename, pcmk_rc_str(rc), rc);
119  free(buffer);
120  buffer = NULL;
121  } else {
122  buffer[length] = '\0';
123  }
124 
125 done:
126  BZ2_bzReadClose(&rc, bz_file);
127  fclose(input);
128  return buffer;
129 }
130 
131 // @COMPAT Remove macro at 3.0.0 when we drop XML_PARSE_RECOVER
141 #define parse_xml_recover(result, fn, ...) do { \
142  *result = fn(__VA_ARGS__, PCMK__XML_PARSE_OPTS_WITHOUT_RECOVER); \
143  if (*result == NULL) { \
144  *result = fn(__VA_ARGS__, PCMK__XML_PARSE_OPTS_WITH_RECOVER); \
145  \
146  if (*result != NULL) { \
147  crm_warn("Successfully recovered from XML errors " \
148  "(note: a future release will treat this as a " \
149  "fatal failure)"); \
150  } \
151  } \
152  } while (0);
153 
165 xmlNode *
166 pcmk__xml_read(const char *filename)
167 {
168  bool use_stdin = pcmk__str_eq(filename, "-", pcmk__str_null_matches);
169  xmlNode *xml = NULL;
170  xmlDoc *output = NULL;
171  xmlParserCtxt *ctxt = NULL;
172  const xmlError *last_error = NULL;
173 
174  // Create a parser context
175  ctxt = xmlNewParserCtxt();
176  CRM_CHECK(ctxt != NULL, return NULL);
177 
178  xmlCtxtResetLastError(ctxt);
179  xmlSetGenericErrorFunc(ctxt, pcmk__log_xmllib_err);
180 
181  if (use_stdin) {
182  /* @COMPAT After dropping XML_PARSE_RECOVER, we can avoid capturing
183  * stdin into a buffer and instead call
184  * xmlCtxtReadFd(ctxt, STDIN_FILENO, NULL, NULL, XML_PARSE_NOBLANKS);
185  *
186  * For now we have to save the input so that we can use it twice.
187  */
188  char *input = read_stdin();
189 
190  if (input != NULL) {
191  parse_xml_recover(&output, xmlCtxtReadDoc, ctxt, (pcmkXmlStr) input,
192  NULL, NULL);
193  free(input);
194  }
195 
196  } else if (pcmk__ends_with_ext(filename, ".bz2")) {
197  char *input = decompress_file(filename);
198 
199  if (input != NULL) {
200  parse_xml_recover(&output, xmlCtxtReadDoc, ctxt, (pcmkXmlStr) input,
201  NULL, NULL);
202  free(input);
203  }
204 
205  } else {
206  parse_xml_recover(&output, xmlCtxtReadFile, ctxt, filename, NULL);
207  }
208 
209  if (output != NULL) {
210  pcmk__xml_new_private_data((xmlNode *) output);
211  xml = xmlDocGetRootElement(output);
212  if (xml != NULL) {
213  /* @TODO Should we really be stripping out text? This seems like an
214  * overly broad way to get rid of whitespace, if that's the goal.
215  * Text nodes may be invalid in most or all Pacemaker inputs, but
216  * stripping them in a generic "parse XML from file" function may
217  * not be the best way to ignore them.
218  */
220  }
221  }
222 
223  // @COMPAT At 3.0.0, free xml and return NULL if xml != NULL on error
224  last_error = xmlCtxtGetLastError(ctxt);
225  if (last_error != NULL) {
226  if (xml != NULL) {
227  crm_log_xml_info(xml, "Partial");
228  }
229  }
230 
231  xmlFreeParserCtxt(ctxt);
232  return xml;
233 }
234 
244 xmlNode *
245 pcmk__xml_parse(const char *input)
246 {
247  xmlNode *xml = NULL;
248  xmlDoc *output = NULL;
249  xmlParserCtxt *ctxt = NULL;
250  const xmlError *last_error = NULL;
251 
252  if (input == NULL) {
253  return NULL;
254  }
255 
256  ctxt = xmlNewParserCtxt();
257  if (ctxt == NULL) {
258  return NULL;
259  }
260 
261  xmlCtxtResetLastError(ctxt);
262  xmlSetGenericErrorFunc(ctxt, pcmk__log_xmllib_err);
263 
264  parse_xml_recover(&output, xmlCtxtReadDoc, ctxt, (pcmkXmlStr) input, NULL,
265  NULL);
266 
267  if (output != NULL) {
268  pcmk__xml_new_private_data((xmlNode *) output);
269  xml = xmlDocGetRootElement(output);
270  }
271 
272  // @COMPAT At 3.0.0, free xml and return NULL if xml != NULL; update doxygen
273  last_error = xmlCtxtGetLastError(ctxt);
274  if (last_error != NULL) {
275  if (xml != NULL) {
276  crm_log_xml_info(xml, "Partial");
277  }
278  }
279 
280  xmlFreeParserCtxt(ctxt);
281  return xml;
282 }
283 
293 static void
294 dump_xml_element(const xmlNode *data, uint32_t options, GString *buffer,
295  int depth)
296 {
297  bool pretty = pcmk_is_set(options, pcmk__xml_fmt_pretty);
298  bool filtered = pcmk_is_set(options, pcmk__xml_fmt_filtered);
299  int spaces = pretty? (2 * depth) : 0;
300 
301  for (int lpc = 0; lpc < spaces; lpc++) {
302  g_string_append_c(buffer, ' ');
303  }
304 
305  pcmk__g_strcat(buffer, "<", data->name, NULL);
306 
307  for (const xmlAttr *attr = pcmk__xe_first_attr(data); attr != NULL;
308  attr = attr->next) {
309 
310  if (!filtered || !pcmk__xa_filterable((const char *) (attr->name))) {
311  pcmk__dump_xml_attr(attr, buffer);
312  }
313  }
314 
315  if (data->children == NULL) {
316  g_string_append(buffer, "/>");
317 
318  } else {
319  g_string_append_c(buffer, '>');
320  }
321 
322  if (pretty) {
323  g_string_append_c(buffer, '\n');
324  }
325 
326  if (data->children) {
327  for (const xmlNode *child = data->children; child != NULL;
328  child = child->next) {
329  pcmk__xml_string(child, options, buffer, depth + 1);
330  }
331 
332  for (int lpc = 0; lpc < spaces; lpc++) {
333  g_string_append_c(buffer, ' ');
334  }
335 
336  pcmk__g_strcat(buffer, "</", data->name, ">", NULL);
337 
338  if (pretty) {
339  g_string_append_c(buffer, '\n');
340  }
341  }
342 }
343 
353 static void
354 dump_xml_text(const xmlNode *data, uint32_t options, GString *buffer,
355  int depth)
356 {
357  bool pretty = pcmk_is_set(options, pcmk__xml_fmt_pretty);
358  int spaces = pretty? (2 * depth) : 0;
359  const char *content = (const char *) data->content;
360  gchar *content_esc = NULL;
361 
363  content_esc = pcmk__xml_escape(content, pcmk__xml_escape_text);
364  content = content_esc;
365  }
366 
367  for (int lpc = 0; lpc < spaces; lpc++) {
368  g_string_append_c(buffer, ' ');
369  }
370 
371  g_string_append(buffer, content);
372 
373  if (pretty) {
374  g_string_append_c(buffer, '\n');
375  }
376  g_free(content_esc);
377 }
378 
388 static void
389 dump_xml_cdata(const xmlNode *data, uint32_t options, GString *buffer,
390  int depth)
391 {
392  bool pretty = pcmk_is_set(options, pcmk__xml_fmt_pretty);
393  int spaces = pretty? (2 * depth) : 0;
394 
395  for (int lpc = 0; lpc < spaces; lpc++) {
396  g_string_append_c(buffer, ' ');
397  }
398 
399  pcmk__g_strcat(buffer, "<![CDATA[", (const char *) data->content, "]]>",
400  NULL);
401 
402  if (pretty) {
403  g_string_append_c(buffer, '\n');
404  }
405 }
406 
416 static void
417 dump_xml_comment(const xmlNode *data, uint32_t options, GString *buffer,
418  int depth)
419 {
420  bool pretty = pcmk_is_set(options, pcmk__xml_fmt_pretty);
421  int spaces = pretty? (2 * depth) : 0;
422 
423  for (int lpc = 0; lpc < spaces; lpc++) {
424  g_string_append_c(buffer, ' ');
425  }
426 
427  pcmk__g_strcat(buffer, "<!--", (const char *) data->content, "-->", NULL);
428 
429  if (pretty) {
430  g_string_append_c(buffer, '\n');
431  }
432 }
433 
442 static const char *
443 xml_element_type_text(xmlElementType type)
444 {
445  static const char *const element_type_names[] = {
446  [XML_ELEMENT_NODE] = "element",
447  [XML_ATTRIBUTE_NODE] = "attribute",
448  [XML_TEXT_NODE] = "text",
449  [XML_CDATA_SECTION_NODE] = "CDATA section",
450  [XML_ENTITY_REF_NODE] = "entity reference",
451  [XML_ENTITY_NODE] = "entity",
452  [XML_PI_NODE] = "PI",
453  [XML_COMMENT_NODE] = "comment",
454  [XML_DOCUMENT_NODE] = "document",
455  [XML_DOCUMENT_TYPE_NODE] = "document type",
456  [XML_DOCUMENT_FRAG_NODE] = "document fragment",
457  [XML_NOTATION_NODE] = "notation",
458  [XML_HTML_DOCUMENT_NODE] = "HTML document",
459  [XML_DTD_NODE] = "DTD",
460  [XML_ELEMENT_DECL] = "element declaration",
461  [XML_ATTRIBUTE_DECL] = "attribute declaration",
462  [XML_ENTITY_DECL] = "entity declaration",
463  [XML_NAMESPACE_DECL] = "namespace declaration",
464  [XML_XINCLUDE_START] = "XInclude start",
465  [XML_XINCLUDE_END] = "XInclude end",
466  };
467 
468  if ((type < 0) || (type >= PCMK__NELEM(element_type_names))) {
469  return "unrecognized type";
470  }
471  return element_type_names[type];
472 }
473 
489 void
490 pcmk__xml_string(const xmlNode *data, uint32_t options, GString *buffer,
491  int depth)
492 {
493  if (data == NULL) {
494  crm_trace("Nothing to dump");
495  return;
496  }
497 
498  pcmk__assert(buffer != NULL);
499  CRM_CHECK(depth >= 0, depth = 0);
500 
501  switch(data->type) {
502  case XML_ELEMENT_NODE:
503  /* Handle below */
504  dump_xml_element(data, options, buffer, depth);
505  break;
506  case XML_TEXT_NODE:
507  if (pcmk_is_set(options, pcmk__xml_fmt_text)) {
508  dump_xml_text(data, options, buffer, depth);
509  }
510  break;
511  case XML_COMMENT_NODE:
512  dump_xml_comment(data, options, buffer, depth);
513  break;
514  case XML_CDATA_SECTION_NODE:
515  dump_xml_cdata(data, options, buffer, depth);
516  break;
517  default:
518  crm_warn("Cannot convert XML %s node to text " CRM_XS " type=%d",
519  xml_element_type_text(data->type), data->type);
520  break;
521  }
522 }
523 
535 static int
536 write_compressed_stream(char *text, const char *filename, FILE *stream,
537  unsigned int *bytes_out)
538 {
539  unsigned int bytes_in = 0;
540  int rc = pcmk_rc_ok;
541 
542  // (5, 0, 0): (intermediate block size, silent, default workFactor)
543  BZFILE *bz_file = BZ2_bzWriteOpen(&rc, stream, 5, 0, 0);
544 
545  rc = pcmk__bzlib2rc(rc);
546  if (rc != pcmk_rc_ok) {
547  crm_warn("Not compressing %s: could not prepare file stream: %s "
548  CRM_XS " rc=%d",
549  filename, pcmk_rc_str(rc), rc);
550  goto done;
551  }
552 
553  BZ2_bzWrite(&rc, bz_file, text, strlen(text));
554  rc = pcmk__bzlib2rc(rc);
555  if (rc != pcmk_rc_ok) {
556  crm_warn("Not compressing %s: could not compress data: %s "
557  CRM_XS " rc=%d errno=%d",
558  filename, pcmk_rc_str(rc), rc, errno);
559  goto done;
560  }
561 
562  BZ2_bzWriteClose(&rc, bz_file, 0, &bytes_in, bytes_out);
563  bz_file = NULL;
564  rc = pcmk__bzlib2rc(rc);
565  if (rc != pcmk_rc_ok) {
566  crm_warn("Not compressing %s: could not write compressed data: %s "
567  CRM_XS " rc=%d errno=%d",
568  filename, pcmk_rc_str(rc), rc, errno);
569  goto done;
570  }
571 
572  crm_trace("Compressed XML for %s from %u bytes to %u",
573  filename, bytes_in, *bytes_out);
574 
575 done:
576  if (bz_file != NULL) {
577  BZ2_bzWriteClose(&rc, bz_file, 0, NULL, NULL);
578  }
579  return rc;
580 }
581 
595 static int
596 write_xml_stream(const xmlNode *xml, const char *filename, FILE *stream,
597  bool compress, unsigned int *nbytes)
598 {
599  // @COMPAT Drop nbytes as arg when we drop write_xml_fd()/write_xml_file()
600  GString *buffer = g_string_sized_new(1024);
601  unsigned int bytes_out = 0;
602  int rc = pcmk_rc_ok;
603 
604  pcmk__xml_string(xml, pcmk__xml_fmt_pretty, buffer, 0);
605  CRM_CHECK(!pcmk__str_empty(buffer->str),
606  crm_log_xml_info(xml, "dump-failed");
607  rc = pcmk_rc_error;
608  goto done);
609 
610  crm_log_xml_trace(xml, "writing");
611 
612  if (compress
613  && (write_compressed_stream(buffer->str, filename, stream,
614  &bytes_out) == pcmk_rc_ok)) {
615  goto done;
616  }
617 
618  rc = fprintf(stream, "%s", buffer->str);
619  if (rc < 0) {
620  rc = EIO;
621  crm_perror(LOG_ERR, "writing %s", filename);
622  goto done;
623  }
624  bytes_out = (unsigned int) rc;
625  rc = pcmk_rc_ok;
626 
627 done:
628  if (fflush(stream) != 0) {
629  rc = errno;
630  crm_perror(LOG_ERR, "flushing %s", filename);
631  }
632 
633  // Don't report error if the file does not support synchronization
634  if ((fsync(fileno(stream)) < 0) && (errno != EROFS) && (errno != EINVAL)) {
635  rc = errno;
636  crm_perror(LOG_ERR, "synchronizing %s", filename);
637  }
638 
639  fclose(stream);
640  crm_trace("Saved %u bytes to %s as XML", bytes_out, filename);
641 
642  if (nbytes != NULL) {
643  *nbytes = bytes_out;
644  }
645  g_string_free(buffer, TRUE);
646  return rc;
647 }
648 
661 int
662 pcmk__xml_write_fd(const xmlNode *xml, const char *filename, int fd,
663  bool compress, unsigned int *nbytes)
664 {
665  // @COMPAT Drop compress and nbytes arguments when we drop write_xml_fd()
666  FILE *stream = NULL;
667 
668  CRM_CHECK((xml != NULL) && (fd > 0), return EINVAL);
669  stream = fdopen(fd, "w");
670  if (stream == NULL) {
671  return errno;
672  }
673 
674  return write_xml_stream(xml, pcmk__s(filename, "unnamed file"), stream,
675  compress, nbytes);
676 }
677 
689 int
690 pcmk__xml_write_file(const xmlNode *xml, const char *filename, bool compress,
691  unsigned int *nbytes)
692 {
693  // @COMPAT Drop nbytes argument when we drop write_xml_fd()
694  FILE *stream = NULL;
695 
696  CRM_CHECK((xml != NULL) && (filename != NULL), return EINVAL);
697  stream = fopen(filename, "w");
698  if (stream == NULL) {
699  return errno;
700  }
701 
702  return write_xml_stream(xml, filename, stream, compress, nbytes);
703 }
704 
714 int
715 pcmk__xml2fd(int fd, xmlNode *cur)
716 {
717  bool success;
718 
719  xmlOutputBuffer *fd_out = xmlOutputBufferCreateFd(fd, NULL);
720  pcmk__mem_assert(fd_out);
721  xmlNodeDumpOutput(fd_out, cur->doc, cur, 0, pcmk__xml_fmt_pretty, NULL);
722 
723  success = xmlOutputBufferWrite(fd_out, sizeof("\n") - 1, "\n") != -1;
724 
725  success = xmlOutputBufferClose(fd_out) != -1 && success;
726 
727  if (!success) {
728  return EIO;
729  }
730 
731  fsync(fd);
732  return pcmk_rc_ok;
733 }
734 
735 void
736 save_xml_to_file(const xmlNode *xml, const char *desc, const char *filename)
737 {
738  char *f = NULL;
739 
740  if (filename == NULL) {
741  char *uuid = crm_generate_uuid();
742 
743  f = crm_strdup_printf("%s/%s", pcmk__get_tmpdir(), uuid);
744  filename = f;
745  free(uuid);
746  }
747 
748  crm_info("Saving %s to %s", desc, filename);
749  pcmk__xml_write_file(xml, filename, false, NULL);
750  free(f);
751 }
752 
753 
754 // Deprecated functions kept only for backward API compatibility
755 // LCOV_EXCL_START
756 
758 
759 xmlNode *
760 filename2xml(const char *filename)
761 {
762  return pcmk__xml_read(filename);
763 }
764 
765 xmlNode *
767 {
768  return pcmk__xml_read(NULL);
769 }
770 
771 xmlNode *
772 string2xml(const char *input)
773 {
774  return pcmk__xml_parse(input);
775 }
776 
777 char *
778 dump_xml_formatted(const xmlNode *xml)
779 {
780  char *str = NULL;
781  GString *buffer = g_string_sized_new(1024);
782 
783  pcmk__xml_string(xml, pcmk__xml_fmt_pretty, buffer, 0);
784 
785  str = pcmk__str_copy(buffer->str);
786  g_string_free(buffer, TRUE);
787  return str;
788 }
789 
790 char *
791 dump_xml_formatted_with_text(const xmlNode *xml)
792 {
793  char *str = NULL;
794  GString *buffer = g_string_sized_new(1024);
795 
797 
798  str = pcmk__str_copy(buffer->str);
799  g_string_free(buffer, TRUE);
800  return str;
801 }
802 
803 char *
804 dump_xml_unformatted(const xmlNode *xml)
805 {
806  char *str = NULL;
807  GString *buffer = g_string_sized_new(1024);
808 
809  pcmk__xml_string(xml, 0, buffer, 0);
810 
811  str = pcmk__str_copy(buffer->str);
812  g_string_free(buffer, TRUE);
813  return str;
814 }
815 
816 int
817 write_xml_fd(const xmlNode *xml, const char *filename, int fd,
818  gboolean compress)
819 {
820  unsigned int nbytes = 0;
821  int rc = pcmk__xml_write_fd(xml, filename, fd, compress, &nbytes);
822 
823  if (rc != pcmk_rc_ok) {
824  return pcmk_rc2legacy(rc);
825  }
826  return (int) nbytes;
827 }
828 
829 int
830 write_xml_file(const xmlNode *xml, const char *filename, gboolean compress)
831 {
832  unsigned int nbytes = 0;
833  int rc = pcmk__xml_write_file(xml, filename, compress, &nbytes);
834 
835  if (rc != pcmk_rc_ok) {
836  return pcmk_rc2legacy(rc);
837  }
838  return (int) nbytes;
839 }
840 
841 // LCOV_EXCL_STOP
842 // End deprecated API
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:245
int pcmk__xml_write_file(const xmlNode *xml, const char *filename, bool compress, unsigned int *nbytes)
Definition: xml_io.c:690
A dumping ground.
char * pcmk__xml_escape(const char *text, enum pcmk__xml_escape_type type)
Definition: xml.c:1199
char data[0]
Definition: cpg.c:58
char * crm_generate_uuid(void)
Definition: utils.c:319
int pcmk_rc2legacy(int rc)
Definition: results.c:548
xmlNode * stdin2xml(void)
Definition: xml_io.c:766
char * dump_xml_formatted(const xmlNode *xml)
Definition: xml_io.c:778
void pcmk__xml_string(const xmlNode *data, uint32_t options, GString *buffer, int depth)
Definition: xml_io.c:490
int write_xml_fd(const xmlNode *xml, const char *filename, int fd, gboolean compress)
Definition: xml_io.c:817
bool pcmk__xml_needs_escape(const char *text, enum pcmk__xml_escape_type type)
Definition: xml.c:1117
G_GNUC_INTERNAL void pcmk__log_xmllib_err(void *ctx, const char *fmt,...) G_GNUC_PRINTF(2
Exclude certain XML attributes (for calculating digests)
Definition: xml_internal.h:137
int pcmk__xml_write_fd(const xmlNode *xml, const char *filename, int fd, bool compress, unsigned int *nbytes)
Definition: xml_io.c:662
xmlNode * pcmk__xml_parse(const char *input)
Definition: xml_io.c:245
xmlNode * string2xml(const char *input)
Definition: xml_io.c:772
xmlNode * filename2xml(const char *filename)
Definition: xml_io.c:760
enum crm_ais_msg_types type
Definition: cpg.c:51
Wrappers for and extensions to XML input/output functions.
const char * pcmk_rc_str(int rc)
Get a user-friendly description of a return code.
Definition: results.c:503
Include indentation and newlines.
Definition: xml_internal.h:140
#define crm_warn(fmt, args...)
Definition: logging.h:394
void pcmk__strip_xml_text(xmlNode *xml)
Definition: xml.c:1012
G_GNUC_INTERNAL void pcmk__xml_new_private_data(xmlNode *xml)
Definition: xml.c:326
#define crm_trace(fmt, args...)
Definition: logging.h:404
void pcmk__g_strcat(GString *buffer,...) G_GNUC_NULL_TERMINATED
Definition: strings.c:1308
char * crm_strdup_printf(char const *format,...) G_GNUC_PRINTF(1
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition: util.h:94
Wrappers for and extensions to libxml2.
#define parse_xml_recover(result, fn,...)
Definition: xml_io.c:141
int write_xml_file(const xmlNode *xml, const char *filename, gboolean compress)
Definition: xml_io.c:830
#define PCMK__NELEM(a)
Definition: internal.h:48
char * dump_xml_formatted_with_text(const xmlNode *xml)
Definition: xml_io.c:791
xmlNode * pcmk__xml_read(const char *filename)
Definition: xml_io.c:166
#define pcmk__str_copy(str)
int pcmk__xml2fd(int fd, xmlNode *cur)
Definition: xml_io.c:715
const xmlChar * pcmkXmlStr
Definition: xml.h:41
G_GNUC_INTERNAL bool pcmk__xa_filterable(const char *name)
Definition: digest.c:232
#define pcmk__assert(expr)
#define CRM_XS
Definition: logging.h:56
const char * pcmk__get_tmpdir(void)
Definition: io.c:547
int pcmk__bzlib2rc(int bz2)
Map a bz2 return code to the most similar Pacemaker return code.
Definition: results.c:908
#define PCMK__BUFFER_SIZE
#define crm_perror(level, fmt, args...)
Send a system error message to both the log and stderr.
Definition: logging.h:331
#define crm_err(fmt, args...)
Definition: logging.h:391
xmlNode * input
G_GNUC_INTERNAL void pcmk__dump_xml_attr(const xmlAttr *attr, GString *buffer)
Definition: xml_attr.c:106
#define pcmk__mem_assert(ptr)
#define crm_log_xml_info(xml, text)
Definition: logging.h:410
Include XML text nodes.
Definition: xml_internal.h:153
#define crm_log_xml_trace(xml, text)
Definition: logging.h:412
char * dump_xml_unformatted(const xmlNode *xml)
Definition: xml_io.c:804
Deprecated Pacemaker XML I/O API.
void save_xml_to_file(const xmlNode *xml, const char *desc, const char *filename)
Definition: xml_io.c:736
#define crm_info(fmt, args...)
Definition: logging.h:399
bool pcmk__ends_with_ext(const char *s, const char *match)
Definition: strings.c:647