pacemaker  2.1.4-dc6eb4362
Scalable High-Availability cluster resource manager
cib_file.c
Go to the documentation of this file.
1 /*
2  * Original copyright 2004 International Business Machines
3  * Later changes copyright 2008-2021 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 
11 #include <crm_internal.h>
12 #include <unistd.h>
13 #include <limits.h>
14 #include <stdlib.h>
15 #include <stdint.h>
16 #include <stdio.h>
17 #include <stdarg.h>
18 #include <string.h>
19 #include <pwd.h>
20 
21 #include <sys/stat.h>
22 #include <sys/types.h>
23 #include <glib.h>
24 
25 #include <crm/crm.h>
26 #include <crm/cib/internal.h>
27 #include <crm/msg_xml.h>
28 #include <crm/common/ipc.h>
29 #include <crm/common/xml.h>
31 
33  cib_file_flag_dirty = (1 << 0),
34  cib_file_flag_live = (1 << 1),
35 };
36 
37 typedef struct cib_file_opaque_s {
38  uint32_t flags; // Group of enum cib_file_flags
39  char *filename;
41 
42 #define cib_set_file_flags(cibfile, flags_to_set) do { \
43  (cibfile)->flags = pcmk__set_flags_as(__func__, __LINE__, \
44  LOG_TRACE, "CIB file", \
45  cibfile->filename, \
46  (cibfile)->flags, \
47  (flags_to_set), \
48  #flags_to_set); \
49  } while (0)
50 
51 #define cib_clear_file_flags(cibfile, flags_to_clear) do { \
52  (cibfile)->flags = pcmk__clear_flags_as(__func__, __LINE__, \
53  LOG_TRACE, "CIB file", \
54  cibfile->filename, \
55  (cibfile)->flags, \
56  (flags_to_clear), \
57  #flags_to_clear); \
58  } while (0)
59 
60 int cib_file_perform_op(cib_t * cib, const char *op, const char *host, const char *section,
61  xmlNode * data, xmlNode ** output_data, int call_options);
62 
63 int cib_file_perform_op_delegate(cib_t * cib, const char *op, const char *host, const char *section,
64  xmlNode * data, xmlNode ** output_data, int call_options,
65  const char *user_name);
66 
67 int cib_file_signon(cib_t * cib, const char *name, enum cib_conn_type type);
68 int cib_file_signoff(cib_t * cib);
69 int cib_file_free(cib_t * cib);
70 
71 static int
72 cib_file_inputfd(cib_t * cib)
73 {
74  return -EPROTONOSUPPORT;
75 }
76 
77 static int
78 cib_file_set_connection_dnotify(cib_t * cib, void (*dnotify) (gpointer user_data))
79 {
80  return -EPROTONOSUPPORT;
81 }
82 
83 static int
84 cib_file_register_notification(cib_t * cib, const char *callback, int enabled)
85 {
86  return -EPROTONOSUPPORT;
87 }
88 
98 static gboolean
99 cib_file_verify_digest(xmlNode *root, const char *sigfile)
100 {
101  gboolean passed = FALSE;
102  char *expected;
103  int rc = pcmk__file_contents(sigfile, &expected);
104 
105  switch (rc) {
106  case pcmk_rc_ok:
107  if (expected == NULL) {
108  crm_err("On-disk digest at %s is empty", sigfile);
109  return FALSE;
110  }
111  break;
112  case ENOENT:
113  crm_warn("No on-disk digest present at %s", sigfile);
114  return TRUE;
115  default:
116  crm_err("Could not read on-disk digest from %s: %s",
117  sigfile, pcmk_rc_str(rc));
118  return FALSE;
119  }
120  passed = pcmk__verify_digest(root, expected);
121  free(expected);
122  return passed;
123 }
124 
140 int
141 cib_file_read_and_verify(const char *filename, const char *sigfile, xmlNode **root)
142 {
143  int s_res;
144  struct stat buf;
145  char *local_sigfile = NULL;
146  xmlNode *local_root = NULL;
147 
148  CRM_ASSERT(filename != NULL);
149  if (root) {
150  *root = NULL;
151  }
152 
153  /* Verify that file exists and its size is nonzero */
154  s_res = stat(filename, &buf);
155  if (s_res < 0) {
156  crm_perror(LOG_WARNING, "Could not verify cluster configuration file %s", filename);
157  return -errno;
158  } else if (buf.st_size == 0) {
159  crm_warn("Cluster configuration file %s is corrupt (size is zero)", filename);
160  return -pcmk_err_cib_corrupt;
161  }
162 
163  /* Parse XML */
164  local_root = filename2xml(filename);
165  if (local_root == NULL) {
166  crm_warn("Cluster configuration file %s is corrupt (unparseable as XML)", filename);
167  return -pcmk_err_cib_corrupt;
168  }
169 
170  /* If sigfile is not specified, use original file name plus .sig */
171  if (sigfile == NULL) {
172  sigfile = local_sigfile = crm_strdup_printf("%s.sig", filename);
173  }
174 
175  /* Verify that digests match */
176  if (cib_file_verify_digest(local_root, sigfile) == FALSE) {
177  free(local_sigfile);
178  free_xml(local_root);
179  return -pcmk_err_cib_modified;
180  }
181 
182  free(local_sigfile);
183  if (root) {
184  *root = local_root;
185  } else {
186  free_xml(local_root);
187  }
188  return pcmk_ok;
189 }
190 
191 #define CIB_SERIES "cib"
192 #define CIB_SERIES_MAX 100
193 #define CIB_SERIES_BZIP FALSE /* Must be false because archived copies are
194  created with hard links
195  */
196 
197 #define CIB_LIVE_NAME CIB_SERIES ".xml"
198 
207 static gboolean
208 cib_file_is_live(const char *filename)
209 {
210  gboolean same = FALSE;
211 
212  if (filename != NULL) {
213  // Canonicalize file names for true comparison
214  char *real_filename = NULL;
215 
216  if (pcmk__real_path(filename, &real_filename) == pcmk_rc_ok) {
217  char *real_livename = NULL;
218 
220  &real_livename) == pcmk_rc_ok) {
221  same = !strcmp(real_filename, real_livename);
222  free(real_livename);
223  }
224  free(real_filename);
225  }
226  }
227  return same;
228 }
229 
230 /* cib_file_backup() and cib_file_write_with_digest() need to chown the
231  * written files only in limited circumstances, so these variables allow
232  * that to be indicated without affecting external callers
233  */
234 static uid_t cib_file_owner = 0;
235 static uid_t cib_file_group = 0;
236 static gboolean cib_do_chown = FALSE;
237 
247 static int
248 cib_file_backup(const char *cib_dirname, const char *cib_filename)
249 {
250  int rc = 0;
251  unsigned int seq;
252  char *cib_path = crm_strdup_printf("%s/%s", cib_dirname, cib_filename);
253  char *cib_digest = crm_strdup_printf("%s.sig", cib_path);
254  char *backup_path;
255  char *backup_digest;
256 
257  // Determine backup and digest file names
258  if (pcmk__read_series_sequence(cib_dirname, CIB_SERIES,
259  &seq) != pcmk_rc_ok) {
260  // @TODO maybe handle errors better ...
261  seq = 0;
262  }
263  backup_path = pcmk__series_filename(cib_dirname, CIB_SERIES, seq,
265  backup_digest = crm_strdup_printf("%s.sig", backup_path);
266 
267  /* Remove the old backups if they exist */
268  unlink(backup_path);
269  unlink(backup_digest);
270 
271  /* Back up the CIB, by hard-linking it to the backup name */
272  if ((link(cib_path, backup_path) < 0) && (errno != ENOENT)) {
273  crm_perror(LOG_ERR, "Could not archive %s by linking to %s",
274  cib_path, backup_path);
275  rc = -1;
276 
277  /* Back up the CIB signature similarly */
278  } else if ((link(cib_digest, backup_digest) < 0) && (errno != ENOENT)) {
279  crm_perror(LOG_ERR, "Could not archive %s by linking to %s",
280  cib_digest, backup_digest);
281  rc = -1;
282 
283  /* Update the last counter and ensure everything is sync'd to media */
284  } else {
285  pcmk__write_series_sequence(cib_dirname, CIB_SERIES, ++seq,
287  if (cib_do_chown) {
288  int rc2;
289 
290  if ((chown(backup_path, cib_file_owner, cib_file_group) < 0)
291  && (errno != ENOENT)) {
292  crm_perror(LOG_ERR, "Could not set owner of %s", backup_path);
293  rc = -1;
294  }
295  if ((chown(backup_digest, cib_file_owner, cib_file_group) < 0)
296  && (errno != ENOENT)) {
297  crm_perror(LOG_ERR, "Could not set owner of %s", backup_digest);
298  rc = -1;
299  }
300  rc2 = pcmk__chown_series_sequence(cib_dirname, CIB_SERIES,
301  cib_file_owner, cib_file_group);
302  if (rc2 != pcmk_rc_ok) {
303  crm_err("Could not set owner of sequence file in %s: %s",
304  cib_dirname, pcmk_rc_str(rc2));
305  rc = -1;
306  }
307  }
308  pcmk__sync_directory(cib_dirname);
309  crm_info("Archived previous version as %s", backup_path);
310  }
311 
312  free(cib_path);
313  free(cib_digest);
314  free(backup_path);
315  free(backup_digest);
316  return rc;
317 }
318 
330 static void
331 cib_file_prepare_xml(xmlNode *root)
332 {
333  xmlNode *cib_status_root = NULL;
334 
335  /* Always write out with num_updates=0 and current last-written timestamp */
336  crm_xml_add(root, XML_ATTR_NUMUPDATES, "0");
338 
339  /* Delete status section before writing to file, because
340  * we discard it on startup anyway, and users get confused by it */
341  cib_status_root = find_xml_node(root, XML_CIB_TAG_STATUS, TRUE);
342  CRM_LOG_ASSERT(cib_status_root != NULL);
343  if (cib_status_root != NULL) {
344  free_xml(cib_status_root);
345  }
346 }
347 
361 int
362 cib_file_write_with_digest(xmlNode *cib_root, const char *cib_dirname,
363  const char *cib_filename)
364 {
365  int exit_rc = pcmk_ok;
366  int rc, fd;
367  char *digest = NULL;
368 
369  /* Detect CIB version for diagnostic purposes */
370  const char *epoch = crm_element_value(cib_root, XML_ATTR_GENERATION);
371  const char *admin_epoch = crm_element_value(cib_root,
373 
374  /* Determine full CIB and signature pathnames */
375  char *cib_path = crm_strdup_printf("%s/%s", cib_dirname, cib_filename);
376  char *digest_path = crm_strdup_printf("%s.sig", cib_path);
377 
378  /* Create temporary file name patterns for writing out CIB and signature */
379  char *tmp_cib = crm_strdup_printf("%s/cib.XXXXXX", cib_dirname);
380  char *tmp_digest = crm_strdup_printf("%s/cib.XXXXXX", cib_dirname);
381 
382  CRM_ASSERT((cib_path != NULL) && (digest_path != NULL)
383  && (tmp_cib != NULL) && (tmp_digest != NULL));
384 
385  /* Ensure the admin didn't modify the existing CIB underneath us */
386  crm_trace("Reading cluster configuration file %s", cib_path);
387  rc = cib_file_read_and_verify(cib_path, NULL, NULL);
388  if ((rc != pcmk_ok) && (rc != -ENOENT)) {
389  crm_err("%s was manually modified while the cluster was active!",
390  cib_path);
391  exit_rc = pcmk_err_cib_modified;
392  goto cleanup;
393  }
394 
395  /* Back up the existing CIB */
396  if (cib_file_backup(cib_dirname, cib_filename) < 0) {
397  exit_rc = pcmk_err_cib_backup;
398  goto cleanup;
399  }
400 
401  crm_debug("Writing CIB to disk");
402  umask(S_IWGRP | S_IWOTH | S_IROTH);
403  cib_file_prepare_xml(cib_root);
404 
405  /* Write the CIB to a temporary file, so we can deploy (near) atomically */
406  fd = mkstemp(tmp_cib);
407  if (fd < 0) {
408  crm_perror(LOG_ERR, "Couldn't open temporary file %s for writing CIB",
409  tmp_cib);
410  exit_rc = pcmk_err_cib_save;
411  goto cleanup;
412  }
413 
414  /* Protect the temporary file */
415  if (fchmod(fd, S_IRUSR | S_IWUSR) < 0) {
416  crm_perror(LOG_ERR, "Couldn't protect temporary file %s for writing CIB",
417  tmp_cib);
418  exit_rc = pcmk_err_cib_save;
419  goto cleanup;
420  }
421  if (cib_do_chown && (fchown(fd, cib_file_owner, cib_file_group) < 0)) {
422  crm_perror(LOG_ERR, "Couldn't protect temporary file %s for writing CIB",
423  tmp_cib);
424  exit_rc = pcmk_err_cib_save;
425  goto cleanup;
426  }
427 
428  /* Write out the CIB */
429  if (write_xml_fd(cib_root, tmp_cib, fd, FALSE) <= 0) {
430  crm_err("Changes couldn't be written to %s", tmp_cib);
431  exit_rc = pcmk_err_cib_save;
432  goto cleanup;
433  }
434 
435  /* Calculate CIB digest */
436  digest = calculate_on_disk_digest(cib_root);
437  CRM_ASSERT(digest != NULL);
438  crm_info("Wrote version %s.%s.0 of the CIB to disk (digest: %s)",
439  (admin_epoch ? admin_epoch : "0"), (epoch ? epoch : "0"), digest);
440 
441  /* Write the CIB digest to a temporary file */
442  fd = mkstemp(tmp_digest);
443  if (fd < 0) {
444  crm_perror(LOG_ERR, "Could not create temporary file for CIB digest");
445  exit_rc = pcmk_err_cib_save;
446  goto cleanup;
447  }
448  if (cib_do_chown && (fchown(fd, cib_file_owner, cib_file_group) < 0)) {
449  crm_perror(LOG_ERR, "Couldn't protect temporary file %s for writing CIB",
450  tmp_cib);
451  exit_rc = pcmk_err_cib_save;
452  close(fd);
453  goto cleanup;
454  }
455  rc = pcmk__write_sync(fd, digest);
456  if (rc != pcmk_rc_ok) {
457  crm_err("Could not write digest to %s: %s",
458  tmp_digest, pcmk_rc_str(rc));
459  exit_rc = pcmk_err_cib_save;
460  close(fd);
461  goto cleanup;
462  }
463  close(fd);
464  crm_debug("Wrote digest %s to disk", digest);
465 
466  /* Verify that what we wrote is sane */
467  crm_info("Reading cluster configuration file %s (digest: %s)",
468  tmp_cib, tmp_digest);
469  rc = cib_file_read_and_verify(tmp_cib, tmp_digest, NULL);
470  CRM_ASSERT(rc == 0);
471 
472  /* Rename temporary files to live, and sync directory changes to media */
473  crm_debug("Activating %s", tmp_cib);
474  if (rename(tmp_cib, cib_path) < 0) {
475  crm_perror(LOG_ERR, "Couldn't rename %s as %s", tmp_cib, cib_path);
476  exit_rc = pcmk_err_cib_save;
477  }
478  if (rename(tmp_digest, digest_path) < 0) {
479  crm_perror(LOG_ERR, "Couldn't rename %s as %s", tmp_digest,
480  digest_path);
481  exit_rc = pcmk_err_cib_save;
482  }
483  pcmk__sync_directory(cib_dirname);
484 
485  cleanup:
486  free(cib_path);
487  free(digest_path);
488  free(digest);
489  free(tmp_digest);
490  free(tmp_cib);
491  return exit_rc;
492 }
493 
494 cib_t *
495 cib_file_new(const char *cib_location)
496 {
497  cib_file_opaque_t *private = NULL;
498  cib_t *cib = cib_new_variant();
499 
500  if (cib == NULL) {
501  return NULL;
502  }
503 
504  private = calloc(1, sizeof(cib_file_opaque_t));
505 
506  if (private == NULL) {
507  free(cib);
508  return NULL;
509  }
510 
511  cib->variant = cib_file;
512  cib->variant_opaque = private;
513 
514  if (cib_location == NULL) {
515  cib_location = getenv("CIB_file");
516  }
517  private->flags = 0;
518  if (cib_file_is_live(cib_location)) {
520  crm_trace("File %s detected as live CIB", cib_location);
521  }
522  private->filename = strdup(cib_location);
523 
524  /* assign variant specific ops */
526  cib->cmds->signon = cib_file_signon;
527  cib->cmds->signoff = cib_file_signoff;
528  cib->cmds->free = cib_file_free;
529  cib->cmds->inputfd = cib_file_inputfd;
530 
531  cib->cmds->register_notification = cib_file_register_notification;
532  cib->cmds->set_connection_dnotify = cib_file_set_connection_dnotify;
533 
534  return cib;
535 }
536 
537 static xmlNode *in_mem_cib = NULL;
538 
553 static int
554 load_file_cib(const char *filename)
555 {
556  struct stat buf;
557  xmlNode *root = NULL;
558 
559  /* Ensure file is readable */
560  if (strcmp(filename, "-") && (stat(filename, &buf) < 0)) {
561  return -ENXIO;
562  }
563 
564  /* Parse XML from file */
565  root = filename2xml(filename);
566  if (root == NULL) {
568  }
569 
570  /* Add a status section if not already present */
571  if (find_xml_node(root, XML_CIB_TAG_STATUS, FALSE) == NULL) {
573  }
574 
575  /* Validate XML against its specified schema */
576  if (validate_xml(root, NULL, TRUE) == FALSE) {
577  const char *schema = crm_element_value(root, XML_ATTR_VALIDATION);
578 
579  crm_err("CIB does not validate against %s", schema);
580  free_xml(root);
582  }
583 
584  /* Remember the parsed XML for later use */
585  in_mem_cib = root;
586  return pcmk_ok;
587 }
588 
589 int
590 cib_file_signon(cib_t * cib, const char *name, enum cib_conn_type type)
591 {
592  int rc = pcmk_ok;
593  cib_file_opaque_t *private = cib->variant_opaque;
594 
595  if (private->filename == NULL) {
596  rc = -EINVAL;
597  } else {
598  rc = load_file_cib(private->filename);
599  }
600 
601  if (rc == pcmk_ok) {
602  crm_debug("Opened connection to local file '%s' for %s",
603  private->filename, name);
605  cib->type = cib_command;
606 
607  } else {
608  crm_info("Connection to local file '%s' for %s failed: %s\n",
609  private->filename, name, pcmk_strerror(rc));
610  }
611  return rc;
612 }
613 
622 static int
623 cib_file_write_live(char *path)
624 {
625  uid_t uid = geteuid();
626  struct passwd *daemon_pwent;
627  char *sep = strrchr(path, '/');
628  const char *cib_dirname, *cib_filename;
629  int rc = 0;
630 
631  /* Get the desired uid/gid */
632  errno = 0;
633  daemon_pwent = getpwnam(CRM_DAEMON_USER);
634  if (daemon_pwent == NULL) {
635  crm_perror(LOG_ERR, "Could not find %s user", CRM_DAEMON_USER);
636  return -1;
637  }
638 
639  /* If we're root, we can change the ownership;
640  * if we're daemon, anything we create will be OK;
641  * otherwise, block access so we don't create wrong owner
642  */
643  if ((uid != 0) && (uid != daemon_pwent->pw_uid)) {
644  crm_perror(LOG_ERR, "Must be root or %s to modify live CIB",
646  return 0;
647  }
648 
649  /* fancy footwork to separate dirname from filename
650  * (we know the canonical name maps to the live CIB,
651  * but the given name might be relative, or symlinked)
652  */
653  if (sep == NULL) { /* no directory component specified */
654  cib_dirname = "./";
655  cib_filename = path;
656  } else if (sep == path) { /* given name is in / */
657  cib_dirname = "/";
658  cib_filename = path + 1;
659  } else { /* typical case; split given name into parts */
660  *sep = '\0';
661  cib_dirname = path;
662  cib_filename = sep + 1;
663  }
664 
665  /* if we're root, we want to update the file ownership */
666  if (uid == 0) {
667  cib_file_owner = daemon_pwent->pw_uid;
668  cib_file_group = daemon_pwent->pw_gid;
669  cib_do_chown = TRUE;
670  }
671 
672  /* write the file */
673  if (cib_file_write_with_digest(in_mem_cib, cib_dirname,
674  cib_filename) != pcmk_ok) {
675  rc = -1;
676  }
677 
678  /* turn off file ownership changes, for other callers */
679  if (uid == 0) {
680  cib_do_chown = FALSE;
681  }
682 
683  /* undo fancy stuff */
684  if ((sep != NULL) && (*sep == '\0')) {
685  *sep = '/';
686  }
687 
688  return rc;
689 }
690 
704 int
706 {
707  int rc = pcmk_ok;
708  cib_file_opaque_t *private = cib->variant_opaque;
709 
710  crm_debug("Disconnecting from the CIB manager");
711  cib->state = cib_disconnected;
712  cib->type = cib_no_connection;
713 
714  /* If the in-memory CIB has been changed, write it to disk */
715  if (pcmk_is_set(private->flags, cib_file_flag_dirty)) {
716 
717  /* If this is the live CIB, write it out with a digest */
718  if (pcmk_is_set(private->flags, cib_file_flag_live)) {
719  if (cib_file_write_live(private->filename) < 0) {
720  rc = pcmk_err_generic;
721  }
722 
723  /* Otherwise, it's a simple write */
724  } else {
725  gboolean do_bzip = pcmk__ends_with_ext(private->filename, ".bz2");
726 
727  if (write_xml_file(in_mem_cib, private->filename, do_bzip) <= 0) {
728  rc = pcmk_err_generic;
729  }
730  }
731 
732  if (rc == pcmk_ok) {
733  crm_info("Wrote CIB to %s", private->filename);
735  } else {
736  crm_err("Could not write CIB to %s", private->filename);
737  }
738  }
739 
740  /* Free the in-memory CIB */
741  free_xml(in_mem_cib);
742  in_mem_cib = NULL;
743  return rc;
744 }
745 
746 int
748 {
749  int rc = pcmk_ok;
750 
751  if (cib->state != cib_disconnected) {
752  rc = cib_file_signoff(cib);
753  }
754 
755  if (rc == pcmk_ok) {
756  cib_file_opaque_t *private = cib->variant_opaque;
757 
758  free(private->filename);
759  free(cib->cmds);
760  free(private);
761  free(cib);
762 
763  } else {
764  fprintf(stderr, "Couldn't sign off: %d\n", rc);
765  }
766 
767  return rc;
768 }
769 
770 struct cib_func_entry {
771  const char *op;
772  gboolean read_only;
773  cib_op_t fn;
774 };
775 
776 /* *INDENT-OFF* */
777 static struct cib_func_entry cib_file_ops[] = {
781  {CIB_OP_BUMP, FALSE, cib_process_bump},
787 };
788 /* *INDENT-ON* */
789 
790 int
791 cib_file_perform_op(cib_t * cib, const char *op, const char *host, const char *section,
792  xmlNode * data, xmlNode ** output_data, int call_options)
793 {
794  return cib_file_perform_op_delegate(cib, op, host, section, data, output_data, call_options,
795  NULL);
796 }
797 
798 int
799 cib_file_perform_op_delegate(cib_t * cib, const char *op, const char *host, const char *section,
800  xmlNode * data, xmlNode ** output_data, int call_options,
801  const char *user_name)
802 {
803  int rc = pcmk_ok;
804  char *effective_user = NULL;
805  gboolean query = FALSE;
806  gboolean changed = FALSE;
807  xmlNode *request = NULL;
808  xmlNode *output = NULL;
809  xmlNode *cib_diff = NULL;
810  xmlNode *result_cib = NULL;
811  cib_op_t *fn = NULL;
812  int lpc = 0;
813  static int max_msg_types = PCMK__NELEM(cib_file_ops);
814  cib_file_opaque_t *private = cib->variant_opaque;
815 
816  crm_info("Handling %s operation for %s as %s",
817  (op? op : "invalid"), (section? section : "entire CIB"),
818  (user_name? user_name : "default user"));
819 
820  cib__set_call_options(call_options, "file operation",
822 
823  if (cib->state == cib_disconnected) {
824  return -ENOTCONN;
825  }
826 
827  if (output_data != NULL) {
828  *output_data = NULL;
829  }
830 
831  if (op == NULL) {
832  return -EINVAL;
833  }
834 
835  for (lpc = 0; lpc < max_msg_types; lpc++) {
836  if (pcmk__str_eq(op, cib_file_ops[lpc].op, pcmk__str_casei)) {
837  fn = &(cib_file_ops[lpc].fn);
838  query = cib_file_ops[lpc].read_only;
839  break;
840  }
841  }
842 
843  if (fn == NULL) {
844  return -EPROTONOSUPPORT;
845  }
846 
847  cib->call_id++;
848  request = cib_create_op(cib->call_id, "dummy-token", op, host, section, data, call_options, user_name);
849  if(user_name) {
850  crm_xml_add(request, XML_ACL_TAG_USER, user_name);
851  }
852 
853  /* Mirror the logic in cib_prepare_common() */
854  if (section != NULL && data != NULL && pcmk__str_eq(crm_element_name(data), XML_TAG_CIB, pcmk__str_none)) {
855  data = pcmk_find_cib_element(data, section);
856  }
857 
858  rc = cib_perform_op(op, call_options, fn, query,
859  section, request, data, TRUE, &changed, in_mem_cib, &result_cib, &cib_diff,
860  &output);
861 
862  free_xml(request);
863  if (rc == -pcmk_err_schema_validation) {
864  validate_xml_verbose(result_cib);
865  }
866 
867  if (rc != pcmk_ok) {
868  free_xml(result_cib);
869 
870  } else if (query == FALSE) {
871  xml_log_patchset(LOG_DEBUG, "cib:diff", cib_diff);
872  free_xml(in_mem_cib);
873  in_mem_cib = result_cib;
875  }
876 
877  free_xml(cib_diff);
878 
879  if (cib->op_callback != NULL) {
880  cib->op_callback(NULL, cib->call_id, rc, output);
881  }
882 
883  if (output_data && output) {
884  if(output == in_mem_cib) {
885  *output_data = copy_xml(output);
886  } else {
887  *output_data = output;
888  }
889 
890  } else if(output != in_mem_cib) {
891  free_xml(output);
892  }
893 
894  free(effective_user);
895  return rc;
896 }
pcmk__cpg_host_t host
Definition: cpg.c:49
#define CIB_OP_CREATE
Definition: internal.h:24
xmlNode * find_xml_node(xmlNode *cib, const char *node_path, gboolean must_find)
Definition: xml.c:445
#define pcmk_err_schema_validation
Definition: results.h:73
A dumping ground.
const char * pcmk_strerror(int rc)
Definition: results.c:58
#define CIB_SERIES_MAX
Definition: cib_file.c:192
char data[0]
Definition: cpg.c:55
#define XML_ATTR_NUMUPDATES
Definition: msg_xml.h:128
const char * name
Definition: cib.c:24
int pcmk__read_series_sequence(const char *directory, const char *series, unsigned int *seq)
Definition: io.c:140
int cib_process_delete(const char *op, int options, const char *section, xmlNode *req, xmlNode *input, xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer)
Definition: cib_ops.c:280
const char * pcmk__xe_add_last_written(xmlNode *xe)
Definition: xml.c:1115
int cib_process_replace(const char *op, int options, const char *section, xmlNode *req, xmlNode *input, xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer)
Definition: cib_ops.c:168
int(* signoff)(cib_t *cib)
Definition: cib_types.h:76
int pcmk__write_sync(int fd, const char *contents)
Definition: io.c:487
int cib_process_erase(const char *op, int options, const char *section, xmlNode *req, xmlNode *input, xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer)
Definition: cib_ops.c:75
int cib_file_perform_op_delegate(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_file.c:799
bool pcmk__verify_digest(xmlNode *input, const char *expected)
Definition: digest.c:220
int cib_process_bump(const char *op, int options, const char *section, xmlNode *req, xmlNode *input, xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer)
Definition: cib_ops.c:127
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:323
#define pcmk_err_generic
Definition: results.h:71
int write_xml_file(xmlNode *xml_node, const char *filename, gboolean compress)
Write XML to a file.
Definition: xml.c:1300
#define CRM_LOG_ASSERT(expr)
Definition: logging.h:210
int(* inputfd)(cib_t *cib)
Definition: cib_types.h:89
enum crm_ais_msg_types type
Definition: cpg.c:48
int cib_file_write_with_digest(xmlNode *cib_root, const char *cib_dirname, const char *cib_filename)
Definition: cib_file.c:362
xmlNode * filename2xml(const char *filename)
Definition: xml.c:1045
struct cib_file_opaque_s cib_file_opaque_t
const char * pcmk_rc_str(int rc)
Get a user-friendly description of a return code.
Definition: results.c:370
#define pcmk_err_cib_backup
Definition: results.h:79
#define CIB_SERIES_BZIP
Definition: cib_file.c:193
char * pcmk__series_filename(const char *directory, const char *series, int sequence, bool bzip)
Definition: io.c:121
#define XML_ATTR_GENERATION
Definition: msg_xml.h:126
gboolean validate_xml(xmlNode *xml_blob, const char *validation, gboolean to_logs)
Definition: schemas.c:698
#define CIB_OP_BUMP
Definition: internal.h:22
gboolean validate_xml_verbose(xmlNode *xml_blob)
Definition: schemas.c:670
cib_file_flags
Definition: cib_file.c:32
xmlNode * cib_create_op(int call_id, const char *token, const char *op, const char *host, const char *section, xmlNode *data, int call_options, const char *user_name)
Definition: cib_utils.c:437
#define CIB_SERIES
Definition: cib_file.c:191
int cib_file_perform_op(cib_t *cib, const char *op, const char *host, const char *section, xmlNode *data, xmlNode **output_data, int call_options)
Definition: cib_file.c:791
xmlNode * copy_xml(xmlNode *src_node)
Definition: xml.c:830
cib_t * cib_new_variant(void)
Definition: cib_client.c:352
int(* set_connection_dnotify)(cib_t *cib, void(*dnotify)(gpointer user_data))
Definition: cib_types.h:87
#define crm_warn(fmt, args...)
Definition: logging.h:359
#define pcmk_err_cib_save
Definition: results.h:80
cib_api_operations_t * cmds
Definition: cib_types.h:147
#define crm_debug(fmt, args...)
Definition: logging.h:363
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:584
#define CIB_OP_APPLY_DIFF
Definition: internal.h:29
cib_conn_type
Definition: cib_types.h:42
int(* signon)(cib_t *cib, const char *name, enum cib_conn_type type)
Definition: cib_types.h:73
int pcmk__real_path(const char *path, char **resolved_path)
Definition: io.c:85
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition: nvpair.c:529
int cib_file_signoff(cib_t *cib)
Definition: cib_file.c:705
xmlNode * pcmk_find_cib_element(xmlNode *cib, const char *element_name)
Find an element in the CIB.
Definition: cib.c:153
int(* cib_op_t)(const char *, int, const char *, xmlNode *, xmlNode *, xmlNode *, xmlNode **, xmlNode **)
Definition: internal.h:122
#define CIB_OP_QUERY
Definition: internal.h:23
#define crm_trace(fmt, args...)
Definition: logging.h:364
char * crm_strdup_printf(char const *format,...) G_GNUC_PRINTF(1
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition: util.h:122
void(* op_callback)(const xmlNode *msg, int call_id, int rc, xmlNode *output)
Definition: cib_types.h:145
Wrappers for and extensions to libxml2.
xmlNode * create_xml_node(xmlNode *parent, const char *name)
Definition: xml.c:696
#define PCMK__NELEM(a)
Definition: internal.h:42
#define XML_ATTR_VALIDATION
Definition: msg_xml.h:120
int pcmk__file_contents(const char *filename, char **contents)
Definition: io.c:431
#define CRM_DAEMON_USER
Definition: config.h:30
#define pcmk_err_cib_modified
Definition: results.h:78
#define CIB_LIVE_NAME
Definition: cib_file.c:197
void free_xml(xmlNode *child)
Definition: xml.c:824
#define cib_clear_file_flags(cibfile, flags_to_clear)
Definition: cib_file.c:51
#define CRM_CONFIG_DIR
Definition: config.h:17
#define CIB_OP_ERASE
Definition: internal.h:27
int(* register_notification)(cib_t *cib, const char *callback, int enabled)
Definition: cib_types.h:119
char * calculate_on_disk_digest(xmlNode *local_cib)
Calculate and return digest of XML tree, suitable for storing on disk.
Definition: digest.c:151
void pcmk__write_series_sequence(const char *directory, const char *series, unsigned int sequence, int max)
Definition: io.c:187
void * variant_opaque
Definition: cib_types.h:141
int cib_process_query(const char *op, int options, const char *section, xmlNode *req, xmlNode *input, xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer)
Definition: cib_ops.c:30
#define XML_TAG_CIB
Definition: msg_xml.h:115
#define cib_set_file_flags(cibfile, flags_to_set)
Definition: cib_file.c:42
int cib_file_read_and_verify(const char *filename, const char *sigfile, xmlNode **root)
Definition: cib_file.c:141
#define cib__set_call_options(cib_call_opts, call_for, flags_to_set)
Definition: internal.h:110
cib_t * cib_file_new(const char *cib_location)
Definition: cib_file.c:495
#define crm_perror(level, fmt, args...)
Send a system error message to both the log and stderr.
Definition: logging.h:309
const char * path
Definition: cib.c:26
#define crm_err(fmt, args...)
Definition: logging.h:358
#define CRM_ASSERT(expr)
Definition: results.h:42
#define CIB_OP_DELETE
Definition: internal.h:26
int cib_perform_op(const char *op, int call_options, cib_op_t *fn, gboolean is_query, const char *section, xmlNode *req, xmlNode *input, gboolean manage_counters, gboolean *config_changed, xmlNode *current_cib, xmlNode **result_cib, xmlNode **diff, xmlNode **output)
Definition: cib_utils.c:145
#define CIB_OP_MODIFY
Definition: internal.h:25
#define XML_ATTR_GENERATION_ADMIN
Definition: msg_xml.h:127
enum cib_variant variant
Definition: cib_types.h:137
int pcmk__chown_series_sequence(const char *directory, const char *series, uid_t uid, gid_t gid)
Definition: io.c:237
#define CIB_OP_REPLACE
Definition: internal.h:28
void pcmk__sync_directory(const char *name)
Definition: io.c:395
#define pcmk_ok
Definition: results.h:68
IPC interface to Pacemaker daemons.
int cib_file_free(cib_t *cib)
Definition: cib_file.c:747
#define XML_CIB_TAG_STATUS
Definition: msg_xml.h:185
int call_id
Definition: cib_types.h:139
int cib_file_signon(cib_t *cib, const char *name, enum cib_conn_type type)
Definition: cib_file.c:590
#define XML_ACL_TAG_USER
Definition: msg_xml.h:414
void xml_log_patchset(uint8_t level, const char *function, xmlNode *xml)
Definition: patchset.c:457
int write_xml_fd(xmlNode *xml_node, const char *filename, int fd, gboolean compress)
Write XML to a file descriptor.
Definition: xml.c:1272
enum cib_conn_type type
Definition: cib_types.h:136
enum cib_state state
Definition: cib_types.h:135
int(* free)(cib_t *cib)
Definition: cib_types.h:77
#define pcmk_err_cib_corrupt
Definition: results.h:82
int cib_process_upgrade(const char *op, int options, const char *section, xmlNode *req, xmlNode *input, xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer)
Definition: cib_ops.c:92
#define crm_info(fmt, args...)
Definition: logging.h:361
int cib_process_modify(const char *op, int options, const char *section, xmlNode *req, xmlNode *input, xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer)
Definition: cib_ops.c:315
bool pcmk__ends_with_ext(const char *s, const char *match)
Definition: strings.c:563
uint64_t flags
Definition: remote.c:149
int cib_process_create(const char *op, int options, const char *section, xmlNode *req, xmlNode *input, xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer)
Definition: cib_ops.c:519
void * delegate_fn
Definition: cib_types.h:142
#define CIB_OP_UPGRADE
Definition: internal.h:30