#include <stdio.h>
#include <dirent.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <asterisk/module.h>
#include <asterisk/options.h>
#include <asterisk/config.h>
#include <asterisk/logger.h>
#include <asterisk/channel.h>
#include <asterisk/term.h>
#include <asterisk/manager.h>
#include <asterisk/enum.h>
#include <asterisk/rtp.h>
#include <dlfcn.h>
#include <asterisk/md5.h>
#include <pthread.h>
#include "asterisk.h"
#include "astconf.h"
Go to the source code of this file.
Data Structures | |
struct | loadupdate |
struct | module |
Defines | |
#define | RTLD_NOW 0 |
Functions | |
int | ast_unload_resource (char *resource_name, int force) |
Unloads a module. | |
void | ast_module_reload (void) |
Reload all modules. | |
int | ast_load_resource (char *resource_name) |
Loads a module. | |
int | load_modules () |
void | ast_update_use_count (void) |
Notify when usecount has been changed. | |
int | ast_update_module_list (int(*modentry)(char *module, char *description, int usecnt)) |
Ask for a list of modules, descriptions, and use counts. | |
int | ast_loader_register (int(*v)(void)) |
Ask this procedure to be run with modules have been updated. | |
int | ast_loader_unregister (int(*v)(void)) |
No longer run me when modules are updated. |
|
Definition at line 39 of file loader.c. Referenced by ast_load_resource(), and dlopen(). |
|
Loads a module.
Definition at line 177 of file loader.c. References ast_config_AST_MODULE_DIR, ast_destroy(), ast_load(), ast_log(), AST_MODULE_CONFIG, ast_mutex_lock, ast_mutex_unlock, ast_true(), ast_unload_resource(), ast_update_use_count(), ast_variable_retrieve(), ast_verbose(), COLOR_BLACK, COLOR_BROWN, dlclose(), dlerror(), dlopen(), dlsym(), free, fully_booted, key(), LOG_WARNING, malloc, option_console, option_verbose, RTLD_GLOBAL, RTLD_LAZY, RTLD_NOW, term_color(), and VERBOSE_PREFIX_1. Referenced by load_modules().
00178 { 00179 static char fn[256]; 00180 int errors=0; 00181 int res; 00182 struct module *m; 00183 int flags=RTLD_NOW; 00184 #ifdef RTLD_GLOBAL 00185 char *val; 00186 #endif 00187 char *key; 00188 int o; 00189 struct ast_config *cfg; 00190 char tmp[80]; 00191 /* Keep the module file parsing silent */ 00192 o = option_verbose; 00193 if (strncasecmp(resource_name, "res_", 4)) { 00194 option_verbose = 0; 00195 cfg = ast_load(AST_MODULE_CONFIG); 00196 option_verbose = o; 00197 if (cfg) { 00198 #ifdef RTLD_GLOBAL 00199 if ((val = ast_variable_retrieve(cfg, "global", resource_name)) 00200 && ast_true(val)) 00201 flags |= RTLD_GLOBAL; 00202 #endif 00203 ast_destroy(cfg); 00204 } 00205 } else { 00206 /* Resource modules are always loaded global and lazy */ 00207 #ifdef RTLD_GLOBAL 00208 flags = (RTLD_GLOBAL | RTLD_LAZY); 00209 #else 00210 flags = RTLD_LAZY; 00211 #endif 00212 } 00213 00214 if (ast_mutex_lock(&modlock)) 00215 ast_log(LOG_WARNING, "Failed to lock\n"); 00216 m = module_list; 00217 while(m) { 00218 if (!strcasecmp(m->resource, resource_name)) { 00219 ast_log(LOG_WARNING, "Module '%s' already exists\n", resource_name); 00220 ast_mutex_unlock(&modlock); 00221 return -1; 00222 } 00223 m = m->next; 00224 } 00225 m = malloc(sizeof(struct module)); 00226 if (!m) { 00227 ast_log(LOG_WARNING, "Out of memory\n"); 00228 ast_mutex_unlock(&modlock); 00229 return -1; 00230 } 00231 strncpy(m->resource, resource_name, sizeof(m->resource)-1); 00232 if (resource_name[0] == '/') { 00233 strncpy(fn, resource_name, sizeof(fn)-1); 00234 } else { 00235 snprintf(fn, sizeof(fn), "%s/%s", (char *)ast_config_AST_MODULE_DIR, resource_name); 00236 } 00237 m->lib = dlopen(fn, flags); 00238 if (!m->lib) { 00239 ast_log(LOG_WARNING, "%s\n", dlerror()); 00240 free(m); 00241 ast_mutex_unlock(&modlock); 00242 return -1; 00243 } 00244 m->load_module = dlsym(m->lib, "load_module"); 00245 if (m->load_module == NULL) 00246 m->load_module = dlsym(m->lib, "_load_module"); 00247 if (!m->load_module) { 00248 ast_log(LOG_WARNING, "No load_module in module %s\n", fn); 00249 errors++; 00250 } 00251 m->unload_module = dlsym(m->lib, "unload_module"); 00252 if (m->unload_module == NULL) 00253 m->unload_module = dlsym(m->lib, "_unload_module"); 00254 if (!m->unload_module) { 00255 ast_log(LOG_WARNING, "No unload_module in module %s\n", fn); 00256 errors++; 00257 } 00258 m->usecount = dlsym(m->lib, "usecount"); 00259 if (m->usecount == NULL) 00260 m->usecount = dlsym(m->lib, "_usecount"); 00261 if (!m->usecount) { 00262 ast_log(LOG_WARNING, "No usecount in module %s\n", fn); 00263 errors++; 00264 } 00265 m->description = dlsym(m->lib, "description"); 00266 if (m->description == NULL) 00267 m->description = dlsym(m->lib, "_description"); 00268 if (!m->description) { 00269 ast_log(LOG_WARNING, "No description in module %s\n", fn); 00270 errors++; 00271 } 00272 m->key = dlsym(m->lib, "key"); 00273 if (m->key == NULL) 00274 m->key = dlsym(m->lib, "_key"); 00275 if (!m->key) { 00276 ast_log(LOG_WARNING, "No key routine in module %s\n", fn); 00277 errors++; 00278 } 00279 m->reload = dlsym(m->lib, "reload"); 00280 if (m->reload == NULL) 00281 m->reload = dlsym(m->lib, "_reload"); 00282 if (m->key && !(key = m->key())) { 00283 ast_log(LOG_WARNING, "Key routine returned NULL in module %s\n", fn); 00284 errors++; 00285 } else 00286 key = NULL; 00287 if (key && verify_key(key)) { 00288 ast_log(LOG_WARNING, "Unexpected key returned by module %s\n", fn); 00289 errors++; 00290 } 00291 if (errors) { 00292 ast_log(LOG_WARNING, "%d error(s) loading module %s, aborted\n", errors, fn); 00293 dlclose(m->lib); 00294 free(m); 00295 ast_mutex_unlock(&modlock); 00296 return -1; 00297 } 00298 if (!fully_booted) { 00299 if (option_verbose) 00300 ast_verbose( " => (%s)\n", term_color(tmp, m->description(), COLOR_BROWN, COLOR_BLACK, sizeof(tmp))); 00301 if (option_console && !option_verbose) 00302 ast_verbose( "."); 00303 } else { 00304 if (option_verbose) 00305 ast_verbose(VERBOSE_PREFIX_1 "Loaded %s => (%s)\n", fn, m->description()); 00306 } 00307 m->next = module_list; 00308 00309 module_list = m; 00310 ast_mutex_unlock(&modlock); 00311 if ((res = m->load_module())) { 00312 ast_log(LOG_WARNING, "%s: load_module failed, returning %d\n", m->resource, res); 00313 ast_unload_resource(resource_name, 0); 00314 return -1; 00315 } 00316 ast_update_use_count(); 00317 return 0; 00318 } |
|
Ask this procedure to be run with modules have been updated.
Definition at line 457 of file loader.c. References ast_log(), ast_mutex_lock, ast_mutex_unlock, LOG_WARNING, and malloc.
00458 { 00459 struct loadupdate *tmp; 00460 /* XXX Should be more flexible here, taking > 1 verboser XXX */ 00461 if ((tmp = malloc(sizeof (struct loadupdate)))) { 00462 tmp->updater = v; 00463 if (ast_mutex_lock(&modlock)) 00464 ast_log(LOG_WARNING, "Failed to lock\n"); 00465 tmp->next = updaters; 00466 updaters = tmp; 00467 ast_mutex_unlock(&modlock); 00468 return 0; 00469 } 00470 return -1; 00471 } |
|
No longer run me when modules are updated.
Definition at line 473 of file loader.c. References ast_log(), ast_mutex_lock, ast_mutex_unlock, and LOG_WARNING.
00474 { 00475 int res = -1; 00476 struct loadupdate *tmp, *tmpl=NULL; 00477 if (ast_mutex_lock(&modlock)) 00478 ast_log(LOG_WARNING, "Failed to lock\n"); 00479 tmp = updaters; 00480 while(tmp) { 00481 if (tmp->updater == v) { 00482 if (tmpl) 00483 tmpl->next = tmp->next; 00484 else 00485 updaters = tmp->next; 00486 break; 00487 } 00488 tmpl = tmp; 00489 tmp = tmp->next; 00490 } 00491 if (tmp) 00492 res = 0; 00493 ast_mutex_unlock(&modlock); 00494 return res; 00495 } |
|
Reload all modules. This reloads all modules set to load in asterisk. It does NOT run the unload routine and then loads them again, it runs the given reload routine. Definition at line 148 of file loader.c. References ast_enum_reload(), ast_lastreloadtime, ast_mutex_lock, ast_mutex_trylock, ast_mutex_unlock, ast_rtp_reload(), ast_verbose(), option_verbose, reload_manager(), and VERBOSE_PREFIX_3.
00149 { 00150 struct module *m; 00151 00152 /* We'll do the logger and manager the favor of calling its reload here first */ 00153 00154 if (ast_mutex_trylock(&reloadlock)) { 00155 ast_verbose("The previous reload command didn't finish yet\n"); 00156 return; 00157 } 00158 reload_manager(); 00159 ast_enum_reload(); 00160 ast_rtp_reload(); 00161 time(&ast_lastreloadtime); 00162 00163 ast_mutex_lock(&modlock); 00164 m = module_list; 00165 while(m) { 00166 if (m->reload) { 00167 if (option_verbose > 2) 00168 ast_verbose(VERBOSE_PREFIX_3 "Reloading module '%s' (%s)\n", m->resource, m->description()); 00169 m->reload(); 00170 } 00171 m = m->next; 00172 } 00173 ast_mutex_unlock(&modlock); 00174 ast_mutex_unlock(&reloadlock); 00175 } |
|
Unloads a module.
Definition at line 106 of file loader.c. References AST_FORCE_FIRM, ast_log(), ast_mutex_lock, ast_mutex_unlock, ast_update_use_count(), dlclose(), free, LOG_WARNING, and module::next. Referenced by ast_load_resource().
00107 { 00108 struct module *m, *ml = NULL; 00109 int res = -1; 00110 if (ast_mutex_lock(&modlock)) 00111 ast_log(LOG_WARNING, "Failed to lock\n"); 00112 m = module_list; 00113 while(m) { 00114 if (!strcasecmp(m->resource, resource_name)) { 00115 if ((res = m->usecount()) > 0) { 00116 if (force) 00117 ast_log(LOG_WARNING, "Warning: Forcing removal of module %s with use count %d\n", resource_name, res); 00118 else { 00119 ast_log(LOG_WARNING, "Soft unload failed, '%s' has use count %d\n", resource_name, res); 00120 ast_mutex_unlock(&modlock); 00121 return -1; 00122 } 00123 } 00124 res = m->unload_module(); 00125 if (res) { 00126 ast_log(LOG_WARNING, "Firm unload failed for %s\n", resource_name); 00127 if (force <= AST_FORCE_FIRM) { 00128 ast_mutex_unlock(&modlock); 00129 return -1; 00130 } else 00131 ast_log(LOG_WARNING, "** Dangerous **: Unloading resource anyway, at user request\n"); 00132 } 00133 if (ml) 00134 ml->next = m->next; 00135 else 00136 module_list = m->next; 00137 dlclose(m->lib); 00138 free(m); 00139 } 00140 ml = m; 00141 m = m->next; 00142 } 00143 ast_mutex_unlock(&modlock); 00144 ast_update_use_count(); 00145 return res; 00146 } |
|
Ask for a list of modules, descriptions, and use counts.
Definition at line 441 of file loader.c. References ast_mutex_trylock, ast_mutex_unlock, and module::next.
00442 { 00443 struct module *m; 00444 int unlock = -1; 00445 if (ast_mutex_trylock(&modlock)) 00446 unlock = 0; 00447 m = module_list; 00448 while(m) { 00449 modentry(m->resource, m->description(), m->usecount()); 00450 m = m->next; 00451 } 00452 if (unlock) 00453 ast_mutex_unlock(&modlock); 00454 return 0; 00455 } |
|
Notify when usecount has been changed. This function goes through and calulates use counts. It also notifies anybody trying to keep track of them. Definition at line 425 of file loader.c. References ast_log(), ast_mutex_lock, ast_mutex_unlock, and LOG_WARNING. Referenced by ast_load_resource(), and ast_unload_resource().
00426 { 00427 /* Notify any module monitors that the use count for a 00428 resource has changed */ 00429 struct loadupdate *m; 00430 if (ast_mutex_lock(&modlock)) 00431 ast_log(LOG_WARNING, "Failed to lock\n"); 00432 m = updaters; 00433 while(m) { 00434 m->updater(); 00435 m = m->next; 00436 } 00437 ast_mutex_unlock(&modlock); 00438 00439 } |
|
Definition at line 338 of file loader.c. References ast_config_AST_MODULE_DIR, ast_destroy(), ast_load(), ast_load_resource(), ast_log(), AST_MODULE_CONFIG, ast_true(), ast_variable_browse(), ast_variable_retrieve(), ast_verbose(), COLOR_BRWHITE, LOG_DEBUG, LOG_WARNING, option_debug, option_quiet, option_verbose, term_color(), and VERBOSE_PREFIX_1. Referenced by main().
00339 { 00340 struct ast_config *cfg; 00341 struct ast_variable *v; 00342 char tmp[80]; 00343 if (option_verbose) 00344 ast_verbose( "Asterisk Dynamic Loader Starting:\n"); 00345 cfg = ast_load(AST_MODULE_CONFIG); 00346 if (cfg) { 00347 /* Load explicitly defined modules */ 00348 v = ast_variable_browse(cfg, "modules"); 00349 while(v) { 00350 if (!strcasecmp(v->name, "load")) { 00351 if (option_debug && !option_verbose) 00352 ast_log(LOG_DEBUG, "Loading module %s\n", v->value); 00353 if (option_verbose) { 00354 ast_verbose( VERBOSE_PREFIX_1 "[%s]", term_color(tmp, v->value, COLOR_BRWHITE, 0, sizeof(tmp))); 00355 fflush(stdout); 00356 } 00357 if (ast_load_resource(v->value)) { 00358 ast_log(LOG_WARNING, "Loading module %s failed!\n", v->value); 00359 if (cfg) 00360 ast_destroy(cfg); 00361 return -1; 00362 } 00363 } 00364 v=v->next; 00365 } 00366 } 00367 if (!cfg || ast_true(ast_variable_retrieve(cfg, "modules", "autoload"))) { 00368 /* Load all modules */ 00369 DIR *mods; 00370 struct dirent *d; 00371 int x; 00372 /* Make two passes. First, load any resource modules, then load the others. */ 00373 for (x=0;x<2;x++) { 00374 mods = opendir((char *)ast_config_AST_MODULE_DIR); 00375 if (mods) { 00376 while((d = readdir(mods))) { 00377 /* Must end in .so to load it. */ 00378 if ((strlen(d->d_name) > 3) && (x || !strncasecmp(d->d_name, "res_", 4)) && 00379 !strcasecmp(d->d_name + strlen(d->d_name) - 3, ".so") && 00380 !ast_resource_exists(d->d_name)) { 00381 /* It's a shared library -- Just be sure we're allowed to load it -- kinda 00382 an inefficient way to do it, but oh well. */ 00383 if (cfg) { 00384 v = ast_variable_browse(cfg, "modules"); 00385 while(v) { 00386 if (!strcasecmp(v->name, "noload") && 00387 !strcasecmp(v->value, d->d_name)) 00388 break; 00389 v = v->next; 00390 } 00391 if (v) { 00392 if (option_verbose) { 00393 ast_verbose( VERBOSE_PREFIX_1 "[skipping %s]\n", d->d_name); 00394 fflush(stdout); 00395 } 00396 continue; 00397 } 00398 00399 } 00400 if (option_debug && !option_verbose) 00401 ast_log(LOG_DEBUG, "Loading module %s\n", d->d_name); 00402 if (option_verbose) { 00403 ast_verbose( VERBOSE_PREFIX_1 "[%s]", term_color(tmp, d->d_name, COLOR_BRWHITE, 0, sizeof(tmp))); 00404 fflush(stdout); 00405 } 00406 if (ast_load_resource(d->d_name)) { 00407 ast_log(LOG_WARNING, "Loading module %s failed!\n", d->d_name); 00408 if (cfg) 00409 ast_destroy(cfg); 00410 return -1; 00411 } 00412 } 00413 } 00414 closedir(mods); 00415 } else { 00416 if (!option_quiet) 00417 ast_log(LOG_WARNING, "Unable to open modules directory %s.\n", (char *)ast_config_AST_MODULE_DIR); 00418 } 00419 } 00420 } 00421 ast_destroy(cfg); 00422 return 0; 00423 } |