pacemaker  2.1.7-0f7f88312f
Scalable High-Availability cluster resource manager
xml_internal.h
Go to the documentation of this file.
1 /*
2  * Copyright 2017-2023 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 #ifndef PCMK__XML_INTERNAL__H
11 # define PCMK__XML_INTERNAL__H
12 
13 /*
14  * Internal-only wrappers for and extensions to libxml2 (libxslt)
15  */
16 
17 # include <stdlib.h>
18 # include <stdio.h>
19 # include <string.h>
20 
21 # include <crm/crm.h> /* transitively imports qblog.h */
23 
24 # include <libxml/relaxng.h>
25 
69 #define PCMK__XML_LOG_BASE(priority, dechunk, postemit, prefix, fmt, ap) \
70 do { \
71  if (!(dechunk) && (prefix) == NULL) { /* quick pass */ \
72  qb_log_from_external_source_va(__func__, __FILE__, (fmt), \
73  (priority), __LINE__, 0, (ap)); \
74  (void) (postemit); \
75  } else { \
76  int CXLB_len = 0; \
77  char *CXLB_buf = NULL; \
78  static int CXLB_buffer_len = 0; \
79  static char *CXLB_buffer = NULL; \
80  static uint8_t CXLB_priority = 0; \
81  \
82  CXLB_len = vasprintf(&CXLB_buf, (fmt), (ap)); \
83  \
84  if (CXLB_len <= 0 || CXLB_buf[CXLB_len - 1] == '\n' || !(dechunk)) { \
85  if (CXLB_len < 0) { \
86  CXLB_buf = (char *) "LOG CORRUPTION HAZARD"; /*we don't modify*/\
87  CXLB_priority = QB_MIN(CXLB_priority, LOG_ERR); \
88  } else if (CXLB_len > 0 /* && (dechunk) */ \
89  && CXLB_buf[CXLB_len - 1] == '\n') { \
90  CXLB_buf[CXLB_len - 1] = '\0'; \
91  } \
92  if (CXLB_buffer) { \
93  qb_log_from_external_source(__func__, __FILE__, "%s%s%s", \
94  CXLB_priority, __LINE__, 0, \
95  (prefix) != NULL ? (prefix) : "", \
96  CXLB_buffer, CXLB_buf); \
97  free(CXLB_buffer); \
98  } else { \
99  qb_log_from_external_source(__func__, __FILE__, "%s%s", \
100  (priority), __LINE__, 0, \
101  (prefix) != NULL ? (prefix) : "", \
102  CXLB_buf); \
103  } \
104  if (CXLB_len < 0) { \
105  CXLB_buf = NULL; /* restore temporary override */ \
106  } \
107  CXLB_buffer = NULL; \
108  CXLB_buffer_len = 0; \
109  (void) (postemit); \
110  \
111  } else if (CXLB_buffer == NULL) { \
112  CXLB_buffer_len = CXLB_len; \
113  CXLB_buffer = CXLB_buf; \
114  CXLB_buf = NULL; \
115  CXLB_priority = (priority); /* remember as a running severest */ \
116  \
117  } else { \
118  CXLB_buffer = realloc(CXLB_buffer, 1 + CXLB_buffer_len + CXLB_len); \
119  memcpy(CXLB_buffer + CXLB_buffer_len, CXLB_buf, CXLB_len); \
120  CXLB_buffer_len += CXLB_len; \
121  CXLB_buffer[CXLB_buffer_len] = '\0'; \
122  CXLB_priority = QB_MIN(CXLB_priority, (priority)); /* severest? */ \
123  } \
124  free(CXLB_buf); \
125  } \
126 } while (0)
127 
128 /*
129  * \enum pcmk__xml_fmt_options
130  * \brief Bit flags to control format in XML logs and dumps
131  */
135 
138 
140  pcmk__xml_fmt_open = (1 << 3),
141 
144 
147 
149  pcmk__xml_fmt_text = (1 << 6),
150 
151  // @COMPAT Remove when v1 patchsets are removed
154 
155  // @COMPAT Remove when v1 patchsets are removed
158 
159  // @COMPAT Remove when v1 patchsets are removed
162 };
163 
164 int pcmk__xml_show(pcmk__output_t *out, const char *prefix, const xmlNode *data,
165  int depth, uint32_t options);
166 int pcmk__xml_show_changes(pcmk__output_t *out, const xmlNode *xml);
167 
168 /* XML search strings for guest, remote and pacemaker_remote nodes */
169 
170 /* search string to find CIB resources entries for cluster nodes */
171 #define PCMK__XP_MEMBER_NODE_CONFIG \
172  "//" XML_TAG_CIB "/" XML_CIB_TAG_CONFIGURATION "/" XML_CIB_TAG_NODES \
173  "/" XML_CIB_TAG_NODE "[not(@type) or @type='member']"
174 
175 /* search string to find CIB resources entries for guest nodes */
176 #define PCMK__XP_GUEST_NODE_CONFIG \
177  "//" XML_TAG_CIB "//" XML_CIB_TAG_CONFIGURATION "//" XML_CIB_TAG_RESOURCE \
178  "//" XML_TAG_META_SETS "//" XML_CIB_TAG_NVPAIR \
179  "[@name='" XML_RSC_ATTR_REMOTE_NODE "']"
180 
181 /* search string to find CIB resources entries for remote nodes */
182 #define PCMK__XP_REMOTE_NODE_CONFIG \
183  "//" XML_TAG_CIB "//" XML_CIB_TAG_CONFIGURATION "//" XML_CIB_TAG_RESOURCE \
184  "[@type='remote'][@provider='pacemaker']"
185 
186 /* search string to find CIB node status entries for pacemaker_remote nodes */
187 #define PCMK__XP_REMOTE_NODE_STATUS \
188  "//" XML_TAG_CIB "//" XML_CIB_TAG_STATUS "//" XML_CIB_TAG_STATE \
189  "[@" XML_NODE_IS_REMOTE "='true']"
190 
199 int pcmk__xml2fd(int fd, xmlNode *cur);
200 
206 };
207 
208 void pcmk__strip_xml_text(xmlNode *xml);
209 const char *pcmk__xe_add_last_written(xmlNode *xe);
210 
211 xmlNode *pcmk__xe_match(const xmlNode *parent, const char *node_name,
212  const char *attr_n, const char *attr_v);
213 
214 void pcmk__xe_remove_matching_attrs(xmlNode *element,
215  bool (*match)(xmlAttrPtr, void *),
216  void *user_data);
217 
218 GString *pcmk__element_xpath(const xmlNode *xml);
219 
228 char *
230 
241  const char *filespec);
242 
252 static inline bool
253 pcmk__xe_is(const xmlNode *xml, const char *name)
254 {
255  return (xml != NULL) && (xml->name != NULL) && (name != NULL)
256  && (strcmp((const char *) xml->name, name) == 0);
257 }
258 
267 static inline xmlNode *
268 pcmk__xml_first_child(const xmlNode *parent)
269 {
270  xmlNode *child = (parent? parent->children : NULL);
271 
272  while (child && (child->type == XML_TEXT_NODE)) {
273  child = child->next;
274  }
275  return child;
276 }
277 
286 static inline xmlNode *
287 pcmk__xml_next(const xmlNode *child)
288 {
289  xmlNode *next = (child? child->next : NULL);
290 
291  while (next && (next->type == XML_TEXT_NODE)) {
292  next = next->next;
293  }
294  return next;
295 }
296 
305 static inline xmlNode *
306 pcmk__xe_first_child(const xmlNode *parent)
307 {
308  xmlNode *child = (parent? parent->children : NULL);
309 
310  while (child && (child->type != XML_ELEMENT_NODE)) {
311  child = child->next;
312  }
313  return child;
314 }
315 
324 static inline xmlNode *
325 pcmk__xe_next(const xmlNode *child)
326 {
327  xmlNode *next = child? child->next : NULL;
328 
329  while (next && (next->type != XML_ELEMENT_NODE)) {
330  next = next->next;
331  }
332  return next;
333 }
334 
343 void
344 pcmk__xe_set_propv(xmlNodePtr node, va_list pairs);
345 
356 void
357 pcmk__xe_set_props(xmlNodePtr node, ...)
358 G_GNUC_NULL_TERMINATED;
359 
368 static inline xmlAttr *
369 pcmk__xe_first_attr(const xmlNode *xe)
370 {
371  return (xe == NULL)? NULL : xe->properties;
372 }
373 
383 char *
384 pcmk__xpath_node_id(const char *xpath, const char *node);
385 
386 /* internal XML-related utilities */
387 
389  pcmk__xf_none = 0x0000,
390  pcmk__xf_dirty = 0x0001,
394 
397  pcmk__xf_skip = 0x0040,
398  pcmk__xf_moved = 0x0080,
399 
404 
407  pcmk__xf_lazy = 0x4000,
408 };
409 
410 void pcmk__set_xml_doc_flag(xmlNode *xml, enum xml_private_flags flag);
411 
432 int
433 pcmk__xe_foreach_child(xmlNode *xml, const char *child_element_name,
434  int (*handler)(xmlNode *xml, void *userdata),
435  void *userdata);
436 
437 static inline const char *
438 pcmk__xml_attr_value(const xmlAttr *attr)
439 {
440  return ((attr == NULL) || (attr->children == NULL))? NULL
441  : (const char *) attr->children->content;
442 }
443 
444 gboolean pcmk__validate_xml(xmlNode *xml_blob, const char *validation,
445  xmlRelaxNGValidityErrorFunc error_handler,
446  void *error_handler_context);
447 
448 #endif // PCMK__XML_INTERNAL__H
char * pcmk__xml_artefact_root(enum pcmk__xml_artefact_ns ns)
Definition: xml.c:2586
A dumping ground.
char data[0]
Definition: cpg.c:55
xmlNode * pcmk__xe_match(const xmlNode *parent, const char *node_name, const char *attr_n, const char *attr_v)
Definition: xml.c:429
const char * name
Definition: cib.c:26
const char * pcmk__xe_add_last_written(xmlNode *xe)
Definition: xml.c:1089
Exclude certain XML attributes (for calculating digests)
Definition: xml_internal.h:134
Include the opening tag of an XML element, and include XML comments.
Definition: xml_internal.h:140
void pcmk__xe_set_propv(xmlNodePtr node, va_list pairs)
Definition: xml.c:2636
void pcmk__set_xml_doc_flag(xmlNode *xml, enum xml_private_flags flag)
Definition: xml.c:78
char * pcmk__xpath_node_id(const char *xpath, const char *node)
Definition: xpath.c:312
Include indentation and newlines.
Definition: xml_internal.h:137
Log a created XML subtree.
Definition: xml_internal.h:153
Formatted output for pacemaker tools.
void pcmk__strip_xml_text(xmlNode *xml)
Definition: xml.c:962
Include the children of an XML element.
Definition: xml_internal.h:143
void pcmk__xe_remove_matching_attrs(xmlNode *element, bool(*match)(xmlAttrPtr, void *), void *user_data)
Definition: xml.c:593
void pcmk__xe_set_props(xmlNodePtr node,...) G_GNUC_NULL_TERMINATED
Definition: xml.c:2654
xml_private_flags
Definition: xml_internal.h:388
pcmk__xml_artefact_ns
Definition: xml_internal.h:201
Log a removed XML subtree.
Definition: xml_internal.h:157
int pcmk__xe_foreach_child(xmlNode *xml, const char *child_element_name, int(*handler)(xmlNode *xml, void *userdata), void *userdata)
Definition: xml.c:2663
int pcmk__xml_show(pcmk__output_t *out, const char *prefix, const xmlNode *data, int depth, uint32_t options)
Definition: xml_display.c:228
Include the closing tag of an XML element.
Definition: xml_internal.h:146
int pcmk__xml_show_changes(pcmk__output_t *out, const xmlNode *xml)
Definition: xml_display.c:369
This structure contains everything that makes up a single output formatter.
Include XML text nodes.
Definition: xml_internal.h:149
Log a minimal version of an XML diff (only showing the changes)
Definition: xml_internal.h:161
GString * pcmk__element_xpath(const xmlNode *xml)
Definition: xpath.c:278
int pcmk__xml2fd(int fd, xmlNode *cur)
Definition: xml.c:1675
const char * parent
Definition: cib.c:27
char * pcmk__xml_artefact_path(enum pcmk__xml_artefact_ns ns, const char *filespec)
Definition: xml.c:2614
pcmk__xml_fmt_options
Definition: xml_internal.h:132
gboolean pcmk__validate_xml(xmlNode *xml_blob, const char *validation, xmlRelaxNGValidityErrorFunc error_handler, void *error_handler_context)
Definition: schemas.c:679