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

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