8dc6103d9f530ebfa3b90ca0019ad94756b90de2
[babeltrace.git] / plugins / 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/source-internal.h>
32 #include <babeltrace/plugin/sink-internal.h>
33 #include <babeltrace/babeltrace-internal.h>
34 #include <babeltrace/compiler.h>
35 #include <babeltrace/ref.h>
36 #include <unistd.h>
37 #include <stdlib.h>
38 #include <sys/stat.h>
39 #include <gmodule.h>
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)
45 #define PLUGIN_SUFFIX_LEN max_t(size_t, sizeof(NATIVE_PLUGIN_SUFFIX), \
46 sizeof(LIBTOOL_PLUGIN_SUFFIX))
47
48 /* Allocate dirent as recommended by READDIR(3), NOTES on readdir_r */
49 static
50 struct 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
65 static
66 enum bt_component_factory_status
67 bt_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;
71 enum bt_component_status component_status;
72 size_t path_len;
73 GModule *module;
74 struct bt_plugin *plugin;
75 bool is_libtool_wrapper = false, is_shared_object = false;
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) {
84 ret = BT_COMPONENT_FACTORY_STATUS_INVAL;
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 */
93 is_libtool_wrapper = !strncmp(LIBTOOL_PLUGIN_SUFFIX,
94 path + path_len - LIBTOOL_PLUGIN_SUFFIX_LEN,
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) {
100 /* Name indicates that this is not a plugin file. */
101 ret = BT_COMPONENT_FACTORY_STATUS_INVAL;
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());
108 ret = BT_COMPONENT_FACTORY_STATUS_ERROR;
109 goto end;
110 }
111
112 /* Load plugin and make sure it defines the required entry points */
113 plugin = bt_plugin_create(module);
114 if (!plugin) {
115 ret = BT_COMPONENT_FACTORY_STATUS_INVAL_PLUGIN;
116 if (!g_module_close(module)) {
117 printf_error("Module close error: %s",
118 g_module_error());
119 }
120 goto end;
121 }
122
123 component_status = bt_plugin_register_component_classes(plugin,
124 factory);
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;
133 }
134
135 BT_PUT(plugin);
136 goto end;
137 }
138 g_ptr_array_add(factory->plugins, plugin);
139 end:
140 return ret;
141 }
142
143 static
144 enum bt_component_factory_status
145 bt_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
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
184 /* Recursively walk directory */
185 while (!readdir_r(directory, entry, &result) && result) {
186 struct stat st;
187 int stat_ret;
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);
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,
213 file_path);
214 if (ret != BT_COMPONENT_FACTORY_STATUS_OK) {
215 goto end;
216 }
217 } else if (S_ISREG(st.st_mode)) {
218 bt_component_factory_load_file(factory, file_path);
219 }
220 }
221 end:
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 }
231 free(entry);
232 free(file_path);
233 return ret;
234 }
235
236 static
237 void bt_component_factory_destroy(struct bt_object *obj)
238 {
239 struct bt_component_factory *factory = NULL;
240
241 assert(obj);
242 factory = container_of(obj, struct bt_component_factory, base);
243
244 if (factory->plugins) {
245 g_ptr_array_free(factory->plugins, TRUE);
246 }
247 if (factory->component_classes) {
248 g_ptr_array_free(factory->component_classes, TRUE);
249 }
250 g_free(factory);
251 }
252
253 struct bt_component_factory *bt_component_factory_create(void)
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
262 bt_object_init(factory, bt_component_factory_destroy);
263 factory->plugins = g_ptr_array_new_with_free_func(
264 (GDestroyNotify) bt_put);
265 if (!factory->plugins) {
266 goto error;
267 }
268 factory->component_classes = g_ptr_array_new_with_free_func(
269 (GDestroyNotify) bt_put);
270 if (!factory->component_classes) {
271 goto error;
272 }
273 end:
274 return factory;
275 error:
276 BT_PUT(factory);
277 return factory;
278 }
279
280 struct bt_object *bt_component_factory_get_components(
281 struct bt_component_factory *factory)
282 {
283 assert(0);
284 return NULL;
285 }
286
287 enum 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;
291
292 if (!factory || !path) {
293 ret = BT_COMPONENT_FACTORY_STATUS_INVAL;
294 goto end;
295 }
296
297 if (!g_file_test(path, G_FILE_TEST_EXISTS)) {
298 ret = BT_COMPONENT_FACTORY_STATUS_NOENT;
299 goto end;
300 }
301
302 if (g_file_test(path, G_FILE_TEST_IS_DIR)) {
303 ret = bt_component_factory_load_dir_recursive(factory, path);
304 } else if (g_file_test(path, G_FILE_TEST_IS_REGULAR) ||
305 g_file_test(path, G_FILE_TEST_IS_SYMLINK)) {
306 ret = bt_component_factory_load_file(factory, path);
307 } else {
308 ret = BT_COMPONENT_FACTORY_STATUS_INVAL;
309 goto end;
310 }
311 end:
312 return ret;
313 }
314
315 enum bt_component_factory_status
316 bt_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
324 enum bt_component_factory_status
325 bt_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
337
338 end:
339 return ret;
340 }
This page took 0.071963 seconds and 3 git commands to generate.