pacemaker  2.1.6-802a72226b
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-2023 the Pacemaker project contributors
4  *
5  * The version control history for this file may have further details.
6  *
7  * This source code is licensed under the GNU Lesser General Public License
8  * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
9  */
10 
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 
32 #define CIB_SERIES "cib"
33 #define CIB_SERIES_MAX 100
34 #define CIB_SERIES_BZIP FALSE /* Must be false because archived copies are
35  created with hard links
36  */
37 
38 #define CIB_LIVE_NAME CIB_SERIES ".xml"
39 
41  cib_file_flag_dirty = (1 << 0),
42  cib_file_flag_live = (1 << 1),
43 };
44 
45 typedef struct cib_file_opaque_s {
46  uint32_t flags; // Group of enum cib_file_flags
47  char *filename;
49 
50 struct cib_func_entry {
51  const char *op;
52  gboolean read_only;
53  cib_op_t fn;
54 };
55 
56 static struct cib_func_entry cib_file_ops[] = {
66 };
67 
68 static xmlNode *in_mem_cib = NULL;
69 
70 /* cib_file_backup() and cib_file_write_with_digest() need to chown the
71  * written files only in limited circumstances, so these variables allow
72  * that to be indicated without affecting external callers
73  */
74 static uid_t cib_file_owner = 0;
75 static uid_t cib_file_group = 0;
76 static gboolean cib_do_chown = FALSE;
77 
78 #define cib_set_file_flags(cibfile, flags_to_set) do { \
79  (cibfile)->flags = pcmk__set_flags_as(__func__, __LINE__, \
80  LOG_TRACE, "CIB file", \
81  cibfile->filename, \
82  (cibfile)->flags, \
83  (flags_to_set), \
84  #flags_to_set); \
85  } while (0)
86 
87 #define cib_clear_file_flags(cibfile, flags_to_clear) do { \
88  (cibfile)->flags = pcmk__clear_flags_as(__func__, __LINE__, \
89  LOG_TRACE, "CIB file", \
90  cibfile->filename, \
91  (cibfile)->flags, \
92  (flags_to_clear), \
93  #flags_to_clear); \
94  } while (0)
95 
104 static gboolean
105 cib_file_is_live(const char *filename)
106 {
107  gboolean same = FALSE;
108 
109  if (filename != NULL) {
110  // Canonicalize file names for true comparison
111  char *real_filename = NULL;
112 
113  if (pcmk__real_path(filename, &real_filename) == pcmk_rc_ok) {
114  char *real_livename = NULL;
115 
117  &real_livename) == pcmk_rc_ok) {
118  same = !strcmp(real_filename, real_livename);
119  free(real_livename);
120  }
121  free(real_filename);
122  }
123  }
124  return same;
125 }
126 
127 static int
128 cib_file_perform_op_delegate(cib_t *cib, const char *op, const char *host,
129  const char *section, xmlNode *data,
130  xmlNode **output_data, int call_options,
131  const char *user_name)
132 {
133  int rc = pcmk_ok;
134  char *effective_user = NULL;
135  gboolean query = FALSE;
136  gboolean changed = FALSE;
137  xmlNode *request = NULL;
138  xmlNode *output = NULL;
139  xmlNode *cib_diff = NULL;
140  xmlNode *result_cib = NULL;
141  cib_op_t *fn = NULL;
142  int lpc = 0;
143  static int max_msg_types = PCMK__NELEM(cib_file_ops);
144  cib_file_opaque_t *private = cib->variant_opaque;
145 
146  crm_info("Handling %s operation for %s as %s",
147  (op? op : "invalid"), (section? section : "entire CIB"),
148  (user_name? user_name : "default user"));
149 
150  cib__set_call_options(call_options, "file operation",
152 
153  if (cib->state == cib_disconnected) {
154  return -ENOTCONN;
155  }
156 
157  if (output_data != NULL) {
158  *output_data = NULL;
159  }
160 
161  if (op == NULL) {
162  return -EINVAL;
163  }
164 
165  for (lpc = 0; lpc < max_msg_types; lpc++) {
166  if (pcmk__str_eq(op, cib_file_ops[lpc].op, pcmk__str_casei)) {
167  fn = &(cib_file_ops[lpc].fn);
168  query = cib_file_ops[lpc].read_only;
169  break;
170  }
171  }
172 
173  if (fn == NULL) {
174  return -EPROTONOSUPPORT;
175  }
176 
177  cib->call_id++;
178  request = cib_create_op(cib->call_id, op, host, section, data, call_options,
179  user_name);
180  if(user_name) {
181  crm_xml_add(request, XML_ACL_TAG_USER, user_name);
182  }
183 
184  /* Mirror the logic in cib_prepare_common() */
185  if (section != NULL && data != NULL && pcmk__str_eq(crm_element_name(data), XML_TAG_CIB, pcmk__str_none)) {
186  data = pcmk_find_cib_element(data, section);
187  }
188 
189  rc = cib_perform_op(op, call_options, fn, query,
190  section, request, data, TRUE, &changed, in_mem_cib, &result_cib, &cib_diff,
191  &output);
192 
193  free_xml(request);
194  if (rc == -pcmk_err_schema_validation) {
195  validate_xml_verbose(result_cib);
196  }
197 
198  if (rc != pcmk_ok) {
199  free_xml(result_cib);
200 
201  } else if (query == FALSE) {
202  pcmk__output_t *out = NULL;
203 
205  CRM_CHECK(rc == pcmk_ok, goto done);
206 
207  pcmk__output_set_log_level(out, LOG_DEBUG);
208  rc = out->message(out, "xml-patchset", cib_diff);
209  out->finish(out, pcmk_rc2exitc(rc), true, NULL);
210  pcmk__output_free(out);
211  rc = pcmk_ok;
212 
213  free_xml(in_mem_cib);
214  in_mem_cib = result_cib;
216  }
217 
218  if (cib->op_callback != NULL) {
219  cib->op_callback(NULL, cib->call_id, rc, output);
220  }
221 
222  if ((output_data != NULL) && (output != NULL)) {
223  *output_data = (output == in_mem_cib)? copy_xml(output) : output;
224  }
225 
226 done:
227  free_xml(cib_diff);
228 
229  if ((output_data == NULL) && (output != in_mem_cib)) {
230  /* Don't free output if we're still using it. (output_data != NULL)
231  * means we may have assigned *output_data = output above.
232  */
233  free_xml(output);
234  }
235  free(effective_user);
236  return rc;
237 }
238 
253 static int
254 load_file_cib(const char *filename)
255 {
256  struct stat buf;
257  xmlNode *root = NULL;
258 
259  /* Ensure file is readable */
260  if (strcmp(filename, "-") && (stat(filename, &buf) < 0)) {
261  return -ENXIO;
262  }
263 
264  /* Parse XML from file */
265  root = filename2xml(filename);
266  if (root == NULL) {
268  }
269 
270  /* Add a status section if not already present */
271  if (find_xml_node(root, XML_CIB_TAG_STATUS, FALSE) == NULL) {
273  }
274 
275  /* Validate XML against its specified schema */
276  if (validate_xml(root, NULL, TRUE) == FALSE) {
277  const char *schema = crm_element_value(root, XML_ATTR_VALIDATION);
278 
279  crm_err("CIB does not validate against %s", schema);
280  free_xml(root);
282  }
283 
284  /* Remember the parsed XML for later use */
285  in_mem_cib = root;
286  return pcmk_ok;
287 }
288 
289 static int
290 cib_file_signon(cib_t *cib, const char *name, enum cib_conn_type type)
291 {
292  int rc = pcmk_ok;
293  cib_file_opaque_t *private = cib->variant_opaque;
294 
295  if (private->filename == NULL) {
296  rc = -EINVAL;
297  } else {
298  rc = load_file_cib(private->filename);
299  }
300 
301  if (rc == pcmk_ok) {
302  crm_debug("Opened connection to local file '%s' for %s",
303  private->filename, name);
305  cib->type = cib_command;
306 
307  } else {
308  crm_info("Connection to local file '%s' for %s failed: %s\n",
309  private->filename, name, pcmk_strerror(rc));
310  }
311  return rc;
312 }
313 
322 static int
323 cib_file_write_live(char *path)
324 {
325  uid_t uid = geteuid();
326  struct passwd *daemon_pwent;
327  char *sep = strrchr(path, '/');
328  const char *cib_dirname, *cib_filename;
329  int rc = 0;
330 
331  /* Get the desired uid/gid */
332  errno = 0;
333  daemon_pwent = getpwnam(CRM_DAEMON_USER);
334  if (daemon_pwent == NULL) {
335  crm_perror(LOG_ERR, "Could not find %s user", CRM_DAEMON_USER);
336  return -1;
337  }
338 
339  /* If we're root, we can change the ownership;
340  * if we're daemon, anything we create will be OK;
341  * otherwise, block access so we don't create wrong owner
342  */
343  if ((uid != 0) && (uid != daemon_pwent->pw_uid)) {
344  crm_perror(LOG_ERR, "Must be root or %s to modify live CIB",
346  return 0;
347  }
348 
349  /* fancy footwork to separate dirname from filename
350  * (we know the canonical name maps to the live CIB,
351  * but the given name might be relative, or symlinked)
352  */
353  if (sep == NULL) { /* no directory component specified */
354  cib_dirname = "./";
355  cib_filename = path;
356  } else if (sep == path) { /* given name is in / */
357  cib_dirname = "/";
358  cib_filename = path + 1;
359  } else { /* typical case; split given name into parts */
360  *sep = '\0';
361  cib_dirname = path;
362  cib_filename = sep + 1;
363  }
364 
365  /* if we're root, we want to update the file ownership */
366  if (uid == 0) {
367  cib_file_owner = daemon_pwent->pw_uid;
368  cib_file_group = daemon_pwent->pw_gid;
369  cib_do_chown = TRUE;
370  }
371 
372  /* write the file */
373  if (cib_file_write_with_digest(in_mem_cib, cib_dirname,
374  cib_filename) != pcmk_ok) {
375  rc = -1;
376  }
377 
378  /* turn off file ownership changes, for other callers */
379  if (uid == 0) {
380  cib_do_chown = FALSE;
381  }
382 
383  /* undo fancy stuff */
384  if ((sep != NULL) && (*sep == '\0')) {
385  *sep = '/';
386  }
387 
388  return rc;
389 }
390 
404 static int
405 cib_file_signoff(cib_t *cib)
406 {
407  int rc = pcmk_ok;
408  cib_file_opaque_t *private = cib->variant_opaque;
409 
410  crm_debug("Disconnecting from the CIB manager");
411  cib->state = cib_disconnected;
412  cib->type = cib_no_connection;
413 
414  /* If the in-memory CIB has been changed, write it to disk */
415  if (pcmk_is_set(private->flags, cib_file_flag_dirty)) {
416 
417  /* If this is the live CIB, write it out with a digest */
418  if (pcmk_is_set(private->flags, cib_file_flag_live)) {
419  if (cib_file_write_live(private->filename) < 0) {
420  rc = pcmk_err_generic;
421  }
422 
423  /* Otherwise, it's a simple write */
424  } else {
425  gboolean do_bzip = pcmk__ends_with_ext(private->filename, ".bz2");
426 
427  if (write_xml_file(in_mem_cib, private->filename, do_bzip) <= 0) {
428  rc = pcmk_err_generic;
429  }
430  }
431 
432  if (rc == pcmk_ok) {
433  crm_info("Wrote CIB to %s", private->filename);
435  } else {
436  crm_err("Could not write CIB to %s", private->filename);
437  }
438  }
439 
440  /* Free the in-memory CIB */
441  free_xml(in_mem_cib);
442  in_mem_cib = NULL;
443  return rc;
444 }
445 
446 static int
447 cib_file_free(cib_t *cib)
448 {
449  int rc = pcmk_ok;
450 
451  if (cib->state != cib_disconnected) {
452  rc = cib_file_signoff(cib);
453  }
454 
455  if (rc == pcmk_ok) {
456  cib_file_opaque_t *private = cib->variant_opaque;
457 
458  free(private->filename);
459  free(cib->cmds);
460  free(private);
461  free(cib);
462 
463  } else {
464  fprintf(stderr, "Couldn't sign off: %d\n", rc);
465  }
466 
467  return rc;
468 }
469 
470 static int
471 cib_file_inputfd(cib_t *cib)
472 {
473  return -EPROTONOSUPPORT;
474 }
475 
476 static int
477 cib_file_register_notification(cib_t *cib, const char *callback, int enabled)
478 {
479  return -EPROTONOSUPPORT;
480 }
481 
482 static int
483 cib_file_set_connection_dnotify(cib_t *cib,
484  void (*dnotify) (gpointer user_data))
485 {
486  return -EPROTONOSUPPORT;
487 }
488 
504 static int
505 cib_file_client_id(const cib_t *cib, const char **async_id,
506  const char **sync_id)
507 {
508  if (async_id != NULL) {
509  *async_id = NULL;
510  }
511  if (sync_id != NULL) {
512  *sync_id = NULL;
513  }
514  return -EPROTONOSUPPORT;
515 }
516 
517 cib_t *
518 cib_file_new(const char *cib_location)
519 {
520  cib_file_opaque_t *private = NULL;
521  cib_t *cib = cib_new_variant();
522 
523  if (cib == NULL) {
524  return NULL;
525  }
526 
527  private = calloc(1, sizeof(cib_file_opaque_t));
528 
529  if (private == NULL) {
530  free(cib);
531  return NULL;
532  }
533 
534  cib->variant = cib_file;
535  cib->variant_opaque = private;
536 
537  if (cib_location == NULL) {
538  cib_location = getenv("CIB_file");
539  CRM_CHECK(cib_location != NULL, return NULL); // Shouldn't be possible
540  }
541  private->flags = 0;
542  if (cib_file_is_live(cib_location)) {
544  crm_trace("File %s detected as live CIB", cib_location);
545  }
546  private->filename = strdup(cib_location);
547 
548  /* assign variant specific ops */
549  cib->delegate_fn = cib_file_perform_op_delegate;
550  cib->cmds->signon = cib_file_signon;
551  cib->cmds->signoff = cib_file_signoff;
552  cib->cmds->free = cib_file_free;
553  cib->cmds->inputfd = cib_file_inputfd;
554 
555  cib->cmds->register_notification = cib_file_register_notification;
556  cib->cmds->set_connection_dnotify = cib_file_set_connection_dnotify;
557 
558  cib->cmds->client_id = cib_file_client_id;
559 
560  return cib;
561 }
562 
572 static gboolean
573 cib_file_verify_digest(xmlNode *root, const char *sigfile)
574 {
575  gboolean passed = FALSE;
576  char *expected;
577  int rc = pcmk__file_contents(sigfile, &expected);
578 
579  switch (rc) {
580  case pcmk_rc_ok:
581  if (expected == NULL) {
582  crm_err("On-disk digest at %s is empty", sigfile);
583  return FALSE;
584  }
585  break;
586  case ENOENT:
587  crm_warn("No on-disk digest present at %s", sigfile);
588  return TRUE;
589  default:
590  crm_err("Could not read on-disk digest from %s: %s",
591  sigfile, pcmk_rc_str(rc));
592  return FALSE;
593  }
594  passed = pcmk__verify_digest(root, expected);
595  free(expected);
596  return passed;
597 }
598 
614 int
615 cib_file_read_and_verify(const char *filename, const char *sigfile, xmlNode **root)
616 {
617  int s_res;
618  struct stat buf;
619  char *local_sigfile = NULL;
620  xmlNode *local_root = NULL;
621 
622  CRM_ASSERT(filename != NULL);
623  if (root) {
624  *root = NULL;
625  }
626 
627  /* Verify that file exists and its size is nonzero */
628  s_res = stat(filename, &buf);
629  if (s_res < 0) {
630  crm_perror(LOG_WARNING, "Could not verify cluster configuration file %s", filename);
631  return -errno;
632  } else if (buf.st_size == 0) {
633  crm_warn("Cluster configuration file %s is corrupt (size is zero)", filename);
634  return -pcmk_err_cib_corrupt;
635  }
636 
637  /* Parse XML */
638  local_root = filename2xml(filename);
639  if (local_root == NULL) {
640  crm_warn("Cluster configuration file %s is corrupt (unparseable as XML)", filename);
641  return -pcmk_err_cib_corrupt;
642  }
643 
644  /* If sigfile is not specified, use original file name plus .sig */
645  if (sigfile == NULL) {
646  sigfile = local_sigfile = crm_strdup_printf("%s.sig", filename);
647  }
648 
649  /* Verify that digests match */
650  if (cib_file_verify_digest(local_root, sigfile) == FALSE) {
651  free(local_sigfile);
652  free_xml(local_root);
653  return -pcmk_err_cib_modified;
654  }
655 
656  free(local_sigfile);
657  if (root) {
658  *root = local_root;
659  } else {
660  free_xml(local_root);
661  }
662  return pcmk_ok;
663 }
664 
674 static int
675 cib_file_backup(const char *cib_dirname, const char *cib_filename)
676 {
677  int rc = 0;
678  unsigned int seq;
679  char *cib_path = crm_strdup_printf("%s/%s", cib_dirname, cib_filename);
680  char *cib_digest = crm_strdup_printf("%s.sig", cib_path);
681  char *backup_path;
682  char *backup_digest;
683 
684  // Determine backup and digest file names
685  if (pcmk__read_series_sequence(cib_dirname, CIB_SERIES,
686  &seq) != pcmk_rc_ok) {
687  // @TODO maybe handle errors better ...
688  seq = 0;
689  }
690  backup_path = pcmk__series_filename(cib_dirname, CIB_SERIES, seq,
692  backup_digest = crm_strdup_printf("%s.sig", backup_path);
693 
694  /* Remove the old backups if they exist */
695  unlink(backup_path);
696  unlink(backup_digest);
697 
698  /* Back up the CIB, by hard-linking it to the backup name */
699  if ((link(cib_path, backup_path) < 0) && (errno != ENOENT)) {
700  crm_perror(LOG_ERR, "Could not archive %s by linking to %s",
701  cib_path, backup_path);
702  rc = -1;
703 
704  /* Back up the CIB signature similarly */
705  } else if ((link(cib_digest, backup_digest) < 0) && (errno != ENOENT)) {
706  crm_perror(LOG_ERR, "Could not archive %s by linking to %s",
707  cib_digest, backup_digest);
708  rc = -1;
709 
710  /* Update the last counter and ensure everything is sync'd to media */
711  } else {
712  pcmk__write_series_sequence(cib_dirname, CIB_SERIES, ++seq,
714  if (cib_do_chown) {
715  int rc2;
716 
717  if ((chown(backup_path, cib_file_owner, cib_file_group) < 0)
718  && (errno != ENOENT)) {
719  crm_perror(LOG_ERR, "Could not set owner of %s", backup_path);
720  rc = -1;
721  }
722  if ((chown(backup_digest, cib_file_owner, cib_file_group) < 0)
723  && (errno != ENOENT)) {
724  crm_perror(LOG_ERR, "Could not set owner of %s", backup_digest);
725  rc = -1;
726  }
727  rc2 = pcmk__chown_series_sequence(cib_dirname, CIB_SERIES,
728  cib_file_owner, cib_file_group);
729  if (rc2 != pcmk_rc_ok) {
730  crm_err("Could not set owner of sequence file in %s: %s",
731  cib_dirname, pcmk_rc_str(rc2));
732  rc = -1;
733  }
734  }
735  pcmk__sync_directory(cib_dirname);
736  crm_info("Archived previous version as %s", backup_path);
737  }
738 
739  free(cib_path);
740  free(cib_digest);
741  free(backup_path);
742  free(backup_digest);
743  return rc;
744 }
745 
757 static void
758 cib_file_prepare_xml(xmlNode *root)
759 {
760  xmlNode *cib_status_root = NULL;
761 
762  /* Always write out with num_updates=0 and current last-written timestamp */
763  crm_xml_add(root, XML_ATTR_NUMUPDATES, "0");
765 
766  /* Delete status section before writing to file, because
767  * we discard it on startup anyway, and users get confused by it */
768  cib_status_root = find_xml_node(root, XML_CIB_TAG_STATUS, TRUE);
769  CRM_LOG_ASSERT(cib_status_root != NULL);
770  if (cib_status_root != NULL) {
771  free_xml(cib_status_root);
772  }
773 }
774 
788 int
789 cib_file_write_with_digest(xmlNode *cib_root, const char *cib_dirname,
790  const char *cib_filename)
791 {
792  int exit_rc = pcmk_ok;
793  int rc, fd;
794  char *digest = NULL;
795 
796  /* Detect CIB version for diagnostic purposes */
797  const char *epoch = crm_element_value(cib_root, XML_ATTR_GENERATION);
798  const char *admin_epoch = crm_element_value(cib_root,
800 
801  /* Determine full CIB and signature pathnames */
802  char *cib_path = crm_strdup_printf("%s/%s", cib_dirname, cib_filename);
803  char *digest_path = crm_strdup_printf("%s.sig", cib_path);
804 
805  /* Create temporary file name patterns for writing out CIB and signature */
806  char *tmp_cib = crm_strdup_printf("%s/cib.XXXXXX", cib_dirname);
807  char *tmp_digest = crm_strdup_printf("%s/cib.XXXXXX", cib_dirname);
808 
809  CRM_ASSERT((cib_path != NULL) && (digest_path != NULL)
810  && (tmp_cib != NULL) && (tmp_digest != NULL));
811 
812  /* Ensure the admin didn't modify the existing CIB underneath us */
813  crm_trace("Reading cluster configuration file %s", cib_path);
814  rc = cib_file_read_and_verify(cib_path, NULL, NULL);
815  if ((rc != pcmk_ok) && (rc != -ENOENT)) {
816  crm_err("%s was manually modified while the cluster was active!",
817  cib_path);
818  exit_rc = pcmk_err_cib_modified;
819  goto cleanup;
820  }
821 
822  /* Back up the existing CIB */
823  if (cib_file_backup(cib_dirname, cib_filename) < 0) {
824  exit_rc = pcmk_err_cib_backup;
825  goto cleanup;
826  }
827 
828  crm_debug("Writing CIB to disk");
829  umask(S_IWGRP | S_IWOTH | S_IROTH);
830  cib_file_prepare_xml(cib_root);
831 
832  /* Write the CIB to a temporary file, so we can deploy (near) atomically */
833  fd = mkstemp(tmp_cib);
834  if (fd < 0) {
835  crm_perror(LOG_ERR, "Couldn't open temporary file %s for writing CIB",
836  tmp_cib);
837  exit_rc = pcmk_err_cib_save;
838  goto cleanup;
839  }
840 
841  /* Protect the temporary file */
842  if (fchmod(fd, S_IRUSR | S_IWUSR) < 0) {
843  crm_perror(LOG_ERR, "Couldn't protect temporary file %s for writing CIB",
844  tmp_cib);
845  exit_rc = pcmk_err_cib_save;
846  goto cleanup;
847  }
848  if (cib_do_chown && (fchown(fd, cib_file_owner, cib_file_group) < 0)) {
849  crm_perror(LOG_ERR, "Couldn't protect temporary file %s for writing CIB",
850  tmp_cib);
851  exit_rc = pcmk_err_cib_save;
852  goto cleanup;
853  }
854 
855  /* Write out the CIB */
856  if (write_xml_fd(cib_root, tmp_cib, fd, FALSE) <= 0) {
857  crm_err("Changes couldn't be written to %s", tmp_cib);
858  exit_rc = pcmk_err_cib_save;
859  goto cleanup;
860  }
861 
862  /* Calculate CIB digest */
863  digest = calculate_on_disk_digest(cib_root);
864  CRM_ASSERT(digest != NULL);
865  crm_info("Wrote version %s.%s.0 of the CIB to disk (digest: %s)",
866  (admin_epoch ? admin_epoch : "0"), (epoch ? epoch : "0"), digest);
867 
868  /* Write the CIB digest to a temporary file */
869  fd = mkstemp(tmp_digest);
870  if (fd < 0) {
871  crm_perror(LOG_ERR, "Could not create temporary file for CIB digest");
872  exit_rc = pcmk_err_cib_save;
873  goto cleanup;
874  }
875  if (cib_do_chown && (fchown(fd, cib_file_owner, cib_file_group) < 0)) {
876  crm_perror(LOG_ERR, "Couldn't protect temporary file %s for writing CIB",
877  tmp_cib);
878  exit_rc = pcmk_err_cib_save;
879  close(fd);
880  goto cleanup;
881  }
882  rc = pcmk__write_sync(fd, digest);
883  if (rc != pcmk_rc_ok) {
884  crm_err("Could not write digest to %s: %s",
885  tmp_digest, pcmk_rc_str(rc));
886  exit_rc = pcmk_err_cib_save;
887  close(fd);
888  goto cleanup;
889  }
890  close(fd);
891  crm_debug("Wrote digest %s to disk", digest);
892 
893  /* Verify that what we wrote is sane */
894  crm_info("Reading cluster configuration file %s (digest: %s)",
895  tmp_cib, tmp_digest);
896  rc = cib_file_read_and_verify(tmp_cib, tmp_digest, NULL);
897  CRM_ASSERT(rc == 0);
898 
899  /* Rename temporary files to live, and sync directory changes to media */
900  crm_debug("Activating %s", tmp_cib);
901  if (rename(tmp_cib, cib_path) < 0) {
902  crm_perror(LOG_ERR, "Couldn't rename %s as %s", tmp_cib, cib_path);
903  exit_rc = pcmk_err_cib_save;
904  }
905  if (rename(tmp_digest, digest_path) < 0) {
906  crm_perror(LOG_ERR, "Couldn't rename %s as %s", tmp_digest,
907  digest_path);
908  exit_rc = pcmk_err_cib_save;
909  }
910  pcmk__sync_directory(cib_dirname);
911 
912  cleanup:
913  free(cib_path);
914  free(digest_path);
915  free(digest);
916  free(tmp_digest);
917  free(tmp_cib);
918  return exit_rc;
919 }
pcmk__cpg_host_t host
Definition: cpg.c:49
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:235
#define pcmk_err_schema_validation
Definition: results.h:73
A dumping ground.
const char * pcmk_strerror(int rc)
Definition: results.c:148
#define CIB_SERIES_MAX
Definition: cib_file.c:33
char data[0]
Definition: cpg.c:55
#define XML_ATTR_NUMUPDATES
Definition: msg_xml.h:140
int pcmk_rc2legacy(int rc)
Definition: results.c:533
#define PCMK__CIB_REQUEST_CREATE
Definition: internal.h:25
const char * name
Definition: cib.c:24
int(* message)(pcmk__output_t *out, const char *message_id,...)
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:284
const char * pcmk__xe_add_last_written(xmlNode *xe)
Definition: xml.c:1077
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:171
void pcmk__write_series_sequence(const char *directory, const char *series, unsigned int sequence, int max)
Definition: io.c:187
int(* signoff)(cib_t *cib)
Definition: cib_types.h:87
#define PCMK__CIB_REQUEST_QUERY
Definition: internal.h:24
int pcmk__chown_series_sequence(const char *directory, const char *series, uid_t uid, gid_t gid)
Definition: io.c:238
xmlNode * find_xml_node(const xmlNode *root, const char *search_path, gboolean must_find)
Definition: xml.c:404
crm_exit_t pcmk_rc2exitc(int rc)
Map a function return code to the most similar exit code.
Definition: results.c:689
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:104
bool pcmk__verify_digest(xmlNode *input, const char *expected)
Definition: digest.c:202
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:156
const char * crm_xml_add(xmlNode *node, const char *name, const char *value)
Create an XML attribute with specified name and value.
Definition: nvpair.c:302
#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:1265
int pcmk__read_series_sequence(const char *directory, const char *series, unsigned int *seq)
Definition: io.c:140
#define CRM_LOG_ASSERT(expr)
Definition: logging.h:219
char * pcmk__series_filename(const char *directory, const char *series, int sequence, bool bzip)
Definition: io.c:121
int(* inputfd)(cib_t *cib)
Definition: cib_types.h:100
enum crm_ais_msg_types type
Definition: cpg.c:48
int pcmk__write_sync(int fd, const char *contents)
Definition: io.c:488
int cib_file_write_with_digest(xmlNode *cib_root, const char *cib_dirname, const char *cib_filename)
Definition: cib_file.c:789
xmlNode * filename2xml(const char *filename)
Definition: xml.c:1007
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:488
#define pcmk_err_cib_backup
Definition: results.h:79
void pcmk__output_set_log_level(pcmk__output_t *out, uint8_t log_level)
Definition: output_log.c:345
#define CIB_SERIES_BZIP
Definition: cib_file.c:34
#define XML_ATTR_GENERATION
Definition: msg_xml.h:138
gboolean validate_xml(xmlNode *xml_blob, const char *validation, gboolean to_logs)
Definition: schemas.c:707
#define PCMK__CIB_REQUEST_ERASE
Definition: internal.h:28
gboolean validate_xml_verbose(xmlNode *xml_blob)
Definition: schemas.c:679
cib_file_flags
Definition: cib_file.c:40
#define CIB_SERIES
Definition: cib_file.c:32
xmlNode * copy_xml(xmlNode *src_node)
Definition: xml.c:819
cib_t * cib_new_variant(void)
Definition: cib_client.c:595
int(* set_connection_dnotify)(cib_t *cib, void(*dnotify)(gpointer user_data))
Definition: cib_types.h:98
#define crm_warn(fmt, args...)
Definition: logging.h:378
#define pcmk_err_cib_save
Definition: results.h:80
cib_api_operations_t * cmds
Definition: cib_types.h:216
#define crm_debug(fmt, args...)
Definition: logging.h:382
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:636
cib_conn_type
Definition: cib_types.h:46
int(* signon)(cib_t *cib, const char *name, enum cib_conn_type type)
Definition: cib_types.h:84
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition: nvpair.c:496
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:127
#define crm_trace(fmt, args...)
Definition: logging.h:383
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:121
void(* op_callback)(const xmlNode *msg, int call_id, int rc, xmlNode *output)
Definition: cib_types.h:214
void pcmk__sync_directory(const char *name)
Definition: io.c:396
Wrappers for and extensions to libxml2.
void(* finish)(pcmk__output_t *out, crm_exit_t exit_status, bool print, void **copy_dest)
xmlNode * create_xml_node(xmlNode *parent, const char *name)
Definition: xml.c:677
#define PCMK__NELEM(a)
Definition: internal.h:44
#define XML_ATTR_VALIDATION
Definition: msg_xml.h:133
#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:38
void free_xml(xmlNode *child)
Definition: xml.c:813
#define cib_clear_file_flags(cibfile, flags_to_clear)
Definition: cib_file.c:87
#define CRM_CONFIG_DIR
Definition: config.h:17
int(* register_notification)(cib_t *cib, const char *callback, int enabled)
Definition: cib_types.h:145
char * calculate_on_disk_digest(xmlNode *local_cib)
Calculate and return digest of XML tree, suitable for storing on disk.
Definition: digest.c:131
void pcmk__output_free(pcmk__output_t *out)
Definition: output.c:28
void * variant_opaque
Definition: cib_types.h:210
#define PCMK__CIB_REQUEST_UPGRADE
Definition: internal.h:31
#define PCMK__CIB_REQUEST_BUMP
Definition: internal.h:23
xmlNode * cib_create_op(int call_id, const char *op, const char *host, const char *section, xmlNode *data, int call_options, const char *user_name)
Definition: cib_utils.c:468
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:128
#define cib_set_file_flags(cibfile, flags_to_set)
Definition: cib_file.c:78
int cib_file_read_and_verify(const char *filename, const char *sigfile, xmlNode **root)
Definition: cib_file.c:615
int pcmk__file_contents(const char *filename, char **contents)
Definition: io.c:432
#define cib__set_call_options(cib_call_opts, call_for, flags_to_set)
Definition: internal.h:115
cib_t * cib_file_new(const char *cib_location)
Definition: cib_file.c:518
#define crm_perror(level, fmt, args...)
Send a system error message to both the log and stderr.
Definition: logging.h:319
const char * path
Definition: cib.c:26
#define crm_err(fmt, args...)
Definition: logging.h:377
#define CRM_ASSERT(expr)
Definition: results.h:42
#define PCMK__CIB_REQUEST_REPLACE
Definition: internal.h:29
This structure contains everything that makes up a single output formatter.
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 XML_ATTR_GENERATION_ADMIN
Definition: msg_xml.h:139
enum cib_variant variant
Definition: cib_types.h:206
#define pcmk_ok
Definition: results.h:68
IPC interface to Pacemaker daemons.
#define XML_CIB_TAG_STATUS
Definition: msg_xml.h:198
int call_id
Definition: cib_types.h:208
#define PCMK__CIB_REQUEST_MODIFY
Definition: internal.h:26
int pcmk__real_path(const char *path, char **resolved_path)
Definition: io.c:85
#define XML_ACL_TAG_USER
Definition: msg_xml.h:434
int write_xml_fd(xmlNode *xml_node, const char *filename, int fd, gboolean compress)
Write XML to a file descriptor.
Definition: xml.c:1237
enum cib_conn_type type
Definition: cib_types.h:205
enum cib_state state
Definition: cib_types.h:204
int(* free)(cib_t *cib)
Definition: cib_types.h:88
int(* client_id)(const cib_t *cib, const char **async_id, const char **sync_id)
Get the given CIB connection&#39;s unique client identifier(s)
Definition: cib_types.h:199
#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:121
#define crm_info(fmt, args...)
Definition: logging.h:380
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:319
#define PCMK__CIB_REQUEST_APPLY_PATCH
Definition: internal.h:30
bool pcmk__ends_with_ext(const char *s, const char *match)
Definition: strings.c:563
uint64_t flags
Definition: remote.c:215
int pcmk__log_output_new(pcmk__output_t **out)
Definition: output.c:272
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:570
#define PCMK__CIB_REQUEST_DELETE
Definition: internal.h:27
void * delegate_fn
Definition: cib_types.h:211