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_client_init_transaction
- cib_client_end_transaction
- cib_client_fetch_schemas
- cib_client_set_user
- 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/common/xml.h>
26
27 static GHashTable *cib_op_callback_table = NULL;
28
29 #define op_common(cib) do { \
30 if(cib == NULL) { \
31 return -EINVAL; \
32 } else if(cib->delegate_fn == NULL) { \
33 return -EPROTONOSUPPORT; \
34 } \
35 } while(0)
36
37 static int
38 cib_client_set_op_callback(cib_t *cib,
39 void (*callback) (const xmlNode * msg, int call_id,
40 int rc, xmlNode * output))
41 {
42 if (callback == NULL) {
43 crm_info("Un-Setting operation callback");
44
45 } else {
46 crm_trace("Setting operation callback");
47 }
48 cib->op_callback = callback;
49 return pcmk_ok;
50 }
51
52 static gint
53 ciblib_GCompareFunc(gconstpointer a, gconstpointer b)
54 {
55 int rc = 0;
56 const cib_notify_client_t *a_client = a;
57 const cib_notify_client_t *b_client = b;
58
59 CRM_CHECK(a_client->event != NULL && b_client->event != NULL, return 0);
60 rc = strcmp(a_client->event, b_client->event);
61 if (rc == 0) {
62 if (a_client->callback == b_client->callback) {
63 return 0;
64 } else if (((long)a_client->callback) < ((long)b_client->callback)) {
65 crm_trace("callbacks for %s are not equal: %p < %p",
66 a_client->event, a_client->callback, b_client->callback);
67 return -1;
68 }
69 crm_trace("callbacks for %s are not equal: %p > %p",
70 a_client->event, a_client->callback, b_client->callback);
71 return 1;
72 }
73 return rc;
74 }
75
76 static int
77 cib_client_add_notify_callback(cib_t * cib, const char *event,
78 void (*callback) (const char *event,
79 xmlNode * msg))
80 {
81 GList *list_item = NULL;
82 cib_notify_client_t *new_client = NULL;
83
84 if ((cib->variant != cib_native) && (cib->variant != cib_remote)) {
85 return -EPROTONOSUPPORT;
86 }
87
88 crm_trace("Adding callback for %s events (%d)",
89 event, g_list_length(cib->notify_list));
90
91 new_client = pcmk__assert_alloc(1, sizeof(cib_notify_client_t));
92 new_client->event = event;
93 new_client->callback = callback;
94
95 list_item = g_list_find_custom(cib->notify_list, new_client,
96 ciblib_GCompareFunc);
97
98 if (list_item != NULL) {
99 crm_warn("Callback already present");
100 free(new_client);
101 return -EINVAL;
102
103 } else {
104 cib->notify_list = g_list_append(cib->notify_list, new_client);
105
106 cib->cmds->register_notification(cib, event, 1);
107
108 crm_trace("Callback added (%d)", g_list_length(cib->notify_list));
109 }
110 return pcmk_ok;
111 }
112
113 static int
114 get_notify_list_event_count(cib_t *cib, const char *event)
115 {
116 int count = 0;
117
118 for (GList *iter = g_list_first(cib->notify_list); iter != NULL;
119 iter = iter->next) {
120 cib_notify_client_t *client = (cib_notify_client_t *) iter->data;
121
122 if (strcmp(client->event, event) == 0) {
123 count++;
124 }
125 }
126 crm_trace("event(%s) count : %d", event, count);
127 return count;
128 }
129
130 static int
131 cib_client_del_notify_callback(cib_t *cib, const char *event,
132 void (*callback) (const char *event,
133 xmlNode *msg))
134 {
135 GList *list_item = NULL;
136 cib_notify_client_t *new_client = NULL;
137
138 if (cib->variant != cib_native && cib->variant != cib_remote) {
139 return -EPROTONOSUPPORT;
140 }
141
142 if (get_notify_list_event_count(cib, event) == 0) {
143 crm_debug("The callback of the event does not exist(%s)", event);
144 return pcmk_ok;
145 }
146
147 crm_debug("Removing callback for %s events", event);
148
149 new_client = pcmk__assert_alloc(1, sizeof(cib_notify_client_t));
150 new_client->event = event;
151 new_client->callback = callback;
152
153 list_item = g_list_find_custom(cib->notify_list, new_client, ciblib_GCompareFunc);
154
155 if (list_item != NULL) {
156 cib_notify_client_t *list_client = list_item->data;
157
158 cib->notify_list = g_list_remove(cib->notify_list, list_client);
159 free(list_client);
160
161 crm_trace("Removed callback");
162
163 } else {
164 crm_trace("Callback not present");
165 }
166
167 if (get_notify_list_event_count(cib, event) == 0) {
168
169 cib->cmds->register_notification(cib, event, 0);
170 }
171
172 free(new_client);
173 return pcmk_ok;
174 }
175
176 static gboolean
177 cib_async_timeout_handler(gpointer data)
178 {
179 struct timer_rec_s *timer = data;
180
181 crm_debug("Async call %d timed out after %ds",
182 timer->call_id, timer->timeout);
183 cib_native_callback(timer->cib, NULL, timer->call_id, -ETIME);
184
185
186 return G_SOURCE_CONTINUE;
187 }
188
189 static gboolean
190 cib_client_register_callback_full(cib_t *cib, int call_id, int timeout,
191 gboolean only_success, void *user_data,
192 const char *callback_name,
193 void (*callback)(xmlNode *, int, int,
194 xmlNode *, void *),
195 void (*free_func)(void *))
196 {
197 cib_callback_client_t *blob = NULL;
198
199 if (call_id < 0) {
200 if (only_success == FALSE) {
201 callback(NULL, call_id, call_id, NULL, user_data);
202 } else {
203 crm_warn("CIB call failed: %s", pcmk_strerror(call_id));
204 }
205 if (user_data && free_func) {
206 free_func(user_data);
207 }
208 return FALSE;
209 }
210
211 blob = pcmk__assert_alloc(1, sizeof(cib_callback_client_t));
212 blob->id = callback_name;
213 blob->only_success = only_success;
214 blob->user_data = user_data;
215 blob->callback = callback;
216 blob->free_func = free_func;
217
218 if (timeout > 0) {
219 struct timer_rec_s *async_timer =
220 pcmk__assert_alloc(1, sizeof(struct timer_rec_s));
221
222 blob->timer = async_timer;
223
224 async_timer->cib = cib;
225 async_timer->call_id = call_id;
226 async_timer->timeout = timeout * 1000;
227 async_timer->ref = g_timeout_add(async_timer->timeout,
228 cib_async_timeout_handler,
229 async_timer);
230 }
231
232 crm_trace("Adding callback %s for call %d", callback_name, call_id);
233 pcmk__intkey_table_insert(cib_op_callback_table, call_id, blob);
234
235 return TRUE;
236 }
237
238 static gboolean
239 cib_client_register_callback(cib_t *cib, int call_id, int timeout,
240 gboolean only_success, void *user_data,
241 const char *callback_name,
242 void (*callback) (xmlNode *, int, int, xmlNode *,
243 void *))
244 {
245 return cib_client_register_callback_full(cib, call_id, timeout,
246 only_success, user_data,
247 callback_name, callback, NULL);
248 }
249
250 static int
251 cib_client_noop(cib_t * cib, int call_options)
252 {
253 op_common(cib);
254 return cib_internal_op(cib, PCMK__CIB_REQUEST_NOOP, NULL, NULL, NULL, NULL,
255 call_options, cib->user);
256 }
257
258 static int
259 cib_client_ping(cib_t * cib, xmlNode ** output_data, int call_options)
260 {
261 op_common(cib);
262 return cib_internal_op(cib, CRM_OP_PING, NULL, NULL, NULL, output_data,
263 call_options, cib->user);
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, cib->user);
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, cib->user);
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, cib->user);
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, cib->user);
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, cib->user);
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, cib->user);
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, cib->user);
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, cib->user);
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, cib->user);
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, cib->user);
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, cib->user);
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, cib->user);
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, cib->user);
388 }
389
390 static int
391 cib_client_init_transaction(cib_t *cib)
392 {
393 int rc = pcmk_rc_ok;
394
395 op_common(cib);
396
397 if (cib->transaction != NULL) {
398
399 rc = pcmk_rc_already;
400 }
401
402 if (rc == pcmk_rc_ok) {
403 cib->transaction = pcmk__xe_create(NULL, PCMK__XE_CIB_TRANSACTION);
404 }
405
406 if (rc != pcmk_rc_ok) {
407 const char *client_id = NULL;
408
409 cib->cmds->client_id(cib, NULL, &client_id);
410 crm_err("Failed to initialize CIB transaction for client %s: %s",
411 client_id, pcmk_rc_str(rc));
412 }
413 return pcmk_rc2legacy(rc);
414 }
415
416 static int
417 cib_client_end_transaction(cib_t *cib, bool commit, int call_options)
418 {
419 const char *client_id = NULL;
420 int rc = pcmk_ok;
421
422 op_common(cib);
423 cib->cmds->client_id(cib, NULL, &client_id);
424 client_id = pcmk__s(client_id, "(unidentified)");
425
426 if (commit) {
427 if (cib->transaction == NULL) {
428 rc = pcmk_rc_no_transaction;
429
430 crm_err("Failed to commit transaction for CIB client %s: %s",
431 client_id, pcmk_rc_str(rc));
432 return pcmk_rc2legacy(rc);
433 }
434 rc = cib_internal_op(cib, PCMK__CIB_REQUEST_COMMIT_TRANSACT, NULL, NULL,
435 cib->transaction, NULL, call_options, cib->user);
436
437 } else {
438
439 if (cib->transaction != NULL) {
440 crm_trace("Discarded transaction for CIB client %s", client_id);
441 } else {
442 crm_trace("No transaction found for CIB client %s", client_id);
443 }
444 }
445 free_xml(cib->transaction);
446 cib->transaction = NULL;
447 return rc;
448 }
449
450 static int
451 cib_client_fetch_schemas(cib_t *cib, xmlNode **output_data, const char *after_ver,
452 int call_options)
453 {
454 xmlNode *data = pcmk__xe_create(NULL, PCMK__XA_SCHEMA);
455 int rc = pcmk_ok;
456
457 crm_xml_add(data, PCMK_XA_VERSION, after_ver);
458
459 rc = cib_internal_op(cib, PCMK__CIB_REQUEST_SCHEMAS, NULL, NULL, data,
460 output_data, call_options, NULL);
461 free_xml(data);
462 return rc;
463 }
464
465 static void
466 cib_client_set_user(cib_t *cib, const char *user)
467 {
468 pcmk__str_update(&(cib->user), user);
469 }
470
471 static void
472 cib_destroy_op_callback(gpointer data)
473 {
474 cib_callback_client_t *blob = data;
475
476 if (blob->timer && blob->timer->ref > 0) {
477 g_source_remove(blob->timer->ref);
478 }
479 free(blob->timer);
480
481 if (blob->user_data && blob->free_func) {
482 blob->free_func(blob->user_data);
483 }
484
485 free(blob);
486 }
487
488 static void
489 destroy_op_callback_table(void)
490 {
491 if (cib_op_callback_table != NULL) {
492 g_hash_table_destroy(cib_op_callback_table);
493 cib_op_callback_table = NULL;
494 }
495 }
496
497 char *
498 get_shadow_file(const char *suffix)
499 {
500 char *cib_home = NULL;
501 char *fullname = NULL;
502 char *name = crm_strdup_printf("shadow.%s", suffix);
503 const char *dir = getenv("CIB_shadow_dir");
504
505 if (dir == NULL) {
506 uid_t uid = geteuid();
507 struct passwd *pwent = getpwuid(uid);
508 const char *user = NULL;
509
510 if (pwent) {
511 user = pwent->pw_name;
512 } else {
513 user = getenv("USER");
514 crm_perror(LOG_ERR,
515 "Assuming %s because cannot get user details for user ID %d",
516 (user? user : "unprivileged user"), uid);
517 }
518
519 if (pcmk__strcase_any_of(user, "root", CRM_DAEMON_USER, NULL)) {
520 dir = CRM_CONFIG_DIR;
521
522 } else {
523 const char *home = NULL;
524
525 if ((home = getenv("HOME")) == NULL) {
526 if (pwent) {
527 home = pwent->pw_dir;
528 }
529 }
530
531 dir = pcmk__get_tmpdir();
532 if (home && home[0] == '/') {
533 int rc = 0;
534
535 cib_home = crm_strdup_printf("%s/.cib", home);
536
537 rc = mkdir(cib_home, 0700);
538 if (rc < 0 && errno != EEXIST) {
539 crm_perror(LOG_ERR, "Couldn't create user-specific shadow directory: %s",
540 cib_home);
541 errno = 0;
542
543 } else {
544 dir = cib_home;
545 }
546 }
547 }
548 }
549
550 fullname = crm_strdup_printf("%s/%s", dir, name);
551 free(cib_home);
552 free(name);
553
554 return fullname;
555 }
556
557 cib_t *
558 cib_shadow_new(const char *shadow)
559 {
560 cib_t *new_cib = NULL;
561 char *shadow_file = NULL;
562
563 CRM_CHECK(shadow != NULL, return NULL);
564
565 shadow_file = get_shadow_file(shadow);
566 new_cib = cib_file_new(shadow_file);
567 free(shadow_file);
568
569 return new_cib;
570 }
571
572
573
574
575
576
577
578
579
580
581
582
583
584 cib_t *
585 cib_new_no_shadow(void)
586 {
587 const char *shadow = getenv("CIB_shadow");
588 cib_t *cib = NULL;
589
590 unsetenv("CIB_shadow");
591 cib = cib_new();
592
593 if (shadow != NULL) {
594 setenv("CIB_shadow", shadow, 1);
595 }
596 return cib;
597 }
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615 cib_t *
616 cib_new(void)
617 {
618 const char *value = getenv("CIB_shadow");
619 int port;
620
621 if (value && value[0] != 0) {
622 return cib_shadow_new(value);
623 }
624
625 value = getenv("CIB_file");
626 if (value) {
627 return cib_file_new(value);
628 }
629
630 value = getenv("CIB_port");
631 if (value) {
632 gboolean encrypted = TRUE;
633 const char *server = getenv("CIB_server");
634 const char *user = getenv("CIB_user");
635 const char *pass = getenv("CIB_passwd");
636
637
638
639
640
641
642 pcmk__scan_port(value, &port);
643
644 value = getenv("CIB_encrypted");
645 if (value && crm_is_true(value) == FALSE) {
646 crm_info("Disabling TLS");
647 encrypted = FALSE;
648 }
649
650 if (user == NULL) {
651 user = CRM_DAEMON_USER;
652 crm_info("Defaulting to user: %s", user);
653 }
654
655 if (server == NULL) {
656 server = "localhost";
657 crm_info("Defaulting to localhost");
658 }
659
660 return cib_remote_new(server, user, pass, port, encrypted);
661 }
662
663 return cib_native_new();
664 }
665
666
667
668
669
670
671
672
673
674
675 cib_t *
676 cib_new_variant(void)
677 {
678 cib_t *new_cib = NULL;
679
680 new_cib = calloc(1, sizeof(cib_t));
681
682 if (new_cib == NULL) {
683 return NULL;
684 }
685
686 remove_cib_op_callback(0, TRUE);
687
688 new_cib->call_id = 1;
689 new_cib->variant = cib_undefined;
690
691 new_cib->type = cib_no_connection;
692 new_cib->state = cib_disconnected;
693
694 new_cib->op_callback = NULL;
695 new_cib->variant_opaque = NULL;
696 new_cib->notify_list = NULL;
697
698
699 new_cib->cmds = calloc(1, sizeof(cib_api_operations_t));
700
701 if (new_cib->cmds == NULL) {
702 free(new_cib);
703 return NULL;
704 }
705
706
707 new_cib->cmds->set_op_callback = cib_client_set_op_callback;
708
709 new_cib->cmds->add_notify_callback = cib_client_add_notify_callback;
710 new_cib->cmds->del_notify_callback = cib_client_del_notify_callback;
711 new_cib->cmds->register_callback = cib_client_register_callback;
712 new_cib->cmds->register_callback_full = cib_client_register_callback_full;
713
714 new_cib->cmds->noop = cib_client_noop;
715 new_cib->cmds->ping = cib_client_ping;
716 new_cib->cmds->query = cib_client_query;
717 new_cib->cmds->sync = cib_client_sync;
718
719 new_cib->cmds->query_from = cib_client_query_from;
720 new_cib->cmds->sync_from = cib_client_sync_from;
721
722 new_cib->cmds->is_master = is_primary;
723
724 new_cib->cmds->set_primary = set_primary;
725 new_cib->cmds->set_master = set_primary;
726
727 new_cib->cmds->set_secondary = set_secondary;
728 new_cib->cmds->set_slave = set_secondary;
729
730 new_cib->cmds->set_slave_all = set_all_secondary;
731
732 new_cib->cmds->upgrade = cib_client_upgrade;
733 new_cib->cmds->bump_epoch = cib_client_bump_epoch;
734
735 new_cib->cmds->create = cib_client_create;
736 new_cib->cmds->modify = cib_client_modify;
737 new_cib->cmds->update = cib_client_modify;
738 new_cib->cmds->replace = cib_client_replace;
739 new_cib->cmds->remove = cib_client_delete;
740 new_cib->cmds->erase = cib_client_erase;
741
742
743 new_cib->cmds->delete_absolute = cib_client_delete_absolute;
744
745 new_cib->cmds->init_transaction = cib_client_init_transaction;
746 new_cib->cmds->end_transaction = cib_client_end_transaction;
747
748 new_cib->cmds->set_user = cib_client_set_user;
749
750 new_cib->cmds->fetch_schemas = cib_client_fetch_schemas;
751
752 return new_cib;
753 }
754
755 void
756 cib_free_notify(cib_t *cib)
757 {
758
759 if (cib) {
760 GList *list = cib->notify_list;
761
762 while (list != NULL) {
763 cib_notify_client_t *client = g_list_nth_data(list, 0);
764
765 list = g_list_remove(list, client);
766 free(client);
767 }
768 cib->notify_list = NULL;
769 }
770 }
771
772
773
774
775
776
777 void
778 cib_free_callbacks(cib_t *cib)
779 {
780 cib_free_notify(cib);
781
782 destroy_op_callback_table();
783 }
784
785
786
787
788
789
790 void
791 cib_delete(cib_t *cib)
792 {
793 cib_free_callbacks(cib);
794 if (cib) {
795 cib->cmds->free(cib);
796 }
797 }
798
799 void
800 remove_cib_op_callback(int call_id, gboolean all_callbacks)
801 {
802 if (all_callbacks) {
803 destroy_op_callback_table();
804 cib_op_callback_table = pcmk__intkey_table(cib_destroy_op_callback);
805 } else {
806 pcmk__intkey_table_remove(cib_op_callback_table, call_id);
807 }
808 }
809
810 int
811 num_cib_op_callbacks(void)
812 {
813 if (cib_op_callback_table == NULL) {
814 return 0;
815 }
816 return g_hash_table_size(cib_op_callback_table);
817 }
818
819 static void
820 cib_dump_pending_op(gpointer key, gpointer value, gpointer user_data)
821 {
822 int call = GPOINTER_TO_INT(key);
823 cib_callback_client_t *blob = value;
824
825 crm_debug("Call %d (%s): pending", call, pcmk__s(blob->id, "without ID"));
826 }
827
828 void
829 cib_dump_pending_callbacks(void)
830 {
831 if (cib_op_callback_table == NULL) {
832 return;
833 }
834 return g_hash_table_foreach(cib_op_callback_table, cib_dump_pending_op, NULL);
835 }
836
837 cib_callback_client_t*
838 cib__lookup_id (int call_id)
839 {
840 return pcmk__intkey_table_lookup(cib_op_callback_table, call_id);
841 }