Add bt_component_class_freeze()
[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;
338 default:
339 printf_verbose("WARNING: Unknown attribute \"%s\" (type %d) for plugin %s\n",
340 cur_attr->type_name, cur_attr->type,
341 descriptor->name);
342 break;
343 }
344 }
345
346 /*
347 * Find component class descriptors attached to this plugin
348 * descriptor and initialize corresponding full component class
349 * descriptors in the array.
350 */
351 for (cur_cc_descr_ptr = cc_descriptors_begin; cur_cc_descr_ptr != cc_descriptors_end; cur_cc_descr_ptr++) {
352 const struct __bt_plugin_component_class_descriptor *cur_cc_descr =
353 *cur_cc_descr_ptr;
d3e4dcd8 354 struct comp_class_full_descriptor full_descriptor = {0};
6ba0b073
PP
355
356 if (cur_cc_descr->plugin_descriptor != descriptor) {
357 continue;
358 }
359
360 full_descriptor.descriptor = cur_cc_descr;
6ba0b073
PP
361 g_array_append_val(comp_class_full_descriptors,
362 full_descriptor);
363 }
364
365 /*
366 * Find component class descriptor attributes attached to this
367 * plugin descriptor and update corresponding full component
368 * class descriptors in the array.
369 */
370 for (cur_cc_descr_attr_ptr = cc_descr_attrs_begin; cur_cc_descr_attr_ptr != cc_descr_attrs_end; cur_cc_descr_attr_ptr++) {
371 const struct __bt_plugin_component_class_descriptor_attribute *cur_cc_descr_attr =
372 *cur_cc_descr_attr_ptr;
373
374 if (cur_cc_descr_attr->comp_class_descriptor->plugin_descriptor !=
375 descriptor) {
376 continue;
377 }
378
379 /* Find the corresponding component class descriptor entry */
380 for (i = 0; i < comp_class_full_descriptors->len; i++) {
381 struct comp_class_full_descriptor *cc_full_descr =
382 &g_array_index(comp_class_full_descriptors,
383 struct comp_class_full_descriptor, i);
384
385 if (cur_cc_descr_attr->comp_class_descriptor ==
386 cc_full_descr->descriptor) {
387 switch (cur_cc_descr_attr->type) {
388 case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_DESCRIPTION:
389 cc_full_descr->description =
390 cur_cc_descr_attr->value.description;
391 break;
d3e4dcd8
PP
392 case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_INIT_METHOD:
393 cc_full_descr->init_method =
394 cur_cc_descr_attr->value.init_method;
395 break;
396 case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_DESTROY_METHOD:
397 cc_full_descr->destroy_method =
398 cur_cc_descr_attr->value.destroy_method;
399 break;
400 case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_FILTER_ADD_ITERATOR_METHOD:
401 cc_full_descr->filter_add_iterator_method =
402 cur_cc_descr_attr->value.filter_add_iterator_method;
403 break;
404 case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_SINK_ADD_ITERATOR_METHOD:
405 cc_full_descr->sink_add_iterator_method =
406 cur_cc_descr_attr->value.sink_add_iterator_method;
407 break;
6ba0b073
PP
408 default:
409 printf_verbose("WARNING: Unknown attribute \"%s\" (type %d) for component class %s (type %d) in plugin %s\n",
410 cur_cc_descr_attr->type_name,
411 cur_cc_descr_attr->type,
412 cur_cc_descr_attr->comp_class_descriptor->name,
413 cur_cc_descr_attr->comp_class_descriptor->type,
414 descriptor->name);
415 break;
416 }
417 }
418 }
419 }
420
421 /* Initialize plugin */
422 if (plugin->init) {
423 status = plugin->init(plugin);
33b34c43
PP
424 if (status < 0) {
425 printf_verbose("Plugin `%s` initialization error: %d\n",
6ba0b073 426 plugin->name, status);
33b34c43
PP
427 goto end;
428 }
429 }
430
431 plugin->shared_lib_handle->init_called = true;
432
d3e4dcd8 433 /* Add described component classes to plugin */
6ba0b073
PP
434 for (i = 0; i < comp_class_full_descriptors->len; i++) {
435 struct comp_class_full_descriptor *cc_full_descr =
436 &g_array_index(comp_class_full_descriptors,
437 struct comp_class_full_descriptor, i);
438 struct bt_component_class *comp_class;
439
d3e4dcd8
PP
440 switch (cc_full_descr->descriptor->type) {
441 case BT_COMPONENT_CLASS_TYPE_SOURCE:
442 comp_class = bt_component_class_source_create(
443 cc_full_descr->descriptor->name,
444 cc_full_descr->descriptor->methods.source.init_iterator);
445 break;
446 case BT_COMPONENT_CLASS_TYPE_FILTER:
447 comp_class = bt_component_class_filter_create(
448 cc_full_descr->descriptor->name,
449 cc_full_descr->descriptor->methods.filter.init_iterator);
450 break;
451 case BT_COMPONENT_CLASS_TYPE_SINK:
452 comp_class = bt_component_class_sink_create(
453 cc_full_descr->descriptor->name,
454 cc_full_descr->descriptor->methods.sink.consume);
455 break;
456 default:
457 printf_verbose("WARNING: Unknown component class type %d for component class %s in plugin %s\n",
458 cc_full_descr->descriptor->type,
459 cc_full_descr->descriptor->name,
460 descriptor->name);
461 continue;
462 }
463
6ba0b073
PP
464 if (!comp_class) {
465 status = BT_PLUGIN_STATUS_ERROR;
466 goto end;
467 }
468
d3e4dcd8
PP
469 if (cc_full_descr->description) {
470 ret = bt_component_class_set_description(comp_class,
471 cc_full_descr->description);
472 if (ret) {
473 status = BT_PLUGIN_STATUS_ERROR;
474 BT_PUT(comp_class);
475 goto end;
476 }
477 }
478
479 if (cc_full_descr->init_method) {
480 ret = bt_component_class_set_init_method(comp_class,
481 cc_full_descr->init_method);
482 if (ret) {
483 status = BT_PLUGIN_STATUS_ERROR;
484 BT_PUT(comp_class);
485 goto end;
486 }
487 }
488
489 if (cc_full_descr->destroy_method) {
490 ret = bt_component_class_set_destroy_method(comp_class,
491 cc_full_descr->destroy_method);
492 if (ret) {
493 status = BT_PLUGIN_STATUS_ERROR;
494 BT_PUT(comp_class);
495 goto end;
496 }
497 }
498
499 if (cc_full_descr->descriptor->type ==
500 BT_COMPONENT_CLASS_TYPE_FILTER &&
501 cc_full_descr->filter_add_iterator_method) {
502 ret = bt_component_class_filter_set_add_iterator_method(comp_class,
503 cc_full_descr->filter_add_iterator_method);
504 if (ret) {
505 status = BT_PLUGIN_STATUS_ERROR;
506 BT_PUT(comp_class);
507 goto end;
508 }
509 }
510
511 if (cc_full_descr->descriptor->type ==
512 BT_COMPONENT_CLASS_TYPE_SINK &&
513 cc_full_descr->sink_add_iterator_method) {
514 ret = bt_component_class_sink_set_add_iterator_method(comp_class,
515 cc_full_descr->sink_add_iterator_method);
516 if (ret) {
517 status = BT_PLUGIN_STATUS_ERROR;
518 BT_PUT(comp_class);
519 goto end;
520 }
521 }
522
523 /* Add component class to the plugin object */
6ba0b073
PP
524 status = bt_plugin_add_component_class(plugin,
525 comp_class);
526 BT_PUT(comp_class);
527 if (status < 0) {
528 printf_verbose("Cannot add component class %s (type %d) to plugin `%s`: status = %d\n",
529 cc_full_descr->descriptor->name,
530 cc_full_descr->descriptor->type,
531 plugin->name, status);
532 goto end;
533 }
534 }
535
33b34c43 536 /*
6ba0b073
PP
537 * All the plugin's component classes should be added at this
538 * point. We freeze the plugin so that it's not possible to add
539 * component classes to this plugin object after this stage
540 * (plugin object becomes immutable).
33b34c43
PP
541 */
542 plugin->frozen = true;
543
544end:
6ba0b073 545 g_array_free(comp_class_full_descriptors, TRUE);
33b34c43
PP
546 return status;
547}
548
6ba0b073
PP
549static
550struct bt_plugin **bt_plugin_create_all_from_sections(
551 struct bt_plugin_shared_lib_handle *shared_lib_handle,
552 struct __bt_plugin_descriptor const * const *descriptors_begin,
553 struct __bt_plugin_descriptor const * const *descriptors_end,
554 struct __bt_plugin_descriptor_attribute const * const *attrs_begin,
555 struct __bt_plugin_descriptor_attribute const * const *attrs_end,
556 struct __bt_plugin_component_class_descriptor const * const *cc_descriptors_begin,
557 struct __bt_plugin_component_class_descriptor const * const *cc_descriptors_end,
558 struct __bt_plugin_component_class_descriptor_attribute const * const *cc_descr_attrs_begin,
559 struct __bt_plugin_component_class_descriptor_attribute const * const *cc_descr_attrs_end)
560{
561 size_t descriptor_count;
562 size_t attrs_count;
563 size_t cc_descriptors_count;
564 size_t cc_descr_attrs_count;
565 size_t i;
566 struct bt_plugin **plugins = NULL;
567
568 descriptor_count = descriptors_end - descriptors_begin;
569 attrs_count = attrs_end - attrs_begin;
570 cc_descriptors_count = cc_descriptors_end - cc_descriptors_begin;
571 cc_descr_attrs_count = cc_descr_attrs_end - cc_descr_attrs_begin;
572 printf_verbose("Section: Plugin descriptors: [%p - %p], (%zu elements)\n",
573 descriptors_begin, descriptors_end, descriptor_count);
574 printf_verbose("Section: Plugin descriptor attributes: [%p - %p], (%zu elements)\n",
575 attrs_begin, attrs_end, attrs_count);
576 printf_verbose("Section: Plugin component class descriptors: [%p - %p], (%zu elements)\n",
577 cc_descriptors_begin, cc_descriptors_end, cc_descriptors_count);
578 printf_verbose("Section: Plugin component class descriptor attributes: [%p - %p], (%zu elements)\n",
d3e4dcd8 579 cc_descr_attrs_begin, cc_descr_attrs_end, cc_descr_attrs_count);
6ba0b073
PP
580 plugins = calloc(descriptor_count + 1, sizeof(*plugins));
581 if (!plugins) {
582 goto error;
583 }
584
585 for (i = 0; i < descriptor_count; i++) {
586 enum bt_plugin_status status;
587 const struct __bt_plugin_descriptor *descriptor =
588 descriptors_begin[i];
589 struct bt_plugin *plugin;
590
591 printf_verbose("Loading plugin %s (%d.%d)\n", descriptor->name,
592 descriptor->major, descriptor->minor);
593
594 if (descriptor->major > __BT_PLUGIN_VERSION_MAJOR) {
595 printf_error("Unknown plugin's major version: %d\n",
596 descriptor->major);
597 goto error;
598 }
599
600 plugin = bt_plugin_create_empty(shared_lib_handle);
601 if (!plugin) {
602 printf_error("Cannot allocate plugin object for plugin %s\n",
603 descriptor->name);
604 goto error;
605 }
606
607 status = bt_plugin_init(plugin, descriptor, attrs_begin,
608 attrs_end, cc_descriptors_begin, cc_descriptors_end,
609 cc_descr_attrs_begin, cc_descr_attrs_end);
610 if (status < 0) {
611 printf_error("Cannot initialize plugin object %s\n",
612 descriptor->name);
613 BT_PUT(plugin);
614 goto error;
615 }
616
617 /* Transfer ownership to the array */
618 plugins[i] = plugin;
619 }
620
621 goto end;
622
623error:
624 g_free(plugins);
625 plugins = NULL;
626
627end:
628 return plugins;
629}
630
631struct bt_plugin **bt_plugin_create_all_from_static(void)
632{
633 struct bt_plugin **plugins = NULL;
634 struct bt_plugin_shared_lib_handle *shared_lib_handle =
635 bt_plugin_shared_lib_handle_create(NULL);
636
637 if (!shared_lib_handle) {
638 goto end;
639 }
640
641 plugins = bt_plugin_create_all_from_sections(shared_lib_handle,
642 SECTION_BEGIN(__bt_plugin_descriptors),
643 SECTION_END(__bt_plugin_descriptors),
644 SECTION_BEGIN(__bt_plugin_descriptor_attributes),
645 SECTION_END(__bt_plugin_descriptor_attributes),
646 SECTION_BEGIN(__bt_plugin_component_class_descriptors),
647 SECTION_END(__bt_plugin_component_class_descriptors),
648 SECTION_BEGIN(__bt_plugin_component_class_descriptor_attributes),
649 SECTION_END(__bt_plugin_component_class_descriptor_attributes));
650
651end:
652 BT_PUT(shared_lib_handle);
653
654 return plugins;
655}
656
657struct bt_plugin **bt_plugin_create_all_from_file(const char *path)
33b34c43
PP
658{
659 size_t path_len;
6ba0b073
PP
660 struct bt_plugin **plugins = NULL;
661 struct __bt_plugin_descriptor const * const *descriptors_begin = NULL;
662 struct __bt_plugin_descriptor const * const *descriptors_end = NULL;
663 struct __bt_plugin_descriptor_attribute const * const *attrs_begin = NULL;
664 struct __bt_plugin_descriptor_attribute const * const *attrs_end = NULL;
665 struct __bt_plugin_component_class_descriptor const * const *cc_descriptors_begin = NULL;
666 struct __bt_plugin_component_class_descriptor const * const *cc_descriptors_end = NULL;
667 struct __bt_plugin_component_class_descriptor_attribute const * const *cc_descr_attrs_begin = NULL;
668 struct __bt_plugin_component_class_descriptor_attribute const * const *cc_descr_attrs_end = NULL;
33b34c43 669 bool is_libtool_wrapper = false, is_shared_object = false;
6ba0b073 670 struct bt_plugin_shared_lib_handle *shared_lib_handle = NULL;
33b34c43
PP
671
672 if (!path) {
6ba0b073 673 goto end;
33b34c43
PP
674 }
675
676 path_len = strlen(path);
677 if (path_len <= PLUGIN_SUFFIX_LEN) {
6ba0b073 678 goto end;
33b34c43
PP
679 }
680
681 path_len++;
682 /*
683 * Check if the file ends with a known plugin file type suffix (i.e. .so
684 * or .la on Linux).
685 */
686 is_libtool_wrapper = !strncmp(LIBTOOL_PLUGIN_SUFFIX,
687 path + path_len - LIBTOOL_PLUGIN_SUFFIX_LEN,
688 LIBTOOL_PLUGIN_SUFFIX_LEN);
689 is_shared_object = !strncmp(NATIVE_PLUGIN_SUFFIX,
690 path + path_len - NATIVE_PLUGIN_SUFFIX_LEN,
691 NATIVE_PLUGIN_SUFFIX_LEN);
692 if (!is_shared_object && !is_libtool_wrapper) {
693 /* Name indicates that this is not a plugin file. */
6ba0b073 694 goto end;
33b34c43
PP
695 }
696
6ba0b073
PP
697 shared_lib_handle = bt_plugin_shared_lib_handle_create(path);
698 if (!shared_lib_handle) {
699 goto end;
33b34c43
PP
700 }
701
6ba0b073
PP
702 if (!g_module_symbol(shared_lib_handle->module, "__start___bt_plugin_descriptors",
703 (gpointer *) &descriptors_begin)) {
704 printf_verbose("Unable to resolve plugin symbol %s from %s\n",
705 "__start___bt_plugin_descriptors",
706 g_module_name(shared_lib_handle->module));
707 goto end;
708 }
33b34c43 709
6ba0b073
PP
710 if (!g_module_symbol(shared_lib_handle->module, "__stop___bt_plugin_descriptors",
711 (gpointer *) &descriptors_end)) {
712 printf_verbose("Unable to resolve plugin symbol %s from %s\n",
713 "__stop___bt_plugin_descriptors",
714 g_module_name(shared_lib_handle->module));
715 goto end;
33b34c43
PP
716 }
717
6ba0b073
PP
718 if (!g_module_symbol(shared_lib_handle->module, "__start___bt_plugin_descriptor_attributes",
719 (gpointer *) &attrs_begin)) {
720 printf_verbose("Unable to resolve plugin symbol %s from %s\n",
721 "__start___bt_plugin_descriptor_attributes",
722 g_module_name(shared_lib_handle->module));
33b34c43
PP
723 }
724
6ba0b073
PP
725 if (!g_module_symbol(shared_lib_handle->module, "__stop___bt_plugin_descriptor_attributes",
726 (gpointer *) &attrs_end)) {
727 printf_verbose("Unable to resolve plugin symbol %s from %s\n",
728 "__stop___bt_plugin_descriptor_attributes",
729 g_module_name(shared_lib_handle->module));
33b34c43
PP
730 }
731
6ba0b073
PP
732 if ((!!attrs_begin - !!attrs_end) != 0) {
733 printf_verbose("Found __start___bt_plugin_descriptor_attributes or __stop___bt_plugin_descriptor_attributes symbol, but not both in %s\n",
734 g_module_name(shared_lib_handle->module));
735 goto end;
736 }
33b34c43 737
6ba0b073
PP
738 if (!g_module_symbol(shared_lib_handle->module, "__start___bt_plugin_component_class_descriptors",
739 (gpointer *) &cc_descriptors_begin)) {
740 printf_verbose("Unable to resolve plugin symbol %s from %s\n",
741 "__start___bt_plugin_component_class_descriptors",
742 g_module_name(shared_lib_handle->module));
743 }
744
745 if (!g_module_symbol(shared_lib_handle->module, "__stop___bt_plugin_component_class_descriptors",
746 (gpointer *) &cc_descriptors_end)) {
747 printf_verbose("Unable to resolve plugin symbol %s from %s\n",
748 "__stop___bt_plugin_component_class_descriptors",
749 g_module_name(shared_lib_handle->module));
750 }
751
752 if ((!!cc_descriptors_begin - !!cc_descriptors_end) != 0) {
753 printf_verbose("Found __start___bt_plugin_component_class_descriptors or __stop___bt_plugin_component_class_descriptors symbol, but not both in %s\n",
754 g_module_name(shared_lib_handle->module));
755 goto end;
756 }
757
758 if (!g_module_symbol(shared_lib_handle->module, "__start___bt_plugin_component_class_descriptor_attributes",
759 (gpointer *) &cc_descr_attrs_begin)) {
760 printf_verbose("Unable to resolve plugin symbol %s from %s\n",
761 "__start___bt_plugin_component_class_descriptor_attributes",
762 g_module_name(shared_lib_handle->module));
763 }
764
765 if (!g_module_symbol(shared_lib_handle->module, "__stop___bt_plugin_component_class_descriptor_attributes",
766 (gpointer *) &cc_descr_attrs_end)) {
767 printf_verbose("Unable to resolve plugin symbol %s from %s\n",
768 "__stop___bt_plugin_component_class_descriptor_attributes",
769 g_module_name(shared_lib_handle->module));
770 }
771
772 if ((!!cc_descr_attrs_begin - !!cc_descr_attrs_end) != 0) {
773 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",
774 g_module_name(shared_lib_handle->module));
775 goto end;
776 }
777
778 /* Initialize plugin */
779 plugins = bt_plugin_create_all_from_sections(shared_lib_handle,
780 descriptors_begin, descriptors_end, attrs_begin, attrs_end,
781 cc_descriptors_begin, cc_descriptors_end,
782 cc_descr_attrs_begin, cc_descr_attrs_end);
33b34c43
PP
783
784end:
6ba0b073
PP
785 BT_PUT(shared_lib_handle);
786 return plugins;
33b34c43
PP
787}
788
789/* Allocate dirent as recommended by READDIR(3), NOTES on readdir_r */
790static
791struct dirent *alloc_dirent(const char *path)
792{
793 size_t len;
794 long name_max;
795 struct dirent *entry;
796
797 name_max = pathconf(path, _PC_NAME_MAX);
798 if (name_max == -1) {
799 name_max = PATH_MAX;
800 }
801 len = offsetof(struct dirent, d_name) + name_max + 1;
802 entry = zmalloc(len);
803 return entry;
804}
805
806static
807enum bt_plugin_status bt_plugin_create_append_all_from_dir(
808 GPtrArray *plugins, const char *path, bool recurse)
809{
810 DIR *directory = NULL;
811 struct dirent *entry = NULL, *result = NULL;
812 char *file_path = NULL;
6ba0b073 813 size_t path_len;
33b34c43
PP
814 enum bt_plugin_status ret = BT_PLUGIN_STATUS_OK;
815
6ba0b073
PP
816 if (!path) {
817 ret = BT_PLUGIN_STATUS_ERROR;
818 goto end;
819 }
820
821 path_len = strlen(path);
822
33b34c43
PP
823 if (path_len >= PATH_MAX) {
824 ret = BT_PLUGIN_STATUS_ERROR;
825 goto end;
826 }
827
828 entry = alloc_dirent(path);
829 if (!entry) {
830 ret = BT_PLUGIN_STATUS_ERROR;
831 goto end;
832 }
833
834 file_path = zmalloc(PATH_MAX);
835 if (!file_path) {
836 ret = BT_PLUGIN_STATUS_NOMEM;
837 goto end;
838 }
839
840 strncpy(file_path, path, path_len);
841 /* Append a trailing '/' to the path */
842 if (file_path[path_len - 1] != '/') {
843 file_path[path_len++] = '/';
844 }
845
846 directory = opendir(file_path);
847 if (!directory) {
848 perror("Failed to open plug-in directory");
849 ret = BT_PLUGIN_STATUS_ERROR;
850 goto end;
851 }
852
853 /* Recursively walk directory */
854 while (!readdir_r(directory, entry, &result) && result) {
855 struct stat st;
856 int stat_ret;
857 size_t file_name_len;
858
859 if (result->d_name[0] == '.') {
860 /* Skip hidden files, . and .. */
861 continue;
862 }
863
864 file_name_len = strlen(result->d_name);
865
866 if (path_len + file_name_len >= PATH_MAX) {
867 continue;
868 }
869
870 strncpy(file_path + path_len, result->d_name, file_name_len);
871 file_path[path_len + file_name_len] = '\0';
872
873 stat_ret = stat(file_path, &st);
874 if (stat_ret < 0) {
875 /* Continue to next file / directory. */
876 printf_perror("Failed to stat() plugin file\n");
877 continue;
878 }
879
880 if (S_ISDIR(st.st_mode) && recurse) {
881 ret = bt_plugin_create_append_all_from_dir(plugins,
882 file_path, true);
883 if (ret < 0) {
884 goto end;
885 }
886 } else if (S_ISREG(st.st_mode)) {
6ba0b073
PP
887 struct bt_plugin **plugins_from_file =
888 bt_plugin_create_all_from_file(file_path);
33b34c43 889
6ba0b073
PP
890 if (plugins_from_file) {
891 struct bt_plugin **plugin;
892
893 for (plugin = plugins_from_file; *plugin; plugin++) {
894 /* Transfer ownership to array */
895 g_ptr_array_add(plugins, *plugin);
896 }
897
898 free(plugins_from_file);
33b34c43
PP
899 }
900 }
901 }
902end:
903 if (directory) {
904 if (closedir(directory)) {
905 /*
906 * We don't want to override the error since there is
907 * nothing could do.
908 */
909 perror("Failed to close plug-in directory");
910 }
911 }
912 free(entry);
913 free(file_path);
914 return ret;
915}
916
917struct bt_plugin **bt_plugin_create_all_from_dir(const char *path,
918 bool recurse)
919{
6ba0b073 920 GPtrArray *plugins_array = g_ptr_array_new();
33b34c43
PP
921 struct bt_plugin **plugins = NULL;
922 enum bt_plugin_status status;
923
33b34c43
PP
924 /* Append found plugins to array */
925 status = bt_plugin_create_append_all_from_dir(plugins_array, path,
926 recurse);
927 if (status < 0) {
928 goto error;
929 }
930
931 /* Add sentinel to array */
932 g_ptr_array_add(plugins_array, NULL);
933 plugins = (struct bt_plugin **) plugins_array->pdata;
934 goto end;
935
936error:
937 if (plugins_array) {
938 g_ptr_array_free(plugins_array, TRUE);
939 plugins_array = NULL;
940 }
941
942end:
943 if (plugins_array) {
944 g_ptr_array_free(plugins_array, FALSE);
945 }
946
947 return plugins;
948}
949
33b34c43
PP
950const char *bt_plugin_get_name(struct bt_plugin *plugin)
951{
6ba0b073 952 return plugin ? plugin->name : NULL;
33b34c43
PP
953}
954
955const char *bt_plugin_get_author(struct bt_plugin *plugin)
956{
6ba0b073 957 return plugin ? plugin->author : NULL;
33b34c43
PP
958}
959
960const char *bt_plugin_get_license(struct bt_plugin *plugin)
961{
6ba0b073 962 return plugin ? plugin->license : NULL;
33b34c43
PP
963}
964
965const char *bt_plugin_get_path(struct bt_plugin *plugin)
966{
967 return (plugin && plugin->shared_lib_handle->path) ?
968 plugin->shared_lib_handle->path->str : NULL;
969}
970
971const char *bt_plugin_get_description(struct bt_plugin *plugin)
972{
6ba0b073 973 return plugin ? plugin->description : NULL;
33b34c43
PP
974}
975
976int bt_plugin_get_component_class_count(struct bt_plugin *plugin)
977{
978 return plugin ? plugin->comp_classes->len : -1;
979}
980
981struct bt_component_class *bt_plugin_get_component_class(
982 struct bt_plugin *plugin, size_t index)
983{
984 struct bt_component_class *comp_class = NULL;
985
986 if (!plugin || index >= plugin->comp_classes->len) {
987 goto error;
988 }
989
990 comp_class = g_ptr_array_index(plugin->comp_classes, index);
991 bt_get(comp_class);
992 goto end;
993
994error:
995 BT_PUT(comp_class);
996
997end:
998 return comp_class;
999}
1000
1001struct bt_component_class *bt_plugin_get_component_class_by_name_and_type(
1002 struct bt_plugin *plugin, const char *name,
d3e4dcd8 1003 enum bt_component_class_type type)
33b34c43
PP
1004{
1005 struct bt_component_class *comp_class = NULL;
1006 size_t i;
1007
1008 if (!plugin || !name) {
1009 goto error;
1010 }
1011
1012 for (i = 0; i < plugin->comp_classes->len; i++) {
1013 struct bt_component_class *comp_class_candidate =
1014 g_ptr_array_index(plugin->comp_classes, i);
1015 const char *comp_class_cand_name =
1016 bt_component_class_get_name(comp_class_candidate);
d3e4dcd8 1017 enum bt_component_class_type comp_class_cand_type =
33b34c43
PP
1018 bt_component_class_get_type(comp_class_candidate);
1019
1020 assert(comp_class_cand_name);
1021 assert(comp_class_cand_type >= 0);
1022
1023 if (strcmp(name, comp_class_cand_name) == 0 &&
1024 comp_class_cand_type == type) {
1025 comp_class = bt_get(comp_class_candidate);
1026 break;
1027 }
1028 }
1029
1030 goto end;
1031
1032error:
1033 BT_PUT(comp_class);
1034
1035end:
1036 return comp_class;
1037}
1038
1039static
1040void plugin_comp_class_destroy_listener(struct bt_component_class *comp_class,
1041 void *data)
1042{
1043 gboolean exists = g_hash_table_remove(comp_classes_to_shlib_handles,
1044 comp_class);
1045 assert(exists);
1046}
1047
1048enum bt_plugin_status bt_plugin_add_component_class(
1049 struct bt_plugin *plugin, struct bt_component_class *comp_class)
1050{
1051 enum bt_plugin_status status = BT_PLUGIN_STATUS_OK;
1052 struct bt_component_class *comp_class_dup = NULL;
1053 int ret;
1054 int comp_class_index = -1;
1055
1056 if (!plugin || !comp_class || plugin->frozen) {
1057 goto error;
1058 }
1059
1060 /* Check for duplicate */
1061 comp_class_dup = bt_plugin_get_component_class_by_name_and_type(plugin,
1062 bt_component_class_get_name(comp_class),
1063 bt_component_class_get_type(comp_class));
1064 if (comp_class_dup) {
1065 printf_verbose("Plugin `%s`: adding component class with existing name `%s` and type %d\n",
6ba0b073 1066 plugin->name,
33b34c43
PP
1067 bt_component_class_get_name(comp_class),
1068 bt_component_class_get_type(comp_class));
1069 goto error;
1070 }
1071
1072 /* Add new component class */
1073 comp_class_index = plugin->comp_classes->len;
1074 g_ptr_array_add(plugin->comp_classes, bt_get(comp_class));
1075
1076 /* Map component class pointer to shared lib handle in global HT */
1077 g_hash_table_insert(comp_classes_to_shlib_handles, comp_class,
1078 bt_get(plugin->shared_lib_handle));
1079
1080 /* Add our custom destroy listener */
1081 ret = bt_component_class_add_destroy_listener(comp_class,
1082 plugin_comp_class_destroy_listener, NULL);
1083 if (ret) {
1084 goto error;
1085 }
1086
1087 goto end;
1088
1089error:
1090 /* Remove entry from global hash table (if exists) */
1091 g_hash_table_remove(comp_classes_to_shlib_handles,
1092 comp_class);
1093
1094 /* Remove entry from plugin's component classes (if added) */
1095 if (comp_class_index >= 0) {
1096 g_ptr_array_remove_index(plugin->comp_classes,
1097 comp_class_index);
1098 }
1099
1100 status = BT_PLUGIN_STATUS_ERROR;
1101
1102end:
1103 bt_put(comp_class_dup);
1104 return status;
1105}
This page took 0.065629 seconds and 4 git commands to generate.