pacemaker  1.1.18-7fdfbbe
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  * Copyright (c) 2004 International Business Machines
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17  *
18  */
19 #include <crm_internal.h>
20 #include <unistd.h>
21 #include <limits.h>
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <stdarg.h>
25 #include <string.h>
26 #include <pwd.h>
27 
28 #include <sys/stat.h>
29 #include <sys/types.h>
30 #include <glib.h>
31 
32 #include <crm/crm.h>
33 #include <crm/cib/internal.h>
34 #include <crm/msg_xml.h>
35 #include <crm/common/ipc.h>
36 #include <crm/common/xml.h>
37 
38 #define cib_flag_dirty 0x00001
39 #define cib_flag_live 0x00002
40 
41 typedef struct cib_file_opaque_s {
42  int flags;
43  char *filename;
44 
46 
47 int cib_file_perform_op(cib_t * cib, const char *op, const char *host, const char *section,
48  xmlNode * data, xmlNode ** output_data, int call_options);
49 
50 int cib_file_perform_op_delegate(cib_t * cib, const char *op, const char *host, const char *section,
51  xmlNode * data, xmlNode ** output_data, int call_options,
52  const char *user_name);
53 
54 int cib_file_signon(cib_t * cib, const char *name, enum cib_conn_type type);
55 int cib_file_signoff(cib_t * cib);
56 int cib_file_free(cib_t * cib);
57 
58 static int
59 cib_file_inputfd(cib_t * cib)
60 {
61  return -EPROTONOSUPPORT;
62 }
63 
64 static int
65 cib_file_set_connection_dnotify(cib_t * cib, void (*dnotify) (gpointer user_data))
66 {
67  return -EPROTONOSUPPORT;
68 }
69 
70 static int
71 cib_file_register_notification(cib_t * cib, const char *callback, int enabled)
72 {
73  return -EPROTONOSUPPORT;
74 }
75 
85 static gboolean
86 cib_file_verify_digest(xmlNode *root, const char *sigfile)
87 {
88  gboolean passed = FALSE;
89  char *expected = crm_read_contents(sigfile);
90 
91  if (expected == NULL) {
92  switch (errno) {
93  case 0:
94  crm_err("On-disk digest at %s is empty", sigfile);
95  return FALSE;
96  case ENOENT:
97  crm_warn("No on-disk digest present at %s", sigfile);
98  return TRUE;
99  default:
100  crm_perror(LOG_ERR, "Could not read on-disk digest from %s", sigfile);
101  return FALSE;
102  }
103  }
104  passed = crm_digest_verify(root, expected);
105  free(expected);
106  return passed;
107 }
108 
124 int
125 cib_file_read_and_verify(const char *filename, const char *sigfile, xmlNode **root)
126 {
127  int s_res;
128  struct stat buf;
129  char *local_sigfile = NULL;
130  xmlNode *local_root = NULL;
131 
132  CRM_ASSERT(filename != NULL);
133  if (root) {
134  *root = NULL;
135  }
136 
137  /* Verify that file exists and its size is nonzero */
138  s_res = stat(filename, &buf);
139  if (s_res < 0) {
140  crm_perror(LOG_WARNING, "Could not verify cluster configuration file %s", filename);
141  return -errno;
142  } else if (buf.st_size == 0) {
143  crm_warn("Cluster configuration file %s is corrupt (size is zero)", filename);
144  return -pcmk_err_cib_corrupt;
145  }
146 
147  /* Parse XML */
148  local_root = filename2xml(filename);
149  if (local_root == NULL) {
150  crm_warn("Cluster configuration file %s is corrupt (unparseable as XML)", filename);
151  return -pcmk_err_cib_corrupt;
152  }
153 
154  /* If sigfile is not specified, use original file name plus .sig */
155  if (sigfile == NULL) {
156  sigfile = local_sigfile = crm_concat(filename, "sig", '.');
157  }
158 
159  /* Verify that digests match */
160  if (cib_file_verify_digest(local_root, sigfile) == FALSE) {
161  free(local_sigfile);
162  free_xml(local_root);
163  return -pcmk_err_cib_modified;
164  }
165 
166  free(local_sigfile);
167  if (root) {
168  *root = local_root;
169  } else {
170  free_xml(local_root);
171  }
172  return pcmk_ok;
173 }
174 
175 #define CIB_SERIES "cib"
176 #define CIB_SERIES_MAX 100
177 #define CIB_SERIES_BZIP FALSE /* Must be false because archived copies are
178  created with hard links
179  */
180 
181 #define CIB_LIVE_NAME CIB_SERIES ".xml"
182 
191 static gboolean
192 cib_file_is_live(const char *filename)
193 {
194  if (filename != NULL) {
195  /* Canonicalize all file names for true comparison */
196  char *real_filename = crm_compat_realpath(filename);
197 
198  if (real_filename != NULL) {
199  const char *livenames[] = {
201  CRM_LEGACY_CONFIG_DIR "/" CIB_LIVE_NAME
202  };
203  char *real_livename;
204  int i;
205 
206  /* Compare against each possible live CIB name */
207  for (i = 0; i < DIMOF(livenames); ++i) {
208  real_livename = crm_compat_realpath(livenames[i]);
209  if (real_livename && !strcmp(real_filename, real_livename)) {
210  free(real_livename);
211  return TRUE;
212  }
213  free(real_livename);
214  }
215  free(real_filename);
216  }
217  }
218  return FALSE;
219 }
220 
221 /* cib_file_backup() and cib_file_write_with_digest() need to chown the
222  * written files only in limited circumstances, so these variables allow
223  * that to be indicated without affecting external callers
224  */
225 static uid_t cib_file_owner = 0;
226 static uid_t cib_file_group = 0;
227 static gboolean cib_do_chown = FALSE;
228 
238 static int
239 cib_file_backup(const char *cib_dirname, const char *cib_filename)
240 {
241  int rc = 0;
242  char *cib_path = crm_concat(cib_dirname, cib_filename, '/');
243  char *cib_digest = crm_concat(cib_path, "sig", '.');
244 
245  /* Figure out what backup file sequence number to use */
246  int seq = get_last_sequence(cib_dirname, CIB_SERIES);
247  char *backup_path = generate_series_filename(cib_dirname, CIB_SERIES, seq,
249  char *backup_digest = crm_concat(backup_path, "sig", '.');
250 
251  CRM_ASSERT((cib_path != NULL) && (cib_digest != NULL)
252  && (backup_path != NULL) && (backup_digest != NULL));
253 
254  /* Remove the old backups if they exist */
255  unlink(backup_path);
256  unlink(backup_digest);
257 
258  /* Back up the CIB, by hard-linking it to the backup name */
259  if ((link(cib_path, backup_path) < 0) && (errno != ENOENT)) {
260  crm_perror(LOG_ERR, "Could not archive %s by linking to %s",
261  cib_path, backup_path);
262  rc = -1;
263 
264  /* Back up the CIB signature similarly */
265  } else if ((link(cib_digest, backup_digest) < 0) && (errno != ENOENT)) {
266  crm_perror(LOG_ERR, "Could not archive %s by linking to %s",
267  cib_digest, backup_digest);
268  rc = -1;
269 
270  /* Update the last counter and ensure everything is sync'd to media */
271  } else {
272  write_last_sequence(cib_dirname, CIB_SERIES, seq + 1, CIB_SERIES_MAX);
273  if (cib_do_chown) {
274  if ((chown(backup_path, cib_file_owner, cib_file_group) < 0)
275  && (errno != ENOENT)) {
276  crm_perror(LOG_ERR, "Could not set owner of %s", backup_path);
277  rc = -1;
278  }
279  if ((chown(backup_digest, cib_file_owner, cib_file_group) < 0)
280  && (errno != ENOENT)) {
281  crm_perror(LOG_ERR, "Could not set owner of %s", backup_digest);
282  rc = -1;
283  }
284  if (crm_chown_last_sequence(cib_dirname, CIB_SERIES, cib_file_owner,
285  cib_file_group) < 0) {
286  crm_perror(LOG_ERR,
287  "Could not set owner of %s last sequence file",
288  cib_dirname);
289  rc = -1;
290  }
291  }
292  crm_sync_directory(cib_dirname);
293  crm_info("Archived previous version as %s", backup_path);
294  }
295 
296  free(cib_path);
297  free(cib_digest);
298  free(backup_path);
299  free(backup_digest);
300  return rc;
301 }
302 
314 static void
315 cib_file_prepare_xml(xmlNode *root)
316 {
317  xmlNode *cib_status_root = NULL;
318 
319  /* Always write out with num_updates=0 and current last-written timestamp */
320  crm_xml_add(root, XML_ATTR_NUMUPDATES, "0");
322 
323  /* Delete status section before writing to file, because
324  * we discard it on startup anyway, and users get confused by it */
325  cib_status_root = find_xml_node(root, XML_CIB_TAG_STATUS, TRUE);
326  CRM_LOG_ASSERT(cib_status_root != NULL);
327  if (cib_status_root != NULL) {
328  free_xml(cib_status_root);
329  }
330 }
331 
345 int
346 cib_file_write_with_digest(xmlNode *cib_root, const char *cib_dirname,
347  const char *cib_filename)
348 {
349  int exit_rc = pcmk_ok;
350  int rc, fd;
351  char *digest = NULL;
352 
353  /* Detect CIB version for diagnostic purposes */
354  const char *epoch = crm_element_value(cib_root, XML_ATTR_GENERATION);
355  const char *admin_epoch = crm_element_value(cib_root,
357 
358  /* Determine full CIB and signature pathnames */
359  char *cib_path = crm_concat(cib_dirname, cib_filename, '/');
360  char *digest_path = crm_concat(cib_path, "sig", '.');
361 
362  /* Create temporary file name patterns for writing out CIB and signature */
363  char *tmp_cib = crm_strdup_printf("%s/cib.XXXXXX", cib_dirname);
364  char *tmp_digest = crm_strdup_printf("%s/cib.XXXXXX", cib_dirname);
365 
366  CRM_ASSERT((cib_path != NULL) && (digest_path != NULL)
367  && (tmp_cib != NULL) && (tmp_digest != NULL));
368 
369  /* Ensure the admin didn't modify the existing CIB underneath us */
370  crm_trace("Reading cluster configuration file %s", cib_path);
371  rc = cib_file_read_and_verify(cib_path, NULL, NULL);
372  if ((rc != pcmk_ok) && (rc != -ENOENT)) {
373  crm_err("%s was manually modified while the cluster was active!",
374  cib_path);
375  exit_rc = pcmk_err_cib_modified;
376  goto cleanup;
377  }
378 
379  /* Back up the existing CIB */
380  if (cib_file_backup(cib_dirname, cib_filename) < 0) {
381  exit_rc = pcmk_err_cib_backup;
382  goto cleanup;
383  }
384 
385  crm_debug("Writing CIB to disk");
386  umask(S_IWGRP | S_IWOTH | S_IROTH);
387  cib_file_prepare_xml(cib_root);
388 
389  /* Write the CIB to a temporary file, so we can deploy (near) atomically */
390  fd = mkstemp(tmp_cib);
391  if (fd < 0) {
392  crm_perror(LOG_ERR, "Couldn't open temporary file %s for writing CIB",
393  tmp_cib);
394  exit_rc = pcmk_err_cib_save;
395  goto cleanup;
396  }
397 
398  /* Protect the temporary file */
399  if (fchmod(fd, S_IRUSR | S_IWUSR) < 0) {
400  crm_perror(LOG_ERR, "Couldn't protect temporary file %s for writing CIB",
401  tmp_cib);
402  exit_rc = pcmk_err_cib_save;
403  goto cleanup;
404  }
405  if (cib_do_chown && (fchown(fd, cib_file_owner, cib_file_group) < 0)) {
406  crm_perror(LOG_ERR, "Couldn't protect temporary file %s for writing CIB",
407  tmp_cib);
408  exit_rc = pcmk_err_cib_save;
409  goto cleanup;
410  }
411 
412  /* Write out the CIB */
413  if (write_xml_fd(cib_root, tmp_cib, fd, FALSE) <= 0) {
414  crm_err("Changes couldn't be written to %s", tmp_cib);
415  exit_rc = pcmk_err_cib_save;
416  goto cleanup;
417  }
418 
419  /* Calculate CIB digest */
420  digest = calculate_on_disk_digest(cib_root);
421  CRM_ASSERT(digest != NULL);
422  crm_info("Wrote version %s.%s.0 of the CIB to disk (digest: %s)",
423  (admin_epoch ? admin_epoch : "0"), (epoch ? epoch : "0"), digest);
424 
425  /* Write the CIB digest to a temporary file */
426  fd = mkstemp(tmp_digest);
427  if (fd < 0) {
428  crm_perror(LOG_ERR, "Could not create temporary file for CIB digest");
429  exit_rc = pcmk_err_cib_save;
430  goto cleanup;
431  }
432  if (cib_do_chown && (fchown(fd, cib_file_owner, cib_file_group) < 0)) {
433  crm_perror(LOG_ERR, "Couldn't protect temporary file %s for writing CIB",
434  tmp_cib);
435  exit_rc = pcmk_err_cib_save;
436  close(fd);
437  goto cleanup;
438  }
439  if (crm_write_sync(fd, digest) < 0) {
440  crm_perror(LOG_ERR, "Could not write digest to file %s", tmp_digest);
441  exit_rc = pcmk_err_cib_save;
442  close(fd);
443  goto cleanup;
444  }
445  close(fd);
446  crm_debug("Wrote digest %s to disk", digest);
447 
448  /* Verify that what we wrote is sane */
449  crm_info("Reading cluster configuration file %s (digest: %s)",
450  tmp_cib, tmp_digest);
451  rc = cib_file_read_and_verify(tmp_cib, tmp_digest, NULL);
452  CRM_ASSERT(rc == 0);
453 
454  /* Rename temporary files to live, and sync directory changes to media */
455  crm_debug("Activating %s", tmp_cib);
456  if (rename(tmp_cib, cib_path) < 0) {
457  crm_perror(LOG_ERR, "Couldn't rename %s as %s", tmp_cib, cib_path);
458  exit_rc = pcmk_err_cib_save;
459  }
460  if (rename(tmp_digest, digest_path) < 0) {
461  crm_perror(LOG_ERR, "Couldn't rename %s as %s", tmp_digest,
462  digest_path);
463  exit_rc = pcmk_err_cib_save;
464  }
465  crm_sync_directory(cib_dirname);
466 
467  cleanup:
468  free(cib_path);
469  free(digest_path);
470  free(digest);
471  free(tmp_digest);
472  free(tmp_cib);
473  return exit_rc;
474 }
475 
476 cib_t *
477 cib_file_new(const char *cib_location)
478 {
479  cib_file_opaque_t *private = NULL;
480  cib_t *cib = cib_new_variant();
481 
482  private = calloc(1, sizeof(cib_file_opaque_t));
483  CRM_ASSERT((cib != NULL) && (private != NULL));
484 
485  cib->variant = cib_file;
486  cib->variant_opaque = private;
487 
488  if (cib_location == NULL) {
489  cib_location = getenv("CIB_file");
490  }
491  private->flags = 0;
492  if (cib_file_is_live(cib_location)) {
493  set_bit(private->flags, cib_flag_live);
494  crm_trace("File %s detected as live CIB", cib_location);
495  }
496  private->filename = strdup(cib_location);
497 
498  /* assign variant specific ops */
500  cib->cmds->signon = cib_file_signon;
501  cib->cmds->signoff = cib_file_signoff;
502  cib->cmds->free = cib_file_free;
503  cib->cmds->inputfd = cib_file_inputfd;
504 
505  cib->cmds->register_notification = cib_file_register_notification;
506  cib->cmds->set_connection_dnotify = cib_file_set_connection_dnotify;
507 
508  return cib;
509 }
510 
511 static xmlNode *in_mem_cib = NULL;
512 
527 static int
528 load_file_cib(const char *filename)
529 {
530  struct stat buf;
531  xmlNode *root = NULL;
532  const char *ignore_dtd = NULL;
533 
534  /* Ensure file is readable */
535  if (stat(filename, &buf) < 0) {
536  return -ENXIO;
537  }
538 
539  /* Parse XML from file */
540  root = filename2xml(filename);
541  if (root == NULL) {
543  }
544 
545  /* Add a status section if not already present */
546  if (find_xml_node(root, XML_CIB_TAG_STATUS, FALSE) == NULL) {
548  }
549 
550  /* Validate XML against its specified DTD */
551  ignore_dtd = crm_element_value(root, XML_ATTR_VALIDATION);
552  if (validate_xml(root, NULL, TRUE) == FALSE) {
553  crm_err("CIB does not validate against %s", ignore_dtd);
554  free_xml(root);
556  }
557 
558  /* Remember the parsed XML for later use */
559  in_mem_cib = root;
560  return pcmk_ok;
561 }
562 
563 int
564 cib_file_signon(cib_t * cib, const char *name, enum cib_conn_type type)
565 {
566  int rc = pcmk_ok;
567  cib_file_opaque_t *private = cib->variant_opaque;
568 
569  if (private->filename == NULL) {
570  rc = -EINVAL;
571  } else {
572  rc = load_file_cib(private->filename);
573  }
574 
575  if (rc == pcmk_ok) {
576  crm_debug("%s: Opened connection to local file '%s'", name, private->filename);
578  cib->type = cib_command;
579 
580  } else {
581  fprintf(stderr, "%s: Connection to local file '%s' failed: %s\n",
582  name, private->filename, pcmk_strerror(rc));
583  }
584 
585  return rc;
586 }
587 
596 static int
597 cib_file_write_live(char *path)
598 {
599  uid_t uid = geteuid();
600  struct passwd *daemon_pwent;
601  char *sep = strrchr(path, '/');
602  const char *cib_dirname, *cib_filename;
603  int rc = 0;
604 
605  /* Get the desired uid/gid */
606  errno = 0;
607  daemon_pwent = getpwnam(CRM_DAEMON_USER);
608  if (daemon_pwent == NULL) {
609  crm_perror(LOG_ERR, "Could not find %s user", CRM_DAEMON_USER);
610  return -1;
611  }
612 
613  /* If we're root, we can change the ownership;
614  * if we're daemon, anything we create will be OK;
615  * otherwise, block access so we don't create wrong owner
616  */
617  if ((uid != 0) && (uid != daemon_pwent->pw_uid)) {
618  crm_perror(LOG_ERR, "Must be root or %s to modify live CIB",
620  return 0;
621  }
622 
623  /* fancy footwork to separate dirname from filename
624  * (we know the canonical name maps to the live CIB,
625  * but the given name might be relative, or symlinked)
626  */
627  if (sep == NULL) { /* no directory component specified */
628  cib_dirname = "./";
629  cib_filename = path;
630  } else if (sep == path) { /* given name is in / */
631  cib_dirname = "/";
632  cib_filename = path + 1;
633  } else { /* typical case; split given name into parts */
634  *sep = '\0';
635  cib_dirname = path;
636  cib_filename = sep + 1;
637  }
638 
639  /* if we're root, we want to update the file ownership */
640  if (uid == 0) {
641  cib_file_owner = daemon_pwent->pw_uid;
642  cib_file_group = daemon_pwent->pw_gid;
643  cib_do_chown = TRUE;
644  }
645 
646  /* write the file */
647  if (cib_file_write_with_digest(in_mem_cib, cib_dirname,
648  cib_filename) != pcmk_ok) {
649  rc = -1;
650  }
651 
652  /* turn off file ownership changes, for other callers */
653  if (uid == 0) {
654  cib_do_chown = FALSE;
655  }
656 
657  /* undo fancy stuff */
658  if ((sep != NULL) && (*sep == '\0')) {
659  *sep = '/';
660  }
661 
662  return rc;
663 }
664 
678 int
680 {
681  int rc = pcmk_ok;
682  cib_file_opaque_t *private = cib->variant_opaque;
683 
684  crm_debug("Signing out of the CIB Service");
685  cib->state = cib_disconnected;
686  cib->type = cib_no_connection;
687 
688  /* If the in-memory CIB has been changed, write it to disk */
689  if (is_set(private->flags, cib_flag_dirty)) {
690 
691  /* If this is the live CIB, write it out with a digest */
692  if (is_set(private->flags, cib_flag_live)) {
693  if (cib_file_write_live(private->filename) < 0) {
694  rc = pcmk_err_generic;
695  }
696 
697  /* Otherwise, it's a simple write */
698  } else {
699  gboolean do_bzip = crm_ends_with_ext(private->filename, ".bz2");
700 
701  if (write_xml_file(in_mem_cib, private->filename, do_bzip) <= 0) {
702  rc = pcmk_err_generic;
703  }
704  }
705 
706  if (rc == pcmk_ok) {
707  crm_info("Wrote CIB to %s", private->filename);
708  clear_bit(private->flags, cib_flag_dirty);
709  } else {
710  crm_err("Could not write CIB to %s", private->filename);
711  }
712  }
713 
714  /* Free the in-memory CIB */
715  free_xml(in_mem_cib);
716  in_mem_cib = NULL;
717  return rc;
718 }
719 
720 int
722 {
723  int rc = pcmk_ok;
724 
725  if (cib->state != cib_disconnected) {
726  rc = cib_file_signoff(cib);
727  }
728 
729  if (rc == pcmk_ok) {
730  cib_file_opaque_t *private = cib->variant_opaque;
731 
732  free(private->filename);
733  free(cib->cmds);
734  free(private);
735  free(cib);
736 
737  } else {
738  fprintf(stderr, "Couldn't sign off: %d\n", rc);
739  }
740 
741  return rc;
742 }
743 
744 struct cib_func_entry {
745  const char *op;
746  gboolean read_only;
747  cib_op_t fn;
748 };
749 
750 /* *INDENT-OFF* */
751 static struct cib_func_entry cib_file_ops[] = {
755  {CIB_OP_BUMP, FALSE, cib_process_bump},
761 };
762 /* *INDENT-ON* */
763 
764 int
765 cib_file_perform_op(cib_t * cib, const char *op, const char *host, const char *section,
766  xmlNode * data, xmlNode ** output_data, int call_options)
767 {
768  return cib_file_perform_op_delegate(cib, op, host, section, data, output_data, call_options,
769  NULL);
770 }
771 
772 int
773 cib_file_perform_op_delegate(cib_t * cib, const char *op, const char *host, const char *section,
774  xmlNode * data, xmlNode ** output_data, int call_options,
775  const char *user_name)
776 {
777  int rc = pcmk_ok;
778  char *effective_user = NULL;
779  gboolean query = FALSE;
780  gboolean changed = FALSE;
781  xmlNode *request = NULL;
782  xmlNode *output = NULL;
783  xmlNode *cib_diff = NULL;
784  xmlNode *result_cib = NULL;
785  cib_op_t *fn = NULL;
786  int lpc = 0;
787  static int max_msg_types = DIMOF(cib_file_ops);
788  cib_file_opaque_t *private = cib->variant_opaque;
789 
790  crm_info("%s on %s", op, section);
791  call_options |= (cib_no_mtime | cib_inhibit_bcast | cib_scope_local);
792 
793  if (cib->state == cib_disconnected) {
794  return -ENOTCONN;
795  }
796 
797  if (output_data != NULL) {
798  *output_data = NULL;
799  }
800 
801  if (op == NULL) {
802  return -EINVAL;
803  }
804 
805  for (lpc = 0; lpc < max_msg_types; lpc++) {
806  if (safe_str_eq(op, cib_file_ops[lpc].op)) {
807  fn = &(cib_file_ops[lpc].fn);
808  query = cib_file_ops[lpc].read_only;
809  break;
810  }
811  }
812 
813  if (fn == NULL) {
814  return -EPROTONOSUPPORT;
815  }
816 
817  cib->call_id++;
818  request = cib_create_op(cib->call_id, "dummy-token", op, host, section, data, call_options, user_name);
819 #if ENABLE_ACL
820  if(user_name) {
821  crm_xml_add(request, XML_ACL_TAG_USER, user_name);
822  }
823  crm_trace("Performing %s operation as %s", op, user_name);
824 #endif
825 
826  /* Mirror the logic in cib_prepare_common() */
827  if (section != NULL && data != NULL && crm_str_eq(crm_element_name(data), XML_TAG_CIB, TRUE)) {
828  data = get_object_root(section, data);
829  }
830 
831  rc = cib_perform_op(op, call_options, fn, query,
832  section, request, data, TRUE, &changed, in_mem_cib, &result_cib, &cib_diff,
833  &output);
834 
835  free_xml(request);
836  if (rc == -pcmk_err_schema_validation) {
837  validate_xml_verbose(result_cib);
838  }
839 
840  if (rc != pcmk_ok) {
841  free_xml(result_cib);
842 
843  } else if (query == FALSE) {
844  xml_log_patchset(LOG_DEBUG, "cib:diff", cib_diff);
845  free_xml(in_mem_cib);
846  in_mem_cib = result_cib;
847  set_bit(private->flags, cib_flag_dirty);
848  }
849 
850  free_xml(cib_diff);
851 
852  if (cib->op_callback != NULL) {
853  cib->op_callback(NULL, cib->call_id, rc, output);
854  }
855 
856  if (output_data && output) {
857  if(output == in_mem_cib) {
858  *output_data = copy_xml(output);
859  } else {
860  *output_data = output;
861  }
862 
863  } else if(output != in_mem_cib) {
864  free_xml(output);
865  }
866 
867  free(effective_user);
868  return rc;
869 }
#define CIB_OP_CREATE
Definition: internal.h:31
xmlNode * find_xml_node(xmlNode *cib, const char *node_path, gboolean must_find)
Definition: xml.c:2235
char * crm_compat_realpath(const char *path)
Definition: compat.c:40
A dumping ground.
#define CIB_SERIES_MAX
Definition: cib_file.c:176
#define XML_ATTR_NUMUPDATES
Definition: msg_xml.h:95
#define CRM_LEGACY_CONFIG_DIR
Definition: config.h:56
int get_last_sequence(const char *directory, const char *series)
Definition: io.c:122
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:288
const char * pcmk_strerror(int rc)
Definition: logging.c:1135
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:176
int(* free)(cib_t *cib)
Definition: cib.h:89
xmlNode * get_object_root(const char *object_type, xmlNode *the_root)
Definition: cib_utils.c:230
int(* cib_op_t)(const char *, int, const char *, xmlNode *, xmlNode *, xmlNode *, xmlNode **, xmlNode **)
Definition: internal.h:119
#define pcmk_ok
Definition: error.h:42
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:83
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:773
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:134
int(* inputfd)(cib_t *cib)
Definition: cib.h:102
int write_xml_file(xmlNode *xml_node, const char *filename, gboolean compress)
Definition: xml.c:3153
gboolean crm_digest_verify(xmlNode *input, const char *expected)
Definition: digest.c:222
AIS_Host host
Definition: internal.h:52
#define CRM_LOG_ASSERT(expr)
Definition: logging.h:150
#define cib_flag_dirty
Definition: cib_file.c:38
#define clear_bit(word, bit)
Definition: crm_internal.h:191
xmlNode * filename2xml(const char *filename)
Definition: xml.c:2934
int(* set_connection_dnotify)(cib_t *cib, void(*dnotify)(gpointer user_data))
Definition: cib.h:100
struct cib_file_opaque_s cib_file_opaque_t
#define CIB_SERIES_BZIP
Definition: cib_file.c:177
char * generate_series_filename(const char *directory, const char *series, int sequence, gboolean bzip)
Definition: io.c:86
#define XML_ATTR_GENERATION
Definition: msg_xml.h:93
char * crm_read_contents(const char *filename)
Definition: io.c:395
gboolean validate_xml(xmlNode *xml_blob, const char *validation, gboolean to_logs)
Definition: schemas.c:650
#define CIB_OP_BUMP
Definition: internal.h:29
gboolean validate_xml_verbose(xmlNode *xml_blob)
Definition: schemas.c:622
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:588
#define CIB_SERIES
Definition: cib_file.c:175
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:765
xmlNode * copy_xml(xmlNode *src_node)
Definition: xml.c:2712
cib_t * cib_new_variant(void)
Definition: cib_client.c:354
#define crm_warn(fmt, args...)
Definition: logging.h:249
#define set_bit(word, bit)
Definition: crm_internal.h:190
cib_api_operations_t * cmds
Definition: cib.h:161
#define crm_debug(fmt, args...)
Definition: logging.h:253
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:590
#define cib_flag_live
Definition: cib_file.c:39
#define CIB_OP_APPLY_DIFF
Definition: internal.h:37
int cib_file_signoff(cib_t *cib)
Definition: cib_file.c:679
void(* op_callback)(const xmlNode *msg, int call_id, int rc, xmlNode *output)
Definition: cib.h:159
#define pcmk_err_schema_validation
Definition: error.h:47
#define CIB_OP_QUERY
Definition: internal.h:30
#define crm_trace(fmt, args...)
Definition: logging.h:254
int(* register_notification)(cib_t *cib, const char *callback, int enabled)
Definition: cib.h:133
#define pcmk_err_cib_save
Definition: error.h:54
Wrappers for and extensions to libxml2.
#define pcmk_err_cib_backup
Definition: error.h:53
xmlNode * create_xml_node(xmlNode *parent, const char *name)
Definition: xml.c:2588
const char * crm_element_value(xmlNode *data, const char *name)
Definition: xml.c:5165
#define pcmk_err_generic
Definition: error.h:45
#define XML_ATTR_VALIDATION
Definition: msg_xml.h:86
#define CRM_DAEMON_USER
Definition: config.h:47
#define CIB_LIVE_NAME
Definition: cib_file.c:181
void free_xml(xmlNode *child)
Definition: xml.c:2706
Definition: cib.h:38
gboolean crm_str_eq(const char *a, const char *b, gboolean use_case)
Definition: strings.c:213
gboolean crm_ends_with_ext(const char *s, const char *match)
Definition: strings.c:331
#define CRM_CONFIG_DIR
Definition: config.h:35
#define CIB_OP_ERASE
Definition: internal.h:35
char * calculate_on_disk_digest(xmlNode *local_cib)
Calculate and return digest of XML tree, suitable for storing on disk.
Definition: digest.c:156
void * variant_opaque
Definition: cib.h:155
cib_t * cib_file_new(const char *filename)
Definition: cib_file.c:477
void write_last_sequence(const char *directory, const char *series, int sequence, int max)
Definition: io.c:194
const char * crm_xml_add(xmlNode *node, const char *name, const char *value)
Definition: xml.c:2490
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:38
#define XML_TAG_CIB
Definition: msg_xml.h:81
int cib_file_write_with_digest(xmlNode *cib_root, const char *cib_dirname, const char *cib_filename)
Definition: cib_file.c:346
cib_conn_type
Definition: cib.h:49
int cib_file_read_and_verify(const char *filename, const char *sigfile, xmlNode **root)
Definition: cib_file.c:125
#define crm_perror(level, fmt, args...)
Log a system error message.
Definition: logging.h:226
#define crm_err(fmt, args...)
Definition: logging.h:248
#define CIB_OP_DELETE
Definition: internal.h:34
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:291
#define CIB_OP_MODIFY
Definition: internal.h:33
int(* signon)(cib_t *cib, const char *name, enum cib_conn_type type)
Definition: cib.h:86
int crm_write_sync(int fd, const char *contents)
Definition: io.c:441
#define DIMOF(a)
Definition: crm.h:39
#define XML_ATTR_GENERATION_ADMIN
Definition: msg_xml.h:94
#define pcmk_err_cib_modified
Definition: error.h:52
#define CRM_ASSERT(expr)
Definition: error.h:35
char data[0]
Definition: internal.h:58
int crm_chown_last_sequence(const char *directory, const char *series, uid_t uid, gid_t gid)
Definition: io.c:251
enum cib_variant variant
Definition: cib.h:151
#define CIB_OP_REPLACE
Definition: internal.h:36
Wrappers for and extensions to libqb IPC.
int cib_file_free(cib_t *cib)
Definition: cib_file.c:721
#define XML_CIB_TAG_STATUS
Definition: msg_xml.h:158
int call_id
Definition: cib.h:153
int cib_file_signon(cib_t *cib, const char *name, enum cib_conn_type type)
Definition: cib_file.c:564
int(* signoff)(cib_t *cib)
Definition: cib.h:88
void crm_sync_directory(const char *name)
Definition: io.c:358
char * crm_concat(const char *prefix, const char *suffix, char join)
Definition: strings.c:32
#define XML_ACL_TAG_USER
Definition: msg_xml.h:395
void xml_log_patchset(uint8_t level, const char *function, xmlNode *xml)
Definition: xml.c:1387
#define safe_str_eq(a, b)
Definition: util.h:72
int write_xml_fd(xmlNode *xml_node, const char *filename, int fd, gboolean compress)
Definition: xml.c:3143
enum cib_conn_type type
Definition: cib.h:150
char * crm_strdup_printf(char const *format,...) __attribute__((__format__(__printf__
#define pcmk_err_cib_corrupt
Definition: error.h:56
enum cib_state state
Definition: cib.h:149
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:100
#define crm_info(fmt, args...)
Definition: logging.h:251
const char * crm_xml_add_last_written(xmlNode *xml_node)
Definition: xml.c:3006
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:322
Definition: cib.h:148
uint64_t flags
Definition: remote.c:156
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:526
void * delegate_fn
Definition: cib.h:156
enum crm_ais_msg_types type
Definition: internal.h:51
#define CIB_OP_UPGRADE
Definition: internal.h:38