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