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