root/lib/cib/cib_client.c

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

DEFINITIONS

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

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

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