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