ref.h: doc: fix typo
[babeltrace.git] / lib / plugin-system / component-factory.c
CommitLineData
f3e4505b
JG
1/*
2 * component-factory.c
3 *
4 * Babeltrace Plugin Component Factory
5 *
6 * Copyright 2015 Jérémie Galarneau <jeremie.galarneau@efficios.com>
7 *
8 * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
9 *
10 * Permission is hereby granted, free of charge, to any person obtaining a copy
11 * of this software and associated documentation files (the "Software"), to deal
12 * in the Software without restriction, including without limitation the rights
13 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 * copies of the Software, and to permit persons to whom the Software is
15 * furnished to do so, subject to the following conditions:
16 *
17 * The above copyright notice and this permission notice shall be included in
18 * all copies or substantial portions of the Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26 * SOFTWARE.
27 */
28
29#include <babeltrace/plugin/component-factory.h>
30#include <babeltrace/plugin/component-factory-internal.h>
38b48196 31#include <babeltrace/plugin/component-class-internal.h>
92893b7b
JG
32#include <babeltrace/plugin/source-internal.h>
33#include <babeltrace/plugin/sink-internal.h>
f3e4505b
JG
34#include <babeltrace/babeltrace-internal.h>
35#include <babeltrace/compiler.h>
b8a06801 36#include <babeltrace/ref.h>
f3e4505b
JG
37#include <unistd.h>
38#include <stdlib.h>
39#include <sys/stat.h>
fb2dcc52 40#include <gmodule.h>
39cfa40f 41#include <stdbool.h>
eef2121c 42#include <dirent.h>
f3e4505b
JG
43
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)
73299554
JG
48#define PLUGIN_SUFFIX_LEN max_t(size_t, sizeof(NATIVE_PLUGIN_SUFFIX), \
49 sizeof(LIBTOOL_PLUGIN_SUFFIX))
f3e4505b 50
cba174d5
JG
51DECLARE_PLUG_IN_SECTIONS;
52
f3e4505b
JG
53/* Allocate dirent as recommended by READDIR(3), NOTES on readdir_r */
54static
55struct dirent *alloc_dirent(const char *path)
56{
57 size_t len;
58 long name_max;
59 struct dirent *entry;
60
61 name_max = pathconf(path, _PC_NAME_MAX);
62 if (name_max == -1) {
63 name_max = PATH_MAX;
64 }
65 len = offsetof(struct dirent, d_name) + name_max + 1;
66 entry = zmalloc(len);
67 return entry;
68}
69
cba174d5
JG
70static
71enum bt_component_factory_status init_plugin(
72 struct bt_component_factory *factory, struct bt_plugin *plugin)
73{
74 enum bt_component_status component_status;
75 enum bt_component_factory_status ret = BT_COMPONENT_FACTORY_STATUS_OK;
76
77 BT_MOVE(factory->current_plugin, plugin);
78 component_status = bt_plugin_register_component_classes(
79 factory->current_plugin, factory);
80 BT_PUT(factory->current_plugin);
81 if (component_status != BT_COMPONENT_STATUS_OK) {
82 switch (component_status) {
83 case BT_COMPONENT_STATUS_NOMEM:
84 ret = BT_COMPONENT_FACTORY_STATUS_NOMEM;
85 break;
86 default:
87 ret = BT_COMPONENT_FACTORY_STATUS_ERROR;
88 break;
89 }
90 }
91 return ret;
92}
93
f3e4505b
JG
94static
95enum bt_component_factory_status
96bt_component_factory_load_file(struct bt_component_factory *factory,
97 const char *path)
98{
99 enum bt_component_factory_status ret = BT_COMPONENT_FACTORY_STATUS_OK;
100 size_t path_len;
101 GModule *module;
fb2dcc52 102 struct bt_plugin *plugin;
92893b7b 103 bool is_libtool_wrapper = false, is_shared_object = false;
f3e4505b
JG
104
105 if (!factory || !path) {
106 ret = BT_COMPONENT_FACTORY_STATUS_INVAL;
107 goto end;
108 }
109
110 path_len = strlen(path);
111 if (path_len <= PLUGIN_SUFFIX_LEN) {
73299554 112 ret = BT_COMPONENT_FACTORY_STATUS_INVAL;
f3e4505b
JG
113 goto end;
114 }
115
116 path_len++;
117 /*
118 * Check if the file ends with a known plugin file type suffix (i.e. .so
119 * or .la on Linux).
120 */
92893b7b 121 is_libtool_wrapper = !strncmp(LIBTOOL_PLUGIN_SUFFIX,
b8a06801 122 path + path_len - LIBTOOL_PLUGIN_SUFFIX_LEN,
92893b7b
JG
123 LIBTOOL_PLUGIN_SUFFIX_LEN);
124 is_shared_object = !strncmp(NATIVE_PLUGIN_SUFFIX,
125 path + path_len - NATIVE_PLUGIN_SUFFIX_LEN,
126 NATIVE_PLUGIN_SUFFIX_LEN);
127 if (!is_shared_object && !is_libtool_wrapper) {
73299554
JG
128 /* Name indicates that this is not a plugin file. */
129 ret = BT_COMPONENT_FACTORY_STATUS_INVAL;
f3e4505b
JG
130 goto end;
131 }
132
133 module = g_module_open(path, 0);
134 if (!module) {
8bbddeca 135 printf_verbose("Module open error: %s\n", g_module_error());
73299554 136 ret = BT_COMPONENT_FACTORY_STATUS_ERROR;
f3e4505b
JG
137 goto end;
138 }
139
cba174d5
JG
140 /* Load plugin and make sure it defines the required entry points. */
141 plugin = bt_plugin_create_from_module(module, path);
73299554 142 if (!plugin) {
fb2dcc52 143 ret = BT_COMPONENT_FACTORY_STATUS_INVAL_PLUGIN;
73299554 144 if (!g_module_close(module)) {
cba174d5 145 printf_error("Module close error: %s\n",
fb2dcc52
JG
146 g_module_error());
147 }
148 goto end;
149 }
cba174d5 150 ret = init_plugin(factory, plugin);
f3e4505b
JG
151end:
152 return ret;
153}
154
155static
156enum bt_component_factory_status
5d4cba3d
JG
157bt_component_factory_load_dir(struct bt_component_factory *factory,
158 const char *path, bool recurse)
f3e4505b
JG
159{
160 DIR *directory = NULL;
161 struct dirent *entry = NULL, *result = NULL;
162 char *file_path = NULL;
163 size_t path_len = strlen(path);
164 enum bt_component_factory_status ret = BT_COMPONENT_FACTORY_STATUS_OK;
165
166 if (path_len >= PATH_MAX) {
167 ret = BT_COMPONENT_FACTORY_STATUS_INVAL;
168 goto end;
169 }
170
171 entry = alloc_dirent(path);
172 if (!entry) {
173 ret = BT_COMPONENT_FACTORY_STATUS_NOMEM;
174 goto end;
175 }
176
177 file_path = zmalloc(PATH_MAX);
178 if (!file_path) {
179 ret = BT_COMPONENT_FACTORY_STATUS_NOMEM;
180 goto end;
181 }
182
183 strncpy(file_path, path, path_len);
184 /* Append a trailing '/' to the path */
185 if (file_path[path_len - 1] != '/') {
186 file_path[path_len++] = '/';
187 }
188
33bceaf8
JG
189 directory = opendir(file_path);
190 if (!directory) {
191 perror("Failed to open plug-in directory");
192 ret = BT_COMPONENT_FACTORY_STATUS_ERROR;
193 goto end;
194 }
195
f3e4505b
JG
196 /* Recursively walk directory */
197 while (!readdir_r(directory, entry, &result) && result) {
198 struct stat st;
199 int stat_ret;
33bceaf8
JG
200 size_t file_name_len;
201
202 if (result->d_name[0] == '.') {
203 /* Skip hidden files, . and .. */
204 continue;
205 }
206
207 file_name_len = strlen(result->d_name);
f3e4505b
JG
208
209 if (path_len + file_name_len >= PATH_MAX) {
210 continue;
211 }
212
213 strncpy(file_path + path_len, result->d_name, file_name_len);
214 file_path[path_len + file_name_len] = '\0';
215
216 stat_ret = stat(file_path, &st);
217 if (stat_ret < 0) {
218 /* Continue to next file / directory. */
5e86a071 219 printf_perror("Failed to stat() plugin file\n");
f3e4505b
JG
220 continue;
221 }
222
5d4cba3d
JG
223 if (S_ISDIR(st.st_mode) && recurse) {
224 ret = bt_component_factory_load_dir(factory,
225 file_path, true);
f3e4505b
JG
226 if (ret != BT_COMPONENT_FACTORY_STATUS_OK) {
227 goto end;
228 }
229 } else if (S_ISREG(st.st_mode)) {
360470eb 230 bt_component_factory_load_file(factory, file_path);
f3e4505b
JG
231 }
232 }
233end:
33bceaf8
JG
234 if (directory) {
235 if (closedir(directory)) {
236 /*
237 * We don't want to override the error since there is
238 * nothing could do.
239 */
240 perror("Failed to close plug-in directory");
241 }
242 }
f3e4505b
JG
243 free(entry);
244 free(file_path);
245 return ret;
246}
247
b8a06801
JG
248static
249void bt_component_factory_destroy(struct bt_object *obj)
f3e4505b 250{
b8a06801
JG
251 struct bt_component_factory *factory = NULL;
252
253 assert(obj);
254 factory = container_of(obj, struct bt_component_factory, base);
f3e4505b 255
92893b7b
JG
256 if (factory->component_classes) {
257 g_ptr_array_free(factory->component_classes, TRUE);
fb2dcc52 258 }
f3e4505b
JG
259 g_free(factory);
260}
261
b8a06801 262struct bt_component_factory *bt_component_factory_create(void)
f3e4505b
JG
263{
264 struct bt_component_factory *factory;
265
266 factory = g_new0(struct bt_component_factory, 1);
267 if (!factory) {
268 goto end;
269 }
270
b8a06801 271 bt_object_init(factory, bt_component_factory_destroy);
92893b7b 272 factory->component_classes = g_ptr_array_new_with_free_func(
b8a06801 273 (GDestroyNotify) bt_put);
92893b7b 274 if (!factory->component_classes) {
fb2dcc52
JG
275 goto error;
276 }
f3e4505b
JG
277end:
278 return factory;
279error:
b8a06801
JG
280 BT_PUT(factory);
281 return factory;
f3e4505b
JG
282}
283
38b48196 284int bt_component_factory_get_component_class_count(
92893b7b
JG
285 struct bt_component_factory *factory)
286{
38b48196
JG
287 return factory ? factory->component_classes->len : -1;
288}
289
290struct bt_component_class *bt_component_factory_get_component_class_index(
291 struct bt_component_factory *factory, int index)
292{
293 struct bt_component_class *component_class = NULL;
294
295 if (!factory || index < 0 || index >= factory->component_classes->len) {
296 goto end;
297 }
298
299 component_class = bt_get(g_ptr_array_index(
300 factory->component_classes, index));
301end:
302 return component_class;
303}
304
305struct bt_component_class *bt_component_factory_get_component_class(
306 struct bt_component_factory *factory,
307 const char *plugin_name, enum bt_component_type type,
308 const char *component_name)
309{
310 size_t i;
311 struct bt_component_class *component_class = NULL;
312
313 if (!factory || (!plugin_name && !component_name &&
314 type == BT_COMPONENT_TYPE_UNKNOWN)) {
315 /* At least one criterion must be provided. */
316 goto no_match;
317 }
318
319 for (i = 0; i < factory->component_classes->len; i++) {
320 struct bt_plugin *plugin = NULL;
321
322 component_class = g_ptr_array_index(factory->component_classes,
323 i);
324 plugin = bt_component_class_get_plugin(component_class);
325 assert(plugin);
326
327 if (type != BT_COMPONENT_TYPE_UNKNOWN) {
328 if (type != bt_component_class_get_type(
329 component_class)) {
0cc9e945 330 bt_put(plugin);
38b48196
JG
331 continue;
332 }
333 }
334
335 if (plugin_name) {
336 const char *cur_plugin_name = bt_plugin_get_name(
337 plugin);
338
339 assert(cur_plugin_name);
340 if (strcmp(plugin_name, cur_plugin_name)) {
0cc9e945 341 bt_put(plugin);
38b48196
JG
342 continue;
343 }
344 }
345
346 if (component_name) {
347 const char *cur_cc_name = bt_component_class_get_name(
348 component_class);
349
350 assert(cur_cc_name);
351 if (strcmp(component_name, cur_cc_name)) {
0cc9e945 352 bt_put(plugin);
38b48196
JG
353 continue;
354 }
355 }
356
0cc9e945 357 bt_put(plugin);
38b48196
JG
358 /* All criteria met. */
359 goto match;
360 }
361
362no_match:
92893b7b 363 return NULL;
38b48196
JG
364match:
365 return bt_get(component_class);
92893b7b
JG
366}
367
5d4cba3d
JG
368static
369enum bt_component_factory_status _bt_component_factory_load(
370 struct bt_component_factory *factory, const char *path,
371 bool recursive)
f3e4505b
JG
372{
373 enum bt_component_factory_status ret = BT_COMPONENT_FACTORY_STATUS_OK;
f3e4505b
JG
374
375 if (!factory || !path) {
376 ret = BT_COMPONENT_FACTORY_STATUS_INVAL;
377 goto end;
378 }
379
b8a06801
JG
380 if (!g_file_test(path, G_FILE_TEST_EXISTS)) {
381 ret = BT_COMPONENT_FACTORY_STATUS_NOENT;
382 goto end;
f3e4505b
JG
383 }
384
b8a06801 385 if (g_file_test(path, G_FILE_TEST_IS_DIR)) {
5d4cba3d 386 ret = bt_component_factory_load_dir(factory, path, recursive);
b8a06801
JG
387 } else if (g_file_test(path, G_FILE_TEST_IS_REGULAR) ||
388 g_file_test(path, G_FILE_TEST_IS_SYMLINK)) {
f3e4505b 389 ret = bt_component_factory_load_file(factory, path);
b8a06801
JG
390 } else {
391 ret = BT_COMPONENT_FACTORY_STATUS_INVAL;
392 goto end;
f3e4505b
JG
393 }
394end:
f3e4505b
JG
395 return ret;
396}
92893b7b 397
5d4cba3d
JG
398enum bt_component_factory_status bt_component_factory_load_recursive(
399 struct bt_component_factory *factory, const char *path)
400{
401 return _bt_component_factory_load(factory, path, true);
402}
403
404enum bt_component_factory_status bt_component_factory_load(
405 struct bt_component_factory *factory, const char *path)
406{
407 return _bt_component_factory_load(factory, path, false);
408}
409
cba174d5
JG
410enum bt_component_factory_status bt_component_factory_load_static(
411 struct bt_component_factory *factory)
412{
413 size_t count, i;
414 enum bt_component_factory_status ret = BT_COMPONENT_FACTORY_STATUS_OK;
415
416 PRINT_PLUG_IN_SECTIONS(printf_verbose);
417
418 count = SECTION_ELEMENT_COUNT(__plugin_register_funcs);
419 if (SECTION_ELEMENT_COUNT(__plugin_register_funcs) != count ||
420 SECTION_ELEMENT_COUNT(__plugin_names) != count ||
421 SECTION_ELEMENT_COUNT(__plugin_authors) != count ||
422 SECTION_ELEMENT_COUNT(__plugin_licenses) != count ||
423 SECTION_ELEMENT_COUNT(__plugin_descriptions) != count) {
424 printf_error("Some statically-linked plug-ins do not define all mandatory symbols\n");
425 ret = BT_COMPONENT_FACTORY_STATUS_INVAL_PLUGIN;
426 goto end;
427 }
428 printf_verbose("Detected %zu statically-linked plug-ins\n", count);
429
430 for (i = 0; i < count; i++) {
431 struct bt_plugin *plugin = bt_plugin_create_from_static(i);
432
433 if (!plugin) {
434 continue;
435 }
436
437 (void) init_plugin(factory, plugin);
438 }
439end:
440 return ret;
441}
442
38b48196 443static
92893b7b 444enum bt_component_factory_status
38b48196 445add_component_class(struct bt_component_factory *factory, const char *name,
7c7c0433
JG
446 const char *description, bt_component_init_cb init,
447 enum bt_component_type type)
92893b7b 448{
0859fe1f 449 struct bt_component_class *component_class;
92893b7b
JG
450 enum bt_component_factory_status ret = BT_COMPONENT_FACTORY_STATUS_OK;
451
452 if (!factory || !name || !init) {
453 ret = BT_COMPONENT_FACTORY_STATUS_INVAL;
454 goto end;
455 }
0859fe1f 456 assert(factory->current_plugin);
92893b7b 457
0859fe1f
JG
458 /*
459 * Ensure this component class does not clash with a currently
460 * registered class.
461 */
462 component_class = bt_component_factory_get_component_class(factory,
463 bt_plugin_get_name(factory->current_plugin), type, name);
464 if (component_class) {
465 struct bt_plugin *plugin = bt_component_class_get_plugin(
466 component_class);
467
b53aefc1 468 printf_verbose("Duplicate component class registration attempted. Component class %s being registered by plugin %s (path: %s) conflicts with one already registered by plugin %s (path: %s)\n",
0859fe1f
JG
469 name, bt_plugin_get_name(factory->current_plugin),
470 bt_plugin_get_path(factory->current_plugin),
471 bt_plugin_get_name(plugin),
472 bt_plugin_get_path(plugin));
473 ret = BT_COMPONENT_FACTORY_STATUS_DUPLICATE;
474 BT_PUT(component_class);
475 bt_put(plugin);
476 goto end;
477 }
478
479 component_class = bt_component_class_create(type, name, description,
fec2a9f2 480 init, factory->current_plugin);
0859fe1f 481 g_ptr_array_add(factory->component_classes, component_class);
92893b7b
JG
482end:
483 return ret;
484}
38b48196
JG
485
486enum bt_component_factory_status
487bt_component_factory_register_source_component_class(
488 struct bt_component_factory *factory, const char *name,
7c7c0433 489 const char *description, bt_component_init_cb init)
38b48196 490{
7c7c0433 491 return add_component_class(factory, name, description, init,
38b48196
JG
492 BT_COMPONENT_TYPE_SOURCE);
493}
494
495enum bt_component_factory_status
496bt_component_factory_register_sink_component_class(
497 struct bt_component_factory *factory, const char *name,
7c7c0433 498 const char *description, bt_component_init_cb init)
38b48196 499{
7c7c0433 500 return add_component_class(factory, name, description, init,
38b48196
JG
501 BT_COMPONENT_TYPE_SINK);
502}
34ac9eaf
JG
503
504enum bt_component_factory_status
505bt_component_factory_register_filter_component_class(
506 struct bt_component_factory *factory, const char *name,
507 const char *description, bt_component_init_cb init)
508{
509 return add_component_class(factory, name, description, init,
510 BT_COMPONENT_TYPE_FILTER);
511}
This page took 0.050039 seconds and 4 git commands to generate.