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