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_set_user
  30. cib_destroy_op_callback
  31. destroy_op_callback_table
  32. get_shadow_file
  33. cib_shadow_new
  34. cib_new_no_shadow
  35. cib_new
  36. cib_new_variant
  37. cib_free_notify
  38. cib_free_callbacks
  39. cib_delete
  40. remove_cib_op_callback
  41. num_cib_op_callbacks
  42. cib_dump_pending_op
  43. cib_dump_pending_callbacks
  44. cib__lookup_id

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

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