Main Page | Alphabetical List | Data Structures | File List | Data Fields | Globals

loader.c File Reference

#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/config_pvt.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 <asterisk/lock.h>
#include <dlfcn.h>
#include <asterisk/md5.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

 AST_MUTEX_DEFINE_STATIC (modlock)
 AST_MUTEX_DEFINE_STATIC (reloadlock)
int ast_unload_resource (char *resource_name, int force)
 Unloads a module.
void ast_module_reload (const char *name)
 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.


Define Documentation

#define RTLD_NOW   0
 

Definition at line 40 of file loader.c.

Referenced by ast_load_resource(), and dlopen().


Function Documentation

int ast_load_resource char *  resource_name  ) 
 

Loads a module.

Parameters:
resource_name the filename of the module to load This function is ran by the PBX to load the modules. It performs all loading, setting up of it's module related data structures, etc. Basically, to load a module, you just give it the name of the module and it will do the rest. It returns 0 on success, -1 on error
Definition at line 186 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, module::next, option_console, option_verbose, RTLD_GLOBAL, RTLD_LAZY, RTLD_NOW, term_color(), and VERBOSE_PREFIX_1.

Referenced by load_modules().

00187 { 00188 static char fn[256]; 00189 int errors=0; 00190 int res; 00191 struct module *m; 00192 int flags=RTLD_NOW; 00193 #ifdef RTLD_GLOBAL 00194 char *val; 00195 #endif 00196 char *key; 00197 int o; 00198 struct ast_config *cfg; 00199 char tmp[80]; 00200 /* Keep the module file parsing silent */ 00201 o = option_verbose; 00202 if (strncasecmp(resource_name, "res_", 4)) { 00203 option_verbose = 0; 00204 cfg = ast_load(AST_MODULE_CONFIG); 00205 option_verbose = o; 00206 if (cfg) { 00207 #ifdef RTLD_GLOBAL 00208 if ((val = ast_variable_retrieve(cfg, "global", resource_name)) 00209 && ast_true(val)) 00210 flags |= RTLD_GLOBAL; 00211 #endif 00212 ast_destroy(cfg); 00213 } 00214 } else { 00215 /* Resource modules are always loaded global and lazy */ 00216 #ifdef RTLD_GLOBAL 00217 flags = (RTLD_GLOBAL | RTLD_LAZY); 00218 #else 00219 flags = RTLD_LAZY; 00220 #endif 00221 } 00222 00223 if (ast_mutex_lock(&modlock)) 00224 ast_log(LOG_WARNING, "Failed to lock\n"); 00225 m = module_list; 00226 while(m) { 00227 if (!strcasecmp(m->resource, resource_name)) { 00228 ast_log(LOG_WARNING, "Module '%s' already exists\n", resource_name); 00229 ast_mutex_unlock(&modlock); 00230 return -1; 00231 } 00232 m = m->next; 00233 } 00234 m = malloc(sizeof(struct module)); 00235 if (!m) { 00236 ast_log(LOG_WARNING, "Out of memory\n"); 00237 ast_mutex_unlock(&modlock); 00238 return -1; 00239 } 00240 strncpy(m->resource, resource_name, sizeof(m->resource)-1); 00241 if (resource_name[0] == '/') { 00242 strncpy(fn, resource_name, sizeof(fn)-1); 00243 } else { 00244 snprintf(fn, sizeof(fn), "%s/%s", (char *)ast_config_AST_MODULE_DIR, resource_name); 00245 } 00246 m->lib = dlopen(fn, flags); 00247 if (!m->lib) { 00248 ast_log(LOG_WARNING, "%s\n", dlerror()); 00249 free(m); 00250 ast_mutex_unlock(&modlock); 00251 return -1; 00252 } 00253 m->load_module = dlsym(m->lib, "load_module"); 00254 if (m->load_module == NULL) 00255 m->load_module = dlsym(m->lib, "_load_module"); 00256 if (!m->load_module) { 00257 ast_log(LOG_WARNING, "No load_module in module %s\n", fn); 00258 errors++; 00259 } 00260 m->unload_module = dlsym(m->lib, "unload_module"); 00261 if (m->unload_module == NULL) 00262 m->unload_module = dlsym(m->lib, "_unload_module"); 00263 if (!m->unload_module) { 00264 ast_log(LOG_WARNING, "No unload_module in module %s\n", fn); 00265 errors++; 00266 } 00267 m->usecount = dlsym(m->lib, "usecount"); 00268 if (m->usecount == NULL) 00269 m->usecount = dlsym(m->lib, "_usecount"); 00270 if (!m->usecount) { 00271 ast_log(LOG_WARNING, "No usecount in module %s\n", fn); 00272 errors++; 00273 } 00274 m->description = dlsym(m->lib, "description"); 00275 if (m->description == NULL) 00276 m->description = dlsym(m->lib, "_description"); 00277 if (!m->description) { 00278 ast_log(LOG_WARNING, "No description in module %s\n", fn); 00279 errors++; 00280 } 00281 m->key = dlsym(m->lib, "key"); 00282 if (m->key == NULL) 00283 m->key = dlsym(m->lib, "_key"); 00284 if (!m->key) { 00285 ast_log(LOG_WARNING, "No key routine in module %s\n", fn); 00286 errors++; 00287 } 00288 m->reload = dlsym(m->lib, "reload"); 00289 if (m->reload == NULL) 00290 m->reload = dlsym(m->lib, "_reload"); 00291 if (!m->key || !(key = m->key())) { 00292 ast_log(LOG_WARNING, "Key routine returned NULL in module %s\n", fn); 00293 key = NULL; 00294 errors++; 00295 } 00296 if (key && verify_key(key)) { 00297 ast_log(LOG_WARNING, "Unexpected key returned by module %s\n", fn); 00298 errors++; 00299 } 00300 if (errors) { 00301 ast_log(LOG_WARNING, "%d error(s) loading module %s, aborted\n", errors, fn); 00302 dlclose(m->lib); 00303 free(m); 00304 ast_mutex_unlock(&modlock); 00305 return -1; 00306 } 00307 if (!fully_booted) { 00308 if (option_verbose) 00309 ast_verbose( " => (%s)\n", term_color(tmp, m->description(), COLOR_BROWN, COLOR_BLACK, sizeof(tmp))); 00310 if (option_console && !option_verbose) 00311 ast_verbose( "."); 00312 } else { 00313 if (option_verbose) 00314 ast_verbose(VERBOSE_PREFIX_1 "Loaded %s => (%s)\n", fn, m->description()); 00315 } 00316 00317 // add module 'm' to end of module_list chain 00318 // so reload commands will be issued in same order modules were loaded 00319 m->next = NULL; 00320 if (module_list == NULL) { 00321 // empty list so far, add at front 00322 module_list = m; 00323 } 00324 else { 00325 struct module *i; 00326 // find end of chain, and add there 00327 for (i = module_list; i->next; i = i->next) 00328 ; 00329 i->next = m; 00330 } 00331 00332 ast_mutex_unlock(&modlock); 00333 if ((res = m->load_module())) { 00334 ast_log(LOG_WARNING, "%s: load_module failed, returning %d\n", m->resource, res); 00335 ast_unload_resource(resource_name, 0); 00336 return -1; 00337 } 00338 ast_update_use_count(); 00339 return 0; 00340 }

int ast_loader_register int(*  updater)(void)  ) 
 

