aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/libraries/eina/src/lib/eina_module.c
diff options
context:
space:
mode:
Diffstat (limited to 'libraries/eina/src/lib/eina_module.c')
-rw-r--r--libraries/eina/src/lib/eina_module.c599
1 files changed, 599 insertions, 0 deletions
diff --git a/libraries/eina/src/lib/eina_module.c b/libraries/eina/src/lib/eina_module.c
new file mode 100644
index 0000000..0dd19a6
--- /dev/null
+++ b/libraries/eina/src/lib/eina_module.c
@@ -0,0 +1,599 @@
1/* EINA - EFL data type library
2 * Copyright (C) 2007-2008 Jorge Luis Zapata Muga, Cedric BAIL
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library;
16 * if not, see <http://www.gnu.org/licenses/>.
17 */
18
19#ifdef HAVE_CONFIG_H
20# include "config.h"
21#endif
22
23#ifdef HAVE_ALLOCA_H
24# include <alloca.h>
25#elif defined __GNUC__
26# define alloca __builtin_alloca
27#elif defined _AIX
28# define alloca __alloca
29#elif defined _MSC_VER
30# include <malloc.h>
31# define alloca _alloca
32#else
33# include <stddef.h>
34# ifdef __cplusplus
35extern "C"
36# endif
37void *alloca (size_t);
38#endif
39
40#include <stdio.h>
41#include <sys/types.h>
42#include <string.h>
43
44#ifdef HAVE_LIBGEN_H
45# include <libgen.h>
46#endif
47
48#ifdef HAVE_DLOPEN
49# include <dlfcn.h>
50#endif
51
52#ifdef HAVE_EVIL
53# include <Evil.h>
54#endif
55
56#ifdef HAVE_ESCAPE
57# include <Escape.h>
58#endif
59
60#include "eina_config.h"
61#include "eina_private.h"
62#include "eina_error.h"
63#include "eina_file.h"
64#include "eina_log.h"
65
66/* undefs EINA_ARG_NONULL() so NULL checks are not compiled out! */
67#include "eina_safety_checks.h"
68#include "eina_module.h"
69
70/*============================================================================*
71* Local *
72*============================================================================*/
73
74/**
75 * @cond LOCAL
76 */
77
78static int EINA_MODULE_LOG_DOM = -1;
79#ifdef ERR
80#undef ERR
81#endif
82#define ERR(...) EINA_LOG_DOM_ERR(EINA_MODULE_LOG_DOM, __VA_ARGS__)
83
84#ifdef WRN
85#undef WRN
86#endif
87#define WRN(...) EINA_LOG_DOM_WARN(EINA_MODULE_LOG_DOM, __VA_ARGS__)
88
89#ifdef DBG
90#undef DBG
91#endif
92#define DBG(...) EINA_LOG_DOM_DBG(EINA_MODULE_LOG_DOM, __VA_ARGS__)
93
94#ifdef _WIN32
95# define SEP_C '\\'
96# define SEP_S "\\"
97#else
98# define SEP_C '/'
99# define SEP_S "/"
100#endif
101
102#define EINA_MODULE_SYMBOL_INIT "__eina_module_init"
103#define EINA_MODULE_SYMBOL_SHUTDOWN "__eina_module_shutdown"
104
105struct _Eina_Module
106{
107 void *handle;
108 int ref;
109 const char file[];
110};
111
112typedef struct _Dir_List_Get_Cb_Data
113{
114 Eina_Module_Cb cb;
115 void *data;
116 Eina_Array *array;
117} Dir_List_Get_Cb_Data;
118
119typedef struct _Dir_List_Cb_Data
120{
121 Eina_Module_Cb cb;
122 void *data;
123} Dir_List_Cb_Data;
124
125static Eina_Bool _dir_list_get_cb(Eina_Module *m, void *data)
126{
127 Dir_List_Get_Cb_Data *cb_data = data;
128 Eina_Bool ret = EINA_TRUE;
129
130 if (cb_data->cb)
131 ret = cb_data->cb(m, cb_data->data);
132
133 if (ret)
134 eina_array_push(cb_data->array, m);
135
136 return ret;
137}
138
139static void _dir_list_cb(const char *name, const char *path, void *data)
140{
141 Dir_List_Cb_Data *cb_data = data;
142 size_t length;
143
144 length = strlen(name);
145 if (length < sizeof(SHARED_LIB_SUFFIX)) /* x.so */
146 return;
147
148 if (!strcmp(name + length - sizeof(SHARED_LIB_SUFFIX) + 1,
149 SHARED_LIB_SUFFIX))
150 {
151 char *file;
152 Eina_Module *m;
153
154 length = strlen(path) + strlen(name) + 2;
155
156 file = alloca(sizeof (char) * length);
157
158 snprintf(file, length, "%s" SEP_S "%s", path, name);
159 m = eina_module_new(file);
160 if (!m)
161 {
162 return; /* call the user provided cb on this module */
163
164 }
165
166 if (!cb_data->cb(m, cb_data->data))
167 eina_module_free(m);
168 }
169}
170
171static void _dir_arch_list_cb(const char *name, const char *path, void *data)
172{
173 Dir_List_Get_Cb_Data *cb_data = data;
174 Eina_Module *m;
175 char *file = NULL;
176 size_t length;
177
178 length = strlen(path) + 1 + strlen(name) + 1 +
179 strlen((char *)(cb_data->data)) + 1 + sizeof("module") +
180 sizeof(SHARED_LIB_SUFFIX) + 1;
181
182 file = alloca(length);
183 snprintf(file, length, "%s" SEP_S "%s" SEP_S "%s" SEP_S "module" SHARED_LIB_SUFFIX,
184 path, name, (char *)(cb_data->data));
185 m = eina_module_new(file);
186 if (!m)
187 return;
188
189 eina_array_push(cb_data->array, m);
190}
191
192/**
193 * @endcond
194 */
195
196
197/*============================================================================*
198* Global *
199*============================================================================*/
200
201/**
202 * @cond LOCAL
203 */
204
205static const char EINA_ERROR_WRONG_MODULE_STR[] =
206 "Wrong file format or no file module found";
207static const char EINA_ERROR_MODULE_INIT_FAILED_STR[] =
208 "Module initialisation function failed";
209
210EAPI Eina_Error EINA_ERROR_WRONG_MODULE = 0;
211EAPI Eina_Error EINA_ERROR_MODULE_INIT_FAILED = 0;
212
213/**
214 * @endcond
215 */
216
217/**
218 * @internal
219 * @brief Initialize the module loader module.
220 *
221 * @return #EINA_TRUE on success, #EINA_FALSE on failure.
222 *
223 * This function sets up the module loader module of Eina. It is
224 * called by eina_init().
225 *
226 * This function sets up the module module of Eina. It also registers
227 * the errors #EINA_ERROR_WRONG_MODULE and
228 * #EINA_ERROR_MODULE_INIT_FAILED.
229 *
230 * @see eina_init()
231 */
232Eina_Bool
233eina_module_init(void)
234{
235 EINA_MODULE_LOG_DOM = eina_log_domain_register
236 ("eina_module", EINA_LOG_COLOR_DEFAULT);
237 if (EINA_MODULE_LOG_DOM < 0)
238 {
239 EINA_LOG_ERR("Could not register log domain: eina_module");
240 return EINA_FALSE;
241 }
242
243#define EEMR(n) n = eina_error_msg_static_register(n ## _STR)
244 EEMR(EINA_ERROR_WRONG_MODULE);
245 EEMR(EINA_ERROR_MODULE_INIT_FAILED);
246#undef EEMR
247
248 return EINA_TRUE;
249}
250
251/**
252 * @internal
253 * @brief Shut down the module loader module.
254 *
255 * @return #EINA_TRUE on success, #EINA_FALSE on failure.
256 *
257 * This function shuts down the module loader module set up by
258 * eina_module_init(). It is called by eina_shutdown().
259 *
260 * @see eina_shutdown()
261 */
262Eina_Bool
263eina_module_shutdown(void)
264{
265 /* TODO should we store every module when "new" is called and
266 * delete the list of modules here
267 */
268
269 eina_log_domain_unregister(EINA_MODULE_LOG_DOM);
270 EINA_MODULE_LOG_DOM = -1;
271 return EINA_TRUE;
272}
273
274/*============================================================================*
275* API *
276*============================================================================*/
277
278EAPI Eina_Module *eina_module_new(const char *file)
279{
280 Eina_Module *m;
281 size_t len;
282
283 EINA_SAFETY_ON_NULL_RETURN_VAL(file, NULL);
284 /* TODO check that the file exists. Update doc too */
285
286 len = strlen(file);
287 EINA_SAFETY_ON_FALSE_RETURN_VAL(len > 0, NULL);
288
289 m = malloc(sizeof(Eina_Module) + len + 1);
290 if (!m)
291 {
292 ERR("could not malloc(%lu)",
293 (unsigned long)(sizeof(Eina_Module) + len + 1));
294 return NULL;
295 }
296
297 memcpy((char *)m->file, file, len + 1);
298 m->ref = 0;
299 m->handle = NULL;
300 DBG("m=%p, file=%s", m, file);
301
302 return m;
303}
304
305EAPI Eina_Bool eina_module_free(Eina_Module *m)
306{
307 EINA_SAFETY_ON_NULL_RETURN_VAL(m, EINA_FALSE);
308
309 DBG("m=%p, handle=%p, file=%s, refs=%d", m, m->handle, m->file, m->ref);
310
311 if (m->handle)
312 if (eina_module_unload(m) == EINA_FALSE)
313 return EINA_FALSE;
314
315 free(m);
316 return EINA_TRUE;
317}
318
319EAPI Eina_Bool eina_module_load(Eina_Module *m)
320{
321#ifdef HAVE_DLOPEN
322 void *dl_handle;
323 Eina_Module_Init *initcall;
324
325 EINA_SAFETY_ON_NULL_RETURN_VAL(m, EINA_FALSE);
326
327 DBG("m=%p, handle=%p, file=%s, refs=%d", m, m->handle, m->file, m->ref);
328
329 if (m->handle)
330 goto loaded;
331
332 dl_handle = dlopen(m->file, RTLD_NOW);
333 if (!dl_handle)
334 {
335 WRN("could not dlopen(\"%s\", RTLD_NOW): %s", m->file, dlerror());
336 eina_error_set(EINA_ERROR_WRONG_MODULE);
337 return EINA_FALSE;
338 }
339
340 initcall = dlsym(dl_handle, EINA_MODULE_SYMBOL_INIT);
341 if ((!initcall) || (!(*initcall)))
342 goto ok;
343
344 if ((*initcall)() == EINA_TRUE)
345 goto ok;
346
347 WRN("could not find eina's entry symbol %s inside module %s",
348 EINA_MODULE_SYMBOL_INIT, m->file);
349 eina_error_set(EINA_ERROR_MODULE_INIT_FAILED);
350 dlclose(dl_handle);
351 return EINA_FALSE;
352ok:
353 DBG("successfully loaded %s", m->file);
354 m->handle = dl_handle;
355loaded:
356 m->ref++;
357 DBG("ref %d", m->ref);
358
359 eina_error_set(0);
360 return EINA_TRUE;
361#else
362 (void) m;
363 return EINA_FALSE;
364#endif
365}
366
367EAPI Eina_Bool eina_module_unload(Eina_Module *m)
368{
369#ifdef HAVE_DLOPEN
370 Eina_Module_Shutdown *shut;
371 EINA_SAFETY_ON_NULL_RETURN_VAL(m, EINA_FALSE);
372
373 DBG("m=%p, handle=%p, file=%s, refs=%d", m, m->handle, m->file, m->ref);
374
375 m->ref--;
376 if (!m->ref)
377 {
378 shut = dlsym(m->handle, EINA_MODULE_SYMBOL_SHUTDOWN);
379 if ((shut) && (*shut))
380 (*shut)();
381
382 dlclose(m->handle);
383 m->handle = NULL;
384 DBG("unloaded module %s", m->file);
385 return EINA_TRUE;
386 }
387
388 return EINA_FALSE;
389#else
390 (void) m;
391 return EINA_FALSE;
392#endif
393}
394
395EAPI void *eina_module_symbol_get(const Eina_Module *m, const char *symbol)
396{
397#ifdef HAVE_DLOPEN
398 EINA_SAFETY_ON_NULL_RETURN_VAL(m, NULL);
399 EINA_SAFETY_ON_NULL_RETURN_VAL(m->handle, NULL);
400 return dlsym(m->handle, symbol);
401#else
402 (void) m;
403 (void) symbol;
404 return NULL;
405#endif
406}
407
408EAPI const char *eina_module_file_get(const Eina_Module *m)
409{
410 EINA_SAFETY_ON_NULL_RETURN_VAL(m, NULL);
411 return m->file;
412}
413
414EAPI char *eina_module_symbol_path_get(const void *symbol, const char *sub_dir)
415{
416#ifdef HAVE_DLADDR
417 Dl_info eina_dl;
418
419 EINA_SAFETY_ON_NULL_RETURN_VAL(symbol, NULL);
420
421 if (dladdr(symbol, &eina_dl))
422 {
423 char *pos = strrchr(eina_dl.dli_fname, SEP_C);
424 if (pos)
425 {
426 char *path;
427 int l0;
428 int l1;
429 int l2 = 0;
430
431 l0 = strlen(eina_dl.dli_fname);
432 l1 = strlen(pos);
433 if (sub_dir && (*sub_dir != '\0'))
434 l2 = strlen(sub_dir);
435
436 path = malloc(l0 - l1 + l2 + 1);
437 if (path)
438 {
439 memcpy(path, eina_dl.dli_fname, l0 - l1);
440 if (sub_dir && (*sub_dir != '\0'))
441 memcpy(path + l0 - l1, sub_dir, l2);
442
443 path[l0 - l1 + l2] = '\0';
444 return path;
445 }
446 }
447 }
448#else
449 (void) symbol;
450 (void) sub_dir;
451#endif /* ! HAVE_DLADDR */
452
453 return NULL;
454}
455
456EAPI char *eina_module_environment_path_get(const char *env,
457 const char *sub_dir)
458{
459 const char *env_dir;
460
461 EINA_SAFETY_ON_NULL_RETURN_VAL(env, NULL);
462
463 env_dir = getenv(env);
464 if (env_dir)
465 {
466 char *path;
467 size_t l1;
468 size_t l2 = 0;
469
470 l1 = strlen(env_dir);
471 if (sub_dir && (*sub_dir != '\0'))
472 l2 = strlen(sub_dir);
473
474 path = (char *)malloc(l1 + l2 + 1);
475 if (path)
476 {
477 memcpy(path, env_dir, l1);
478 if (sub_dir && (*sub_dir != '\0'))
479 memcpy(path + l1, sub_dir, l2);
480
481 path[l1 + l2] = '\0';
482
483 return path;
484 }
485 }
486
487 return NULL;
488}
489
490EAPI Eina_Array *eina_module_arch_list_get(Eina_Array *array,
491 const char *path,
492 const char *arch)
493{
494 Dir_List_Get_Cb_Data list_get_cb_data;
495
496 if ((!path) || (!arch))
497 return array;
498
499 list_get_cb_data.array = array ? array : eina_array_new(4);
500 list_get_cb_data.cb = NULL;
501 list_get_cb_data.data = (void *)arch;
502
503 eina_file_dir_list(path, 0, &_dir_arch_list_cb, &list_get_cb_data);
504
505 return list_get_cb_data.array;
506}
507
508EAPI Eina_Array *eina_module_list_get(Eina_Array *array,
509 const char *path,
510 Eina_Bool recursive,
511 Eina_Module_Cb cb,
512 void *data)
513{
514 Dir_List_Get_Cb_Data list_get_cb_data;
515 Dir_List_Cb_Data list_cb_data;
516
517 if (!path)
518 return array;
519
520 list_get_cb_data.array = array ? array : eina_array_new(4);
521 list_get_cb_data.cb = cb;
522 list_get_cb_data.data = data;
523
524 list_cb_data.cb = &_dir_list_get_cb;
525 list_cb_data.data = &list_get_cb_data;
526
527 eina_file_dir_list(path, recursive, &_dir_list_cb, &list_cb_data);
528
529 return list_get_cb_data.array;
530}
531
532EAPI Eina_Module *
533eina_module_find(const Eina_Array *array, const char *module)
534{
535 unsigned int i;
536 Eina_Array_Iterator iterator;
537 Eina_Module *m;
538
539 EINA_ARRAY_ITER_NEXT(array, i, m, iterator)
540 {
541 char *file_m;
542 char *tmp;
543 ssize_t len;
544
545 /* basename() can modify its argument, so we first get a copie */
546 /* do not use strdupa, as opensolaris does not have it */
547 len = strlen(eina_module_file_get(m));
548 tmp = alloca(len + 1);
549 memcpy(tmp, eina_module_file_get(m), len + 1);
550 file_m = basename(tmp);
551 len = strlen(file_m);
552 len -= sizeof(SHARED_LIB_SUFFIX) - 1;
553 if (len <= 0)
554 continue;
555
556 if (!strncmp(module, file_m, len))
557 return m;;
558 }
559
560 return NULL;
561}
562
563EAPI void eina_module_list_load(Eina_Array *array)
564{
565 Eina_Array_Iterator iterator;
566 Eina_Module *m;
567 unsigned int i;
568
569 EINA_SAFETY_ON_NULL_RETURN(array);
570 DBG("array %p, count %u", array, array->count);
571 EINA_ARRAY_ITER_NEXT(array, i, m, iterator)
572 eina_module_load(m);
573}
574
575EAPI void eina_module_list_unload(Eina_Array *array)
576{
577 Eina_Array_Iterator iterator;
578 Eina_Module *m;
579 unsigned int i;
580
581 EINA_SAFETY_ON_NULL_RETURN(array);
582 DBG("array %p, count %u", array, array->count);
583 EINA_ARRAY_ITER_NEXT(array, i, m, iterator)
584 eina_module_unload(m);
585}
586
587EAPI void eina_module_list_free(Eina_Array *array)
588{
589 Eina_Array_Iterator iterator;
590 Eina_Module *m;
591 unsigned int i;
592
593 EINA_SAFETY_ON_NULL_RETURN(array);
594 DBG("array %p, count %u", array, array->count);
595 EINA_ARRAY_ITER_NEXT(array, i, m, iterator)
596 eina_module_free(m);
597
598 eina_array_flush(array);
599}