pacemaker 2.1.1-77db578727
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-2021 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
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 private = calloc(1, sizeof(cib_file_opaque_t));
501 CRM_ASSERT((cib != NULL) && (private != NULL));
502
503 cib->variant = cib_file;
504 cib->variant_opaque = private;
505
506 if (cib_location == NULL) {
507 cib_location = getenv("CIB_file");
508 }
509 private->flags = 0;
510 if (cib_file_is_live(cib_location)) {
512 crm_trace("File %s detected as live CIB", cib_location);
513 }
514 private->filename = strdup(cib_location);
515
516 /* assign variant specific ops */
520 cib->cmds->free = cib_file_free;
521 cib->cmds->inputfd = cib_file_inputfd;
522
523 cib->cmds->register_notification = cib_file_register_notification;
524 cib->cmds->set_connection_dnotify = cib_file_set_connection_dnotify;
525
526 return cib;
527}
528
529static xmlNode *in_mem_cib = NULL;
530
545static int
546load_file_cib(const char *filename)
547{
548 struct stat buf;
549 xmlNode *root = NULL;
550
551 /* Ensure file is readable */
552 if (strcmp(filename, "-") && (stat(filename, &buf) < 0)) {
553 return -ENXIO;
554 }
555
556 /* Parse XML from file */
557 root = filename2xml(filename);
558 if (root == NULL) {
560 }
561
562 /* Add a status section if not already present */
563 if (find_xml_node(root, XML_CIB_TAG_STATUS, FALSE) == NULL) {
565 }
566
567 /* Validate XML against its specified schema */
568 if (validate_xml(root, NULL, TRUE) == FALSE) {
569 const char *schema = crm_element_value(root, XML_ATTR_VALIDATION);
570
571 crm_err("CIB does not validate against %s", schema);
572 free_xml(root);
574 }
575
576 /* Remember the parsed XML for later use */
577 in_mem_cib = root;
578 return pcmk_ok;
579}
581int
582cib_file_signon(cib_t * cib, const char *name, enum cib_conn_type type)
583{
584 int rc = pcmk_ok;
585 cib_file_opaque_t *private = cib->variant_opaque;
586
587 if (private->filename == NULL) {
588 rc = -EINVAL;
589 } else {
590 rc = load_file_cib(private->filename);
591 }
592
593 if (rc == pcmk_ok) {
594 crm_debug("Opened connection to local file '%s' for %s",
595 private->filename, name);
597 cib->type = cib_command;
598
599 } else {
600 crm_info("Connection to local file '%s' for %s failed: %s\n",
601 private->filename, name, pcmk_strerror(rc));
602 }
603 return rc;
604}
605
614static int
615cib_file_write_live(char *path)
616{
617 uid_t uid = geteuid();
618 struct passwd *daemon_pwent;
619 char *sep = strrchr(path, '/');
620 const char *cib_dirname, *cib_filename;
621 int rc = 0;
622
623 /* Get the desired uid/gid */
624 errno = 0;
625 daemon_pwent = getpwnam(CRM_DAEMON_USER);
626 if (daemon_pwent == NULL) {
627 crm_perror(LOG_ERR, "Could not find %s user", CRM_DAEMON_USER);
628 return -1;
629 }
630
631 /* If we're root, we can change the ownership;
632 * if we're daemon, anything we create will be OK;
633 * otherwise, block access so we don't create wrong owner
634 */
635 if ((uid != 0) && (uid != daemon_pwent->pw_uid)) {
636 crm_perror(LOG_ERR, "Must be root or %s to modify live CIB",
638 return 0;
639 }
640
641 /* fancy footwork to separate dirname from filename
642 * (we know the canonical name maps to the live CIB,
643 * but the given name might be relative, or symlinked)
644 */
645 if (sep == NULL) { /* no directory component specified */
646 cib_dirname = "./";
647 cib_filename = path;
648 } else if (sep == path) { /* given name is in / */
649 cib_dirname = "/";
650 cib_filename = path + 1;
651 } else { /* typical case; split given name into parts */
652 *sep = '\0';
653 cib_dirname = path;
654 cib_filename = sep + 1;
655 }
656
657 /* if we're root, we want to update the file ownership */
658 if (uid == 0) {
659 cib_file_owner = daemon_pwent->pw_uid;
660 cib_file_group = daemon_pwent->pw_gid;
661 cib_do_chown = TRUE;
662 }
663
664 /* write the file */
665 if (cib_file_write_with_digest(in_mem_cib, cib_dirname,
666 cib_filename) != pcmk_ok) {
667 rc = -1;
668 }
669
670 /* turn off file ownership changes, for other callers */
671 if (uid == 0) {
672 cib_do_chown = FALSE;
673 }
674
675 /* undo fancy stuff */
676 if ((sep != NULL) && (*sep == '\0')) {
677 *sep = '/';
678 }
679
680 return rc;
681}
682
696int
698{
699 int rc = pcmk_ok;
700 cib_file_opaque_t *private = cib->variant_opaque;
701
702 crm_debug("Disconnecting from the CIB manager");
703 cib->state = cib_disconnected;
704 cib->type = cib_no_connection;
705
706 /* If the in-memory CIB has been changed, write it to disk */
707 if (pcmk_is_set(private->flags, cib_file_flag_dirty)) {
708
709 /* If this is the live CIB, write it out with a digest */
710 if (pcmk_is_set(private->flags, cib_file_flag_live)) {
711 if (cib_file_write_live(private->filename) < 0) {
713 }
714
715 /* Otherwise, it's a simple write */
716 } else {
717 gboolean do_bzip = pcmk__ends_with_ext(private->filename, ".bz2");
718
719 if (write_xml_file(in_mem_cib, private->filename, do_bzip) <= 0) {
721 }
722 }
723
724 if (rc == pcmk_ok) {
725 crm_info("Wrote CIB to %s", private->filename);
727 } else {
728 crm_err("Could not write CIB to %s", private->filename);
729 }
730 }
731
732 /* Free the in-memory CIB */
733 free_xml(in_mem_cib);
734 in_mem_cib = NULL;
735 return rc;
736}
738int
739cib_file_free(cib_t * cib)
740{
741 int rc = pcmk_ok;
742
743 if (cib->state != cib_disconnected) {
744 rc = cib_file_signoff(cib);
745 }
746
747 if (rc == pcmk_ok) {
748 cib_file_opaque_t *private = cib->variant_opaque;
749
750 free(private->filename);
751 free(cib->cmds);
752 free(private);
753 free(cib);
754
755 } else {
756 fprintf(stderr, "Couldn't sign off: %d\n", rc);
757 }
758
759 return rc;
760}
761
762struct cib_func_entry {
763 const char *op;
764 gboolean read_only;
765 cib_op_t fn;
766};
767
768/* *INDENT-OFF* */
769static struct cib_func_entry cib_file_ops[] = {
779};
780/* *INDENT-ON* */
782int
783cib_file_perform_op(cib_t * cib, const char *op, const char *host, const char *section,
784 xmlNode * data, xmlNode ** output_data, int call_options)
785{
786 return cib_file_perform_op_delegate(cib, op, host, section, data, output_data, call_options,
787 NULL);
788}
790int
791cib_file_perform_op_delegate(cib_t * cib, const char *op, const char *host, const char *section,
792 xmlNode * data, xmlNode ** output_data, int call_options,
793 const char *user_name)
794{
795 int rc = pcmk_ok;
796 char *effective_user = NULL;
797 gboolean query = FALSE;
798 gboolean changed = FALSE;
799 xmlNode *request = NULL;
800 xmlNode *output = NULL;
801 xmlNode *cib_diff = NULL;
802 xmlNode *result_cib = NULL;
803 cib_op_t *fn = NULL;
804 int lpc = 0;
805 static int max_msg_types = PCMK__NELEM(cib_file_ops);
806 cib_file_opaque_t *private = cib->variant_opaque;
807
808 crm_info("Handling %s operation for %s as %s",
809 (op? op : "invalid"), (section? section : "entire CIB"),
810 (user_name? user_name : "default user"));
811
812 cib__set_call_options(call_options, "file operation",
814
815 if (cib->state == cib_disconnected) {
816 return -ENOTCONN;
817 }
818
819 if (output_data != NULL) {
820 *output_data = NULL;
821 }
822
823 if (op == NULL) {
824 return -EINVAL;
825 }
826
827 for (lpc = 0; lpc < max_msg_types; lpc++) {
828 if (pcmk__str_eq(op, cib_file_ops[lpc].op, pcmk__str_casei)) {
829 fn = &(cib_file_ops[lpc].fn);
830 query = cib_file_ops[lpc].read_only;
831 break;
832 }
833 }
834
835 if (fn == NULL) {
836 return -EPROTONOSUPPORT;
837 }
838
839 cib->call_id++;
840 request = cib_create_op(cib->call_id, "dummy-token", op, host, section, data, call_options, user_name);
841 if(user_name) {
842 crm_xml_add(request, XML_ACL_TAG_USER, user_name);
843 }
844
845 /* Mirror the logic in cib_prepare_common() */
846 if (section != NULL && data != NULL && pcmk__str_eq(crm_element_name(data), XML_TAG_CIB, pcmk__str_none)) {
847 data = get_object_root(section, data);
848 }
849
850 rc = cib_perform_op(op, call_options, fn, query,
851 section, request, data, TRUE, &changed, in_mem_cib, &result_cib, &cib_diff,
852 &output);
853
854 free_xml(request);
856 validate_xml_verbose(result_cib);
857 }
858
859 if (rc != pcmk_ok) {
860 free_xml(result_cib);
861
862 } else if (query == FALSE) {
863 xml_log_patchset(LOG_DEBUG, "cib:diff", cib_diff);
864 free_xml(in_mem_cib);
865 in_mem_cib = result_cib;
867 }
868
869 free_xml(cib_diff);
870
871 if (cib->op_callback != NULL) {
872 cib->op_callback(NULL, cib->call_id, rc, output);
873 }
874
875 if (output_data && output) {
876 if(output == in_mem_cib) {
877 *output_data = copy_xml(output);
878 } else {
879 *output_data = output;
880 }
881
882 } else if(output != in_mem_cib) {
883 free_xml(output);
884 }
885
886 free(effective_user);
887 return rc;
888}
#define CIB_OP_MODIFY
Definition internal.h:25
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:280
#define CIB_OP_UPGRADE
Definition internal.h:30
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:315
cib_t * cib_new_variant(void)
Definition cib_client.c:352
#define CIB_OP_APPLY_DIFF
Definition internal.h:29
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:519
#define CIB_OP_ERASE
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:127
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:168
#define CIB_OP_CREATE
Definition internal.h:24
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:584
#define CIB_OP_REPLACE
Definition internal.h:28
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:92
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:222
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:514
int(* cib_op_t)(const char *, int, const char *, xmlNode *, xmlNode *, xmlNode *, xmlNode **, xmlNode **)
Definition internal.h:114
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:75
#define CIB_OP_QUERY
Definition internal.h:23
#define CIB_OP_BUMP
Definition internal.h:22
#define cib__set_call_options(cib_call_opts, call_for, flags_to_set)
Definition internal.h:102
#define CIB_OP_DELETE
Definition internal.h:26
xmlNode * get_object_root(const char *object_type, xmlNode *the_root)
Definition cib_utils.c:146
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:737
#define CIB_SERIES_BZIP
Definition cib_file.c:193
int cib_file_signoff(cib_t *cib)
Definition cib_file.c:695
#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:789
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:781
#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:580
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
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:237
void pcmk__sync_directory(const char *name)
Definition io.c:395
int pcmk__file_contents(const char *filename, char **contents)
Definition io.c:431
int pcmk__read_series_sequence(const char *directory, const char *series, unsigned int *seq)
Definition io.c:140
#define PCMK__NELEM(a)
Definition internal.h:38
int pcmk__write_sync(int fd, const char *contents)
Definition io.c:487
bool pcmk__verify_digest(xmlNode *input, const char *expected)
Definition digest.c:220
char * pcmk__series_filename(const char *directory, const char *series, int sequence, bool bzip)
Definition io.c:121
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:114
#define CRM_DAEMON_USER
Definition config.h:32
#define CRM_CONFIG_DIR
Definition config.h:20
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.
IPC interface to Pacemaker daemons.
#define crm_info(fmt, args...)
Definition logging.h:353
#define crm_warn(fmt, args...)
Definition logging.h:351
#define CRM_LOG_ASSERT(expr)
Definition logging.h:202
#define crm_perror(level, fmt, args...)
Send a system error message to both the log and stderr.
Definition logging.h:301
#define crm_debug(fmt, args...)
Definition logging.h:355
#define crm_err(fmt, args...)
Definition logging.h:350
#define crm_trace(fmt, args...)
Definition logging.h:356
#define XML_TAG_CIB
Definition msg_xml.h:109
#define XML_ACL_TAG_USER
Definition msg_xml.h:408
#define XML_ATTR_VALIDATION
Definition msg_xml.h:114
#define XML_ATTR_GENERATION_ADMIN
Definition msg_xml.h:121
#define XML_ATTR_NUMUPDATES
Definition msg_xml.h:122
#define XML_CIB_TAG_STATUS
Definition msg_xml.h:179
#define XML_ATTR_GENERATION
Definition msg_xml.h:120
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition nvpair.c:530
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:324
char * name
Definition pcmk_fence.c:31
int rc
Definition pcmk_fence.c:35
#define pcmk_err_cib_corrupt
Definition results.h:81
const char * pcmk_strerror(int rc)
Definition results.c:58
#define pcmk_err_generic
Definition results.h:70
#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:420
#define pcmk_err_cib_modified
Definition results.h:77
#define pcmk_err_schema_validation
Definition results.h:72
@ pcmk_rc_ok
Definition results.h:142
#define pcmk_err_cib_save
Definition results.h:79
#define pcmk_ok
Definition results.h:67
#define pcmk_err_cib_backup
Definition results.h:78
bool pcmk__ends_with_ext(const char *s, const char *match)
Definition strings.c:562
@ 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:119
int(* free)(cib_t *cib)
Definition cib_types.h:77
enum cib_conn_type type
Definition cib_types.h:136
enum cib_state state
Definition cib_types.h:135
void * variant_opaque
Definition cib_types.h:141
void * delegate_fn
Definition cib_types.h:142
cib_api_operations_t * cmds
Definition cib_types.h:147
enum cib_variant variant
Definition cib_types.h:137
int call_id
Definition cib_types.h:139
void(* op_callback)(const xmlNode *msg, int call_id, int rc, xmlNode *output)
Definition cib_types.h:145
Wrappers for and extensions to libxml2.
xmlNode * filename2xml(const char *filename)
Definition xml.c:1043
xmlNode * find_xml_node(xmlNode *cib, const char *node_path, gboolean must_find)
Definition xml.c:446
gboolean validate_xml_verbose(xmlNode *xml_blob)
Definition schemas.c:672
char * calculate_on_disk_digest(xmlNode *local_cib)
Calculate and return digest of XML tree, suitable for storing on disk.
Definition digest.c:151
int write_xml_fd(xmlNode *xml_node, const char *filename, int fd, gboolean compress)
Write XML to a file descriptor.
Definition xml.c:1270
int write_xml_file(xmlNode *xml_node, const char *filename, gboolean compress)
Write XML to a file.
Definition xml.c:1298
void free_xml(xmlNode *child)
Definition xml.c:823
gboolean validate_xml(xmlNode *xml_blob, const char *validation, gboolean to_logs)
Definition schemas.c:700
xmlNode * copy_xml(xmlNode *src_node)
Definition xml.c:829
xmlNode * create_xml_node(xmlNode *parent, const char *name)
Definition xml.c:696
void xml_log_patchset(uint8_t level, const char *function, xmlNode *xml)
Definition patchset.c:458
const char * pcmk__xe_add_last_written(xmlNode *xe)
Definition xml.c:1113