/** * @file common.h * @author Michal Vasko * @brief common routines header * * @copyright * Copyright 2018 Deutsche Telekom AG. * Copyright 2018 - 2021 CESNET, z.s.p.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef _COMMON_H #define _COMMON_H #define _GNU_SOURCE #define _POSIX_C_SOURCE 200809L #include #include #include #include #include #include #include #include "compat.h" #include "sysrepo.h" /* * If the compiler supports attribute to mark objects as hidden, mark all * objects as hidden and export only objects explicitly marked to be part of * the public API. */ #define API __attribute__((visibility("default"))) /** support for pthread_mutex_timedlock */ #cmakedefine SR_HAVE_PTHREAD_MUTEX_TIMEDLOCK #ifndef SR_HAVE_PTHREAD_MUTEX_TIMEDLOCK int pthread_mutex_timedlock(pthread_mutex_t *mutex, const struct timespec *abstime); #endif /** use access() if eaccess() is not available (it may adversely affect access control, however) */ #cmakedefine SR_HAVE_EACCESS #ifndef SR_HAVE_EACCESS # define eaccess access #endif /** atomic variables */ #cmakedefine SR_HAVE_STDATOMIC #ifdef SR_HAVE_STDATOMIC # include # define ATOMIC_T atomic_uint_fast32_t # define ATOMIC_T_MAX UINT_FAST32_MAX # define ATOMIC_STORE_RELAXED(var, x) atomic_store_explicit(&(var), x, memory_order_relaxed) # define ATOMIC_LOAD_RELAXED(var) atomic_load_explicit(&(var), memory_order_relaxed) # define ATOMIC_INC_RELAXED(var) atomic_fetch_add_explicit(&(var), 1, memory_order_relaxed) # define ATOMIC_ADD_RELAXED(var, x) atomic_fetch_add_explicit(&(var), x, memory_order_relaxed) # define ATOMIC_DEC_RELAXED(var) atomic_fetch_sub_explicit(&(var), 1, memory_order_relaxed) # define ATOMIC_SUB_RELAXED(var, x) atomic_fetch_sub_explicit(&(var), x, memory_order_relaxed) #else # define ATOMIC_T uint32_t # define ATOMIC_T_MAX UINT32_MAX # define ATOMIC_STORE_RELAXED(var, x) ((var) = (x)) # define ATOMIC_LOAD_RELAXED(var) (var) # define ATOMIC_INC_RELAXED(var) __sync_fetch_and_add(&(var), 1) # define ATOMIC_ADD_RELAXED(var, x) __sync_fetch_and_add(&(var), x) # define ATOMIC_DEC_RELAXED(var) __sync_fetch_and_sub(&(var), 1) # define ATOMIC_SUB_RELAXED(var, x) __sync_fetch_and_sub(&(var), x) #endif /** macro for mutex align check */ #define SR_MUTEX_ALIGN_CHECK(mutex) ((uintptr_t)mutex % sizeof(void *)) /** macro for cond align check */ #define SR_COND_ALIGN_CHECK(cond) ((uintptr_t)cond % sizeof(void *)) /** macro for checking datastore type */ #define SR_IS_CONVENTIONAL_DS(ds) ((ds == SR_DS_STARTUP) || (ds == SR_DS_RUNNING) || (ds == SR_DS_CANDIDATE)) /** macro for all datastore types count */ #define SR_DS_COUNT 4 /** macro for checking session type */ #define SR_IS_EVENT_SESS(session) (session->ev != SR_SUB_EV_NONE) /** macro for getting a SHM module on a specific index */ #define SR_SHM_MOD_IDX(main_shm_addr, idx) ((sr_mod_t *)(((char *)main_shm_addr) + sizeof(sr_main_shm_t) + idx * sizeof(sr_mod_t))) /* macro for getting aligned SHM size */ #define SR_SHM_SIZE(size) ((size) + ((~(size) + 1) & (SR_SHM_MEM_ALIGN - 1))) /* macro for getting main SHM from a connection */ #define SR_CONN_MAIN_SHM(conn) ((sr_main_shm_t *)(conn)->main_shm.addr) /* macro for getting ext SHM from a connection */ #define SR_CONN_EXT_SHM(conn) ((sr_ext_shm_t *)(conn)->ext_shm.addr) /** name of sysrepo YANG module */ #define SR_YANG_MOD "sysrepo" /** UID of the superuser that can execute sensitive functions */ #define SR_SU_UID @SYSREPO_SUPERUSER_UID@ /** implemented ietf-yang-library revision */ #define SR_YANGLIB_REVISION @YANGLIB_REVISION@ /** main sysrepo repository path; prefix of all other paths by default */ #define SR_REPO_PATH "@REPO_PATH@" /** environment variable overriding the compiled-in value */ #define SR_REPO_PATH_ENV "SYSREPO_REPOSITORY_PATH" /** if not set, defaults to "SR_REPO_PATH/data" */ #define SR_STARTUP_PATH "@STARTUP_DATA_PATH@" /** if not set, defaults to "SR_REPO_PATH/data/notif" */ #define SR_NOTIFICATION_PATH "@NOTIFICATION_PATH@" /** if not set, defaults to "SR_REPO_PATH/yang" */ #define SR_YANG_PATH "@YANG_MODULE_PATH@" /** where SHM files are stored */ #define SR_SHM_DIR "/dev/shm" /** default prefix for SHM files in /dev/shm */ #define SR_SHM_PREFIX_DEFAULT "sr" /** suffix of backed-up LYB files */ #define SR_FILE_BACKUP_SUFFIX ".bck" /** environment variable for setting a custom prefix for SHM files */ #define SR_SHM_PREFIX_ENV "SYSREPO_SHM_PREFIX" /** maximum number of possible system-wide concurrent owners of a read lock */ #define SR_RWLOCK_READ_LIMIT 10 /** all ext SHM item sizes will be aligned to this number; also represents the allocation unit (B) */ #define SR_SHM_MEM_ALIGN 8 /** notification file will never exceed this size (kB) */ #define SR_EV_NOTIF_FILE_MAX_SIZE 1024 /** timeout for locking subscription structure lock, should be enough for a single ::sr_process_events() call (ms) */ #define SR_SUBSCR_LOCK_TIMEOUT 30000 /** timeout for locking lydmods data for access; should be enough for parsing, applying any scheduled changes, and printing (ms) */ #define SR_LYDMODS_LOCK_TIMEOUT 5000 /** timeout for locking notification buffer lock, used when adding/removing notifications (ms) */ #define SR_NOTIF_BUF_LOCK_TIMEOUT 100 /** timeout for locking subscription SHM; maximum time an event handling should take (ms) */ #define SR_SUBSHM_LOCK_TIMEOUT 10000 /** timeout for locking ext SHM lock; time that truncating and writing into SHM may take (ms) */ #define SR_EXT_LOCK_TIMEOUT 100 /** timeout for locking the local connection list; maximum time the list can be accessed (ms) */ #define SR_CONN_LIST_LOCK_TIMEOUT 100 /** timeout for locking connection remap lock; maximum time it can be continuously read/written to it (ms) */ #define SR_CONN_REMAP_LOCK_TIMEOUT 10000 /** timeout for locking (data of) a module; maximum time a module write lock is expected to be held (ms) */ #define SR_MOD_LOCK_TIMEOUT 5000 /** timeout for locking SHM module/RPC subscriptions; maxmum time full event processing may take (ms) */ #define SR_SHMEXT_SUB_LOCK_TIMEOUT 15000 /** timeout for locking module cache (ms) */ #define SR_MOD_CACHE_LOCK_TIMEOUT 10000 /** default timeout for change subscription callback (ms) */ #define SR_CHANGE_CB_TIMEOUT 60000 /** default timeout for operational subscription callback (ms) */ #define SR_OPER_CB_TIMEOUT 60000 /** default timeout for RPC/action subscription callback (ms) */ #define SR_RPC_CB_TIMEOUT 60000 /** group to own all directories/files */ #define SR_GROUP "@SYSREPO_GROUP@" /** umask modifying all the permissions below */ #define SR_UMASK @SYSREPO_UMASK@ /** permissions of main SHM lock file and main SHM itself */ #define SR_MAIN_SHM_PERM 00666 /** permissions of connection lock files */ #define SR_CONN_LOCKFILE_PERM 00666 /** permissions of all subscription SHMs */ #define SR_SUB_SHM_PERM 00666 /** permissions of all event pipes (only owner read, anyone else write */ #define SR_EVPIPE_PERM 00622 /** permissions of directories for sysrepo files */ #define SR_DIR_PERM 00777 /** permissions of used YANG modules */ #define SR_YANG_PERM 00644 /** permissions of stored notifications and data files */ #define SR_FILE_PERM 00600 /** permissions of data files of internal modules */ #define SR_INT_FILE_PERM 00664 /** permission of data files of sysrepo-monitoring internal module */ #define SR_MON_INT_FILE_PERM 00600 /** initial length of message buffer (B) */ #define SR_MSG_LEN_START 128 /** default operational origin for operational data (push/pull) */ #define SR_OPER_ORIGIN "unknown" /** default operational origin for enabled running data */ #define SR_CONFIG_ORIGIN "intended" /* * Internal declarations + definitions */ extern char sysrepo_yang[]; typedef struct sr_mod_s sr_mod_t; typedef struct sr_dep_s sr_dep_t; /** static initializer of the shared memory structure */ #define SR_SHM_INITIALIZER {.fd = -1, .size = 0, .addr = NULL} /** initializer of mod_info structure */ #define SR_MODINFO_INIT(mi, c, d, d2) mi.ds = (d); mi.ds2 = (d2); mi.diff = NULL; mi.data = NULL; \ mi.data_cached = 0; mi.conn = (c); mi.mods = NULL; mi.mod_count = 0 /** * @brief Generic shared memory information structure. */ typedef struct sr_shm_s { int fd; /**< Shared memory file desriptor. */ size_t size; /**< Shared memory mapping current size. */ char *addr; /**< Shared memory mapping address. */ } sr_shm_t; /** * @brief Session information structure. */ typedef struct sr_sid_s { uint32_t sr; /**< Sysrepo session ID. */ uint32_t nc; /**< NETCONF session ID. */ char *user; /**< Sysrepo user. */ } sr_sid_t; /** * @brief Connection ID. */ typedef uint32_t sr_cid_t; /** * @brief Lock mode. */ typedef enum sr_lock_mode_e { SR_LOCK_NONE = 0, /**< Not locked. */ SR_LOCK_READ, /**< Read lock. */ SR_LOCK_READ_UPGR, /**< Read lock with the upgrade capability. */ SR_LOCK_WRITE /**< Write lock. */ } sr_lock_mode_t; /** * @brief Sysrepo read-write lock. */ typedef struct sr_rwlock_s { pthread_mutex_t mutex; /**< Lock mutex. */ pthread_cond_t cond; /**< Lock condition variable. */ pthread_mutex_t r_mutex; /**< Mutex for accessing readers, needed because of concurrent reading. */ sr_cid_t readers[SR_RWLOCK_READ_LIMIT]; /**< CIDs of all READ lock owners (including READ-UPGR), 0s otherwise. */ sr_cid_t upgr; /**< CID of the READ-UPGR lock owner if locked, 0 otherwise. */ sr_cid_t writer; /**< CID of the WRITE lock owner if locked, 0 otherwise. */ } sr_rwlock_t; struct modsub_changesub_s; struct modsub_change_s; struct modsub_opersub_s; struct modsub_oper_s; struct opsub_rpcsub_s; struct opsub_rpc_s; struct modsub_notif_s; #include "edit_diff.h" #include "log.h" #include "modinfo.h" #include "shm.h" #include "lyd_mods.h" #include "replay.h" /* * Private definitions of public declarations */ /** * @brief Sysrepo connection. */ struct sr_conn_ctx_s { struct ly_ctx *ly_ctx; /**< Libyang context, also available to user. */ sr_conn_options_t opts; /**< Connection options. */ sr_diff_check_cb diff_check_cb; /**< Connection user diff check callback. */ pthread_mutex_t ptr_lock; /**< Session-shared lock for accessing pointers to sessions. */ sr_session_ctx_t **sessions; /**< Array of sessions for this connection. */ uint32_t session_count; /**< Session count. */ sr_cid_t cid; /**< Globally unique connection ID */ int main_create_lock; /**< Process-shared file lock for creating main/ext SHM. */ sr_rwlock_t ext_remap_lock; /**< Session-shared lock only for remapping ext SHM. */ sr_shm_t main_shm; /**< Main SHM structure. */ sr_shm_t ext_shm; /**< External SHM structure (all stored offsets point here). */ struct sr_mod_cache_s { sr_rwlock_t lock; /**< Session-shared lock for accessing the module cache. */ struct lyd_node *data; /**< Data of all cached modules, */ struct { const struct lys_module *ly_mod; /**< Libyang module in the cache. */ uint32_t ver; /**< Version of the module data in the cache, 0 is not valid */ } *mods; /**< Array of cached modules. */ uint32_t mod_count; /**< Cached modules count. */ } mod_cache; /**< Module running data cache. */ }; /** * @brief Sysrepo session. */ struct sr_session_ctx_s { sr_conn_ctx_t *conn; /**< Connection used for creating this session. */ sr_datastore_t ds; /**< Datastore of the session. */ sr_sub_event_t ev; /**< Event of a callback session. ::SR_SUB_EV_NONE for standard user sessions. */ sr_sid_t sid; /**< Session information. */ sr_sid_t ev_sid; /**< Event (originator) session information. Valid only if ev is not ::SR_SUB_EV_NONE. */ sr_error_info_t *err_info; /**< Session error information. */ pthread_mutex_t ptr_lock; /**< Lock for accessing pointers to subscriptions. */ sr_subscription_ctx_t **subscriptions; /**< Array of subscriptions of this session. */ uint32_t subscription_count; /**< Subscription count. */ struct { struct lyd_node *edit; /**< Prepared edit data tree. */ struct lyd_node *diff; /**< Diff data tree, used for module change iterator. */ } dt[SR_DS_COUNT]; /**< Session-exclusive prepared changes. */ struct sr_sess_notif_buf { ATOMIC_T thread_running; /**< Flag whether the notification buffering thread of this session is running. */ pthread_t tid; /**< Thread ID of the thread. */ sr_rwlock_t lock; /**< Lock for accessing thread_running and the notification buffer (READ-lock is not used). */ struct sr_sess_notif_buf_node { char *notif_lyb; /**< Buffered notification to be stored in LYB format. */ time_t notif_ts; /**< Buffered notification timestamp. */ const struct lys_module *notif_mod; /**< Buffered notification modules. */ struct sr_sess_notif_buf_node *next; /**< Next stored notification buffer node. */ } *first; /**< First stored notification buffer node. */ struct sr_sess_notif_buf_node *last; /**< Last stored notification buffer node. */ } notif_buf; /**< Notification buffering attributes. */ }; /** * @brief Sysrepo subscription. */ struct sr_subscription_ctx_s { sr_conn_ctx_t *conn; /**< Connection of the subscription. */ uint32_t evpipe_num; /**< Event pipe number of this subscription structure. */ int evpipe; /**< Event pipe opened for reading. */ ATOMIC_T thread_running; /**< Flag whether the thread handling this subscription is running. */ pthread_t tid; /**< Thread ID of the handler thread. */ sr_rwlock_t subs_lock; /**< Session-shared lock for accessing the subscriptions. */ struct modsub_change_s { char *module_name; /**< Module of the subscriptions. */ sr_datastore_t ds; /**< Datastore of the subscriptions. */ struct modsub_changesub_s { char *xpath; /**< Subscription XPath. */ uint32_t priority; /**< Subscription priority. */ sr_subscr_options_t opts; /**< Subscription options. */ sr_module_change_cb cb; /**< Subscription callback. */ void *private_data; /**< Subscription callback private data. */ sr_session_ctx_t *sess; /**< Subscription session. */ uint32_t request_id; /**< Request ID of the last processed request. */ sr_sub_event_t event; /**< Type of the last processed event. */ } *subs; /**< Configuration change subscriptions for each XPath. */ uint32_t sub_count; /**< Configuration change module XPath subscription count. */ sr_shm_t sub_shm; /**< Subscription SHM. */ } *change_subs; /**< Change subscriptions for each module. */ uint32_t change_sub_count; /**< Change module subscription count. */ struct modsub_oper_s { char *module_name; /**< Module of the subscriptions. */ struct modsub_opersub_s { char *xpath; /**< Subscription XPath. */ sr_oper_get_items_cb cb; /**< Subscription callback. */ void *private_data; /**< Subscription callback private data. */ sr_session_ctx_t *sess; /**< Subscription session. */ uint32_t request_id; /**< Request ID of the last processed request. */ sr_shm_t sub_shm; /**< Subscription SHM. */ } *subs; /**< Operational subscriptions for each XPath. */ uint32_t sub_count; /**< Operational module XPath subscription count. */ } *oper_subs; /**< Operational subscriptions for each module. */ uint32_t oper_sub_count; /**< Operational module subscription count. */ struct modsub_notif_s { char *module_name; /**< Module of the subscriptions. */ struct modsub_notifsub_s { uint32_t sub_id; /**< Unique (notification) subscription ID. */ char *xpath; /**< Subscription XPath. */ time_t start_time; /**< Subscription start time. */ int replayed; /**< Flag whether the subscription replay is finished. */ time_t stop_time; /**< Subscription stop time. */ sr_event_notif_cb cb; /**< Subscription value callback. */ sr_event_notif_tree_cb tree_cb; /**< Subscription tree callback. */ void *private_data; /**< Subscription callback private data. */ sr_session_ctx_t *sess; /**< Subscription session. */ } *subs; /**< Notification subscriptions for each XPath. */ uint32_t sub_count; /**< Notification module XPath subscription count. */ uint32_t request_id; /**< Request ID of the last processed request. */ sr_shm_t sub_shm; /**< Subscription SHM. */ } *notif_subs; /**< Notification subscriptions for each module. */ uint32_t notif_sub_count; /**< Notification module subscription count. */ struct opsub_rpc_s { char *path; /**< Subscription RPC/action path. */ struct opsub_rpcsub_s { char *xpath; /**< Subscription XPath. */ uint32_t priority; /**< Subscription priority. */ sr_rpc_cb cb; /**< Subscription value callback. */ sr_rpc_tree_cb tree_cb; /**< Subscription tree callback. */ void *private_data; /**< Subscription callback private data. */ sr_session_ctx_t *sess; /**< Subscription session. */ uint32_t request_id; /**< Request ID of the last processed request. */ sr_sub_event_t event; /**< Type of the last processed event. */ } *subs; /**< RPC/action subscription for each XPath. */ uint32_t sub_count; /**< RPC/action XPath subscription count. */ sr_shm_t sub_shm; /**< Subscription SHM. */ } *rpc_subs; /**< RPC/action subscriptions for each operation. */ uint32_t rpc_sub_count; /**< RPC/action operation subscription count. */ }; /** * @brief Change iterator. */ struct sr_change_iter_s { struct lyd_node *diff; /**< Optional copied diff that set items point into. */ struct ly_set *set; /**< Set of all the selected diff nodes. */ uint32_t idx; /**< Index of the next change. */ }; /* * From sysrepo.c */ /** * @brief Start a new session. * * @param[in] conn Connection of the session. * @param[in] datastore Datastore of the session. * @param[in] event Optional event the session is handling, SR_SUB_EV_NONE for a standard session. * @param[in] ev_sid Event originator SID. * @param[in] ev_ncid Event originator NCID. * @param[in] ev_user Event originator user. * @param[out] session Created session. * @return err_info, NULL on success. */ sr_error_info_t *_sr_session_start(sr_conn_ctx_t *conn, const sr_datastore_t datastore, sr_sub_event_t event, uint32_t ev_sid, uint32_t ev_ncid, const char *ev_user, sr_session_ctx_t **session); /* * Subscription functions */ /** * @brief Add a change subscription into a subscription structure. * * @param[in] sess Subscription session. * @param[in] mod_name Subscription module name. * @param[in] xpath Subscription XPath. * @param[in] change_cb Subscription callback. * @param[in] private_data Subscription callback private data. * @param[in] priority Subscription priority. * @param[in] sub_opts Subscription options. * @param[in] has_subs_lock What kind of SUBS lock is held. * @param[in,out] subs Subscription structure. * @return err_info, NULL on success. */ sr_error_info_t *sr_sub_change_add(sr_session_ctx_t *sess, const char *mod_name, const char *xpath, sr_module_change_cb change_cb, void *private_data, uint32_t priority, sr_subscr_options_t sub_opts, sr_lock_mode_t has_subs_lock, sr_subscription_ctx_t *subs); /** * @brief Delete a change subscription from a subscription structure. * * @param[in] mod_name Subscription module name. * @param[in] xpath Subscription XPath. * @param[in] ds Subscription datastore. * @param[in] change_cb Subscription callback. * @param[in] private_data Subscription callback private data. * @param[in] priority Subscription priority. * @param[in] sub_opts Subscription options. * @param[in] has_subs_lock What kind of SUBS lock is held. * @param[in,out] subs Subscription structure. */ void sr_sub_change_del(const char *mod_name, const char *xpath, sr_datastore_t ds, sr_module_change_cb change_cb, void *private_data, uint32_t priority, sr_subscr_options_t sub_opts, sr_lock_mode_t has_subs_lock, sr_subscription_ctx_t *subs); /** * @brief Add an operational subscription into a subscription structure. * * @param[in] sess Subscription session. * @param[in] mod_name Subscription module name. * @param[in] xpath Subscription XPath. * @param[in] oper_cb Subscription callback. * @param[in] private_data Subscription callback private data. * @param[in] has_subs_lock What kind of SUBS lock is held. * @param[in,out] subs Subscription structure. * @return err_info, NULL on success. */ sr_error_info_t *sr_sub_oper_add(sr_session_ctx_t *sess, const char *mod_name, const char *xpath, sr_oper_get_items_cb oper_cb, void *private_data, sr_lock_mode_t has_subs_lock, sr_subscription_ctx_t *subs); /** * @brief Delete an operational subscription from a subscription structure. * * @param[in] mod_name Subscription module name. * @param[in] xpath Subscription XPath. * @param[in] has_subs_lock What kind of SUBS lock is held. * @param[in,out] subs Subscription structure. */ void sr_sub_oper_del(const char *mod_name, const char *xpath, sr_lock_mode_t has_subs_lock, sr_subscription_ctx_t *subs); /** * @brief Add a notification subscription into a subscription structure. * * @param[in] sess Subscription session. * @param[in] mod_name Subscription module name. * @param[in] sub_id Unique notif sub ID. * @param[in] xpath Subscription XPath. * @param[in] start_time Subscription start time. * @param[in] stop_time Subscription stop time. * @param[in] notif_cb Subscription value callback. * @param[in] notif_tree_cb Subscription tree callback. * @param[in] private_data Subscription callback private data. * @param[in] has_subs_lock What kind of SUBS lock is held. * @param[in,out] subs Subscription structure. * @return err_info, NULL on success. */ sr_error_info_t *sr_sub_notif_add(sr_session_ctx_t *sess, const char *mod_name, uint32_t sub_id, const char *xpath, time_t start_time, time_t stop_time, sr_event_notif_cb notif_cb, sr_event_notif_tree_cb notif_tree_cb, void *private_data, sr_lock_mode_t has_subs_lock, sr_subscription_ctx_t *subs); /** * @brief Delete a notification subscription from a subscription structure. * * @param[in] mod_name Subscription module name. * @param[in] sub_id Unique notif sub ID. * @param[in] has_subs_lock What kind of SUBS lock is held. * @param[in,out] subs Subscription structure. */ void sr_sub_notif_del(const char *mod_name, uint32_t sub_id, sr_lock_mode_t has_subs_lock, sr_subscription_ctx_t *subs); /** * @brief Add an RPC subscription into a subscription structure. * * @param[in] sess Subscription session. * @param[in] path Subscription RPC path. * @param[in] xpath Subscription XPath. * @param[in] rpc_cb Subscription value callback. * @param[in] rpc_tree_cb Subscription tree callback. * @param[in] private_data Subscription callback private data. * @param[in] priority Subscription priority. * @param[in] has_subs_lock What kind of SUBS lock is held. * @param[in,out] subs Subscription structure. * @return err_info, NULL on success. */ sr_error_info_t *sr_sub_rpc_add(sr_session_ctx_t *sess, const char *path, const char *xpath, sr_rpc_cb rpc_cb, sr_rpc_tree_cb rpc_tree_cb, void *private_data, uint32_t priority, sr_lock_mode_t has_subs_lock, sr_subscription_ctx_t *subs); /** * @brief Delete an RPC subscription from a subscription structure. * * @param[in] path Subscription RPC path. * @param[in] xpath Subscription XPath. * @param[in] rpc_cb Subscription value callback. * @param[in] rpc_tree_cb Subscription tree callback. * @param[in] private_data Subscription callback private data. * @param[in] priority Subscription priority. * @param[in] has_subs_lock What kind of SUBS lock is held. * @param[in,out] subs Subscription structure. */ void sr_sub_rpc_del(const char *path, const char *xpath, sr_rpc_cb rpc_cb, sr_rpc_tree_cb rpc_tree_cb, void *private_data, uint32_t priority, sr_lock_mode_t has_subs_lock, sr_subscription_ctx_t *subs); /** * @brief Count subscriptions of session \p sess in subscriptions structure \p subs. * * @param[in] sess Subscription session. * @param[in] has_subs_lock What kind of SUBS lock is held. * @param[in] subs Session subscription. * @return Number of session subscriptions. */ int sr_subs_session_count(sr_session_ctx_t *sess, sr_lock_mode_t has_subs_lock, sr_subscription_ctx_t *subs); /** * @brief Delete all subscriptions in \p subs of session \p sess. * Main SHM read-upgr lock must be held and will be temporarily upgraded! * * @param[in] sess Subscription session. * @param[in] has_subs_lock What kind of SUBS lock is held. * @param[in] subs Session subscription. * @return err_info, NULL on success. */ sr_error_info_t *sr_subs_session_del(sr_session_ctx_t *sess, sr_lock_mode_t has_subs_lock, sr_subscription_ctx_t *subs); /** * @brief Delete all subscriptions in \p subs of all the sessions. * Main SHM read-upgr lock must be held and will be temporarily upgraded! * * @param[in,out] subs Subscription structure. * @return err_info, NULL on success. */ sr_error_info_t *sr_subs_del_all(sr_subscription_ctx_t *subs); /** * @brief Find notifications subscribers for a module. * * @param[in] conn Connection to use. * @param[in] mod_name Module name. * @param[out] notif_subs Notification subscriptions. * @param[out] notif_sub_count Number of subscribers. * @return err_info, NULL on success. */ sr_error_info_t *sr_notif_find_subscriber(sr_conn_ctx_t *conn, const char *mod_name, sr_mod_notif_sub_t **notif_subs, uint32_t *notif_sub_count); /** * @brief Call notification callback for a notification. * * @param[in] ev_sess Event session to provide for the callback. * @param[in] cb Value callback. * @param[in] tree_cb Tree callback. * @param[in] private_data Callback private data. * @param[in] notif_type Notification type. * @param[in] notif_op Notification node of the notification (relevant for nested notifications). * @param[in] notif_ts Timestamp of when the notification was generated. * @return err_info, NULL on success. */ sr_error_info_t *sr_notif_call_callback(sr_session_ctx_t *ev_sess, sr_event_notif_cb cb, sr_event_notif_tree_cb tree_cb, void *private_data, const sr_ev_notif_type_t notif_type, const struct lyd_node *notif_op, time_t notif_ts); /* * Utility functions */ /** * @brief Add a generic pointer to a ptr array. * * @param[in] ptr_lock Pointers lock. * @param[in,out] ptrs Pointer array to enlarge. * @param[in,out] ptr_count Pointer array count. * @param[in] add_ptr Pointer to add. * @return err_info, NULL on success. */ sr_error_info_t *sr_ptr_add(pthread_mutex_t *ptr_lock, void ***ptrs, uint32_t *ptr_count, void *add_ptr); /** * @brief Delete a generic pointer from a ptr array. * * @param[in,out] ptrs Pointer array to delete from. * @param[in,out] ptr_count Pointer array count. * @param[in] del_ptr Pointer to delete. * @return err_info, NULL on success. */ sr_error_info_t *sr_ptr_del(pthread_mutex_t *ptr_lock, void ***ptrs, uint32_t *ptr_count, void *del_ptr); /** * @brief Wrapper for libyang ly_ctx_new(). * * @param[out] ly_ctx libyang context. * @return err_info, NULL on success. */ sr_error_info_t *sr_ly_ctx_new(struct ly_ctx **ly_ctx); /** * @brief Remove module YANG file. * * @param[in] name Module name. * @param[in] revision Module revision, NULL if none. * @return err_info, NULL on success. */ sr_error_info_t *sr_remove_module_file(const char *name, const char *revision); /** * @brief Create (print) YANG module file and all of its submodules. * * @param[in] ly_mod Module to print. * @return err_info, NULL on success. */ sr_error_info_t *sr_store_module_files(const struct lys_module *ly_mod); /** * @brief Unlink startup, running, and candidate files of a module. * * @param[in] mod_name Module name. * @return err_info, NULL on success. */ sr_error_info_t *sr_remove_data_files(const char *mod_name); /** * @brief Check whether a module is internal libyang or sysrepo module. * * @param[in] ly_mod Module to check. * @return 0 if not, non-zero if it is. */ int sr_module_is_internal(const struct lys_module *ly_mod); /** * @brief Create startup file for a module. * * @param[in] ly_mod Module to create startup file for. * @return err_info, NULL on success. */ sr_error_info_t *sr_create_startup_file(const struct lys_module *ly_mod); /** * @brief Create all module import and include files, recursively. * * @param[in] ly_mod libyang module whose imports and includes to create. * @return err_info, NULL on success. */ sr_error_info_t *sr_create_module_imps_incs_r(const struct lys_module *ly_mod); /** * @brief Get the path the main SHM. * * @param[out] path Created path. Should be freed by the caller. * @return err_info, NULL on success. */ sr_error_info_t *sr_path_main_shm(char **path); /** * @brief Get the path the external SHM. * * @param[out] path Created path. Should be freed by the caller. * @return err_info, NULL on success. */ sr_error_info_t *sr_path_ext_shm(char **path); /** * @brief Get the path to a subscription SHM. * * @param[in] mod_name Module name. * @param[in] suffix1 First suffix. * @param[in] suffix2 Second suffix, none if equals -1. * @param[out] path Created path. * @return err_info, NULL on success. */ sr_error_info_t *sr_path_sub_shm(const char *mod_name, const char *suffix1, int64_t suffix2, char **path); /** * @brief Get the path to a subscription data SHM. * * @param[in] mod_name Module name. * @param[in] suffix1 First suffix. * @param[in] suffix2 Second suffix, none if equals -1. * @param[out] path Created path. * @return err_info, NULL on success. */ sr_error_info_t *sr_path_sub_data_shm(const char *mod_name, const char *suffix1, int64_t suffix2, char **path); /** * @brief Get the path to a volatile datastore SHM. * * @param[in] mod_name Module name. * @param[in] ds Target datastore. * @param[out] path Created path. * @return err_info, NULL on success. */ sr_error_info_t *sr_path_ds_shm(const char *mod_name, sr_datastore_t ds, char **path); /** * @brief Get the path to an event pipe. * * @param[in] evpipe_num Event pipe number. * @param[out] path Created path. * @return err_info, NULL on success. */ sr_error_info_t *sr_path_evpipe(uint32_t evpipe_num, char **path); /** * @brief Get the path to startup files directory. * * @param[out] path Created path. * @return err_info, NULL on success. */ sr_error_info_t *sr_path_startup_dir(char **path); /** * @brief Get the path to notification files directory. * * @param[out] path Created path. * @return err_info, NULL on success. */ sr_error_info_t *sr_path_notif_dir(char **path); /** * @brief Get the path to YANG module files directory. * * @param[out] path Created path. * @return err_info, NULL on success. */ sr_error_info_t *sr_path_yang_dir(char **path); /** * @brief Get the path to a module startup file. * * @param[in] mod_name Module name. * @param[out] path Created path. * @return err_info, NULL on success. */ sr_error_info_t *sr_path_startup_file(const char *mod_name, char **path); /** * @brief Get the path to a module notification file. * * @param[in] mod_name Module name. * @param[in] from_ts Timestamp of the first stored notification. * @param[in] to_ts Timestamp of the last stored notification. * @param[out] path Created path. * @return err_info, NULL on success. */ sr_error_info_t *sr_path_notif_file(const char *mod_name, time_t from_ts, time_t to_ts, char **path); /** * @brief Get the path to a YANG module file. * * @param[in] mod_name Module name. * @param[in] mod_rev Module revision. * @param[out] path Created path. * @return err_info, NULL on success. */ sr_error_info_t *sr_path_yang_file(const char *mod_name, const char *mod_rev, char **path); /** * @brief Populate the lockfile path for a given Connection ID. * When called with cid of 0 the path will be set to the lock file directory * path. The path parameter is set to newly allocated memory. Caller is * responsible for freeing memory. * * @param[in] cid Connection ID for which the lockfile path is constructed. * @param[out] path Lockfile directory if cid is 0, path of lockfile otherwise. * @return err_info, NULL on success. */ sr_error_info_t *sr_path_conn_lockfile(sr_cid_t cid, char **path); /** * @brief Remove any leftover event pipes after crashed subscriptions. * There should be none unless there was a subscription structure without subscriptions that crashed. */ void sr_remove_evpipes(void); /** * @brief Get the UID of a user or vice versa. * * @param[in,out] uid UID. * @param[in,out] user User name. * @return err_info, NULL on success. */ sr_error_info_t *sr_get_pwd(uid_t *uid, char **user); /** * @brief Change mode (permissions) and/or owner and group of a file. * * @param[in] path File path. * @param[in] owner New owner if not NULL. * @param[in] group New group if not NULL. * @param[in] perm New permissions if not 0. * @return err_info, NULL on success. */ sr_error_info_t *sr_chmodown(const char *path, const char *owner, const char *group, mode_t perm); /** * @brief Check whether the effective user has permissions for a module. * * @param[in] mod_name Module to check. * @param[in] wr Check write access if set, otherwise read. * @param[in,out] has_access If set, it will contain the result of the access check. * If not set, denied access returns an error. * @return err_info, NULL on success. */ sr_error_info_t *sr_perm_check(const char *mod_name, int wr, int *has_access); /** * @brief Get mode (permissions) and/or owner and group of a module. * * @param[in] mod_name Module name. * @param[in] ds Datastore file to check, for general module access permissions, startup should always be used. * @param[in,out] owner Module owner if not NULL. * @param[in,out] group Module group if not NULL. * @param[in,out] perm Module permissions if not NULL; * @return err_info, NULL on success. */ sr_error_info_t *sr_perm_get(const char *mod_name, sr_datastore_t ds, char **owner, char **group, mode_t *perm); /** * @brief Check whether a file exists. * * @param[in] path Path to the file. * @return 0 if file does not exist, non-zero if it exists. */ int sr_file_exists(const char *path); /** * @brief Get current time with an offset. * * @param[out] ts Current time offset by \p add_ms. * @param[in] add_ms Number os milliseconds added. */ void sr_time_get(struct timespec *ts, uint32_t add_ms); /** * @brief Remap and possibly resize a SHM. Needs WRITE lock for resizing, * otherwise READ lock is fine. * * @param[in] shm SHM structure to remap. * @param[in] new_shm_size Resize SHM to this size, if 0 read the size of the SHM file. * @return err_info, NULL on success. */ sr_error_info_t *sr_shm_remap(sr_shm_t *shm, size_t new_shm_size); /** * @brief Clear a SHM structure. * * @param[in] shm SHM structure to clear. */ void sr_shm_clear(sr_shm_t *shm); /** * @brief Get the next ext SHM memory hole. * * @param[in] last Last returned hole, NULL on first call. * @param[in] ext_shm Ext SHM. * @return Next ext SHM memor hole, NULL if the last was returned. */ sr_ext_hole_t *sr_ext_hole_next(sr_ext_hole_t *last, sr_ext_shm_t *ext_shm); /** * @brief Find an existing hole. * * @param[in] ext_shm Ext SHM. * @param[in] off Optional offset of the hole. * @param[in] min_size Minimum matching hole size. * @return First suitable hole, NULL if none found. */ sr_ext_hole_t *sr_ext_hole_find(sr_ext_shm_t *ext_shm, uint32_t off, uint32_t min_size); /** * @brief Delete an existing hole. * * @param[in] ext_shm Ext SHM. * @param[in] hole Hole to delete. */ void sr_ext_hole_del(sr_ext_shm_t *ext_shm, sr_ext_hole_t *hole); /** * @brief Add a new hole. * * @param[in] ext_shm Ext SHM. * @param[in] off Offset of the new hole. * @param[in] size Size of the new hole. * @return First suitable hole, NULL if none found. */ void sr_ext_hole_add(sr_ext_shm_t *ext_shm, uint32_t off, uint32_t size); /** * @brief Copy memory into SHM. * * @param[in] shm_addr Mapped SHM address. * @param[in] src Source memory. * @param[in] size Size of source memory. * @param[in,out] shm_end Current SHM end pointer, it is updated. * @return Offset of the copied memory in SHM. */ off_t sr_shmcpy(char *shm_addr, const void *src, size_t size, char **shm_end); /** * @brief Copy string into SHM. * * @param[in] shm_addr Mapped SHM address. * @param[in] str Source string. * @param[in,out] shm_end Current SHM end pointer, it is updated. * @return Offset of the copied memory in SHM. */ off_t sr_shmstrcpy(char *shm_addr, const char *str, char **shm_end); /** * @brief Get required memory in ext SHM for a string. * * @param[in] str String to be examined. * @return Number of required bytes. */ size_t sr_strshmlen(const char *str); /** * @brief Realloc for an array in ext SHM adding one new item. The array offset and item count is properly * updated in the ext SHM. * * May remap ext SHM! * * @param[in] shm_ext Ext SHM structure. * @param[in,out] shm_array_off Pointer to array offset in SHM, is updated. * @param[in,out] shm_count Pointer to array count in SHM, is updated. * @param[in] in_ext_shm Whether @p shm_array_off and @p shm_count themselves are stored in ext SHM or not (in main SHM). * In case they are in ext SHM, they should not be used directly after this function as they may have been remapped! * @param[in] item_size Array item size. * @param[in] add_idx Index of the new item, -1 for adding at the end. * @param[out] new_item Pointer to the new item. * @param[in] dyn_attr_size Optional dynamic attribute size to allocate as well. * @param[out] dyn_attr_off Optional allocated dynamic attribute offset. * @return err_info, NULL on success. */ sr_error_info_t *sr_shmrealloc_add(sr_shm_t *shm_ext, off_t *shm_array_off, uint32_t *shm_count_off, int in_ext_shm, size_t item_size, int64_t add_idx, void **new_item, size_t dyn_attr_size, off_t *dyn_attr_off); /** * @brief Realloc for an array in SHM deleting one item. * * @param[in] shm_ext Ext SHM structure. * @param[in,out] shm_array_off Pointer to array in SHM, set to 0 if last item was removed. * @param[in,out] shm_count Pointer to array count in SHM, will be updated. * @param[in] item_size Array item size. * @param[in] del_idx Item index to delete. * @param[in] dyn_attr_size Aligned size of dynamic attributes of the deleted item, if any. * @param[in] dyn_attr_off Offset of the dynamic attribute, if any. */ void sr_shmrealloc_del(sr_shm_t *shm_ext, off_t *shm_array_off, uint32_t *shm_count, size_t item_size, uint32_t del_idx, size_t dyn_attr_size, off_t dyn_attr_off); /** * @brief Wrapper for pthread_mutex_init(). * * @param[in,out] lock pthread mutex to initialize. * @param[in] shared Whether the mutex will be shared between processes or not. * @return err_info, NULL on success. */ sr_error_info_t *sr_mutex_init(pthread_mutex_t *lock, int shared); /** * @brief Callback called for each recovered owner of a lock. * * @param[in] mode Dead owner lock mode. * @param[in] cid Dead owner connection ID. * @param[in] data Arbitrary user data. */ typedef void (*sr_lock_recover_cb)(sr_lock_mode_t mode, sr_cid_t cid, void *data); /** * @brief Lock a mutex. * * @param[in] lock Mutex to lock. * @param[in] timeout_ms Timeout in ms for locking. * @param[in] finc Name of the calling function for logging. * @param[in] cb Optional callback called when recovering locks. When calling it, the lock is always held. * Callback @p mode is set to ::SR_LOCK_WRITE and @p cid to 0. * @param[in] cb_data Arbitrary user data for @p cb. * @return err_info, NULL on success. */ sr_error_info_t *sr_mlock(pthread_mutex_t *lock, int timeout_ms, const char *func, sr_lock_recover_cb cb, void *cb_data); /** * @brief Unlock a mutex. * * @param[in] lock Mutex to unlock. */ void sr_munlock(pthread_mutex_t *lock); /** * @brief Initialize a sysrepo RW lock. * * @param[in,out] rwlock RW lock to initialize. * @param[in] shared Whether the RW lock will be shared between processes or not. * @return err_info, NULL on success. */ sr_error_info_t *sr_rwlock_init(sr_rwlock_t *rwlock, int shared); /** * @brief Destroy a sysrepo RW lock. * * @param[in] rwlock RW lock to destroy. */ void sr_rwlock_destroy(sr_rwlock_t *rwlock); /** * @brief Lock a sysrepo RW lock. On failure, the lock is not changed in any way. * * @param[in] rwlock RW lock to lock. * @param[in] timeout_ms Timeout in ms for locking. * @param[in] mode Lock mode to set. * @param[in] cid Lock owner connection ID. * @param[in] func Name of the calling function for logging. * @param[in] cb Optional callback called when recovering locks. When calling it, WRITE lock is always held. * @param[in] cb_data Arbitrary user data for @p cb. * @return err_info, NULL on success. */ sr_error_info_t *sr_rwlock(sr_rwlock_t *rwlock, int timeout_ms, sr_lock_mode_t mode, sr_cid_t cid, const char *func, sr_lock_recover_cb cb, void *cb_data); /** * @brief Relock a sysrepo RW lock (upgrade or downgrade). On failure, the lock is not changed in any way. * * If @p mode is ::SR_LOCK_WRITE, the @p rwlock must be locked with ::SR_LOCK_READ_UPGR. * If @p mode is ::SR_LOCK_READ or ::SR_LOCK_READ_UPGR, the @p rwlock must be locked with ::SR_LOCK_WRITE. * * @param[in] rwlock RW lock to lock. * @param[in] timeout_ms Timeout in ms for locking. Only needed for lock upgrade (if @p mode is ::SR_LOCK_WRITE). * @param[in] mode Lock mode to set. * @param[in] cid Lock owner connection ID. * @param[in] func Name of the calling function for logging. * @param[in] cb Optional callback called when recovering locks. When calling it, WRITE lock is always held. * @param[in] cb_data Arbitrary user data for @p cb. * @return err_info, NULL on success. */ sr_error_info_t *sr_rwrelock(sr_rwlock_t *rwlock, int timeout_ms, sr_lock_mode_t mode, sr_cid_t cid, const char *func, sr_lock_recover_cb cb, void *cb_data); /** * @brief Unlock a sysrepo RW lock. On failure, whatever steps are possible are still performed. * * @param[in] rwlock RW lock to unlock. * @param[in] timeout_ms Timeout in ms for locking. Only needed for read or read-upgr unlock. * @param[in] mode Lock mode that was successfully set for the lock. * @param[in] cid Lock owner connection ID. * @param[in] func Name of the calling function for logging. */ void sr_rwunlock(sr_rwlock_t *rwlock, int timeout_ms, sr_lock_mode_t mode, sr_cid_t cid, const char *func); /** * @brief Check whether a connection is alive. * * @param[in] cid Connection CID. * @return 0 if it is dead, non-zero if it alive. */ int sr_conn_is_alive(sr_cid_t cid); /** * @brief Wrapper to realloc() that frees memory on failure. * * @param[in] ptr Pointer to the current memory. * @param[in] size New size of the memory. * @return Resized memory, NULL on error. */ void *sr_realloc(void *ptr, size_t size); /** * @brief Copy file contents to another file. * * @param[in] to Destination file path. * @param[in] from Source file path. * @param[in] file_mode Permissions of \p to file, if being created. * @return err_info, NULL on success. */ sr_error_info_t *sr_cp_path(const char *to, const char *from, mode_t file_mode); /** * @brief Wrapper for open(2). * * Additionally sets umask. * * @param[in] pathname Path of the file to open. * @param[in] flags Flags to use. * @param[in] mode Permissions for the file in case it is created. * @return Opened file descriptor. * @return -1 on error, errno set. */ int sr_open(const char *pathname, int flags, mode_t mode); /** * @brief Create all directories in the path, wrapper for mkdir(2). * * Additionally sets umask. * * @param[in] path Full path, is temporarily modified. * @param[in] mode Mode (permissions) of the directories. * @return err_info, NULL on success. */ sr_error_info_t *sr_mkpath(char *path, mode_t mode); /** * @brief Get first namespace (module name) from an XPath expression. * * @param[in] expr Expression to inspect. * @return First module name, NULL on error. */ char *sr_get_first_ns(const char *expr); /** * @brief Get XPath expression without any predicates. * * @param[in] expr Expression to transform. * @param[out] expr2 Expression without predicates. * @return err_info, NULL on success. */ sr_error_info_t *sr_get_trim_predicates(const char *expr, char **expr2); /** * @brief Get datastore string name. * * @param[in] ds Datastore to transform. * @return Datastore string name. */ const char *sr_ds2str(sr_datastore_t ds); /** * @brief Get datastore identity name from ietf-datastores. * * @param[in] ds Datastore to transform. * @return Datastore identity name. */ const char *sr_ds2ident(sr_datastore_t ds); /** * @brief Sleep for specified milliseconds. * * @param[in] msec Number of ms to sleep for. * @return err_info, NULL on success. */ sr_error_info_t *sr_msleep(uint32_t msec); /** * @brief Print a message into a newly allocated buffer. * * @param[in,out] str Buffer for the message. * @param[in,out] str_len Current buffer length. * @param[in] offset Print into buffer with an offset. * @param[in] format Format of the message. * @param[in] ap Format argument list. * @return Number of printed characters, -1 on error. */ int sr_vsprintf(char **str, int *str_len, int offset, const char *format, va_list ap); /** * @brief Print a message into a newly allocated buffer. * * @param[in,out] str Buffer for the message. * @param[in,out] str_len Current buffer length. * @param[in] offset Print into buffer with an offset. * @param[in] format Format of the message. * @param[in] ... Format arguments. * @return Number of printed characters, -1 on error. */ int sr_sprintf(char **str, int *str_len, int offset, const char *format, ...); /** * @brief Get a file descriptor size. * * @param[in] fd File descriptor to inspect. * @param[out] size Size of \p fd. * @return err_info, NULL on success. */ sr_error_info_t *sr_file_get_size(int fd, size_t *size); /** * @brief Get string value of a libyang leaf(-list). * * @param[in] leaf Node to inspect. * @return String value of the node. */ const char *sr_ly_leaf_value_str(const struct lyd_node *leaf); /** * @brief Get event string name. * * @param[in] ev Event to transform. * @return Event string name. */ const char *sr_ev2str(sr_sub_event_t ev); /** * @brief Transform internal event type into a public API event type. * * @param[in] ev Internal event. * @return Public API event. */ sr_event_t sr_ev2api(sr_sub_event_t ev); /** * @brief Transform a libyang node into sysrepo value. * * @param[in] node libyang node to transform. * @param[out] sr_val sysrepo value. * @return err_info, NULL on success. */ sr_error_info_t *sr_val_ly2sr(const struct lyd_node *node, sr_val_t *sr_val); /** * @brief Transform a sysrepo value into libyang string value. * * @param[in] ctx libyang context. * @param[in] sr_val sysrepo value to transform. * @param[in] xpath XPath of the sysrepo value. * @param[in] buf Function buffer, must be of size at least 22 bytes. * @param[in] output Whether to look for output nodes instead of input. * @return String value. */ char *sr_val_sr2ly_str(struct ly_ctx *ctx, const sr_val_t *sr_val, const char *xpath, char *buf, int output); /** * @brief Transform a sysrepo value into libyang node. * * @param[in] ctx libyang context. * @param[in] xpath XPath of the sysrepo value. * @param[in] val_str String value of the sysrepo value. * @param[in] dflt Dflt flag if the sysrepo value. * @param[in] output Whether the sysrepo value is from an output. * @param[in,out] root Transformed sysrepo value, appended if set. * @return err_info, NULL on success. */ sr_error_info_t *sr_val_sr2ly(struct ly_ctx *ctx, const char *xpath, const char *val_str, int dflt, int output, struct lyd_node **root); /** * @brief Split this sibling with following siblings and its preceding siblings. * Works only for top-level nodes! * * @param[in] sibling Specific sibling where to split the siblings. */ void sr_ly_split(struct lyd_node *sibling); /** * @brief Link together split siblings. Works only for top-level nodes! * * @param[in] first First sibling of the preceding siblings. * @param[in] sibling First sibling of the following siblings. */ void sr_ly_link(struct lyd_node *first, struct lyd_node *sibling); /** * @brief Duplicate nodes to the specified depth. * * @param[in] src_parent Source parent. * @param[in] depth Depth to duplicate. * @param[in,out] trg_parent Target parent to add children to. * @return err_info, NULL on success. */ sr_error_info_t *sr_lyd_dup(const struct lyd_node *src_parent, uint32_t depth, struct lyd_node *trg_parent); /** * @brief Get pointer to data node children. * * @param[in] node Node to get children of. * @param[in] skip_keys Whether to return first non-key child in case of lists. * @return Node children, NULL if has none. */ struct lyd_node *sr_lyd_child(const struct lyd_node *node, int skip_keys); /** * @brief Create any missing config/state NP containers in the siblings, recursively. * * @param[in,out] first First sibling to add NP containers into, set if @p parent is NULL. * Only @p ly_mod data are considered. * @param[in] parent Parent of any added NP containers, set if @p first is NULL. * @param[in] ly_mod Module to consider, set if @p parent is NULL. * @param[in,out] diff Optional diff to append any performed changes to. * @return err_info, NULL on success. */ sr_error_info_t *sr_lyd_create_sibling_np_cont_r(struct lyd_node **first, struct lyd_node *parent, const struct lys_module *ly_mod, struct lyd_node **diff); /** * @brief Duplicate only config NP containers of a module from a data tree. Also optionally create state NP containers. * * @param[in] data Data tree to duplicate from. * @param[in] ly_mod Module whose data to duplicate. * @param[in] add_state_np_conts Whether to also add state NP containers. * @param[in,out] new_data Data with appended duplicated nodes. * @return err_info, NULL on success. */ sr_error_info_t *sr_lyd_dup_module_np_cont(const struct lyd_node *data, const struct lys_module *ly_mod, int add_state_np_conts, struct lyd_node **new_data); /** * @brief Duplicate all data of a module from a data tree. Also properly handles config NP containers * and optionally even state NP containers. * * @param[in] data Data tree to duplicate from. * @param[in] ly_mod Module whose data to duplicate. * @param[in] add_state_np_conts Whether to also add state NP containers. * @param[in,out] new_data Data with appended duplicated nodes. * @return err_info, NULL on success. */ sr_error_info_t *sr_lyd_dup_module_data(const struct lyd_node *data, const struct lys_module *ly_mod, int add_state_np_conts, struct lyd_node **new_data); /** * @brief Duplicate selected nodes from a data tree. Also properly handles config/state NP containers. * Works well even for XPaths with intersections. * * @param[in] data Data tree to duplicate from. * @param[in] xpaths Array of XPaths that will select the duplicated nodes. * @param[in] xp_count XPath count. * @param[in,out] new_data Data with appended duplicated selected nodes. * @return err_info, NULL on success. */ sr_error_info_t *sr_lyd_dup_enabled_xpath(const struct lyd_node *data, char **xpaths, uint16_t xp_count, struct lyd_node **new_data); /** * @brief Remove all nodes selected by XPath. * * @param[in,out] data Data to filter. * @param[in] xpath XPath selecting the nodes that will be freed. * @return err_info, NULL on success. */ sr_error_info_t *sr_lyd_xpath_complement(struct lyd_node **data, const char *xpath); /** * @brief Learn whether a node is user-ordered (leaf-)list. * * @param[in] node (Leaf-)list instance. * @return 0 if not, non-zero if it is. */ int sr_ly_is_userord(const struct lyd_node *node); /** * @brief Learn whether 2 anydata/anyxml nodes are equal or not. * * @param[in] any1 First anydata/anyxml node. * @param[in] any2 Second anydata/anyxml node. * @param[out] equal 1 if equal, 0 otherwise. * @return err_info, NULL on success. */ sr_error_info_t *sr_lyd_anydata_equal(const struct lyd_node *any1, const struct lyd_node *any2, int *equal); /** * @brief Free anydata/anyxml value. * * @param[in] any Node with value to free. */ void sr_lyd_anydata_free(struct lyd_node *any); /** * @brief Copy anydata/anyxml value from src to trg. * * @param[in] trg Target to copy to. * @param[in] src Source to copy from. * @return err_info, NULL on success. */ sr_error_info_t *sr_lyd_anydata_copy(struct lyd_node *trg, const struct lyd_node *src); /** * @brief Get string value of an anydata/anyxml node. * * @param[in] any Anydata/anyxml to get the value from. * @param[out] value_str String value. * @return err_info, NULL on success. */ sr_error_info_t *sr_ly_anydata_value_str(const struct lyd_node *any, char **value_str); /** * @brief Get a hash of a string value. * * @param[in] str String to hash. * @return String hash. */ uint32_t sr_str_hash(const char *str); /** * @brief Trim last node from an XPath. * * @param[in] xpath Full XPath. * @param[out] trim_xpath XPath without the last node (and its predicates, if any). * @return err_info, NULL on success. */ sr_error_info_t *sr_xpath_trim_last_node(const char *xpath, char **trim_xpath); /** * @brief Get the first node (with predicates if any) from an XPath. * * @param[in] xpath Full XPath. * @return First XPath node path. */ char *sr_xpath_first_node_with_predicates(const char *xpath); /** * @brief Get pointers to the next node name in an XPath. * * @param[in] xpath Current position in the XPath (`/` expected at the beginning). * @param[out] mod Module name, if any. * @param[out] mod_len Moduel name length. * @param[out] name Node name. * @param[out] len Node name length, * @param[out] double_slash Whether the node starts with '//'. * @param[out] has_predicate Whether a predicate follows. * @return Pointer to the next XPath part (node name or predicate). */ const char *sr_xpath_next_name(const char *xpath, const char **mod, int *mod_len, const char **name, int *len, int *double_slash, int *has_predicate); /** * @brief Get pointers to the next predicate in an XPath. * * @param[in] xpath Current position in the XPath (`[` expected at the beginning). * @param[out] pred Predicate content. * @param[out] len Predicate content length, * @param[out] has_predicate Whether another predicate follows. * @return Pointer to the next XPath part (node name or predicate). */ const char *sr_xpath_next_predicate(const char *xpath, const char **pred, int *len, int *has_predicate); /** * @brief Learn length of an XPath withtout any predicates. * * @param[in] xpath Full XPath. * @return XPath length. */ size_t sr_xpath_len_no_predicates(const char *xpath); /** * @brief Find last (most nested) parent (node with possible children) in a data tree. * * @param[in,out] parent Any subtree node, will be moved to the last parent. * @param[in] nodetype Whether to stop when a specific node type is found or not. * @return err_info, NULL on success. */ sr_error_info_t *sr_ly_find_last_parent(struct lyd_node **parent, int nodetype); /** * @brief Unlink data of a specific module from a data tree. * * @param[in,out] data Data tree. * @param[in] ly_mod libyang module of interest. * @return Unlinked data tree. */ struct lyd_node *sr_module_data_unlink(struct lyd_node **data, const struct lys_module *ly_mod); /** * @brief Append data loaded from a file/SHM for a specific module. Do not use for operational datastore. * * @param[in] ly_mod Module to process. * @param[in] ds Datastore. * @param[in,out] data Data tree to append to. * @return err_info, NULL on success. */ sr_error_info_t *sr_module_file_data_append(const struct lys_module *ly_mod, sr_datastore_t ds, struct lyd_node **data); /** * @brief Load operational data (diff) loaded from a SHM for a specific module. * * @param[in] mod Mod info mod. * @param[out] diff Loaded diff to return. * @return err_info, NULL on success. */ sr_error_info_t *sr_module_file_oper_data_load(struct sr_mod_info_mod_s *mod, struct lyd_node **diff); /** * @brief Set (replace) data in file/SHM for a specific module. * * @param[in] mod_name Module name. * @param[in] ds Target datastore * @param[in] mod_data Module data. * @param[in] create_flags Additional flags that will be used for opening the file, * any of O_CREATE and O_EXCL are expected. * @param[in] file_mode Permissions (mode) of the file, must always be correctly set because of the backup. * @return err_info, NULL on success. */ sr_error_info_t *sr_module_file_data_set(const char *mod_name, sr_datastore_t ds, struct lyd_node *mod_data, int create_flags, mode_t file_mode); /** * @brief Update sysrepo stored operational diff of a module. * * @param[in] conn Connection to use. * @param[in] mod_name Module name. * @return err_info, NULL on success. */ sr_error_info_t *sr_module_update_oper_diff(sr_conn_ctx_t *conn, const char *mod_name); /** * @brief Get next feature of a module. * * @param[in] last Last returned feature, NULL on first call, * @param[in] ly_mod Module with the features. * @param[in,out] idx Internal index fo the feature, arbitrary value can be passed but must not be changed in between calls. * @return Next found feature, NULL if last was previously returned. */ struct lys_feature *sr_lys_next_feature(struct lys_feature *last, const struct lys_module *ly_mod, uint32_t *idx); /** * @brief Learn CIDs and PIDs of all the live connections. * * @param[out] cids Optional array of CIDs. * @param[out] pids Optional array of PIDs. * @param[out] count Connection count, length of both @p cids and @p pids. * @param[out] dead_cids Optional array of dead CIDs. * @param[out] dead_count Length of @p dead_cids. * @return err_info, NULL on success. */ sr_error_info_t *sr_conn_info(sr_cid_t **cids, pid_t **pids, uint32_t *count, sr_cid_t **dead_cids, uint32_t *dead_count); /** * @brief Transform given time_t (seconds since the epoch) into the RFC 3339 format (YANG date-and-time). * * @param[in] time Time to convert. * @param[in] tz Timezone name for the result. See tzselect(1) for list of * correct values. If not specified (NULL) or unknown/invalid, the result is provided in UTC (Zulu). * @param[in,out] buf Buffer to print the datetime into, must be at least 26 characters long. If not set, @p buf2 is used. * @param[in,out] buf2 Pointer to a buffer to allocate for the datetime. * @return err_info, NULL on success. */ sr_error_info_t *sr_time2datetime(time_t time, const char *tz, char *buf, char **buf2); #endif