2008-08-06 11:15:24 -07:00
|
|
|
/* EINA - EFL data type library
|
2008-09-01 05:42:16 -07:00
|
|
|
* Copyright (C) 2007-2008 Jorge Luis Zapata Muga, Cedric BAIL
|
2008-08-06 11:15:24 -07:00
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with this library;
|
|
|
|
* if not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
2008-08-18 01:18:16 -07:00
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
# include "config.h"
|
|
|
|
#endif
|
|
|
|
|
2008-11-01 08:39:53 -07:00
|
|
|
#ifdef HAVE_DLADDR
|
2009-08-23 02:18:14 -07:00
|
|
|
# define _GNU_SOURCE
|
2008-11-01 08:39:53 -07:00
|
|
|
#endif
|
|
|
|
|
2009-01-20 00:29:41 -08:00
|
|
|
#ifdef HAVE_ALLOCA_H
|
|
|
|
# include <alloca.h>
|
|
|
|
#elif defined __GNUC__
|
|
|
|
# define alloca __builtin_alloca
|
|
|
|
#elif defined _AIX
|
|
|
|
# define alloca __alloca
|
|
|
|
#elif defined _MSC_VER
|
|
|
|
# include <malloc.h>
|
|
|
|
# define alloca _alloca
|
|
|
|
#else
|
|
|
|
# include <stddef.h>
|
|
|
|
# ifdef __cplusplus
|
|
|
|
extern "C"
|
|
|
|
# endif
|
|
|
|
void *alloca (size_t);
|
|
|
|
#endif
|
|
|
|
|
2009-08-23 02:18:14 -07:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <dirent.h>
|
|
|
|
#include <string.h>
|
2010-01-16 08:41:24 -08:00
|
|
|
#include <libgen.h>
|
2009-08-23 02:18:14 -07:00
|
|
|
|
2008-08-27 23:49:04 -07:00
|
|
|
#include <dlfcn.h>
|
|
|
|
|
2008-11-01 08:39:53 -07:00
|
|
|
#ifdef HAVE_EVIL
|
|
|
|
# include <Evil.h>
|
|
|
|
#endif
|
|
|
|
|
2009-08-28 05:03:34 -07:00
|
|
|
#include "eina_config.h"
|
|
|
|
#include "eina_private.h"
|
2008-10-22 01:56:19 -07:00
|
|
|
#include "eina_error.h"
|
2008-07-30 06:35:49 -07:00
|
|
|
#include "eina_file.h"
|
2009-09-02 16:06:55 -07:00
|
|
|
#include "eina_log.h"
|
2008-07-30 05:46:55 -07:00
|
|
|
|
2009-09-06 15:21:56 -07:00
|
|
|
/* undefs EINA_ARG_NONULL() so NULL checks are not compiled out! */
|
|
|
|
#include "eina_safety_checks.h"
|
|
|
|
#include "eina_module.h"
|
|
|
|
|
2008-07-30 05:46:55 -07:00
|
|
|
/*============================================================================*
|
2008-08-18 01:18:16 -07:00
|
|
|
* Local *
|
2008-07-30 05:46:55 -07:00
|
|
|
*============================================================================*/
|
2008-08-27 23:49:04 -07:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @cond LOCAL
|
|
|
|
*/
|
|
|
|
|
2009-09-02 16:06:55 -07:00
|
|
|
static int EINA_MODULE_LOG_DOM = -1;
|
2009-09-06 21:23:05 -07:00
|
|
|
#ifdef ERR
|
|
|
|
#undef ERR
|
|
|
|
#endif
|
2009-09-02 16:06:55 -07:00
|
|
|
#define ERR(...) EINA_LOG_DOM_ERR(EINA_MODULE_LOG_DOM, __VA_ARGS__)
|
2009-09-06 21:23:05 -07:00
|
|
|
|
|
|
|
#ifdef WRN
|
|
|
|
#undef WRN
|
|
|
|
#endif
|
2009-09-02 16:06:55 -07:00
|
|
|
#define WRN(...) EINA_LOG_DOM_WARN(EINA_MODULE_LOG_DOM, __VA_ARGS__)
|
2009-09-06 21:23:05 -07:00
|
|
|
|
|
|
|
#ifdef DBG
|
|
|
|
#undef DBG
|
|
|
|
#endif
|
2009-09-02 16:06:55 -07:00
|
|
|
#define DBG(...) EINA_LOG_DOM_DBG(EINA_MODULE_LOG_DOM, __VA_ARGS__)
|
|
|
|
|
2008-09-24 05:55:31 -07:00
|
|
|
#define EINA_MODULE_SYMBOL_INIT "__eina_module_init"
|
|
|
|
#define EINA_MODULE_SYMBOL_SHUTDOWN "__eina_module_shutdown"
|
2008-08-18 01:18:16 -07:00
|
|
|
|
2008-07-30 05:46:55 -07:00
|
|
|
struct _Eina_Module
|
|
|
|
{
|
2009-09-02 15:39:41 -07:00
|
|
|
void *handle;
|
|
|
|
int ref;
|
2009-09-02 16:11:22 -07:00
|
|
|
const char file[];
|
2008-08-18 01:18:16 -07:00
|
|
|
};
|
|
|
|
|
2008-09-24 05:55:31 -07:00
|
|
|
typedef struct _Dir_List_Get_Cb_Data
|
2008-08-18 01:18:16 -07:00
|
|
|
{
|
2009-09-02 15:39:41 -07:00
|
|
|
Eina_Module_Cb cb;
|
|
|
|
void *data;
|
|
|
|
Eina_Array *array;
|
2008-09-24 05:55:31 -07:00
|
|
|
} Dir_List_Get_Cb_Data;
|
2008-08-18 01:18:16 -07:00
|
|
|
|
2008-09-24 05:55:31 -07:00
|
|
|
typedef struct _Dir_List_Cb_Data
|
2008-08-18 01:18:16 -07:00
|
|
|
{
|
2009-09-02 15:39:41 -07:00
|
|
|
Eina_Module_Cb cb;
|
|
|
|
void *data;
|
2008-09-24 05:55:31 -07:00
|
|
|
} Dir_List_Cb_Data;
|
2008-07-31 09:54:02 -07:00
|
|
|
|
2008-09-24 05:55:31 -07:00
|
|
|
static Eina_Bool _dir_list_get_cb(Eina_Module *m, void *data)
|
2008-08-18 01:18:16 -07:00
|
|
|
{
|
2009-09-02 15:39:41 -07:00
|
|
|
Dir_List_Get_Cb_Data *cb_data = data;
|
|
|
|
Eina_Bool ret = EINA_TRUE;
|
|
|
|
|
|
|
|
if (cb_data->cb)
|
|
|
|
{
|
|
|
|
ret = cb_data->cb(m, cb_data->data);
|
|
|
|
}
|
|
|
|
if (ret)
|
|
|
|
{
|
|
|
|
eina_array_push(cb_data->array, m);
|
|
|
|
}
|
|
|
|
return ret;
|
2008-07-30 05:46:55 -07:00
|
|
|
}
|
2008-08-18 01:18:16 -07:00
|
|
|
|
2008-09-24 05:55:31 -07:00
|
|
|
static void _dir_list_cb(const char *name, const char *path, void *data)
|
2008-08-18 01:18:16 -07:00
|
|
|
{
|
2009-09-02 15:39:41 -07:00
|
|
|
Dir_List_Cb_Data *cb_data = data;
|
|
|
|
size_t length;
|
|
|
|
|
|
|
|
length = strlen(name);
|
2010-01-16 08:46:39 -08:00
|
|
|
if (length < sizeof(SHARED_LIB_SUFFIX)) /* x.so */
|
2009-09-02 15:39:41 -07:00
|
|
|
return;
|
2010-01-16 08:46:39 -08:00
|
|
|
if (!strcmp(name + length - sizeof(SHARED_LIB_SUFFIX) + 1,
|
|
|
|
SHARED_LIB_SUFFIX))
|
2009-09-02 15:39:41 -07:00
|
|
|
{
|
|
|
|
char *file;
|
|
|
|
Eina_Module *m;
|
2008-08-18 01:18:16 -07:00
|
|
|
|
2009-09-02 15:39:41 -07:00
|
|
|
length = strlen(path) + strlen(name) + 2;
|
|
|
|
|
|
|
|
file = alloca(sizeof (char) * length);
|
|
|
|
if (!file) return ;
|
|
|
|
|
|
|
|
snprintf(file, length, "%s/%s", path, name);
|
|
|
|
m = eina_module_new(file);
|
|
|
|
if (!m)
|
|
|
|
return;
|
|
|
|
/* call the user provided cb on this module */
|
|
|
|
if (!cb_data->cb(m, cb_data->data))
|
|
|
|
eina_module_free(m);
|
|
|
|
}
|
2008-08-18 01:18:16 -07:00
|
|
|
}
|
2009-01-20 00:29:41 -08:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @endcond
|
|
|
|
*/
|
|
|
|
|
2009-06-27 23:29:11 -07:00
|
|
|
|
2009-01-20 00:29:41 -08:00
|
|
|
/*============================================================================*
|
|
|
|
* Global *
|
|
|
|
*============================================================================*/
|
|
|
|
|
2009-08-19 00:54:13 -07:00
|
|
|
/**
|
|
|
|
* @cond LOCAL
|
|
|
|
*/
|
|
|
|
|
2009-09-06 20:32:22 -07:00
|
|
|
static const char EINA_ERROR_WRONG_MODULE_STR[] = "Wrong file format or no file module found";
|
|
|
|
static const char EINA_ERROR_MODULE_INIT_FAILED_STR[] = "Module initialisation function failed";
|
|
|
|
|
2009-08-19 00:54:13 -07:00
|
|
|
EAPI Eina_Error EINA_ERROR_WRONG_MODULE = 0;
|
|
|
|
EAPI Eina_Error EINA_ERROR_MODULE_INIT_FAILED = 0;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @endcond
|
|
|
|
*/
|
|
|
|
|
2009-06-27 23:29:11 -07:00
|
|
|
/**
|
2009-09-06 15:21:56 -07:00
|
|
|
* @internal
|
|
|
|
* @brief Initialize the module loader module.
|
|
|
|
*
|
|
|
|
* @return #EINA_TRUE on success, #EINA_FALSE on failure.
|
2009-06-27 23:29:11 -07:00
|
|
|
*
|
2009-09-06 15:21:56 -07:00
|
|
|
* This function sets up the module loader module of Eina. It is
|
|
|
|
* called by eina_init().
|
2009-06-27 23:29:11 -07:00
|
|
|
*
|
|
|
|
* This function sets up the module module of Eina. It also registers
|
|
|
|
* the errors #EINA_ERROR_WRONG_MODULE and
|
2009-09-06 15:21:56 -07:00
|
|
|
* #EINA_ERROR_MODULE_INIT_FAILED.
|
2009-06-27 23:29:11 -07:00
|
|
|
*
|
|
|
|
* @see eina_init()
|
|
|
|
*/
|
2009-09-06 15:21:56 -07:00
|
|
|
Eina_Bool
|
2008-08-18 01:18:16 -07:00
|
|
|
eina_module_init(void)
|
2008-07-30 05:46:55 -07:00
|
|
|
{
|
2009-09-02 16:06:55 -07:00
|
|
|
EINA_MODULE_LOG_DOM = eina_log_domain_register
|
|
|
|
("eina_module", EINA_LOG_COLOR_DEFAULT);
|
|
|
|
if (EINA_MODULE_LOG_DOM < 0)
|
|
|
|
{
|
2009-09-02 18:39:45 -07:00
|
|
|
EINA_LOG_ERR("Could not register log domain: eina_module");
|
2009-09-06 15:21:56 -07:00
|
|
|
return EINA_FALSE;
|
2009-09-02 15:39:41 -07:00
|
|
|
}
|
2008-10-22 01:56:19 -07:00
|
|
|
|
2009-09-06 20:32:22 -07:00
|
|
|
#define EEMR(n) n = eina_error_msg_static_register(n##_STR)
|
|
|
|
EEMR(EINA_ERROR_WRONG_MODULE);
|
|
|
|
EEMR(EINA_ERROR_MODULE_INIT_FAILED);
|
|
|
|
#undef EEMR
|
2008-10-22 01:56:19 -07:00
|
|
|
|
2009-09-06 15:21:56 -07:00
|
|
|
return EINA_TRUE;
|
2008-07-30 05:46:55 -07:00
|
|
|
}
|
2009-06-22 13:03:58 -07:00
|
|
|
|
2009-06-27 23:29:11 -07:00
|
|
|
/**
|
2009-09-06 15:21:56 -07:00
|
|
|
* @internal
|
|
|
|
* @brief Shut down the module loader module.
|
2009-06-27 23:29:11 -07:00
|
|
|
*
|
2009-09-06 15:21:56 -07:00
|
|
|
* @return #EINA_TRUE on success, #EINA_FALSE on failure.
|
2009-06-27 23:29:11 -07:00
|
|
|
*
|
2009-09-06 15:21:56 -07:00
|
|
|
* This function shuts down the module loader module set up by
|
|
|
|
* eina_module_init(). It is called by eina_shutdown().
|
2009-06-27 23:29:11 -07:00
|
|
|
*
|
|
|
|
* @see eina_shutdown()
|
|
|
|
*/
|
2009-09-06 15:21:56 -07:00
|
|
|
Eina_Bool
|
2008-08-18 01:18:16 -07:00
|
|
|
eina_module_shutdown(void)
|
2008-07-30 05:46:55 -07:00
|
|
|
{
|
2009-09-02 15:39:41 -07:00
|
|
|
/* TODO should we store every module when "new" is called and
|
|
|
|
* delete the list of modules here
|
|
|
|
*/
|
2008-09-24 05:55:31 -07:00
|
|
|
|
2009-09-02 16:06:55 -07:00
|
|
|
eina_log_domain_unregister(EINA_MODULE_LOG_DOM);
|
|
|
|
EINA_MODULE_LOG_DOM = -1;
|
2009-09-06 15:21:56 -07:00
|
|
|
return EINA_TRUE;
|
2008-07-30 05:46:55 -07:00
|
|
|
}
|
2009-06-22 13:03:58 -07:00
|
|
|
|
2009-12-27 00:45:30 -08:00
|
|
|
/*============================================================================*
|
|
|
|
* API *
|
|
|
|
*============================================================================*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @addtogroup Eina_Module_Group Module
|
|
|
|
*
|
|
|
|
* @brief These functions provide module management.
|
|
|
|
*
|
|
|
|
* @{
|
|
|
|
*/
|
|
|
|
|
2009-06-27 23:29:11 -07:00
|
|
|
/**
|
|
|
|
* @brief Return a new module.
|
|
|
|
*
|
|
|
|
* @param file The name of the file module to load.
|
|
|
|
*
|
|
|
|
* This function returns a new module. If @p file is @c NULL, the
|
|
|
|
* function returns @c NULL, otherwise, it allocates an Eina_Module,
|
|
|
|
* stores a duplicate string of @p file, sets its reference to @c 0
|
|
|
|
* and its handle to @c NULL.
|
|
|
|
*
|
|
|
|
* When the new module is not needed anymore, use eina_module_free()
|
|
|
|
* to free the allocated memory.
|
|
|
|
*
|
|
|
|
* @see eina_module_load
|
|
|
|
*/
|
|
|
|
EAPI Eina_Module *eina_module_new(const char *file)
|
|
|
|
{
|
2009-09-02 15:39:41 -07:00
|
|
|
Eina_Module *m;
|
2009-09-02 16:11:22 -07:00
|
|
|
size_t len;
|
2009-06-27 23:29:11 -07:00
|
|
|
|
2009-09-02 15:39:41 -07:00
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(file, NULL);
|
|
|
|
/* TODO check that the file exists. Update doc too */
|
2009-06-27 23:29:11 -07:00
|
|
|
|
2009-09-02 16:11:22 -07:00
|
|
|
len = strlen(file);
|
|
|
|
EINA_SAFETY_ON_FALSE_RETURN_VAL(len > 0, NULL);
|
|
|
|
|
|
|
|
m = malloc(sizeof(Eina_Module) + len + 1);
|
|
|
|
if (!m) {
|
2009-10-25 01:45:36 -07:00
|
|
|
ERR("could not malloc(%lu)", (unsigned long)(sizeof(Eina_Module) + len + 1));
|
2009-09-02 16:11:22 -07:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
memcpy((char *)m->file, file, len + 1);
|
2009-09-02 15:39:41 -07:00
|
|
|
m->ref = 0;
|
|
|
|
m->handle = NULL;
|
2009-09-02 18:39:45 -07:00
|
|
|
DBG("m=%p, file=%s", m, file);
|
2009-06-27 23:29:11 -07:00
|
|
|
|
2009-09-02 15:39:41 -07:00
|
|
|
return m;
|
2009-06-27 23:29:11 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Delete a module.
|
|
|
|
*
|
|
|
|
* @param m The module to delete.
|
|
|
|
* @return EINA_TRUE on success, EINA_FALSE otherwise.
|
|
|
|
*
|
|
|
|
* This function calls eina_module_unload() if @p m has been previously
|
|
|
|
* loaded and frees the allocated memory. On success this function
|
|
|
|
* returns EINA_TRUE and EINA_FALSE otherwise. If @p m is @c NULL, the
|
|
|
|
* function returns immediatly.
|
|
|
|
*/
|
|
|
|
EAPI Eina_Bool eina_module_free(Eina_Module *m)
|
|
|
|
{
|
2009-09-02 15:39:41 -07:00
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(m, EINA_FALSE);
|
|
|
|
|
2009-09-02 18:39:45 -07:00
|
|
|
DBG("m=%p, handle=%p, file=%s, refs=%d", m, m->handle, m->file, m->ref);
|
2009-09-02 16:06:55 -07:00
|
|
|
|
2009-09-02 15:39:41 -07:00
|
|
|
if (m->handle)
|
|
|
|
{
|
|
|
|
if (eina_module_unload(m) == EINA_FALSE)
|
|
|
|
return EINA_FALSE;
|
|
|
|
}
|
|
|
|
free(m);
|
|
|
|
return EINA_TRUE;
|
2009-06-27 23:29:11 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Load a module.
|
|
|
|
*
|
|
|
|
* @param m The module to load.
|
|
|
|
* @return EINA_TRUE on success, EINA_FALSE otherwise.
|
|
|
|
*
|
|
|
|
* This function load the shared file object passed in
|
|
|
|
* eina_module_new(). If it is a internal Eina module (like the
|
|
|
|
* mempools), it also initialize it. It the shared file object can not
|
|
|
|
* be loaded, the error #EINA_ERROR_WRONG_MODULE is set and
|
|
|
|
* #EINA_FALSE is returned. If it is a internal Eina module and the
|
|
|
|
* module can not be initialized, the error
|
|
|
|
* #EINA_ERROR_MODULE_INIT_FAILED is set and #EINA_FALSE is
|
|
|
|
* returned. If the module has already been loaded, it's refeence
|
|
|
|
* counter is increased by one and #EINA_TRUE is returned. If @p m is
|
|
|
|
* @c NULL, the function returns immediatly #EINA_FALSE.
|
|
|
|
*
|
|
|
|
* When the symbols of the shared file objetcts are not needed
|
|
|
|
* anymore, call eina_module_unload() to unload the module.
|
|
|
|
*/
|
2008-09-24 05:55:31 -07:00
|
|
|
EAPI Eina_Bool eina_module_load(Eina_Module *m)
|
|
|
|
{
|
2009-09-02 15:39:41 -07:00
|
|
|
void *dl_handle;
|
|
|
|
Eina_Module_Init *initcall;
|
2008-09-24 05:55:31 -07:00
|
|
|
|
2009-09-02 15:39:41 -07:00
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(m, EINA_FALSE);
|
2008-12-26 10:31:14 -08:00
|
|
|
|
2009-09-02 18:39:45 -07:00
|
|
|
DBG("m=%p, handle=%p, file=%s, refs=%d", m, m->handle, m->file, m->ref);
|
2009-09-02 16:06:55 -07:00
|
|
|
|
2009-09-02 15:39:41 -07:00
|
|
|
if (m->handle) goto loaded;
|
2008-09-24 05:55:31 -07:00
|
|
|
|
2009-09-02 15:39:41 -07:00
|
|
|
dl_handle = dlopen(m->file, RTLD_NOW);
|
|
|
|
if (!dl_handle)
|
|
|
|
{
|
2009-09-02 18:39:45 -07:00
|
|
|
WRN("could not dlopen(\"%s\", RTLD_NOW): %s", m->file, dlerror());
|
2009-09-02 15:39:41 -07:00
|
|
|
eina_error_set(EINA_ERROR_WRONG_MODULE);
|
2008-09-24 05:55:31 -07:00
|
|
|
return EINA_FALSE;
|
2009-09-02 15:39:41 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
initcall = dlsym(dl_handle, EINA_MODULE_SYMBOL_INIT);
|
|
|
|
if ((!initcall) || (!(*initcall)))
|
|
|
|
goto ok;
|
|
|
|
if ((*initcall)() == EINA_TRUE)
|
|
|
|
goto ok;
|
|
|
|
|
2009-09-02 18:39:45 -07:00
|
|
|
WRN("could not find eina's entry symbol %s inside module %s",
|
2009-09-02 16:06:55 -07:00
|
|
|
EINA_MODULE_SYMBOL_INIT, m->file);
|
2009-09-02 15:39:41 -07:00
|
|
|
eina_error_set(EINA_ERROR_MODULE_INIT_FAILED);
|
|
|
|
dlclose(dl_handle);
|
|
|
|
return EINA_FALSE;
|
|
|
|
ok:
|
2009-09-02 16:06:55 -07:00
|
|
|
DBG("successfully loaded %s", m->file);
|
2009-09-02 15:39:41 -07:00
|
|
|
m->handle = dl_handle;
|
|
|
|
loaded:
|
|
|
|
m->ref++;
|
2009-09-02 16:06:55 -07:00
|
|
|
DBG("ref %d", m->ref);
|
2009-09-02 15:39:41 -07:00
|
|
|
|
|
|
|
eina_error_set(0);
|
|
|
|
return EINA_TRUE;
|
2008-08-18 01:18:16 -07:00
|
|
|
}
|
2009-06-22 13:03:58 -07:00
|
|
|
|
2009-06-27 23:29:11 -07:00
|
|
|
/**
|
|
|
|
* @brief Unload a module.
|
|
|
|
*
|
|
|
|
* @param m The module to load.
|
|
|
|
* @return EINA_TRUE on success, EINA_FALSE otherwise.
|
|
|
|
*
|
|
|
|
* This function unload the module @p m that has been previously
|
|
|
|
* loaded by eina_module_load(). If the reference counter of @p m is
|
|
|
|
* strictly greater than @c 1, #EINA_FALSE is returned. Otherwise, the
|
|
|
|
* shared object file is closed and if it is a internal Eina module, it
|
|
|
|
* is shutted down just before. In that case, #EINA_TRUE is
|
|
|
|
* returned. In all case, the reference counter is decreased. If @p m
|
|
|
|
* is @c NULL, the function returns immediatly #EINA_FALSE.
|
|
|
|
*/
|
2008-09-24 05:55:31 -07:00
|
|
|
EAPI Eina_Bool eina_module_unload(Eina_Module *m)
|
2008-08-18 01:18:16 -07:00
|
|
|
{
|
2009-09-02 15:39:41 -07:00
|
|
|
Eina_Module_Shutdown *shut;
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(m, EINA_FALSE);
|
|
|
|
|
2009-09-02 18:39:45 -07:00
|
|
|
DBG("m=%p, handle=%p, file=%s, refs=%d", m, m->handle, m->file, m->ref);
|
2009-09-02 16:06:55 -07:00
|
|
|
|
2009-09-02 15:39:41 -07:00
|
|
|
m->ref--;
|
|
|
|
if (!m->ref)
|
|
|
|
{
|
|
|
|
shut = dlsym(m->handle, EINA_MODULE_SYMBOL_SHUTDOWN);
|
|
|
|
if ((shut) && (*shut))
|
|
|
|
(*shut)();
|
|
|
|
dlclose(m->handle);
|
|
|
|
m->handle = NULL;
|
2009-09-02 18:39:45 -07:00
|
|
|
DBG("unloaded module %s", m->file);
|
2009-09-02 15:39:41 -07:00
|
|
|
return EINA_TRUE;
|
|
|
|
}
|
|
|
|
return EINA_FALSE;
|
2008-08-18 01:18:16 -07:00
|
|
|
}
|
2009-06-22 13:03:58 -07:00
|
|
|
|
2009-06-27 23:29:11 -07:00
|
|
|
/**
|
|
|
|
* @brief Retrive the data associated to a symbol.
|
|
|
|
*
|
2009-08-19 00:54:13 -07:00
|
|
|
* @param m The module.
|
2009-06-27 23:29:11 -07:00
|
|
|
* @param symbol The symbol.
|
|
|
|
* @return The data associated to the symbol, or @c NULL on failure.
|
|
|
|
*
|
|
|
|
* This function returns the data associated to @p symbol of @p m. @p
|
|
|
|
* m must have been loaded before with eina_module_load(). If @p m
|
|
|
|
* is @c NULL, or if it has not been correctly loaded before, the
|
|
|
|
* function returns immediatly @c NULL.
|
|
|
|
*/
|
2009-11-23 05:24:48 -08:00
|
|
|
EAPI void * eina_module_symbol_get(const Eina_Module *m, const char *symbol)
|
2008-08-18 01:18:16 -07:00
|
|
|
{
|
2009-09-02 15:39:41 -07:00
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(m, NULL);
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(m->handle, NULL);
|
|
|
|
return dlsym(m->handle, symbol);
|
2008-08-18 01:18:16 -07:00
|
|
|
}
|
2009-06-22 13:03:58 -07:00
|
|
|
|
2009-06-27 23:29:11 -07:00
|
|
|
/**
|
|
|
|
* @brief Return the file name associated to the module.
|
|
|
|
*
|
|
|
|
* @param m The module.
|
|
|
|
* @return The file name.
|
|
|
|
*
|
|
|
|
* Return the file name passed in eina_module_new(). If @p m is
|
|
|
|
* @c NULL, the function returns immediatly @c NULL. The returned
|
|
|
|
* value must no be freed.
|
|
|
|
*/
|
2009-11-23 05:24:48 -08:00
|
|
|
EAPI const char * eina_module_file_get(const Eina_Module *m)
|
2008-08-18 01:18:16 -07:00
|
|
|
{
|
2009-09-02 15:39:41 -07:00
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(m, NULL);
|
|
|
|
return m->file;
|
2008-08-18 01:18:16 -07:00
|
|
|
}
|
|
|
|
|
2008-11-01 08:39:53 -07:00
|
|
|
EAPI char *eina_module_symbol_path_get(const void *symbol, const char *sub_dir)
|
|
|
|
{
|
2009-09-02 15:39:41 -07:00
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(symbol, NULL);
|
2008-12-26 10:31:14 -08:00
|
|
|
|
2008-11-01 08:39:53 -07:00
|
|
|
#ifdef HAVE_DLADDR
|
2009-09-02 15:39:41 -07:00
|
|
|
Dl_info eina_dl;
|
|
|
|
|
|
|
|
if (dladdr(symbol, &eina_dl))
|
|
|
|
{
|
|
|
|
if (strrchr(eina_dl.dli_fname, '/'))
|
|
|
|
{
|
|
|
|
char *path;
|
|
|
|
int l0;
|
|
|
|
int l1;
|
|
|
|
int l2 = 0;
|
|
|
|
|
|
|
|
l0 = strlen(eina_dl.dli_fname);
|
|
|
|
l1 = strlen(strrchr(eina_dl.dli_fname, '/'));
|
|
|
|
if (sub_dir && (*sub_dir != '\0'))
|
|
|
|
l2 = strlen(sub_dir);
|
|
|
|
path = malloc(l0 - l1 + l2 + 1);
|
|
|
|
if (path)
|
|
|
|
{
|
|
|
|
memcpy(path, eina_dl.dli_fname, l0 - l1);
|
|
|
|
if (sub_dir && (*sub_dir != '\0'))
|
|
|
|
memcpy(path + l0 - l1, sub_dir, l2);
|
|
|
|
path[l0 - l1 + l2] = '\0';
|
|
|
|
return path;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2008-11-01 08:39:53 -07:00
|
|
|
#endif /* ! HAVE_DLADDR */
|
|
|
|
|
2009-09-02 15:39:41 -07:00
|
|
|
return NULL;
|
2008-11-01 08:39:53 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
EAPI char *eina_module_environment_path_get(const char *env, const char *sub_dir)
|
|
|
|
{
|
2009-09-02 15:39:41 -07:00
|
|
|
const char *env_dir;
|
|
|
|
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(env, NULL);
|
|
|
|
|
|
|
|
env_dir = getenv(env);
|
|
|
|
if (env_dir)
|
|
|
|
{
|
|
|
|
char *path;
|
|
|
|
size_t l1;
|
|
|
|
size_t l2 = 0;
|
|
|
|
|
|
|
|
l1 = strlen(env_dir);
|
|
|
|
if (sub_dir && (*sub_dir != '\0'))
|
|
|
|
l2 = strlen(sub_dir);
|
|
|
|
|
|
|
|
path = (char *)malloc(l1 + l2 + 1);
|
|
|
|
if (path)
|
|
|
|
{
|
|
|
|
memcpy(path, env_dir, l1);
|
|
|
|
if (sub_dir && (*sub_dir != '\0'))
|
|
|
|
memcpy(path + l1, sub_dir, l2);
|
|
|
|
path[l1 + l2] = '\0';
|
|
|
|
|
|
|
|
return path;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
2008-11-01 08:39:53 -07:00
|
|
|
}
|
|
|
|
|
2008-09-24 05:55:31 -07:00
|
|
|
/**
|
2009-06-27 23:29:11 -07:00
|
|
|
* Get a list of modules found on the directory path
|
2008-11-01 08:39:53 -07:00
|
|
|
*
|
2009-08-19 00:54:13 -07:00
|
|
|
* @param array The array that stores the list of the modules.
|
2008-09-24 05:55:31 -07:00
|
|
|
* @param path The directory's path to search for modules
|
|
|
|
* @param recursive Iterate recursively on the path
|
|
|
|
* @param cb Callback function to call, if the return value of the callback is zero
|
|
|
|
* it won't be added to the list, if it is one, it will.
|
|
|
|
* @param data Data passed to the callback function
|
|
|
|
*/
|
2008-11-01 08:39:53 -07:00
|
|
|
EAPI Eina_Array * eina_module_list_get(Eina_Array *array, const char *path, unsigned int recursive, Eina_Module_Cb cb, void *data)
|
2008-09-24 05:55:31 -07:00
|
|
|
{
|
2009-09-02 15:39:41 -07:00
|
|
|
Dir_List_Get_Cb_Data list_get_cb_data;
|
|
|
|
Dir_List_Cb_Data list_cb_data;
|
2008-09-29 06:28:42 -07:00
|
|
|
|
2009-09-02 15:39:41 -07:00
|
|
|
if (!path) return array;
|
2008-09-24 05:55:31 -07:00
|
|
|
|
2009-09-02 15:39:41 -07:00
|
|
|
list_get_cb_data.array = array ? array : eina_array_new(4);
|
|
|
|
list_get_cb_data.cb = cb;
|
|
|
|
list_get_cb_data.data = data;
|
2008-09-29 06:28:42 -07:00
|
|
|
|
2009-09-02 15:39:41 -07:00
|
|
|
list_cb_data.cb = &_dir_list_get_cb;
|
|
|
|
list_cb_data.data = &list_get_cb_data;
|
2008-09-29 06:28:42 -07:00
|
|
|
|
2009-09-02 15:39:41 -07:00
|
|
|
eina_file_dir_list(path, recursive, &_dir_list_cb, &list_cb_data);
|
2008-09-29 06:28:42 -07:00
|
|
|
|
2009-09-02 15:39:41 -07:00
|
|
|
return list_get_cb_data.array;
|
2008-08-18 01:18:16 -07:00
|
|
|
}
|
2009-06-22 13:03:58 -07:00
|
|
|
|
2009-11-20 12:46:24 -08:00
|
|
|
/**
|
|
|
|
* @brief Find an module in array.
|
|
|
|
*
|
|
|
|
* @param array The array to find the module.
|
|
|
|
* @param module The name of module to be searched;
|
|
|
|
*
|
|
|
|
* This function finds an @p module in an @p array;
|
|
|
|
* If the element is found return the module else NULL.
|
|
|
|
*/
|
|
|
|
EAPI Eina_Module *
|
2009-11-23 05:20:34 -08:00
|
|
|
eina_module_find(const Eina_Array *array, const char *module)
|
2009-11-20 12:46:24 -08:00
|
|
|
{
|
|
|
|
unsigned int i;
|
|
|
|
Eina_Array_Iterator iterator;
|
|
|
|
Eina_Module *m;
|
|
|
|
|
|
|
|
EINA_ARRAY_ITER_NEXT(array, i, m, iterator)
|
|
|
|
{
|
2010-01-16 08:41:24 -08:00
|
|
|
char *file_m;
|
|
|
|
char *tmp;
|
2009-11-20 12:46:24 -08:00
|
|
|
ssize_t len;
|
|
|
|
|
2010-01-16 08:41:24 -08:00
|
|
|
/* basename() can modify its argument, so we first get a copie */
|
|
|
|
/* do not use strdupa, as opensolaris does not have it */
|
|
|
|
len = strlen(eina_module_file_get(m));
|
|
|
|
tmp = alloca(len + 1);
|
|
|
|
memcpy(tmp, eina_module_file_get(m), len + 1);
|
|
|
|
file_m = basename(tmp);
|
2009-11-20 12:46:24 -08:00
|
|
|
len = strlen(file_m);
|
2010-01-16 08:46:39 -08:00
|
|
|
len -= sizeof(SHARED_LIB_SUFFIX) - 1;
|
2009-11-20 12:46:24 -08:00
|
|
|
if (len <= 0) continue;
|
|
|
|
if (!strncmp(module, file_m, len)) return m;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2008-09-24 05:55:31 -07:00
|
|
|
/**
|
|
|
|
* Load every module on the list of modules
|
2009-08-19 00:54:13 -07:00
|
|
|
* @param array The array of modules to load
|
2008-09-24 05:55:31 -07:00
|
|
|
*/
|
2008-09-29 06:28:42 -07:00
|
|
|
EAPI void eina_module_list_load(Eina_Array *array)
|
2008-08-18 01:18:16 -07:00
|
|
|
{
|
2009-09-02 15:39:41 -07:00
|
|
|
Eina_Array_Iterator iterator;
|
|
|
|
Eina_Module *m;
|
|
|
|
unsigned int i;
|
2008-09-29 06:28:42 -07:00
|
|
|
|
2009-09-02 15:39:41 -07:00
|
|
|
EINA_SAFETY_ON_NULL_RETURN(array);
|
2009-09-02 18:39:45 -07:00
|
|
|
DBG("array %p, count %u", array, array->count);
|
2009-09-02 15:39:41 -07:00
|
|
|
EINA_ARRAY_ITER_NEXT(array, i, m, iterator)
|
|
|
|
eina_module_load(m);
|
2008-08-18 01:18:16 -07:00
|
|
|
}
|
2009-06-22 13:03:58 -07:00
|
|
|
|
2009-08-19 00:54:13 -07:00
|
|
|
/**
|
|
|
|
* Unload every module on the list of modules
|
|
|
|
* @param array The array of modules to unload
|
|
|
|
*/
|
2008-09-29 06:28:42 -07:00
|
|
|
EAPI void eina_module_list_unload(Eina_Array *array)
|
2008-08-18 01:18:16 -07:00
|
|
|
{
|
2009-09-02 15:39:41 -07:00
|
|
|
Eina_Array_Iterator iterator;
|
|
|
|
Eina_Module *m;
|
|
|
|
unsigned int i;
|
2008-09-29 06:28:42 -07:00
|
|
|
|
2009-09-02 15:39:41 -07:00
|
|
|
EINA_SAFETY_ON_NULL_RETURN(array);
|
2009-09-02 18:39:45 -07:00
|
|
|
DBG("array %p, count %u", array, array->count);
|
2009-09-02 15:39:41 -07:00
|
|
|
EINA_ARRAY_ITER_NEXT(array, i, m, iterator)
|
|
|
|
eina_module_unload(m);
|
2008-08-18 01:18:16 -07:00
|
|
|
}
|
2009-06-22 13:03:58 -07:00
|
|
|
|
2008-09-24 05:55:31 -07:00
|
|
|
/**
|
|
|
|
* Helper function that iterates over the list of modules and calls
|
2009-06-24 09:56:49 -07:00
|
|
|
* eina_module_free on each
|
2008-09-24 05:55:31 -07:00
|
|
|
*/
|
2010-01-08 04:22:23 -08:00
|
|
|
EAPI void eina_module_list_free(Eina_Array *array)
|
2008-08-18 01:18:16 -07:00
|
|
|
{
|
2009-09-02 15:39:41 -07:00
|
|
|
Eina_Array_Iterator iterator;
|
|
|
|
Eina_Module *m;
|
|
|
|
unsigned int i;
|
2008-09-29 06:28:42 -07:00
|
|
|
|
2009-09-02 15:39:41 -07:00
|
|
|
EINA_SAFETY_ON_NULL_RETURN(array);
|
2009-09-02 18:39:45 -07:00
|
|
|
DBG("array %p, count %u", array, array->count);
|
2009-09-02 15:39:41 -07:00
|
|
|
EINA_ARRAY_ITER_NEXT(array, i, m, iterator)
|
|
|
|
eina_module_free(m);
|
2009-02-17 04:58:09 -08:00
|
|
|
|
2009-09-02 15:39:41 -07:00
|
|
|
eina_array_flush(array);
|
2008-08-18 01:18:16 -07:00
|
|
|
}
|
2009-06-22 13:03:58 -07:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @}
|
|
|
|
*/
|