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