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

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