root/lib/cib/cib_client.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. cib_client_noop
  2. cib_client_ping
  3. cib_client_query
  4. cib_client_query_from
  5. cib_client_is_master
  6. cib_client_set_slave
  7. cib_client_set_slave_all
  8. cib_client_set_master
  9. cib_client_bump_epoch
  10. cib_client_upgrade
  11. cib_client_sync
  12. cib_client_sync_from
  13. cib_client_create
  14. cib_client_modify
  15. cib_client_update
  16. cib_client_replace
  17. cib_client_delete
  18. cib_client_delete_absolute
  19. cib_client_erase
  20. cib_destroy_op_callback
  21. destroy_op_callback_table
  22. get_shadow_file
  23. cib_shadow_new
  24. cib_new_no_shadow
  25. cib_new
  26. cib_new_variant
  27. cib_free_notify
  28. cib_free_callbacks
  29. cib_delete
  30. cib_client_set_op_callback
  31. cib_client_add_notify_callback
  32. get_notify_list_event_count
  33. cib_client_del_notify_callback
  34. ciblib_GCompareFunc
  35. cib_async_timeout_handler
  36. cib_client_register_callback
  37. cib_client_register_callback_full
  38. remove_cib_op_callback
  39. num_cib_op_callbacks
  40. cib_dump_pending_op
  41. cib_dump_pending_callbacks
  42. cib__lookup_id

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

/* [previous][next][first][last][top][bottom][index][help] */