plugin-dev.h: put selector (type) close to union in structures
[babeltrace.git] / lib / plugin / plugin.c
CommitLineData
33b34c43
PP
1/*
2 * plugin.c
3 *
4 * Babeltrace Plugin
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/compiler.h>
31#include <babeltrace/ref.h>
32#include <babeltrace/plugin/plugin-dev.h>
33#include <babeltrace/plugin/plugin-internal.h>
34#include <babeltrace/component/component-class-internal.h>
35#include <string.h>
36#include <stdbool.h>
37#include <glib.h>
38#include <gmodule.h>
39#include <unistd.h>
40#include <stdlib.h>
41#include <sys/stat.h>
42#include <dirent.h>
43
33b34c43
PP
44#define NATIVE_PLUGIN_SUFFIX ".so"
45#define NATIVE_PLUGIN_SUFFIX_LEN sizeof(NATIVE_PLUGIN_SUFFIX)
46#define LIBTOOL_PLUGIN_SUFFIX ".la"
47#define LIBTOOL_PLUGIN_SUFFIX_LEN sizeof(LIBTOOL_PLUGIN_SUFFIX)
48
49#define PLUGIN_SUFFIX_LEN max_t(size_t, sizeof(NATIVE_PLUGIN_SUFFIX), \
50 sizeof(LIBTOOL_PLUGIN_SUFFIX))
51
6ba0b073
PP
52#define SECTION_BEGIN(_name) (&(__start_##_name))
53#define SECTION_END(_name) (&(__stop_##_name))
33b34c43
PP
54#define SECTION_ELEMENT_COUNT(_name) (SECTION_END(_name) - SECTION_BEGIN(_name))
55
56#define DECLARE_SECTION(_type, _name) \
6ba0b073
PP
57 extern _type __start_##_name __attribute((weak)); \
58 extern _type __stop_##_name __attribute((weak))
59
60DECLARE_SECTION(struct __bt_plugin_descriptor const *, __bt_plugin_descriptors);
61DECLARE_SECTION(struct __bt_plugin_descriptor_attribute const *, __bt_plugin_descriptor_attributes);
62DECLARE_SECTION(struct __bt_plugin_component_class_descriptor const *, __bt_plugin_component_class_descriptors);
63DECLARE_SECTION(struct __bt_plugin_component_class_descriptor_attribute const *, __bt_plugin_component_class_descriptor_attributes);
33b34c43
PP
64
65/*
66 * This hash table, global to the library, maps component class pointers
67 * to shared library handles.
68 *
69 * The keys (component classes) are NOT owned by this hash table, whereas
70 * the values (shared library handles) are owned by this hash table.
71 *
72 * The keys are the component classes created with
73 * bt_plugin_add_component_class(). They keep the shared library handle
74 * object created by their plugin alive so that the plugin's code is
75 * not discarded when it could still be in use by living components
76 * created from those component classes:
77 *
78 * [component] --ref-> [component class] --through this HT-> [shlib handle]
79 *
80 * This hash table exists for two reasons:
81 *
82 * 1. To allow this application:
83 *
6ba0b073
PP
84 * my_plugins = bt_plugin_create_all_from_file("/path/to/my-plugin.so");
85 * // instantiate components from a plugin's component classes
86 * // put plugins and free my_plugins here
33b34c43
PP
87 * // user code of instantiated components still exists
88 *
89 * 2. To decouple the plugin subsystem from the component subsystem:
90 * while plugins objects need to know component class objects, the
91 * opposite is not necessary, thus it makes no sense for a component
92 * class to keep a reference to the plugin object from which it was
93 * created.
94 *
95 * An entry is removed from this HT when a component class is destroyed
96 * thanks to a custom destroy listener. When the entry is removed, the
97 * GLib function calls the value destroy notifier of the HT, which is
98 * bt_put(). This decreases the reference count of the mapped shared
99 * library handle. Assuming the original plugin object which contained
100 * some component classes is put first, when the last component class is
101 * removed from this HT, the shared library handle object's reference
102 * count falls to zero and the shared library is finally closed.
103 */
104static
105GHashTable *comp_classes_to_shlib_handles;
106
107__attribute__((constructor)) static
108void init_comp_classes_to_shlib_handles(void) {
109 comp_classes_to_shlib_handles = g_hash_table_new_full(g_direct_hash,
110 g_direct_equal, NULL, bt_put);
111 assert(comp_classes_to_shlib_handles);
112}
113
114__attribute__((destructor)) static
115void fini_comp_classes_to_shlib_handles(void) {
116 if (comp_classes_to_shlib_handles) {
117 g_hash_table_destroy(comp_classes_to_shlib_handles);
118 }
119}
120
121static
122void bt_plugin_shared_lib_handle_destroy(struct bt_object *obj)
123{
124 struct bt_plugin_shared_lib_handle *shared_lib_handle;
125
126 assert(obj);
127 shared_lib_handle = container_of(obj,
128 struct bt_plugin_shared_lib_handle, base);
129
130 if (shared_lib_handle->init_called && shared_lib_handle->exit) {
131 enum bt_plugin_status status = shared_lib_handle->exit();
132
133 if (status < 0) {
6ba0b073
PP
134 const char *path = shared_lib_handle->path ?
135 shared_lib_handle->path->str : "[built-in]";
136
137 printf_verbose("Plugin in module `%s` exited with error %d\n",
138 path, status);
33b34c43
PP
139 }
140 }
141
142 if (shared_lib_handle->module) {
143 if (!g_module_close(shared_lib_handle->module)) {
144 printf_error("Module close error: %s\n",
145 g_module_error());
146 }
147 }
148
149 if (shared_lib_handle->path) {
150 g_string_free(shared_lib_handle->path, TRUE);
151 }
152
153 g_free(shared_lib_handle);
154}
155
156static
157struct bt_plugin_shared_lib_handle *bt_plugin_shared_lib_handle_create(
158 const char *path)
159{
160 struct bt_plugin_shared_lib_handle *shared_lib_handle = NULL;
33b34c43
PP
161
162 shared_lib_handle = g_new0(struct bt_plugin_shared_lib_handle, 1);
163 if (!shared_lib_handle) {
164 goto error;
165 }
166
167 bt_object_init(shared_lib_handle, bt_plugin_shared_lib_handle_destroy);
168
169 if (!path) {
170 goto end;
171 }
172
173 shared_lib_handle->path = g_string_new(path);
174 if (!shared_lib_handle->path) {
175 goto error;
176 }
177
178 shared_lib_handle->module = g_module_open(path, 0);
179 if (!shared_lib_handle->module) {
180 printf_verbose("Module open error: %s\n", g_module_error());
181 goto error;
182 }
183
33b34c43
PP
184 goto end;
185
186error:
187 BT_PUT(shared_lib_handle);
188
189end:
190 return shared_lib_handle;
191}
192
193static
194void bt_plugin_destroy(struct bt_object *obj)
195{
196 struct bt_plugin *plugin;
197
198 assert(obj);
199 plugin = container_of(obj, struct bt_plugin, base);
200
201 BT_PUT(plugin->shared_lib_handle);
202
203 if (plugin->comp_classes) {
204 g_ptr_array_free(plugin->comp_classes, TRUE);
205 }
206
207 g_free(plugin);
208}
209
210static
6ba0b073
PP
211struct bt_plugin *bt_plugin_create_empty(
212 struct bt_plugin_shared_lib_handle *shared_lib_handle)
213{
214 struct bt_plugin *plugin = NULL;
215
216 plugin = g_new0(struct bt_plugin, 1);
217 if (!plugin) {
218 goto error;
219 }
220
221 bt_object_init(plugin, bt_plugin_destroy);
222 plugin->shared_lib_handle = bt_get(shared_lib_handle);
223
224 /* Create empty array of component classes */
225 plugin->comp_classes =
226 g_ptr_array_new_with_free_func((GDestroyNotify) bt_put);
227 if (!plugin->comp_classes) {
228 goto error;
229 }
230
231 goto end;
232
233error:
234 BT_PUT(plugin);
235
236end:
237 return plugin;
238}
239
d3e4dcd8
PP
240/*
241 * This function does the following:
242 *
243 * 1. Iterate on the plugin descriptor attributes section and set the
244 * plugin's attributes depending on the attribute types. This
245 * includes the name of the plugin, its description, and its
246 * initialization function, for example.
247 *
248 * 2. Iterate on the component class descriptors section and create one
249 * "full descriptor" (temporary structure) for each one that is found
250 * and attached to our plugin descriptor.
251 *
252 * 3. Iterate on the component class descriptor attributes section and
253 * set the corresponding full descriptor's attributes depending on
254 * the attribute types. This includes the description of the
255 * component class, as well as its initialization and destroy
256 * methods.
257 *
258 * 4. Call the user's plugin initialization function, if any is
259 * defined.
260 *
261 * 5. For each full component class descriptor, create a component class
262 * object, set its optional attributes, and add it to the plugin
263 * object.
264 *
265 * 6. Freeze the plugin object.
266 */
6ba0b073
PP
267static
268enum bt_plugin_status bt_plugin_init(
269 struct bt_plugin *plugin,
270 const struct __bt_plugin_descriptor *descriptor,
271 struct __bt_plugin_descriptor_attribute const * const *attrs_begin,
272 struct __bt_plugin_descriptor_attribute const * const *attrs_end,
273 struct __bt_plugin_component_class_descriptor const * const *cc_descriptors_begin,
274 struct __bt_plugin_component_class_descriptor const * const *cc_descriptors_end,
275 struct __bt_plugin_component_class_descriptor_attribute const * const *cc_descr_attrs_begin,
276 struct __bt_plugin_component_class_descriptor_attribute const * const *cc_descr_attrs_end)
33b34c43 277{
6ba0b073
PP
278 /*
279 * This structure's members point to the plugin's memory
280 * (do NOT free).
281 */
282 struct comp_class_full_descriptor {
283 const struct __bt_plugin_component_class_descriptor *descriptor;
284 const char *description;
d3e4dcd8
PP
285 bt_component_class_init_method init_method;
286 bt_component_class_destroy_method destroy_method;
287 bt_component_class_filter_add_iterator_method filter_add_iterator_method;
288 bt_component_class_sink_add_iterator_method sink_add_iterator_method;
6ba0b073
PP
289 };
290
33b34c43 291 enum bt_plugin_status status = BT_PLUGIN_STATUS_OK;
6ba0b073
PP
292 struct __bt_plugin_descriptor_attribute const * const *cur_attr_ptr;
293 struct __bt_plugin_component_class_descriptor const * const *cur_cc_descr_ptr;
294 struct __bt_plugin_component_class_descriptor_attribute const * const *cur_cc_descr_attr_ptr;
295 GArray *comp_class_full_descriptors;
296 size_t i;
d3e4dcd8 297 int ret;
6ba0b073
PP
298
299 comp_class_full_descriptors = g_array_new(FALSE, TRUE,
300 sizeof(struct comp_class_full_descriptor));
301 if (!comp_class_full_descriptors) {
302 status = BT_PLUGIN_STATUS_ERROR;
303 goto end;
304 }
33b34c43 305
6ba0b073
PP
306 /* Set mandatory attributes */
307 plugin->descriptor = descriptor;
308 plugin->name = descriptor->name;
33b34c43 309
6ba0b073
PP
310 /*
311 * Find and set optional attributes attached to this plugin
312 * descriptor.
313 */
314 for (cur_attr_ptr = attrs_begin; cur_attr_ptr != attrs_end; cur_attr_ptr++) {
315 const struct __bt_plugin_descriptor_attribute *cur_attr =
316 *cur_attr_ptr;
317
318 if (cur_attr->plugin_descriptor != descriptor) {
319 continue;
320 }
321
322 switch (cur_attr->type) {
323 case BT_PLUGIN_DESCRIPTOR_ATTRIBUTE_TYPE_INIT:
324 plugin->init = cur_attr->value.init;
325 break;
326 case BT_PLUGIN_DESCRIPTOR_ATTRIBUTE_TYPE_EXIT:
327 plugin->shared_lib_handle->exit = cur_attr->value.exit;
328 break;
329 case BT_PLUGIN_DESCRIPTOR_ATTRIBUTE_TYPE_AUTHOR:
330 plugin->author = cur_attr->value.author;
331 break;
332 case BT_PLUGIN_DESCRIPTOR_ATTRIBUTE_TYPE_LICENSE:
333 plugin->license = cur_attr->value.license;
334 break;
335 case BT_PLUGIN_DESCRIPTOR_ATTRIBUTE_TYPE_DESCRIPTION:
336 plugin->description = cur_attr->value.description;
337 break;
b6de043b
PP
338 case BT_PLUGIN_DESCRIPTOR_ATTRIBUTE_TYPE_VERSION:
339 plugin->version = &cur_attr->value.version;
340 break;
6ba0b073
PP
341 default:
342 printf_verbose("WARNING: Unknown attribute \"%s\" (type %d) for plugin %s\n",
343 cur_attr->type_name, cur_attr->type,
344 descriptor->name);
345 break;
346 }
347 }
348
349 /*
350 * Find component class descriptors attached to this plugin
351 * descriptor and initialize corresponding full component class
352 * descriptors in the array.
353 */
354 for (cur_cc_descr_ptr = cc_descriptors_begin; cur_cc_descr_ptr != cc_descriptors_end; cur_cc_descr_ptr++) {
355 const struct __bt_plugin_component_class_descriptor *cur_cc_descr =
356 *cur_cc_descr_ptr;
d3e4dcd8 357 struct comp_class_full_descriptor full_descriptor = {0};
6ba0b073
PP
358
359 if (cur_cc_descr->plugin_descriptor != descriptor) {
360 continue;
361 }
362
363 full_descriptor.descriptor = cur_cc_descr;
6ba0b073
PP
364 g_array_append_val(comp_class_full_descriptors,
365 full_descriptor);
366 }
367
368 /*
369 * Find component class descriptor attributes attached to this
370 * plugin descriptor and update corresponding full component
371 * class descriptors in the array.
372 */
373 for (cur_cc_descr_attr_ptr = cc_descr_attrs_begin; cur_cc_descr_attr_ptr != cc_descr_attrs_end; cur_cc_descr_attr_ptr++) {
374 const struct __bt_plugin_component_class_descriptor_attribute *cur_cc_descr_attr =
375 *cur_cc_descr_attr_ptr;
376
377 if (cur_cc_descr_attr->comp_class_descriptor->plugin_descriptor !=
378 descriptor) {
379 continue;
380 }
381
382 /* Find the corresponding component class descriptor entry */
383 for (i = 0; i < comp_class_full_descriptors->len; i++) {
384 struct comp_class_full_descriptor *cc_full_descr =
385 &g_array_index(comp_class_full_descriptors,
386 struct comp_class_full_descriptor, i);
387
388 if (cur_cc_descr_attr->comp_class_descriptor ==
389 cc_full_descr->descriptor) {
390 switch (cur_cc_descr_attr->type) {
391 case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_DESCRIPTION:
392 cc_full_descr->description =
393 cur_cc_descr_attr->value.description;
394 break;
d3e4dcd8
PP
395 case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_INIT_METHOD:
396 cc_full_descr->init_method =
397 cur_cc_descr_attr->value.init_method;
398 break;
399 case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_DESTROY_METHOD:
400 cc_full_descr->destroy_method =
401 cur_cc_descr_attr->value.destroy_method;
402 break;
403 case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_FILTER_ADD_ITERATOR_METHOD:
404 cc_full_descr->filter_add_iterator_method =
405 cur_cc_descr_attr->value.filter_add_iterator_method;
406 break;
407 case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_SINK_ADD_ITERATOR_METHOD:
408 cc_full_descr->sink_add_iterator_method =
409 cur_cc_descr_attr->value.sink_add_iterator_method;
410 break;
6ba0b073
PP
411 default:
412 printf_verbose("WARNING: Unknown attribute \"%s\" (type %d) for component class %s (type %d) in plugin %s\n",
413 cur_cc_descr_attr->type_name,
414 cur_cc_descr_attr->type,
415 cur_cc_descr_attr->comp_class_descriptor->name,
416 cur_cc_descr_attr->comp_class_descriptor->type,
417 descriptor->name);
418 break;
419 }
420 }
421 }
422 }
423
424 /* Initialize plugin */
425 if (plugin->init) {
426 status = plugin->init(plugin);
33b34c43
PP
427 if (status < 0) {
428 printf_verbose("Plugin `%s` initialization error: %d\n",
6ba0b073 429 plugin->name, status);
33b34c43
PP
430 goto end;
431 }
432 }
433
434 plugin->shared_lib_handle->init_called = true;
435
d3e4dcd8 436 /* Add described component classes to plugin */
6ba0b073
PP
437 for (i = 0; i < comp_class_full_descriptors->len; i++) {
438 struct comp_class_full_descriptor *cc_full_descr =
439 &g_array_index(comp_class_full_descriptors,
440 struct comp_class_full_descriptor, i);
441 struct bt_component_class *comp_class;
442
d3e4dcd8
PP
443 switch (cc_full_descr->descriptor->type) {
444 case BT_COMPONENT_CLASS_TYPE_SOURCE:
445 comp_class = bt_component_class_source_create(
446 cc_full_descr->descriptor->name,
447 cc_full_descr->descriptor->methods.source.init_iterator);
448 break;
449 case BT_COMPONENT_CLASS_TYPE_FILTER:
450 comp_class = bt_component_class_filter_create(
451 cc_full_descr->descriptor->name,
452 cc_full_descr->descriptor->methods.filter.init_iterator);
453 break;
454 case BT_COMPONENT_CLASS_TYPE_SINK:
455 comp_class = bt_component_class_sink_create(
456 cc_full_descr->descriptor->name,
457 cc_full_descr->descriptor->methods.sink.consume);
458 break;
459 default:
460 printf_verbose("WARNING: Unknown component class type %d for component class %s in plugin %s\n",
461 cc_full_descr->descriptor->type,
462 cc_full_descr->descriptor->name,
463 descriptor->name);
464 continue;
465 }
466
6ba0b073
PP
467 if (!comp_class) {
468 status = BT_PLUGIN_STATUS_ERROR;
469 goto end;
470 }
471
d3e4dcd8
PP
472 if (cc_full_descr->description) {
473 ret = bt_component_class_set_description(comp_class,
474 cc_full_descr->description);
475 if (ret) {
476 status = BT_PLUGIN_STATUS_ERROR;
477 BT_PUT(comp_class);
478 goto end;
479 }
480 }
481
482 if (cc_full_descr->init_method) {
483 ret = bt_component_class_set_init_method(comp_class,
484 cc_full_descr->init_method);
485 if (ret) {
486 status = BT_PLUGIN_STATUS_ERROR;
487 BT_PUT(comp_class);
488 goto end;
489 }
490 }
491
492 if (cc_full_descr->destroy_method) {
493 ret = bt_component_class_set_destroy_method(comp_class,
494 cc_full_descr->destroy_method);
495 if (ret) {
496 status = BT_PLUGIN_STATUS_ERROR;
497 BT_PUT(comp_class);
498 goto end;
499 }
500 }
501
502 if (cc_full_descr->descriptor->type ==
503 BT_COMPONENT_CLASS_TYPE_FILTER &&
504 cc_full_descr->filter_add_iterator_method) {
505 ret = bt_component_class_filter_set_add_iterator_method(comp_class,
506 cc_full_descr->filter_add_iterator_method);
507 if (ret) {
508 status = BT_PLUGIN_STATUS_ERROR;
509 BT_PUT(comp_class);
510 goto end;
511 }
512 }
513
514 if (cc_full_descr->descriptor->type ==
515 BT_COMPONENT_CLASS_TYPE_SINK &&
516 cc_full_descr->sink_add_iterator_method) {
517 ret = bt_component_class_sink_set_add_iterator_method(comp_class,
518 cc_full_descr->sink_add_iterator_method);
519 if (ret) {
520 status = BT_PLUGIN_STATUS_ERROR;
521 BT_PUT(comp_class);
522 goto end;
523 }
524 }
525
526 /* Add component class to the plugin object */
6ba0b073
PP
527 status = bt_plugin_add_component_class(plugin,
528 comp_class);
529 BT_PUT(comp_class);
530 if (status < 0) {
531 printf_verbose("Cannot add component class %s (type %d) to plugin `%s`: status = %d\n",
532 cc_full_descr->descriptor->name,
533 cc_full_descr->descriptor->type,
534 plugin->name, status);
535 goto end;
536 }
537 }
538
33b34c43 539 /*
6ba0b073
PP
540 * All the plugin's component classes should be added at this
541 * point. We freeze the plugin so that it's not possible to add
542 * component classes to this plugin object after this stage
543 * (plugin object becomes immutable).
33b34c43
PP
544 */
545 plugin->frozen = true;
546
547end:
6ba0b073 548 g_array_free(comp_class_full_descriptors, TRUE);
33b34c43
PP
549 return status;
550}
551
6ba0b073
PP
552static
553struct bt_plugin **bt_plugin_create_all_from_sections(
554 struct bt_plugin_shared_lib_handle *shared_lib_handle,
555 struct __bt_plugin_descriptor const * const *descriptors_begin,
556 struct __bt_plugin_descriptor const * const *descriptors_end,
557 struct __bt_plugin_descriptor_attribute const * const *attrs_begin,
558 struct __bt_plugin_descriptor_attribute const * const *attrs_end,
559 struct __bt_plugin_component_class_descriptor const * const *cc_descriptors_begin,
560 struct __bt_plugin_component_class_descriptor const * const *cc_descriptors_end,
561 struct __bt_plugin_component_class_descriptor_attribute const * const *cc_descr_attrs_begin,
562 struct __bt_plugin_component_class_descriptor_attribute const * const *cc_descr_attrs_end)
563{
564 size_t descriptor_count;
565 size_t attrs_count;
566 size_t cc_descriptors_count;
567 size_t cc_descr_attrs_count;
568 size_t i;
569 struct bt_plugin **plugins = NULL;
570
571 descriptor_count = descriptors_end - descriptors_begin;
572 attrs_count = attrs_end - attrs_begin;
573 cc_descriptors_count = cc_descriptors_end - cc_descriptors_begin;
574 cc_descr_attrs_count = cc_descr_attrs_end - cc_descr_attrs_begin;
575 printf_verbose("Section: Plugin descriptors: [%p - %p], (%zu elements)\n",
576 descriptors_begin, descriptors_end, descriptor_count);
577 printf_verbose("Section: Plugin descriptor attributes: [%p - %p], (%zu elements)\n",
578 attrs_begin, attrs_end, attrs_count);
579 printf_verbose("Section: Plugin component class descriptors: [%p - %p], (%zu elements)\n",
580 cc_descriptors_begin, cc_descriptors_end, cc_descriptors_count);
581 printf_verbose("Section: Plugin component class descriptor attributes: [%p - %p], (%zu elements)\n",
d3e4dcd8 582 cc_descr_attrs_begin, cc_descr_attrs_end, cc_descr_attrs_count);
6ba0b073
PP
583 plugins = calloc(descriptor_count + 1, sizeof(*plugins));
584 if (!plugins) {
585 goto error;
586 }
587
588 for (i = 0; i < descriptor_count; i++) {
589 enum bt_plugin_status status;
590 const struct __bt_plugin_descriptor *descriptor =
591 descriptors_begin[i];
592 struct bt_plugin *plugin;
593
594 printf_verbose("Loading plugin %s (%d.%d)\n", descriptor->name,
595 descriptor->major, descriptor->minor);
596
597 if (descriptor->major > __BT_PLUGIN_VERSION_MAJOR) {
598 printf_error("Unknown plugin's major version: %d\n",
599 descriptor->major);
600 goto error;
601 }
602
603 plugin = bt_plugin_create_empty(shared_lib_handle);
604 if (!plugin) {
605 printf_error("Cannot allocate plugin object for plugin %s\n",
606 descriptor->name);
607 goto error;
608 }
609
610 status = bt_plugin_init(plugin, descriptor, attrs_begin,
611 attrs_end, cc_descriptors_begin, cc_descriptors_end,
612 cc_descr_attrs_begin, cc_descr_attrs_end);
613 if (status < 0) {
614 printf_error("Cannot initialize plugin object %s\n",
615 descriptor->name);
616 BT_PUT(plugin);
617 goto error;
618 }
619
620 /* Transfer ownership to the array */
621 plugins[i] = plugin;
622 }
623
624 goto end;
625
626error:
627 g_free(plugins);
628 plugins = NULL;
629
630end:
631 return plugins;
632}
633
634struct bt_plugin **bt_plugin_create_all_from_static(void)
635{
636 struct bt_plugin **plugins = NULL;
637 struct bt_plugin_shared_lib_handle *shared_lib_handle =
638 bt_plugin_shared_lib_handle_create(NULL);
639
640 if (!shared_lib_handle) {
641 goto end;
642 }
643
644 plugins = bt_plugin_create_all_from_sections(shared_lib_handle,
645 SECTION_BEGIN(__bt_plugin_descriptors),
646 SECTION_END(__bt_plugin_descriptors),
647 SECTION_BEGIN(__bt_plugin_descriptor_attributes),
648 SECTION_END(__bt_plugin_descriptor_attributes),
649 SECTION_BEGIN(__bt_plugin_component_class_descriptors),
650 SECTION_END(__bt_plugin_component_class_descriptors),
651 SECTION_BEGIN(__bt_plugin_component_class_descriptor_attributes),
652 SECTION_END(__bt_plugin_component_class_descriptor_attributes));
653
654end:
655 BT_PUT(shared_lib_handle);
656
657 return plugins;
658}
659
660struct bt_plugin **bt_plugin_create_all_from_file(const char *path)
33b34c43
PP
661{
662 size_t path_len;
6ba0b073
PP
663 struct bt_plugin **plugins = NULL;
664 struct __bt_plugin_descriptor const * const *descriptors_begin = NULL;
665 struct __bt_plugin_descriptor const * const *descriptors_end = NULL;
666 struct __bt_plugin_descriptor_attribute const * const *attrs_begin = NULL;
667 struct __bt_plugin_descriptor_attribute const * const *attrs_end = NULL;
668 struct __bt_plugin_component_class_descriptor const * const *cc_descriptors_begin = NULL;
669 struct __bt_plugin_component_class_descriptor const * const *cc_descriptors_end = NULL;
670 struct __bt_plugin_component_class_descriptor_attribute const * const *cc_descr_attrs_begin = NULL;
671 struct __bt_plugin_component_class_descriptor_attribute const * const *cc_descr_attrs_end = NULL;
33b34c43 672 bool is_libtool_wrapper = false, is_shared_object = false;
6ba0b073 673 struct bt_plugin_shared_lib_handle *shared_lib_handle = NULL;
33b34c43
PP
674
675 if (!path) {
6ba0b073 676 goto end;
33b34c43
PP
677 }
678
679 path_len = strlen(path);
680 if (path_len <= PLUGIN_SUFFIX_LEN) {
6ba0b073 681 goto end;
33b34c43
PP
682 }
683
684 path_len++;
685 /*
686 * Check if the file ends with a known plugin file type suffix (i.e. .so
687 * or .la on Linux).
688 */
689 is_libtool_wrapper = !strncmp(LIBTOOL_PLUGIN_SUFFIX,
690 path + path_len - LIBTOOL_PLUGIN_SUFFIX_LEN,
691 LIBTOOL_PLUGIN_SUFFIX_LEN);
692 is_shared_object = !strncmp(NATIVE_PLUGIN_SUFFIX,
693 path + path_len - NATIVE_PLUGIN_SUFFIX_LEN,
694 NATIVE_PLUGIN_SUFFIX_LEN);
695 if (!is_shared_object && !is_libtool_wrapper) {
696 /* Name indicates that this is not a plugin file. */
6ba0b073 697 goto end;
33b34c43
PP
698 }
699
6ba0b073
PP
700 shared_lib_handle = bt_plugin_shared_lib_handle_create(path);
701 if (!shared_lib_handle) {
702 goto end;
33b34c43
PP
703 }
704
6ba0b073
PP
705 if (!g_module_symbol(shared_lib_handle->module, "__start___bt_plugin_descriptors",
706 (gpointer *) &descriptors_begin)) {
707 printf_verbose("Unable to resolve plugin symbol %s from %s\n",
708 "__start___bt_plugin_descriptors",
709 g_module_name(shared_lib_handle->module));
710 goto end;
711 }
33b34c43 712
6ba0b073
PP
713 if (!g_module_symbol(shared_lib_handle->module, "__stop___bt_plugin_descriptors",
714 (gpointer *) &descriptors_end)) {
715 printf_verbose("Unable to resolve plugin symbol %s from %s\n",
716 "__stop___bt_plugin_descriptors",
717 g_module_name(shared_lib_handle->module));
718 goto end;
33b34c43
PP
719 }
720
6ba0b073
PP
721 if (!g_module_symbol(shared_lib_handle->module, "__start___bt_plugin_descriptor_attributes",
722 (gpointer *) &attrs_begin)) {
723 printf_verbose("Unable to resolve plugin symbol %s from %s\n",
724 "__start___bt_plugin_descriptor_attributes",
725 g_module_name(shared_lib_handle->module));
33b34c43
PP
726 }
727
6ba0b073
PP
728 if (!g_module_symbol(shared_lib_handle->module, "__stop___bt_plugin_descriptor_attributes",
729 (gpointer *) &attrs_end)) {
730 printf_verbose("Unable to resolve plugin symbol %s from %s\n",
731 "__stop___bt_plugin_descriptor_attributes",
732 g_module_name(shared_lib_handle->module));
33b34c43
PP
733 }
734
6ba0b073
PP
735 if ((!!attrs_begin - !!attrs_end) != 0) {
736 printf_verbose("Found __start___bt_plugin_descriptor_attributes or __stop___bt_plugin_descriptor_attributes symbol, but not both in %s\n",
737 g_module_name(shared_lib_handle->module));
738 goto end;
739 }
33b34c43 740
6ba0b073
PP
741 if (!g_module_symbol(shared_lib_handle->module, "__start___bt_plugin_component_class_descriptors",
742 (gpointer *) &cc_descriptors_begin)) {
743 printf_verbose("Unable to resolve plugin symbol %s from %s\n",
744 "__start___bt_plugin_component_class_descriptors",
745 g_module_name(shared_lib_handle->module));
746 }
747
748 if (!g_module_symbol(shared_lib_handle->module, "__stop___bt_plugin_component_class_descriptors",
749 (gpointer *) &cc_descriptors_end)) {
750 printf_verbose("Unable to resolve plugin symbol %s from %s\n",
751 "__stop___bt_plugin_component_class_descriptors",
752 g_module_name(shared_lib_handle->module));
753 }
754
755 if ((!!cc_descriptors_begin - !!cc_descriptors_end) != 0) {
756 printf_verbose("Found __start___bt_plugin_component_class_descriptors or __stop___bt_plugin_component_class_descriptors symbol, but not both in %s\n",
757 g_module_name(shared_lib_handle->module));
758 goto end;
759 }
760
761 if (!g_module_symbol(shared_lib_handle->module, "__start___bt_plugin_component_class_descriptor_attributes",
762 (gpointer *) &cc_descr_attrs_begin)) {
763 printf_verbose("Unable to resolve plugin symbol %s from %s\n",
764 "__start___bt_plugin_component_class_descriptor_attributes",
765 g_module_name(shared_lib_handle->module));
766 }
767
768 if (!g_module_symbol(shared_lib_handle->module, "__stop___bt_plugin_component_class_descriptor_attributes",
769 (gpointer *) &cc_descr_attrs_end)) {
770 printf_verbose("Unable to resolve plugin symbol %s from %s\n",
771 "__stop___bt_plugin_component_class_descriptor_attributes",
772 g_module_name(shared_lib_handle->module));
773 }
774
775 if ((!!cc_descr_attrs_begin - !!cc_descr_attrs_end) != 0) {
776 printf_verbose("Found __start___bt_plugin_component_class_descriptor_attributes or __stop___bt_plugin_component_class_descriptor_attributes symbol, but not both in %s\n",
777 g_module_name(shared_lib_handle->module));
778 goto end;
779 }
780
781 /* Initialize plugin */
782 plugins = bt_plugin_create_all_from_sections(shared_lib_handle,
783 descriptors_begin, descriptors_end, attrs_begin, attrs_end,
784 cc_descriptors_begin, cc_descriptors_end,
785 cc_descr_attrs_begin, cc_descr_attrs_end);
33b34c43
PP
786
787end:
6ba0b073
PP
788 BT_PUT(shared_lib_handle);
789 return plugins;
33b34c43
PP
790}
791
792/* Allocate dirent as recommended by READDIR(3), NOTES on readdir_r */
793static
794struct dirent *alloc_dirent(const char *path)
795{
796 size_t len;
797 long name_max;
798 struct dirent *entry;
799
800 name_max = pathconf(path, _PC_NAME_MAX);
801 if (name_max == -1) {
802 name_max = PATH_MAX;
803 }
804 len = offsetof(struct dirent, d_name) + name_max + 1;
805 entry = zmalloc(len);
806 return entry;
807}
808
809static
810enum bt_plugin_status bt_plugin_create_append_all_from_dir(
811 GPtrArray *plugins, const char *path, bool recurse)
812{
813 DIR *directory = NULL;
814 struct dirent *entry = NULL, *result = NULL;
815 char *file_path = NULL;
6ba0b073 816 size_t path_len;
33b34c43
PP
817 enum bt_plugin_status ret = BT_PLUGIN_STATUS_OK;
818
6ba0b073
PP
819 if (!path) {
820 ret = BT_PLUGIN_STATUS_ERROR;
821 goto end;
822 }
823
824 path_len = strlen(path);
825
33b34c43
PP
826 if (path_len >= PATH_MAX) {
827 ret = BT_PLUGIN_STATUS_ERROR;
828 goto end;
829 }
830
831 entry = alloc_dirent(path);
832 if (!entry) {
833 ret = BT_PLUGIN_STATUS_ERROR;
834 goto end;
835 }
836
837 file_path = zmalloc(PATH_MAX);
838 if (!file_path) {
839 ret = BT_PLUGIN_STATUS_NOMEM;
840 goto end;
841 }
842
843 strncpy(file_path, path, path_len);
844 /* Append a trailing '/' to the path */
845 if (file_path[path_len - 1] != '/') {
846 file_path[path_len++] = '/';
847 }
848
849 directory = opendir(file_path);
850 if (!directory) {
851 perror("Failed to open plug-in directory");
852 ret = BT_PLUGIN_STATUS_ERROR;
853 goto end;
854 }
855
856 /* Recursively walk directory */
857 while (!readdir_r(directory, entry, &result) && result) {
858 struct stat st;
859 int stat_ret;
860 size_t file_name_len;
861
862 if (result->d_name[0] == '.') {
863 /* Skip hidden files, . and .. */
864 continue;
865 }
866
867 file_name_len = strlen(result->d_name);
868
869 if (path_len + file_name_len >= PATH_MAX) {
870 continue;
871 }
872
873 strncpy(file_path + path_len, result->d_name, file_name_len);
874 file_path[path_len + file_name_len] = '\0';
875
876 stat_ret = stat(file_path, &st);
877 if (stat_ret < 0) {
878 /* Continue to next file / directory. */
879 printf_perror("Failed to stat() plugin file\n");
880 continue;
881 }
882
883 if (S_ISDIR(st.st_mode) && recurse) {
884 ret = bt_plugin_create_append_all_from_dir(plugins,
885 file_path, true);
886 if (ret < 0) {
887 goto end;
888 }
889 } else if (S_ISREG(st.st_mode)) {
6ba0b073
PP
890 struct bt_plugin **plugins_from_file =
891 bt_plugin_create_all_from_file(file_path);
33b34c43 892
6ba0b073
PP
893 if (plugins_from_file) {
894 struct bt_plugin **plugin;
895
896 for (plugin = plugins_from_file; *plugin; plugin++) {
897 /* Transfer ownership to array */
898 g_ptr_array_add(plugins, *plugin);
899 }
900
901 free(plugins_from_file);
33b34c43
PP
902 }
903 }
904 }
905end:
906 if (directory) {
907 if (closedir(directory)) {
908 /*
909 * We don't want to override the error since there is
910 * nothing could do.
911 */
912 perror("Failed to close plug-in directory");
913 }
914 }
915 free(entry);
916 free(file_path);
917 return ret;
918}
919
920struct bt_plugin **bt_plugin_create_all_from_dir(const char *path,
921 bool recurse)
922{
6ba0b073 923 GPtrArray *plugins_array = g_ptr_array_new();
33b34c43
PP
924 struct bt_plugin **plugins = NULL;
925 enum bt_plugin_status status;
926
33b34c43
PP
927 /* Append found plugins to array */
928 status = bt_plugin_create_append_all_from_dir(plugins_array, path,
929 recurse);
930 if (status < 0) {
931 goto error;
932 }
933
934 /* Add sentinel to array */
935 g_ptr_array_add(plugins_array, NULL);
936 plugins = (struct bt_plugin **) plugins_array->pdata;
937 goto end;
938
939error:
940 if (plugins_array) {
941 g_ptr_array_free(plugins_array, TRUE);
942 plugins_array = NULL;
943 }
944
945end:
946 if (plugins_array) {
947 g_ptr_array_free(plugins_array, FALSE);
948 }
949
950 return plugins;
951}
952
33b34c43
PP
953const char *bt_plugin_get_name(struct bt_plugin *plugin)
954{
6ba0b073 955 return plugin ? plugin->name : NULL;
33b34c43
PP
956}
957
958const char *bt_plugin_get_author(struct bt_plugin *plugin)
959{
6ba0b073 960 return plugin ? plugin->author : NULL;
33b34c43
PP
961}
962
963const char *bt_plugin_get_license(struct bt_plugin *plugin)
964{
6ba0b073 965 return plugin ? plugin->license : NULL;
33b34c43
PP
966}
967
968const char *bt_plugin_get_path(struct bt_plugin *plugin)
969{
970 return (plugin && plugin->shared_lib_handle->path) ?
971 plugin->shared_lib_handle->path->str : NULL;
972}
973
974const char *bt_plugin_get_description(struct bt_plugin *plugin)
975{
6ba0b073 976 return plugin ? plugin->description : NULL;
33b34c43
PP
977}
978
b6de043b
PP
979enum bt_plugin_status bt_plugin_get_version(struct bt_plugin *plugin,
980 unsigned int *major, unsigned int *minor, unsigned int *patch,
981 const char **extra)
982{
983 enum bt_plugin_status status = BT_PLUGIN_STATUS_OK;
984
985 if (!plugin || !plugin->version) {
986 status = BT_PLUGIN_STATUS_ERROR;
987 goto end;
988 }
989
990 if (major) {
991 *major = (unsigned int) plugin->version->major;
992 }
993
994 if (minor) {
995 *minor = (unsigned int) plugin->version->minor;
996 }
997
998 if (patch) {
999 *patch = (unsigned int) plugin->version->patch;
1000 }
1001
1002 if (extra) {
1003 *extra = plugin->version->extra;
1004 }
1005
1006end:
1007 return status;
1008}
1009
33b34c43
PP
1010int bt_plugin_get_component_class_count(struct bt_plugin *plugin)
1011{
1012 return plugin ? plugin->comp_classes->len : -1;
1013}
1014
1015struct bt_component_class *bt_plugin_get_component_class(
1016 struct bt_plugin *plugin, size_t index)
1017{
1018 struct bt_component_class *comp_class = NULL;
1019
1020 if (!plugin || index >= plugin->comp_classes->len) {
1021 goto error;
1022 }
1023
1024 comp_class = g_ptr_array_index(plugin->comp_classes, index);
1025 bt_get(comp_class);
1026 goto end;
1027
1028error:
1029 BT_PUT(comp_class);
1030
1031end:
1032 return comp_class;
1033}
1034
1035struct bt_component_class *bt_plugin_get_component_class_by_name_and_type(
1036 struct bt_plugin *plugin, const char *name,
d3e4dcd8 1037 enum bt_component_class_type type)
33b34c43
PP
1038{
1039 struct bt_component_class *comp_class = NULL;
1040 size_t i;
1041
1042 if (!plugin || !name) {
1043 goto error;
1044 }
1045
1046 for (i = 0; i < plugin->comp_classes->len; i++) {
1047 struct bt_component_class *comp_class_candidate =
1048 g_ptr_array_index(plugin->comp_classes, i);
1049 const char *comp_class_cand_name =
1050 bt_component_class_get_name(comp_class_candidate);
d3e4dcd8 1051 enum bt_component_class_type comp_class_cand_type =
33b34c43
PP
1052 bt_component_class_get_type(comp_class_candidate);
1053
1054 assert(comp_class_cand_name);
1055 assert(comp_class_cand_type >= 0);
1056
1057 if (strcmp(name, comp_class_cand_name) == 0 &&
1058 comp_class_cand_type == type) {
1059 comp_class = bt_get(comp_class_candidate);
1060 break;
1061 }
1062 }
1063
1064 goto end;
1065
1066error:
1067 BT_PUT(comp_class);
1068
1069end:
1070 return comp_class;
1071}
1072
1073static
1074void plugin_comp_class_destroy_listener(struct bt_component_class *comp_class,
1075 void *data)
1076{
1077 gboolean exists = g_hash_table_remove(comp_classes_to_shlib_handles,
1078 comp_class);
1079 assert(exists);
1080}
1081
1082enum bt_plugin_status bt_plugin_add_component_class(
1083 struct bt_plugin *plugin, struct bt_component_class *comp_class)
1084{
1085 enum bt_plugin_status status = BT_PLUGIN_STATUS_OK;
1086 struct bt_component_class *comp_class_dup = NULL;
1087 int ret;
1088 int comp_class_index = -1;
1089
1090 if (!plugin || !comp_class || plugin->frozen) {
1091 goto error;
1092 }
1093
1094 /* Check for duplicate */
1095 comp_class_dup = bt_plugin_get_component_class_by_name_and_type(plugin,
1096 bt_component_class_get_name(comp_class),
1097 bt_component_class_get_type(comp_class));
1098 if (comp_class_dup) {
1099 printf_verbose("Plugin `%s`: adding component class with existing name `%s` and type %d\n",
6ba0b073 1100 plugin->name,
33b34c43
PP
1101 bt_component_class_get_name(comp_class),
1102 bt_component_class_get_type(comp_class));
1103 goto error;
1104 }
1105
1106 /* Add new component class */
1107 comp_class_index = plugin->comp_classes->len;
1108 g_ptr_array_add(plugin->comp_classes, bt_get(comp_class));
1109
1110 /* Map component class pointer to shared lib handle in global HT */
1111 g_hash_table_insert(comp_classes_to_shlib_handles, comp_class,
1112 bt_get(plugin->shared_lib_handle));
1113
1114 /* Add our custom destroy listener */
1115 ret = bt_component_class_add_destroy_listener(comp_class,
1116 plugin_comp_class_destroy_listener, NULL);
1117 if (ret) {
1118 goto error;
1119 }
1120
1121 goto end;
1122
1123error:
1124 /* Remove entry from global hash table (if exists) */
1125 g_hash_table_remove(comp_classes_to_shlib_handles,
1126 comp_class);
1127
1128 /* Remove entry from plugin's component classes (if added) */
1129 if (comp_class_index >= 0) {
1130 g_ptr_array_remove_index(plugin->comp_classes,
1131 comp_class_index);
1132 }
1133
1134 status = BT_PLUGIN_STATUS_ERROR;
1135
1136end:
1137 bt_put(comp_class_dup);
1138 return status;
1139}
This page took 0.066483 seconds and 4 git commands to generate.