diff --git a/main/loader.c b/main/loader.c index 25c6c3773b2408770905155539500be1d253ec40..27a6c9b60b1c092be1a319a4a4674d2421403c9b 100644 --- a/main/loader.c +++ b/main/loader.c @@ -333,8 +333,8 @@ static struct ast_module *load_dynamic_module(const char *resource_in, unsigned char fn[256]; void *lib; struct ast_module *mod; - unsigned int load_global = global_symbols_only; char *resource = (char *) resource_in; + unsigned int wants_global; if (strcasecmp(resource + strlen(resource) - 3, ".so")) { resource = alloca(strlen(resource_in) + 3); @@ -344,18 +344,16 @@ static struct ast_module *load_dynamic_module(const char *resource_in, unsigned snprintf(fn, sizeof(fn), "%s/%s", ast_config_AST_MODULE_DIR, resource); -tryload: + /* 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 */ + if (!(resource_being_loaded = ast_calloc(1, sizeof(*resource_being_loaded) + strlen(resource) + 1))) return NULL; strcpy(resource_being_loaded->resource, resource); - if (load_global) - lib = dlopen(fn, RTLD_LAZY | RTLD_GLOBAL); - else - lib = dlopen(fn, RTLD_NOW | RTLD_LOCAL); - - if (!lib) { + if (!(lib = dlopen(fn, RTLD_LAZY | RTLD_LOCAL))) { ast_log(LOG_WARNING, "%s\n", dlerror()); free(resource_being_loaded); return NULL; @@ -371,31 +369,43 @@ tryload: if (resource_being_loaded != (mod = AST_LIST_LAST(&module_list))) { /* no, it did not, so close it and return */ dlclose(lib); - free(resource_being_loaded); + /* note that the module's destructor will call ast_module_unregister(), + which will free the structure we allocated in resource_being_loaded */ return NULL; } + wants_global = ast_test_flag(mod->info, AST_MODFLAG_GLOBAL_SYMBOLS); + + /* we are done with this first load, so clean up and start over */ + + dlclose(lib); resource_being_loaded = NULL; - mod->lib = lib; /* if we are being asked only to load modules that provide global symbols, and this one does not, then close it and return */ - if (load_global && !ast_test_flag(mod->info, AST_MODFLAG_GLOBAL_SYMBOLS)) { - unload_dynamic_module(mod); + if (global_symbols_only && !wants_global) return NULL; - } - /* if we were not asked to load _only_ modules with global symbols, but - this module wants to provide some, then we have to close and re-open - in global mode - */ - if (!load_global && ast_test_flag(mod->info, AST_MODFLAG_GLOBAL_SYMBOLS)) { - unload_dynamic_module(mod); - load_global = 1; - goto tryload; + /* start the load process again */ + + if (!(resource_being_loaded = ast_calloc(1, sizeof(*resource_being_loaded) + strlen(resource) + 1))) + return NULL; + + strcpy(resource_being_loaded->resource, resource); + + if (!(lib = dlopen(fn, wants_global ? RTLD_LAZY | RTLD_GLOBAL : RTLD_NOW | RTLD_LOCAL))) { + ast_log(LOG_WARNING, "%s\n", dlerror()); + free(resource_being_loaded); + return NULL; } - return mod; + /* 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 :) */ + AST_LIST_LAST(&module_list)->lib = lib; + resource_being_loaded = NULL; + + return AST_LIST_LAST(&module_list); } #endif