21 #include <sys/param.h> 23 #include <sys/types.h> 41 # include <libxml/parser.h> 42 # include <libxml/tree.h> 45 #define XML_BUFFER_SIZE 4096 46 #define XML_PARSER_DEBUG 0 49 __get_prefix(
const char *prefix, xmlNode *xml,
char *buffer,
int offset);
78 typedef struct xml_private_s
87 typedef struct xml_acl_s {
92 typedef struct xml_deleted_obj_s {
99 static filter_t filter[] = {
108 static xmlNode *subtract_xml_comment(xmlNode * parent, xmlNode * left, xmlNode * right, gboolean * changed);
109 static xmlNode *find_xml_comment(xmlNode * root, xmlNode * search_comment, gboolean exact);
110 static int add_xml_comment(xmlNode * parent, xmlNode * target, xmlNode * update);
111 static bool __xml_acl_check(xmlNode *xml,
const char *name,
enum xml_private_flags mode);
114 #define CHUNK_SIZE 1024 115 static inline bool TRACKING_CHANGES(xmlNode *xml)
117 if(xml == NULL || xml->doc == NULL || xml->doc->_private == NULL) {
125 static inline bool TRACKING_CHANGES_LAZY(xmlNode *xml)
127 if(xml == NULL || xml->doc == NULL || xml->doc->_private == NULL) {
137 #define buffer_print(buffer, max, offset, fmt, args...) do { \ 140 rc = snprintf((buffer) + (offset), (max) - (offset), fmt, ##args); \ 142 if(buffer && rc < 0) { \ 143 crm_perror(LOG_ERR, "snprintf failed at offset %d", offset); \ 144 (buffer)[(offset)] = 0; \ 146 } else if(rc >= ((max) - (offset))) { \ 148 (max) = QB_MAX(CHUNK_SIZE, (max) * 2); \ 149 tmp = realloc_safe((buffer), (max)); \ 159 insert_prefix(
int options,
char **buffer,
int *offset,
int *max,
int depth)
162 size_t spaces = 2 * depth;
164 if ((*buffer) == NULL || spaces >= ((*max) - (*offset))) {
166 (*buffer) = realloc_safe((*buffer), (*max));
168 memset((*buffer) + (*offset),
' ', spaces);
174 set_parent_flag(xmlNode *xml,
long flag)
177 for(; xml; xml = xml->parent) {
190 set_doc_flag(xmlNode *xml,
long flag)
193 if(xml && xml->doc && xml->doc->_private){
203 __xml_node_dirty(xmlNode *xml)
210 __xml_node_clean(xmlNode *xml)
212 xmlNode *cIter = NULL;
219 for (cIter = __xml_first_child(xml); cIter != NULL; cIter = __xml_next(cIter)) {
220 __xml_node_clean(cIter);
225 crm_node_created(xmlNode *xml)
227 xmlNode *cIter = NULL;
230 if(p && TRACKING_CHANGES(xml)) {
233 __xml_node_dirty(xml);
236 for (cIter = __xml_first_child(xml); cIter != NULL; cIter = __xml_next(cIter)) {
237 crm_node_created(cIter);
243 crm_attr_dirty(xmlAttr *a)
245 xmlNode *parent = a->parent;
254 __xml_node_dirty(parent);
257 int get_tag_name(
const char *input,
size_t offset,
size_t max);
258 int get_attr_name(
const char *input,
size_t offset,
size_t max);
263 xmlNode * xml_node, xmlNode * parent);
265 int add_xml_object(xmlNode * parent, xmlNode * target, xmlNode * update, gboolean as_diff);
267 static inline const char *
268 crm_attr_value(xmlAttr * attr)
270 if (attr == NULL || attr->children == NULL) {
273 return (
const char *)attr->children->content;
276 static inline xmlAttr *
277 crm_first_attr(xmlNode * xml)
282 return xml->properties;
285 #define XML_PRIVATE_MAGIC (long) 0x81726354 288 __xml_acl_free(
void *
data)
299 __xml_deleted_obj_free(
void *
data)
304 free(deleted_obj->path);
319 g_list_free_full(p->acls, __xml_acl_free);
323 if(p->deleted_objs) {
324 g_list_free_full(p->deleted_objs, __xml_deleted_obj_free);
325 p->deleted_objs = NULL;
334 __xml_private_clean(p);
339 pcmkDeregisterNode(xmlNodePtr node)
341 __xml_private_free(node->_private);
345 pcmkRegisterNode(xmlNodePtr node)
350 case XML_ELEMENT_NODE:
351 case XML_DOCUMENT_NODE:
352 case XML_ATTRIBUTE_NODE:
353 case XML_COMMENT_NODE:
362 case XML_CDATA_SECTION_NODE:
366 crm_trace(
"Ignoring %p %d", node, node->type);
371 if(p && TRACKING_CHANGES(node)) {
376 __xml_node_dirty(node);
399 if(target == NULL || target->doc == NULL || target->doc->_private == NULL){
405 }
else if (tag == NULL && ref == NULL && xpath == NULL) {
410 p = target->doc->_private;
417 acl->xpath = strdup(xpath);
418 crm_trace(
"Using xpath: %s", acl->xpath);
425 offset += snprintf(buffer + offset,
XML_BUFFER_SIZE - offset,
"//%s", tag);
435 offset += snprintf(buffer + offset,
XML_BUFFER_SIZE - offset,
"@id='%s'", ref);
439 offset += snprintf(buffer + offset,
XML_BUFFER_SIZE - offset,
" and ");
443 offset += snprintf(buffer + offset,
XML_BUFFER_SIZE - offset,
"@%s", attr);
451 acl->xpath = strdup(buffer);
452 crm_trace(
"Built xpath: %s", acl->xpath);
455 p->acls = g_list_append(p->acls, acl);
461 __xml_acl_parse_entry(xmlNode * acl_top, xmlNode * acl_entry, xmlNode *target)
463 xmlNode *child = NULL;
465 for (child = __xml_first_child(acl_entry); child; child = __xml_next(child)) {
466 const char *tag = crm_element_name(child);
473 crm_trace(
"Processing %s %p", tag, child);
482 xmlNode *role = NULL;
484 for (role = __xml_first_child(acl_top); role; role = __xml_next(role)) {
488 if (role_id && strcmp(ref_role, role_id) == 0) {
489 crm_debug(
"Unpacking referenced role: %s", role_id);
490 __xml_acl_parse_entry(acl_top, role, target);
507 crm_warn(
"Unknown ACL entry: %s/%s", tag, kind);
553 __xml_acl_apply(xmlNode *xml)
557 xmlXPathObjectPtr xpathObj = NULL;
560 p = xml->doc->_private;
561 crm_trace(
"Not applying ACLs for %s", p->user);
565 p = xml->doc->_private;
566 for(aIter = p->acls; aIter != NULL; aIter = aIter->next) {
567 int max = 0, lpc = 0;
571 max = numXpathResults(xpathObj);
573 for(lpc = 0; lpc < max; lpc++) {
578 crm_trace(
"Applying %x to %s for %s", acl->mode, path, acl->xpath);
580 #ifdef SUSE_ACL_COMPAT 581 if(is_not_set(p->flags, acl->mode)) {
585 crm_config_warn(
"Configuration element %s is matched by multiple ACL rules, only the first applies ('%s' wins over '%s')",
593 p->flags |= acl->mode;
596 crm_trace(
"Now enforcing ACL: %s (%d matches)", acl->xpath, max);
603 p = xml->doc->_private;
604 crm_info(
"Enforcing default ACL for %s to %s", p->user, crm_element_name(xml));
610 __xml_acl_unpack(xmlNode *source, xmlNode *target,
const char *user)
615 if(target == NULL || target->doc == NULL || target->doc->_private == NULL) {
619 p = target->doc->_private;
621 crm_trace(
"no acls needed for '%s'", user);
623 }
else if(p->acls == NULL) {
627 p->user = strdup(user);
630 xmlNode *child = NULL;
632 for (child = __xml_first_child(acls); child; child = __xml_next(child)) {
633 const char *tag = crm_element_name(child);
638 if(
id && strcmp(
id, user) == 0) {
640 __xml_acl_parse_entry(acls, child, target);
655 }
else if(is_set(allowed, requested)) {
674 __xml_purge_attributes(xmlNode *xml)
676 xmlNode *child = NULL;
677 xmlAttr *xIter = NULL;
678 bool readable_children = FALSE;
682 crm_trace(
"%s[@id=%s] is readable", crm_element_name(xml),
ID(xml));
686 xIter = crm_first_attr(xml);
687 while(xIter != NULL) {
688 xmlAttr *tmp = xIter;
689 const char *prop_name = (
const char *)xIter->name;
696 xmlUnsetProp(xml, tmp->name);
699 child = __xml_first_child(xml);
700 while ( child != NULL ) {
701 xmlNode *tmp = child;
703 child = __xml_next(child);
704 readable_children |= __xml_purge_attributes(tmp);
707 if(readable_children == FALSE) {
710 return readable_children;
717 xmlNode *target = NULL;
723 crm_trace(
"no acls needed for '%s'", user);
727 crm_trace(
"filtering copy of %p for '%s'", xml, user);
733 __xml_acl_unpack(acl_source, target, user);
735 __xml_acl_apply(target);
737 doc = target->doc->_private;
738 for(aIter = doc->acls; aIter != NULL && target; aIter = aIter->next) {
745 }
else if(acl->xpath) {
747 xmlXPathObjectPtr xpathObj =
xpath_search(target, acl->xpath);
749 max = numXpathResults(xpathObj);
750 for(lpc = 0; lpc < max; lpc++) {
753 crm_trace(
"Purging attributes from %s", acl->xpath);
754 if(__xml_purge_attributes(match) == FALSE && match == target) {
755 crm_trace(
"No access to the entire document for %s", user);
760 crm_trace(
"Enforced ACL %s (%d matches)", acl->xpath, max);
765 p = target->_private;
766 if(is_set(p->flags,
xpf_acl_deny) && __xml_purge_attributes(target) == FALSE) {
767 crm_trace(
"No access to the entire document for %s", user);
772 g_list_free_full(doc->acls, __xml_acl_free);
776 crm_trace(
"Ordinary user '%s' cannot access the CIB without any defined ACLs", doc->user);
789 __xml_acl_post_process(xmlNode * xml)
791 xmlNode *cIter = __xml_first_child(xml);
795 xmlAttr *xIter = NULL;
802 for (xIter = crm_first_attr(xml); xIter != NULL; xIter = xIter->next) {
803 const char *prop_name = (
const char *)xIter->name;
810 crm_trace(
"Creation of %s=%s is allowed", crm_element_name(xml),
ID(xml));
814 crm_trace(
"Cannot add new node %s at %s", crm_element_name(xml), path);
816 if(xml != xmlDocGetRootElement(xml->doc)) {
827 while (cIter != NULL) {
828 xmlNode *child = cIter;
829 cIter = __xml_next(cIter);
830 __xml_acl_post_process(child);
837 if(xml && xml->doc && xml->doc->_private){
852 __xml_acl_apply(xml);
853 __xml_acl_post_process(xml);
861 if(xml && xml->doc && xml->doc->_private){
873 crm_trace(
"Tracking changes%s to %p", enforce_acls?
" with ACLs":
"", xml);
876 if(acl_source == NULL) {
880 __xml_acl_unpack(acl_source, xml, user);
881 __xml_acl_apply(xml);
898 if(xml != NULL && xml->doc && xml->doc->_private) {
954 static int __xml_offset(xmlNode *xml)
957 xmlNode *cIter = NULL;
959 for(cIter = xml; cIter->prev; cIter = cIter->prev) {
962 if(is_not_set(p->flags,
xpf_skip)) {
970 static int __xml_offset_no_deletions(xmlNode *xml)
973 xmlNode *cIter = NULL;
975 for(cIter = xml; cIter->prev; cIter = cIter->prev) {
987 __xml_build_changes(xmlNode * xml, xmlNode *patchset)
989 xmlNode *cIter = NULL;
990 xmlAttr *pIter = NULL;
991 xmlNode *change = NULL;
998 if(__get_prefix(NULL, xml->parent, buffer, offset) > 0) {
999 int position = __xml_offset_no_deletions(xml);
1012 for (pIter = crm_first_attr(xml); pIter != NULL; pIter = pIter->next) {
1013 xmlNode *attr = NULL;
1015 p = pIter->_private;
1020 if(change == NULL) {
1024 if(__get_prefix(NULL, xml, buffer, offset) > 0) {
1049 xmlNode *result = NULL;
1054 for (pIter = crm_first_attr(xml); pIter != NULL; pIter = pIter->next) {
1057 p = pIter->_private;
1059 crm_xml_add(result, (
const char *)pIter->name, value);
1064 for (cIter = __xml_first_child(xml); cIter != NULL; cIter = __xml_next(cIter)) {
1065 __xml_build_changes(cIter, patchset);
1069 if(patchset && is_set(p->flags,
xpf_moved)) {
1073 crm_trace(
"%s.%s moved to position %d", xml->name,
ID(xml), __xml_offset(xml));
1074 if(__get_prefix(NULL, xml, buffer, offset) > 0) {
1085 __xml_accept_changes(xmlNode * xml)
1087 xmlNode *cIter = NULL;
1088 xmlAttr *pIter = NULL;
1092 pIter = crm_first_attr(xml);
1094 while (pIter != NULL) {
1095 const xmlChar *name = pIter->name;
1097 p = pIter->_private;
1098 pIter = pIter->next;
1108 for (cIter = __xml_first_child(xml); cIter != NULL; cIter = __xml_next(cIter)) {
1109 __xml_accept_changes(cIter);
1114 is_config_change(xmlNode *xml)
1121 p = config->_private;
1127 if(xml->doc && xml->doc->_private) {
1128 p = xml->doc->_private;
1129 for(gIter = p->deleted_objs; gIter; gIter = gIter->next) {
1142 xml_repair_v1_diff(xmlNode * last, xmlNode * next, xmlNode * local_diff, gboolean changed)
1145 xmlNode *cib = NULL;
1146 xmlNode *diff_child = NULL;
1148 const char *tag = NULL;
1150 const char *vfields[] = {
1156 if (local_diff == NULL) {
1161 tag =
"diff-removed";
1163 if (diff_child == NULL) {
1173 for(lpc = 0; last && lpc <
DIMOF(vfields); lpc++){
1177 if(changed || lpc == 2) {
1184 if (diff_child == NULL) {
1194 for(lpc = 0; next && lpc <
DIMOF(vfields); lpc++){
1201 xmlAttrPtr xIter = NULL;
1203 for (xIter = next->properties; xIter; xIter = xIter->next) {
1204 const char *p_name = (
const char *)xIter->name;
1207 xmlSetProp(cib, (
const xmlChar *)p_name, (
const xmlChar *)p_value);
1215 xml_create_patchset_v1(xmlNode *source, xmlNode *target,
bool config,
bool suppress)
1221 xml_repair_v1_diff(source, target, patchset, config);
1228 xml_create_patchset_v2(xmlNode *source, xmlNode *target)
1236 xmlNode *patchset = NULL;
1237 const char *vfields[] = {
1249 doc = target->doc->_private;
1257 for(lpc = 0; lpc <
DIMOF(vfields); lpc++){
1267 for(lpc = 0; lpc <
DIMOF(vfields); lpc++){
1276 for(gIter = doc->deleted_objs; gIter; gIter = gIter->next) {
1282 if (deleted_obj->position >= 0) {
1287 __xml_build_changes(target, patchset);
1291 static gboolean patch_legacy_mode(
void)
1293 static gboolean init = TRUE;
1294 static gboolean legacy = FALSE;
1310 bool config = FALSE;
1311 xmlNode *patch = NULL;
1320 config = is_config_change(target);
1321 if(config_changed) {
1322 *config_changed = config;
1325 if(manage_version && config) {
1332 }
else if(manage_version) {
1339 if(patch_legacy_mode()) {
1348 crm_trace(
"Using patch format %d for version: %s", format, version);
1353 patch = xml_create_patchset_v1(source, target, config, FALSE);
1356 patch = xml_create_patchset_v2(source, target);
1359 crm_err(
"Unknown patch format: %d", format);
1371 char *digest = NULL;
1373 if (patch == NULL || source == NULL || target == NULL) {
1382 if (format > 1 && with_digest == FALSE) {
1396 __xml_log_element(
int log_level,
const char *file,
const char *
function,
int line,
1397 const char *prefix, xmlNode *
data,
int depth,
int options);
1403 xmlNode *child = NULL;
1404 xmlNode *added = NULL;
1405 xmlNode *removed = NULL;
1406 gboolean is_first = TRUE;
1408 int add[] = { 0, 0, 0 };
1409 int del[] = { 0, 0, 0 };
1411 const char *fmt = NULL;
1412 const char *digest = NULL;
1415 static struct qb_log_callsite *patchset_cs = NULL;
1417 if (patchset_cs == NULL) {
1418 patchset_cs = qb_log_callsite_get(
function, __FILE__,
"xml-patchset", log_level, __LINE__, 0);
1421 if (patchset == NULL) {
1425 }
else if (log_level == 0) {
1435 if (add[2] != del[2] || add[1] != del[1] || add[0] != del[0]) {
1437 "Diff: --- %d.%d.%d %s", del[0], del[1], del[2], fmt);
1439 "Diff: +++ %d.%d.%d %s", add[0], add[1], add[2], digest);
1441 }
else if (patchset != NULL && (add[0] || add[1] || add[2])) {
1443 "%s: Local-only Change: %d.%d.%d",
function ?
function :
"",
1444 add[0], add[1], add[2]);
1449 xmlNode *change = NULL;
1451 for (change = __xml_first_child(patchset); change != NULL; change = __xml_next(change)) {
1456 }
else if(strcmp(op,
"create") == 0) {
1457 int lpc = 0, max = 0;
1460 max = strlen(prefix);
1461 __xml_log_element(log_level, __FILE__,
function, __LINE__, prefix, change->children,
1464 for(lpc = 2; lpc < max; lpc++) {
1468 __xml_log_element(log_level, __FILE__,
function, __LINE__, prefix, change->children,
1472 }
else if(strcmp(op,
"move") == 0) {
1475 }
else if(strcmp(op,
"modify") == 0) {
1483 buffer_unset[0] = 0;
1484 for (child = __xml_first_child(clist); child != NULL; child = __xml_next(child)) {
1489 }
else if(strcmp(op,
"set") == 0) {
1495 o_set += snprintf(buffer_set + o_set,
XML_BUFFER_SIZE - o_set,
"@%s=%s", name, value);
1497 }
else if(strcmp(op,
"unset") == 0) {
1499 o_unset += snprintf(buffer_unset + o_unset,
XML_BUFFER_SIZE - o_unset,
", ");
1501 o_unset += snprintf(buffer_unset + o_unset,
XML_BUFFER_SIZE - o_unset,
"@%s", name);
1505 do_crm_log_alias(log_level, __FILE__,
function, __LINE__,
"+ %s: %s", xpath, buffer_set);
1508 do_crm_log_alias(log_level, __FILE__,
function, __LINE__,
"-- %s: %s", xpath, buffer_unset);
1511 }
else if(strcmp(op,
"delete") == 0) {
1515 if (position >= 0) {
1516 do_crm_log_alias(log_level, __FILE__,
function, __LINE__,
"-- %s (%d)", xpath, position);
1526 if (log_level < LOG_DEBUG ||
function == NULL) {
1531 for (child = __xml_first_child(removed); child != NULL; child = __xml_next(child)) {
1543 for (child = __xml_first_child(added); child != NULL; child = __xml_next(child)) {
1563 doc = xml->doc->_private;
1568 for(gIter = doc->deleted_objs; gIter; gIter = gIter->next) {
1571 if (deleted_obj->position >= 0) {
1573 deleted_obj->path, deleted_obj->position);
1588 xmlNode *top = NULL;
1595 crm_trace(
"Accepting changes to %p", xml);
1596 doc = xml->doc->_private;
1597 top = xmlDocGetRootElement(xml->doc);
1599 __xml_private_clean(xml->doc->_private);
1607 __xml_accept_changes(top);
1611 find_element(xmlNode *haystack, xmlNode *needle, gboolean exact)
1614 return (needle->type == XML_COMMENT_NODE)?
1615 find_xml_comment(haystack, needle, exact)
1616 :
find_entity(haystack, crm_element_name(needle),
ID(needle));
1621 __subtract_xml_object(xmlNode * target, xmlNode * patch)
1623 xmlNode *patch_child = NULL;
1624 xmlNode *cIter = NULL;
1625 xmlAttrPtr xIter = NULL;
1628 const char *name = NULL;
1629 const char *value = NULL;
1631 if (target == NULL || patch == NULL) {
1635 if (target->type == XML_COMMENT_NODE) {
1638 subtract_xml_comment(target->parent, target, patch, &dummy);
1641 name = crm_element_name(target);
1649 if (value != NULL && strcmp(value,
"removed:top") == 0) {
1650 crm_trace(
"We are the root of the deletion: %s.id=%s", name,
id);
1656 for (xIter = crm_first_attr(patch); xIter != NULL; xIter = xIter->next) {
1657 const char *p_name = (
const char *)xIter->name;
1666 cIter = __xml_first_child(target);
1668 xmlNode *target_child = cIter;
1670 cIter = __xml_next(cIter);
1671 patch_child = find_element(patch, target_child, FALSE);
1672 __subtract_xml_object(target_child, patch_child);
1678 __add_xml_object(xmlNode * parent, xmlNode * target, xmlNode * patch)
1680 xmlNode *patch_child = NULL;
1681 xmlNode *target_child = NULL;
1682 xmlAttrPtr xIter = NULL;
1684 const char *
id = NULL;
1685 const char *name = NULL;
1686 const char *value = NULL;
1688 if (patch == NULL) {
1690 }
else if (parent == NULL && target == NULL) {
1698 && strcmp(value,
"added:top") == 0) {
1700 name = crm_element_name(patch);
1701 crm_trace(
"We are the root of the addition: %s.id=%s", name,
id);
1705 }
else if(target == NULL) {
1707 name = crm_element_name(patch);
1708 crm_err(
"Could not locate: %s.id=%s", name,
id);
1712 if (target->type == XML_COMMENT_NODE) {
1713 add_xml_comment(parent, target, patch);
1716 name = crm_element_name(target);
1721 for (xIter = crm_first_attr(patch); xIter != NULL; xIter = xIter->next) {
1722 const char *p_name = (
const char *)xIter->name;
1730 for (patch_child = __xml_first_child(patch); patch_child != NULL;
1731 patch_child = __xml_next(patch_child)) {
1733 target_child = find_element(target, patch_child, FALSE);
1734 __add_xml_object(target, target_child, patch_child);
1750 find_patch_xml_node(xmlNode *patchset,
int format,
bool added,
1751 xmlNode **patch_node)
1758 label = added?
"diff-added" :
"diff-removed";
1761 if (cib_node != NULL) {
1762 *patch_node = cib_node;
1766 label = added?
"target" :
"source";
1771 crm_warn(
"Unknown patch format: %d", format);
1782 xmlNode *tmp = NULL;
1784 const char *vfields[] = {
1794 if (!find_patch_xml_node(patchset, format, FALSE, &tmp)) {
1798 for(lpc = 0; lpc <
DIMOF(vfields); lpc++) {
1800 crm_trace(
"Got %d for del[%s]", del[lpc], vfields[lpc]);
1805 if (!find_patch_xml_node(patchset, format, TRUE, &tmp)) {
1809 for(lpc = 0; lpc <
DIMOF(vfields); lpc++) {
1811 crm_trace(
"Got %d for add[%s]", add[lpc], vfields[lpc]);
1819 xml_patch_version_check(xmlNode *xml, xmlNode *patchset,
int format)
1822 bool changed = FALSE;
1824 int this[] = { 0, 0, 0 };
1825 int add[] = { 0, 0, 0 };
1826 int del[] = { 0, 0, 0 };
1828 const char *vfields[] = {
1834 for(lpc = 0; lpc <
DIMOF(vfields); lpc++) {
1836 crm_trace(
"Got %d for this[%s]",
this[lpc], vfields[lpc]);
1837 if (
this[lpc] < 0) {
1845 add[2] =
this[2] + 1;
1846 for(lpc = 0; lpc <
DIMOF(vfields); lpc++) {
1847 del[lpc] =
this[lpc];
1852 for(lpc = 0; lpc <
DIMOF(vfields); lpc++) {
1853 if(
this[lpc] < del[lpc]) {
1854 crm_debug(
"Current %s is too low (%d.%d.%d < %d.%d.%d --> %d.%d.%d)", vfields[lpc],
1855 this[0],
this[1],
this[2], del[0], del[1], del[2], add[0], add[1], add[2]);
1858 }
else if(
this[lpc] > del[lpc]) {
1859 crm_info(
"Current %s is too high (%d.%d.%d > %d.%d.%d --> %d.%d.%d) %p", vfields[lpc],
1860 this[0],
this[1],
this[2], del[0], del[1], del[2], add[0], add[1], add[2], patchset);
1866 for(lpc = 0; lpc <
DIMOF(vfields); lpc++) {
1867 if(add[lpc] > del[lpc]) {
1872 if(changed == FALSE) {
1873 crm_notice(
"Versions did not change in patch %d.%d.%d", add[0], add[1], add[2]);
1877 crm_debug(
"Can apply patch %d.%d.%d to %d.%d.%d",
1878 add[0], add[1], add[2],
this[0],
this[1],
this[2]);
1883 xml_apply_patchset_v1(xmlNode *xml, xmlNode *patchset)
1886 int root_nodes_seen = 0;
1888 xmlNode *child_diff = NULL;
1889 xmlNode *added =
find_xml_node(patchset,
"diff-added", FALSE);
1890 xmlNode *removed =
find_xml_node(patchset,
"diff-removed", FALSE);
1894 for (child_diff = __xml_first_child(removed); child_diff != NULL;
1895 child_diff = __xml_next(child_diff)) {
1896 CRM_CHECK(root_nodes_seen == 0, rc = FALSE);
1897 if (root_nodes_seen == 0) {
1898 __subtract_xml_object(xml, child_diff);
1903 if (root_nodes_seen > 1) {
1904 crm_err(
"(-) Diffs cannot contain more than one change set... saw %d", root_nodes_seen);
1908 root_nodes_seen = 0;
1911 xmlNode *child_diff = NULL;
1913 for (child_diff = __xml_first_child(added); child_diff != NULL;
1914 child_diff = __xml_next(child_diff)) {
1915 CRM_CHECK(root_nodes_seen == 0, rc = FALSE);
1916 if (root_nodes_seen == 0) {
1917 __add_xml_object(NULL, xml, child_diff);
1923 if (root_nodes_seen > 1) {
1924 crm_err(
"(+) Diffs cannot contain more than one change set... saw %d", root_nodes_seen);
1935 __first_xml_child_match(xmlNode *parent,
const char *name,
const char *
id,
int position)
1937 xmlNode *cIter = NULL;
1939 for (cIter = __xml_first_child(parent); cIter != NULL; cIter = __xml_next(cIter)) {
1940 if(strcmp((
const char *)cIter->name, name) != 0) {
1943 const char *cid =
ID(cIter);
1944 if(cid == NULL || strcmp(cid,
id) != 0) {
1950 if (cIter->type == XML_COMMENT_NODE
1952 && __xml_offset(cIter) != position) {
1962 __xml_find_path(xmlNode *top,
const char *key,
int target_position)
1964 xmlNode *target = (xmlNode*)top->doc;
1968 char *current = strdup(key);
1973 rc = sscanf (current,
"/%[^/]%s", section, remainder);
1983 }
else if(tag && section) {
1984 int f = sscanf (section,
"%[^[][@id='%[^']", tag,
id);
1985 int current_position = -1;
1988 if (rc == 1 && target_position >= 0) {
1989 current_position = target_position;
1994 target = __first_xml_child_match(target, tag, NULL, current_position);
1997 target = __first_xml_child_match(target, tag,
id, current_position);
2005 if(rc == 1 || target == NULL) {
2010 char *tmp = current;
2011 current = remainder;
2018 char *path = (
char *)xmlGetNodePath(target);
2020 crm_trace(
"Found %s for %s", path, key);
2035 xml_apply_patchset_v2(xmlNode *xml, xmlNode *patchset)
2038 xmlNode *change = NULL;
2039 for (change = __xml_first_child(patchset); change != NULL; change = __xml_next(change)) {
2040 xmlNode *match = NULL;
2045 crm_trace(
"Processing %s %s", change->name, op);
2050 if(strcmp(op,
"delete") == 0) {
2056 match = __xml_find_path(xml, xpath, position);
2058 crm_trace(
"Performing %s on %s with %p", op, xpath, match);
2060 if(match == NULL && strcmp(op,
"delete") == 0) {
2061 crm_debug(
"No %s match for %s in %p", op, xpath, xml->doc);
2064 }
else if(match == NULL) {
2065 crm_err(
"No %s match for %s in %p", op, xpath, xml->doc);
2069 }
else if(strcmp(op,
"create") == 0) {
2071 xmlNode *child = NULL;
2072 xmlNode *match_child = NULL;
2074 match_child = match->children;
2077 while(match_child && position != __xml_offset(match_child)) {
2078 match_child = match_child->next;
2081 child = xmlDocCopyNode(change->children, match->doc, 1);
2083 crm_trace(
"Adding %s at position %d", child->name, position);
2084 xmlAddPrevSibling(match_child, child);
2086 }
else if(match->last) {
2087 crm_trace(
"Adding %s at position %d (end)", child->name, position);
2088 xmlAddNextSibling(match->last, child);
2091 crm_trace(
"Adding %s at position %d (first)", child->name, position);
2093 xmlAddChild(match, child);
2095 crm_node_created(child);
2097 }
else if(strcmp(op,
"move") == 0) {
2101 if(position != __xml_offset(match)) {
2102 xmlNode *match_child = NULL;
2105 if(p > __xml_offset(match)) {
2110 match_child = match->parent->children;
2112 while(match_child && p != __xml_offset(match_child)) {
2113 match_child = match_child->next;
2116 crm_trace(
"Moving %s to position %d (was %d, prev %p, %s %p)",
2117 match->name, position, __xml_offset(match), match->prev,
2118 match_child?
"next":
"last", match_child?match_child:match->parent->last);
2121 xmlAddPrevSibling(match_child, match);
2125 xmlAddNextSibling(match->parent->last, match);
2129 crm_trace(
"%s is already in position %d", match->name, position);
2132 if(position != __xml_offset(match)) {
2133 crm_err(
"Moved %s.%d to position %d instead of %d (%p)",
2134 match->name,
ID(match), __xml_offset(match), position, match->prev);
2138 }
else if(strcmp(op,
"delete") == 0) {
2141 }
else if(strcmp(op,
"modify") == 0) {
2142 xmlAttr *pIter = crm_first_attr(match);
2149 while(pIter != NULL) {
2150 const char *name = (
const char *)pIter->name;
2152 pIter = pIter->next;
2156 for (pIter = crm_first_attr(attrs); pIter != NULL; pIter = pIter->next) {
2157 const char *name = (
const char *)pIter->name;
2164 crm_err(
"Unknown operation: %s", op);
2175 xmlNode *old = NULL;
2178 if(patchset == NULL) {
2186 rc = xml_patch_version_check(xml, patchset, format);
2200 rc = xml_apply_patchset_v1(xml, patchset);
2203 rc = xml_apply_patchset_v2(xml, patchset);
2206 crm_err(
"Unknown patch format: %d", format);
2212 static struct qb_log_callsite *digest_cs = NULL;
2214 char *new_digest = NULL;
2217 if (digest_cs == NULL) {
2219 qb_log_callsite_get(__func__, __FILE__,
"diff-digest",
LOG_TRACE, __LINE__,
2225 crm_info(
"v%d digest mis-match: expected %s, calculated %s", format, digest, new_digest);
2228 if (digest_cs && digest_cs->targets) {
2234 crm_trace(
"%p %.6x", digest_cs, digest_cs ? digest_cs->targets : 0);
2238 crm_trace(
"v%d digest matched: expected %s, calculated %s", format, digest, new_digest);
2250 xmlNode *a_child = NULL;
2251 const char *name =
"NULL";
2254 name = crm_element_name(root);
2257 if (search_path == NULL) {
2258 crm_warn(
"Will never find <NULL>");
2262 for (a_child = __xml_first_child(root); a_child != NULL; a_child = __xml_next(a_child)) {
2263 if (strcmp((
const char *)a_child->name, search_path) == 0) {
2270 crm_warn(
"Could not find %s in %s.", search_path, name);
2271 }
else if (root != NULL) {
2272 crm_trace(
"Could not find %s in %s.", search_path, name);
2274 crm_trace(
"Could not find %s in <NULL>.", search_path);
2284 find_entity_by_attr_or_just_name(xmlNode *parent,
const char *node_name,
2285 const char *attr_n,
const char *attr_v)
2290 CRM_CHECK(attr_n == NULL || attr_v != NULL,
return NULL);
2292 for (child = __xml_first_child(parent); child != NULL; child = __xml_next(child)) {
2294 if (node_name == NULL || !strcmp((
const char *) child->name, node_name)) {
2304 attr_n ? attr_n :
"",
2306 attr_n ? attr_v :
"",
2307 crm_element_name(parent));
2315 return find_entity_by_attr_or_just_name(parent, node_name,
2323 crm_warn(
"No node to copy properties from");
2325 }
else if (target == NULL) {
2326 crm_err(
"No node to copy properties into");
2329 xmlAttrPtr pIter = NULL;
2331 for (pIter = crm_first_attr(src); pIter != NULL; pIter = pIter->next) {
2332 const char *p_name = (
const char *)pIter->name;
2333 const char *p_value = crm_attr_value(pIter);
2346 xmlNode *child = NULL;
2347 xmlAttrPtr pIter = NULL;
2349 for (pIter = crm_first_attr(target); pIter != NULL; pIter = pIter->next) {
2350 const char *p_name = (
const char *)pIter->name;
2351 const char *p_value = crm_attr_value(pIter);
2355 for (child = __xml_first_child(target); child != NULL; child = __xml_next(child)) {
2368 const char *old_value = NULL;
2370 if (value == NULL || name == NULL) {
2376 if (old_value == NULL) {
2378 goto set_unexpanded;
2380 }
else if (strstr(value, name) != value) {
2381 goto set_unexpanded;
2384 name_len = strlen(name);
2385 value_len = strlen(value);
2386 if (value_len < (name_len + 2)
2387 || value[name_len] !=
'+' || (value[name_len + 1] !=
'+' && value[name_len + 1] !=
'=')) {
2388 goto set_unexpanded;
2394 if (old_value != value) {
2398 if (value[name_len + 1] !=
'+') {
2399 const char *offset_s = value + (name_len + 2);
2403 int_value += offset;
2413 if (old_value == value) {
2430 doc = xmlNewDoc((
const xmlChar *)
"1.0");
2431 xmlDocSetRootElement(doc, node);
2432 xmlSetTreeDoc(node, doc);
2440 xmlNode *child = NULL;
2443 CRM_CHECK(src_node != NULL,
return NULL);
2445 child = xmlDocCopyNode(src_node, doc, 1);
2446 xmlAddChild(parent, child);
2447 crm_node_created(child);
2470 xmlNode *parent = xml;
2474 if(docp->acls == NULL) {
2475 crm_trace(
"Ordinary user %s cannot access the CIB without any defined ACLs", docp->user);
2480 offset = __get_prefix(NULL, xml, buffer, offset);
2482 offset += snprintf(buffer + offset,
XML_BUFFER_SIZE - offset,
"[@%s]", name);
2492 xmlAttr *attr = xmlHasProp(xml, (
const xmlChar *)name);
2499 while(parent && parent->_private) {
2501 if(__xml_acl_mode_test(p->flags, mode)) {
2505 crm_trace(
"%x access denied to %s: parent", mode, buffer);
2509 parent = parent->parent;
2512 crm_trace(
"%x access denied to %s: default", mode, buffer);
2526 xmlAttr *attr = NULL;
2531 if (value == NULL) {
2534 #if XML_PARANOIA_CHECKS 2536 const char *old_value = NULL;
2541 CRM_CHECK(old_value != value,
crm_err(
"Cannot reset %s with crm_xml_add(%s)", name, value);
2546 if(TRACKING_CHANGES(node)) {
2549 if(old == NULL || value == NULL || strcmp(old, value) != 0) {
2554 if(dirty && __xml_acl_check(node, name,
xpf_acl_create) == FALSE) {
2555 crm_trace(
"Cannot add %s=%s to %s", name, value, node->name);
2559 attr = xmlSetProp(node, (
const xmlChar *)name, (
const xmlChar *)value);
2561 crm_attr_dirty(attr);
2564 CRM_CHECK(attr && attr->children && attr->children->content,
return NULL);
2565 return (
char *)attr->children->content;
2572 xmlAttr *attr = NULL;
2573 const char *old_value = NULL;
2576 CRM_CHECK(name != NULL && name[0] != 0,
return NULL);
2581 CRM_CHECK(old_value != value,
return value);
2585 crm_trace(
"Cannot replace %s=%s to %s", name, value, node->name);
2588 }
else if (old_value != NULL && value == NULL) {
2592 }
else if (value == NULL) {
2596 if(TRACKING_CHANGES(node)) {
2597 if(old_value == NULL || value == NULL || strcmp(old_value, value) != 0) {
2602 attr = xmlSetProp(node, (
const xmlChar *)name, (
const xmlChar *)value);
2604 crm_attr_dirty(attr);
2606 CRM_CHECK(attr && attr->children && attr->children->content,
return NULL);
2607 return (
char *)attr->children->content;
2614 const char *added =
crm_xml_add(node, name, number);
2624 xmlNode *node = NULL;
2626 if (name == NULL || name[0] == 0) {
2627 CRM_CHECK(name != NULL && name[0] == 0,
return NULL);
2631 if (parent == NULL) {
2632 doc = xmlNewDoc((
const xmlChar *)
"1.0");
2633 node = xmlNewDocRawNode(doc, NULL, (
const xmlChar *)name, NULL);
2634 xmlDocSetRootElement(doc, node);
2638 node = xmlNewDocRawNode(doc, NULL, (
const xmlChar *)name, NULL);
2639 xmlAddChild(parent, node);
2641 crm_node_created(node);
2646 __get_prefix(
const char *prefix, xmlNode *xml,
char *buffer,
int offset)
2648 const char *
id =
ID(xml);
2650 if(offset == 0 && prefix == NULL && xml->parent) {
2651 offset = __get_prefix(NULL, xml->parent, buffer, offset);
2655 offset += snprintf(buffer + offset,
XML_BUFFER_SIZE - offset,
"/%s[@id='%s']", (
const char *)xml->name,
id);
2656 }
else if(xml->name) {
2657 offset += snprintf(buffer + offset,
XML_BUFFER_SIZE - offset,
"/%s", (
const char *)xml->name);
2669 if(__get_prefix(NULL, xml, buffer, offset) > 0) {
2670 return strdup(buffer);
2676 free_xml_with_position(xmlNode * child,
int position)
2678 if (child != NULL) {
2679 xmlNode *top = NULL;
2680 xmlDoc *doc = child->doc;
2684 top = xmlDocGetRootElement(doc);
2687 if (doc != NULL && top == child) {
2691 }
else if(__xml_acl_check(child, NULL,
xpf_acl_write) == FALSE) {
2695 __get_prefix(NULL, child, buffer, offset);
2696 crm_trace(
"Cannot remove %s %x", buffer, p->flags);
2700 if(doc && TRACKING_CHANGES(child) && is_not_set(p->flags,
xpf_created)) {
2704 if(__get_prefix(NULL, child, buffer, offset) > 0) {
2707 crm_trace(
"Deleting %s %p from %p", buffer, child, doc);
2709 deleted_obj->path = strdup(buffer);
2711 deleted_obj->position = -1;
2713 if (child->type == XML_COMMENT_NODE) {
2714 if (position >= 0) {
2715 deleted_obj->position = position;
2718 deleted_obj->position = __xml_offset(child);
2723 p->deleted_objs = g_list_append(p->deleted_objs, deleted_obj);
2731 xmlUnlinkNode(child);
2741 free_xml_with_position(child, -1);
2747 xmlDoc *doc = xmlNewDoc((
const xmlChar *)
"1.0");
2748 xmlNode *copy = xmlDocCopyNode(src, doc, 1);
2750 xmlDocSetRootElement(doc, copy);
2751 xmlSetTreeDoc(copy, doc);
2756 crm_xml_err(
void *ctx,
const char *fmt, ...)
2757 G_GNUC_PRINTF(2, 3);
2760 crm_xml_err(
void *ctx,
const char *fmt, ...)
2763 static struct qb_log_callsite *xml_error_cs = NULL;
2765 if (xml_error_cs == NULL) {
2766 xml_error_cs = qb_log_callsite_get(
2771 if (xml_error_cs && xml_error_cs->targets) {
2773 crm_abort(__FILE__, __PRETTY_FUNCTION__, __LINE__,
"xml library error",
2775 "XML Error: ", fmt, ap);
2785 xmlNode *xml = NULL;
2786 xmlDocPtr output = NULL;
2787 xmlParserCtxtPtr ctxt = NULL;
2788 xmlErrorPtr last_error = NULL;
2790 if (input == NULL) {
2791 crm_err(
"Can't parse NULL input");
2796 ctxt = xmlNewParserCtxt();
2801 xmlCtxtResetLastError(ctxt);
2802 xmlSetGenericErrorFunc(ctxt, crm_xml_err);
2805 xmlCtxtReadDoc(ctxt, (
const xmlChar *)input, NULL, NULL,
2806 XML_PARSE_NOBLANKS | XML_PARSE_RECOVER);
2808 xml = xmlDocGetRootElement(output);
2810 last_error = xmlCtxtGetLastError(ctxt);
2811 if (last_error && last_error->code != XML_ERR_OK) {
2817 crm_warn(
"Parsing failed (domain=%d, level=%d, code=%d): %s",
2818 last_error->domain, last_error->level, last_error->code, last_error->message);
2820 if (last_error->code == XML_ERR_DOCUMENT_EMPTY) {
2823 }
else if (last_error->code != XML_ERR_DOCUMENT_END) {
2824 crm_err(
"Couldn't%s parse %d chars: %s", xml ?
" fully" :
"", (
int)strlen(input),
2831 int len = strlen(input);
2835 crm_warn(
"Parse error[+%.3d]: %.80s", lpc, input+lpc);
2843 xmlFreeParserCtxt(ctxt);
2850 size_t data_length = 0;
2851 size_t read_chars = 0;
2853 char *xml_buffer = NULL;
2854 xmlNode *xml_obj = NULL;
2864 xml_buffer = realloc_safe(xml_buffer, next);
2865 read_chars = fread(xml_buffer + data_length, 1,
XML_BUFFER_SIZE, stdin);
2866 data_length += read_chars;
2867 }
while (read_chars > 0);
2869 if (data_length == 0) {
2870 crm_warn(
"No XML supplied on stdin");
2875 xml_buffer[data_length] =
'\0';
2885 decompress_file(
const char *filename)
2887 char *buffer = NULL;
2891 size_t length = 0, read_len = 0;
2893 BZFILE *bz_file = NULL;
2894 FILE *input = fopen(filename,
"r");
2896 if (input == NULL) {
2897 crm_perror(LOG_ERR,
"Could not open %s for reading", filename);
2901 bz_file = BZ2_bzReadOpen(&rc, input, 0, 0, NULL, 0);
2904 BZ2_bzReadClose(&rc, bz_file);
2909 while (rc == BZ_OK) {
2911 read_len = BZ2_bzRead(&rc, bz_file, buffer + length,
XML_BUFFER_SIZE);
2913 crm_trace(
"Read %ld bytes from file: %d", (
long)read_len, rc);
2915 if (rc == BZ_OK || rc == BZ_STREAM_END) {
2920 buffer[length] =
'\0';
2922 if (rc != BZ_STREAM_END) {
2923 crm_err(
"Couldn't read compressed xml from file");
2928 BZ2_bzReadClose(&rc, bz_file);
2932 crm_err(
"Cannot read compressed files:" " bzlib was not available at compile time");
2940 xmlNode *iter = xml->children;
2943 xmlNode *next = iter->next;
2945 switch (iter->type) {
2948 xmlUnlinkNode(iter);
2952 case XML_ELEMENT_NODE:
2969 xmlNode *xml = NULL;
2970 xmlDocPtr output = NULL;
2971 gboolean uncompressed = TRUE;
2972 xmlParserCtxtPtr ctxt = NULL;
2973 xmlErrorPtr last_error = NULL;
2974 static int xml_options = XML_PARSE_NOBLANKS | XML_PARSE_RECOVER;
2977 ctxt = xmlNewParserCtxt();
2982 xmlCtxtResetLastError(ctxt);
2983 xmlSetGenericErrorFunc(ctxt, crm_xml_err);
2990 if (filename == NULL) {
2992 output = xmlCtxtReadFd(ctxt, STDIN_FILENO,
"unknown.xml", NULL, xml_options);
2994 }
else if (uncompressed) {
2995 output = xmlCtxtReadFile(ctxt, filename, NULL, xml_options);
2998 char *input = decompress_file(filename);
3000 output = xmlCtxtReadDoc(ctxt, (
const xmlChar *)input, NULL, NULL, xml_options);
3004 if (output && (xml = xmlDocGetRootElement(output))) {
3008 last_error = xmlCtxtGetLastError(ctxt);
3009 if (last_error && last_error->code != XML_ERR_OK) {
3015 crm_err(
"Parsing failed (domain=%d, level=%d, code=%d): %s",
3016 last_error->domain, last_error->level, last_error->code, last_error->message);
3018 if (last_error && last_error->code != XML_ERR_OK) {
3019 crm_err(
"Couldn't%s parse %s", xml ?
" fully" :
"", filename);
3026 xmlFreeParserCtxt(ctxt);
3041 time_t now = time(NULL);
3042 char *now_str = ctime(&now);
3058 for (c =
id; *c; ++c) {
3083 va_start(ap, format);
3084 len = vasprintf(&
id, format, ap);
3094 write_xml_stream(xmlNode * xml_node,
const char *filename, FILE * stream, gboolean compress)
3097 char *buffer = NULL;
3098 unsigned int out = 0;
3102 crm_trace(
"Writing XML out to %s", filename);
3103 if (xml_node == NULL) {
3104 crm_err(
"Cannot write NULL to %s", filename);
3119 unsigned int in = 0;
3120 BZFILE *bz_file = NULL;
3122 bz_file = BZ2_bzWriteOpen(&rc, stream, 5, 0, 30);
3124 crm_err(
"bzWriteOpen failed: %d", rc);
3126 BZ2_bzWrite(&rc, bz_file, buffer, strlen(buffer));
3128 crm_err(
"bzWrite() failed: %d", rc);
3133 BZ2_bzWriteClose(&rc, bz_file, 0, &in, &out);
3135 crm_err(
"bzWriteClose() failed: %d", rc);
3138 crm_trace(
"%s: In: %d, out: %d", filename, in, out);
3142 crm_err(
"Cannot write compressed files:" " bzlib was not available at compile time");
3147 res = fprintf(stream,
"%s", buffer);
3149 crm_perror(LOG_ERR,
"Cannot write output to %s", filename);
3156 if (fflush(stream) != 0) {
3157 crm_perror(LOG_ERR,
"fflush for %s failed", filename);
3162 if (fsync(fileno(stream)) < 0 && errno != EROFS && errno != EINVAL) {
3163 crm_perror(LOG_ERR,
"fsync for %s failed", filename);
3169 crm_trace(
"Saved %d bytes to the Cib as XML", res);
3176 write_xml_fd(xmlNode * xml_node,
const char *filename,
int fd, gboolean compress)
3178 FILE *stream = NULL;
3181 stream = fdopen(fd,
"w");
3182 return write_xml_stream(xml_node, filename, stream, compress);
3188 FILE *stream = NULL;
3190 stream = fopen(filename,
"w");
3192 return write_xml_stream(xml_node, filename, stream, compress);
3200 return __xml_first_child(tmp);
3213 crm_xml_escape_shuffle(
char *text,
int start,
int *length,
const char *replace)
3216 int offset = strlen(replace) - 1;
3219 text = realloc_safe(text, *length);
3221 for (lpc = (*length) - 1; lpc > (start + offset); lpc--) {
3222 text[lpc] = text[lpc - offset];
3225 memcpy(text + start, replace, offset + 1);
3234 int length = 1 + strlen(text);
3235 char *copy = strdup(text);
3252 for (index = 0; index < length; index++) {
3253 switch (copy[index]) {
3257 copy = crm_xml_escape_shuffle(copy, index, &length,
"<");
3261 copy = crm_xml_escape_shuffle(copy, index, &length,
">");
3265 copy = crm_xml_escape_shuffle(copy, index, &length,
""");
3269 copy = crm_xml_escape_shuffle(copy, index, &length,
"'");
3273 copy = crm_xml_escape_shuffle(copy, index, &length,
"&");
3278 copy = crm_xml_escape_shuffle(copy, index, &length,
" ");
3283 copy = crm_xml_escape_shuffle(copy, index, &length,
"\\n");
3287 copy = crm_xml_escape_shuffle(copy, index, &length,
"\\r");
3297 if(copy[index] <
' ' || copy[index] >
'~') {
3301 copy = crm_xml_escape_shuffle(copy, index, &length, replace);
3315 dump_xml_attr(xmlAttrPtr attr,
int options,
char **buffer,
int *offset,
int *max)
3317 char *p_value = NULL;
3318 const char *p_name = NULL;
3322 if (attr == NULL || attr->children == NULL) {
3331 p_name = (
const char *)attr->name;
3333 buffer_print(*buffer, *max, *offset,
" %s=\"%s\"", p_name, p_value);
3338 __xml_log_element(
int log_level,
const char *file,
const char *
function,
int line,
3339 const char *prefix, xmlNode *
data,
int depth,
int options)
3343 const char *name = NULL;
3344 const char *hidden = NULL;
3346 xmlNode *child = NULL;
3347 xmlAttrPtr pIter = NULL;
3353 name = crm_element_name(
data);
3356 char *buffer = NULL;
3358 insert_prefix(options, &buffer, &offset, &max, depth);
3360 if (
data->type == XML_COMMENT_NODE) {
3367 for (pIter = crm_first_attr(
data); pIter != NULL; pIter = pIter->next) {
3369 const char *p_name = (
const char *)pIter->name;
3370 const char *p_value = crm_attr_value(pIter);
3371 char *p_copy = NULL;
3380 }
else if (hidden != NULL && p_name[0] != 0 && strstr(hidden, p_name) != NULL) {
3381 p_copy = strdup(
"*****");
3387 buffer_print(buffer, max, offset,
" %s=\"%s\"", p_name, p_copy);
3402 do_crm_log_alias(log_level, file,
function, line,
"%s %s", prefix, buffer);
3406 if(
data->type == XML_COMMENT_NODE) {
3416 for (child = __xml_first_child(
data); child != NULL; child = __xml_next(child)) {
3422 char *buffer = NULL;
3424 insert_prefix(options, &buffer, &offset, &max, depth);
3427 do_crm_log_alias(log_level, file,
function, line,
"%s %s", prefix, buffer);
3433 __xml_log_change_element(
int log_level,
const char *file,
const char *
function,
int line,
3434 const char *prefix, xmlNode *
data,
int depth,
int options)
3437 char *prefix_m = NULL;
3438 xmlNode *child = NULL;
3439 xmlAttrPtr pIter = NULL;
3447 prefix_m = strdup(prefix);
3452 __xml_log_element(log_level, file,
function, line,
3455 }
else if(is_set(p->flags,
xpf_dirty)) {
3456 char *spaces = calloc(80, 1);
3457 int s_count = 0, s_max = 80;
3458 char *prefix_del = NULL;
3459 char *prefix_moved = NULL;
3460 const char *
flags = prefix;
3462 insert_prefix(options, &spaces, &s_count, &s_max, depth);
3463 prefix_del = strdup(prefix);
3464 prefix_del[0] =
'-';
3465 prefix_del[1] =
'-';
3466 prefix_moved = strdup(prefix);
3467 prefix_moved[1] =
'~';
3470 flags = prefix_moved;
3475 __xml_log_element(log_level, file,
function, line,
3478 for (pIter = crm_first_attr(
data); pIter != NULL; pIter = pIter->next) {
3479 const char *aname = (
const char*)pIter->name;
3481 p = pIter->_private;
3486 "%s %s @%s=%s", flags, spaces, aname, value);
3488 }
else if(is_set(p->flags,
xpf_dirty)) {
3497 }
else if(is_set(p->flags,
xpf_moved)) {
3498 flags = prefix_moved;
3504 "%s %s @%s=%s", flags, spaces, aname, value);
3511 for (child = __xml_first_child(
data); child != NULL; child = __xml_next(child)) {
3512 __xml_log_change_element(log_level, file,
function, line, prefix, child, depth + 1, options);
3515 __xml_log_element(log_level, file,
function, line,
3519 for (child = __xml_first_child(
data); child != NULL; child = __xml_next(child)) {
3520 __xml_log_change_element(log_level, file,
function, line, prefix, child, depth + 1, options);
3530 const char *prefix, xmlNode *
data,
int depth,
int options)
3532 xmlNode *a_child = NULL;
3534 char *prefix_m = NULL;
3536 if (prefix == NULL) {
3543 "No data to dump as XML");
3548 __xml_log_change_element(log_level, file,
function, line, prefix, data, depth, options);
3556 prefix_m = strdup(prefix);
3563 prefix_m = strdup(prefix);
3572 for (a_child = __xml_first_child(data); a_child != NULL; a_child = __xml_next(a_child)) {
3573 log_data_element(log_level, file,
function, line, prefix, a_child, depth + 1, options);
3576 __xml_log_element(log_level, file,
function, line, prefix, data, depth,
3583 dump_filtered_xml(xmlNode *
data,
int options,
char **buffer,
int *offset,
int *max)
3586 xmlAttrPtr xIter = NULL;
3587 static int filter_len =
DIMOF(filter);
3589 for (lpc = 0; options && lpc < filter_len; lpc++) {
3590 filter[lpc].found = FALSE;
3593 for (xIter = crm_first_attr(
data); xIter != NULL; xIter = xIter->next) {
3595 const char *p_name = (
const char *)xIter->name;
3597 for (lpc = 0; skip == FALSE && lpc < filter_len; lpc++) {
3598 if (filter[lpc].found == FALSE && strcmp(p_name, filter[lpc].
string) == 0) {
3599 filter[lpc].found = TRUE;
3605 if (skip == FALSE) {
3606 dump_xml_attr(xIter, options, buffer, offset, max);
3612 dump_xml_element(xmlNode *
data,
int options,
char **buffer,
int *offset,
int *max,
int depth)
3614 const char *name = NULL;
3625 if (*buffer == NULL) {
3630 name = crm_element_name(
data);
3633 insert_prefix(options, buffer, offset, max, depth);
3637 dump_filtered_xml(
data, options, buffer, offset, max);
3640 xmlAttrPtr xIter = NULL;
3642 for (xIter = crm_first_attr(
data); xIter != NULL; xIter = xIter->next) {
3643 dump_xml_attr(xIter, options, buffer, offset, max);
3647 if (
data->children == NULL) {
3658 if (
data->children) {
3659 xmlNode *xChild = NULL;
3660 for(xChild =
data->children; xChild != NULL; xChild = xChild->next) {
3661 crm_xml_dump(xChild, options, buffer, offset, max, depth + 1);
3664 insert_prefix(options, buffer, offset, max, depth);
3667 if (options & xml_log_option_formatted) {
3674 dump_xml_text(xmlNode *
data,
int options,
char **buffer,
int *offset,
int *max,
int depth)
3685 if (*buffer == NULL) {
3690 insert_prefix(options, buffer, offset, max, depth);
3701 dump_xml_comment(xmlNode *
data,
int options,
char **buffer,
int *offset,
int *max,
int depth)
3712 if (*buffer == NULL) {
3717 insert_prefix(options, buffer, offset, max, depth);
3752 xmlBuffer *xml_buffer = NULL;
3760 xml_buffer = xmlBufferCreate();
3771 xmlBufferSetAllocationScheme(xml_buffer, XML_BUFFER_ALLOC_DOUBLEIT);
3775 *buffer = strdup((
char *)xml_buffer->content);
3779 if ((now + 1) < next) {
3781 crm_err(
"xmlNodeDump() -> %dbytes took %ds", *max, next - now);
3784 xmlBufferFree(xml_buffer);
3789 switch(data->type) {
3790 case XML_ELEMENT_NODE:
3792 dump_xml_element(data, options, buffer, offset, max, depth);
3797 dump_xml_text(data, options, buffer, offset, max, depth);
3800 case XML_COMMENT_NODE:
3801 dump_xml_comment(data, options, buffer, offset, max, depth);
3804 crm_warn(
"Unhandled type: %d", data->type);
3840 char *buffer = NULL;
3841 int offset = 0, max = 0;
3850 char *buffer = NULL;
3851 int offset = 0, max = 0;
3860 char *buffer = NULL;
3861 int offset = 0, max = 0;
3863 crm_xml_dump(an_xml_node, 0, &buffer, &offset, &max, 0);
3870 if (xml_root != NULL && xml_root->children != NULL) {
3904 char *value_copy = NULL;
3907 if (value != NULL) {
3908 value_copy = strdup(value);
3917 crm_trace(
"Cannot remove %s from %s", name, obj->name);
3919 }
else if(TRACKING_CHANGES(obj)) {
3922 xmlAttr *attr = xmlHasProp(obj, (
const xmlChar *)name);
3930 xmlUnsetProp(obj, (
const xmlChar *)name);
3937 xmlNode *child = NULL;
3942 for (child = __xml_first_child(a_node); child != NULL; child = __xml_next(child)) {
3952 if (filename == NULL) {
3960 crm_info(
"Saving %s to %s", desc, filename);
3968 gboolean result = TRUE;
3969 int root_nodes_seen = 0;
3970 static struct qb_log_callsite *digest_cs = NULL;
3974 xmlNode *child_diff = NULL;
3976 xmlNode *removed =
find_xml_node(diff,
"diff-removed", FALSE);
3979 if (digest_cs == NULL) {
3981 qb_log_callsite_get(__func__, __FILE__,
"diff-digest",
LOG_TRACE, __LINE__,
3986 for (child_diff = __xml_first_child(removed); child_diff != NULL;
3987 child_diff = __xml_next(child_diff)) {
3988 CRM_CHECK(root_nodes_seen == 0, result = FALSE);
3989 if (root_nodes_seen == 0) {
3995 if (root_nodes_seen == 0) {
3998 }
else if (root_nodes_seen > 1) {
3999 crm_err(
"(-) Diffs cannot contain more than one change set..." " saw %d", root_nodes_seen);
4003 root_nodes_seen = 0;
4006 xmlNode *child_diff = NULL;
4008 for (child_diff = __xml_first_child(added); child_diff != NULL;
4009 child_diff = __xml_next(child_diff)) {
4010 CRM_CHECK(root_nodes_seen == 0, result = FALSE);
4011 if (root_nodes_seen == 0) {
4018 if (root_nodes_seen > 1) {
4019 crm_err(
"(+) Diffs cannot contain more than one change set..." " saw %d", root_nodes_seen);
4022 }
else if (result && digest) {
4023 char *new_digest = NULL;
4028 crm_info(
"Digest mis-match: expected %s, calculated %s", digest, new_digest);
4031 crm_trace(
"%p %.6x", digest_cs, digest_cs ? digest_cs->targets : 0);
4032 if (digest_cs && digest_cs->targets) {
4039 crm_trace(
"Digest matched: expected %s, calculated %s", digest, new_digest);
4043 }
else if (result) {
4051 __xml_diff_object(xmlNode * old, xmlNode *
new)
4053 xmlNode *cIter = NULL;
4054 xmlAttr *pIter = NULL;
4058 crm_node_created(
new);
4059 __xml_acl_post_process(
new);
4072 for (pIter = crm_first_attr(
new); pIter != NULL; pIter = pIter->next) {
4079 for (pIter = crm_first_attr(old); pIter != NULL; ) {
4080 xmlAttr *prop = pIter;
4082 const char *name = (
const char *)pIter->name;
4084 xmlAttr *exists = xmlHasProp(
new, pIter->name);
4086 pIter = pIter->next;
4087 if(exists == NULL) {
4088 p =
new->doc->_private;
4092 exists = xmlSetProp(
new, (
const xmlChar *)name, (
const xmlChar *)old_value);
4095 p = exists->_private;
4098 crm_trace(
"Lost %s@%s=%s", old->name, name, old_value);
4102 int p_new = __xml_offset((xmlNode*)exists);
4103 int p_old = __xml_offset((xmlNode*)prop);
4106 p = exists->_private;
4109 if(strcmp(value, old_value) != 0) {
4115 crm_trace(
"Modified %s@%s %s->%s", old->name, name, old_value, vcopy);
4116 xmlSetProp(
new, prop->name, (
const xmlChar *)old_value);
4120 }
else if(p_old != p_new && TRACKING_CHANGES_LAZY(
new) == FALSE) {
4121 crm_info(
"Moved %s@%s (%d -> %d)", old->name, name, p_old, p_new);
4122 __xml_node_dirty(
new);
4130 p = exists->_private;
4137 for (pIter = crm_first_attr(
new); pIter != NULL; ) {
4138 xmlAttr *prop = pIter;
4141 pIter = pIter->next;
4143 char *name = strdup((
const char *)prop->name);
4146 crm_trace(
"Created %s@%s=%s", new->name, name, value);
4149 crm_attr_dirty(prop);
4151 xmlUnsetProp(
new, prop->name);
4159 for (cIter = __xml_first_child(old); cIter != NULL; ) {
4160 xmlNode *old_child = cIter;
4161 xmlNode *new_child = find_element(
new, cIter, TRUE);
4163 cIter = __xml_next(cIter);
4165 __xml_diff_object(old_child, new_child);
4170 xmlNode *top = xmlDocGetRootElement(candidate->doc);
4172 __xml_node_clean(candidate);
4173 __xml_acl_apply(top);
4175 free_xml_with_position(candidate, __xml_offset(old_child));
4177 if (find_element(
new, old_child, TRUE) == NULL) {
4185 for (cIter = __xml_first_child(
new); cIter != NULL; ) {
4186 xmlNode *new_child = cIter;
4187 xmlNode *old_child = find_element(old, cIter, TRUE);
4189 cIter = __xml_next(cIter);
4190 if(old_child == NULL) {
4193 __xml_diff_object(old_child, new_child);
4197 int p_new = __xml_offset(new_child);
4198 int p_old = __xml_offset(old_child);
4200 if(p_old != p_new) {
4203 crm_info(
"%s.%s moved from %d to %d",
4204 new_child->name,
ID(new_child), p_old, p_new);
4205 __xml_node_dirty(
new);
4209 p = old_child->_private;
4211 p = new_child->_private;
4236 __xml_diff_object(old,
new);
4242 xmlNode *tmp1 = NULL;
4259 if (added->children == NULL && removed->children == NULL) {
4270 xmlNode *cIter = NULL;
4271 xmlAttrPtr pIter = NULL;
4272 gboolean can_prune = TRUE;
4273 const char *name = crm_element_name(xml_node);
4282 for (pIter = crm_first_attr(xml_node); pIter != NULL; pIter = pIter->next) {
4283 const char *p_name = (
const char *)pIter->name;
4291 cIter = __xml_first_child(xml_node);
4293 xmlNode *child = cIter;
4295 cIter = __xml_next(cIter);
4307 xmlNode * xml_node, xmlNode * parent)
4310 xmlNode *child = NULL;
4311 xmlAttrPtr pIter = NULL;
4312 xmlNode *new_parent = parent;
4313 const char *name = crm_element_name(xml_node);
4315 CRM_CHECK(xml_node != NULL && name != NULL,
return);
4318 for (pIter = crm_first_attr(xml_node); pIter != NULL; pIter = pIter->next) {
4319 const char *p_name = (
const char *)pIter->name;
4320 const char *p_value = crm_attr_value(pIter);
4322 lower_bound = context;
4326 if (lower_bound >= 0 || upper_bound >= 0) {
4332 if (upper_bound >= 0) {
4341 for (child = __xml_first_child(us); child != NULL; child = __xml_next(child)) {
4353 if (xml_node->properties) {
4356 }
else if (depth < context) {
4357 xmlNode *child = NULL;
4359 for (child = __xml_first_child(xml_node); child != NULL; child = __xml_next(child)) {
4369 find_xml_comment(xmlNode * root, xmlNode * search_comment, gboolean exact)
4371 xmlNode *a_child = NULL;
4372 int search_offset = __xml_offset(search_comment);
4374 CRM_CHECK(search_comment->type == XML_COMMENT_NODE,
return NULL);
4376 for (a_child = __xml_first_child(root); a_child != NULL; a_child = __xml_next(a_child)) {
4378 int offset = __xml_offset(a_child);
4381 if (offset < search_offset) {
4384 }
else if (offset > search_offset) {
4393 if (a_child->type == XML_COMMENT_NODE
4394 &&
safe_str_eq((
const char *)a_child->content, (
const char *)search_comment->content)) {
4406 subtract_xml_comment(xmlNode * parent, xmlNode * left, xmlNode * right,
4410 CRM_CHECK(left->type == XML_COMMENT_NODE,
return NULL);
4413 ||
safe_str_neq((
const char *)left->content, (
const char *)right->content)) {
4414 xmlNode *deleted = NULL;
4427 gboolean full, gboolean * changed,
const char *marker)
4429 gboolean dummy = FALSE;
4430 gboolean skip = FALSE;
4431 xmlNode *diff = NULL;
4432 xmlNode *right_child = NULL;
4433 xmlNode *left_child = NULL;
4434 xmlAttrPtr xIter = NULL;
4436 const char *
id = NULL;
4437 const char *name = NULL;
4438 const char *value = NULL;
4439 const char *right_val = NULL;
4442 static int filter_len =
DIMOF(filter);
4444 if (changed == NULL) {
4452 if (left->type == XML_COMMENT_NODE) {
4453 return subtract_xml_comment(parent, left, right, changed);
4457 if (right == NULL) {
4458 xmlNode *deleted = NULL;
4460 crm_trace(
"Processing <%s id=%s> (complete copy)", crm_element_name(left),
id);
4468 name = crm_element_name(left);
4474 if (value != NULL && strcmp(value,
"removed:top") == 0) {
4475 crm_trace(
"We are the root of the deletion: %s.id=%s", name,
id);
4484 for (lpc = 0; lpc < filter_len; lpc++) {
4485 filter[lpc].found = FALSE;
4489 for (left_child = __xml_first_child(left); left_child != NULL;
4490 left_child = __xml_next(left_child)) {
4491 gboolean child_changed = FALSE;
4493 right_child = find_element(right, left_child, FALSE);
4495 if (child_changed) {
4500 if (*changed == FALSE) {
4504 xmlAttrPtr pIter = NULL;
4506 for (pIter = crm_first_attr(left); pIter != NULL; pIter = pIter->next) {
4507 const char *p_name = (
const char *)pIter->name;
4508 const char *p_value = crm_attr_value(pIter);
4510 xmlSetProp(diff, (
const xmlChar *)p_name, (
const xmlChar *)p_value);
4517 xmlSetProp(diff, (
const xmlChar *)
XML_ATTR_ID, (
const xmlChar *)
id);
4521 for (xIter = crm_first_attr(left); xIter != NULL; xIter = xIter->next) {
4522 const char *prop_name = (
const char *)xIter->name;
4523 xmlAttrPtr right_attr = NULL;
4531 for (lpc = 0; skip == FALSE && lpc < filter_len; lpc++) {
4532 if (filter[lpc].found == FALSE && strcmp(prop_name, filter[lpc].
string) == 0) {
4533 filter[lpc].found = TRUE;
4543 right_attr = xmlHasProp(right, (
const xmlChar *)prop_name);
4545 p = right_attr->_private;
4549 if (right_val == NULL || (p && is_set(p->flags,
xpf_deleted))) {
4553 xmlAttrPtr pIter = NULL;
4555 for (pIter = crm_first_attr(left); pIter != NULL; pIter = pIter->next) {
4556 const char *p_name = (
const char *)pIter->name;
4557 const char *p_value = crm_attr_value(pIter);
4559 xmlSetProp(diff, (
const xmlChar *)p_name, (
const xmlChar *)p_value);
4566 xmlSetProp(diff, (
const xmlChar *)prop_name, (
const xmlChar *)value);
4574 if (strcmp(left_value, right_val) == 0) {
4580 xmlAttrPtr pIter = NULL;
4582 crm_trace(
"Changes detected to %s in <%s id=%s>", prop_name,
4583 crm_element_name(left),
id);
4584 for (pIter = crm_first_attr(left); pIter != NULL; pIter = pIter->next) {
4585 const char *p_name = (
const char *)pIter->name;
4586 const char *p_value = crm_attr_value(pIter);
4588 xmlSetProp(diff, (
const xmlChar *)p_name, (
const xmlChar *)p_value);
4593 crm_trace(
"Changes detected to %s (%s -> %s) in <%s id=%s>",
4594 prop_name, left_value, right_val, crm_element_name(left),
id);
4601 if (*changed == FALSE) {
4605 }
else if (full == FALSE &&
id) {
4613 add_xml_comment(xmlNode * parent, xmlNode * target, xmlNode * update)
4616 CRM_CHECK(update->type == XML_COMMENT_NODE,
return 0);
4618 if (target == NULL) {
4619 target = find_xml_comment(parent, update, FALSE);
4622 if (target == NULL) {
4626 }
else if (
safe_str_neq((
const char *)target->content, (
const char *)update->content)) {
4627 xmlFree(target->content);
4628 target->content = xmlStrdup(update->content);
4635 add_xml_object(xmlNode * parent, xmlNode * target, xmlNode * update, gboolean as_diff)
4637 xmlNode *a_child = NULL;
4638 const char *object_name = NULL,
4639 *object_href = NULL,
4640 *object_href_val = NULL;
4649 if (update->type == XML_COMMENT_NODE) {
4650 return add_xml_comment(parent, target, update);
4653 object_name = crm_element_name(update);
4654 object_href_val =
ID(update);
4655 if (object_href_val != NULL) {
4662 CRM_CHECK(object_name != NULL,
return 0);
4663 CRM_CHECK(target != NULL || parent != NULL,
return 0);
4665 if (target == NULL) {
4666 target = find_entity_by_attr_or_just_name(parent, object_name,
4667 object_href, object_href_val);
4670 if (target == NULL) {
4673 #if XML_PARSER_DEBUG 4675 object_href ?
" " :
"",
4676 object_href ? object_href :
"",
4677 object_href ?
"=" :
"",
4678 object_href ? object_href_val :
"");
4682 object_href ?
" " :
"",
4683 object_href ? object_href :
"",
4684 object_href ?
"=" :
"",
4685 object_href ? object_href_val :
"");
4691 if (as_diff == FALSE) {
4697 xmlAttrPtr pIter = NULL;
4699 for (pIter = crm_first_attr(update); pIter != NULL; pIter = pIter->next) {
4700 const char *p_name = (
const char *)pIter->name;
4701 const char *p_value = crm_attr_value(pIter);
4704 xmlUnsetProp(target, (
const xmlChar *)p_name);
4705 xmlSetProp(target, (
const xmlChar *)p_name, (
const xmlChar *)p_value);
4709 for (a_child = __xml_first_child(update); a_child != NULL; a_child = __xml_next(a_child)) {
4710 #if XML_PARSER_DEBUG 4712 object_href ?
" " :
"",
4713 object_href ? object_href :
"",
4714 object_href ?
"=" :
"",
4715 object_href ? object_href_val :
"");
4720 #if XML_PARSER_DEBUG 4722 object_href ?
" " :
"",
4723 object_href ? object_href :
"",
4724 object_href ?
"=" :
"",
4725 object_href ? object_href_val :
"");
4733 gboolean can_update = TRUE;
4734 xmlNode *child_of_child = NULL;
4737 CRM_CHECK(to_update != NULL,
return FALSE);
4739 if (
safe_str_neq(crm_element_name(to_update), crm_element_name(child))) {
4745 }
else if (can_update) {
4746 #if XML_PARSER_DEBUG 4752 for (child_of_child = __xml_first_child(child); child_of_child != NULL;
4753 child_of_child = __xml_next(child_of_child)) {
4766 const char *tag,
const char *field,
const char *value, gboolean search_matches)
4768 int match_found = 0;
4771 CRM_CHECK(children != NULL,
return FALSE);
4773 if (tag != NULL &&
safe_str_neq(tag, crm_element_name(root))) {
4778 if (*children == NULL) {
4785 if (search_matches || match_found == 0) {
4786 xmlNode *child = NULL;
4788 for (child = __xml_first_child(root); child != NULL; child = __xml_next(child)) {
4789 match_found +=
find_xml_children(children, child, tag, field, value, search_matches);
4799 gboolean can_delete = FALSE;
4800 xmlNode *child_of_child = NULL;
4802 const char *up_id = NULL;
4803 const char *child_id = NULL;
4804 const char *right_val = NULL;
4807 CRM_CHECK(update != NULL,
return FALSE);
4810 child_id =
ID(child);
4812 if (up_id == NULL || (child_id && strcmp(child_id, up_id) == 0)) {
4815 if (
safe_str_neq(crm_element_name(update), crm_element_name(child))) {
4818 if (can_delete && delete_only) {
4819 xmlAttrPtr pIter = NULL;
4821 for (pIter = crm_first_attr(update); pIter != NULL; pIter = pIter->next) {
4822 const char *p_name = (
const char *)pIter->name;
4823 const char *p_value = crm_attr_value(pIter);
4832 if (can_delete && parent != NULL) {
4834 if (delete_only || update == NULL) {
4839 xmlDoc *doc = tmp->doc;
4840 xmlNode *old = NULL;
4843 old = xmlReplaceNode(child, tmp);
4847 __xml_acl_apply(tmp);
4851 xmlDocSetRootElement(doc, old);
4857 }
else if (can_delete) {
4862 child_of_child = __xml_first_child(child);
4863 while (child_of_child) {
4864 xmlNode *next = __xml_next(child_of_child);
4870 child_of_child = NULL;
4872 child_of_child = next;
4906 const char *parent_id =
ID(parent);
4919 const char *name = key;
4920 const char *s_value = value;
4921 xmlNode *xml_node = user_data;
4924 crm_trace(
"dumped: name=%s value=%s", name, s_value);
4930 const char *name = key;
4931 const char *s_value = value;
4933 xmlNode *xml_node = user_data;
4935 if (isdigit(name[0])) {
4943 crm_trace(
"dumped: %s=%s", name, s_value);
4946 crm_trace(
"duplicate: %s=%s", name, s_value);
4953 const char *name = key;
4954 const char *s_value = value;
4956 xmlNode *xml_node = user_data;
4962 crm_trace(
"duplicate: %s=%s", name, s_value);
4969 char *crm_name = NULL;
4971 if (key == NULL || value == NULL) {
4978 for (crm_name = key; *crm_name; ++crm_name) {
4979 if ((*crm_name ==
'#') || (*crm_name ==
':')) {
4992 xmlNode *child = NULL;
4993 xmlAttrPtr pIter = NULL;
4994 xmlNode *nvpair_list = NULL;
4995 GHashTable *nvpair_hash = crm_str_table_new();
4997 CRM_CHECK(parent != NULL,
return nvpair_hash);
5000 if (nvpair_list == NULL) {
5001 crm_trace(
"No attributes in %s", crm_element_name(parent));
5007 for (pIter = crm_first_attr(nvpair_list); pIter != NULL; pIter = pIter->next) {
5008 const char *p_name = (
const char *)pIter->name;
5009 const char *p_value = crm_attr_value(pIter);
5011 crm_trace(
"Added %s=%s", p_name, p_value);
5013 g_hash_table_insert(nvpair_hash, strdup(p_name), strdup(p_value));
5016 for (child = __xml_first_child(nvpair_list); child != NULL; child = __xml_next(child)) {
5017 if (strcmp((
const char *)child->name,
XML_TAG_PARAM) == 0) {
5022 if (key != NULL && value != NULL) {
5023 g_hash_table_insert(nvpair_hash, strdup(key), strdup(value));
5031 typedef struct name_value_s {
5037 sort_pairs(gconstpointer a, gconstpointer b)
5049 rc = strcmp(pair_a->name, pair_b->name);
5052 }
else if (rc > 0) {
5059 dump_pair(gpointer
data, gpointer user_data)
5062 xmlNode *parent = user_data;
5068 sorted_xml(xmlNode * input, xmlNode * parent, gboolean recursive)
5070 xmlNode *child = NULL;
5074 xmlNode *result = NULL;
5075 const char *name = NULL;
5076 xmlAttrPtr pIter = NULL;
5080 name = crm_element_name(input);
5085 for (pIter = crm_first_attr(input); pIter != NULL; pIter = pIter->next) {
5086 const char *p_name = (
const char *)pIter->name;
5087 const char *p_value = crm_attr_value(pIter);
5090 pair->name = p_name;
5091 pair->value = p_value;
5092 unsorted = g_list_prepend(unsorted, pair);
5096 sorted = g_list_sort(unsorted, sort_pairs);
5097 g_list_foreach(sorted, dump_pair, result);
5098 g_list_free_full(sorted, free);
5100 for (child = __xml_first_child(input); child != NULL; child = __xml_next(child)) {
5114 xmlNode *match = NULL;
5116 for (match = __xml_first_child(parent); match != NULL; match = __xml_next(match)) {
5122 if (name == NULL || strcmp((
const char *)match->name, name) == 0) {
5139 xmlNode *match = __xml_next(sibling);
5140 const char *name = crm_element_name(sibling);
5142 while (match != NULL) {
5143 if (!strcmp(crm_element_name(match), name)) {
5146 match = __xml_next(match);
5154 static bool init = TRUE;
5163 xmlSetBufferAllocationScheme(XML_BUFFER_ALLOC_DOUBLEIT);
5166 xmlDeregisterNodeDefault(pcmkDeregisterNode);
5167 xmlRegisterNodeDefault(pcmkRegisterNode);
5176 crm_info(
"Cleaning up memory from libxml2");
5181 #define XPATH_MAX 512 5186 const char *tag = NULL;
5187 const char *ref = NULL;
5188 xmlNode *result = input;
5189 char *xpath_string = NULL;
5191 if (result == NULL) {
5194 }
else if (top == NULL) {
5198 tag = crm_element_name(result);
5206 offset += snprintf(xpath_string + offset,
XPATH_MAX - offset,
"//%s[@id='%s']", tag, ref);
5210 if (result == NULL) {
5211 char *nodePath = (
char *)xmlGetNodePath(top);
5213 crm_err(
"No match for %s found in %s: Invalid configuration", xpath_string,
5226 xmlAttr *attr = NULL;
5229 crm_err(
"Couldn't find %s in NULL", name ? name :
"<null>");
5233 }
else if (name == NULL) {
5234 crm_err(
"Couldn't find NULL in %s", crm_element_name(data));
5238 attr = xmlHasProp(data, (
const xmlChar *)name);
5239 if (attr == NULL || attr->children == NULL) {
5242 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)
void xml_calculate_significant_changes(xmlNode *old_xml, xmlNode *new_xml)
xmlNode * crm_next_same_xml(xmlNode *sibling)
Get next instance of same XML tag.
void crm_schema_init(void)
#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)
xmlNode * crm_create_nvpair_xml(xmlNode *parent, const char *id, const char *name, const char *value)
Create an XML name/value pair.
const char * __xml_acl_to_text(enum xml_private_flags flags)
#define pcmk_err_old_data
void crm_xml_sanitize_id(char *id)
Sanitize a string so it is usable as an XML ID.
long long crm_int_helper(const char *text, char **end_text)
#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...)
void crm_schema_cleanup(void)
#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_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
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)
#define CRM_XML_LOG_BASE(priority, dechunk, postemit, prefix, fmt, ap)
Base for directing lib{xml2,xslt} log into standard libqb backend.
#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
#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 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
#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_ACL_ATTR_ATTRIBUTE
void crm_xml_set_id(xmlNode *xml, const char *format,...)
Set the ID of an XML element using a format.
#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)
gboolean crm_str_eq(const char *a, const char *b, gboolean use_case)
xmlNode * xml_create_patchset(int format, xmlNode *source, xmlNode *target, bool *config_changed, bool manage_version)
gboolean crm_ends_with_ext(const char *s, const char *match)
void xml_log_changes(uint8_t log_level, const char *function, xmlNode *xml)
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)
#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 crm_destroy_xml(gpointer data)
xmlNode destructor which can be used in glib collections
bool xml_acl_filtered_copy(const char *user, xmlNode *acl_source, xmlNode *xml, xmlNode **result)
char * crm_xml_escape(const char *text)
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)
#define XML_ACL_TAG_ROLE_REF
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)
xmlNode * find_entity(xmlNode *parent, const char *node_name, const char *id)
#define crm_info(fmt, args...)
gboolean can_prune_leaf(xmlNode *xml_node)
bool xml_patch_versions(xmlNode *patchset, int add[3], int del[3])
bool xml_document_dirty(xmlNode *xml)
struct xml_deleted_obj_s xml_deleted_obj_t