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"

Include dependency graph for loader.c:

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.


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

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

int ast_loader_register ( int(*)(void)  updater  ) 

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

00491 {
00492    struct loadupdate *tmp;
00493    /* XXX Should be more flexible here, taking > 1 verboser XXX */
00494    if ((tmp = malloc(sizeof (struct loadupdate)))) {
00495       tmp->updater = v;
00496       if (ast_mutex_lock(&modlock))
00497          ast_log(LOG_WARNING, "Failed to lock\n");
00498       tmp->next = updaters;
00499       updaters = tmp;
00500       ast_mutex_unlock(&modlock);
00501       return 0;
00502    }
00503    return -1;
00504 }

int ast_loader_unregister ( int(*)(void)  updater  ) 

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

00507 {
00508    int res = -1;
00509    struct loadupdate *tmp, *tmpl=NULL;
00510    if (ast_mutex_lock(&modlock))
00511       ast_log(LOG_WARNING, "Failed to lock\n");
00512    tmp = updaters;
00513    while(tmp) {
00514       if (tmp->updater == v)  {
00515          if (tmpl)
00516             tmpl->next = tmp->next;
00517          else
00518             updaters = tmp->next;
00519          break;
00520       }
00521       tmpl = tmp;
00522       tmp = tmp->next;
00523    }
00524    if (tmp)
00525       res = 0;
00526    ast_mutex_unlock(&modlock);
00527    return res;
00528 }

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

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

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

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

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

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

00475 {
00476    struct module *m;
00477    int unlock = -1;
00478    if (ast_mutex_trylock(&modlock))
00479       unlock = 0;
00480    m = module_list;
00481    while(m) {
00482       modentry(m->resource, m->description(), m->usecount());
00483       m = m->next;
00484    }
00485    if (unlock)
00486       ast_mutex_unlock(&modlock);
00487    return 0;
00488 }

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

00459 {
00460    /* Notify any module monitors that the use count for a 
00461       resource has changed */
00462    struct loadupdate *m;
00463    if (ast_mutex_lock(&modlock))
00464       ast_log(LOG_WARNING, "Failed to lock\n");
00465    m = updaters;
00466    while(m) {
00467       m->updater();
00468       m = m->next;
00469    }
00470    ast_mutex_unlock(&modlock);
00471    
00472 }

int load_modules ( void   ) 

Definition at line 371 of file loader.c.

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


Generated on Wed Oct 28 17:00:56 2009 for Asterisk by  doxygen 1.5.6