Ask this procedure to be run with modules have been updated.

Parameters:
updater the function to run when modules have been updated This function adds the given function to a linked list of functions to be run when the modules are updated. It returns 0 on success and -1 on failure.
Definition at line 479 of file loader.c.

References ast_log(), ast_mutex_lock, ast_mutex_unlock, LOG_WARNING, and malloc.

00480 { 00481 struct loadupdate *tmp; 00482 /* XXX Should be more flexible here, taking > 1 verboser XXX */ 00483 if ((tmp = malloc(sizeof (struct loadupdate)))) { 00484 tmp->updater = v; 00485 if (ast_mutex_lock(&modlock)) 00486 ast_log(LOG_WARNING, "Failed to lock\n"); 00487 tmp->next = updaters; 00488 updaters = tmp; 00489 ast_mutex_unlock(&modlock); 00490 return 0; 00491 } 00492 return -1; 00493 }

int ast_loader_unregister int(*  updater)(void)  ) 
 

No longer run me when modules are updated.

Parameters:
updater function to unregister This removes the given function from the updater list. It returns 0 on success, -1 on failure.
Definition at line 495 of file loader.c.

References ast_log(), ast_mutex_lock, ast_mutex_unlock, and LOG_WARNING.

00496 { 00497 int res = -1; 00498 struct loadupdate *tmp, *tmpl=NULL; 00499 if (ast_mutex_lock(&modlock)) 00500 ast_log(LOG_WARNING, "Failed to lock\n"); 00501 tmp = updaters; 00502 while(tmp) { 00503 if (tmp->updater == v) { 00504 if (tmpl) 00505 tmpl->next = tmp->next; 00506 else 00507 updaters = tmp->next; 00508 break; 00509 } 00510 tmpl = tmp; 00511 tmp = tmp->next; 00512 } 00513 if (tmp) 00514 res = 0; 00515 ast_mutex_unlock(&modlock); 00516 return res; 00517 }

