This source file includes following definitions.
- cib_client_set_op_callback
- ciblib_GCompareFunc
- cib_client_add_notify_callback
- get_notify_list_event_count
- cib_client_del_notify_callback
- cib_async_timeout_handler
- cib_client_register_callback_full
- cib_client_register_callback
- cib_client_noop
- cib_client_ping
- cib_client_query
- cib_client_query_from
- is_primary
- set_secondary
- set_all_secondary
- set_primary
- cib_client_bump_epoch
- cib_client_upgrade
- cib_client_sync
- cib_client_sync_from
- cib_client_create
- cib_client_modify
- cib_client_replace
- cib_client_delete
- cib_client_delete_absolute
- cib_client_erase
- cib_destroy_op_callback
- destroy_op_callback_table
- get_shadow_file
- cib_shadow_new
- cib_new_no_shadow
- cib_new
- cib_new_variant
- cib_free_notify
- cib_free_callbacks
- cib_delete
- remove_cib_op_callback
- num_cib_op_callbacks
- cib_dump_pending_op
- cib_dump_pending_callbacks
- cib__lookup_id
1
2
3
4
5
6
7
8
9
10 #include <crm_internal.h>
11 #include <unistd.h>
12 #include <stdlib.h>
13 #include <stdio.h>
14 #include <stdarg.h>
15 #include <string.h>
16 #include <pwd.h>
17
18 #include <sys/stat.h>
19 #include <sys/types.h>
20
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/xml.h>
27
28 static GHashTable *cib_op_callback_table = NULL;
29
30 #define op_common(cib) do { \
31 if(cib == NULL) { \
32 return -EINVAL; \
33 } else if(cib->delegate_fn == NULL) { \
34 return -EPROTONOSUPPORT; \
35 } \
36 } while(0)
37
38 static int
39 cib_client_set_op_callback(cib_t *cib,
40 void (*callback) (const xmlNode * msg, int call_id,
41 int rc, xmlNode * output))
42 {
43 if (callback == NULL) {
44 crm_info("Un-Setting operation callback");
45
46 } else {
47 crm_trace("Setting operation callback");
48 }
49 cib->op_callback = callback;
50 return pcmk_ok;
51 }
52
53 static gint
54 ciblib_GCompareFunc(gconstpointer a, gconstpointer b)
55 {
56 int rc = 0;
57 const cib_notify_client_t *a_client = a;
58 const cib_notify_client_t *b_client = b;
59
60 CRM_CHECK(a_client->event != NULL && b_client->event != NULL, return 0);
61 rc = strcmp(a_client->event, b_client->event);
62 if (rc == 0) {
63 if (a_client->callback == b_client->callback) {
64 return 0;
65 } else if (((long)a_client->callback) < ((long)b_client->callback)) {
66 crm_trace("callbacks for %s are not equal: %p < %p",
67 a_client->event, a_client->callback, b_client->callback);
68 return -1;
69 }
70 crm_trace("callbacks for %s are not equal: %p > %p",
71 a_client->event, a_client->callback, b_client->callback);
72 return 1;
73 }
74 return rc;
75 }
76
77 static int
78 cib_client_add_notify_callback(cib_t * cib, const char *event,
79 void (*callback) (const char *event,
80 xmlNode * msg))
81 {
82 GList *list_item = NULL;
83 cib_notify_client_t *new_client = NULL;
84
85 if ((cib->variant != cib_native) && (cib->variant != cib_remote)) {
86 return -EPROTONOSUPPORT;
87 }
88
89 crm_trace("Adding callback for %s events (%d)",
90 event, g_list_length(cib->notify_list));
91
92 new_client = calloc(1, sizeof(cib_notify_client_t));
93 new_client->event = event;
94 new_client->callback = callback;
95
96 list_item = g_list_find_custom(cib->notify_list, new_client,
97 ciblib_GCompareFunc);
98
99 if (list_item != NULL) {
100 crm_warn("Callback already present");
101 free(new_client);
102 return -EINVAL;
103
104 } else {
105 cib->notify_list = g_list_append(cib->notify_list, new_client);
106
107 cib->cmds->register_notification(cib, event, 1);
108
109 crm_trace("Callback added (%d)", g_list_length(cib->notify_list));
110 }
111 return pcmk_ok;
112 }
113
114 static int
115 get_notify_list_event_count(cib_t *cib, const char *event)
116 {
117 int count = 0;
118
119 for (GList *iter = g_list_first(cib->notify_list); iter != NULL;
120 iter = iter->next) {
121 cib_notify_client_t *client = (cib_notify_client_t *) iter->data;
122
123 if (strcmp(client->event, event) == 0) {
124 count++;
125 }
126 }
127 crm_trace("event(%s) count : %d", event, count);
128 return count;
129 }
130
131 static int
132 cib_client_del_notify_callback(cib_t *cib, const char *event,
133 void (*callback) (const char *event,
134 xmlNode *msg))
135 {
136 GList *list_item = NULL;
137 cib_notify_client_t *new_client = NULL;
138
139 if (cib->variant != cib_native && cib->variant != cib_remote) {
140 return -EPROTONOSUPPORT;
141 }
142
143 if (get_notify_list_event_count(cib, event) == 0) {
144 crm_debug("The callback of the event does not exist(%s)", event);
145 return pcmk_ok;
146 }
147
148 crm_debug("Removing callback for %s events", event);
149
150 new_client = calloc(1, sizeof(cib_notify_client_t));
151 new_client->event = event;
152 new_client->callback = callback;
153
154 list_item = g_list_find_custom(cib->notify_list, new_client, ciblib_GCompareFunc);
155
156 if (list_item != NULL) {
157 cib_notify_client_t *list_client = list_item->data;
158
159 cib->notify_list = g_list_remove(cib->notify_list, list_client);
160 free(list_client);
161
162 crm_trace("Removed callback");
163
164 } else {
165 crm_trace("Callback not present");
166 }
167
168 if (get_notify_list_event_count(cib, event) == 0) {
169
170 cib->cmds->register_notification(cib, event, 0);
171 }
172
173 free(new_client);
174 return pcmk_ok;
175 }
176
177 static gboolean
178 cib_async_timeout_handler(gpointer data)
179 {
180 struct timer_rec_s *timer = data;
181
182 crm_debug("Async call %d timed out after %ds",
183 timer->call_id, timer->timeout);
184 cib_native_callback(timer->cib, NULL, timer->call_id, -ETIME);
185
186
187 return G_SOURCE_CONTINUE;
188 }
189
190 static gboolean
191 cib_client_register_callback_full(cib_t *cib, int call_id, int timeout,
192 gboolean only_success, void *user_data,
193 const char *callback_name,
194 void (*callback)(xmlNode *, int, int,
195 xmlNode *, void *),
196 void (*free_func)(void *))
197 {
198 cib_callback_client_t *blob = NULL;
199
200 if (call_id < 0) {
201 if (only_success == FALSE) {
202 callback(NULL, call_id, call_id, NULL, user_data);
203 } else {
204 crm_warn("CIB call failed: %s", pcmk_strerror(call_id));
205 }
206 if (user_data && free_func) {
207 free_func(user_data);
208 }
209 return FALSE;
210 }
211
212 blob = calloc(1, sizeof(cib_callback_client_t));
213 blob->id = callback_name;
214 blob->only_success = only_success;
215 blob->user_data = user_data;
216 blob->callback = callback;
217 blob->free_func = free_func;
218
219 if (timeout > 0) {
220 struct timer_rec_s *async_timer = NULL;
221
222 async_timer = calloc(1, sizeof(struct timer_rec_s));
223 blob->timer = async_timer;
224
225 async_timer->cib = cib;
226 async_timer->call_id = call_id;
227 async_timer->timeout = timeout * 1000;
228 async_timer->ref = g_timeout_add(async_timer->timeout,
229 cib_async_timeout_handler,
230 async_timer);
231 }
232
233 crm_trace("Adding callback %s for call %d", callback_name, call_id);
234 pcmk__intkey_table_insert(cib_op_callback_table, call_id, blob);
235
236 return TRUE;
237 }
238
239 static gboolean
240 cib_client_register_callback(cib_t *cib, int call_id, int timeout,
241 gboolean only_success, void *user_data,
242 const char *callback_name,
243 void (*callback) (xmlNode *, int, int, xmlNode *,
244 void *))
245 {
246 return cib_client_register_callback_full(cib, call_id, timeout,
247 only_success, user_data,
248 callback_name, callback, NULL);
249 }
250
251 static int
252 cib_client_noop(cib_t * cib, int call_options)
253 {
254 op_common(cib);
255 return cib_internal_op(cib, PCMK__CIB_REQUEST_NOOP, NULL, NULL, NULL, NULL,
256 call_options, NULL);
257 }
258
259 static int
260 cib_client_ping(cib_t * cib, xmlNode ** output_data, int call_options)
261 {
262 op_common(cib);
263 return cib_internal_op(cib, CRM_OP_PING, NULL, NULL, NULL, output_data, call_options, NULL);
264 }
265
266 static int
267 cib_client_query(cib_t * cib, const char *section, xmlNode ** output_data, int call_options)
268 {
269 return cib->cmds->query_from(cib, NULL, section, output_data, call_options);
270 }
271
272 static int
273 cib_client_query_from(cib_t * cib, const char *host, const char *section,
274 xmlNode ** output_data, int call_options)
275 {
276 op_common(cib);
277 return cib_internal_op(cib, PCMK__CIB_REQUEST_QUERY, host, section, NULL,
278 output_data, call_options, NULL);
279 }
280
281 static int
282 is_primary(cib_t *cib)
283 {
284 op_common(cib);
285 return cib_internal_op(cib, PCMK__CIB_REQUEST_IS_PRIMARY, NULL, NULL, NULL,
286 NULL, cib_scope_local|cib_sync_call, NULL);
287 }
288
289 static int
290 set_secondary(cib_t *cib, int call_options)
291 {
292 op_common(cib);
293 return cib_internal_op(cib, PCMK__CIB_REQUEST_SECONDARY, NULL, NULL, NULL,
294 NULL, call_options, NULL);
295 }
296
297 static int
298 set_all_secondary(cib_t * cib, int call_options)
299 {
300 return -EPROTONOSUPPORT;
301 }
302
303 static int
304 set_primary(cib_t *cib, int call_options)
305 {
306 op_common(cib);
307 crm_trace("Adding cib_scope_local to options");
308 return cib_internal_op(cib, PCMK__CIB_REQUEST_PRIMARY, NULL, NULL, NULL,
309 NULL, call_options|cib_scope_local, NULL);
310 }
311
312 static int
313 cib_client_bump_epoch(cib_t * cib, int call_options)
314 {
315 op_common(cib);
316 return cib_internal_op(cib, PCMK__CIB_REQUEST_BUMP, NULL, NULL, NULL, NULL,
317 call_options, NULL);
318 }
319
320 static int
321 cib_client_upgrade(cib_t * cib, int call_options)
322 {
323 op_common(cib);
324 return cib_internal_op(cib, PCMK__CIB_REQUEST_UPGRADE, NULL, NULL, NULL,
325 NULL, call_options, NULL);
326 }
327
328 static int
329 cib_client_sync(cib_t * cib, const char *section, int call_options)
330 {
331 return cib->cmds->sync_from(cib, NULL, section, call_options);
332 }
333
334 static int
335 cib_client_sync_from(cib_t * cib, const char *host, const char *section, int call_options)
336 {
337 op_common(cib);
338 return cib_internal_op(cib, PCMK__CIB_REQUEST_SYNC_TO_ALL, host, section,
339 NULL, NULL, call_options, NULL);
340 }
341
342 static int
343 cib_client_create(cib_t * cib, const char *section, xmlNode * data, int call_options)
344 {
345 op_common(cib);
346 return cib_internal_op(cib, PCMK__CIB_REQUEST_CREATE, NULL, section, data,
347 NULL, call_options, NULL);
348 }
349
350 static int
351 cib_client_modify(cib_t * cib, const char *section, xmlNode * data, int call_options)
352 {
353 op_common(cib);
354 return cib_internal_op(cib, PCMK__CIB_REQUEST_MODIFY, NULL, section, data,
355 NULL, call_options, NULL);
356 }
357
358 static int
359 cib_client_replace(cib_t * cib, const char *section, xmlNode * data, int call_options)
360 {
361 op_common(cib);
362 return cib_internal_op(cib, PCMK__CIB_REQUEST_REPLACE, NULL, section, data,
363 NULL, call_options, NULL);
364 }
365
366 static int
367 cib_client_delete(cib_t * cib, const char *section, xmlNode * data, int call_options)
368 {
369 op_common(cib);
370 return cib_internal_op(cib, PCMK__CIB_REQUEST_DELETE, NULL, section, data,
371 NULL, call_options, NULL);
372 }
373
374 static int
375 cib_client_delete_absolute(cib_t * cib, const char *section, xmlNode * data, int call_options)
376 {
377 op_common(cib);
378 return cib_internal_op(cib, PCMK__CIB_REQUEST_ABS_DELETE, NULL, section,
379 data, NULL, call_options, NULL);
380 }
381
382 static int
383 cib_client_erase(cib_t * cib, xmlNode ** output_data, int call_options)
384 {
385 op_common(cib);
386 return cib_internal_op(cib, PCMK__CIB_REQUEST_ERASE, NULL, NULL, NULL,
387 output_data, call_options, NULL);
388 }
389
390 static void
391 cib_destroy_op_callback(gpointer data)
392 {
393 cib_callback_client_t *blob = data;
394
395 if (blob->timer && blob->timer->ref > 0) {
396 g_source_remove(blob->timer->ref);
397 }
398 free(blob->timer);
399
400 if (blob->user_data && blob->free_func) {
401 blob->free_func(blob->user_data);
402 }
403
404 free(blob);
405 }
406
407 static void
408 destroy_op_callback_table(void)
409 {
410 if (cib_op_callback_table != NULL) {
411 g_hash_table_destroy(cib_op_callback_table);
412 cib_op_callback_table = NULL;
413 }
414 }
415
416 char *
417 get_shadow_file(const char *suffix)
418 {
419 char *cib_home = NULL;
420 char *fullname = NULL;
421 char *name = crm_strdup_printf("shadow.%s", suffix);
422 const char *dir = getenv("CIB_shadow_dir");
423
424 if (dir == NULL) {
425 uid_t uid = geteuid();
426 struct passwd *pwent = getpwuid(uid);
427 const char *user = NULL;
428
429 if (pwent) {
430 user = pwent->pw_name;
431 } else {
432 user = getenv("USER");
433 crm_perror(LOG_ERR,
434 "Assuming %s because cannot get user details for user ID %d",
435 (user? user : "unprivileged user"), uid);
436 }
437
438 if (pcmk__strcase_any_of(user, "root", CRM_DAEMON_USER, NULL)) {
439 dir = CRM_CONFIG_DIR;
440
441 } else {
442 const char *home = NULL;
443
444 if ((home = getenv("HOME")) == NULL) {
445 if (pwent) {
446 home = pwent->pw_dir;
447 }
448 }
449
450 dir = pcmk__get_tmpdir();
451 if (home && home[0] == '/') {
452 int rc = 0;
453
454 cib_home = crm_strdup_printf("%s/.cib", home);
455
456 rc = mkdir(cib_home, 0700);
457 if (rc < 0 && errno != EEXIST) {
458 crm_perror(LOG_ERR, "Couldn't create user-specific shadow directory: %s",
459 cib_home);
460 errno = 0;
461
462 } else {
463 dir = cib_home;
464 }
465 }
466 }
467 }
468
469 fullname = crm_strdup_printf("%s/%s", dir, name);
470 free(cib_home);
471 free(name);
472
473 return fullname;
474 }
475
476 cib_t *
477 cib_shadow_new(const char *shadow)
478 {
479 cib_t *new_cib = NULL;
480 char *shadow_file = NULL;
481
482 CRM_CHECK(shadow != NULL, return NULL);
483
484 shadow_file = get_shadow_file(shadow);
485 new_cib = cib_file_new(shadow_file);
486 free(shadow_file);
487
488 return new_cib;
489 }
490
491
492
493
494
495
496
497
498
499
500
501
502
503 cib_t *
504 cib_new_no_shadow(void)
505 {
506 const char *shadow = getenv("CIB_shadow");
507 cib_t *cib = NULL;
508
509 unsetenv("CIB_shadow");
510 cib = cib_new();
511
512 if (shadow != NULL) {
513 setenv("CIB_shadow", shadow, 1);
514 }
515 return cib;
516 }
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534 cib_t *
535 cib_new(void)
536 {
537 const char *value = getenv("CIB_shadow");
538 int port;
539
540 if (value && value[0] != 0) {
541 return cib_shadow_new(value);
542 }
543
544 value = getenv("CIB_file");
545 if (value) {
546 return cib_file_new(value);
547 }
548
549 value = getenv("CIB_port");
550 if (value) {
551 gboolean encrypted = TRUE;
552 const char *server = getenv("CIB_server");
553 const char *user = getenv("CIB_user");
554 const char *pass = getenv("CIB_passwd");
555
556
557
558
559
560
561 pcmk__scan_port(value, &port);
562
563 value = getenv("CIB_encrypted");
564 if (value && crm_is_true(value) == FALSE) {
565 crm_info("Disabling TLS");
566 encrypted = FALSE;
567 }
568
569 if (user == NULL) {
570 user = CRM_DAEMON_USER;
571 crm_info("Defaulting to user: %s", user);
572 }
573
574 if (server == NULL) {
575 server = "localhost";
576 crm_info("Defaulting to localhost");
577 }
578
579 return cib_remote_new(server, user, pass, port, encrypted);
580 }
581
582 return cib_native_new();
583 }
584
585
586
587
588
589
590
591
592
593
594 cib_t *
595 cib_new_variant(void)
596 {
597 cib_t *new_cib = NULL;
598
599 new_cib = calloc(1, sizeof(cib_t));
600
601 if (new_cib == NULL) {
602 return NULL;
603 }
604
605 remove_cib_op_callback(0, TRUE);
606
607 new_cib->call_id = 1;
608 new_cib->variant = cib_undefined;
609
610 new_cib->type = cib_no_connection;
611 new_cib->state = cib_disconnected;
612
613 new_cib->op_callback = NULL;
614 new_cib->variant_opaque = NULL;
615 new_cib->notify_list = NULL;
616
617
618 new_cib->cmds = calloc(1, sizeof(cib_api_operations_t));
619
620 if (new_cib->cmds == NULL) {
621 free(new_cib);
622 return NULL;
623 }
624
625 new_cib->cmds->set_op_callback = cib_client_set_op_callback;
626 new_cib->cmds->add_notify_callback = cib_client_add_notify_callback;
627 new_cib->cmds->del_notify_callback = cib_client_del_notify_callback;
628 new_cib->cmds->register_callback = cib_client_register_callback;
629 new_cib->cmds->register_callback_full = cib_client_register_callback_full;
630
631 new_cib->cmds->noop = cib_client_noop;
632 new_cib->cmds->ping = cib_client_ping;
633 new_cib->cmds->query = cib_client_query;
634 new_cib->cmds->sync = cib_client_sync;
635
636 new_cib->cmds->query_from = cib_client_query_from;
637 new_cib->cmds->sync_from = cib_client_sync_from;
638
639 new_cib->cmds->is_master = is_primary;
640
641 new_cib->cmds->set_primary = set_primary;
642 new_cib->cmds->set_master = set_primary;
643
644 new_cib->cmds->set_secondary = set_secondary;
645 new_cib->cmds->set_slave = set_secondary;
646
647 new_cib->cmds->set_slave_all = set_all_secondary;
648
649 new_cib->cmds->upgrade = cib_client_upgrade;
650 new_cib->cmds->bump_epoch = cib_client_bump_epoch;
651
652 new_cib->cmds->create = cib_client_create;
653 new_cib->cmds->modify = cib_client_modify;
654 new_cib->cmds->update = cib_client_modify;
655 new_cib->cmds->replace = cib_client_replace;
656 new_cib->cmds->remove = cib_client_delete;
657 new_cib->cmds->erase = cib_client_erase;
658
659 new_cib->cmds->delete_absolute = cib_client_delete_absolute;
660
661 return new_cib;
662 }
663
664 void
665 cib_free_notify(cib_t *cib)
666 {
667
668 if (cib) {
669 GList *list = cib->notify_list;
670
671 while (list != NULL) {
672 cib_notify_client_t *client = g_list_nth_data(list, 0);
673
674 list = g_list_remove(list, client);
675 free(client);
676 }
677 cib->notify_list = NULL;
678 }
679 }
680
681
682
683
684
685
686 void
687 cib_free_callbacks(cib_t *cib)
688 {
689 cib_free_notify(cib);
690
691 destroy_op_callback_table();
692 }
693
694
695
696
697
698
699 void
700 cib_delete(cib_t *cib)
701 {
702 cib_free_callbacks(cib);
703 if (cib) {
704 cib->cmds->free(cib);
705 }
706 }
707
708 void
709 remove_cib_op_callback(int call_id, gboolean all_callbacks)
710 {
711 if (all_callbacks) {
712 destroy_op_callback_table();
713 cib_op_callback_table = pcmk__intkey_table(cib_destroy_op_callback);
714 } else {
715 pcmk__intkey_table_remove(cib_op_callback_table, call_id);
716 }
717 }
718
719 int
720 num_cib_op_callbacks(void)
721 {
722 if (cib_op_callback_table == NULL) {
723 return 0;
724 }
725 return g_hash_table_size(cib_op_callback_table);
726 }
727
728 static void
729 cib_dump_pending_op(gpointer key, gpointer value, gpointer user_data)
730 {
731 int call = GPOINTER_TO_INT(key);
732 cib_callback_client_t *blob = value;
733
734 crm_debug("Call %d (%s): pending", call, pcmk__s(blob->id, "without ID"));
735 }
736
737 void
738 cib_dump_pending_callbacks(void)
739 {
740 if (cib_op_callback_table == NULL) {
741 return;
742 }
743 return g_hash_table_foreach(cib_op_callback_table, cib_dump_pending_op, NULL);
744 }
745
746 cib_callback_client_t*
747 cib__lookup_id (int call_id)
748 {
749 return pcmk__intkey_table_lookup(cib_op_callback_table, call_id);
750 }