summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJenkins2 <jenkins2@gerrit.asterisk.org>2017-12-18 08:31:46 -0600
committerGerrit Code Review <gerrit2@gerrit.digium.api>2017-12-18 08:31:46 -0600
commit73404801a6f852cc761b843d507836060ec6f1f6 (patch)
treeff0f09a4a9d585d642f4f4caaa5e1ced13954746
parent4ae244841c5eb59f6393934c45b35e7ce79bde6b (diff)
parent5295c4685aae48bd060ddb8a7fdfffe0dcacfbb9 (diff)
Merge "loader: Rework of load_dynamic_module." into 15
-rw-r--r--main/loader.c106
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)