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