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