This source file includes following definitions.
- cib_compare_generation
- get_cib_copy
- cib_get_generation
- cib_version_details
- cib_diff_version_details
- get_object_path
- get_object_parent
- get_object_root
- createEmptyCib
- cib_acl_enabled
- cib_perform_op
- cib_create_op
- cib_native_callback
- cib_native_notify
- cib_metadata
- verify_cib_options
- cib_pref
- cib_read_config
- cib_apply_patch_event
- cib_internal_config_changed
- cib_internal_op
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 #include <crm_internal.h>
20 #include <unistd.h>
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include <stdarg.h>
24 #include <string.h>
25 #include <sys/utsname.h>
26
27 #include <glib.h>
28
29 #include <crm/crm.h>
30 #include <crm/cib/internal.h>
31 #include <crm/msg_xml.h>
32 #include <crm/common/xml.h>
33 #include <crm/pengine/rules.h>
34
35 struct config_root_s {
36 const char *name;
37 const char *parent;
38 const char *path;
39 };
40
41
42
43
44
45
46
47 struct config_root_s known_paths[] = {
48 { NULL, NULL, "//cib" },
49 { XML_TAG_CIB, NULL, "//cib" },
50 { XML_CIB_TAG_STATUS, "/cib", "//cib/status" },
51 { XML_CIB_TAG_CONFIGURATION,"/cib", "//cib/configuration" },
52 { XML_CIB_TAG_CRMCONFIG, "/cib/configuration", "//cib/configuration/crm_config" },
53 { XML_CIB_TAG_NODES, "/cib/configuration", "//cib/configuration/nodes" },
54 { XML_CIB_TAG_DOMAINS, "/cib/configuration", "//cib/configuration/domains" },
55 { XML_CIB_TAG_RESOURCES, "/cib/configuration", "//cib/configuration/resources" },
56 { XML_CIB_TAG_CONSTRAINTS, "/cib/configuration", "//cib/configuration/constraints" },
57 { XML_CIB_TAG_OPCONFIG, "/cib/configuration", "//cib/configuration/op_defaults" },
58 { XML_CIB_TAG_RSCCONFIG, "/cib/configuration", "//cib/configuration/rsc_defaults" },
59 { XML_CIB_TAG_ACLS, "/cib/configuration", "//cib/configuration/acls" },
60 { XML_TAG_FENCING_TOPOLOGY, "/cib/configuration", "//cib/configuration/fencing-topology" },
61 { XML_CIB_TAG_SECTION_ALL, NULL, "//cib" },
62 };
63
64
65 int
66 cib_compare_generation(xmlNode * left, xmlNode * right)
67 {
68 int lpc = 0;
69
70 const char *attributes[] = {
71 XML_ATTR_GENERATION_ADMIN,
72 XML_ATTR_GENERATION,
73 XML_ATTR_NUMUPDATES,
74 };
75
76 crm_log_xml_trace(left, "left");
77 crm_log_xml_trace(right, "right");
78
79 for (lpc = 0; lpc < DIMOF(attributes); lpc++) {
80 int int_elem_l = -1;
81 int int_elem_r = -1;
82 const char *elem_r = NULL;
83 const char *elem_l = crm_element_value(left, attributes[lpc]);
84
85 if (right != NULL) {
86 elem_r = crm_element_value(right, attributes[lpc]);
87 }
88
89 if (elem_l != NULL) {
90 int_elem_l = crm_parse_int(elem_l, NULL);
91 }
92 if (elem_r != NULL) {
93 int_elem_r = crm_parse_int(elem_r, NULL);
94 }
95
96 if (int_elem_l < int_elem_r) {
97 crm_trace("%s (%s < %s)", attributes[lpc], crm_str(elem_l), crm_str(elem_r));
98 return -1;
99
100 } else if (int_elem_l > int_elem_r) {
101 crm_trace("%s (%s > %s)", attributes[lpc], crm_str(elem_l), crm_str(elem_r));
102 return 1;
103 }
104 }
105
106 return 0;
107 }
108
109
110 xmlNode *
111 get_cib_copy(cib_t * cib)
112 {
113 xmlNode *xml_cib;
114 int options = cib_scope_local | cib_sync_call;
115 int rc = pcmk_ok;
116
117 if (cib->state == cib_disconnected) {
118 return NULL;
119 }
120
121 rc = cib->cmds->query(cib, NULL, &xml_cib, options);
122 if (rc == -EACCES) {
123 return NULL;
124
125 } else if (rc != pcmk_ok) {
126 crm_err("Couldn't retrieve the CIB");
127 free_xml(xml_cib);
128 return NULL;
129
130 } else if (xml_cib == NULL) {
131 crm_err("The CIB result was empty");
132 free_xml(xml_cib);
133 return NULL;
134 }
135
136 if (safe_str_eq(crm_element_name(xml_cib), XML_TAG_CIB)) {
137 return xml_cib;
138 }
139 free_xml(xml_cib);
140 return NULL;
141 }
142
143 xmlNode *
144 cib_get_generation(cib_t * cib)
145 {
146 xmlNode *the_cib = NULL;
147 xmlNode *generation = create_xml_node(NULL, XML_CIB_TAG_GENERATION_TUPPLE);
148
149 cib->cmds->query(cib, NULL, &the_cib, cib_scope_local | cib_sync_call);
150 if (the_cib != NULL) {
151 copy_in_properties(generation, the_cib);
152 free_xml(the_cib);
153 }
154
155 return generation;
156 }
157
158 gboolean
159 cib_version_details(xmlNode * cib, int *admin_epoch, int *epoch, int *updates)
160 {
161 *epoch = -1;
162 *updates = -1;
163 *admin_epoch = -1;
164
165 if (cib == NULL) {
166 return FALSE;
167
168 } else {
169 crm_element_value_int(cib, XML_ATTR_GENERATION, epoch);
170 crm_element_value_int(cib, XML_ATTR_NUMUPDATES, updates);
171 crm_element_value_int(cib, XML_ATTR_GENERATION_ADMIN, admin_epoch);
172 }
173 return TRUE;
174 }
175
176 gboolean
177 cib_diff_version_details(xmlNode * diff, int *admin_epoch, int *epoch, int *updates,
178 int *_admin_epoch, int *_epoch, int *_updates)
179 {
180 int add[] = { 0, 0, 0 };
181 int del[] = { 0, 0, 0 };
182
183 xml_patch_versions(diff, add, del);
184
185 *admin_epoch = add[0];
186 *epoch = add[1];
187 *updates = add[2];
188
189 *_admin_epoch = del[0];
190 *_epoch = del[1];
191 *_updates = del[2];
192
193 return TRUE;
194 }
195
196
197
198
199
200 const char *
201 get_object_path(const char *object_type)
202 {
203 int lpc = 0;
204 int max = DIMOF(known_paths);
205
206 for (; lpc < max; lpc++) {
207 if ((object_type == NULL && known_paths[lpc].name == NULL)
208 || safe_str_eq(object_type, known_paths[lpc].name)) {
209 return known_paths[lpc].path;
210 }
211 }
212 return NULL;
213 }
214
215 const char *
216 get_object_parent(const char *object_type)
217 {
218 int lpc = 0;
219 int max = DIMOF(known_paths);
220
221 for (; lpc < max; lpc++) {
222 if (safe_str_eq(object_type, known_paths[lpc].name)) {
223 return known_paths[lpc].parent;
224 }
225 }
226 return NULL;
227 }
228
229 xmlNode *
230 get_object_root(const char *object_type, xmlNode * the_root)
231 {
232 const char *xpath = get_object_path(object_type);
233
234 if (xpath == NULL) {
235 return the_root;
236 }
237
238 return get_xpath_object(xpath, the_root, LOG_DEBUG_4);
239 }
240
241
242
243
244
245 xmlNode *
246 createEmptyCib(int admin_epoch)
247 {
248 xmlNode *cib_root = NULL, *config = NULL;
249
250 cib_root = create_xml_node(NULL, XML_TAG_CIB);
251 crm_xml_add(cib_root, XML_ATTR_CRM_VERSION, CRM_FEATURE_SET);
252 crm_xml_add(cib_root, XML_ATTR_VALIDATION, xml_latest_schema());
253
254 crm_xml_add_int(cib_root, XML_ATTR_GENERATION, admin_epoch);
255 crm_xml_add_int(cib_root, XML_ATTR_NUMUPDATES, 0);
256 crm_xml_add_int(cib_root, XML_ATTR_GENERATION_ADMIN, 0);
257
258 config = create_xml_node(cib_root, XML_CIB_TAG_CONFIGURATION);
259 create_xml_node(cib_root, XML_CIB_TAG_STATUS);
260
261 create_xml_node(config, XML_CIB_TAG_CRMCONFIG);
262 create_xml_node(config, XML_CIB_TAG_NODES);
263 create_xml_node(config, XML_CIB_TAG_RESOURCES);
264 create_xml_node(config, XML_CIB_TAG_CONSTRAINTS);
265
266 return cib_root;
267 }
268
269 static bool
270 cib_acl_enabled(xmlNode *xml, const char *user)
271 {
272 bool rc = FALSE;
273
274 #if ENABLE_ACL
275 if(pcmk_acl_required(user)) {
276 const char *value = NULL;
277 GHashTable *options = crm_str_table_new();
278
279 cib_read_config(options, xml);
280 value = cib_pref(options, "enable-acl");
281 rc = crm_is_true(value);
282 g_hash_table_destroy(options);
283 }
284
285 crm_trace("CIB ACL is %s", rc ? "enabled" : "disabled");
286 #endif
287 return rc;
288 }
289
290 int
291 cib_perform_op(const char *op, int call_options, cib_op_t * fn, gboolean is_query,
292 const char *section, xmlNode * req, xmlNode * input,
293 gboolean manage_counters, gboolean * config_changed,
294 xmlNode * current_cib, xmlNode ** result_cib, xmlNode ** diff, xmlNode ** output)
295 {
296 int rc = pcmk_ok;
297 gboolean check_dtd = TRUE;
298 xmlNode *top = NULL;
299 xmlNode *scratch = NULL;
300 xmlNode *local_diff = NULL;
301
302 const char *new_version = NULL;
303 static struct qb_log_callsite *diff_cs = NULL;
304 const char *user = crm_element_value(req, F_CIB_USER);
305 bool with_digest = FALSE;
306
307 crm_trace("Begin %s%s%s op", is_set(call_options, cib_dryrun)?"dry-run of ":"", is_query ? "read-only " : "", op);
308
309 CRM_CHECK(output != NULL, return -ENOMSG);
310 CRM_CHECK(result_cib != NULL, return -ENOMSG);
311 CRM_CHECK(config_changed != NULL, return -ENOMSG);
312
313 if(output) {
314 *output = NULL;
315 }
316
317 *result_cib = NULL;
318 *config_changed = FALSE;
319
320 if (fn == NULL) {
321 return -EINVAL;
322 }
323
324 if (is_query) {
325 xmlNode *cib_ro = current_cib;
326 xmlNode *cib_filtered = NULL;
327
328 if(cib_acl_enabled(cib_ro, user)) {
329 if(xml_acl_filtered_copy(user, current_cib, current_cib, &cib_filtered)) {
330 if (cib_filtered == NULL) {
331 crm_debug("Pre-filtered the entire cib");
332 return -EACCES;
333 }
334 cib_ro = cib_filtered;
335 crm_log_xml_trace(cib_ro, "filtered");
336 }
337 }
338
339 rc = (*fn) (op, call_options, section, req, input, cib_ro, result_cib, output);
340
341 if(output == NULL || *output == NULL) {
342
343
344 } else if(cib_filtered == *output) {
345 cib_filtered = NULL;
346
347 } else if(*output == current_cib) {
348
349
350 } else if(cib_filtered && (*output)->doc == cib_filtered->doc) {
351
352 *output = copy_xml(*output);
353
354 } else if((*output)->doc == current_cib->doc) {
355
356 *output = copy_xml(*output);
357 }
358
359 free_xml(cib_filtered);
360 return rc;
361 }
362
363
364 if (is_set(call_options, cib_zero_copy)) {
365
366
367 scratch = current_cib;
368
369
370 current_cib = create_xml_node(NULL, (const char *)scratch->name);
371 copy_in_properties(current_cib, scratch);
372 top = current_cib;
373
374 xml_track_changes(scratch, user, NULL, cib_acl_enabled(scratch, user));
375 rc = (*fn) (op, call_options, section, req, input, scratch, &scratch, output);
376
377 } else {
378 scratch = copy_xml(current_cib);
379 xml_track_changes(scratch, user, NULL, cib_acl_enabled(scratch, user));
380 rc = (*fn) (op, call_options, section, req, input, current_cib, &scratch, output);
381
382 if(scratch && xml_tracking_changes(scratch) == FALSE) {
383 crm_trace("Inferring changes after %s op", op);
384 xml_track_changes(scratch, user, current_cib, cib_acl_enabled(current_cib, user));
385 xml_calculate_changes(current_cib, scratch);
386 }
387 CRM_CHECK(current_cib != scratch, return -EINVAL);
388 }
389
390 xml_acl_disable(scratch);
391
392 if (rc == pcmk_ok && scratch == NULL) {
393 rc = -EINVAL;
394 goto done;
395
396 } else if(rc == pcmk_ok && xml_acl_denied(scratch)) {
397 crm_trace("ACL rejected part or all of the proposed changes");
398 rc = -EACCES;
399 goto done;
400
401 } else if (rc != pcmk_ok) {
402 goto done;
403 }
404
405 if (scratch) {
406 new_version = crm_element_value(scratch, XML_ATTR_CRM_VERSION);
407
408 if (new_version && compare_version(new_version, CRM_FEATURE_SET) > 0) {
409 crm_err("Discarding update with feature set '%s' greater than our own '%s'",
410 new_version, CRM_FEATURE_SET);
411 rc = -EPROTONOSUPPORT;
412 goto done;
413 }
414 }
415
416 if (current_cib) {
417 int old = 0;
418 int new = 0;
419
420 crm_element_value_int(scratch, XML_ATTR_GENERATION_ADMIN, &new);
421 crm_element_value_int(current_cib, XML_ATTR_GENERATION_ADMIN, &old);
422
423 if (old > new) {
424 crm_err("%s went backwards: %d -> %d (Opts: 0x%x)",
425 XML_ATTR_GENERATION_ADMIN, old, new, call_options);
426 crm_log_xml_warn(req, "Bad Op");
427 crm_log_xml_warn(input, "Bad Data");
428 rc = -pcmk_err_old_data;
429
430 } else if (old == new) {
431 crm_element_value_int(scratch, XML_ATTR_GENERATION, &new);
432 crm_element_value_int(current_cib, XML_ATTR_GENERATION, &old);
433 if (old > new) {
434 crm_err("%s went backwards: %d -> %d (Opts: 0x%x)",
435 XML_ATTR_GENERATION, old, new, call_options);
436 crm_log_xml_warn(req, "Bad Op");
437 crm_log_xml_warn(input, "Bad Data");
438 rc = -pcmk_err_old_data;
439 }
440 }
441 }
442
443 crm_trace("Massaging CIB contents");
444 strip_text_nodes(scratch);
445 fix_plus_plus_recursive(scratch);
446
447 if (is_set(call_options, cib_zero_copy)) {
448
449
450
451
452
453 local_diff = xml_create_patchset(2, current_cib, scratch, (bool*)config_changed, manage_counters);
454
455 } else {
456 static time_t expires = 0;
457 time_t tm_now = time(NULL);
458
459 if (expires < tm_now) {
460 expires = tm_now + 60;
461 with_digest = TRUE;
462 }
463
464 local_diff = xml_create_patchset(0, current_cib, scratch, (bool*)config_changed, manage_counters);
465 }
466
467 xml_log_changes(LOG_TRACE, __FUNCTION__, scratch);
468 xml_accept_changes(scratch);
469
470 if (diff_cs == NULL) {
471 diff_cs = qb_log_callsite_get(__PRETTY_FUNCTION__, __FILE__, "diff-validation", LOG_DEBUG, __LINE__, crm_trace_nonlog);
472 }
473
474 if(local_diff) {
475 patchset_process_digest(local_diff, current_cib, scratch, with_digest);
476
477 xml_log_patchset(LOG_INFO, __FUNCTION__, local_diff);
478 crm_log_xml_trace(local_diff, "raw patch");
479 }
480
481 if (is_not_set(call_options, cib_zero_copy)
482 && local_diff
483 && crm_is_callsite_active(diff_cs, LOG_TRACE, 0)) {
484
485
486 int test_rc, format = 1;
487 xmlNode * c = copy_xml(current_cib);
488
489 crm_element_value_int(local_diff, "format", &format);
490 test_rc = xml_apply_patchset(c, local_diff, manage_counters);
491
492 if(test_rc != pcmk_ok) {
493 save_xml_to_file(c, "PatchApply:calculated", NULL);
494 save_xml_to_file(current_cib, "PatchApply:input", NULL);
495 save_xml_to_file(scratch, "PatchApply:actual", NULL);
496 save_xml_to_file(local_diff, "PatchApply:diff", NULL);
497 crm_err("v%d patchset error, patch failed to apply: %s (%d)", format, pcmk_strerror(test_rc), test_rc);
498 }
499 free_xml(c);
500 }
501
502 if (safe_str_eq(section, XML_CIB_TAG_STATUS)) {
503
504
505
506
507 check_dtd = FALSE;
508 }
509
510
511
512
513
514
515
516
517
518
519
520
521
522 if (*config_changed && is_not_set(call_options, cib_no_mtime)) {
523 char *now_str = NULL;
524 time_t now = time(NULL);
525 const char *schema = crm_element_value(scratch, XML_ATTR_VALIDATION);
526
527 now_str = ctime(&now);
528 now_str[24] = EOS;
529 crm_xml_replace(scratch, XML_CIB_ATTR_WRITTEN, now_str);
530
531 if (schema) {
532 static int minimum_schema = 0;
533 int current_schema = get_schema_version(schema);
534
535 if (minimum_schema == 0) {
536 minimum_schema = get_schema_version("pacemaker-1.2");
537 }
538
539
540 if (current_schema >= minimum_schema) {
541 const char *origin = crm_element_value(req, F_ORIG);
542
543 CRM_LOG_ASSERT(origin != NULL);
544 crm_xml_replace(scratch, XML_ATTR_UPDATE_ORIG, origin);
545 crm_xml_replace(scratch, XML_ATTR_UPDATE_CLIENT,
546 crm_element_value(req, F_CIB_CLIENTNAME));
547 #if ENABLE_ACL
548 crm_xml_replace(scratch, XML_ATTR_UPDATE_USER, crm_element_value(req, F_CIB_USER));
549 #endif
550 }
551 }
552 }
553
554 crm_trace("Perform validation: %s", check_dtd ? "true" : "false");
555 if (rc == pcmk_ok && check_dtd && validate_xml(scratch, NULL, TRUE) == FALSE) {
556 const char *current_dtd = crm_element_value(scratch, XML_ATTR_VALIDATION);
557
558 crm_warn("Updated CIB does not validate against %s schema/dtd", crm_str(current_dtd));
559 rc = -pcmk_err_schema_validation;
560 }
561
562 done:
563
564 *result_cib = scratch;
565 #if ENABLE_ACL
566 if(rc != pcmk_ok && cib_acl_enabled(current_cib, user)) {
567 if(xml_acl_filtered_copy(user, current_cib, scratch, result_cib)) {
568 if (*result_cib == NULL) {
569 crm_debug("Pre-filtered the entire cib result");
570 }
571 free_xml(scratch);
572 }
573 }
574 #endif
575
576 if(diff) {
577 *diff = local_diff;
578 } else {
579 free_xml(local_diff);
580 }
581
582 free_xml(top);
583 crm_trace("Done");
584 return rc;
585 }
586
587 xmlNode *
588 cib_create_op(int call_id, const char *token, const char *op, const char *host, const char *section,
589 xmlNode * data, int call_options, const char *user_name)
590 {
591 xmlNode *op_msg = create_xml_node(NULL, "cib_command");
592
593 CRM_CHECK(op_msg != NULL, return NULL);
594 CRM_CHECK(token != NULL, return NULL);
595
596 crm_xml_add(op_msg, F_XML_TAGNAME, "cib_command");
597
598 crm_xml_add(op_msg, F_TYPE, T_CIB);
599 crm_xml_add(op_msg, F_CIB_CALLBACK_TOKEN, token);
600 crm_xml_add(op_msg, F_CIB_OPERATION, op);
601 crm_xml_add(op_msg, F_CIB_HOST, host);
602 crm_xml_add(op_msg, F_CIB_SECTION, section);
603 crm_xml_add_int(op_msg, F_CIB_CALLID, call_id);
604 #if ENABLE_ACL
605 if (user_name) {
606 crm_xml_add(op_msg, F_CIB_USER, user_name);
607 }
608 #endif
609 crm_trace("Sending call options: %.8lx, %d", (long)call_options, call_options);
610 crm_xml_add_int(op_msg, F_CIB_CALLOPTS, call_options);
611
612 if (data != NULL) {
613 add_message_xml(op_msg, F_CIB_CALLDATA, data);
614 }
615
616 if (call_options & cib_inhibit_bcast) {
617 CRM_CHECK((call_options & cib_scope_local), return NULL);
618 }
619 return op_msg;
620 }
621
622 void
623 cib_native_callback(cib_t * cib, xmlNode * msg, int call_id, int rc)
624 {
625 xmlNode *output = NULL;
626 cib_callback_client_t *blob = NULL;
627
628 if (msg != NULL) {
629 crm_element_value_int(msg, F_CIB_RC, &rc);
630 crm_element_value_int(msg, F_CIB_CALLID, &call_id);
631 output = get_message_xml(msg, F_CIB_CALLDATA);
632 }
633
634 blob = g_hash_table_lookup(cib_op_callback_table, GINT_TO_POINTER(call_id));
635 if (blob == NULL) {
636 crm_trace("No callback found for call %d", call_id);
637 }
638
639 if (cib == NULL) {
640 crm_debug("No cib object supplied");
641 }
642
643 if (rc == -pcmk_err_diff_resync) {
644
645 rc = pcmk_ok;
646 }
647
648 if (blob && blob->callback && (rc == pcmk_ok || blob->only_success == FALSE)) {
649 crm_trace("Invoking callback %s for call %d", crm_str(blob->id), call_id);
650 blob->callback(msg, call_id, rc, output, blob->user_data);
651
652 } else if (cib && cib->op_callback == NULL && rc != pcmk_ok) {
653 crm_warn("CIB command failed: %s", pcmk_strerror(rc));
654 crm_log_xml_debug(msg, "Failed CIB Update");
655 }
656
657
658 if (blob) {
659 remove_cib_op_callback(call_id, FALSE);
660 }
661
662 if (cib && cib->op_callback != NULL) {
663 crm_trace("Invoking global callback for call %d", call_id);
664 cib->op_callback(msg, call_id, rc, output);
665 }
666 crm_trace("OP callback activated for %d", call_id);
667 }
668
669 void
670 cib_native_notify(gpointer data, gpointer user_data)
671 {
672 xmlNode *msg = user_data;
673 cib_notify_client_t *entry = data;
674 const char *event = NULL;
675
676 if (msg == NULL) {
677 crm_warn("Skipping callback - NULL message");
678 return;
679 }
680
681 event = crm_element_value(msg, F_SUBTYPE);
682
683 if (entry == NULL) {
684 crm_warn("Skipping callback - NULL callback client");
685 return;
686
687 } else if (entry->callback == NULL) {
688 crm_warn("Skipping callback - NULL callback");
689 return;
690
691 } else if (safe_str_neq(entry->event, event)) {
692 crm_trace("Skipping callback - event mismatch %p/%s vs. %s", entry, entry->event, event);
693 return;
694 }
695
696 crm_trace("Invoking callback for %p/%s event...", entry, event);
697 entry->callback(event, msg);
698 crm_trace("Callback invoked...");
699 }
700
701 pe_cluster_option cib_opts[] = {
702
703
704
705
706
707
708 {
709 "enable-acl", NULL,
710 "boolean", NULL, "false", &check_boolean,
711 "Enable CIB ACL",
712 NULL
713 },
714 {
715 "cluster-ipc-limit", NULL,
716 "integer", NULL, "500", &check_positive_number,
717 "Maximum IPC message backlog before disconnecting a cluster daemon",
718 "Raise this if log has \"Evicting client\" messages for cluster daemon"
719 " PIDs (a good value is the number of resources in the cluster"
720 " multiplied by the number of nodes)"
721 },
722 };
723
724 void
725 cib_metadata(void)
726 {
727 config_metadata("Cluster Information Base", "1.0",
728 "Cluster Information Base Options",
729 "This is a fake resource that details the options that can be configured for the Cluster Information Base.",
730 cib_opts, DIMOF(cib_opts));
731 }
732
733 void
734 verify_cib_options(GHashTable * options)
735 {
736 verify_all_options(options, cib_opts, DIMOF(cib_opts));
737 }
738
739 const char *
740 cib_pref(GHashTable * options, const char *name)
741 {
742 return get_cluster_pref(options, cib_opts, DIMOF(cib_opts), name);
743 }
744
745 gboolean
746 cib_read_config(GHashTable * options, xmlNode * current_cib)
747 {
748 xmlNode *config = NULL;
749 crm_time_t *now = NULL;
750
751 if (options == NULL || current_cib == NULL) {
752 return FALSE;
753 }
754
755 now = crm_time_new(NULL);
756
757 g_hash_table_remove_all(options);
758
759 config = get_object_root(XML_CIB_TAG_CRMCONFIG, current_cib);
760 if (config) {
761 unpack_instance_attributes(current_cib, config, XML_CIB_TAG_PROPSET, NULL, options,
762 CIB_OPTIONS_FIRST, TRUE, now);
763 }
764
765 verify_cib_options(options);
766
767 crm_time_free(now);
768
769 return TRUE;
770 }
771
772 int
773 cib_apply_patch_event(xmlNode * event, xmlNode * input, xmlNode ** output, int level)
774 {
775 int rc = pcmk_err_generic;
776
777 xmlNode *diff = NULL;
778
779 CRM_ASSERT(event);
780 CRM_ASSERT(input);
781 CRM_ASSERT(output);
782
783 crm_element_value_int(event, F_CIB_RC, &rc);
784 diff = get_message_xml(event, F_CIB_UPDATE_RESULT);
785
786 if (rc < pcmk_ok || diff == NULL) {
787 return rc;
788 }
789
790 if (level > LOG_CRIT) {
791 xml_log_patchset(level, "Config update", diff);
792 }
793
794 if (input != NULL) {
795 rc = cib_process_diff(NULL, cib_none, NULL, event, diff, input, output, NULL);
796
797 if (rc != pcmk_ok) {
798 crm_debug("Update didn't apply: %s (%d) %p", pcmk_strerror(rc), rc, *output);
799
800 if (rc == -pcmk_err_old_data) {
801 crm_trace("Masking error, we already have the supplied update");
802 return pcmk_ok;
803 }
804 free_xml(*output); *output = NULL;
805
806 return rc;
807 }
808 }
809
810 return rc;
811 }
812
813
814 #define XPATH_CONFIG_CHANGE \
815 "//" XML_CIB_TAG_CRMCONFIG " | " \
816 "//" XML_DIFF_CHANGE "[contains(@" XML_DIFF_PATH ",'/" XML_CIB_TAG_CRMCONFIG "/')]"
817
818 gboolean
819 cib_internal_config_changed(xmlNode *diff)
820 {
821 gboolean changed = FALSE;
822
823 if (diff) {
824 xmlXPathObject *xpathObj = xpath_search(diff, XPATH_CONFIG_CHANGE);
825
826 if (numXpathResults(xpathObj) > 0) {
827 changed = TRUE;
828 }
829 freeXpathObject(xpathObj);
830 }
831 return changed;
832 }
833
834 int
835 cib_internal_op(cib_t * cib, const char *op, const char *host,
836 const char *section, xmlNode * data,
837 xmlNode ** output_data, int call_options, const char *user_name)
838 {
839 int (*delegate) (cib_t * cib, const char *op, const char *host,
840 const char *section, xmlNode * data,
841 xmlNode ** output_data, int call_options, const char *user_name) =
842 cib->delegate_fn;
843
844 #if ENABLE_ACL
845 if(user_name == NULL) {
846 user_name = getenv("CIB_user");
847 }
848 #endif
849
850 return delegate(cib, op, host, section, data, output_data, call_options, user_name);
851 }