text plugin test
[babeltrace.git] / plugins / 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>
92893b7b
JG
31#include <babeltrace/plugin/source-internal.h>
32#include <babeltrace/plugin/sink-internal.h>
f3e4505b
JG
33#include <babeltrace/babeltrace-internal.h>
34#include <babeltrace/compiler.h>
b8a06801 35#include <babeltrace/ref.h>
f3e4505b
JG
36#include <unistd.h>
37#include <stdlib.h>
38#include <sys/stat.h>
fb2dcc52 39#include <gmodule.h>
f3e4505b
JG
40
41#define NATIVE_PLUGIN_SUFFIX ".so"
42#define NATIVE_PLUGIN_SUFFIX_LEN sizeof(NATIVE_PLUGIN_SUFFIX)
43#define LIBTOOL_PLUGIN_SUFFIX ".la"
44#define LIBTOOL_PLUGIN_SUFFIX_LEN sizeof(LIBTOOL_PLUGIN_SUFFIX)
73299554
JG
45#define PLUGIN_SUFFIX_LEN max_t(size_t, sizeof(NATIVE_PLUGIN_SUFFIX), \
46 sizeof(LIBTOOL_PLUGIN_SUFFIX))
f3e4505b 47
f3e4505b
JG
48/* Allocate dirent as recommended by READDIR(3), NOTES on readdir_r */
49static
50struct dirent *alloc_dirent(const char *path)
51{
52 size_t len;
53 long name_max;
54 struct dirent *entry;
55
56 name_max = pathconf(path, _PC_NAME_MAX);
57 if (name_max == -1) {
58 name_max = PATH_MAX;
59 }
60 len = offsetof(struct dirent, d_name) + name_max + 1;
61 entry = zmalloc(len);
62 return entry;
63}
64
65static
66enum bt_component_factory_status
67bt_component_factory_load_file(struct bt_component_factory *factory,
68 const char *path)
69{
70 enum bt_component_factory_status ret = BT_COMPONENT_FACTORY_STATUS_OK;
fb2dcc52 71 enum bt_component_status component_status;
f3e4505b
JG
72 size_t path_len;
73 GModule *module;
fb2dcc52 74 struct bt_plugin *plugin;
92893b7b 75 bool is_libtool_wrapper = false, is_shared_object = false;
f3e4505b
JG
76
77 if (!factory || !path) {
78 ret = BT_COMPONENT_FACTORY_STATUS_INVAL;
79 goto end;
80 }
81
82 path_len = strlen(path);
83 if (path_len <= PLUGIN_SUFFIX_LEN) {
73299554 84 ret = BT_COMPONENT_FACTORY_STATUS_INVAL;
f3e4505b
JG
85 goto end;
86 }
87
88 path_len++;
89 /*
90 * Check if the file ends with a known plugin file type suffix (i.e. .so
91 * or .la on Linux).
92 */
92893b7b 93 is_libtool_wrapper = !strncmp(LIBTOOL_PLUGIN_SUFFIX,
b8a06801 94 path + path_len - LIBTOOL_PLUGIN_SUFFIX_LEN,
92893b7b
JG
95 LIBTOOL_PLUGIN_SUFFIX_LEN);
96 is_shared_object = !strncmp(NATIVE_PLUGIN_SUFFIX,
97 path + path_len - NATIVE_PLUGIN_SUFFIX_LEN,
98 NATIVE_PLUGIN_SUFFIX_LEN);
99 if (!is_shared_object && !is_libtool_wrapper) {
73299554
JG
100 /* Name indicates that this is not a plugin file. */
101 ret = BT_COMPONENT_FACTORY_STATUS_INVAL;
f3e4505b
JG
102 goto end;
103 }
104
105 module = g_module_open(path, 0);
106 if (!module) {
107 printf_error("Module open error: %s", g_module_error());
73299554 108 ret = BT_COMPONENT_FACTORY_STATUS_ERROR;
f3e4505b
JG
109 goto end;
110 }
111
fb2dcc52
JG
112 /* Load plugin and make sure it defines the required entry points */
113 plugin = bt_plugin_create(module);
73299554 114 if (!plugin) {
fb2dcc52 115 ret = BT_COMPONENT_FACTORY_STATUS_INVAL_PLUGIN;
73299554
JG
116 if (!g_module_close(module)) {
117 printf_error("Module close error: %s",
fb2dcc52
JG
118 g_module_error());
119 }
120 goto end;
121 }
122
123 component_status = bt_plugin_register_component_classes(plugin,
b8a06801 124 factory);
fb2dcc52
JG
125 if (component_status != BT_COMPONENT_STATUS_OK) {
126 switch (component_status) {
127 case BT_COMPONENT_STATUS_NOMEM:
128 ret = BT_COMPONENT_FACTORY_STATUS_NOMEM;
129 break;
130 default:
131 ret = BT_COMPONENT_FACTORY_STATUS_ERROR;
132 break;
73299554 133 }
b8a06801
JG
134
135 BT_PUT(plugin);
73299554
JG
136 goto end;
137 }
fb2dcc52 138 g_ptr_array_add(factory->plugins, plugin);
f3e4505b
JG
139end:
140 return ret;
141}
142
143static
144enum bt_component_factory_status
145bt_component_factory_load_dir_recursive(struct bt_component_factory *factory,
146 const char *path)
147{
148 DIR *directory = NULL;
149 struct dirent *entry = NULL, *result = NULL;
150 char *file_path = NULL;
151 size_t path_len = strlen(path);
152 enum bt_component_factory_status ret = BT_COMPONENT_FACTORY_STATUS_OK;
153
154 if (path_len >= PATH_MAX) {
155 ret = BT_COMPONENT_FACTORY_STATUS_INVAL;
156 goto end;
157 }
158
159 entry = alloc_dirent(path);
160 if (!entry) {
161 ret = BT_COMPONENT_FACTORY_STATUS_NOMEM;
162 goto end;
163 }
164
165 file_path = zmalloc(PATH_MAX);
166 if (!file_path) {
167 ret = BT_COMPONENT_FACTORY_STATUS_NOMEM;
168 goto end;
169 }
170
171 strncpy(file_path, path, path_len);
172 /* Append a trailing '/' to the path */
173 if (file_path[path_len - 1] != '/') {
174 file_path[path_len++] = '/';
175 }
176
33bceaf8
JG
177 directory = opendir(file_path);
178 if (!directory) {
179 perror("Failed to open plug-in directory");
180 ret = BT_COMPONENT_FACTORY_STATUS_ERROR;
181 goto end;
182 }
183
f3e4505b
JG
184 /* Recursively walk directory */
185 while (!readdir_r(directory, entry, &result) && result) {
186 struct stat st;
187 int stat_ret;
33bceaf8
JG
188 size_t file_name_len;
189
190 if (result->d_name[0] == '.') {
191 /* Skip hidden files, . and .. */
192 continue;
193 }
194
195 file_name_len = strlen(result->d_name);
f3e4505b
JG
196
197 if (path_len + file_name_len >= PATH_MAX) {
198 continue;
199 }
200
201 strncpy(file_path + path_len, result->d_name, file_name_len);
202 file_path[path_len + file_name_len] = '\0';
203
204 stat_ret = stat(file_path, &st);
205 if (stat_ret < 0) {
206 /* Continue to next file / directory. */
207 printf_perror("Failed to stat() plugin file");
208 continue;
209 }
210
211 if (S_ISDIR(st.st_mode)) {
212 ret = bt_component_factory_load_dir_recursive(factory,
b8a06801 213 file_path);
f3e4505b
JG
214 if (ret != BT_COMPONENT_FACTORY_STATUS_OK) {
215 goto end;
216 }
217 } else if (S_ISREG(st.st_mode)) {
73299554 218 bt_component_factory_load_file(factory, file_path);
f3e4505b
JG
219 }
220 }
221end:
33bceaf8
JG
222 if (directory) {
223 if (closedir(directory)) {
224 /*
225 * We don't want to override the error since there is
226 * nothing could do.
227 */
228 perror("Failed to close plug-in directory");
229 }
230 }
f3e4505b
JG
231 free(entry);
232 free(file_path);
233 return ret;
234}
235
b8a06801
JG
236static
237void bt_component_factory_destroy(struct bt_object *obj)
f3e4505b 238{
b8a06801
JG
239 struct bt_component_factory *factory = NULL;
240
241 assert(obj);
242 factory = container_of(obj, struct bt_component_factory, base);
f3e4505b 243
fb2dcc52
JG
244 if (factory->plugins) {
245 g_ptr_array_free(factory->plugins, TRUE);
246 }
92893b7b
JG
247 if (factory->component_classes) {
248 g_ptr_array_free(factory->component_classes, TRUE);
fb2dcc52 249 }
f3e4505b
JG
250 g_free(factory);
251}
252
b8a06801 253struct bt_component_factory *bt_component_factory_create(void)
f3e4505b
JG
254{
255 struct bt_component_factory *factory;
256
257 factory = g_new0(struct bt_component_factory, 1);
258 if (!factory) {
259 goto end;
260 }
261
b8a06801 262 bt_object_init(factory, bt_component_factory_destroy);
fb2dcc52 263 factory->plugins = g_ptr_array_new_with_free_func(
b8a06801 264 (GDestroyNotify) bt_put);
73299554 265 if (!factory->plugins) {
f3e4505b
JG
266 goto error;
267 }
92893b7b 268 factory->component_classes = g_ptr_array_new_with_free_func(
b8a06801 269 (GDestroyNotify) bt_put);
92893b7b 270 if (!factory->component_classes) {
fb2dcc52
JG
271 goto error;
272 }
f3e4505b
JG
273end:
274 return factory;
275error:
b8a06801
JG
276 BT_PUT(factory);
277 return factory;
f3e4505b
JG
278}
279
92893b7b
JG
280struct bt_object *bt_component_factory_get_components(
281 struct bt_component_factory *factory)
282{
283 assert(0);
284 return NULL;
285}
286
f3e4505b
JG
287enum bt_component_factory_status bt_component_factory_load(
288 struct bt_component_factory *factory, const char *path)
289{
290 enum bt_component_factory_status ret = BT_COMPONENT_FACTORY_STATUS_OK;
f3e4505b
JG
291
292 if (!factory || !path) {
293 ret = BT_COMPONENT_FACTORY_STATUS_INVAL;
294 goto end;
295 }
296
b8a06801
JG
297 if (!g_file_test(path, G_FILE_TEST_EXISTS)) {
298 ret = BT_COMPONENT_FACTORY_STATUS_NOENT;
299 goto end;
f3e4505b
JG
300 }
301
b8a06801 302 if (g_file_test(path, G_FILE_TEST_IS_DIR)) {
f3e4505b 303 ret = bt_component_factory_load_dir_recursive(factory, path);
b8a06801
JG
304 } else if (g_file_test(path, G_FILE_TEST_IS_REGULAR) ||
305 g_file_test(path, G_FILE_TEST_IS_SYMLINK)) {
f3e4505b 306 ret = bt_component_factory_load_file(factory, path);
b8a06801
JG
307 } else {
308 ret = BT_COMPONENT_FACTORY_STATUS_INVAL;
309 goto end;
f3e4505b
JG
310 }
311end:
f3e4505b
JG
312 return ret;
313}
92893b7b
JG
314
315enum bt_component_factory_status
316bt_component_factory_register_source_component_class(
317 struct bt_component_factory *factory, const char *name,
318 bt_component_source_init_cb init)
319{
320 assert(0);
321 return BT_COMPONENT_FACTORY_STATUS_ERROR;
322}
323
324enum bt_component_factory_status
325bt_component_factory_register_sink_component_class(
326 struct bt_component_factory *factory, const char *name,
327 bt_component_sink_init_cb init)
328{
329 struct bt_component_class *class;
330 enum bt_component_factory_status ret = BT_COMPONENT_FACTORY_STATUS_OK;
331
332 if (!factory || !name || !init) {
333 ret = BT_COMPONENT_FACTORY_STATUS_INVAL;
334 goto end;
335 }
336
92893b7b
JG
337end:
338 return ret;
339}
This page took 0.036672 seconds and 4 git commands to generate.