Fix -Wmissing-prototypes/-Wmissing-declarations warnings
[babeltrace.git] / src / lib / plugin / plugin.c
CommitLineData
33b34c43 1/*
f2b0325d 2 * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
33b34c43 3 * Copyright 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
33b34c43
PP
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
b03487ab 26#define BT_LOG_TAG "LIB/PLUGIN"
1633ef46 27#include "lib/logging.h"
8c1a3187 28
57952005
MJ
29#include "common/assert.h"
30#include "lib/assert-pre.h"
85e7137b 31#include "common/macros.h"
57952005
MJ
32#include "compat/compiler.h"
33#include "common/common.h"
71c5da58
MJ
34#include <babeltrace2/plugin/plugin-const.h>
35#include <babeltrace2/graph/component-class-const.h>
a8f90e5d 36#include <babeltrace2/current-thread.h>
57952005 37#include "lib/graph/component-class.h"
71c5da58 38#include <babeltrace2/types.h>
33b34c43 39#include <glib.h>
33b34c43
PP
40#include <unistd.h>
41#include <stdlib.h>
9ac68eb1 42#include <stdint.h>
8c1a3187 43#include <inttypes.h>
33b34c43 44#include <sys/stat.h>
1307d39e
MJ
45#include <ftw.h>
46#include <pthread.h>
33b34c43 47
57952005
MJ
48#include "plugin.h"
49#include "plugin-so.h"
fb25b9e3 50#include "lib/func-status.h"
57952005 51
7b783015
MJ
52#define PYTHON_PLUGIN_PROVIDER_FILENAME "babeltrace2-python-plugin-provider." G_MODULE_SUFFIX
53#define PYTHON_PLUGIN_PROVIDER_DIR BABELTRACE_PLUGIN_PROVIDERS_DIR
6fbd4105 54#define PYTHON_PLUGIN_PROVIDER_SYM_NAME bt_plugin_python_create_all_from_file
85e7137b 55#define PYTHON_PLUGIN_PROVIDER_SYM_NAME_STR G_STRINGIFY(PYTHON_PLUGIN_PROVIDER_SYM_NAME)
33b34c43 56
1307d39e
MJ
57#define APPEND_ALL_FROM_DIR_NFDOPEN_MAX 8
58
f3847c75
SM
59/* Declare here to make sure definition in both ifdef branches are in sync. */
60static
61int init_python_plugin_provider(void);
62typedef 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
6fbd4105 67#ifdef BT_BUILT_IN_PYTHON_PLUGIN_SUPPORT
57952005 68#include <plugin/python-plugin-provider.h>
1307d39e 69
33b34c43 70static
f3847c75
SM
71create_all_from_file_sym_type
72 bt_plugin_python_create_all_from_file_sym =
73 bt_plugin_python_create_all_from_file;
336ea5cd
MJ
74
75static
f3847c75 76int init_python_plugin_provider(void)
01f50d54
PP
77{
78}
6fbd4105
PP
79#else /* BT_BUILT_IN_PYTHON_PLUGIN_SUPPORT */
80static GModule *python_plugin_provider_module;
01f50d54 81
6fbd4105 82static
f3847c75 83create_all_from_file_sym_type bt_plugin_python_create_all_from_file_sym;
33b34c43 84
336ea5cd 85static
a8f90e5d
PP
86int init_python_plugin_provider(void) {
87 int status = BT_FUNC_STATUS_OK;
7b783015
MJ
88 const char *provider_dir_envvar;
89 static const char * const provider_dir_envvar_name = "LIBBABELTRACE2_PLUGIN_PROVIDER_DIR";
90 char *provider_path = NULL;
a8f90e5d 91
8e01f2d9 92 if (bt_plugin_python_create_all_from_file_sym) {
a8f90e5d 93 goto end;
336ea5cd
MJ
94 }
95
a684a357 96 BT_LOGI_STR("Loading Python plugin provider module.");
7b783015
MJ
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);
6fbd4105 114 if (!python_plugin_provider_module) {
01f50d54
PP
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 */
20e3b31e 120 BT_LOGI("Cannot open `%s`: %s: continuing without Python plugin support.",
7b783015 121 provider_path, g_module_error());
a8f90e5d 122 goto end;
33b34c43
PP
123 }
124
6fbd4105
PP
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)) {
01f50d54
PP
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 */
a8f90e5d
PP
133 BT_LIB_LOGE_APPEND_CAUSE(
134 "Cannot find the Python plugin provider loading symbol: "
01f50d54 135 "%s: continuing without Python plugin support: "
8c1a3187 136 "file=\"%s\", symbol=\"%s\"",
01f50d54 137 g_module_error(),
7b783015 138 provider_path,
8c1a3187 139 PYTHON_PLUGIN_PROVIDER_SYM_NAME_STR);
a8f90e5d
PP
140 status = BT_FUNC_STATUS_ERROR;
141 goto end;
33b34c43 142 }
8c1a3187 143
9e0bf9b0 144 BT_LOGI("Loaded Python plugin provider module: addr=%p",
8c1a3187 145 python_plugin_provider_module);
a8f90e5d
PP
146
147end:
7b783015
MJ
148 g_free(provider_path);
149
a8f90e5d 150 return status;
33b34c43
PP
151}
152
6fbd4105
PP
153__attribute__((destructor)) static
154void fini_python_plugin_provider(void) {
155 if (python_plugin_provider_module) {
a684a357 156 BT_LOGI("Unloading Python plugin provider module.");
8c1a3187
PP
157
158 if (!g_module_close(python_plugin_provider_module)) {
a8f90e5d
PP
159 /*
160 * This occurs when the library is finalized: do
161 * NOT append an error cause.
162 */
8c1a3187
PP
163 BT_LOGE("Failed to close the Python plugin provider module: %s.",
164 g_module_error());
165 }
166
6fbd4105 167 python_plugin_provider_module = NULL;
6ba0b073 168 }
6ba0b073 169}
6fbd4105 170#endif
6ba0b073 171
15a5b9a8 172uint64_t bt_plugin_set_get_plugin_count(const struct bt_plugin_set *plugin_set)
a8ff38ef 173{
fa6cfec3 174 BT_ASSERT_PRE_DEV_NON_NULL(plugin_set, "Plugin set");
834e9996 175 return (uint64_t) plugin_set->plugins->len;
a8ff38ef
PP
176}
177
3a2cb327
PP
178const struct bt_plugin *bt_plugin_set_borrow_plugin_by_index_const(
179 const struct bt_plugin_set *plugin_set, uint64_t index)
a8ff38ef 180{
fa6cfec3
PP
181 BT_ASSERT_PRE_DEV_NON_NULL(plugin_set, "Plugin set");
182 BT_ASSERT_PRE_DEV_VALID_INDEX(index, plugin_set->plugins->len);
834e9996 183 return g_ptr_array_index(plugin_set->plugins, index);
a8ff38ef
PP
184}
185
fb25b9e3 186enum bt_plugin_find_all_from_static_status bt_plugin_find_all_from_static(
01f50d54
PP
187 bt_bool fail_on_load_error,
188 const struct bt_plugin_set **plugin_set_out)
6ba0b073 189{
8c1a3187 190 /* bt_plugin_so_create_all_from_static() logs errors */
01f50d54
PP
191 return bt_plugin_so_create_all_from_static(fail_on_load_error,
192 (void *) plugin_set_out);
6ba0b073
PP
193}
194
fb25b9e3
PP
195enum bt_plugin_find_all_from_file_status bt_plugin_find_all_from_file(
196 const char *path, bt_bool fail_on_load_error,
01f50d54 197 const struct bt_plugin_set **plugin_set_out)
33b34c43 198{
fb25b9e3 199 enum bt_plugin_find_all_from_file_status status;
33b34c43 200
834e9996 201 BT_ASSERT_PRE_NON_NULL(path, "Path");
01f50d54 202 BT_ASSERT_PRE_NON_NULL(path, "Plugin set (output)");
a684a357 203 BT_LOGI("Creating plugins from file: path=\"%s\"", path);
6ba0b073 204
55bb57e0 205 /* Try shared object plugins */
01f50d54
PP
206 status = bt_plugin_so_create_all_from_file(path, fail_on_load_error,
207 (void *) plugin_set_out);
fb25b9e3 208 if (status == BT_FUNC_STATUS_OK) {
01f50d54
PP
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);
6ba0b073
PP
214 goto end;
215 }
216
fb25b9e3 217 BT_ASSERT(status == BT_FUNC_STATUS_NOT_FOUND);
01f50d54
PP
218 BT_ASSERT(!*plugin_set_out);
219
6fbd4105 220 /* Try Python plugins if support is available */
a8f90e5d
PP
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
6fbd4105 230 if (bt_plugin_python_create_all_from_file_sym) {
a8f90e5d 231 /* Python plugin provider exists */
01f50d54
PP
232 status = bt_plugin_python_create_all_from_file_sym(path,
233 fail_on_load_error, (void *) plugin_set_out);
fb25b9e3 234 if (status == BT_FUNC_STATUS_OK) {
01f50d54
PP
235 BT_ASSERT(*plugin_set_out);
236 BT_ASSERT((*plugin_set_out)->plugins->len > 0);
237 goto end;
238 } else if (status < 0) {
a8f90e5d
PP
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 */
01f50d54 244 BT_ASSERT(!*plugin_set_out);
6fbd4105
PP
245 goto end;
246 }
01f50d54 247
fb25b9e3 248 BT_ASSERT(status == BT_FUNC_STATUS_NOT_FOUND);
01f50d54 249 BT_ASSERT(!*plugin_set_out);
6ba0b073
PP
250 }
251
33b34c43 252end:
fb25b9e3 253 if (status == BT_FUNC_STATUS_OK) {
a684a357 254 BT_LOGI("Created %u plugins from file: "
8c1a3187 255 "path=\"%s\", count=%u, plugin-set-addr=%p",
01f50d54
PP
256 (*plugin_set_out)->plugins->len, path,
257 (*plugin_set_out)->plugins->len,
258 *plugin_set_out);
fb25b9e3 259 } else if (status == BT_FUNC_STATUS_NOT_FOUND) {
a684a357 260 BT_LOGI("Found no plugins in file: path=\"%s\"", path);
8c1a3187
PP
261 }
262
01f50d54 263 return status;
33b34c43
PP
264}
265
7d8f15e6
PP
266static
267void destroy_gstring(void *data)
1670bffd
PP
268{
269 g_string_free(data, TRUE);
270}
271
7d8f15e6
PP
272enum 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)
1670bffd 276{
1670bffd 277 char *home_plugin_dir = NULL;
3a2cb327 278 const struct bt_plugin_set *plugin_set = NULL;
1670bffd
PP
279 GPtrArray *dirs = NULL;
280 int ret;
fb25b9e3 281 int status = BT_FUNC_STATUS_OK;
7d8f15e6
PP
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);
1670bffd
PP
290 dirs = g_ptr_array_new_with_free_func((GDestroyNotify) destroy_gstring);
291 if (!dirs) {
a8f90e5d 292 BT_LIB_LOGE_APPEND_CAUSE("Failed to allocate a GPtrArray.");
fb25b9e3 293 status = BT_FUNC_STATUS_MEMORY_ERROR;
1670bffd
PP
294 goto end;
295 }
296
7d8f15e6
PP
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
1670bffd
PP
304 /*
305 * Search order is:
306 *
7d8f15e6 307 * 1. `BABELTRACE_PLUGIN_PATH` environment variable
1670bffd 308 * (colon-separated list of directories)
7d8f15e6 309 * 2. `~/.local/lib/babeltrace2/plugins`
1670bffd 310 * 3. Default system directory for Babeltrace plugins, usually
7d8f15e6
PP
311 * `/usr/lib/babeltrace2/plugins` or
312 * `/usr/local/lib/babeltrace2/plugins` if installed locally
1670bffd
PP
313 * 4. Built-in plugins (static)
314 *
315 * Directories are searched non-recursively.
316 */
7d8f15e6
PP
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 }
1670bffd
PP
328 }
329 }
330
7d8f15e6
PP
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);
1670bffd 337
7d8f15e6
PP
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 }
1670bffd 343
7d8f15e6
PP
344 g_ptr_array_add(dirs, home_plugin_dir_str);
345 }
1670bffd
PP
346 }
347
7d8f15e6
PP
348 if (find_in_sys_dir) {
349 const char *system_plugin_dir =
350 bt_common_get_system_plugin_path();
1670bffd 351
7d8f15e6
PP
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 }
1670bffd 361
7d8f15e6
PP
362 g_ptr_array_add(dirs, system_plugin_dir_str);
363 }
1670bffd
PP
364 }
365
7d8f15e6
PP
366 for (dir_i = 0; dir_i < dirs->len; dir_i++) {
367 GString *dir = dirs->pdata[dir_i];
1670bffd 368
8138bfe1 369 BT_OBJECT_PUT_REF_AND_RESET(plugin_set);
8c1a3187 370
50ad9320
PP
371 /*
372 * Skip this if the directory does not exist because
781ae911 373 * bt_plugin_find_all_from_dir() would log a warning.
50ad9320
PP
374 */
375 if (!g_file_test(dir->str, G_FILE_TEST_IS_DIR)) {
a684a357 376 BT_LOGI("Skipping nonexistent directory path: "
50ad9320
PP
377 "path=\"%s\"", dir->str);
378 continue;
379 }
380
781ae911 381 /* bt_plugin_find_all_from_dir() logs details/errors */
01f50d54
PP
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;
fb25b9e3 387 } else if (status == BT_FUNC_STATUS_NOT_FOUND) {
01f50d54 388 BT_ASSERT(!plugin_set);
a684a357 389 BT_LOGI("No plugins found in directory: path=\"%s\"",
8c1a3187 390 dir->str);
1670bffd
PP
391 continue;
392 }
393
fb25b9e3 394 BT_ASSERT(status == BT_FUNC_STATUS_OK);
01f50d54 395 BT_ASSERT(plugin_set);
7d8f15e6
PP
396 BT_LOGI("Found plugins in directory: path=\"%s\", count=%u",
397 dir->str, plugin_set->plugins->len);
01f50d54 398
7d8f15e6
PP
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 }
1670bffd 405
7d8f15e6
PP
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;
1670bffd 417 }
8c1a3187 418
7d8f15e6
PP
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
431end:
432 free(home_plugin_dir);
433 bt_object_put_ref(plugin_set);
434
435 if (dirs) {
436 g_ptr_array_free(dirs, TRUE);
1670bffd
PP
437 }
438
01f50d54 439 if (status < 0) {
7d8f15e6
PP
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
458enum 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);
a99db7a1 474 status = (enum bt_plugin_find_status) bt_plugin_find_all(find_in_std_env_var, find_in_user_dir,
7d8f15e6
PP
475 find_in_sys_dir, find_in_static, fail_on_load_error,
476 &plugin_set);
477 if (status != BT_FUNC_STATUS_OK) {
467bf409 478 BT_ASSERT(!plugin_set);
01f50d54
PP
479 goto end;
480 }
481
01f50d54
PP
482 BT_ASSERT(plugin_set);
483
7d8f15e6
PP
484 for (i = 0; i < plugin_set->plugins->len; i++) {
485 const struct bt_plugin *plugin = plugin_set->plugins->pdata[i];
01f50d54 486
7d8f15e6
PP
487 if (strcmp(plugin->info.name->str, plugin_name) == 0) {
488 *plugin_out = plugin;
864aa43f 489 bt_object_get_ref_no_null_check(*plugin_out);
01f50d54 490 goto end;
1670bffd 491 }
1670bffd
PP
492 }
493
fb25b9e3 494 status = BT_FUNC_STATUS_NOT_FOUND;
01f50d54 495
1670bffd 496end:
fb25b9e3 497 if (status == BT_FUNC_STATUS_OK) {
7d8f15e6 498 BT_ASSERT(*plugin_out);
a684a357 499 BT_LIB_LOGI("Found plugin in standard directories and built-in plugins: "
7d8f15e6
PP
500 "%!+l", *plugin_out);
501 } else if (status == BT_FUNC_STATUS_NOT_FOUND) {
a684a357 502 BT_LOGI("No plugin found in standard directories and built-in plugins: "
8c1a3187
PP
503 "name=\"%s\"", plugin_name);
504 }
505
467bf409
FD
506 bt_plugin_set_put_ref(plugin_set);
507
01f50d54 508 return status;
1670bffd
PP
509}
510
1307d39e
MJ
511static struct {
512 pthread_mutex_t lock;
513 struct bt_plugin_set *plugin_set;
834e9996 514 bool recurse;
01f50d54 515 bool fail_on_load_error;
fb25b9e3 516 int status;
1307d39e
MJ
517} append_all_from_dir_info = {
518 .lock = PTHREAD_MUTEX_INITIALIZER
519};
520
33b34c43 521static
01f50d54
PP
522int nftw_append_all_from_dir(const char *file,
523 const struct stat *sb, int flag, struct FTW *s)
33b34c43 524{
1307d39e
MJ
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:
be3c4e36 535 {
01f50d54 536 const struct bt_plugin_set *plugins_from_file = NULL;
be3c4e36 537
1307d39e
MJ
538 if (name[0] == '.') {
539 /* Skip hidden files */
a684a357 540 BT_LOGI("Skipping hidden file: path=\"%s\"", file);
1307d39e
MJ
541 goto end;
542 }
be3c4e36 543
01f50d54
PP
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);
fb25b9e3 548 if (append_all_from_dir_info.status == BT_FUNC_STATUS_OK) {
1307d39e
MJ
549 size_t j;
550
01f50d54
PP
551 BT_ASSERT(plugins_from_file);
552
1307d39e
MJ
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
a684a357 557 BT_LIB_LOGI("Adding plugin to plugin set: "
834e9996
PP
558 "plugin-path=\"%s\", %![plugin-]+l",
559 file, plugin);
3a2cb327
PP
560 bt_plugin_set_add_plugin(
561 append_all_from_dir_info.plugin_set,
562 plugin);
1307d39e 563 }
33b34c43 564
8138bfe1 565 bt_object_put_ref(plugins_from_file);
01f50d54
PP
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;
1307d39e 572 }
01f50d54
PP
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 ==
fb25b9e3 580 BT_FUNC_STATUS_NOT_FOUND);
1307d39e 581 break;
be3c4e36 582 }
1307d39e
MJ
583 case FTW_DNR:
584 /* Continue to next file / directory. */
01f50d54 585 BT_LOGI("Cannot enter directory: continuing: path=\"%s\"", file);
1307d39e
MJ
586 break;
587 case FTW_NS:
588 /* Continue to next file / directory. */
a684a357 589 BT_LOGI("Cannot get file information: continuing: path=\"%s\"", file);
1307d39e 590 break;
33b34c43 591 }
1307d39e
MJ
592
593end:
594 return ret;
33b34c43
PP
595}
596
597static
fb25b9e3
PP
598int 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)
33b34c43 600{
1307d39e 601 int nftw_flags = FTW_PHYS;
01f50d54 602 int ret;
fb25b9e3 603 int status;
f9d17c1c 604 struct stat sb;
33b34c43 605
834e9996
PP
606 BT_ASSERT(plugin_set);
607 BT_ASSERT(path);
608 BT_ASSERT(strlen(path) < PATH_MAX);
f9d17c1c
JR
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);
a8f90e5d
PP
622 (void) BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_UNKNOWN(
623 "Babeltrace library",
624 "Cannot open directory: path=\"%s\", recurse=%d",
625 path, recurse);
fb25b9e3 626 status = BT_FUNC_STATUS_ERROR;
f9d17c1c
JR
627 goto end;
628 }
629
1307d39e 630 pthread_mutex_lock(&append_all_from_dir_info.lock);
1307d39e
MJ
631 append_all_from_dir_info.plugin_set = plugin_set;
632 append_all_from_dir_info.recurse = recurse;
fb25b9e3 633 append_all_from_dir_info.status = BT_FUNC_STATUS_OK;
01f50d54 634 append_all_from_dir_info.fail_on_load_error = fail_on_load_error;
1307d39e
MJ
635 ret = nftw(path, nftw_append_all_from_dir,
636 APPEND_ALL_FROM_DIR_NFDOPEN_MAX, nftw_flags);
01f50d54
PP
637 append_all_from_dir_info.plugin_set = NULL;
638 status = append_all_from_dir_info.status;
1307d39e 639 pthread_mutex_unlock(&append_all_from_dir_info.lock);
01f50d54 640 if (ret) {
a8f90e5d 641 BT_LIB_LOGW_APPEND_CAUSE("Failed to walk directory",
01f50d54
PP
642 ": path=\"%s\", recurse=%d",
643 path, recurse);
fb25b9e3 644 status = BT_FUNC_STATUS_ERROR;
01f50d54
PP
645 goto end;
646 }
647
fb25b9e3 648 if (status == BT_FUNC_STATUS_NOT_FOUND) {
01f50d54
PP
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 */
fb25b9e3 654 status = BT_FUNC_STATUS_OK;
33b34c43 655 }
8c1a3187 656
01f50d54 657end:
70d47316 658 return status;
33b34c43
PP
659}
660
fb25b9e3
PP
661enum 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,
01f50d54 663 const struct bt_plugin_set **plugin_set_out)
33b34c43 664{
fb25b9e3
PP
665 enum bt_plugin_find_all_from_dir_status status =
666 BT_FUNC_STATUS_OK;
33b34c43 667
01f50d54 668 BT_ASSERT_PRE_NON_NULL(plugin_set_out, "Plugin set (output)");
a684a357 669 BT_LOGI("Creating all plugins in directory: path=\"%s\", recurse=%d",
8c1a3187 670 path, recurse);
01f50d54
PP
671 *plugin_set_out = bt_plugin_set_create();
672 if (!*plugin_set_out) {
a8f90e5d 673 BT_LIB_LOGE_APPEND_CAUSE("Cannot create empty plugin set.");
fb25b9e3 674 status = BT_FUNC_STATUS_MEMORY_ERROR;
a8ff38ef
PP
675 goto error;
676 }
677
01f50d54
PP
678 /*
679 * Append found plugins to array (never returns
fb25b9e3 680 * `BT_FUNC_STATUS_NOT_FOUND`)
01f50d54
PP
681 */
682 status = bt_plugin_create_append_all_from_dir((void *) *plugin_set_out,
683 path, recurse, fail_on_load_error);
33b34c43 684 if (status < 0) {
01f50d54
PP
685 /*
686 * bt_plugin_create_append_all_from_dir() handles
687 * `fail_on_load_error`, so this is a "real" error.
688 */
a8f90e5d
PP
689 BT_LIB_LOGE_APPEND_CAUSE(
690 "Cannot append plugins found in directory: "
dbd7f7e9 691 "path=\"%s\", status=%s",
fb25b9e3 692 path, bt_common_func_status_string(status));
33b34c43
PP
693 goto error;
694 }
695
fb25b9e3 696 BT_ASSERT(status == BT_FUNC_STATUS_OK);
01f50d54
PP
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);
fb25b9e3 701 status = BT_FUNC_STATUS_NOT_FOUND;
01f50d54
PP
702 goto error;
703 }
704
a684a357 705 BT_LOGI("Created %u plugins from directory: count=%u, path=\"%s\"",
01f50d54
PP
706 (*plugin_set_out)->plugins->len,
707 (*plugin_set_out)->plugins->len, path);
33b34c43
PP
708 goto end;
709
710error:
fb25b9e3 711 BT_ASSERT(status != BT_FUNC_STATUS_OK);
01f50d54 712 BT_OBJECT_PUT_REF_AND_RESET(*plugin_set_out);
33b34c43
PP
713
714end:
01f50d54 715 return status;
33b34c43
PP
716}
717
3a2cb327 718const char *bt_plugin_get_name(const struct bt_plugin *plugin)
33b34c43 719{
fa6cfec3 720 BT_ASSERT_PRE_DEV_NON_NULL(plugin, "Plugin");
834e9996 721 return plugin->info.name_set ? plugin->info.name->str : NULL;
33b34c43
PP
722}
723
3a2cb327 724const char *bt_plugin_get_author(const struct bt_plugin *plugin)
33b34c43 725{
fa6cfec3 726 BT_ASSERT_PRE_DEV_NON_NULL(plugin, "Plugin");
834e9996 727 return plugin->info.author_set ? plugin->info.author->str : NULL;
33b34c43
PP
728}
729
3a2cb327 730const char *bt_plugin_get_license(const struct bt_plugin *plugin)
33b34c43 731{
fa6cfec3 732 BT_ASSERT_PRE_DEV_NON_NULL(plugin, "Plugin");
834e9996 733 return plugin->info.license_set ? plugin->info.license->str : NULL;
33b34c43
PP
734}
735
3a2cb327 736const char *bt_plugin_get_path(const struct bt_plugin *plugin)
33b34c43 737{
fa6cfec3 738 BT_ASSERT_PRE_DEV_NON_NULL(plugin, "Plugin");
834e9996 739 return plugin->info.path_set ? plugin->info.path->str : NULL;
33b34c43
PP
740}
741
3a2cb327 742const char *bt_plugin_get_description(const struct bt_plugin *plugin)
33b34c43 743{
fa6cfec3 744 BT_ASSERT_PRE_DEV_NON_NULL(plugin, "Plugin");
834e9996
PP
745 return plugin->info.description_set ?
746 plugin->info.description->str : NULL;
33b34c43
PP
747}
748
3a2cb327 749enum bt_property_availability bt_plugin_get_version(const struct bt_plugin *plugin,
b6de043b
PP
750 unsigned int *major, unsigned int *minor, unsigned int *patch,
751 const char **extra)
752{
834e9996
PP
753 enum bt_property_availability avail =
754 BT_PROPERTY_AVAILABILITY_AVAILABLE;
b6de043b 755
fa6cfec3 756 BT_ASSERT_PRE_DEV_NON_NULL(plugin, "Plugin");
8c1a3187
PP
757
758 if (!plugin->info.version_set) {
a684a357 759 BT_LIB_LOGD("Plugin's version is not set: %!+l", plugin);
834e9996 760 avail = BT_PROPERTY_AVAILABILITY_NOT_AVAILABLE;
b6de043b
PP
761 goto end;
762 }
763
764 if (major) {
55bb57e0 765 *major = plugin->info.version.major;
b6de043b
PP
766 }
767
768 if (minor) {
55bb57e0 769 *minor = plugin->info.version.minor;
b6de043b
PP
770 }
771
772 if (patch) {
55bb57e0 773 *patch = plugin->info.version.patch;
b6de043b
PP
774 }
775
776 if (extra) {
55bb57e0 777 *extra = plugin->info.version.extra->str;
b6de043b
PP
778 }
779
780end:
834e9996 781 return avail;
b6de043b
PP
782}
783
3a2cb327 784uint64_t bt_plugin_get_source_component_class_count(const struct bt_plugin *plugin)
33b34c43 785{
fa6cfec3 786 BT_ASSERT_PRE_DEV_NON_NULL(plugin, "Plugin");
834e9996 787 return (uint64_t) plugin->src_comp_classes->len;
33b34c43
PP
788}
789
3a2cb327 790uint64_t bt_plugin_get_filter_component_class_count(const struct bt_plugin *plugin)
33b34c43 791{
fa6cfec3 792 BT_ASSERT_PRE_DEV_NON_NULL(plugin, "Plugin");
834e9996
PP
793 return (uint64_t) plugin->flt_comp_classes->len;
794}
33b34c43 795
3a2cb327 796uint64_t bt_plugin_get_sink_component_class_count(const struct bt_plugin *plugin)
834e9996 797{
fa6cfec3 798 BT_ASSERT_PRE_DEV_NON_NULL(plugin, "Plugin");
834e9996
PP
799 return (uint64_t) plugin->sink_comp_classes->len;
800}
8c1a3187 801
834e9996
PP
802static inline
803struct bt_component_class *borrow_component_class_by_index(
3a2cb327 804 const struct bt_plugin *plugin, GPtrArray *comp_classes,
834e9996
PP
805 uint64_t index)
806{
fa6cfec3
PP
807 BT_ASSERT_PRE_DEV_NON_NULL(plugin, "Plugin");
808 BT_ASSERT_PRE_DEV_VALID_INDEX(index, comp_classes->len);
834e9996
PP
809 return g_ptr_array_index(comp_classes, index);
810}
33b34c43 811
7b53201c 812const struct bt_component_class_source *
3eff3102 813bt_plugin_borrow_source_component_class_by_index_const(
3a2cb327 814 const struct bt_plugin *plugin, uint64_t index)
834e9996 815{
7b53201c 816 return (const void *) borrow_component_class_by_index(plugin,
834e9996
PP
817 plugin->src_comp_classes, index);
818}
33b34c43 819
7b53201c 820const struct bt_component_class_filter *
3a2cb327
PP
821bt_plugin_borrow_filter_component_class_by_index_const(
822 const struct bt_plugin *plugin, uint64_t index)
834e9996 823{
7b53201c 824 return (const void *) borrow_component_class_by_index(plugin,
834e9996
PP
825 plugin->flt_comp_classes, index);
826}
827
7b53201c 828const struct bt_component_class_sink *
3a2cb327
PP
829bt_plugin_borrow_sink_component_class_by_index_const(
830 const struct bt_plugin *plugin, uint64_t index)
834e9996 831{
7b53201c 832 return (const void *) borrow_component_class_by_index(plugin,
834e9996 833 plugin->sink_comp_classes, index);
33b34c43
PP
834}
835
834e9996
PP
836static inline
837struct bt_component_class *borrow_component_class_by_name(
3a2cb327 838 const struct bt_plugin *plugin, GPtrArray *comp_classes,
834e9996 839 const char *name)
33b34c43
PP
840{
841 struct bt_component_class *comp_class = NULL;
842 size_t i;
843
fa6cfec3
PP
844 BT_ASSERT_PRE_DEV_NON_NULL(plugin, "Plugin");
845 BT_ASSERT_PRE_DEV_NON_NULL(name, "Name");
33b34c43 846
834e9996 847 for (i = 0; i < comp_classes->len; i++) {
33b34c43 848 struct bt_component_class *comp_class_candidate =
834e9996 849 g_ptr_array_index(comp_classes, i);
33b34c43
PP
850 const char *comp_class_cand_name =
851 bt_component_class_get_name(comp_class_candidate);
33b34c43 852
ec4a3354 853 BT_ASSERT_DBG(comp_class_cand_name);
33b34c43 854
834e9996
PP
855 if (strcmp(name, comp_class_cand_name) == 0) {
856 comp_class = comp_class_candidate;
33b34c43
PP
857 break;
858 }
859 }
860
33b34c43
PP
861 return comp_class;
862}
863
7b53201c 864const struct bt_component_class_source *
3a2cb327
PP
865bt_plugin_borrow_source_component_class_by_name_const(
866 const struct bt_plugin *plugin, const char *name)
33b34c43 867{
7b53201c 868 return (const void *) borrow_component_class_by_name(plugin,
834e9996
PP
869 plugin->src_comp_classes, name);
870}
33b34c43 871
7b53201c 872const struct bt_component_class_filter *
3a2cb327
PP
873bt_plugin_borrow_filter_component_class_by_name_const(
874 const struct bt_plugin *plugin, const char *name)
834e9996 875{
7b53201c 876 return (const void *) borrow_component_class_by_name(plugin,
834e9996
PP
877 plugin->flt_comp_classes, name);
878}
33b34c43 879
7b53201c 880const struct bt_component_class_sink *
3a2cb327
PP
881bt_plugin_borrow_sink_component_class_by_name_const(
882 const struct bt_plugin *plugin, const char *name)
834e9996 883{
7b53201c 884 return (const void *) borrow_component_class_by_name(plugin,
834e9996 885 plugin->sink_comp_classes, name);
33b34c43 886}
8c6884d9
PP
887
888void bt_plugin_get_ref(const struct bt_plugin *plugin)
889{
890 bt_object_get_ref(plugin);
891}
892
893void bt_plugin_put_ref(const struct bt_plugin *plugin)
894{
895 bt_object_put_ref(plugin);
896}
897
898void bt_plugin_set_get_ref(const struct bt_plugin_set *plugin_set)
899{
900 bt_object_get_ref(plugin_set);
901}
902
903void 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.110108 seconds and 4 git commands to generate.