diff options
Diffstat (limited to 'main/loader.c')
-rw-r--r-- | main/loader.c | 106 |
1 files changed, 57 insertions, 49 deletions
diff --git a/main/loader.c b/main/loader.c index f06d637a8..f204a865c 100644 --- a/main/loader.c +++ b/main/loader.c @@ -520,83 +520,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) |