pacemaker  2.0.4-2deceaa
Scalable High-Availability cluster resource manager
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
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 <stdio.h>
14 #include <stdarg.h>
15 #include <string.h>
16 #include <pwd.h>
17 
18 #include <sys/stat.h>
19 #include <sys/types.h>
20 #include <glib.h>
21 
22 #include <crm/crm.h>
23 #include <crm/cib/internal.h>
24 #include <crm/msg_xml.h>
25 #include <crm/common/ipc.h>
26 #include <crm/common/xml.h>
27 
28 #define CIB_FLAG_DIRTY 0x00001
29 #define CIB_FLAG_LIVE 0x00002
30 
31 typedef struct cib_file_opaque_s {
32  int flags;
33  char *filename;
34 
36 
37 int cib_file_perform_op(cib_t * cib, const char *op, const char *host, const char *section,
38  xmlNode * data, xmlNode ** output_data, int call_options);
39 
40 int cib_file_perform_op_delegate(cib_t * cib, const char *op, const char *host, const char *section,
41  xmlNode * data, xmlNode ** output_data, int call_options,
42  const char *user_name);
43 
44 int cib_file_signon(cib_t * cib, const char *name, enum cib_conn_type type);
45 int cib_file_signoff(cib_t * cib);
46 int cib_file_free(cib_t * cib);
47 
48 static int
49 cib_file_inputfd(cib_t * cib)
50 {
51  return -EPROTONOSUPPORT;
52 }
53 
54 static int
55 cib_file_set_connection_dnotify(cib_t * cib, void (*dnotify) (gpointer user_data))
56 {
57  return -EPROTONOSUPPORT;
58 }
59 
60 static int
61 cib_file_register_notification(cib_t * cib, const char *callback, int enabled)
62 {
63  return -EPROTONOSUPPORT;
64 }
65 
75 static gboolean
76 cib_file_verify_digest(xmlNode *root, const char *sigfile)
77 {
78  gboolean passed = FALSE;
79  char *expected;
80  int rc = pcmk__file_contents(sigfile, &expected);
81 
82  switch (rc) {
83  case pcmk_rc_ok:
84  if (expected == NULL) {
85  crm_err("On-disk digest at %s is empty", sigfile);
86  return FALSE;
87  }
88  break;
89  case ENOENT:
90  crm_warn("No on-disk digest present at %s", sigfile);
91  return TRUE;
92  default:
93  crm_err("Could not read on-disk digest from %s: %s",
94  sigfile, pcmk_rc_str(rc));
95  return FALSE;
96  }
97  passed = pcmk__verify_digest(root, expected);
98  free(expected);
99  return passed;
100 }
101 
117 int
118 cib_file_read_and_verify(const char *filename, const char *sigfile, xmlNode **root)
119 {
120  int s_res;
121  struct stat buf;
122  char *local_sigfile = NULL;
123  xmlNode *local_root = NULL;
124 
125  CRM_ASSERT(filename != NULL);
126  if (root) {
127  *root = NULL;
128  }
129 
130  /* Verify that file exists and its size is nonzero */
131  s_res = stat(filename, &buf);
132  if (s_res < 0) {
133  crm_perror(LOG_WARNING, "Could not verify cluster configuration file %s", filename);
134  return -errno;
135  } else if (buf.st_size == 0) {
136  crm_warn("Cluster configuration file %s is corrupt (size is zero)", filename);
137  return -pcmk_err_cib_corrupt;
138  }
139 
140  /* Parse XML */
141  local_root = filename2xml(filename);
142  if (local_root == NULL) {
143  crm_warn("Cluster configuration file %s is corrupt (unparseable as XML)", filename);
144  return -pcmk_err_cib_corrupt;
145  }
146 
147  /* If sigfile is not specified, use original file name plus .sig */
148  if (sigfile == NULL) {
149  sigfile = local_sigfile = crm_strdup_printf("%s.sig", filename);
150  }
151 
152  /* Verify that digests match */
153  if (cib_file_verify_digest(local_root, sigfile) == FALSE) {
154  free(local_sigfile);
155  free_xml(local_root);
156  return -pcmk_err_cib_modified;
157  }
158 
159  free(local_sigfile);
160  if (root) {
161  *root = local_root;
162  } else {
163  free_xml(local_root);
164  }
165  return pcmk_ok;
166 }
167 
168 #define CIB_SERIES "cib"
169 #define CIB_SERIES_MAX 100
170 #define CIB_SERIES_BZIP FALSE /* Must be false because archived copies are
171  created with hard links
172  */
173 
174 #define CIB_LIVE_NAME CIB_SERIES ".xml"
175 
184 static gboolean
185 cib_file_is_live(const char *filename)
186 {
187  gboolean same = FALSE;
188 
189  if (filename != NULL) {
190  // Canonicalize file names for true comparison
191  char *real_filename = NULL;
192 
193  if (pcmk__real_path(filename, &real_filename) == pcmk_rc_ok) {
194  char *real_livename = NULL;
195 
197  &real_livename) == pcmk_rc_ok) {
198  same = !strcmp(real_filename, real_livename);
199  free(real_livename);
200  }
201  free(real_filename);
202  }
203  }
204  return same;
205 }
206 
207 /* cib_file_backup() and cib_file_write_with_digest() need to chown the
208  * written files only in limited circumstances, so these variables allow
209  * that to be indicated without affecting external callers
210  */
211 static uid_t cib_file_owner = 0;
212 static uid_t cib_file_group = 0;
213 static gboolean cib_do_chown = FALSE;
214 
224 static int
225 cib_file_backup(const char *cib_dirname, const char *cib_filename)
226 {
227  int rc = 0;
228  unsigned int seq;
229  char *cib_path = crm_strdup_printf("%s/%s", cib_dirname, cib_filename);
230  char *cib_digest = crm_strdup_printf("%s.sig", cib_path);
231  char *backup_path;
232  char *backup_digest;
233 
234  // Determine backup and digest file names
235  if (pcmk__read_series_sequence(cib_dirname, CIB_SERIES,
236  &seq) != pcmk_rc_ok) {
237  // @TODO maybe handle errors better ...
238  seq = 0;
239  }
240  backup_path = pcmk__series_filename(cib_dirname, CIB_SERIES, seq,
242  backup_digest = crm_strdup_printf("%s.sig", backup_path);
243 
244  /* Remove the old backups if they exist */
245  unlink(backup_path);
246  unlink(backup_digest);
247 
248  /* Back up the CIB, by hard-linking it to the backup name */
249  if ((link(cib_path, backup_path) < 0) && (errno != ENOENT)) {
250  crm_perror(LOG_ERR, "Could not archive %s by linking to %s",
251  cib_path, backup_path);
252  rc = -1;
253 
254  /* Back up the CIB signature similarly */
255  } else if ((link(cib_digest, backup_digest) < 0) && (errno != ENOENT)) {
256  crm_perror(LOG_ERR, "Could not archive %s by linking to %s",
257  cib_digest, backup_digest);
258  rc = -1;
259 
260  /* Update the last counter and ensure everything is sync'd to media */
261  } else {
262  pcmk__write_series_sequence(cib_dirname, CIB_SERIES, ++seq,
264  if (cib_do_chown) {
265  int rc2;
266 
267  if ((chown(backup_path, cib_file_owner, cib_file_group) < 0)
268  && (errno != ENOENT)) {
269  crm_perror(LOG_ERR, "Could not set owner of %s", backup_path);
270  rc = -1;
271  }
272  if ((chown(backup_digest, cib_file_owner, cib_file_group) < 0)
273  && (errno != ENOENT)) {
274  crm_perror(LOG_ERR, "Could not set owner of %s", backup_digest);
275  rc = -1;
276  }
277  rc2 = pcmk__chown_series_sequence(cib_dirname, CIB_SERIES,
278  cib_file_owner, cib_file_group);
279  if (rc2 != pcmk_rc_ok) {
280  crm_err("Could not set owner of sequence file in %s: %s",
281  cib_dirname, pcmk_rc_str(rc2));
282  rc = -1;
283  }
284  }
285  pcmk__sync_directory(cib_dirname);
286  crm_info("Archived previous version as %s", backup_path);
287  }
288 
289  free(cib_path);
290  free(cib_digest);
291  free(backup_path);
292  free(backup_digest);
293  return rc;
294 }
295 
307 static void
308 cib_file_prepare_xml(xmlNode *root)
309 {
310  xmlNode *cib_status_root = NULL;
311 
312  /* Always write out with num_updates=0 and current last-written timestamp */
313  crm_xml_add(root, XML_ATTR_NUMUPDATES, "0");
315 
316  /* Delete status section before writing to file, because
317  * we discard it on startup anyway, and users get confused by it */
318  cib_status_root = find_xml_node(root, XML_CIB_TAG_STATUS, TRUE);
319  CRM_LOG_ASSERT(cib_status_root != NULL);
320  if (cib_status_root != NULL) {
321  free_xml(cib_status_root);
322  }
323 }
324 
338 int
339 cib_file_write_with_digest(xmlNode *cib_root, const char *cib_dirname,
340  const char *cib_filename)
341 {
342  int exit_rc = pcmk_ok;
343  int rc, fd;
344  char *digest = NULL;
345 
346  /* Detect CIB version for diagnostic purposes */
347  const char *epoch = crm_element_value(cib_root, XML_ATTR_GENERATION);
348  const char *admin_epoch = crm_element_value(cib_root,
350 
351  /* Determine full CIB and signature pathnames */
352  char *cib_path = crm_strdup_printf("%s/%s", cib_dirname, cib_filename);
353  char *digest_path = crm_strdup_printf("%s.sig", cib_path);
354 
355  /* Create temporary file name patterns for writing out CIB and signature */
356  char *tmp_cib = crm_strdup_printf("%s/cib.XXXXXX", cib_dirname);
357  char *tmp_digest = crm_strdup_printf("%s/cib.XXXXXX", cib_dirname);
358 
359  CRM_ASSERT((cib_path != NULL) && (digest_path != NULL)
360  && (tmp_cib != NULL) && (tmp_digest != NULL));
361 
362  /* Ensure the admin didn't modify the existing CIB underneath us */
363  crm_trace("Reading cluster configuration file %s", cib_path);
364  rc = cib_file_read_and_verify(cib_path, NULL, NULL);
365  if ((rc != pcmk_ok) && (rc != -ENOENT)) {
366  crm_err("%s was manually modified while the cluster was active!",
367  cib_path);
368  exit_rc = pcmk_err_cib_modified;
369  goto cleanup;
370  }
371 
372  /* Back up the existing CIB */
373  if (cib_file_backup(cib_dirname, cib_filename) < 0) {
374  exit_rc = pcmk_err_cib_backup;
375  goto cleanup;
376  }
377 
378  crm_debug("Writing CIB to disk");
379  umask(S_IWGRP | S_IWOTH | S_IROTH);
380  cib_file_prepare_xml(cib_root);
381 
382  /* Write the CIB to a temporary file, so we can deploy (near) atomically */
383  fd = mkstemp(tmp_cib);
384  if (fd < 0) {
385  crm_perror(LOG_ERR, "Couldn't open temporary file %s for writing CIB",
386  tmp_cib);
387  exit_rc = pcmk_err_cib_save;
388  goto cleanup;
389  }
390 
391  /* Protect the temporary file */
392  if (fchmod(fd, S_IRUSR | S_IWUSR) < 0) {
393  crm_perror(LOG_ERR, "Couldn't protect temporary file %s for writing CIB",
394  tmp_cib);
395  exit_rc = pcmk_err_cib_save;
396  goto cleanup;
397  }
398  if (cib_do_chown && (fchown(fd, cib_file_owner, cib_file_group) < 0)) {
399  crm_perror(LOG_ERR, "Couldn't protect temporary file %s for writing CIB",
400  tmp_cib);
401  exit_rc = pcmk_err_cib_save;
402  goto cleanup;
403  }
404 
405  /* Write out the CIB */
406  if (write_xml_fd(cib_root, tmp_cib, fd, FALSE) <= 0) {
407  crm_err("Changes couldn't be written to %s", tmp_cib);
408  exit_rc = pcmk_err_cib_save;
409  goto cleanup;
410  }
411 
412  /* Calculate CIB digest */
413  digest = calculate_on_disk_digest(cib_root);
414  CRM_ASSERT(digest != NULL);
415  crm_info("Wrote version %s.%s.0 of the CIB to disk (digest: %s)",
416  (admin_epoch ? admin_epoch : "0"), (epoch ? epoch : "0"), digest);
417 
418  /* Write the CIB digest to a temporary file */
419  fd = mkstemp(tmp_digest);
420  if (fd < 0) {
421  crm_perror(LOG_ERR, "Could not create temporary file for CIB digest");
422  exit_rc = pcmk_err_cib_save;
423  goto cleanup;
424  }
425  if (cib_do_chown && (fchown(fd, cib_file_owner, cib_file_group) < 0)) {
426  crm_perror(LOG_ERR, "Couldn't protect temporary file %s for writing CIB",
427  tmp_cib);
428  exit_rc = pcmk_err_cib_save;
429  close(fd);
430  goto cleanup;
431  }
432  rc = pcmk__write_sync(fd, digest);
433  if (rc != pcmk_rc_ok) {
434  crm_err("Could not write digest to %s: %s",
435  tmp_digest, pcmk_rc_str(rc));
436  exit_rc = pcmk_err_cib_save;
437  close(fd);
438  goto cleanup;
439  }
440  close(fd);
441  crm_debug("Wrote digest %s to disk", digest);
442 
443  /* Verify that what we wrote is sane */
444  crm_info("Reading cluster configuration file %s (digest: %s)",
445  tmp_cib, tmp_digest);
446  rc = cib_file_read_and_verify(tmp_cib, tmp_digest, NULL);
447  CRM_ASSERT(rc == 0);
448 
449  /* Rename temporary files to live, and sync directory changes to media */
450  crm_debug("Activating %s", tmp_cib);
451  if (rename(tmp_cib, cib_path) < 0) {
452  crm_perror(LOG_ERR, "Couldn't rename %s as %s", tmp_cib, cib_path);
453  exit_rc = pcmk_err_cib_save;
454  }
455  if (rename(tmp_digest, digest_path) < 0) {
456  crm_perror(LOG_ERR, "Couldn't rename %s as %s", tmp_digest,
457  digest_path);
458  exit_rc = pcmk_err_cib_save;
459  }
460  pcmk__sync_directory(cib_dirname);
461 
462  cleanup:
463  free(cib_path);
464  free(digest_path);
465  free(digest);
466  free(tmp_digest);
467  free(tmp_cib);
468  return exit_rc;
469 }
470 
471 cib_t *
472 cib_file_new(const char *cib_location)
473 {
474  cib_file_opaque_t *private = NULL;
475  cib_t *cib = cib_new_variant();
476 
477  private = calloc(1, sizeof(cib_file_opaque_t));
478  CRM_ASSERT((cib != NULL) && (private != NULL));
479 
480  cib->variant = cib_file;
481  cib->variant_opaque = private;
482 
483  if (cib_location == NULL) {
484  cib_location = getenv("CIB_file");
485  }
486  private->flags = 0;
487  if (cib_file_is_live(cib_location)) {
488  set_bit(private->flags, CIB_FLAG_LIVE);
489  crm_trace("File %s detected as live CIB", cib_location);
490  }
491  private->filename = strdup(cib_location);
492 
493  /* assign variant specific ops */
495  cib->cmds->signon = cib_file_signon;
496  cib->cmds->signoff = cib_file_signoff;
497  cib->cmds->free = cib_file_free;
498  cib->cmds->inputfd = cib_file_inputfd;
499 
500  cib->cmds->register_notification = cib_file_register_notification;
501  cib->cmds->set_connection_dnotify = cib_file_set_connection_dnotify;
502 
503  return cib;
504 }
505 
506 static xmlNode *in_mem_cib = NULL;
507 
522 static int
523 load_file_cib(const char *filename)
524 {
525  struct stat buf;
526  xmlNode *root = NULL;
527 
528  /* Ensure file is readable */
529  if (stat(filename, &buf) < 0) {
530  return -ENXIO;
531  }
532 
533  /* Parse XML from file */
534  root = filename2xml(filename);
535  if (root == NULL) {
537  }
538 
539  /* Add a status section if not already present */
540  if (find_xml_node(root, XML_CIB_TAG_STATUS, FALSE) == NULL) {
542  }
543 
544  /* Validate XML against its specified schema */
545  if (validate_xml(root, NULL, TRUE) == FALSE) {
546  const char *schema = crm_element_value(root, XML_ATTR_VALIDATION);
547 
548  crm_err("CIB does not validate against %s", schema);
549  free_xml(root);
551  }
552 
553  /* Remember the parsed XML for later use */
554  in_mem_cib = root;
555  return pcmk_ok;
556 }
557 
558 int
559 cib_file_signon(cib_t * cib, const char *name, enum cib_conn_type type)
560 {
561  int rc = pcmk_ok;
562  cib_file_opaque_t *private = cib->variant_opaque;
563 
564  if (private->filename == NULL) {
565  rc = -EINVAL;
566  } else {
567  rc = load_file_cib(private->filename);
568  }
569 
570  if (rc == pcmk_ok) {
571  crm_debug("Opened connection to local file '%s' for %s",
572  private->filename, name);
574  cib->type = cib_command;
575 
576  } else {
577  crm_info("Connection to local file '%s' for %s failed: %s\n",
578  private->filename, name, pcmk_strerror(rc));
579  }
580  return rc;
581 }
582 
591 static int
592 cib_file_write_live(char *path)
593 {
594  uid_t uid = geteuid();
595  struct passwd *daemon_pwent;
596  char *sep = strrchr(path, '/');
597  const char *cib_dirname, *cib_filename;
598  int rc = 0;
599 
600  /* Get the desired uid/gid */
601  errno = 0;
602  daemon_pwent = getpwnam(CRM_DAEMON_USER);
603  if (daemon_pwent == NULL) {
604  crm_perror(LOG_ERR, "Could not find %s user", CRM_DAEMON_USER);
605  return -1;
606  }
607 
608  /* If we're root, we can change the ownership;
609  * if we're daemon, anything we create will be OK;
610  * otherwise, block access so we don't create wrong owner
611  */
612  if ((uid != 0) && (uid != daemon_pwent->pw_uid)) {
613  crm_perror(LOG_ERR, "Must be root or %s to modify live CIB",
615  return 0;
616  }
617 
618  /* fancy footwork to separate dirname from filename
619  * (we know the canonical name maps to the live CIB,
620  * but the given name might be relative, or symlinked)
621  */
622  if (sep == NULL) { /* no directory component specified */
623  cib_dirname = "./";
624  cib_filename = path;
625  } else if (sep == path) { /* given name is in / */
626  cib_dirname = "/";
627  cib_filename = path + 1;
628  } else { /* typical case; split given name into parts */
629  *sep = '\0';
630  cib_dirname = path;
631  cib_filename = sep + 1;
632  }
633 
634  /* if we're root, we want to update the file ownership */
635  if (uid == 0) {
636  cib_file_owner = daemon_pwent->pw_uid;
637  cib_file_group = daemon_pwent->pw_gid;
638  cib_do_chown = TRUE;
639  }
640 
641  /* write the file */
642  if (cib_file_write_with_digest(in_mem_cib, cib_dirname,
643  cib_filename) != pcmk_ok) {
644  rc = -1;
645  }
646 
647  /* turn off file ownership changes, for other callers */
648  if (uid == 0) {
649  cib_do_chown = FALSE;
650  }
651 
652  /* undo fancy stuff */
653  if ((sep != NULL) && (*sep == '\0')) {
654  *sep = '/';
655  }
656 
657  return rc;
658 }
659 
673 int
675 {
676  int rc = pcmk_ok;
677  cib_file_opaque_t *private = cib->variant_opaque;
678 
679  crm_debug("Disconnecting from the CIB manager");
680  cib->state = cib_disconnected;
681  cib->type = cib_no_connection;
682 
683  /* If the in-memory CIB has been changed, write it to disk */
684  if (is_set(private->flags, CIB_FLAG_DIRTY)) {
685 
686  /* If this is the live CIB, write it out with a digest */
687  if (is_set(private->flags, CIB_FLAG_LIVE)) {
688  if (cib_file_write_live(private->filename) < 0) {
689  rc = pcmk_err_generic;
690  }
691 
692  /* Otherwise, it's a simple write */
693  } else {
694  gboolean do_bzip = pcmk__ends_with_ext(private->filename, ".bz2");
695 
696  if (write_xml_file(in_mem_cib, private->filename, do_bzip) <= 0) {
697  rc = pcmk_err_generic;
698  }
699  }
700 
701  if (rc == pcmk_ok) {
702  crm_info("Wrote CIB to %s", private->filename);
703  clear_bit(private->flags, CIB_FLAG_DIRTY);
704  } else {
705  crm_err("Could not write CIB to %s", private->filename);
706  }
707  }
708 
709  /* Free the in-memory CIB */
710  free_xml(in_mem_cib);
711  in_mem_cib = NULL;
712  return rc;
713 }
714 
715 int
717 {
718  int rc = pcmk_ok;
719 
720  if (cib->state != cib_disconnected) {
721  rc = cib_file_signoff(cib);
722  }
723 
724  if (rc == pcmk_ok) {
725  cib_file_opaque_t *private = cib->variant_opaque;
726 
727  free(private->filename);
728  free(cib->cmds);
729  free(private);
730  free(cib);
731 
732  } else {
733  fprintf(stderr, "Couldn't sign off: %d\n", rc);
734  }
735 
736  return rc;
737 }
738 
739 struct cib_func_entry {
740  const char *op;
741  gboolean read_only;
742  cib_op_t fn;
743 };
744 
745 /* *INDENT-OFF* */
746 static struct cib_func_entry cib_file_ops[] = {
750  {CIB_OP_BUMP, FALSE, cib_process_bump},
756 };
757 /* *INDENT-ON* */
758 
759 int
760 cib_file_perform_op(cib_t * cib, const char *op, const char *host, const char *section,
761  xmlNode * data, xmlNode ** output_data, int call_options)
762 {
763  return cib_file_perform_op_delegate(cib, op, host, section, data, output_data, call_options,
764  NULL);
765 }
766 
767 int
768 cib_file_perform_op_delegate(cib_t * cib, const char *op, const char *host, const char *section,
769  xmlNode * data, xmlNode ** output_data, int call_options,
770  const char *user_name)
771 {
772  int rc = pcmk_ok;
773  char *effective_user = NULL;
774  gboolean query = FALSE;
775  gboolean changed = FALSE;
776  xmlNode *request = NULL;
777  xmlNode *output = NULL;
778  xmlNode *cib_diff = NULL;
779  xmlNode *result_cib = NULL;
780  cib_op_t *fn = NULL;
781  int lpc = 0;
782  static int max_msg_types = DIMOF(cib_file_ops);
783  cib_file_opaque_t *private = cib->variant_opaque;
784 
785 #if ENABLE_ACL
786  crm_info("Handling %s operation for %s as %s",
787  (op? op : "invalid"), (section? section : "entire CIB"),
788  (user_name? user_name : "default user"));
789 #else
790  crm_info("Handling %s operation for %s",
791  (op? op : "invalid"), (section? section : "entire CIB"));
792 #endif
793 
794  call_options |= (cib_no_mtime | cib_inhibit_bcast | cib_scope_local);
795 
796  if (cib->state == cib_disconnected) {
797  return -ENOTCONN;
798  }
799 
800  if (output_data != NULL) {
801  *output_data = NULL;
802  }
803 
804  if (op == NULL) {
805  return -EINVAL;
806  }
807 
808  for (lpc = 0; lpc < max_msg_types; lpc++) {
809  if (safe_str_eq(op, cib_file_ops[lpc].op)) {
810  fn = &(cib_file_ops[lpc].fn);
811  query = cib_file_ops[lpc].read_only;
812  break;
813  }
814  }
815 
816  if (fn == NULL) {
817  return -EPROTONOSUPPORT;
818  }
819 
820  cib->call_id++;
821  request = cib_create_op(cib->call_id, "dummy-token", op, host, section, data, call_options, user_name);
822 #if ENABLE_ACL
823  if(user_name) {
824  crm_xml_add(request, XML_ACL_TAG_USER, user_name);
825  }
826 #endif
827 
828  /* Mirror the logic in cib_prepare_common() */
829  if (section != NULL && data != NULL && crm_str_eq(crm_element_name(data), XML_TAG_CIB, TRUE)) {
830  data = get_object_root(section, data);
831  }
832 
833  rc = cib_perform_op(op, call_options, fn, query,
834  section, request, data, TRUE, &changed, in_mem_cib, &result_cib, &cib_diff,
835  &output);
836 
837  free_xml(request);
838  if (rc == -pcmk_err_schema_validation) {
839  validate_xml_verbose(result_cib);
840  }
841 
842  if (rc != pcmk_ok) {
843  free_xml(result_cib);
844 
845  } else if (query == FALSE) {
846  xml_log_patchset(LOG_DEBUG, "cib:diff", cib_diff);
847  free_xml(in_mem_cib);
848  in_mem_cib = result_cib;
849  set_bit(private->flags, CIB_FLAG_DIRTY);
850  }
851 
852  free_xml(cib_diff);
853 
854  if (cib->op_callback != NULL) {
855  cib->op_callback(NULL, cib->call_id, rc, output);
856  }
857 
858  if (output_data && output) {
859  if(output == in_mem_cib) {
860  *output_data = copy_xml(output);
861  } else {
862  *output_data = output;
863  }
864 
865  } else if(output != in_mem_cib) {
866  free_xml(output);
867  }
868 
869  free(effective_user);
870  return rc;
871 }
#define CIB_OP_CREATE
Definition: internal.h:23
xmlNode * find_xml_node(xmlNode *cib, const char *node_path, gboolean must_find)
Definition: xml.c:1764
#define pcmk_err_schema_validation
Definition: results.h:72
A dumping ground.
const char * pcmk_strerror(int rc)
Definition: results.c:55
#define CIB_SERIES_MAX
Definition: cib_file.c:169
#define XML_ATTR_NUMUPDATES
Definition: msg_xml.h:89
bool pcmk__ends_with_ext(const char *s, const char *match)
Definition: strings.c:437
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:277
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:165
int(* free)(cib_t *cib)
Definition: cib_types.h:77
xmlNode * get_object_root(const char *object_type, xmlNode *the_root)
Definition: cib_utils.c:144
int pcmk__write_sync(int fd, const char *contents)
Definition: io.c:506
int(* cib_op_t)(const char *, int, const char *, xmlNode *, xmlNode *, xmlNode *, xmlNode **, xmlNode **)
Definition: internal.h:101
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:72
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:768
bool pcmk__verify_digest(xmlNode *input, const char *expected)
Definition: digest.c:217
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:124
int(* inputfd)(cib_t *cib)
Definition: cib_types.h:89
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:316
#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:2606
AIS_Host host
Definition: internal.h:84
#define CRM_LOG_ASSERT(expr)
Definition: logging.h:219
#define CIB_FLAG_DIRTY
Definition: cib_file.c:28
#define clear_bit(word, bit)
Definition: crm_internal.h:69
xmlNode * filename2xml(const char *filename)
Definition: xml.c:2356
int(* set_connection_dnotify)(cib_t *cib, void(*dnotify)(gpointer user_data))
Definition: cib_types.h:87
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:413
#define pcmk_err_cib_backup
Definition: results.h:78
#define CIB_SERIES_BZIP
Definition: cib_file.c:170
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
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:499
#define CIB_SERIES
Definition: cib_file.c:168
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:760
xmlNode * copy_xml(xmlNode *src_node)
Definition: xml.c:2142
cib_t * cib_new_variant(void)
Definition: cib_client.c:345
#define crm_warn(fmt, args...)
Definition: logging.h:364
#define pcmk_err_cib_save
Definition: results.h:79
#define set_bit(word, bit)
Definition: crm_internal.h:68
int rc
Definition: pcmk_fence.c:34
cib_api_operations_t * cmds
Definition: cib_types.h:147
#define crm_debug(fmt, args...)
Definition: logging.h:368
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:577
#define CIB_OP_APPLY_DIFF
Definition: internal.h:28
cib_conn_type
Definition: cib_types.h:42
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:522
int cib_file_signoff(cib_t *cib)
Definition: cib_file.c:674
void(* op_callback)(const xmlNode *msg, int call_id, int rc, xmlNode *output)
Definition: cib_types.h:145
#define CIB_OP_QUERY
Definition: internal.h:22
#define crm_trace(fmt, args...)
Definition: logging.h:369
int(* register_notification)(cib_t *cib, const char *callback, int enabled)
Definition: cib_types.h:119
Wrappers for and extensions to libxml2.
xmlNode * create_xml_node(xmlNode *parent, const char *name)
Definition: xml.c:1976
#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:174
void free_xml(xmlNode *child)
Definition: xml.c:2136
gboolean crm_str_eq(const char *a, const char *b, gboolean use_case)
Definition: strings.c:326
#define CRM_CONFIG_DIR
Definition: config.h:20
#define CIB_OP_ERASE
Definition: internal.h:26
char * calculate_on_disk_digest(xmlNode *local_cib)
Calculate and return digest of XML tree, suitable for storing on disk.
Definition: digest.c:148
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
cib_t * cib_file_new(const char *filename)
Definition: cib_file.c:472
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:27
#define XML_TAG_CIB
Definition: msg_xml.h:76
int cib_file_write_with_digest(xmlNode *cib_root, const char *cib_dirname, const char *cib_filename)
Definition: cib_file.c:339
#define CIB_FLAG_LIVE
Definition: cib_file.c:29
int cib_file_read_and_verify(const char *filename, const char *sigfile, xmlNode **root)
Definition: cib_file.c:118
#define crm_perror(level, fmt, args...)
Send a system error message to both the log and stderr.
Definition: logging.h:314
#define crm_err(fmt, args...)
Definition: logging.h:363
#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:205
#define CIB_OP_MODIFY
Definition: internal.h:24
int(* signon)(cib_t *cib, const char *name, enum cib_conn_type type)
Definition: cib_types.h:73
#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
Wrappers for and extensions to libqb IPC.
int cib_file_free(cib_t *cib)
Definition: cib_file.c:716
#define XML_CIB_TAG_STATUS
Definition: msg_xml.h:139
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:559
int(* signoff)(cib_t *cib)
Definition: cib_types.h:76
#define XML_ACL_TAG_USER
Definition: msg_xml.h:370
void xml_log_patchset(uint8_t level, const char *function, xmlNode *xml)
Definition: xml.c:824
#define safe_str_eq(a, b)
Definition: util.h:65
int write_xml_fd(xmlNode *xml_node, const char *filename, int fd, gboolean compress)
Write XML to a file descriptor.
Definition: xml.c:2584
enum cib_conn_type type
Definition: cib_types.h:136
char * name
Definition: pcmk_fence.c:30
enum cib_state state
Definition: cib_types.h:135
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:89
#define crm_info(fmt, args...)
Definition: logging.h:366
const char * crm_xml_add_last_written(xmlNode *xml_node)
Definition: xml.c:2426
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:311
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:513
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