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)