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


Define Documentation

#define RTLD_NOW   0
 

Definition at line 39 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 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 }  

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 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 }

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 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 }

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 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 }

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 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 }

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 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 }

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 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 }

int load_modules void   ) 
 

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 }


Generated on Fri Feb 27 12:19:49 2004 for Asterisk by doxygen 1.3.5