LCOV - code coverage report
Current view: top level - cib - cib_ops.c (source / functions) Hit Total Coverage
Test: Pacemaker code coverage Lines: 0 401 0.0 %
Date: 2024-05-07 11:09:47 Functions: 0 16 0.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright 2004-2024 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 <glib.h>
      23             : #include <libxml/tree.h>
      24             : 
      25             : #include <crm/crm.h>
      26             : #include <crm/cib/internal.h>
      27             : 
      28             : #include <crm/common/xml.h>
      29             : #include <crm/common/xml_internal.h>
      30             : 
      31             : // @TODO: Free this via crm_exit() when libcib gets merged with libcrmcommon
      32             : static GHashTable *operation_table = NULL;
      33             : 
      34             : static const cib__operation_t cib_ops[] = {
      35             :     {
      36             :         PCMK__CIB_REQUEST_ABS_DELETE, cib__op_abs_delete,
      37             :         cib__op_attr_modifies|cib__op_attr_privileged
      38             :     },
      39             :     {
      40             :         PCMK__CIB_REQUEST_APPLY_PATCH, cib__op_apply_patch,
      41             :         cib__op_attr_modifies
      42             :         |cib__op_attr_privileged
      43             :         |cib__op_attr_transaction
      44             :     },
      45             :     {
      46             :         PCMK__CIB_REQUEST_BUMP, cib__op_bump,
      47             :         cib__op_attr_modifies
      48             :         |cib__op_attr_privileged
      49             :         |cib__op_attr_transaction
      50             :     },
      51             :     {
      52             :         PCMK__CIB_REQUEST_COMMIT_TRANSACT, cib__op_commit_transact,
      53             :         cib__op_attr_modifies
      54             :         |cib__op_attr_privileged
      55             :         |cib__op_attr_replaces
      56             :         |cib__op_attr_writes_through
      57             :     },
      58             :     {
      59             :         PCMK__CIB_REQUEST_CREATE, cib__op_create,
      60             :         cib__op_attr_modifies
      61             :         |cib__op_attr_privileged
      62             :         |cib__op_attr_transaction
      63             :     },
      64             :     {
      65             :         PCMK__CIB_REQUEST_DELETE, cib__op_delete,
      66             :         cib__op_attr_modifies
      67             :         |cib__op_attr_privileged
      68             :         |cib__op_attr_transaction
      69             :     },
      70             :     {
      71             :         PCMK__CIB_REQUEST_ERASE, cib__op_erase,
      72             :         cib__op_attr_modifies
      73             :         |cib__op_attr_privileged
      74             :         |cib__op_attr_replaces
      75             :         |cib__op_attr_transaction
      76             :     },
      77             :     {
      78             :         PCMK__CIB_REQUEST_IS_PRIMARY, cib__op_is_primary,
      79             :         cib__op_attr_privileged
      80             :     },
      81             :     {
      82             :         PCMK__CIB_REQUEST_MODIFY, cib__op_modify,
      83             :         cib__op_attr_modifies
      84             :         |cib__op_attr_privileged
      85             :         |cib__op_attr_transaction
      86             :     },
      87             :     {
      88             :         PCMK__CIB_REQUEST_NOOP, cib__op_noop, cib__op_attr_none
      89             :     },
      90             :     {
      91             :         CRM_OP_PING, cib__op_ping, cib__op_attr_none
      92             :     },
      93             :     {
      94             :         // @COMPAT: Drop cib__op_attr_modifies when we drop legacy mode support
      95             :         PCMK__CIB_REQUEST_PRIMARY, cib__op_primary,
      96             :         cib__op_attr_modifies|cib__op_attr_privileged|cib__op_attr_local
      97             :     },
      98             :     {
      99             :         PCMK__CIB_REQUEST_QUERY, cib__op_query, cib__op_attr_none
     100             :     },
     101             :     {
     102             :         PCMK__CIB_REQUEST_REPLACE, cib__op_replace,
     103             :         cib__op_attr_modifies
     104             :         |cib__op_attr_privileged
     105             :         |cib__op_attr_replaces
     106             :         |cib__op_attr_writes_through
     107             :         |cib__op_attr_transaction
     108             :     },
     109             :     {
     110             :         PCMK__CIB_REQUEST_SECONDARY, cib__op_secondary,
     111             :         cib__op_attr_privileged|cib__op_attr_local
     112             :     },
     113             :     {
     114             :         PCMK__CIB_REQUEST_SHUTDOWN, cib__op_shutdown, cib__op_attr_privileged
     115             :     },
     116             :     {
     117             :         PCMK__CIB_REQUEST_SYNC_TO_ALL, cib__op_sync_all, cib__op_attr_privileged
     118             :     },
     119             :     {
     120             :         PCMK__CIB_REQUEST_SYNC_TO_ONE, cib__op_sync_one, cib__op_attr_privileged
     121             :     },
     122             :     {
     123             :         PCMK__CIB_REQUEST_UPGRADE, cib__op_upgrade,
     124             :         cib__op_attr_modifies
     125             :         |cib__op_attr_privileged
     126             :         |cib__op_attr_writes_through
     127             :         |cib__op_attr_transaction
     128             :     },
     129             :     {
     130             :         PCMK__CIB_REQUEST_SCHEMAS, cib__op_schemas, cib__op_attr_local
     131             :     }
     132             : };
     133             : 
     134             : /*!
     135             :  * \internal
     136             :  * \brief Get the \c cib__operation_t object for a given CIB operation name
     137             :  *
     138             :  * \param[in]  op         CIB operation name
     139             :  * \param[out] operation  Where to store CIB operation object
     140             :  *
     141             :  * \return Standard Pacemaker return code
     142             :  */
     143             : int
     144           0 : cib__get_operation(const char *op, const cib__operation_t **operation)
     145             : {
     146           0 :     CRM_ASSERT((op != NULL) && (operation != NULL));
     147             : 
     148           0 :     if (operation_table == NULL) {
     149           0 :         operation_table = pcmk__strkey_table(NULL, NULL);
     150             : 
     151           0 :         for (int lpc = 0; lpc < PCMK__NELEM(cib_ops); lpc++) {
     152           0 :             const cib__operation_t *oper = &(cib_ops[lpc]);
     153             : 
     154           0 :             g_hash_table_insert(operation_table, (gpointer) oper->name,
     155             :                                 (gpointer) oper);
     156             :         }
     157             :     }
     158             : 
     159           0 :     *operation = g_hash_table_lookup(operation_table, op);
     160           0 :     if (*operation == NULL) {
     161           0 :         crm_err("Operation %s is invalid", op);
     162           0 :         return EINVAL;
     163             :     }
     164           0 :     return pcmk_rc_ok;
     165             : }
     166             : 
     167             : int
     168           0 : cib_process_query(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
     169             :                   xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
     170             : {
     171           0 :     xmlNode *obj_root = NULL;
     172           0 :     int result = pcmk_ok;
     173             : 
     174           0 :     crm_trace("Processing %s for %s section",
     175             :               op, pcmk__s(section, "unspecified"));
     176             : 
     177           0 :     if (options & cib_xpath) {
     178           0 :         return cib_process_xpath(op, options, section, req, input,
     179             :                                  existing_cib, result_cib, answer);
     180             :     }
     181             : 
     182           0 :     CRM_CHECK(*answer == NULL, free_xml(*answer));
     183           0 :     *answer = NULL;
     184             : 
     185           0 :     if (pcmk__str_eq(PCMK__XE_ALL, section, pcmk__str_casei)) {
     186           0 :         section = NULL;
     187             :     }
     188             : 
     189           0 :     obj_root = pcmk_find_cib_element(existing_cib, section);
     190             : 
     191           0 :     if (obj_root == NULL) {
     192           0 :         result = -ENXIO;
     193             : 
     194           0 :     } else if (options & cib_no_children) {
     195           0 :         xmlNode *shallow = pcmk__xe_create(*answer,
     196           0 :                                            (const char *) obj_root->name);
     197             : 
     198           0 :         pcmk__xe_copy_attrs(shallow, obj_root, pcmk__xaf_none);
     199           0 :         *answer = shallow;
     200             : 
     201             :     } else {
     202           0 :         *answer = obj_root;
     203             :     }
     204             : 
     205           0 :     if (result == pcmk_ok && *answer == NULL) {
     206           0 :         crm_err("Error creating query response");
     207           0 :         result = -ENOMSG;
     208             :     }
     209             : 
     210           0 :     return result;
     211             : }
     212             : 
     213             : static int
     214           0 : update_counter(xmlNode *xml_obj, const char *field, bool reset)
     215             : {
     216           0 :     char *new_value = NULL;
     217           0 :     char *old_value = NULL;
     218           0 :     int int_value = -1;
     219             : 
     220           0 :     if (!reset && crm_element_value(xml_obj, field) != NULL) {
     221           0 :         old_value = crm_element_value_copy(xml_obj, field);
     222             :     }
     223           0 :     if (old_value != NULL) {
     224           0 :         int_value = atoi(old_value);
     225           0 :         new_value = pcmk__itoa(++int_value);
     226             :     } else {
     227           0 :         new_value = pcmk__str_copy("1");
     228             :     }
     229             : 
     230           0 :     crm_trace("Update %s from %s to %s",
     231             :               field, pcmk__s(old_value, "unset"), new_value);
     232           0 :     crm_xml_add(xml_obj, field, new_value);
     233             : 
     234           0 :     free(new_value);
     235           0 :     free(old_value);
     236             : 
     237           0 :     return pcmk_ok;
     238             : }
     239             : 
     240             : int
     241           0 : cib_process_erase(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
     242             :                   xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
     243             : {
     244           0 :     int result = pcmk_ok;
     245             : 
     246           0 :     crm_trace("Processing \"%s\" event", op);
     247             : 
     248           0 :     if (*result_cib != existing_cib) {
     249           0 :         free_xml(*result_cib);
     250             :     }
     251           0 :     *result_cib = createEmptyCib(0);
     252           0 :     pcmk__xe_copy_attrs(*result_cib, existing_cib, pcmk__xaf_none);
     253           0 :     update_counter(*result_cib, PCMK_XA_ADMIN_EPOCH, false);
     254           0 :     *answer = NULL;
     255             : 
     256           0 :     return result;
     257             : }
     258             : 
     259             : int
     260           0 : cib_process_upgrade(const char *op, int options, const char *section, xmlNode * req,
     261             :                     xmlNode * input, xmlNode * existing_cib, xmlNode ** result_cib,
     262             :                     xmlNode ** answer)
     263             : {
     264           0 :     int rc = 0;
     265           0 :     const char *max_schema = crm_element_value(req, PCMK__XA_CIB_SCHEMA_MAX);
     266           0 :     const char *original_schema = NULL;
     267           0 :     const char *new_schema = NULL;
     268             : 
     269           0 :     *answer = NULL;
     270           0 :     crm_trace("Processing \"%s\" event with max=%s", op, max_schema);
     271             : 
     272           0 :     original_schema = crm_element_value(existing_cib, PCMK_XA_VALIDATE_WITH);
     273           0 :     rc = pcmk__update_schema(result_cib, max_schema, true,
     274           0 :                              !pcmk_is_set(options, cib_verbose));
     275           0 :     rc = pcmk_rc2legacy(rc);
     276           0 :     new_schema = crm_element_value(*result_cib, PCMK_XA_VALIDATE_WITH);
     277             : 
     278           0 :     if (pcmk__cmp_schemas_by_name(new_schema, original_schema) > 0) {
     279           0 :         update_counter(*result_cib, PCMK_XA_ADMIN_EPOCH, false);
     280           0 :         update_counter(*result_cib, PCMK_XA_EPOCH, true);
     281           0 :         update_counter(*result_cib, PCMK_XA_NUM_UPDATES, true);
     282           0 :         return pcmk_ok;
     283             :     }
     284             : 
     285           0 :     return rc;
     286             : }
     287             : 
     288             : int
     289           0 : cib_process_bump(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
     290             :                  xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
     291             : {
     292           0 :     int result = pcmk_ok;
     293             : 
     294           0 :     crm_trace("Processing %s for epoch='%s'", op,
     295             :               pcmk__s(crm_element_value(existing_cib, PCMK_XA_EPOCH), ""));
     296             : 
     297           0 :     *answer = NULL;
     298           0 :     update_counter(*result_cib, PCMK_XA_EPOCH, false);
     299             : 
     300           0 :     return result;
     301             : }
     302             : 
     303             : int
     304           0 : cib_process_replace(const char *op, int options, const char *section, xmlNode * req,
     305             :                     xmlNode * input, xmlNode * existing_cib, xmlNode ** result_cib,
     306             :                     xmlNode ** answer)
     307             : {
     308           0 :     int result = pcmk_ok;
     309             : 
     310           0 :     crm_trace("Processing %s for %s section",
     311             :               op, pcmk__s(section, "unspecified"));
     312             : 
     313           0 :     if (options & cib_xpath) {
     314           0 :         return cib_process_xpath(op, options, section, req, input,
     315             :                                  existing_cib, result_cib, answer);
     316             :     }
     317             : 
     318           0 :     *answer = NULL;
     319             : 
     320           0 :     if (input == NULL) {
     321           0 :         return -EINVAL;
     322             :     }
     323             : 
     324           0 :     if (pcmk__str_eq(PCMK__XE_ALL, section, pcmk__str_casei)) {
     325           0 :         section = NULL;
     326             : 
     327           0 :     } else if (pcmk__xe_is(input, section)) {
     328           0 :         section = NULL;
     329             :     }
     330             : 
     331           0 :     if (pcmk__xe_is(input, PCMK_XE_CIB)) {
     332           0 :         int updates = 0;
     333           0 :         int epoch = 0;
     334           0 :         int admin_epoch = 0;
     335             : 
     336           0 :         int replace_updates = 0;
     337           0 :         int replace_epoch = 0;
     338           0 :         int replace_admin_epoch = 0;
     339             : 
     340           0 :         const char *reason = NULL;
     341           0 :         const char *peer = crm_element_value(req, PCMK__XA_SRC);
     342           0 :         const char *digest = crm_element_value(req, PCMK__XA_DIGEST);
     343             : 
     344           0 :         if (digest) {
     345           0 :             const char *version = crm_element_value(req,
     346             :                                                     PCMK_XA_CRM_FEATURE_SET);
     347           0 :             char *digest_verify = calculate_xml_versioned_digest(input, FALSE, TRUE,
     348             :                                                                  version ? version :
     349             :                                                                  CRM_FEATURE_SET);
     350             : 
     351           0 :             if (!pcmk__str_eq(digest_verify, digest, pcmk__str_casei)) {
     352           0 :                 crm_err("Digest mis-match on replace from %s: %s vs. %s (expected)", peer,
     353             :                         digest_verify, digest);
     354           0 :                 reason = "digest mismatch";
     355             : 
     356             :             } else {
     357           0 :                 crm_info("Digest matched on replace from %s: %s", peer, digest);
     358             :             }
     359           0 :             free(digest_verify);
     360             : 
     361             :         } else {
     362           0 :             crm_trace("No digest to verify");
     363             :         }
     364             : 
     365           0 :         cib_version_details(existing_cib, &admin_epoch, &epoch, &updates);
     366           0 :         cib_version_details(input, &replace_admin_epoch, &replace_epoch, &replace_updates);
     367             : 
     368           0 :         if (replace_admin_epoch < admin_epoch) {
     369           0 :             reason = PCMK_XA_ADMIN_EPOCH;
     370             : 
     371           0 :         } else if (replace_admin_epoch > admin_epoch) {
     372             :             /* no more checks */
     373             : 
     374           0 :         } else if (replace_epoch < epoch) {
     375           0 :             reason = PCMK_XA_EPOCH;
     376             : 
     377           0 :         } else if (replace_epoch > epoch) {
     378             :             /* no more checks */
     379             : 
     380           0 :         } else if (replace_updates < updates) {
     381           0 :             reason = PCMK_XA_NUM_UPDATES;
     382             :         }
     383             : 
     384           0 :         if (reason != NULL) {
     385           0 :             crm_info("Replacement %d.%d.%d from %s not applied to %d.%d.%d:"
     386             :                      " current %s is greater than the replacement",
     387             :                      replace_admin_epoch, replace_epoch,
     388             :                      replace_updates, peer, admin_epoch, epoch, updates, reason);
     389           0 :             result = -pcmk_err_old_data;
     390             :         } else {
     391           0 :             crm_info("Replaced %d.%d.%d with %d.%d.%d from %s",
     392             :                      admin_epoch, epoch, updates,
     393             :                      replace_admin_epoch, replace_epoch, replace_updates, peer);
     394             :         }
     395             : 
     396           0 :         if (*result_cib != existing_cib) {
     397           0 :             free_xml(*result_cib);
     398             :         }
     399           0 :         *result_cib = pcmk__xml_copy(NULL, input);
     400             : 
     401             :     } else {
     402           0 :         xmlNode *obj_root = NULL;
     403             : 
     404           0 :         obj_root = pcmk_find_cib_element(*result_cib, section);
     405           0 :         result = pcmk__xe_replace_match(obj_root, input);
     406           0 :         result = pcmk_rc2legacy(result);
     407           0 :         if (result != pcmk_ok) {
     408           0 :             crm_trace("No matching object to replace");
     409             :         }
     410             :     }
     411             : 
     412           0 :     return result;
     413             : }
     414             : 
     415             : static int
     416           0 : delete_child(xmlNode *child, void *userdata)
     417             : {
     418           0 :     xmlNode *obj_root = userdata;
     419             : 
     420           0 :     if (pcmk__xe_delete_match(obj_root, child) != pcmk_rc_ok) {
     421           0 :         crm_trace("No matching object to delete: %s=%s",
     422             :                   child->name, pcmk__xe_id(child));
     423             :     }
     424             : 
     425           0 :     return pcmk_rc_ok;
     426             : }
     427             : 
     428             : int
     429           0 : cib_process_delete(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
     430             :                    xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
     431             : {
     432           0 :     xmlNode *obj_root = NULL;
     433             : 
     434           0 :     crm_trace("Processing \"%s\" event", op);
     435             : 
     436           0 :     if (options & cib_xpath) {
     437           0 :         return cib_process_xpath(op, options, section, req, input,
     438             :                                  existing_cib, result_cib, answer);
     439             :     }
     440             : 
     441           0 :     if (input == NULL) {
     442           0 :         crm_err("Cannot perform modification with no data");
     443           0 :         return -EINVAL;
     444             :     }
     445             : 
     446           0 :     obj_root = pcmk_find_cib_element(*result_cib, section);
     447           0 :     if (pcmk__xe_is(input, section)) {
     448           0 :         pcmk__xe_foreach_child(input, NULL, delete_child, obj_root);
     449             :     } else {
     450           0 :         delete_child(input, obj_root);
     451             :     }
     452             : 
     453           0 :     return pcmk_ok;
     454             : }
     455             : 
     456             : int
     457           0 : cib_process_modify(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
     458             :                    xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
     459             : {
     460           0 :     xmlNode *obj_root = NULL;
     461           0 :     uint32_t flags = pcmk__xaf_none;
     462             : 
     463           0 :     crm_trace("Processing \"%s\" event", op);
     464             : 
     465           0 :     if (options & cib_xpath) {
     466           0 :         return cib_process_xpath(op, options, section, req, input,
     467             :                                  existing_cib, result_cib, answer);
     468             :     }
     469             : 
     470           0 :     if (input == NULL) {
     471           0 :         crm_err("Cannot perform modification with no data");
     472           0 :         return -EINVAL;
     473             :     }
     474             : 
     475           0 :     obj_root = pcmk_find_cib_element(*result_cib, section);
     476           0 :     if (obj_root == NULL) {
     477           0 :         xmlNode *tmp_section = NULL;
     478           0 :         const char *path = pcmk_cib_parent_name_for(section);
     479             : 
     480           0 :         if (path == NULL) {
     481           0 :             return -EINVAL;
     482             :         }
     483             : 
     484           0 :         tmp_section = pcmk__xe_create(NULL, section);
     485           0 :         cib_process_xpath(PCMK__CIB_REQUEST_CREATE, 0, path, NULL, tmp_section,
     486             :                           NULL, result_cib, answer);
     487           0 :         free_xml(tmp_section);
     488             : 
     489           0 :         obj_root = pcmk_find_cib_element(*result_cib, section);
     490             :     }
     491             : 
     492           0 :     CRM_CHECK(obj_root != NULL, return -EINVAL);
     493             : 
     494           0 :     if (pcmk_is_set(options, cib_score_update)) {
     495           0 :         flags |= pcmk__xaf_score_update;
     496             :     }
     497             : 
     498           0 :     if (pcmk__xe_update_match(obj_root, input, flags) != pcmk_rc_ok) {
     499           0 :         if (options & cib_can_create) {
     500           0 :             pcmk__xml_copy(obj_root, input);
     501             :         } else {
     502           0 :             return -ENXIO;
     503             :         }
     504             :     }
     505             : 
     506             :     // @COMPAT cib_mixed_update is deprecated as of 2.1.7
     507           0 :     if (pcmk_is_set(options, cib_mixed_update)) {
     508           0 :         int max = 0, lpc;
     509           0 :         xmlXPathObjectPtr xpathObj = xpath_search(*result_cib, "//@__delete__");
     510             : 
     511           0 :         if (xpathObj) {
     512           0 :             max = numXpathResults(xpathObj);
     513           0 :             crm_log_xml_trace(*result_cib, "Mixed result");
     514             :         }
     515             : 
     516           0 :         for (lpc = 0; lpc < max; lpc++) {
     517           0 :             xmlNode *match = getXpathResult(xpathObj, lpc);
     518           0 :             xmlChar *match_path = xmlGetNodePath(match);
     519             : 
     520           0 :             crm_debug("Destroying %s", match_path);
     521           0 :             free(match_path);
     522           0 :             free_xml(match);
     523             :         }
     524             : 
     525           0 :         freeXpathObject(xpathObj);
     526             :     }
     527           0 :     return pcmk_ok;
     528             : }
     529             : 
     530             : static int
     531           0 : add_cib_object(xmlNode * parent, xmlNode * new_obj)
     532             : {
     533           0 :     const char *object_name = NULL;
     534           0 :     const char *object_id = NULL;
     535             : 
     536           0 :     if ((parent == NULL) || (new_obj == NULL)) {
     537           0 :         return -EINVAL;
     538             :     }
     539             : 
     540           0 :     object_name = (const char *) new_obj->name;
     541           0 :     if (object_name == NULL) {
     542           0 :         return -EINVAL;
     543             :     }
     544             : 
     545           0 :     object_id = pcmk__xe_id(new_obj);
     546           0 :     if (pcmk__xe_first_child(parent, object_name,
     547             :                              ((object_id != NULL)? PCMK_XA_ID : NULL),
     548             :                              object_id)) {
     549           0 :         return -EEXIST;
     550             :     }
     551             : 
     552           0 :     if (object_id != NULL) {
     553           0 :         crm_trace("Processing creation of <%s " PCMK_XA_ID "='%s'>",
     554             :                   object_name, object_id);
     555             :     } else {
     556           0 :         crm_trace("Processing creation of <%s>", object_name);
     557             :     }
     558             : 
     559             :     /* @COMPAT PCMK__XA_REPLACE is deprecated since 2.1.6. Due to a legacy use
     560             :      * case, PCMK__XA_REPLACE has special meaning and should not be included in
     561             :      * the newly created object until we can break behavioral backward
     562             :      * compatibility.
     563             :      *
     564             :      * At a compatibility break, drop this and drop the definition of
     565             :      * PCMK__XA_REPLACE. Treat it like any other attribute.
     566             :      */
     567           0 :     pcmk__xml_tree_foreach(new_obj, pcmk__xe_remove_attr_cb,
     568             :                            (void *) PCMK__XA_REPLACE);
     569             : 
     570           0 :     pcmk__xml_copy(parent, new_obj);
     571           0 :     return pcmk_ok;
     572             : }
     573             : 
     574             : static bool
     575           0 : update_results(xmlNode *failed, xmlNode *target, const char *operation,
     576             :                int return_code)
     577             : {
     578           0 :     xmlNode *xml_node = NULL;
     579           0 :     bool was_error = false;
     580           0 :     const char *error_msg = NULL;
     581             : 
     582           0 :     if (return_code != pcmk_ok) {
     583           0 :         error_msg = pcmk_strerror(return_code);
     584             : 
     585           0 :         was_error = true;
     586           0 :         xml_node = pcmk__xe_create(failed, PCMK__XE_FAILED_UPDATE);
     587           0 :         pcmk__xml_copy(xml_node, target);
     588             : 
     589           0 :         crm_xml_add(xml_node, PCMK_XA_ID, pcmk__xe_id(target));
     590           0 :         crm_xml_add(xml_node, PCMK_XA_OBJECT_TYPE, (const char *) target->name);
     591           0 :         crm_xml_add(xml_node, PCMK_XA_OPERATION, operation);
     592           0 :         crm_xml_add(xml_node, PCMK_XA_REASON, error_msg);
     593             : 
     594           0 :         crm_warn("Action %s failed: %s (cde=%d)",
     595             :                  operation, error_msg, return_code);
     596             :     }
     597             : 
     598           0 :     return was_error;
     599             : }
     600             : 
     601             : int
     602           0 : cib_process_create(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
     603             :                    xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
     604             : {
     605           0 :     xmlNode *failed = NULL;
     606           0 :     int result = pcmk_ok;
     607           0 :     xmlNode *update_section = NULL;
     608             : 
     609           0 :     crm_trace("Processing %s for %s section",
     610             :               op, pcmk__s(section, "unspecified"));
     611           0 :     if (pcmk__str_eq(PCMK__XE_ALL, section, pcmk__str_casei)) {
     612           0 :         section = NULL;
     613             : 
     614           0 :     } else if (pcmk__str_eq(section, PCMK_XE_CIB, pcmk__str_casei)) {
     615           0 :         section = NULL;
     616             : 
     617           0 :     } else if (pcmk__xe_is(input, PCMK_XE_CIB)) {
     618           0 :         section = NULL;
     619             :     }
     620             : 
     621           0 :     CRM_CHECK(strcmp(op, PCMK__CIB_REQUEST_CREATE) == 0, return -EINVAL);
     622             : 
     623           0 :     if (input == NULL) {
     624           0 :         crm_err("Cannot perform modification with no data");
     625           0 :         return -EINVAL;
     626             :     }
     627             : 
     628           0 :     if (section == NULL) {
     629           0 :         return cib_process_modify(op, options, section, req, input, existing_cib, result_cib,
     630             :                                   answer);
     631             :     }
     632             : 
     633             :     // @COMPAT Deprecated since 2.1.8
     634           0 :     failed = pcmk__xe_create(NULL, PCMK__XE_FAILED);
     635             : 
     636           0 :     update_section = pcmk_find_cib_element(*result_cib, section);
     637           0 :     if (pcmk__xe_is(input, section)) {
     638           0 :         xmlNode *a_child = NULL;
     639             : 
     640           0 :         for (a_child = pcmk__xml_first_child(input); a_child != NULL;
     641           0 :              a_child = pcmk__xml_next(a_child)) {
     642           0 :             result = add_cib_object(update_section, a_child);
     643           0 :             if (update_results(failed, a_child, op, result)) {
     644           0 :                 break;
     645             :             }
     646             :         }
     647             : 
     648             :     } else {
     649           0 :         result = add_cib_object(update_section, input);
     650           0 :         update_results(failed, input, op, result);
     651             :     }
     652             : 
     653           0 :     if ((result == pcmk_ok) && (failed->children != NULL)) {
     654           0 :         result = -EINVAL;
     655             :     }
     656             : 
     657           0 :     if (result != pcmk_ok) {
     658           0 :         crm_log_xml_err(failed, "CIB Update failures");
     659           0 :         *answer = failed;
     660             : 
     661             :     } else {
     662           0 :         free_xml(failed);
     663             :     }
     664             : 
     665           0 :     return result;
     666             : }
     667             : 
     668             : int
     669           0 : cib_process_diff(const char *op, int options, const char *section, xmlNode * req, xmlNode * input,
     670             :                  xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer)
     671             : {
     672           0 :     const char *originator = NULL;
     673             : 
     674           0 :     if (req != NULL) {
     675           0 :         originator = crm_element_value(req, PCMK__XA_SRC);
     676             :     }
     677             : 
     678           0 :     crm_trace("Processing \"%s\" event from %s%s",
     679             :               op, originator,
     680             :               (pcmk_is_set(options, cib_force_diff)? " (global update)" : ""));
     681             : 
     682           0 :     if (*result_cib != existing_cib) {
     683           0 :         free_xml(*result_cib);
     684             :     }
     685           0 :     *result_cib = pcmk__xml_copy(NULL, existing_cib);
     686             : 
     687           0 :     return xml_apply_patchset(*result_cib, input, TRUE);
     688             : }
     689             : 
     690             : // @COMPAT: v1-only
     691             : bool
     692           0 : cib__config_changed_v1(xmlNode *last, xmlNode *next, xmlNode **diff)
     693             : {
     694           0 :     int lpc = 0, max = 0;
     695           0 :     bool config_changes = false;
     696           0 :     xmlXPathObject *xpathObj = NULL;
     697           0 :     int format = 1;
     698             : 
     699           0 :     CRM_ASSERT(diff != NULL);
     700             : 
     701           0 :     if (*diff == NULL && last != NULL && next != NULL) {
     702           0 :         *diff = pcmk__diff_v1_xml_object(last, next, false);
     703             :     }
     704             : 
     705           0 :     if (*diff == NULL) {
     706           0 :         goto done;
     707             :     }
     708             : 
     709           0 :     crm_element_value_int(*diff, PCMK_XA_FORMAT, &format);
     710           0 :     CRM_LOG_ASSERT(format == 1);
     711             : 
     712           0 :     xpathObj = xpath_search(*diff, "//" PCMK_XE_CONFIGURATION);
     713           0 :     if (numXpathResults(xpathObj) > 0) {
     714           0 :         config_changes = true;
     715           0 :         goto done;
     716             :     }
     717           0 :     freeXpathObject(xpathObj);
     718             : 
     719             :     /*
     720             :      * Do not check PCMK__XE_DIFF_ADDED "//" PCMK_XE_CIB
     721             :      * This always contains every field and would produce a false positive
     722             :      * every time if the checked value existed
     723             :      */
     724           0 :     xpathObj = xpath_search(*diff, "//" PCMK__XE_DIFF_REMOVED "//" PCMK_XE_CIB);
     725           0 :     max = numXpathResults(xpathObj);
     726             : 
     727           0 :     for (lpc = 0; lpc < max; lpc++) {
     728           0 :         xmlNode *top = getXpathResult(xpathObj, lpc);
     729             : 
     730           0 :         if (crm_element_value(top, PCMK_XA_EPOCH) != NULL) {
     731           0 :             config_changes = true;
     732           0 :             goto done;
     733             :         }
     734           0 :         if (crm_element_value(top, PCMK_XA_ADMIN_EPOCH) != NULL) {
     735           0 :             config_changes = true;
     736           0 :             goto done;
     737             :         }
     738             : 
     739           0 :         if (crm_element_value(top, PCMK_XA_VALIDATE_WITH) != NULL) {
     740           0 :             config_changes = true;
     741           0 :             goto done;
     742             :         }
     743           0 :         if (crm_element_value(top, PCMK_XA_CRM_FEATURE_SET) != NULL) {
     744           0 :             config_changes = true;
     745           0 :             goto done;
     746             :         }
     747           0 :         if (crm_element_value(top, PCMK_XA_REMOTE_CLEAR_PORT) != NULL) {
     748           0 :             config_changes = true;
     749           0 :             goto done;
     750             :         }
     751           0 :         if (crm_element_value(top, PCMK_XA_REMOTE_TLS_PORT) != NULL) {
     752           0 :             config_changes = true;
     753           0 :             goto done;
     754             :         }
     755             :     }
     756             : 
     757           0 :   done:
     758           0 :     freeXpathObject(xpathObj);
     759           0 :     return config_changes;
     760             : }
     761             : 
     762             : int
     763           0 : cib_process_xpath(const char *op, int options, const char *section,
     764             :                   const xmlNode *req, xmlNode *input, xmlNode *existing_cib,
     765             :                   xmlNode **result_cib, xmlNode **answer)
     766             : {
     767           0 :     int lpc = 0;
     768           0 :     int max = 0;
     769           0 :     int rc = pcmk_ok;
     770           0 :     bool is_query = pcmk__str_eq(op, PCMK__CIB_REQUEST_QUERY, pcmk__str_none);
     771             : 
     772           0 :     xmlXPathObjectPtr xpathObj = NULL;
     773             : 
     774           0 :     crm_trace("Processing \"%s\" event", op);
     775             : 
     776           0 :     if (is_query) {
     777           0 :         xpathObj = xpath_search(existing_cib, section);
     778             :     } else {
     779           0 :         xpathObj = xpath_search(*result_cib, section);
     780             :     }
     781             : 
     782           0 :     max = numXpathResults(xpathObj);
     783             : 
     784           0 :     if ((max < 1)
     785           0 :         && pcmk__str_eq(op, PCMK__CIB_REQUEST_DELETE, pcmk__str_none)) {
     786           0 :         crm_debug("%s was already removed", section);
     787             : 
     788           0 :     } else if (max < 1) {
     789           0 :         crm_debug("%s: %s does not exist", op, section);
     790           0 :         rc = -ENXIO;
     791             : 
     792           0 :     } else if (is_query) {
     793           0 :         if (max > 1) {
     794           0 :             *answer = pcmk__xe_create(NULL, PCMK__XE_XPATH_QUERY);
     795             :         }
     796             :     }
     797             : 
     798           0 :     if (pcmk_is_set(options, cib_multiple)
     799           0 :         && pcmk__str_eq(op, PCMK__CIB_REQUEST_DELETE, pcmk__str_none)) {
     800           0 :         dedupXpathResults(xpathObj);
     801             :     }
     802             : 
     803           0 :     for (lpc = 0; lpc < max; lpc++) {
     804           0 :         xmlChar *path = NULL;
     805           0 :         xmlNode *match = getXpathResult(xpathObj, lpc);
     806             : 
     807           0 :         if (match == NULL) {
     808           0 :             continue;
     809             :         }
     810             : 
     811           0 :         path = xmlGetNodePath(match);
     812           0 :         crm_debug("Processing %s op for %s with %s", op, section, path);
     813           0 :         free(path);
     814             : 
     815           0 :         if (pcmk__str_eq(op, PCMK__CIB_REQUEST_DELETE, pcmk__str_none)) {
     816           0 :             if (match == *result_cib) {
     817             :                 /* Attempting to delete the whole "/cib" */
     818           0 :                 crm_warn("Cannot perform %s for %s: The xpath is addressing the whole /cib", op, section);
     819           0 :                 rc = -EINVAL;
     820           0 :                 break;
     821             :             }
     822             : 
     823           0 :             free_xml(match);
     824           0 :             if ((options & cib_multiple) == 0) {
     825           0 :                 break;
     826             :             }
     827             : 
     828           0 :         } else if (pcmk__str_eq(op, PCMK__CIB_REQUEST_MODIFY, pcmk__str_none)) {
     829           0 :             uint32_t flags = pcmk__xaf_none;
     830             : 
     831           0 :             if (pcmk_is_set(options, cib_score_update)) {
     832           0 :                 flags |= pcmk__xaf_score_update;
     833             :             }
     834             : 
     835           0 :             if (pcmk__xe_update_match(match, input, flags) != pcmk_rc_ok) {
     836           0 :                 rc = -ENXIO;
     837           0 :             } else if ((options & cib_multiple) == 0) {
     838           0 :                 break;
     839             :             }
     840             : 
     841           0 :         } else if (pcmk__str_eq(op, PCMK__CIB_REQUEST_CREATE, pcmk__str_none)) {
     842           0 :             pcmk__xml_copy(match, input);
     843           0 :             break;
     844             : 
     845           0 :         } else if (pcmk__str_eq(op, PCMK__CIB_REQUEST_QUERY, pcmk__str_none)) {
     846             : 
     847           0 :             if (options & cib_no_children) {
     848           0 :                 xmlNode *shallow = pcmk__xe_create(*answer,
     849           0 :                                                    (const char *) match->name);
     850             : 
     851           0 :                 pcmk__xe_copy_attrs(shallow, match, pcmk__xaf_none);
     852             : 
     853           0 :                 if (*answer == NULL) {
     854           0 :                     *answer = shallow;
     855             :                 }
     856             : 
     857           0 :             } else if (options & cib_xpath_address) {
     858           0 :                 char *path = NULL;
     859           0 :                 xmlNode *parent = match;
     860             : 
     861           0 :                 while (parent && parent->type == XML_ELEMENT_NODE) {
     862           0 :                     const char *id = crm_element_value(parent, PCMK_XA_ID);
     863           0 :                     char *new_path = NULL;
     864             : 
     865           0 :                     if (id) {
     866           0 :                         new_path = crm_strdup_printf("/%s[@" PCMK_XA_ID "='%s']"
     867             :                                                      "%s",
     868             :                                                      parent->name, id,
     869             :                                                      pcmk__s(path, ""));
     870             :                     } else {
     871           0 :                         new_path = crm_strdup_printf("/%s%s", parent->name,
     872             :                                                      pcmk__s(path, ""));
     873             :                     }
     874           0 :                     free(path);
     875           0 :                     path = new_path;
     876           0 :                     parent = parent->parent;
     877             :                 }
     878           0 :                 crm_trace("Got: %s", path);
     879             : 
     880           0 :                 if (*answer == NULL) {
     881           0 :                     *answer = pcmk__xe_create(NULL, PCMK__XE_XPATH_QUERY);
     882             :                 }
     883           0 :                 parent = pcmk__xe_create(*answer, PCMK__XE_XPATH_QUERY_PATH);
     884           0 :                 crm_xml_add(parent, PCMK_XA_ID, path);
     885           0 :                 free(path);
     886             : 
     887           0 :             } else if (*answer) {
     888           0 :                 pcmk__xml_copy(*answer, match);
     889             : 
     890             :             } else {
     891           0 :                 *answer = match;
     892             :             }
     893             : 
     894           0 :         } else if (pcmk__str_eq(op, PCMK__CIB_REQUEST_REPLACE,
     895             :                                 pcmk__str_none)) {
     896           0 :             xmlNode *parent = match->parent;
     897             : 
     898           0 :             free_xml(match);
     899           0 :             pcmk__xml_copy(parent, input);
     900             : 
     901           0 :             if ((options & cib_multiple) == 0) {
     902           0 :                 break;
     903             :             }
     904             :         }
     905             :     }
     906             : 
     907           0 :     freeXpathObject(xpathObj);
     908           0 :     return rc;
     909             : }

Generated by: LCOV version 1.14