Port: dirfd is not portable, replace it
[babeltrace.git] / lib / plugin / plugin.c
... / ...
CommitLineData
1/*
2 * plugin.c
3 *
4 * Babeltrace Plugin (generic)
5 *
6 * Copyright 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
7 * Copyright 2017 Philippe Proulx <pproulx@efficios.com>
8 *
9 * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
10 *
11 * Permission is hereby granted, free of charge, to any person obtaining a copy
12 * of this software and associated documentation files (the "Software"), to deal
13 * in the Software without restriction, including without limitation the rights
14 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15 * copies of the Software, and to permit persons to whom the Software is
16 * furnished to do so, subject to the following conditions:
17 *
18 * The above copyright notice and this permission notice shall be included in
19 * all copies or substantial portions of the Software.
20 *
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27 * SOFTWARE.
28 */
29
30#define BT_LOG_TAG "PLUGIN"
31#include <babeltrace/lib-logging-internal.h>
32
33#include <babeltrace/babeltrace-internal.h>
34#include <babeltrace/compiler-internal.h>
35#include <babeltrace/ref.h>
36#include <babeltrace/common-internal.h>
37#include <babeltrace/plugin/plugin-internal.h>
38#include <babeltrace/plugin/plugin-so-internal.h>
39#include <babeltrace/graph/component-class.h>
40#include <babeltrace/graph/component-class-internal.h>
41#include <babeltrace/types.h>
42#include <glib.h>
43#include <unistd.h>
44#include <stdlib.h>
45#include <stdint.h>
46#include <inttypes.h>
47#include <sys/stat.h>
48#include <dirent.h>
49
50#define PYTHON_PLUGIN_PROVIDER_FILENAME "libbabeltrace-python-plugin-provider." G_MODULE_SUFFIX
51#define PYTHON_PLUGIN_PROVIDER_SYM_NAME bt_plugin_python_create_all_from_file
52#define PYTHON_PLUGIN_PROVIDER_SYM_NAME_STR TOSTRING(PYTHON_PLUGIN_PROVIDER_SYM_NAME)
53
54#ifdef BT_BUILT_IN_PYTHON_PLUGIN_SUPPORT
55#include <babeltrace/plugin/python-plugin-provider-internal.h>
56static
57struct bt_plugin_set *(*bt_plugin_python_create_all_from_file_sym)(const char *path) =
58 bt_plugin_python_create_all_from_file;
59#else /* BT_BUILT_IN_PYTHON_PLUGIN_SUPPORT */
60static GModule *python_plugin_provider_module;
61static
62struct bt_plugin_set *(*bt_plugin_python_create_all_from_file_sym)(const char *path);
63
64__attribute__((constructor)) static
65void init_python_plugin_provider(void) {
66 BT_LOGD_STR("Loading Python plugin provider module.");
67 python_plugin_provider_module =
68 g_module_open(PYTHON_PLUGIN_PROVIDER_FILENAME,
69 G_MODULE_BIND_LOCAL);
70 if (!python_plugin_provider_module) {
71 BT_LOGI("Cannot find `%s`: continuing without Python plugin support.",
72 PYTHON_PLUGIN_PROVIDER_FILENAME);
73 return;
74 }
75
76 if (!g_module_symbol(python_plugin_provider_module,
77 PYTHON_PLUGIN_PROVIDER_SYM_NAME_STR,
78 (gpointer) &bt_plugin_python_create_all_from_file_sym)) {
79 BT_LOGI("Cannot find the Python plugin provider loading symbol: continuing without Python plugin support: "
80 "file=\"%s\", symbol=\"%s\"",
81 PYTHON_PLUGIN_PROVIDER_FILENAME,
82 PYTHON_PLUGIN_PROVIDER_SYM_NAME_STR);
83 return;
84 }
85
86 BT_LOGI("Loaded Python plugin provider module: addr=%p",
87 python_plugin_provider_module);
88}
89
90__attribute__((destructor)) static
91void fini_python_plugin_provider(void) {
92 if (python_plugin_provider_module) {
93 BT_LOGD("Unloading Python plugin provider module.");
94
95 if (!g_module_close(python_plugin_provider_module)) {
96 BT_LOGE("Failed to close the Python plugin provider module: %s.",
97 g_module_error());
98 }
99
100 python_plugin_provider_module = NULL;
101 }
102}
103#endif
104
105extern
106int64_t bt_plugin_set_get_plugin_count(struct bt_plugin_set *plugin_set)
107{
108 int64_t count = -1;
109
110 if (!plugin_set) {
111 BT_LOGW_STR("Invalid parameter: plugin set is NULL.");
112 goto end;
113 }
114
115 count = (int64_t) plugin_set->plugins->len;
116
117end:
118 return count;
119}
120
121extern
122struct bt_plugin *bt_plugin_set_get_plugin(struct bt_plugin_set *plugin_set,
123 uint64_t index)
124{
125 struct bt_plugin *plugin = NULL;
126
127 if (!plugin_set) {
128 BT_LOGW_STR("Invalid parameter: plugin set is NULL.");
129 goto end;
130 }
131
132 if (index >= plugin_set->plugins->len) {
133 BT_LOGW("Invalid parameter: index is out of bounds: "
134 "addr=%p, index=%" PRIu64 ", count=%u",
135 plugin_set, index, plugin_set->plugins->len);
136 goto end;
137 }
138
139 plugin = bt_get(g_ptr_array_index(plugin_set->plugins, index));
140
141end:
142 return plugin;
143}
144
145struct bt_plugin_set *bt_plugin_create_all_from_static(void)
146{
147 /* bt_plugin_so_create_all_from_static() logs errors */
148 return bt_plugin_so_create_all_from_static();
149}
150
151struct bt_plugin_set *bt_plugin_create_all_from_file(const char *path)
152{
153 struct bt_plugin_set *plugin_set = NULL;
154
155 if (!path) {
156 BT_LOGW_STR("Invalid parameter: path is NULL.");
157 goto end;
158 }
159
160 BT_LOGD("Creating plugins from file: path=\"%s\"", path);
161
162 /* Try shared object plugins */
163 plugin_set = bt_plugin_so_create_all_from_file(path);
164 if (plugin_set) {
165 goto end;
166 }
167
168 /* Try Python plugins if support is available */
169 if (bt_plugin_python_create_all_from_file_sym) {
170 plugin_set = bt_plugin_python_create_all_from_file_sym(path);
171 if (plugin_set) {
172 goto end;
173 }
174 }
175
176end:
177 if (plugin_set) {
178 BT_LOGD("Created %u plugins from file: "
179 "path=\"%s\", count=%u, plugin-set-addr=%p",
180 plugin_set->plugins->len, path,
181 plugin_set->plugins->len, plugin_set);
182 } else {
183 BT_LOGD("Found no plugins in file: path=\"%s\"", path);
184 }
185
186 return plugin_set;
187}
188
189static void destroy_gstring(void *data)
190{
191 g_string_free(data, TRUE);
192}
193
194struct bt_plugin *bt_plugin_find(const char *plugin_name)
195{
196 const char *system_plugin_dir;
197 char *home_plugin_dir = NULL;
198 const char *envvar;
199 struct bt_plugin *plugin = NULL;
200 struct bt_plugin_set *plugin_set = NULL;
201 GPtrArray *dirs = NULL;
202 int ret;
203 size_t i, j;
204
205 if (!plugin_name) {
206 BT_LOGW_STR("Invalid parameter: plugin name is NULL.");
207 goto end;
208 }
209
210 BT_LOGD("Finding named plugin in standard directories and built-in plugins: "
211 "name=\"%s\"", plugin_name);
212 dirs = g_ptr_array_new_with_free_func((GDestroyNotify) destroy_gstring);
213 if (!dirs) {
214 BT_LOGE_STR("Failed to allocate a GPtrArray.");
215 goto end;
216 }
217
218 /*
219 * Search order is:
220 *
221 * 1. BABELTRACE_PLUGIN_PATH environment variable
222 * (colon-separated list of directories)
223 * 2. ~/.local/lib/babeltrace/plugins
224 * 3. Default system directory for Babeltrace plugins, usually
225 * /usr/lib/babeltrace/plugins or
226 * /usr/local/lib/babeltrace/plugins if installed
227 * locally
228 * 4. Built-in plugins (static)
229 *
230 * Directories are searched non-recursively.
231 */
232 envvar = getenv("BABELTRACE_PLUGIN_PATH");
233 if (envvar) {
234 ret = bt_common_append_plugin_path_dirs(envvar, dirs);
235 if (ret) {
236 BT_LOGE_STR("Failed to append plugin path to array of directories.");
237 goto end;
238 }
239 }
240
241 home_plugin_dir = bt_common_get_home_plugin_path();
242 if (home_plugin_dir) {
243 GString *home_plugin_dir_str =
244 g_string_new(home_plugin_dir);
245
246 if (!home_plugin_dir_str) {
247 BT_LOGE_STR("Failed to allocate a GString.");
248 goto end;
249 }
250
251 g_ptr_array_add(dirs, home_plugin_dir_str);
252 }
253
254 system_plugin_dir = bt_common_get_system_plugin_path();
255 if (system_plugin_dir) {
256 GString *system_plugin_dir_str =
257 g_string_new(system_plugin_dir);
258
259 if (!system_plugin_dir_str) {
260 BT_LOGE_STR("Failed to allocate a GString.");
261 goto end;
262 }
263
264 g_ptr_array_add(dirs, system_plugin_dir_str);
265 }
266
267 for (i = 0; i < dirs->len; i++) {
268 GString *dir = g_ptr_array_index(dirs, i);
269
270 BT_PUT(plugin_set);
271
272 /*
273 * Skip this if the directory does not exist because
274 * bt_plugin_create_all_from_dir() would log a warning.
275 */
276 if (!g_file_test(dir->str, G_FILE_TEST_IS_DIR)) {
277 BT_LOGV("Skipping nonexistent directory path: "
278 "path=\"%s\"", dir->str);
279 continue;
280 }
281
282 /* bt_plugin_create_all_from_dir() logs details/errors */
283 plugin_set = bt_plugin_create_all_from_dir(dir->str, BT_FALSE);
284 if (!plugin_set) {
285 BT_LOGD("No plugins found in directory: path=\"%s\"",
286 dir->str);
287 continue;
288 }
289
290 for (j = 0; j < plugin_set->plugins->len; j++) {
291 struct bt_plugin *candidate_plugin =
292 g_ptr_array_index(plugin_set->plugins, j);
293
294 if (strcmp(bt_plugin_get_name(candidate_plugin),
295 plugin_name) == 0) {
296 BT_LOGD("Plugin found in directory: name=\"%s\", path=\"%s\"",
297 plugin_name, dir->str);
298 plugin = bt_get(candidate_plugin);
299 goto end;
300 }
301 }
302
303 BT_LOGD("Plugin not found in directory: name=\"%s\", path=\"%s\"",
304 plugin_name, dir->str);
305 }
306
307 bt_put(plugin_set);
308 plugin_set = bt_plugin_create_all_from_static();
309 if (plugin_set) {
310 for (j = 0; j < plugin_set->plugins->len; j++) {
311 struct bt_plugin *candidate_plugin =
312 g_ptr_array_index(plugin_set->plugins, j);
313
314 if (strcmp(bt_plugin_get_name(candidate_plugin),
315 plugin_name) == 0) {
316 BT_LOGD("Plugin found in built-in plugins: "
317 "name=\"%s\"", plugin_name);
318 plugin = bt_get(candidate_plugin);
319 goto end;
320 }
321 }
322 }
323
324end:
325 free(home_plugin_dir);
326 bt_put(plugin_set);
327
328 if (dirs) {
329 g_ptr_array_free(dirs, TRUE);
330 }
331
332 if (plugin) {
333 BT_LOGD("Found plugin in standard directories and built-in plugins: "
334 "addr=%p, name=\"%s\", path=\"%s\"",
335 plugin, plugin_name, bt_plugin_get_path(plugin));
336 } else {
337 BT_LOGD("No plugin found in standard directories and built-in plugins: "
338 "name=\"%s\"", plugin_name);
339 }
340
341 return plugin;
342}
343
344struct bt_component_class *bt_plugin_find_component_class(
345 const char *plugin_name, const char *comp_cls_name,
346 enum bt_component_class_type comp_cls_type)
347{
348 struct bt_plugin *plugin = NULL;
349 struct bt_component_class *comp_cls = NULL;
350
351 if (!plugin_name) {
352 BT_LOGW_STR("Invalid parameter: plugin name is NULL.");
353 goto end;
354 }
355
356 if (!comp_cls_name) {
357 BT_LOGW_STR("Invalid parameter: component class name is NULL.");
358 goto end;
359 }
360
361 BT_LOGD("Finding named plugin and component class in standard directories and built-in plugins: "
362 "plugin-name=\"%s\", comp-class-name=\"%s\"",
363 plugin_name, comp_cls_name);
364 plugin = bt_plugin_find(plugin_name);
365 if (!plugin) {
366 BT_LOGD_STR("Plugin not found.");
367 goto end;
368 }
369
370 comp_cls = bt_plugin_get_component_class_by_name_and_type(
371 plugin, comp_cls_name, comp_cls_type);
372 if (!comp_cls) {
373 BT_LOGD("Component class not found in plugin: "
374 "plugin-addr=%p, plugin-path=\"%s\"",
375 plugin, bt_plugin_get_path(plugin));
376 }
377
378end:
379 bt_put(plugin);
380 return comp_cls;
381}
382
383/* Allocate dirent as recommended by READDIR(3), NOTES on readdir_r */
384static
385struct dirent *alloc_dirent(const char *path)
386{
387 size_t len;
388 long name_max;
389 struct dirent *entry;
390
391 name_max = pathconf(path, _PC_NAME_MAX);
392 if (name_max == -1) {
393 name_max = PATH_MAX;
394 }
395 len = offsetof(struct dirent, d_name) + name_max + 1;
396 entry = zmalloc(len);
397 return entry;
398}
399
400static
401enum bt_plugin_status bt_plugin_create_append_all_from_dir(
402 struct bt_plugin_set *plugin_set, const char *path,
403 bt_bool recurse)
404{
405 DIR *directory = NULL;
406 struct dirent *entry = NULL, *result = NULL;
407 char *file_path = NULL;
408 size_t path_len;
409 enum bt_plugin_status ret = BT_PLUGIN_STATUS_OK;
410
411 if (!path) {
412 BT_LOGW_STR("Invalid parameter: path is NULL.");
413 ret = BT_PLUGIN_STATUS_ERROR;
414 goto end;
415 }
416
417 path_len = strlen(path);
418 if (path_len >= PATH_MAX) {
419 BT_LOGW("Invalid parameter: path length is too large: "
420 "path-length=%zu", path_len);
421 ret = BT_PLUGIN_STATUS_ERROR;
422 goto end;
423 }
424
425 entry = alloc_dirent(path);
426 if (!entry) {
427 BT_LOGE_STR("Failed to allocate a directory entry.");
428 ret = BT_PLUGIN_STATUS_ERROR;
429 goto end;
430 }
431
432 file_path = zmalloc(PATH_MAX);
433 if (!file_path) {
434 BT_LOGE("Failed to allocate %zu bytes.", (size_t) PATH_MAX);
435 ret = BT_PLUGIN_STATUS_NOMEM;
436 goto end;
437 }
438
439 strncpy(file_path, path, path_len);
440 /* Append a trailing '/' to the path */
441 if (file_path[path_len - 1] != '/') {
442 file_path[path_len++] = '/';
443 }
444
445 directory = opendir(file_path);
446 if (!directory) {
447 if (errno == EACCES) {
448 BT_LOGD("Cannot open directory: %s: continuing: "
449 "path=\"%s\", errno=%d",
450 strerror(errno), file_path, errno);
451 goto end;
452 }
453
454 BT_LOGW("Cannot open directory: %s: "
455 "path=\"%s\", errno=%d",
456 strerror(errno), file_path, errno);
457 ret = BT_PLUGIN_STATUS_ERROR;
458 goto end;
459 }
460
461 /* Recursively walk directory */
462 while (!readdir_r(directory, entry, &result) && result) {
463 struct stat st;
464 int stat_ret;
465 size_t file_name_len;
466
467 if (strcmp(result->d_name, ".") == 0 ||
468 strcmp(result->d_name, "..") == 0) {
469 /* Obviously not logging this */
470 continue;
471 }
472
473 if (result->d_name[0] == '.') {
474 /* Skip hidden files, . and .. */
475 BT_LOGV("Skipping hidden file: path=\"%s/%s\"",
476 path, result->d_name);
477 continue;
478 }
479
480 file_name_len = strlen(result->d_name);
481
482 if (path_len + file_name_len >= PATH_MAX) {
483 BT_LOGD("Skipping file because its path length is too large: continuing: "
484 "path=\"%s/%s\", length=%zu",
485 path, result->d_name,
486 (size_t) (path_len + file_name_len));
487 continue;
488 }
489
490 strncpy(file_path + path_len, result->d_name, file_name_len);
491 file_path[path_len + file_name_len] = '\0';
492 stat_ret = stat(file_path, &st);
493 if (stat_ret < 0) {
494 /* Continue to next file / directory. */
495 BT_LOGD("Cannot get file information: %s: continuing: "
496 "path=\"%s\", errno=%d",
497 strerror(errno), file_path, errno);
498 continue;
499 }
500
501 if (S_ISDIR(st.st_mode) && recurse) {
502 ret = bt_plugin_create_append_all_from_dir(plugin_set,
503 file_path, BT_TRUE);
504 if (ret < 0) {
505 BT_LOGW("Cannot recurse into directory to find plugins: "
506 "path=\"%s\", ret=%d", file_path, ret);
507 goto end;
508 }
509 } else if (S_ISREG(st.st_mode)) {
510 struct bt_plugin_set *plugins_from_file =
511 bt_plugin_create_all_from_file(file_path);
512
513 if (plugins_from_file) {
514 size_t j;
515
516 for (j = 0; j < plugins_from_file->plugins->len; j++) {
517 struct bt_plugin *plugin =
518 g_ptr_array_index(plugins_from_file->plugins, j);
519
520 BT_LOGD("Adding plugin to plugin set: "
521 "plugin-path=\"%s\", plugin-addr=%p, plugin-name=\"%s\"",
522 file_path, plugin,
523 bt_plugin_get_name(plugin));
524 bt_plugin_set_add_plugin(plugin_set,
525 plugin);
526 }
527
528 bt_put(plugins_from_file);
529 }
530 }
531 }
532
533end:
534 if (directory) {
535 if (closedir(directory)) {
536 /*
537 * We don't want to override the error since there is
538 * nothing could do.
539 */
540 BT_LOGE("Cannot close directory entry: %s: "
541 "path=\"%s\", errno=%d",
542 strerror(errno), path, errno);
543 }
544 }
545
546 free(entry);
547 free(file_path);
548 return ret;
549}
550
551struct bt_plugin_set *bt_plugin_create_all_from_dir(const char *path,
552 bt_bool recurse)
553{
554 struct bt_plugin_set *plugin_set;
555 enum bt_plugin_status status;
556
557 BT_LOGD("Creating all plugins in directory: path=\"%s\", recurse=%d",
558 path, recurse);
559 plugin_set = bt_plugin_set_create();
560 if (!plugin_set) {
561 BT_LOGE_STR("Cannot create empty plugin set.");
562 goto error;
563 }
564
565 /* Append found plugins to array */
566 status = bt_plugin_create_append_all_from_dir(plugin_set, path,
567 recurse);
568 if (status < 0) {
569 BT_LOGW("Cannot append plugins found in directory: "
570 "path=\"%s\", status=%s",
571 path, bt_plugin_status_string(status));
572 goto error;
573 }
574
575 BT_LOGD("Created %u plugins from directory: count=%u, path=\"%s\"",
576 plugin_set->plugins->len, plugin_set->plugins->len, path);
577 goto end;
578
579error:
580 BT_PUT(plugin_set);
581
582end:
583 return plugin_set;
584}
585
586const char *bt_plugin_get_name(struct bt_plugin *plugin)
587{
588 const char *val = NULL;
589
590 if (!plugin) {
591 BT_LOGW_STR("Invalid parameter: plugin is NULL.");
592 goto end;
593 }
594
595 if (plugin->info.name_set) {
596 val = plugin->info.name->str;
597 }
598
599end:
600 return val;
601}
602
603const char *bt_plugin_get_author(struct bt_plugin *plugin)
604{
605 const char *val = NULL;
606
607 if (!plugin) {
608 BT_LOGW_STR("Invalid parameter: plugin is NULL.");
609 goto end;
610 }
611
612 if (plugin->info.author_set) {
613 val = plugin->info.author->str;
614 }
615
616end:
617 return val;
618}
619
620const char *bt_plugin_get_license(struct bt_plugin *plugin)
621{
622 const char *val = NULL;
623
624 if (!plugin) {
625 BT_LOGW_STR("Invalid parameter: plugin is NULL.");
626 goto end;
627 }
628
629 if (plugin->info.license_set) {
630 val = plugin->info.license->str;
631 }
632
633end:
634 return val;
635}
636
637const char *bt_plugin_get_path(struct bt_plugin *plugin)
638{
639 const char *val = NULL;
640
641 if (!plugin) {
642 BT_LOGW_STR("Invalid parameter: plugin is NULL.");
643 goto end;
644 }
645
646 if (plugin->info.path_set) {
647 val = plugin->info.path->str;
648 }
649
650end:
651 return val;
652}
653
654const char *bt_plugin_get_description(struct bt_plugin *plugin)
655{
656 const char *val = NULL;
657
658 if (!plugin) {
659 BT_LOGW_STR("Invalid parameter: plugin is NULL.");
660 goto end;
661 }
662
663 if (plugin->info.description_set) {
664 val = plugin->info.description->str;
665 }
666
667end:
668 return val;
669}
670
671enum bt_plugin_status bt_plugin_get_version(struct bt_plugin *plugin,
672 unsigned int *major, unsigned int *minor, unsigned int *patch,
673 const char **extra)
674{
675 enum bt_plugin_status status = BT_PLUGIN_STATUS_OK;
676
677 if (!plugin) {
678 BT_LOGW_STR("Invalid parameter: plugin is NULL.");
679 status = BT_PLUGIN_STATUS_ERROR;
680 goto end;
681 }
682
683 if (!plugin->info.version_set) {
684 BT_LOGV("Plugin's version is not set: addr=%p", plugin);
685 status = BT_PLUGIN_STATUS_ERROR;
686 goto end;
687 }
688
689 if (major) {
690 *major = plugin->info.version.major;
691 }
692
693 if (minor) {
694 *minor = plugin->info.version.minor;
695 }
696
697 if (patch) {
698 *patch = plugin->info.version.patch;
699 }
700
701 if (extra) {
702 *extra = plugin->info.version.extra->str;
703 }
704
705end:
706 return status;
707}
708
709int64_t bt_plugin_get_component_class_count(struct bt_plugin *plugin)
710{
711 return plugin ? plugin->comp_classes->len : (int64_t) -1;
712}
713
714struct bt_component_class *bt_plugin_get_component_class_by_index(
715 struct bt_plugin *plugin, uint64_t index)
716{
717 struct bt_component_class *comp_class = NULL;
718
719 if (!plugin) {
720 BT_LOGW_STR("Invalid parameter: plugin is NULL.");
721 goto error;
722 }
723
724 if (index >= plugin->comp_classes->len) {
725 BT_LOGW("Invalid parameter: index is out of bounds: "
726 "addr=%p, index=%" PRIu64 ", count=%u",
727 plugin, index, plugin->comp_classes->len);
728 goto error;
729 }
730
731 comp_class = g_ptr_array_index(plugin->comp_classes, index);
732 bt_get(comp_class);
733 goto end;
734
735error:
736 BT_PUT(comp_class);
737
738end:
739 return comp_class;
740}
741
742struct bt_component_class *bt_plugin_get_component_class_by_name_and_type(
743 struct bt_plugin *plugin, const char *name,
744 enum bt_component_class_type type)
745{
746 struct bt_component_class *comp_class = NULL;
747 size_t i;
748
749 if (!plugin) {
750 BT_LOGW_STR("Invalid parameter: plugin is NULL.");
751 goto error;
752 }
753
754 if (!name) {
755 BT_LOGW_STR("Invalid parameter: name is NULL.");
756 goto error;
757 }
758
759 for (i = 0; i < plugin->comp_classes->len; i++) {
760 struct bt_component_class *comp_class_candidate =
761 g_ptr_array_index(plugin->comp_classes, i);
762 const char *comp_class_cand_name =
763 bt_component_class_get_name(comp_class_candidate);
764 enum bt_component_class_type comp_class_cand_type =
765 bt_component_class_get_type(comp_class_candidate);
766
767 assert(comp_class_cand_name);
768 assert(comp_class_cand_type >= 0);
769
770 if (strcmp(name, comp_class_cand_name) == 0 &&
771 comp_class_cand_type == type) {
772 comp_class = bt_get(comp_class_candidate);
773 break;
774 }
775 }
776
777 goto end;
778
779error:
780 BT_PUT(comp_class);
781
782end:
783 return comp_class;
784}
785
786enum bt_plugin_status bt_plugin_add_component_class(
787 struct bt_plugin *plugin, struct bt_component_class *comp_class)
788{
789 enum bt_plugin_status status = BT_PLUGIN_STATUS_OK;
790 struct bt_component_class *comp_class_dup = NULL;
791 int comp_class_index = -1;
792
793 if (!plugin) {
794 BT_LOGW_STR("Invalid parameter: plugin is NULL.");
795 goto error;
796 }
797
798 if (!comp_class) {
799 BT_LOGW_STR("Invalid parameter: component class is NULL.");
800 goto error;
801 }
802
803 if (plugin->frozen) {
804 BT_LOGW("Invalid parameter: plugin is frozen: "
805 "addr=%p, name=\"%s\"", plugin,
806 bt_plugin_get_name(plugin));
807 goto error;
808 }
809
810 /* Check for duplicate */
811 comp_class_dup = bt_plugin_get_component_class_by_name_and_type(plugin,
812 bt_component_class_get_name(comp_class),
813 bt_component_class_get_type(comp_class));
814 if (comp_class_dup) {
815 BT_LOGW("Invalid parameter: a component class with this name and type already exists in the plugin: "
816 "plugin-addr=%p, plugin-name=\"%s\", plugin-path=\"%s\", "
817 "comp-class-name=\"%s\", comp-class-type=%s",
818 plugin, bt_plugin_get_name(plugin),
819 bt_plugin_get_path(plugin),
820 bt_component_class_get_name(comp_class),
821 bt_component_class_type_string(
822 bt_component_class_get_type(comp_class)));
823 goto error;
824 }
825
826 /* Add new component class */
827 comp_class_index = plugin->comp_classes->len;
828 g_ptr_array_add(plugin->comp_classes, bt_get(comp_class));
829
830 /* Special case for a shared object plugin */
831 if (plugin->type == BT_PLUGIN_TYPE_SO) {
832 bt_plugin_so_on_add_component_class(plugin, comp_class);
833 }
834
835 BT_LOGD("Added component class to plugin: "
836 "plugin-addr=%p, plugin-name=\"%s\", plugin-path=\"%s\", "
837 "comp-class-addr=%p, comp-class-name=\"%s\", comp-class-type=%s",
838 plugin, bt_plugin_get_name(plugin),
839 bt_plugin_get_path(plugin),
840 comp_class,
841 bt_component_class_get_name(comp_class),
842 bt_component_class_type_string(
843 bt_component_class_get_type(comp_class)));
844 goto end;
845
846error:
847 /* Remove entry from plugin's component classes (if added) */
848 if (comp_class_index >= 0) {
849 g_ptr_array_remove_index(plugin->comp_classes,
850 comp_class_index);
851 }
852
853 status = BT_PLUGIN_STATUS_ERROR;
854
855end:
856 bt_put(comp_class_dup);
857 return status;
858}
This page took 0.038435 seconds and 4 git commands to generate.