11 #include <sys/types.h> 19 #include <libxml/parser.h> 20 #include <libxml/tree.h> 32 #define XML_BUFFER_SIZE 4096 33 #define XML_PARSER_DEBUG 0 40 typedef struct xml_deleted_obj_s {
47 static filter_t filter[] = {
56 static xmlNode *subtract_xml_comment(xmlNode * parent, xmlNode * left, xmlNode * right, gboolean * changed);
57 static xmlNode *find_xml_comment(xmlNode * root, xmlNode * search_comment, gboolean exact);
58 static int add_xml_comment(xmlNode * parent, xmlNode * target, xmlNode * update);
60 #define CHUNK_SIZE 1024 65 if(xml == NULL || xml->doc == NULL || xml->doc->_private == NULL) {
69 }
else if (lazy && is_not_set(((
xml_private_t *)xml->doc->_private)->flags,
76 #define buffer_print(buffer, max, offset, fmt, args...) do { \ 79 rc = snprintf((buffer) + (offset), (max) - (offset), fmt, ##args); \ 81 if(buffer && rc < 0) { \ 82 crm_perror(LOG_ERR, "snprintf failed at offset %d", offset); \ 83 (buffer)[(offset)] = 0; \ 85 } else if(rc >= ((max) - (offset))) { \ 87 (max) = QB_MAX(CHUNK_SIZE, (max) * 2); \ 88 tmp = realloc_safe((buffer), (max)); \ 98 insert_prefix(
int options,
char **buffer,
int *offset,
int *max,
int depth)
101 size_t spaces = 2 * depth;
103 if ((*buffer) == NULL || spaces >= ((*max) - (*offset))) {
105 (*buffer) = realloc_safe((*buffer), (*max));
107 memset((*buffer) + (*offset),
' ', spaces);
113 set_parent_flag(xmlNode *xml,
long flag)
116 for(; xml; xml = xml->parent) {
132 if(xml && xml->doc && xml->doc->_private){
142 __xml_node_dirty(xmlNode *xml)
149 __xml_node_clean(xmlNode *xml)
151 xmlNode *cIter = NULL;
158 for (cIter = __xml_first_child(xml); cIter != NULL; cIter = __xml_next(cIter)) {
159 __xml_node_clean(cIter);
164 crm_node_created(xmlNode *xml)
166 xmlNode *cIter = NULL;
172 __xml_node_dirty(xml);
175 for (cIter = __xml_first_child(xml); cIter != NULL; cIter = __xml_next(cIter)) {
176 crm_node_created(cIter);
182 crm_attr_dirty(xmlAttr *a)
184 xmlNode *parent = a->parent;
193 __xml_node_dirty(parent);
196 int get_tag_name(
const char *input,
size_t offset,
size_t max);
197 int get_attr_name(
const char *input,
size_t offset,
size_t max);
201 static int add_xml_object(xmlNode * parent, xmlNode * target, xmlNode * update, gboolean as_diff);
203 static inline const char *
204 crm_attr_value(
const xmlAttr *attr)
206 if (attr == NULL || attr->children == NULL) {
209 return (
const char *) attr->children->content;
212 static inline xmlAttr *
213 crm_first_attr(
const xmlNode *xml)
218 return xml->properties;
221 #define XML_PRIVATE_MAGIC (long) 0x81726354 224 __xml_deleted_obj_free(
void *
data)
229 free(deleted_obj->path);
249 g_list_free_full(p->
deleted_objs, __xml_deleted_obj_free);
259 __xml_private_clean(p);
264 pcmkDeregisterNode(xmlNodePtr node)
273 if (node->type != XML_DOCUMENT_NODE || node->name == NULL
274 || node->name[0] !=
' ') {
275 __xml_private_free(node->_private);
280 pcmkRegisterNode(xmlNodePtr node)
285 case XML_ELEMENT_NODE:
286 case XML_DOCUMENT_NODE:
287 case XML_ATTRIBUTE_NODE:
288 case XML_COMMENT_NODE:
297 case XML_CDATA_SECTION_NODE:
301 crm_trace(
"Ignoring %p %d", node, node->type);
311 __xml_node_dirty(node);
319 crm_trace(
"Tracking changes%s to %p", enforce_acls?
" with ACLs":
"", xml);
322 if(acl_source == NULL) {
344 if(xml != NULL && xml->doc && xml->doc->_private) {
400 static int __xml_offset(xmlNode *xml)
403 xmlNode *cIter = NULL;
405 for(cIter = xml; cIter->prev; cIter = cIter->prev) {
416 static int __xml_offset_no_deletions(xmlNode *xml)
419 xmlNode *cIter = NULL;
421 for(cIter = xml; cIter->prev; cIter = cIter->prev) {
433 __xml_build_changes(xmlNode * xml, xmlNode *patchset)
435 xmlNode *cIter = NULL;
436 xmlAttr *pIter = NULL;
437 xmlNode *change = NULL;
445 sizeof(buffer)) > 0) {
446 int position = __xml_offset_no_deletions(xml);
459 for (pIter = crm_first_attr(xml); pIter != NULL; pIter = pIter->next) {
460 xmlNode *attr = NULL;
472 sizeof(buffer)) > 0) {
497 xmlNode *result = NULL;
502 for (pIter = crm_first_attr(xml); pIter != NULL; pIter = pIter->next) {
507 crm_xml_add(result, (
const char *)pIter->name, value);
512 for (cIter = __xml_first_child(xml); cIter != NULL; cIter = __xml_next(cIter)) {
513 __xml_build_changes(cIter, patchset);
521 crm_trace(
"%s.%s moved to position %d", xml->name,
ID(xml), __xml_offset(xml));
523 sizeof(buffer)) > 0) {
534 __xml_accept_changes(xmlNode * xml)
536 xmlNode *cIter = NULL;
537 xmlAttr *pIter = NULL;
541 pIter = crm_first_attr(xml);
543 while (pIter != NULL) {
544 const xmlChar *name = pIter->name;
557 for (cIter = __xml_first_child(xml); cIter != NULL; cIter = __xml_next(cIter)) {
558 __xml_accept_changes(cIter);
563 is_config_change(xmlNode *xml)
570 p = config->_private;
576 if(xml->doc && xml->doc->_private) {
577 p = xml->doc->_private;
578 for(gIter = p->
deleted_objs; gIter; gIter = gIter->next) {
591 xml_repair_v1_diff(xmlNode * last, xmlNode * next, xmlNode * local_diff, gboolean changed)
595 xmlNode *diff_child = NULL;
597 const char *tag = NULL;
599 const char *vfields[] = {
605 if (local_diff == NULL) {
610 tag =
"diff-removed";
612 if (diff_child == NULL) {
622 for(lpc = 0; last && lpc <
DIMOF(vfields); lpc++){
626 if(changed || lpc == 2) {
633 if (diff_child == NULL) {
643 for(lpc = 0; next && lpc <
DIMOF(vfields); lpc++){
650 xmlAttrPtr xIter = NULL;
652 for (xIter = next->properties; xIter; xIter = xIter->next) {
653 const char *p_name = (
const char *)xIter->name;
656 xmlSetProp(cib, (
const xmlChar *)p_name, (
const xmlChar *)p_value);
664 xml_create_patchset_v1(xmlNode *source, xmlNode *target,
bool config,
bool suppress)
670 xml_repair_v1_diff(source, target, patchset, config);
677 xml_create_patchset_v2(xmlNode *source, xmlNode *target)
685 xmlNode *patchset = NULL;
686 const char *vfields[] = {
698 doc = target->doc->_private;
706 for(lpc = 0; lpc <
DIMOF(vfields); lpc++){
716 for(lpc = 0; lpc <
DIMOF(vfields); lpc++){
725 for(gIter = doc->
deleted_objs; gIter; gIter = gIter->next) {
731 if (deleted_obj->position >= 0) {
736 __xml_build_changes(target, patchset);
741 xml_create_patchset(
int format, xmlNode *source, xmlNode *target,
bool *config_changed,
bool manage_version)
745 xmlNode *patch = NULL;
754 config = is_config_change(target);
756 *config_changed = config;
759 if(manage_version && config) {
766 }
else if(manage_version) {
779 crm_trace(
"Using patch format %d for version: %s", format, version);
784 patch = xml_create_patchset_v1(source, target, config, FALSE);
787 patch = xml_create_patchset_v2(source, target);
790 crm_err(
"Unknown patch format: %d", format);
804 if (patch == NULL || source == NULL || target == NULL) {
813 if (format > 1 && with_digest == FALSE) {
827 __xml_log_element(
int log_level,
const char *file,
const char *
function,
int line,
828 const char *prefix, xmlNode *
data,
int depth,
int options);
834 xmlNode *child = NULL;
835 xmlNode *added = NULL;
836 xmlNode *removed = NULL;
837 gboolean is_first = TRUE;
839 int add[] = { 0, 0, 0 };
840 int del[] = { 0, 0, 0 };
842 const char *fmt = NULL;
843 const char *digest = NULL;
846 static struct qb_log_callsite *patchset_cs = NULL;
848 if (patchset_cs == NULL) {
849 patchset_cs = qb_log_callsite_get(
function, __FILE__,
"xml-patchset", log_level, __LINE__, 0);
852 if (patchset == NULL) {
856 }
else if (log_level == 0) {
866 if (add[2] != del[2] || add[1] != del[1] || add[0] != del[0]) {
868 "Diff: --- %d.%d.%d %s", del[0], del[1], del[2], fmt);
870 "Diff: +++ %d.%d.%d %s", add[0], add[1], add[2], digest);
872 }
else if (patchset != NULL && (add[0] || add[1] || add[2])) {
874 "%s: Local-only Change: %d.%d.%d",
function ?
function :
"",
875 add[0], add[1], add[2]);
880 xmlNode *change = NULL;
882 for (change = __xml_first_child(patchset); change != NULL; change = __xml_next(change)) {
887 }
else if(strcmp(op,
"create") == 0) {
888 int lpc = 0, max = 0;
891 max = strlen(prefix);
892 __xml_log_element(log_level, __FILE__,
function, __LINE__, prefix, change->children,
895 for(lpc = 2; lpc < max; lpc++) {
899 __xml_log_element(log_level, __FILE__,
function, __LINE__, prefix, change->children,
903 }
else if(strcmp(op,
"move") == 0) {
906 }
else if(strcmp(op,
"modify") == 0) {
915 for (child = __xml_first_child(clist); child != NULL; child = __xml_next(child)) {
920 }
else if(strcmp(op,
"set") == 0) {
926 o_set += snprintf(buffer_set + o_set,
XML_BUFFER_SIZE - o_set,
"@%s=%s", name, value);
928 }
else if(strcmp(op,
"unset") == 0) {
930 o_unset += snprintf(buffer_unset + o_unset,
XML_BUFFER_SIZE - o_unset,
", ");
932 o_unset += snprintf(buffer_unset + o_unset,
XML_BUFFER_SIZE - o_unset,
"@%s", name);
936 do_crm_log_alias(log_level, __FILE__,
function, __LINE__,
"+ %s: %s", xpath, buffer_set);
939 do_crm_log_alias(log_level, __FILE__,
function, __LINE__,
"-- %s: %s", xpath, buffer_unset);
942 }
else if(strcmp(op,
"delete") == 0) {
947 do_crm_log_alias(log_level, __FILE__,
function, __LINE__,
"-- %s (%d)", xpath, position);
957 if (log_level < LOG_DEBUG ||
function == NULL) {
962 for (child = __xml_first_child(removed); child != NULL; child = __xml_next(child)) {
974 for (child = __xml_first_child(added); child != NULL; child = __xml_next(child)) {
994 doc = xml->doc->_private;
999 for(gIter = doc->
deleted_objs; gIter; gIter = gIter->next) {
1002 if (deleted_obj->position >= 0) {
1004 deleted_obj->path, deleted_obj->position);
1019 xmlNode *top = NULL;
1026 crm_trace(
"Accepting changes to %p", xml);
1027 doc = xml->doc->_private;
1028 top = xmlDocGetRootElement(xml->doc);
1030 __xml_private_clean(xml->doc->_private);
1038 __xml_accept_changes(top);
1042 find_element(xmlNode *haystack, xmlNode *needle, gboolean exact)
1045 return (needle->type == XML_COMMENT_NODE)?
1046 find_xml_comment(haystack, needle, exact)
1047 :
find_entity(haystack, crm_element_name(needle),
ID(needle));
1052 __subtract_xml_object(xmlNode * target, xmlNode * patch)
1054 xmlNode *patch_child = NULL;
1055 xmlNode *cIter = NULL;
1056 xmlAttrPtr xIter = NULL;
1059 const char *name = NULL;
1060 const char *value = NULL;
1062 if (target == NULL || patch == NULL) {
1066 if (target->type == XML_COMMENT_NODE) {
1069 subtract_xml_comment(target->parent, target, patch, &dummy);
1072 name = crm_element_name(target);
1080 if (value != NULL && strcmp(value,
"removed:top") == 0) {
1081 crm_trace(
"We are the root of the deletion: %s.id=%s", name,
id);
1087 for (xIter = crm_first_attr(patch); xIter != NULL; xIter = xIter->next) {
1088 const char *p_name = (
const char *)xIter->name;
1097 cIter = __xml_first_child(target);
1099 xmlNode *target_child = cIter;
1101 cIter = __xml_next(cIter);
1102 patch_child = find_element(patch, target_child, FALSE);
1103 __subtract_xml_object(target_child, patch_child);
1109 __add_xml_object(xmlNode * parent, xmlNode * target, xmlNode * patch)
1111 xmlNode *patch_child = NULL;
1112 xmlNode *target_child = NULL;
1113 xmlAttrPtr xIter = NULL;
1115 const char *
id = NULL;
1116 const char *name = NULL;
1117 const char *value = NULL;
1119 if (patch == NULL) {
1121 }
else if (parent == NULL && target == NULL) {
1129 && strcmp(value,
"added:top") == 0) {
1131 name = crm_element_name(patch);
1132 crm_trace(
"We are the root of the addition: %s.id=%s", name,
id);
1136 }
else if(target == NULL) {
1138 name = crm_element_name(patch);
1139 crm_err(
"Could not locate: %s.id=%s", name,
id);
1143 if (target->type == XML_COMMENT_NODE) {
1144 add_xml_comment(parent, target, patch);
1147 name = crm_element_name(target);
1152 for (xIter = crm_first_attr(patch); xIter != NULL; xIter = xIter->next) {
1153 const char *p_name = (
const char *)xIter->name;
1161 for (patch_child = __xml_first_child(patch); patch_child != NULL;
1162 patch_child = __xml_next(patch_child)) {
1164 target_child = find_element(target, patch_child, FALSE);
1165 __add_xml_object(target, target_child, patch_child);
1181 find_patch_xml_node(xmlNode *patchset,
int format,
bool added,
1182 xmlNode **patch_node)
1189 label = added?
"diff-added" :
"diff-removed";
1192 if (cib_node != NULL) {
1193 *patch_node = cib_node;
1197 label = added?
"target" :
"source";
1202 crm_warn(
"Unknown patch format: %d", format);
1213 xmlNode *tmp = NULL;
1215 const char *vfields[] = {
1225 if (!find_patch_xml_node(patchset, format, FALSE, &tmp)) {
1229 for(lpc = 0; lpc <
DIMOF(vfields); lpc++) {
1231 crm_trace(
"Got %d for del[%s]", del[lpc], vfields[lpc]);
1236 if (!find_patch_xml_node(patchset, format, TRUE, &tmp)) {
1240 for(lpc = 0; lpc <
DIMOF(vfields); lpc++) {
1242 crm_trace(
"Got %d for add[%s]", add[lpc], vfields[lpc]);
1250 xml_patch_version_check(xmlNode *xml, xmlNode *patchset,
int format)
1253 bool changed = FALSE;
1255 int this[] = { 0, 0, 0 };
1256 int add[] = { 0, 0, 0 };
1257 int del[] = { 0, 0, 0 };
1259 const char *vfields[] = {
1265 for(lpc = 0; lpc <
DIMOF(vfields); lpc++) {
1267 crm_trace(
"Got %d for this[%s]",
this[lpc], vfields[lpc]);
1268 if (
this[lpc] < 0) {
1276 add[2] =
this[2] + 1;
1277 for(lpc = 0; lpc <
DIMOF(vfields); lpc++) {
1278 del[lpc] =
this[lpc];
1283 for(lpc = 0; lpc <
DIMOF(vfields); lpc++) {
1284 if(
this[lpc] < del[lpc]) {
1285 crm_debug(
"Current %s is too low (%d.%d.%d < %d.%d.%d --> %d.%d.%d)", vfields[lpc],
1286 this[0],
this[1],
this[2], del[0], del[1], del[2], add[0], add[1], add[2]);
1289 }
else if(
this[lpc] > del[lpc]) {
1290 crm_info(
"Current %s is too high (%d.%d.%d > %d.%d.%d --> %d.%d.%d) %p", vfields[lpc],
1291 this[0],
this[1],
this[2], del[0], del[1], del[2], add[0], add[1], add[2], patchset);
1297 for(lpc = 0; lpc <
DIMOF(vfields); lpc++) {
1298 if(add[lpc] > del[lpc]) {
1303 if(changed == FALSE) {
1304 crm_notice(
"Versions did not change in patch %d.%d.%d", add[0], add[1], add[2]);
1308 crm_debug(
"Can apply patch %d.%d.%d to %d.%d.%d",
1309 add[0], add[1], add[2],
this[0],
this[1],
this[2]);
1314 xml_apply_patchset_v1(xmlNode *xml, xmlNode *patchset)
1317 int root_nodes_seen = 0;
1319 xmlNode *child_diff = NULL;
1320 xmlNode *added =
find_xml_node(patchset,
"diff-added", FALSE);
1321 xmlNode *removed =
find_xml_node(patchset,
"diff-removed", FALSE);
1325 for (child_diff = __xml_first_child(removed); 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 __subtract_xml_object(xml, child_diff);
1334 if (root_nodes_seen > 1) {
1335 crm_err(
"(-) Diffs cannot contain more than one change set... saw %d", root_nodes_seen);
1339 root_nodes_seen = 0;
1342 xmlNode *child_diff = NULL;
1344 for (child_diff = __xml_first_child(added); child_diff != NULL;
1345 child_diff = __xml_next(child_diff)) {
1346 CRM_CHECK(root_nodes_seen == 0, rc = FALSE);
1347 if (root_nodes_seen == 0) {
1348 __add_xml_object(NULL, xml, child_diff);
1354 if (root_nodes_seen > 1) {
1355 crm_err(
"(+) Diffs cannot contain more than one change set... saw %d", root_nodes_seen);
1366 __first_xml_child_match(xmlNode *parent,
const char *name,
const char *
id,
int position)
1368 xmlNode *cIter = NULL;
1370 for (cIter = __xml_first_child(parent); cIter != NULL; cIter = __xml_next(cIter)) {
1371 if(strcmp((
const char *)cIter->name, name) != 0) {
1374 const char *cid =
ID(cIter);
1375 if(cid == NULL || strcmp(cid,
id) != 0) {
1381 if (cIter->type == XML_COMMENT_NODE
1383 && __xml_offset(cIter) != position) {
1406 __xml_find_path(xmlNode *top,
const char *key,
int target_position)
1408 xmlNode *target = (xmlNode*) top->doc;
1409 const char *current = key;
1419 key_len = strlen(key);
1425 remainder = calloc(key_len,
sizeof(
char));
1428 section = calloc(key_len,
sizeof(
char));
1431 id = calloc(key_len,
sizeof(
char));
1434 tag = calloc(key_len,
sizeof(
char));
1439 rc = sscanf(current,
"/%[^/]%s", section, remainder);
1442 int f = sscanf(section,
"%[^[][@id='%[^']", tag,
id);
1443 int current_position = -1;
1448 if ((rc == 1) && (target_position >= 0)) {
1449 current_position = target_position;
1454 target = __first_xml_child_match(target, tag, NULL, current_position);
1457 target = __first_xml_child_match(target, tag,
id, current_position);
1464 current = remainder;
1468 }
while ((rc == 2) && target);
1472 (path = (
char *) xmlGetNodePath(target)), key);
1486 xml_apply_patchset_v2(xmlNode *xml, xmlNode *patchset)
1489 xmlNode *change = NULL;
1490 for (change = __xml_first_child(patchset); change != NULL; change = __xml_next(change)) {
1491 xmlNode *match = NULL;
1496 crm_trace(
"Processing %s %s", change->name, op);
1501 if(strcmp(op,
"delete") == 0) {
1504 match = __xml_find_path(xml, xpath, position);
1505 crm_trace(
"Performing %s on %s with %p", op, xpath, match);
1507 if(match == NULL && strcmp(op,
"delete") == 0) {
1508 crm_debug(
"No %s match for %s in %p", op, xpath, xml->doc);
1511 }
else if(match == NULL) {
1512 crm_err(
"No %s match for %s in %p", op, xpath, xml->doc);
1516 }
else if(strcmp(op,
"create") == 0) {
1518 xmlNode *child = NULL;
1519 xmlNode *match_child = NULL;
1521 match_child = match->children;
1524 while(match_child && position != __xml_offset(match_child)) {
1525 match_child = match_child->next;
1528 child = xmlDocCopyNode(change->children, match->doc, 1);
1530 crm_trace(
"Adding %s at position %d", child->name, position);
1531 xmlAddPrevSibling(match_child, child);
1533 }
else if(match->last) {
1534 crm_trace(
"Adding %s at position %d (end)", child->name, position);
1535 xmlAddNextSibling(match->last, child);
1538 crm_trace(
"Adding %s at position %d (first)", child->name, position);
1540 xmlAddChild(match, child);
1542 crm_node_created(child);
1544 }
else if(strcmp(op,
"move") == 0) {
1548 if(position != __xml_offset(match)) {
1549 xmlNode *match_child = NULL;
1552 if(p > __xml_offset(match)) {
1557 match_child = match->parent->children;
1559 while(match_child && p != __xml_offset(match_child)) {
1560 match_child = match_child->next;
1563 crm_trace(
"Moving %s to position %d (was %d, prev %p, %s %p)",
1564 match->name, position, __xml_offset(match), match->prev,
1565 match_child?
"next":
"last", match_child?match_child:match->parent->last);
1568 xmlAddPrevSibling(match_child, match);
1572 xmlAddNextSibling(match->parent->last, match);
1576 crm_trace(
"%s is already in position %d", match->name, position);
1579 if(position != __xml_offset(match)) {
1580 crm_err(
"Moved %s.%s to position %d instead of %d (%p)",
1581 match->name,
ID(match), __xml_offset(match), position, match->prev);
1585 }
else if(strcmp(op,
"delete") == 0) {
1588 }
else if(strcmp(op,
"modify") == 0) {
1589 xmlAttr *pIter = crm_first_attr(match);
1596 while(pIter != NULL) {
1597 const char *name = (
const char *)pIter->name;
1599 pIter = pIter->next;
1603 for (pIter = crm_first_attr(attrs); pIter != NULL; pIter = pIter->next) {
1604 const char *name = (
const char *)pIter->name;
1611 crm_err(
"Unknown operation: %s", op);
1622 xmlNode *old = NULL;
1625 if(patchset == NULL) {
1633 rc = xml_patch_version_check(xml, patchset, format);
1647 rc = xml_apply_patchset_v1(xml, patchset);
1650 rc = xml_apply_patchset_v2(xml, patchset);
1653 crm_err(
"Unknown patch format: %d", format);
1659 static struct qb_log_callsite *digest_cs = NULL;
1661 char *new_digest = NULL;
1664 if (digest_cs == NULL) {
1666 qb_log_callsite_get(__func__, __FILE__,
"diff-digest",
LOG_TRACE, __LINE__,
1672 crm_info(
"v%d digest mis-match: expected %s, calculated %s", format, digest, new_digest);
1675 if (digest_cs && digest_cs->targets) {
1681 crm_trace(
"%p %.6x", digest_cs, digest_cs ? digest_cs->targets : 0);
1685 crm_trace(
"v%d digest matched: expected %s, calculated %s", format, digest, new_digest);
1697 xmlNode *a_child = NULL;
1698 const char *name =
"NULL";
1701 name = crm_element_name(root);
1704 if (search_path == NULL) {
1705 crm_warn(
"Will never find <NULL>");
1709 for (a_child = __xml_first_child(root); a_child != NULL; a_child = __xml_next(a_child)) {
1710 if (strcmp((
const char *)a_child->name, search_path) == 0) {
1717 crm_warn(
"Could not find %s in %s.", search_path, name);
1718 }
else if (root != NULL) {
1719 crm_trace(
"Could not find %s in %s.", search_path, name);
1721 crm_trace(
"Could not find %s in <NULL>.", search_path);
1731 find_entity_by_attr_or_just_name(xmlNode *parent,
const char *node_name,
1732 const char *attr_n,
const char *attr_v)
1737 CRM_CHECK(attr_n == NULL || attr_v != NULL,
return NULL);
1739 for (child = __xml_first_child(parent); child != NULL; child = __xml_next(child)) {
1741 if (node_name == NULL || !strcmp((
const char *) child->name, node_name)) {
1751 attr_n ? attr_n :
"",
1753 attr_n ? attr_v :
"",
1754 crm_element_name(parent));
1762 return find_entity_by_attr_or_just_name(parent, node_name,
1770 crm_warn(
"No node to copy properties from");
1772 }
else if (target == NULL) {
1773 crm_err(
"No node to copy properties into");
1776 xmlAttrPtr pIter = NULL;
1778 for (pIter = crm_first_attr(src); pIter != NULL; pIter = pIter->next) {
1779 const char *p_name = (
const char *)pIter->name;
1780 const char *p_value = crm_attr_value(pIter);
1793 xmlNode *child = NULL;
1794 xmlAttrPtr pIter = NULL;
1796 for (pIter = crm_first_attr(target); pIter != NULL; pIter = pIter->next) {
1797 const char *p_name = (
const char *)pIter->name;
1798 const char *p_value = crm_attr_value(pIter);
1802 for (child = __xml_first_child(target); child != NULL; child = __xml_next(child)) {
1815 const char *old_value = NULL;
1817 if (value == NULL || name == NULL) {
1823 if (old_value == NULL) {
1825 goto set_unexpanded;
1827 }
else if (strstr(value, name) != value) {
1828 goto set_unexpanded;
1831 name_len = strlen(name);
1832 value_len = strlen(value);
1833 if (value_len < (name_len + 2)
1834 || value[name_len] !=
'+' || (value[name_len + 1] !=
'+' && value[name_len + 1] !=
'=')) {
1835 goto set_unexpanded;
1841 if (old_value != value) {
1845 if (value[name_len + 1] !=
'+') {
1846 const char *offset_s = value + (name_len + 2);
1850 int_value += offset;
1860 if (old_value == value) {
1877 doc = xmlNewDoc((
const xmlChar *)
"1.0");
1878 xmlDocSetRootElement(doc, node);
1879 xmlSetTreeDoc(node, doc);
1887 xmlNode *child = NULL;
1890 CRM_CHECK(src_node != NULL,
return NULL);
1892 child = xmlDocCopyNode(src_node, doc, 1);
1893 xmlAddChild(parent, child);
1894 crm_node_created(child);
1910 xmlAttr *attr = NULL;
1915 if (value == NULL) {
1918 #if XML_PARANOIA_CHECKS 1920 const char *old_value = NULL;
1925 CRM_CHECK(old_value != value,
crm_err(
"Cannot reset %s with crm_xml_add(%s)", name, value);
1933 if(old == NULL || value == NULL || strcmp(old, value) != 0) {
1939 crm_trace(
"Cannot add %s=%s to %s", name, value, node->name);
1943 attr = xmlSetProp(node, (
const xmlChar *)name, (
const xmlChar *)value);
1945 crm_attr_dirty(attr);
1948 CRM_CHECK(attr && attr->children && attr->children->content,
return NULL);
1949 return (
char *)attr->children->content;
1956 xmlAttr *attr = NULL;
1957 const char *old_value = NULL;
1960 CRM_CHECK(name != NULL && name[0] != 0,
return NULL);
1965 CRM_CHECK(old_value != value,
return value);
1969 crm_trace(
"Cannot replace %s=%s to %s", name, value, node->name);
1972 }
else if (old_value != NULL && value == NULL) {
1976 }
else if (value == NULL) {
1981 if(old_value == NULL || value == NULL || strcmp(old_value, value) != 0) {
1986 attr = xmlSetProp(node, (
const xmlChar *)name, (
const xmlChar *)value);
1988 crm_attr_dirty(attr);
1990 CRM_CHECK(attr && attr->children && attr->children->content,
return NULL);
1991 return (
char *)attr->children->content;
1997 char *number = crm_itoa(value);
1998 const char *added =
crm_xml_add(node, name, number);
2008 const char *added =
crm_xml_add(node, name, number);
2018 xmlNode *node = NULL;
2020 if (name == NULL || name[0] == 0) {
2021 CRM_CHECK(name != NULL && name[0] == 0,
return NULL);
2025 if (parent == NULL) {
2026 doc = xmlNewDoc((
const xmlChar *)
"1.0");
2027 node = xmlNewDocRawNode(doc, NULL, (
const xmlChar *)name, NULL);
2028 xmlDocSetRootElement(doc, node);
2032 node = xmlNewDocRawNode(doc, NULL, (
const xmlChar *)name, NULL);
2033 xmlAddChild(parent, node);
2035 crm_node_created(node);
2041 int offset,
size_t buffer_size)
2043 const char *
id =
ID(xml);
2045 if(offset == 0 && prefix == NULL && xml->parent) {
2051 offset += snprintf(buffer + offset, buffer_size - offset,
2052 "/%s[@id='%s']", (
const char *) xml->name,
id);
2053 }
else if(xml->name) {
2054 offset += snprintf(buffer + offset, buffer_size - offset,
2055 "/%s", (
const char *) xml->name);
2068 return strdup(buffer);
2074 free_xml_with_position(xmlNode * child,
int position)
2076 if (child != NULL) {
2077 xmlNode *top = NULL;
2078 xmlDoc *doc = child->doc;
2082 top = xmlDocGetRootElement(doc);
2085 if (doc != NULL && top == child) {
2104 sizeof(buffer)) > 0) {
2107 crm_trace(
"Deleting %s %p from %p", buffer, child, doc);
2109 deleted_obj->path = strdup(buffer);
2111 deleted_obj->position = -1;
2113 if (child->type == XML_COMMENT_NODE) {
2114 if (position >= 0) {
2115 deleted_obj->position = position;
2118 deleted_obj->position = __xml_offset(child);
2131 xmlUnlinkNode(child);
2141 free_xml_with_position(child, -1);
2147 xmlDoc *doc = xmlNewDoc((
const xmlChar *)
"1.0");
2148 xmlNode *copy = xmlDocCopyNode(src, doc, 1);
2150 xmlDocSetRootElement(doc, copy);
2151 xmlSetTreeDoc(copy, doc);
2156 crm_xml_err(
void *ctx,
const char *fmt, ...)
2157 G_GNUC_PRINTF(2, 3);
2160 crm_xml_err(
void *ctx,
const char *fmt, ...)
2163 static struct qb_log_callsite *xml_error_cs = NULL;
2165 if (xml_error_cs == NULL) {
2166 xml_error_cs = qb_log_callsite_get(
2171 if (xml_error_cs && xml_error_cs->targets) {
2173 crm_abort(__FILE__, __PRETTY_FUNCTION__, __LINE__,
"xml library error",
2175 "XML Error: ", fmt, ap);
2185 xmlNode *xml = NULL;
2186 xmlDocPtr output = NULL;
2187 xmlParserCtxtPtr ctxt = NULL;
2188 xmlErrorPtr last_error = NULL;
2190 if (input == NULL) {
2191 crm_err(
"Can't parse NULL input");
2196 ctxt = xmlNewParserCtxt();
2201 xmlCtxtResetLastError(ctxt);
2202 xmlSetGenericErrorFunc(ctxt, crm_xml_err);
2205 xmlCtxtReadDoc(ctxt, (
const xmlChar *)input, NULL, NULL,
2206 XML_PARSE_NOBLANKS | XML_PARSE_RECOVER);
2208 xml = xmlDocGetRootElement(output);
2210 last_error = xmlCtxtGetLastError(ctxt);
2211 if (last_error && last_error->code != XML_ERR_OK) {
2217 crm_warn(
"Parsing failed (domain=%d, level=%d, code=%d): %s",
2218 last_error->domain, last_error->level, last_error->code, last_error->message);
2220 if (last_error->code == XML_ERR_DOCUMENT_EMPTY) {
2223 }
else if (last_error->code != XML_ERR_DOCUMENT_END) {
2224 crm_err(
"Couldn't%s parse %d chars: %s", xml ?
" fully" :
"", (
int)strlen(input),
2231 int len = strlen(input);
2235 crm_warn(
"Parse error[+%.3d]: %.80s", lpc, input+lpc);
2243 xmlFreeParserCtxt(ctxt);
2250 size_t data_length = 0;
2251 size_t read_chars = 0;
2253 char *xml_buffer = NULL;
2254 xmlNode *xml_obj = NULL;
2258 read_chars = fread(xml_buffer + data_length, 1,
XML_BUFFER_SIZE, stdin);
2259 data_length += read_chars;
2262 if (data_length == 0) {
2263 crm_warn(
"No XML supplied on stdin");
2268 xml_buffer[data_length] =
'\0';
2277 decompress_file(
const char *filename)
2279 char *buffer = NULL;
2283 size_t length = 0, read_len = 0;
2285 BZFILE *bz_file = NULL;
2286 FILE *input = fopen(filename,
"r");
2288 if (input == NULL) {
2289 crm_perror(LOG_ERR,
"Could not open %s for reading", filename);
2293 bz_file = BZ2_bzReadOpen(&rc, input, 0, 0, NULL, 0);
2295 crm_err(
"Could not prepare to read compressed %s: %s " 2297 BZ2_bzReadClose(&rc, bz_file);
2302 while (rc == BZ_OK) {
2304 read_len = BZ2_bzRead(&rc, bz_file, buffer + length,
XML_BUFFER_SIZE);
2306 crm_trace(
"Read %ld bytes from file: %d", (
long)read_len, rc);
2308 if (rc == BZ_OK || rc == BZ_STREAM_END) {
2313 buffer[length] =
'\0';
2315 if (rc != BZ_STREAM_END) {
2316 crm_err(
"Could not read compressed %s: %s " 2322 BZ2_bzReadClose(&rc, bz_file);
2326 crm_err(
"Could not read compressed %s: not built with bzlib support",
2335 xmlNode *iter = xml->children;
2338 xmlNode *next = iter->next;
2340 switch (iter->type) {
2343 xmlUnlinkNode(iter);
2347 case XML_ELEMENT_NODE:
2364 xmlNode *xml = NULL;
2365 xmlDocPtr output = NULL;
2366 gboolean uncompressed = TRUE;
2367 xmlParserCtxtPtr ctxt = NULL;
2368 xmlErrorPtr last_error = NULL;
2369 static int xml_options = XML_PARSE_NOBLANKS | XML_PARSE_RECOVER;
2372 ctxt = xmlNewParserCtxt();
2377 xmlCtxtResetLastError(ctxt);
2378 xmlSetGenericErrorFunc(ctxt, crm_xml_err);
2385 if (filename == NULL) {
2387 output = xmlCtxtReadFd(ctxt, STDIN_FILENO,
"unknown.xml", NULL, xml_options);
2389 }
else if (uncompressed) {
2390 output = xmlCtxtReadFile(ctxt, filename, NULL, xml_options);
2393 char *input = decompress_file(filename);
2395 output = xmlCtxtReadDoc(ctxt, (
const xmlChar *)input, NULL, NULL,
2400 if (output && (xml = xmlDocGetRootElement(output))) {
2404 last_error = xmlCtxtGetLastError(ctxt);
2405 if (last_error && last_error->code != XML_ERR_OK) {
2411 crm_err(
"Parsing failed (domain=%d, level=%d, code=%d): %s",
2412 last_error->domain, last_error->level, last_error->code, last_error->message);
2414 if (last_error && last_error->code != XML_ERR_OK) {
2415 crm_err(
"Couldn't%s parse %s", xml ?
" fully" :
"", filename);
2422 xmlFreeParserCtxt(ctxt);
2437 time_t now = time(NULL);
2438 char *now_str = ctime(&now);
2454 for (c =
id; *c; ++c) {
2479 va_start(ap, format);
2480 len = vasprintf(&
id, format, ap);
2501 write_xml_stream(xmlNode * xml_node,
const char *filename, FILE * stream, gboolean compress)
2504 char *buffer = NULL;
2505 unsigned int out = 0;
2518 unsigned int in = 0;
2519 BZFILE *bz_file = NULL;
2521 bz_file = BZ2_bzWriteOpen(&rc, stream, 5, 0, 30);
2523 crm_warn(
"Not compressing %s: could not prepare file stream: %s " 2526 BZ2_bzWrite(&rc, bz_file, buffer, strlen(buffer));
2528 crm_warn(
"Not compressing %s: could not compress data: %s " 2529 CRM_XS " bzerror=%d errno=%d",
2535 BZ2_bzWriteClose(&rc, bz_file, 0, &in, &out);
2537 crm_warn(
"Not compressing %s: could not write compressed data: %s " 2538 CRM_XS " bzerror=%d errno=%d",
2543 crm_trace(
"Compressed XML for %s from %u bytes to %u",
2548 crm_warn(
"Not compressing %s: not built with bzlib support", filename);
2553 res = fprintf(stream,
"%s", buffer);
2563 if (fflush(stream) != 0) {
2565 crm_perror(LOG_ERR,
"flushing %s", filename);
2569 if (fsync(fileno(stream)) < 0 && errno != EROFS && errno != EINVAL) {
2571 crm_perror(LOG_ERR,
"synchronizing %s", filename);
2576 crm_trace(
"Saved %d bytes%s to %s as XML",
2577 res, ((out > 0)?
" (compressed)" :
""), filename);
2594 write_xml_fd(xmlNode * xml_node,
const char *filename,
int fd, gboolean compress)
2596 FILE *stream = NULL;
2598 CRM_CHECK(xml_node && (fd > 0),
return -EINVAL);
2599 stream = fdopen(fd,
"w");
2600 if (stream == NULL) {
2603 return write_xml_stream(xml_node, filename, stream, compress);
2618 FILE *stream = NULL;
2620 CRM_CHECK(xml_node && filename,
return -EINVAL);
2621 stream = fopen(filename,
"w");
2622 if (stream == NULL) {
2625 return write_xml_stream(xml_node, filename, stream, compress);
2633 return __xml_first_child(tmp);
2646 crm_xml_escape_shuffle(
char *text,
int start,
int *length,
const char *replace)
2649 int offset = strlen(replace) - 1;
2652 text = realloc_safe(text, *length);
2654 for (lpc = (*length) - 1; lpc > (start + offset); lpc--) {
2655 text[lpc] = text[lpc - offset];
2658 memcpy(text + start, replace, offset + 1);
2667 int length = 1 + strlen(text);
2668 char *copy = strdup(text);
2685 for (index = 0; index < length; index++) {
2686 switch (copy[index]) {
2690 copy = crm_xml_escape_shuffle(copy, index, &length,
"<");
2694 copy = crm_xml_escape_shuffle(copy, index, &length,
">");
2698 copy = crm_xml_escape_shuffle(copy, index, &length,
""");
2702 copy = crm_xml_escape_shuffle(copy, index, &length,
"'");
2706 copy = crm_xml_escape_shuffle(copy, index, &length,
"&");
2711 copy = crm_xml_escape_shuffle(copy, index, &length,
" ");
2716 copy = crm_xml_escape_shuffle(copy, index, &length,
"\\n");
2720 copy = crm_xml_escape_shuffle(copy, index, &length,
"\\r");
2730 if(copy[index] <
' ' || copy[index] >
'~') {
2734 copy = crm_xml_escape_shuffle(copy, index, &length, replace);
2748 dump_xml_attr(xmlAttrPtr attr,
int options,
char **buffer,
int *offset,
int *max)
2750 char *p_value = NULL;
2751 const char *p_name = NULL;
2755 if (attr == NULL || attr->children == NULL) {
2764 p_name = (
const char *)attr->name;
2766 buffer_print(*buffer, *max, *offset,
" %s=\"%s\"", p_name, p_value);
2771 __xml_log_element(
int log_level,
const char *file,
const char *
function,
int line,
2772 const char *prefix, xmlNode *
data,
int depth,
int options)
2776 const char *name = NULL;
2777 const char *hidden = NULL;
2779 xmlNode *child = NULL;
2780 xmlAttrPtr pIter = NULL;
2786 name = crm_element_name(
data);
2789 char *buffer = NULL;
2791 insert_prefix(options, &buffer, &offset, &max, depth);
2793 if (
data->type == XML_COMMENT_NODE) {
2800 for (pIter = crm_first_attr(
data); pIter != NULL; pIter = pIter->next) {
2802 const char *p_name = (
const char *)pIter->name;
2803 const char *p_value = crm_attr_value(pIter);
2804 char *p_copy = NULL;
2813 }
else if (hidden != NULL && p_name[0] != 0 && strstr(hidden, p_name) != NULL) {
2814 p_copy = strdup(
"*****");
2820 buffer_print(buffer, max, offset,
" %s=\"%s\"", p_name, p_copy);
2835 do_crm_log_alias(log_level, file,
function, line,
"%s %s", prefix, buffer);
2839 if(
data->type == XML_COMMENT_NODE) {
2849 for (child = __xml_first_child(
data); child != NULL; child = __xml_next(child)) {
2855 char *buffer = NULL;
2857 insert_prefix(options, &buffer, &offset, &max, depth);
2860 do_crm_log_alias(log_level, file,
function, line,
"%s %s", prefix, buffer);
2866 __xml_log_change_element(
int log_level,
const char *file,
const char *
function,
int line,
2867 const char *prefix, xmlNode *
data,
int depth,
int options)
2870 char *prefix_m = NULL;
2871 xmlNode *child = NULL;
2872 xmlAttrPtr pIter = NULL;
2880 prefix_m = strdup(prefix);
2885 __xml_log_element(log_level, file,
function, line,
2889 char *spaces = calloc(80, 1);
2890 int s_count = 0, s_max = 80;
2891 char *prefix_del = NULL;
2892 char *prefix_moved = NULL;
2893 const char *
flags = prefix;
2895 insert_prefix(options, &spaces, &s_count, &s_max, depth);
2896 prefix_del = strdup(prefix);
2897 prefix_del[0] =
'-';
2898 prefix_del[1] =
'-';
2899 prefix_moved = strdup(prefix);
2900 prefix_moved[1] =
'~';
2903 flags = prefix_moved;
2908 __xml_log_element(log_level, file,
function, line,
2911 for (pIter = crm_first_attr(
data); pIter != NULL; pIter = pIter->next) {
2912 const char *aname = (
const char*)pIter->name;
2914 p = pIter->_private;
2919 "%s %s @%s=%s", flags, spaces, aname, value);
2931 flags = prefix_moved;
2937 "%s %s @%s=%s", flags, spaces, aname, value);
2944 for (child = __xml_first_child(
data); child != NULL; child = __xml_next(child)) {
2945 __xml_log_change_element(log_level, file,
function, line, prefix, child, depth + 1, options);
2948 __xml_log_element(log_level, file,
function, line,
2952 for (child = __xml_first_child(
data); child != NULL; child = __xml_next(child)) {
2953 __xml_log_change_element(log_level, file,
function, line, prefix, child, depth + 1, options);
2963 const char *prefix, xmlNode *
data,
int depth,
int options)
2965 xmlNode *a_child = NULL;
2967 char *prefix_m = NULL;
2969 if (prefix == NULL) {
2976 "No data to dump as XML");
2981 __xml_log_change_element(log_level, file,
function, line, prefix, data, depth, options);
2989 prefix_m = strdup(prefix);
2996 prefix_m = strdup(prefix);
3005 for (a_child = __xml_first_child(data); a_child != NULL; a_child = __xml_next(a_child)) {
3006 log_data_element(log_level, file,
function, line, prefix, a_child, depth + 1, options);
3009 __xml_log_element(log_level, file,
function, line, prefix, data, depth,
3016 dump_filtered_xml(xmlNode *
data,
int options,
char **buffer,
int *offset,
int *max)
3019 xmlAttrPtr xIter = NULL;
3020 static int filter_len =
DIMOF(filter);
3022 for (lpc = 0; options && lpc < filter_len; lpc++) {
3023 filter[lpc].found = FALSE;
3026 for (xIter = crm_first_attr(
data); xIter != NULL; xIter = xIter->next) {
3028 const char *p_name = (
const char *)xIter->name;
3030 for (lpc = 0; skip == FALSE && lpc < filter_len; lpc++) {
3031 if (filter[lpc].found == FALSE && strcmp(p_name, filter[lpc].
string) == 0) {
3032 filter[lpc].found = TRUE;
3038 if (skip == FALSE) {
3039 dump_xml_attr(xIter, options, buffer, offset, max);
3045 dump_xml_element(xmlNode *
data,
int options,
char **buffer,
int *offset,
int *max,
int depth)
3047 const char *name = NULL;
3058 if (*buffer == NULL) {
3063 name = crm_element_name(
data);
3066 insert_prefix(options, buffer, offset, max, depth);
3070 dump_filtered_xml(
data, options, buffer, offset, max);
3073 xmlAttrPtr xIter = NULL;
3075 for (xIter = crm_first_attr(
data); xIter != NULL; xIter = xIter->next) {
3076 dump_xml_attr(xIter, options, buffer, offset, max);
3080 if (
data->children == NULL) {
3091 if (
data->children) {
3092 xmlNode *xChild = NULL;
3093 for(xChild =
data->children; xChild != NULL; xChild = xChild->next) {
3094 crm_xml_dump(xChild, options, buffer, offset, max, depth + 1);
3097 insert_prefix(options, buffer, offset, max, depth);
3100 if (options & xml_log_option_formatted) {
3107 dump_xml_text(xmlNode *
data,
int options,
char **buffer,
int *offset,
int *max,
int depth)
3118 if (*buffer == NULL) {
3123 insert_prefix(options, buffer, offset, max, depth);
3134 dump_xml_comment(xmlNode *
data,
int options,
char **buffer,
int *offset,
int *max,
int depth)
3145 if (*buffer == NULL) {
3150 insert_prefix(options, buffer, offset, max, depth);
3185 xmlBuffer *xml_buffer = NULL;
3193 xml_buffer = xmlBufferCreate();
3204 xmlBufferSetAllocationScheme(xml_buffer, XML_BUFFER_ALLOC_DOUBLEIT);
3208 *buffer = strdup((
char *)xml_buffer->content);
3212 if ((now + 1) < next) {
3214 crm_err(
"xmlNodeDump() -> %dbytes took %ds", *max, next - now);
3217 xmlBufferFree(xml_buffer);
3222 switch(data->type) {
3223 case XML_ELEMENT_NODE:
3225 dump_xml_element(data, options, buffer, offset, max, depth);
3230 dump_xml_text(data, options, buffer, offset, max, depth);
3233 case XML_COMMENT_NODE:
3234 dump_xml_comment(data, options, buffer, offset, max, depth);
3237 crm_warn(
"Unhandled type: %d", data->type);
3273 char *buffer = NULL;
3274 int offset = 0, max = 0;
3283 char *buffer = NULL;
3284 int offset = 0, max = 0;
3293 char *buffer = NULL;
3294 int offset = 0, max = 0;
3296 crm_xml_dump(an_xml_node, 0, &buffer, &offset, &max, 0);
3303 if (xml_root != NULL && xml_root->children != NULL) {
3312 const char *value = NULL;
3326 const char *value = NULL;
3331 return errno? -1 : 0;
3347 const char *name_usec,
struct timeval *dest)
3349 const char *value_s = NULL;
3350 long long value_i = 0;
3352 CRM_CHECK(dest != NULL,
return -EINVAL);
3367 dest->tv_sec = (time_t) value_i;
3377 dest->tv_usec = (suseconds_t) value_i;
3385 char *value_copy = NULL;
3388 if (value != NULL) {
3389 value_copy = strdup(value);
3398 crm_trace(
"Cannot remove %s from %s", name, obj->name);
3403 xmlAttr *attr = xmlHasProp(obj, (
const xmlChar *)name);
3411 xmlUnsetProp(obj, (
const xmlChar *)name);
3418 xmlNode *child = NULL;
3423 for (child = __xml_first_child(a_node); child != NULL; child = __xml_next(child)) {
3433 if (filename == NULL) {
3441 crm_info(
"Saving %s to %s", desc, filename);
3449 gboolean result = TRUE;
3450 int root_nodes_seen = 0;
3451 static struct qb_log_callsite *digest_cs = NULL;
3455 xmlNode *child_diff = NULL;
3457 xmlNode *removed =
find_xml_node(diff,
"diff-removed", FALSE);
3459 CRM_CHECK(new_xml != NULL,
return FALSE);
3460 if (digest_cs == NULL) {
3462 qb_log_callsite_get(__func__, __FILE__,
"diff-digest",
LOG_TRACE, __LINE__,
3467 for (child_diff = __xml_first_child(removed); child_diff != NULL;
3468 child_diff = __xml_next(child_diff)) {
3469 CRM_CHECK(root_nodes_seen == 0, result = FALSE);
3470 if (root_nodes_seen == 0) {
3476 if (root_nodes_seen == 0) {
3479 }
else if (root_nodes_seen > 1) {
3480 crm_err(
"(-) Diffs cannot contain more than one change set..." " saw %d", root_nodes_seen);
3484 root_nodes_seen = 0;
3487 xmlNode *child_diff = NULL;
3489 for (child_diff = __xml_first_child(added); child_diff != NULL;
3490 child_diff = __xml_next(child_diff)) {
3491 CRM_CHECK(root_nodes_seen == 0, result = FALSE);
3492 if (root_nodes_seen == 0) {
3493 add_xml_object(NULL, *new_xml, child_diff, TRUE);
3499 if (root_nodes_seen > 1) {
3500 crm_err(
"(+) Diffs cannot contain more than one change set..." " saw %d", root_nodes_seen);
3503 }
else if (result && digest) {
3504 char *new_digest = NULL;
3509 crm_info(
"Digest mis-match: expected %s, calculated %s", digest, new_digest);
3512 crm_trace(
"%p %.6x", digest_cs, digest_cs ? digest_cs->targets : 0);
3513 if (digest_cs && digest_cs->targets) {
3520 crm_trace(
"Digest matched: expected %s, calculated %s", digest, new_digest);
3524 }
else if (result) {
3532 __xml_diff_object(xmlNode *old_xml, xmlNode *new_xml)
3534 xmlNode *cIter = NULL;
3535 xmlAttr *pIter = NULL;
3538 if (old_xml == NULL) {
3539 crm_node_created(new_xml);
3553 for (pIter = crm_first_attr(new_xml); pIter != NULL; pIter = pIter->next) {
3560 for (pIter = crm_first_attr(old_xml); pIter != NULL; ) {
3561 xmlAttr *prop = pIter;
3563 const char *name = (
const char *)pIter->name;
3565 xmlAttr *exists = xmlHasProp(new_xml, pIter->name);
3567 pIter = pIter->next;
3568 if(exists == NULL) {
3569 p = new_xml->doc->_private;
3573 exists = xmlSetProp(new_xml, (
const xmlChar *) name,
3574 (
const xmlChar *) old_value);
3577 p = exists->_private;
3580 crm_trace(
"Lost %s@%s=%s", old_xml->name, name, old_value);
3584 int p_new = __xml_offset((xmlNode*)exists);
3585 int p_old = __xml_offset((xmlNode*)prop);
3588 p = exists->_private;
3591 if(strcmp(value, old_value) != 0) {
3598 old_xml->name, name, old_value, vcopy);
3599 xmlSetProp(new_xml, prop->name, (
const xmlChar *) old_value);
3603 }
else if ((p_old != p_new)
3606 old_xml->name, name, p_old, p_new);
3607 __xml_node_dirty(new_xml);
3615 p = exists->_private;
3622 for (pIter = crm_first_attr(new_xml); pIter != NULL; ) {
3623 xmlAttr *prop = pIter;
3626 pIter = pIter->next;
3628 char *name = strdup((
const char *)prop->name);
3631 crm_trace(
"Created %s@%s=%s", new_xml->name, name, value);
3634 crm_attr_dirty(prop);
3636 xmlUnsetProp(new_xml, prop->name);
3644 for (cIter = __xml_first_child(old_xml); cIter != NULL; ) {
3645 xmlNode *old_child = cIter;
3646 xmlNode *new_child = find_element(new_xml, cIter, TRUE);
3648 cIter = __xml_next(cIter);
3650 __xml_diff_object(old_child, new_child);
3655 xmlNode *top = xmlDocGetRootElement(candidate->doc);
3657 __xml_node_clean(candidate);
3660 free_xml_with_position(candidate, __xml_offset(old_child));
3662 if (find_element(new_xml, old_child, TRUE) == NULL) {
3670 for (cIter = __xml_first_child(new_xml); cIter != NULL; ) {
3671 xmlNode *new_child = cIter;
3672 xmlNode *old_child = find_element(old_xml, cIter, TRUE);
3674 cIter = __xml_next(cIter);
3675 if(old_child == NULL) {
3678 __xml_diff_object(old_child, new_child);
3682 int p_new = __xml_offset(new_child);
3683 int p_old = __xml_offset(old_child);
3685 if(p_old != p_new) {
3688 crm_info(
"%s.%s moved from %d to %d",
3689 new_child->name,
ID(new_child), p_old, p_new);
3690 __xml_node_dirty(new_xml);
3694 p = old_child->_private;
3696 p = new_child->_private;
3715 crm_element_name(new_xml)),
3723 __xml_diff_object(old_xml, new_xml);
3729 xmlNode *tmp1 = NULL;
3746 if (added->children == NULL && removed->children == NULL) {
3757 xmlNode *cIter = NULL;
3758 xmlAttrPtr pIter = NULL;
3759 gboolean can_prune = TRUE;
3760 const char *name = crm_element_name(xml_node);
3769 for (pIter = crm_first_attr(xml_node); pIter != NULL; pIter = pIter->next) {
3770 const char *p_name = (
const char *)pIter->name;
3778 cIter = __xml_first_child(xml_node);
3780 xmlNode *child = cIter;
3782 cIter = __xml_next(cIter);
3793 find_xml_comment(xmlNode * root, xmlNode * search_comment, gboolean exact)
3795 xmlNode *a_child = NULL;
3796 int search_offset = __xml_offset(search_comment);
3798 CRM_CHECK(search_comment->type == XML_COMMENT_NODE,
return NULL);
3800 for (a_child = __xml_first_child(root); a_child != NULL; a_child = __xml_next(a_child)) {
3802 int offset = __xml_offset(a_child);
3805 if (offset < search_offset) {
3808 }
else if (offset > search_offset) {
3817 if (a_child->type == XML_COMMENT_NODE
3818 &&
safe_str_eq((
const char *)a_child->content, (
const char *)search_comment->content)) {
3830 subtract_xml_comment(xmlNode * parent, xmlNode * left, xmlNode * right,
3834 CRM_CHECK(left->type == XML_COMMENT_NODE,
return NULL);
3837 ||
safe_str_neq((
const char *)left->content, (
const char *)right->content)) {
3838 xmlNode *deleted = NULL;
3851 gboolean full, gboolean * changed,
const char *marker)
3853 gboolean dummy = FALSE;
3854 gboolean skip = FALSE;
3855 xmlNode *diff = NULL;
3856 xmlNode *right_child = NULL;
3857 xmlNode *left_child = NULL;
3858 xmlAttrPtr xIter = NULL;
3860 const char *
id = NULL;
3861 const char *name = NULL;
3862 const char *value = NULL;
3863 const char *right_val = NULL;
3866 static int filter_len =
DIMOF(filter);
3868 if (changed == NULL) {
3876 if (left->type == XML_COMMENT_NODE) {
3877 return subtract_xml_comment(parent, left, right, changed);
3881 if (right == NULL) {
3882 xmlNode *deleted = NULL;
3884 crm_trace(
"Processing <%s id=%s> (complete copy)", crm_element_name(left),
id);
3892 name = crm_element_name(left);
3898 if (value != NULL && strcmp(value,
"removed:top") == 0) {
3899 crm_trace(
"We are the root of the deletion: %s.id=%s", name,
id);
3908 for (lpc = 0; lpc < filter_len; lpc++) {
3909 filter[lpc].found = FALSE;
3913 for (left_child = __xml_first_child(left); left_child != NULL;
3914 left_child = __xml_next(left_child)) {
3915 gboolean child_changed = FALSE;
3917 right_child = find_element(right, left_child, FALSE);
3919 if (child_changed) {
3924 if (*changed == FALSE) {
3928 xmlAttrPtr pIter = NULL;
3930 for (pIter = crm_first_attr(left); pIter != NULL; pIter = pIter->next) {
3931 const char *p_name = (
const char *)pIter->name;
3932 const char *p_value = crm_attr_value(pIter);
3934 xmlSetProp(diff, (
const xmlChar *)p_name, (
const xmlChar *)p_value);
3941 xmlSetProp(diff, (
const xmlChar *)
XML_ATTR_ID, (
const xmlChar *)
id);
3945 for (xIter = crm_first_attr(left); xIter != NULL; xIter = xIter->next) {
3946 const char *prop_name = (
const char *)xIter->name;
3947 xmlAttrPtr right_attr = NULL;
3955 for (lpc = 0; skip == FALSE && lpc < filter_len; lpc++) {
3956 if (filter[lpc].found == FALSE && strcmp(prop_name, filter[lpc].
string) == 0) {
3957 filter[lpc].found = TRUE;
3967 right_attr = xmlHasProp(right, (
const xmlChar *)prop_name);
3969 p = right_attr->_private;
3977 xmlAttrPtr pIter = NULL;
3979 for (pIter = crm_first_attr(left); pIter != NULL; pIter = pIter->next) {
3980 const char *p_name = (
const char *)pIter->name;
3981 const char *p_value = crm_attr_value(pIter);
3983 xmlSetProp(diff, (
const xmlChar *)p_name, (
const xmlChar *)p_value);
3990 xmlSetProp(diff, (
const xmlChar *)prop_name, (
const xmlChar *)value);
3998 if (strcmp(left_value, right_val) == 0) {
4004 xmlAttrPtr pIter = NULL;
4006 crm_trace(
"Changes detected to %s in <%s id=%s>", prop_name,
4007 crm_element_name(left),
id);
4008 for (pIter = crm_first_attr(left); pIter != NULL; pIter = pIter->next) {
4009 const char *p_name = (
const char *)pIter->name;
4010 const char *p_value = crm_attr_value(pIter);
4012 xmlSetProp(diff, (
const xmlChar *)p_name, (
const xmlChar *)p_value);
4017 crm_trace(
"Changes detected to %s (%s -> %s) in <%s id=%s>",
4018 prop_name, left_value, right_val, crm_element_name(left),
id);
4025 if (*changed == FALSE) {
4029 }
else if (full == FALSE &&
id) {
4037 add_xml_comment(xmlNode * parent, xmlNode * target, xmlNode * update)
4040 CRM_CHECK(update->type == XML_COMMENT_NODE,
return 0);
4042 if (target == NULL) {
4043 target = find_xml_comment(parent, update, FALSE);
4046 if (target == NULL) {
4050 }
else if (
safe_str_neq((
const char *)target->content, (
const char *)update->content)) {
4051 xmlFree(target->content);
4052 target->content = xmlStrdup(update->content);
4059 add_xml_object(xmlNode * parent, xmlNode * target, xmlNode * update, gboolean as_diff)
4061 xmlNode *a_child = NULL;
4062 const char *object_name = NULL,
4063 *object_href = NULL,
4064 *object_href_val = NULL;
4073 if (update->type == XML_COMMENT_NODE) {
4074 return add_xml_comment(parent, target, update);
4077 object_name = crm_element_name(update);
4078 object_href_val =
ID(update);
4079 if (object_href_val != NULL) {
4086 CRM_CHECK(object_name != NULL,
return 0);
4087 CRM_CHECK(target != NULL || parent != NULL,
return 0);
4089 if (target == NULL) {
4090 target = find_entity_by_attr_or_just_name(parent, object_name,
4091 object_href, object_href_val);
4094 if (target == NULL) {
4097 #if XML_PARSER_DEBUG 4099 object_href ?
" " :
"",
4100 object_href ? object_href :
"",
4101 object_href ?
"=" :
"",
4102 object_href ? object_href_val :
"");
4106 object_href ?
" " :
"",
4107 object_href ? object_href :
"",
4108 object_href ?
"=" :
"",
4109 object_href ? object_href_val :
"");
4115 if (as_diff == FALSE) {
4121 xmlAttrPtr pIter = NULL;
4123 for (pIter = crm_first_attr(update); pIter != NULL; pIter = pIter->next) {
4124 const char *p_name = (
const char *)pIter->name;
4125 const char *p_value = crm_attr_value(pIter);
4128 xmlUnsetProp(target, (
const xmlChar *)p_name);
4129 xmlSetProp(target, (
const xmlChar *)p_name, (
const xmlChar *)p_value);
4133 for (a_child = __xml_first_child(update); a_child != NULL; a_child = __xml_next(a_child)) {
4134 #if XML_PARSER_DEBUG 4136 object_href ?
" " :
"",
4137 object_href ? object_href :
"",
4138 object_href ?
"=" :
"",
4139 object_href ? object_href_val :
"");
4141 add_xml_object(target, NULL, a_child, as_diff);
4144 #if XML_PARSER_DEBUG 4146 object_href ?
" " :
"",
4147 object_href ? object_href :
"",
4148 object_href ?
"=" :
"",
4149 object_href ? object_href_val :
"");
4157 gboolean can_update = TRUE;
4158 xmlNode *child_of_child = NULL;
4161 CRM_CHECK(to_update != NULL,
return FALSE);
4163 if (
safe_str_neq(crm_element_name(to_update), crm_element_name(child))) {
4169 }
else if (can_update) {
4170 #if XML_PARSER_DEBUG 4173 add_xml_object(NULL, child, to_update, FALSE);
4176 for (child_of_child = __xml_first_child(child); child_of_child != NULL;
4177 child_of_child = __xml_next(child_of_child)) {
4190 const char *tag,
const char *field,
const char *value, gboolean search_matches)
4192 int match_found = 0;
4195 CRM_CHECK(children != NULL,
return FALSE);
4197 if (tag != NULL &&
safe_str_neq(tag, crm_element_name(root))) {
4202 if (*children == NULL) {
4209 if (search_matches || match_found == 0) {
4210 xmlNode *child = NULL;
4212 for (child = __xml_first_child(root); child != NULL; child = __xml_next(child)) {
4213 match_found +=
find_xml_children(children, child, tag, field, value, search_matches);
4223 gboolean can_delete = FALSE;
4224 xmlNode *child_of_child = NULL;
4226 const char *up_id = NULL;
4227 const char *child_id = NULL;
4228 const char *right_val = NULL;
4231 CRM_CHECK(update != NULL,
return FALSE);
4234 child_id =
ID(child);
4236 if (up_id == NULL || (child_id && strcmp(child_id, up_id) == 0)) {
4239 if (
safe_str_neq(crm_element_name(update), crm_element_name(child))) {
4242 if (can_delete && delete_only) {
4243 xmlAttrPtr pIter = NULL;
4245 for (pIter = crm_first_attr(update); pIter != NULL; pIter = pIter->next) {
4246 const char *p_name = (
const char *)pIter->name;
4247 const char *p_value = crm_attr_value(pIter);
4256 if (can_delete && parent != NULL) {
4258 if (delete_only || update == NULL) {
4263 xmlDoc *doc = tmp->doc;
4264 xmlNode *old = NULL;
4267 old = xmlReplaceNode(child, tmp);
4275 xmlDocSetRootElement(doc, old);
4281 }
else if (can_delete) {
4286 child_of_child = __xml_first_child(child);
4287 while (child_of_child) {
4288 xmlNode *next = __xml_next(child_of_child);
4294 child_of_child = NULL;
4296 child_of_child = next;
4330 const char *parent_id =
ID(parent);
4343 const char *name = key;
4344 const char *s_value = value;
4345 xmlNode *xml_node = user_data;
4348 crm_trace(
"dumped: name=%s value=%s", name, s_value);
4354 const char *name = key;
4355 const char *s_value = value;
4357 xmlNode *xml_node = user_data;
4359 if (isdigit(name[0])) {
4367 crm_trace(
"dumped: %s=%s", name, s_value);
4370 crm_trace(
"duplicate: %s=%s", name, s_value);
4377 const char *name = key;
4378 const char *s_value = value;
4380 xmlNode *xml_node = user_data;
4386 crm_trace(
"duplicate: %s=%s", name, s_value);
4393 char *crm_name = NULL;
4395 if (key == NULL || value == NULL) {
4402 for (crm_name = key; *crm_name; ++crm_name) {
4403 if ((*crm_name ==
'#') || (*crm_name ==
':')) {
4416 xmlNode *child = NULL;
4417 xmlAttrPtr pIter = NULL;
4418 xmlNode *nvpair_list = NULL;
4419 GHashTable *nvpair_hash = crm_str_table_new();
4421 CRM_CHECK(parent != NULL,
return nvpair_hash);
4424 if (nvpair_list == NULL) {
4425 crm_trace(
"No attributes in %s", crm_element_name(parent));
4431 for (pIter = crm_first_attr(nvpair_list); pIter != NULL; pIter = pIter->next) {
4432 const char *p_name = (
const char *)pIter->name;
4433 const char *p_value = crm_attr_value(pIter);
4435 crm_trace(
"Added %s=%s", p_name, p_value);
4437 g_hash_table_insert(nvpair_hash, strdup(p_name), strdup(p_value));
4440 for (child = __xml_first_child(nvpair_list); child != NULL; child = __xml_next(child)) {
4441 if (strcmp((
const char *)child->name,
XML_TAG_PARAM) == 0) {
4446 if (key != NULL && value != NULL) {
4447 g_hash_table_insert(nvpair_hash, strdup(key), strdup(value));
4455 typedef struct name_value_s {
4461 sort_pairs(gconstpointer a, gconstpointer b)
4473 rc = strcmp(pair_a->name, pair_b->name);
4476 }
else if (rc > 0) {
4483 dump_pair(gpointer
data, gpointer user_data)
4486 xmlNode *parent = user_data;
4492 sorted_xml(xmlNode * input, xmlNode * parent, gboolean recursive)
4494 xmlNode *child = NULL;
4498 xmlNode *result = NULL;
4499 const char *name = NULL;
4500 xmlAttrPtr pIter = NULL;
4504 name = crm_element_name(input);
4509 for (pIter = crm_first_attr(input); pIter != NULL; pIter = pIter->next) {
4510 const char *p_name = (
const char *)pIter->name;
4511 const char *p_value = crm_attr_value(pIter);
4514 pair->name = p_name;
4515 pair->value = p_value;
4516 unsorted = g_list_prepend(unsorted, pair);
4520 sorted = g_list_sort(unsorted, sort_pairs);
4521 g_list_foreach(sorted, dump_pair, result);
4522 g_list_free_full(sorted, free);
4524 for (child = __xml_first_child(input); child != NULL; child = __xml_next(child)) {
4538 xmlNode *match = NULL;
4540 for (match = __xml_first_child(parent); match != NULL; match = __xml_next(match)) {
4546 if (name == NULL || strcmp((
const char *)match->name, name) == 0) {
4563 xmlNode *match = __xml_next(sibling);
4564 const char *name = crm_element_name(sibling);
4566 while (match != NULL) {
4567 if (!strcmp(crm_element_name(match), name)) {
4570 match = __xml_next(match);
4578 static bool init = TRUE;
4587 xmlSetBufferAllocationScheme(XML_BUFFER_ALLOC_DOUBLEIT);
4590 xmlDeregisterNodeDefault(pcmkDeregisterNode);
4591 xmlRegisterNodeDefault(pcmkRegisterNode);
4600 crm_info(
"Cleaning up memory from libxml2");
4605 #define XPATH_MAX 512 4610 const char *tag = NULL;
4611 const char *ref = NULL;
4612 xmlNode *result = input;
4614 if (result == NULL) {
4617 }
else if (top == NULL) {
4621 tag = crm_element_name(result);
4628 if (result == NULL) {
4629 char *nodePath = (
char *)xmlGetNodePath(top);
4631 crm_err(
"No match for %s found in %s: Invalid configuration", xpath_string,
4643 xmlAttr *attr = NULL;
4646 crm_err(
"Couldn't find %s in NULL", name ? name :
"<null>");
4650 }
else if (name == NULL) {
4651 crm_err(
"Couldn't find NULL in %s", crm_element_name(data));
4658 attr = xmlHasProp((xmlNode *) data, (
const xmlChar *)name);
4659 if (attr == NULL || attr->children == NULL) {
4662 return (
const char *)attr->children->content;
#define pcmk_err_old_data
#define CRM_CHECK(expr, failure_action)
bool pcmk__tracking_xml_changes(xmlNode *xml, bool lazy)
const char * crm_get_tmpdir(void)
#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)
void crm_schema_init(void)
#define crm_notice(fmt, args...)
#define XML_ATTR_UPDATE_CLIENT
const char * bz2_strerror(int rc)
xmlNode * diff_xml_object(xmlNode *old, xmlNode *new, gboolean suppress)
int crm_element_value_ms(const xmlNode *data, const char *name, guint *dest)
gboolean safe_str_neq(const char *a, const char *b)
char * crm_generate_uuid(void)
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
void pcmk__free_acls(GList *acls)
const char * crm_xml_add(xmlNode *node, const char *name, const char *value)
void xml_track_changes(xmlNode *xml, const char *user, xmlNode *acl_source, bool enforce_acls)
char * crm_element_value_copy(const xmlNode *data, const char *name)
xmlNode * crm_create_nvpair_xml(xmlNode *parent, const char *id, const char *name, const char *value)
Create an XML name/value pair.
void xml_calculate_changes(xmlNode *old_xml, xmlNode *new_xml)
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)
Write XML to a file descriptor.
void fix_plus_plus_recursive(xmlNode *target)
const char * crm_element_value(const xmlNode *data, const char *name)
xmlNode * first_named_child(const xmlNode *parent, const char *name)
#define buffer_print(buffer, max, offset, fmt, args...)
void crm_schema_cleanup(void)
#define XML_NVPAIR_ATTR_NAME
void purge_diff_markers(xmlNode *a_node)
int pcmk__element_xpath(const char *prefix, xmlNode *xml, char *buffer, int offset, size_t buffer_size)
xmlNode * stdin2xml(void)
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
xmlNode * crm_next_same_xml(const xmlNode *sibling)
Get next instance of same XML tag.
#define XML_CIB_TAG_NVPAIR
void hash2field(gpointer key, gpointer value, gpointer user_data)
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)
void pcmk__post_process_acl(xmlNode *xml)
#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
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)
bool pcmk__check_acl(xmlNode *xml, const char *name, enum xml_private_flags mode)
#define crm_warn(fmt, args...)
#define pcmk_err_diff_failed
#define set_bit(word, bit)
xmlNode * copy_xml(xmlNode *src)
#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)
void xml_log_patchset(uint8_t log_level, const char *function, xmlNode *patchset)
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
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)
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 xml_acl_disable(xmlNode *xml)
void crm_xml_cleanup(void)
xmlNode * add_node_copy(xmlNode *parent, xmlNode *src_node)
xmlDoc * getDocPtr(xmlNode *node)
char * dump_xml_formatted(xmlNode *an_xml_node)
void pcmk__unpack_acl(xmlNode *source, xmlNode *target, const char *user)
const char * crm_xml_add_ms(xmlNode *node, const char *name, guint ms)
int crm_element_value_timeval(const xmlNode *xml, const char *name_sec, const char *name_usec, struct timeval *dest)
Parse a time value from XML.
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)
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)
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)
Write XML to a file.
guint crm_parse_ms(const char *text)
void copy_in_properties(xmlNode *target, xmlNode *src)
long long crm_parse_ll(const char *text, const char *default_text)
Parse a long long integer value from a string.
#define pcmk_err_diff_resync
#define crm_log_xml_err(xml, text)
void pcmk__set_xml_flag(xmlNode *xml, enum xml_private_flags flag)
#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...)
#define XML_CIB_ATTR_WRITTEN
#define XML_ACL_TAG_ROLE_REFv1
int get_attr_value(const char *input, size_t offset, size_t max)
void pcmk__apply_acl(xmlNode *xml)
const char * crm_xml_replace(xmlNode *node, const char *name, const char *value)
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
int crm_element_value_int(const xmlNode *data, const char *name, int *dest)
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)
#define XML_CIB_TAG_CONFIGURATION
#define safe_str_eq(a, b)
int add_node_nocopy(xmlNode *parent, const char *name, xmlNode *child)
void crm_abort(const char *file, const char *function, int line, const char *condition, gboolean do_core, gboolean do_fork)
gboolean replace_xml_child(xmlNode *parent, xmlNode *child, xmlNode *update, gboolean delete_only)
void xml_remove_prop(xmlNode *obj, const char *name)
char * crm_strdup_printf(char const *format,...) __attribute__((__format__(__printf__
xmlNode * find_entity(xmlNode *parent, const char *node_name, const char *id)
#define crm_info(fmt, args...)
gboolean apply_xml_diff(xmlNode *old_xml, xmlNode *diff, xmlNode **new_xml)
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