void ast_module_reload const char *  name  ) 
 

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 150 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, read_ast_cust_config(), reload_manager(), and VERBOSE_PREFIX_3.

00151 { 00152 struct module *m; 00153 00154 /* We'll do the logger and manager the favor of calling its reload here first */ 00155 00156 if (ast_mutex_trylock(&reloadlock)) { 00157 ast_verbose("The previous reload command didn't finish yet\n"); 00158 return; 00159 } 00160 if (!name || !strcasecmp(name, "astconfig")) 00161 read_ast_cust_config(); 00162 if (!name || !strcasecmp(name, "manager")) 00163 reload_manager(); 00164 if (!name || !strcasecmp(name, "enum")) 00165 ast_enum_reload(); 00166 if (!name || !strcasecmp(name, "rtp")) 00167 ast_rtp_reload(); 00168 time(&ast_lastreloadtime); 00169 00170 ast_mutex_lock(&modlock); 00171 m = module_list; 00172 while(m) { 00173 if (!name || !strcasecmp(name, m->resource)) { 00174 if (m->reload) { 00175 if (option_verbose > 2) 00176 ast_verbose(VERBOSE_PREFIX_3 "Reloading module '%s' (%s)\n", m->resource, m->description()); 00177 m->reload(); 00178 } 00179 } 00180 m = m->next; 00181 } 00182 ast_mutex_unlock(&modlock); 00183 ast_mutex_unlock(&reloadlock); 00184 }

AST_MUTEX_DEFINE_STATIC reloadlock   ) 
 

AST_MUTEX_DEFINE_STATIC modlock   ) 
 

int ast_unload_resource char *  resource_name,
int  force
 

Unloads a module.

Parameters:
resourcename the name of the module to unload
force the force flag. Setting this to non-zero will force the module to be unloaded This function unloads a particular module. If the force flag is not set, it will not unload a module with a usecount > 0. However, if it is set, it will unload the module regardless of consequences (NOT_RECOMMENDED)
Definition at line 107 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().

00108 { 00109 struct module *m, *ml = NULL; 00110 int res = -1; 00111 if (ast_mutex_lock(&modlock)) 00112 ast_log(LOG_WARNING, "Failed to lock\n"); 00113 m = module_list; 00114 while(m) { 00115 if (!strcasecmp(m->resource, resource_name)) { 00116 if ((res = m->usecount()) > 0) { 00117 if (force) 00118 ast_log(LOG_WARNING, "Warning: Forcing removal of module %s with use count %d\n", resource_name, res); 00119 else { 00120 ast_log(LOG_WARNING, "Soft unload failed, '%s' has use count %d\n", resource_name, res); 00121 ast_mutex_unlock(&modlock); 00122 return -1; 00123 } 00124 } 00125 res = m->unload_module(); 00126 if (res) { 00127 ast_log(LOG_WARNING, "Firm unload failed for %s\n", resource_name); 00128 if (force <= AST_FORCE_FIRM) { 00129 ast_mutex_unlock(&modlock); 00130 return -1; 00131 } else 00132 ast_log(LOG_WARNING, "** Dangerous **: Unloading resource anyway, at user request\n"); 00133 } 00134 if (ml) 00135 ml->next = m->next; 00136 else 00137 module_list = m->next; 00138 dlclose(m->lib); 00139 free(m); 00140 break; 00141 } 00142 ml = m; 00143 m = m->next; 00144 } 00145 ast_mutex_unlock(&modlock); 00146 ast_update_use_count(); 00147 return res; 00148 }

int ast_update_module_list int(*  modentry)(char *module, char *description, int usecnt)  ) 
 

Ask for a list of modules, descriptions, and use counts.

Parameters:
modentry a callback to an updater function For each of the modules loaded, modentry will be executed with the resource, description, and usecount values of each particular module.
Definition at line 463 of file loader.c.

References ast_mutex_trylock, ast_mutex_unlock, and module::next.

