blob: d62da1c3556cd0db6141612f4cbd157e5b26515d [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 Vaskode4a3412021-04-14 15:38:27 +020073extern const struct lyplg_type_record plugins_xpath10[];
74
75/*
Michal Vasko7a53c7d2021-08-06 11:28:57 +020076 * ietf-netconf-acm
77 */
78extern const struct lyplg_type_record plugins_node_instanceid[];
79
80/*
Radek Krejci3e6632f2021-03-22 22:08:21 +010081 * internal extension plugins records
82 */
83extern struct lyplg_ext_record plugins_metadata[];
84extern struct lyplg_ext_record plugins_nacm[];
85extern struct lyplg_ext_record plugins_yangdata[];
tadeas-vintrlik2aa36b42021-11-03 13:07:34 +010086extern struct lyplg_ext_record plugins_schema_mount[];
Michal Vaskoedb0fa52022-10-04 10:36:00 +020087extern struct lyplg_ext_record plugins_structure[];
Radek Krejci3e6632f2021-03-22 22:08:21 +010088
89static pthread_mutex_t plugins_guard = PTHREAD_MUTEX_INITIALIZER;
90
91/**
92 * @brief Counter for currently present contexts able to refer to the loaded plugins.
93 *
94 * Plugins are shared among all the created contexts. They are loaded with the creation of the very first context and
95 * unloaded with the destroy of the last context. Therefore, to reload the list of plugins, all the contexts must be
96 * destroyed and with the creation of a first new context after that, the plugins will be reloaded.
97 */
98static uint32_t context_refcount = 0;
99
100/**
101 * @brief Record describing an implemented extension.
102 *
103 * Matches ::lyplg_ext_record and ::lyplg_type_record
104 */
105struct lyplg_record {
106 const char *module; /**< name of the module where the extension/type is defined */
107 const char *revision; /**< optional module revision - if not specified, the plugin applies to any revision,
108 which is not an optimal approach due to a possible future revisions of the module.
109 Instead, there should be defined multiple items in the plugins list, each with the
110 different revision, but all with the same pointer to the plugin functions. The
111 only valid use case for the NULL revision is the case the module has no revision. */
112 const char *name; /**< name of the extension/typedef */
113 int8_t plugin[]; /**< specific plugin type's data - ::lyplg_ext or ::lyplg_type */
114};
115
Michal Vasko9e2bc702021-06-09 11:43:36 +0200116#ifndef STATIC
Radek Krejcibf940f92021-03-24 21:04:13 +0100117static struct ly_set plugins_handlers = {0};
Michal Vasko9e2bc702021-06-09 11:43:36 +0200118#endif
Radek Krejci3e6632f2021-03-22 22:08:21 +0100119static struct ly_set plugins_types = {0};
120static struct ly_set plugins_extensions = {0};
121
122/**
123 * @brief Iterate over list of loaded plugins of the given @p type.
124 *
125 * @param[in] type Type of the plugins to iterate.
126 * @param[in,out] index The iterator - set to 0 for the first call.
127 * @return The plugin records, NULL if no more record is available.
128 */
129static struct lyplg_record *
130plugins_iter(enum LYPLG type, uint32_t *index)
131{
132 struct ly_set *plugins;
133
134 assert(index);
135
136 if (type == LYPLG_EXTENSION) {
137 plugins = &plugins_extensions;
138 } else {
139 plugins = &plugins_types;
140 }
141
142 if (*index == plugins->count) {
143 return NULL;
144 }
145
146 *index += 1;
147 return plugins->objs[*index - 1];
148}
149
Michal Vaskoc0c64ae2022-10-06 10:15:23 +0200150static void *
151lyplg_record_find(enum LYPLG type, const char *module, const char *revision, const char *name)
Radek Krejci3e6632f2021-03-22 22:08:21 +0100152{
153 uint32_t i = 0;
154 struct lyplg_record *item;
155
156 assert(module);
157 assert(name);
158
159 while ((item = plugins_iter(type, &i)) != NULL) {
160 if (!strcmp(item->module, module) && !strcmp(item->name, name)) {
161 if (item->revision && revision && strcmp(item->revision, revision)) {
162 continue;
163 } else if (!revision && item->revision) {
164 continue;
165 }
166
Michal Vaskoc0c64ae2022-10-06 10:15:23 +0200167 return item;
Radek Krejci3e6632f2021-03-22 22:08:21 +0100168 }
169 }
170
171 return NULL;
172}
173
Michal Vaskoc0c64ae2022-10-06 10:15:23 +0200174struct lyplg_type *
175lyplg_type_plugin_find(const char *module, const char *revision, const char *name)
176{
177 struct lyplg_record *record;
178
179 record = lyplg_record_find(LYPLG_TYPE, module, revision, name);
180 return record ? &((struct lyplg_type_record *)record)->plugin : NULL;
181}
182
183struct lyplg_ext_record *
184lyplg_ext_record_find(const char *module, const char *revision, const char *name)
185{
186 return lyplg_record_find(LYPLG_EXTENSION, module, revision, name);
187}
188
Radek Krejci3e6632f2021-03-22 22:08:21 +0100189/**
190 * @brief Insert the provided extension plugin records into the internal set of extension plugins for use by libyang.
191 *
192 * @param[in] recs An array of plugin records provided by the plugin implementation. The array must be terminated by a zeroed
193 * record.
194 * @return LY_SUCCESS in case of success
195 * @return LY_EINVAL for invalid information in @p recs.
196 * @return LY_EMEM in case of memory allocation failure.
197 */
198static LY_ERR
199plugins_insert(enum LYPLG type, const void *recs)
200{
201 if (!recs) {
202 return LY_SUCCESS;
203 }
204
205 if (type == LYPLG_EXTENSION) {
206 const struct lyplg_ext_record *rec = (const struct lyplg_ext_record *)recs;
207
208 for (uint32_t i = 0; rec[i].name; i++) {
209 LY_CHECK_RET(ly_set_add(&plugins_extensions, (void *)&rec[i], 0, NULL));
210 }
Radek Krejcibf940f92021-03-24 21:04:13 +0100211 } else { /* LYPLG_TYPE */
Radek Krejci3e6632f2021-03-22 22:08:21 +0100212 const struct lyplg_type_record *rec = (const struct lyplg_type_record *)recs;
213
214 for (uint32_t i = 0; rec[i].name; i++) {
215 LY_CHECK_RET(ly_set_add(&plugins_types, (void *)&rec[i], 0, NULL));
216 }
217 }
218
219 return LY_SUCCESS;
220}
221
Michal Vasko9e2bc702021-06-09 11:43:36 +0200222#ifndef STATIC
223
Radek Krejci3e6632f2021-03-22 22:08:21 +0100224static void
Michal Vaskoe43a34e2021-04-13 13:43:04 +0200225lyplg_close_cb(void *handle)
226{
227 dlclose(handle);
228}
229
230static void
Radek Krejci3e6632f2021-03-22 22:08:21 +0100231lyplg_clean_(void)
232{
233 if (--context_refcount) {
234 /* there is still some other context, do not remove the plugins */
235 return;
236 }
237
238 ly_set_erase(&plugins_types, NULL);
239 ly_set_erase(&plugins_extensions, NULL);
Michal Vaskoe43a34e2021-04-13 13:43:04 +0200240 ly_set_erase(&plugins_handlers, lyplg_close_cb);
Radek Krejci3e6632f2021-03-22 22:08:21 +0100241}
242
Michal Vasko9e2bc702021-06-09 11:43:36 +0200243#endif
244
Radek Krejci3e6632f2021-03-22 22:08:21 +0100245void
246lyplg_clean(void)
247{
Michal Vasko9e2bc702021-06-09 11:43:36 +0200248#ifndef STATIC
Radek Krejci3e6632f2021-03-22 22:08:21 +0100249 pthread_mutex_lock(&plugins_guard);
250 lyplg_clean_();
251 pthread_mutex_unlock(&plugins_guard);
Michal Vasko9e2bc702021-06-09 11:43:36 +0200252#endif
Radek Krejci3e6632f2021-03-22 22:08:21 +0100253}
254
Michal Vasko9e2bc702021-06-09 11:43:36 +0200255#ifndef STATIC
256
257/**
258 * @brief Just a variadic data to cover extension and type plugins by a single ::plugins_load() function.
259 *
260 * The values are taken from ::LY_PLUGINS_EXTENSIONS and ::LYPLG_TYPES macros.
261 */
262static const struct {
263 const char *id; /**< string identifier: type/extension */
264 const char *apiver_var; /**< expected variable name holding API version value */
265 const char *plugins_var; /**< expected variable name holding plugin records */
266 const char *envdir; /**< environment variable containing directory with the plugins */
267 const char *dir; /**< default directory with the plugins (has less priority than envdir) */
268 uint32_t apiver; /**< expected API version */
269} plugins_load_info[] = {
270 { /* LYPLG_TYPE */
271 .id = "type",
272 .apiver_var = "plugins_types_apiver__",
273 .plugins_var = "plugins_types__",
274 .envdir = "LIBYANG_TYPES_PLUGINS_DIR",
275 .dir = LYPLG_TYPE_DIR,
276 .apiver = LYPLG_TYPE_API_VERSION
277 }, {/* LYPLG_EXTENSION */
278 .id = "extension",
279 .apiver_var = "plugins_extensions_apiver__",
280 .plugins_var = "plugins_extensions__",
281 .envdir = "LIBYANG_EXTENSIONS_PLUGINS_DIR",
282 .dir = LYPLG_EXT_DIR,
283 .apiver = LYPLG_EXT_API_VERSION
284 }
285};
286
Radek Krejcibf940f92021-03-24 21:04:13 +0100287/**
288 * @brief Get the expected plugin objects from the loaded dynamic object and add the defined plugins into the lists of
289 * available extensions/types plugins.
290 *
291 * @param[in] dlhandler Loaded dynamic library handler.
292 * @param[in] pathname Path of the loaded library for logging.
293 * @param[in] type Type of the plugins to get from the dynamic library. Note that a single library can hold both types
294 * and extensions plugins implementations, so this function should be called twice (once for each plugin type) with
295 * different @p type values
296 * @return LY_ERR values.
297 */
298static LY_ERR
299plugins_load(void *dlhandler, const char *pathname, enum LYPLG type)
300{
301 const void *plugins;
302 uint32_t *version;
303
304 /* type plugin */
305 version = dlsym(dlhandler, plugins_load_info[type].apiver_var);
306 if (version) {
307 /* check version ... */
308 if (*version != plugins_load_info[type].apiver) {
309 LOGERR(NULL, LY_EINVAL, "Processing user %s plugin \"%s\" failed, wrong API version - %d expected, %d found.",
310 plugins_load_info[type].id, pathname, plugins_load_info[type].apiver, *version);
311 return LY_EINVAL;
312 }
313
314 /* ... get types plugins information ... */
315 if (!(plugins = dlsym(dlhandler, plugins_load_info[type].plugins_var))) {
316 char *errstr = dlerror();
Michal Vasko26bbb272022-08-02 14:54:33 +0200317
Radek Krejcibf940f92021-03-24 21:04:13 +0100318 LOGERR(NULL, LY_EINVAL, "Processing user %s plugin \"%s\" failed, missing %s plugins information (%s).",
319 plugins_load_info[type].id, pathname, plugins_load_info[type].id, errstr);
320 return LY_EINVAL;
321 }
322
323 /* ... and load all the types plugins */
324 LY_CHECK_RET(plugins_insert(type, plugins));
325 }
326
327 return LY_SUCCESS;
328}
329
330static LY_ERR
331plugins_load_module(const char *pathname)
332{
333 LY_ERR ret = LY_SUCCESS;
334 void *dlhandler;
335 uint32_t types_count = 0, extensions_count = 0;
336
337 dlerror(); /* Clear any existing error */
338
339 dlhandler = dlopen(pathname, RTLD_NOW);
340 if (!dlhandler) {
341 LOGERR(NULL, LY_ESYS, "Loading \"%s\" as a plugin failed (%s).", pathname, dlerror());
342 return LY_ESYS;
343 }
344
345 if (ly_set_contains(&plugins_handlers, dlhandler, NULL)) {
346 /* the plugin is already loaded */
347 LOGVRB("Plugin \"%s\" already loaded.", pathname);
348
349 /* keep the correct refcount */
350 dlclose(dlhandler);
351 return LY_SUCCESS;
352 }
353
354 /* remember the current plugins lists for recovery */
355 types_count = plugins_types.count;
356 extensions_count = plugins_extensions.count;
357
358 /* type plugin */
359 ret = plugins_load(dlhandler, pathname, LYPLG_TYPE);
360 LY_CHECK_GOTO(ret, error);
361
362 /* extension plugin */
363 ret = plugins_load(dlhandler, pathname, LYPLG_EXTENSION);
364 LY_CHECK_GOTO(ret, error);
365
366 /* remember the dynamic plugin */
367 ret = ly_set_add(&plugins_handlers, dlhandler, 1, NULL);
368 LY_CHECK_GOTO(ret, error);
369
370 return LY_SUCCESS;
371
372error:
373 dlclose(dlhandler);
374
375 /* revert changes in the lists */
376 while (plugins_types.count > types_count) {
377 ly_set_rm_index(&plugins_types, plugins_types.count - 1, NULL);
378 }
379 while (plugins_extensions.count > extensions_count) {
380 ly_set_rm_index(&plugins_extensions, plugins_extensions.count - 1, NULL);
381 }
382
383 return ret;
384}
385
Radek Krejci968d7552021-03-26 20:33:51 +0100386static LY_ERR
387plugins_insert_dir(enum LYPLG type)
388{
389 LY_ERR ret = LY_SUCCESS;
390 const char *pluginsdir;
391 DIR *dir;
392 ly_bool default_dir = 0;
393
394 /* try to get the plugins directory from environment variable */
395 pluginsdir = getenv(plugins_load_info[type].envdir);
396 if (!pluginsdir) {
397 /* remember that we are going to a default dir and do not print warning if the directory doesn't exist */
398 default_dir = 1;
399 pluginsdir = plugins_load_info[type].dir;
400 }
401
402 dir = opendir(pluginsdir);
403 if (!dir) {
404 /* no directory (or no access to it), no extension plugins */
405 if (!default_dir || (errno != ENOENT)) {
406 LOGWRN(NULL, "Failed to open libyang %s plugins directory \"%s\" (%s).", plugins_load_info[type].id,
407 pluginsdir, strerror(errno));
408 }
409 } else {
410 struct dirent *file;
411
412 while ((file = readdir(dir))) {
413 size_t len;
414 char pathname[PATH_MAX];
415
416 /* required format of the filename is *LYPLG_SUFFIX */
417 len = strlen(file->d_name);
418 if ((len < LYPLG_SUFFIX_LEN + 1) || strcmp(&file->d_name[len - LYPLG_SUFFIX_LEN], LYPLG_SUFFIX)) {
419 continue;
420 }
421
422 /* and construct the filepath */
423 snprintf(pathname, PATH_MAX, "%s/%s", pluginsdir, file->d_name);
424
425 ret = plugins_load_module(pathname);
426 if (ret) {
427 break;
428 }
429 }
430 closedir(dir);
431 }
432
433 return ret;
434}
435
Michal Vasko9e2bc702021-06-09 11:43:36 +0200436#endif
437
Radek Krejci3e6632f2021-03-22 22:08:21 +0100438LY_ERR
439lyplg_init(void)
440{
441 LY_ERR ret;
442
443 pthread_mutex_lock(&plugins_guard);
444 /* let only the first context to initiate plugins, but let others wait for finishing the initiation */
445 if (context_refcount++) {
446 /* already initiated */
447 pthread_mutex_unlock(&plugins_guard);
448 return LY_SUCCESS;
449 }
450
451 /* internal types */
452 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_binary), error);
453 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_bits), error);
454 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_boolean), error);
455 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_decimal64), error);
456 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_empty), error);
457 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_enumeration), error);
458 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_identityref), error);
459 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_instanceid), error);
460 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_integer), error);
461 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_leafref), error);
462 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_string), error);
463 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_union), error);
464
Michal Vasko79a7a872022-06-17 09:00:48 +0200465 /* yang */
466 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_instanceid_keys), error);
467
Michal Vaskode4a3412021-04-14 15:38:27 +0200468 /* ietf-inet-types */
Michal Vasko3159e782021-05-03 15:12:35 +0200469 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_ipv4_address), error);
Michal Vasko82bf15e2021-05-06 16:01:56 +0200470 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_ipv4_address_no_zone), error);
Michal Vasko7caa3e62021-05-03 14:59:25 +0200471 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_ipv6_address), error);
Michal Vasko18a4a732021-05-06 16:21:44 +0200472 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_ipv6_address_no_zone), error);
Michal Vasko15dc9fa2021-05-03 14:33:05 +0200473 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_ipv4_prefix), error);
474 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_ipv6_prefix), error);
Michal Vasko3e52de52021-04-13 13:45:55 +0200475
Michal Vaskode4a3412021-04-14 15:38:27 +0200476 /* ietf-yang-types */
477 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_date_and_time), error);
Michal Vaskode4a3412021-04-14 15:38:27 +0200478 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_xpath10), error);
479
Michal Vasko7a53c7d2021-08-06 11:28:57 +0200480 /* ietf-netconf-acm */
481 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_node_instanceid), error);
482
Radek Krejci3e6632f2021-03-22 22:08:21 +0100483 /* internal extensions */
484 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_EXTENSION, plugins_metadata), error);
485 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_EXTENSION, plugins_nacm), error);
486 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_EXTENSION, plugins_yangdata), error);
tadeas-vintrlik2aa36b42021-11-03 13:07:34 +0100487 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_EXTENSION, plugins_schema_mount), error);
Michal Vaskoedb0fa52022-10-04 10:36:00 +0200488 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_EXTENSION, plugins_structure), error);
Radek Krejci3e6632f2021-03-22 22:08:21 +0100489
Michal Vasko9e2bc702021-06-09 11:43:36 +0200490#ifndef STATIC
Radek Krejci968d7552021-03-26 20:33:51 +0100491 /* external types */
492 LY_CHECK_GOTO(ret = plugins_insert_dir(LYPLG_TYPE), error);
493
494 /* external extensions */
495 LY_CHECK_GOTO(ret = plugins_insert_dir(LYPLG_EXTENSION), error);
Michal Vasko9e2bc702021-06-09 11:43:36 +0200496#endif
Radek Krejci968d7552021-03-26 20:33:51 +0100497
Radek Krejci3e6632f2021-03-22 22:08:21 +0100498 /* initiation done, wake-up possibly waiting threads creating another contexts */
499 pthread_mutex_unlock(&plugins_guard);
500
501 return LY_SUCCESS;
502
503error:
504 /* initiation was not successful - cleanup (and let others to try) */
Michal Vasko9e2bc702021-06-09 11:43:36 +0200505#ifndef STATIC
Radek Krejci3e6632f2021-03-22 22:08:21 +0100506 lyplg_clean_();
Michal Vasko9e2bc702021-06-09 11:43:36 +0200507#endif
Radek Krejci3e6632f2021-03-22 22:08:21 +0100508 pthread_mutex_unlock(&plugins_guard);
509
510 if (ret == LY_EINVAL) {
511 /* all the plugins here are internal, invalid record actually means an internal libyang error */
512 ret = LY_EINT;
513 }
514 return ret;
515}
Radek Krejcibf940f92021-03-24 21:04:13 +0100516
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100517LIBYANG_API_DEF LY_ERR
Radek Krejcibf940f92021-03-24 21:04:13 +0100518lyplg_add(const char *pathname)
519{
Michal Vasko9e2bc702021-06-09 11:43:36 +0200520#ifdef STATIC
521 (void)pathname;
522
523 LOGERR(NULL, LY_EINVAL, "Plugins are not supported in statically built library.");
524 return LY_EINVAL;
Jan Kundrát323c3122021-12-14 11:44:57 +0100525#elif defined (_WIN32)
526 (void)pathname;
527
528 LOGERR(NULL, LY_EINVAL, "Plugins are not (yet) supported on Windows.");
529 return LY_EINVAL;
Michal Vasko9e2bc702021-06-09 11:43:36 +0200530#else
Radek Krejcibf940f92021-03-24 21:04:13 +0100531 LY_ERR ret = LY_SUCCESS;
532
533 LY_CHECK_ARG_RET(NULL, pathname, LY_EINVAL);
534
535 /* works only in case a context exists */
536 pthread_mutex_lock(&plugins_guard);
537 if (!context_refcount) {
538 /* no context */
539 pthread_mutex_unlock(&plugins_guard);
540 LOGERR(NULL, LY_EDENIED, "To add a plugin, at least one context must exists.");
541 return LY_EDENIED;
542 }
543
544 ret = plugins_load_module(pathname);
545
546 pthread_mutex_unlock(&plugins_guard);
547
548 return ret;
Michal Vasko9e2bc702021-06-09 11:43:36 +0200549#endif
Radek Krejcibf940f92021-03-24 21:04:13 +0100550}