/src/libyang/src/plugins.c
Line | Count | Source (jump to first uncovered line) |
1 | | /** |
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 | | |
15 | | #define _GNU_SOURCE |
16 | | |
17 | | #include "plugins.h" |
18 | | #include "plugins_internal.h" |
19 | | |
20 | | #include <assert.h> |
21 | | #include <dirent.h> |
22 | | #ifndef STATIC |
23 | | # include <dlfcn.h> |
24 | | #endif |
25 | | #include <errno.h> |
26 | | #include <limits.h> |
27 | | #include <pthread.h> |
28 | | #include <stddef.h> |
29 | | #include <stdint.h> |
30 | | #include <stdio.h> |
31 | | #include <stdlib.h> |
32 | | #include <string.h> |
33 | | |
34 | | #include "ly_common.h" |
35 | | #include "ly_config.h" |
36 | | #include "plugins_exts.h" |
37 | | #include "plugins_types.h" |
38 | | #include "set.h" |
39 | | |
40 | | /* |
41 | | * internal type plugins records |
42 | | */ |
43 | | extern const struct lyplg_type_record plugins_binary[]; |
44 | | extern const struct lyplg_type_record plugins_bits[]; |
45 | | extern const struct lyplg_type_record plugins_boolean[]; |
46 | | extern const struct lyplg_type_record plugins_decimal64[]; |
47 | | extern const struct lyplg_type_record plugins_empty[]; |
48 | | extern const struct lyplg_type_record plugins_enumeration[]; |
49 | | extern const struct lyplg_type_record plugins_identityref[]; |
50 | | extern const struct lyplg_type_record plugins_instanceid[]; |
51 | | extern const struct lyplg_type_record plugins_integer[]; |
52 | | extern const struct lyplg_type_record plugins_leafref[]; |
53 | | extern const struct lyplg_type_record plugins_string[]; |
54 | | extern const struct lyplg_type_record plugins_union[]; |
55 | | |
56 | | /* |
57 | | * yang |
58 | | */ |
59 | | extern const struct lyplg_type_record plugins_instanceid_keys[]; |
60 | | |
61 | | /* |
62 | | * ietf-inet-types |
63 | | */ |
64 | | extern const struct lyplg_type_record plugins_ipv4_address[]; |
65 | | extern const struct lyplg_type_record plugins_ipv4_address_no_zone[]; |
66 | | extern const struct lyplg_type_record plugins_ipv6_address[]; |
67 | | extern const struct lyplg_type_record plugins_ipv6_address_no_zone[]; |
68 | | extern const struct lyplg_type_record plugins_ipv4_prefix[]; |
69 | | extern const struct lyplg_type_record plugins_ipv6_prefix[]; |
70 | | |
71 | | /* |
72 | | * ietf-yang-types |
73 | | */ |
74 | | extern const struct lyplg_type_record plugins_date_and_time[]; |
75 | | extern const struct lyplg_type_record plugins_hex_string[]; |
76 | | extern const struct lyplg_type_record plugins_xpath10[]; |
77 | | |
78 | | /* |
79 | | * ietf-netconf-acm |
80 | | */ |
81 | | extern const struct lyplg_type_record plugins_node_instanceid[]; |
82 | | |
83 | | /* |
84 | | * lyds_tree |
85 | | */ |
86 | | extern const struct lyplg_type_record plugins_lyds_tree[]; |
87 | | |
88 | | /* |
89 | | * internal extension plugins records |
90 | | */ |
91 | | extern struct lyplg_ext_record plugins_metadata[]; |
92 | | extern struct lyplg_ext_record plugins_nacm[]; |
93 | | extern struct lyplg_ext_record plugins_yangdata[]; |
94 | | extern struct lyplg_ext_record plugins_schema_mount[]; |
95 | | extern struct lyplg_ext_record plugins_structure[]; |
96 | | |
97 | | static 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 | | */ |
106 | | static 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 | | */ |
113 | | struct 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 | | |
124 | | #ifndef STATIC |
125 | | static struct ly_set plugins_handlers = {0}; |
126 | | #endif |
127 | | static struct ly_set plugins_types = {0}; |
128 | | static 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 | | */ |
137 | | static struct lyplg_record * |
138 | | plugins_iter(enum LYPLG type, uint32_t *index) |
139 | 19.1M | { |
140 | 19.1M | struct ly_set *plugins; |
141 | | |
142 | 19.1M | assert(index); |
143 | | |
144 | 19.1M | if (type == LYPLG_EXTENSION) { |
145 | 179k | plugins = &plugins_extensions; |
146 | 19.0M | } else { |
147 | 19.0M | plugins = &plugins_types; |
148 | 19.0M | } |
149 | | |
150 | 19.1M | if (*index == plugins->count) { |
151 | 71.9k | return NULL; |
152 | 71.9k | } |
153 | | |
154 | 19.1M | *index += 1; |
155 | 19.1M | return plugins->objs[*index - 1]; |
156 | 19.1M | } |
157 | | |
158 | | static void * |
159 | | lyplg_record_find(enum LYPLG type, const char *module, const char *revision, const char *name) |
160 | 1.41M | { |
161 | 1.41M | uint32_t i = 0; |
162 | 1.41M | struct lyplg_record *item; |
163 | | |
164 | 1.41M | assert(module); |
165 | 0 | assert(name); |
166 | | |
167 | 19.1M | while ((item = plugins_iter(type, &i)) != NULL) { |
168 | 19.1M | if (!strcmp(item->module, module) && !strcmp(item->name, name)) { |
169 | 1.34M | if (item->revision && revision && strcmp(item->revision, revision)) { |
170 | 0 | continue; |
171 | 1.34M | } else if (!revision && item->revision) { |
172 | 0 | continue; |
173 | 0 | } |
174 | | |
175 | 1.34M | return item; |
176 | 1.34M | } |
177 | 19.1M | } |
178 | | |
179 | 71.9k | return NULL; |
180 | 1.41M | } |
181 | | |
182 | | struct lyplg_type * |
183 | | lyplg_type_plugin_find(const char *module, const char *revision, const char *name) |
184 | 1.23M | { |
185 | 1.23M | struct lyplg_record *record; |
186 | | |
187 | 1.23M | record = lyplg_record_find(LYPLG_TYPE, module, revision, name); |
188 | 1.23M | return record ? &((struct lyplg_type_record *)record)->plugin : NULL; |
189 | 1.23M | } |
190 | | |
191 | | struct lyplg_ext_record * |
192 | | lyplg_ext_record_find(const char *module, const char *revision, const char *name) |
193 | 179k | { |
194 | 179k | return lyplg_record_find(LYPLG_EXTENSION, module, revision, name); |
195 | 179k | } |
196 | | |
197 | | /** |
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 | | */ |
206 | | static LY_ERR |
207 | | plugins_insert(enum LYPLG type, const void *recs) |
208 | 87 | { |
209 | 87 | if (!recs) { |
210 | 0 | return LY_SUCCESS; |
211 | 0 | } |
212 | | |
213 | 87 | if (type == LYPLG_EXTENSION) { |
214 | 15 | const struct lyplg_ext_record *rec = (const struct lyplg_ext_record *)recs; |
215 | | |
216 | 42 | for (uint32_t i = 0; rec[i].name; i++) { |
217 | 27 | LY_CHECK_RET(ly_set_add(&plugins_extensions, (void *)&rec[i], 0, NULL)); |
218 | 27 | } |
219 | 72 | } else { /* LYPLG_TYPE */ |
220 | 72 | const struct lyplg_type_record *rec = (const struct lyplg_type_record *)recs; |
221 | | |
222 | 177 | for (uint32_t i = 0; rec[i].name; i++) { |
223 | 105 | LY_CHECK_RET(ly_set_add(&plugins_types, (void *)&rec[i], 0, NULL)); |
224 | 105 | } |
225 | 72 | } |
226 | | |
227 | 87 | return LY_SUCCESS; |
228 | 87 | } |
229 | | |
230 | | #ifndef STATIC |
231 | | |
232 | | static void |
233 | | lyplg_close_cb(void *handle) |
234 | | { |
235 | | dlclose(handle); |
236 | | } |
237 | | |
238 | | static void |
239 | | lyplg_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); |
248 | | ly_set_erase(&plugins_handlers, lyplg_close_cb); |
249 | | } |
250 | | |
251 | | #endif |
252 | | |
253 | | void |
254 | | lyplg_clean(void) |
255 | 17.9k | { |
256 | | #ifndef STATIC |
257 | | pthread_mutex_lock(&plugins_guard); |
258 | | lyplg_clean_(); |
259 | | pthread_mutex_unlock(&plugins_guard); |
260 | | #endif |
261 | 17.9k | } |
262 | | |
263 | | #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 | | */ |
270 | | static 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 | | |
295 | | /** |
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 | | */ |
306 | | static LY_ERR |
307 | | plugins_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(); |
325 | | |
326 | | 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 | | |
338 | | static LY_ERR |
339 | | plugins_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 | | |
380 | | error: |
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 | | |
394 | | static LY_ERR |
395 | | plugins_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 | | |
444 | | #endif |
445 | | |
446 | | LY_ERR |
447 | | lyplg_init(ly_bool builtin_type_plugins_only) |
448 | 17.9k | { |
449 | 17.9k | LY_ERR ret; |
450 | | |
451 | 17.9k | pthread_mutex_lock(&plugins_guard); |
452 | | /* let only the first context to initiate plugins, but let others wait for finishing the initiation */ |
453 | 17.9k | if (context_refcount++) { |
454 | | /* already initiated */ |
455 | 17.9k | pthread_mutex_unlock(&plugins_guard); |
456 | 17.9k | return LY_SUCCESS; |
457 | 17.9k | } |
458 | | |
459 | | /* internal types */ |
460 | 3 | LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_binary), error); |
461 | 3 | LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_bits), error); |
462 | 3 | LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_boolean), error); |
463 | 3 | LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_decimal64), error); |
464 | 3 | LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_empty), error); |
465 | 3 | LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_enumeration), error); |
466 | 3 | LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_identityref), error); |
467 | 3 | LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_instanceid), error); |
468 | 3 | LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_integer), error); |
469 | 3 | LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_leafref), error); |
470 | 3 | LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_string), error); |
471 | 3 | LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_union), error); |
472 | | |
473 | 3 | if (!builtin_type_plugins_only) { |
474 | | /* yang */ |
475 | 3 | LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_instanceid_keys), error); |
476 | | |
477 | | /* ietf-inet-types */ |
478 | 3 | LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_ipv4_address), error); |
479 | 3 | LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_ipv4_address_no_zone), error); |
480 | 3 | LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_ipv6_address), error); |
481 | 3 | LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_ipv6_address_no_zone), error); |
482 | 3 | LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_ipv4_prefix), error); |
483 | 3 | LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_ipv6_prefix), error); |
484 | | |
485 | | /* ietf-yang-types */ |
486 | 3 | LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_date_and_time), error); |
487 | 3 | LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_hex_string), error); |
488 | 3 | LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_xpath10), error); |
489 | | |
490 | | /* ietf-netconf-acm */ |
491 | 3 | LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_node_instanceid), error); |
492 | | |
493 | | /* lyds_tree */ |
494 | 3 | LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_lyds_tree), error); |
495 | | |
496 | | /* internal extensions */ |
497 | 3 | LY_CHECK_GOTO(ret = plugins_insert(LYPLG_EXTENSION, plugins_metadata), error); |
498 | 3 | LY_CHECK_GOTO(ret = plugins_insert(LYPLG_EXTENSION, plugins_nacm), error); |
499 | 3 | LY_CHECK_GOTO(ret = plugins_insert(LYPLG_EXTENSION, plugins_yangdata), error); |
500 | 3 | LY_CHECK_GOTO(ret = plugins_insert(LYPLG_EXTENSION, plugins_schema_mount), error); |
501 | 3 | LY_CHECK_GOTO(ret = plugins_insert(LYPLG_EXTENSION, plugins_structure), error); |
502 | 3 | } |
503 | | |
504 | | #ifndef STATIC |
505 | | /* 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); |
510 | | #endif |
511 | | |
512 | | /* initiation done, wake-up possibly waiting threads creating another contexts */ |
513 | 3 | pthread_mutex_unlock(&plugins_guard); |
514 | | |
515 | 3 | return LY_SUCCESS; |
516 | | |
517 | 0 | error: |
518 | | /* initiation was not successful - cleanup (and let others to try) */ |
519 | | #ifndef STATIC |
520 | | lyplg_clean_(); |
521 | | #endif |
522 | 0 | pthread_mutex_unlock(&plugins_guard); |
523 | |
|
524 | 0 | if (ret == LY_EINVAL) { |
525 | | /* all the plugins here are internal, invalid record actually means an internal libyang error */ |
526 | 0 | ret = LY_EINT; |
527 | 0 | } |
528 | 0 | return ret; |
529 | 3 | } |
530 | | |
531 | | LIBYANG_API_DEF LY_ERR |
532 | | lyplg_add(const char *pathname) |
533 | 0 | { |
534 | 0 | #ifdef STATIC |
535 | 0 | (void)pathname; |
536 | |
|
537 | 0 | LOGERR(NULL, LY_EINVAL, "Plugins are not supported in statically built library."); |
538 | 0 | return LY_EINVAL; |
539 | | #elif defined (_WIN32) |
540 | | (void)pathname; |
541 | | |
542 | | LOGERR(NULL, LY_EINVAL, "Plugins are not (yet) supported on Windows."); |
543 | | return LY_EINVAL; |
544 | | #else |
545 | | 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; |
563 | | #endif |
564 | 0 | } |