root/lib/cib/cib_ops.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. cib_process_query
  2. cib_process_erase
  3. cib_process_upgrade
  4. cib_process_bump
  5. cib_update_counter
  6. cib_process_replace
  7. cib_process_delete
  8. cib_process_modify
  9. update_cib_object
  10. add_cib_object
  11. cib_process_create
  12. cib_process_diff
  13. cib_config_changed
  14. cib_process_xpath
  15. update_results

   1 /*
   2  * Copyright 2004-2022 the Pacemaker project contributors
   3  *
   4  * The version control history for this file may have further details.
   5  *
   6  * This source code is licensed under the GNU Lesser General Public License
   7  * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
   8  */
   9 
  10 #include <crm_internal.h>
  11 
  12 #include <stdio.h>
  13 #include <unistd.h>
  14 #include <stdlib.h>
  15 #include <errno.h>
  16 #include <fcntl.h>
  17 #include <time.h>
  18 
  19 #include <sys/param.h>
  20 #include <sys/types.h>
  21 
  22 #include <crm/crm.h>
  23 #include <crm/cib/internal.h>
  24 #include <crm/msg_xml.h>
  25 
  26 #include <crm/common/xml.h>
  27 #include <crm/common/xml_internal.h>
  28 
  29 int
  30 cib_process_query(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
     /* [previous][next][first][last][top][bottom][index][help] */
  31                   xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
  32 {
  33     xmlNode *obj_root = NULL;
  34     int result = pcmk_ok;
  35 
  36     crm_trace("Processing %s for %s section",
  37               op, pcmk__s(section, "unspecified"));
  38 
  39     if (options & cib_xpath) {
  40         return cib_process_xpath(op, options, section, req, input,
  41                                  existing_cib, result_cib, answer);
  42     }
  43 
  44     CRM_CHECK(*answer == NULL, free_xml(*answer));
  45     *answer = NULL;
  46 
  47     if (pcmk__str_eq(XML_CIB_TAG_SECTION_ALL, section, pcmk__str_casei)) {
  48         section = NULL;
  49     }
  50 
  51     obj_root = pcmk_find_cib_element(existing_cib, section);
  52 
  53     if (obj_root == NULL) {
  54         result = -ENXIO;
  55 
  56     } else if (options & cib_no_children) {
  57         const char *tag = TYPE(obj_root);
  58         xmlNode *shallow = create_xml_node(*answer, tag);
  59 
  60         copy_in_properties(shallow, obj_root);
  61         *answer = shallow;
  62 
  63     } else {
  64         *answer = obj_root;
  65     }
  66 
  67     if (result == pcmk_ok && *answer == NULL) {
  68         crm_err("Error creating query response");
  69         result = -ENOMSG;
  70     }
  71 
  72     return result;
  73 }
  74 
  75 int
  76 cib_process_erase(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
     /* [previous][next][first][last][top][bottom][index][help] */
  77                   xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
  78 {
  79     int result = pcmk_ok;
  80 
  81     crm_trace("Processing \"%s\" event", op);
  82     *answer = NULL;
  83     free_xml(*result_cib);
  84     *result_cib = createEmptyCib(0);
  85 
  86     copy_in_properties(*result_cib, existing_cib);
  87     cib_update_counter(*result_cib, XML_ATTR_GENERATION_ADMIN, FALSE);
  88 
  89     return result;
  90 }
  91 
  92 int
  93 cib_process_upgrade(const char *op, int options, const char *section, xmlNode * req,
     /* [previous][next][first][last][top][bottom][index][help] */
  94                     xmlNode * input, xmlNode * existing_cib, xmlNode ** result_cib,
  95                     xmlNode ** answer)
  96 {
  97     int rc = 0;
  98     int new_version = 0;
  99     int current_version = 0;
 100     int max_version = 0;
 101     const char *max = crm_element_value(req, F_CIB_SCHEMA_MAX);
 102     const char *value = crm_element_value(existing_cib, XML_ATTR_VALIDATION);
 103 
 104     *answer = NULL;
 105     crm_trace("Processing \"%s\" event with max=%s", op, max);
 106 
 107     if (value != NULL) {
 108         current_version = get_schema_version(value);
 109     }
 110 
 111     if (max) {
 112         max_version = get_schema_version(max);
 113     }
 114 
 115     rc = update_validation(result_cib, &new_version, max_version, TRUE,
 116                            !(options & cib_verbose));
 117     if (new_version > current_version) {
 118         cib_update_counter(*result_cib, XML_ATTR_GENERATION_ADMIN, FALSE);
 119         cib_update_counter(*result_cib, XML_ATTR_GENERATION, TRUE);
 120         cib_update_counter(*result_cib, XML_ATTR_NUMUPDATES, TRUE);
 121         return pcmk_ok;
 122     }
 123 
 124     return rc;
 125 }
 126 
 127 int
 128 cib_process_bump(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
     /* [previous][next][first][last][top][bottom][index][help] */
 129                  xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
 130 {
 131     int result = pcmk_ok;
 132 
 133     crm_trace("Processing %s for epoch='%s'", op,
 134               pcmk__s(crm_element_value(existing_cib, XML_ATTR_GENERATION), ""));
 135 
 136     *answer = NULL;
 137     cib_update_counter(*result_cib, XML_ATTR_GENERATION, FALSE);
 138 
 139     return result;
 140 }
 141 
 142 int
 143 cib_update_counter(xmlNode * xml_obj, const char *field, gboolean reset)
     /* [previous][next][first][last][top][bottom][index][help] */
 144 {
 145     char *new_value = NULL;
 146     char *old_value = NULL;
 147     int int_value = -1;
 148 
 149     if (reset == FALSE && crm_element_value(xml_obj, field) != NULL) {
 150         old_value = crm_element_value_copy(xml_obj, field);
 151     }
 152     if (old_value != NULL) {
 153         int_value = atoi(old_value);
 154         new_value = pcmk__itoa(++int_value);
 155     } else {
 156         new_value = strdup("1");
 157         CRM_ASSERT(new_value != NULL);
 158     }
 159 
 160     crm_trace("Update %s from %s to %s",
 161               field, pcmk__s(old_value, "unset"), new_value);
 162     crm_xml_add(xml_obj, field, new_value);
 163 
 164     free(new_value);
 165     free(old_value);
 166 
 167     return pcmk_ok;
 168 }
 169 
 170 int
 171 cib_process_replace(const char *op, int options, const char *section, xmlNode * req,
     /* [previous][next][first][last][top][bottom][index][help] */
 172                     xmlNode * input, xmlNode * existing_cib, xmlNode ** result_cib,
 173                     xmlNode ** answer)
 174 {
 175     const char *tag = NULL;
 176     int result = pcmk_ok;
 177 
 178     crm_trace("Processing %s for %s section",
 179               op, pcmk__s(section, "unspecified"));
 180 
 181     if (options & cib_xpath) {
 182         return cib_process_xpath(op, options, section, req, input,
 183                                  existing_cib, result_cib, answer);
 184     }
 185 
 186     *answer = NULL;
 187 
 188     if (input == NULL) {
 189         return -EINVAL;
 190     }
 191 
 192     tag = crm_element_name(input);
 193 
 194     if (pcmk__str_eq(XML_CIB_TAG_SECTION_ALL, section, pcmk__str_casei)) {
 195         section = NULL;
 196 
 197     } else if (pcmk__str_eq(tag, section, pcmk__str_casei)) {
 198         section = NULL;
 199     }
 200 
 201     if (pcmk__str_eq(tag, XML_TAG_CIB, pcmk__str_casei)) {
 202         int updates = 0;
 203         int epoch = 0;
 204         int admin_epoch = 0;
 205 
 206         int replace_updates = 0;
 207         int replace_epoch = 0;
 208         int replace_admin_epoch = 0;
 209 
 210         const char *reason = NULL;
 211         const char *peer = crm_element_value(req, F_ORIG);
 212         const char *digest = crm_element_value(req, XML_ATTR_DIGEST);
 213 
 214         if (digest) {
 215             const char *version = crm_element_value(req, XML_ATTR_CRM_VERSION);
 216             char *digest_verify = calculate_xml_versioned_digest(input, FALSE, TRUE,
 217                                                                  version ? version :
 218                                                                  CRM_FEATURE_SET);
 219 
 220             if (!pcmk__str_eq(digest_verify, digest, pcmk__str_casei)) {
 221                 crm_err("Digest mis-match on replace from %s: %s vs. %s (expected)", peer,
 222                         digest_verify, digest);
 223                 reason = "digest mismatch";
 224 
 225             } else {
 226                 crm_info("Digest matched on replace from %s: %s", peer, digest);
 227             }
 228             free(digest_verify);
 229 
 230         } else {
 231             crm_trace("No digest to verify");
 232         }
 233 
 234         cib_version_details(existing_cib, &admin_epoch, &epoch, &updates);
 235         cib_version_details(input, &replace_admin_epoch, &replace_epoch, &replace_updates);
 236 
 237         if (replace_admin_epoch < admin_epoch) {
 238             reason = XML_ATTR_GENERATION_ADMIN;
 239 
 240         } else if (replace_admin_epoch > admin_epoch) {
 241             /* no more checks */
 242 
 243         } else if (replace_epoch < epoch) {
 244             reason = XML_ATTR_GENERATION;
 245 
 246         } else if (replace_epoch > epoch) {
 247             /* no more checks */
 248 
 249         } else if (replace_updates < updates) {
 250             reason = XML_ATTR_NUMUPDATES;
 251         }
 252 
 253         if (reason != NULL) {
 254             crm_info("Replacement %d.%d.%d from %s not applied to %d.%d.%d:"
 255                      " current %s is greater than the replacement",
 256                      replace_admin_epoch, replace_epoch,
 257                      replace_updates, peer, admin_epoch, epoch, updates, reason);
 258             result = -pcmk_err_old_data;
 259         } else {
 260             crm_info("Replaced %d.%d.%d with %d.%d.%d from %s",
 261                      admin_epoch, epoch, updates,
 262                      replace_admin_epoch, replace_epoch, replace_updates, peer);
 263         }
 264 
 265         free_xml(*result_cib);
 266         *result_cib = copy_xml(input);
 267 
 268     } else {
 269         xmlNode *obj_root = NULL;
 270         gboolean ok = TRUE;
 271 
 272         obj_root = pcmk_find_cib_element(*result_cib, section);
 273         ok = replace_xml_child(NULL, obj_root, input, FALSE);
 274         if (ok == FALSE) {
 275             crm_trace("No matching object to replace");
 276             result = -ENXIO;
 277         }
 278     }
 279 
 280     return result;
 281 }
 282 
 283 int
 284 cib_process_delete(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
     /* [previous][next][first][last][top][bottom][index][help] */
 285                    xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
 286 {
 287     xmlNode *obj_root = NULL;
 288 
 289     crm_trace("Processing \"%s\" event", op);
 290 
 291     if (options & cib_xpath) {
 292         return cib_process_xpath(op, options, section, req, input,
 293                                  existing_cib, result_cib, answer);
 294     }
 295 
 296     if (input == NULL) {
 297         crm_err("Cannot perform modification with no data");
 298         return -EINVAL;
 299     }
 300 
 301     obj_root = pcmk_find_cib_element(*result_cib, section);
 302     if(pcmk__str_eq(crm_element_name(input), section, pcmk__str_casei)) {
 303         xmlNode *child = NULL;
 304         for (child = pcmk__xml_first_child(input); child;
 305              child = pcmk__xml_next(child)) {
 306             if (replace_xml_child(NULL, obj_root, child, TRUE) == FALSE) {
 307                 crm_trace("No matching object to delete: %s=%s", child->name, ID(child));
 308             }
 309         }
 310 
 311     } else if (replace_xml_child(NULL, obj_root, input, TRUE) == FALSE) {
 312             crm_trace("No matching object to delete: %s=%s", input->name, ID(input));
 313     }
 314 
 315     return pcmk_ok;
 316 }
 317 
 318 int
 319 cib_process_modify(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
     /* [previous][next][first][last][top][bottom][index][help] */
 320                    xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
 321 {
 322     xmlNode *obj_root = NULL;
 323 
 324     crm_trace("Processing \"%s\" event", op);
 325 
 326     if (options & cib_xpath) {
 327         return cib_process_xpath(op, options, section, req, input,
 328                                  existing_cib, result_cib, answer);
 329     }
 330 
 331     if (input == NULL) {
 332         crm_err("Cannot perform modification with no data");
 333         return -EINVAL;
 334     }
 335 
 336     obj_root = pcmk_find_cib_element(*result_cib, section);
 337     if (obj_root == NULL) {
 338         xmlNode *tmp_section = NULL;
 339         const char *path = pcmk_cib_parent_name_for(section);
 340 
 341         if (path == NULL) {
 342             return -EINVAL;
 343         }
 344 
 345         tmp_section = create_xml_node(NULL, section);
 346         cib_process_xpath(PCMK__CIB_REQUEST_CREATE, 0, path, NULL, tmp_section,
 347                           NULL, result_cib, answer);
 348         free_xml(tmp_section);
 349 
 350         obj_root = pcmk_find_cib_element(*result_cib, section);
 351     }
 352 
 353     CRM_CHECK(obj_root != NULL, return -EINVAL);
 354 
 355     if (update_xml_child(obj_root, input) == FALSE) {
 356         if (options & cib_can_create) {
 357             add_node_copy(obj_root, input);
 358         } else {
 359             return -ENXIO;
 360         }
 361     }
 362 
 363     if(options & cib_mixed_update) {
 364         int max = 0, lpc;
 365         xmlXPathObjectPtr xpathObj = xpath_search(*result_cib, "//@__delete__");
 366 
 367         if (xpathObj) {
 368             max = numXpathResults(xpathObj);
 369             crm_log_xml_trace(*result_cib, "Mixed result");
 370         }
 371 
 372         for (lpc = 0; lpc < max; lpc++) {
 373             xmlNode *match = getXpathResult(xpathObj, lpc);
 374             xmlChar *match_path = xmlGetNodePath(match);
 375 
 376             crm_debug("Destroying %s", match_path);
 377             free(match_path);
 378             free_xml(match);
 379         }
 380 
 381         freeXpathObject(xpathObj);
 382     }
 383     return pcmk_ok;
 384 }
 385 
 386 static int
 387 update_cib_object(xmlNode * parent, xmlNode * update)
     /* [previous][next][first][last][top][bottom][index][help] */
 388 {
 389     int result = pcmk_ok;
 390     xmlNode *target = NULL;
 391     xmlNode *a_child = NULL;
 392     const char *replace = NULL;
 393     const char *object_id = NULL;
 394     const char *object_name = NULL;
 395 
 396     CRM_CHECK(update != NULL, return -EINVAL);
 397     CRM_CHECK(parent != NULL, return -EINVAL);
 398 
 399     object_name = crm_element_name(update);
 400     CRM_CHECK(object_name != NULL, return -EINVAL);
 401 
 402     object_id = ID(update);
 403     crm_trace("Processing update for <%s%s%s%s>", object_name,
 404               ((object_id == NULL)? "" : " id='"), pcmk__s(object_id, ""),
 405               ((object_id == NULL)? "" : "'"));
 406 
 407     if (object_id == NULL) {
 408         /*  placeholder object */
 409         target = find_xml_node(parent, object_name, FALSE);
 410 
 411     } else {
 412         target = pcmk__xe_match(parent, object_name, XML_ATTR_ID, object_id);
 413     }
 414 
 415     if (target == NULL) {
 416         target = create_xml_node(parent, object_name);
 417     }
 418 
 419     crm_trace("Found node <%s%s%s%s> to update", object_name,
 420               ((object_id == NULL)? "" : " id='"), pcmk__s(object_id, ""),
 421               ((object_id == NULL)? "" : "'"));
 422 
 423     replace = crm_element_value(update, XML_CIB_ATTR_REPLACE);
 424     if (replace != NULL) {
 425         xmlNode *remove = NULL;
 426         int last = 0, lpc = 0, len = 0;
 427 
 428         len = strlen(replace);
 429         while (lpc <= len) {
 430             if (replace[lpc] == ',' || replace[lpc] == 0) {
 431                 char *replace_item = NULL;
 432 
 433                 if (last == lpc) {
 434                     /* nothing to do */
 435                     last = lpc + 1;
 436                     goto incr;
 437                 }
 438 
 439                 replace_item = strndup(replace + last, lpc - last);
 440                 remove = find_xml_node(target, replace_item, FALSE);
 441                 if (remove != NULL) {
 442                     crm_trace("Replacing node <%s> in <%s>",
 443                               replace_item, crm_element_name(target));
 444                     free_xml(remove);
 445                     remove = NULL;
 446                 }
 447                 free(replace_item);
 448                 last = lpc + 1;
 449             }
 450   incr:
 451             lpc++;
 452         }
 453         xml_remove_prop(update, XML_CIB_ATTR_REPLACE);
 454         xml_remove_prop(target, XML_CIB_ATTR_REPLACE);
 455     }
 456 
 457     copy_in_properties(target, update);
 458 
 459     if (xml_acl_denied(target)) {
 460         crm_notice("Cannot update <%s id=%s>", pcmk__s(object_name, "<null>"), pcmk__s(object_id, "<null>"));
 461         return -EACCES;
 462     }
 463 
 464     crm_trace("Processing children of <%s%s%s%s>", object_name,
 465               ((object_id == NULL)? "" : " id='"), pcmk__s(object_id, ""),
 466               ((object_id == NULL)? "" : "'"));
 467 
 468     for (a_child = pcmk__xml_first_child(update); a_child != NULL;
 469          a_child = pcmk__xml_next(a_child)) {
 470         int tmp_result = 0;
 471 
 472         crm_trace("Updating child <%s%s%s%s>", crm_element_name(a_child),
 473                   ((ID(a_child) == NULL)? "" : " id='"),
 474                   pcmk__s(ID(a_child), ""), ((ID(a_child) == NULL)? "" : "'"));
 475 
 476         tmp_result = update_cib_object(target, a_child);
 477 
 478         /*  only the first error is likely to be interesting */
 479         if (tmp_result != pcmk_ok) {
 480             crm_err("Error updating child <%s%s%s%s>",
 481                     crm_element_name(a_child),
 482                     ((ID(a_child) == NULL)? "" : " id='"),
 483                     pcmk__s(ID(a_child), ""),
 484                     ((ID(a_child) == NULL)? "" : "'"));
 485 
 486             if (result == pcmk_ok) {
 487                 result = tmp_result;
 488             }
 489         }
 490     }
 491 
 492     crm_trace("Finished handling update for <%s%s%s%s>", object_name,
 493               ((object_id == NULL)? "" : " id='"), pcmk__s(object_id, ""),
 494               ((object_id == NULL)? "" : "'"));
 495 
 496     return result;
 497 }
 498 
 499 static int
 500 add_cib_object(xmlNode * parent, xmlNode * new_obj)
     /* [previous][next][first][last][top][bottom][index][help] */
 501 {
 502     const char *object_name = NULL;
 503     const char *object_id = NULL;
 504     xmlNode *equiv_node = NULL;
 505 
 506     if ((parent == NULL) || (new_obj == NULL)) {
 507         return -EINVAL;
 508     }
 509 
 510     object_name = crm_element_name(new_obj);
 511     if (object_name == NULL) {
 512         return -EINVAL;
 513     }
 514 
 515     object_id = ID(new_obj);
 516 
 517     crm_trace("Processing creation of <%s%s%s%s>", object_name,
 518               ((object_id == NULL)? "" : " id='"), pcmk__s(object_id, ""),
 519               ((object_id == NULL)? "" : "'"));
 520 
 521     if (object_id == NULL) {
 522         equiv_node = find_xml_node(parent, object_name, FALSE);
 523     } else {
 524         equiv_node = pcmk__xe_match(parent, object_name, XML_ATTR_ID,
 525                                     object_id);
 526     }
 527     if (equiv_node != NULL) {
 528         return -EEXIST;
 529     }
 530 
 531     return update_cib_object(parent, new_obj);
 532 }
 533 
 534 int
 535 cib_process_create(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
     /* [previous][next][first][last][top][bottom][index][help] */
 536                    xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
 537 {
 538     xmlNode *failed = NULL;
 539     int result = pcmk_ok;
 540     xmlNode *update_section = NULL;
 541 
 542     crm_trace("Processing %s for %s section",
 543               op, pcmk__s(section, "unspecified"));
 544     if (pcmk__str_eq(XML_CIB_TAG_SECTION_ALL, section, pcmk__str_casei)) {
 545         section = NULL;
 546 
 547     } else if (pcmk__str_eq(XML_TAG_CIB, section, pcmk__str_casei)) {
 548         section = NULL;
 549 
 550     } else if (pcmk__str_eq(crm_element_name(input), XML_TAG_CIB, pcmk__str_casei)) {
 551         section = NULL;
 552     }
 553 
 554     CRM_CHECK(strcmp(op, PCMK__CIB_REQUEST_CREATE) == 0, return -EINVAL);
 555 
 556     if (input == NULL) {
 557         crm_err("Cannot perform modification with no data");
 558         return -EINVAL;
 559     }
 560 
 561     if (section == NULL) {
 562         return cib_process_modify(op, options, section, req, input, existing_cib, result_cib,
 563                                   answer);
 564     }
 565 
 566     failed = create_xml_node(NULL, XML_TAG_FAILED);
 567 
 568     update_section = pcmk_find_cib_element(*result_cib, section);
 569     if (pcmk__str_eq(crm_element_name(input), section, pcmk__str_casei)) {
 570         xmlNode *a_child = NULL;
 571 
 572         for (a_child = pcmk__xml_first_child(input); a_child != NULL;
 573              a_child = pcmk__xml_next(a_child)) {
 574             result = add_cib_object(update_section, a_child);
 575             if (update_results(failed, a_child, op, result)) {
 576                 break;
 577             }
 578         }
 579 
 580     } else {
 581         result = add_cib_object(update_section, input);
 582         update_results(failed, input, op, result);
 583     }
 584 
 585     if ((result == pcmk_ok) && xml_has_children(failed)) {
 586         result = -EINVAL;
 587     }
 588 
 589     if (result != pcmk_ok) {
 590         crm_log_xml_err(failed, "CIB Update failures");
 591         *answer = failed;
 592 
 593     } else {
 594         free_xml(failed);
 595     }
 596 
 597     return result;
 598 }
 599 
 600 int
 601 cib_process_diff(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
     /* [previous][next][first][last][top][bottom][index][help] */
 602                  xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
 603 {
 604     const char *originator = NULL;
 605 
 606     if (req != NULL) {
 607         originator = crm_element_value(req, F_ORIG);
 608     }
 609 
 610     crm_trace("Processing \"%s\" event from %s%s",
 611               op, originator,
 612               (pcmk_is_set(options, cib_force_diff)? " (global update)" : ""));
 613 
 614     free_xml(*result_cib);
 615     *result_cib = copy_xml(existing_cib);
 616     return xml_apply_patchset(*result_cib, input, TRUE);
 617 }
 618 
 619 gboolean
 620 cib_config_changed(xmlNode * last, xmlNode * next, xmlNode ** diff)
     /* [previous][next][first][last][top][bottom][index][help] */
 621 {
 622     int lpc = 0, max = 0;
 623     gboolean config_changes = FALSE;
 624     xmlXPathObject *xpathObj = NULL;
 625     int format = 1;
 626 
 627     CRM_ASSERT(diff != NULL);
 628 
 629     if (*diff == NULL && last != NULL && next != NULL) {
 630         *diff = diff_xml_object(last, next, FALSE);
 631     }
 632 
 633     if (*diff == NULL) {
 634         goto done;
 635     }
 636 
 637     crm_element_value_int(*diff, "format", &format);
 638     /* This function only applies to v1 diffs. */
 639     CRM_LOG_ASSERT(format == 1);
 640 
 641     xpathObj = xpath_search(*diff, "//" XML_CIB_TAG_CONFIGURATION);
 642     if (numXpathResults(xpathObj) > 0) {
 643         config_changes = TRUE;
 644         goto done;
 645     }
 646     freeXpathObject(xpathObj);
 647 
 648     /*
 649      * Do not check XML_TAG_DIFF_ADDED "//" XML_TAG_CIB
 650      * This always contains every field and would produce a false positive
 651      * every time if the checked value existed
 652      */
 653     xpathObj = xpath_search(*diff, "//" XML_TAG_DIFF_REMOVED "//" XML_TAG_CIB);
 654     max = numXpathResults(xpathObj);
 655 
 656     for (lpc = 0; lpc < max; lpc++) {
 657         xmlNode *top = getXpathResult(xpathObj, lpc);
 658 
 659         if (crm_element_value(top, XML_ATTR_GENERATION) != NULL) {
 660             config_changes = TRUE;
 661             goto done;
 662         }
 663         if (crm_element_value(top, XML_ATTR_GENERATION_ADMIN) != NULL) {
 664             config_changes = TRUE;
 665             goto done;
 666         }
 667 
 668         if (crm_element_value(top, XML_ATTR_VALIDATION) != NULL) {
 669             config_changes = TRUE;
 670             goto done;
 671         }
 672         if (crm_element_value(top, XML_ATTR_CRM_VERSION) != NULL) {
 673             config_changes = TRUE;
 674             goto done;
 675         }
 676         if (crm_element_value(top, "remote-clear-port") != NULL) {
 677             config_changes = TRUE;
 678             goto done;
 679         }
 680         if (crm_element_value(top, "remote-tls-port") != NULL) {
 681             config_changes = TRUE;
 682             goto done;
 683         }
 684     }
 685 
 686   done:
 687     freeXpathObject(xpathObj);
 688     return config_changes;
 689 }
 690 
 691 int
 692 cib_process_xpath(const char *op, int options, const char *section,
     /* [previous][next][first][last][top][bottom][index][help] */
 693                   const xmlNode *req, xmlNode *input, xmlNode *existing_cib,
 694                   xmlNode **result_cib, xmlNode **answer)
 695 {
 696     int lpc = 0;
 697     int max = 0;
 698     int rc = pcmk_ok;
 699     bool is_query = pcmk__str_eq(op, PCMK__CIB_REQUEST_QUERY, pcmk__str_none);
 700 
 701     xmlXPathObjectPtr xpathObj = NULL;
 702 
 703     crm_trace("Processing \"%s\" event", op);
 704 
 705     if (is_query) {
 706         xpathObj = xpath_search(existing_cib, section);
 707     } else {
 708         xpathObj = xpath_search(*result_cib, section);
 709     }
 710 
 711     max = numXpathResults(xpathObj);
 712 
 713     if ((max < 1)
 714         && pcmk__str_eq(op, PCMK__CIB_REQUEST_DELETE, pcmk__str_none)) {
 715         crm_debug("%s was already removed", section);
 716 
 717     } else if (max < 1) {
 718         crm_debug("%s: %s does not exist", op, section);
 719         rc = -ENXIO;
 720 
 721     } else if (is_query) {
 722         if (max > 1) {
 723             *answer = create_xml_node(NULL, "xpath-query");
 724         }
 725     }
 726 
 727     if (pcmk_is_set(options, cib_multiple)
 728         && pcmk__str_eq(op, PCMK__CIB_REQUEST_DELETE, pcmk__str_none)) {
 729         dedupXpathResults(xpathObj);
 730     }
 731 
 732     for (lpc = 0; lpc < max; lpc++) {
 733         xmlChar *path = NULL;
 734         xmlNode *match = getXpathResult(xpathObj, lpc);
 735 
 736         if (match == NULL) {
 737             continue;
 738         }
 739 
 740         path = xmlGetNodePath(match);
 741         crm_debug("Processing %s op for %s with %s", op, section, path);
 742         free(path);
 743 
 744         if (pcmk__str_eq(op, PCMK__CIB_REQUEST_DELETE, pcmk__str_none)) {
 745             if (match == *result_cib) {
 746                 /* Attempting to delete the whole "/cib" */
 747                 crm_warn("Cannot perform %s for %s: The xpath is addressing the whole /cib", op, section);
 748                 rc = -EINVAL;
 749                 break;
 750             }
 751 
 752             free_xml(match);
 753             if ((options & cib_multiple) == 0) {
 754                 break;
 755             }
 756 
 757         } else if (pcmk__str_eq(op, PCMK__CIB_REQUEST_MODIFY, pcmk__str_none)) {
 758             if (update_xml_child(match, input) == FALSE) {
 759                 rc = -ENXIO;
 760             } else if ((options & cib_multiple) == 0) {
 761                 break;
 762             }
 763 
 764         } else if (pcmk__str_eq(op, PCMK__CIB_REQUEST_CREATE, pcmk__str_none)) {
 765             add_node_copy(match, input);
 766             break;
 767 
 768         } else if (pcmk__str_eq(op, PCMK__CIB_REQUEST_QUERY, pcmk__str_none)) {
 769 
 770             if (options & cib_no_children) {
 771                 const char *tag = TYPE(match);
 772                 xmlNode *shallow = create_xml_node(*answer, tag);
 773 
 774                 copy_in_properties(shallow, match);
 775 
 776                 if (*answer == NULL) {
 777                     *answer = shallow;
 778                 }
 779 
 780             } else if (options & cib_xpath_address) {
 781                 char *path = NULL;
 782                 xmlNode *parent = match;
 783 
 784                 while (parent && parent->type == XML_ELEMENT_NODE) {
 785                     const char *id = crm_element_value(parent, XML_ATTR_ID);
 786                     char *new_path = NULL;
 787 
 788                     if (id) {
 789                         new_path = crm_strdup_printf("/%s[@id='%s']%s",
 790                                                      parent->name, id,
 791                                                      (path? path : ""));
 792                     } else {
 793                         new_path = crm_strdup_printf("/%s%s", parent->name,
 794                                                      (path? path : ""));
 795                     }
 796                     free(path);
 797                     path = new_path;
 798                     parent = parent->parent;
 799                 }
 800                 crm_trace("Got: %s", path);
 801 
 802                 if (*answer == NULL) {
 803                     *answer = create_xml_node(NULL, "xpath-query");
 804                 }
 805                 parent = create_xml_node(*answer, "xpath-query-path");
 806                 crm_xml_add(parent, XML_ATTR_ID, path);
 807                 free(path);
 808 
 809             } else if (*answer) {
 810                 add_node_copy(*answer, match);
 811 
 812             } else {
 813                 *answer = match;
 814             }
 815 
 816         } else if (pcmk__str_eq(op, PCMK__CIB_REQUEST_REPLACE,
 817                                 pcmk__str_none)) {
 818             xmlNode *parent = match->parent;
 819 
 820             free_xml(match);
 821             if (input != NULL) {
 822                 add_node_copy(parent, input);
 823             }
 824 
 825             if ((options & cib_multiple) == 0) {
 826                 break;
 827             }
 828         }
 829     }
 830 
 831     freeXpathObject(xpathObj);
 832     return rc;
 833 }
 834 
 835 /* remove this function */
 836 gboolean
 837 update_results(xmlNode * failed, xmlNode * target, const char *operation, int return_code)
     /* [previous][next][first][last][top][bottom][index][help] */
 838 {
 839     xmlNode *xml_node = NULL;
 840     gboolean was_error = FALSE;
 841     const char *error_msg = NULL;
 842 
 843     if (return_code != pcmk_ok) {
 844         error_msg = pcmk_strerror(return_code);
 845 
 846         was_error = TRUE;
 847         xml_node = create_xml_node(failed, XML_FAIL_TAG_CIB);
 848         add_node_copy(xml_node, target);
 849 
 850         crm_xml_add(xml_node, XML_FAILCIB_ATTR_ID, ID(target));
 851         crm_xml_add(xml_node, XML_FAILCIB_ATTR_OBJTYPE, TYPE(target));
 852         crm_xml_add(xml_node, XML_FAILCIB_ATTR_OP, operation);
 853         crm_xml_add(xml_node, XML_FAILCIB_ATTR_REASON, error_msg);
 854 
 855         crm_warn("Action %s failed: %s (cde=%d)", operation, error_msg, return_code);
 856     }
 857 
 858     return was_error;
 859 }

/* [previous][next][first][last][top][bottom][index][help] */