Line data Source code
1 : /*
2 : * Copyright 2004-2024 the Pacemaker project contributors
3 : *
4 : * The version control history for this file may have further details.
5 : *
6 : * This source code is licensed under the GNU Lesser General Public License
7 : * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
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 0 : cib_client_set_op_callback(cib_t *cib,
39 : void (*callback) (const xmlNode * msg, int call_id,
40 : int rc, xmlNode * output))
41 : {
42 0 : if (callback == NULL) {
43 0 : crm_info("Un-Setting operation callback");
44 :
45 : } else {
46 0 : crm_trace("Setting operation callback");
47 : }
48 0 : cib->op_callback = callback;
49 0 : return pcmk_ok;
50 : }
51 :
52 : static gint
53 0 : ciblib_GCompareFunc(gconstpointer a, gconstpointer b)
54 : {
55 0 : int rc = 0;
56 0 : const cib_notify_client_t *a_client = a;
57 0 : const cib_notify_client_t *b_client = b;
58 :
59 0 : CRM_CHECK(a_client->event != NULL && b_client->event != NULL, return 0);
60 0 : rc = strcmp(a_client->event, b_client->event);
61 0 : if (rc == 0) {
62 0 : if (a_client->callback == b_client->callback) {
63 0 : return 0;
64 0 : } else if (((long)a_client->callback) < ((long)b_client->callback)) {
65 0 : crm_trace("callbacks for %s are not equal: %p < %p",
66 : a_client->event, a_client->callback, b_client->callback);
67 0 : return -1;
68 : }
69 0 : crm_trace("callbacks for %s are not equal: %p > %p",
70 : a_client->event, a_client->callback, b_client->callback);
71 0 : return 1;
72 : }
73 0 : return rc;
74 : }
75 :
76 : static int
77 0 : cib_client_add_notify_callback(cib_t * cib, const char *event,
78 : void (*callback) (const char *event,
79 : xmlNode * msg))
80 : {
81 0 : GList *list_item = NULL;
82 0 : cib_notify_client_t *new_client = NULL;
83 :
84 0 : if ((cib->variant != cib_native) && (cib->variant != cib_remote)) {
85 0 : return -EPROTONOSUPPORT;
86 : }
87 :
88 0 : crm_trace("Adding callback for %s events (%d)",
89 : event, g_list_length(cib->notify_list));
90 :
91 0 : new_client = pcmk__assert_alloc(1, sizeof(cib_notify_client_t));
92 0 : new_client->event = event;
93 0 : new_client->callback = callback;
94 :
95 0 : list_item = g_list_find_custom(cib->notify_list, new_client,
96 : ciblib_GCompareFunc);
97 :
98 0 : if (list_item != NULL) {
99 0 : crm_warn("Callback already present");
100 0 : free(new_client);
101 0 : return -EINVAL;
102 :
103 : } else {
104 0 : cib->notify_list = g_list_append(cib->notify_list, new_client);
105 :
106 0 : cib->cmds->register_notification(cib, event, 1);
107 :
108 0 : crm_trace("Callback added (%d)", g_list_length(cib->notify_list));
109 : }
110 0 : return pcmk_ok;
111 : }
112 :
113 : static int
114 0 : get_notify_list_event_count(cib_t *cib, const char *event)
115 : {
116 0 : int count = 0;
117 :
118 0 : for (GList *iter = g_list_first(cib->notify_list); iter != NULL;
119 0 : iter = iter->next) {
120 0 : cib_notify_client_t *client = (cib_notify_client_t *) iter->data;
121 :
122 0 : if (strcmp(client->event, event) == 0) {
123 0 : count++;
124 : }
125 : }
126 0 : crm_trace("event(%s) count : %d", event, count);
127 0 : return count;
128 : }
129 :
130 : static int
131 0 : cib_client_del_notify_callback(cib_t *cib, const char *event,
132 : void (*callback) (const char *event,
133 : xmlNode *msg))
134 : {
135 0 : GList *list_item = NULL;
136 0 : cib_notify_client_t *new_client = NULL;
137 :
138 0 : if (cib->variant != cib_native && cib->variant != cib_remote) {
139 0 : return -EPROTONOSUPPORT;
140 : }
141 :
142 0 : if (get_notify_list_event_count(cib, event) == 0) {
143 0 : crm_debug("The callback of the event does not exist(%s)", event);
144 0 : return pcmk_ok;
145 : }
146 :
147 0 : crm_debug("Removing callback for %s events", event);
148 :
149 0 : new_client = pcmk__assert_alloc(1, sizeof(cib_notify_client_t));
150 0 : new_client->event = event;
151 0 : new_client->callback = callback;
152 :
153 0 : list_item = g_list_find_custom(cib->notify_list, new_client, ciblib_GCompareFunc);
154 :
155 0 : if (list_item != NULL) {
156 0 : cib_notify_client_t *list_client = list_item->data;
157 :
158 0 : cib->notify_list = g_list_remove(cib->notify_list, list_client);
159 0 : free(list_client);
160 :
161 0 : crm_trace("Removed callback");
162 :
163 : } else {
164 0 : crm_trace("Callback not present");
165 : }
166 :
167 0 : if (get_notify_list_event_count(cib, event) == 0) {
168 : /* When there is not the registration of the event, the processing turns off a notice. */
169 0 : cib->cmds->register_notification(cib, event, 0);
170 : }
171 :
172 0 : free(new_client);
173 0 : return pcmk_ok;
174 : }
175 :
176 : static gboolean
177 0 : cib_async_timeout_handler(gpointer data)
178 : {
179 0 : struct timer_rec_s *timer = data;
180 :
181 0 : crm_debug("Async call %d timed out after %ds",
182 : timer->call_id, timer->timeout);
183 0 : cib_native_callback(timer->cib, NULL, timer->call_id, -ETIME);
184 :
185 : // We remove the handler in remove_cib_op_callback()
186 0 : return G_SOURCE_CONTINUE;
187 : }
188 :
189 : static gboolean
190 0 : 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 0 : cib_callback_client_t *blob = NULL;
198 :
199 0 : if (call_id < 0) {
200 0 : if (only_success == FALSE) {
201 0 : callback(NULL, call_id, call_id, NULL, user_data);
202 : } else {
203 0 : crm_warn("CIB call failed: %s", pcmk_strerror(call_id));
204 : }
205 0 : if (user_data && free_func) {
206 0 : free_func(user_data);
207 : }
208 0 : return FALSE;
209 : }
210 :
211 0 : blob = pcmk__assert_alloc(1, sizeof(cib_callback_client_t));
212 0 : blob->id = callback_name;
213 0 : blob->only_success = only_success;
214 0 : blob->user_data = user_data;
215 0 : blob->callback = callback;
216 0 : blob->free_func = free_func;
217 :
218 0 : if (timeout > 0) {
219 : struct timer_rec_s *async_timer =
220 0 : pcmk__assert_alloc(1, sizeof(struct timer_rec_s));
221 :
222 0 : blob->timer = async_timer;
223 :
224 0 : async_timer->cib = cib;
225 0 : async_timer->call_id = call_id;
226 0 : async_timer->timeout = timeout * 1000;
227 0 : async_timer->ref = g_timeout_add(async_timer->timeout,
228 : cib_async_timeout_handler,
229 : async_timer);
230 : }
231 :
232 0 : crm_trace("Adding callback %s for call %d", callback_name, call_id);
233 0 : pcmk__intkey_table_insert(cib_op_callback_table, call_id, blob);
234 :
235 0 : return TRUE;
236 : }
237 :
238 : static gboolean
239 0 : 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 0 : 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 0 : cib_client_noop(cib_t * cib, int call_options)
252 : {
253 0 : op_common(cib);
254 0 : return cib_internal_op(cib, PCMK__CIB_REQUEST_NOOP, NULL, NULL, NULL, NULL,
255 0 : call_options, cib->user);
256 : }
257 :
258 : static int
259 0 : cib_client_ping(cib_t * cib, xmlNode ** output_data, int call_options)
260 : {
261 0 : op_common(cib);
262 0 : return cib_internal_op(cib, CRM_OP_PING, NULL, NULL, NULL, output_data,
263 0 : call_options, cib->user);
264 : }
265 :
266 : static int
267 0 : cib_client_query(cib_t * cib, const char *section, xmlNode ** output_data, int call_options)
268 : {
269 0 : return cib->cmds->query_from(cib, NULL, section, output_data, call_options);
270 : }
271 :
272 : static int
273 0 : cib_client_query_from(cib_t * cib, const char *host, const char *section,
274 : xmlNode ** output_data, int call_options)
275 : {
276 0 : op_common(cib);
277 0 : return cib_internal_op(cib, PCMK__CIB_REQUEST_QUERY, host, section, NULL,
278 0 : output_data, call_options, cib->user);
279 : }
280 :
281 : static int
282 0 : is_primary(cib_t *cib)
283 : {
284 0 : op_common(cib);
285 0 : return cib_internal_op(cib, PCMK__CIB_REQUEST_IS_PRIMARY, NULL, NULL, NULL,
286 0 : NULL, cib_scope_local|cib_sync_call, cib->user);
287 : }
288 :
289 : static int
290 0 : set_secondary(cib_t *cib, int call_options)
291 : {
292 0 : op_common(cib);
293 0 : return cib_internal_op(cib, PCMK__CIB_REQUEST_SECONDARY, NULL, NULL, NULL,
294 0 : NULL, call_options, cib->user);
295 : }
296 :
297 : static int
298 0 : set_all_secondary(cib_t * cib, int call_options)
299 : {
300 0 : return -EPROTONOSUPPORT;
301 : }
302 :
303 : static int
304 0 : set_primary(cib_t *cib, int call_options)
305 : {
306 0 : op_common(cib);
307 0 : crm_trace("Adding cib_scope_local to options");
308 0 : return cib_internal_op(cib, PCMK__CIB_REQUEST_PRIMARY, NULL, NULL, NULL,
309 0 : NULL, call_options|cib_scope_local, cib->user);
310 : }
311 :
312 : static int
313 0 : cib_client_bump_epoch(cib_t * cib, int call_options)
314 : {
315 0 : op_common(cib);
316 0 : return cib_internal_op(cib, PCMK__CIB_REQUEST_BUMP, NULL, NULL, NULL, NULL,
317 0 : call_options, cib->user);
318 : }
319 :
320 : static int
321 0 : cib_client_upgrade(cib_t * cib, int call_options)
322 : {
323 0 : op_common(cib);
324 0 : return cib_internal_op(cib, PCMK__CIB_REQUEST_UPGRADE, NULL, NULL, NULL,
325 0 : NULL, call_options, cib->user);
326 : }
327 :
328 : static int
329 0 : cib_client_sync(cib_t * cib, const char *section, int call_options)
330 : {
331 0 : return cib->cmds->sync_from(cib, NULL, section, call_options);
332 : }
333 :
334 : static int
335 0 : cib_client_sync_from(cib_t * cib, const char *host, const char *section, int call_options)
336 : {
337 0 : op_common(cib);
338 0 : return cib_internal_op(cib, PCMK__CIB_REQUEST_SYNC_TO_ALL, host, section,
339 0 : NULL, NULL, call_options, cib->user);
340 : }
341 :
342 : static int
343 0 : cib_client_create(cib_t * cib, const char *section, xmlNode * data, int call_options)
344 : {
345 0 : op_common(cib);
346 0 : return cib_internal_op(cib, PCMK__CIB_REQUEST_CREATE, NULL, section, data,
347 0 : NULL, call_options, cib->user);
348 : }
349 :
350 : static int
351 0 : cib_client_modify(cib_t * cib, const char *section, xmlNode * data, int call_options)
352 : {
353 0 : op_common(cib);
354 0 : return cib_internal_op(cib, PCMK__CIB_REQUEST_MODIFY, NULL, section, data,
355 0 : NULL, call_options, cib->user);
356 : }
357 :
358 : static int
359 0 : cib_client_replace(cib_t * cib, const char *section, xmlNode * data, int call_options)
360 : {
361 0 : op_common(cib);
362 0 : return cib_internal_op(cib, PCMK__CIB_REQUEST_REPLACE, NULL, section, data,
363 0 : NULL, call_options, cib->user);
364 : }
365 :
366 : static int
367 0 : cib_client_delete(cib_t * cib, const char *section, xmlNode * data, int call_options)
368 : {
369 0 : op_common(cib);
370 0 : return cib_internal_op(cib, PCMK__CIB_REQUEST_DELETE, NULL, section, data,
371 0 : NULL, call_options, cib->user);
372 : }
373 :
374 : static int
375 0 : cib_client_delete_absolute(cib_t * cib, const char *section, xmlNode * data, int call_options)
376 : {
377 0 : op_common(cib);
378 0 : return cib_internal_op(cib, PCMK__CIB_REQUEST_ABS_DELETE, NULL, section,
379 0 : data, NULL, call_options, cib->user);
380 : }
381 :
382 : static int
383 0 : cib_client_erase(cib_t * cib, xmlNode ** output_data, int call_options)
384 : {
385 0 : op_common(cib);
386 0 : return cib_internal_op(cib, PCMK__CIB_REQUEST_ERASE, NULL, NULL, NULL,
387 0 : output_data, call_options, cib->user);
388 : }
389 :
390 : static int
391 0 : cib_client_init_transaction(cib_t *cib)
392 : {
393 0 : int rc = pcmk_rc_ok;
394 :
395 0 : op_common(cib);
396 :
397 0 : if (cib->transaction != NULL) {
398 : // A client can have at most one transaction at a time
399 0 : rc = pcmk_rc_already;
400 : }
401 :
402 0 : if (rc == pcmk_rc_ok) {
403 0 : cib->transaction = pcmk__xe_create(NULL, PCMK__XE_CIB_TRANSACTION);
404 : }
405 :
406 0 : if (rc != pcmk_rc_ok) {
407 0 : const char *client_id = NULL;
408 :
409 0 : cib->cmds->client_id(cib, NULL, &client_id);
410 0 : crm_err("Failed to initialize CIB transaction for client %s: %s",
411 : client_id, pcmk_rc_str(rc));
412 : }
413 0 : return pcmk_rc2legacy(rc);
414 : }
415 :
416 : static int
417 0 : cib_client_end_transaction(cib_t *cib, bool commit, int call_options)
418 : {
419 0 : const char *client_id = NULL;
420 0 : int rc = pcmk_ok;
421 :
422 0 : op_common(cib);
423 0 : cib->cmds->client_id(cib, NULL, &client_id);
424 0 : client_id = pcmk__s(client_id, "(unidentified)");
425 :
426 0 : if (commit) {
427 0 : if (cib->transaction == NULL) {
428 0 : rc = pcmk_rc_no_transaction;
429 :
430 0 : crm_err("Failed to commit transaction for CIB client %s: %s",
431 : client_id, pcmk_rc_str(rc));
432 0 : return pcmk_rc2legacy(rc);
433 : }
434 0 : rc = cib_internal_op(cib, PCMK__CIB_REQUEST_COMMIT_TRANSACT, NULL, NULL,
435 0 : cib->transaction, NULL, call_options, cib->user);
436 :
437 : } else {
438 : // Discard always succeeds
439 0 : if (cib->transaction != NULL) {
440 0 : crm_trace("Discarded transaction for CIB client %s", client_id);
441 : } else {
442 0 : crm_trace("No transaction found for CIB client %s", client_id);
443 : }
444 : }
445 0 : free_xml(cib->transaction);
446 0 : cib->transaction = NULL;
447 0 : return rc;
448 : }
449 :
450 : static int
451 0 : cib_client_fetch_schemas(cib_t *cib, xmlNode **output_data, const char *after_ver,
452 : int call_options)
453 : {
454 0 : xmlNode *data = pcmk__xe_create(NULL, PCMK__XA_SCHEMA);
455 :
456 0 : crm_xml_add(data, PCMK_XA_VERSION, after_ver);
457 :
458 0 : return cib_internal_op(cib, PCMK__CIB_REQUEST_SCHEMAS, NULL, NULL, data,
459 : output_data, call_options, NULL);
460 :
461 : }
462 :
463 : static void
464 0 : cib_client_set_user(cib_t *cib, const char *user)
465 : {
466 0 : pcmk__str_update(&(cib->user), user);
467 0 : }
468 :
469 : static void
470 0 : cib_destroy_op_callback(gpointer data)
471 : {
472 0 : cib_callback_client_t *blob = data;
473 :
474 0 : if (blob->timer && blob->timer->ref > 0) {
475 0 : g_source_remove(blob->timer->ref);
476 : }
477 0 : free(blob->timer);
478 :
479 0 : if (blob->user_data && blob->free_func) {
480 0 : blob->free_func(blob->user_data);
481 : }
482 :
483 0 : free(blob);
484 0 : }
485 :
486 : static void
487 0 : destroy_op_callback_table(void)
488 : {
489 0 : if (cib_op_callback_table != NULL) {
490 0 : g_hash_table_destroy(cib_op_callback_table);
491 0 : cib_op_callback_table = NULL;
492 : }
493 0 : }
494 :
495 : char *
496 0 : get_shadow_file(const char *suffix)
497 : {
498 0 : char *cib_home = NULL;
499 0 : char *fullname = NULL;
500 0 : char *name = crm_strdup_printf("shadow.%s", suffix);
501 0 : const char *dir = getenv("CIB_shadow_dir");
502 :
503 0 : if (dir == NULL) {
504 0 : uid_t uid = geteuid();
505 0 : struct passwd *pwent = getpwuid(uid);
506 0 : const char *user = NULL;
507 :
508 0 : if (pwent) {
509 0 : user = pwent->pw_name;
510 : } else {
511 0 : user = getenv("USER");
512 0 : crm_perror(LOG_ERR,
513 : "Assuming %s because cannot get user details for user ID %d",
514 : (user? user : "unprivileged user"), uid);
515 : }
516 :
517 0 : if (pcmk__strcase_any_of(user, "root", CRM_DAEMON_USER, NULL)) {
518 0 : dir = CRM_CONFIG_DIR;
519 :
520 : } else {
521 0 : const char *home = NULL;
522 :
523 0 : if ((home = getenv("HOME")) == NULL) {
524 0 : if (pwent) {
525 0 : home = pwent->pw_dir;
526 : }
527 : }
528 :
529 0 : dir = pcmk__get_tmpdir();
530 0 : if (home && home[0] == '/') {
531 0 : int rc = 0;
532 :
533 0 : cib_home = crm_strdup_printf("%s/.cib", home);
534 :
535 0 : rc = mkdir(cib_home, 0700);
536 0 : if (rc < 0 && errno != EEXIST) {
537 0 : crm_perror(LOG_ERR, "Couldn't create user-specific shadow directory: %s",
538 : cib_home);
539 0 : errno = 0;
540 :
541 : } else {
542 0 : dir = cib_home;
543 : }
544 : }
545 : }
546 : }
547 :
548 0 : fullname = crm_strdup_printf("%s/%s", dir, name);
549 0 : free(cib_home);
550 0 : free(name);
551 :
552 0 : return fullname;
553 : }
554 :
555 : cib_t *
556 0 : cib_shadow_new(const char *shadow)
557 : {
558 0 : cib_t *new_cib = NULL;
559 0 : char *shadow_file = NULL;
560 :
561 0 : CRM_CHECK(shadow != NULL, return NULL);
562 :
563 0 : shadow_file = get_shadow_file(shadow);
564 0 : new_cib = cib_file_new(shadow_file);
565 0 : free(shadow_file);
566 :
567 0 : return new_cib;
568 : }
569 :
570 : /*!
571 : * \brief Create a new CIB connection object, ignoring any active shadow CIB
572 : *
573 : * Create a new live, file, or remote CIB connection object based on the values
574 : * of CIB-related environment variables (CIB_file, CIB_port, CIB_server,
575 : * CIB_user, and CIB_passwd). The object will not be connected.
576 : *
577 : * \return Newly allocated CIB connection object
578 : * \note The CIB API does not fully support opening multiple CIB connection
579 : * objects simultaneously, so the returned object should be treated as a
580 : * singleton.
581 : */
582 : cib_t *
583 0 : cib_new_no_shadow(void)
584 : {
585 0 : const char *shadow = getenv("CIB_shadow");
586 0 : cib_t *cib = NULL;
587 :
588 0 : unsetenv("CIB_shadow");
589 0 : cib = cib_new();
590 :
591 0 : if (shadow != NULL) {
592 0 : setenv("CIB_shadow", shadow, 1);
593 : }
594 0 : return cib;
595 : }
596 :
597 : /*!
598 : * \brief Create a new CIB connection object
599 : *
600 : * Create a new live, remote, file, or shadow file CIB connection object based
601 : * on the values of CIB-related environment variables (CIB_shadow, CIB_file,
602 : * CIB_port, CIB_server, CIB_user, and CIB_passwd). The object will not be
603 : * connected.
604 : *
605 : * \return Newly allocated CIB connection object
606 : * \note The CIB API does not fully support opening multiple CIB connection
607 : * objects simultaneously, so the returned object should be treated as a
608 : * singleton.
609 : */
610 : /* @TODO Ensure all APIs support multiple simultaneous CIB connection objects
611 : * (at least cib_free_callbacks() currently does not).
612 : */
613 : cib_t *
614 0 : cib_new(void)
615 : {
616 0 : const char *value = getenv("CIB_shadow");
617 : int port;
618 :
619 0 : if (value && value[0] != 0) {
620 0 : return cib_shadow_new(value);
621 : }
622 :
623 0 : value = getenv("CIB_file");
624 0 : if (value) {
625 0 : return cib_file_new(value);
626 : }
627 :
628 0 : value = getenv("CIB_port");
629 0 : if (value) {
630 0 : gboolean encrypted = TRUE;
631 0 : const char *server = getenv("CIB_server");
632 0 : const char *user = getenv("CIB_user");
633 0 : const char *pass = getenv("CIB_passwd");
634 :
635 : /* We don't ensure port is valid (>= 0) because cib_new() currently
636 : * can't return NULL in practice, and introducing a NULL return here
637 : * could cause core dumps that would previously just cause signon()
638 : * failures.
639 : */
640 0 : pcmk__scan_port(value, &port);
641 :
642 0 : value = getenv("CIB_encrypted");
643 0 : if (value && crm_is_true(value) == FALSE) {
644 0 : crm_info("Disabling TLS");
645 0 : encrypted = FALSE;
646 : }
647 :
648 0 : if (user == NULL) {
649 0 : user = CRM_DAEMON_USER;
650 0 : crm_info("Defaulting to user: %s", user);
651 : }
652 :
653 0 : if (server == NULL) {
654 0 : server = "localhost";
655 0 : crm_info("Defaulting to localhost");
656 : }
657 :
658 0 : return cib_remote_new(server, user, pass, port, encrypted);
659 : }
660 :
661 0 : return cib_native_new();
662 : }
663 :
664 : /*!
665 : * \internal
666 : * \brief Create a generic CIB connection instance
667 : *
668 : * \return Newly allocated and initialized cib_t instance
669 : *
670 : * \note This is called by each variant's cib_*_new() function before setting
671 : * variant-specific values.
672 : */
673 : cib_t *
674 0 : cib_new_variant(void)
675 : {
676 0 : cib_t *new_cib = NULL;
677 :
678 0 : new_cib = calloc(1, sizeof(cib_t));
679 :
680 0 : if (new_cib == NULL) {
681 0 : return NULL;
682 : }
683 :
684 0 : remove_cib_op_callback(0, TRUE); /* remove all */
685 :
686 0 : new_cib->call_id = 1;
687 0 : new_cib->variant = cib_undefined;
688 :
689 0 : new_cib->type = cib_no_connection;
690 0 : new_cib->state = cib_disconnected;
691 :
692 0 : new_cib->op_callback = NULL;
693 0 : new_cib->variant_opaque = NULL;
694 0 : new_cib->notify_list = NULL;
695 :
696 : /* the rest will get filled in by the variant constructor */
697 0 : new_cib->cmds = calloc(1, sizeof(cib_api_operations_t));
698 :
699 0 : if (new_cib->cmds == NULL) {
700 0 : free(new_cib);
701 0 : return NULL;
702 : }
703 :
704 : // Deprecated method
705 0 : new_cib->cmds->set_op_callback = cib_client_set_op_callback;
706 :
707 0 : new_cib->cmds->add_notify_callback = cib_client_add_notify_callback;
708 0 : new_cib->cmds->del_notify_callback = cib_client_del_notify_callback;
709 0 : new_cib->cmds->register_callback = cib_client_register_callback;
710 0 : new_cib->cmds->register_callback_full = cib_client_register_callback_full;
711 :
712 0 : new_cib->cmds->noop = cib_client_noop; // Deprecated method
713 0 : new_cib->cmds->ping = cib_client_ping;
714 0 : new_cib->cmds->query = cib_client_query;
715 0 : new_cib->cmds->sync = cib_client_sync;
716 :
717 0 : new_cib->cmds->query_from = cib_client_query_from;
718 0 : new_cib->cmds->sync_from = cib_client_sync_from;
719 :
720 0 : new_cib->cmds->is_master = is_primary; // Deprecated method
721 :
722 0 : new_cib->cmds->set_primary = set_primary;
723 0 : new_cib->cmds->set_master = set_primary; // Deprecated method
724 :
725 0 : new_cib->cmds->set_secondary = set_secondary;
726 0 : new_cib->cmds->set_slave = set_secondary; // Deprecated method
727 :
728 0 : new_cib->cmds->set_slave_all = set_all_secondary; // Deprecated method
729 :
730 0 : new_cib->cmds->upgrade = cib_client_upgrade;
731 0 : new_cib->cmds->bump_epoch = cib_client_bump_epoch;
732 :
733 0 : new_cib->cmds->create = cib_client_create;
734 0 : new_cib->cmds->modify = cib_client_modify;
735 0 : new_cib->cmds->update = cib_client_modify; // Deprecated method
736 0 : new_cib->cmds->replace = cib_client_replace;
737 0 : new_cib->cmds->remove = cib_client_delete;
738 0 : new_cib->cmds->erase = cib_client_erase;
739 :
740 : // Deprecated method
741 0 : new_cib->cmds->delete_absolute = cib_client_delete_absolute;
742 :
743 0 : new_cib->cmds->init_transaction = cib_client_init_transaction;
744 0 : new_cib->cmds->end_transaction = cib_client_end_transaction;
745 :
746 0 : new_cib->cmds->set_user = cib_client_set_user;
747 :
748 0 : new_cib->cmds->fetch_schemas = cib_client_fetch_schemas;
749 :
750 0 : return new_cib;
751 : }
752 :
753 : void
754 0 : cib_free_notify(cib_t *cib)
755 : {
756 :
757 0 : if (cib) {
758 0 : GList *list = cib->notify_list;
759 :
760 0 : while (list != NULL) {
761 0 : cib_notify_client_t *client = g_list_nth_data(list, 0);
762 :
763 0 : list = g_list_remove(list, client);
764 0 : free(client);
765 : }
766 0 : cib->notify_list = NULL;
767 : }
768 0 : }
769 :
770 : /*!
771 : * \brief Free all callbacks for a CIB connection
772 : *
773 : * \param[in,out] cib CIB connection to clean up
774 : */
775 : void
776 0 : cib_free_callbacks(cib_t *cib)
777 : {
778 0 : cib_free_notify(cib);
779 :
780 0 : destroy_op_callback_table();
781 0 : }
782 :
783 : /*!
784 : * \brief Free all memory used by CIB connection
785 : *
786 : * \param[in,out] cib CIB connection to delete
787 : */
788 : void
789 0 : cib_delete(cib_t *cib)
790 : {
791 0 : cib_free_callbacks(cib);
792 0 : if (cib) {
793 0 : cib->cmds->free(cib);
794 : }
795 0 : }
796 :
797 : void
798 0 : remove_cib_op_callback(int call_id, gboolean all_callbacks)
799 : {
800 0 : if (all_callbacks) {
801 0 : destroy_op_callback_table();
802 0 : cib_op_callback_table = pcmk__intkey_table(cib_destroy_op_callback);
803 : } else {
804 0 : pcmk__intkey_table_remove(cib_op_callback_table, call_id);
805 : }
806 0 : }
807 :
808 : int
809 0 : num_cib_op_callbacks(void)
810 : {
811 0 : if (cib_op_callback_table == NULL) {
812 0 : return 0;
813 : }
814 0 : return g_hash_table_size(cib_op_callback_table);
815 : }
816 :
817 : static void
818 0 : cib_dump_pending_op(gpointer key, gpointer value, gpointer user_data)
819 : {
820 0 : int call = GPOINTER_TO_INT(key);
821 0 : cib_callback_client_t *blob = value;
822 :
823 0 : crm_debug("Call %d (%s): pending", call, pcmk__s(blob->id, "without ID"));
824 0 : }
825 :
826 : void
827 0 : cib_dump_pending_callbacks(void)
828 : {
829 0 : if (cib_op_callback_table == NULL) {
830 0 : return;
831 : }
832 0 : return g_hash_table_foreach(cib_op_callback_table, cib_dump_pending_op, NULL);
833 : }
834 :
835 : cib_callback_client_t*
836 0 : cib__lookup_id (int call_id)
837 : {
838 0 : return pcmk__intkey_table_lookup(cib_op_callback_table, call_id);
839 : }
|