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


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

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

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 473 of file loader.c.

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

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

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 489 of file loader.c.

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

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

void ast_module_reload void   ) 
 

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 read_ast_cust_config(); 00161 reload_manager(); 00162 ast_enum_reload(); 00163 ast_rtp_reload(); 00164 time(&ast_lastreloadtime); 00165 00166 ast_mutex_lock(&modlock); 00167 m = module_list; 00168 while(m) { 00169 if (m->reload) { 00170 if (option_verbose > 2) 00171 ast_verbose(VERBOSE_PREFIX_3 "Reloading module '%s' (%s)\n", m->resource, m->description()); 00172 m->reload(); 00173 } 00174 m = m->next; 00175 } 00176 ast_mutex_unlock(&modlock); 00177 ast_mutex_unlock(&reloadlock); 00178 }

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 457 of file loader.c.

References ast_mutex_trylock, ast_mutex_unlock, and module::next.

00458 { 00459 struct module *m; 00460 int unlock = -1; 00461 if (ast_mutex_trylock(&modlock)) 00462 unlock = 0; 00463 m = module_list; 00464 while(m) { 00465 modentry(m->resource, m->description(), m->usecount()); 00466 m = m->next; 00467 } 00468 if (unlock) 00469 ast_mutex_unlock(&modlock); 00470 return 0; 00471 }

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

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

int load_modules void   ) 
 

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

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


Generated on Tue Aug 17 16:13:55 2004 for Asterisk by doxygen 1.3.8