11 #include <sys/types.h>
18 #include <libxml/parser.h>
19 #include <libxml/tree.h>
31 #define XML_BUFFER_SIZE 4096
32 #define XML_PARSER_DEBUG 0
39 typedef struct xml_deleted_obj_s {
46 static filter_t filter[] = {
55 static xmlNode *subtract_xml_comment(xmlNode * parent, xmlNode * left, xmlNode * right, gboolean * changed);
56 static xmlNode *find_xml_comment(xmlNode * root, xmlNode * search_comment, gboolean exact);
57 static int add_xml_comment(xmlNode * parent, xmlNode * target, xmlNode * update);
59 #define CHUNK_SIZE 1024
64 if(xml == NULL || xml->doc == NULL || xml->doc->_private == NULL) {
68 }
else if (lazy && is_not_set(((
xml_private_t *)xml->doc->_private)->flags,
75 #define buffer_print(buffer, max, offset, fmt, args...) do { \
78 rc = snprintf((buffer) + (offset), (max) - (offset), fmt, ##args); \
80 if(buffer && rc < 0) { \
81 crm_perror(LOG_ERR, "snprintf failed at offset %d", offset); \
82 (buffer)[(offset)] = 0; \
84 } else if(rc >= ((max) - (offset))) { \
86 (max) = QB_MAX(CHUNK_SIZE, (max) * 2); \
87 tmp = realloc_safe((buffer), (max)); \
97 insert_prefix(
int options,
char **buffer,
int *offset,
int *max,
int depth)
100 size_t spaces = 2 * depth;
102 if ((*buffer) == NULL || spaces >= ((*max) - (*offset))) {
104 (*buffer) = realloc_safe((*buffer), (*max));
106 memset((*buffer) + (*offset),
' ', spaces);
112 set_parent_flag(xmlNode *xml,
long flag)
115 for(; xml; xml = xml->parent) {
131 if(xml && xml->doc && xml->doc->_private){
141 __xml_node_dirty(xmlNode *xml)
148 __xml_node_clean(xmlNode *xml)
150 xmlNode *cIter = NULL;
157 for (cIter = __xml_first_child(xml); cIter != NULL; cIter = __xml_next(cIter)) {
158 __xml_node_clean(cIter);
163 crm_node_created(xmlNode *xml)
165 xmlNode *cIter = NULL;
171 __xml_node_dirty(xml);
174 for (cIter = __xml_first_child(xml); cIter != NULL; cIter = __xml_next(cIter)) {
175 crm_node_created(cIter);
183 xmlNode *parent = a->parent;
192 __xml_node_dirty(parent);
195 int get_tag_name(
const char *input,
size_t offset,
size_t max);
196 int get_attr_name(
const char *input,
size_t offset,
size_t max);
200 static int add_xml_object(xmlNode * parent, xmlNode * target, xmlNode * update, gboolean as_diff);
202 #define XML_PRIVATE_MAGIC (long) 0x81726354
205 __xml_deleted_obj_free(
void *
data)
210 free(deleted_obj->path);
230 g_list_free_full(p->
deleted_objs, __xml_deleted_obj_free);
240 __xml_private_clean(p);
245 pcmkDeregisterNode(xmlNodePtr node)
254 if (node->type != XML_DOCUMENT_NODE || node->name == NULL
255 || node->name[0] !=
' ') {
256 __xml_private_free(node->_private);
261 pcmkRegisterNode(xmlNodePtr node)
266 case XML_ELEMENT_NODE:
267 case XML_DOCUMENT_NODE:
268 case XML_ATTRIBUTE_NODE:
269 case XML_COMMENT_NODE:
278 case XML_CDATA_SECTION_NODE:
282 crm_trace(
"Ignoring %p %d", node, node->type);
292 __xml_node_dirty(node);
300 crm_trace(
"Tracking changes%s to %p", enforce_acls?
" with ACLs":
"", xml);
303 if(acl_source == NULL) {
325 if(xml != NULL && xml->doc && xml->doc->_private) {
381 static int __xml_offset(xmlNode *xml)
384 xmlNode *cIter = NULL;
386 for(cIter = xml; cIter->prev; cIter = cIter->prev) {
397 static int __xml_offset_no_deletions(xmlNode *xml)
400 xmlNode *cIter = NULL;
402 for(cIter = xml; cIter->prev; cIter = cIter->prev) {
414 __xml_build_changes(xmlNode * xml, xmlNode *patchset)
416 xmlNode *cIter = NULL;
417 xmlAttr *pIter = NULL;
418 xmlNode *change = NULL;
426 sizeof(buffer)) > 0) {
427 int position = __xml_offset_no_deletions(xml);
440 for (pIter = pcmk__first_xml_attr(xml); pIter != NULL; pIter = pIter->next) {
441 xmlNode *attr = NULL;
453 sizeof(buffer)) > 0) {
478 xmlNode *result = NULL;
483 for (pIter = pcmk__first_xml_attr(xml); pIter != NULL; pIter = pIter->next) {
488 crm_xml_add(result, (
const char *)pIter->name, value);
493 for (cIter = __xml_first_child(xml); cIter != NULL; cIter = __xml_next(cIter)) {
494 __xml_build_changes(cIter, patchset);
502 crm_trace(
"%s.%s moved to position %d", xml->name,
ID(xml), __xml_offset(xml));
504 sizeof(buffer)) > 0) {
515 __xml_accept_changes(xmlNode * xml)
517 xmlNode *cIter = NULL;
518 xmlAttr *pIter = NULL;
522 pIter = pcmk__first_xml_attr(xml);
524 while (pIter != NULL) {
525 const xmlChar *name = pIter->name;
538 for (cIter = __xml_first_child(xml); cIter != NULL; cIter = __xml_next(cIter)) {
539 __xml_accept_changes(cIter);
544 is_config_change(xmlNode *xml)
551 p = config->_private;
557 if(xml->doc && xml->doc->_private) {
558 p = xml->doc->_private;
559 for(gIter = p->
deleted_objs; gIter; gIter = gIter->next) {
572 xml_repair_v1_diff(xmlNode * last, xmlNode * next, xmlNode * local_diff, gboolean changed)
576 xmlNode *diff_child = NULL;
578 const char *tag = NULL;
580 const char *vfields[] = {
586 if (local_diff == NULL) {
591 tag =
"diff-removed";
593 if (diff_child == NULL) {
603 for(lpc = 0; last && lpc <
DIMOF(vfields); lpc++){
607 if(changed || lpc == 2) {
614 if (diff_child == NULL) {
624 for(lpc = 0; next && lpc <
DIMOF(vfields); lpc++){
631 xmlAttrPtr xIter = NULL;
633 for (xIter = next->properties; xIter; xIter = xIter->next) {
634 const char *p_name = (
const char *)xIter->name;
637 xmlSetProp(cib, (
const xmlChar *)p_name, (
const xmlChar *)p_value);
645 xml_create_patchset_v1(xmlNode *source, xmlNode *target,
bool config,
bool suppress)
651 xml_repair_v1_diff(source, target, patchset, config);
658 xml_create_patchset_v2(xmlNode *source, xmlNode *target)
666 xmlNode *patchset = NULL;
667 const char *vfields[] = {
679 doc = target->doc->_private;
687 for(lpc = 0; lpc <
DIMOF(vfields); lpc++){
697 for(lpc = 0; lpc <
DIMOF(vfields); lpc++){
706 for(gIter = doc->
deleted_objs; gIter; gIter = gIter->next) {
712 if (deleted_obj->position >= 0) {
717 __xml_build_changes(target, patchset);
722 xml_create_patchset(
int format, xmlNode *source, xmlNode *target,
bool *config_changed,
bool manage_version)
726 xmlNode *patch = NULL;
735 config = is_config_change(target);
737 *config_changed = config;
740 if(manage_version && config) {
747 }
else if(manage_version) {
765 patch = xml_create_patchset_v1(source, target, config, FALSE);
768 patch = xml_create_patchset_v2(source, target);
771 crm_err(
"Unknown patch format: %d", format);
785 if (patch == NULL || source == NULL || target == NULL) {
794 if (format > 1 && with_digest == FALSE) {
808 __xml_log_element(
int log_level,
const char *file,
const char *
function,
int line,
809 const char *prefix, xmlNode *
data,
int depth,
int options);
815 xmlNode *child = NULL;
816 xmlNode *added = NULL;
817 xmlNode *removed = NULL;
818 gboolean is_first = TRUE;
820 int add[] = { 0, 0, 0 };
821 int del[] = { 0, 0, 0 };
823 const char *fmt = NULL;
824 const char *digest = NULL;
827 static struct qb_log_callsite *patchset_cs = NULL;
829 if (patchset_cs == NULL) {
830 patchset_cs = qb_log_callsite_get(
function, __FILE__,
"xml-patchset", log_level, __LINE__, 0);
833 if (patchset == NULL) {
837 }
else if (log_level == 0) {
847 if (add[2] != del[2] || add[1] != del[1] || add[0] != del[0]) {
849 "Diff: --- %d.%d.%d %s", del[0], del[1], del[2], fmt);
851 "Diff: +++ %d.%d.%d %s", add[0], add[1], add[2], digest);
853 }
else if (patchset != NULL && (add[0] || add[1] || add[2])) {
855 "%s: Local-only Change: %d.%d.%d",
function ?
function :
"",
856 add[0], add[1], add[2]);
861 xmlNode *change = NULL;
863 for (change = __xml_first_child(patchset); change != NULL; change = __xml_next(change)) {
868 }
else if(strcmp(op,
"create") == 0) {
869 int lpc = 0, max = 0;
872 max = strlen(prefix);
873 __xml_log_element(log_level, __FILE__,
function, __LINE__, prefix, change->children,
876 for(lpc = 2; lpc < max; lpc++) {
880 __xml_log_element(log_level, __FILE__,
function, __LINE__, prefix, change->children,
884 }
else if(strcmp(op,
"move") == 0) {
887 }
else if(strcmp(op,
"modify") == 0) {
896 for (child = __xml_first_child(clist); child != NULL; child = __xml_next(child)) {
901 }
else if(strcmp(op,
"set") == 0) {
907 o_set += snprintf(buffer_set + o_set,
XML_BUFFER_SIZE - o_set,
"@%s=%s", name, value);
909 }
else if(strcmp(op,
"unset") == 0) {
911 o_unset += snprintf(buffer_unset + o_unset,
XML_BUFFER_SIZE - o_unset,
", ");
913 o_unset += snprintf(buffer_unset + o_unset,
XML_BUFFER_SIZE - o_unset,
"@%s", name);
917 do_crm_log_alias(log_level, __FILE__,
function, __LINE__,
"+ %s: %s", xpath, buffer_set);
920 do_crm_log_alias(log_level, __FILE__,
function, __LINE__,
"-- %s: %s", xpath, buffer_unset);
923 }
else if(strcmp(op,
"delete") == 0) {
928 do_crm_log_alias(log_level, __FILE__,
function, __LINE__,
"-- %s (%d)", xpath, position);
938 if (log_level < LOG_DEBUG ||
function == NULL) {
943 for (child = __xml_first_child(removed); child != NULL; child = __xml_next(child)) {
955 for (child = __xml_first_child(added); child != NULL; child = __xml_next(child)) {
975 doc = xml->doc->_private;
980 for(gIter = doc->
deleted_objs; gIter; gIter = gIter->next) {
983 if (deleted_obj->position >= 0) {
985 deleted_obj->path, deleted_obj->position);
1000 xmlNode *top = NULL;
1007 crm_trace(
"Accepting changes to %p", xml);
1008 doc = xml->doc->_private;
1009 top = xmlDocGetRootElement(xml->doc);
1011 __xml_private_clean(xml->doc->_private);
1019 __xml_accept_changes(top);
1023 find_element(xmlNode *haystack, xmlNode *needle, gboolean exact)
1026 return (needle->type == XML_COMMENT_NODE)?
1027 find_xml_comment(haystack, needle, exact)
1028 :
find_entity(haystack, crm_element_name(needle),
ID(needle));
1033 __subtract_xml_object(xmlNode * target, xmlNode * patch)
1035 xmlNode *patch_child = NULL;
1036 xmlNode *cIter = NULL;
1037 xmlAttrPtr xIter = NULL;
1040 const char *name = NULL;
1041 const char *value = NULL;
1043 if (target == NULL || patch == NULL) {
1047 if (target->type == XML_COMMENT_NODE) {
1050 subtract_xml_comment(target->parent, target, patch, &dummy);
1053 name = crm_element_name(target);
1061 if (value != NULL && strcmp(value,
"removed:top") == 0) {
1062 crm_trace(
"We are the root of the deletion: %s.id=%s", name,
id);
1068 for (xIter = pcmk__first_xml_attr(patch); xIter != NULL; xIter = xIter->next) {
1069 const char *p_name = (
const char *)xIter->name;
1078 cIter = __xml_first_child(target);
1080 xmlNode *target_child = cIter;
1082 cIter = __xml_next(cIter);
1083 patch_child = find_element(patch, target_child, FALSE);
1084 __subtract_xml_object(target_child, patch_child);
1090 __add_xml_object(xmlNode * parent, xmlNode * target, xmlNode * patch)
1092 xmlNode *patch_child = NULL;
1093 xmlNode *target_child = NULL;
1094 xmlAttrPtr xIter = NULL;
1096 const char *
id = NULL;
1097 const char *name = NULL;
1098 const char *value = NULL;
1100 if (patch == NULL) {
1102 }
else if (parent == NULL && target == NULL) {
1110 && strcmp(value,
"added:top") == 0) {
1112 name = crm_element_name(patch);
1113 crm_trace(
"We are the root of the addition: %s.id=%s", name,
id);
1117 }
else if(target == NULL) {
1119 name = crm_element_name(patch);
1120 crm_err(
"Could not locate: %s.id=%s", name,
id);
1124 if (target->type == XML_COMMENT_NODE) {
1125 add_xml_comment(parent, target, patch);
1128 name = crm_element_name(target);
1133 for (xIter = pcmk__first_xml_attr(patch); xIter != NULL; xIter = xIter->next) {
1134 const char *p_name = (
const char *)xIter->name;
1142 for (patch_child = __xml_first_child(patch); patch_child != NULL;
1143 patch_child = __xml_next(patch_child)) {
1145 target_child = find_element(target, patch_child, FALSE);
1146 __add_xml_object(target, target_child, patch_child);
1162 find_patch_xml_node(xmlNode *patchset,
int format,
bool added,
1163 xmlNode **patch_node)
1170 label = added?
"diff-added" :
"diff-removed";
1173 if (cib_node != NULL) {
1174 *patch_node = cib_node;
1178 label = added?
"target" :
"source";
1183 crm_warn(
"Unknown patch format: %d", format);
1194 xmlNode *tmp = NULL;
1196 const char *vfields[] = {
1206 if (!find_patch_xml_node(patchset, format, FALSE, &tmp)) {
1210 for(lpc = 0; lpc <
DIMOF(vfields); lpc++) {
1212 crm_trace(
"Got %d for del[%s]", del[lpc], vfields[lpc]);
1217 if (!find_patch_xml_node(patchset, format, TRUE, &tmp)) {
1221 for(lpc = 0; lpc <
DIMOF(vfields); lpc++) {
1223 crm_trace(
"Got %d for add[%s]", add[lpc], vfields[lpc]);
1231 xml_patch_version_check(xmlNode *xml, xmlNode *patchset,
int format)
1234 bool changed = FALSE;
1236 int this[] = { 0, 0, 0 };
1237 int add[] = { 0, 0, 0 };
1238 int del[] = { 0, 0, 0 };
1240 const char *vfields[] = {
1246 for(lpc = 0; lpc <
DIMOF(vfields); lpc++) {
1248 crm_trace(
"Got %d for this[%s]",
this[lpc], vfields[lpc]);
1249 if (
this[lpc] < 0) {
1257 add[2] =
this[2] + 1;
1258 for(lpc = 0; lpc <
DIMOF(vfields); lpc++) {
1259 del[lpc] =
this[lpc];
1264 for(lpc = 0; lpc <
DIMOF(vfields); lpc++) {
1265 if(
this[lpc] < del[lpc]) {
1266 crm_debug(
"Current %s is too low (%d.%d.%d < %d.%d.%d --> %d.%d.%d)", vfields[lpc],
1267 this[0],
this[1],
this[2], del[0], del[1], del[2], add[0], add[1], add[2]);
1270 }
else if(
this[lpc] > del[lpc]) {
1271 crm_info(
"Current %s is too high (%d.%d.%d > %d.%d.%d --> %d.%d.%d) %p", vfields[lpc],
1272 this[0],
this[1],
this[2], del[0], del[1], del[2], add[0], add[1], add[2], patchset);
1278 for(lpc = 0; lpc <
DIMOF(vfields); lpc++) {
1279 if(add[lpc] > del[lpc]) {
1284 if(changed == FALSE) {
1285 crm_notice(
"Versions did not change in patch %d.%d.%d", add[0], add[1], add[2]);
1289 crm_debug(
"Can apply patch %d.%d.%d to %d.%d.%d",
1290 add[0], add[1], add[2],
this[0],
this[1],
this[2]);
1295 xml_apply_patchset_v1(xmlNode *xml, xmlNode *patchset)
1298 int root_nodes_seen = 0;
1300 xmlNode *child_diff = NULL;
1301 xmlNode *added =
find_xml_node(patchset,
"diff-added", FALSE);
1302 xmlNode *removed =
find_xml_node(patchset,
"diff-removed", FALSE);
1306 for (child_diff = __xml_first_child(removed); child_diff != NULL;
1307 child_diff = __xml_next(child_diff)) {
1308 CRM_CHECK(root_nodes_seen == 0, rc = FALSE);
1309 if (root_nodes_seen == 0) {
1310 __subtract_xml_object(xml, child_diff);
1315 if (root_nodes_seen > 1) {
1316 crm_err(
"(-) Diffs cannot contain more than one change set... saw %d", root_nodes_seen);
1320 root_nodes_seen = 0;
1323 xmlNode *child_diff = NULL;
1325 for (child_diff = __xml_first_child(added); child_diff != NULL;
1326 child_diff = __xml_next(child_diff)) {
1327 CRM_CHECK(root_nodes_seen == 0, rc = FALSE);
1328 if (root_nodes_seen == 0) {
1329 __add_xml_object(NULL, xml, child_diff);
1335 if (root_nodes_seen > 1) {
1336 crm_err(
"(+) Diffs cannot contain more than one change set... saw %d", root_nodes_seen);
1347 __first_xml_child_match(xmlNode *parent,
const char *name,
const char *
id,
int position)
1349 xmlNode *cIter = NULL;
1351 for (cIter = __xml_first_child(parent); cIter != NULL; cIter = __xml_next(cIter)) {
1352 if(strcmp((
const char *)cIter->name, name) != 0) {
1355 const char *cid =
ID(cIter);
1356 if(cid == NULL || strcmp(cid,
id) != 0) {
1362 if (cIter->type == XML_COMMENT_NODE
1364 && __xml_offset(cIter) != position) {
1387 __xml_find_path(xmlNode *top,
const char *key,
int target_position)
1389 xmlNode *target = (xmlNode*) top->doc;
1390 const char *current = key;
1400 key_len = strlen(key);
1406 remainder = calloc(key_len,
sizeof(
char));
1409 section = calloc(key_len,
sizeof(
char));
1412 id = calloc(key_len,
sizeof(
char));
1415 tag = calloc(key_len,
sizeof(
char));
1420 rc = sscanf(current,
"/%[^/]%s", section, remainder);
1423 int f = sscanf(section,
"%[^[][@id='%[^']", tag,
id);
1424 int current_position = -1;
1429 if ((rc == 1) && (target_position >= 0)) {
1430 current_position = target_position;
1435 target = __first_xml_child_match(target, tag, NULL, current_position);
1438 target = __first_xml_child_match(target, tag,
id, current_position);
1445 current = remainder;
1449 }
while ((rc == 2) && target);
1453 (path = (
char *) xmlGetNodePath(target)), key);
1467 xml_apply_patchset_v2(xmlNode *xml, xmlNode *patchset)
1470 xmlNode *change = NULL;
1471 for (change = __xml_first_child(patchset); change != NULL; change = __xml_next(change)) {
1472 xmlNode *match = NULL;
1477 crm_trace(
"Processing %s %s", change->name, op);
1482 if(strcmp(op,
"delete") == 0) {
1485 match = __xml_find_path(xml, xpath, position);
1486 crm_trace(
"Performing %s on %s with %p", op, xpath, match);
1488 if(match == NULL && strcmp(op,
"delete") == 0) {
1489 crm_debug(
"No %s match for %s in %p", op, xpath, xml->doc);
1492 }
else if(match == NULL) {
1493 crm_err(
"No %s match for %s in %p", op, xpath, xml->doc);
1497 }
else if(strcmp(op,
"create") == 0) {
1499 xmlNode *child = NULL;
1500 xmlNode *match_child = NULL;
1502 match_child = match->children;
1505 while(match_child && position != __xml_offset(match_child)) {
1506 match_child = match_child->next;
1509 child = xmlDocCopyNode(change->children, match->doc, 1);
1511 crm_trace(
"Adding %s at position %d", child->name, position);
1512 xmlAddPrevSibling(match_child, child);
1514 }
else if(match->last) {
1515 crm_trace(
"Adding %s at position %d (end)", child->name, position);
1516 xmlAddNextSibling(match->last, child);
1519 crm_trace(
"Adding %s at position %d (first)", child->name, position);
1521 xmlAddChild(match, child);
1523 crm_node_created(child);
1525 }
else if(strcmp(op,
"move") == 0) {
1529 if(position != __xml_offset(match)) {
1530 xmlNode *match_child = NULL;
1533 if(p > __xml_offset(match)) {
1538 match_child = match->parent->children;
1540 while(match_child && p != __xml_offset(match_child)) {
1541 match_child = match_child->next;
1544 crm_trace(
"Moving %s to position %d (was %d, prev %p, %s %p)",
1545 match->name, position, __xml_offset(match), match->prev,
1546 match_child?
"next":
"last", match_child?match_child:match->parent->last);
1549 xmlAddPrevSibling(match_child, match);
1553 xmlAddNextSibling(match->parent->last, match);
1557 crm_trace(
"%s is already in position %d", match->name, position);
1560 if(position != __xml_offset(match)) {
1561 crm_err(
"Moved %s.%s to position %d instead of %d (%p)",
1562 match->name,
ID(match), __xml_offset(match), position, match->prev);
1566 }
else if(strcmp(op,
"delete") == 0) {
1569 }
else if(strcmp(op,
"modify") == 0) {
1570 xmlAttr *pIter = pcmk__first_xml_attr(match);
1577 while(pIter != NULL) {
1578 const char *name = (
const char *)pIter->name;
1580 pIter = pIter->next;
1584 for (pIter = pcmk__first_xml_attr(attrs); pIter != NULL; pIter = pIter->next) {
1585 const char *name = (
const char *)pIter->name;
1592 crm_err(
"Unknown operation: %s", op);
1603 xmlNode *old = NULL;
1606 if(patchset == NULL) {
1614 rc = xml_patch_version_check(xml, patchset, format);
1628 rc = xml_apply_patchset_v1(xml, patchset);
1631 rc = xml_apply_patchset_v2(xml, patchset);
1634 crm_err(
"Unknown patch format: %d", format);
1640 static struct qb_log_callsite *digest_cs = NULL;
1642 char *new_digest = NULL;
1645 if (digest_cs == NULL) {
1647 qb_log_callsite_get(__func__, __FILE__,
"diff-digest",
LOG_TRACE, __LINE__,
1653 crm_info(
"v%d digest mis-match: expected %s, calculated %s", format, digest, new_digest);
1656 if (digest_cs && digest_cs->targets) {
1662 crm_trace(
"%p %.6x", digest_cs, digest_cs ? digest_cs->targets : 0);
1666 crm_trace(
"v%d digest matched: expected %s, calculated %s", format, digest, new_digest);
1678 xmlNode *a_child = NULL;
1679 const char *name =
"NULL";
1682 name = crm_element_name(root);
1685 if (search_path == NULL) {
1686 crm_warn(
"Will never find <NULL>");
1690 for (a_child = __xml_first_child(root); a_child != NULL; a_child = __xml_next(a_child)) {
1691 if (strcmp((
const char *)a_child->name, search_path) == 0) {
1698 crm_warn(
"Could not find %s in %s.", search_path, name);
1699 }
else if (root != NULL) {
1700 crm_trace(
"Could not find %s in %s.", search_path, name);
1702 crm_trace(
"Could not find %s in <NULL>.", search_path);
1712 find_entity_by_attr_or_just_name(xmlNode *parent,
const char *node_name,
1713 const char *attr_n,
const char *attr_v)
1718 CRM_CHECK(attr_n == NULL || attr_v != NULL,
return NULL);
1720 for (child = __xml_first_child(parent); child != NULL; child = __xml_next(child)) {
1722 if (node_name == NULL || !strcmp((
const char *) child->name, node_name)) {
1732 attr_n ? attr_n :
"",
1734 attr_n ? attr_v :
"",
1735 crm_element_name(parent));
1743 return find_entity_by_attr_or_just_name(parent, node_name,
1751 crm_warn(
"No node to copy properties from");
1753 }
else if (target == NULL) {
1754 crm_err(
"No node to copy properties into");
1757 xmlAttrPtr pIter = NULL;
1759 for (pIter = pcmk__first_xml_attr(src); pIter != NULL; pIter = pIter->next) {
1760 const char *p_name = (
const char *)pIter->name;
1761 const char *p_value = pcmk__xml_attr_value(pIter);
1774 xmlNode *child = NULL;
1775 xmlAttrPtr pIter = NULL;
1777 for (pIter = pcmk__first_xml_attr(target); pIter != NULL; pIter = pIter->next) {
1778 const char *p_name = (
const char *)pIter->name;
1779 const char *p_value = pcmk__xml_attr_value(pIter);
1783 for (child = __xml_first_child(target); child != NULL; child = __xml_next(child)) {
1796 const char *old_value = NULL;
1798 if (value == NULL || name == NULL) {
1804 if (old_value == NULL) {
1806 goto set_unexpanded;
1808 }
else if (strstr(value, name) != value) {
1809 goto set_unexpanded;
1812 name_len = strlen(name);
1813 value_len = strlen(value);
1814 if (value_len < (name_len + 2)
1815 || value[name_len] !=
'+' || (value[name_len + 1] !=
'+' && value[name_len + 1] !=
'=')) {
1816 goto set_unexpanded;
1822 if (old_value != value) {
1826 if (value[name_len + 1] !=
'+') {
1827 const char *offset_s = value + (name_len + 2);
1831 int_value += offset;
1841 if (old_value == value) {
1858 doc = xmlNewDoc((
const xmlChar *)
"1.0");
1859 xmlDocSetRootElement(doc, node);
1860 xmlSetTreeDoc(node, doc);
1868 xmlNode *child = NULL;
1871 CRM_CHECK(src_node != NULL,
return NULL);
1873 child = xmlDocCopyNode(src_node, doc, 1);
1874 xmlAddChild(parent, child);
1875 crm_node_created(child);
1891 xmlNode *node = NULL;
1893 if (name == NULL || name[0] == 0) {
1894 CRM_CHECK(name != NULL && name[0] == 0,
return NULL);
1898 if (parent == NULL) {
1899 doc = xmlNewDoc((
const xmlChar *)
"1.0");
1900 node = xmlNewDocRawNode(doc, NULL, (
const xmlChar *)name, NULL);
1901 xmlDocSetRootElement(doc, node);
1905 node = xmlNewDocRawNode(doc, NULL, (
const xmlChar *)name, NULL);
1906 xmlAddChild(parent, node);
1908 crm_node_created(node);
1914 int offset,
size_t buffer_size)
1916 const char *
id =
ID(xml);
1918 if(offset == 0 && prefix == NULL && xml->parent) {
1924 offset += snprintf(buffer + offset, buffer_size - offset,
1925 "/%s[@id='%s']", (
const char *) xml->name,
id);
1926 }
else if(xml->name) {
1927 offset += snprintf(buffer + offset, buffer_size - offset,
1928 "/%s", (
const char *) xml->name);
1941 return strdup(buffer);
1947 free_xml_with_position(xmlNode * child,
int position)
1949 if (child != NULL) {
1950 xmlNode *top = NULL;
1951 xmlDoc *doc = child->doc;
1955 top = xmlDocGetRootElement(doc);
1958 if (doc != NULL && top == child) {
1977 sizeof(buffer)) > 0) {
1980 crm_trace(
"Deleting %s %p from %p", buffer, child, doc);
1982 deleted_obj->path = strdup(buffer);
1984 deleted_obj->position = -1;
1986 if (child->type == XML_COMMENT_NODE) {
1987 if (position >= 0) {
1988 deleted_obj->position = position;
1991 deleted_obj->position = __xml_offset(child);
2004 xmlUnlinkNode(child);
2014 free_xml_with_position(child, -1);
2020 xmlDoc *doc = xmlNewDoc((
const xmlChar *)
"1.0");
2021 xmlNode *copy = xmlDocCopyNode(src, doc, 1);
2023 xmlDocSetRootElement(doc, copy);
2024 xmlSetTreeDoc(copy, doc);
2029 crm_xml_err(
void *ctx,
const char *fmt, ...)
2030 G_GNUC_PRINTF(2, 3);
2033 crm_xml_err(
void *ctx, const
char *fmt, ...)
2036 static struct qb_log_callsite *xml_error_cs = NULL;
2038 if (xml_error_cs == NULL) {
2039 xml_error_cs = qb_log_callsite_get(
2044 if (xml_error_cs && xml_error_cs->targets) {
2046 crm_abort(__FILE__, __PRETTY_FUNCTION__, __LINE__,
"xml library error",
2048 "XML Error: ", fmt, ap);
2058 xmlNode *xml = NULL;
2059 xmlDocPtr output = NULL;
2060 xmlParserCtxtPtr ctxt = NULL;
2061 xmlErrorPtr last_error = NULL;
2063 if (input == NULL) {
2064 crm_err(
"Can't parse NULL input");
2069 ctxt = xmlNewParserCtxt();
2074 xmlCtxtResetLastError(ctxt);
2075 xmlSetGenericErrorFunc(ctxt, crm_xml_err);
2078 xmlCtxtReadDoc(ctxt, (
const xmlChar *)input, NULL, NULL,
2079 XML_PARSE_NOBLANKS | XML_PARSE_RECOVER);
2081 xml = xmlDocGetRootElement(output);
2083 last_error = xmlCtxtGetLastError(ctxt);
2084 if (last_error && last_error->code != XML_ERR_OK) {
2090 crm_warn(
"Parsing failed (domain=%d, level=%d, code=%d): %s",
2091 last_error->domain, last_error->level, last_error->code, last_error->message);
2093 if (last_error->code == XML_ERR_DOCUMENT_EMPTY) {
2096 }
else if (last_error->code != XML_ERR_DOCUMENT_END) {
2097 crm_err(
"Couldn't%s parse %d chars: %s", xml ?
" fully" :
"", (
int)strlen(input),
2104 int len = strlen(input);
2108 crm_warn(
"Parse error[+%.3d]: %.80s", lpc, input+lpc);
2116 xmlFreeParserCtxt(ctxt);
2123 size_t data_length = 0;
2124 size_t read_chars = 0;
2126 char *xml_buffer = NULL;
2127 xmlNode *xml_obj = NULL;
2131 read_chars = fread(xml_buffer + data_length, 1,
XML_BUFFER_SIZE, stdin);
2132 data_length += read_chars;
2135 if (data_length == 0) {
2136 crm_warn(
"No XML supplied on stdin");
2141 xml_buffer[data_length] =
'\0';
2150 decompress_file(
const char *filename)
2152 char *buffer = NULL;
2156 size_t length = 0, read_len = 0;
2158 BZFILE *bz_file = NULL;
2159 FILE *input = fopen(filename,
"r");
2161 if (input == NULL) {
2162 crm_perror(LOG_ERR,
"Could not open %s for reading", filename);
2166 bz_file = BZ2_bzReadOpen(&rc, input, 0, 0, NULL, 0);
2168 crm_err(
"Could not prepare to read compressed %s: %s "
2170 BZ2_bzReadClose(&rc, bz_file);
2175 while (rc == BZ_OK) {
2177 read_len = BZ2_bzRead(&rc, bz_file, buffer + length,
XML_BUFFER_SIZE);
2179 crm_trace(
"Read %ld bytes from file: %d", (
long)read_len, rc);
2181 if (rc == BZ_OK || rc == BZ_STREAM_END) {
2186 buffer[length] =
'\0';
2188 if (rc != BZ_STREAM_END) {
2189 crm_err(
"Could not read compressed %s: %s "
2195 BZ2_bzReadClose(&rc, bz_file);
2199 crm_err(
"Could not read compressed %s: not built with bzlib support",
2208 xmlNode *iter = xml->children;
2211 xmlNode *next = iter->next;
2213 switch (iter->type) {
2216 xmlUnlinkNode(iter);
2220 case XML_ELEMENT_NODE:
2237 xmlNode *xml = NULL;
2238 xmlDocPtr output = NULL;
2239 gboolean uncompressed = TRUE;
2240 xmlParserCtxtPtr ctxt = NULL;
2241 xmlErrorPtr last_error = NULL;
2242 static int xml_options = XML_PARSE_NOBLANKS | XML_PARSE_RECOVER;
2245 ctxt = xmlNewParserCtxt();
2250 xmlCtxtResetLastError(ctxt);
2251 xmlSetGenericErrorFunc(ctxt, crm_xml_err);
2258 if (filename == NULL) {
2260 output = xmlCtxtReadFd(ctxt, STDIN_FILENO,
"unknown.xml", NULL, xml_options);
2262 }
else if (uncompressed) {
2263 output = xmlCtxtReadFile(ctxt, filename, NULL, xml_options);
2266 char *input = decompress_file(filename);
2268 output = xmlCtxtReadDoc(ctxt, (
const xmlChar *)input, NULL, NULL,
2273 if (output && (xml = xmlDocGetRootElement(output))) {
2277 last_error = xmlCtxtGetLastError(ctxt);
2278 if (last_error && last_error->code != XML_ERR_OK) {
2284 crm_err(
"Parsing failed (domain=%d, level=%d, code=%d): %s",
2285 last_error->domain, last_error->level, last_error->code, last_error->message);
2287 if (last_error && last_error->code != XML_ERR_OK) {
2288 crm_err(
"Couldn't%s parse %s", xml ?
" fully" :
"", filename);
2295 xmlFreeParserCtxt(ctxt);
2310 time_t now = time(NULL);
2311 char *now_str = ctime(&now);
2327 for (c =
id; *c; ++c) {
2352 va_start(ap, format);
2353 len = vasprintf(&
id, format, ap);
2374 write_xml_stream(xmlNode * xml_node,
const char *filename, FILE * stream, gboolean compress)
2377 char *buffer = NULL;
2378 unsigned int out = 0;
2391 unsigned int in = 0;
2392 BZFILE *bz_file = NULL;
2394 bz_file = BZ2_bzWriteOpen(&rc, stream, 5, 0, 30);
2396 crm_warn(
"Not compressing %s: could not prepare file stream: %s "
2399 BZ2_bzWrite(&rc, bz_file, buffer, strlen(buffer));
2401 crm_warn(
"Not compressing %s: could not compress data: %s "
2402 CRM_XS " bzerror=%d errno=%d",
2408 BZ2_bzWriteClose(&rc, bz_file, 0, &in, &out);
2410 crm_warn(
"Not compressing %s: could not write compressed data: %s "
2411 CRM_XS " bzerror=%d errno=%d",
2416 crm_trace(
"Compressed XML for %s from %u bytes to %u",
2421 crm_warn(
"Not compressing %s: not built with bzlib support", filename);
2426 res = fprintf(stream,
"%s", buffer);
2436 if (fflush(stream) != 0) {
2438 crm_perror(LOG_ERR,
"flushing %s", filename);
2442 if (fsync(fileno(stream)) < 0 && errno != EROFS && errno != EINVAL) {
2444 crm_perror(LOG_ERR,
"synchronizing %s", filename);
2449 crm_trace(
"Saved %d bytes%s to %s as XML",
2450 res, ((out > 0)?
" (compressed)" :
""), filename);
2467 write_xml_fd(xmlNode * xml_node,
const char *filename,
int fd, gboolean compress)
2469 FILE *stream = NULL;
2471 CRM_CHECK(xml_node && (fd > 0),
return -EINVAL);
2472 stream = fdopen(fd,
"w");
2473 if (stream == NULL) {
2476 return write_xml_stream(xml_node, filename, stream, compress);
2491 FILE *stream = NULL;
2493 CRM_CHECK(xml_node && filename,
return -EINVAL);
2494 stream = fopen(filename,
"w");
2495 if (stream == NULL) {
2498 return write_xml_stream(xml_node, filename, stream, compress);
2506 return __xml_first_child(tmp);
2519 crm_xml_escape_shuffle(
char *text,
int start,
int *length,
const char *replace)
2522 int offset = strlen(replace) - 1;
2525 text = realloc_safe(text, *length);
2527 for (lpc = (*length) - 1; lpc > (start + offset); lpc--) {
2528 text[lpc] = text[lpc - offset];
2531 memcpy(text + start, replace, offset + 1);
2540 int length = 1 + strlen(text);
2541 char *copy = strdup(text);
2558 for (index = 0; index < length; index++) {
2559 switch (copy[index]) {
2563 copy = crm_xml_escape_shuffle(copy, index, &length,
"<");
2567 copy = crm_xml_escape_shuffle(copy, index, &length,
">");
2571 copy = crm_xml_escape_shuffle(copy, index, &length,
""");
2575 copy = crm_xml_escape_shuffle(copy, index, &length,
"'");
2579 copy = crm_xml_escape_shuffle(copy, index, &length,
"&");
2584 copy = crm_xml_escape_shuffle(copy, index, &length,
" ");
2589 copy = crm_xml_escape_shuffle(copy, index, &length,
"\\n");
2593 copy = crm_xml_escape_shuffle(copy, index, &length,
"\\r");
2603 if(copy[index] <
' ' || copy[index] >
'~') {
2607 copy = crm_xml_escape_shuffle(copy, index, &length, replace);
2621 dump_xml_attr(xmlAttrPtr attr,
int options,
char **buffer,
int *offset,
int *max)
2623 char *p_value = NULL;
2624 const char *p_name = NULL;
2628 if (attr == NULL || attr->children == NULL) {
2637 p_name = (
const char *)attr->name;
2639 buffer_print(*buffer, *max, *offset,
" %s=\"%s\"", p_name, p_value);
2644 __xml_log_element(
int log_level,
const char *file,
const char *
function,
int line,
2645 const char *prefix, xmlNode *
data,
int depth,
int options)
2649 const char *name = NULL;
2650 const char *hidden = NULL;
2652 xmlNode *child = NULL;
2653 xmlAttrPtr pIter = NULL;
2659 name = crm_element_name(
data);
2662 char *buffer = NULL;
2664 insert_prefix(options, &buffer, &offset, &max, depth);
2666 if (
data->type == XML_COMMENT_NODE) {
2673 for (pIter = pcmk__first_xml_attr(
data); pIter != NULL; pIter = pIter->next) {
2675 const char *p_name = (
const char *)pIter->name;
2676 const char *p_value = pcmk__xml_attr_value(pIter);
2677 char *p_copy = NULL;
2686 }
else if (hidden != NULL && p_name[0] != 0 && strstr(hidden, p_name) != NULL) {
2687 p_copy = strdup(
"*****");
2693 buffer_print(buffer, max, offset,
" %s=\"%s\"", p_name, p_copy);
2708 do_crm_log_alias(log_level, file,
function, line,
"%s %s", prefix, buffer);
2712 if(
data->type == XML_COMMENT_NODE) {
2722 for (child = __xml_first_child(
data); child != NULL; child = __xml_next(child)) {
2728 char *buffer = NULL;
2730 insert_prefix(options, &buffer, &offset, &max, depth);
2733 do_crm_log_alias(log_level, file,
function, line,
"%s %s", prefix, buffer);
2739 __xml_log_change_element(
int log_level,
const char *file,
const char *
function,
int line,
2740 const char *prefix, xmlNode *
data,
int depth,
int options)
2743 char *prefix_m = NULL;
2744 xmlNode *child = NULL;
2745 xmlAttrPtr pIter = NULL;
2753 prefix_m = strdup(prefix);
2758 __xml_log_element(log_level, file,
function, line,
2762 char *spaces = calloc(80, 1);
2763 int s_count = 0, s_max = 80;
2764 char *prefix_del = NULL;
2765 char *prefix_moved = NULL;
2766 const char *
flags = prefix;
2768 insert_prefix(options, &spaces, &s_count, &s_max, depth);
2769 prefix_del = strdup(prefix);
2770 prefix_del[0] =
'-';
2771 prefix_del[1] =
'-';
2772 prefix_moved = strdup(prefix);
2773 prefix_moved[1] =
'~';
2776 flags = prefix_moved;
2781 __xml_log_element(log_level, file,
function, line,
2784 for (pIter = pcmk__first_xml_attr(
data); pIter != NULL; pIter = pIter->next) {
2785 const char *aname = (
const char*)pIter->name;
2787 p = pIter->_private;
2792 "%s %s @%s=%s",
flags, spaces, aname, value);
2804 flags = prefix_moved;
2810 "%s %s @%s=%s",
flags, spaces, aname, value);
2817 for (child = __xml_first_child(
data); child != NULL; child = __xml_next(child)) {
2818 __xml_log_change_element(log_level, file,
function, line, prefix, child, depth + 1, options);
2821 __xml_log_element(log_level, file,
function, line,
2825 for (child = __xml_first_child(
data); child != NULL; child = __xml_next(child)) {
2826 __xml_log_change_element(log_level, file,
function, line, prefix, child, depth + 1, options);
2836 const char *prefix, xmlNode *
data,
int depth,
int options)
2838 xmlNode *a_child = NULL;
2840 char *prefix_m = NULL;
2842 if (prefix == NULL) {
2849 "No data to dump as XML");
2854 __xml_log_change_element(log_level, file,
function, line, prefix,
data, depth, options);
2862 prefix_m = strdup(prefix);
2869 prefix_m = strdup(prefix);
2878 for (a_child = __xml_first_child(
data); a_child != NULL; a_child = __xml_next(a_child)) {
2879 log_data_element(log_level, file,
function, line, prefix, a_child, depth + 1, options);
2882 __xml_log_element(log_level, file,
function, line, prefix,
data, depth,
2889 dump_filtered_xml(xmlNode *
data,
int options,
char **buffer,
int *offset,
int *max)
2892 xmlAttrPtr xIter = NULL;
2893 static int filter_len =
DIMOF(filter);
2895 for (lpc = 0; options && lpc < filter_len; lpc++) {
2896 filter[lpc].found = FALSE;
2899 for (xIter = pcmk__first_xml_attr(
data); xIter != NULL; xIter = xIter->next) {
2901 const char *p_name = (
const char *)xIter->name;
2903 for (lpc = 0; skip == FALSE && lpc < filter_len; lpc++) {
2904 if (filter[lpc].found == FALSE && strcmp(p_name, filter[lpc].
string) == 0) {
2905 filter[lpc].found = TRUE;
2911 if (skip == FALSE) {
2912 dump_xml_attr(xIter, options, buffer, offset, max);
2918 dump_xml_element(xmlNode *
data,
int options,
char **buffer,
int *offset,
int *max,
int depth)
2920 const char *name = NULL;
2931 if (*buffer == NULL) {
2936 name = crm_element_name(
data);
2939 insert_prefix(options, buffer, offset, max, depth);
2943 dump_filtered_xml(
data, options, buffer, offset, max);
2946 xmlAttrPtr xIter = NULL;
2948 for (xIter = pcmk__first_xml_attr(
data); xIter != NULL; xIter = xIter->next) {
2949 dump_xml_attr(xIter, options, buffer, offset, max);
2953 if (
data->children == NULL) {
2964 if (
data->children) {
2965 xmlNode *xChild = NULL;
2966 for(xChild =
data->children; xChild != NULL; xChild = xChild->next) {
2967 crm_xml_dump(xChild, options, buffer, offset, max, depth + 1);
2970 insert_prefix(options, buffer, offset, max, depth);
2980 dump_xml_text(xmlNode *
data,
int options,
char **buffer,
int *offset,
int *max,
int depth)
2991 if (*buffer == NULL) {
2996 insert_prefix(options, buffer, offset, max, depth);
3007 dump_xml_comment(xmlNode *
data,
int options,
char **buffer,
int *offset,
int *max,
int depth)
3018 if (*buffer == NULL) {
3023 insert_prefix(options, buffer, offset, max, depth);
3058 xmlBuffer *xml_buffer = NULL;
3066 xml_buffer = xmlBufferCreate();
3077 xmlBufferSetAllocationScheme(xml_buffer, XML_BUFFER_ALLOC_DOUBLEIT);
3081 *buffer = strdup((
char *)xml_buffer->content);
3085 if ((now + 1) < next) {
3087 crm_err(
"xmlNodeDump() -> %dbytes took %ds", *max, next - now);
3090 xmlBufferFree(xml_buffer);
3095 switch(
data->type) {
3096 case XML_ELEMENT_NODE:
3098 dump_xml_element(
data, options, buffer, offset, max, depth);
3103 dump_xml_text(
data, options, buffer, offset, max, depth);
3106 case XML_COMMENT_NODE:
3107 dump_xml_comment(
data, options, buffer, offset, max, depth);
3146 char *buffer = NULL;
3147 int offset = 0, max = 0;
3156 char *buffer = NULL;
3157 int offset = 0, max = 0;
3166 char *buffer = NULL;
3167 int offset = 0, max = 0;
3169 crm_xml_dump(an_xml_node, 0, &buffer, &offset, &max, 0);
3176 if (xml_root != NULL && xml_root->children != NULL) {
3186 crm_trace(
"Cannot remove %s from %s", name, obj->name);
3191 xmlAttr *attr = xmlHasProp(obj, (
const xmlChar *)name);
3199 xmlUnsetProp(obj, (
const xmlChar *)name);
3206 xmlNode *child = NULL;
3211 for (child = __xml_first_child(a_node); child != NULL; child = __xml_next(child)) {
3221 if (filename == NULL) {
3229 crm_info(
"Saving %s to %s", desc, filename);
3237 gboolean result = TRUE;
3238 int root_nodes_seen = 0;
3239 static struct qb_log_callsite *digest_cs = NULL;
3243 xmlNode *child_diff = NULL;
3245 xmlNode *removed =
find_xml_node(diff,
"diff-removed", FALSE);
3247 CRM_CHECK(new_xml != NULL,
return FALSE);
3248 if (digest_cs == NULL) {
3250 qb_log_callsite_get(__func__, __FILE__,
"diff-digest",
LOG_TRACE, __LINE__,
3255 for (child_diff = __xml_first_child(removed); child_diff != NULL;
3256 child_diff = __xml_next(child_diff)) {
3257 CRM_CHECK(root_nodes_seen == 0, result = FALSE);
3258 if (root_nodes_seen == 0) {
3264 if (root_nodes_seen == 0) {
3267 }
else if (root_nodes_seen > 1) {
3268 crm_err(
"(-) Diffs cannot contain more than one change set..." " saw %d", root_nodes_seen);
3272 root_nodes_seen = 0;
3275 xmlNode *child_diff = NULL;
3277 for (child_diff = __xml_first_child(added); child_diff != NULL;
3278 child_diff = __xml_next(child_diff)) {
3279 CRM_CHECK(root_nodes_seen == 0, result = FALSE);
3280 if (root_nodes_seen == 0) {
3281 add_xml_object(NULL, *new_xml, child_diff, TRUE);
3287 if (root_nodes_seen > 1) {
3288 crm_err(
"(+) Diffs cannot contain more than one change set..." " saw %d", root_nodes_seen);
3291 }
else if (result && digest) {
3292 char *new_digest = NULL;
3297 crm_info(
"Digest mis-match: expected %s, calculated %s", digest, new_digest);
3300 crm_trace(
"%p %.6x", digest_cs, digest_cs ? digest_cs->targets : 0);
3301 if (digest_cs && digest_cs->targets) {
3308 crm_trace(
"Digest matched: expected %s, calculated %s", digest, new_digest);
3312 }
else if (result) {
3320 __xml_diff_object(xmlNode *old_xml, xmlNode *new_xml)
3322 xmlNode *cIter = NULL;
3323 xmlAttr *pIter = NULL;
3326 if (old_xml == NULL) {
3327 crm_node_created(new_xml);
3341 for (pIter = pcmk__first_xml_attr(new_xml); pIter != NULL; pIter = pIter->next) {
3348 for (pIter = pcmk__first_xml_attr(old_xml); pIter != NULL; ) {
3349 xmlAttr *prop = pIter;
3351 const char *name = (
const char *)pIter->name;
3353 xmlAttr *exists = xmlHasProp(new_xml, pIter->name);
3355 pIter = pIter->next;
3356 if(exists == NULL) {
3357 p = new_xml->doc->_private;
3361 exists = xmlSetProp(new_xml, (
const xmlChar *) name,
3362 (
const xmlChar *) old_value);
3365 p = exists->_private;
3368 crm_trace(
"Lost %s@%s=%s", old_xml->name, name, old_value);
3372 int p_new = __xml_offset((xmlNode*)exists);
3373 int p_old = __xml_offset((xmlNode*)prop);
3376 p = exists->_private;
3379 if(strcmp(value, old_value) != 0) {
3386 old_xml->name, name, old_value, vcopy);
3387 xmlSetProp(new_xml, prop->name, (
const xmlChar *) old_value);
3391 }
else if ((p_old != p_new)
3394 old_xml->name, name, p_old, p_new);
3395 __xml_node_dirty(new_xml);
3403 p = exists->_private;
3410 for (pIter = pcmk__first_xml_attr(new_xml); pIter != NULL; ) {
3411 xmlAttr *prop = pIter;
3414 pIter = pIter->next;
3416 char *name = strdup((
const char *)prop->name);
3419 crm_trace(
"Created %s@%s=%s", new_xml->name, name, value);
3424 xmlUnsetProp(new_xml, prop->name);
3432 for (cIter = __xml_first_child(old_xml); cIter != NULL; ) {
3433 xmlNode *old_child = cIter;
3434 xmlNode *new_child = find_element(new_xml, cIter, TRUE);
3436 cIter = __xml_next(cIter);
3438 __xml_diff_object(old_child, new_child);
3443 xmlNode *top = xmlDocGetRootElement(candidate->doc);
3445 __xml_node_clean(candidate);
3448 free_xml_with_position(candidate, __xml_offset(old_child));
3450 if (find_element(new_xml, old_child, TRUE) == NULL) {
3458 for (cIter = __xml_first_child(new_xml); cIter != NULL; ) {
3459 xmlNode *new_child = cIter;
3460 xmlNode *old_child = find_element(old_xml, cIter, TRUE);
3462 cIter = __xml_next(cIter);
3463 if(old_child == NULL) {
3466 __xml_diff_object(old_child, new_child);
3470 int p_new = __xml_offset(new_child);
3471 int p_old = __xml_offset(old_child);
3473 if(p_old != p_new) {
3476 crm_info(
"%s.%s moved from %d to %d",
3477 new_child->name,
ID(new_child), p_old, p_new);
3478 __xml_node_dirty(new_xml);
3482 p = old_child->_private;
3484 p = new_child->_private;
3503 crm_element_name(new_xml)),
3511 __xml_diff_object(old_xml, new_xml);
3517 xmlNode *tmp1 = NULL;
3534 if (added->children == NULL && removed->children == NULL) {
3545 xmlNode *cIter = NULL;
3546 xmlAttrPtr pIter = NULL;
3547 gboolean can_prune = TRUE;
3548 const char *name = crm_element_name(xml_node);
3557 for (pIter = pcmk__first_xml_attr(xml_node); pIter != NULL; pIter = pIter->next) {
3558 const char *p_name = (
const char *)pIter->name;
3566 cIter = __xml_first_child(xml_node);
3568 xmlNode *child = cIter;
3570 cIter = __xml_next(cIter);
3581 find_xml_comment(xmlNode * root, xmlNode * search_comment, gboolean exact)
3583 xmlNode *a_child = NULL;
3584 int search_offset = __xml_offset(search_comment);
3586 CRM_CHECK(search_comment->type == XML_COMMENT_NODE,
return NULL);
3588 for (a_child = __xml_first_child(root); a_child != NULL; a_child = __xml_next(a_child)) {
3590 int offset = __xml_offset(a_child);
3593 if (offset < search_offset) {
3596 }
else if (offset > search_offset) {
3605 if (a_child->type == XML_COMMENT_NODE
3606 &&
safe_str_eq((
const char *)a_child->content, (
const char *)search_comment->content)) {
3618 subtract_xml_comment(xmlNode * parent, xmlNode * left, xmlNode * right,
3622 CRM_CHECK(left->type == XML_COMMENT_NODE,
return NULL);
3625 ||
safe_str_neq((
const char *)left->content, (
const char *)right->content)) {
3626 xmlNode *deleted = NULL;
3639 gboolean full, gboolean * changed,
const char *marker)
3641 gboolean dummy = FALSE;
3642 gboolean skip = FALSE;
3643 xmlNode *diff = NULL;
3644 xmlNode *right_child = NULL;
3645 xmlNode *left_child = NULL;
3646 xmlAttrPtr xIter = NULL;
3648 const char *
id = NULL;
3649 const char *name = NULL;
3650 const char *value = NULL;
3651 const char *right_val = NULL;
3654 static int filter_len =
DIMOF(filter);
3656 if (changed == NULL) {
3664 if (left->type == XML_COMMENT_NODE) {
3665 return subtract_xml_comment(parent, left, right, changed);
3669 if (right == NULL) {
3670 xmlNode *deleted = NULL;
3672 crm_trace(
"Processing <%s id=%s> (complete copy)", crm_element_name(left),
id);
3680 name = crm_element_name(left);
3686 if (value != NULL && strcmp(value,
"removed:top") == 0) {
3687 crm_trace(
"We are the root of the deletion: %s.id=%s", name,
id);
3696 for (lpc = 0; lpc < filter_len; lpc++) {
3697 filter[lpc].found = FALSE;
3701 for (left_child = __xml_first_child(left); left_child != NULL;
3702 left_child = __xml_next(left_child)) {
3703 gboolean child_changed = FALSE;
3705 right_child = find_element(right, left_child, FALSE);
3707 if (child_changed) {
3712 if (*changed == FALSE) {
3716 xmlAttrPtr pIter = NULL;
3718 for (pIter = pcmk__first_xml_attr(left); pIter != NULL; pIter = pIter->next) {
3719 const char *p_name = (
const char *)pIter->name;
3720 const char *p_value = pcmk__xml_attr_value(pIter);
3722 xmlSetProp(diff, (
const xmlChar *)p_name, (
const xmlChar *)p_value);
3729 xmlSetProp(diff, (
const xmlChar *)
XML_ATTR_ID, (
const xmlChar *)
id);
3733 for (xIter = pcmk__first_xml_attr(left); xIter != NULL; xIter = xIter->next) {
3734 const char *prop_name = (
const char *)xIter->name;
3735 xmlAttrPtr right_attr = NULL;
3743 for (lpc = 0; skip == FALSE && lpc < filter_len; lpc++) {
3744 if (filter[lpc].found == FALSE && strcmp(prop_name, filter[lpc].
string) == 0) {
3745 filter[lpc].found = TRUE;
3755 right_attr = xmlHasProp(right, (
const xmlChar *)prop_name);
3757 p = right_attr->_private;
3765 xmlAttrPtr pIter = NULL;
3767 for (pIter = pcmk__first_xml_attr(left); pIter != NULL; pIter = pIter->next) {
3768 const char *p_name = (
const char *)pIter->name;
3769 const char *p_value = pcmk__xml_attr_value(pIter);
3771 xmlSetProp(diff, (
const xmlChar *)p_name, (
const xmlChar *)p_value);
3778 xmlSetProp(diff, (
const xmlChar *)prop_name, (
const xmlChar *)value);
3786 if (strcmp(left_value, right_val) == 0) {
3792 xmlAttrPtr pIter = NULL;
3794 crm_trace(
"Changes detected to %s in <%s id=%s>", prop_name,
3795 crm_element_name(left),
id);
3796 for (pIter = pcmk__first_xml_attr(left); pIter != NULL; pIter = pIter->next) {
3797 const char *p_name = (
const char *)pIter->name;
3798 const char *p_value = pcmk__xml_attr_value(pIter);
3800 xmlSetProp(diff, (
const xmlChar *)p_name, (
const xmlChar *)p_value);
3805 crm_trace(
"Changes detected to %s (%s -> %s) in <%s id=%s>",
3806 prop_name, left_value, right_val, crm_element_name(left),
id);
3813 if (*changed == FALSE) {
3817 }
else if (full == FALSE &&
id) {
3825 add_xml_comment(xmlNode * parent, xmlNode * target, xmlNode * update)
3828 CRM_CHECK(update->type == XML_COMMENT_NODE,
return 0);
3830 if (target == NULL) {
3831 target = find_xml_comment(parent, update, FALSE);
3834 if (target == NULL) {
3838 }
else if (
safe_str_neq((
const char *)target->content, (
const char *)update->content)) {
3839 xmlFree(target->content);
3840 target->content = xmlStrdup(update->content);
3847 add_xml_object(xmlNode * parent, xmlNode * target, xmlNode * update, gboolean as_diff)
3849 xmlNode *a_child = NULL;
3850 const char *object_name = NULL,
3851 *object_href = NULL,
3852 *object_href_val = NULL;
3861 if (update->type == XML_COMMENT_NODE) {
3862 return add_xml_comment(parent, target, update);
3865 object_name = crm_element_name(update);
3866 object_href_val =
ID(update);
3867 if (object_href_val != NULL) {
3874 CRM_CHECK(object_name != NULL,
return 0);
3875 CRM_CHECK(target != NULL || parent != NULL,
return 0);
3877 if (target == NULL) {
3878 target = find_entity_by_attr_or_just_name(parent, object_name,
3879 object_href, object_href_val);
3882 if (target == NULL) {
3885 #if XML_PARSER_DEBUG
3887 object_href ?
" " :
"",
3888 object_href ? object_href :
"",
3889 object_href ?
"=" :
"",
3890 object_href ? object_href_val :
"");
3894 object_href ?
" " :
"",
3895 object_href ? object_href :
"",
3896 object_href ?
"=" :
"",
3897 object_href ? object_href_val :
"");
3903 if (as_diff == FALSE) {
3909 xmlAttrPtr pIter = NULL;
3911 for (pIter = pcmk__first_xml_attr(update); pIter != NULL; pIter = pIter->next) {
3912 const char *p_name = (
const char *)pIter->name;
3913 const char *p_value = pcmk__xml_attr_value(pIter);
3916 xmlUnsetProp(target, (
const xmlChar *)p_name);
3917 xmlSetProp(target, (
const xmlChar *)p_name, (
const xmlChar *)p_value);
3921 for (a_child = __xml_first_child(update); a_child != NULL; a_child = __xml_next(a_child)) {
3922 #if XML_PARSER_DEBUG
3924 object_href ?
" " :
"",
3925 object_href ? object_href :
"",
3926 object_href ?
"=" :
"",
3927 object_href ? object_href_val :
"");
3929 add_xml_object(target, NULL, a_child, as_diff);
3932 #if XML_PARSER_DEBUG
3934 object_href ?
" " :
"",
3935 object_href ? object_href :
"",
3936 object_href ?
"=" :
"",
3937 object_href ? object_href_val :
"");
3945 gboolean can_update = TRUE;
3946 xmlNode *child_of_child = NULL;
3949 CRM_CHECK(to_update != NULL,
return FALSE);
3951 if (
safe_str_neq(crm_element_name(to_update), crm_element_name(child))) {
3957 }
else if (can_update) {
3958 #if XML_PARSER_DEBUG
3961 add_xml_object(NULL, child, to_update, FALSE);
3964 for (child_of_child = __xml_first_child(child); child_of_child != NULL;
3965 child_of_child = __xml_next(child_of_child)) {
3978 const char *tag,
const char *field,
const char *value, gboolean search_matches)
3980 int match_found = 0;
3983 CRM_CHECK(children != NULL,
return FALSE);
3985 if (tag != NULL &&
safe_str_neq(tag, crm_element_name(root))) {
3990 if (*children == NULL) {
3997 if (search_matches || match_found == 0) {
3998 xmlNode *child = NULL;
4000 for (child = __xml_first_child(root); child != NULL; child = __xml_next(child)) {
4001 match_found +=
find_xml_children(children, child, tag, field, value, search_matches);
4011 gboolean can_delete = FALSE;
4012 xmlNode *child_of_child = NULL;
4014 const char *up_id = NULL;
4015 const char *child_id = NULL;
4016 const char *right_val = NULL;
4019 CRM_CHECK(update != NULL,
return FALSE);
4022 child_id =
ID(child);
4024 if (up_id == NULL || (child_id && strcmp(child_id, up_id) == 0)) {
4027 if (
safe_str_neq(crm_element_name(update), crm_element_name(child))) {
4030 if (can_delete && delete_only) {
4031 xmlAttrPtr pIter = NULL;
4033 for (pIter = pcmk__first_xml_attr(update); pIter != NULL; pIter = pIter->next) {
4034 const char *p_name = (
const char *)pIter->name;
4035 const char *p_value = pcmk__xml_attr_value(pIter);
4044 if (can_delete && parent != NULL) {
4046 if (delete_only || update == NULL) {
4051 xmlDoc *doc = tmp->doc;
4052 xmlNode *old = NULL;
4055 old = xmlReplaceNode(child, tmp);
4063 xmlDocSetRootElement(doc, old);
4069 }
else if (can_delete) {
4074 child_of_child = __xml_first_child(child);
4075 while (child_of_child) {
4076 xmlNode *next = __xml_next(child_of_child);
4082 child_of_child = NULL;
4084 child_of_child = next;
4094 xmlNode *child = NULL;
4095 GSList *nvpairs = NULL;
4096 xmlNode *result = NULL;
4097 const char *name = NULL;
4101 name = crm_element_name(input);
4110 for (child = __xml_first_child(input); child != NULL;
4111 child = __xml_next(child)) {
4126 xmlNode *match = NULL;
4128 for (match = __xml_first_child(parent); match != NULL; match = __xml_next(match)) {
4134 if (name == NULL || strcmp((
const char *)match->name, name) == 0) {
4151 xmlNode *match = __xml_next(sibling);
4152 const char *name = crm_element_name(sibling);
4154 while (match != NULL) {
4155 if (!strcmp(crm_element_name(match), name)) {
4158 match = __xml_next(match);
4166 static bool init = TRUE;
4175 xmlSetBufferAllocationScheme(XML_BUFFER_ALLOC_DOUBLEIT);
4178 xmlDeregisterNodeDefault(pcmkDeregisterNode);
4179 xmlRegisterNodeDefault(pcmkRegisterNode);
4188 crm_info(
"Cleaning up memory from libxml2");
4193 #define XPATH_MAX 512
4198 const char *tag = NULL;
4199 const char *ref = NULL;
4200 xmlNode *result = input;
4202 if (result == NULL) {
4205 }
else if (top == NULL) {
4209 tag = crm_element_name(result);
4216 if (result == NULL) {
4217 char *nodePath = (
char *)xmlGetNodePath(top);
4219 crm_err(
"No match for %s found in %s: Invalid configuration", xpath_string,