Do not use `bool` type; use new `bt_bool` instead
[babeltrace.git] / lib / plugin / plugin.c
1 /*
2 * plugin.c
3 *
4 * Babeltrace Plugin (generic)
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
30 #include <babeltrace/babeltrace-internal.h>
31 #include <babeltrace/compiler-internal.h>
32 #include <babeltrace/ref.h>
33 #include <babeltrace/common-internal.h>
34 #include <babeltrace/plugin/plugin-internal.h>
35 #include <babeltrace/plugin/plugin-so-internal.h>
36 #include <babeltrace/types.h>
37 #include <glib.h>
38 #include <unistd.h>
39 #include <stdlib.h>
40 #include <stdint.h>
41 #include <sys/stat.h>
42 #include <dirent.h>
43
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)
47
48 #ifdef BT_BUILT_IN_PYTHON_PLUGIN_SUPPORT
49 #include <babeltrace/plugin/python-plugin-provider-internal.h>
50 static
51 struct bt_plugin_set *(*bt_plugin_python_create_all_from_file_sym)(const char *path) =
52 bt_plugin_python_create_all_from_file;
53 #else /* BT_BUILT_IN_PYTHON_PLUGIN_SUPPORT */
54 static GModule *python_plugin_provider_module;
55 static
56 struct bt_plugin_set *(*bt_plugin_python_create_all_from_file_sym)(const char *path);
57
58 __attribute__((constructor)) static
59 void 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) {
64 printf_verbose("Cannot find `%s`: Python plugin support is disabled\n",
65 PYTHON_PLUGIN_PROVIDER_FILENAME);
66 return;
67 }
68
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)) {
72 printf_verbose("Cannot find the Python plugin provider loading symbole: Python plugin support is disabled\n");
73 }
74 }
75
76 __attribute__((destructor)) static
77 void 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;
81 }
82 }
83 #endif
84
85 extern
86 int64_t bt_plugin_set_get_plugin_count(struct bt_plugin_set *plugin_set)
87 {
88 int64_t count = -1;
89
90 if (!plugin_set) {
91 goto end;
92 }
93
94 count = (int64_t) plugin_set->plugins->len;
95
96 end:
97 return count;
98 }
99
100 extern
101 struct bt_plugin *bt_plugin_set_get_plugin(struct bt_plugin_set *plugin_set,
102 uint64_t index)
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
112 end:
113 return plugin;
114 }
115
116 struct bt_plugin_set *bt_plugin_create_all_from_static(void)
117 {
118 return bt_plugin_so_create_all_from_static();
119 }
120
121 struct bt_plugin_set *bt_plugin_create_all_from_file(const char *path)
122 {
123 struct bt_plugin_set *plugin_set = NULL;
124
125 if (!path) {
126 goto end;
127 }
128
129 printf_verbose("Trying to load plugins from `%s`\n", path);
130
131 /* Try shared object plugins */
132 plugin_set = bt_plugin_so_create_all_from_file(path);
133 if (plugin_set) {
134 goto end;
135 }
136
137 /* Try Python plugins if support is available */
138 if (bt_plugin_python_create_all_from_file_sym) {
139 plugin_set = bt_plugin_python_create_all_from_file_sym(path);
140 if (plugin_set) {
141 goto end;
142 }
143 }
144
145 end:
146 return plugin_set;
147 }
148
149 static void destroy_gstring(void *data)
150 {
151 g_string_free(data, TRUE);
152 }
153
154 struct bt_plugin *bt_plugin_find(const char *plugin_name)
155 {
156 const char *system_plugin_dir;
157 char *home_plugin_dir = NULL;
158 const char *envvar;
159 struct bt_plugin *plugin = NULL;
160 struct bt_plugin_set *plugin_set = NULL;
161 GPtrArray *dirs = NULL;
162 int ret;
163 size_t i, j;
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);
225 BT_PUT(plugin_set);
226 plugin_set = bt_plugin_create_all_from_dir(dir->str, BT_FALSE);
227 if (!plugin_set) {
228 continue;
229 }
230
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);
234
235 if (strcmp(bt_plugin_get_name(candidate_plugin),
236 plugin_name) == 0) {
237 plugin = bt_get(candidate_plugin);
238 goto end;
239 }
240 }
241 }
242
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);
249
250 if (strcmp(bt_plugin_get_name(candidate_plugin),
251 plugin_name) == 0) {
252 plugin = bt_get(candidate_plugin);
253 goto end;
254 }
255 }
256
257 end:
258 free(home_plugin_dir);
259 bt_put(plugin_set);
260
261 if (dirs) {
262 g_ptr_array_free(dirs, TRUE);
263 }
264
265 return plugin;
266 }
267
268 struct 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
287 end:
288 bt_put(plugin);
289 return comp_cls;
290 }
291
292 /* Allocate dirent as recommended by READDIR(3), NOTES on readdir_r */
293 static
294 struct 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
309 static
310 enum bt_plugin_status bt_plugin_create_append_all_from_dir(
311 struct bt_plugin_set *plugin_set, const char *path,
312 bt_bool recurse)
313 {
314 DIR *directory = NULL;
315 struct dirent *entry = NULL, *result = NULL;
316 char *file_path = NULL;
317 size_t path_len;
318 enum bt_plugin_status ret = BT_PLUGIN_STATUS_OK;
319
320 if (!path) {
321 ret = BT_PLUGIN_STATUS_ERROR;
322 goto end;
323 }
324
325 path_len = strlen(path);
326
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) {
352 printf_verbose("Failed to open plugin directory \"%s\"\n",
353 file_path);
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';
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) {
385 ret = bt_plugin_create_append_all_from_dir(plugin_set,
386 file_path, BT_TRUE);
387 if (ret < 0) {
388 goto end;
389 }
390 } else if (S_ISREG(st.st_mode)) {
391 struct bt_plugin_set *plugins_from_file =
392 bt_plugin_create_all_from_file(file_path);
393
394 if (plugins_from_file) {
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);
400
401 bt_plugin_set_add_plugin(plugin_set,
402 plugin);
403 }
404
405 bt_put(plugins_from_file);
406 }
407 }
408 }
409 end:
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
424 struct bt_plugin_set *bt_plugin_create_all_from_dir(const char *path,
425 bt_bool recurse)
426 {
427 struct bt_plugin_set *plugin_set;
428 enum bt_plugin_status status;
429
430 plugin_set = bt_plugin_set_create();
431 if (!plugin_set) {
432 goto error;
433 }
434
435 /* Append found plugins to array */
436 status = bt_plugin_create_append_all_from_dir(plugin_set, path,
437 recurse);
438 if (status < 0) {
439 goto error;
440 }
441
442 goto end;
443
444 error:
445 BT_PUT(plugin_set);
446
447 end:
448 return plugin_set;
449 }
450
451 const char *bt_plugin_get_name(struct bt_plugin *plugin)
452 {
453 return plugin && plugin->info.name_set ? plugin->info.name->str : NULL;
454 }
455
456 const char *bt_plugin_get_author(struct bt_plugin *plugin)
457 {
458 return plugin && plugin->info.author_set ? plugin->info.author->str : NULL;
459 }
460
461 const char *bt_plugin_get_license(struct bt_plugin *plugin)
462 {
463 return plugin && plugin->info.license_set ? plugin->info.license->str : NULL;
464 }
465
466 const char *bt_plugin_get_path(struct bt_plugin *plugin)
467 {
468 return plugin && plugin->info.path_set ? plugin->info.path->str : NULL;
469 }
470
471 const char *bt_plugin_get_description(struct bt_plugin *plugin)
472 {
473 return plugin && plugin->info.description_set ? plugin->info.description->str : NULL;
474 }
475
476 enum 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
482 if (!plugin || !plugin->info.version_set) {
483 status = BT_PLUGIN_STATUS_ERROR;
484 goto end;
485 }
486
487 if (major) {
488 *major = plugin->info.version.major;
489 }
490
491 if (minor) {
492 *minor = plugin->info.version.minor;
493 }
494
495 if (patch) {
496 *patch = plugin->info.version.patch;
497 }
498
499 if (extra) {
500 *extra = plugin->info.version.extra->str;
501 }
502
503 end:
504 return status;
505 }
506
507 int64_t bt_plugin_get_component_class_count(struct bt_plugin *plugin)
508 {
509 return plugin ? plugin->comp_classes->len : (int64_t) -1;
510 }
511
512 struct bt_component_class *bt_plugin_get_component_class_by_index(
513 struct bt_plugin *plugin, uint64_t index)
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
525 error:
526 BT_PUT(comp_class);
527
528 end:
529 return comp_class;
530 }
531
532 struct bt_component_class *bt_plugin_get_component_class_by_name_and_type(
533 struct bt_plugin *plugin, const char *name,
534 enum bt_component_class_type type)
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);
548 enum bt_component_class_type comp_class_cand_type =
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
563 error:
564 BT_PUT(comp_class);
565
566 end:
567 return comp_class;
568 }
569
570 enum 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;
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",
587 bt_plugin_get_name(plugin),
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
597 /* Special case for a shared object plugin */
598 if (plugin->type == BT_PLUGIN_TYPE_SO) {
599 bt_plugin_so_on_add_component_class(plugin, comp_class);
600 }
601
602 goto end;
603
604 error:
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
613 end:
614 bt_put(comp_class_dup);
615 return status;
616 }
This page took 0.045913 seconds and 4 git commands to generate.