ref.h: doc: fix typo
[babeltrace.git] / lib / plugin-system / component-factory.c
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>
31 #include <babeltrace/plugin/component-class-internal.h>
32 #include <babeltrace/plugin/source-internal.h>
33 #include <babeltrace/plugin/sink-internal.h>
34 #include <babeltrace/babeltrace-internal.h>
35 #include <babeltrace/compiler.h>
36 #include <babeltrace/ref.h>
37 #include <unistd.h>
38 #include <stdlib.h>
39 #include <sys/stat.h>
40 #include <gmodule.h>
41 #include <stdbool.h>
42 #include <dirent.h>
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)
48 #define PLUGIN_SUFFIX_LEN max_t(size_t, sizeof(NATIVE_PLUGIN_SUFFIX), \
49 sizeof(LIBTOOL_PLUGIN_SUFFIX))
50
51 DECLARE_PLUG_IN_SECTIONS;
52
53 /* Allocate dirent as recommended by READDIR(3), NOTES on readdir_r */
54 static
55 struct 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
70 static
71 enum 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
94 static
95 enum bt_component_factory_status
96 bt_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;
102 struct bt_plugin *plugin;
103 bool is_libtool_wrapper = false, is_shared_object = false;
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) {
112 ret = BT_COMPONENT_FACTORY_STATUS_INVAL;
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 */
121 is_libtool_wrapper = !strncmp(LIBTOOL_PLUGIN_SUFFIX,
122 path + path_len - LIBTOOL_PLUGIN_SUFFIX_LEN,
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) {
128 /* Name indicates that this is not a plugin file. */
129 ret = BT_COMPONENT_FACTORY_STATUS_INVAL;
130 goto end;
131 }
132
133 module = g_module_open(path, 0);
134 if (!module) {
135 printf_verbose("Module open error: %s\n", g_module_error());
136 ret = BT_COMPONENT_FACTORY_STATUS_ERROR;
137 goto end;
138 }
139
140 /* Load plugin and make sure it defines the required entry points. */
141 plugin = bt_plugin_create_from_module(module, path);
142 if (!plugin) {
143 ret = BT_COMPONENT_FACTORY_STATUS_INVAL_PLUGIN;
144 if (!g_module_close(module)) {
145 printf_error("Module close error: %s\n",
146 g_module_error());
147 }
148 goto end;
149 }
150 ret = init_plugin(factory, plugin);
151 end:
152 return ret;
153 }
154
155 static
156 enum bt_component_factory_status
157 bt_component_factory_load_dir(struct bt_component_factory *factory,
158 const char *path, bool recurse)
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
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
196 /* Recursively walk directory */
197 while (!readdir_r(directory, entry, &result) && result) {
198 struct stat st;
199 int stat_ret;
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);
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. */
219 printf_perror("Failed to stat() plugin file\n");
220 continue;
221 }
222
223 if (S_ISDIR(st.st_mode) && recurse) {
224 ret = bt_component_factory_load_dir(factory,
225 file_path, true);
226 if (ret != BT_COMPONENT_FACTORY_STATUS_OK) {
227 goto end;
228 }
229 } else if (S_ISREG(st.st_mode)) {
230 bt_component_factory_load_file(factory, file_path);
231 }
232 }
233 end:
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 }
243 free(entry);
244 free(file_path);
245 return ret;
246 }
247
248 static
249 void bt_component_factory_destroy(struct bt_object *obj)
250 {
251 struct bt_component_factory *factory = NULL;
252
253 assert(obj);
254 factory = container_of(obj, struct bt_component_factory, base);
255
256 if (factory->component_classes) {
257 g_ptr_array_free(factory->component_classes, TRUE);
258 }
259 g_free(factory);
260 }
261
262 struct bt_component_factory *bt_component_factory_create(void)
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
271 bt_object_init(factory, bt_component_factory_destroy);
272 factory->component_classes = g_ptr_array_new_with_free_func(
273 (GDestroyNotify) bt_put);
274 if (!factory->component_classes) {
275 goto error;
276 }
277 end:
278 return factory;
279 error:
280 BT_PUT(factory);
281 return factory;
282 }
283
284 int bt_component_factory_get_component_class_count(
285 struct bt_component_factory *factory)
286 {
287 return factory ? factory->component_classes->len : -1;
288 }
289
290 struct 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));
301 end:
302 return component_class;
303 }
304
305 struct 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)) {
330 bt_put(plugin);
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)) {
341 bt_put(plugin);
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)) {
352 bt_put(plugin);
353 continue;
354 }
355 }
356
357 bt_put(plugin);
358 /* All criteria met. */
359 goto match;
360 }
361
362 no_match:
363 return NULL;
364 match:
365 return bt_get(component_class);
366 }
367
368 static
369 enum bt_component_factory_status _bt_component_factory_load(
370 struct bt_component_factory *factory, const char *path,
371 bool recursive)
372 {
373 enum bt_component_factory_status ret = BT_COMPONENT_FACTORY_STATUS_OK;
374
375 if (!factory || !path) {
376 ret = BT_COMPONENT_FACTORY_STATUS_INVAL;
377 goto end;
378 }
379
380 if (!g_file_test(path, G_FILE_TEST_EXISTS)) {
381 ret = BT_COMPONENT_FACTORY_STATUS_NOENT;
382 goto end;
383 }
384
385 if (g_file_test(path, G_FILE_TEST_IS_DIR)) {
386 ret = bt_component_factory_load_dir(factory, path, recursive);
387 } else if (g_file_test(path, G_FILE_TEST_IS_REGULAR) ||
388 g_file_test(path, G_FILE_TEST_IS_SYMLINK)) {
389 ret = bt_component_factory_load_file(factory, path);
390 } else {
391 ret = BT_COMPONENT_FACTORY_STATUS_INVAL;
392 goto end;
393 }
394 end:
395 return ret;
396 }
397
398 enum 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
404 enum 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
410 enum 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 }
439 end:
440 return ret;
441 }
442
443 static
444 enum bt_component_factory_status
445 add_component_class(struct bt_component_factory *factory, const char *name,
446 const char *description, bt_component_init_cb init,
447 enum bt_component_type type)
448 {
449 struct bt_component_class *component_class;
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 }
456 assert(factory->current_plugin);
457
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
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",
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,
480 init, factory->current_plugin);
481 g_ptr_array_add(factory->component_classes, component_class);
482 end:
483 return ret;
484 }
485
486 enum bt_component_factory_status
487 bt_component_factory_register_source_component_class(
488 struct bt_component_factory *factory, const char *name,
489 const char *description, bt_component_init_cb init)
490 {
491 return add_component_class(factory, name, description, init,
492 BT_COMPONENT_TYPE_SOURCE);
493 }
494
495 enum bt_component_factory_status
496 bt_component_factory_register_sink_component_class(
497 struct bt_component_factory *factory, const char *name,
498 const char *description, bt_component_init_cb init)
499 {
500 return add_component_class(factory, name, description, init,
501 BT_COMPONENT_TYPE_SINK);
502 }
503
504 enum bt_component_factory_status
505 bt_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.042042 seconds and 4 git commands to generate.