blob: 011e464aebb2f8c36cb252be38dfebe9f02516aa [file] [log] [blame]
Radek Krejci3e6632f2021-03-22 22:08:21 +01001/**
2 * @file plugins.c
3 * @author Radek Krejci <rkrejci@cesnet.cz>
4 * @brief Manipulate with the type and extension plugins.
5 *
6 * Copyright (c) 2021 CESNET, z.s.p.o.
7 *
8 * This source code is licensed under BSD 3-Clause License (the "License").
9 * You may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * https://opensource.org/licenses/BSD-3-Clause
13 */
14
Radek Krejci968d7552021-03-26 20:33:51 +010015#define _GNU_SOURCE
16
Radek Krejci3e6632f2021-03-22 22:08:21 +010017#include "plugins.h"
18#include "plugins_internal.h"
19
20#include <assert.h>
Radek Krejci968d7552021-03-26 20:33:51 +010021#include <dirent.h>
Radek Krejci3e6632f2021-03-22 22:08:21 +010022#include <dlfcn.h>
Radek Krejci968d7552021-03-26 20:33:51 +010023#include <errno.h>
24#include <limits.h>
Radek Krejci3e6632f2021-03-22 22:08:21 +010025#include <pthread.h>
Radek Krejcibf940f92021-03-24 21:04:13 +010026#include <stddef.h>
Radek Krejci0aa1f702021-04-01 16:16:19 +020027#include <stdint.h>
28#include <stdio.h>
29#include <stdlib.h>
Radek Krejci3e6632f2021-03-22 22:08:21 +010030#include <string.h>
31
32#include "common.h"
Radek Krejci12a28c72021-04-06 17:23:37 +020033#include "config.h"
Radek Krejci3e6632f2021-03-22 22:08:21 +010034#include "plugins_exts.h"
35#include "plugins_types.h"
Radek Krejci0aa1f702021-04-01 16:16:19 +020036#include "set.h"
Radek Krejci3e6632f2021-03-22 22:08:21 +010037
38/*
39 * internal type plugins records
40 */
41extern const struct lyplg_type_record plugins_binary[];
42extern const struct lyplg_type_record plugins_bits[];
43extern const struct lyplg_type_record plugins_boolean[];
44extern const struct lyplg_type_record plugins_decimal64[];
45extern const struct lyplg_type_record plugins_empty[];
46extern const struct lyplg_type_record plugins_enumeration[];
47extern const struct lyplg_type_record plugins_identityref[];
48extern const struct lyplg_type_record plugins_instanceid[];
49extern const struct lyplg_type_record plugins_integer[];
50extern const struct lyplg_type_record plugins_leafref[];
51extern const struct lyplg_type_record plugins_string[];
52extern const struct lyplg_type_record plugins_union[];
53
Michal Vaskode4a3412021-04-14 15:38:27 +020054/*
Michal Vasko79a7a872022-06-17 09:00:48 +020055 * yang
56 */
57extern const struct lyplg_type_record plugins_instanceid_keys[];
58
59/*
Michal Vaskode4a3412021-04-14 15:38:27 +020060 * ietf-inet-types
61 */
Michal Vasko3159e782021-05-03 15:12:35 +020062extern const struct lyplg_type_record plugins_ipv4_address[];
Michal Vasko82bf15e2021-05-06 16:01:56 +020063extern const struct lyplg_type_record plugins_ipv4_address_no_zone[];
Michal Vasko7caa3e62021-05-03 14:59:25 +020064extern const struct lyplg_type_record plugins_ipv6_address[];
Michal Vasko18a4a732021-05-06 16:21:44 +020065extern const struct lyplg_type_record plugins_ipv6_address_no_zone[];
Michal Vasko15dc9fa2021-05-03 14:33:05 +020066extern const struct lyplg_type_record plugins_ipv4_prefix[];
67extern const struct lyplg_type_record plugins_ipv6_prefix[];
Michal Vasko3e52de52021-04-13 13:45:55 +020068
Radek Krejci3e6632f2021-03-22 22:08:21 +010069/*
Michal Vaskode4a3412021-04-14 15:38:27 +020070 * ietf-yang-types
71 */
72extern const struct lyplg_type_record plugins_date_and_time[];
Michal Vasko30e75a72023-08-08 11:35:54 +020073extern const struct lyplg_type_record plugins_hex_string[];
Michal Vaskode4a3412021-04-14 15:38:27 +020074extern const struct lyplg_type_record plugins_xpath10[];
75
76/*
Michal Vasko7a53c7d2021-08-06 11:28:57 +020077 * ietf-netconf-acm
78 */
79extern const struct lyplg_type_record plugins_node_instanceid[];
80
81/*
Radek Krejci3e6632f2021-03-22 22:08:21 +010082 * internal extension plugins records
83 */
84extern struct lyplg_ext_record plugins_metadata[];
85extern struct lyplg_ext_record plugins_nacm[];
86extern struct lyplg_ext_record plugins_yangdata[];
tadeas-vintrlik2aa36b42021-11-03 13:07:34 +010087extern struct lyplg_ext_record plugins_schema_mount[];
Michal Vaskoedb0fa52022-10-04 10:36:00 +020088extern struct lyplg_ext_record plugins_structure[];
Radek Krejci3e6632f2021-03-22 22:08:21 +010089
90static pthread_mutex_t plugins_guard = PTHREAD_MUTEX_INITIALIZER;
91
92/**
93 * @brief Counter for currently present contexts able to refer to the loaded plugins.
94 *
95 * Plugins are shared among all the created contexts. They are loaded with the creation of the very first context and
96 * unloaded with the destroy of the last context. Therefore, to reload the list of plugins, all the contexts must be
97 * destroyed and with the creation of a first new context after that, the plugins will be reloaded.
98 */
99static uint32_t context_refcount = 0;
100
101/**
102 * @brief Record describing an implemented extension.
103 *
104 * Matches ::lyplg_ext_record and ::lyplg_type_record
105 */
106struct lyplg_record {
107 const char *module; /**< name of the module where the extension/type is defined */
108 const char *revision; /**< optional module revision - if not specified, the plugin applies to any revision,
109 which is not an optimal approach due to a possible future revisions of the module.
110 Instead, there should be defined multiple items in the plugins list, each with the
111 different revision, but all with the same pointer to the plugin functions. The
112 only valid use case for the NULL revision is the case the module has no revision. */
113 const char *name; /**< name of the extension/typedef */
114 int8_t plugin[]; /**< specific plugin type's data - ::lyplg_ext or ::lyplg_type */
115};
116
Michal Vasko9e2bc702021-06-09 11:43:36 +0200117#ifndef STATIC
Radek Krejcibf940f92021-03-24 21:04:13 +0100118static struct ly_set plugins_handlers = {0};
Michal Vasko9e2bc702021-06-09 11:43:36 +0200119#endif
Radek Krejci3e6632f2021-03-22 22:08:21 +0100120static struct ly_set plugins_types = {0};
121static struct ly_set plugins_extensions = {0};
122
123/**
124 * @brief Iterate over list of loaded plugins of the given @p type.
125 *
126 * @param[in] type Type of the plugins to iterate.
127 * @param[in,out] index The iterator - set to 0 for the first call.
128 * @return The plugin records, NULL if no more record is available.
129 */
130static struct lyplg_record *
131plugins_iter(enum LYPLG type, uint32_t *index)
132{
133 struct ly_set *plugins;
134
135 assert(index);
136
137 if (type == LYPLG_EXTENSION) {
138 plugins = &plugins_extensions;
139 } else {
140 plugins = &plugins_types;
141 }
142
143 if (*index == plugins->count) {
144 return NULL;
145 }
146
147 *index += 1;
148 return plugins->objs[*index - 1];
149}
150
Michal Vaskoc0c64ae2022-10-06 10:15:23 +0200151static void *
152lyplg_record_find(enum LYPLG type, const char *module, const char *revision, const char *name)
Radek Krejci3e6632f2021-03-22 22:08:21 +0100153{
154 uint32_t i = 0;
155 struct lyplg_record *item;
156
157 assert(module);
158 assert(name);
159
160 while ((item = plugins_iter(type, &i)) != NULL) {
161 if (!strcmp(item->module, module) && !strcmp(item->name, name)) {
162 if (item->revision && revision && strcmp(item->revision, revision)) {
163 continue;
164 } else if (!revision && item->revision) {
165 continue;
166 }
167
Michal Vaskoc0c64ae2022-10-06 10:15:23 +0200168 return item;
Radek Krejci3e6632f2021-03-22 22:08:21 +0100169 }
170 }
171
172 return NULL;
173}
174
Michal Vaskoc0c64ae2022-10-06 10:15:23 +0200175struct lyplg_type *
176lyplg_type_plugin_find(const char *module, const char *revision, const char *name)
177{
178 struct lyplg_record *record;
179
180 record = lyplg_record_find(LYPLG_TYPE, module, revision, name);
181 return record ? &((struct lyplg_type_record *)record)->plugin : NULL;
182}
183
184struct lyplg_ext_record *
185lyplg_ext_record_find(const char *module, const char *revision, const char *name)
186{
187 return lyplg_record_find(LYPLG_EXTENSION, module, revision, name);
188}
189
Radek Krejci3e6632f2021-03-22 22:08:21 +0100190/**
191 * @brief Insert the provided extension plugin records into the internal set of extension plugins for use by libyang.
192 *
193 * @param[in] recs An array of plugin records provided by the plugin implementation. The array must be terminated by a zeroed
194 * record.
195 * @return LY_SUCCESS in case of success
196 * @return LY_EINVAL for invalid information in @p recs.
197 * @return LY_EMEM in case of memory allocation failure.
198 */
199static LY_ERR
200plugins_insert(enum LYPLG type, const void *recs)
201{
202 if (!recs) {
203 return LY_SUCCESS;
204 }
205
206 if (type == LYPLG_EXTENSION) {
207 const struct lyplg_ext_record *rec = (const struct lyplg_ext_record *)recs;
208
209 for (uint32_t i = 0; rec[i].name; i++) {
210 LY_CHECK_RET(ly_set_add(&plugins_extensions, (void *)&rec[i], 0, NULL));
211 }
Radek Krejcibf940f92021-03-24 21:04:13 +0100212 } else { /* LYPLG_TYPE */
Radek Krejci3e6632f2021-03-22 22:08:21 +0100213 const struct lyplg_type_record *rec = (const struct lyplg_type_record *)recs;
214
215 for (uint32_t i = 0; rec[i].name; i++) {
216 LY_CHECK_RET(ly_set_add(&plugins_types, (void *)&rec[i], 0, NULL));
217 }
218 }
219
220 return LY_SUCCESS;
221}
222
Michal Vasko9e2bc702021-06-09 11:43:36 +0200223#ifndef STATIC
224
Radek Krejci3e6632f2021-03-22 22:08:21 +0100225static void
Michal Vaskoe43a34e2021-04-13 13:43:04 +0200226lyplg_close_cb(void *handle)
227{
228 dlclose(handle);
229}
230
231static void
Radek Krejci3e6632f2021-03-22 22:08:21 +0100232lyplg_clean_(void)
233{
234 if (--context_refcount) {
235 /* there is still some other context, do not remove the plugins */
236 return;
237 }
238
239 ly_set_erase(&plugins_types, NULL);
240 ly_set_erase(&plugins_extensions, NULL);
Michal Vaskoe43a34e2021-04-13 13:43:04 +0200241 ly_set_erase(&plugins_handlers, lyplg_close_cb);
Radek Krejci3e6632f2021-03-22 22:08:21 +0100242}
243
Michal Vasko9e2bc702021-06-09 11:43:36 +0200244#endif
245
Radek Krejci3e6632f2021-03-22 22:08:21 +0100246void
247lyplg_clean(void)
248{
Michal Vasko9e2bc702021-06-09 11:43:36 +0200249#ifndef STATIC
Radek Krejci3e6632f2021-03-22 22:08:21 +0100250 pthread_mutex_lock(&plugins_guard);
251 lyplg_clean_();
252 pthread_mutex_unlock(&plugins_guard);
Michal Vasko9e2bc702021-06-09 11:43:36 +0200253#endif
Radek Krejci3e6632f2021-03-22 22:08:21 +0100254}
255
Michal Vasko9e2bc702021-06-09 11:43:36 +0200256#ifndef STATIC
257
258/**
259 * @brief Just a variadic data to cover extension and type plugins by a single ::plugins_load() function.
260 *
261 * The values are taken from ::LY_PLUGINS_EXTENSIONS and ::LYPLG_TYPES macros.
262 */
263static const struct {
264 const char *id; /**< string identifier: type/extension */
265 const char *apiver_var; /**< expected variable name holding API version value */
266 const char *plugins_var; /**< expected variable name holding plugin records */
267 const char *envdir; /**< environment variable containing directory with the plugins */
268 const char *dir; /**< default directory with the plugins (has less priority than envdir) */
269 uint32_t apiver; /**< expected API version */
270} plugins_load_info[] = {
271 { /* LYPLG_TYPE */
272 .id = "type",
273 .apiver_var = "plugins_types_apiver__",
274 .plugins_var = "plugins_types__",
275 .envdir = "LIBYANG_TYPES_PLUGINS_DIR",
276 .dir = LYPLG_TYPE_DIR,
277 .apiver = LYPLG_TYPE_API_VERSION
278 }, {/* LYPLG_EXTENSION */
279 .id = "extension",
280 .apiver_var = "plugins_extensions_apiver__",
281 .plugins_var = "plugins_extensions__",
282 .envdir = "LIBYANG_EXTENSIONS_PLUGINS_DIR",
283 .dir = LYPLG_EXT_DIR,
284 .apiver = LYPLG_EXT_API_VERSION
285 }
286};
287
Radek Krejcibf940f92021-03-24 21:04:13 +0100288/**
289 * @brief Get the expected plugin objects from the loaded dynamic object and add the defined plugins into the lists of
290 * available extensions/types plugins.
291 *
292 * @param[in] dlhandler Loaded dynamic library handler.
293 * @param[in] pathname Path of the loaded library for logging.
294 * @param[in] type Type of the plugins to get from the dynamic library. Note that a single library can hold both types
295 * and extensions plugins implementations, so this function should be called twice (once for each plugin type) with
296 * different @p type values
297 * @return LY_ERR values.
298 */
299static LY_ERR
300plugins_load(void *dlhandler, const char *pathname, enum LYPLG type)
301{
302 const void *plugins;
303 uint32_t *version;
304
305 /* type plugin */
306 version = dlsym(dlhandler, plugins_load_info[type].apiver_var);
307 if (version) {
308 /* check version ... */
309 if (*version != plugins_load_info[type].apiver) {
310 LOGERR(NULL, LY_EINVAL, "Processing user %s plugin \"%s\" failed, wrong API version - %d expected, %d found.",
311 plugins_load_info[type].id, pathname, plugins_load_info[type].apiver, *version);
312 return LY_EINVAL;
313 }
314
315 /* ... get types plugins information ... */
316 if (!(plugins = dlsym(dlhandler, plugins_load_info[type].plugins_var))) {
317 char *errstr = dlerror();
Michal Vasko26bbb272022-08-02 14:54:33 +0200318
Radek Krejcibf940f92021-03-24 21:04:13 +0100319 LOGERR(NULL, LY_EINVAL, "Processing user %s plugin \"%s\" failed, missing %s plugins information (%s).",
320 plugins_load_info[type].id, pathname, plugins_load_info[type].id, errstr);
321 return LY_EINVAL;
322 }
323
324 /* ... and load all the types plugins */
325 LY_CHECK_RET(plugins_insert(type, plugins));
326 }
327
328 return LY_SUCCESS;
329}
330
331static LY_ERR
332plugins_load_module(const char *pathname)
333{
334 LY_ERR ret = LY_SUCCESS;
335 void *dlhandler;
336 uint32_t types_count = 0, extensions_count = 0;
337
338 dlerror(); /* Clear any existing error */
339
340 dlhandler = dlopen(pathname, RTLD_NOW);
341 if (!dlhandler) {
342 LOGERR(NULL, LY_ESYS, "Loading \"%s\" as a plugin failed (%s).", pathname, dlerror());
343 return LY_ESYS;
344 }
345
346 if (ly_set_contains(&plugins_handlers, dlhandler, NULL)) {
347 /* the plugin is already loaded */
348 LOGVRB("Plugin \"%s\" already loaded.", pathname);
349
350 /* keep the correct refcount */
351 dlclose(dlhandler);
352 return LY_SUCCESS;
353 }
354
355 /* remember the current plugins lists for recovery */
356 types_count = plugins_types.count;
357 extensions_count = plugins_extensions.count;
358
359 /* type plugin */
360 ret = plugins_load(dlhandler, pathname, LYPLG_TYPE);
361 LY_CHECK_GOTO(ret, error);
362
363 /* extension plugin */
364 ret = plugins_load(dlhandler, pathname, LYPLG_EXTENSION);
365 LY_CHECK_GOTO(ret, error);
366
367 /* remember the dynamic plugin */
368 ret = ly_set_add(&plugins_handlers, dlhandler, 1, NULL);
369 LY_CHECK_GOTO(ret, error);
370
371 return LY_SUCCESS;
372
373error:
374 dlclose(dlhandler);
375
376 /* revert changes in the lists */
377 while (plugins_types.count > types_count) {
378 ly_set_rm_index(&plugins_types, plugins_types.count - 1, NULL);
379 }
380 while (plugins_extensions.count > extensions_count) {
381 ly_set_rm_index(&plugins_extensions, plugins_extensions.count - 1, NULL);
382 }
383
384 return ret;
385}
386
Radek Krejci968d7552021-03-26 20:33:51 +0100387static LY_ERR
388plugins_insert_dir(enum LYPLG type)
389{
390 LY_ERR ret = LY_SUCCESS;
391 const char *pluginsdir;
392 DIR *dir;
393 ly_bool default_dir = 0;
394
395 /* try to get the plugins directory from environment variable */
396 pluginsdir = getenv(plugins_load_info[type].envdir);
397 if (!pluginsdir) {
398 /* remember that we are going to a default dir and do not print warning if the directory doesn't exist */
399 default_dir = 1;
400 pluginsdir = plugins_load_info[type].dir;
401 }
402
403 dir = opendir(pluginsdir);
404 if (!dir) {
405 /* no directory (or no access to it), no extension plugins */
406 if (!default_dir || (errno != ENOENT)) {
407 LOGWRN(NULL, "Failed to open libyang %s plugins directory \"%s\" (%s).", plugins_load_info[type].id,
408 pluginsdir, strerror(errno));
409 }
410 } else {
411 struct dirent *file;
412
413 while ((file = readdir(dir))) {
414 size_t len;
415 char pathname[PATH_MAX];
416
417 /* required format of the filename is *LYPLG_SUFFIX */
418 len = strlen(file->d_name);
419 if ((len < LYPLG_SUFFIX_LEN + 1) || strcmp(&file->d_name[len - LYPLG_SUFFIX_LEN], LYPLG_SUFFIX)) {
420 continue;
421 }
422
423 /* and construct the filepath */
424 snprintf(pathname, PATH_MAX, "%s/%s", pluginsdir, file->d_name);
425
426 ret = plugins_load_module(pathname);
427 if (ret) {
428 break;
429 }
430 }
431 closedir(dir);
432 }
433
434 return ret;
435}
436
Michal Vasko9e2bc702021-06-09 11:43:36 +0200437#endif
438
Radek Krejci3e6632f2021-03-22 22:08:21 +0100439LY_ERR
440lyplg_init(void)
441{
442 LY_ERR ret;
443
444 pthread_mutex_lock(&plugins_guard);
445 /* let only the first context to initiate plugins, but let others wait for finishing the initiation */
446 if (context_refcount++) {
447 /* already initiated */
448 pthread_mutex_unlock(&plugins_guard);
449 return LY_SUCCESS;
450 }
451
452 /* internal types */
453 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_binary), error);
454 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_bits), error);
455 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_boolean), error);
456 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_decimal64), error);
457 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_empty), error);
458 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_enumeration), error);
459 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_identityref), error);
460 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_instanceid), error);
461 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_integer), error);
462 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_leafref), error);
463 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_string), error);
464 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_union), error);
465
Michal Vasko79a7a872022-06-17 09:00:48 +0200466 /* yang */
467 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_instanceid_keys), error);
468
Michal Vaskode4a3412021-04-14 15:38:27 +0200469 /* ietf-inet-types */
Michal Vasko3159e782021-05-03 15:12:35 +0200470 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_ipv4_address), error);
Michal Vasko82bf15e2021-05-06 16:01:56 +0200471 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_ipv4_address_no_zone), error);
Michal Vasko7caa3e62021-05-03 14:59:25 +0200472 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_ipv6_address), error);
Michal Vasko18a4a732021-05-06 16:21:44 +0200473 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_ipv6_address_no_zone), error);
Michal Vasko15dc9fa2021-05-03 14:33:05 +0200474 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_ipv4_prefix), error);
475 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_ipv6_prefix), error);
Michal Vasko3e52de52021-04-13 13:45:55 +0200476
Michal Vaskode4a3412021-04-14 15:38:27 +0200477 /* ietf-yang-types */
478 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_date_and_time), error);
Michal Vasko30e75a72023-08-08 11:35:54 +0200479 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_hex_string), error);
Michal Vaskode4a3412021-04-14 15:38:27 +0200480 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_xpath10), error);
481
Michal Vasko7a53c7d2021-08-06 11:28:57 +0200482 /* ietf-netconf-acm */
483 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_node_instanceid), error);
484
Radek Krejci3e6632f2021-03-22 22:08:21 +0100485 /* internal extensions */
486 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_EXTENSION, plugins_metadata), error);
487 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_EXTENSION, plugins_nacm), error);
488 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_EXTENSION, plugins_yangdata), error);
tadeas-vintrlik2aa36b42021-11-03 13:07:34 +0100489 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_EXTENSION, plugins_schema_mount), error);
Michal Vaskoedb0fa52022-10-04 10:36:00 +0200490 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_EXTENSION, plugins_structure), error);
Radek Krejci3e6632f2021-03-22 22:08:21 +0100491
Michal Vasko9e2bc702021-06-09 11:43:36 +0200492#ifndef STATIC
Radek Krejci968d7552021-03-26 20:33:51 +0100493 /* external types */
494 LY_CHECK_GOTO(ret = plugins_insert_dir(LYPLG_TYPE), error);
495
496 /* external extensions */
497 LY_CHECK_GOTO(ret = plugins_insert_dir(LYPLG_EXTENSION), error);
Michal Vasko9e2bc702021-06-09 11:43:36 +0200498#endif
Radek Krejci968d7552021-03-26 20:33:51 +0100499
Radek Krejci3e6632f2021-03-22 22:08:21 +0100500 /* initiation done, wake-up possibly waiting threads creating another contexts */
501 pthread_mutex_unlock(&plugins_guard);
502
503 return LY_SUCCESS;
504
505error:
506 /* initiation was not successful - cleanup (and let others to try) */
Michal Vasko9e2bc702021-06-09 11:43:36 +0200507#ifndef STATIC
Radek Krejci3e6632f2021-03-22 22:08:21 +0100508 lyplg_clean_();
Michal Vasko9e2bc702021-06-09 11:43:36 +0200509#endif
Radek Krejci3e6632f2021-03-22 22:08:21 +0100510 pthread_mutex_unlock(&plugins_guard);
511
512 if (ret == LY_EINVAL) {
513 /* all the plugins here are internal, invalid record actually means an internal libyang error */
514 ret = LY_EINT;
515 }
516 return ret;
517}
Radek Krejcibf940f92021-03-24 21:04:13 +0100518
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100519LIBYANG_API_DEF LY_ERR
Radek Krejcibf940f92021-03-24 21:04:13 +0100520lyplg_add(const char *pathname)
521{
Michal Vasko9e2bc702021-06-09 11:43:36 +0200522#ifdef STATIC
523 (void)pathname;
524
525 LOGERR(NULL, LY_EINVAL, "Plugins are not supported in statically built library.");
526 return LY_EINVAL;
Jan Kundrát323c3122021-12-14 11:44:57 +0100527#elif defined (_WIN32)
528 (void)pathname;
529
530 LOGERR(NULL, LY_EINVAL, "Plugins are not (yet) supported on Windows.");
531 return LY_EINVAL;
Michal Vasko9e2bc702021-06-09 11:43:36 +0200532#else
Radek Krejcibf940f92021-03-24 21:04:13 +0100533 LY_ERR ret = LY_SUCCESS;
534
535 LY_CHECK_ARG_RET(NULL, pathname, LY_EINVAL);
536
537 /* works only in case a context exists */
538 pthread_mutex_lock(&plugins_guard);
539 if (!context_refcount) {
540 /* no context */
541 pthread_mutex_unlock(&plugins_guard);
542 LOGERR(NULL, LY_EDENIED, "To add a plugin, at least one context must exists.");
543 return LY_EDENIED;
544 }
545
546 ret = plugins_load_module(pathname);
547
548 pthread_mutex_unlock(&plugins_guard);
549
550 return ret;
Michal Vasko9e2bc702021-06-09 11:43:36 +0200551#endif
Radek Krejcibf940f92021-03-24 21:04:13 +0100552}