This source file includes following definitions.
- cib_file_inputfd
- cib_file_set_connection_dnotify
- cib_file_register_notification
- cib_file_verify_digest
- cib_file_read_and_verify
- cib_file_is_live
- cib_file_backup
- cib_file_prepare_xml
- cib_file_write_with_digest
- cib_file_new
- load_file_cib
- cib_file_signon
- cib_file_write_live
- cib_file_signoff
- cib_file_free
- cib_file_perform_op
- cib_file_perform_op_delegate
1
2
3
4
5
6
7
8
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>
30 #include <crm/common/xml_internal.h>
31
32 enum cib_file_flags {
33 cib_file_flag_dirty = (1 << 0),
34 cib_file_flag_live = (1 << 1),
35 };
36
37 typedef struct cib_file_opaque_s {
38 uint32_t flags;
39 char *filename;
40 } cib_file_opaque_t;
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
60 int 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
63 int 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
67 int cib_file_signon(cib_t * cib, const char *name, enum cib_conn_type type);
68 int cib_file_signoff(cib_t * cib);
69 int cib_file_free(cib_t * cib);
70
71 static int
72 cib_file_inputfd(cib_t * cib)
73 {
74 return -EPROTONOSUPPORT;
75 }
76
77 static int
78 cib_file_set_connection_dnotify(cib_t * cib, void (*dnotify) (gpointer user_data))
79 {
80 return -EPROTONOSUPPORT;
81 }
82
83 static int
84 cib_file_register_notification(cib_t * cib, const char *callback, int enabled)
85 {
86 return -EPROTONOSUPPORT;
87 }
88
89
90
91
92
93
94
95
96
97
98 static gboolean
99 cib_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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140 int
141 cib_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
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
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
171 if (sigfile == NULL) {
172 sigfile = local_sigfile = crm_strdup_printf("%s.sig", filename);
173 }
174
175
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
194
195
196
197 #define CIB_LIVE_NAME CIB_SERIES ".xml"
198
199
200
201
202
203
204
205
206
207 static gboolean
208 cib_file_is_live(const char *filename)
209 {
210 gboolean same = FALSE;
211
212 if (filename != NULL) {
213
214 char *real_filename = NULL;
215
216 if (pcmk__real_path(filename, &real_filename) == pcmk_rc_ok) {
217 char *real_livename = NULL;
218
219 if (pcmk__real_path(CRM_CONFIG_DIR "/" CIB_LIVE_NAME,
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
231
232
233
234 static uid_t cib_file_owner = 0;
235 static uid_t cib_file_group = 0;
236 static gboolean cib_do_chown = FALSE;
237
238
239
240
241
242
243
244
245
246
247 static int
248 cib_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
258 if (pcmk__read_series_sequence(cib_dirname, CIB_SERIES,
259 &seq) != pcmk_rc_ok) {
260
261 seq = 0;
262 }
263 backup_path = pcmk__series_filename(cib_dirname, CIB_SERIES, seq,
264 CIB_SERIES_BZIP);
265 backup_digest = crm_strdup_printf("%s.sig", backup_path);
266
267
268 unlink(backup_path);
269 unlink(backup_digest);
270
271
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
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
284 } else {
285 pcmk__write_series_sequence(cib_dirname, CIB_SERIES, ++seq,
286 CIB_SERIES_MAX);
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
319
320
321
322
323
324
325
326
327
328
329
330 static void
331 cib_file_prepare_xml(xmlNode *root)
332 {
333 xmlNode *cib_status_root = NULL;
334
335
336 crm_xml_add(root, XML_ATTR_NUMUPDATES, "0");
337 pcmk__xe_add_last_written(root);
338
339
340
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
348
349
350
351
352
353
354
355
356
357
358
359
360
361 int
362 cib_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
370 const char *epoch = crm_element_value(cib_root, XML_ATTR_GENERATION);
371 const char *admin_epoch = crm_element_value(cib_root,
372 XML_ATTR_GENERATION_ADMIN);
373
374
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
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
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
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
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
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
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
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
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
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
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 }
493
494 cib_t *
495 cib_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 }
517 private->flags = 0;
518 if (cib_file_is_live(cib_location)) {
519 cib_set_file_flags(private, cib_file_flag_live);
520 crm_trace("File %s detected as live CIB", cib_location);
521 }
522 private->filename = strdup(cib_location);
523
524
525 cib->delegate_fn = cib_file_perform_op_delegate;
526 cib->cmds->signon = cib_file_signon;
527 cib->cmds->signoff = cib_file_signoff;
528 cib->cmds->free = cib_file_free;
529 cib->cmds->inputfd = cib_file_inputfd;
530
531 cib->cmds->register_notification = cib_file_register_notification;
532 cib->cmds->set_connection_dnotify = cib_file_set_connection_dnotify;
533
534 return cib;
535 }
536
537 static xmlNode *in_mem_cib = NULL;
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553 static int
554 load_file_cib(const char *filename)
555 {
556 struct stat buf;
557 xmlNode *root = NULL;
558
559
560 if (strcmp(filename, "-") && (stat(filename, &buf) < 0)) {
561 return -ENXIO;
562 }
563
564
565 root = filename2xml(filename);
566 if (root == NULL) {
567 return -pcmk_err_schema_validation;
568 }
569
570
571 if (find_xml_node(root, XML_CIB_TAG_STATUS, FALSE) == NULL) {
572 create_xml_node(root, XML_CIB_TAG_STATUS);
573 }
574
575
576 if (validate_xml(root, NULL, TRUE) == FALSE) {
577 const char *schema = crm_element_value(root, XML_ATTR_VALIDATION);
578
579 crm_err("CIB does not validate against %s", schema);
580 free_xml(root);
581 return -pcmk_err_schema_validation;
582 }
583
584
585 in_mem_cib = root;
586 return pcmk_ok;
587 }
588
589 int
590 cib_file_signon(cib_t * cib, const char *name, enum cib_conn_type type)
591 {
592 int rc = pcmk_ok;
593 cib_file_opaque_t *private = cib->variant_opaque;
594
595 if (private->filename == NULL) {
596 rc = -EINVAL;
597 } else {
598 rc = load_file_cib(private->filename);
599 }
600
601 if (rc == pcmk_ok) {
602 crm_debug("Opened connection to local file '%s' for %s",
603 private->filename, name);
604 cib->state = cib_connected_command;
605 cib->type = cib_command;
606
607 } else {
608 crm_info("Connection to local file '%s' for %s failed: %s\n",
609 private->filename, name, pcmk_strerror(rc));
610 }
611 return rc;
612 }
613
614
615
616
617
618
619
620
621
622 static int
623 cib_file_write_live(char *path)
624 {
625 uid_t uid = geteuid();
626 struct passwd *daemon_pwent;
627 char *sep = strrchr(path, '/');
628 const char *cib_dirname, *cib_filename;
629 int rc = 0;
630
631
632 errno = 0;
633 daemon_pwent = getpwnam(CRM_DAEMON_USER);
634 if (daemon_pwent == NULL) {
635 crm_perror(LOG_ERR, "Could not find %s user", CRM_DAEMON_USER);
636 return -1;
637 }
638
639
640
641
642
643 if ((uid != 0) && (uid != daemon_pwent->pw_uid)) {
644 crm_perror(LOG_ERR, "Must be root or %s to modify live CIB",
645 CRM_DAEMON_USER);
646 return 0;
647 }
648
649
650
651
652
653 if (sep == NULL) {
654 cib_dirname = "./";
655 cib_filename = path;
656 } else if (sep == path) {
657 cib_dirname = "/";
658 cib_filename = path + 1;
659 } else {
660 *sep = '\0';
661 cib_dirname = path;
662 cib_filename = sep + 1;
663 }
664
665
666 if (uid == 0) {
667 cib_file_owner = daemon_pwent->pw_uid;
668 cib_file_group = daemon_pwent->pw_gid;
669 cib_do_chown = TRUE;
670 }
671
672
673 if (cib_file_write_with_digest(in_mem_cib, cib_dirname,
674 cib_filename) != pcmk_ok) {
675 rc = -1;
676 }
677
678
679 if (uid == 0) {
680 cib_do_chown = FALSE;
681 }
682
683
684 if ((sep != NULL) && (*sep == '\0')) {
685 *sep = '/';
686 }
687
688 return rc;
689 }
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704 int
705 cib_file_signoff(cib_t * cib)
706 {
707 int rc = pcmk_ok;
708 cib_file_opaque_t *private = cib->variant_opaque;
709
710 crm_debug("Disconnecting from the CIB manager");
711 cib->state = cib_disconnected;
712 cib->type = cib_no_connection;
713
714
715 if (pcmk_is_set(private->flags, cib_file_flag_dirty)) {
716
717
718 if (pcmk_is_set(private->flags, cib_file_flag_live)) {
719 if (cib_file_write_live(private->filename) < 0) {
720 rc = pcmk_err_generic;
721 }
722
723
724 } else {
725 gboolean do_bzip = pcmk__ends_with_ext(private->filename, ".bz2");
726
727 if (write_xml_file(in_mem_cib, private->filename, do_bzip) <= 0) {
728 rc = pcmk_err_generic;
729 }
730 }
731
732 if (rc == pcmk_ok) {
733 crm_info("Wrote CIB to %s", private->filename);
734 cib_clear_file_flags(private, cib_file_flag_dirty);
735 } else {
736 crm_err("Could not write CIB to %s", private->filename);
737 }
738 }
739
740
741 free_xml(in_mem_cib);
742 in_mem_cib = NULL;
743 return rc;
744 }
745
746 int
747 cib_file_free(cib_t * cib)
748 {
749 int rc = pcmk_ok;
750
751 if (cib->state != cib_disconnected) {
752 rc = cib_file_signoff(cib);
753 }
754
755 if (rc == pcmk_ok) {
756 cib_file_opaque_t *private = cib->variant_opaque;
757
758 free(private->filename);
759 free(cib->cmds);
760 free(private);
761 free(cib);
762
763 } else {
764 fprintf(stderr, "Couldn't sign off: %d\n", rc);
765 }
766
767 return rc;
768 }
769
770 struct cib_func_entry {
771 const char *op;
772 gboolean read_only;
773 cib_op_t fn;
774 };
775
776
777 static struct cib_func_entry cib_file_ops[] = {
778 {CIB_OP_QUERY, TRUE, cib_process_query},
779 {CIB_OP_MODIFY, FALSE, cib_process_modify},
780 {CIB_OP_APPLY_DIFF, FALSE, cib_process_diff},
781 {CIB_OP_BUMP, FALSE, cib_process_bump},
782 {CIB_OP_REPLACE, FALSE, cib_process_replace},
783 {CIB_OP_CREATE, FALSE, cib_process_create},
784 {CIB_OP_DELETE, FALSE, cib_process_delete},
785 {CIB_OP_ERASE, FALSE, cib_process_erase},
786 {CIB_OP_UPGRADE, FALSE, cib_process_upgrade},
787 };
788
789
790 int
791 cib_file_perform_op(cib_t * cib, const char *op, const char *host, const char *section,
792 xmlNode * data, xmlNode ** output_data, int call_options)
793 {
794 return cib_file_perform_op_delegate(cib, op, host, section, data, output_data, call_options,
795 NULL);
796 }
797
798 int
799 cib_file_perform_op_delegate(cib_t * cib, const char *op, const char *host, const char *section,
800 xmlNode * data, xmlNode ** output_data, int call_options,
801 const char *user_name)
802 {
803 int rc = pcmk_ok;
804 char *effective_user = NULL;
805 gboolean query = FALSE;
806 gboolean changed = FALSE;
807 xmlNode *request = NULL;
808 xmlNode *output = NULL;
809 xmlNode *cib_diff = NULL;
810 xmlNode *result_cib = NULL;
811 cib_op_t *fn = NULL;
812 int lpc = 0;
813 static int max_msg_types = PCMK__NELEM(cib_file_ops);
814 cib_file_opaque_t *private = cib->variant_opaque;
815
816 crm_info("Handling %s operation for %s as %s",
817 (op? op : "invalid"), (section? section : "entire CIB"),
818 (user_name? user_name : "default user"));
819
820 cib__set_call_options(call_options, "file operation",
821 cib_no_mtime|cib_inhibit_bcast|cib_scope_local);
822
823 if (cib->state == cib_disconnected) {
824 return -ENOTCONN;
825 }
826
827 if (output_data != NULL) {
828 *output_data = NULL;
829 }
830
831 if (op == NULL) {
832 return -EINVAL;
833 }
834
835 for (lpc = 0; lpc < max_msg_types; lpc++) {
836 if (pcmk__str_eq(op, cib_file_ops[lpc].op, pcmk__str_casei)) {
837 fn = &(cib_file_ops[lpc].fn);
838 query = cib_file_ops[lpc].read_only;
839 break;
840 }
841 }
842
843 if (fn == NULL) {
844 return -EPROTONOSUPPORT;
845 }
846
847 cib->call_id++;
848 request = cib_create_op(cib->call_id, "dummy-token", op, host, section, data, call_options, user_name);
849 if(user_name) {
850 crm_xml_add(request, XML_ACL_TAG_USER, user_name);
851 }
852
853
854 if (section != NULL && data != NULL && pcmk__str_eq(crm_element_name(data), XML_TAG_CIB, pcmk__str_none)) {
855 data = get_object_root(section, data);
856 }
857
858 rc = cib_perform_op(op, call_options, fn, query,
859 section, request, data, TRUE, &changed, in_mem_cib, &result_cib, &cib_diff,
860 &output);
861
862 free_xml(request);
863 if (rc == -pcmk_err_schema_validation) {
864 validate_xml_verbose(result_cib);
865 }
866
867 if (rc != pcmk_ok) {
868 free_xml(result_cib);
869
870 } else if (query == FALSE) {
871 xml_log_patchset(LOG_DEBUG, "cib:diff", cib_diff);
872 free_xml(in_mem_cib);
873 in_mem_cib = result_cib;
874 cib_set_file_flags(private, cib_file_flag_dirty);
875 }
876
877 free_xml(cib_diff);
878
879 if (cib->op_callback != NULL) {
880 cib->op_callback(NULL, cib->call_id, rc, output);
881 }
882
883 if (output_data && output) {
884 if(output == in_mem_cib) {
885 *output_data = copy_xml(output);
886 } else {
887 *output_data = output;
888 }
889
890 } else if(output != in_mem_cib) {
891 free_xml(output);
892 }
893
894 free(effective_user);
895 return rc;
896 }