13 #include <sys/types.h> 21 #include <libxml/parser.h> 22 #include <libxml/tree.h> 23 #include <libxml/xmlIO.h> 32 static xmlNode *subtract_xml_comment(xmlNode *parent, xmlNode *left,
33 xmlNode *right, gboolean *changed);
86 add_xml_changes_to_patchset(xmlNode *xml, xmlNode *patchset)
88 xmlNode *cIter = NULL;
89 xmlAttr *pIter = NULL;
90 xmlNode *change = NULL;
92 const char *value = NULL;
100 sizeof(buffer)) > 0) {
115 for (pIter = pcmk__first_xml_attr(xml); pIter != NULL;
116 pIter = pIter->next) {
117 xmlNode *attr = NULL;
124 if (change == NULL) {
129 sizeof(buffer)) > 0) {
154 xmlNode *result = NULL;
159 for (pIter = pcmk__first_xml_attr(xml); pIter != NULL;
160 pIter = pIter->next) {
164 crm_xml_add(result, (
const char *)pIter->name, value);
170 for (cIter = pcmk__xml_first_child(xml); cIter != NULL;
171 cIter = pcmk__xml_next(cIter)) {
172 add_xml_changes_to_patchset(cIter, patchset);
183 sizeof(buffer)) > 0) {
195 is_config_change(xmlNode *xml)
202 p = config->_private;
208 if ((xml->doc != NULL) && (xml->doc->_private != NULL)) {
209 p = xml->doc->_private;
210 for (gIter = p->
deleted_objs; gIter; gIter = gIter->next) {
213 if (strstr(deleted_obj->
path,
223 xml_repair_v1_diff(xmlNode *last, xmlNode *next, xmlNode *local_diff,
228 xmlNode *diff_child = NULL;
230 const char *tag = NULL;
232 const char *vfields[] = {
238 if (local_diff == NULL) {
243 tag =
"diff-removed";
245 if (diff_child == NULL) {
255 for (lpc = 0; (last != NULL) && (lpc <
DIMOF(vfields)); lpc++) {
259 if (changed || lpc == 2) {
266 if (diff_child == NULL) {
276 for (lpc = 0; next && lpc <
DIMOF(vfields); lpc++) {
283 xmlAttrPtr xIter = NULL;
285 for (xIter = next->properties; xIter; xIter = xIter->next) {
286 const char *p_name = (
const char *) xIter->name;
297 xml_create_patchset_v1(xmlNode *source, xmlNode *
target,
bool config,
304 xml_repair_v1_diff(source,
target, patchset, config);
311 xml_create_patchset_v2(xmlNode *source, xmlNode *
target)
319 xmlNode *patchset = NULL;
320 const char *vfields[] = {
332 doc =
target->doc->_private;
340 for (lpc = 0; lpc <
DIMOF(vfields); lpc++) {
350 for (lpc = 0; lpc <
DIMOF(vfields); lpc++) {
359 for (gIter = doc->
deleted_objs; gIter; gIter = gIter->next) {
370 add_xml_changes_to_patchset(
target, patchset);
376 bool *config_changed,
bool manage_version)
380 xmlNode *patch = NULL;
389 config = is_config_change(
target);
390 if (config_changed) {
391 *config_changed = config;
394 if (manage_version && config) {
401 }
else if (manage_version) {
403 crm_trace(
"Status changed %d - %d %s", format, counter,
419 patch = xml_create_patchset_v1(source,
target, config, FALSE);
422 patch = xml_create_patchset_v2(source,
target);
425 crm_err(
"Unknown patch format: %d", format);
439 if ((patch == NULL) || (source == NULL) || (
target == NULL)) {
449 if ((format > 1) && !with_digest) {
466 xmlNode *child = NULL;
467 xmlNode *added = NULL;
468 xmlNode *removed = NULL;
469 gboolean is_first = TRUE;
471 int add[] = { 0, 0, 0 };
472 int del[] = { 0, 0, 0 };
474 const char *fmt = NULL;
475 const char *digest = NULL;
478 static struct qb_log_callsite *patchset_cs = NULL;
483 if (patchset_cs == NULL) {
484 patchset_cs = qb_log_callsite_get(
function, __FILE__,
"xml-patchset",
485 log_level, __LINE__, 0);
488 if (patchset == NULL) {
501 if ((add[2] != del[2]) || (add[1] != del[1]) || (add[0] != del[0])) {
503 "Diff: --- %d.%d.%d %s", del[0], del[1], del[2], fmt);
505 "Diff: +++ %d.%d.%d %s",
506 add[0], add[1], add[2], digest);
508 }
else if ((patchset != NULL) && (add[0] || add[1] || add[2])) {
510 "%s: Local-only Change: %d.%d.%d",
511 (
function?
function :
""), add[0], add[1], add[2]);
516 xmlNode *change = NULL;
518 for (change = pcmk__xml_first_child(patchset); change != NULL;
519 change = pcmk__xml_next(change)) {
524 }
else if (strcmp(op,
"create") == 0) {
525 int lpc = 0, max = 0;
528 max = strlen(prefix);
529 pcmk__xe_log(log_level, __FILE__,
function, __LINE__, prefix,
533 for (lpc = 2; lpc < max; lpc++) {
537 pcmk__xe_log(log_level, __FILE__,
function, __LINE__, prefix,
543 }
else if (strcmp(op,
"move") == 0) {
545 "+~ %s moved to offset %s", xpath,
548 }
else if (strcmp(op,
"modify") == 0) {
557 for (child = pcmk__xml_first_child(clist); child != NULL;
558 child = pcmk__xml_next(child)) {
563 }
else if (strcmp(op,
"set") == 0) {
567 o_set += snprintf(buffer_set + o_set,
570 o_set += snprintf(buffer_set + o_set,
574 }
else if (strcmp(op,
"unset") == 0) {
576 o_unset += snprintf(buffer_unset + o_unset,
580 o_unset += snprintf(buffer_unset + o_unset,
587 "+ %s: %s", xpath, buffer_set);
591 "-- %s: %s", xpath, buffer_unset);
594 }
else if (strcmp(op,
"delete") == 0) {
600 "-- %s (%d)", xpath, position);
611 if ((log_level < LOG_DEBUG) || (
function == NULL)) {
616 for (child = pcmk__xml_first_child(removed); child != NULL;
617 child = pcmk__xml_next(child)) {
629 for (child = pcmk__xml_first_child(added); child != NULL;
630 child = pcmk__xml_next(child)) {
643 process_v1_removals(xmlNode *
target, xmlNode *patch)
645 xmlNode *patch_child = NULL;
646 xmlNode *cIter = NULL;
647 xmlAttrPtr xIter = NULL;
650 const char *
name = NULL;
651 const char *value = NULL;
653 if ((
target == NULL) || (patch == NULL)) {
657 if (
target->type == XML_COMMENT_NODE) {
660 subtract_xml_comment(
target->parent,
target, patch, &dummy);
665 CRM_CHECK(pcmk__str_eq(crm_element_name(
target), crm_element_name(patch),
673 if ((value != NULL) && (strcmp(value,
"removed:top") == 0)) {
674 crm_trace(
"We are the root of the deletion: %s.id=%s",
name,
id);
680 for (xIter = pcmk__first_xml_attr(patch); xIter != NULL;
681 xIter = xIter->next) {
682 const char *p_name = (
const char *)xIter->name;
691 cIter = pcmk__xml_first_child(
target);
693 xmlNode *target_child = cIter;
695 cIter = pcmk__xml_next(cIter);
697 process_v1_removals(target_child, patch_child);
704 process_v1_additions(xmlNode *parent, xmlNode *
target, xmlNode *patch)
706 xmlNode *patch_child = NULL;
707 xmlNode *target_child = NULL;
708 xmlAttrPtr xIter = NULL;
710 const char *
id = NULL;
711 const char *
name = NULL;
712 const char *value = NULL;
716 }
else if ((parent == NULL) && (
target == NULL)) {
722 if ((
target == NULL) && (value != NULL)
723 && (strcmp(value,
"added:top") == 0)) {
725 name = crm_element_name(patch);
726 crm_trace(
"We are the root of the addition: %s.id=%s",
name,
id);
730 }
else if (
target == NULL) {
732 name = crm_element_name(patch);
737 if (
target->type == XML_COMMENT_NODE) {
743 CRM_CHECK(pcmk__str_eq(crm_element_name(
target), crm_element_name(patch),
748 for (xIter = pcmk__first_xml_attr(patch); xIter != NULL;
749 xIter = xIter->next) {
750 const char *p_name = (
const char *) xIter->name;
758 for (patch_child = pcmk__xml_first_child(patch); patch_child != NULL;
759 patch_child = pcmk__xml_next(patch_child)) {
762 process_v1_additions(
target, target_child, patch_child);
778 find_patch_xml_node(xmlNode *patchset,
int format,
bool added,
779 xmlNode **patch_node)
786 label = added?
"diff-added" :
"diff-removed";
789 if (cib_node != NULL) {
790 *patch_node = cib_node;
794 label = added?
"target" :
"source";
799 crm_warn(
"Unknown patch format: %d", format);
814 const char *vfields[] = {
824 if (!find_patch_xml_node(patchset, format, FALSE, &tmp)) {
828 for (lpc = 0; lpc <
DIMOF(vfields); lpc++) {
830 crm_trace(
"Got %d for del[%s]", del[lpc], vfields[lpc]);
835 if (!find_patch_xml_node(patchset, format, TRUE, &tmp)) {
839 for (lpc = 0; lpc <
DIMOF(vfields); lpc++) {
841 crm_trace(
"Got %d for add[%s]", add[lpc], vfields[lpc]);
858 xml_patch_version_check(xmlNode *xml, xmlNode *patchset,
int format)
861 bool changed = FALSE;
863 int this[] = { 0, 0, 0 };
864 int add[] = { 0, 0, 0 };
865 int del[] = { 0, 0, 0 };
867 const char *vfields[] = {
873 for (lpc = 0; lpc <
DIMOF(vfields); lpc++) {
875 crm_trace(
"Got %d for this[%s]",
this[lpc], vfields[lpc]);
884 add[2] =
this[2] + 1;
885 for (lpc = 0; lpc <
DIMOF(vfields); lpc++) {
886 del[lpc] =
this[lpc];
891 for (lpc = 0; lpc <
DIMOF(vfields); lpc++) {
892 if (
this[lpc] < del[lpc]) {
893 crm_debug(
"Current %s is too low (%d.%d.%d < %d.%d.%d --> %d.%d.%d)",
894 vfields[lpc],
this[0],
this[1],
this[2],
895 del[0], del[1], del[2], add[0], add[1], add[2]);
898 }
else if (
this[lpc] > del[lpc]) {
899 crm_info(
"Current %s is too high (%d.%d.%d > %d.%d.%d --> %d.%d.%d) %p",
900 vfields[lpc],
this[0],
this[1],
this[2],
901 del[0], del[1], del[2], add[0], add[1], add[2], patchset);
907 for (lpc = 0; lpc <
DIMOF(vfields); lpc++) {
908 if (add[lpc] > del[lpc]) {
914 crm_notice(
"Versions did not change in patch %d.%d.%d",
915 add[0], add[1], add[2]);
919 crm_debug(
"Can apply patch %d.%d.%d to %d.%d.%d",
920 add[0], add[1], add[2],
this[0],
this[1],
this[2]);
934 apply_v1_patchset(xmlNode *xml, xmlNode *patchset)
937 int root_nodes_seen = 0;
939 xmlNode *child_diff = NULL;
940 xmlNode *added =
find_xml_node(patchset,
"diff-added", FALSE);
941 xmlNode *removed =
find_xml_node(patchset,
"diff-removed", FALSE);
945 for (child_diff = pcmk__xml_first_child(removed); child_diff != NULL;
946 child_diff = pcmk__xml_next(child_diff)) {
948 if (root_nodes_seen == 0) {
949 process_v1_removals(xml, child_diff);
954 if (root_nodes_seen > 1) {
955 crm_err(
"(-) Diffs cannot contain more than one change set... saw %d",
963 xmlNode *child_diff = NULL;
965 for (child_diff = pcmk__xml_first_child(added); child_diff != NULL;
966 child_diff = pcmk__xml_next(child_diff)) {
968 if (root_nodes_seen == 0) {
969 process_v1_additions(NULL, xml, child_diff);
975 if (root_nodes_seen > 1) {
976 crm_err(
"(+) Diffs cannot contain more than one change set... saw %d",
989 first_matching_xml_child(xmlNode *parent,
const char *
name,
const char *
id,
992 xmlNode *cIter = NULL;
994 for (cIter = pcmk__xml_first_child(parent); cIter != NULL;
995 cIter = pcmk__xml_next(cIter)) {
996 if (strcmp((
const char *) cIter->name,
name) != 0) {
999 const char *cid =
ID(cIter);
1001 if ((cid == NULL) || (strcmp(cid,
id) != 0)) {
1007 if ((cIter->type == XML_COMMENT_NODE)
1032 search_v2_xpath(xmlNode *top,
const char *key,
int target_position)
1034 xmlNode *
target = (xmlNode *) top->doc;
1035 const char *current = key;
1045 key_len = strlen(key);
1051 remainder = calloc(key_len,
sizeof(
char));
1054 section = calloc(key_len,
sizeof(
char));
1057 id = calloc(key_len,
sizeof(
char));
1060 tag = calloc(key_len,
sizeof(
char));
1065 rc = sscanf(current,
"/%[^/]%s", section, remainder);
1068 int f = sscanf(section,
"%[^[][@id='%[^']", tag,
id);
1069 int current_position = -1;
1074 if ((
rc == 1) && (target_position >= 0)) {
1075 current_position = target_position;
1092 current = remainder;
1100 (path = (
char *) xmlGetNodePath(
target)), key);
1113 typedef struct xml_change_obj_s {
1119 sort_change_obj_by_position(gconstpointer a, gconstpointer b)
1123 int position_a = -1;
1124 int position_b = -1;
1129 if (position_a < position_b) {
1132 }
else if (position_a > position_b) {
1149 apply_v2_patchset(xmlNode *xml, xmlNode *patchset)
1152 xmlNode *change = NULL;
1156 for (change = pcmk__xml_first_child(patchset); change != NULL;
1157 change = pcmk__xml_next(change)) {
1158 xmlNode *match = NULL;
1167 crm_trace(
"Processing %s %s", change->name, op);
1170 if (strcmp(op,
"delete") == 0) {
1173 match = search_v2_xpath(xml, xpath, position);
1174 crm_trace(
"Performing %s on %s with %p", op, xpath, match);
1176 if ((match == NULL) && (strcmp(op,
"delete") == 0)) {
1177 crm_debug(
"No %s match for %s in %p", op, xpath, xml->doc);
1180 }
else if (match == NULL) {
1181 crm_err(
"No %s match for %s in %p", op, xpath, xml->doc);
1185 }
else if ((strcmp(op,
"create") == 0) || (strcmp(op,
"move") == 0)) {
1191 change_obj->change = change;
1192 change_obj->match = match;
1194 change_objs = g_list_append(change_objs, change_obj);
1196 if (strcmp(op,
"move") == 0) {
1198 if ((match->parent != NULL) && (match->parent->last != NULL)) {
1199 xmlAddNextSibling(match->parent->last, match);
1203 }
else if (strcmp(op,
"delete") == 0) {
1206 }
else if (strcmp(op,
"modify") == 0) {
1207 xmlAttr *pIter = pcmk__first_xml_attr(match);
1208 xmlNode *attrs = NULL;
1212 if (attrs == NULL) {
1216 while (pIter != NULL) {
1217 const char *
name = (
const char *)pIter->name;
1219 pIter = pIter->next;
1223 for (pIter = pcmk__first_xml_attr(attrs); pIter != NULL;
1224 pIter = pIter->next) {
1225 const char *
name = (
const char *) pIter->name;
1232 crm_err(
"Unknown operation: %s", op);
1238 change_objs = g_list_sort(change_objs, sort_change_obj_by_position);
1240 for (gIter = change_objs; gIter; gIter = gIter->next) {
1242 xmlNode *match = change_obj->match;
1243 const char *op = NULL;
1244 const char *xpath = NULL;
1246 change = change_obj->change;
1251 crm_trace(
"Continue performing %s on %s with %p", op, xpath, match);
1253 if (strcmp(op,
"create") == 0) {
1255 xmlNode *child = NULL;
1256 xmlNode *match_child = NULL;
1258 match_child = match->children;
1261 while ((match_child != NULL)
1263 match_child = match_child->next;
1266 child = xmlDocCopyNode(change->children, match->doc, 1);
1268 crm_trace(
"Adding %s at position %d", child->name, position);
1269 xmlAddPrevSibling(match_child, child);
1271 }
else if (match->last) {
1272 crm_trace(
"Adding %s at position %d (end)",
1273 child->name, position);
1274 xmlAddNextSibling(match->last, child);
1277 crm_trace(
"Adding %s at position %d (first)",
1278 child->name, position);
1280 xmlAddChild(match, child);
1284 }
else if (strcmp(op,
"move") == 0) {
1289 xmlNode *match_child = NULL;
1297 match_child = match->parent->children;
1299 while ((match_child != NULL)
1301 match_child = match_child->next;
1304 crm_trace(
"Moving %s to position %d (was %d, prev %p, %s %p)",
1305 match->name, position,
1307 match->prev, (match_child?
"next":
"last"),
1308 (match_child? match_child : match->parent->last));
1311 xmlAddPrevSibling(match_child, match);
1315 xmlAddNextSibling(match->parent->last, match);
1319 crm_trace(
"%s is already in position %d",
1320 match->name, position);
1324 crm_err(
"Moved %s.%s to position %d instead of %d (%p)",
1325 match->name,
ID(match),
1327 position, match->prev);
1333 g_list_free_full(change_objs, free);
1342 xmlNode *old = NULL;
1345 if (patchset == NULL) {
1352 if (check_version) {
1373 crm_err(
"Unknown patch format: %d", format);
1378 if ((
rc ==
pcmk_ok) && (digest != NULL)) {
1379 static struct qb_log_callsite *digest_cs = NULL;
1381 char *new_digest = NULL;
1384 if (digest_cs == NULL) {
1385 digest_cs = qb_log_callsite_get(__func__, __FILE__,
"diff-digest",
1392 crm_info(
"v%d digest mis-match: expected %s, calculated %s",
1393 format, digest, new_digest);
1396 if ((digest_cs != NULL) && digest_cs->targets) {
1403 ((digest_cs != NULL)? digest_cs->targets : 0));
1407 crm_trace(
"v%d digest matched: expected %s, calculated %s",
1408 format, digest, new_digest);
1420 xmlNode *child = NULL;
1425 for (child = pcmk__xml_first_child(a_node); child != NULL;
1426 child = pcmk__xml_next(child)) {
1434 xmlNode *tmp1 = NULL;
1451 if ((added->children == NULL) && (removed->children == NULL)) {
1460 subtract_xml_comment(xmlNode *parent, xmlNode *left, xmlNode *right,
1464 CRM_CHECK(left->type == XML_COMMENT_NODE,
return NULL);
1466 if ((right == NULL) || !pcmk__str_eq((
const char *)left->content,
1467 (
const char *)right->content,
1469 xmlNode *deleted = NULL;
1482 gboolean full, gboolean *changed,
const char *marker)
1484 gboolean dummy = FALSE;
1485 xmlNode *diff = NULL;
1486 xmlNode *right_child = NULL;
1487 xmlNode *left_child = NULL;
1488 xmlAttrPtr xIter = NULL;
1490 const char *
id = NULL;
1491 const char *
name = NULL;
1492 const char *value = NULL;
1493 const char *right_val = NULL;
1495 if (changed == NULL) {
1503 if (left->type == XML_COMMENT_NODE) {
1504 return subtract_xml_comment(parent, left, right, changed);
1508 if (right == NULL) {
1509 xmlNode *deleted = NULL;
1511 crm_trace(
"Processing <%s id=%s> (complete copy)",
1512 crm_element_name(left),
id);
1520 name = crm_element_name(left);
1522 CRM_CHECK(pcmk__str_eq(crm_element_name(left), crm_element_name(right),
1528 if ((value != NULL) && (strcmp(value,
"removed:top") == 0)) {
1529 crm_trace(
"We are the root of the deletion: %s.id=%s",
name,
id);
1538 for (left_child = pcmk__xml_first_child(left); left_child != NULL;
1539 left_child = pcmk__xml_next(left_child)) {
1540 gboolean child_changed = FALSE;
1545 if (child_changed) {
1554 xmlAttrPtr pIter = NULL;
1556 for (pIter = pcmk__first_xml_attr(left); pIter != NULL;
1557 pIter = pIter->next) {
1558 const char *p_name = (
const char *)pIter->name;
1559 const char *p_value = pcmk__xml_attr_value(pIter);
1569 for (xIter = pcmk__first_xml_attr(left); xIter != NULL;
1570 xIter = xIter->next) {
1571 const char *prop_name = (
const char *) xIter->name;
1572 xmlAttrPtr right_attr = NULL;
1585 right_attr = xmlHasProp(right, (
pcmkXmlStr) prop_name);
1587 p = right_attr->_private;
1595 xmlAttrPtr pIter = NULL;
1597 for (pIter = pcmk__first_xml_attr(left); pIter != NULL;
1598 pIter = pIter->next) {
1599 const char *p_name = (
const char *) pIter->name;
1600 const char *p_value = pcmk__xml_attr_value(pIter);
1617 if (strcmp(left_value, right_val) == 0) {
1623 xmlAttrPtr pIter = NULL;
1625 crm_trace(
"Changes detected to %s in <%s id=%s>", prop_name,
1626 crm_element_name(left),
id);
1627 for (pIter = pcmk__first_xml_attr(left); pIter != NULL;
1628 pIter = pIter->next) {
1629 const char *p_name = (
const char *) pIter->name;
1630 const char *p_value = pcmk__xml_attr_value(pIter);
1638 crm_trace(
"Changes detected to %s (%s -> %s) in <%s id=%s>",
1639 prop_name, left_value, right_val,
1640 crm_element_name(left),
id);
1651 }
else if (!full && (
id != NULL)) {
1660 gboolean
apply_xml_diff(xmlNode *old_xml, xmlNode *diff, xmlNode **new_xml);
1669 gboolean result = TRUE;
1670 int root_nodes_seen = 0;
1671 static struct qb_log_callsite *digest_cs = NULL;
1675 xmlNode *child_diff = NULL;
1677 xmlNode *removed =
find_xml_node(diff,
"diff-removed", FALSE);
1679 CRM_CHECK(new_xml != NULL,
return FALSE);
1680 if (digest_cs == NULL) {
1681 digest_cs = qb_log_callsite_get(__func__, __FILE__,
"diff-digest",
1686 for (child_diff = pcmk__xml_first_child(removed); child_diff != NULL;
1687 child_diff = pcmk__xml_next(child_diff)) {
1688 CRM_CHECK(root_nodes_seen == 0, result = FALSE);
1689 if (root_nodes_seen == 0) {
1696 if (root_nodes_seen == 0) {
1699 }
else if (root_nodes_seen > 1) {
1700 crm_err(
"(-) Diffs cannot contain more than one change set... saw %d",
1705 root_nodes_seen = 0;
1708 xmlNode *child_diff = NULL;
1710 for (child_diff = pcmk__xml_first_child(added); child_diff != NULL;
1711 child_diff = pcmk__xml_next(child_diff)) {
1712 CRM_CHECK(root_nodes_seen == 0, result = FALSE);
1713 if (root_nodes_seen == 0) {
1720 if (root_nodes_seen > 1) {
1721 crm_err(
"(+) Diffs cannot contain more than one change set... saw %d",
1725 }
else if (result && (digest != NULL)) {
1726 char *new_digest = NULL;
1732 crm_info(
"Digest mis-match: expected %s, calculated %s",
1733 digest, new_digest);
1736 crm_trace(
"%p %.6x", digest_cs, digest_cs ? digest_cs->targets : 0);
1737 if ((digest_cs != NULL) && digest_cs->targets) {
1744 crm_trace(
"Digest matched: expected %s, calculated %s",
1745 digest, new_digest);
1749 }
else if (result) {
#define CRM_CHECK(expr, failure_action)
xmlNode * find_xml_node(xmlNode *cib, const char *node_path, gboolean must_find)
#define crm_notice(fmt, args...)
void patchset_process_digest(xmlNode *patch, xmlNode *source, xmlNode *target, bool with_digest)
#define XML_ATTR_NUMUPDATES
int pcmk_rc2legacy(int rc)
bool xml_patch_versions(xmlNode *patchset, int add[3], int del[3])
void log_data_element(int log_level, const char *file, const char *function, int line, const char *prefix, xmlNode *data, int depth, gboolean formatted)
G_GNUC_INTERNAL int pcmk__element_xpath(const char *prefix, xmlNode *xml, char *buffer, int offset, size_t buffer_size)
xmlNode * first_named_child(const xmlNode *parent, const char *name)
const char * crm_xml_add_int(xmlNode *node, const char *name, int value)
Create an XML attribute with specified name and integer value.
const char * crm_xml_add(xmlNode *node, const char *name, const char *value)
Create an XML attribute with specified name and value.
#define XML_NVPAIR_ATTR_NAME
#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.
unsigned int crm_trace_nonlog
int crm_element_value_int(const xmlNode *data, const char *name, int *dest)
Retrieve the integer value of an XML attribute.
#define XML_ATTR_GENERATION
void xml_log_patchset(uint8_t log_level, const char *function, xmlNode *patchset)
xmlNode * copy_xml(xmlNode *src_node)
#define crm_warn(fmt, args...)
#define pcmk_err_diff_failed
G_GNUC_INTERNAL void pcmk__xc_update(xmlNode *parent, xmlNode *target, xmlNode *update)
#define crm_debug(fmt, args...)
char * crm_element_value_copy(const xmlNode *data, const char *name)
Retrieve a copy of the value of an XML attribute.
struct xml_change_obj_s xml_change_obj_t
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
#define crm_trace(fmt, args...)
#define crm_log_xml_explicit(xml, text)
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
xmlNode * add_node_copy(xmlNode *new_parent, xmlNode *xml_node)
Wrappers for and extensions to libxml2.
bool xml_document_dirty(xmlNode *xml)
xmlNode * create_xml_node(xmlNode *parent, const char *name)
#define XML_DIFF_POSITION
void purge_diff_markers(xmlNode *a_node)
void free_xml(xmlNode *child)
xmlNode * xml_create_patchset(int format, xmlNode *source, xmlNode *target, bool *config_changed, bool manage_version)
G_GNUC_INTERNAL xmlNode * pcmk__xml_match(xmlNode *haystack, xmlNode *needle, bool exact)
const xmlChar * pcmkXmlStr
G_GNUC_INTERNAL void pcmk__xe_log(int log_level, const char *file, const char *function, int line, const char *prefix, xmlNode *data, int depth, int options)
G_GNUC_INTERNAL bool pcmk__xa_filterable(const char *name)
gboolean crm_is_callsite_active(struct qb_log_callsite *cs, uint8_t level, uint32_t tags)
gboolean apply_xml_diff(xmlNode *old_xml, xmlNode *diff, xmlNode **new_xml)
#define PCMK__BUFFER_SIZE
xmlNode * diff_xml_object(xmlNode *old, xmlNode *new, gboolean suppress)
#define crm_err(fmt, args...)
void xml_remove_prop(xmlNode *obj, const char *name)
char * calculate_xml_versioned_digest(xmlNode *input, gboolean sort, gboolean do_filter, const char *version)
Calculate and return digest of XML tree.
gboolean can_prune_leaf(xmlNode *xml_node)
void xml_acl_disable(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
#define XML_ATTR_CRM_VERSION
void save_xml_to_file(xmlNode *xml, const char *desc, const char *filename)
#define XML_CIB_TAG_CONFIGURATION
xmlNode * subtract_xml_object(xmlNode *parent, xmlNode *left, xmlNode *right, gboolean full, gboolean *changed, const char *marker)
int xml_apply_patchset(xmlNode *xml, xmlNode *patchset, bool check_version)
G_GNUC_INTERNAL void pcmk__mark_xml_created(xmlNode *xml)
G_GNUC_INTERNAL void pcmk__xml_update(xmlNode *parent, xmlNode *target, xmlNode *update, bool as_diff)
char * crm_strdup_printf(char const *format,...) __attribute__((__format__(__printf__
#define crm_info(fmt, args...)
G_GNUC_INTERNAL int pcmk__xml_position(xmlNode *xml, enum xml_private_flags ignore_if_set)