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