LCOV - code coverage report
Current view: top level - cib - cib_client.c (source / functions) Hit Total Coverage
Test: Pacemaker code coverage Lines: 0 383 0.0 %
Date: 2024-05-07 11:09:47 Functions: 0 45 0.0 %

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

Generated by: LCOV version 1.14