pacemaker 3.0.1-16e74fc4da
Scalable High-Availability cluster resource manager
Loading...
Searching...
No Matches
xml_internal.h
Go to the documentation of this file.
1/*
2 * Copyright 2017-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#ifndef PCMK__CRM_COMMON_XML_INTERNAL__H
11#define PCMK__CRM_COMMON_XML_INTERNAL__H
12
13/*
14 * Internal-only wrappers for and extensions to libxml2 (libxslt)
15 */
16
17#include <stdlib.h>
18#include <stdint.h> // uint32_t
19#include <stdio.h>
20
21#include <crm/crm.h> /* transitively imports qblog.h */
23#include <crm/common/xml_names.h> // PCMK_XA_ID, PCMK_XE_CLONE
24
25// This file is a wrapper for other {xml_*,xpath}_internal.h headers
32
33#include <libxml/relaxng.h>
34
35#ifdef __cplusplus
36extern "C" {
37#endif
38
82#define PCMK__XML_LOG_BASE(priority, dechunk, postemit, prefix, fmt, ap) \
83do { \
84 if (!(dechunk) && (prefix) == NULL) { /* quick pass */ \
85 qb_log_from_external_source_va(__func__, __FILE__, (fmt), \
86 (priority), __LINE__, 0, (ap)); \
87 (void) (postemit); \
88 } else { \
89 int CXLB_len = 0; \
90 char *CXLB_buf = NULL; \
91 static int CXLB_buffer_len = 0; \
92 static char *CXLB_buffer = NULL; \
93 static uint8_t CXLB_priority = 0; \
94 \
95 CXLB_len = vasprintf(&CXLB_buf, (fmt), (ap)); \
96 \
97 if (CXLB_len <= 0 || CXLB_buf[CXLB_len - 1] == '\n' || !(dechunk)) { \
98 if (CXLB_len < 0) { \
99 CXLB_buf = (char *) "LOG CORRUPTION HAZARD"; /*we don't modify*/\
100 CXLB_priority = QB_MIN(CXLB_priority, LOG_ERR); \
101 } else if (CXLB_len > 0 /* && (dechunk) */ \
102 && CXLB_buf[CXLB_len - 1] == '\n') { \
103 CXLB_buf[CXLB_len - 1] = '\0'; \
104 } \
105 if (CXLB_buffer) { \
106 qb_log_from_external_source(__func__, __FILE__, "%s%s%s", \
107 CXLB_priority, __LINE__, 0, \
108 (prefix) != NULL ? (prefix) : "", \
109 CXLB_buffer, CXLB_buf); \
110 free(CXLB_buffer); \
111 } else { \
112 qb_log_from_external_source(__func__, __FILE__, "%s%s", \
113 (priority), __LINE__, 0, \
114 (prefix) != NULL ? (prefix) : "", \
115 CXLB_buf); \
116 } \
117 if (CXLB_len < 0) { \
118 CXLB_buf = NULL; /* restore temporary override */ \
119 } \
120 CXLB_buffer = NULL; \
121 CXLB_buffer_len = 0; \
122 (void) (postemit); \
123 \
124 } else if (CXLB_buffer == NULL) { \
125 CXLB_buffer_len = CXLB_len; \
126 CXLB_buffer = CXLB_buf; \
127 CXLB_buf = NULL; \
128 CXLB_priority = (priority); /* remember as a running severest */ \
129 \
130 } else { \
131 CXLB_buffer = realloc(CXLB_buffer, 1 + CXLB_buffer_len + CXLB_len); \
132 memcpy(CXLB_buffer + CXLB_buffer_len, CXLB_buf, CXLB_len); \
133 CXLB_buffer_len += CXLB_len; \
134 CXLB_buffer[CXLB_buffer_len] = '\0'; \
135 CXLB_priority = QB_MIN(CXLB_priority, (priority)); /* severest? */ \
136 } \
137 free(CXLB_buf); \
138 } \
139} while (0)
140
148
151
154
157
160
161 // @COMPAT Can we start including text nodes unconditionally?
164};
165
166int pcmk__xml_show(pcmk__output_t *out, const char *prefix, const xmlNode *data,
167 int depth, uint32_t options);
168int pcmk__xml_show_changes(pcmk__output_t *out, const xmlNode *xml);
169
176
177void pcmk__strip_xml_text(xmlNode *xml);
178
230
238
239 /* @COMPAT Drop escaping of at least '\n' and '\t' for
240 * pcmk__xml_escape_attr_pretty when openstack-info, openstack-floating-ip,
241 * and openstack-virtual-ip resource agents no longer depend on it.
242 *
243 * At time of writing, openstack-info may set a multiline value for the
244 * openstack_ports node attribute. The other two agents query the value and
245 * require it to be on one line with no spaces.
246 */
255};
256
257bool pcmk__xml_needs_escape(const char *text, enum pcmk__xml_escape_type type);
258char *pcmk__xml_escape(const char *text, enum pcmk__xml_escape_type type);
259
268char *
270
281 const char *filespec);
282
291static inline xmlNode *
292pcmk__xml_first_child(const xmlNode *parent)
293{
294 xmlNode *child = (parent? parent->children : NULL);
295
296 while (child && (child->type == XML_TEXT_NODE)) {
297 child = child->next;
298 }
299 return child;
300}
301
310static inline xmlNode *
311pcmk__xml_next(const xmlNode *child)
312{
313 xmlNode *next = (child? child->next : NULL);
314
315 while (next && (next->type == XML_TEXT_NODE)) {
316 next = next->next;
317 }
318 return next;
319}
320
321void pcmk__xml_free(xmlNode *xml);
322void pcmk__xml_free_doc(xmlDoc *doc);
323xmlNode *pcmk__xml_copy(xmlNode *parent, xmlNode *src);
324
342
343void pcmk__xml_sanitize_id(char *id);
344
345/* internal XML-related utilities */
346
353 pcmk__xf_none = UINT32_C(0),
354
359 pcmk__xf_dirty = (UINT32_C(1) << 0),
360
362 pcmk__xf_deleted = (UINT32_C(1) << 1),
363
365 pcmk__xf_created = (UINT32_C(1) << 2),
366
368 pcmk__xf_modified = (UINT32_C(1) << 3),
369
376 pcmk__xf_tracking = (UINT32_C(1) << 4),
377
379 pcmk__xf_skip = (UINT32_C(1) << 6),
380
382 pcmk__xf_moved = (UINT32_C(1) << 7),
383
385 pcmk__xf_acl_enabled = (UINT32_C(1) << 8),
386
387 /* @TODO Consider splitting the ACL permission flags (pcmk__xf_acl_read,
388 * pcmk__xf_acl_write, pcmk__xf_acl_write, and pcmk__xf_acl_create) into a
389 * separate enum and reserving this enum for tracking-related flags.
390 *
391 * The ACL permission flags have various meanings in different contexts (for
392 * example, what permission an ACL grants or denies; what permissions the
393 * current ACL user has for a given XML node; and possibly others). And
394 * for xml_acl_t objects, they're used in exclusive mode (exactly one is
395 * set), rather than as flags.
396 */
397
399 pcmk__xf_acl_read = (UINT32_C(1) << 9),
400
402 pcmk__xf_acl_write = (UINT32_C(1) << 10),
403
405 pcmk__xf_acl_deny = (UINT32_C(1) << 11),
406
411 pcmk__xf_acl_create = (UINT32_C(1) << 12),
412
414 pcmk__xf_acl_denied = (UINT32_C(1) << 13),
415
417 pcmk__xf_ignore_attr_pos = (UINT32_C(1) << 14),
418};
419
420void pcmk__xml_doc_set_flags(xmlDoc *doc, uint32_t flags);
421bool pcmk__xml_doc_all_flags_set(const xmlDoc *xml, uint32_t flags);
422
423void pcmk__xml_commit_changes(xmlDoc *doc);
424void pcmk__xml_mark_changes(xmlNode *old_xml, xmlNode *new_xml);
425
426bool pcmk__xml_tree_foreach(xmlNode *xml, bool (*fn)(xmlNode *, void *),
427 void *user_data);
428
429static inline const char *
430pcmk__xml_attr_value(const xmlAttr *attr)
431{
432 return ((attr == NULL) || (attr->children == NULL))? NULL
433 : (const char *) attr->children->content;
434}
435
447bool pcmk__cib_element_in_patchset(const xmlNode *patchset,
448 const char *element);
449
450#ifdef __cplusplus
451}
452#endif
453
454#endif // PCMK__CRM_COMMON_XML_INTERNAL__H
const char * parent
Definition cib.c:27
uint64_t flags
Definition remote.c:3
char data[0]
Definition cpg.c:10
enum pcmk_ipc_server type
Definition cpg.c:3
A dumping ground.
Formatted output for pacemaker tools.
This structure contains everything that makes up a single output formatter.
pcmk__xml_fmt_options
@ pcmk__xml_fmt_close
Include the closing tag of an XML element.
@ pcmk__xml_fmt_children
Include the children of an XML element.
@ pcmk__xml_fmt_open
Include the opening tag of an XML element, and include XML comments.
@ pcmk__xml_fmt_pretty
Include indentation and newlines.
@ pcmk__xml_fmt_filtered
Exclude certain XML attributes (for calculating digests)
@ pcmk__xml_fmt_text
Include XML text nodes.
xmlNode * pcmk__xml_copy(xmlNode *parent, xmlNode *src)
Definition xml.c:832
bool pcmk__cib_element_in_patchset(const xmlNode *patchset, const char *element)
Definition patchset.c:833
void pcmk__xml_sanitize_id(char *id)
Definition xml.c:674
pcmk__xa_flags
@ pcmk__xaf_none
Flag has no effect.
@ pcmk__xaf_no_overwrite
Don't overwrite existing values.
@ pcmk__xaf_score_update
bool pcmk__xml_doc_all_flags_set(const xmlDoc *xml, uint32_t flags)
Definition xml.c:147
void pcmk__xml_commit_changes(xmlDoc *doc)
Definition xml.c:468
char * pcmk__xml_artefact_root(enum pcmk__xml_artefact_ns ns)
Definition xml.c:1635
bool pcmk__xml_needs_escape(const char *text, enum pcmk__xml_escape_type type)
Definition xml.c:909
bool pcmk__xml_tree_foreach(xmlNode *xml, bool(*fn)(xmlNode *, void *), void *user_data)
Definition xml.c:87
void pcmk__strip_xml_text(xmlNode *xml)
Definition xml.c:870
void pcmk__xml_doc_set_flags(xmlDoc *doc, uint32_t flags)
Definition xml.c:128
int pcmk__xml_show_changes(pcmk__output_t *out, const xmlNode *xml)
pcmk__xml_escape_type
@ pcmk__xml_escape_attr_pretty
@ pcmk__xml_escape_attr
@ pcmk__xml_escape_text
pcmk__xml_flags
@ pcmk__xf_acl_create
@ pcmk__xf_deleted
Node was deleted (set for attribute only)
@ pcmk__xf_acl_enabled
ACLs are enabled (set for document only)
@ pcmk__xf_created
Node was created.
@ pcmk__xf_ignore_attr_pos
Ignore attribute moves within an element (set for document only)
@ pcmk__xf_acl_denied
ACLs deny the user access (set for document only)
@ pcmk__xf_dirty
@ pcmk__xf_modified
Node was modified.
@ pcmk__xf_acl_deny
ACL deny permission (that is, no permission)
@ pcmk__xf_skip
Skip counting this node when getting a node's position among siblings.
@ pcmk__xf_acl_write
ACL write permission (implies read permission in most or all contexts)
@ pcmk__xf_tracking
Tracking is enabled (set for document only)
@ pcmk__xf_none
This flag has no effect.
@ pcmk__xf_moved
Node was moved.
@ pcmk__xf_acl_read
ACL read permission.
char * pcmk__xml_escape(const char *text, enum pcmk__xml_escape_type type)
Definition xml.c:991
void pcmk__xml_free(xmlNode *xml)
Definition xml.c:816
int pcmk__xml_show(pcmk__output_t *out, const char *prefix, const xmlNode *data, int depth, uint32_t options)
void pcmk__xml_free_doc(xmlDoc *doc)
Definition xml.c:515
pcmk__xml_artefact_ns
@ pcmk__xml_artefact_ns_legacy_xslt
@ pcmk__xml_artefact_ns_legacy_rng
@ pcmk__xml_artefact_ns_base_rng
@ pcmk__xml_artefact_ns_base_xslt
void pcmk__xml_mark_changes(xmlNode *old_xml, xmlNode *new_xml)
Definition xml.c:1537
char * pcmk__xml_artefact_path(enum pcmk__xml_artefact_ns ns, const char *filespec)
Definition xml.c:1692
Defined string constants for XML element and attribute names.