Replace all assert(false) and assert(0) with abort()
[babeltrace.git] / lib / plugin / plugin.c
CommitLineData
33b34c43
PP
1/*
2 * plugin.c
3 *
55bb57e0 4 * Babeltrace Plugin (generic)
33b34c43
PP
5 *
6 * Copyright 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
7 * Copyright 2017 Philippe Proulx <pproulx@efficios.com>
8 *
9 * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
10 *
11 * Permission is hereby granted, free of charge, to any person obtaining a copy
12 * of this software and associated documentation files (the "Software"), to deal
13 * in the Software without restriction, including without limitation the rights
14 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15 * copies of the Software, and to permit persons to whom the Software is
16 * furnished to do so, subject to the following conditions:
17 *
18 * The above copyright notice and this permission notice shall be included in
19 * all copies or substantial portions of the Software.
20 *
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27 * SOFTWARE.
28 */
29
6fbd4105 30#include <babeltrace/babeltrace-internal.h>
3d9990ac 31#include <babeltrace/compiler-internal.h>
33b34c43 32#include <babeltrace/ref.h>
1670bffd 33#include <babeltrace/common-internal.h>
33b34c43 34#include <babeltrace/plugin/plugin-internal.h>
55bb57e0 35#include <babeltrace/plugin/plugin-so-internal.h>
c55a9f58 36#include <babeltrace/types.h>
33b34c43 37#include <glib.h>
33b34c43
PP
38#include <unistd.h>
39#include <stdlib.h>
9ac68eb1 40#include <stdint.h>
33b34c43
PP
41#include <sys/stat.h>
42#include <dirent.h>
43
6fbd4105
PP
44#define PYTHON_PLUGIN_PROVIDER_FILENAME "libbabeltrace-python-plugin-provider." G_MODULE_SUFFIX
45#define PYTHON_PLUGIN_PROVIDER_SYM_NAME bt_plugin_python_create_all_from_file
46#define PYTHON_PLUGIN_PROVIDER_SYM_NAME_STR TOSTRING(PYTHON_PLUGIN_PROVIDER_SYM_NAME)
33b34c43 47
6fbd4105
PP
48#ifdef BT_BUILT_IN_PYTHON_PLUGIN_SUPPORT
49#include <babeltrace/plugin/python-plugin-provider-internal.h>
33b34c43 50static
a8ff38ef 51struct bt_plugin_set *(*bt_plugin_python_create_all_from_file_sym)(const char *path) =
6fbd4105
PP
52 bt_plugin_python_create_all_from_file;
53#else /* BT_BUILT_IN_PYTHON_PLUGIN_SUPPORT */
54static GModule *python_plugin_provider_module;
55static
a8ff38ef 56struct bt_plugin_set *(*bt_plugin_python_create_all_from_file_sym)(const char *path);
33b34c43 57
6fbd4105
PP
58__attribute__((constructor)) static
59void init_python_plugin_provider(void) {
60 python_plugin_provider_module =
61 g_module_open(PYTHON_PLUGIN_PROVIDER_FILENAME,
62 G_MODULE_BIND_LOCAL);
63 if (!python_plugin_provider_module) {
1aec753b 64 printf_verbose("Cannot find `%s`: Python plugin support is disabled\n",
6fbd4105
PP
65 PYTHON_PLUGIN_PROVIDER_FILENAME);
66 return;
33b34c43
PP
67 }
68
6fbd4105
PP
69 if (!g_module_symbol(python_plugin_provider_module,
70 PYTHON_PLUGIN_PROVIDER_SYM_NAME_STR,
71 (gpointer) &bt_plugin_python_create_all_from_file_sym)) {
1aec753b 72 printf_verbose("Cannot find the Python plugin provider loading symbole: Python plugin support is disabled\n");
33b34c43 73 }
33b34c43
PP
74}
75
6fbd4105
PP
76__attribute__((destructor)) static
77void fini_python_plugin_provider(void) {
78 if (python_plugin_provider_module) {
79 (void) g_module_close(python_plugin_provider_module);
80 python_plugin_provider_module = NULL;
6ba0b073 81 }
6ba0b073 82}
6fbd4105 83#endif
6ba0b073 84
a8ff38ef 85extern
544d0515 86int64_t bt_plugin_set_get_plugin_count(struct bt_plugin_set *plugin_set)
a8ff38ef 87{
544d0515 88 int64_t count = -1;
a8ff38ef
PP
89
90 if (!plugin_set) {
91 goto end;
92 }
93
9ac68eb1 94 count = (int64_t) plugin_set->plugins->len;
a8ff38ef
PP
95
96end:
97 return count;
98}
99
100extern
101struct bt_plugin *bt_plugin_set_get_plugin(struct bt_plugin_set *plugin_set,
9ac68eb1 102 uint64_t index)
a8ff38ef
PP
103{
104 struct bt_plugin *plugin = NULL;
105
106 if (!plugin_set || index >= plugin_set->plugins->len) {
107 goto end;
108 }
109
110 plugin = bt_get(g_ptr_array_index(plugin_set->plugins, index));
111
112end:
113 return plugin;
114}
115
116struct bt_plugin_set *bt_plugin_create_all_from_static(void)
6ba0b073 117{
55bb57e0 118 return bt_plugin_so_create_all_from_static();
6ba0b073
PP
119}
120
a8ff38ef 121struct bt_plugin_set *bt_plugin_create_all_from_file(const char *path)
33b34c43 122{
a8ff38ef 123 struct bt_plugin_set *plugin_set = NULL;
33b34c43
PP
124
125 if (!path) {
6ba0b073 126 goto end;
33b34c43
PP
127 }
128
55bb57e0 129 printf_verbose("Trying to load plugins from `%s`\n", path);
6ba0b073 130
55bb57e0 131 /* Try shared object plugins */
a8ff38ef
PP
132 plugin_set = bt_plugin_so_create_all_from_file(path);
133 if (plugin_set) {
6ba0b073
PP
134 goto end;
135 }
136
6fbd4105
PP
137 /* Try Python plugins if support is available */
138 if (bt_plugin_python_create_all_from_file_sym) {
a8ff38ef
PP
139 plugin_set = bt_plugin_python_create_all_from_file_sym(path);
140 if (plugin_set) {
6fbd4105
PP
141 goto end;
142 }
6ba0b073
PP
143 }
144
33b34c43 145end:
a8ff38ef 146 return plugin_set;
33b34c43
PP
147}
148
1670bffd
PP
149static void destroy_gstring(void *data)
150{
151 g_string_free(data, TRUE);
152}
153
2b43acf9 154struct bt_plugin *bt_plugin_find(const char *plugin_name)
1670bffd
PP
155{
156 const char *system_plugin_dir;
157 char *home_plugin_dir = NULL;
158 const char *envvar;
159 struct bt_plugin *plugin = NULL;
a8ff38ef 160 struct bt_plugin_set *plugin_set = NULL;
1670bffd
PP
161 GPtrArray *dirs = NULL;
162 int ret;
a8ff38ef 163 size_t i, j;
1670bffd
PP
164
165 if (!plugin_name) {
166 goto end;
167 }
168
169 dirs = g_ptr_array_new_with_free_func((GDestroyNotify) destroy_gstring);
170 if (!dirs) {
171 goto end;
172 }
173
174 /*
175 * Search order is:
176 *
177 * 1. BABELTRACE_PLUGIN_PATH environment variable
178 * (colon-separated list of directories)
179 * 2. ~/.local/lib/babeltrace/plugins
180 * 3. Default system directory for Babeltrace plugins, usually
181 * /usr/lib/babeltrace/plugins or
182 * /usr/local/lib/babeltrace/plugins if installed
183 * locally
184 * 4. Built-in plugins (static)
185 *
186 * Directories are searched non-recursively.
187 */
188 envvar = getenv("BABELTRACE_PLUGIN_PATH");
189 if (envvar) {
190 ret = bt_common_append_plugin_path_dirs(envvar, dirs);
191 if (ret) {
192 goto end;
193 }
194 }
195
196 home_plugin_dir = bt_common_get_home_plugin_path();
197 if (home_plugin_dir) {
198 GString *home_plugin_dir_str =
199 g_string_new(home_plugin_dir);
200
201 if (!home_plugin_dir_str) {
202 goto end;
203 }
204
205 g_ptr_array_add(dirs, home_plugin_dir_str);
206 }
207
208 system_plugin_dir = bt_common_get_system_plugin_path();
209 if (system_plugin_dir) {
210 GString *system_plugin_dir_str =
211 g_string_new(system_plugin_dir);
212
213 if (!system_plugin_dir_str) {
214 goto end;
215 }
216
217 g_ptr_array_add(dirs, system_plugin_dir_str);
218 }
219
220 for (i = 0; i < dirs->len; i++) {
221 GString *dir = g_ptr_array_index(dirs, i);
222
223 printf_verbose("Trying to load plugins from directory `%s`\n",
224 dir->str);
a8ff38ef 225 BT_PUT(plugin_set);
c55a9f58 226 plugin_set = bt_plugin_create_all_from_dir(dir->str, BT_FALSE);
a8ff38ef 227 if (!plugin_set) {
1670bffd
PP
228 continue;
229 }
230
a8ff38ef
PP
231 for (j = 0; j < plugin_set->plugins->len; j++) {
232 struct bt_plugin *candidate_plugin =
233 g_ptr_array_index(plugin_set->plugins, j);
1670bffd 234
a8ff38ef
PP
235 if (strcmp(bt_plugin_get_name(candidate_plugin),
236 plugin_name) == 0) {
237 plugin = bt_get(candidate_plugin);
1670bffd
PP
238 goto end;
239 }
1670bffd
PP
240 }
241 }
242
a8ff38ef
PP
243 bt_put(plugin_set);
244 plugin_set = bt_plugin_create_all_from_static();
245
246 for (j = 0; j < plugin_set->plugins->len; j++) {
247 struct bt_plugin *candidate_plugin =
248 g_ptr_array_index(plugin_set->plugins, j);
1670bffd 249
a8ff38ef
PP
250 if (strcmp(bt_plugin_get_name(candidate_plugin),
251 plugin_name) == 0) {
252 plugin = bt_get(candidate_plugin);
1670bffd
PP
253 goto end;
254 }
1670bffd
PP
255 }
256
257end:
258 free(home_plugin_dir);
a8ff38ef 259 bt_put(plugin_set);
1670bffd
PP
260
261 if (dirs) {
262 g_ptr_array_free(dirs, TRUE);
263 }
264
265 return plugin;
266}
267
2b43acf9
PP
268struct bt_component_class *bt_plugin_find_component_class(
269 const char *plugin_name, const char *comp_cls_name,
270 enum bt_component_class_type comp_cls_type)
271{
272 struct bt_plugin *plugin = NULL;
273 struct bt_component_class *comp_cls = NULL;
274
275 if (!plugin_name || !comp_cls_name) {
276 goto end;
277 }
278
279 plugin = bt_plugin_find(plugin_name);
280 if (!plugin) {
281 goto end;
282 }
283
284 comp_cls = bt_plugin_get_component_class_by_name_and_type(
285 plugin, comp_cls_name, comp_cls_type);
286
287end:
288 bt_put(plugin);
289 return comp_cls;
290}
291
33b34c43
PP
292/* Allocate dirent as recommended by READDIR(3), NOTES on readdir_r */
293static
294struct dirent *alloc_dirent(const char *path)
295{
296 size_t len;
297 long name_max;
298 struct dirent *entry;
299
300 name_max = pathconf(path, _PC_NAME_MAX);
301 if (name_max == -1) {
302 name_max = PATH_MAX;
303 }
304 len = offsetof(struct dirent, d_name) + name_max + 1;
305 entry = zmalloc(len);
306 return entry;
307}
308
309static
310enum bt_plugin_status bt_plugin_create_append_all_from_dir(
a8ff38ef 311 struct bt_plugin_set *plugin_set, const char *path,
c55a9f58 312 bt_bool recurse)
33b34c43
PP
313{
314 DIR *directory = NULL;
315 struct dirent *entry = NULL, *result = NULL;
316 char *file_path = NULL;
6ba0b073 317 size_t path_len;
33b34c43
PP
318 enum bt_plugin_status ret = BT_PLUGIN_STATUS_OK;
319
6ba0b073
PP
320 if (!path) {
321 ret = BT_PLUGIN_STATUS_ERROR;
322 goto end;
323 }
324
325 path_len = strlen(path);
326
33b34c43
PP
327 if (path_len >= PATH_MAX) {
328 ret = BT_PLUGIN_STATUS_ERROR;
329 goto end;
330 }
331
332 entry = alloc_dirent(path);
333 if (!entry) {
334 ret = BT_PLUGIN_STATUS_ERROR;
335 goto end;
336 }
337
338 file_path = zmalloc(PATH_MAX);
339 if (!file_path) {
340 ret = BT_PLUGIN_STATUS_NOMEM;
341 goto end;
342 }
343
344 strncpy(file_path, path, path_len);
345 /* Append a trailing '/' to the path */
346 if (file_path[path_len - 1] != '/') {
347 file_path[path_len++] = '/';
348 }
349
350 directory = opendir(file_path);
351 if (!directory) {
47e56665
PP
352 printf_verbose("Failed to open plugin directory \"%s\"\n",
353 file_path);
33b34c43
PP
354 ret = BT_PLUGIN_STATUS_ERROR;
355 goto end;
356 }
357
358 /* Recursively walk directory */
359 while (!readdir_r(directory, entry, &result) && result) {
360 struct stat st;
361 int stat_ret;
362 size_t file_name_len;
363
364 if (result->d_name[0] == '.') {
365 /* Skip hidden files, . and .. */
366 continue;
367 }
368
369 file_name_len = strlen(result->d_name);
370
371 if (path_len + file_name_len >= PATH_MAX) {
372 continue;
373 }
374
375 strncpy(file_path + path_len, result->d_name, file_name_len);
376 file_path[path_len + file_name_len] = '\0';
33b34c43
PP
377 stat_ret = stat(file_path, &st);
378 if (stat_ret < 0) {
379 /* Continue to next file / directory. */
380 printf_perror("Failed to stat() plugin file\n");
381 continue;
382 }
383
384 if (S_ISDIR(st.st_mode) && recurse) {
a8ff38ef 385 ret = bt_plugin_create_append_all_from_dir(plugin_set,
c55a9f58 386 file_path, BT_TRUE);
33b34c43
PP
387 if (ret < 0) {
388 goto end;
389 }
390 } else if (S_ISREG(st.st_mode)) {
a8ff38ef 391 struct bt_plugin_set *plugins_from_file =
6ba0b073 392 bt_plugin_create_all_from_file(file_path);
33b34c43 393
6ba0b073 394 if (plugins_from_file) {
a8ff38ef
PP
395 size_t j;
396
397 for (j = 0; j < plugins_from_file->plugins->len; j++) {
398 struct bt_plugin *plugin =
399 g_ptr_array_index(plugins_from_file->plugins, j);
6ba0b073 400
a8ff38ef
PP
401 bt_plugin_set_add_plugin(plugin_set,
402 plugin);
6ba0b073
PP
403 }
404
a8ff38ef 405 bt_put(plugins_from_file);
33b34c43
PP
406 }
407 }
408 }
409end:
410 if (directory) {
411 if (closedir(directory)) {
412 /*
413 * We don't want to override the error since there is
414 * nothing could do.
415 */
416 perror("Failed to close plug-in directory");
417 }
418 }
419 free(entry);
420 free(file_path);
421 return ret;
422}
423
a8ff38ef 424struct bt_plugin_set *bt_plugin_create_all_from_dir(const char *path,
c55a9f58 425 bt_bool recurse)
33b34c43 426{
a8ff38ef 427 struct bt_plugin_set *plugin_set;
33b34c43
PP
428 enum bt_plugin_status status;
429
a8ff38ef
PP
430 plugin_set = bt_plugin_set_create();
431 if (!plugin_set) {
432 goto error;
433 }
434
33b34c43 435 /* Append found plugins to array */
a8ff38ef 436 status = bt_plugin_create_append_all_from_dir(plugin_set, path,
33b34c43
PP
437 recurse);
438 if (status < 0) {
439 goto error;
440 }
441
33b34c43
PP
442 goto end;
443
444error:
a8ff38ef 445 BT_PUT(plugin_set);
33b34c43
PP
446
447end:
a8ff38ef 448 return plugin_set;
33b34c43
PP
449}
450
33b34c43
PP
451const char *bt_plugin_get_name(struct bt_plugin *plugin)
452{
55bb57e0 453 return plugin && plugin->info.name_set ? plugin->info.name->str : NULL;
33b34c43
PP
454}
455
456const char *bt_plugin_get_author(struct bt_plugin *plugin)
457{
55bb57e0 458 return plugin && plugin->info.author_set ? plugin->info.author->str : NULL;
33b34c43
PP
459}
460
461const char *bt_plugin_get_license(struct bt_plugin *plugin)
462{
55bb57e0 463 return plugin && plugin->info.license_set ? plugin->info.license->str : NULL;
33b34c43
PP
464}
465
466const char *bt_plugin_get_path(struct bt_plugin *plugin)
467{
55bb57e0 468 return plugin && plugin->info.path_set ? plugin->info.path->str : NULL;
33b34c43
PP
469}
470
471const char *bt_plugin_get_description(struct bt_plugin *plugin)
472{
55bb57e0 473 return plugin && plugin->info.description_set ? plugin->info.description->str : NULL;
33b34c43
PP
474}
475
b6de043b
PP
476enum bt_plugin_status bt_plugin_get_version(struct bt_plugin *plugin,
477 unsigned int *major, unsigned int *minor, unsigned int *patch,
478 const char **extra)
479{
480 enum bt_plugin_status status = BT_PLUGIN_STATUS_OK;
481
55bb57e0 482 if (!plugin || !plugin->info.version_set) {
b6de043b
PP
483 status = BT_PLUGIN_STATUS_ERROR;
484 goto end;
485 }
486
487 if (major) {
55bb57e0 488 *major = plugin->info.version.major;
b6de043b
PP
489 }
490
491 if (minor) {
55bb57e0 492 *minor = plugin->info.version.minor;
b6de043b
PP
493 }
494
495 if (patch) {
55bb57e0 496 *patch = plugin->info.version.patch;
b6de043b
PP
497 }
498
499 if (extra) {
55bb57e0 500 *extra = plugin->info.version.extra->str;
b6de043b
PP
501 }
502
503end:
504 return status;
505}
506
544d0515 507int64_t bt_plugin_get_component_class_count(struct bt_plugin *plugin)
33b34c43 508{
9ac68eb1 509 return plugin ? plugin->comp_classes->len : (int64_t) -1;
33b34c43
PP
510}
511
9ac68eb1
PP
512struct bt_component_class *bt_plugin_get_component_class_by_index(
513 struct bt_plugin *plugin, uint64_t index)
33b34c43
PP
514{
515 struct bt_component_class *comp_class = NULL;
516
517 if (!plugin || index >= plugin->comp_classes->len) {
518 goto error;
519 }
520
521 comp_class = g_ptr_array_index(plugin->comp_classes, index);
522 bt_get(comp_class);
523 goto end;
524
525error:
526 BT_PUT(comp_class);
527
528end:
529 return comp_class;
530}
531
532struct bt_component_class *bt_plugin_get_component_class_by_name_and_type(
533 struct bt_plugin *plugin, const char *name,
d3e4dcd8 534 enum bt_component_class_type type)
33b34c43
PP
535{
536 struct bt_component_class *comp_class = NULL;
537 size_t i;
538
539 if (!plugin || !name) {
540 goto error;
541 }
542
543 for (i = 0; i < plugin->comp_classes->len; i++) {
544 struct bt_component_class *comp_class_candidate =
545 g_ptr_array_index(plugin->comp_classes, i);
546 const char *comp_class_cand_name =
547 bt_component_class_get_name(comp_class_candidate);
d3e4dcd8 548 enum bt_component_class_type comp_class_cand_type =
33b34c43
PP
549 bt_component_class_get_type(comp_class_candidate);
550
551 assert(comp_class_cand_name);
552 assert(comp_class_cand_type >= 0);
553
554 if (strcmp(name, comp_class_cand_name) == 0 &&
555 comp_class_cand_type == type) {
556 comp_class = bt_get(comp_class_candidate);
557 break;
558 }
559 }
560
561 goto end;
562
563error:
564 BT_PUT(comp_class);
565
566end:
567 return comp_class;
568}
569
33b34c43
PP
570enum bt_plugin_status bt_plugin_add_component_class(
571 struct bt_plugin *plugin, struct bt_component_class *comp_class)
572{
573 enum bt_plugin_status status = BT_PLUGIN_STATUS_OK;
574 struct bt_component_class *comp_class_dup = NULL;
33b34c43
PP
575 int comp_class_index = -1;
576
577 if (!plugin || !comp_class || plugin->frozen) {
578 goto error;
579 }
580
581 /* Check for duplicate */
582 comp_class_dup = bt_plugin_get_component_class_by_name_and_type(plugin,
583 bt_component_class_get_name(comp_class),
584 bt_component_class_get_type(comp_class));
585 if (comp_class_dup) {
586 printf_verbose("Plugin `%s`: adding component class with existing name `%s` and type %d\n",
55bb57e0 587 bt_plugin_get_name(plugin),
33b34c43
PP
588 bt_component_class_get_name(comp_class),
589 bt_component_class_get_type(comp_class));
590 goto error;
591 }
592
593 /* Add new component class */
594 comp_class_index = plugin->comp_classes->len;
595 g_ptr_array_add(plugin->comp_classes, bt_get(comp_class));
596
55bb57e0
PP
597 /* Special case for a shared object plugin */
598 if (plugin->type == BT_PLUGIN_TYPE_SO) {
3230ee6b 599 bt_plugin_so_on_add_component_class(plugin, comp_class);
33b34c43
PP
600 }
601
602 goto end;
603
604error:
33b34c43
PP
605 /* Remove entry from plugin's component classes (if added) */
606 if (comp_class_index >= 0) {
607 g_ptr_array_remove_index(plugin->comp_classes,
608 comp_class_index);
609 }
610
611 status = BT_PLUGIN_STATUS_ERROR;
612
613end:
614 bt_put(comp_class_dup);
615 return status;
616}
This page took 0.053391 seconds and 4 git commands to generate.