58a2419044fc9cd1c34e37d981220fa8079e09b2
[babeltrace.git] / src / lib / plugin / plugin.c
1 /*
2 * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
3 * Copyright 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
4 *
5 * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 * SOFTWARE.
24 */
25
26 #define BT_LOG_TAG "LIB/PLUGIN"
27 #include "lib/logging.h"
28
29 #include "common/assert.h"
30 #include "lib/assert-pre.h"
31 #include "common/macros.h"
32 #include "compat/compiler.h"
33 #include "common/common.h"
34 #include <babeltrace2/plugin/plugin-const.h>
35 #include <babeltrace2/graph/component-class-const.h>
36 #include <babeltrace2/current-thread.h>
37 #include "lib/graph/component-class.h"
38 #include <babeltrace2/types.h>
39 #include <glib.h>
40 #include <unistd.h>
41 #include <stdbool.h>
42 #include <stdlib.h>
43 #include <stdint.h>
44 #include <inttypes.h>
45 #include <sys/stat.h>
46 #include <ftw.h>
47 #include <pthread.h>
48
49 #include "plugin.h"
50 #include "plugin-so.h"
51 #include "lib/func-status.h"
52
53 #define PYTHON_PLUGIN_PROVIDER_FILENAME "babeltrace2-python-plugin-provider." G_MODULE_SUFFIX
54 #define PYTHON_PLUGIN_PROVIDER_DIR BABELTRACE_PLUGIN_PROVIDERS_DIR
55 #define PYTHON_PLUGIN_PROVIDER_SYM_NAME bt_plugin_python_create_all_from_file
56 #define PYTHON_PLUGIN_PROVIDER_SYM_NAME_STR G_STRINGIFY(PYTHON_PLUGIN_PROVIDER_SYM_NAME)
57
58 #define APPEND_ALL_FROM_DIR_NFDOPEN_MAX 8
59
60 /* Declare here to make sure definition in both ifdef branches are in sync. */
61 static
62 int init_python_plugin_provider(void);
63 typedef int (*create_all_from_file_sym_type)(
64 const char *path,
65 bool fail_on_load_error,
66 struct bt_plugin_set **plugin_set_out);
67
68 #ifdef BT_BUILT_IN_PYTHON_PLUGIN_SUPPORT
69 #include <plugin/python-plugin-provider.h>
70
71 static
72 create_all_from_file_sym_type
73 bt_plugin_python_create_all_from_file_sym =
74 bt_plugin_python_create_all_from_file;
75
76 static
77 int init_python_plugin_provider(void)
78 {
79 }
80 #else /* BT_BUILT_IN_PYTHON_PLUGIN_SUPPORT */
81 static GModule *python_plugin_provider_module;
82
83 static
84 create_all_from_file_sym_type bt_plugin_python_create_all_from_file_sym;
85
86 static
87 int init_python_plugin_provider(void) {
88 int status = BT_FUNC_STATUS_OK;
89 const char *provider_dir_envvar;
90 static const char * const provider_dir_envvar_name = "LIBBABELTRACE2_PLUGIN_PROVIDER_DIR";
91 char *provider_path = NULL;
92
93 if (bt_plugin_python_create_all_from_file_sym) {
94 goto end;
95 }
96
97 BT_LOGI_STR("Loading Python plugin provider module.");
98
99 provider_dir_envvar = getenv(provider_dir_envvar_name);
100 if (provider_dir_envvar) {
101 provider_path = g_build_filename(provider_dir_envvar,
102 PYTHON_PLUGIN_PROVIDER_FILENAME, NULL);
103 BT_LOGI("Using `%s` environment variable to find the Python "
104 "plugin provider: path=\"%s\"", provider_dir_envvar_name,
105 provider_path);
106 } else {
107 provider_path = g_build_filename(PYTHON_PLUGIN_PROVIDER_DIR,
108 PYTHON_PLUGIN_PROVIDER_FILENAME, NULL);
109 BT_LOGI("Using default path (`%s` environment variable is not "
110 "set) to find the Python plugin provider: path=\"%s\"",
111 provider_dir_envvar_name, provider_path);
112 }
113
114 python_plugin_provider_module = g_module_open(provider_path, 0);
115 if (!python_plugin_provider_module) {
116 /*
117 * This is not an error. The whole point of having an
118 * external Python plugin provider is that it can be
119 * missing and the Babeltrace library still works.
120 */
121 BT_LOGI("Cannot open `%s`: %s: continuing without Python plugin support.",
122 provider_path, g_module_error());
123 goto end;
124 }
125
126 if (!g_module_symbol(python_plugin_provider_module,
127 PYTHON_PLUGIN_PROVIDER_SYM_NAME_STR,
128 (gpointer) &bt_plugin_python_create_all_from_file_sym)) {
129 /*
130 * This is an error because, since we found the Python
131 * plugin provider shared object, we expect this symbol
132 * to exist.
133 */
134 BT_LIB_LOGE_APPEND_CAUSE(
135 "Cannot find the Python plugin provider loading symbol: "
136 "%s: continuing without Python plugin support: "
137 "file=\"%s\", symbol=\"%s\"",
138 g_module_error(),
139 provider_path,
140 PYTHON_PLUGIN_PROVIDER_SYM_NAME_STR);
141 status = BT_FUNC_STATUS_ERROR;
142 goto end;
143 }
144
145 BT_LOGI("Loaded Python plugin provider module: addr=%p",
146 python_plugin_provider_module);
147
148 end:
149 g_free(provider_path);
150
151 return status;
152 }
153
154 __attribute__((destructor)) static
155 void fini_python_plugin_provider(void) {
156 if (python_plugin_provider_module) {
157 BT_LOGI("Unloading Python plugin provider module.");
158
159 if (!g_module_close(python_plugin_provider_module)) {
160 /*
161 * This occurs when the library is finalized: do
162 * NOT append an error cause.
163 */
164 BT_LOGE("Failed to close the Python plugin provider module: %s.",
165 g_module_error());
166 }
167
168 python_plugin_provider_module = NULL;
169 }
170 }
171 #endif
172
173 uint64_t bt_plugin_set_get_plugin_count(const struct bt_plugin_set *plugin_set)
174 {
175 BT_ASSERT_PRE_DEV_NON_NULL(plugin_set, "Plugin set");
176 return (uint64_t) plugin_set->plugins->len;
177 }
178
179 const struct bt_plugin *bt_plugin_set_borrow_plugin_by_index_const(
180 const struct bt_plugin_set *plugin_set, uint64_t index)
181 {
182 BT_ASSERT_PRE_DEV_NON_NULL(plugin_set, "Plugin set");
183 BT_ASSERT_PRE_DEV_VALID_INDEX(index, plugin_set->plugins->len);
184 return g_ptr_array_index(plugin_set->plugins, index);
185 }
186
187 enum bt_plugin_find_all_from_static_status bt_plugin_find_all_from_static(
188 bt_bool fail_on_load_error,
189 const struct bt_plugin_set **plugin_set_out)
190 {
191 /* bt_plugin_so_create_all_from_static() logs errors */
192 return bt_plugin_so_create_all_from_static(fail_on_load_error,
193 (void *) plugin_set_out);
194 }
195
196 enum bt_plugin_find_all_from_file_status bt_plugin_find_all_from_file(
197 const char *path, bt_bool fail_on_load_error,
198 const struct bt_plugin_set **plugin_set_out)
199 {
200 enum bt_plugin_find_all_from_file_status status;
201
202 BT_ASSERT_PRE_NON_NULL(path, "Path");
203 BT_ASSERT_PRE_NON_NULL(path, "Plugin set (output)");
204 BT_LOGI("Creating plugins from file: path=\"%s\"", path);
205
206 /* Try shared object plugins */
207 status = bt_plugin_so_create_all_from_file(path, fail_on_load_error,
208 (void *) plugin_set_out);
209 if (status == BT_FUNC_STATUS_OK) {
210 BT_ASSERT(*plugin_set_out);
211 BT_ASSERT((*plugin_set_out)->plugins->len > 0);
212 goto end;
213 } else if (status < 0) {
214 BT_ASSERT(!*plugin_set_out);
215 goto end;
216 }
217
218 BT_ASSERT(status == BT_FUNC_STATUS_NOT_FOUND);
219 BT_ASSERT(!*plugin_set_out);
220
221 /* Try Python plugins if support is available */
222 status = init_python_plugin_provider();
223 if (status < 0) {
224 /* init_python_plugin_provider() logs errors */
225 goto end;
226 }
227
228 BT_ASSERT(status == BT_FUNC_STATUS_OK);
229 status = BT_FUNC_STATUS_NOT_FOUND;
230
231 if (bt_plugin_python_create_all_from_file_sym) {
232 /* Python plugin provider exists */
233 status = bt_plugin_python_create_all_from_file_sym(path,
234 fail_on_load_error, (void *) plugin_set_out);
235 if (status == BT_FUNC_STATUS_OK) {
236 BT_ASSERT(*plugin_set_out);
237 BT_ASSERT((*plugin_set_out)->plugins->len > 0);
238 goto end;
239 } else if (status < 0) {
240 /*
241 * bt_plugin_python_create_all_from_file_sym()
242 * handles `fail_on_load_error` itself, so this
243 * is a "real" error.
244 */
245 BT_ASSERT(!*plugin_set_out);
246 goto end;
247 }
248
249 BT_ASSERT(status == BT_FUNC_STATUS_NOT_FOUND);
250 BT_ASSERT(!*plugin_set_out);
251 }
252
253 end:
254 if (status == BT_FUNC_STATUS_OK) {
255 BT_LOGI("Created %u plugins from file: "
256 "path=\"%s\", count=%u, plugin-set-addr=%p",
257 (*plugin_set_out)->plugins->len, path,
258 (*plugin_set_out)->plugins->len,
259 *plugin_set_out);
260 } else if (status == BT_FUNC_STATUS_NOT_FOUND) {
261 BT_LOGI("Found no plugins in file: path=\"%s\"", path);
262 }
263
264 return status;
265 }
266
267 static
268 void destroy_gstring(void *data)
269 {
270 g_string_free(data, TRUE);
271 }
272
273 enum bt_plugin_find_all_status bt_plugin_find_all(bt_bool find_in_std_env_var,
274 bt_bool find_in_user_dir, bt_bool find_in_sys_dir,
275 bt_bool find_in_static, bt_bool fail_on_load_error,
276 const struct bt_plugin_set **plugin_set_out)
277 {
278 char *home_plugin_dir = NULL;
279 const struct bt_plugin_set *plugin_set = NULL;
280 GPtrArray *dirs = NULL;
281 int ret;
282 int status = BT_FUNC_STATUS_OK;
283 uint64_t dir_i, plugin_i;
284
285 BT_ASSERT_PRE_NON_NULL(plugin_set_out, "Plugin set (output)");
286 BT_LOGI("Finding all plugins in standard directories and built-in plugins: "
287 "find-in-std-env-var=%d, find-in-user-dir=%d, "
288 "find-in-sys-dir=%d, find-in-static=%d",
289 find_in_std_env_var, find_in_user_dir, find_in_sys_dir,
290 find_in_static);
291 dirs = g_ptr_array_new_with_free_func((GDestroyNotify) destroy_gstring);
292 if (!dirs) {
293 BT_LIB_LOGE_APPEND_CAUSE("Failed to allocate a GPtrArray.");
294 status = BT_FUNC_STATUS_MEMORY_ERROR;
295 goto end;
296 }
297
298 *plugin_set_out = bt_plugin_set_create();
299 if (!*plugin_set_out) {
300 BT_LIB_LOGE_APPEND_CAUSE("Cannot create empty plugin set.");
301 status = BT_FUNC_STATUS_MEMORY_ERROR;
302 goto end;
303 }
304
305 /*
306 * Search order is:
307 *
308 * 1. `BABELTRACE_PLUGIN_PATH` environment variable
309 * (colon-separated list of directories)
310 * 2. `~/.local/lib/babeltrace2/plugins`
311 * 3. Default system directory for Babeltrace plugins, usually
312 * `/usr/lib/babeltrace2/plugins` or
313 * `/usr/local/lib/babeltrace2/plugins` if installed locally
314 * 4. Built-in plugins (static)
315 *
316 * Directories are searched non-recursively.
317 */
318 if (find_in_std_env_var) {
319 const char *envvar = getenv("BABELTRACE_PLUGIN_PATH");
320
321 if (envvar) {
322 ret = bt_common_append_plugin_path_dirs(envvar, dirs);
323 if (ret) {
324 BT_LIB_LOGE_APPEND_CAUSE(
325 "Failed to append plugin path to array of directories.");
326 status = BT_FUNC_STATUS_MEMORY_ERROR;
327 goto end;
328 }
329 }
330 }
331
332 if (find_in_user_dir) {
333 home_plugin_dir = bt_common_get_home_plugin_path(
334 BT_LOG_OUTPUT_LEVEL);
335 if (home_plugin_dir) {
336 GString *home_plugin_dir_str = g_string_new(
337 home_plugin_dir);
338
339 if (!home_plugin_dir_str) {
340 BT_LIB_LOGE_APPEND_CAUSE("Failed to allocate a GString.");
341 status = BT_FUNC_STATUS_MEMORY_ERROR;
342 goto end;
343 }
344
345 g_ptr_array_add(dirs, home_plugin_dir_str);
346 }
347 }
348
349 if (find_in_sys_dir) {
350 const char *system_plugin_dir =
351 bt_common_get_system_plugin_path();
352
353 if (system_plugin_dir) {
354 GString *system_plugin_dir_str =
355 g_string_new(system_plugin_dir);
356
357 if (!system_plugin_dir_str) {
358 BT_LIB_LOGE_APPEND_CAUSE("Failed to allocate a GString.");
359 status = BT_FUNC_STATUS_MEMORY_ERROR;
360 goto end;
361 }
362
363 g_ptr_array_add(dirs, system_plugin_dir_str);
364 }
365 }
366
367 for (dir_i = 0; dir_i < dirs->len; dir_i++) {
368 GString *dir = dirs->pdata[dir_i];
369
370 BT_OBJECT_PUT_REF_AND_RESET(plugin_set);
371
372 /*
373 * Skip this if the directory does not exist because
374 * bt_plugin_find_all_from_dir() would log a warning.
375 */
376 if (!g_file_test(dir->str, G_FILE_TEST_IS_DIR)) {
377 BT_LOGI("Skipping nonexistent directory path: "
378 "path=\"%s\"", dir->str);
379 continue;
380 }
381
382 /* bt_plugin_find_all_from_dir() logs details/errors */
383 status = bt_plugin_find_all_from_dir(dir->str, BT_FALSE,
384 fail_on_load_error, &plugin_set);
385 if (status < 0) {
386 BT_ASSERT(!plugin_set);
387 goto end;
388 } else if (status == BT_FUNC_STATUS_NOT_FOUND) {
389 BT_ASSERT(!plugin_set);
390 BT_LOGI("No plugins found in directory: path=\"%s\"",
391 dir->str);
392 continue;
393 }
394
395 BT_ASSERT(status == BT_FUNC_STATUS_OK);
396 BT_ASSERT(plugin_set);
397 BT_LOGI("Found plugins in directory: path=\"%s\", count=%u",
398 dir->str, plugin_set->plugins->len);
399
400 for (plugin_i = 0; plugin_i < plugin_set->plugins->len;
401 plugin_i++) {
402 bt_plugin_set_add_plugin((void *) *plugin_set_out,
403 plugin_set->plugins->pdata[plugin_i]);
404 }
405 }
406
407 if (find_in_static) {
408 BT_OBJECT_PUT_REF_AND_RESET(plugin_set);
409 status = bt_plugin_find_all_from_static(fail_on_load_error,
410 &plugin_set);
411 if (status < 0) {
412 BT_ASSERT(!plugin_set);
413 goto end;
414 } else if (status == BT_FUNC_STATUS_NOT_FOUND) {
415 BT_ASSERT(!plugin_set);
416 BT_LOGI_STR("No plugins found in built-in plugins.");
417 goto end;
418 }
419
420 BT_ASSERT(status == BT_FUNC_STATUS_OK);
421 BT_ASSERT(plugin_set);
422 BT_LOGI("Found built-in plugins: count=%u",
423 plugin_set->plugins->len);
424
425 for (plugin_i = 0; plugin_i < plugin_set->plugins->len;
426 plugin_i++) {
427 bt_plugin_set_add_plugin((void *) *plugin_set_out,
428 plugin_set->plugins->pdata[plugin_i]);
429 }
430 }
431
432 end:
433 free(home_plugin_dir);
434 bt_object_put_ref(plugin_set);
435
436 if (dirs) {
437 g_ptr_array_free(dirs, TRUE);
438 }
439
440 if (status < 0) {
441 BT_OBJECT_PUT_REF_AND_RESET(*plugin_set_out);
442 } else {
443 BT_ASSERT(*plugin_set_out);
444
445 if ((*plugin_set_out)->plugins->len > 0) {
446 BT_LOGI("Found plugins in standard directories and built-in plugins: "
447 "count=%u", (*plugin_set_out)->plugins->len);
448 status = BT_FUNC_STATUS_OK;
449 } else {
450 BT_LOGI_STR("No plugins found in standard directories and built-in plugins.");
451 status = BT_FUNC_STATUS_NOT_FOUND;
452 BT_OBJECT_PUT_REF_AND_RESET(*plugin_set_out);
453 }
454 }
455
456 return status;
457 }
458
459 enum bt_plugin_find_status bt_plugin_find(const char *plugin_name,
460 bt_bool find_in_std_env_var, bt_bool find_in_user_dir,
461 bt_bool find_in_sys_dir, bt_bool find_in_static,
462 bt_bool fail_on_load_error, const struct bt_plugin **plugin_out)
463 {
464 enum bt_plugin_find_status status;
465 const struct bt_plugin_set *plugin_set = NULL;
466 uint64_t i;
467
468 BT_ASSERT_PRE_NON_NULL(plugin_name, "Name");
469 BT_ASSERT_PRE_NON_NULL(plugin_out, "Plugin (output)");
470 BT_LOGI("Finding named plugin in standard directories and built-in plugins: "
471 "name=\"%s\", find-in-std-env-var=%d, find-in-user-dir=%d, "
472 "find-in-sys-dir=%d, find-in-static=%d",
473 plugin_name, find_in_std_env_var, find_in_user_dir,
474 find_in_sys_dir, find_in_static);
475 status = (enum bt_plugin_find_status) bt_plugin_find_all(find_in_std_env_var, find_in_user_dir,
476 find_in_sys_dir, find_in_static, fail_on_load_error,
477 &plugin_set);
478 if (status != BT_FUNC_STATUS_OK) {
479 BT_ASSERT(!plugin_set);
480 goto end;
481 }
482
483 BT_ASSERT(plugin_set);
484
485 for (i = 0; i < plugin_set->plugins->len; i++) {
486 const struct bt_plugin *plugin = plugin_set->plugins->pdata[i];
487
488 if (strcmp(plugin->info.name->str, plugin_name) == 0) {
489 *plugin_out = plugin;
490 bt_object_get_ref_no_null_check(*plugin_out);
491 goto end;
492 }
493 }
494
495 status = BT_FUNC_STATUS_NOT_FOUND;
496
497 end:
498 if (status == BT_FUNC_STATUS_OK) {
499 BT_ASSERT(*plugin_out);
500 BT_LIB_LOGI("Found plugin in standard directories and built-in plugins: "
501 "%!+l", *plugin_out);
502 } else if (status == BT_FUNC_STATUS_NOT_FOUND) {
503 BT_LOGI("No plugin found in standard directories and built-in plugins: "
504 "name=\"%s\"", plugin_name);
505 }
506
507 bt_plugin_set_put_ref(plugin_set);
508
509 return status;
510 }
511
512 static struct {
513 pthread_mutex_t lock;
514 struct bt_plugin_set *plugin_set;
515 bool recurse;
516 bool fail_on_load_error;
517 int status;
518 } append_all_from_dir_info = {
519 .lock = PTHREAD_MUTEX_INITIALIZER
520 };
521
522 static
523 int nftw_append_all_from_dir(const char *file,
524 const struct stat *sb, int flag, struct FTW *s)
525 {
526 int ret = 0;
527 const char *name = file + s->base;
528
529 /* Check for recursion */
530 if (!append_all_from_dir_info.recurse && s->level > 1) {
531 goto end;
532 }
533
534 switch (flag) {
535 case FTW_F:
536 {
537 const struct bt_plugin_set *plugins_from_file = NULL;
538
539 if (name[0] == '.') {
540 /* Skip hidden files */
541 BT_LOGI("Skipping hidden file: path=\"%s\"", file);
542 goto end;
543 }
544
545 append_all_from_dir_info.status =
546 bt_plugin_find_all_from_file(file,
547 append_all_from_dir_info.fail_on_load_error,
548 &plugins_from_file);
549 if (append_all_from_dir_info.status == BT_FUNC_STATUS_OK) {
550 size_t j;
551
552 BT_ASSERT(plugins_from_file);
553
554 for (j = 0; j < plugins_from_file->plugins->len; j++) {
555 struct bt_plugin *plugin =
556 g_ptr_array_index(plugins_from_file->plugins, j);
557
558 BT_LIB_LOGI("Adding plugin to plugin set: "
559 "plugin-path=\"%s\", %![plugin-]+l",
560 file, plugin);
561 bt_plugin_set_add_plugin(
562 append_all_from_dir_info.plugin_set,
563 plugin);
564 }
565
566 bt_object_put_ref(plugins_from_file);
567 goto end;
568 } else if (append_all_from_dir_info.status < 0) {
569 /* bt_plugin_find_all_from_file() logs errors */
570 BT_ASSERT(!plugins_from_file);
571 ret = -1;
572 goto end;
573 }
574
575 /*
576 * Not found in this file: this is no an error; continue
577 * walking the directories.
578 */
579 BT_ASSERT(!plugins_from_file);
580 BT_ASSERT(append_all_from_dir_info.status ==
581 BT_FUNC_STATUS_NOT_FOUND);
582 break;
583 }
584 case FTW_DNR:
585 /* Continue to next file / directory. */
586 BT_LOGI("Cannot enter directory: continuing: path=\"%s\"", file);
587 break;
588 case FTW_NS:
589 /* Continue to next file / directory. */
590 BT_LOGI("Cannot get file information: continuing: path=\"%s\"", file);
591 break;
592 }
593
594 end:
595 return ret;
596 }
597
598 static
599 int bt_plugin_create_append_all_from_dir(struct bt_plugin_set *plugin_set,
600 const char *path, bt_bool recurse, bt_bool fail_on_load_error)
601 {
602 int nftw_flags = FTW_PHYS;
603 int ret;
604 int status;
605 struct stat sb;
606
607 BT_ASSERT(plugin_set);
608 BT_ASSERT(path);
609 BT_ASSERT(strlen(path) < PATH_MAX);
610
611 /*
612 * Make sure that path exists and is accessible.
613 * This is necessary since Cygwin implementation of nftw() is not POSIX
614 * compliant. Cygwin nftw() implementation does not fail on non-existent
615 * path with ENOENT. Instead, it flags the directory as FTW_NS. FTW_NS during
616 * nftw_append_all_from_dir is not treated as an error since we are
617 * traversing the tree for plugin discovery.
618 */
619 if (stat(path, &sb)) {
620 BT_LOGW_ERRNO("Cannot open directory",
621 ": path=\"%s\", recurse=%d",
622 path, recurse);
623 (void) BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_UNKNOWN(
624 BT_LIB_LOG_LIBBABELTRACE2_NAME,
625 "Cannot open directory: path=\"%s\", recurse=%d",
626 path, recurse);
627 status = BT_FUNC_STATUS_ERROR;
628 goto end;
629 }
630
631 pthread_mutex_lock(&append_all_from_dir_info.lock);
632 append_all_from_dir_info.plugin_set = plugin_set;
633 append_all_from_dir_info.recurse = recurse;
634 append_all_from_dir_info.status = BT_FUNC_STATUS_OK;
635 append_all_from_dir_info.fail_on_load_error = fail_on_load_error;
636 ret = nftw(path, nftw_append_all_from_dir,
637 APPEND_ALL_FROM_DIR_NFDOPEN_MAX, nftw_flags);
638 append_all_from_dir_info.plugin_set = NULL;
639 status = append_all_from_dir_info.status;
640 pthread_mutex_unlock(&append_all_from_dir_info.lock);
641 if (ret) {
642 BT_LIB_LOGW_APPEND_CAUSE("Failed to walk directory",
643 ": path=\"%s\", recurse=%d",
644 path, recurse);
645 status = BT_FUNC_STATUS_ERROR;
646 goto end;
647 }
648
649 if (status == BT_FUNC_STATUS_NOT_FOUND) {
650 /*
651 * We're just appending in this function; even if
652 * nothing was found, it's still okay from the caller's
653 * perspective.
654 */
655 status = BT_FUNC_STATUS_OK;
656 }
657
658 end:
659 return status;
660 }
661
662 enum bt_plugin_find_all_from_dir_status bt_plugin_find_all_from_dir(
663 const char *path, bt_bool recurse, bt_bool fail_on_load_error,
664 const struct bt_plugin_set **plugin_set_out)
665 {
666 enum bt_plugin_find_all_from_dir_status status =
667 BT_FUNC_STATUS_OK;
668
669 BT_ASSERT_PRE_NON_NULL(plugin_set_out, "Plugin set (output)");
670 BT_LOGI("Creating all plugins in directory: path=\"%s\", recurse=%d",
671 path, recurse);
672 *plugin_set_out = bt_plugin_set_create();
673 if (!*plugin_set_out) {
674 BT_LIB_LOGE_APPEND_CAUSE("Cannot create empty plugin set.");
675 status = BT_FUNC_STATUS_MEMORY_ERROR;
676 goto error;
677 }
678
679 /*
680 * Append found plugins to array (never returns
681 * `BT_FUNC_STATUS_NOT_FOUND`)
682 */
683 status = bt_plugin_create_append_all_from_dir((void *) *plugin_set_out,
684 path, recurse, fail_on_load_error);
685 if (status < 0) {
686 /*
687 * bt_plugin_create_append_all_from_dir() handles
688 * `fail_on_load_error`, so this is a "real" error.
689 */
690 BT_LIB_LOGE_APPEND_CAUSE(
691 "Cannot append plugins found in directory: "
692 "path=\"%s\", status=%s",
693 path, bt_common_func_status_string(status));
694 goto error;
695 }
696
697 BT_ASSERT(status == BT_FUNC_STATUS_OK);
698
699 if ((*plugin_set_out)->plugins->len == 0) {
700 /* Nothing was appended: not found */
701 BT_LOGI("No plugins found in directory: path=\"%s\"", path);
702 status = BT_FUNC_STATUS_NOT_FOUND;
703 goto error;
704 }
705
706 BT_LOGI("Created %u plugins from directory: count=%u, path=\"%s\"",
707 (*plugin_set_out)->plugins->len,
708 (*plugin_set_out)->plugins->len, path);
709 goto end;
710
711 error:
712 BT_ASSERT(status != BT_FUNC_STATUS_OK);
713 BT_OBJECT_PUT_REF_AND_RESET(*plugin_set_out);
714
715 end:
716 return status;
717 }
718
719 const char *bt_plugin_get_name(const struct bt_plugin *plugin)
720 {
721 BT_ASSERT_PRE_DEV_NON_NULL(plugin, "Plugin");
722 return plugin->info.name_set ? plugin->info.name->str : NULL;
723 }
724
725 const char *bt_plugin_get_author(const struct bt_plugin *plugin)
726 {
727 BT_ASSERT_PRE_DEV_NON_NULL(plugin, "Plugin");
728 return plugin->info.author_set ? plugin->info.author->str : NULL;
729 }
730
731 const char *bt_plugin_get_license(const struct bt_plugin *plugin)
732 {
733 BT_ASSERT_PRE_DEV_NON_NULL(plugin, "Plugin");
734 return plugin->info.license_set ? plugin->info.license->str : NULL;
735 }
736
737 const char *bt_plugin_get_path(const struct bt_plugin *plugin)
738 {
739 BT_ASSERT_PRE_DEV_NON_NULL(plugin, "Plugin");
740 return plugin->info.path_set ? plugin->info.path->str : NULL;
741 }
742
743 const char *bt_plugin_get_description(const struct bt_plugin *plugin)
744 {
745 BT_ASSERT_PRE_DEV_NON_NULL(plugin, "Plugin");
746 return plugin->info.description_set ?
747 plugin->info.description->str : NULL;
748 }
749
750 enum bt_property_availability bt_plugin_get_version(const struct bt_plugin *plugin,
751 unsigned int *major, unsigned int *minor, unsigned int *patch,
752 const char **extra)
753 {
754 enum bt_property_availability avail =
755 BT_PROPERTY_AVAILABILITY_AVAILABLE;
756
757 BT_ASSERT_PRE_DEV_NON_NULL(plugin, "Plugin");
758
759 if (!plugin->info.version_set) {
760 BT_LIB_LOGD("Plugin's version is not set: %!+l", plugin);
761 avail = BT_PROPERTY_AVAILABILITY_NOT_AVAILABLE;
762 goto end;
763 }
764
765 if (major) {
766 *major = plugin->info.version.major;
767 }
768
769 if (minor) {
770 *minor = plugin->info.version.minor;
771 }
772
773 if (patch) {
774 *patch = plugin->info.version.patch;
775 }
776
777 if (extra) {
778 *extra = plugin->info.version.extra->str;
779 }
780
781 end:
782 return avail;
783 }
784
785 uint64_t bt_plugin_get_source_component_class_count(const struct bt_plugin *plugin)
786 {
787 BT_ASSERT_PRE_DEV_NON_NULL(plugin, "Plugin");
788 return (uint64_t) plugin->src_comp_classes->len;
789 }
790
791 uint64_t bt_plugin_get_filter_component_class_count(const struct bt_plugin *plugin)
792 {
793 BT_ASSERT_PRE_DEV_NON_NULL(plugin, "Plugin");
794 return (uint64_t) plugin->flt_comp_classes->len;
795 }
796
797 uint64_t bt_plugin_get_sink_component_class_count(const struct bt_plugin *plugin)
798 {
799 BT_ASSERT_PRE_DEV_NON_NULL(plugin, "Plugin");
800 return (uint64_t) plugin->sink_comp_classes->len;
801 }
802
803 static inline
804 struct bt_component_class *borrow_component_class_by_index(
805 const struct bt_plugin *plugin, GPtrArray *comp_classes,
806 uint64_t index)
807 {
808 BT_ASSERT_PRE_DEV_NON_NULL(plugin, "Plugin");
809 BT_ASSERT_PRE_DEV_VALID_INDEX(index, comp_classes->len);
810 return g_ptr_array_index(comp_classes, index);
811 }
812
813 const struct bt_component_class_source *
814 bt_plugin_borrow_source_component_class_by_index_const(
815 const struct bt_plugin *plugin, uint64_t index)
816 {
817 return (const void *) borrow_component_class_by_index(plugin,
818 plugin->src_comp_classes, index);
819 }
820
821 const struct bt_component_class_filter *
822 bt_plugin_borrow_filter_component_class_by_index_const(
823 const struct bt_plugin *plugin, uint64_t index)
824 {
825 return (const void *) borrow_component_class_by_index(plugin,
826 plugin->flt_comp_classes, index);
827 }
828
829 const struct bt_component_class_sink *
830 bt_plugin_borrow_sink_component_class_by_index_const(
831 const struct bt_plugin *plugin, uint64_t index)
832 {
833 return (const void *) borrow_component_class_by_index(plugin,
834 plugin->sink_comp_classes, index);
835 }
836
837 static inline
838 struct bt_component_class *borrow_component_class_by_name(
839 const struct bt_plugin *plugin, GPtrArray *comp_classes,
840 const char *name)
841 {
842 struct bt_component_class *comp_class = NULL;
843 size_t i;
844
845 BT_ASSERT_PRE_DEV_NON_NULL(plugin, "Plugin");
846 BT_ASSERT_PRE_DEV_NON_NULL(name, "Name");
847
848 for (i = 0; i < comp_classes->len; i++) {
849 struct bt_component_class *comp_class_candidate =
850 g_ptr_array_index(comp_classes, i);
851 const char *comp_class_cand_name =
852 bt_component_class_get_name(comp_class_candidate);
853
854 BT_ASSERT_DBG(comp_class_cand_name);
855
856 if (strcmp(name, comp_class_cand_name) == 0) {
857 comp_class = comp_class_candidate;
858 break;
859 }
860 }
861
862 return comp_class;
863 }
864
865 const struct bt_component_class_source *
866 bt_plugin_borrow_source_component_class_by_name_const(
867 const struct bt_plugin *plugin, const char *name)
868 {
869 return (const void *) borrow_component_class_by_name(plugin,
870 plugin->src_comp_classes, name);
871 }
872
873 const struct bt_component_class_filter *
874 bt_plugin_borrow_filter_component_class_by_name_const(
875 const struct bt_plugin *plugin, const char *name)
876 {
877 return (const void *) borrow_component_class_by_name(plugin,
878 plugin->flt_comp_classes, name);
879 }
880
881 const struct bt_component_class_sink *
882 bt_plugin_borrow_sink_component_class_by_name_const(
883 const struct bt_plugin *plugin, const char *name)
884 {
885 return (const void *) borrow_component_class_by_name(plugin,
886 plugin->sink_comp_classes, name);
887 }
888
889 void bt_plugin_get_ref(const struct bt_plugin *plugin)
890 {
891 bt_object_get_ref(plugin);
892 }
893
894 void bt_plugin_put_ref(const struct bt_plugin *plugin)
895 {
896 bt_object_put_ref(plugin);
897 }
898
899 void bt_plugin_set_get_ref(const struct bt_plugin_set *plugin_set)
900 {
901 bt_object_get_ref(plugin_set);
902 }
903
904 void bt_plugin_set_put_ref(const struct bt_plugin_set *plugin_set)
905 {
906 bt_object_put_ref(plugin_set);
907 }
This page took 0.050253 seconds and 3 git commands to generate.