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 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)) {
511 cib_set_file_flags(private, cib_file_flag_live);
512 crm_trace("File %s detected as live CIB", cib_location);
513 }
514 private->filename = strdup(cib_location);
515
516
517 cib->delegate_fn = cib_file_perform_op_delegate;
518 cib->cmds->signon = cib_file_signon;
519 cib->cmds->signoff = cib_file_signoff;
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
529 static xmlNode *in_mem_cib = NULL;
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545 static int
546 load_file_cib(const char *filename)
547 {
548 struct stat buf;
549 xmlNode *root = NULL;
550
551
552 if (strcmp(filename, "-") && (stat(filename, &buf) < 0)) {
553 return -ENXIO;
554 }
555
556
557 root = filename2xml(filename);
558 if (root == NULL) {
559 return -pcmk_err_schema_validation;
560 }
561
562
563 if (find_xml_node(root, XML_CIB_TAG_STATUS, FALSE) == NULL) {
564 create_xml_node(root, XML_CIB_TAG_STATUS);
565 }
566
567
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);
573 return -pcmk_err_schema_validation;
574 }
575
576
577 in_mem_cib = root;
578 return pcmk_ok;
579 }
580
581 int
582 cib_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);
596 cib->state = cib_connected_command;
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
606
607
608
609
610
611
612
613
614 static int
615 cib_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
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
632
633
634
635 if ((uid != 0) && (uid != daemon_pwent->pw_uid)) {
636 crm_perror(LOG_ERR, "Must be root or %s to modify live CIB",
637 CRM_DAEMON_USER);
638 return 0;
639 }
640
641
642
643
644
645 if (sep == NULL) {
646 cib_dirname = "./";
647 cib_filename = path;
648 } else if (sep == path) {
649 cib_dirname = "/";
650 cib_filename = path + 1;
651 } else {
652 *sep = '\0';
653 cib_dirname = path;
654 cib_filename = sep + 1;
655 }
656
657
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
665 if (cib_file_write_with_digest(in_mem_cib, cib_dirname,
666 cib_filename) != pcmk_ok) {
667 rc = -1;
668 }
669
670
671 if (uid == 0) {
672 cib_do_chown = FALSE;
673 }
674
675
676 if ((sep != NULL) && (*sep == '\0')) {
677 *sep = '/';
678 }
679
680 return rc;
681 }
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696 int
697 cib_file_signoff(cib_t * cib)
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
707 if (pcmk_is_set(private->flags, cib_file_flag_dirty)) {
708
709
710 if (pcmk_is_set(private->flags, cib_file_flag_live)) {
711 if (cib_file_write_live(private->filename) < 0) {
712 rc = pcmk_err_generic;
713 }
714
715
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) {
720 rc = pcmk_err_generic;
721 }
722 }
723
724 if (rc == pcmk_ok) {
725 crm_info("Wrote CIB to %s", private->filename);
726 cib_clear_file_flags(private, cib_file_flag_dirty);
727 } else {
728 crm_err("Could not write CIB to %s", private->filename);
729 }
730 }
731
732
733 free_xml(in_mem_cib);
734 in_mem_cib = NULL;
735 return rc;
736 }
737
738 int
739 cib_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
762 struct cib_func_entry {
763 const char *op;
764 gboolean read_only;
765 cib_op_t fn;
766 };
767
768
769 static struct cib_func_entry cib_file_ops[] = {
770 {CIB_OP_QUERY, TRUE, cib_process_query},
771 {CIB_OP_MODIFY, FALSE, cib_process_modify},
772 {CIB_OP_APPLY_DIFF, FALSE, cib_process_diff},
773 {CIB_OP_BUMP, FALSE, cib_process_bump},
774 {CIB_OP_REPLACE, FALSE, cib_process_replace},
775 {CIB_OP_CREATE, FALSE, cib_process_create},
776 {CIB_OP_DELETE, FALSE, cib_process_delete},
777 {CIB_OP_ERASE, FALSE, cib_process_erase},
778 {CIB_OP_UPGRADE, FALSE, cib_process_upgrade},
779 };
780
781
782 int
783 cib_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 }
789
790 int
791 cib_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",
813 cib_no_mtime|cib_inhibit_bcast|cib_scope_local);
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
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);
855 if (rc == -pcmk_err_schema_validation) {
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;
866 cib_set_file_flags(private, cib_file_flag_dirty);
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 }