pacemaker  2.1.7-0f7f88312f
Scalable High-Availability cluster resource manager
cib_utils.c
Go to the documentation of this file.
1 /*
2  * Original copyright 2004 International Business Machines
3  * Later changes copyright 2008-2023 the Pacemaker project contributors
4  *
5  * The version control history for this file may have further details.
6  *
7  * This source code is licensed under the GNU Lesser General Public License
8  * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
9  */
10 #include <crm_internal.h>
11 #include <unistd.h>
12 #include <stdlib.h>
13 #include <stdio.h>
14 #include <stdarg.h>
15 #include <string.h>
16 #include <sys/utsname.h>
17 
18 #include <glib.h>
19 
20 #include <crm/crm.h>
21 #include <crm/cib/internal.h>
22 #include <crm/msg_xml.h>
24 #include <crm/common/xml.h>
26 #include <crm/pengine/rules.h>
27 
28 xmlNode *
30 {
31  xmlNode *the_cib = NULL;
32  xmlNode *generation = create_xml_node(NULL, XML_CIB_TAG_GENERATION_TUPPLE);
33 
34  cib->cmds->query(cib, NULL, &the_cib, cib_scope_local | cib_sync_call);
35  if (the_cib != NULL) {
36  copy_in_properties(generation, the_cib);
37  free_xml(the_cib);
38  }
39 
40  return generation;
41 }
42 
43 gboolean
44 cib_version_details(xmlNode * cib, int *admin_epoch, int *epoch, int *updates)
45 {
46  *epoch = -1;
47  *updates = -1;
48  *admin_epoch = -1;
49 
50  if (cib == NULL) {
51  return FALSE;
52 
53  } else {
57  }
58  return TRUE;
59 }
60 
61 gboolean
62 cib_diff_version_details(xmlNode * diff, int *admin_epoch, int *epoch, int *updates,
63  int *_admin_epoch, int *_epoch, int *_updates)
64 {
65  int add[] = { 0, 0, 0 };
66  int del[] = { 0, 0, 0 };
67 
68  xml_patch_versions(diff, add, del);
69 
70  *admin_epoch = add[0];
71  *epoch = add[1];
72  *updates = add[2];
73 
74  *_admin_epoch = del[0];
75  *_epoch = del[1];
76  *_updates = del[2];
77 
78  return TRUE;
79 }
80 
90 int
91 cib__get_notify_patchset(const xmlNode *msg, const xmlNode **patchset)
92 {
93  int rc = pcmk_err_generic;
94 
95  CRM_ASSERT(patchset != NULL);
96  *patchset = NULL;
97 
98  if (msg == NULL) {
99  crm_err("CIB diff notification received with no XML");
100  return ENOMSG;
101  }
102 
103  if ((crm_element_value_int(msg, F_CIB_RC, &rc) != 0) || (rc != pcmk_ok)) {
104  crm_warn("Ignore failed CIB update: %s " CRM_XS " rc=%d",
105  pcmk_strerror(rc), rc);
106  crm_log_xml_debug(msg, "failed");
107  return pcmk_legacy2rc(rc);
108  }
109 
110  *patchset = get_message_xml(msg, F_CIB_UPDATE_RESULT);
111 
112  if (*patchset == NULL) {
113  crm_err("CIB diff notification received with no patchset");
114  return ENOMSG;
115  }
116  return pcmk_rc_ok;
117 }
118 
119 #define XPATH_DIFF_V1 "//" F_CIB_UPDATE_RESULT "//" XML_TAG_DIFF_ADDED
120 
131 static bool
132 element_in_patchset_v1(const xmlNode *patchset, const char *element)
133 {
134  char *xpath = crm_strdup_printf(XPATH_DIFF_V1 "//%s",
135  pcmk__s(element, XML_TAG_CIB));
136  xmlXPathObject *xpath_obj = xpath_search(patchset, xpath);
137 
138  free(xpath);
139 
140  if (xpath_obj == NULL) {
141  return false;
142  }
143  freeXpathObject(xpath_obj);
144  return true;
145 }
146 
158 static bool
159 element_in_patchset_v2(const xmlNode *patchset, const char *element)
160 {
161  const char *element_xpath = pcmk__cib_abs_xpath_for(element);
162  const char *parent_xpath = pcmk_cib_parent_name_for(element);
163  char *element_regex = NULL;
164  bool rc = false;
165 
166  CRM_CHECK(element_xpath != NULL, return false); // Unsupported element
167 
168  // Matches if and only if element_xpath is part of a changed path
169  element_regex = crm_strdup_printf("^%s(/|$)", element_xpath);
170 
171  for (const xmlNode *change = first_named_child(patchset, XML_DIFF_CHANGE);
172  change != NULL; change = crm_next_same_xml(change)) {
173 
174  const char *op = crm_element_value(change, F_CIB_OPERATION);
175  const char *diff_xpath = crm_element_value(change, XML_DIFF_PATH);
176 
177  if (pcmk__str_eq(diff_xpath, element_regex, pcmk__str_regex)) {
178  // Change to an existing element
179  rc = true;
180  break;
181  }
182 
183  if (pcmk__str_eq(op, "create", pcmk__str_none)
184  && pcmk__str_eq(diff_xpath, parent_xpath, pcmk__str_none)
185  && pcmk__xe_is(pcmk__xml_first_child(change), element)) {
186 
187  // Newly added element
188  rc = true;
189  break;
190  }
191  }
192 
193  free(element_regex);
194  return rc;
195 }
196 
208 bool
209 cib__element_in_patchset(const xmlNode *patchset, const char *element)
210 {
211  int format = 1;
212 
213  CRM_ASSERT(patchset != NULL);
214 
215  crm_element_value_int(patchset, PCMK_XA_FORMAT, &format);
216  switch (format) {
217  case 1:
218  return element_in_patchset_v1(patchset, element);
219 
220  case 2:
221  return element_in_patchset_v2(patchset, element);
222 
223  default:
224  crm_warn("Unknown patch format: %d", format);
225  return false;
226  }
227 }
228 
237 xmlNode *
238 createEmptyCib(int cib_epoch)
239 {
240  xmlNode *cib_root = NULL, *config = NULL;
241 
242  cib_root = create_xml_node(NULL, XML_TAG_CIB);
245 
246  crm_xml_add_int(cib_root, XML_ATTR_GENERATION, cib_epoch);
247  crm_xml_add_int(cib_root, XML_ATTR_NUMUPDATES, 0);
249 
250  config = create_xml_node(cib_root, XML_CIB_TAG_CONFIGURATION);
252 
257 
258 #if PCMK__RESOURCE_STICKINESS_DEFAULT != 0
259  {
260  xmlNode *rsc_defaults = create_xml_node(config, XML_CIB_TAG_RSCCONFIG);
261  xmlNode *meta = create_xml_node(rsc_defaults, XML_TAG_META_SETS);
262  xmlNode *nvpair = create_xml_node(meta, XML_CIB_TAG_NVPAIR);
263 
264  crm_xml_add(meta, XML_ATTR_ID, "build-resource-defaults");
269  }
270 #endif
271  return cib_root;
272 }
273 
274 static bool
275 cib_acl_enabled(xmlNode *xml, const char *user)
276 {
277  bool rc = FALSE;
278 
279  if(pcmk_acl_required(user)) {
280  const char *value = NULL;
281  GHashTable *options = pcmk__strkey_table(free, free);
282 
283  cib_read_config(options, xml);
284  value = cib_pref(options, "enable-acl");
285  rc = crm_is_true(value);
286  g_hash_table_destroy(options);
287  }
288 
289  crm_trace("CIB ACL is %s", rc ? "enabled" : "disabled");
290  return rc;
291 }
292 
303 static bool
304 should_copy_cib(const char *op, const char *section, int call_options)
305 {
306  if (pcmk_is_set(call_options, cib_dryrun)) {
307  // cib_dryrun implies a scratch copy by definition; no side effects
308  return true;
309  }
310 
311  if (pcmk__str_eq(op, PCMK__CIB_REQUEST_COMMIT_TRANSACT, pcmk__str_none)) {
312  /* Commit-transaction must make a copy for atomicity. We must revert to
313  * the original CIB if the entire transaction cannot be applied
314  * successfully.
315  */
316  return true;
317  }
318 
319  if (pcmk_is_set(call_options, cib_transaction)) {
320  /* If cib_transaction is set, then we're in the process of committing a
321  * transaction. The commit-transaction request already made a scratch
322  * copy, and we're accumulating changes in that copy.
323  */
324  return false;
325  }
326 
327  if (pcmk__str_eq(section, XML_CIB_TAG_STATUS, pcmk__str_none)) {
328  /* Copying large CIBs accounts for a huge percentage of our CIB usage,
329  * and this avoids some of it.
330  *
331  * @TODO: Is this safe? See discussion at
332  * https://github.com/ClusterLabs/pacemaker/pull/3094#discussion_r1211400690.
333  */
334  return false;
335  }
336 
337  // Default behavior is to operate on a scratch copy
338  return true;
339 }
340 
341 int
342 cib_perform_op(const char *op, int call_options, cib__op_fn_t fn, bool is_query,
343  const char *section, xmlNode *req, xmlNode *input,
344  bool manage_counters, bool *config_changed,
345  xmlNode **current_cib, xmlNode **result_cib, xmlNode **diff,
346  xmlNode **output)
347 {
348  int rc = pcmk_ok;
349  bool check_schema = true;
350  bool make_copy = true;
351  xmlNode *top = NULL;
352  xmlNode *scratch = NULL;
353  xmlNode *patchset_cib = NULL;
354  xmlNode *local_diff = NULL;
355 
356  const char *new_version = NULL;
357  const char *user = crm_element_value(req, F_CIB_USER);
358  bool with_digest = false;
359 
360  crm_trace("Begin %s%s%s op",
361  (pcmk_is_set(call_options, cib_dryrun)? "dry run of " : ""),
362  (is_query? "read-only " : ""), op);
363 
364  CRM_CHECK(output != NULL, return -ENOMSG);
365  CRM_CHECK(current_cib != NULL, return -ENOMSG);
366  CRM_CHECK(result_cib != NULL, return -ENOMSG);
367  CRM_CHECK(config_changed != NULL, return -ENOMSG);
368 
369  if(output) {
370  *output = NULL;
371  }
372 
373  *result_cib = NULL;
374  *config_changed = false;
375 
376  if (fn == NULL) {
377  return -EINVAL;
378  }
379 
380  if (is_query) {
381  xmlNode *cib_ro = *current_cib;
382  xmlNode *cib_filtered = NULL;
383 
384  if (cib_acl_enabled(cib_ro, user)
385  && xml_acl_filtered_copy(user, *current_cib, *current_cib,
386  &cib_filtered)) {
387 
388  if (cib_filtered == NULL) {
389  crm_debug("Pre-filtered the entire cib");
390  return -EACCES;
391  }
392  cib_ro = cib_filtered;
393  crm_log_xml_trace(cib_ro, "filtered");
394  }
395 
396  rc = (*fn) (op, call_options, section, req, input, cib_ro, result_cib, output);
397 
398  if(output == NULL || *output == NULL) {
399  /* nothing */
400 
401  } else if(cib_filtered == *output) {
402  cib_filtered = NULL; /* Let them have this copy */
403 
404  } else if (*output == *current_cib) {
405  /* They already know not to free it */
406 
407  } else if(cib_filtered && (*output)->doc == cib_filtered->doc) {
408  /* We're about to free the document of which *output is a part */
409  *output = copy_xml(*output);
410 
411  } else if ((*output)->doc == (*current_cib)->doc) {
412  /* Give them a copy they can free */
413  *output = copy_xml(*output);
414  }
415 
416  free_xml(cib_filtered);
417  return rc;
418  }
419 
420  make_copy = should_copy_cib(op, section, call_options);
421 
422  if (!make_copy) {
423  /* Conditional on v2 patch style */
424 
425  scratch = *current_cib;
426 
427  // Make a copy of the top-level element to store version details
428  top = create_xml_node(NULL, (const char *) scratch->name);
429  copy_in_properties(top, scratch);
430  patchset_cib = top;
431 
432  xml_track_changes(scratch, user, NULL, cib_acl_enabled(scratch, user));
433  rc = (*fn) (op, call_options, section, req, input, scratch, &scratch, output);
434 
435  /* If scratch points to a new object now (for example, after an erase
436  * operation), then *current_cib should point to the same object.
437  */
438  *current_cib = scratch;
439 
440  } else {
441  scratch = copy_xml(*current_cib);
442  patchset_cib = *current_cib;
443 
444  xml_track_changes(scratch, user, NULL, cib_acl_enabled(scratch, user));
445  rc = (*fn) (op, call_options, section, req, input, *current_cib,
446  &scratch, output);
447 
448  if ((scratch != NULL) && !xml_tracking_changes(scratch)) {
449  crm_trace("Inferring changes after %s op", op);
450  xml_track_changes(scratch, user, *current_cib,
451  cib_acl_enabled(*current_cib, user));
452  xml_calculate_changes(*current_cib, scratch);
453  }
454  CRM_CHECK(*current_cib != scratch, return -EINVAL);
455  }
456 
457  xml_acl_disable(scratch); /* Allow the system to make any additional changes */
458 
459  if (rc == pcmk_ok && scratch == NULL) {
460  rc = -EINVAL;
461  goto done;
462 
463  } else if(rc == pcmk_ok && xml_acl_denied(scratch)) {
464  crm_trace("ACL rejected part or all of the proposed changes");
465  rc = -EACCES;
466  goto done;
467 
468  } else if (rc != pcmk_ok) {
469  goto done;
470  }
471 
472  if (scratch) {
473  new_version = crm_element_value(scratch, XML_ATTR_CRM_VERSION);
474 
475  if (new_version && compare_version(new_version, CRM_FEATURE_SET) > 0) {
476  crm_err("Discarding update with feature set '%s' greater than our own '%s'",
477  new_version, CRM_FEATURE_SET);
478  rc = -EPROTONOSUPPORT;
479  goto done;
480  }
481  }
482 
483  if (patchset_cib != NULL) {
484  int old = 0;
485  int new = 0;
486 
489 
490  if (old > new) {
491  crm_err("%s went backwards: %d -> %d (Opts: %#x)",
492  XML_ATTR_GENERATION_ADMIN, old, new, call_options);
493  crm_log_xml_warn(req, "Bad Op");
494  crm_log_xml_warn(input, "Bad Data");
495  rc = -pcmk_err_old_data;
496 
497  } else if (old == new) {
499  crm_element_value_int(patchset_cib, XML_ATTR_GENERATION, &old);
500  if (old > new) {
501  crm_err("%s went backwards: %d -> %d (Opts: %#x)",
502  XML_ATTR_GENERATION, old, new, call_options);
503  crm_log_xml_warn(req, "Bad Op");
504  crm_log_xml_warn(input, "Bad Data");
505  rc = -pcmk_err_old_data;
506  }
507  }
508  }
509 
510  crm_trace("Massaging CIB contents");
511  pcmk__strip_xml_text(scratch);
512  fix_plus_plus_recursive(scratch);
513 
514  if (!make_copy) {
515  /* At this point, patchset_cib is just the "cib" tag and its properties.
516  *
517  * The v1 format would barf on this, but we know the v2 patch
518  * format only needs it for the top-level version fields
519  */
520  local_diff = xml_create_patchset(2, patchset_cib, scratch,
521  config_changed, manage_counters);
522 
523  } else {
524  static time_t expires = 0;
525  time_t tm_now = time(NULL);
526 
527  if (expires < tm_now) {
528  expires = tm_now + 60; /* Validate clients are correctly applying v2-style diffs at most once a minute */
529  with_digest = true;
530  }
531 
532  local_diff = xml_create_patchset(0, patchset_cib, scratch,
533  config_changed, manage_counters);
534  }
535 
537  xml_accept_changes(scratch);
538 
539  if(local_diff) {
540  patchset_process_digest(local_diff, patchset_cib, scratch, with_digest);
541  pcmk__log_xml_patchset(LOG_INFO, local_diff);
542  crm_log_xml_trace(local_diff, "raw patch");
543  }
544 
545  if (make_copy && (local_diff != NULL)) {
546  // Original to compare against doesn't exist
548  {
549  // Validate the calculated patch set
550  int test_rc = pcmk_ok;
551  int format = 1;
552  xmlNode *cib_copy = copy_xml(patchset_cib);
553 
554  crm_element_value_int(local_diff, PCMK_XA_FORMAT, &format);
555  test_rc = xml_apply_patchset(cib_copy, local_diff,
556  manage_counters);
557 
558  if (test_rc != pcmk_ok) {
559  save_xml_to_file(cib_copy, "PatchApply:calculated", NULL);
560  save_xml_to_file(patchset_cib, "PatchApply:input", NULL);
561  save_xml_to_file(scratch, "PatchApply:actual", NULL);
562  save_xml_to_file(local_diff, "PatchApply:diff", NULL);
563  crm_err("v%d patchset error, patch failed to apply: %s "
564  "(%d)",
565  format, pcmk_rc_str(pcmk_legacy2rc(test_rc)),
566  test_rc);
567  }
568  free_xml(cib_copy);
569  },
570  {}
571  );
572  }
573 
574  if (pcmk__str_eq(section, XML_CIB_TAG_STATUS, pcmk__str_casei)) {
575  /* Throttle the amount of costly validation we perform due to status updates
576  * a) we don't really care whats in the status section
577  * b) we don't validate any of its contents at the moment anyway
578  */
579  check_schema = false;
580  }
581 
582  /* === scratch must not be modified after this point ===
583  * Exceptions, anything in:
584 
585  static filter_t filter[] = {
586  { 0, XML_ATTR_ORIGIN },
587  { 0, XML_CIB_ATTR_WRITTEN },
588  { 0, XML_ATTR_UPDATE_ORIG },
589  { 0, XML_ATTR_UPDATE_CLIENT },
590  { 0, XML_ATTR_UPDATE_USER },
591  };
592  */
593 
594  if (*config_changed && !pcmk_is_set(call_options, cib_no_mtime)) {
595  const char *schema = crm_element_value(scratch, XML_ATTR_VALIDATION);
596 
597  pcmk__xe_add_last_written(scratch);
598  if (schema) {
599  static int minimum_schema = 0;
600  int current_schema = get_schema_version(schema);
601 
602  if (minimum_schema == 0) {
603  minimum_schema = get_schema_version("pacemaker-1.2");
604  }
605 
606  /* Does the CIB support the "update-*" attributes... */
607  if (current_schema >= minimum_schema) {
608  /* Ensure values of origin, client, and user in scratch match
609  * the values in req
610  */
611  const char *origin = crm_element_value(req, F_ORIG);
612  const char *client = crm_element_value(req, F_CIB_CLIENTNAME);
613 
614  if (origin != NULL) {
615  crm_xml_add(scratch, XML_ATTR_UPDATE_ORIG, origin);
616  } else {
618  }
619 
620  if (client != NULL) {
621  crm_xml_add(scratch, XML_ATTR_UPDATE_CLIENT, user);
622  } else {
624  }
625 
626  if (user != NULL) {
627  crm_xml_add(scratch, XML_ATTR_UPDATE_USER, user);
628  } else {
630  }
631  }
632  }
633  }
634 
635  crm_trace("Perform validation: %s", pcmk__btoa(check_schema));
636  if ((rc == pcmk_ok) && check_schema && !validate_xml(scratch, NULL, true)) {
637  const char *current_schema = crm_element_value(scratch,
639 
640  crm_warn("Updated CIB does not validate against %s schema",
641  pcmk__s(current_schema, "unspecified"));
643  }
644 
645  done:
646 
647  *result_cib = scratch;
648 
649  /* @TODO: This may not work correctly with !make_copy, since we don't
650  * keep the original CIB.
651  */
652  if ((rc != pcmk_ok) && cib_acl_enabled(patchset_cib, user)
653  && xml_acl_filtered_copy(user, patchset_cib, scratch, result_cib)) {
654 
655  if (*result_cib == NULL) {
656  crm_debug("Pre-filtered the entire cib result");
657  }
658  free_xml(scratch);
659  }
660 
661  if(diff) {
662  *diff = local_diff;
663  } else {
664  free_xml(local_diff);
665  }
666 
667  free_xml(top);
668  crm_trace("Done");
669  return rc;
670 }
671 
672 int
673 cib__create_op(cib_t *cib, const char *op, const char *host,
674  const char *section, xmlNode *data, int call_options,
675  const char *user_name, const char *client_name,
676  xmlNode **op_msg)
677 {
678  CRM_CHECK((cib != NULL) && (op_msg != NULL), return -EPROTO);
679 
680  *op_msg = create_xml_node(NULL, T_CIB_COMMAND);
681  if (*op_msg == NULL) {
682  return -EPROTO;
683  }
684 
685  cib->call_id++;
686  if (cib->call_id < 1) {
687  cib->call_id = 1;
688  }
689 
691  crm_xml_add(*op_msg, F_TYPE, T_CIB);
692  crm_xml_add(*op_msg, F_CIB_OPERATION, op);
693  crm_xml_add(*op_msg, F_CIB_HOST, host);
694  crm_xml_add(*op_msg, F_CIB_SECTION, section);
695  crm_xml_add(*op_msg, F_CIB_USER, user_name);
696  crm_xml_add(*op_msg, F_CIB_CLIENTNAME, client_name);
697  crm_xml_add_int(*op_msg, F_CIB_CALLID, cib->call_id);
698 
699  crm_trace("Sending call options: %.8lx, %d", (long)call_options, call_options);
700  crm_xml_add_int(*op_msg, F_CIB_CALLOPTS, call_options);
701 
702  if (data != NULL) {
704  }
705 
706  if (pcmk_is_set(call_options, cib_inhibit_bcast)) {
707  CRM_CHECK(pcmk_is_set(call_options, cib_scope_local),
708  free_xml(*op_msg); return -EPROTO);
709  }
710  return pcmk_ok;
711 }
712 
721 static int
722 validate_transaction_request(const xmlNode *request)
723 {
724  const char *op = crm_element_value(request, F_CIB_OPERATION);
725  const char *host = crm_element_value(request, F_CIB_HOST);
726  const cib__operation_t *operation = NULL;
727  int rc = cib__get_operation(op, &operation);
728 
729  if (rc != pcmk_rc_ok) {
730  // cib__get_operation() logs error
731  return rc;
732  }
733 
734  if (!pcmk_is_set(operation->flags, cib__op_attr_transaction)) {
735  crm_err("Operation %s is not supported in CIB transactions", op);
736  return EOPNOTSUPP;
737  }
738 
739  if (host != NULL) {
740  crm_err("Operation targeting a specific node (%s) is not supported in "
741  "a CIB transaction",
742  host);
743  return EOPNOTSUPP;
744  }
745  return pcmk_rc_ok;
746 }
747 
757 int
758 cib__extend_transaction(cib_t *cib, xmlNode *request)
759 {
760  int rc = pcmk_rc_ok;
761 
762  CRM_ASSERT((cib != NULL) && (request != NULL));
763 
764  rc = validate_transaction_request(request);
765 
766  if ((rc == pcmk_rc_ok) && (cib->transaction == NULL)) {
768  }
769 
770  if (rc == pcmk_rc_ok) {
771  add_node_copy(cib->transaction, request);
772 
773  } else {
774  const char *op = crm_element_value(request, F_CIB_OPERATION);
775  const char *client_id = NULL;
776 
777  cib->cmds->client_id(cib, NULL, &client_id);
778  crm_err("Failed to add '%s' operation to transaction for client %s: %s",
779  op, pcmk__s(client_id, "(unidentified)"), pcmk_rc_str(rc));
780  crm_log_xml_info(request, "failed");
781  }
782  return pcmk_rc2legacy(rc);
783 }
784 
785 void
786 cib_native_callback(cib_t * cib, xmlNode * msg, int call_id, int rc)
787 {
788  xmlNode *output = NULL;
789  cib_callback_client_t *blob = NULL;
790 
791  if (msg != NULL) {
792  crm_element_value_int(msg, F_CIB_RC, &rc);
793  crm_element_value_int(msg, F_CIB_CALLID, &call_id);
794  output = get_message_xml(msg, F_CIB_CALLDATA);
795  }
796 
797  blob = cib__lookup_id(call_id);
798 
799  if (blob == NULL) {
800  crm_trace("No callback found for call %d", call_id);
801  }
802 
803  if (cib == NULL) {
804  crm_debug("No cib object supplied");
805  }
806 
807  if (rc == -pcmk_err_diff_resync) {
808  /* This is an internal value that clients do not and should not care about */
809  rc = pcmk_ok;
810  }
811 
812  if (blob && blob->callback && (rc == pcmk_ok || blob->only_success == FALSE)) {
813  crm_trace("Invoking callback %s for call %d",
814  pcmk__s(blob->id, "without ID"), call_id);
815  blob->callback(msg, call_id, rc, output, blob->user_data);
816 
817  } else if (cib && cib->op_callback == NULL && rc != pcmk_ok) {
818  crm_warn("CIB command failed: %s", pcmk_strerror(rc));
819  crm_log_xml_debug(msg, "Failed CIB Update");
820  }
821 
822  /* This may free user_data, so do it after the callback */
823  if (blob) {
824  remove_cib_op_callback(call_id, FALSE);
825  }
826 
827  if (cib && cib->op_callback != NULL) {
828  crm_trace("Invoking global callback for call %d", call_id);
829  cib->op_callback(msg, call_id, rc, output);
830  }
831  crm_trace("OP callback activated for %d", call_id);
832 }
833 
834 void
835 cib_native_notify(gpointer data, gpointer user_data)
836 {
837  xmlNode *msg = user_data;
838  cib_notify_client_t *entry = data;
839  const char *event = NULL;
840 
841  if (msg == NULL) {
842  crm_warn("Skipping callback - NULL message");
843  return;
844  }
845 
846  event = crm_element_value(msg, F_SUBTYPE);
847 
848  if (entry == NULL) {
849  crm_warn("Skipping callback - NULL callback client");
850  return;
851 
852  } else if (entry->callback == NULL) {
853  crm_warn("Skipping callback - NULL callback");
854  return;
855 
856  } else if (!pcmk__str_eq(entry->event, event, pcmk__str_casei)) {
857  crm_trace("Skipping callback - event mismatch %p/%s vs. %s", entry, entry->event, event);
858  return;
859  }
860 
861  crm_trace("Invoking callback for %p/%s event...", entry, event);
862  entry->callback(event, msg);
863  crm_trace("Callback invoked...");
864 }
865 
866 static pcmk__cluster_option_t cib_opts[] = {
867  /* name, legacy name, type, allowed values,
868  * default value, validator,
869  * short description,
870  * long description
871  */
872  {
873  "enable-acl", NULL, "boolean", NULL,
874  "false", pcmk__valid_boolean,
875  N_("Enable Access Control Lists (ACLs) for the CIB"),
876  NULL
877  },
878  {
879  "cluster-ipc-limit", NULL, "integer", NULL,
881  N_("Maximum IPC message backlog before disconnecting a cluster daemon"),
882  N_("Raise this if log has \"Evicting client\" messages for cluster daemon"
883  " PIDs (a good value is the number of resources in the cluster"
884  " multiplied by the number of nodes).")
885  },
886 };
887 
888 void
890 {
891  const char *desc_short = "Cluster Information Base manager options";
892  const char *desc_long = "Cluster options used by Pacemaker's Cluster "
893  "Information Base manager";
894 
895  gchar *s = pcmk__format_option_metadata("pacemaker-based", desc_short,
896  desc_long, cib_opts,
897  PCMK__NELEM(cib_opts));
898  printf("%s", s);
899  g_free(s);
900 }
901 
902 static void
903 verify_cib_options(GHashTable *options)
904 {
905  pcmk__validate_cluster_options(options, cib_opts, PCMK__NELEM(cib_opts));
906 }
907 
908 const char *
909 cib_pref(GHashTable * options, const char *name)
910 {
911  return pcmk__cluster_option(options, cib_opts, PCMK__NELEM(cib_opts),
912  name);
913 }
914 
915 gboolean
916 cib_read_config(GHashTable * options, xmlNode * current_cib)
917 {
918  xmlNode *config = NULL;
919  crm_time_t *now = NULL;
920 
921  if (options == NULL || current_cib == NULL) {
922  return FALSE;
923  }
924 
925  now = crm_time_new(NULL);
926 
927  g_hash_table_remove_all(options);
928 
929  config = pcmk_find_cib_element(current_cib, XML_CIB_TAG_CRMCONFIG);
930  if (config) {
931  pe_unpack_nvpairs(current_cib, config, XML_CIB_TAG_PROPSET, NULL,
932  options, CIB_OPTIONS_FIRST, TRUE, now, NULL);
933  }
934 
935  verify_cib_options(options);
936 
937  crm_time_free(now);
938 
939  return TRUE;
940 }
941 
942 int
943 cib_internal_op(cib_t * cib, const char *op, const char *host,
944  const char *section, xmlNode * data,
945  xmlNode ** output_data, int call_options, const char *user_name)
946 {
947  int (*delegate) (cib_t * cib, const char *op, const char *host,
948  const char *section, xmlNode * data,
949  xmlNode ** output_data, int call_options, const char *user_name) =
950  cib->delegate_fn;
951 
952  if(user_name == NULL) {
953  user_name = getenv("CIB_user");
954  }
955 
956  return delegate(cib, op, host, section, data, output_data, call_options, user_name);
957 }
958 
970 int
971 cib_apply_patch_event(xmlNode *event, xmlNode *input, xmlNode **output,
972  int level)
973 {
974  int rc = pcmk_err_generic;
975 
976  xmlNode *diff = NULL;
977 
978  CRM_ASSERT(event);
979  CRM_ASSERT(input);
980  CRM_ASSERT(output);
981 
982  crm_element_value_int(event, F_CIB_RC, &rc);
983  diff = get_message_xml(event, F_CIB_UPDATE_RESULT);
984 
985  if (rc < pcmk_ok || diff == NULL) {
986  return rc;
987  }
988 
989  if (level > LOG_CRIT) {
990  pcmk__log_xml_patchset(level, diff);
991  }
992 
993  if (input != NULL) {
994  rc = cib_process_diff(NULL, cib_none, NULL, event, diff, input, output,
995  NULL);
996 
997  if (rc != pcmk_ok) {
998  crm_debug("Update didn't apply: %s (%d) %p",
999  pcmk_strerror(rc), rc, *output);
1000 
1001  if (rc == -pcmk_err_old_data) {
1002  crm_trace("Masking error, we already have the supplied update");
1003  return pcmk_ok;
1004  }
1005  free_xml(*output);
1006  *output = NULL;
1007  return rc;
1008  }
1009  }
1010  return rc;
1011 }
1012 
1013 #define log_signon_query_err(out, fmt, args...) do { \
1014  if (out != NULL) { \
1015  out->err(out, fmt, ##args); \
1016  } else { \
1017  crm_err(fmt, ##args); \
1018  } \
1019  } while (0)
1020 
1021 int
1022 cib__signon_query(pcmk__output_t *out, cib_t **cib, xmlNode **cib_object)
1023 {
1024  int rc = pcmk_rc_ok;
1025  cib_t *cib_conn = NULL;
1026 
1027  CRM_ASSERT(cib_object != NULL);
1028 
1029  if (cib == NULL) {
1030  cib_conn = cib_new();
1031  } else {
1032  if (*cib == NULL) {
1033  *cib = cib_new();
1034  }
1035  cib_conn = *cib;
1036  }
1037 
1038  if (cib_conn == NULL) {
1039  return ENOMEM;
1040  }
1041 
1042  if (cib_conn->state == cib_disconnected) {
1043  rc = cib_conn->cmds->signon(cib_conn, crm_system_name, cib_command);
1044  rc = pcmk_legacy2rc(rc);
1045  }
1046 
1047  if (rc != pcmk_rc_ok) {
1048  log_signon_query_err(out, "Could not connect to the CIB: %s",
1049  pcmk_rc_str(rc));
1050  goto done;
1051  }
1052 
1053  if (out != NULL) {
1054  out->transient(out, "Querying CIB...");
1055  }
1056  rc = cib_conn->cmds->query(cib_conn, NULL, cib_object,
1058  rc = pcmk_legacy2rc(rc);
1059 
1060  if (rc != pcmk_rc_ok) {
1061  log_signon_query_err(out, "CIB query failed: %s", pcmk_rc_str(rc));
1062  }
1063 
1064 done:
1065  if (cib == NULL) {
1066  cib__clean_up_connection(&cib_conn);
1067  }
1068 
1069  if ((rc == pcmk_rc_ok) && (*cib_object == NULL)) {
1070  return pcmk_rc_no_input;
1071  }
1072  return rc;
1073 }
1074 
1075 int
1077 {
1078  int rc;
1079 
1080  if (*cib == NULL) {
1081  return pcmk_rc_ok;
1082  }
1083 
1084  rc = (*cib)->cmds->signoff(*cib);
1085  cib_delete(*cib);
1086  *cib = NULL;
1087  return pcmk_legacy2rc(rc);
1088 }
1089 
1090 // Deprecated functions kept only for backward API compatibility
1091 // LCOV_EXCL_START
1092 
1093 #include <crm/cib/util_compat.h>
1094 
1095 const char *
1096 get_object_path(const char *object_type)
1097 {
1098  return pcmk_cib_xpath_for(object_type);
1099 }
1100 
1101 const char *
1102 get_object_parent(const char *object_type)
1103 {
1104  return pcmk_cib_parent_name_for(object_type);
1105 }
1106 
1107 xmlNode *
1108 get_object_root(const char *object_type, xmlNode *the_root)
1109 {
1110  return pcmk_find_cib_element(the_root, object_type);
1111 }
1112 
1113 // LCOV_EXCL_STOP
1114 // End deprecated API
#define pcmk_err_old_data
Definition: results.h:75
#define LOG_TRACE
Definition: logging.h:38
pcmk__cpg_host_t host
Definition: cpg.c:49
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:238
#define XML_ATTR_UPDATE_ORIG
Definition: msg_xml.h:163
#define pcmk_err_schema_validation
Definition: results.h:73
const char * get_object_parent(const char *object_type)
Definition: cib_utils.c:1102
A dumping ground.
#define F_TYPE
Definition: msg_xml.h:91
#define XML_ATTR_UPDATE_CLIENT
Definition: msg_xml.h:164
const char * pcmk_strerror(int rc)
Definition: results.c:149
int cib_perform_op(const char *op, int call_options, cib__op_fn_t fn, bool is_query, const char *section, xmlNode *req, xmlNode *input, bool manage_counters, bool *config_changed, xmlNode **current_cib, xmlNode **result_cib, xmlNode **diff, xmlNode **output)
Definition: cib_utils.c:342
char data[0]
Definition: cpg.c:55
#define pcmk__if_tracing(if_action, else_action)
#define XML_ATTR_NUMUPDATES
Definition: msg_xml.h:149
int pcmk_rc2legacy(int rc)
Definition: results.c:546
cib_t * cib_new(void)
Create a new CIB connection object.
Definition: cib_client.c:605
const char * name
Definition: cib.c:26
const char * pcmk__xe_add_last_written(xmlNode *xe)
Definition: xml.c:1089
struct crm_time_s crm_time_t
Definition: iso8601.h:32
#define XML_CIB_TAG_CONSTRAINTS
Definition: msg_xml.h:207
gboolean cib_version_details(xmlNode *cib, int *admin_epoch, int *epoch, int *updates)
Definition: cib_utils.c:44
#define PCMK__RESOURCE_STICKINESS_DEFAULT
Definition: config.h:568
bool xml_acl_filtered_copy(const char *user, xmlNode *acl_source, xmlNode *xml, xmlNode **result)
Copy ACL-allowed portions of specified XML.
Definition: acl.c:435
xmlNode * first_named_child(const xmlNode *parent, const char *name)
Definition: xml.c:2484
#define F_SUBTYPE
Definition: msg_xml.h:87
void(* callback)(const char *event, xmlNode *msg)
Definition: internal.h:133
const char * crm_xml_add_int(xmlNode *node, const char *name, int value)
Create an XML attribute with specified name and integer value.
Definition: nvpair.c:349
#define CRM_FEATURE_SET
Definition: crm.h:70
void copy_in_properties(xmlNode *target, const xmlNode *src)
Definition: xml.c:456
#define XML_ATTR_UPDATE_USER
Definition: msg_xml.h:165
xmlNode * cib_get_generation(cib_t *cib)
Definition: cib_utils.c:29
#define PCMK__CIB_REQUEST_COMMIT_TRANSACT
Definition: internal.h:34
void xml_track_changes(xmlNode *xml, const char *user, xmlNode *acl_source, bool enforce_acls)
Definition: xml.c:263
void remove_cib_op_callback(int call_id, gboolean all_callbacks)
Definition: cib_client.c:787
int cib__extend_transaction(cib_t *cib, xmlNode *request)
Definition: cib_utils.c:758
const char * crm_xml_add(xmlNode *node, const char *name, const char *value)
Create an XML attribute with specified name and value.
Definition: nvpair.c:302
xmlNode * get_object_root(const char *object_type, xmlNode *the_root)
Definition: cib_utils.c:1108
#define pcmk_err_generic
Definition: results.h:71
#define XPATH_DIFF_V1
Definition: cib_utils.c:119
#define XML_NVPAIR_ATTR_NAME
Definition: msg_xml.h:393
int get_schema_version(const char *name)
Definition: schemas.c:967
char * crm_system_name
Definition: utils.c:51
int cib_apply_patch_event(xmlNode *event, xmlNode *input, xmlNode **output, int level)
Apply a CIB update patch to a given CIB.
Definition: cib_utils.c:971
#define XML_RSC_ATTR_STICKINESS
Definition: msg_xml.h:252
Supported in a transaction.
Definition: internal.h:85
Deprecated Pacemaker configuration utilities.
void xml_accept_changes(xmlNode *xml)
Definition: xml.c:359
gboolean only_success
Definition: internal.h:141
#define XML_CIB_TAG_NVPAIR
Definition: msg_xml.h:224
const char * pcmk_rc_str(int rc)
Get a user-friendly description of a return code.
Definition: results.c:501
int crm_element_value_int(const xmlNode *data, const char *name, int *dest)
Retrieve the integer value of an XML attribute.
Definition: nvpair.c:483
#define XML_CIB_TAG_NODES
Definition: msg_xml.h:206
#define F_CIB_SECTION
Definition: internal.h:42
int cib__clean_up_connection(cib_t **cib)
Definition: cib_utils.c:1076
bool pcmk__valid_positive_number(const char *value)
Definition: options.c:209
void cib_delete(cib_t *cib)
Free all memory used by CIB connection.
Definition: cib_client.c:778
#define XML_ATTR_GENERATION
Definition: msg_xml.h:147
gboolean validate_xml(xmlNode *xml_blob, const char *validation, gboolean to_logs)
Definition: schemas.c:673
cib_callback_client_t * cib__lookup_id(int call_id)
Definition: cib_client.c:825
bool cib__element_in_patchset(const xmlNode *patchset, const char *element)
Definition: cib_utils.c:209
#define XML_CIB_TAG_PROPSET
Definition: msg_xml.h:226
bool xml_tracking_changes(xmlNode *xml)
Definition: xml.c:278
gboolean cib_read_config(GHashTable *options, xmlNode *current_cib)
Definition: cib_utils.c:916
int cib__get_notify_patchset(const xmlNode *msg, const xmlNode **patchset)
Definition: cib_utils.c:91
xmlNode * copy_xml(xmlNode *src_node)
Definition: xml.c:789
const char * get_object_path(const char *object_type)
Definition: cib_utils.c:1096
void cib_metadata(void)
Definition: cib_utils.c:889
#define XML_CIB_TAG_RESOURCES
Definition: msg_xml.h:205
#define crm_warn(fmt, args...)
Definition: logging.h:382
int cib__signon_query(pcmk__output_t *out, cib_t **cib, xmlNode **cib_object)
Definition: cib_utils.c:1022
void pcmk__strip_xml_text(xmlNode *xml)
Definition: xml.c:962
cib_api_operations_t * cmds
Definition: cib_types.h:345
#define crm_debug(fmt, args...)
Definition: logging.h:386
int cib_process_diff(const char *op, int options, const char *section, xmlNode *req, xmlNode *input, xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer)
Definition: cib_ops.c:767
void cib_native_callback(cib_t *cib, xmlNode *msg, int call_id, int rc)
Definition: cib_utils.c:786
int xml_apply_patchset(xmlNode *xml, xmlNode *patchset, bool check_version)
Definition: patchset.c:1099
#define F_CIB_RC
Definition: internal.h:44
int(* signon)(cib_t *cib, const char *name, enum cib_conn_type type)
Definition: cib_types.h:126
#define XML_ATTR_ID
Definition: msg_xml.h:156
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition: nvpair.c:447
#define F_CIB_OPERATION
Definition: internal.h:40
xmlNode * pcmk_find_cib_element(xmlNode *cib, const char *element_name)
Find an element in the CIB.
Definition: cib.c:172
#define F_CIB_CLIENTNAME
Definition: internal.h:55
void(* callback)(xmlNode *, int, int, xmlNode *, void *)
Definition: internal.h:138
#define crm_trace(fmt, args...)
Definition: logging.h:387
char * crm_strdup_printf(char const *format,...) G_GNUC_PRINTF(1
gchar * pcmk__format_option_metadata(const char *name, const char *desc_short, const char *desc_long, pcmk__cluster_option_t *option_list, int len)
Definition: options.c:426
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition: util.h:99
xmlNode * add_node_copy(xmlNode *new_parent, xmlNode *xml_node)
Definition: xml.c:622
#define F_CIB_USER
Definition: internal.h:59
void(* op_callback)(const xmlNode *msg, int call_id, int rc, xmlNode *output)
Definition: cib_types.h:342
#define crm_log_xml_debug(xml, text)
Definition: logging.h:394
const char * pcmk__cluster_option(GHashTable *options, const pcmk__cluster_option_t *option_list, int len, const char *name)
Definition: options.c:350
#define F_CIB_UPDATE_RESULT
Definition: internal.h:54
#define F_CIB_HOST
Definition: internal.h:43
#define XML_TAG_META_SETS
Definition: msg_xml.h:228
Wrappers for and extensions to libxml2.
#define PCMK_XA_FORMAT
Definition: msg_xml.h:51
xmlNode * create_xml_node(xmlNode *parent, const char *name)
Definition: xml.c:638
#define crm_log_xml_warn(xml, text)
Definition: logging.h:391
void pe_unpack_nvpairs(xmlNode *top, const xmlNode *xml_obj, const char *set_name, GHashTable *node_hash, GHashTable *hash, const char *always_first, gboolean overwrite, crm_time_t *now, crm_time_t *next_change)
Extract nvpair blocks contained by an XML element into a hash table.
Definition: rules.c:535
int(* query)(cib_t *cib, const char *section, xmlNode **output_data, int call_options)
Definition: cib_types.h:156
#define PCMK__NELEM(a)
Definition: internal.h:46
#define XML_ATTR_VALIDATION
Definition: msg_xml.h:142
const char * event
Definition: internal.h:130
const char * pcmk_cib_parent_name_for(const char *element_name)
Get the parent element name of a given CIB element name.
Definition: cib.c:150
xmlNode * transaction
Definition: cib_types.h:347
int(*) int(* transient)(pcmk__output_t *out, const char *format,...) G_GNUC_PRINTF(2
int pcmk_legacy2rc(int legacy_rc)
Definition: results.c:559
#define CIB_OPTIONS_FIRST
Definition: msg_xml.h:110
#define F_ORIG
Definition: msg_xml.h:79
xmlNode * createEmptyCib(int cib_epoch)
Create XML for a new (empty) CIB.
Definition: cib_utils.c:238
gboolean add_message_xml(xmlNode *msg, const char *field, xmlNode *xml)
Definition: messages.c:160
void free_xml(xmlNode *child)
Definition: xml.c:783
gboolean cib_diff_version_details(xmlNode *diff, int *admin_epoch, int *epoch, int *updates, int *_admin_epoch, int *_epoch, int *_updates)
Definition: cib_utils.c:62
xmlNode * get_message_xml(const xmlNode *msg, const char *field)
Definition: messages.c:154
#define T_CIB_COMMAND
Definition: internal.h:65
#define XML_CIB_TAG_GENERATION_TUPPLE
Definition: msg_xml.h:413
const char * pcmk__cib_abs_xpath_for(const char *element)
Definition: cib.c:133
#define T_CIB
Definition: internal.h:64
const char * xml_latest_schema(void)
Definition: schemas.c:113
void patchset_process_digest(xmlNode *patch, xmlNode *source, xmlNode *target, bool with_digest)
Definition: patchset.c:385
const char * pcmk_cib_xpath_for(const char *element_name)
Get the relative XPath needed to find a specified CIB element name.
Definition: cib.c:112
int(* cib__op_fn_t)(const char *, int, const char *, xmlNode *, xmlNode *, xmlNode *, xmlNode **, xmlNode **)
Definition: internal.h:120
#define CRM_XS
Definition: logging.h:56
#define XML_TAG_CIB
Definition: msg_xml.h:137
bool pcmk__valid_boolean(const char *value)
Definition: options.c:187
#define XML_DIFF_CHANGE
Definition: msg_xml.h:466
xmlXPathObjectPtr xpath_search(const xmlNode *xml_top, const char *path)
Definition: xpath.c:139
#define XML_DIFF_PATH
Definition: msg_xml.h:471
#define N_(String)
Definition: crm_internal.h:48
#define pcmk_err_diff_resync
Definition: results.h:77
#define F_CIB_CALLOPTS
Definition: internal.h:37
void save_xml_to_file(const xmlNode *xml, const char *desc, const char *filename)
Definition: xml.c:1718
GHashTable * pcmk__strkey_table(GDestroyNotify key_destroy_func, GDestroyNotify value_destroy_func)
Definition: strings.c:608
#define F_CIB_CALLDATA
Definition: internal.h:39
int cib__create_op(cib_t *cib, const char *op, const char *host, const char *section, xmlNode *data, int call_options, const char *user_name, const char *client_name, xmlNode **op_msg)
Definition: cib_utils.c:673
#define crm_err(fmt, args...)
Definition: logging.h:381
#define CRM_ASSERT(expr)
Definition: results.h:42
xmlNode * input
crm_time_t * crm_time_new(const char *string)
Definition: iso8601.c:109
#define XML_CIB_TAG_CRMCONFIG
Definition: msg_xml.h:208
#define XML_CIB_TAG_RSCCONFIG
Definition: msg_xml.h:210
const char * id
Definition: internal.h:139
void xml_remove_prop(xmlNode *obj, const char *name)
Definition: xml.c:1696
void xml_acl_disable(xmlNode *xml)
Definition: acl.c:616
This structure contains everything that makes up a single output formatter.
int compare_version(const char *version1, const char *version2)
Definition: utils.c:189
#define crm_log_xml_info(xml, text)
Definition: logging.h:393
#define XML_ATTR_GENERATION_ADMIN
Definition: msg_xml.h:148
#define XML_NVPAIR_ATTR_VALUE
Definition: msg_xml.h:394
uint32_t flags
Group of enum cib__op_attr flags.
Definition: internal.h:126
#define XML_ATTR_CRM_VERSION
Definition: msg_xml.h:140
bool xml_acl_denied(const xmlNode *xml)
Check whether or not an XML node is ACL-denied.
Definition: acl.c:605
#define pcmk_ok
Definition: results.h:68
#define XML_CIB_TAG_STATUS
Definition: msg_xml.h:204
#define pcmk__log_xml_patchset(level, patchset)
int call_id
Definition: cib_types.h:334
#define crm_log_xml_trace(xml, text)
Definition: logging.h:395
void pcmk__validate_cluster_options(GHashTable *options, pcmk__cluster_option_t *option_list, int len)
Definition: options.c:501
#define F_CIB_CALLID
Definition: internal.h:38
gboolean crm_is_true(const char *s)
Definition: strings.c:416
#define pcmk__log_xml_changes(level, xml)
bool xml_patch_versions(const xmlNode *patchset, int add[3], int del[3])
Definition: patchset.c:572
int cib__get_operation(const char *op, const cib__operation_t **operation)
Definition: cib_ops.c:142
const char * cib_pref(GHashTable *options, const char *name)
Definition: cib_utils.c:909
#define XML_CIB_TAG_CONFIGURATION
Definition: msg_xml.h:203
#define F_XML_TAGNAME
Definition: msg_xml.h:99
void fix_plus_plus_recursive(xmlNode *target)
Parse integer assignment statements on this node and all its child nodes.
Definition: xml.c:489
enum cib_state state
Definition: cib_types.h:330
void freeXpathObject(xmlXPathObjectPtr xpathObj)
Definition: xpath.c:39
int(* client_id)(const cib_t *cib, const char **async_id, const char **sync_id)
Get the given CIB connection&#39;s unique client identifier(s)
Definition: cib_types.h:251
xmlNode * xml_create_patchset(int format, xmlNode *source, xmlNode *target, bool *config, bool manage_version)
Definition: patchset.c:328
void cib_native_notify(gpointer data, gpointer user_data)
Definition: cib_utils.c:835
void xml_calculate_changes(xmlNode *old_xml, xmlNode *new_xml)
Definition: xml.c:2068
Process request when the client commits the active transaction.
Definition: cib_types.h:100
bool pcmk_acl_required(const char *user)
Check whether ACLs are required for a given user.
Definition: acl.c:743
#define log_signon_query_err(out, fmt, args...)
Definition: cib_utils.c:1013
int cib_internal_op(cib_t *cib, const char *op, const char *host, const char *section, xmlNode *data, xmlNode **output_data, int call_options, const char *user_name)
Definition: cib_utils.c:943
void * delegate_fn
Definition: cib_types.h:337
xmlNode * crm_next_same_xml(const xmlNode *sibling)
Get next instance of same XML tag.
Definition: xml.c:2510
void crm_time_free(crm_time_t *dt)
Definition: iso8601.c:150