pacemaker  2.0.3-4b1f869f0f
Scalable High-Availability cluster resource manager
cib_file.c
Go to the documentation of this file.
1 /*
2  * Copyright 2004-2018 International Business Machines
3  *
4  * This source code is licensed under the GNU Lesser General Public License
5  * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
6  */
7 
8 #include <crm_internal.h>
9 #include <unistd.h>
10 #include <limits.h>
11 #include <stdlib.h>
12 #include <stdio.h>
13 #include <stdarg.h>
14 #include <string.h>
15 #include <pwd.h>
16 
17 #include <sys/stat.h>
18 #include <sys/types.h>
19 #include <glib.h>
20 
21 #include <crm/crm.h>
22 #include <crm/cib/internal.h>
23 #include <crm/msg_xml.h>
24 #include <crm/common/ipc.h>
25 #include <crm/common/xml.h>
26 
27 #define CIB_FLAG_DIRTY 0x00001
28 #define CIB_FLAG_LIVE 0x00002
29 
30 typedef struct cib_file_opaque_s {
31  int flags;
32  char *filename;
33 
35 
36 int cib_file_perform_op(cib_t * cib, const char *op, const char *host, const char *section,
37  xmlNode * data, xmlNode ** output_data, int call_options);
38 
39 int cib_file_perform_op_delegate(cib_t * cib, const char *op, const char *host, const char *section,
40  xmlNode * data, xmlNode ** output_data, int call_options,
41  const char *user_name);
42 
43 int cib_file_signon(cib_t * cib, const char *name, enum cib_conn_type type);
44 int cib_file_signoff(cib_t * cib);
45 int cib_file_free(cib_t * cib);
46 
47 static int
48 cib_file_inputfd(cib_t * cib)
49 {
50  return -EPROTONOSUPPORT;
51 }
52 
53 static int
54 cib_file_set_connection_dnotify(cib_t * cib, void (*dnotify) (gpointer user_data))
55 {
56  return -EPROTONOSUPPORT;
57 }
58 
59 static int
60 cib_file_register_notification(cib_t * cib, const char *callback, int enabled)
61 {
62  return -EPROTONOSUPPORT;
63 }
64 
74 static gboolean
75 cib_file_verify_digest(xmlNode *root, const char *sigfile)
76 {
77  gboolean passed = FALSE;
78  char *expected = crm_read_contents(sigfile);
79 
80  if (expected == NULL) {
81  switch (errno) {
82  case 0:
83  crm_err("On-disk digest at %s is empty", sigfile);
84  return FALSE;
85  case ENOENT:
86  crm_warn("No on-disk digest present at %s", sigfile);
87  return TRUE;
88  default:
89  crm_perror(LOG_ERR, "Could not read on-disk digest from %s", sigfile);
90  return FALSE;
91  }
92  }
93  passed = crm_digest_verify(root, expected);
94  free(expected);
95  return passed;
96 }
97 
113 int
114 cib_file_read_and_verify(const char *filename, const char *sigfile, xmlNode **root)
115 {
116  int s_res;
117  struct stat buf;
118  char *local_sigfile = NULL;
119  xmlNode *local_root = NULL;
120 
121  CRM_ASSERT(filename != NULL);
122  if (root) {
123  *root = NULL;
124  }
125 
126  /* Verify that file exists and its size is nonzero */
127  s_res = stat(filename, &buf);
128  if (s_res < 0) {
129  crm_perror(LOG_WARNING, "Could not verify cluster configuration file %s", filename);
130  return -errno;
131  } else if (buf.st_size == 0) {
132  crm_warn("Cluster configuration file %s is corrupt (size is zero)", filename);
133  return -pcmk_err_cib_corrupt;
134  }
135 
136  /* Parse XML */
137  local_root = filename2xml(filename);
138  if (local_root == NULL) {
139  crm_warn("Cluster configuration file %s is corrupt (unparseable as XML)", filename);
140  return -pcmk_err_cib_corrupt;
141  }
142 
143  /* If sigfile is not specified, use original file name plus .sig */
144  if (sigfile == NULL) {
145  sigfile = local_sigfile = crm_concat(filename, "sig", '.');
146  }
147 
148  /* Verify that digests match */
149  if (cib_file_verify_digest(local_root, sigfile) == FALSE) {
150  free(local_sigfile);
151  free_xml(local_root);
152  return -pcmk_err_cib_modified;
153  }
154 
155  free(local_sigfile);
156  if (root) {
157  *root = local_root;
158  } else {
159  free_xml(local_root);
160  }
161  return pcmk_ok;
162 }
163 
164 #define CIB_SERIES "cib"
165 #define CIB_SERIES_MAX 100
166 #define CIB_SERIES_BZIP FALSE /* Must be false because archived copies are
167  created with hard links
168  */
169 
170 #define CIB_LIVE_NAME CIB_SERIES ".xml"
171 
180 static gboolean
181 cib_file_is_live(const char *filename)
182 {
183  gboolean same = FALSE;
184 
185  if (filename != NULL) {
186  // Canonicalize file names for true comparison
187  char *real_filename = crm_compat_realpath(filename);
188 
189  if (real_filename != NULL) {
190  char *real_livename;
191 
192  real_livename = crm_compat_realpath(CRM_CONFIG_DIR "/" CIB_LIVE_NAME);
193  if (real_livename && !strcmp(real_filename, real_livename)) {
194  same = TRUE;
195  }
196  free(real_livename);
197  free(real_filename);
198  }
199  }
200  return same;
201 }
202 
203 /* cib_file_backup() and cib_file_write_with_digest() need to chown the
204  * written files only in limited circumstances, so these variables allow
205  * that to be indicated without affecting external callers
206  */
207 static uid_t cib_file_owner = 0;
208 static uid_t cib_file_group = 0;
209 static gboolean cib_do_chown = FALSE;
210 
220 static int
221 cib_file_backup(const char *cib_dirname, const char *cib_filename)
222 {
223  int rc = 0;
224  char *cib_path = crm_concat(cib_dirname, cib_filename, '/');
225  char *cib_digest = crm_concat(cib_path, "sig", '.');
226 
227  /* Figure out what backup file sequence number to use */
228  int seq = get_last_sequence(cib_dirname, CIB_SERIES);
229  char *backup_path = generate_series_filename(cib_dirname, CIB_SERIES, seq,
231  char *backup_digest = crm_concat(backup_path, "sig", '.');
232 
233  CRM_ASSERT((cib_path != NULL) && (cib_digest != NULL)
234  && (backup_path != NULL) && (backup_digest != NULL));
235 
236  /* Remove the old backups if they exist */
237  unlink(backup_path);
238  unlink(backup_digest);
239 
240  /* Back up the CIB, by hard-linking it to the backup name */
241  if ((link(cib_path, backup_path) < 0) && (errno != ENOENT)) {
242  crm_perror(LOG_ERR, "Could not archive %s by linking to %s",
243  cib_path, backup_path);
244  rc = -1;
245 
246  /* Back up the CIB signature similarly */
247  } else if ((link(cib_digest, backup_digest) < 0) && (errno != ENOENT)) {
248  crm_perror(LOG_ERR, "Could not archive %s by linking to %s",
249  cib_digest, backup_digest);
250  rc = -1;
251 
252  /* Update the last counter and ensure everything is sync'd to media */
253  } else {
254  write_last_sequence(cib_dirname, CIB_SERIES, seq + 1, CIB_SERIES_MAX);
255  if (cib_do_chown) {
256  if ((chown(backup_path, cib_file_owner, cib_file_group) < 0)
257  && (errno != ENOENT)) {
258  crm_perror(LOG_ERR, "Could not set owner of %s", backup_path);
259  rc = -1;
260  }
261  if ((chown(backup_digest, cib_file_owner, cib_file_group) < 0)
262  && (errno != ENOENT)) {
263  crm_perror(LOG_ERR, "Could not set owner of %s", backup_digest);
264  rc = -1;
265  }
266  if (crm_chown_last_sequence(cib_dirname, CIB_SERIES, cib_file_owner,
267  cib_file_group) < 0) {
268  crm_perror(LOG_ERR,
269  "Could not set owner of %s last sequence file",
270  cib_dirname);
271  rc = -1;
272  }
273  }
274  crm_sync_directory(cib_dirname);
275  crm_info("Archived previous version as %s", backup_path);
276  }
277 
278  free(cib_path);
279  free(cib_digest);
280  free(backup_path);
281  free(backup_digest);
282  return rc;
283 }
284 
296 static void
297 cib_file_prepare_xml(xmlNode *root)
298 {
299  xmlNode *cib_status_root = NULL;
300 
301  /* Always write out with num_updates=0 and current last-written timestamp */
302  crm_xml_add(root, XML_ATTR_NUMUPDATES, "0");
304 
305  /* Delete status section before writing to file, because
306  * we discard it on startup anyway, and users get confused by it */
307  cib_status_root = find_xml_node(root, XML_CIB_TAG_STATUS, TRUE);
308  CRM_LOG_ASSERT(cib_status_root != NULL);
309  if (cib_status_root != NULL) {
310  free_xml(cib_status_root);
311  }
312 }
313 
327 int
328 cib_file_write_with_digest(xmlNode *cib_root, const char *cib_dirname,
329  const char *cib_filename)
330 {
331  int exit_rc = pcmk_ok;
332  int rc, fd;
333  char *digest = NULL;
334 
335  /* Detect CIB version for diagnostic purposes */
336  const char *epoch = crm_element_value(cib_root, XML_ATTR_GENERATION);
337  const char *admin_epoch = crm_element_value(cib_root,
339 
340  /* Determine full CIB and signature pathnames */
341  char *cib_path = crm_concat(cib_dirname, cib_filename, '/');
342  char *digest_path = crm_concat(cib_path, "sig", '.');
343 
344  /* Create temporary file name patterns for writing out CIB and signature */
345  char *tmp_cib = crm_strdup_printf("%s/cib.XXXXXX", cib_dirname);
346  char *tmp_digest = crm_strdup_printf("%s/cib.XXXXXX", cib_dirname);
347 
348  CRM_ASSERT((cib_path != NULL) && (digest_path != NULL)
349  && (tmp_cib != NULL) && (tmp_digest != NULL));
350 
351  /* Ensure the admin didn't modify the existing CIB underneath us */
352  crm_trace("Reading cluster configuration file %s", cib_path);
353  rc = cib_file_read_and_verify(cib_path, NULL, NULL);
354  if ((rc != pcmk_ok) && (rc != -ENOENT)) {
355  crm_err("%s was manually modified while the cluster was active!",
356  cib_path);
357  exit_rc = pcmk_err_cib_modified;
358  goto cleanup;
359  }
360 
361  /* Back up the existing CIB */
362  if (cib_file_backup(cib_dirname, cib_filename) < 0) {
363  exit_rc = pcmk_err_cib_backup;
364  goto cleanup;
365  }
366 
367  crm_debug("Writing CIB to disk");
368  umask(S_IWGRP | S_IWOTH | S_IROTH);
369  cib_file_prepare_xml(cib_root);
370 
371  /* Write the CIB to a temporary file, so we can deploy (near) atomically */
372  fd = mkstemp(tmp_cib);
373  if (fd < 0) {
374  crm_perror(LOG_ERR, "Couldn't open temporary file %s for writing CIB",
375  tmp_cib);
376  exit_rc = pcmk_err_cib_save;
377  goto cleanup;
378  }
379 
380  /* Protect the temporary file */
381  if (fchmod(fd, S_IRUSR | S_IWUSR) < 0) {
382  crm_perror(LOG_ERR, "Couldn't protect temporary file %s for writing CIB",
383  tmp_cib);
384  exit_rc = pcmk_err_cib_save;
385  goto cleanup;
386  }
387  if (cib_do_chown && (fchown(fd, cib_file_owner, cib_file_group) < 0)) {
388  crm_perror(LOG_ERR, "Couldn't protect temporary file %s for writing CIB",
389  tmp_cib);
390  exit_rc = pcmk_err_cib_save;
391  goto cleanup;
392  }
393 
394  /* Write out the CIB */
395  if (write_xml_fd(cib_root, tmp_cib, fd, FALSE) <= 0) {
396  crm_err("Changes couldn't be written to %s", tmp_cib);
397  exit_rc = pcmk_err_cib_save;
398  goto cleanup;
399  }
400 
401  /* Calculate CIB digest */
402  digest = calculate_on_disk_digest(cib_root);
403  CRM_ASSERT(digest != NULL);
404  crm_info("Wrote version %s.%s.0 of the CIB to disk (digest: %s)",
405  (admin_epoch ? admin_epoch : "0"), (epoch ? epoch : "0"), digest);
406 
407  /* Write the CIB digest to a temporary file */
408  fd = mkstemp(tmp_digest);
409  if (fd < 0) {
410  crm_perror(LOG_ERR, "Could not create temporary file for CIB digest");
411  exit_rc = pcmk_err_cib_save;
412  goto cleanup;
413  }
414  if (cib_do_chown && (fchown(fd, cib_file_owner, cib_file_group) < 0)) {
415  crm_perror(LOG_ERR, "Couldn't protect temporary file %s for writing CIB",
416  tmp_cib);
417  exit_rc = pcmk_err_cib_save;
418  close(fd);
419  goto cleanup;
420  }
421  if (crm_write_sync(fd, digest) < 0) {
422  crm_perror(LOG_ERR, "Could not write digest to file %s", tmp_digest);
423  exit_rc = pcmk_err_cib_save;
424  close(fd);
425  goto cleanup;
426  }
427  close(fd);
428  crm_debug("Wrote digest %s to disk", digest);
429 
430  /* Verify that what we wrote is sane */
431  crm_info("Reading cluster configuration file %s (digest: %s)",
432  tmp_cib, tmp_digest);
433  rc = cib_file_read_and_verify(tmp_cib, tmp_digest, NULL);
434  CRM_ASSERT(rc == 0);
435 
436  /* Rename temporary files to live, and sync directory changes to media */
437  crm_debug("Activating %s", tmp_cib);
438  if (rename(tmp_cib, cib_path) < 0) {
439  crm_perror(LOG_ERR, "Couldn't rename %s as %s", tmp_cib, cib_path);
440  exit_rc = pcmk_err_cib_save;
441  }
442  if (rename(tmp_digest, digest_path) < 0) {
443  crm_perror(LOG_ERR, "Couldn't rename %s as %s", tmp_digest,
444  digest_path);
445  exit_rc = pcmk_err_cib_save;
446  }
447  crm_sync_directory(cib_dirname);
448 
449  cleanup:
450  free(cib_path);
451  free(digest_path);
452  free(digest);
453  free(tmp_digest);
454  free(tmp_cib);
455  return exit_rc;
456 }
457 
458 cib_t *
459 cib_file_new(const char *cib_location)
460 {
461  cib_file_opaque_t *private = NULL;
462  cib_t *cib = cib_new_variant();
463 
464  private = calloc(1, sizeof(cib_file_opaque_t));
465  CRM_ASSERT((cib != NULL) && (private != NULL));
466 
467  cib->variant = cib_file;
468  cib->variant_opaque = private;
469 
470  if (cib_location == NULL) {
471  cib_location = getenv("CIB_file");
472  }
473  private->flags = 0;
474  if (cib_file_is_live(cib_location)) {
475  set_bit(private->flags, CIB_FLAG_LIVE);
476  crm_trace("File %s detected as live CIB", cib_location);
477  }
478  private->filename = strdup(cib_location);
479 
480  /* assign variant specific ops */
482  cib->cmds->signon = cib_file_signon;
483  cib->cmds->signoff = cib_file_signoff;
484  cib->cmds->free = cib_file_free;
485  cib->cmds->inputfd = cib_file_inputfd;
486 
487  cib->cmds->register_notification = cib_file_register_notification;
488  cib->cmds->set_connection_dnotify = cib_file_set_connection_dnotify;
489 
490  return cib;
491 }
492 
493 static xmlNode *in_mem_cib = NULL;
494 
509 static int
510 load_file_cib(const char *filename)
511 {
512  struct stat buf;
513  xmlNode *root = NULL;
514 
515  /* Ensure file is readable */
516  if (stat(filename, &buf) < 0) {
517  return -ENXIO;
518  }
519 
520  /* Parse XML from file */
521  root = filename2xml(filename);
522  if (root == NULL) {
524  }
525 
526  /* Add a status section if not already present */
527  if (find_xml_node(root, XML_CIB_TAG_STATUS, FALSE) == NULL) {
529  }
530 
531  /* Validate XML against its specified schema */
532  if (validate_xml(root, NULL, TRUE) == FALSE) {
533  const char *schema = crm_element_value(root, XML_ATTR_VALIDATION);
534 
535  crm_err("CIB does not validate against %s", schema);
536  free_xml(root);
538  }
539 
540  /* Remember the parsed XML for later use */
541  in_mem_cib = root;
542  return pcmk_ok;
543 }
544 
545 int
546 cib_file_signon(cib_t * cib, const char *name, enum cib_conn_type type)
547 {
548  int rc = pcmk_ok;
549  cib_file_opaque_t *private = cib->variant_opaque;
550 
551  if (private->filename == NULL) {
552  rc = -EINVAL;
553  } else {
554  rc = load_file_cib(private->filename);
555  }
556 
557  if (rc == pcmk_ok) {
558  crm_debug("%s: Opened connection to local file '%s'", name, private->filename);
560  cib->type = cib_command;
561 
562  } else {
563  fprintf(stderr, "%s: Connection to local file '%s' failed: %s\n",
564  name, private->filename, pcmk_strerror(rc));
565  }
566 
567  return rc;
568 }
569 
578 static int
579 cib_file_write_live(char *path)
580 {
581  uid_t uid = geteuid();
582  struct passwd *daemon_pwent;
583  char *sep = strrchr(path, '/');
584  const char *cib_dirname, *cib_filename;
585  int rc = 0;
586 
587  /* Get the desired uid/gid */
588  errno = 0;
589  daemon_pwent = getpwnam(CRM_DAEMON_USER);
590  if (daemon_pwent == NULL) {
591  crm_perror(LOG_ERR, "Could not find %s user", CRM_DAEMON_USER);
592  return -1;
593  }
594 
595  /* If we're root, we can change the ownership;
596  * if we're daemon, anything we create will be OK;
597  * otherwise, block access so we don't create wrong owner
598  */
599  if ((uid != 0) && (uid != daemon_pwent->pw_uid)) {
600  crm_perror(LOG_ERR, "Must be root or %s to modify live CIB",
602  return 0;
603  }
604 
605  /* fancy footwork to separate dirname from filename
606  * (we know the canonical name maps to the live CIB,
607  * but the given name might be relative, or symlinked)
608  */
609  if (sep == NULL) { /* no directory component specified */
610  cib_dirname = "./";
611  cib_filename = path;
612  } else if (sep == path) { /* given name is in / */
613  cib_dirname = "/";
614  cib_filename = path + 1;
615  } else { /* typical case; split given name into parts */
616  *sep = '\0';
617  cib_dirname = path;
618  cib_filename = sep + 1;
619  }
620 
621  /* if we're root, we want to update the file ownership */
622  if (uid == 0) {
623  cib_file_owner = daemon_pwent->pw_uid;
624  cib_file_group = daemon_pwent->pw_gid;
625  cib_do_chown = TRUE;
626  }
627 
628  /* write the file */
629  if (cib_file_write_with_digest(in_mem_cib, cib_dirname,
630  cib_filename) != pcmk_ok) {
631  rc = -1;
632  }
633 
634  /* turn off file ownership changes, for other callers */
635  if (uid == 0) {
636  cib_do_chown = FALSE;
637  }
638 
639  /* undo fancy stuff */
640  if ((sep != NULL) && (*sep == '\0')) {
641  *sep = '/';
642  }
643 
644  return rc;
645 }
646 
660 int
661 cib_file_signoff(cib_t * cib)
662 {
663  int rc = pcmk_ok;
664  cib_file_opaque_t *private = cib->variant_opaque;
665 
666  crm_debug("Disconnecting from the CIB manager");
667  cib->state = cib_disconnected;
668  cib->type = cib_no_connection;
669 
670  /* If the in-memory CIB has been changed, write it to disk */
671  if (is_set(private->flags, CIB_FLAG_DIRTY)) {
672 
673  /* If this is the live CIB, write it out with a digest */
674  if (is_set(private->flags, CIB_FLAG_LIVE)) {
675  if (cib_file_write_live(private->filename) < 0) {
676  rc = pcmk_err_generic;
677  }
678 
679  /* Otherwise, it's a simple write */
680  } else {
681  gboolean do_bzip = crm_ends_with_ext(private->filename, ".bz2");
682 
683  if (write_xml_file(in_mem_cib, private->filename, do_bzip) <= 0) {
684  rc = pcmk_err_generic;
685  }
686  }
687 
688  if (rc == pcmk_ok) {
689  crm_info("Wrote CIB to %s", private->filename);
690  clear_bit(private->flags, CIB_FLAG_DIRTY);
691  } else {
692  crm_err("Could not write CIB to %s", private->filename);
693  }
694  }
695 
696  /* Free the in-memory CIB */
697  free_xml(in_mem_cib);
698  in_mem_cib = NULL;
699  return rc;
700 }
701 
702 int
703 cib_file_free(cib_t * cib)
704 {
705  int rc = pcmk_ok;
706 
707  if (cib->state != cib_disconnected) {
708  rc = cib_file_signoff(cib);
709  }
710 
711  if (rc == pcmk_ok) {
712  cib_file_opaque_t *private = cib->variant_opaque;
713 
714  free(private->filename);
715  free(cib->cmds);
716  free(private);
717  free(cib);
718 
719  } else {
720  fprintf(stderr, "Couldn't sign off: %d\n", rc);
721  }
722 
723  return rc;
724 }
725 
726 struct cib_func_entry {
727  const char *op;
728  gboolean read_only;
729  cib_op_t fn;
730 };
731 
732 /* *INDENT-OFF* */
733 static struct cib_func_entry cib_file_ops[] = {
737  {CIB_OP_BUMP, FALSE, cib_process_bump},
743 };
744 /* *INDENT-ON* */
745 
746 int
747 cib_file_perform_op(cib_t * cib, const char *op, const char *host, const char *section,
748  xmlNode * data, xmlNode ** output_data, int call_options)
749 {
750  return cib_file_perform_op_delegate(cib, op, host, section, data, output_data, call_options,
751  NULL);
752 }
753 
754 int
755 cib_file_perform_op_delegate(cib_t * cib, const char *op, const char *host, const char *section,
756  xmlNode * data, xmlNode ** output_data, int call_options,
757  const char *user_name)
758 {
759  int rc = pcmk_ok;
760  char *effective_user = NULL;
761  gboolean query = FALSE;
762  gboolean changed = FALSE;
763  xmlNode *request = NULL;
764  xmlNode *output = NULL;
765  xmlNode *cib_diff = NULL;
766  xmlNode *result_cib = NULL;
767  cib_op_t *fn = NULL;
768  int lpc = 0;
769  static int max_msg_types = DIMOF(cib_file_ops);
770  cib_file_opaque_t *private = cib->variant_opaque;
771 
772 #if ENABLE_ACL
773  crm_info("Handling %s operation for %s as %s",
774  (op? op : "invalid"), (section? section : "entire CIB"),
775  (user_name? user_name : "default user"));
776 #else
777  crm_info("Handling %s operation for %s",
778  (op? op : "invalid"), (section? section : "entire CIB"));
779 #endif
780 
781  call_options |= (cib_no_mtime | cib_inhibit_bcast | cib_scope_local);
782 
783  if (cib->state == cib_disconnected) {
784  return -ENOTCONN;
785  }
786 
787  if (output_data != NULL) {
788  *output_data = NULL;
789  }
790 
791  if (op == NULL) {
792  return -EINVAL;
793  }
794 
795  for (lpc = 0; lpc < max_msg_types; lpc++) {
796  if (safe_str_eq(op, cib_file_ops[lpc].op)) {
797  fn = &(cib_file_ops[lpc].fn);
798  query = cib_file_ops[lpc].read_only;
799  break;
800  }
801  }
802 
803  if (fn == NULL) {
804  return -EPROTONOSUPPORT;
805  }
806 
807  cib->call_id++;
808  request = cib_create_op(cib->call_id, "dummy-token", op, host, section, data, call_options, user_name);
809 #if ENABLE_ACL
810  if(user_name) {
811  crm_xml_add(request, XML_ACL_TAG_USER, user_name);
812  }
813 #endif
814 
815  /* Mirror the logic in cib_prepare_common() */
816  if (section != NULL && data != NULL && crm_str_eq(crm_element_name(data), XML_TAG_CIB, TRUE)) {
817  data = get_object_root(section, data);
818  }
819 
820  rc = cib_perform_op(op, call_options, fn, query,
821  section, request, data, TRUE, &changed, in_mem_cib, &result_cib, &cib_diff,
822  &output);
823 
824  free_xml(request);
825  if (rc == -pcmk_err_schema_validation) {
826  validate_xml_verbose(result_cib);
827  }
828 
829  if (rc != pcmk_ok) {
830  free_xml(result_cib);
831 
832  } else if (query == FALSE) {
833  xml_log_patchset(LOG_DEBUG, "cib:diff", cib_diff);
834  free_xml(in_mem_cib);
835  in_mem_cib = result_cib;
836  set_bit(private->flags, CIB_FLAG_DIRTY);
837  }
838 
839  free_xml(cib_diff);
840 
841  if (cib->op_callback != NULL) {
842  cib->op_callback(NULL, cib->call_id, rc, output);
843  }
844 
845  if (output_data && output) {
846  if(output == in_mem_cib) {
847  *output_data = copy_xml(output);
848  } else {
849  *output_data = output;
850  }
851 
852  } else if(output != in_mem_cib) {
853  free_xml(output);
854  }
855 
856  free(effective_user);
857  return rc;
858 }
XML_ACL_TAG_USER
#define XML_ACL_TAG_USER
Definition: msg_xml.h:367
XML_ATTR_VALIDATION
#define XML_ATTR_VALIDATION
Definition: msg_xml.h:81
CIB_SERIES
#define CIB_SERIES
Definition: cib_file.c:164
cib_no_connection
@ cib_no_connection
Definition: cib_types.h:45
crm_str_eq
gboolean crm_str_eq(const char *a, const char *b, gboolean use_case)
Definition: strings.c:224
pcmk_err_generic
#define pcmk_err_generic
Definition: results.h:60
CIB_OP_CREATE
#define CIB_OP_CREATE
Definition: internal.h:23
cib_s::cmds
cib_api_operations_t * cmds
Definition: cib_types.h:147
flags
uint64_t flags
Definition: remote.c:5
msg_xml.h
cib_api_operations_s::signoff
int(* signoff)(cib_t *cib)
Definition: cib_types.h:76
cib_api_operations_s::free
int(* free)(cib_t *cib)
Definition: cib_types.h:77
data
char data[0]
Definition: internal.h:12
cib_file_signoff
int cib_file_signoff(cib_t *cib)
Definition: cib_file.c:659
crm_read_contents
char * crm_read_contents(const char *filename)
Definition: io.c:409
cib_conn_type
cib_conn_type
Definition: cib_types.h:42
cib_process_erase
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
cib_process_bump
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
create_xml_node
xmlNode * create_xml_node(xmlNode *parent, const char *name)
Definition: xml.c:1970
CIB_OP_UPGRADE
#define CIB_OP_UPGRADE
Definition: internal.h:29
cib_file_free
int cib_file_free(cib_t *cib)
Definition: cib_file.c:701
cib_file_read_and_verify
int cib_file_read_and_verify(const char *filename, const char *sigfile, xmlNode **root)
Definition: cib_file.c:114
CIB_OP_BUMP
#define CIB_OP_BUMP
Definition: internal.h:21
cib_process_replace
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
crm_compat_realpath
char * crm_compat_realpath(const char *path)
Definition: compat.c:40
cib_file_opaque_t
struct cib_file_opaque_s cib_file_opaque_t
pcmk_err_schema_validation
#define pcmk_err_schema_validation
Definition: results.h:62
pcmk_strerror
const char * pcmk_strerror(int rc)
Definition: results.c:188
copy_xml
xmlNode * copy_xml(xmlNode *src_node)
Definition: xml.c:2136
cib_api_operations_s::register_notification
int(* register_notification)(cib_t *cib, const char *callback, int enabled)
Definition: cib_types.h:119
clear_bit
#define clear_bit(word, bit)
Definition: crm_internal.h:168
write_last_sequence
void write_last_sequence(const char *directory, const char *series, int sequence, int max)
Definition: io.c:167
filename2xml
xmlNode * filename2xml(const char *filename)
Definition: xml.c:2348
pcmk_err_cib_save
#define pcmk_err_cib_save
Definition: results.h:69
type
enum crm_ais_msg_types type
Definition: internal.h:5
crm_chown_last_sequence
int crm_chown_last_sequence(const char *directory, const char *series, uid_t uid, gid_t gid)
Definition: io.c:216
crm_err
#define crm_err(fmt, args...)
Definition: logging.h:241
write_xml_file
int write_xml_file(xmlNode *xml_node, const char *filename, gboolean compress)
Write XML to a file.
Definition: xml.c:2597
crm_trace
#define crm_trace(fmt, args...)
Definition: logging.h:247
safe_str_eq
#define safe_str_eq(a, b)
Definition: util.h:61
crm_warn
#define crm_warn(fmt, args...)
Definition: logging.h:242
free_xml
void free_xml(xmlNode *child)
Definition: xml.c:2130
crm_digest_verify
gboolean crm_digest_verify(xmlNode *input, const char *expected)
Definition: digest.c:226
get_last_sequence
int get_last_sequence(const char *directory, const char *series)
Definition: io.c:101
cib_inhibit_bcast
@ cib_inhibit_bcast
Definition: cib_types.h:66
cib_file_perform_op_delegate
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:753
xml.h
Wrappers for and extensions to libxml2.
cib_new_variant
cib_t * cib_new_variant(void)
Definition: cib_client.c:343
XML_CIB_TAG_STATUS
#define XML_CIB_TAG_STATUS
Definition: msg_xml.h:139
internal.h
set_bit
#define set_bit(word, bit)
Definition: crm_internal.h:167
write_xml_fd
int write_xml_fd(xmlNode *xml_node, const char *filename, int fd, gboolean compress)
Write XML to a file descriptor.
Definition: xml.c:2575
CIB_OP_APPLY_DIFF
#define CIB_OP_APPLY_DIFF
Definition: internal.h:28
get_object_root
xmlNode * get_object_root(const char *object_type, xmlNode *the_root)
Definition: cib_utils.c:144
pcmk_err_cib_modified
#define pcmk_err_cib_modified
Definition: results.h:67
cib_op_t
int(* cib_op_t)(const char *, int, const char *, xmlNode *, xmlNode *, xmlNode *, xmlNode **, xmlNode **)
Definition: internal.h:105
cib_s::variant_opaque
void * variant_opaque
Definition: cib_types.h:141
cib_connected_command
@ cib_connected_command
Definition: cib_types.h:37
crm_info
#define crm_info(fmt, args...)
Definition: logging.h:244
CIB_FLAG_DIRTY
#define CIB_FLAG_DIRTY
Definition: cib_file.c:27
CRM_LOG_ASSERT
#define CRM_LOG_ASSERT(expr)
Definition: logging.h:143
CIB_FLAG_LIVE
#define CIB_FLAG_LIVE
Definition: cib_file.c:28
pcmk_err_cib_backup
#define pcmk_err_cib_backup
Definition: results.h:68
crm_strdup_printf
char * crm_strdup_printf(char const *format,...) __attribute__((__format__(__printf__
DIMOF
#define DIMOF(a)
Definition: crm.h:58
crm_debug
#define crm_debug(fmt, args...)
Definition: logging.h:246
cib_create_op
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
XML_TAG_CIB
#define XML_TAG_CIB
Definition: msg_xml.h:76
CIB_OP_QUERY
#define CIB_OP_QUERY
Definition: internal.h:22
cib_file_signon
int cib_file_signon(cib_t *cib, const char *name, enum cib_conn_type type)
Definition: cib_file.c:544
cib_process_diff
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
CIB_OP_ERASE
#define CIB_OP_ERASE
Definition: internal.h:26
crm_xml_add
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:313
cib_s::delegate_fn
void * delegate_fn
Definition: cib_types.h:142
cib_s::variant
enum cib_variant variant
Definition: cib_types.h:137
crm_element_value
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition: nvpair.c:519
cib_file_perform_op
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:745
cib_process_query
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
ipc.h
Wrappers for and extensions to libqb IPC.
cib_api_operations_s::inputfd
int(* inputfd)(cib_t *cib)
Definition: cib_types.h:89
XML_ATTR_GENERATION
#define XML_ATTR_GENERATION
Definition: msg_xml.h:87
CIB_OP_MODIFY
#define CIB_OP_MODIFY
Definition: internal.h:24
cib_api_operations_s::set_connection_dnotify
int(* set_connection_dnotify)(cib_t *cib, void(*dnotify)(gpointer user_data))
Definition: cib_types.h:87
cib_disconnected
@ cib_disconnected
Definition: cib_types.h:39
cib_scope_local
@ cib_scope_local
Definition: cib_types.h:59
validate_xml
gboolean validate_xml(xmlNode *xml_blob, const char *validation, gboolean to_logs)
Definition: schemas.c:701
crm_perror
#define crm_perror(level, fmt, args...)
Log a system error message.
Definition: logging.h:219
host
AIS_Host host
Definition: internal.h:6
CIB_LIVE_NAME
#define CIB_LIVE_NAME
Definition: cib_file.c:168
cib_file_write_with_digest
int cib_file_write_with_digest(xmlNode *cib_root, const char *cib_dirname, const char *cib_filename)
Definition: cib_file.c:326
cib_s::call_id
int call_id
Definition: cib_types.h:139
crm_write_sync
int crm_write_sync(int fd, const char *contents)
Definition: io.c:455
cib_file_new
cib_t * cib_file_new(const char *cib_location)
Definition: cib_file.c:457
cib_perform_op
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
generate_series_filename
char * generate_series_filename(const char *directory, const char *series, int sequence, gboolean bzip)
Definition: io.c:78
cib_s::type
enum cib_conn_type type
Definition: cib_types.h:136
cib_s
Definition: cib_types.h:134
cib_s::state
enum cib_state state
Definition: cib_types.h:135
CRM_ASSERT
#define CRM_ASSERT(expr)
Definition: results.h:42
find_xml_node
xmlNode * find_xml_node(xmlNode *cib, const char *node_path, gboolean must_find)
Definition: xml.c:1758
CIB_SERIES_MAX
#define CIB_SERIES_MAX
Definition: cib_file.c:165
XML_ATTR_NUMUPDATES
#define XML_ATTR_NUMUPDATES
Definition: msg_xml.h:89
crm_sync_directory
void crm_sync_directory(const char *name)
Definition: io.c:372
validate_xml_verbose
gboolean validate_xml_verbose(xmlNode *xml_blob)
Definition: schemas.c:673
CRM_CONFIG_DIR
#define CRM_CONFIG_DIR
Definition: config.h:20
pcmk_err_cib_corrupt
#define pcmk_err_cib_corrupt
Definition: results.h:71
cib_api_operations_s::signon
int(* signon)(cib_t *cib, const char *name, enum cib_conn_type type)
Definition: cib_types.h:73
xml_log_patchset
void xml_log_patchset(uint8_t level, const char *function, xmlNode *xml)
Definition: xml.c:824
XML_ATTR_GENERATION_ADMIN
#define XML_ATTR_GENERATION_ADMIN
Definition: msg_xml.h:88
crm_ends_with_ext
gboolean crm_ends_with_ext(const char *s, const char *match)
Definition: strings.c:342
cib_process_upgrade
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
crm_xml_add_last_written
const char * crm_xml_add_last_written(xmlNode *xml_node)
Definition: xml.c:2418
cib_process_modify
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
CRM_DAEMON_USER
#define CRM_DAEMON_USER
Definition: config.h:32
cib_process_create
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
cib_s::op_callback
void(* op_callback)(const xmlNode *msg, int call_id, int rc, xmlNode *output)
Definition: cib_types.h:145
CIB_OP_DELETE
#define CIB_OP_DELETE
Definition: internal.h:25
cib_file
@ cib_file
Definition: cib_types.h:31
crm_internal.h
cib_no_mtime
@ cib_no_mtime
Definition: cib_types.h:62
CIB_SERIES_BZIP
#define CIB_SERIES_BZIP
Definition: cib_file.c:166
crm.h
A dumping ground.
cib_process_delete
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
calculate_on_disk_digest
char * calculate_on_disk_digest(xmlNode *local_cib)
Calculate and return digest of XML tree, suitable for storing on disk.
Definition: digest.c:157
CIB_OP_REPLACE
#define CIB_OP_REPLACE
Definition: internal.h:27
cib_command
@ cib_command
Definition: cib_types.h:43
pcmk_ok
#define pcmk_ok
Definition: results.h:57