00464 { 00465 struct module *m; 00466 int unlock = -1; 00467 if (ast_mutex_trylock(&modlock)) 00468 unlock = 0; 00469 m = module_list; 00470 while(m) { 00471 modentry(m->resource, m->description(), m->usecount()); 00472 m = m->next; 00473 } 00474 if (unlock) 00475 ast_mutex_unlock(&modlock); 00476 return 0; 00477 }

void ast_update_use_count void   ) 
 

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 447 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().

00448 { 00449 /* Notify any module monitors that the use count for a 00450 resource has changed */ 00451 struct loadupdate *m; 00452 if (ast_mutex_lock(&modlock)) 00453 ast_log(LOG_WARNING, "Failed to lock\n"); 00454 m = updaters; 00455 while(m) { 00456 m->updater(); 00457 m = m->next; 00458 } 00459 ast_mutex_unlock(&modlock); 00460 00461 }

int load_modules void   ) 
 

Definition at line 360 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().

00361 { 00362 struct ast_config *cfg; 00363 struct ast_variable *v; 00364 char tmp[80]; 00365 if (option_verbose) 00366 ast_verbose( "Asterisk Dynamic Loader Starting:\n"); 00367 cfg = ast_load(AST_MODULE_CONFIG); 00368 if (cfg) { 00369 /* Load explicitly defined modules */ 00370 v = ast_variable_browse(cfg, "modules"); 00371 while(v) { 00372 if (!strcasecmp(v->name, "load")) { 00373 if (option_debug && !option_verbose) 00374 ast_log(LOG_DEBUG, "Loading module %s\n", v->value); 00375 if (option_verbose) { 00376 ast_verbose( VERBOSE_PREFIX_1 "[%s]", term_color(tmp, v->value, COLOR_BRWHITE, 0, sizeof(tmp))); 00377 fflush(stdout); 00378 } 00379 if (ast_load_resource(v->value)) { 00380 ast_log(LOG_WARNING, "Loading module %s failed!\n", v->value); 00381 if (cfg) 00382 ast_destroy(cfg); 00383 return -1; 00384 } 00385 } 00386 v=v->next; 00387 } 00388 } 00389 if (!cfg || ast_true(ast_variable_retrieve(cfg, "modules", "autoload"))) { 00390 /* Load all modules */ 00391 DIR *mods; 00392 struct dirent *d; 00393 int x; 00394 /* Make two passes. First, load any resource modules, then load the others. */ 00395 for (x=0;x<2;x++) { 00396 mods = opendir((char *)ast_config_AST_MODULE_DIR); 00397 if (mods) { 00398 while((d = readdir(mods))) { 00399 /* Must end in .so to load it. */ 00400 if ((strlen(d->d_name) > 3) && (x || !strncasecmp(d->d_name, "res_", 4)) && 00401 !strcasecmp(d->d_name + strlen(d->d_name) - 3, ".so") && 00402 !ast_resource_exists(d->d_name)) { 00403 /* It's a shared library -- Just be sure we're allowed to load it -- kinda 00404 an inefficient way to do it, but oh well. */ 00405 if (cfg) { 00406 v = ast_variable_browse(cfg, "modules"); 00407 while(v) { 00408 if (!strcasecmp(v->name, "noload") && 00409 !strcasecmp(v->value, d->d_name)) 00410 break; 00411 v = v->next; 00412 } 00413 if (v) { 00414 if (option_verbose) { 00415 ast_verbose( VERBOSE_PREFIX_1 "[skipping %s]\n", d->d_name); 00416 fflush(stdout); 00417 } 00418 continue; 00419 } 00420 00421 } 00422 if (option_debug && !option_verbose) 00423 ast_log(LOG_DEBUG, "Loading module %s\n", d->d_name); 00424 if (option_verbose) { 00425 ast_verbose( VERBOSE_PREFIX_1 "[%s]", term_color(tmp, d->d_name, COLOR_BRWHITE, 0, sizeof(tmp))); 00426 fflush(stdout); 00427 } 00428 if (ast_load_resource(d->d_name)) { 00429 ast_log(LOG_WARNING, "Loading module %s failed!\n", d->d_name); 00430 if (cfg) 00431 ast_destroy(cfg); 00432 return -1; 00433 } 00434 } 00435 } 00436 closedir(mods); 00437 } else { 00438 if (!option_quiet) 00439 ast_log(LOG_WARNING, "Unable to open modules directory %s.\n", (char *)ast_config_AST_MODULE_DIR); 00440 } 00441 } 00442 } 00443 ast_destroy(cfg); 00444 return 0; 00445 }


Generated on Fri Sep 24 21:03:52 2004 for Asterisk by doxygen 1.3.8