blob: 70b23b82cf265dcf9e6d880d74396a82b6a5a147 [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[];
Radek Krejci3e6632f2021-03-22 22:08:21 +010087
88static pthread_mutex_t plugins_guard = PTHREAD_MUTEX_INITIALIZER;
89
90/**
91 * @brief Counter for currently present contexts able to refer to the loaded plugins.
92 *
93 * Plugins are shared among all the created contexts. They are loaded with the creation of the very first context and
94 * unloaded with the destroy of the last context. Therefore, to reload the list of plugins, all the contexts must be
95 * destroyed and with the creation of a first new context after that, the plugins will be reloaded.
96 */
97static uint32_t context_refcount = 0;
98
99/**
100 * @brief Record describing an implemented extension.
101 *
102 * Matches ::lyplg_ext_record and ::lyplg_type_record
103 */
104struct lyplg_record {
105 const char *module; /**< name of the module where the extension/type is defined */
106 const char *revision; /**< optional module revision - if not specified, the plugin applies to any revision,
107 which is not an optimal approach due to a possible future revisions of the module.
108 Instead, there should be defined multiple items in the plugins list, each with the
109 different revision, but all with the same pointer to the plugin functions. The
110 only valid use case for the NULL revision is the case the module has no revision. */
111 const char *name; /**< name of the extension/typedef */
112 int8_t plugin[]; /**< specific plugin type's data - ::lyplg_ext or ::lyplg_type */
113};
114
Michal Vasko9e2bc702021-06-09 11:43:36 +0200115#ifndef STATIC
Radek Krejcibf940f92021-03-24 21:04:13 +0100116static struct ly_set plugins_handlers = {0};
Michal Vasko9e2bc702021-06-09 11:43:36 +0200117#endif
Radek Krejci3e6632f2021-03-22 22:08:21 +0100118static struct ly_set plugins_types = {0};
119static struct ly_set plugins_extensions = {0};
120
121/**
122 * @brief Iterate over list of loaded plugins of the given @p type.
123 *
124 * @param[in] type Type of the plugins to iterate.
125 * @param[in,out] index The iterator - set to 0 for the first call.
126 * @return The plugin records, NULL if no more record is available.
127 */
128static struct lyplg_record *
129plugins_iter(enum LYPLG type, uint32_t *index)
130{
131 struct ly_set *plugins;
132
133 assert(index);
134
135 if (type == LYPLG_EXTENSION) {
136 plugins = &plugins_extensions;
137 } else {
138 plugins = &plugins_types;
139 }
140
141 if (*index == plugins->count) {
142 return NULL;
143 }
144
145 *index += 1;
146 return plugins->objs[*index - 1];
147}
148
149void *
150lyplg_find(enum LYPLG type, const char *module, const char *revision, const char *name)
151{
152 uint32_t i = 0;
153 struct lyplg_record *item;
154
155 assert(module);
156 assert(name);
157
158 while ((item = plugins_iter(type, &i)) != NULL) {
159 if (!strcmp(item->module, module) && !strcmp(item->name, name)) {
160 if (item->revision && revision && strcmp(item->revision, revision)) {
161 continue;
162 } else if (!revision && item->revision) {
163 continue;
164 }
165
166 return &item->plugin;
167 }
168 }
169
170 return NULL;
171}
172
173/**
174 * @brief Insert the provided extension plugin records into the internal set of extension plugins for use by libyang.
175 *
176 * @param[in] recs An array of plugin records provided by the plugin implementation. The array must be terminated by a zeroed
177 * record.
178 * @return LY_SUCCESS in case of success
179 * @return LY_EINVAL for invalid information in @p recs.
180 * @return LY_EMEM in case of memory allocation failure.
181 */
182static LY_ERR
183plugins_insert(enum LYPLG type, const void *recs)
184{
185 if (!recs) {
186 return LY_SUCCESS;
187 }
188
189 if (type == LYPLG_EXTENSION) {
190 const struct lyplg_ext_record *rec = (const struct lyplg_ext_record *)recs;
191
192 for (uint32_t i = 0; rec[i].name; i++) {
193 LY_CHECK_RET(ly_set_add(&plugins_extensions, (void *)&rec[i], 0, NULL));
194 }
Radek Krejcibf940f92021-03-24 21:04:13 +0100195 } else { /* LYPLG_TYPE */
Radek Krejci3e6632f2021-03-22 22:08:21 +0100196 const struct lyplg_type_record *rec = (const struct lyplg_type_record *)recs;
197
198 for (uint32_t i = 0; rec[i].name; i++) {
199 LY_CHECK_RET(ly_set_add(&plugins_types, (void *)&rec[i], 0, NULL));
200 }
201 }
202
203 return LY_SUCCESS;
204}
205
Michal Vasko9e2bc702021-06-09 11:43:36 +0200206#ifndef STATIC
207
Radek Krejci3e6632f2021-03-22 22:08:21 +0100208static void
Michal Vaskoe43a34e2021-04-13 13:43:04 +0200209lyplg_close_cb(void *handle)
210{
211 dlclose(handle);
212}
213
214static void
Radek Krejci3e6632f2021-03-22 22:08:21 +0100215lyplg_clean_(void)
216{
217 if (--context_refcount) {
218 /* there is still some other context, do not remove the plugins */
219 return;
220 }
221
222 ly_set_erase(&plugins_types, NULL);
223 ly_set_erase(&plugins_extensions, NULL);
Michal Vaskoe43a34e2021-04-13 13:43:04 +0200224 ly_set_erase(&plugins_handlers, lyplg_close_cb);
Radek Krejci3e6632f2021-03-22 22:08:21 +0100225}
226
Michal Vasko9e2bc702021-06-09 11:43:36 +0200227#endif
228
Radek Krejci3e6632f2021-03-22 22:08:21 +0100229void
230lyplg_clean(void)
231{
Michal Vasko9e2bc702021-06-09 11:43:36 +0200232#ifndef STATIC
Radek Krejci3e6632f2021-03-22 22:08:21 +0100233 pthread_mutex_lock(&plugins_guard);
234 lyplg_clean_();
235 pthread_mutex_unlock(&plugins_guard);
Michal Vasko9e2bc702021-06-09 11:43:36 +0200236#endif
Radek Krejci3e6632f2021-03-22 22:08:21 +0100237}
238
Michal Vasko9e2bc702021-06-09 11:43:36 +0200239#ifndef STATIC
240
241/**
242 * @brief Just a variadic data to cover extension and type plugins by a single ::plugins_load() function.
243 *
244 * The values are taken from ::LY_PLUGINS_EXTENSIONS and ::LYPLG_TYPES macros.
245 */
246static const struct {
247 const char *id; /**< string identifier: type/extension */
248 const char *apiver_var; /**< expected variable name holding API version value */
249 const char *plugins_var; /**< expected variable name holding plugin records */
250 const char *envdir; /**< environment variable containing directory with the plugins */
251 const char *dir; /**< default directory with the plugins (has less priority than envdir) */
252 uint32_t apiver; /**< expected API version */
253} plugins_load_info[] = {
254 { /* LYPLG_TYPE */
255 .id = "type",
256 .apiver_var = "plugins_types_apiver__",
257 .plugins_var = "plugins_types__",
258 .envdir = "LIBYANG_TYPES_PLUGINS_DIR",
259 .dir = LYPLG_TYPE_DIR,
260 .apiver = LYPLG_TYPE_API_VERSION
261 }, {/* LYPLG_EXTENSION */
262 .id = "extension",
263 .apiver_var = "plugins_extensions_apiver__",
264 .plugins_var = "plugins_extensions__",
265 .envdir = "LIBYANG_EXTENSIONS_PLUGINS_DIR",
266 .dir = LYPLG_EXT_DIR,
267 .apiver = LYPLG_EXT_API_VERSION
268 }
269};
270
Radek Krejcibf940f92021-03-24 21:04:13 +0100271/**
272 * @brief Get the expected plugin objects from the loaded dynamic object and add the defined plugins into the lists of
273 * available extensions/types plugins.
274 *
275 * @param[in] dlhandler Loaded dynamic library handler.
276 * @param[in] pathname Path of the loaded library for logging.
277 * @param[in] type Type of the plugins to get from the dynamic library. Note that a single library can hold both types
278 * and extensions plugins implementations, so this function should be called twice (once for each plugin type) with
279 * different @p type values
280 * @return LY_ERR values.
281 */
282static LY_ERR
283plugins_load(void *dlhandler, const char *pathname, enum LYPLG type)
284{
285 const void *plugins;
286 uint32_t *version;
287
288 /* type plugin */
289 version = dlsym(dlhandler, plugins_load_info[type].apiver_var);
290 if (version) {
291 /* check version ... */
292 if (*version != plugins_load_info[type].apiver) {
293 LOGERR(NULL, LY_EINVAL, "Processing user %s plugin \"%s\" failed, wrong API version - %d expected, %d found.",
294 plugins_load_info[type].id, pathname, plugins_load_info[type].apiver, *version);
295 return LY_EINVAL;
296 }
297
298 /* ... get types plugins information ... */
299 if (!(plugins = dlsym(dlhandler, plugins_load_info[type].plugins_var))) {
300 char *errstr = dlerror();
Michal Vasko26bbb272022-08-02 14:54:33 +0200301
Radek Krejcibf940f92021-03-24 21:04:13 +0100302 LOGERR(NULL, LY_EINVAL, "Processing user %s plugin \"%s\" failed, missing %s plugins information (%s).",
303 plugins_load_info[type].id, pathname, plugins_load_info[type].id, errstr);
304 return LY_EINVAL;
305 }
306
307 /* ... and load all the types plugins */
308 LY_CHECK_RET(plugins_insert(type, plugins));
309 }
310
311 return LY_SUCCESS;
312}
313
314static LY_ERR
315plugins_load_module(const char *pathname)
316{
317 LY_ERR ret = LY_SUCCESS;
318 void *dlhandler;
319 uint32_t types_count = 0, extensions_count = 0;
320
321 dlerror(); /* Clear any existing error */
322
323 dlhandler = dlopen(pathname, RTLD_NOW);
324 if (!dlhandler) {
325 LOGERR(NULL, LY_ESYS, "Loading \"%s\" as a plugin failed (%s).", pathname, dlerror());
326 return LY_ESYS;
327 }
328
329 if (ly_set_contains(&plugins_handlers, dlhandler, NULL)) {
330 /* the plugin is already loaded */
331 LOGVRB("Plugin \"%s\" already loaded.", pathname);
332
333 /* keep the correct refcount */
334 dlclose(dlhandler);
335 return LY_SUCCESS;
336 }
337
338 /* remember the current plugins lists for recovery */
339 types_count = plugins_types.count;
340 extensions_count = plugins_extensions.count;
341
342 /* type plugin */
343 ret = plugins_load(dlhandler, pathname, LYPLG_TYPE);
344 LY_CHECK_GOTO(ret, error);
345
346 /* extension plugin */
347 ret = plugins_load(dlhandler, pathname, LYPLG_EXTENSION);
348 LY_CHECK_GOTO(ret, error);
349
350 /* remember the dynamic plugin */
351 ret = ly_set_add(&plugins_handlers, dlhandler, 1, NULL);
352 LY_CHECK_GOTO(ret, error);
353
354 return LY_SUCCESS;
355
356error:
357 dlclose(dlhandler);
358
359 /* revert changes in the lists */
360 while (plugins_types.count > types_count) {
361 ly_set_rm_index(&plugins_types, plugins_types.count - 1, NULL);
362 }
363 while (plugins_extensions.count > extensions_count) {
364 ly_set_rm_index(&plugins_extensions, plugins_extensions.count - 1, NULL);
365 }
366
367 return ret;
368}
369
Radek Krejci968d7552021-03-26 20:33:51 +0100370static LY_ERR
371plugins_insert_dir(enum LYPLG type)
372{
373 LY_ERR ret = LY_SUCCESS;
374 const char *pluginsdir;
375 DIR *dir;
376 ly_bool default_dir = 0;
377
378 /* try to get the plugins directory from environment variable */
379 pluginsdir = getenv(plugins_load_info[type].envdir);
380 if (!pluginsdir) {
381 /* remember that we are going to a default dir and do not print warning if the directory doesn't exist */
382 default_dir = 1;
383 pluginsdir = plugins_load_info[type].dir;
384 }
385
386 dir = opendir(pluginsdir);
387 if (!dir) {
388 /* no directory (or no access to it), no extension plugins */
389 if (!default_dir || (errno != ENOENT)) {
390 LOGWRN(NULL, "Failed to open libyang %s plugins directory \"%s\" (%s).", plugins_load_info[type].id,
391 pluginsdir, strerror(errno));
392 }
393 } else {
394 struct dirent *file;
395
396 while ((file = readdir(dir))) {
397 size_t len;
398 char pathname[PATH_MAX];
399
400 /* required format of the filename is *LYPLG_SUFFIX */
401 len = strlen(file->d_name);
402 if ((len < LYPLG_SUFFIX_LEN + 1) || strcmp(&file->d_name[len - LYPLG_SUFFIX_LEN], LYPLG_SUFFIX)) {
403 continue;
404 }
405
406 /* and construct the filepath */
407 snprintf(pathname, PATH_MAX, "%s/%s", pluginsdir, file->d_name);
408
409 ret = plugins_load_module(pathname);
410 if (ret) {
411 break;
412 }
413 }
414 closedir(dir);
415 }
416
417 return ret;
418}
419
Michal Vasko9e2bc702021-06-09 11:43:36 +0200420#endif
421
Radek Krejci3e6632f2021-03-22 22:08:21 +0100422LY_ERR
423lyplg_init(void)
424{
425 LY_ERR ret;
426
427 pthread_mutex_lock(&plugins_guard);
428 /* let only the first context to initiate plugins, but let others wait for finishing the initiation */
429 if (context_refcount++) {
430 /* already initiated */
431 pthread_mutex_unlock(&plugins_guard);
432 return LY_SUCCESS;
433 }
434
435 /* internal types */
436 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_binary), error);
437 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_bits), error);
438 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_boolean), error);
439 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_decimal64), error);
440 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_empty), error);
441 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_enumeration), error);
442 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_identityref), error);
443 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_instanceid), error);
444 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_integer), error);
445 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_leafref), error);
446 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_string), error);
447 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_union), error);
448
Michal Vasko79a7a872022-06-17 09:00:48 +0200449 /* yang */
450 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_instanceid_keys), error);
451
Michal Vaskode4a3412021-04-14 15:38:27 +0200452 /* ietf-inet-types */
Michal Vasko3159e782021-05-03 15:12:35 +0200453 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_ipv4_address), error);
Michal Vasko82bf15e2021-05-06 16:01:56 +0200454 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_ipv4_address_no_zone), error);
Michal Vasko7caa3e62021-05-03 14:59:25 +0200455 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_ipv6_address), error);
Michal Vasko18a4a732021-05-06 16:21:44 +0200456 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_ipv6_address_no_zone), error);
Michal Vasko15dc9fa2021-05-03 14:33:05 +0200457 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_ipv4_prefix), error);
458 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_ipv6_prefix), error);
Michal Vasko3e52de52021-04-13 13:45:55 +0200459
Michal Vaskode4a3412021-04-14 15:38:27 +0200460 /* ietf-yang-types */
461 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_date_and_time), error);
Michal Vaskode4a3412021-04-14 15:38:27 +0200462 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_xpath10), error);
463
Michal Vasko7a53c7d2021-08-06 11:28:57 +0200464 /* ietf-netconf-acm */
465 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_node_instanceid), error);
466
Radek Krejci3e6632f2021-03-22 22:08:21 +0100467 /* internal extensions */
468 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_EXTENSION, plugins_metadata), error);
469 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_EXTENSION, plugins_nacm), error);
470 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_EXTENSION, plugins_yangdata), error);
tadeas-vintrlik2aa36b42021-11-03 13:07:34 +0100471 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_EXTENSION, plugins_schema_mount), error);
Radek Krejci3e6632f2021-03-22 22:08:21 +0100472
Michal Vasko9e2bc702021-06-09 11:43:36 +0200473#ifndef STATIC
Radek Krejci968d7552021-03-26 20:33:51 +0100474 /* external types */
475 LY_CHECK_GOTO(ret = plugins_insert_dir(LYPLG_TYPE), error);
476
477 /* external extensions */
478 LY_CHECK_GOTO(ret = plugins_insert_dir(LYPLG_EXTENSION), error);
Michal Vasko9e2bc702021-06-09 11:43:36 +0200479#endif
Radek Krejci968d7552021-03-26 20:33:51 +0100480
Radek Krejci3e6632f2021-03-22 22:08:21 +0100481 /* initiation done, wake-up possibly waiting threads creating another contexts */
482 pthread_mutex_unlock(&plugins_guard);
483
484 return LY_SUCCESS;
485
486error:
487 /* initiation was not successful - cleanup (and let others to try) */
Michal Vasko9e2bc702021-06-09 11:43:36 +0200488#ifndef STATIC
Radek Krejci3e6632f2021-03-22 22:08:21 +0100489 lyplg_clean_();
Michal Vasko9e2bc702021-06-09 11:43:36 +0200490#endif
Radek Krejci3e6632f2021-03-22 22:08:21 +0100491 pthread_mutex_unlock(&plugins_guard);
492
493 if (ret == LY_EINVAL) {
494 /* all the plugins here are internal, invalid record actually means an internal libyang error */
495 ret = LY_EINT;
496 }
497 return ret;
498}
Radek Krejcibf940f92021-03-24 21:04:13 +0100499
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100500LIBYANG_API_DEF LY_ERR
Radek Krejcibf940f92021-03-24 21:04:13 +0100501lyplg_add(const char *pathname)
502{
Michal Vasko9e2bc702021-06-09 11:43:36 +0200503#ifdef STATIC
504 (void)pathname;
505
506 LOGERR(NULL, LY_EINVAL, "Plugins are not supported in statically built library.");
507 return LY_EINVAL;
Jan Kundrát323c3122021-12-14 11:44:57 +0100508#elif defined (_WIN32)
509 (void)pathname;
510
511 LOGERR(NULL, LY_EINVAL, "Plugins are not (yet) supported on Windows.");
512 return LY_EINVAL;
Michal Vasko9e2bc702021-06-09 11:43:36 +0200513#else
Radek Krejcibf940f92021-03-24 21:04:13 +0100514 LY_ERR ret = LY_SUCCESS;
515
516 LY_CHECK_ARG_RET(NULL, pathname, LY_EINVAL);
517
518 /* works only in case a context exists */
519 pthread_mutex_lock(&plugins_guard);
520 if (!context_refcount) {
521 /* no context */
522 pthread_mutex_unlock(&plugins_guard);
523 LOGERR(NULL, LY_EDENIED, "To add a plugin, at least one context must exists.");
524 return LY_EDENIED;
525 }
526
527 ret = plugins_load_module(pathname);
528
529 pthread_mutex_unlock(&plugins_guard);
530
531 return ret;
Michal Vasko9e2bc702021-06-09 11:43:36 +0200532#endif
Radek Krejcibf940f92021-03-24 21:04:13 +0100533}