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 CRM_CHECK(cib_location != NULL, return NULL);
517 }
518 private->flags = 0;
519 if (cib_file_is_live(cib_location)) {
520 cib_set_file_flags(private, cib_file_flag_live);
521 crm_trace("File %s detected as live CIB", cib_location);
522 }
523 private->filename = strdup(cib_location);
524
525
526 cib->delegate_fn = cib_file_perform_op_delegate;
527 cib->cmds->signon = cib_file_signon;
528 cib->cmds->signoff = cib_file_signoff;
529 cib->cmds->free = cib_file_free;
530 cib->cmds->inputfd = cib_file_inputfd;
531
532 cib->cmds->register_notification = cib_file_register_notification;
533 cib->cmds->set_connection_dnotify = cib_file_set_connection_dnotify;
534
535 return cib;
536 }
537
538 static xmlNode *in_mem_cib = NULL;
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554 static int
555 load_file_cib(const char *filename)
556 {
557 struct stat buf;
558 xmlNode *root = NULL;
559
560
561 if (strcmp(filename, "-") && (stat(filename, &buf) < 0)) {
562 return -ENXIO;
563 }
564
565
566 root = filename2xml(filename);
567 if (root == NULL) {
568 return -pcmk_err_schema_validation;
569 }
570
571
572 if (find_xml_node(root, XML_CIB_TAG_STATUS, FALSE) == NULL) {
573 create_xml_node(root, XML_CIB_TAG_STATUS);
574 }
575
576
577 if (validate_xml(root, NULL, TRUE) == FALSE) {
578 const char *schema = crm_element_value(root, XML_ATTR_VALIDATION);
579
580 crm_err("CIB does not validate against %s", schema);
581 free_xml(root);
582 return -pcmk_err_schema_validation;
583 }
584
585
586 in_mem_cib = root;
587 return pcmk_ok;
588 }
589
590 int
591 cib_file_signon(cib_t * cib, const char *name, enum cib_conn_type type)
592 {
593 int rc = pcmk_ok;
594 cib_file_opaque_t *private = cib->variant_opaque;
595
596 if (private->filename == NULL) {
597 rc = -EINVAL;
598 } else {
599 rc = load_file_cib(private->filename);
600 }
601
602 if (rc == pcmk_ok) {
603 crm_debug("Opened connection to local file '%s' for %s",
604 private->filename, name);
605 cib->state = cib_connected_command;
606 cib->type = cib_command;
607
608 } else {
609 crm_info("Connection to local file '%s' for %s failed: %s\n",
610 private->filename, name, pcmk_strerror(rc));
611 }
612 return rc;
613 }
614
615
616
617
618
619
620
621
622
623 static int
624 cib_file_write_live(char *path)
625 {
626 uid_t uid = geteuid();
627 struct passwd *daemon_pwent;
628 char *sep = strrchr(path, '/');
629 const char *cib_dirname, *cib_filename;
630 int rc = 0;
631
632
633 errno = 0;
634 daemon_pwent = getpwnam(CRM_DAEMON_USER);
635 if (daemon_pwent == NULL) {
636 crm_perror(LOG_ERR, "Could not find %s user", CRM_DAEMON_USER);
637 return -1;
638 }
639
640
641
642
643
644 if ((uid != 0) && (uid != daemon_pwent->pw_uid)) {
645 crm_perror(LOG_ERR, "Must be root or %s to modify live CIB",
646 CRM_DAEMON_USER);
647 return 0;
648 }
649
650
651
652
653
654 if (sep == NULL) {
655 cib_dirname = "./";
656 cib_filename = path;
657 } else if (sep == path) {
658 cib_dirname = "/";
659 cib_filename = path + 1;
660 } else {
661 *sep = '\0';
662 cib_dirname = path;
663 cib_filename = sep + 1;
664 }
665
666
667 if (uid == 0) {
668 cib_file_owner = daemon_pwent->pw_uid;
669 cib_file_group = daemon_pwent->pw_gid;
670 cib_do_chown = TRUE;
671 }
672
673
674 if (cib_file_write_with_digest(in_mem_cib, cib_dirname,
675 cib_filename) != pcmk_ok) {
676 rc = -1;
677 }
678
679
680 if (uid == 0) {
681 cib_do_chown = FALSE;
682 }
683
684
685 if ((sep != NULL) && (*sep == '\0')) {
686 *sep = '/';
687 }
688
689 return rc;
690 }
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705 int
706 cib_file_signoff(cib_t * cib)
707 {
708 int rc = pcmk_ok;
709 cib_file_opaque_t *private = cib->variant_opaque;
710
711 crm_debug("Disconnecting from the CIB manager");
712 cib->state = cib_disconnected;
713 cib->type = cib_no_connection;
714
715
716 if (pcmk_is_set(private->flags, cib_file_flag_dirty)) {
717
718
719 if (pcmk_is_set(private->flags, cib_file_flag_live)) {
720 if (cib_file_write_live(private->filename) < 0) {
721 rc = pcmk_err_generic;
722 }
723
724
725 } else {
726 gboolean do_bzip = pcmk__ends_with_ext(private->filename, ".bz2");
727
728 if (write_xml_file(in_mem_cib, private->filename, do_bzip) <= 0) {
729 rc = pcmk_err_generic;
730 }
731 }
732
733 if (rc == pcmk_ok) {
734 crm_info("Wrote CIB to %s", private->filename);
735 cib_clear_file_flags(private, cib_file_flag_dirty);
736 } else {
737 crm_err("Could not write CIB to %s", private->filename);
738 }
739 }
740
741
742 free_xml(in_mem_cib);
743 in_mem_cib = NULL;
744 return rc;
745 }
746
747 int
748 cib_file_free(cib_t * cib)
749 {
750 int rc = pcmk_ok;
751
752 if (cib->state != cib_disconnected) {
753 rc = cib_file_signoff(cib);
754 }
755
756 if (rc == pcmk_ok) {
757 cib_file_opaque_t *private = cib->variant_opaque;
758
759 free(private->filename);
760 free(cib->cmds);
761 free(private);
762 free(cib);
763
764 } else {
765 fprintf(stderr, "Couldn't sign off: %d\n", rc);
766 }
767
768 return rc;
769 }
770
771 struct cib_func_entry {
772 const char *op;
773 gboolean read_only;
774 cib_op_t fn;
775 };
776
777
778 static struct cib_func_entry cib_file_ops[] = {
779 { PCMK__CIB_REQUEST_QUERY, TRUE, cib_process_query},
780 { PCMK__CIB_REQUEST_MODIFY, FALSE, cib_process_modify},
781 { PCMK__CIB_REQUEST_APPLY_PATCH,FALSE, cib_process_diff},
782 { PCMK__CIB_REQUEST_BUMP, FALSE, cib_process_bump },
783 { PCMK__CIB_REQUEST_REPLACE, FALSE, cib_process_replace},
784 { PCMK__CIB_REQUEST_CREATE, FALSE, cib_process_create },
785 { PCMK__CIB_REQUEST_DELETE, FALSE, cib_process_delete},
786 { PCMK__CIB_REQUEST_ERASE, FALSE, cib_process_erase},
787 { PCMK__CIB_REQUEST_UPGRADE, FALSE, cib_process_upgrade},
788 };
789
790
791 int
792 cib_file_perform_op(cib_t * cib, const char *op, const char *host, const char *section,
793 xmlNode * data, xmlNode ** output_data, int call_options)
794 {
795 return cib_file_perform_op_delegate(cib, op, host, section, data, output_data, call_options,
796 NULL);
797 }
798
799 int
800 cib_file_perform_op_delegate(cib_t * cib, const char *op, const char *host, const char *section,
801 xmlNode * data, xmlNode ** output_data, int call_options,
802 const char *user_name)
803 {
804 int rc = pcmk_ok;
805 char *effective_user = NULL;
806 gboolean query = FALSE;
807 gboolean changed = FALSE;
808 xmlNode *request = NULL;
809 xmlNode *output = NULL;
810 xmlNode *cib_diff = NULL;
811 xmlNode *result_cib = NULL;
812 cib_op_t *fn = NULL;
813 int lpc = 0;
814 static int max_msg_types = PCMK__NELEM(cib_file_ops);
815 cib_file_opaque_t *private = cib->variant_opaque;
816
817 crm_info("Handling %s operation for %s as %s",
818 (op? op : "invalid"), (section? section : "entire CIB"),
819 (user_name? user_name : "default user"));
820
821 cib__set_call_options(call_options, "file operation",
822 cib_no_mtime|cib_inhibit_bcast|cib_scope_local);
823
824 if (cib->state == cib_disconnected) {
825 return -ENOTCONN;
826 }
827
828 if (output_data != NULL) {
829 *output_data = NULL;
830 }
831
832 if (op == NULL) {
833 return -EINVAL;
834 }
835
836 for (lpc = 0; lpc < max_msg_types; lpc++) {
837 if (pcmk__str_eq(op, cib_file_ops[lpc].op, pcmk__str_casei)) {
838 fn = &(cib_file_ops[lpc].fn);
839 query = cib_file_ops[lpc].read_only;
840 break;
841 }
842 }
843
844 if (fn == NULL) {
845 return -EPROTONOSUPPORT;
846 }
847
848 cib->call_id++;
849 request = cib_create_op(cib->call_id, "dummy-token", op, host, section, data, call_options, user_name);
850 if(user_name) {
851 crm_xml_add(request, XML_ACL_TAG_USER, user_name);
852 }
853
854
855 if (section != NULL && data != NULL && pcmk__str_eq(crm_element_name(data), XML_TAG_CIB, pcmk__str_none)) {
856 data = pcmk_find_cib_element(data, section);
857 }
858
859 rc = cib_perform_op(op, call_options, fn, query,
860 section, request, data, TRUE, &changed, in_mem_cib, &result_cib, &cib_diff,
861 &output);
862
863 free_xml(request);
864 if (rc == -pcmk_err_schema_validation) {
865 validate_xml_verbose(result_cib);
866 }
867
868 if (rc != pcmk_ok) {
869 free_xml(result_cib);
870
871 } else if (query == FALSE) {
872 xml_log_patchset(LOG_DEBUG, "cib:diff", cib_diff);
873 free_xml(in_mem_cib);
874 in_mem_cib = result_cib;
875 cib_set_file_flags(private, cib_file_flag_dirty);
876 }
877
878 free_xml(cib_diff);
879
880 if (cib->op_callback != NULL) {
881 cib->op_callback(NULL, cib->call_id, rc, output);
882 }
883
884 if (output_data && output) {
885 if(output == in_mem_cib) {
886 *output_data = copy_xml(output);
887 } else {
888 *output_data = output;
889 }
890
891 } else if(output != in_mem_cib) {
892 free_xml(output);
893 }
894
895 free(effective_user);
896 return rc;
897 }