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 #include <crm_internal.h>
10 #include <unistd.h>
11 #include <limits.h>
12 #include <stdlib.h>
13 #include <stdint.h>
14 #include <stdio.h>
15 #include <stdarg.h>
16 #include <string.h>
17 #include <pwd.h>
18
19 #include <sys/stat.h>
20 #include <sys/types.h>
21 #include <glib.h>
22
23 #include <crm/crm.h>
24 #include <crm/cib/internal.h>
25 #include <crm/msg_xml.h>
26 #include <crm/common/ipc.h>
27 #include <crm/common/xml.h>
28 #include <crm/common/xml_internal.h>
29
30 enum cib_file_flags {
31 cib_file_flag_dirty = (1 << 0),
32 cib_file_flag_live = (1 << 1),
33 };
34
35 typedef struct cib_file_opaque_s {
36 uint32_t flags;
37 char *filename;
38 } cib_file_opaque_t;
39
40 #define cib_set_file_flags(cibfile, flags_to_set) do { \
41 (cibfile)->flags = pcmk__set_flags_as(__func__, __LINE__, \
42 LOG_TRACE, "CIB file", \
43 cibfile->filename, \
44 (cibfile)->flags, \
45 (flags_to_set), \
46 #flags_to_set); \
47 } while (0)
48
49 #define cib_clear_file_flags(cibfile, flags_to_clear) do { \
50 (cibfile)->flags = pcmk__clear_flags_as(__func__, __LINE__, \
51 LOG_TRACE, "CIB file", \
52 cibfile->filename, \
53 (cibfile)->flags, \
54 (flags_to_clear), \
55 #flags_to_clear); \
56 } while (0)
57
58 int cib_file_perform_op(cib_t * cib, const char *op, const char *host, const char *section,
59 xmlNode * data, xmlNode ** output_data, int call_options);
60
61 int cib_file_perform_op_delegate(cib_t * cib, const char *op, const char *host, const char *section,
62 xmlNode * data, xmlNode ** output_data, int call_options,
63 const char *user_name);
64
65 int cib_file_signon(cib_t * cib, const char *name, enum cib_conn_type type);
66 int cib_file_signoff(cib_t * cib);
67 int cib_file_free(cib_t * cib);
68
69 static int
70 cib_file_inputfd(cib_t * cib)
71 {
72 return -EPROTONOSUPPORT;
73 }
74
75 static int
76 cib_file_set_connection_dnotify(cib_t * cib, void (*dnotify) (gpointer user_data))
77 {
78 return -EPROTONOSUPPORT;
79 }
80
81 static int
82 cib_file_register_notification(cib_t * cib, const char *callback, int enabled)
83 {
84 return -EPROTONOSUPPORT;
85 }
86
87
88
89
90
91
92
93
94
95
96 static gboolean
97 cib_file_verify_digest(xmlNode *root, const char *sigfile)
98 {
99 gboolean passed = FALSE;
100 char *expected;
101 int rc = pcmk__file_contents(sigfile, &expected);
102
103 switch (rc) {
104 case pcmk_rc_ok:
105 if (expected == NULL) {
106 crm_err("On-disk digest at %s is empty", sigfile);
107 return FALSE;
108 }
109 break;
110 case ENOENT:
111 crm_warn("No on-disk digest present at %s", sigfile);
112 return TRUE;
113 default:
114 crm_err("Could not read on-disk digest from %s: %s",
115 sigfile, pcmk_rc_str(rc));
116 return FALSE;
117 }
118 passed = pcmk__verify_digest(root, expected);
119 free(expected);
120 return passed;
121 }
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138 int
139 cib_file_read_and_verify(const char *filename, const char *sigfile, xmlNode **root)
140 {
141 int s_res;
142 struct stat buf;
143 char *local_sigfile = NULL;
144 xmlNode *local_root = NULL;
145
146 CRM_ASSERT(filename != NULL);
147 if (root) {
148 *root = NULL;
149 }
150
151
152 s_res = stat(filename, &buf);
153 if (s_res < 0) {
154 crm_perror(LOG_WARNING, "Could not verify cluster configuration file %s", filename);
155 return -errno;
156 } else if (buf.st_size == 0) {
157 crm_warn("Cluster configuration file %s is corrupt (size is zero)", filename);
158 return -pcmk_err_cib_corrupt;
159 }
160
161
162 local_root = filename2xml(filename);
163 if (local_root == NULL) {
164 crm_warn("Cluster configuration file %s is corrupt (unparseable as XML)", filename);
165 return -pcmk_err_cib_corrupt;
166 }
167
168
169 if (sigfile == NULL) {
170 sigfile = local_sigfile = crm_strdup_printf("%s.sig", filename);
171 }
172
173
174 if (cib_file_verify_digest(local_root, sigfile) == FALSE) {
175 free(local_sigfile);
176 free_xml(local_root);
177 return -pcmk_err_cib_modified;
178 }
179
180 free(local_sigfile);
181 if (root) {
182 *root = local_root;
183 } else {
184 free_xml(local_root);
185 }
186 return pcmk_ok;
187 }
188
189 #define CIB_SERIES "cib"
190 #define CIB_SERIES_MAX 100
191 #define CIB_SERIES_BZIP FALSE
192
193
194
195 #define CIB_LIVE_NAME CIB_SERIES ".xml"
196
197
198
199
200
201
202
203
204
205 static gboolean
206 cib_file_is_live(const char *filename)
207 {
208 gboolean same = FALSE;
209
210 if (filename != NULL) {
211
212 char *real_filename = NULL;
213
214 if (pcmk__real_path(filename, &real_filename) == pcmk_rc_ok) {
215 char *real_livename = NULL;
216
217 if (pcmk__real_path(CRM_CONFIG_DIR "/" CIB_LIVE_NAME,
218 &real_livename) == pcmk_rc_ok) {
219 same = !strcmp(real_filename, real_livename);
220 free(real_livename);
221 }
222 free(real_filename);
223 }
224 }
225 return same;
226 }
227
228
229
230
231
232 static uid_t cib_file_owner = 0;
233 static uid_t cib_file_group = 0;
234 static gboolean cib_do_chown = FALSE;
235
236
237
238
239
240
241
242
243
244
245 static int
246 cib_file_backup(const char *cib_dirname, const char *cib_filename)
247 {
248 int rc = 0;
249 unsigned int seq;
250 char *cib_path = crm_strdup_printf("%s/%s", cib_dirname, cib_filename);
251 char *cib_digest = crm_strdup_printf("%s.sig", cib_path);
252 char *backup_path;
253 char *backup_digest;
254
255
256 if (pcmk__read_series_sequence(cib_dirname, CIB_SERIES,
257 &seq) != pcmk_rc_ok) {
258
259 seq = 0;
260 }
261 backup_path = pcmk__series_filename(cib_dirname, CIB_SERIES, seq,
262 CIB_SERIES_BZIP);
263 backup_digest = crm_strdup_printf("%s.sig", backup_path);
264
265
266 unlink(backup_path);
267 unlink(backup_digest);
268
269
270 if ((link(cib_path, backup_path) < 0) && (errno != ENOENT)) {
271 crm_perror(LOG_ERR, "Could not archive %s by linking to %s",
272 cib_path, backup_path);
273 rc = -1;
274
275
276 } else if ((link(cib_digest, backup_digest) < 0) && (errno != ENOENT)) {
277 crm_perror(LOG_ERR, "Could not archive %s by linking to %s",
278 cib_digest, backup_digest);
279 rc = -1;
280
281
282 } else {
283 pcmk__write_series_sequence(cib_dirname, CIB_SERIES, ++seq,
284 CIB_SERIES_MAX);
285 if (cib_do_chown) {
286 int rc2;
287
288 if ((chown(backup_path, cib_file_owner, cib_file_group) < 0)
289 && (errno != ENOENT)) {
290 crm_perror(LOG_ERR, "Could not set owner of %s", backup_path);
291 rc = -1;
292 }
293 if ((chown(backup_digest, cib_file_owner, cib_file_group) < 0)
294 && (errno != ENOENT)) {
295 crm_perror(LOG_ERR, "Could not set owner of %s", backup_digest);
296 rc = -1;
297 }
298 rc2 = pcmk__chown_series_sequence(cib_dirname, CIB_SERIES,
299 cib_file_owner, cib_file_group);
300 if (rc2 != pcmk_rc_ok) {
301 crm_err("Could not set owner of sequence file in %s: %s",
302 cib_dirname, pcmk_rc_str(rc2));
303 rc = -1;
304 }
305 }
306 pcmk__sync_directory(cib_dirname);
307 crm_info("Archived previous version as %s", backup_path);
308 }
309
310 free(cib_path);
311 free(cib_digest);
312 free(backup_path);
313 free(backup_digest);
314 return rc;
315 }
316
317
318
319
320
321
322
323
324
325
326
327
328 static void
329 cib_file_prepare_xml(xmlNode *root)
330 {
331 xmlNode *cib_status_root = NULL;
332
333
334 crm_xml_add(root, XML_ATTR_NUMUPDATES, "0");
335 pcmk__xe_add_last_written(root);
336
337
338
339 cib_status_root = find_xml_node(root, XML_CIB_TAG_STATUS, TRUE);
340 CRM_LOG_ASSERT(cib_status_root != NULL);
341 if (cib_status_root != NULL) {
342 free_xml(cib_status_root);
343 }
344 }
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359 int
360 cib_file_write_with_digest(xmlNode *cib_root, const char *cib_dirname,
361 const char *cib_filename)
362 {
363 int exit_rc = pcmk_ok;
364 int rc, fd;
365 char *digest = NULL;
366
367
368 const char *epoch = crm_element_value(cib_root, XML_ATTR_GENERATION);
369 const char *admin_epoch = crm_element_value(cib_root,
370 XML_ATTR_GENERATION_ADMIN);
371
372
373 char *cib_path = crm_strdup_printf("%s/%s", cib_dirname, cib_filename);
374 char *digest_path = crm_strdup_printf("%s.sig", cib_path);
375
376
377 char *tmp_cib = crm_strdup_printf("%s/cib.XXXXXX", cib_dirname);
378 char *tmp_digest = crm_strdup_printf("%s/cib.XXXXXX", cib_dirname);
379
380 CRM_ASSERT((cib_path != NULL) && (digest_path != NULL)
381 && (tmp_cib != NULL) && (tmp_digest != NULL));
382
383
384 crm_trace("Reading cluster configuration file %s", cib_path);
385 rc = cib_file_read_and_verify(cib_path, NULL, NULL);
386 if ((rc != pcmk_ok) && (rc != -ENOENT)) {
387 crm_err("%s was manually modified while the cluster was active!",
388 cib_path);
389 exit_rc = pcmk_err_cib_modified;
390 goto cleanup;
391 }
392
393
394 if (cib_file_backup(cib_dirname, cib_filename) < 0) {
395 exit_rc = pcmk_err_cib_backup;
396 goto cleanup;
397 }
398
399 crm_debug("Writing CIB to disk");
400 umask(S_IWGRP | S_IWOTH | S_IROTH);
401 cib_file_prepare_xml(cib_root);
402
403
404 fd = mkstemp(tmp_cib);
405 if (fd < 0) {
406 crm_perror(LOG_ERR, "Couldn't open temporary file %s for writing CIB",
407 tmp_cib);
408 exit_rc = pcmk_err_cib_save;
409 goto cleanup;
410 }
411
412
413 if (fchmod(fd, S_IRUSR | S_IWUSR) < 0) {
414 crm_perror(LOG_ERR, "Couldn't protect temporary file %s for writing CIB",
415 tmp_cib);
416 exit_rc = pcmk_err_cib_save;
417 goto cleanup;
418 }
419 if (cib_do_chown && (fchown(fd, cib_file_owner, cib_file_group) < 0)) {
420 crm_perror(LOG_ERR, "Couldn't protect temporary file %s for writing CIB",
421 tmp_cib);
422 exit_rc = pcmk_err_cib_save;
423 goto cleanup;
424 }
425
426
427 if (write_xml_fd(cib_root, tmp_cib, fd, FALSE) <= 0) {
428 crm_err("Changes couldn't be written to %s", tmp_cib);
429 exit_rc = pcmk_err_cib_save;
430 goto cleanup;
431 }
432
433
434 digest = calculate_on_disk_digest(cib_root);
435 CRM_ASSERT(digest != NULL);
436 crm_info("Wrote version %s.%s.0 of the CIB to disk (digest: %s)",
437 (admin_epoch ? admin_epoch : "0"), (epoch ? epoch : "0"), digest);
438
439
440 fd = mkstemp(tmp_digest);
441 if (fd < 0) {
442 crm_perror(LOG_ERR, "Could not create temporary file for CIB digest");
443 exit_rc = pcmk_err_cib_save;
444 goto cleanup;
445 }
446 if (cib_do_chown && (fchown(fd, cib_file_owner, cib_file_group) < 0)) {
447 crm_perror(LOG_ERR, "Couldn't protect temporary file %s for writing CIB",
448 tmp_cib);
449 exit_rc = pcmk_err_cib_save;
450 close(fd);
451 goto cleanup;
452 }
453 rc = pcmk__write_sync(fd, digest);
454 if (rc != pcmk_rc_ok) {
455 crm_err("Could not write digest to %s: %s",
456 tmp_digest, pcmk_rc_str(rc));
457 exit_rc = pcmk_err_cib_save;
458 close(fd);
459 goto cleanup;
460 }
461 close(fd);
462 crm_debug("Wrote digest %s to disk", digest);
463
464
465 crm_info("Reading cluster configuration file %s (digest: %s)",
466 tmp_cib, tmp_digest);
467 rc = cib_file_read_and_verify(tmp_cib, tmp_digest, NULL);
468 CRM_ASSERT(rc == 0);
469
470
471 crm_debug("Activating %s", tmp_cib);
472 if (rename(tmp_cib, cib_path) < 0) {
473 crm_perror(LOG_ERR, "Couldn't rename %s as %s", tmp_cib, cib_path);
474 exit_rc = pcmk_err_cib_save;
475 }
476 if (rename(tmp_digest, digest_path) < 0) {
477 crm_perror(LOG_ERR, "Couldn't rename %s as %s", tmp_digest,
478 digest_path);
479 exit_rc = pcmk_err_cib_save;
480 }
481 pcmk__sync_directory(cib_dirname);
482
483 cleanup:
484 free(cib_path);
485 free(digest_path);
486 free(digest);
487 free(tmp_digest);
488 free(tmp_cib);
489 return exit_rc;
490 }
491
492 cib_t *
493 cib_file_new(const char *cib_location)
494 {
495 cib_file_opaque_t *private = NULL;
496 cib_t *cib = cib_new_variant();
497
498 private = calloc(1, sizeof(cib_file_opaque_t));
499 CRM_ASSERT((cib != NULL) && (private != NULL));
500
501 cib->variant = cib_file;
502 cib->variant_opaque = private;
503
504 if (cib_location == NULL) {
505 cib_location = getenv("CIB_file");
506 }
507 private->flags = 0;
508 if (cib_file_is_live(cib_location)) {
509 cib_set_file_flags(private, cib_file_flag_live);
510 crm_trace("File %s detected as live CIB", cib_location);
511 }
512 private->filename = strdup(cib_location);
513
514
515 cib->delegate_fn = cib_file_perform_op_delegate;
516 cib->cmds->signon = cib_file_signon;
517 cib->cmds->signoff = cib_file_signoff;
518 cib->cmds->free = cib_file_free;
519 cib->cmds->inputfd = cib_file_inputfd;
520
521 cib->cmds->register_notification = cib_file_register_notification;
522 cib->cmds->set_connection_dnotify = cib_file_set_connection_dnotify;
523
524 return cib;
525 }
526
527 static xmlNode *in_mem_cib = NULL;
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543 static int
544 load_file_cib(const char *filename)
545 {
546 struct stat buf;
547 xmlNode *root = NULL;
548
549
550 if (stat(filename, &buf) < 0) {
551 return -ENXIO;
552 }
553
554
555 root = filename2xml(filename);
556 if (root == NULL) {
557 return -pcmk_err_schema_validation;
558 }
559
560
561 if (find_xml_node(root, XML_CIB_TAG_STATUS, FALSE) == NULL) {
562 create_xml_node(root, XML_CIB_TAG_STATUS);
563 }
564
565
566 if (validate_xml(root, NULL, TRUE) == FALSE) {
567 const char *schema = crm_element_value(root, XML_ATTR_VALIDATION);
568
569 crm_err("CIB does not validate against %s", schema);
570 free_xml(root);
571 return -pcmk_err_schema_validation;
572 }
573
574
575 in_mem_cib = root;
576 return pcmk_ok;
577 }
578
579 int
580 cib_file_signon(cib_t * cib, const char *name, enum cib_conn_type type)
581 {
582 int rc = pcmk_ok;
583 cib_file_opaque_t *private = cib->variant_opaque;
584
585 if (private->filename == NULL) {
586 rc = -EINVAL;
587 } else {
588 rc = load_file_cib(private->filename);
589 }
590
591 if (rc == pcmk_ok) {
592 crm_debug("Opened connection to local file '%s' for %s",
593 private->filename, name);
594 cib->state = cib_connected_command;
595 cib->type = cib_command;
596
597 } else {
598 crm_info("Connection to local file '%s' for %s failed: %s\n",
599 private->filename, name, pcmk_strerror(rc));
600 }
601 return rc;
602 }
603
604
605
606
607
608
609
610
611
612 static int
613 cib_file_write_live(char *path)
614 {
615 uid_t uid = geteuid();
616 struct passwd *daemon_pwent;
617 char *sep = strrchr(path, '/');
618 const char *cib_dirname, *cib_filename;
619 int rc = 0;
620
621
622 errno = 0;
623 daemon_pwent = getpwnam(CRM_DAEMON_USER);
624 if (daemon_pwent == NULL) {
625 crm_perror(LOG_ERR, "Could not find %s user", CRM_DAEMON_USER);
626 return -1;
627 }
628
629
630
631
632
633 if ((uid != 0) && (uid != daemon_pwent->pw_uid)) {
634 crm_perror(LOG_ERR, "Must be root or %s to modify live CIB",
635 CRM_DAEMON_USER);
636 return 0;
637 }
638
639
640
641
642
643 if (sep == NULL) {
644 cib_dirname = "./";
645 cib_filename = path;
646 } else if (sep == path) {
647 cib_dirname = "/";
648 cib_filename = path + 1;
649 } else {
650 *sep = '\0';
651 cib_dirname = path;
652 cib_filename = sep + 1;
653 }
654
655
656 if (uid == 0) {
657 cib_file_owner = daemon_pwent->pw_uid;
658 cib_file_group = daemon_pwent->pw_gid;
659 cib_do_chown = TRUE;
660 }
661
662
663 if (cib_file_write_with_digest(in_mem_cib, cib_dirname,
664 cib_filename) != pcmk_ok) {
665 rc = -1;
666 }
667
668
669 if (uid == 0) {
670 cib_do_chown = FALSE;
671 }
672
673
674 if ((sep != NULL) && (*sep == '\0')) {
675 *sep = '/';
676 }
677
678 return rc;
679 }
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694 int
695 cib_file_signoff(cib_t * cib)
696 {
697 int rc = pcmk_ok;
698 cib_file_opaque_t *private = cib->variant_opaque;
699
700 crm_debug("Disconnecting from the CIB manager");
701 cib->state = cib_disconnected;
702 cib->type = cib_no_connection;
703
704
705 if (pcmk_is_set(private->flags, cib_file_flag_dirty)) {
706
707
708 if (pcmk_is_set(private->flags, cib_file_flag_live)) {
709 if (cib_file_write_live(private->filename) < 0) {
710 rc = pcmk_err_generic;
711 }
712
713
714 } else {
715 gboolean do_bzip = pcmk__ends_with_ext(private->filename, ".bz2");
716
717 if (write_xml_file(in_mem_cib, private->filename, do_bzip) <= 0) {
718 rc = pcmk_err_generic;
719 }
720 }
721
722 if (rc == pcmk_ok) {
723 crm_info("Wrote CIB to %s", private->filename);
724 cib_clear_file_flags(private, cib_file_flag_dirty);
725 } else {
726 crm_err("Could not write CIB to %s", private->filename);
727 }
728 }
729
730
731 free_xml(in_mem_cib);
732 in_mem_cib = NULL;
733 return rc;
734 }
735
736 int
737 cib_file_free(cib_t * cib)
738 {
739 int rc = pcmk_ok;
740
741 if (cib->state != cib_disconnected) {
742 rc = cib_file_signoff(cib);
743 }
744
745 if (rc == pcmk_ok) {
746 cib_file_opaque_t *private = cib->variant_opaque;
747
748 free(private->filename);
749 free(cib->cmds);
750 free(private);
751 free(cib);
752
753 } else {
754 fprintf(stderr, "Couldn't sign off: %d\n", rc);
755 }
756
757 return rc;
758 }
759
760 struct cib_func_entry {
761 const char *op;
762 gboolean read_only;
763 cib_op_t fn;
764 };
765
766
767 static struct cib_func_entry cib_file_ops[] = {
768 {CIB_OP_QUERY, TRUE, cib_process_query},
769 {CIB_OP_MODIFY, FALSE, cib_process_modify},
770 {CIB_OP_APPLY_DIFF, FALSE, cib_process_diff},
771 {CIB_OP_BUMP, FALSE, cib_process_bump},
772 {CIB_OP_REPLACE, FALSE, cib_process_replace},
773 {CIB_OP_CREATE, FALSE, cib_process_create},
774 {CIB_OP_DELETE, FALSE, cib_process_delete},
775 {CIB_OP_ERASE, FALSE, cib_process_erase},
776 {CIB_OP_UPGRADE, FALSE, cib_process_upgrade},
777 };
778
779
780 int
781 cib_file_perform_op(cib_t * cib, const char *op, const char *host, const char *section,
782 xmlNode * data, xmlNode ** output_data, int call_options)
783 {
784 return cib_file_perform_op_delegate(cib, op, host, section, data, output_data, call_options,
785 NULL);
786 }
787
788 int
789 cib_file_perform_op_delegate(cib_t * cib, const char *op, const char *host, const char *section,
790 xmlNode * data, xmlNode ** output_data, int call_options,
791 const char *user_name)
792 {
793 int rc = pcmk_ok;
794 char *effective_user = NULL;
795 gboolean query = FALSE;
796 gboolean changed = FALSE;
797 xmlNode *request = NULL;
798 xmlNode *output = NULL;
799 xmlNode *cib_diff = NULL;
800 xmlNode *result_cib = NULL;
801 cib_op_t *fn = NULL;
802 int lpc = 0;
803 static int max_msg_types = DIMOF(cib_file_ops);
804 cib_file_opaque_t *private = cib->variant_opaque;
805
806 #if ENABLE_ACL
807 crm_info("Handling %s operation for %s as %s",
808 (op? op : "invalid"), (section? section : "entire CIB"),
809 (user_name? user_name : "default user"));
810 #else
811 crm_info("Handling %s operation for %s",
812 (op? op : "invalid"), (section? section : "entire CIB"));
813 #endif
814
815 cib__set_call_options(call_options, "file operation",
816 cib_no_mtime|cib_inhibit_bcast|cib_scope_local);
817
818 if (cib->state == cib_disconnected) {
819 return -ENOTCONN;
820 }
821
822 if (output_data != NULL) {
823 *output_data = NULL;
824 }
825
826 if (op == NULL) {
827 return -EINVAL;
828 }
829
830 for (lpc = 0; lpc < max_msg_types; lpc++) {
831 if (pcmk__str_eq(op, cib_file_ops[lpc].op, pcmk__str_casei)) {
832 fn = &(cib_file_ops[lpc].fn);
833 query = cib_file_ops[lpc].read_only;
834 break;
835 }
836 }
837
838 if (fn == NULL) {
839 return -EPROTONOSUPPORT;
840 }
841
842 cib->call_id++;
843 request = cib_create_op(cib->call_id, "dummy-token", op, host, section, data, call_options, user_name);
844 #if ENABLE_ACL
845 if(user_name) {
846 crm_xml_add(request, XML_ACL_TAG_USER, user_name);
847 }
848 #endif
849
850
851 if (section != NULL && data != NULL && pcmk__str_eq(crm_element_name(data), XML_TAG_CIB, pcmk__str_none)) {
852 data = get_object_root(section, data);
853 }
854
855 rc = cib_perform_op(op, call_options, fn, query,
856 section, request, data, TRUE, &changed, in_mem_cib, &result_cib, &cib_diff,
857 &output);
858
859 free_xml(request);
860 if (rc == -pcmk_err_schema_validation) {
861 validate_xml_verbose(result_cib);
862 }
863
864 if (rc != pcmk_ok) {
865 free_xml(result_cib);
866
867 } else if (query == FALSE) {
868 xml_log_patchset(LOG_DEBUG, "cib:diff", cib_diff);
869 free_xml(in_mem_cib);
870 in_mem_cib = result_cib;
871 cib_set_file_flags(private, cib_file_flag_dirty);
872 }
873
874 free_xml(cib_diff);
875
876 if (cib->op_callback != NULL) {
877 cib->op_callback(NULL, cib->call_id, rc, output);
878 }
879
880 if (output_data && output) {
881 if(output == in_mem_cib) {
882 *output_data = copy_xml(output);
883 } else {
884 *output_data = output;
885 }
886
887 } else if(output != in_mem_cib) {
888 free_xml(output);
889 }
890
891 free(effective_user);
892 return rc;
893 }