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  loadupdate
struct  module

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

void ast_module_reload (const char *name)
 Reload all modules. More...

int ast_load_resource (char *resource_name)
 Loads a module. More...

int load_modules ()
void ast_update_use_count (void)
 Notify when usecount has been changed. More...

int ast_update_module_list (int(*modentry)(char *module, char *description, int usecnt))
 Ask for a list of modules, descriptions, and use counts. More...

int ast_loader_register (int(*v)(void))
 Ask this procedure to be run with modules have been updated. More...

int ast_loader_unregister (int(*v)(void))
 No longer run me when modules are updated. More...


Define Documentation

#define RTLD_NOW   0
 

Definition at line 40 of file loader.c.

Referenced by ast_load_resource().


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_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, module::description, dlclose(), dlerror(), dlopen(), dlsym(), free, key(), module::key, module::lib, module::load_module, LOG_WARNING, malloc, module::next, module::reload, module::resource, RTLD_GLOBAL, RTLD_LAZY, RTLD_NOW, term_color(), module::unload_module, module::usecount, 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_mutex_lock, ast_mutex_trylock, ast_mutex_unlock, ast_rtp_reload(), ast_verbose(), module::description, module::next, read_ast_cust_config(), module::reload, reload_manager(), module::resource, 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, module::lib, LOG_WARNING, module::next, module::resource, module::unload_module, and module::usecount.

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, description(), module::description, module::next, module::resource, and module::usecount.

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_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, ast_variable::name, ast_variable::next, term_color(), ast_variable::value, 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 Thu Oct 28 11:33:03 2004 for Asterisk by doxygen1.2.15