blob: 3f120c41af269d1c36b63bf5386b26911aba8954 [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>
Michal Vasko0d8434d2024-02-20 15:49:10 +010022#ifndef STATIC
23# include <dlfcn.h>
24#endif
Radek Krejci968d7552021-03-26 20:33:51 +010025#include <errno.h>
26#include <limits.h>
Radek Krejci3e6632f2021-03-22 22:08:21 +010027#include <pthread.h>
Radek Krejcibf940f92021-03-24 21:04:13 +010028#include <stddef.h>
Radek Krejci0aa1f702021-04-01 16:16:19 +020029#include <stdint.h>
30#include <stdio.h>
31#include <stdlib.h>
Radek Krejci3e6632f2021-03-22 22:08:21 +010032#include <string.h>
33
Michal Vasko8f702ee2024-02-20 15:44:24 +010034#include "ly_common.h"
35#include "ly_config.h"
Radek Krejci3e6632f2021-03-22 22:08:21 +010036#include "plugins_exts.h"
37#include "plugins_types.h"
Radek Krejci0aa1f702021-04-01 16:16:19 +020038#include "set.h"
Radek Krejci3e6632f2021-03-22 22:08:21 +010039
40/*
41 * internal type plugins records
42 */
43extern const struct lyplg_type_record plugins_binary[];
44extern const struct lyplg_type_record plugins_bits[];
45extern const struct lyplg_type_record plugins_boolean[];
46extern const struct lyplg_type_record plugins_decimal64[];
47extern const struct lyplg_type_record plugins_empty[];
48extern const struct lyplg_type_record plugins_enumeration[];
49extern const struct lyplg_type_record plugins_identityref[];
50extern const struct lyplg_type_record plugins_instanceid[];
51extern const struct lyplg_type_record plugins_integer[];
52extern const struct lyplg_type_record plugins_leafref[];
53extern const struct lyplg_type_record plugins_string[];
54extern const struct lyplg_type_record plugins_union[];
55
Michal Vaskode4a3412021-04-14 15:38:27 +020056/*
Michal Vasko79a7a872022-06-17 09:00:48 +020057 * yang
58 */
59extern const struct lyplg_type_record plugins_instanceid_keys[];
60
61/*
Michal Vaskode4a3412021-04-14 15:38:27 +020062 * ietf-inet-types
63 */
Michal Vasko3159e782021-05-03 15:12:35 +020064extern const struct lyplg_type_record plugins_ipv4_address[];
Michal Vasko82bf15e2021-05-06 16:01:56 +020065extern const struct lyplg_type_record plugins_ipv4_address_no_zone[];
Michal Vasko7caa3e62021-05-03 14:59:25 +020066extern const struct lyplg_type_record plugins_ipv6_address[];
Michal Vasko18a4a732021-05-06 16:21:44 +020067extern const struct lyplg_type_record plugins_ipv6_address_no_zone[];
Michal Vasko15dc9fa2021-05-03 14:33:05 +020068extern const struct lyplg_type_record plugins_ipv4_prefix[];
69extern const struct lyplg_type_record plugins_ipv6_prefix[];
Michal Vasko3e52de52021-04-13 13:45:55 +020070
Radek Krejci3e6632f2021-03-22 22:08:21 +010071/*
Michal Vaskode4a3412021-04-14 15:38:27 +020072 * ietf-yang-types
73 */
74extern const struct lyplg_type_record plugins_date_and_time[];
Michal Vasko30e75a72023-08-08 11:35:54 +020075extern const struct lyplg_type_record plugins_hex_string[];
Michal Vaskode4a3412021-04-14 15:38:27 +020076extern const struct lyplg_type_record plugins_xpath10[];
77
78/*
Michal Vasko7a53c7d2021-08-06 11:28:57 +020079 * ietf-netconf-acm
80 */
81extern const struct lyplg_type_record plugins_node_instanceid[];
82
83/*
Radek Krejci3e6632f2021-03-22 22:08:21 +010084 * internal extension plugins records
85 */
86extern struct lyplg_ext_record plugins_metadata[];
87extern struct lyplg_ext_record plugins_nacm[];
88extern struct lyplg_ext_record plugins_yangdata[];
tadeas-vintrlik2aa36b42021-11-03 13:07:34 +010089extern struct lyplg_ext_record plugins_schema_mount[];
Michal Vaskoedb0fa52022-10-04 10:36:00 +020090extern struct lyplg_ext_record plugins_structure[];
Radek Krejci3e6632f2021-03-22 22:08:21 +010091
92static pthread_mutex_t plugins_guard = PTHREAD_MUTEX_INITIALIZER;
93
94/**
95 * @brief Counter for currently present contexts able to refer to the loaded plugins.
96 *
97 * Plugins are shared among all the created contexts. They are loaded with the creation of the very first context and
98 * unloaded with the destroy of the last context. Therefore, to reload the list of plugins, all the contexts must be
99 * destroyed and with the creation of a first new context after that, the plugins will be reloaded.
100 */
101static uint32_t context_refcount = 0;
102
103/**
104 * @brief Record describing an implemented extension.
105 *
106 * Matches ::lyplg_ext_record and ::lyplg_type_record
107 */
108struct lyplg_record {
109 const char *module; /**< name of the module where the extension/type is defined */
110 const char *revision; /**< optional module revision - if not specified, the plugin applies to any revision,
111 which is not an optimal approach due to a possible future revisions of the module.
112 Instead, there should be defined multiple items in the plugins list, each with the
113 different revision, but all with the same pointer to the plugin functions. The
114 only valid use case for the NULL revision is the case the module has no revision. */
115 const char *name; /**< name of the extension/typedef */
116 int8_t plugin[]; /**< specific plugin type's data - ::lyplg_ext or ::lyplg_type */
117};
118
Michal Vasko9e2bc702021-06-09 11:43:36 +0200119#ifndef STATIC
Radek Krejcibf940f92021-03-24 21:04:13 +0100120static struct ly_set plugins_handlers = {0};
Michal Vasko9e2bc702021-06-09 11:43:36 +0200121#endif
Radek Krejci3e6632f2021-03-22 22:08:21 +0100122static struct ly_set plugins_types = {0};
123static struct ly_set plugins_extensions = {0};
124
125/**
126 * @brief Iterate over list of loaded plugins of the given @p type.
127 *
128 * @param[in] type Type of the plugins to iterate.
129 * @param[in,out] index The iterator - set to 0 for the first call.
130 * @return The plugin records, NULL if no more record is available.
131 */
132static struct lyplg_record *
133plugins_iter(enum LYPLG type, uint32_t *index)
134{
135 struct ly_set *plugins;
136
137 assert(index);
138
139 if (type == LYPLG_EXTENSION) {
140 plugins = &plugins_extensions;
141 } else {
142 plugins = &plugins_types;
143 }
144
145 if (*index == plugins->count) {
146 return NULL;
147 }
148
149 *index += 1;
150 return plugins->objs[*index - 1];
151}
152
Michal Vaskoc0c64ae2022-10-06 10:15:23 +0200153static void *
154lyplg_record_find(enum LYPLG type, const char *module, const char *revision, const char *name)
Radek Krejci3e6632f2021-03-22 22:08:21 +0100155{
156 uint32_t i = 0;
157 struct lyplg_record *item;
158
159 assert(module);
160 assert(name);
161
162 while ((item = plugins_iter(type, &i)) != NULL) {
163 if (!strcmp(item->module, module) && !strcmp(item->name, name)) {
164 if (item->revision && revision && strcmp(item->revision, revision)) {
165 continue;
166 } else if (!revision && item->revision) {
167 continue;
168 }
169
Michal Vaskoc0c64ae2022-10-06 10:15:23 +0200170 return item;
Radek Krejci3e6632f2021-03-22 22:08:21 +0100171 }
172 }
173
174 return NULL;
175}
176
Michal Vaskoc0c64ae2022-10-06 10:15:23 +0200177struct lyplg_type *
178lyplg_type_plugin_find(const char *module, const char *revision, const char *name)
179{
180 struct lyplg_record *record;
181
182 record = lyplg_record_find(LYPLG_TYPE, module, revision, name);
183 return record ? &((struct lyplg_type_record *)record)->plugin : NULL;
184}
185
186struct lyplg_ext_record *
187lyplg_ext_record_find(const char *module, const char *revision, const char *name)
188{
189 return lyplg_record_find(LYPLG_EXTENSION, module, revision, name);
190}
191
Radek Krejci3e6632f2021-03-22 22:08:21 +0100192/**
193 * @brief Insert the provided extension plugin records into the internal set of extension plugins for use by libyang.
194 *
195 * @param[in] recs An array of plugin records provided by the plugin implementation. The array must be terminated by a zeroed
196 * record.
197 * @return LY_SUCCESS in case of success
198 * @return LY_EINVAL for invalid information in @p recs.
199 * @return LY_EMEM in case of memory allocation failure.
200 */
201static LY_ERR
202plugins_insert(enum LYPLG type, const void *recs)
203{
204 if (!recs) {
205 return LY_SUCCESS;
206 }
207
208 if (type == LYPLG_EXTENSION) {
209 const struct lyplg_ext_record *rec = (const struct lyplg_ext_record *)recs;
210
211 for (uint32_t i = 0; rec[i].name; i++) {
212 LY_CHECK_RET(ly_set_add(&plugins_extensions, (void *)&rec[i], 0, NULL));
213 }
Radek Krejcibf940f92021-03-24 21:04:13 +0100214 } else { /* LYPLG_TYPE */
Radek Krejci3e6632f2021-03-22 22:08:21 +0100215 const struct lyplg_type_record *rec = (const struct lyplg_type_record *)recs;
216
217 for (uint32_t i = 0; rec[i].name; i++) {
218 LY_CHECK_RET(ly_set_add(&plugins_types, (void *)&rec[i], 0, NULL));
219 }
220 }
221
222 return LY_SUCCESS;
223}
224
Michal Vasko9e2bc702021-06-09 11:43:36 +0200225#ifndef STATIC
226
Radek Krejci3e6632f2021-03-22 22:08:21 +0100227static void
Michal Vaskoe43a34e2021-04-13 13:43:04 +0200228lyplg_close_cb(void *handle)
229{
230 dlclose(handle);
231}
232
233static void
Radek Krejci3e6632f2021-03-22 22:08:21 +0100234lyplg_clean_(void)
235{
236 if (--context_refcount) {
237 /* there is still some other context, do not remove the plugins */
238 return;
239 }
240
241 ly_set_erase(&plugins_types, NULL);
242 ly_set_erase(&plugins_extensions, NULL);
Michal Vaskoe43a34e2021-04-13 13:43:04 +0200243 ly_set_erase(&plugins_handlers, lyplg_close_cb);
Radek Krejci3e6632f2021-03-22 22:08:21 +0100244}
245
Michal Vasko9e2bc702021-06-09 11:43:36 +0200246#endif
247
Radek Krejci3e6632f2021-03-22 22:08:21 +0100248void
249lyplg_clean(void)
250{
Michal Vasko9e2bc702021-06-09 11:43:36 +0200251#ifndef STATIC
Radek Krejci3e6632f2021-03-22 22:08:21 +0100252 pthread_mutex_lock(&plugins_guard);
253 lyplg_clean_();
254 pthread_mutex_unlock(&plugins_guard);
Michal Vasko9e2bc702021-06-09 11:43:36 +0200255#endif
Radek Krejci3e6632f2021-03-22 22:08:21 +0100256}
257
Michal Vasko9e2bc702021-06-09 11:43:36 +0200258#ifndef STATIC
259
260/**
261 * @brief Just a variadic data to cover extension and type plugins by a single ::plugins_load() function.
262 *
263 * The values are taken from ::LY_PLUGINS_EXTENSIONS and ::LYPLG_TYPES macros.
264 */
265static const struct {
266 const char *id; /**< string identifier: type/extension */
267 const char *apiver_var; /**< expected variable name holding API version value */
268 const char *plugins_var; /**< expected variable name holding plugin records */
269 const char *envdir; /**< environment variable containing directory with the plugins */
270 const char *dir; /**< default directory with the plugins (has less priority than envdir) */
271 uint32_t apiver; /**< expected API version */
272} plugins_load_info[] = {
273 { /* LYPLG_TYPE */
274 .id = "type",
275 .apiver_var = "plugins_types_apiver__",
276 .plugins_var = "plugins_types__",
277 .envdir = "LIBYANG_TYPES_PLUGINS_DIR",
278 .dir = LYPLG_TYPE_DIR,
279 .apiver = LYPLG_TYPE_API_VERSION
280 }, {/* LYPLG_EXTENSION */
281 .id = "extension",
282 .apiver_var = "plugins_extensions_apiver__",
283 .plugins_var = "plugins_extensions__",
284 .envdir = "LIBYANG_EXTENSIONS_PLUGINS_DIR",
285 .dir = LYPLG_EXT_DIR,
286 .apiver = LYPLG_EXT_API_VERSION
287 }
288};
289
Radek Krejcibf940f92021-03-24 21:04:13 +0100290/**
291 * @brief Get the expected plugin objects from the loaded dynamic object and add the defined plugins into the lists of
292 * available extensions/types plugins.
293 *
294 * @param[in] dlhandler Loaded dynamic library handler.
295 * @param[in] pathname Path of the loaded library for logging.
296 * @param[in] type Type of the plugins to get from the dynamic library. Note that a single library can hold both types
297 * and extensions plugins implementations, so this function should be called twice (once for each plugin type) with
298 * different @p type values
299 * @return LY_ERR values.
300 */
301static LY_ERR
302plugins_load(void *dlhandler, const char *pathname, enum LYPLG type)
303{
304 const void *plugins;
305 uint32_t *version;
306
307 /* type plugin */
308 version = dlsym(dlhandler, plugins_load_info[type].apiver_var);
309 if (version) {
310 /* check version ... */
311 if (*version != plugins_load_info[type].apiver) {
312 LOGERR(NULL, LY_EINVAL, "Processing user %s plugin \"%s\" failed, wrong API version - %d expected, %d found.",
313 plugins_load_info[type].id, pathname, plugins_load_info[type].apiver, *version);
314 return LY_EINVAL;
315 }
316
317 /* ... get types plugins information ... */
318 if (!(plugins = dlsym(dlhandler, plugins_load_info[type].plugins_var))) {
319 char *errstr = dlerror();
Michal Vasko26bbb272022-08-02 14:54:33 +0200320
Radek Krejcibf940f92021-03-24 21:04:13 +0100321 LOGERR(NULL, LY_EINVAL, "Processing user %s plugin \"%s\" failed, missing %s plugins information (%s).",
322 plugins_load_info[type].id, pathname, plugins_load_info[type].id, errstr);
323 return LY_EINVAL;
324 }
325
326 /* ... and load all the types plugins */
327 LY_CHECK_RET(plugins_insert(type, plugins));
328 }
329
330 return LY_SUCCESS;
331}
332
333static LY_ERR
334plugins_load_module(const char *pathname)
335{
336 LY_ERR ret = LY_SUCCESS;
337 void *dlhandler;
338 uint32_t types_count = 0, extensions_count = 0;
339
340 dlerror(); /* Clear any existing error */
341
342 dlhandler = dlopen(pathname, RTLD_NOW);
343 if (!dlhandler) {
344 LOGERR(NULL, LY_ESYS, "Loading \"%s\" as a plugin failed (%s).", pathname, dlerror());
345 return LY_ESYS;
346 }
347
348 if (ly_set_contains(&plugins_handlers, dlhandler, NULL)) {
349 /* the plugin is already loaded */
350 LOGVRB("Plugin \"%s\" already loaded.", pathname);
351
352 /* keep the correct refcount */
353 dlclose(dlhandler);
354 return LY_SUCCESS;
355 }
356
357 /* remember the current plugins lists for recovery */
358 types_count = plugins_types.count;
359 extensions_count = plugins_extensions.count;
360
361 /* type plugin */
362 ret = plugins_load(dlhandler, pathname, LYPLG_TYPE);
363 LY_CHECK_GOTO(ret, error);
364
365 /* extension plugin */
366 ret = plugins_load(dlhandler, pathname, LYPLG_EXTENSION);
367 LY_CHECK_GOTO(ret, error);
368
369 /* remember the dynamic plugin */
370 ret = ly_set_add(&plugins_handlers, dlhandler, 1, NULL);
371 LY_CHECK_GOTO(ret, error);
372
373 return LY_SUCCESS;
374
375error:
376 dlclose(dlhandler);
377
378 /* revert changes in the lists */
379 while (plugins_types.count > types_count) {
380 ly_set_rm_index(&plugins_types, plugins_types.count - 1, NULL);
381 }
382 while (plugins_extensions.count > extensions_count) {
383 ly_set_rm_index(&plugins_extensions, plugins_extensions.count - 1, NULL);
384 }
385
386 return ret;
387}
388
Radek Krejci968d7552021-03-26 20:33:51 +0100389static LY_ERR
390plugins_insert_dir(enum LYPLG type)
391{
392 LY_ERR ret = LY_SUCCESS;
393 const char *pluginsdir;
394 DIR *dir;
395 ly_bool default_dir = 0;
396
397 /* try to get the plugins directory from environment variable */
398 pluginsdir = getenv(plugins_load_info[type].envdir);
399 if (!pluginsdir) {
400 /* remember that we are going to a default dir and do not print warning if the directory doesn't exist */
401 default_dir = 1;
402 pluginsdir = plugins_load_info[type].dir;
403 }
404
405 dir = opendir(pluginsdir);
406 if (!dir) {
407 /* no directory (or no access to it), no extension plugins */
408 if (!default_dir || (errno != ENOENT)) {
409 LOGWRN(NULL, "Failed to open libyang %s plugins directory \"%s\" (%s).", plugins_load_info[type].id,
410 pluginsdir, strerror(errno));
411 }
412 } else {
413 struct dirent *file;
414
415 while ((file = readdir(dir))) {
416 size_t len;
417 char pathname[PATH_MAX];
418
419 /* required format of the filename is *LYPLG_SUFFIX */
420 len = strlen(file->d_name);
421 if ((len < LYPLG_SUFFIX_LEN + 1) || strcmp(&file->d_name[len - LYPLG_SUFFIX_LEN], LYPLG_SUFFIX)) {
422 continue;
423 }
424
425 /* and construct the filepath */
426 snprintf(pathname, PATH_MAX, "%s/%s", pluginsdir, file->d_name);
427
428 ret = plugins_load_module(pathname);
429 if (ret) {
430 break;
431 }
432 }
433 closedir(dir);
434 }
435
436 return ret;
437}
438
Michal Vasko9e2bc702021-06-09 11:43:36 +0200439#endif
440
Radek Krejci3e6632f2021-03-22 22:08:21 +0100441LY_ERR
442lyplg_init(void)
443{
444 LY_ERR ret;
445
446 pthread_mutex_lock(&plugins_guard);
447 /* let only the first context to initiate plugins, but let others wait for finishing the initiation */
448 if (context_refcount++) {
449 /* already initiated */
450 pthread_mutex_unlock(&plugins_guard);
451 return LY_SUCCESS;
452 }
453
454 /* internal types */
455 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_binary), error);
456 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_bits), error);
457 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_boolean), error);
458 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_decimal64), error);
459 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_empty), error);
460 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_enumeration), error);
461 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_identityref), error);
462 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_instanceid), error);
463 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_integer), error);
464 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_leafref), error);
465 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_string), error);
466 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_union), error);
467
Michal Vasko79a7a872022-06-17 09:00:48 +0200468 /* yang */
469 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_instanceid_keys), error);
470
Michal Vaskode4a3412021-04-14 15:38:27 +0200471 /* ietf-inet-types */
Michal Vasko3159e782021-05-03 15:12:35 +0200472 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_ipv4_address), error);
Michal Vasko82bf15e2021-05-06 16:01:56 +0200473 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_ipv4_address_no_zone), error);
Michal Vasko7caa3e62021-05-03 14:59:25 +0200474 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_ipv6_address), error);
Michal Vasko18a4a732021-05-06 16:21:44 +0200475 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_ipv6_address_no_zone), error);
Michal Vasko15dc9fa2021-05-03 14:33:05 +0200476 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_ipv4_prefix), error);
477 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_ipv6_prefix), error);
Michal Vasko3e52de52021-04-13 13:45:55 +0200478
Michal Vaskode4a3412021-04-14 15:38:27 +0200479 /* ietf-yang-types */
480 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_date_and_time), error);
Michal Vasko30e75a72023-08-08 11:35:54 +0200481 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_hex_string), error);
Michal Vaskode4a3412021-04-14 15:38:27 +0200482 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_xpath10), error);
483
Michal Vasko7a53c7d2021-08-06 11:28:57 +0200484 /* ietf-netconf-acm */
485 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_node_instanceid), error);
486
Radek Krejci3e6632f2021-03-22 22:08:21 +0100487 /* internal extensions */
488 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_EXTENSION, plugins_metadata), error);
489 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_EXTENSION, plugins_nacm), error);
490 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_EXTENSION, plugins_yangdata), error);
tadeas-vintrlik2aa36b42021-11-03 13:07:34 +0100491 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_EXTENSION, plugins_schema_mount), error);
Michal Vaskoedb0fa52022-10-04 10:36:00 +0200492 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_EXTENSION, plugins_structure), error);
Radek Krejci3e6632f2021-03-22 22:08:21 +0100493
Michal Vasko9e2bc702021-06-09 11:43:36 +0200494#ifndef STATIC
Radek Krejci968d7552021-03-26 20:33:51 +0100495 /* external types */
496 LY_CHECK_GOTO(ret = plugins_insert_dir(LYPLG_TYPE), error);
497
498 /* external extensions */
499 LY_CHECK_GOTO(ret = plugins_insert_dir(LYPLG_EXTENSION), error);
Michal Vasko9e2bc702021-06-09 11:43:36 +0200500#endif
Radek Krejci968d7552021-03-26 20:33:51 +0100501
Radek Krejci3e6632f2021-03-22 22:08:21 +0100502 /* initiation done, wake-up possibly waiting threads creating another contexts */
503 pthread_mutex_unlock(&plugins_guard);
504
505 return LY_SUCCESS;
506
507error:
508 /* initiation was not successful - cleanup (and let others to try) */
Michal Vasko9e2bc702021-06-09 11:43:36 +0200509#ifndef STATIC
Radek Krejci3e6632f2021-03-22 22:08:21 +0100510 lyplg_clean_();
Michal Vasko9e2bc702021-06-09 11:43:36 +0200511#endif
Radek Krejci3e6632f2021-03-22 22:08:21 +0100512 pthread_mutex_unlock(&plugins_guard);
513
514 if (ret == LY_EINVAL) {
515 /* all the plugins here are internal, invalid record actually means an internal libyang error */
516 ret = LY_EINT;
517 }
518 return ret;
519}
Radek Krejcibf940f92021-03-24 21:04:13 +0100520
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100521LIBYANG_API_DEF LY_ERR
Radek Krejcibf940f92021-03-24 21:04:13 +0100522lyplg_add(const char *pathname)
523{
Michal Vasko9e2bc702021-06-09 11:43:36 +0200524#ifdef STATIC
525 (void)pathname;
526
527 LOGERR(NULL, LY_EINVAL, "Plugins are not supported in statically built library.");
528 return LY_EINVAL;
Jan Kundrát323c3122021-12-14 11:44:57 +0100529#elif defined (_WIN32)
530 (void)pathname;
531
532 LOGERR(NULL, LY_EINVAL, "Plugins are not (yet) supported on Windows.");
533 return LY_EINVAL;
Michal Vasko9e2bc702021-06-09 11:43:36 +0200534#else
Radek Krejcibf940f92021-03-24 21:04:13 +0100535 LY_ERR ret = LY_SUCCESS;
536
537 LY_CHECK_ARG_RET(NULL, pathname, LY_EINVAL);
538
539 /* works only in case a context exists */
540 pthread_mutex_lock(&plugins_guard);
541 if (!context_refcount) {
542 /* no context */
543 pthread_mutex_unlock(&plugins_guard);
544 LOGERR(NULL, LY_EDENIED, "To add a plugin, at least one context must exists.");
545 return LY_EDENIED;
546 }
547
548 ret = plugins_load_module(pathname);
549
550 pthread_mutex_unlock(&plugins_guard);
551
552 return ret;
Michal Vasko9e2bc702021-06-09 11:43:36 +0200553#endif
Radek Krejcibf940f92021-03-24 21:04:13 +0100554}