This source file includes following definitions.
- register_client
- unregister_client
- get_client
- file_get_op_function
- cib_file_is_live
- cib_file_process_request
- cib_file_perform_op_delegate
- load_file_cib
- cib_file_signon
- cib_file_write_live
- cib_file_signoff
- cib_file_free
- cib_file_register_notification
- cib_file_set_connection_dnotify
- cib_file_client_id
- cib_file_new
- cib_file_verify_digest
- cib_file_read_and_verify
- cib_file_backup
- cib_file_prepare_xml
- cib_file_write_with_digest
- cib_file_process_transaction_requests
- cib_file_commit_transaction
- cib_file_process_commit_transaction
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/common/ipc.h>
28 #include <crm/common/xml.h>
29 #include <crm/common/xml_internal.h>
30
31 #define CIB_SERIES "cib"
32 #define CIB_SERIES_MAX 100
33 #define CIB_SERIES_BZIP FALSE
34
35
36
37 #define CIB_LIVE_NAME CIB_SERIES ".xml"
38
39
40 static GHashTable *client_table = NULL;
41
42 enum cib_file_flags {
43 cib_file_flag_dirty = (1 << 0),
44 cib_file_flag_live = (1 << 1),
45 };
46
47 typedef struct cib_file_opaque_s {
48 char *id;
49 char *filename;
50 uint32_t flags;
51 xmlNode *cib_xml;
52 } cib_file_opaque_t;
53
54 static int cib_file_process_commit_transaction(const char *op, int options,
55 const char *section,
56 xmlNode *req, xmlNode *input,
57 xmlNode *existing_cib,
58 xmlNode **result_cib,
59 xmlNode **answer);
60
61
62
63
64
65
66
67 static void
68 register_client(const cib_t *cib)
69 {
70 cib_file_opaque_t *private = cib->variant_opaque;
71
72 if (client_table == NULL) {
73 client_table = pcmk__strkey_table(NULL, NULL);
74 }
75 g_hash_table_insert(client_table, private->id, (gpointer) cib);
76 }
77
78
79
80
81
82
83
84 static void
85 unregister_client(const cib_t *cib)
86 {
87 cib_file_opaque_t *private = cib->variant_opaque;
88
89 if (client_table == NULL) {
90 return;
91 }
92
93 g_hash_table_remove(client_table, private->id);
94
95
96
97
98 if (g_hash_table_size(client_table) == 0) {
99 g_hash_table_destroy(client_table);
100 client_table = NULL;
101 }
102 }
103
104
105
106
107
108
109
110
111
112 static cib_t *
113 get_client(const char *client_id)
114 {
115 if (client_table == NULL) {
116 return NULL;
117 }
118 return g_hash_table_lookup(client_table, (gpointer) client_id);
119 }
120
121 static const cib__op_fn_t cib_op_functions[] = {
122 [cib__op_apply_patch] = cib_process_diff,
123 [cib__op_bump] = cib_process_bump,
124 [cib__op_commit_transact] = cib_file_process_commit_transaction,
125 [cib__op_create] = cib_process_create,
126 [cib__op_delete] = cib_process_delete,
127 [cib__op_erase] = cib_process_erase,
128 [cib__op_modify] = cib_process_modify,
129 [cib__op_query] = cib_process_query,
130 [cib__op_replace] = cib_process_replace,
131 [cib__op_upgrade] = cib_process_upgrade,
132 };
133
134
135
136
137
138 static uid_t cib_file_owner = 0;
139 static uid_t cib_file_group = 0;
140 static gboolean cib_do_chown = FALSE;
141
142 #define cib_set_file_flags(cibfile, flags_to_set) do { \
143 (cibfile)->flags = pcmk__set_flags_as(__func__, __LINE__, \
144 LOG_TRACE, "CIB file", \
145 cibfile->filename, \
146 (cibfile)->flags, \
147 (flags_to_set), \
148 #flags_to_set); \
149 } while (0)
150
151 #define cib_clear_file_flags(cibfile, flags_to_clear) do { \
152 (cibfile)->flags = pcmk__clear_flags_as(__func__, __LINE__, \
153 LOG_TRACE, "CIB file", \
154 cibfile->filename, \
155 (cibfile)->flags, \
156 (flags_to_clear), \
157 #flags_to_clear); \
158 } while (0)
159
160
161
162
163
164
165
166
167
168 static cib__op_fn_t
169 file_get_op_function(const cib__operation_t *operation)
170 {
171 enum cib__op_type type = operation->type;
172
173 pcmk__assert(type >= 0);
174
175 if (type >= PCMK__NELEM(cib_op_functions)) {
176 return NULL;
177 }
178 return cib_op_functions[type];
179 }
180
181
182
183
184
185
186
187
188
189 static gboolean
190 cib_file_is_live(const char *filename)
191 {
192 gboolean same = FALSE;
193
194 if (filename != NULL) {
195
196 char *real_filename = NULL;
197
198 if (pcmk__real_path(filename, &real_filename) == pcmk_rc_ok) {
199 char *real_livename = NULL;
200
201 if (pcmk__real_path(CRM_CONFIG_DIR "/" CIB_LIVE_NAME,
202 &real_livename) == pcmk_rc_ok) {
203 same = !strcmp(real_filename, real_livename);
204 free(real_livename);
205 }
206 free(real_filename);
207 }
208 }
209 return same;
210 }
211
212 static int
213 cib_file_process_request(cib_t *cib, xmlNode *request, xmlNode **output)
214 {
215 int rc = pcmk_ok;
216 const cib__operation_t *operation = NULL;
217 cib__op_fn_t op_function = NULL;
218
219 int call_id = 0;
220 uint32_t call_options = cib_none;
221 const char *op = crm_element_value(request, PCMK__XA_CIB_OP);
222 const char *section = crm_element_value(request, PCMK__XA_CIB_SECTION);
223 xmlNode *wrapper = pcmk__xe_first_child(request, PCMK__XE_CIB_CALLDATA,
224 NULL, NULL);
225 xmlNode *data = pcmk__xe_first_child(wrapper, NULL, NULL, NULL);
226
227 bool changed = false;
228 bool read_only = false;
229 xmlNode *result_cib = NULL;
230 xmlNode *cib_diff = NULL;
231
232 cib_file_opaque_t *private = cib->variant_opaque;
233
234
235 cib__get_operation(op, &operation);
236 op_function = file_get_op_function(operation);
237
238 crm_element_value_int(request, PCMK__XA_CIB_CALLID, &call_id);
239 rc = pcmk__xe_get_flags(request, PCMK__XA_CIB_CALLOPT, &call_options,
240 cib_none);
241 if (rc != pcmk_rc_ok) {
242 crm_warn("Couldn't parse options from request: %s", pcmk_rc_str(rc));
243 }
244
245 read_only = !pcmk_is_set(operation->flags, cib__op_attr_modifies);
246
247
248 if ((section != NULL) && pcmk__xe_is(data, PCMK_XE_CIB)) {
249
250 data = pcmk_find_cib_element(data, section);
251 }
252
253 rc = cib_perform_op(cib, op, call_options, op_function, read_only, section,
254 request, data, true, &changed, &private->cib_xml,
255 &result_cib, &cib_diff, output);
256
257 if (pcmk_is_set(call_options, cib_transaction)) {
258
259
260
261 goto done;
262 }
263
264 if (rc == -pcmk_err_schema_validation) {
265
266 pcmk__validate_xml(result_cib, NULL, NULL, NULL);
267
268 } else if ((rc == pcmk_ok) && !read_only) {
269 pcmk__log_xml_patchset(LOG_DEBUG, cib_diff);
270
271 if (result_cib != private->cib_xml) {
272 pcmk__xml_free(private->cib_xml);
273 private->cib_xml = result_cib;
274 }
275 cib_set_file_flags(private, cib_file_flag_dirty);
276 }
277
278 done:
279 if ((result_cib != private->cib_xml) && (result_cib != *output)) {
280 pcmk__xml_free(result_cib);
281 }
282 pcmk__xml_free(cib_diff);
283 return rc;
284 }
285
286 static int
287 cib_file_perform_op_delegate(cib_t *cib, const char *op, const char *host,
288 const char *section, xmlNode *data,
289 xmlNode **output_data, int call_options,
290 const char *user_name)
291 {
292 int rc = pcmk_ok;
293 xmlNode *request = NULL;
294 xmlNode *output = NULL;
295 cib_file_opaque_t *private = cib->variant_opaque;
296
297 const cib__operation_t *operation = NULL;
298
299 crm_info("Handling %s operation for %s as %s",
300 pcmk__s(op, "invalid"), pcmk__s(section, "entire CIB"),
301 pcmk__s(user_name, "default user"));
302
303 if (output_data != NULL) {
304 *output_data = NULL;
305 }
306
307 if (cib->state == cib_disconnected) {
308 return -ENOTCONN;
309 }
310
311 rc = cib__get_operation(op, &operation);
312 rc = pcmk_rc2legacy(rc);
313 if (rc != pcmk_ok) {
314
315 return -EPROTONOSUPPORT;
316 }
317
318 if (file_get_op_function(operation) == NULL) {
319
320 crm_err("Operation %s is not supported by CIB file clients", op);
321 return -EPROTONOSUPPORT;
322 }
323
324 cib__set_call_options(call_options, "file operation", cib_no_mtime);
325
326 rc = cib__create_op(cib, op, host, section, data, call_options, user_name,
327 NULL, &request);
328 if (rc != pcmk_ok) {
329 return rc;
330 }
331 crm_xml_add(request, PCMK__XA_ACL_TARGET, user_name);
332 crm_xml_add(request, PCMK__XA_CIB_CLIENTID, private->id);
333
334 if (pcmk_is_set(call_options, cib_transaction)) {
335 rc = cib__extend_transaction(cib, request);
336 goto done;
337 }
338
339 rc = cib_file_process_request(cib, request, &output);
340
341 if ((output_data != NULL) && (output != NULL)) {
342 if (output->doc == private->cib_xml->doc) {
343 *output_data = pcmk__xml_copy(NULL, output);
344 } else {
345 *output_data = output;
346 }
347 }
348
349 done:
350 if ((output != NULL)
351 && (output->doc != private->cib_xml->doc)
352 && ((output_data == NULL) || (output != *output_data))) {
353
354 pcmk__xml_free(output);
355 }
356 pcmk__xml_free(request);
357 return rc;
358 }
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375 static int
376 load_file_cib(const char *filename, xmlNode **output)
377 {
378 struct stat buf;
379 xmlNode *root = NULL;
380
381
382 if (strcmp(filename, "-") && (stat(filename, &buf) < 0)) {
383 return -ENXIO;
384 }
385
386
387 root = pcmk__xml_read(filename);
388 if (root == NULL) {
389 return -pcmk_err_schema_validation;
390 }
391
392
393 if (pcmk__xe_first_child(root, PCMK_XE_STATUS, NULL, NULL) == NULL) {
394 pcmk__xe_create(root, PCMK_XE_STATUS);
395 }
396
397
398 if (!pcmk__configured_schema_validates(root)) {
399 pcmk__xml_free(root);
400 return -pcmk_err_schema_validation;
401 }
402
403
404 *output = root;
405 return pcmk_ok;
406 }
407
408 static int
409 cib_file_signon(cib_t *cib, const char *name, enum cib_conn_type type)
410 {
411 int rc = pcmk_ok;
412 cib_file_opaque_t *private = cib->variant_opaque;
413
414 if (private->filename == NULL) {
415 rc = -EINVAL;
416 } else {
417 rc = load_file_cib(private->filename, &private->cib_xml);
418 }
419
420 if (rc == pcmk_ok) {
421 crm_debug("Opened connection to local file '%s' for %s",
422 private->filename, pcmk__s(name, "client"));
423 cib->state = cib_connected_command;
424 cib->type = cib_command;
425 register_client(cib);
426
427 } else {
428 crm_info("Connection to local file '%s' for %s (client %s) failed: %s",
429 private->filename, pcmk__s(name, "client"), private->id,
430 pcmk_strerror(rc));
431 }
432 return rc;
433 }
434
435
436
437
438
439
440
441
442
443
444 static int
445 cib_file_write_live(xmlNode *cib_root, char *path)
446 {
447 uid_t uid = geteuid();
448 struct passwd *daemon_pwent;
449 char *sep = strrchr(path, '/');
450 const char *cib_dirname, *cib_filename;
451 int rc = 0;
452
453
454 errno = 0;
455 daemon_pwent = getpwnam(CRM_DAEMON_USER);
456 if (daemon_pwent == NULL) {
457 crm_perror(LOG_ERR, "Could not find %s user", CRM_DAEMON_USER);
458 return -1;
459 }
460
461
462
463
464
465 if ((uid != 0) && (uid != daemon_pwent->pw_uid)) {
466 crm_perror(LOG_ERR, "Must be root or %s to modify live CIB",
467 CRM_DAEMON_USER);
468 return 0;
469 }
470
471
472
473
474
475 if (sep == NULL) {
476 cib_dirname = "./";
477 cib_filename = path;
478 } else if (sep == path) {
479 cib_dirname = "/";
480 cib_filename = path + 1;
481 } else {
482 *sep = '\0';
483 cib_dirname = path;
484 cib_filename = sep + 1;
485 }
486
487
488 if (uid == 0) {
489 cib_file_owner = daemon_pwent->pw_uid;
490 cib_file_group = daemon_pwent->pw_gid;
491 cib_do_chown = TRUE;
492 }
493
494
495 if (cib_file_write_with_digest(cib_root, cib_dirname,
496 cib_filename) != pcmk_ok) {
497 rc = -1;
498 }
499
500
501 if (uid == 0) {
502 cib_do_chown = FALSE;
503 }
504
505
506 if ((sep != NULL) && (*sep == '\0')) {
507 *sep = '/';
508 }
509
510 return rc;
511 }
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526 static int
527 cib_file_signoff(cib_t *cib)
528 {
529 int rc = pcmk_ok;
530 cib_file_opaque_t *private = cib->variant_opaque;
531
532 crm_debug("Disconnecting from the CIB manager");
533 cib->state = cib_disconnected;
534 cib->type = cib_no_connection;
535 unregister_client(cib);
536 cib->cmds->end_transaction(cib, false, cib_none);
537
538
539 if (pcmk_is_set(private->flags, cib_file_flag_dirty)) {
540
541
542 if (pcmk_is_set(private->flags, cib_file_flag_live)) {
543 if (cib_file_write_live(private->cib_xml, private->filename) < 0) {
544 rc = pcmk_err_generic;
545 }
546
547
548 } else {
549 bool compress = pcmk__ends_with_ext(private->filename, ".bz2");
550
551 if (pcmk__xml_write_file(private->cib_xml, private->filename,
552 compress) != pcmk_rc_ok) {
553 rc = pcmk_err_generic;
554 }
555 }
556
557 if (rc == pcmk_ok) {
558 crm_info("Wrote CIB to %s", private->filename);
559 cib_clear_file_flags(private, cib_file_flag_dirty);
560 } else {
561 crm_err("Could not write CIB to %s", private->filename);
562 }
563 }
564
565
566 pcmk__xml_free(private->cib_xml);
567 private->cib_xml = NULL;
568 return rc;
569 }
570
571 static int
572 cib_file_free(cib_t *cib)
573 {
574 int rc = pcmk_ok;
575
576 if (cib->state != cib_disconnected) {
577 rc = cib_file_signoff(cib);
578 }
579
580 if (rc == pcmk_ok) {
581 cib_file_opaque_t *private = cib->variant_opaque;
582
583 free(private->id);
584 free(private->filename);
585 free(private);
586 free(cib->cmds);
587 free(cib->user);
588 free(cib);
589
590 } else {
591 fprintf(stderr, "Couldn't sign off: %d\n", rc);
592 }
593
594 return rc;
595 }
596
597 static int
598 cib_file_register_notification(cib_t *cib, const char *callback, int enabled)
599 {
600 return -EPROTONOSUPPORT;
601 }
602
603 static int
604 cib_file_set_connection_dnotify(cib_t *cib,
605 void (*dnotify) (gpointer user_data))
606 {
607 return -EPROTONOSUPPORT;
608 }
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623 static int
624 cib_file_client_id(const cib_t *cib, const char **async_id,
625 const char **sync_id)
626 {
627 cib_file_opaque_t *private = cib->variant_opaque;
628
629 if (async_id != NULL) {
630 *async_id = private->id;
631 }
632 if (sync_id != NULL) {
633 *sync_id = private->id;
634 }
635 return pcmk_ok;
636 }
637
638 cib_t *
639 cib_file_new(const char *cib_location)
640 {
641 cib_t *cib = NULL;
642 cib_file_opaque_t *private = NULL;
643 char *filename = NULL;
644
645 if (cib_location == NULL) {
646 cib_location = getenv("CIB_file");
647 if (cib_location == NULL) {
648 return NULL;
649 }
650 }
651
652 cib = cib_new_variant();
653 if (cib == NULL) {
654 return NULL;
655 }
656
657 filename = strdup(cib_location);
658 if (filename == NULL) {
659 free(cib);
660 return NULL;
661 }
662
663 private = calloc(1, sizeof(cib_file_opaque_t));
664 if (private == NULL) {
665 free(cib);
666 free(filename);
667 return NULL;
668 }
669
670 private->id = crm_generate_uuid();
671 private->filename = filename;
672
673 cib->variant = cib_file;
674 cib->variant_opaque = private;
675
676 private->flags = 0;
677 if (cib_file_is_live(cib_location)) {
678 cib_set_file_flags(private, cib_file_flag_live);
679 crm_trace("File %s detected as live CIB", cib_location);
680 }
681
682
683 cib->delegate_fn = cib_file_perform_op_delegate;
684 cib->cmds->signon = cib_file_signon;
685 cib->cmds->signoff = cib_file_signoff;
686 cib->cmds->free = cib_file_free;
687 cib->cmds->register_notification = cib_file_register_notification;
688 cib->cmds->set_connection_dnotify = cib_file_set_connection_dnotify;
689
690 cib->cmds->client_id = cib_file_client_id;
691
692 return cib;
693 }
694
695
696
697
698
699
700
701
702
703
704 static gboolean
705 cib_file_verify_digest(xmlNode *root, const char *sigfile)
706 {
707 gboolean passed = FALSE;
708 char *expected;
709 int rc = pcmk__file_contents(sigfile, &expected);
710
711 switch (rc) {
712 case pcmk_rc_ok:
713 if (expected == NULL) {
714 crm_err("On-disk digest at %s is empty", sigfile);
715 return FALSE;
716 }
717 break;
718 case ENOENT:
719 crm_warn("No on-disk digest present at %s", sigfile);
720 return TRUE;
721 default:
722 crm_err("Could not read on-disk digest from %s: %s",
723 sigfile, pcmk_rc_str(rc));
724 return FALSE;
725 }
726 passed = pcmk__verify_digest(root, expected);
727 free(expected);
728 return passed;
729 }
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746 int
747 cib_file_read_and_verify(const char *filename, const char *sigfile, xmlNode **root)
748 {
749 int s_res;
750 struct stat buf;
751 char *local_sigfile = NULL;
752 xmlNode *local_root = NULL;
753
754 pcmk__assert(filename != NULL);
755 if (root) {
756 *root = NULL;
757 }
758
759
760 s_res = stat(filename, &buf);
761 if (s_res < 0) {
762 crm_perror(LOG_WARNING, "Could not verify cluster configuration file %s", filename);
763 return -errno;
764 } else if (buf.st_size == 0) {
765 crm_warn("Cluster configuration file %s is corrupt (size is zero)", filename);
766 return -pcmk_err_cib_corrupt;
767 }
768
769
770 local_root = pcmk__xml_read(filename);
771 if (local_root == NULL) {
772 crm_warn("Cluster configuration file %s is corrupt (unparseable as XML)", filename);
773 return -pcmk_err_cib_corrupt;
774 }
775
776
777 if (sigfile == NULL) {
778 sigfile = local_sigfile = crm_strdup_printf("%s.sig", filename);
779 }
780
781
782 if (cib_file_verify_digest(local_root, sigfile) == FALSE) {
783 free(local_sigfile);
784 pcmk__xml_free(local_root);
785 return -pcmk_err_cib_modified;
786 }
787
788 free(local_sigfile);
789 if (root) {
790 *root = local_root;
791 } else {
792 pcmk__xml_free(local_root);
793 }
794 return pcmk_ok;
795 }
796
797
798
799
800
801
802
803
804
805
806 static int
807 cib_file_backup(const char *cib_dirname, const char *cib_filename)
808 {
809 int rc = 0;
810 unsigned int seq = 0U;
811 char *cib_path = crm_strdup_printf("%s/%s", cib_dirname, cib_filename);
812 char *cib_digest = crm_strdup_printf("%s.sig", cib_path);
813 char *backup_path;
814 char *backup_digest;
815
816
817 if (pcmk__read_series_sequence(cib_dirname, CIB_SERIES,
818 &seq) != pcmk_rc_ok) {
819
820 seq = 0U;
821 }
822 backup_path = pcmk__series_filename(cib_dirname, CIB_SERIES, seq,
823 CIB_SERIES_BZIP);
824 backup_digest = crm_strdup_printf("%s.sig", backup_path);
825
826
827 unlink(backup_path);
828 unlink(backup_digest);
829
830
831 if ((link(cib_path, backup_path) < 0) && (errno != ENOENT)) {
832 crm_perror(LOG_ERR, "Could not archive %s by linking to %s",
833 cib_path, backup_path);
834 rc = -1;
835
836
837 } else if ((link(cib_digest, backup_digest) < 0) && (errno != ENOENT)) {
838 crm_perror(LOG_ERR, "Could not archive %s by linking to %s",
839 cib_digest, backup_digest);
840 rc = -1;
841
842
843 } else {
844 pcmk__write_series_sequence(cib_dirname, CIB_SERIES, ++seq,
845 CIB_SERIES_MAX);
846 if (cib_do_chown) {
847 int rc2;
848
849 if ((chown(backup_path, cib_file_owner, cib_file_group) < 0)
850 && (errno != ENOENT)) {
851 crm_perror(LOG_ERR, "Could not set owner of %s", backup_path);
852 rc = -1;
853 }
854 if ((chown(backup_digest, cib_file_owner, cib_file_group) < 0)
855 && (errno != ENOENT)) {
856 crm_perror(LOG_ERR, "Could not set owner of %s", backup_digest);
857 rc = -1;
858 }
859 rc2 = pcmk__chown_series_sequence(cib_dirname, CIB_SERIES,
860 cib_file_owner, cib_file_group);
861 if (rc2 != pcmk_rc_ok) {
862 crm_err("Could not set owner of sequence file in %s: %s",
863 cib_dirname, pcmk_rc_str(rc2));
864 rc = -1;
865 }
866 }
867 pcmk__sync_directory(cib_dirname);
868 crm_info("Archived previous version as %s", backup_path);
869 }
870
871 free(cib_path);
872 free(cib_digest);
873 free(backup_path);
874 free(backup_digest);
875 return rc;
876 }
877
878
879
880
881
882
883
884
885
886
887
888
889 static void
890 cib_file_prepare_xml(xmlNode *root)
891 {
892 xmlNode *cib_status_root = NULL;
893
894
895 crm_xml_add(root, PCMK_XA_NUM_UPDATES, "0");
896 pcmk__xe_add_last_written(root);
897
898
899
900 cib_status_root = pcmk__xe_first_child(root, PCMK_XE_STATUS, NULL, NULL);
901 CRM_CHECK(cib_status_root != NULL, return);
902 pcmk__xml_free(cib_status_root);
903 }
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918 int
919 cib_file_write_with_digest(xmlNode *cib_root, const char *cib_dirname,
920 const char *cib_filename)
921 {
922 int exit_rc = pcmk_ok;
923 int rc, fd;
924 char *digest = NULL;
925
926
927 const char *epoch = crm_element_value(cib_root, PCMK_XA_EPOCH);
928 const char *admin_epoch = crm_element_value(cib_root, PCMK_XA_ADMIN_EPOCH);
929
930
931 char *cib_path = crm_strdup_printf("%s/%s", cib_dirname, cib_filename);
932 char *digest_path = crm_strdup_printf("%s.sig", cib_path);
933
934
935 char *tmp_cib = crm_strdup_printf("%s/cib.XXXXXX", cib_dirname);
936 char *tmp_digest = crm_strdup_printf("%s/cib.XXXXXX", cib_dirname);
937
938
939 crm_trace("Reading cluster configuration file %s", cib_path);
940 rc = cib_file_read_and_verify(cib_path, NULL, NULL);
941 if ((rc != pcmk_ok) && (rc != -ENOENT)) {
942 crm_err("%s was manually modified while the cluster was active!",
943 cib_path);
944 exit_rc = pcmk_err_cib_modified;
945 goto cleanup;
946 }
947
948
949 if (cib_file_backup(cib_dirname, cib_filename) < 0) {
950 exit_rc = pcmk_err_cib_backup;
951 goto cleanup;
952 }
953
954 crm_debug("Writing CIB to disk");
955 umask(S_IWGRP | S_IWOTH | S_IROTH);
956 cib_file_prepare_xml(cib_root);
957
958
959 fd = mkstemp(tmp_cib);
960 if (fd < 0) {
961 crm_perror(LOG_ERR, "Couldn't open temporary file %s for writing CIB",
962 tmp_cib);
963 exit_rc = pcmk_err_cib_save;
964 goto cleanup;
965 }
966
967
968 if (fchmod(fd, S_IRUSR | S_IWUSR) < 0) {
969 crm_perror(LOG_ERR, "Couldn't protect temporary file %s for writing CIB",
970 tmp_cib);
971 exit_rc = pcmk_err_cib_save;
972 goto cleanup;
973 }
974 if (cib_do_chown && (fchown(fd, cib_file_owner, cib_file_group) < 0)) {
975 crm_perror(LOG_ERR, "Couldn't protect temporary file %s for writing CIB",
976 tmp_cib);
977 exit_rc = pcmk_err_cib_save;
978 goto cleanup;
979 }
980
981
982 if (pcmk__xml_write_fd(cib_root, tmp_cib, fd) != pcmk_rc_ok) {
983 crm_err("Changes couldn't be written to %s", tmp_cib);
984 exit_rc = pcmk_err_cib_save;
985 goto cleanup;
986 }
987
988
989 digest = pcmk__digest_on_disk_cib(cib_root);
990 pcmk__assert(digest != NULL);
991 crm_info("Wrote version %s.%s.0 of the CIB to disk (digest: %s)",
992 (admin_epoch ? admin_epoch : "0"), (epoch ? epoch : "0"), digest);
993
994
995 fd = mkstemp(tmp_digest);
996 if (fd < 0) {
997 crm_perror(LOG_ERR, "Could not create temporary file for CIB digest");
998 exit_rc = pcmk_err_cib_save;
999 goto cleanup;
1000 }
1001 if (cib_do_chown && (fchown(fd, cib_file_owner, cib_file_group) < 0)) {
1002 crm_perror(LOG_ERR, "Couldn't protect temporary file %s for writing CIB",
1003 tmp_cib);
1004 exit_rc = pcmk_err_cib_save;
1005 close(fd);
1006 goto cleanup;
1007 }
1008 rc = pcmk__write_sync(fd, digest);
1009 if (rc != pcmk_rc_ok) {
1010 crm_err("Could not write digest to %s: %s",
1011 tmp_digest, pcmk_rc_str(rc));
1012 exit_rc = pcmk_err_cib_save;
1013 close(fd);
1014 goto cleanup;
1015 }
1016 close(fd);
1017 crm_debug("Wrote digest %s to disk", digest);
1018
1019
1020 crm_info("Reading cluster configuration file %s (digest: %s)",
1021 tmp_cib, tmp_digest);
1022 rc = cib_file_read_and_verify(tmp_cib, tmp_digest, NULL);
1023 pcmk__assert(rc == 0);
1024
1025
1026 crm_debug("Activating %s", tmp_cib);
1027 if (rename(tmp_cib, cib_path) < 0) {
1028 crm_perror(LOG_ERR, "Couldn't rename %s as %s", tmp_cib, cib_path);
1029 exit_rc = pcmk_err_cib_save;
1030 }
1031 if (rename(tmp_digest, digest_path) < 0) {
1032 crm_perror(LOG_ERR, "Couldn't rename %s as %s", tmp_digest,
1033 digest_path);
1034 exit_rc = pcmk_err_cib_save;
1035 }
1036 pcmk__sync_directory(cib_dirname);
1037
1038 cleanup:
1039 free(cib_path);
1040 free(digest_path);
1041 free(digest);
1042 free(tmp_digest);
1043 free(tmp_cib);
1044 return exit_rc;
1045 }
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058 static int
1059 cib_file_process_transaction_requests(cib_t *cib, xmlNode *transaction)
1060 {
1061 cib_file_opaque_t *private = cib->variant_opaque;
1062
1063 for (xmlNode *request = pcmk__xe_first_child(transaction,
1064 PCMK__XE_CIB_COMMAND, NULL,
1065 NULL);
1066 request != NULL;
1067 request = pcmk__xe_next(request, PCMK__XE_CIB_COMMAND)) {
1068
1069 xmlNode *output = NULL;
1070 const char *op = crm_element_value(request, PCMK__XA_CIB_OP);
1071
1072 int rc = cib_file_process_request(cib, request, &output);
1073
1074 rc = pcmk_legacy2rc(rc);
1075 if (rc != pcmk_rc_ok) {
1076 crm_err("Aborting transaction for CIB file client (%s) on file "
1077 "'%s' due to failed %s request: %s",
1078 private->id, private->filename, op, pcmk_rc_str(rc));
1079 crm_log_xml_info(request, "Failed request");
1080 return rc;
1081 }
1082
1083 crm_trace("Applied %s request to transaction working CIB for CIB file "
1084 "client (%s) on file '%s'",
1085 op, private->id, private->filename);
1086 crm_log_xml_trace(request, "Successful request");
1087 }
1088
1089 return pcmk_rc_ok;
1090 }
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106 static int
1107 cib_file_commit_transaction(cib_t *cib, xmlNode *transaction,
1108 xmlNode **result_cib)
1109 {
1110 int rc = pcmk_rc_ok;
1111 cib_file_opaque_t *private = cib->variant_opaque;
1112 xmlNode *saved_cib = private->cib_xml;
1113
1114 CRM_CHECK(pcmk__xe_is(transaction, PCMK__XE_CIB_TRANSACTION),
1115 return pcmk_rc_no_transaction);
1116
1117
1118
1119
1120
1121
1122
1123
1124 CRM_CHECK((*result_cib != NULL) && (*result_cib != private->cib_xml),
1125 *result_cib = pcmk__xml_copy(NULL, private->cib_xml));
1126
1127 crm_trace("Committing transaction for CIB file client (%s) on file '%s' to "
1128 "working CIB",
1129 private->id, private->filename);
1130
1131
1132 private->cib_xml = *result_cib;
1133
1134 rc = cib_file_process_transaction_requests(cib, transaction);
1135
1136 crm_trace("Transaction commit %s for CIB file client (%s) on file '%s'",
1137 ((rc == pcmk_rc_ok)? "succeeded" : "failed"),
1138 private->id, private->filename);
1139
1140
1141
1142
1143
1144
1145
1146 *result_cib = private->cib_xml;
1147
1148
1149 private->cib_xml = saved_cib;
1150
1151 return rc;
1152 }
1153
1154 static int
1155 cib_file_process_commit_transaction(const char *op, int options,
1156 const char *section, xmlNode *req,
1157 xmlNode *input, xmlNode *existing_cib,
1158 xmlNode **result_cib, xmlNode **answer)
1159 {
1160 int rc = pcmk_rc_ok;
1161 const char *client_id = crm_element_value(req, PCMK__XA_CIB_CLIENTID);
1162 cib_t *cib = NULL;
1163
1164 CRM_CHECK(client_id != NULL, return -EINVAL);
1165
1166 cib = get_client(client_id);
1167 CRM_CHECK(cib != NULL, return -EINVAL);
1168
1169 rc = cib_file_commit_transaction(cib, input, result_cib);
1170 if (rc != pcmk_rc_ok) {
1171 cib_file_opaque_t *private = cib->variant_opaque;
1172
1173 crm_err("Could not commit transaction for CIB file client (%s) on "
1174 "file '%s': %s",
1175 private->id, private->filename, pcmk_rc_str(rc));
1176 }
1177 return pcmk_rc2legacy(rc);
1178 }