20 #include <sys/param.h>
22 #include <sys/types.h>
38 #include <libxml/xmlreader.h>
45 # include <libxml/parser.h>
46 # include <libxml/tree.h>
47 # include <libxml/relaxng.h>
51 # include <libxslt/xslt.h>
52 # include <libxslt/transform.h>
55 #define XML_BUFFER_SIZE 4096
56 #define XML_PARSER_DEBUG 0
59 xml_log(
int priority,
const char *fmt, ...)
62 __get_prefix(const
char *prefix, xmlNode *xml,
char *buffer,
int offset);
65 xml_log(
int priority, const
char *fmt, ...)
70 qb_log_from_external_source_va(__FUNCTION__, __FILE__, fmt, priority, __LINE__, 0, ap);
76 xmlRelaxNGValidCtxtPtr valid;
77 xmlRelaxNGParserCtxtPtr parser;
78 } relaxng_ctx_cache_t;
116 typedef struct xml_private_s
125 typedef struct xml_acl_s {
132 static filter_t filter[] = {
141 static struct schema_s *known_schemas = NULL;
142 static int xml_schema_max = 0;
144 static xmlNode *subtract_xml_comment(xmlNode * parent, xmlNode * left, xmlNode * right, gboolean * changed);
145 static xmlNode *find_xml_comment(xmlNode * root, xmlNode * search_comment);
146 static int add_xml_comment(xmlNode * parent, xmlNode * target, xmlNode * update);
147 static bool __xml_acl_check(xmlNode *xml,
const char *name,
enum xml_private_flags mode);
151 xml_latest_schema_index(
void)
153 return xml_schema_max - 4;
157 xml_minimum_schema_index(
void)
164 best = xml_latest_schema_index();
165 target = floor(known_schemas[best].
version);
167 for(lpc = best; lpc > 0; lpc--) {
168 if(known_schemas[lpc].
version < target) {
174 best = xml_latest_schema_index();
185 #define CHUNK_SIZE 1024
186 static inline bool TRACKING_CHANGES(xmlNode *xml)
188 if(xml == NULL || xml->doc == NULL || xml->doc->_private == NULL) {
196 #define buffer_print(buffer, max, offset, fmt, args...) do { \
199 rc = snprintf((buffer) + (offset), (max) - (offset), fmt, ##args); \
201 if(buffer && rc < 0) { \
202 crm_perror(LOG_ERR, "snprintf failed at offset %d", offset); \
203 (buffer)[(offset)] = 0; \
204 } else if(rc >= ((max) - (offset))) { \
206 (max) = QB_MAX(CHUNK_SIZE, (max) * 2); \
207 tmp = realloc_safe((buffer), (max) + 1); \
217 insert_prefix(
int options,
char **buffer,
int *offset,
int *max,
int depth)
220 size_t spaces = 2 * depth;
222 if ((*buffer) == NULL || spaces >= ((*max) - (*offset))) {
224 (*buffer) = realloc_safe((*buffer), (*max) + 1);
226 memset((*buffer) + (*offset),
' ', spaces);
232 get_schema_root(
void)
234 static const char *base = NULL;
237 base = getenv(
"PCMK_schema_directory");
239 if (base == NULL || strlen(base) == 0) {
246 get_schema_path(
const char *name,
const char *file)
248 const char *base = get_schema_root();
256 static int schema_filter(
const struct dirent * a)
261 if(strstr(a->d_name,
"pacemaker-") != a->d_name) {
264 }
else if(strstr(a->d_name,
".rng") == NULL) {
267 }
else if(sscanf(a->d_name,
"pacemaker-%f.rng", &version) == 0) {
270 }
else if(strcmp(a->d_name,
"pacemaker-1.1.rng") == 0) {
281 static int schema_sort(
const struct dirent ** a,
const struct dirent **b)
284 float a_version = 0.0;
285 float b_version = 0.0;
287 sscanf(a[0]->d_name,
"pacemaker-%f.rng", &a_version);
288 sscanf(b[0]->d_name,
"pacemaker-%f.rng", &b_version);
290 if(a_version > b_version) {
292 }
else if(a_version < b_version) {
300 static void __xml_schema_add(
301 int type,
float version,
const char *name,
const char *location,
const char *transform,
int after_transform)
303 int last = xml_schema_max;
306 known_schemas = realloc_safe(known_schemas, xml_schema_max*
sizeof(
struct schema_s));
308 memset(known_schemas+last, 0,
sizeof(
struct schema_s));
309 known_schemas[last].type =
type;
310 known_schemas[last].after_transform = after_transform;
313 known_schemas[last].version =
version;
315 known_schemas[last].location =
crm_strdup_printf(
"%s.rng", known_schemas[last].name);
321 sscanf(name,
"%[^-]-%f", dummy, &version);
322 known_schemas[last].version =
version;
323 known_schemas[last].name = strdup(name);
324 known_schemas[last].location = strdup(location);
328 known_schemas[last].transform = strdup(transform);
330 if(after_transform == 0) {
331 after_transform = xml_schema_max;
333 known_schemas[last].after_transform = after_transform;
335 if(known_schemas[last].after_transform < 0) {
336 crm_debug(
"Added supported schema %d: %s (%s)",
337 last, known_schemas[last].name, known_schemas[last].location);
339 }
else if(known_schemas[last].transform) {
340 crm_debug(
"Added supported schema %d: %s (%s upgrades to %d with %s)",
341 last, known_schemas[last].name, known_schemas[last].location,
342 known_schemas[last].after_transform,
343 known_schemas[last].transform);
346 crm_debug(
"Added supported schema %d: %s (%s upgrades to %d)",
347 last, known_schemas[last].name, known_schemas[last].location,
348 known_schemas[last].after_transform);
353 static int __xml_build_schema_list(
void)
356 const char *base = get_schema_root();
357 struct dirent **namelist = NULL;
359 max = scandir(base, &namelist, schema_filter, schema_sort);
360 __xml_schema_add(1, 0.0,
"pacemaker-0.6",
"crm.dtd",
"upgrade06.xsl", 3);
361 __xml_schema_add(1, 0.0,
"transitional-0.6",
"crm-transitional.dtd",
"upgrade06.xsl", 3);
362 __xml_schema_add(2, 0.0,
"pacemaker-0.7",
"pacemaker-1.0.rng", NULL, 0);
368 for (lpc = 0; lpc < max; lpc++) {
371 char *transform = NULL;
373 sscanf(namelist[lpc]->d_name,
"pacemaker-%f.rng", &version);
374 if((lpc + 1) < max) {
375 float next_version = 0.0;
377 sscanf(namelist[lpc+1]->d_name,
"pacemaker-%f.rng", &next_version);
379 if(floor(version) < floor(next_version)) {
384 xslt = get_schema_path(NULL, transform);
385 if(stat(xslt, &s) != 0) {
386 crm_err(
"Transform %s not found", xslt);
388 __xml_schema_add(2, version, NULL, NULL, NULL, -1);
398 __xml_schema_add(2, version, NULL, NULL, transform, next);
405 __xml_schema_add(2, 0.0,
"pacemaker-1.1",
"pacemaker-next.rng", NULL, 0);
406 __xml_schema_add(2, 0.0,
"pacemaker-next",
"pacemaker-next.rng", NULL, -1);
407 __xml_schema_add(0, 0.0,
"none",
"N/A", NULL, -1);
413 set_parent_flag(xmlNode *xml,
long flag)
416 for(; xml; xml = xml->parent) {
429 set_doc_flag(xmlNode *xml,
long flag)
432 if(xml && xml->doc && xml->doc->_private){
442 __xml_node_dirty(xmlNode *xml)
449 __xml_node_clean(xmlNode *xml)
451 xmlNode *cIter = NULL;
458 for (cIter = __xml_first_child(xml); cIter != NULL; cIter = __xml_next(cIter)) {
459 __xml_node_clean(cIter);
464 crm_node_created(xmlNode *xml)
466 xmlNode *cIter = NULL;
469 if(p && TRACKING_CHANGES(xml)) {
472 __xml_node_dirty(xml);
475 for (cIter = __xml_first_child(xml); cIter != NULL; cIter = __xml_next(cIter)) {
476 crm_node_created(cIter);
482 crm_attr_dirty(xmlAttr *a)
484 xmlNode *parent = a->parent;
493 __xml_node_dirty(parent);
496 int get_tag_name(
const char *input,
size_t offset,
size_t max);
497 int get_attr_name(
const char *input,
size_t offset,
size_t max);
502 xmlNode * xml_node, xmlNode * parent);
504 int add_xml_object(xmlNode * parent, xmlNode * target, xmlNode * update, gboolean as_diff);
506 static inline const char *
507 crm_attr_value(xmlAttr * attr)
509 if (attr == NULL || attr->children == NULL) {
512 return (
const char *)attr->children->content;
515 static inline xmlAttr *
516 crm_first_attr(xmlNode * xml)
521 return xml->properties;
524 #define XML_PRIVATE_MAGIC (long) 0x81726354
527 __xml_acl_free(
void *
data)
547 g_list_free_full(p->acls, __xml_acl_free);
551 if(p->deleted_paths) {
552 g_list_free_full(p->deleted_paths, free);
553 p->deleted_paths = NULL;
562 __xml_private_clean(p);
567 pcmkDeregisterNode(xmlNodePtr node)
569 __xml_private_free(node->_private);
573 pcmkRegisterNode(xmlNodePtr node)
578 case XML_ELEMENT_NODE:
579 case XML_DOCUMENT_NODE:
580 case XML_ATTRIBUTE_NODE:
581 case XML_COMMENT_NODE:
590 case XML_CDATA_SECTION_NODE:
594 crm_trace(
"Ignoring %p %d", node, node->type);
599 if(p && TRACKING_CHANGES(node)) {
604 __xml_node_dirty(node);
627 if(target == NULL || target->doc == NULL || target->doc->_private == NULL){
633 }
else if (tag == NULL && ref == NULL && xpath == NULL) {
638 p = target->doc->_private;
645 acl->xpath = strdup(xpath);
646 crm_trace(
"Using xpath: %s", acl->xpath);
653 offset += snprintf(buffer + offset,
XML_BUFFER_SIZE - offset,
"//%s", tag);
663 offset += snprintf(buffer + offset,
XML_BUFFER_SIZE - offset,
"@id='%s'", ref);
667 offset += snprintf(buffer + offset,
XML_BUFFER_SIZE - offset,
" and ");
671 offset += snprintf(buffer + offset,
XML_BUFFER_SIZE - offset,
"@%s", attr);
679 acl->xpath = strdup(buffer);
680 crm_trace(
"Built xpath: %s", acl->xpath);
683 p->acls = g_list_append(p->acls, acl);
689 __xml_acl_parse_entry(xmlNode * acl_top, xmlNode * acl_entry, xmlNode *target)
691 xmlNode *child = NULL;
693 for (child = __xml_first_child(acl_entry); child; child = __xml_next(child)) {
694 const char *tag = crm_element_name(child);
701 crm_trace(
"Processing %s %p", tag, child);
710 xmlNode *role = NULL;
712 for (role = __xml_first_child(acl_top); role; role = __xml_next(role)) {
716 if (role_id && strcmp(ref_role, role_id) == 0) {
717 crm_debug(
"Unpacking referenced role: %s", role_id);
718 __xml_acl_parse_entry(acl_top, role, target);
735 crm_warn(
"Unknown ACL entry: %s/%s", tag, kind);
781 __xml_acl_apply(xmlNode *xml)
785 xmlXPathObjectPtr xpathObj = NULL;
788 p = xml->doc->_private;
789 crm_trace(
"Not applying ACLs for %s", p->user);
793 p = xml->doc->_private;
794 for(aIter = p->acls; aIter != NULL; aIter = aIter->next) {
795 int max = 0, lpc = 0;
799 max = numXpathResults(xpathObj);
801 for(lpc = 0; lpc < max; lpc++) {
806 crm_trace(
"Applying %x to %s for %s", acl->mode, path, acl->xpath);
808 #ifdef SUSE_ACL_COMPAT
809 if(is_not_set(p->flags, acl->mode)) {
813 crm_config_warn(
"Configuration element %s is matched by multiple ACL rules, only the first applies ('%s' wins over '%s')",
821 p->flags |= acl->mode;
824 crm_trace(
"Now enforcing ACL: %s (%d matches)", acl->xpath, max);
831 p = xml->doc->_private;
832 crm_info(
"Enforcing default ACL for %s to %s", p->user, crm_element_name(xml));
838 __xml_acl_unpack(xmlNode *source, xmlNode *target,
const char *user)
843 if(target == NULL || target->doc == NULL || target->doc->_private == NULL) {
847 p = target->doc->_private;
849 crm_trace(
"no acls needed for '%s'", user);
851 }
else if(p->acls == NULL) {
855 p->user = strdup(user);
858 xmlNode *child = NULL;
860 for (child = __xml_first_child(acls); child; child = __xml_next(child)) {
861 const char *tag = crm_element_name(child);
866 if(
id && strcmp(
id, user) == 0) {
868 __xml_acl_parse_entry(acls, child, target);
883 }
else if(is_set(allowed, requested)) {
902 __xml_purge_attributes(xmlNode *xml)
904 xmlNode *child = NULL;
905 xmlAttr *xIter = NULL;
906 bool readable_children = FALSE;
910 crm_trace(
"%s[@id=%s] is readable", crm_element_name(xml),
ID(xml));
914 xIter = crm_first_attr(xml);
915 while(xIter != NULL) {
916 xmlAttr *tmp = xIter;
917 const char *prop_name = (
const char *)xIter->name;
924 xmlUnsetProp(xml, tmp->name);
927 child = __xml_first_child(xml);
928 while ( child != NULL ) {
929 xmlNode *tmp = child;
931 child = __xml_next(child);
932 readable_children |= __xml_purge_attributes(tmp);
935 if(readable_children == FALSE) {
938 return readable_children;
945 xmlNode *target = NULL;
951 crm_trace(
"no acls needed for '%s'", user);
955 crm_trace(
"filtering copy of %p for '%s'", xml, user);
961 __xml_acl_unpack(acl_source, target, user);
963 __xml_acl_apply(target);
965 doc = target->doc->_private;
966 for(aIter = doc->acls; aIter != NULL && target; aIter = aIter->next) {
973 }
else if(acl->xpath) {
975 xmlXPathObjectPtr xpathObj =
xpath_search(target, acl->xpath);
977 max = numXpathResults(xpathObj);
978 for(lpc = 0; lpc < max; lpc++) {
981 crm_trace(
"Purging attributes from %s", acl->xpath);
982 if(__xml_purge_attributes(match) == FALSE && match == target) {
983 crm_trace(
"No access to the entire document for %s", user);
988 crm_trace(
"Enforced ACL %s (%d matches)", acl->xpath, max);
993 p = target->_private;
994 if(is_set(p->flags,
xpf_acl_deny) && __xml_purge_attributes(target) == FALSE) {
995 crm_trace(
"No access to the entire document for %s", user);
1000 g_list_free_full(doc->acls, __xml_acl_free);
1004 crm_trace(
"Ordinary user '%s' cannot access the CIB without any defined ACLs", doc->user);
1017 __xml_acl_post_process(xmlNode * xml)
1019 xmlNode *cIter = __xml_first_child(xml);
1023 xmlAttr *xIter = NULL;
1030 for (xIter = crm_first_attr(xml); xIter != NULL; xIter = xIter->next) {
1031 const char *prop_name = (
const char *)xIter->name;
1038 crm_trace(
"Creation of %s=%s is allowed", crm_element_name(xml),
ID(xml));
1042 crm_trace(
"Cannot add new node %s at %s", crm_element_name(xml), path);
1044 if(xml != xmlDocGetRootElement(xml->doc)) {
1055 while (cIter != NULL) {
1056 xmlNode *child = cIter;
1057 cIter = __xml_next(cIter);
1058 __xml_acl_post_process(child);
1065 if(xml && xml->doc && xml->doc->_private){
1080 __xml_acl_apply(xml);
1081 __xml_acl_post_process(xml);
1089 if(xml && xml->doc && xml->doc->_private){
1101 crm_trace(
"Tracking changes%s to %p", enforce_acls?
" with ACLs":
"", xml);
1104 if(acl_source == NULL) {
1108 __xml_acl_unpack(acl_source, xml, user);
1109 __xml_acl_apply(xml);
1126 if(xml != NULL && xml->doc && xml->doc->_private) {
1182 static int __xml_offset(xmlNode *xml)
1185 xmlNode *cIter = NULL;
1187 for(cIter = xml; cIter->prev; cIter = cIter->prev) {
1190 if(is_not_set(p->flags,
xpf_skip)) {
1198 static int __xml_offset_no_deletions(xmlNode *xml)
1201 xmlNode *cIter = NULL;
1203 for(cIter = xml; cIter->prev; cIter = cIter->prev) {
1215 __xml_build_changes(xmlNode * xml, xmlNode *patchset)
1217 xmlNode *cIter = NULL;
1218 xmlAttr *pIter = NULL;
1219 xmlNode *change = NULL;
1226 if(__get_prefix(NULL, xml->parent, buffer, offset) > 0) {
1227 int position = __xml_offset_no_deletions(xml);
1240 for (pIter = crm_first_attr(xml); pIter != NULL; pIter = pIter->next) {
1241 xmlNode *attr = NULL;
1243 p = pIter->_private;
1248 if(change == NULL) {
1252 if(__get_prefix(NULL, xml, buffer, offset) > 0) {
1277 xmlNode *result = NULL;
1282 for (pIter = crm_first_attr(xml); pIter != NULL; pIter = pIter->next) {
1285 p = pIter->_private;
1287 crm_xml_add(result, (
const char *)pIter->name, value);
1292 for (cIter = __xml_first_child(xml); cIter != NULL; cIter = __xml_next(cIter)) {
1293 __xml_build_changes(cIter, patchset);
1297 if(patchset && is_set(p->flags,
xpf_moved)) {
1301 crm_trace(
"%s.%s moved to position %d", xml->name,
ID(xml), __xml_offset(xml));
1302 if(__get_prefix(NULL, xml, buffer, offset) > 0) {
1313 __xml_accept_changes(xmlNode * xml)
1315 xmlNode *cIter = NULL;
1316 xmlAttr *pIter = NULL;
1320 pIter = crm_first_attr(xml);
1322 while (pIter != NULL) {
1323 const xmlChar *name = pIter->name;
1325 p = pIter->_private;
1326 pIter = pIter->next;
1336 for (cIter = __xml_first_child(xml); cIter != NULL; cIter = __xml_next(cIter)) {
1337 __xml_accept_changes(cIter);
1342 is_config_change(xmlNode *xml)
1349 p = config->_private;
1355 if(xml->doc && xml->doc->_private) {
1356 p = xml->doc->_private;
1357 for(gIter = p->deleted_paths; gIter; gIter = gIter->next) {
1358 char *path = gIter->data;
1370 xml_repair_v1_diff(xmlNode * last, xmlNode * next, xmlNode * local_diff, gboolean changed)
1373 xmlNode *cib = NULL;
1374 xmlNode *diff_child = NULL;
1376 const char *tag = NULL;
1378 const char *vfields[] = {
1384 if (local_diff == NULL) {
1389 tag =
"diff-removed";
1391 if (diff_child == NULL) {
1401 for(lpc = 0; last && lpc <
DIMOF(vfields); lpc++){
1405 if(changed || lpc == 2) {
1412 if (diff_child == NULL) {
1422 for(lpc = 0; next && lpc <
DIMOF(vfields); lpc++){
1429 xmlAttrPtr xIter = NULL;
1431 for (xIter = next->properties; xIter; xIter = xIter->next) {
1432 const char *p_name = (
const char *)xIter->name;
1435 xmlSetProp(cib, (
const xmlChar *)p_name, (
const xmlChar *)p_value);
1443 xml_create_patchset_v1(xmlNode *source, xmlNode *target,
bool config,
bool suppress)
1449 xml_repair_v1_diff(source, target, patchset, config);
1456 xml_create_patchset_v2(xmlNode *source, xmlNode *target)
1463 xmlNode *version = NULL;
1464 xmlNode *patchset = NULL;
1465 const char *vfields[] = {
1477 doc = target->doc->_private;
1485 for(lpc = 0; lpc <
DIMOF(vfields); lpc++){
1495 for(lpc = 0; lpc <
DIMOF(vfields); lpc++){
1504 for(gIter = doc->deleted_paths; gIter; gIter = gIter->next) {
1511 __xml_build_changes(target, patchset);
1515 static gboolean patch_legacy_mode(
void)
1517 static gboolean init = TRUE;
1518 static gboolean legacy = FALSE;
1534 bool config = FALSE;
1535 xmlNode *patch = NULL;
1544 config = is_config_change(target);
1545 if(config_changed) {
1546 *config_changed = config;
1549 if(manage_version && config) {
1556 }
else if(manage_version) {
1563 if(patch_legacy_mode()) {
1572 crm_trace(
"Using patch format %d for version: %s", format, version);
1577 patch = xml_create_patchset_v1(source, target, config, FALSE);
1580 patch = xml_create_patchset_v2(source, target);
1583 crm_err(
"Unknown patch format: %d", format);
1594 const char *version = NULL;
1595 char *digest = NULL;
1597 if (patch == NULL || source == NULL || target == NULL) {
1606 if (format > 1 && with_digest == FALSE) {
1620 __xml_log_element(
int log_level,
const char *file,
const char *
function,
int line,
1621 const char *prefix, xmlNode *
data,
int depth,
int options);
1627 xmlNode *child = NULL;
1628 xmlNode *added = NULL;
1629 xmlNode *removed = NULL;
1630 gboolean is_first = TRUE;
1632 int add[] = { 0, 0, 0 };
1633 int del[] = { 0, 0, 0 };
1635 const char *fmt = NULL;
1636 const char *digest = NULL;
1639 static struct qb_log_callsite *patchset_cs = NULL;
1641 if (patchset_cs == NULL) {
1642 patchset_cs = qb_log_callsite_get(
function, __FILE__,
"xml-patchset", log_level, __LINE__, 0);
1645 if (patchset == NULL) {
1649 }
else if (log_level == 0) {
1659 if (add[2] != del[2] || add[1] != del[1] || add[0] != del[0]) {
1661 "Diff: --- %d.%d.%d %s", del[0], del[1], del[2], fmt);
1663 "Diff: +++ %d.%d.%d %s", add[0], add[1], add[2], digest);
1665 }
else if (patchset != NULL && (add[0] || add[1] || add[2])) {
1667 "%s: Local-only Change: %d.%d.%d",
function ?
function :
"",
1668 add[0], add[1], add[2]);
1673 xmlNode *change = NULL;
1675 for (change = __xml_first_child(patchset); change != NULL; change = __xml_next(change)) {
1680 }
else if(strcmp(op,
"create") == 0) {
1681 int lpc = 0, max = 0;
1684 max = strlen(prefix);
1685 __xml_log_element(log_level, __FILE__,
function, __LINE__, prefix, change->children,
1688 for(lpc = 2; lpc < max; lpc++) {
1692 __xml_log_element(log_level, __FILE__,
function, __LINE__, prefix, change->children,
1696 }
else if(strcmp(op,
"move") == 0) {
1699 }
else if(strcmp(op,
"modify") == 0) {
1707 buffer_unset[0] = 0;
1708 for (child = __xml_first_child(clist); child != NULL; child = __xml_next(child)) {
1713 }
else if(strcmp(op,
"set") == 0) {
1719 o_set += snprintf(buffer_set + o_set,
XML_BUFFER_SIZE - o_set,
"@%s=%s", name, value);
1721 }
else if(strcmp(op,
"unset") == 0) {
1723 o_unset += snprintf(buffer_unset + o_unset,
XML_BUFFER_SIZE - o_unset,
", ");
1725 o_unset += snprintf(buffer_unset + o_unset,
XML_BUFFER_SIZE - o_unset,
"@%s", name);
1729 do_crm_log_alias(log_level, __FILE__,
function, __LINE__,
"+ %s: %s", xpath, buffer_set);
1732 do_crm_log_alias(log_level, __FILE__,
function, __LINE__,
"-- %s: %s", xpath, buffer_unset);
1735 }
else if(strcmp(op,
"delete") == 0) {
1742 if (log_level < LOG_DEBUG ||
function == NULL) {
1747 for (child = __xml_first_child(removed); child != NULL; child = __xml_next(child)) {
1759 for (child = __xml_first_child(added); child != NULL; child = __xml_next(child)) {
1779 doc = xml->doc->_private;
1784 for(gIter = doc->deleted_paths; gIter; gIter = gIter->next) {
1785 do_crm_log_alias(log_level, __FILE__,
function, __LINE__,
"-- %s", (
char*)gIter->data);
1795 xmlNode *top = NULL;
1802 crm_trace(
"Accepting changes to %p", xml);
1803 doc = xml->doc->_private;
1804 top = xmlDocGetRootElement(xml->doc);
1806 __xml_private_clean(xml->doc->_private);
1814 __xml_accept_changes(top);
1819 __subtract_xml_object(xmlNode * target, xmlNode * patch)
1821 xmlNode *patch_child = NULL;
1822 xmlNode *cIter = NULL;
1823 xmlAttrPtr xIter = NULL;
1826 const char *name = NULL;
1827 const char *value = NULL;
1829 if (target == NULL || patch == NULL) {
1833 if (target->type == XML_COMMENT_NODE) {
1836 subtract_xml_comment(target->parent, target, patch, &dummy);
1839 name = crm_element_name(target);
1847 if (value != NULL && strcmp(value,
"removed:top") == 0) {
1848 crm_trace(
"We are the root of the deletion: %s.id=%s", name,
id);
1854 for (xIter = crm_first_attr(patch); xIter != NULL; xIter = xIter->next) {
1855 const char *p_name = (
const char *)xIter->name;
1864 cIter = __xml_first_child(target);
1866 xmlNode *target_child = cIter;
1868 cIter = __xml_next(cIter);
1870 if (target_child->type == XML_COMMENT_NODE) {
1871 patch_child = find_xml_comment(patch, target_child);
1874 patch_child =
find_entity(patch, crm_element_name(target_child),
ID(target_child));
1877 __subtract_xml_object(target_child, patch_child);
1883 __add_xml_object(xmlNode * parent, xmlNode * target, xmlNode * patch)
1885 xmlNode *patch_child = NULL;
1886 xmlNode *target_child = NULL;
1887 xmlAttrPtr xIter = NULL;
1889 const char *
id = NULL;
1890 const char *name = NULL;
1891 const char *value = NULL;
1893 if (patch == NULL) {
1895 }
else if (parent == NULL && target == NULL) {
1903 && strcmp(value,
"added:top") == 0) {
1905 name = crm_element_name(patch);
1906 crm_trace(
"We are the root of the addition: %s.id=%s", name,
id);
1910 }
else if(target == NULL) {
1912 name = crm_element_name(patch);
1913 crm_err(
"Could not locate: %s.id=%s", name,
id);
1917 if (target->type == XML_COMMENT_NODE) {
1918 add_xml_comment(parent, target, patch);
1921 name = crm_element_name(target);
1926 for (xIter = crm_first_attr(patch); xIter != NULL; xIter = xIter->next) {
1927 const char *p_name = (
const char *)xIter->name;
1935 for (patch_child = __xml_first_child(patch); patch_child != NULL;
1936 patch_child = __xml_next(patch_child)) {
1938 if (patch_child->type == XML_COMMENT_NODE) {
1939 target_child = find_xml_comment(target, patch_child);
1942 target_child =
find_entity(target, crm_element_name(patch_child),
ID(patch_child));
1945 __add_xml_object(target, target_child, patch_child);
1961 find_patch_xml_node(xmlNode *patchset,
int format,
bool added,
1962 xmlNode **patch_node)
1969 label = added?
"diff-added" :
"diff-removed";
1972 if (cib_node != NULL) {
1973 *patch_node = cib_node;
1977 label = added?
"target" :
"source";
1982 crm_warn(
"Unknown patch format: %d", format);
1993 xmlNode *tmp = NULL;
1995 const char *vfields[] = {
2005 if (!find_patch_xml_node(patchset, format, FALSE, &tmp)) {
2009 for(lpc = 0; lpc <
DIMOF(vfields); lpc++) {
2011 crm_trace(
"Got %d for del[%s]", del[lpc], vfields[lpc]);
2016 if (!find_patch_xml_node(patchset, format, TRUE, &tmp)) {
2020 for(lpc = 0; lpc <
DIMOF(vfields); lpc++) {
2022 crm_trace(
"Got %d for add[%s]", add[lpc], vfields[lpc]);
2030 xml_patch_version_check(xmlNode *xml, xmlNode *patchset,
int format)
2033 bool changed = FALSE;
2035 int this[] = { 0, 0, 0 };
2036 int add[] = { 0, 0, 0 };
2037 int del[] = { 0, 0, 0 };
2039 const char *vfields[] = {
2045 for(lpc = 0; lpc <
DIMOF(vfields); lpc++) {
2047 crm_trace(
"Got %d for this[%s]",
this[lpc], vfields[lpc]);
2048 if (
this[lpc] < 0) {
2056 add[2] =
this[2] + 1;
2057 for(lpc = 0; lpc <
DIMOF(vfields); lpc++) {
2058 del[lpc] =
this[lpc];
2063 for(lpc = 0; lpc <
DIMOF(vfields); lpc++) {
2064 if(
this[lpc] < del[lpc]) {
2065 crm_debug(
"Current %s is too low (%d.%d.%d < %d.%d.%d --> %d.%d.%d)", vfields[lpc],
2066 this[0],
this[1],
this[2], del[0], del[1], del[2], add[0], add[1], add[2]);
2069 }
else if(
this[lpc] > del[lpc]) {
2070 crm_info(
"Current %s is too high (%d.%d.%d > %d.%d.%d --> %d.%d.%d) %p", vfields[lpc],
2071 this[0],
this[1],
this[2], del[0], del[1], del[2], add[0], add[1], add[2], patchset);
2077 for(lpc = 0; lpc <
DIMOF(vfields); lpc++) {
2078 if(add[lpc] > del[lpc]) {
2083 if(changed == FALSE) {
2084 crm_notice(
"Versions did not change in patch %d.%d.%d", add[0], add[1], add[2]);
2088 crm_debug(
"Can apply patch %d.%d.%d to %d.%d.%d",
2089 add[0], add[1], add[2],
this[0],
this[1],
this[2]);
2094 xml_apply_patchset_v1(xmlNode *xml, xmlNode *patchset,
bool check_version)
2097 int root_nodes_seen = 0;
2100 xmlNode *child_diff = NULL;
2101 xmlNode *added =
find_xml_node(patchset,
"diff-added", FALSE);
2102 xmlNode *removed =
find_xml_node(patchset,
"diff-removed", FALSE);
2106 for (child_diff = __xml_first_child(removed); child_diff != NULL;
2107 child_diff = __xml_next(child_diff)) {
2108 CRM_CHECK(root_nodes_seen == 0, rc = FALSE);
2109 if (root_nodes_seen == 0) {
2110 __subtract_xml_object(xml, child_diff);
2115 if (root_nodes_seen > 1) {
2116 crm_err(
"(-) Diffs cannot contain more than one change set... saw %d", root_nodes_seen);
2120 root_nodes_seen = 0;
2123 xmlNode *child_diff = NULL;
2125 for (child_diff = __xml_first_child(added); child_diff != NULL;
2126 child_diff = __xml_next(child_diff)) {
2127 CRM_CHECK(root_nodes_seen == 0, rc = FALSE);
2128 if (root_nodes_seen == 0) {
2129 __add_xml_object(NULL, xml, child_diff);
2135 if (root_nodes_seen > 1) {
2136 crm_err(
"(+) Diffs cannot contain more than one change set... saw %d", root_nodes_seen);
2148 __first_xml_child_match(xmlNode *parent,
const char *name,
const char *
id)
2150 xmlNode *cIter = NULL;
2152 for (cIter = __xml_first_child(parent); cIter != NULL; cIter = __xml_next(cIter)) {
2153 if(strcmp((
const char *)cIter->name, name) != 0) {
2156 const char *cid =
ID(cIter);
2157 if(cid == NULL || strcmp(cid,
id) != 0) {
2167 __xml_find_path(xmlNode *top,
const char *key)
2169 xmlNode *target = (xmlNode*)top->doc;
2173 char *current = strdup(key);
2178 rc = sscanf (current,
"/%[^/]%s", section, remainder);
2188 }
else if(tag && section) {
2189 int f = sscanf (section,
"%[^[][@id='%[^']", tag,
id);
2193 target = __first_xml_child_match(target, tag, NULL);
2196 target = __first_xml_child_match(target, tag,
id);
2204 if(rc == 1 || target == NULL) {
2209 char *tmp = current;
2210 current = remainder;
2217 char *path = (
char *)xmlGetNodePath(target);
2219 crm_trace(
"Found %s for %s", path, key);
2234 xml_apply_patchset_v2(xmlNode *xml, xmlNode *patchset,
bool check_version)
2237 xmlNode *change = NULL;
2238 for (change = __xml_first_child(patchset); change != NULL; change = __xml_next(change)) {
2239 xmlNode *match = NULL;
2243 crm_trace(
"Processing %s %s", change->name, op);
2251 match = __xml_find_path(xml, xpath);
2253 crm_trace(
"Performing %s on %s with %p", op, xpath, match);
2255 if(match == NULL && strcmp(op,
"delete") == 0) {
2256 crm_debug(
"No %s match for %s in %p", op, xpath, xml->doc);
2259 }
else if(match == NULL) {
2260 crm_err(
"No %s match for %s in %p", op, xpath, xml->doc);
2264 }
else if(strcmp(op,
"create") == 0) {
2266 xmlNode *child = NULL;
2267 xmlNode *match_child = NULL;
2269 match_child = match->children;
2272 while(match_child && position != __xml_offset(match_child)) {
2273 match_child = match_child->next;
2276 child = xmlDocCopyNode(change->children, match->doc, 1);
2278 crm_trace(
"Adding %s at position %d", child->name, position);
2279 xmlAddPrevSibling(match_child, child);
2281 }
else if(match->last) {
2282 crm_trace(
"Adding %s at position %d (end)", child->name, position);
2283 xmlAddNextSibling(match->last, child);
2286 crm_trace(
"Adding %s at position %d (first)", child->name, position);
2288 xmlAddChild(match, child);
2290 crm_node_created(child);
2292 }
else if(strcmp(op,
"move") == 0) {
2296 if(position != __xml_offset(match)) {
2297 xmlNode *match_child = NULL;
2300 if(p > __xml_offset(match)) {
2305 match_child = match->parent->children;
2307 while(match_child && p != __xml_offset(match_child)) {
2308 match_child = match_child->next;
2311 crm_trace(
"Moving %s to position %d (was %d, prev %p, %s %p)",
2312 match->name, position, __xml_offset(match), match->prev,
2313 match_child?
"next":
"last", match_child?match_child:match->parent->last);
2316 xmlAddPrevSibling(match_child, match);
2320 xmlAddNextSibling(match->parent->last, match);
2324 crm_trace(
"%s is already in position %d", match->name, position);
2327 if(position != __xml_offset(match)) {
2328 crm_err(
"Moved %s.%d to position %d instead of %d (%p)",
2329 match->name,
ID(match), __xml_offset(match), position, match->prev);
2333 }
else if(strcmp(op,
"delete") == 0) {
2336 }
else if(strcmp(op,
"modify") == 0) {
2337 xmlAttr *pIter = crm_first_attr(match);
2344 while(pIter != NULL) {
2345 const char *name = (
const char *)pIter->name;
2347 pIter = pIter->next;
2351 for (pIter = crm_first_attr(attrs); pIter != NULL; pIter = pIter->next) {
2352 const char *name = (
const char *)pIter->name;
2359 crm_err(
"Unknown operation: %s", op);
2370 xmlNode *old = NULL;
2373 if(patchset == NULL) {
2381 rc = xml_patch_version_check(xml, patchset, format);
2395 rc = xml_apply_patchset_v1(xml, patchset, check_version);
2398 rc = xml_apply_patchset_v2(xml, patchset, check_version);
2401 crm_err(
"Unknown patch format: %d", format);
2407 static struct qb_log_callsite *digest_cs = NULL;
2409 char *new_digest = NULL;
2412 if (digest_cs == NULL) {
2414 qb_log_callsite_get(__func__, __FILE__,
"diff-digest",
LOG_TRACE, __LINE__,
2420 crm_info(
"v%d digest mis-match: expected %s, calculated %s", format, digest, new_digest);
2423 if (digest_cs && digest_cs->targets) {
2429 crm_trace(
"%p %.6x", digest_cs, digest_cs ? digest_cs->targets : 0);
2433 crm_trace(
"v%d digest matched: expected %s, calculated %s", format, digest, new_digest);
2445 xmlNode *a_child = NULL;
2446 const char *name =
"NULL";
2449 name = crm_element_name(root);
2452 if (search_path == NULL) {
2453 crm_warn(
"Will never find <NULL>");
2457 for (a_child = __xml_first_child(root); a_child != NULL; a_child = __xml_next(a_child)) {
2458 if (strcmp((
const char *)a_child->name, search_path) == 0) {
2465 crm_warn(
"Could not find %s in %s.", search_path, name);
2466 }
else if (root != NULL) {
2467 crm_trace(
"Could not find %s in %s.", search_path, name);
2469 crm_trace(
"Could not find %s in <NULL>.", search_path);
2478 xmlNode *a_child = NULL;
2480 for (a_child = __xml_first_child(parent); a_child != NULL; a_child = __xml_next(a_child)) {
2482 if (node_name == NULL || strcmp((
const char *)a_child->name, node_name) == 0) {
2483 const char *cid =
ID(a_child);
2484 if (
id == NULL || (cid != NULL && strcmp(
id, cid) == 0)) {
2490 crm_trace(
"node <%s id=%s> not found in %s.", node_name,
id, crm_element_name(parent));
2498 crm_warn(
"No node to copy properties from");
2500 }
else if (target == NULL) {
2501 crm_err(
"No node to copy properties into");
2504 xmlAttrPtr pIter = NULL;
2506 for (pIter = crm_first_attr(src); pIter != NULL; pIter = pIter->next) {
2507 const char *p_name = (
const char *)pIter->name;
2508 const char *p_value = crm_attr_value(pIter);
2521 xmlNode *child = NULL;
2522 xmlAttrPtr pIter = NULL;
2524 for (pIter = crm_first_attr(target); pIter != NULL; pIter = pIter->next) {
2525 const char *p_name = (
const char *)pIter->name;
2526 const char *p_value = crm_attr_value(pIter);
2530 for (child = __xml_first_child(target); child != NULL; child = __xml_next(child)) {
2543 const char *old_value = NULL;
2545 if (value == NULL || name == NULL) {
2551 if (old_value == NULL) {
2553 goto set_unexpanded;
2555 }
else if (strstr(value, name) != value) {
2556 goto set_unexpanded;
2559 name_len = strlen(name);
2560 value_len = strlen(value);
2561 if (value_len < (name_len + 2)
2562 || value[name_len] !=
'+' || (value[name_len + 1] !=
'+' && value[name_len + 1] !=
'=')) {
2563 goto set_unexpanded;
2569 if (old_value != value) {
2573 if (value[name_len + 1] !=
'+') {
2574 const char *offset_s = value + (name_len + 2);
2578 int_value += offset;
2588 if (old_value == value) {
2605 doc = xmlNewDoc((
const xmlChar *)
"1.0");
2606 xmlDocSetRootElement(doc, node);
2607 xmlSetTreeDoc(node, doc);
2615 xmlNode *child = NULL;
2618 CRM_CHECK(src_node != NULL,
return NULL);
2620 child = xmlDocCopyNode(src_node, doc, 1);
2621 xmlAddChild(parent, child);
2622 crm_node_created(child);
2645 xmlNode *parent = xml;
2649 if(docp->acls == NULL) {
2650 crm_trace(
"Ordinary user %s cannot access the CIB without any defined ACLs", docp->user);
2655 offset = __get_prefix(NULL, xml, buffer, offset);
2657 offset += snprintf(buffer + offset,
XML_BUFFER_SIZE - offset,
"[@%s]", name);
2667 xmlAttr *attr = xmlHasProp(xml, (
const xmlChar *)name);
2674 while(parent && parent->_private) {
2676 if(__xml_acl_mode_test(p->flags, mode)) {
2680 crm_trace(
"%x access denied to %s: parent", mode, buffer);
2684 parent = parent->parent;
2687 crm_trace(
"%x access denied to %s: default", mode, buffer);
2701 xmlAttr *attr = NULL;
2706 if (value == NULL) {
2709 #if XML_PARANOIA_CHECKS
2711 const char *old_value = NULL;
2716 CRM_CHECK(old_value != value,
crm_err(
"Cannot reset %s with crm_xml_add(%s)", name, value);
2721 if(TRACKING_CHANGES(node)) {
2724 if(old == NULL || value == NULL || strcmp(old, value) != 0) {
2729 if(dirty && __xml_acl_check(node, name,
xpf_acl_create) == FALSE) {
2730 crm_trace(
"Cannot add %s=%s to %s", name, value, node->name);
2734 attr = xmlSetProp(node, (
const xmlChar *)name, (
const xmlChar *)value);
2736 crm_attr_dirty(attr);
2739 CRM_CHECK(attr && attr->children && attr->children->content,
return NULL);
2740 return (
char *)attr->children->content;
2747 xmlAttr *attr = NULL;
2748 const char *old_value = NULL;
2751 CRM_CHECK(name != NULL && name[0] != 0,
return NULL);
2756 CRM_CHECK(old_value != value,
return value);
2760 crm_trace(
"Cannot replace %s=%s to %s", name, value, node->name);
2763 }
else if (old_value != NULL && value == NULL) {
2767 }
else if (value == NULL) {
2771 if(TRACKING_CHANGES(node)) {
2772 if(old_value == NULL || value == NULL || strcmp(old_value, value) != 0) {
2777 attr = xmlSetProp(node, (
const xmlChar *)name, (
const xmlChar *)value);
2779 crm_attr_dirty(attr);
2781 CRM_CHECK(attr && attr->children && attr->children->content,
return NULL);
2782 return (
char *)attr->children->content;
2789 const char *added =
crm_xml_add(node, name, number);
2799 xmlNode *node = NULL;
2801 if (name == NULL || name[0] == 0) {
2802 CRM_CHECK(name != NULL && name[0] == 0,
return NULL);
2806 if (parent == NULL) {
2807 doc = xmlNewDoc((
const xmlChar *)
"1.0");
2808 node = xmlNewDocRawNode(doc, NULL, (
const xmlChar *)name, NULL);
2809 xmlDocSetRootElement(doc, node);
2813 node = xmlNewDocRawNode(doc, NULL, (
const xmlChar *)name, NULL);
2814 xmlAddChild(parent, node);
2816 crm_node_created(node);
2821 __get_prefix(
const char *prefix, xmlNode *xml,
char *buffer,
int offset)
2823 const char *
id =
ID(xml);
2825 if(offset == 0 && prefix == NULL && xml->parent) {
2826 offset = __get_prefix(NULL, xml->parent, buffer, offset);
2830 offset += snprintf(buffer + offset,
XML_BUFFER_SIZE - offset,
"/%s[@id='%s']", (
const char *)xml->name,
id);
2831 }
else if(xml->name) {
2832 offset += snprintf(buffer + offset,
XML_BUFFER_SIZE - offset,
"/%s", (
const char *)xml->name);
2844 if(__get_prefix(NULL, xml, buffer, offset) > 0) {
2845 return strdup(buffer);
2853 if (child != NULL) {
2854 xmlNode *top = NULL;
2855 xmlDoc *doc = child->doc;
2859 top = xmlDocGetRootElement(doc);
2862 if (doc != NULL && top == child) {
2866 }
else if(__xml_acl_check(child, NULL,
xpf_acl_write) == FALSE) {
2870 __get_prefix(NULL, child, buffer, offset);
2871 crm_trace(
"Cannot remove %s %x", buffer, p->flags);
2875 if(doc && TRACKING_CHANGES(child) && is_not_set(p->flags,
xpf_created)) {
2879 if(__get_prefix(NULL, child, buffer, offset) > 0) {
2880 crm_trace(
"Deleting %s %p from %p", buffer, child, doc);
2882 p->deleted_paths = g_list_append(p->deleted_paths, strdup(buffer));
2890 xmlUnlinkNode(child);
2899 xmlDoc *doc = xmlNewDoc((
const xmlChar *)
"1.0");
2900 xmlNode *copy = xmlDocCopyNode(src, doc, 1);
2902 xmlDocSetRootElement(doc, copy);
2903 xmlSetTreeDoc(copy, doc);
2908 crm_xml_err(
void *ctx,
const char *msg, ...)
2909 G_GNUC_PRINTF(2, 3);
2912 crm_xml_err(
void *ctx, const
char *msg, ...)
2917 static int buffer_len = 0;
2918 static char *buffer = NULL;
2919 static struct qb_log_callsite *xml_error_cs = NULL;
2921 va_start(args, msg);
2922 len = vasprintf(&buf, msg, args);
2924 if(xml_error_cs == NULL) {
2925 xml_error_cs = qb_log_callsite_get(
2929 if (strchr(buf,
'\n')) {
2932 crm_err(
"XML Error: %s%s", buffer, buf);
2935 crm_err(
"XML Error: %s", buf);
2937 if (xml_error_cs && xml_error_cs->targets) {
2938 crm_abort(__FILE__, __PRETTY_FUNCTION__, __LINE__,
"xml library error", TRUE, TRUE);
2943 }
else if (buffer == NULL) {
2949 buffer = realloc_safe(buffer, 1 + buffer_len + len);
2950 memcpy(buffer + buffer_len, buf, len);
2952 buffer[buffer_len] = 0;
2962 xmlNode *xml = NULL;
2963 xmlDocPtr output = NULL;
2964 xmlParserCtxtPtr ctxt = NULL;
2965 xmlErrorPtr last_error = NULL;
2967 if (input == NULL) {
2968 crm_err(
"Can't parse NULL input");
2973 ctxt = xmlNewParserCtxt();
2978 xmlCtxtResetLastError(ctxt);
2979 xmlSetGenericErrorFunc(ctxt, crm_xml_err);
2982 xmlCtxtReadDoc(ctxt, (
const xmlChar *)input, NULL, NULL,
2983 XML_PARSE_NOBLANKS | XML_PARSE_RECOVER);
2985 xml = xmlDocGetRootElement(output);
2987 last_error = xmlCtxtGetLastError(ctxt);
2988 if (last_error && last_error->code != XML_ERR_OK) {
2994 crm_warn(
"Parsing failed (domain=%d, level=%d, code=%d): %s",
2995 last_error->domain, last_error->level, last_error->code, last_error->message);
2997 if (last_error->code == XML_ERR_DOCUMENT_EMPTY) {
3000 }
else if (last_error->code != XML_ERR_DOCUMENT_END) {
3001 crm_err(
"Couldn't%s parse %d chars: %s", xml ?
" fully" :
"", (
int)strlen(input),
3008 int len = strlen(input);
3012 crm_warn(
"Parse error[+%.3d]: %.80s", lpc, input+lpc);
3020 xmlFreeParserCtxt(ctxt);
3027 size_t data_length = 0;
3028 size_t read_chars = 0;
3030 char *xml_buffer = NULL;
3031 xmlNode *xml_obj = NULL;
3041 xml_buffer = realloc_safe(xml_buffer, next);
3042 read_chars = fread(xml_buffer + data_length, 1,
XML_BUFFER_SIZE, stdin);
3043 data_length += read_chars;
3044 }
while (read_chars > 0);
3046 if (data_length == 0) {
3047 crm_warn(
"No XML supplied on stdin");
3052 xml_buffer[data_length] =
'\0';
3062 decompress_file(
const char *filename)
3064 char *buffer = NULL;
3068 size_t length = 0, read_len = 0;
3070 BZFILE *bz_file = NULL;
3071 FILE *input = fopen(filename,
"r");
3073 if (input == NULL) {
3074 crm_perror(LOG_ERR,
"Could not open %s for reading", filename);
3078 bz_file = BZ2_bzReadOpen(&rc, input, 0, 0, NULL, 0);
3081 BZ2_bzReadClose(&rc, bz_file);
3086 while (rc == BZ_OK) {
3088 read_len = BZ2_bzRead(&rc, bz_file, buffer + length,
XML_BUFFER_SIZE);
3090 crm_trace(
"Read %ld bytes from file: %d", (
long)read_len, rc);
3092 if (rc == BZ_OK || rc == BZ_STREAM_END) {
3097 buffer[length] =
'\0';
3099 if (rc != BZ_STREAM_END) {
3100 crm_err(
"Couldn't read compressed xml from file");
3105 BZ2_bzReadClose(&rc, bz_file);
3109 crm_err(
"Cannot read compressed files:" " bzlib was not available at compile time");
3117 xmlNode *iter = xml->children;
3120 xmlNode *next = iter->next;
3122 switch (iter->type) {
3125 xmlUnlinkNode(iter);
3129 case XML_ELEMENT_NODE:
3146 xmlNode *xml = NULL;
3147 xmlDocPtr output = NULL;
3148 const char *match = NULL;
3149 xmlParserCtxtPtr ctxt = NULL;
3150 xmlErrorPtr last_error = NULL;
3151 static int xml_options = XML_PARSE_NOBLANKS | XML_PARSE_RECOVER;
3154 ctxt = xmlNewParserCtxt();
3159 xmlCtxtResetLastError(ctxt);
3160 xmlSetGenericErrorFunc(ctxt, crm_xml_err);
3164 match = strstr(filename,
".bz2");
3167 if (filename == NULL) {
3169 output = xmlCtxtReadFd(ctxt, STDIN_FILENO,
"unknown.xml", NULL, xml_options);
3171 }
else if (match == NULL || match[4] != 0) {
3172 output = xmlCtxtReadFile(ctxt, filename, NULL, xml_options);
3175 char *input = decompress_file(filename);
3177 output = xmlCtxtReadDoc(ctxt, (
const xmlChar *)input, NULL, NULL, xml_options);
3181 if (output && (xml = xmlDocGetRootElement(output))) {
3185 last_error = xmlCtxtGetLastError(ctxt);
3186 if (last_error && last_error->code != XML_ERR_OK) {
3192 crm_err(
"Parsing failed (domain=%d, level=%d, code=%d): %s",
3193 last_error->domain, last_error->level, last_error->code, last_error->message);
3195 if (last_error && last_error->code != XML_ERR_OK) {
3196 crm_err(
"Couldn't%s parse %s", xml ?
" fully" :
"", filename);
3203 xmlFreeParserCtxt(ctxt);
3218 time_t now = time(NULL);
3219 char *now_str = ctime(&now);
3226 write_xml_stream(xmlNode * xml_node,
const char *filename, FILE * stream, gboolean compress)
3229 char *buffer = NULL;
3230 unsigned int out = 0;
3234 crm_trace(
"Writing XML out to %s", filename);
3235 if (xml_node == NULL) {
3236 crm_err(
"Cannot write NULL to %s", filename);
3251 unsigned int in = 0;
3252 BZFILE *bz_file = NULL;
3254 bz_file = BZ2_bzWriteOpen(&rc, stream, 5, 0, 30);
3256 crm_err(
"bzWriteOpen failed: %d", rc);
3258 BZ2_bzWrite(&rc, bz_file, buffer, strlen(buffer));
3260 crm_err(
"bzWrite() failed: %d", rc);
3265 BZ2_bzWriteClose(&rc, bz_file, 0, &in, &out);
3267 crm_err(
"bzWriteClose() failed: %d", rc);
3270 crm_trace(
"%s: In: %d, out: %d", filename, in, out);
3274 crm_err(
"Cannot write compressed files:" " bzlib was not available at compile time");
3279 res = fprintf(stream,
"%s", buffer);
3281 crm_perror(LOG_ERR,
"Cannot write output to %s", filename);
3288 if (fflush(stream) != 0) {
3289 crm_perror(LOG_ERR,
"fflush for %s failed:", filename);
3293 if (fsync(fileno(stream)) < 0) {
3294 crm_perror(LOG_ERR,
"fsync for %s failed:", filename);
3300 crm_trace(
"Saved %d bytes to the Cib as XML", res);
3307 write_xml_fd(xmlNode * xml_node,
const char *filename,
int fd, gboolean compress)
3309 FILE *stream = NULL;
3312 stream = fdopen(fd,
"w");
3313 return write_xml_stream(xml_node, filename, stream, compress);
3319 FILE *stream = NULL;
3321 stream = fopen(filename,
"w");
3323 return write_xml_stream(xml_node, filename, stream, compress);
3331 return __xml_first_child(tmp);
3344 crm_xml_escape_shuffle(
char *text,
int start,
int *length,
const char *replace)
3347 int offset = strlen(replace) - 1;
3350 text = realloc_safe(text, *length);
3352 for (lpc = (*length) - 1; lpc > (start + offset); lpc--) {
3353 text[lpc] = text[lpc - offset];
3356 memcpy(text + start, replace, offset + 1);
3365 int length = 1 + strlen(text);
3366 char *copy = strdup(text);
3383 for (index = 0; index < length; index++) {
3384 switch (copy[index]) {
3388 copy = crm_xml_escape_shuffle(copy, index, &length,
"<");
3392 copy = crm_xml_escape_shuffle(copy, index, &length,
">");
3396 copy = crm_xml_escape_shuffle(copy, index, &length,
""");
3400 copy = crm_xml_escape_shuffle(copy, index, &length,
"'");
3404 copy = crm_xml_escape_shuffle(copy, index, &length,
"&");
3409 copy = crm_xml_escape_shuffle(copy, index, &length,
" ");
3414 copy = crm_xml_escape_shuffle(copy, index, &length,
"\\n");
3418 copy = crm_xml_escape_shuffle(copy, index, &length,
"\\r");
3428 if(copy[index] <
' ' || copy[index] >
'~') {
3432 copy = crm_xml_escape_shuffle(copy, index, &length, replace);
3446 dump_xml_attr(xmlAttrPtr attr,
int options,
char **buffer,
int *offset,
int *max)
3448 char *p_value = NULL;
3449 const char *p_name = NULL;
3453 if (attr == NULL || attr->children == NULL) {
3462 p_name = (
const char *)attr->name;
3464 buffer_print(*buffer, *max, *offset,
" %s=\"%s\"", p_name, p_value);
3469 __xml_log_element(
int log_level,
const char *file,
const char *
function,
int line,
3470 const char *prefix, xmlNode *
data,
int depth,
int options)
3474 const char *name = NULL;
3475 const char *hidden = NULL;
3477 xmlNode *child = NULL;
3478 xmlAttrPtr pIter = NULL;
3484 name = crm_element_name(data);
3487 char *buffer = NULL;
3489 insert_prefix(options, &buffer, &offset, &max, depth);
3490 if(data->type == XML_COMMENT_NODE) {
3492 buffer_print(buffer, max, offset,
"%s", data->content);
3500 for (pIter = crm_first_attr(data); pIter != NULL; pIter = pIter->next) {
3502 const char *p_name = (
const char *)pIter->name;
3503 const char *p_value = crm_attr_value(pIter);
3504 char *p_copy = NULL;
3513 }
else if (hidden != NULL && p_name[0] != 0 && strstr(hidden, p_name) != NULL) {
3514 p_copy = strdup(
"*****");
3520 buffer_print(buffer, max, offset,
" %s=\"%s\"", p_name, p_copy);
3534 do_crm_log_alias(log_level, file,
function, line,
"%s %s", prefix, buffer);
3538 if(data->type == XML_COMMENT_NODE) {
3548 for (child = __xml_first_child(data); child != NULL; child = __xml_next(child)) {
3554 char *buffer = NULL;
3556 insert_prefix(options, &buffer, &offset, &max, depth);
3559 do_crm_log_alias(log_level, file,
function, line,
"%s %s", prefix, buffer);
3565 __xml_log_change_element(
int log_level,
const char *file,
const char *
function,
int line,
3566 const char *prefix, xmlNode * data,
int depth,
int options)
3569 char *prefix_m = NULL;
3570 xmlNode *child = NULL;
3571 xmlAttrPtr pIter = NULL;
3579 prefix_m = strdup(prefix);
3584 __xml_log_element(log_level, file,
function, line,
3587 }
else if(is_set(p->flags,
xpf_dirty)) {
3588 char *spaces = calloc(80, 1);
3589 int s_count = 0, s_max = 80;
3590 char *prefix_del = NULL;
3591 char *prefix_moved = NULL;
3592 const char *
flags = prefix;
3594 insert_prefix(options, &spaces, &s_count, &s_max, depth);
3595 prefix_del = strdup(prefix);
3596 prefix_del[0] =
'-';
3597 prefix_del[1] =
'-';
3598 prefix_moved = strdup(prefix);
3599 prefix_moved[1] =
'~';
3602 flags = prefix_moved;
3607 __xml_log_element(log_level, file,
function, line,
3610 for (pIter = crm_first_attr(data); pIter != NULL; pIter = pIter->next) {
3611 const char *aname = (
const char*)pIter->name;
3613 p = pIter->_private;
3618 "%s %s @%s=%s", flags, spaces, aname, value);
3620 }
else if(is_set(p->flags,
xpf_dirty)) {
3629 }
else if(is_set(p->flags,
xpf_moved)) {
3630 flags = prefix_moved;
3636 "%s %s @%s=%s", flags, spaces, aname, value);
3643 for (child = __xml_first_child(data); child != NULL; child = __xml_next(child)) {
3644 __xml_log_change_element(log_level, file,
function, line, prefix, child, depth + 1, options);
3647 __xml_log_element(log_level, file,
function, line,
3651 for (child = __xml_first_child(data); child != NULL; child = __xml_next(child)) {
3652 __xml_log_change_element(log_level, file,
function, line, prefix, child, depth + 1, options);
3662 const char *prefix, xmlNode * data,
int depth,
int options)
3664 xmlNode *a_child = NULL;
3666 char *prefix_m = NULL;
3668 if (prefix == NULL) {
3675 "No data to dump as XML");
3680 __xml_log_change_element(log_level, file,
function, line, prefix, data, depth, options);
3688 prefix_m = strdup(prefix);
3695 prefix_m = strdup(prefix);
3704 for (a_child = __xml_first_child(data); a_child != NULL; a_child = __xml_next(a_child)) {
3705 log_data_element(log_level, file,
function, line, prefix, a_child, depth + 1, options);
3708 __xml_log_element(log_level, file,
function, line, prefix, data, depth,
3715 dump_filtered_xml(xmlNode * data,
int options,
char **buffer,
int *offset,
int *max)
3718 xmlAttrPtr xIter = NULL;
3719 static int filter_len =
DIMOF(filter);
3721 for (lpc = 0; options && lpc < filter_len; lpc++) {
3722 filter[lpc].found = FALSE;
3725 for (xIter = crm_first_attr(data); xIter != NULL; xIter = xIter->next) {
3727 const char *p_name = (
const char *)xIter->name;
3729 for (lpc = 0; skip == FALSE && lpc < filter_len; lpc++) {
3730 if (filter[lpc].found == FALSE && strcmp(p_name, filter[lpc].
string) == 0) {
3731 filter[lpc].found = TRUE;
3737 if (skip == FALSE) {
3738 dump_xml_attr(xIter, options, buffer, offset, max);
3744 dump_xml_element(xmlNode * data,
int options,
char **buffer,
int *offset,
int *max,
int depth)
3746 const char *name = NULL;
3757 if (*buffer == NULL) {
3762 name = crm_element_name(data);
3765 insert_prefix(options, buffer, offset, max, depth);
3769 dump_filtered_xml(data, options, buffer, offset, max);
3772 xmlAttrPtr xIter = NULL;
3774 for (xIter = crm_first_attr(data); xIter != NULL; xIter = xIter->next) {
3775 dump_xml_attr(xIter, options, buffer, offset, max);
3779 if (data->children == NULL) {
3790 if (data->children) {
3791 xmlNode *xChild = NULL;
3792 for(xChild = data->children; xChild != NULL; xChild = xChild->next) {
3793 crm_xml_dump(xChild, options, buffer, offset, max, depth + 1);
3796 insert_prefix(options, buffer, offset, max, depth);
3799 if (options & xml_log_option_formatted) {
3806 dump_xml_text(xmlNode * data,
int options,
char **buffer,
int *offset,
int *max,
int depth)
3817 if (*buffer == NULL) {
3822 insert_prefix(options, buffer, offset, max, depth);
3824 buffer_print(*buffer, *max, *offset,
"%s", data->content);
3826 if (options & xml_log_option_formatted) {
3833 dump_xml_comment(xmlNode * data,
int options,
char **buffer,
int *offset,
int *max,
int depth)
3844 if (*buffer == NULL) {
3849 insert_prefix(options, buffer, offset, max, depth);
3852 buffer_print(*buffer, *max, *offset,
"%s", data->content);
3855 if (options & xml_log_option_formatted) {
3861 crm_xml_dump(xmlNode * data,
int options,
char **buffer,
int *offset,
int *max,
int depth)
3869 if (is_not_set(options, xml_log_option_filtered)) {
3884 xmlBuffer *xml_buffer = NULL;
3892 xml_buffer = xmlBufferCreate();
3903 xmlBufferSetAllocationScheme(xml_buffer, XML_BUFFER_ALLOC_DOUBLEIT);
3905 *max = xmlNodeDump(xml_buffer, doc, data, 0, (options & xml_log_option_formatted));
3907 *buffer = strdup((
char *)xml_buffer->content);
3911 if ((now + 1) < next) {
3913 crm_err(
"xmlNodeDump() -> %dbytes took %ds", *max, next - now);
3916 xmlBufferFree(xml_buffer);
3921 switch(data->type) {
3922 case XML_ELEMENT_NODE:
3924 dump_xml_element(data, options, buffer, offset, max, depth);
3929 dump_xml_text(data, options, buffer, offset, max, depth);
3932 case XML_COMMENT_NODE:
3933 dump_xml_comment(data, options, buffer, offset, max, depth);
3936 crm_warn(
"Unhandled type: %d", data->type);
3972 char *buffer = NULL;
3973 int offset = 0, max = 0;
3982 char *buffer = NULL;
3983 int offset = 0, max = 0;
3985 crm_xml_dump(an_xml_node, xml_log_option_formatted, &buffer, &offset, &max, 0);
3992 char *buffer = NULL;
3993 int offset = 0, max = 0;
3995 crm_xml_dump(an_xml_node, 0, &buffer, &offset, &max, 0);
4002 if (xml_root != NULL && xml_root->children != NULL) {
4036 char *value_copy = NULL;
4039 if (value != NULL) {
4040 value_copy = strdup(value);
4049 crm_trace(
"Cannot remove %s from %s", name, obj->name);
4051 }
else if(TRACKING_CHANGES(obj)) {
4054 xmlAttr *attr = xmlHasProp(obj, (
const xmlChar *)name);
4062 xmlUnsetProp(obj, (
const xmlChar *)name);
4069 xmlNode *child = NULL;
4074 for (child = __xml_first_child(a_node); child != NULL; child = __xml_next(child)) {
4084 if (filename == NULL) {
4092 crm_info(
"Saving %s to %s", desc, filename);
4100 gboolean result = TRUE;
4101 int root_nodes_seen = 0;
4102 static struct qb_log_callsite *digest_cs = NULL;
4106 xmlNode *child_diff = NULL;
4108 xmlNode *removed =
find_xml_node(diff,
"diff-removed", FALSE);
4111 if (digest_cs == NULL) {
4113 qb_log_callsite_get(__func__, __FILE__,
"diff-digest",
LOG_TRACE, __LINE__,
4118 for (child_diff = __xml_first_child(removed); child_diff != NULL;
4119 child_diff = __xml_next(child_diff)) {
4120 CRM_CHECK(root_nodes_seen == 0, result = FALSE);
4121 if (root_nodes_seen == 0) {
4127 if (root_nodes_seen == 0) {
4130 }
else if (root_nodes_seen > 1) {
4131 crm_err(
"(-) Diffs cannot contain more than one change set..." " saw %d", root_nodes_seen);
4135 root_nodes_seen = 0;
4138 xmlNode *child_diff = NULL;
4140 for (child_diff = __xml_first_child(added); child_diff != NULL;
4141 child_diff = __xml_next(child_diff)) {
4142 CRM_CHECK(root_nodes_seen == 0, result = FALSE);
4143 if (root_nodes_seen == 0) {
4150 if (root_nodes_seen > 1) {
4151 crm_err(
"(+) Diffs cannot contain more than one change set..." " saw %d", root_nodes_seen);
4154 }
else if (result && digest) {
4155 char *new_digest = NULL;
4160 crm_info(
"Digest mis-match: expected %s, calculated %s", digest, new_digest);
4163 crm_trace(
"%p %.6x", digest_cs, digest_cs ? digest_cs->targets : 0);
4164 if (digest_cs && digest_cs->targets) {
4171 crm_trace(
"Digest matched: expected %s, calculated %s", digest, new_digest);
4175 }
else if (result) {
4183 __xml_diff_object(xmlNode * old, xmlNode *
new)
4185 xmlNode *cIter = NULL;
4186 xmlAttr *pIter = NULL;
4190 crm_node_created(
new);
4191 __xml_acl_post_process(
new);
4204 for (pIter = crm_first_attr(
new); pIter != NULL; pIter = pIter->next) {
4211 for (pIter = crm_first_attr(old); pIter != NULL; ) {
4212 xmlAttr *prop = pIter;
4214 const char *name = (
const char *)pIter->name;
4216 xmlAttr *exists = xmlHasProp(
new, pIter->name);
4218 pIter = pIter->next;
4219 if(exists == NULL) {
4220 p =
new->doc->_private;
4224 exists = xmlSetProp(
new, (
const xmlChar *)name, (
const xmlChar *)old_value);
4227 p = exists->_private;
4230 crm_trace(
"Lost %s@%s=%s", old->name, name, old_value);
4234 int p_new = __xml_offset((xmlNode*)exists);
4235 int p_old = __xml_offset((xmlNode*)prop);
4238 p = exists->_private;
4241 if(strcmp(value, old_value) != 0) {
4245 crm_trace(
"Modified %s@%s %s->%s", old->name, name, old_value, vcopy);
4246 xmlSetProp(
new, prop->name, (
const xmlChar *)old_value);
4250 }
else if(p_old != p_new) {
4251 crm_info(
"Moved %s@%s (%d -> %d)", old->name, name, p_old, p_new);
4252 __xml_node_dirty(
new);
4260 p = exists->_private;
4267 for (pIter = crm_first_attr(
new); pIter != NULL; ) {
4268 xmlAttr *prop = pIter;
4271 pIter = pIter->next;
4273 char *name = strdup((
const char *)prop->name);
4276 crm_trace(
"Created %s@%s=%s", new->name, name, value);
4279 crm_attr_dirty(prop);
4281 xmlUnsetProp(
new, prop->name);
4289 for (cIter = __xml_first_child(old); cIter != NULL; ) {
4290 xmlNode *old_child = cIter;
4291 xmlNode *new_child =
find_entity(
new, crm_element_name(cIter),
ID(cIter));
4293 cIter = __xml_next(cIter);
4295 __xml_diff_object(old_child, new_child);
4302 xmlNode *top = xmlDocGetRootElement(candidate->doc);
4304 __xml_node_clean(candidate);
4305 __xml_acl_apply(top);
4308 if(NULL ==
find_entity(
new, crm_element_name(old_child),
ID(old_child))) {
4314 for (cIter = __xml_first_child(
new); cIter != NULL; ) {
4315 xmlNode *new_child = cIter;
4316 xmlNode *old_child =
find_entity(old, crm_element_name(cIter),
ID(cIter));
4318 cIter = __xml_next(cIter);
4319 if(old_child == NULL) {
4322 __xml_diff_object(old_child, new_child);
4326 int p_new = __xml_offset(new_child);
4327 int p_old = __xml_offset(old_child);
4330 if(p_old != p_new) {
4331 crm_info(
"%s.%s moved from %d to %d - %d",
4332 new_child->name,
ID(new_child), p_old, p_new);
4333 __xml_node_dirty(
new);
4337 p = old_child->_private;
4341 p = new_child->_private;
4359 __xml_diff_object(old,
new);
4365 xmlNode *tmp1 = NULL;
4382 if (added->children == NULL && removed->children == NULL) {
4393 xmlNode *cIter = NULL;
4394 xmlAttrPtr pIter = NULL;
4395 gboolean can_prune = TRUE;
4396 const char *name = crm_element_name(xml_node);
4405 for (pIter = crm_first_attr(xml_node); pIter != NULL; pIter = pIter->next) {
4406 const char *p_name = (
const char *)pIter->name;
4414 cIter = __xml_first_child(xml_node);
4416 xmlNode *child = cIter;
4418 cIter = __xml_next(cIter);
4430 xmlNode * xml_node, xmlNode * parent)
4433 xmlNode *child = NULL;
4434 xmlAttrPtr pIter = NULL;
4435 xmlNode *new_parent = parent;
4436 const char *name = crm_element_name(xml_node);
4438 CRM_CHECK(xml_node != NULL && name != NULL,
return);
4441 for (pIter = crm_first_attr(xml_node); pIter != NULL; pIter = pIter->next) {
4442 const char *p_name = (
const char *)pIter->name;
4443 const char *p_value = crm_attr_value(pIter);
4445 lower_bound = context;
4449 if (lower_bound >= 0 || upper_bound >= 0) {
4455 if (upper_bound >= 0) {
4464 for (child = __xml_first_child(us); child != NULL; child = __xml_next(child)) {
4476 if (xml_node->properties) {
4479 }
else if (depth < context) {
4480 xmlNode *child = NULL;
4482 for (child = __xml_first_child(xml_node); child != NULL; child = __xml_next(child)) {
4492 find_xml_comment(xmlNode * root, xmlNode * search_comment)
4494 xmlNode *a_child = NULL;
4496 CRM_CHECK(search_comment->type == XML_COMMENT_NODE,
return NULL);
4498 for (a_child = __xml_first_child(root); a_child != NULL; a_child = __xml_next(a_child)) {
4499 if (a_child->type != XML_COMMENT_NODE) {
4502 if (
safe_str_eq((
const char *)a_child->content, (
const char *)search_comment->content)) {
4511 subtract_xml_comment(xmlNode * parent, xmlNode * left, xmlNode * right,
4515 CRM_CHECK(left->type == XML_COMMENT_NODE,
return NULL);
4518 ||
safe_str_neq((
const char *)left->content, (
const char *)right->content)) {
4519 xmlNode *deleted = NULL;
4532 gboolean full, gboolean * changed,
const char *marker)
4534 gboolean dummy = FALSE;
4535 gboolean skip = FALSE;
4536 xmlNode *diff = NULL;
4537 xmlNode *right_child = NULL;
4538 xmlNode *left_child = NULL;
4539 xmlAttrPtr xIter = NULL;
4541 const char *
id = NULL;
4542 const char *name = NULL;
4543 const char *value = NULL;
4544 const char *right_val = NULL;
4547 static int filter_len =
DIMOF(filter);
4549 if (changed == NULL) {
4557 if (left->type == XML_COMMENT_NODE) {
4558 return subtract_xml_comment(parent, left, right, changed);
4562 if (right == NULL) {
4563 xmlNode *deleted = NULL;
4565 crm_trace(
"Processing <%s id=%s> (complete copy)", crm_element_name(left),
id);
4573 name = crm_element_name(left);
4579 if (value != NULL && strcmp(value,
"removed:top") == 0) {
4580 crm_trace(
"We are the root of the deletion: %s.id=%s", name,
id);
4589 for (lpc = 0; lpc < filter_len; lpc++) {
4590 filter[lpc].found = FALSE;
4594 for (left_child = __xml_first_child(left); left_child != NULL;
4595 left_child = __xml_next(left_child)) {
4596 gboolean child_changed = FALSE;
4598 if (left_child->type == XML_COMMENT_NODE) {
4599 right_child = find_xml_comment(right, left_child);
4602 right_child =
find_entity(right, crm_element_name(left_child),
ID(left_child));
4606 if (child_changed) {
4611 if (*changed == FALSE) {
4615 xmlAttrPtr pIter = NULL;
4617 for (pIter = crm_first_attr(left); pIter != NULL; pIter = pIter->next) {
4618 const char *p_name = (
const char *)pIter->name;
4619 const char *p_value = crm_attr_value(pIter);
4621 xmlSetProp(diff, (
const xmlChar *)p_name, (
const xmlChar *)p_value);
4628 xmlSetProp(diff, (
const xmlChar *)
XML_ATTR_ID, (
const xmlChar *)
id);
4632 for (xIter = crm_first_attr(left); xIter != NULL; xIter = xIter->next) {
4633 const char *prop_name = (
const char *)xIter->name;
4634 xmlAttrPtr right_attr = NULL;
4642 for (lpc = 0; skip == FALSE && lpc < filter_len; lpc++) {
4643 if (filter[lpc].found == FALSE && strcmp(prop_name, filter[lpc].
string) == 0) {
4644 filter[lpc].found = TRUE;
4654 right_attr = xmlHasProp(right, (
const xmlChar *)prop_name);
4656 p = right_attr->_private;
4660 if (right_val == NULL || (p && is_set(p->flags,
xpf_deleted))) {
4664 xmlAttrPtr pIter = NULL;
4666 for (pIter = crm_first_attr(left); pIter != NULL; pIter = pIter->next) {
4667 const char *p_name = (
const char *)pIter->name;
4668 const char *p_value = crm_attr_value(pIter);
4670 xmlSetProp(diff, (
const xmlChar *)p_name, (
const xmlChar *)p_value);
4677 xmlSetProp(diff, (
const xmlChar *)prop_name, (
const xmlChar *)value);
4685 if (strcmp(left_value, right_val) == 0) {
4691 xmlAttrPtr pIter = NULL;
4693 crm_trace(
"Changes detected to %s in <%s id=%s>", prop_name,
4694 crm_element_name(left),
id);
4695 for (pIter = crm_first_attr(left); pIter != NULL; pIter = pIter->next) {
4696 const char *p_name = (
const char *)pIter->name;
4697 const char *p_value = crm_attr_value(pIter);
4699 xmlSetProp(diff, (
const xmlChar *)p_name, (
const xmlChar *)p_value);
4704 crm_trace(
"Changes detected to %s (%s -> %s) in <%s id=%s>",
4705 prop_name, left_value, right_val, crm_element_name(left),
id);
4712 if (*changed == FALSE) {
4716 }
else if (full == FALSE &&
id) {
4724 add_xml_comment(xmlNode * parent, xmlNode * target, xmlNode * update)
4727 CRM_CHECK(update->type == XML_COMMENT_NODE,
return 0);
4729 if (target == NULL) {
4730 target = find_xml_comment(parent, update);
4733 if (target == NULL) {
4737 }
else if (
safe_str_neq((
const char *)target->content, (
const char *)update->content)) {
4738 xmlFree(target->content);
4739 target->content = xmlStrdup(update->content);
4746 add_xml_object(xmlNode * parent, xmlNode * target, xmlNode * update, gboolean as_diff)
4748 xmlNode *a_child = NULL;
4749 const char *object_id = NULL;
4750 const char *object_name = NULL;
4759 if (update->type == XML_COMMENT_NODE) {
4760 return add_xml_comment(parent, target, update);
4763 object_name = crm_element_name(update);
4764 object_id =
ID(update);
4766 CRM_CHECK(object_name != NULL,
return 0);
4768 if (target == NULL && object_id == NULL) {
4772 }
else if (target == NULL) {
4773 target =
find_entity(parent, object_name, object_id);
4776 if (target == NULL) {
4779 #if XML_PARSER_DEBUG
4781 object_id ?
" id=" :
"", object_id ? object_id :
"");
4784 crm_trace(
"Found node <%s%s%s/> to update",
4785 crm_str(object_name), object_id ?
" id=" :
"", object_id ? object_id :
"");
4791 if (as_diff == FALSE) {
4797 xmlAttrPtr pIter = NULL;
4799 for (pIter = crm_first_attr(update); pIter != NULL; pIter = pIter->next) {
4800 const char *p_name = (
const char *)pIter->name;
4801 const char *p_value = crm_attr_value(pIter);
4804 xmlUnsetProp(target, (
const xmlChar *)p_name);
4805 xmlSetProp(target, (
const xmlChar *)p_name, (
const xmlChar *)p_value);
4809 for (a_child = __xml_first_child(update); a_child != NULL; a_child = __xml_next(a_child)) {
4810 #if XML_PARSER_DEBUG
4811 crm_trace(
"Updating child <%s id=%s>", crm_element_name(a_child),
ID(a_child));
4816 #if XML_PARSER_DEBUG
4825 gboolean can_update = TRUE;
4826 xmlNode *child_of_child = NULL;
4829 CRM_CHECK(to_update != NULL,
return FALSE);
4831 if (
safe_str_neq(crm_element_name(to_update), crm_element_name(child))) {
4837 }
else if (can_update) {
4838 #if XML_PARSER_DEBUG
4844 for (child_of_child = __xml_first_child(child); child_of_child != NULL;
4845 child_of_child = __xml_next(child_of_child)) {
4858 const char *tag,
const char *field,
const char *value, gboolean search_matches)
4860 int match_found = 0;
4863 CRM_CHECK(children != NULL,
return FALSE);
4865 if (tag != NULL &&
safe_str_neq(tag, crm_element_name(root))) {
4870 if (*children == NULL) {
4877 if (search_matches || match_found == 0) {
4878 xmlNode *child = NULL;
4880 for (child = __xml_first_child(root); child != NULL; child = __xml_next(child)) {
4881 match_found +=
find_xml_children(children, child, tag, field, value, search_matches);
4891 gboolean can_delete = FALSE;
4892 xmlNode *child_of_child = NULL;
4894 const char *up_id = NULL;
4895 const char *child_id = NULL;
4896 const char *right_val = NULL;
4899 CRM_CHECK(update != NULL,
return FALSE);
4902 child_id =
ID(child);
4904 if (up_id == NULL || (child_id && strcmp(child_id, up_id) == 0)) {
4907 if (
safe_str_neq(crm_element_name(update), crm_element_name(child))) {
4910 if (can_delete && delete_only) {
4911 xmlAttrPtr pIter = NULL;
4913 for (pIter = crm_first_attr(update); pIter != NULL; pIter = pIter->next) {
4914 const char *p_name = (
const char *)pIter->name;
4915 const char *p_value = crm_attr_value(pIter);
4924 if (can_delete && parent != NULL) {
4926 if (delete_only || update == NULL) {
4931 xmlDoc *doc = tmp->doc;
4932 xmlNode *old = NULL;
4935 old = xmlReplaceNode(child, tmp);
4939 __xml_acl_apply(tmp);
4943 xmlDocSetRootElement(doc, old);
4949 }
else if (can_delete) {
4954 child_of_child = __xml_first_child(child);
4955 while (child_of_child) {
4956 xmlNode *next = __xml_next(child_of_child);
4962 child_of_child = NULL;
4964 child_of_child = next;
4974 const char *name = key;
4975 const char *s_value = value;
4977 xmlNode *xml_node = user_data;
4984 crm_trace(
"dumped: name=%s value=%s", name, s_value);
4990 const char *name = key;
4991 const char *s_value = value;
4993 xmlNode *xml_node = user_data;
4995 if (isdigit(name[0])) {
5003 crm_trace(
"dumped: %s=%s", name, s_value);
5006 crm_trace(
"duplicate: %s=%s", name, s_value);
5013 const char *name = key;
5014 const char *s_value = value;
5016 xmlNode *xml_node = user_data;
5022 crm_trace(
"duplicate: %s=%s", name, s_value);
5029 char *crm_name = NULL;
5031 if (key == NULL || value == NULL) {
5033 }
else if (((
char *)key)[0] ==
'#') {
5035 }
else if (strstr(key,
":")) {
5047 xmlNode *child = NULL;
5048 xmlAttrPtr pIter = NULL;
5049 xmlNode *nvpair_list = NULL;
5050 GHashTable *nvpair_hash = g_hash_table_new_full(
crm_str_hash, g_str_equal,
5053 CRM_CHECK(parent != NULL,
return nvpair_hash);
5056 if (nvpair_list == NULL) {
5057 crm_trace(
"No attributes in %s", crm_element_name(parent));
5063 for (pIter = crm_first_attr(nvpair_list); pIter != NULL; pIter = pIter->next) {
5064 const char *p_name = (
const char *)pIter->name;
5065 const char *p_value = crm_attr_value(pIter);
5067 crm_trace(
"Added %s=%s", p_name, p_value);
5069 g_hash_table_insert(nvpair_hash, strdup(p_name), strdup(p_value));
5072 for (child = __xml_first_child(nvpair_list); child != NULL; child = __xml_next(child)) {
5073 if (strcmp((
const char *)child->name,
XML_TAG_PARAM) == 0) {
5078 if (key != NULL && value != NULL) {
5079 g_hash_table_insert(nvpair_hash, strdup(key), strdup(value));
5087 typedef struct name_value_s {
5093 sort_pairs(gconstpointer a, gconstpointer b)
5105 rc = strcmp(pair_a->name, pair_b->name);
5108 }
else if (rc > 0) {
5115 dump_pair(gpointer data, gpointer user_data)
5118 xmlNode *parent = user_data;
5124 sorted_xml(xmlNode * input, xmlNode * parent, gboolean recursive)
5126 xmlNode *child = NULL;
5130 xmlNode *result = NULL;
5131 const char *name = NULL;
5132 xmlAttrPtr pIter = NULL;
5136 name = crm_element_name(input);
5141 for (pIter = crm_first_attr(input); pIter != NULL; pIter = pIter->next) {
5142 const char *p_name = (
const char *)pIter->name;
5143 const char *p_value = crm_attr_value(pIter);
5146 pair->name = p_name;
5147 pair->value = p_value;
5148 unsorted = g_list_prepend(unsorted, pair);
5152 sorted = g_list_sort(unsorted, sort_pairs);
5153 g_list_foreach(sorted, dump_pair, result);
5154 g_list_free_full(sorted, free);
5156 for (child = __xml_first_child(input); child != NULL; child = __xml_next(child)) {
5168 validate_with_dtd(xmlDocPtr doc, gboolean to_logs,
const char *dtd_file)
5170 gboolean valid = TRUE;
5172 xmlDtdPtr dtd = NULL;
5173 xmlValidCtxtPtr cvp = NULL;
5176 CRM_CHECK(dtd_file != NULL,
return FALSE);
5178 dtd = xmlParseDTD(NULL, (
const xmlChar *)dtd_file);
5180 crm_err(
"Could not locate/parse DTD: %s", dtd_file);
5184 cvp = xmlNewValidCtxt();
5187 cvp->userData = (
void *)LOG_ERR;
5188 cvp->error = (xmlValidityErrorFunc)
xml_log;
5189 cvp->warning = (xmlValidityWarningFunc)
xml_log;
5191 cvp->userData = (
void *)stderr;
5192 cvp->error = (xmlValidityErrorFunc) fprintf;
5193 cvp->warning = (xmlValidityWarningFunc) fprintf;
5196 if (!xmlValidateDtd(cvp, doc, dtd)) {
5199 xmlFreeValidCtxt(cvp);
5202 crm_err(
"Internal error: No valid context");
5212 xmlNode *match = NULL;
5214 for (match = __xml_first_child(parent); match != NULL; match = __xml_next(match)) {
5220 if (name == NULL || strcmp((
const char *)match->name, name) == 0) {
5229 relaxng_invalid_stderr(
void *userData, xmlErrorPtr error)
5249 crm_err(
"Structured error: line=%d, level=%d %s", error->line, error->level, error->message);
5254 validate_with_relaxng(xmlDocPtr doc, gboolean to_logs,
const char *relaxng_file,
5255 relaxng_ctx_cache_t ** cached_ctx)
5258 gboolean valid = TRUE;
5259 relaxng_ctx_cache_t *ctx = NULL;
5262 CRM_CHECK(relaxng_file != NULL,
return FALSE);
5264 if (cached_ctx && *cached_ctx) {
5268 crm_info(
"Creating RNG parser context");
5269 ctx = calloc(1,
sizeof(relaxng_ctx_cache_t));
5271 xmlLoadExtDtdDefaultValue = 1;
5272 ctx->parser = xmlRelaxNGNewParserCtxt(relaxng_file);
5273 CRM_CHECK(ctx->parser != NULL,
goto cleanup);
5276 xmlRelaxNGSetParserErrors(ctx->parser,
5277 (xmlRelaxNGValidityErrorFunc)
xml_log,
5278 (xmlRelaxNGValidityWarningFunc) xml_log,
5279 GUINT_TO_POINTER(LOG_ERR));
5281 xmlRelaxNGSetParserErrors(ctx->parser,
5282 (xmlRelaxNGValidityErrorFunc) fprintf,
5283 (xmlRelaxNGValidityWarningFunc) fprintf, stderr);
5286 ctx->rng = xmlRelaxNGParse(ctx->parser);
5287 CRM_CHECK(ctx->rng != NULL,
crm_err(
"Could not find/parse %s", relaxng_file);
5290 ctx->valid = xmlRelaxNGNewValidCtxt(ctx->rng);
5291 CRM_CHECK(ctx->valid != NULL,
goto cleanup);
5294 xmlRelaxNGSetValidErrors(ctx->valid,
5295 (xmlRelaxNGValidityErrorFunc)
xml_log,
5296 (xmlRelaxNGValidityWarningFunc) xml_log,
5297 GUINT_TO_POINTER(LOG_ERR));
5299 xmlRelaxNGSetValidErrors(ctx->valid,
5300 (xmlRelaxNGValidityErrorFunc) fprintf,
5301 (xmlRelaxNGValidityWarningFunc) fprintf, stderr);
5308 xmlLineNumbersDefault(1);
5309 rc = xmlRelaxNGValidateDoc(ctx->valid, doc);
5313 }
else if (rc < 0) {
5314 crm_err(
"Internal libxml error during validation\n");
5323 if (ctx->parser != NULL) {
5324 xmlRelaxNGFreeParserCtxt(ctx->parser);
5326 if (ctx->valid != NULL) {
5327 xmlRelaxNGFreeValidCtxt(ctx->valid);
5329 if (ctx->rng != NULL) {
5330 xmlRelaxNGFree(ctx->rng);
5341 static bool init = TRUE;
5350 xmlSetBufferAllocationScheme(XML_BUFFER_ALLOC_DOUBLEIT);
5353 xmlDeregisterNodeDefault(pcmkDeregisterNode);
5354 xmlRegisterNodeDefault(pcmkRegisterNode);
5356 __xml_build_schema_list();
5364 relaxng_ctx_cache_t *ctx = NULL;
5366 crm_info(
"Cleaning up memory from libxml2");
5367 for (; lpc < xml_schema_max; lpc++) {
5369 switch (known_schemas[lpc].type) {
5378 ctx = (relaxng_ctx_cache_t *) known_schemas[lpc].cache;
5382 if (ctx->parser != NULL) {
5383 xmlRelaxNGFreeParserCtxt(ctx->parser);
5385 if (ctx->valid != NULL) {
5386 xmlRelaxNGFreeValidCtxt(ctx->valid);
5388 if (ctx->rng != NULL) {
5389 xmlRelaxNGFree(ctx->rng);
5392 known_schemas[lpc].cache = NULL;
5397 free(known_schemas[lpc].name);
5398 free(known_schemas[lpc].location);
5399 free(known_schemas[lpc].transform);
5401 free(known_schemas);
5402 xsltCleanupGlobals();
5407 validate_with(xmlNode * xml,
int method, gboolean to_logs)
5409 xmlDocPtr doc = NULL;
5410 gboolean valid = FALSE;
5418 type = known_schemas[method].type;
5425 file = get_schema_path(known_schemas[method].name, known_schemas[method].location);
5430 valid = validate_with_dtd(doc, to_logs, file);
5434 validate_with_relaxng(doc, to_logs, file,
5435 (relaxng_ctx_cache_t **) & (known_schemas[method].cache));
5438 crm_err(
"Unknown validator type: %d", type);
5448 dump_file(
const char *filename)
5456 fp = fopen(filename,
"r");
5459 fprintf(stderr,
"%4d ", ++line);
5465 }
else if (ch ==
'\n') {
5466 fprintf(stderr,
"\n%4d ", ++line);
5480 xmlNode *xml = NULL;
5481 gboolean rc = FALSE;
5482 char *filename = strdup(
CRM_STATE_DIR "/cib-invalid.XXXXXX");
5484 umask(S_IWGRP | S_IWOTH | S_IROTH);
5485 fd = mkstemp(filename);
5488 dump_file(filename);
5490 doc = xmlParseFile(filename);
5491 xml = xmlDocGetRootElement(doc);
5506 if (validation == NULL) {
5510 if (validation == NULL) {
5522 for (lpc = 0; lpc < xml_schema_max; lpc++) {
5523 if(validate_with(xml_blob, lpc, FALSE)) {
5526 crm_info(
"XML validated against %s", known_schemas[lpc].name);
5527 if(known_schemas[lpc].after_transform == 0) {
5537 if (strcmp(validation,
"none") == 0) {
5540 }
else if(version < xml_schema_max) {
5541 return validate_with(xml_blob, version, to_logs);
5545 crm_err(
"Unknown validator: %s", validation);
5551 apply_transformation(xmlNode * xml,
const char *transform)
5554 xmlNode *out = NULL;
5555 xmlDocPtr res = NULL;
5556 xmlDocPtr doc = NULL;
5557 xsltStylesheet *xslt = NULL;
5561 xform = get_schema_path(NULL, transform);
5563 xmlLoadExtDtdDefaultValue = 1;
5564 xmlSubstituteEntitiesDefault(1);
5566 xslt = xsltParseStylesheetFile((
const xmlChar *)xform);
5569 res = xsltApplyStylesheet(xslt, doc, NULL);
5572 out = xmlDocGetRootElement(res);
5576 xsltFreeStylesheet(xslt);
5588 if (version < 0 || version >= xml_schema_max) {
5591 return known_schemas[
version].name;
5602 for (; lpc < xml_schema_max; lpc++) {
5615 xmlNode *xml = NULL;
5617 int max_stable_schemas = xml_latest_schema_index();
5618 int lpc = 0, match = -1, rc =
pcmk_ok;
5620 CRM_CHECK(best != NULL,
return -EINVAL);
5621 CRM_CHECK(xml_blob != NULL,
return -EINVAL);
5622 CRM_CHECK(*xml_blob != NULL,
return -EINVAL);
5628 if (value != NULL) {
5632 if (lpc >= 0 && transform == FALSE) {
5635 }
else if (lpc < 0) {
5641 if (match >= max_stable_schemas) {
5648 while(lpc <= max_stable_schemas) {
5649 gboolean valid = TRUE;
5651 crm_debug(
"Testing '%s' validation (%d of %d)",
5652 known_schemas[lpc].name ? known_schemas[lpc].name :
"<unset>",
5653 lpc, max_stable_schemas);
5654 valid = validate_with(xml, lpc, to_logs);
5659 crm_trace(
"%s validation failed", known_schemas[lpc].name ? known_schemas[lpc].name :
"<unset>");
5662 if (valid && transform) {
5663 xmlNode *upgrade = NULL;
5664 int next = known_schemas[lpc].after_transform;
5667 crm_trace(
"Stopping at %s", known_schemas[lpc].name);
5670 }
else if (max > 0 && lpc == max) {
5671 crm_trace(
"Upgrade limit reached at %s (lpc=%d, next=%d, max=%d)",
5672 known_schemas[lpc].name, lpc, next, max);
5675 }
else if (max > 0 && next > max) {
5676 crm_debug(
"Upgrade limit reached at %s (lpc=%d, next=%d, max=%d)",
5677 known_schemas[lpc].name, lpc, next, max);
5680 }
else if (known_schemas[lpc].transform == NULL) {
5681 crm_debug(
"%s-style configuration is also valid for %s",
5682 known_schemas[lpc].name, known_schemas[next].name);
5684 if (validate_with(xml, next, to_logs)) {
5685 crm_debug(
"Configuration valid for schema: %s", known_schemas[next].name);
5691 crm_info(
"Configuration not valid for schema: %s", known_schemas[next].name);
5695 crm_debug(
"Upgrading %s-style configuration to %s with %s",
5696 known_schemas[lpc].name, known_schemas[next].name,
5697 known_schemas[lpc].transform ? known_schemas[lpc].transform :
"no-op");
5700 upgrade = apply_transformation(xml, known_schemas[lpc].transform);
5702 if (upgrade == NULL) {
5703 crm_err(
"Transformation %s failed", known_schemas[lpc].transform);
5706 }
else if (validate_with(upgrade, next, to_logs)) {
5707 crm_info(
"Transformation %s successful", known_schemas[lpc].transform);
5715 crm_err(
"Transformation %s did not produce a valid configuration",
5716 known_schemas[lpc].transform);
5725 if (*best > match) {
5726 crm_info(
"%s the configuration from %s to %s",
5727 transform?
"Transformed":
"Upgraded",
5728 value ? value :
"<none>", known_schemas[*best].name);
5744 int min_version = xml_minimum_schema_index();
5746 if (version < min_version) {
5747 xmlNode *converted = NULL;
5753 if (version < min_version) {
5755 crm_config_err(
"Your current configuration could only be upgraded to %s... "
5756 "the minimum requirement is %s.\n",
crm_str(value),
5759 fprintf(stderr,
"Your current configuration could only be upgraded to %s... "
5760 "the minimum requirement is %s.\n",
5772 if (version < xml_latest_schema_index()) {
5774 "which is acceptable but not the most recent",
5777 }
else if (to_logs) {
5778 crm_info(
"Your configuration was internally updated to the latest version (%s)",
5786 " It is highly encouraged and prevents many common cluster issues.");
5789 fprintf(stderr,
"Configuration validation is currently disabled."
5790 " It is highly encouraged and prevents many common cluster issues.\n");
5804 const char *tag = NULL;
5805 const char *ref = NULL;
5806 xmlNode *result = input;
5807 char *xpath_string = NULL;
5809 if (result == NULL) {
5812 }
else if (top == NULL) {
5816 tag = crm_element_name(result);
5820 int xpath_max = 512, offset = 0;
5822 xpath_string = calloc(1, xpath_max);
5824 offset += snprintf(xpath_string + offset, xpath_max - offset,
"//%s[@id='%s']", tag, ref);
5828 if (result == NULL) {
5829 char *nodePath = (
char *)xmlGetNodePath(top);
5831 crm_err(
"No match for %s found in %s: Invalid configuration", xpath_string,
5844 xmlAttr *attr = NULL;
5847 crm_err(
"Couldn't find %s in NULL", name ? name :
"<null>");
5851 }
else if (name == NULL) {
5852 crm_err(
"Couldn't find NULL in %s", crm_element_name(data));
5856 attr = xmlHasProp(data, (
const xmlChar *)name);
5857 if (attr == NULL || attr->children == NULL) {
5860 return (
const char *)attr->children->content;
#define CRM_CHECK(expr, failure_action)
gboolean daemon_option_enabled(const char *daemon, const char *option)
#define XML_ATTR_UPDATE_ORIG
void patchset_process_digest(xmlNode *patch, xmlNode *source, xmlNode *target, bool with_digest)
#define crm_notice(fmt, args...)
#define XML_ATTR_UPDATE_CLIENT
xmlNode * diff_xml_object(xmlNode *old, xmlNode *new, gboolean suppress)
gboolean safe_str_neq(const char *a, const char *b)
char * crm_generate_uuid(void)
int add_xml_object(xmlNode *parent, xmlNode *target, xmlNode *update, gboolean as_diff)
void log_data_element(int log_level, const char *file, const char *function, int line, const char *prefix, xmlNode *data, int depth, int options)
#define XML_ATTR_NUMUPDATES
struct xml_acl_s xml_acl_t
const char * crm_xml_add(xmlNode *node, const char *name, const char *value)
bool xml_acl_enabled(xmlNode *xml)
void xml_track_changes(xmlNode *xml, const char *user, xmlNode *acl_source, bool enforce_acls)
const char * __xml_acl_to_text(enum xml_private_flags flags)
#define crm_config_err(fmt...)
#define pcmk_err_old_data
#define XML_ATTR_UPDATE_USER
int char2score(const char *score)
int write_xml_fd(xmlNode *xml_node, const char *filename, int fd, gboolean compress)
void fix_plus_plus_recursive(xmlNode *target)
#define buffer_print(buffer, max, offset, fmt, args...)
#define XML_ACL_TAG_WRITE
#define XML_NVPAIR_ATTR_NAME
void purge_diff_markers(xmlNode *a_node)
xmlNode * stdin2xml(void)
void xml_acl_disable(xmlNode *xml)
int get_attr_name(const char *input, size_t offset, size_t max)
#define CRM_DTD_DIRECTORY
void g_hash_destroy_str(gpointer data)
#define CRM_LOG_ASSERT(expr)
#define do_crm_log_alias(level, file, function, line, fmt, args...)
Log a message as if it came from a different code location.
int xml_apply_patchset(xmlNode *xml, xmlNode *patchset, bool check_version)
#define clear_bit(word, bit)
unsigned int crm_trace_nonlog
#define XML_CIB_TAG_NVPAIR
char * strerror(int errnum)
void hash2field(gpointer key, gpointer value, gpointer user_data)
xmlNode * first_named_child(xmlNode *parent, const char *name)
xmlNode * get_xpath_object(const char *xpath, xmlNode *xml_obj, int error_level)
char * xml_get_path(xmlNode *xml)
char * crm_meta_name(const char *field)
gboolean validate_xml_verbose(xmlNode *xml_blob)
#define XML_ATTR_GENERATION
const char * crm_element_value_const(const xmlNode *data, const char *name)
xmlNode * filename2xml(const char *filename)
int find_xml_children(xmlNode **children, xmlNode *root, const char *tag, const char *field, const char *value, gboolean search_matches)
void expand_plus_plus(xmlNode *target, const char *name, const char *value)
#define XML_ACL_ATTR_REFv1
#define XML_ACL_ATTR_KIND
#define pcmk_err_diff_failed
gboolean validate_xml(xmlNode *xml_blob, const char *validation, gboolean to_logs)
#define pcmk_err_diff_resync
#define crm_warn(fmt, args...)
#define set_bit(word, bit)
xmlNode * copy_xml(xmlNode *src)
bool pcmk_acl_required(const char *user)
void diff_filter_context(int context, int upper_bound, int lower_bound, xmlNode *xml_node, xmlNode *parent)
#define crm_debug(fmt, args...)
gboolean add_message_xml(xmlNode *msg, const char *field, xmlNode *xml)
xmlNode * expand_idref(xmlNode *input, xmlNode *top)
xmlNode * create_xml_node(xmlNode *parent, const char *name)
#define XML_ACL_ATTR_XPATH
void xml_log_patchset(uint8_t log_level, const char *function, xmlNode *patchset)
#define pcmk_err_schema_validation
#define XML_ACL_TAG_PERMISSION
void free_xml(xmlNode *child)
#define crm_trace(fmt, args...)
#define crm_log_xml_explicit(xml, text)
#define XML_PRIVATE_MAGIC
const char * get_schema_name(int version)
#define crm_log_xml_debug(xml, text)
void save_xml_to_file(xmlNode *xml, const char *desc, const char *filename)
struct name_value_s name_value_t
bool xml_acl_denied(xmlNode *xml)
#define XML_ACL_TAG_USERv1
void hash2smartfield(gpointer key, gpointer value, gpointer user_data)
Wrappers for and extensions to libxml2.
void crm_xml_dump(xmlNode *data, int options, char **buffer, int *offset, int *max, int depth)
#define crm_log_xml_warn(xml, text)
#define XML_ATTR_VALIDATION
#define XML_ACL_ATTR_ATTRIBUTE
#define XML_DIFF_POSITION
#define XML_TAG_RESOURCE_REF
void crm_xml_cleanup(void)
xmlNode * add_node_copy(xmlNode *parent, xmlNode *src_node)
int crm_element_value_int(xmlNode *data, const char *name, int *dest)
xmlDoc * getDocPtr(xmlNode *node)
char * dump_xml_formatted(xmlNode *an_xml_node)
void xml_calculate_changes(xmlNode *old, xmlNode *new)
const char * crm_xml_add_last_written(xmlNode *xml_node)
xmlNode * string2xml(const char *input)
xmlNode * xml_create_patchset(int format, xmlNode *source, xmlNode *target, bool *config_changed, bool manage_version)
void xml_log_changes(uint8_t log_level, const char *function, xmlNode *xml)
#define pcmk_err_transform_failed
void crm_buffer_add_char(char **buffer, int *offset, int *max, char c)
const char * crm_xml_add_int(xmlNode *node, const char *name, int value)
int crm_element_value_const_int(const xmlNode *data, const char *name, int *dest)
#define XML_ACL_ATTR_TAGv1
char * dump_xml_formatted_with_text(xmlNode *an_xml_node)
gboolean crm_is_callsite_active(struct qb_log_callsite *cs, uint8_t level, uint32_t tags)
#define crm_config_warn(fmt...)
xmlNode * get_message_xml(xmlNode *msg, const char *field)
char * dump_xml_unformatted(xmlNode *an_xml_node)
int write_xml_file(xmlNode *xml_node, const char *filename, gboolean compress)
void copy_in_properties(xmlNode *target, xmlNode *src)
#define crm_log_xml_err(xml, text)
char * crm_element_value_copy(xmlNode *data, const char *name)
int update_validation(xmlNode **xml_blob, int *best, int max, gboolean transform, gboolean to_logs)
#define crm_perror(level, fmt, args...)
Log a system error message.
void strip_text_nodes(xmlNode *xml)
gboolean xml_has_children(const xmlNode *xml_root)
#define crm_err(fmt, args...)
xmlXPathObjectPtr xpath_search(xmlNode *xml_top, const char *path)
#define XML_CIB_ATTR_WRITTEN
#define XML_ACL_TAG_ROLE_REFv1
int get_attr_value(const char *input, size_t offset, size_t max)
const char * crm_xml_replace(xmlNode *node, const char *name, const char *value)
xmlNode * getXpathResult(xmlXPathObjectPtr xpathObj, int index)
xmlNode * find_xml_node(xmlNode *root, const char *search_path, gboolean must_find)
char * calculate_xml_versioned_digest(xmlNode *input, gboolean sort, gboolean do_filter, const char *version)
Calculate and return digest of XML tree.
void xml_accept_changes(xmlNode *xml)
int compare_version(const char *version1, const char *version2)
#define crm_log_xml_info(xml, text)
#define XML_ATTR_GENERATION_ADMIN
#define XML_NVPAIR_ATTR_VALUE
void hash2metafield(gpointer key, gpointer value, gpointer user_data)
#define XML_ATTR_CRM_VERSION
void xml_log(int priority, const char *fmt,...) G_GNUC_PRINTF(2
bool xml_acl_filtered_copy(const char *user, xmlNode *acl_source, xmlNode *xml, xmlNode **result)
char * crm_xml_escape(const char *text)
gboolean cli_config_update(xmlNode **xml, int *best_version, gboolean to_logs)
gboolean update_xml_child(xmlNode *child, xmlNode *to_update)
int get_tag_name(const char *input, size_t offset, size_t max)
xmlNode * subtract_xml_object(xmlNode *parent, xmlNode *left, xmlNode *right, gboolean full, gboolean *changed, const char *marker)
#define XML_CIB_TAG_OBJ_REF
xmlNode * sorted_xml(xmlNode *input, xmlNode *parent, gboolean recursive)
#define crm_log_xml_trace(xml, text)
GHashTable * xml2list(xmlNode *parent)
bool xml_tracking_changes(xmlNode *xml)
gboolean crm_is_true(const char *s)
#define XML_ACL_TAG_ROLE_REF
const char * xml_latest_schema(void)
void hash2nvpair(gpointer key, gpointer value, gpointer user_data)
gboolean apply_xml_diff(xmlNode *old, xmlNode *diff, xmlNode **new)
#define XML_CIB_TAG_CONFIGURATION
char * crm_itoa(int an_int)
#define safe_str_eq(a, b)
int add_node_nocopy(xmlNode *parent, const char *name, xmlNode *child)
int in_upper_context(int depth, int context, xmlNode *xml_node)
char * crm_strdup_printf(char const *format,...) __attribute__((__format__(__printf__
void crm_abort(const char *file, const char *function, int line, const char *condition, gboolean do_core, gboolean do_fork)
struct xml_private_s xml_private_t
gboolean replace_xml_child(xmlNode *parent, xmlNode *child, xmlNode *update, gboolean delete_only)
const char * crm_element_value(xmlNode *data, const char *name)
void freeXpathObject(xmlXPathObjectPtr xpathObj)
void xml_remove_prop(xmlNode *obj, const char *name)
long long crm_int_helper(const char *text, char **end_text)
xmlNode * find_entity(xmlNode *parent, const char *node_name, const char *id)
#define crm_info(fmt, args...)
int get_schema_version(const char *name)
gboolean can_prune_leaf(xmlNode *xml_node)
bool xml_patch_versions(xmlNode *patchset, int add[3], int del[3])
enum crm_ais_msg_types type
bool xml_document_dirty(xmlNode *xml)