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