blob: ab264f0a3abfc6ebfc8846b3cb8929f215b9d65e [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/*
aPiecek6cf1d162023-11-08 16:07:00 +010084 * lyds_tree
85 */
86extern const struct lyplg_type_record plugins_lyds_tree[];
87
88/*
Radek Krejci3e6632f2021-03-22 22:08:21 +010089 * internal extension plugins records
90 */
91extern struct lyplg_ext_record plugins_metadata[];
92extern struct lyplg_ext_record plugins_nacm[];
93extern struct lyplg_ext_record plugins_yangdata[];
tadeas-vintrlik2aa36b42021-11-03 13:07:34 +010094extern struct lyplg_ext_record plugins_schema_mount[];
Michal Vaskoedb0fa52022-10-04 10:36:00 +020095extern struct lyplg_ext_record plugins_structure[];
Radek Krejci3e6632f2021-03-22 22:08:21 +010096
97static pthread_mutex_t plugins_guard = PTHREAD_MUTEX_INITIALIZER;
98
99/**
100 * @brief Counter for currently present contexts able to refer to the loaded plugins.
101 *
102 * Plugins are shared among all the created contexts. They are loaded with the creation of the very first context and
103 * unloaded with the destroy of the last context. Therefore, to reload the list of plugins, all the contexts must be
104 * destroyed and with the creation of a first new context after that, the plugins will be reloaded.
105 */
106static uint32_t context_refcount = 0;
107
108/**
109 * @brief Record describing an implemented extension.
110 *
111 * Matches ::lyplg_ext_record and ::lyplg_type_record
112 */
113struct lyplg_record {
114 const char *module; /**< name of the module where the extension/type is defined */
115 const char *revision; /**< optional module revision - if not specified, the plugin applies to any revision,
116 which is not an optimal approach due to a possible future revisions of the module.
117 Instead, there should be defined multiple items in the plugins list, each with the
118 different revision, but all with the same pointer to the plugin functions. The
119 only valid use case for the NULL revision is the case the module has no revision. */
120 const char *name; /**< name of the extension/typedef */
121 int8_t plugin[]; /**< specific plugin type's data - ::lyplg_ext or ::lyplg_type */
122};
123
Michal Vasko9e2bc702021-06-09 11:43:36 +0200124#ifndef STATIC
Radek Krejcibf940f92021-03-24 21:04:13 +0100125static struct ly_set plugins_handlers = {0};
Michal Vasko9e2bc702021-06-09 11:43:36 +0200126#endif
Radek Krejci3e6632f2021-03-22 22:08:21 +0100127static struct ly_set plugins_types = {0};
128static struct ly_set plugins_extensions = {0};
129
130/**
131 * @brief Iterate over list of loaded plugins of the given @p type.
132 *
133 * @param[in] type Type of the plugins to iterate.
134 * @param[in,out] index The iterator - set to 0 for the first call.
135 * @return The plugin records, NULL if no more record is available.
136 */
137static struct lyplg_record *
138plugins_iter(enum LYPLG type, uint32_t *index)
139{
140 struct ly_set *plugins;
141
142 assert(index);
143
144 if (type == LYPLG_EXTENSION) {
145 plugins = &plugins_extensions;
146 } else {
147 plugins = &plugins_types;
148 }
149
150 if (*index == plugins->count) {
151 return NULL;
152 }
153
154 *index += 1;
155 return plugins->objs[*index - 1];
156}
157
Michal Vaskoc0c64ae2022-10-06 10:15:23 +0200158static void *
159lyplg_record_find(enum LYPLG type, const char *module, const char *revision, const char *name)
Radek Krejci3e6632f2021-03-22 22:08:21 +0100160{
161 uint32_t i = 0;
162 struct lyplg_record *item;
163
164 assert(module);
165 assert(name);
166
167 while ((item = plugins_iter(type, &i)) != NULL) {
168 if (!strcmp(item->module, module) && !strcmp(item->name, name)) {
169 if (item->revision && revision && strcmp(item->revision, revision)) {
170 continue;
171 } else if (!revision && item->revision) {
172 continue;
173 }
174
Michal Vaskoc0c64ae2022-10-06 10:15:23 +0200175 return item;
Radek Krejci3e6632f2021-03-22 22:08:21 +0100176 }
177 }
178
179 return NULL;
180}
181
Michal Vaskoc0c64ae2022-10-06 10:15:23 +0200182struct lyplg_type *
183lyplg_type_plugin_find(const char *module, const char *revision, const char *name)
184{
185 struct lyplg_record *record;
186
187 record = lyplg_record_find(LYPLG_TYPE, module, revision, name);
188 return record ? &((struct lyplg_type_record *)record)->plugin : NULL;
189}
190
191struct lyplg_ext_record *
192lyplg_ext_record_find(const char *module, const char *revision, const char *name)
193{
194 return lyplg_record_find(LYPLG_EXTENSION, module, revision, name);
195}
196
Radek Krejci3e6632f2021-03-22 22:08:21 +0100197/**
198 * @brief Insert the provided extension plugin records into the internal set of extension plugins for use by libyang.
199 *
200 * @param[in] recs An array of plugin records provided by the plugin implementation. The array must be terminated by a zeroed
201 * record.
202 * @return LY_SUCCESS in case of success
203 * @return LY_EINVAL for invalid information in @p recs.
204 * @return LY_EMEM in case of memory allocation failure.
205 */
206static LY_ERR
207plugins_insert(enum LYPLG type, const void *recs)
208{
209 if (!recs) {
210 return LY_SUCCESS;
211 }
212
213 if (type == LYPLG_EXTENSION) {
214 const struct lyplg_ext_record *rec = (const struct lyplg_ext_record *)recs;
215
216 for (uint32_t i = 0; rec[i].name; i++) {
217 LY_CHECK_RET(ly_set_add(&plugins_extensions, (void *)&rec[i], 0, NULL));
218 }
Radek Krejcibf940f92021-03-24 21:04:13 +0100219 } else { /* LYPLG_TYPE */
Radek Krejci3e6632f2021-03-22 22:08:21 +0100220 const struct lyplg_type_record *rec = (const struct lyplg_type_record *)recs;
221
222 for (uint32_t i = 0; rec[i].name; i++) {
223 LY_CHECK_RET(ly_set_add(&plugins_types, (void *)&rec[i], 0, NULL));
224 }
225 }
226
227 return LY_SUCCESS;
228}
229
Michal Vasko9e2bc702021-06-09 11:43:36 +0200230#ifndef STATIC
231
Radek Krejci3e6632f2021-03-22 22:08:21 +0100232static void
Michal Vaskoe43a34e2021-04-13 13:43:04 +0200233lyplg_close_cb(void *handle)
234{
235 dlclose(handle);
236}
237
238static void
Radek Krejci3e6632f2021-03-22 22:08:21 +0100239lyplg_clean_(void)
240{
241 if (--context_refcount) {
242 /* there is still some other context, do not remove the plugins */
243 return;
244 }
245
246 ly_set_erase(&plugins_types, NULL);
247 ly_set_erase(&plugins_extensions, NULL);
Michal Vaskoe43a34e2021-04-13 13:43:04 +0200248 ly_set_erase(&plugins_handlers, lyplg_close_cb);
Radek Krejci3e6632f2021-03-22 22:08:21 +0100249}
250
Michal Vasko9e2bc702021-06-09 11:43:36 +0200251#endif
252
Radek Krejci3e6632f2021-03-22 22:08:21 +0100253void
254lyplg_clean(void)
255{
Michal Vasko9e2bc702021-06-09 11:43:36 +0200256#ifndef STATIC
Radek Krejci3e6632f2021-03-22 22:08:21 +0100257 pthread_mutex_lock(&plugins_guard);
258 lyplg_clean_();
259 pthread_mutex_unlock(&plugins_guard);
Michal Vasko9e2bc702021-06-09 11:43:36 +0200260#endif
Radek Krejci3e6632f2021-03-22 22:08:21 +0100261}
262
Michal Vasko9e2bc702021-06-09 11:43:36 +0200263#ifndef STATIC
264
265/**
266 * @brief Just a variadic data to cover extension and type plugins by a single ::plugins_load() function.
267 *
268 * The values are taken from ::LY_PLUGINS_EXTENSIONS and ::LYPLG_TYPES macros.
269 */
270static const struct {
271 const char *id; /**< string identifier: type/extension */
272 const char *apiver_var; /**< expected variable name holding API version value */
273 const char *plugins_var; /**< expected variable name holding plugin records */
274 const char *envdir; /**< environment variable containing directory with the plugins */
275 const char *dir; /**< default directory with the plugins (has less priority than envdir) */
276 uint32_t apiver; /**< expected API version */
277} plugins_load_info[] = {
278 { /* LYPLG_TYPE */
279 .id = "type",
280 .apiver_var = "plugins_types_apiver__",
281 .plugins_var = "plugins_types__",
282 .envdir = "LIBYANG_TYPES_PLUGINS_DIR",
283 .dir = LYPLG_TYPE_DIR,
284 .apiver = LYPLG_TYPE_API_VERSION
285 }, {/* LYPLG_EXTENSION */
286 .id = "extension",
287 .apiver_var = "plugins_extensions_apiver__",
288 .plugins_var = "plugins_extensions__",
289 .envdir = "LIBYANG_EXTENSIONS_PLUGINS_DIR",
290 .dir = LYPLG_EXT_DIR,
291 .apiver = LYPLG_EXT_API_VERSION
292 }
293};
294
Radek Krejcibf940f92021-03-24 21:04:13 +0100295/**
296 * @brief Get the expected plugin objects from the loaded dynamic object and add the defined plugins into the lists of
297 * available extensions/types plugins.
298 *
299 * @param[in] dlhandler Loaded dynamic library handler.
300 * @param[in] pathname Path of the loaded library for logging.
301 * @param[in] type Type of the plugins to get from the dynamic library. Note that a single library can hold both types
302 * and extensions plugins implementations, so this function should be called twice (once for each plugin type) with
303 * different @p type values
304 * @return LY_ERR values.
305 */
306static LY_ERR
307plugins_load(void *dlhandler, const char *pathname, enum LYPLG type)
308{
309 const void *plugins;
310 uint32_t *version;
311
312 /* type plugin */
313 version = dlsym(dlhandler, plugins_load_info[type].apiver_var);
314 if (version) {
315 /* check version ... */
316 if (*version != plugins_load_info[type].apiver) {
317 LOGERR(NULL, LY_EINVAL, "Processing user %s plugin \"%s\" failed, wrong API version - %d expected, %d found.",
318 plugins_load_info[type].id, pathname, plugins_load_info[type].apiver, *version);
319 return LY_EINVAL;
320 }
321
322 /* ... get types plugins information ... */
323 if (!(plugins = dlsym(dlhandler, plugins_load_info[type].plugins_var))) {
324 char *errstr = dlerror();
Michal Vasko26bbb272022-08-02 14:54:33 +0200325
Radek Krejcibf940f92021-03-24 21:04:13 +0100326 LOGERR(NULL, LY_EINVAL, "Processing user %s plugin \"%s\" failed, missing %s plugins information (%s).",
327 plugins_load_info[type].id, pathname, plugins_load_info[type].id, errstr);
328 return LY_EINVAL;
329 }
330
331 /* ... and load all the types plugins */
332 LY_CHECK_RET(plugins_insert(type, plugins));
333 }
334
335 return LY_SUCCESS;
336}
337
338static LY_ERR
339plugins_load_module(const char *pathname)
340{
341 LY_ERR ret = LY_SUCCESS;
342 void *dlhandler;
343 uint32_t types_count = 0, extensions_count = 0;
344
345 dlerror(); /* Clear any existing error */
346
347 dlhandler = dlopen(pathname, RTLD_NOW);
348 if (!dlhandler) {
349 LOGERR(NULL, LY_ESYS, "Loading \"%s\" as a plugin failed (%s).", pathname, dlerror());
350 return LY_ESYS;
351 }
352
353 if (ly_set_contains(&plugins_handlers, dlhandler, NULL)) {
354 /* the plugin is already loaded */
355 LOGVRB("Plugin \"%s\" already loaded.", pathname);
356
357 /* keep the correct refcount */
358 dlclose(dlhandler);
359 return LY_SUCCESS;
360 }
361
362 /* remember the current plugins lists for recovery */
363 types_count = plugins_types.count;
364 extensions_count = plugins_extensions.count;
365
366 /* type plugin */
367 ret = plugins_load(dlhandler, pathname, LYPLG_TYPE);
368 LY_CHECK_GOTO(ret, error);
369
370 /* extension plugin */
371 ret = plugins_load(dlhandler, pathname, LYPLG_EXTENSION);
372 LY_CHECK_GOTO(ret, error);
373
374 /* remember the dynamic plugin */
375 ret = ly_set_add(&plugins_handlers, dlhandler, 1, NULL);
376 LY_CHECK_GOTO(ret, error);
377
378 return LY_SUCCESS;
379
380error:
381 dlclose(dlhandler);
382
383 /* revert changes in the lists */
384 while (plugins_types.count > types_count) {
385 ly_set_rm_index(&plugins_types, plugins_types.count - 1, NULL);
386 }
387 while (plugins_extensions.count > extensions_count) {
388 ly_set_rm_index(&plugins_extensions, plugins_extensions.count - 1, NULL);
389 }
390
391 return ret;
392}
393
Radek Krejci968d7552021-03-26 20:33:51 +0100394static LY_ERR
395plugins_insert_dir(enum LYPLG type)
396{
397 LY_ERR ret = LY_SUCCESS;
398 const char *pluginsdir;
399 DIR *dir;
400 ly_bool default_dir = 0;
401
402 /* try to get the plugins directory from environment variable */
403 pluginsdir = getenv(plugins_load_info[type].envdir);
404 if (!pluginsdir) {
405 /* remember that we are going to a default dir and do not print warning if the directory doesn't exist */
406 default_dir = 1;
407 pluginsdir = plugins_load_info[type].dir;
408 }
409
410 dir = opendir(pluginsdir);
411 if (!dir) {
412 /* no directory (or no access to it), no extension plugins */
413 if (!default_dir || (errno != ENOENT)) {
414 LOGWRN(NULL, "Failed to open libyang %s plugins directory \"%s\" (%s).", plugins_load_info[type].id,
415 pluginsdir, strerror(errno));
416 }
417 } else {
418 struct dirent *file;
419
420 while ((file = readdir(dir))) {
421 size_t len;
422 char pathname[PATH_MAX];
423
424 /* required format of the filename is *LYPLG_SUFFIX */
425 len = strlen(file->d_name);
426 if ((len < LYPLG_SUFFIX_LEN + 1) || strcmp(&file->d_name[len - LYPLG_SUFFIX_LEN], LYPLG_SUFFIX)) {
427 continue;
428 }
429
430 /* and construct the filepath */
431 snprintf(pathname, PATH_MAX, "%s/%s", pluginsdir, file->d_name);
432
433 ret = plugins_load_module(pathname);
434 if (ret) {
435 break;
436 }
437 }
438 closedir(dir);
439 }
440
441 return ret;
442}
443
Michal Vasko9e2bc702021-06-09 11:43:36 +0200444#endif
445
Radek Krejci3e6632f2021-03-22 22:08:21 +0100446LY_ERR
Michal Vasko6a027db2024-02-21 09:55:34 +0100447lyplg_init(ly_bool builtin_type_plugins_only)
Radek Krejci3e6632f2021-03-22 22:08:21 +0100448{
449 LY_ERR ret;
450
451 pthread_mutex_lock(&plugins_guard);
452 /* let only the first context to initiate plugins, but let others wait for finishing the initiation */
453 if (context_refcount++) {
454 /* already initiated */
455 pthread_mutex_unlock(&plugins_guard);
456 return LY_SUCCESS;
457 }
458
459 /* internal types */
460 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_binary), error);
461 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_bits), error);
462 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_boolean), error);
463 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_decimal64), error);
464 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_empty), error);
465 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_enumeration), error);
466 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_identityref), error);
467 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_instanceid), error);
468 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_integer), error);
469 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_leafref), error);
470 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_string), error);
471 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_union), error);
472
Michal Vasko6a027db2024-02-21 09:55:34 +0100473 if (!builtin_type_plugins_only) {
stewegd4cde642024-02-21 08:34:16 +0100474 /* yang */
475 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_instanceid_keys), error);
Michal Vasko79a7a872022-06-17 09:00:48 +0200476
stewegd4cde642024-02-21 08:34:16 +0100477 /* ietf-inet-types */
478 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_ipv4_address), error);
479 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_ipv4_address_no_zone), error);
480 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_ipv6_address), error);
481 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_ipv6_address_no_zone), error);
482 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_ipv4_prefix), error);
483 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_ipv6_prefix), error);
Michal Vasko3e52de52021-04-13 13:45:55 +0200484
stewegd4cde642024-02-21 08:34:16 +0100485 /* ietf-yang-types */
486 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_date_and_time), error);
487 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_hex_string), error);
488 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_xpath10), error);
Michal Vaskode4a3412021-04-14 15:38:27 +0200489
stewegd4cde642024-02-21 08:34:16 +0100490 /* ietf-netconf-acm */
491 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_node_instanceid), error);
Michal Vasko7a53c7d2021-08-06 11:28:57 +0200492
stewegd4cde642024-02-21 08:34:16 +0100493 /* lyds_tree */
494 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_lyds_tree), error);
aPiecek6cf1d162023-11-08 16:07:00 +0100495
stewegd4cde642024-02-21 08:34:16 +0100496 /* internal extensions */
497 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_EXTENSION, plugins_metadata), error);
498 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_EXTENSION, plugins_nacm), error);
499 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_EXTENSION, plugins_yangdata), error);
500 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_EXTENSION, plugins_schema_mount), error);
501 LY_CHECK_GOTO(ret = plugins_insert(LYPLG_EXTENSION, plugins_structure), error);
502 }
Radek Krejci3e6632f2021-03-22 22:08:21 +0100503
Michal Vasko9e2bc702021-06-09 11:43:36 +0200504#ifndef STATIC
Radek Krejci968d7552021-03-26 20:33:51 +0100505 /* external types */
506 LY_CHECK_GOTO(ret = plugins_insert_dir(LYPLG_TYPE), error);
507
508 /* external extensions */
509 LY_CHECK_GOTO(ret = plugins_insert_dir(LYPLG_EXTENSION), error);
Michal Vasko9e2bc702021-06-09 11:43:36 +0200510#endif
Radek Krejci968d7552021-03-26 20:33:51 +0100511
Radek Krejci3e6632f2021-03-22 22:08:21 +0100512 /* initiation done, wake-up possibly waiting threads creating another contexts */
513 pthread_mutex_unlock(&plugins_guard);
514
515 return LY_SUCCESS;
516
517error:
518 /* initiation was not successful - cleanup (and let others to try) */
Michal Vasko9e2bc702021-06-09 11:43:36 +0200519#ifndef STATIC
Radek Krejci3e6632f2021-03-22 22:08:21 +0100520 lyplg_clean_();
Michal Vasko9e2bc702021-06-09 11:43:36 +0200521#endif
Radek Krejci3e6632f2021-03-22 22:08:21 +0100522 pthread_mutex_unlock(&plugins_guard);
523
524 if (ret == LY_EINVAL) {
525 /* all the plugins here are internal, invalid record actually means an internal libyang error */
526 ret = LY_EINT;
527 }
528 return ret;
529}
Radek Krejcibf940f92021-03-24 21:04:13 +0100530
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100531LIBYANG_API_DEF LY_ERR
Radek Krejcibf940f92021-03-24 21:04:13 +0100532lyplg_add(const char *pathname)
533{
Michal Vasko9e2bc702021-06-09 11:43:36 +0200534#ifdef STATIC
535 (void)pathname;
536
537 LOGERR(NULL, LY_EINVAL, "Plugins are not supported in statically built library.");
538 return LY_EINVAL;
Jan Kundrát323c3122021-12-14 11:44:57 +0100539#elif defined (_WIN32)
540 (void)pathname;
541
542 LOGERR(NULL, LY_EINVAL, "Plugins are not (yet) supported on Windows.");
543 return LY_EINVAL;
Michal Vasko9e2bc702021-06-09 11:43:36 +0200544#else
Radek Krejcibf940f92021-03-24 21:04:13 +0100545 LY_ERR ret = LY_SUCCESS;
546
547 LY_CHECK_ARG_RET(NULL, pathname, LY_EINVAL);
548
549 /* works only in case a context exists */
550 pthread_mutex_lock(&plugins_guard);
551 if (!context_refcount) {
552 /* no context */
553 pthread_mutex_unlock(&plugins_guard);
554 LOGERR(NULL, LY_EDENIED, "To add a plugin, at least one context must exists.");
555 return LY_EDENIED;
556 }
557
558 ret = plugins_load_module(pathname);
559
560 pthread_mutex_unlock(&plugins_guard);
561
562 return ret;
Michal Vasko9e2bc702021-06-09 11:43:36 +0200563#endif
Radek Krejcibf940f92021-03-24 21:04:13 +0100564}