|
|
|
@ -526,83 +526,91 @@ static enum ast_module_load_result load_resource(const char *resource_name, unsi
|
|
|
|
|
|
|
|
|
|
#define MODULE_LOCAL_ONLY (void *)-1
|
|
|
|
|
|
|
|
|
|
static struct ast_module *load_dynamic_module(const char *resource_in, unsigned int global_symbols_only, unsigned int suppress_logging, struct ast_heap *resource_heap)
|
|
|
|
|
/*!
|
|
|
|
|
* \internal
|
|
|
|
|
* \brief Attempt to dlopen a module.
|
|
|
|
|
*
|
|
|
|
|
* \param resource_in The module name to load.
|
|
|
|
|
* \param so_ext ".so" or blank if ".so" is already part of resource_in.
|
|
|
|
|
* \param filename Passed directly to dlopen.
|
|
|
|
|
* \param flags Passed directly to dlopen.
|
|
|
|
|
* \param suppress_logging Do not log any error from dlopen.
|
|
|
|
|
*
|
|
|
|
|
* \return Pointer to opened module, NULL on error.
|
|
|
|
|
*
|
|
|
|
|
* \warning module_list must be locked before calling this function.
|
|
|
|
|
*/
|
|
|
|
|
static struct ast_module *load_dlopen(const char *resource_in, const char *so_ext,
|
|
|
|
|
const char *filename, int flags, unsigned int suppress_logging)
|
|
|
|
|
{
|
|
|
|
|
char fn[PATH_MAX] = "";
|
|
|
|
|
void *lib = NULL;
|
|
|
|
|
struct ast_module *mod;
|
|
|
|
|
unsigned int wants_global;
|
|
|
|
|
int space; /* room needed for the descriptor */
|
|
|
|
|
int missing_so = 0;
|
|
|
|
|
|
|
|
|
|
ast_assert(!resource_being_loaded);
|
|
|
|
|
|
|
|
|
|
space = sizeof(*resource_being_loaded) + strlen(resource_in) + 1;
|
|
|
|
|
if (strcasecmp(resource_in + strlen(resource_in) - 3, ".so")) {
|
|
|
|
|
missing_so = 1;
|
|
|
|
|
space += 3; /* room for the extra ".so" */
|
|
|
|
|
mod = ast_calloc(1, sizeof(*mod) + strlen(resource_in) + strlen(so_ext) + 1);
|
|
|
|
|
if (!mod) {
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
snprintf(fn, sizeof(fn), "%s/%s%s", ast_config_AST_MODULE_DIR, resource_in, missing_so ? ".so" : "");
|
|
|
|
|
sprintf(mod->resource, "%s%s", resource_in, so_ext); /* safe */
|
|
|
|
|
|
|
|
|
|
/* make a first load of the module in 'quiet' mode... don't try to resolve
|
|
|
|
|
any symbols, and don't export any symbols. this will allow us to peek into
|
|
|
|
|
the module's info block (if available) to see what flags it has set */
|
|
|
|
|
|
|
|
|
|
mod = resource_being_loaded = ast_calloc(1, space);
|
|
|
|
|
if (!resource_being_loaded)
|
|
|
|
|
return NULL;
|
|
|
|
|
strcpy(resource_being_loaded->resource, resource_in);
|
|
|
|
|
if (missing_so)
|
|
|
|
|
strcat(resource_being_loaded->resource, ".so");
|
|
|
|
|
|
|
|
|
|
lib = dlopen(fn, RTLD_LAZY | RTLD_GLOBAL);
|
|
|
|
|
resource_being_loaded = mod;
|
|
|
|
|
mod->lib = dlopen(filename, flags);
|
|
|
|
|
if (resource_being_loaded) {
|
|
|
|
|
resource_being_loaded = NULL;
|
|
|
|
|
if (lib) {
|
|
|
|
|
if (mod->lib) {
|
|
|
|
|
ast_log(LOG_ERROR, "Module '%s' did not register itself during load\n", resource_in);
|
|
|
|
|
logged_dlclose(resource_in, lib);
|
|
|
|
|
logged_dlclose(resource_in, mod->lib);
|
|
|
|
|
} else if (!suppress_logging) {
|
|
|
|
|
ast_log(LOG_WARNING, "Error loading module '%s': %s\n", resource_in, dlerror());
|
|
|
|
|
}
|
|
|
|
|
ast_free(mod);
|
|
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
wants_global = ast_test_flag(mod->info, AST_MODFLAG_GLOBAL_SYMBOLS);
|
|
|
|
|
return mod;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* if we are being asked only to load modules that provide global symbols,
|
|
|
|
|
and this one does not, then close it and return */
|
|
|
|
|
if (global_symbols_only && !wants_global) {
|
|
|
|
|
logged_dlclose(resource_in, lib);
|
|
|
|
|
return MODULE_LOCAL_ONLY;
|
|
|
|
|
static struct ast_module *load_dynamic_module(const char *resource_in, unsigned int global_symbols_only, unsigned int suppress_logging, struct ast_heap *resource_heap)
|
|
|
|
|
{
|
|
|
|
|
char fn[PATH_MAX];
|
|
|
|
|
struct ast_module *mod;
|
|
|
|
|
size_t resource_in_len = strlen(resource_in);
|
|
|
|
|
int exports_globals;
|
|
|
|
|
const char *so_ext = "";
|
|
|
|
|
|
|
|
|
|
if (resource_in_len < 4 || strcasecmp(resource_in + resource_in_len - 3, ".so")) {
|
|
|
|
|
so_ext = ".so";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
logged_dlclose(resource_in, lib);
|
|
|
|
|
snprintf(fn, sizeof(fn), "%s/%s%s", ast_config_AST_MODULE_DIR, resource_in, so_ext);
|
|
|
|
|
|
|
|
|
|
/* start the load process again */
|
|
|
|
|
mod = resource_being_loaded = ast_calloc(1, space);
|
|
|
|
|
if (!resource_being_loaded)
|
|
|
|
|
return NULL;
|
|
|
|
|
strcpy(resource_being_loaded->resource, resource_in);
|
|
|
|
|
if (missing_so)
|
|
|
|
|
strcat(resource_being_loaded->resource, ".so");
|
|
|
|
|
/* Try loading in quiet mode first with flags to export global symbols.
|
|
|
|
|
* If the module does not want to export globals we will close and reopen. */
|
|
|
|
|
mod = load_dlopen(resource_in, so_ext, fn,
|
|
|
|
|
global_symbols_only ? RTLD_LAZY | RTLD_GLOBAL : RTLD_NOW | RTLD_LOCAL,
|
|
|
|
|
suppress_logging);
|
|
|
|
|
|
|
|
|
|
lib = dlopen(fn, wants_global ? RTLD_LAZY | RTLD_GLOBAL : RTLD_NOW | RTLD_LOCAL);
|
|
|
|
|
resource_being_loaded = NULL;
|
|
|
|
|
if (!lib) {
|
|
|
|
|
ast_log(LOG_WARNING, "Error loading module '%s': %s\n", resource_in, dlerror());
|
|
|
|
|
ast_free(mod);
|
|
|
|
|
if (!mod) {
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* since the module was successfully opened, and it registered itself
|
|
|
|
|
the previous time we did that, we're going to assume it worked this
|
|
|
|
|
time too :) */
|
|
|
|
|
exports_globals = ast_test_flag(mod->info, AST_MODFLAG_GLOBAL_SYMBOLS);
|
|
|
|
|
if ((global_symbols_only && exports_globals) || (!global_symbols_only && !exports_globals)) {
|
|
|
|
|
/* The first dlopen had the correct flags. */
|
|
|
|
|
return mod;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
AST_DLLIST_LAST(&module_list)->lib = lib;
|
|
|
|
|
/* Close the module so we can reopen with correct flags. */
|
|
|
|
|
logged_dlclose(resource_in, mod->lib);
|
|
|
|
|
if (global_symbols_only) {
|
|
|
|
|
return MODULE_LOCAL_ONLY;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return AST_DLLIST_LAST(&module_list);
|
|
|
|
|
return load_dlopen(resource_in, so_ext, fn,
|
|
|
|
|
exports_globals ? RTLD_LAZY | RTLD_GLOBAL : RTLD_NOW | RTLD_LOCAL,
|
|
|
|
|
0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int modules_shutdown(void)
|
|
|
|
|