root/lib/cib/cib_client.c

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

DEFINITIONS

This source file includes following definitions.
  1. cib_client_set_op_callback
  2. ciblib_GCompareFunc
  3. cib_client_add_notify_callback
  4. get_notify_list_event_count
  5. cib_client_del_notify_callback
  6. cib_async_timeout_handler
  7. cib_client_register_callback_full
  8. cib_client_register_callback
  9. cib_client_noop
  10. cib_client_ping
  11. cib_client_query
  12. cib_client_query_from
  13. is_primary
  14. set_secondary
  15. set_all_secondary
  16. set_primary
  17. cib_client_bump_epoch
  18. cib_client_upgrade
  19. cib_client_sync
  20. cib_client_sync_from
  21. cib_client_create
  22. cib_client_modify
  23. cib_client_replace
  24. cib_client_delete
  25. cib_client_delete_absolute
  26. cib_client_erase
  27. cib_client_init_transaction
  28. cib_client_end_transaction
  29. cib_client_fetch_schemas
  30. cib_client_set_user
  31. cib_destroy_op_callback
  32. destroy_op_callback_table
  33. get_shadow_file
  34. cib_shadow_new
  35. cib_new_no_shadow
  36. cib_new
  37. cib_new_variant
  38. cib_free_notify
  39. cib_free_callbacks
  40. cib_delete
  41. remove_cib_op_callback
  42. num_cib_op_callbacks
  43. cib_dump_pending_op
  44. cib_dump_pending_callbacks
  45. 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 #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,
     /* [previous][next][first][last][top][bottom][index][help] */
  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)
     /* [previous][next][first][last][top][bottom][index][help] */
  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,
     /* [previous][next][first][last][top][bottom][index][help] */
  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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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,
     /* [previous][next][first][last][top][bottom][index][help] */
 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         /* When there is not the registration of the event, the processing turns off a notice. */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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     // We remove the handler in remove_cib_op_callback()
 186     return G_SOURCE_CONTINUE;
 187 }
 188 
 189 static gboolean
 190 cib_client_register_callback_full(cib_t *cib, int call_id, int timeout,
     /* [previous][next][first][last][top][bottom][index][help] */
 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,
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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,
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 299 {
 300     return -EPROTONOSUPPORT;
 301 }
 302 
 303 static int
 304 set_primary(cib_t *cib, int call_options)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 392 {
 393     int rc = pcmk_rc_ok;
 394 
 395     op_common(cib);
 396 
 397     if (cib->transaction != NULL) {
 398         // A client can have at most one transaction at a time
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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         // Discard always succeeds
 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,
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 467 {
 468     pcmk__str_update(&(cib->user), user);
 469 }
 470 
 471 static void
 472 cib_destroy_op_callback(gpointer data)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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  * \brief Create a new CIB connection object, ignoring any active shadow CIB
 574  *
 575  * Create a new live, file, or remote CIB connection object based on the values
 576  * of CIB-related environment variables (CIB_file, CIB_port, CIB_server,
 577  * CIB_user, and CIB_passwd). The object will not be connected.
 578  *
 579  * \return Newly allocated CIB connection object
 580  * \note The CIB API does not fully support opening multiple CIB connection
 581  *       objects simultaneously, so the returned object should be treated as a
 582  *       singleton.
 583  */
 584 cib_t *
 585 cib_new_no_shadow(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 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  * \brief Create a new CIB connection object
 601  *
 602  * Create a new live, remote, file, or shadow file CIB connection object based
 603  * on the values of CIB-related environment variables (CIB_shadow, CIB_file,
 604  * CIB_port, CIB_server, CIB_user, and CIB_passwd). The object will not be
 605  * connected.
 606  *
 607  * \return Newly allocated CIB connection object
 608  * \note The CIB API does not fully support opening multiple CIB connection
 609  *       objects simultaneously, so the returned object should be treated as a
 610  *       singleton.
 611  */
 612 /* @TODO Ensure all APIs support multiple simultaneous CIB connection objects
 613  * (at least cib_free_callbacks() currently does not).
 614  */
 615 cib_t *
 616 cib_new(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 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         /* We don't ensure port is valid (>= 0) because cib_new() currently
 638          * can't return NULL in practice, and introducing a NULL return here
 639          * could cause core dumps that would previously just cause signon()
 640          * failures.
 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  * \internal
 668  * \brief Create a generic CIB connection instance
 669  *
 670  * \return Newly allocated and initialized cib_t instance
 671  *
 672  * \note This is called by each variant's cib_*_new() function before setting
 673  *       variant-specific values.
 674  */
 675 cib_t *
 676 cib_new_variant(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 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); /* remove all */
 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     /* the rest will get filled in by the variant constructor */
 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     // Deprecated method
 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; // Deprecated method
 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; // Deprecated method
 723 
 724     new_cib->cmds->set_primary = set_primary;
 725     new_cib->cmds->set_master = set_primary; // Deprecated method
 726 
 727     new_cib->cmds->set_secondary = set_secondary;
 728     new_cib->cmds->set_slave = set_secondary; // Deprecated method
 729 
 730     new_cib->cmds->set_slave_all = set_all_secondary; // Deprecated method
 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; // Deprecated method
 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     // Deprecated method
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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  * \brief Free all callbacks for a CIB connection
 774  *
 775  * \param[in,out] cib  CIB connection to clean up
 776  */
 777 void
 778 cib_free_callbacks(cib_t *cib)
     /* [previous][next][first][last][top][bottom][index][help] */
 779 {
 780     cib_free_notify(cib);
 781 
 782     destroy_op_callback_table();
 783 }
 784 
 785 /*!
 786  * \brief Free all memory used by CIB connection
 787  *
 788  * \param[in,out] cib  CIB connection to delete
 789  */
 790 void
 791 cib_delete(cib_t *cib)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 839 {
 840     return pcmk__intkey_table_lookup(cib_op_callback_table, call_id);
 841 }

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