Thu May 14 14:49:04 2009

Asterisk developer's documentation


loader.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 1999 - 2006, Digium, Inc.
00005  *
00006  * Mark Spencer <markster@digium.com>
00007  * Kevin P. Fleming <kpfleming@digium.com>
00008  * Luigi Rizzo <rizzo@icir.org>
00009  *
00010  * See http://www.asterisk.org for more information about
00011  * the Asterisk project. Please do not directly contact
00012  * any of the maintainers of this project for assistance;
00013  * the project provides a web site, mailing lists and IRC
00014  * channels for your use.
00015  *
00016  * This program is free software, distributed under the terms of
00017  * the GNU General Public License Version 2. See the LICENSE file
00018  * at the top of the source tree.
00019  */
00020 
00021 /*! \file
00022  *
00023  * \brief Module Loader
00024  * \author Mark Spencer <markster@digium.com>
00025  * \author Kevin P. Fleming <kpfleming@digium.com>
00026  * \author Luigi Rizzo <rizzo@icir.org>
00027  * - See ModMngMnt
00028  */
00029 
00030 #include "asterisk.h"
00031 
00032 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 131921 $")
00033 
00034 #include <stdio.h>
00035 #include <dirent.h>
00036 #include <unistd.h>
00037 #include <stdlib.h>
00038 #include <errno.h>
00039 #include <string.h>
00040 
00041 #include "asterisk/linkedlists.h"
00042 #include "asterisk/module.h"
00043 #include "asterisk/options.h"
00044 #include "asterisk/config.h"
00045 #include "asterisk/logger.h"
00046 #include "asterisk/channel.h"
00047 #include "asterisk/term.h"
00048 #include "asterisk/manager.h"
00049 #include "asterisk/cdr.h"
00050 #include "asterisk/enum.h"
00051 #include "asterisk/rtp.h"
00052 #include "asterisk/http.h"
00053 #include "asterisk/lock.h"
00054 
00055 #include <dlfcn.h>
00056 
00057 #include "asterisk/md5.h"
00058 #include "asterisk/utils.h"
00059 
00060 #ifndef RTLD_NOW
00061 #define RTLD_NOW 0
00062 #endif
00063 
00064 struct ast_module_user {
00065    struct ast_channel *chan;
00066    AST_LIST_ENTRY(ast_module_user) entry;
00067 };
00068 
00069 AST_LIST_HEAD(module_user_list, ast_module_user);
00070 
00071 static unsigned char expected_key[] =
00072 { 0x87, 0x76, 0x79, 0x35, 0x23, 0xea, 0x3a, 0xd3,
00073   0x25, 0x2a, 0xbb, 0x35, 0x87, 0xe4, 0x22, 0x24 };
00074 
00075 static char buildopt_sum[33] = AST_BUILDOPT_SUM;
00076 
00077 static unsigned int embedding = 1; /* we always start out by registering embedded modules,
00078                   since they are here before we dlopen() any
00079                */
00080 
00081 struct ast_module {
00082    const struct ast_module_info *info;
00083    void *lib;              /* the shared lib, or NULL if embedded */
00084    int usecount;              /* the number of 'users' currently in this module */
00085    struct module_user_list users;         /* the list of users in the module */
00086    struct {
00087       unsigned int running:1;
00088       unsigned int declined:1;
00089    } flags;
00090    AST_LIST_ENTRY(ast_module) entry;
00091    char resource[0];
00092 };
00093 
00094 static AST_LIST_HEAD_STATIC(module_list, ast_module);
00095 
00096 struct loadupdate {
00097    int (*updater)(void);
00098    AST_LIST_ENTRY(loadupdate) entry;
00099 };
00100 
00101 static AST_LIST_HEAD_STATIC(updaters, loadupdate);
00102 
00103 AST_MUTEX_DEFINE_STATIC(reloadlock);
00104 
00105 /* when dynamic modules are being loaded, ast_module_register() will
00106    need to know what filename the module was loaded from while it
00107    is being registered
00108 */
00109 struct ast_module *resource_being_loaded;
00110 
00111 /* XXX: should we check for duplicate resource names here? */
00112 
00113 void ast_module_register(const struct ast_module_info *info)
00114 {
00115    struct ast_module *mod;
00116 
00117    if (embedding) {
00118       if (!(mod = ast_calloc(1, sizeof(*mod) + strlen(info->name) + 1)))
00119          return;
00120       strcpy(mod->resource, info->name);
00121    } else {
00122       mod = resource_being_loaded;
00123    }
00124 
00125    mod->info = info;
00126    AST_LIST_HEAD_INIT(&mod->users);
00127 
00128    /* during startup, before the loader has been initialized,
00129       there are no threads, so there is no need to take the lock
00130       on this list to manipulate it. it is also possible that it
00131       might be unsafe to use the list lock at that point... so
00132       let's avoid it altogether
00133    */
00134    if (!embedding)
00135       AST_LIST_LOCK(&module_list);
00136 
00137    /* it is paramount that the new entry be placed at the tail of
00138       the list, otherwise the code that uses dlopen() to load
00139       dynamic modules won't be able to find out if the module it
00140       just opened was registered or failed to load
00141    */
00142    AST_LIST_INSERT_TAIL(&module_list, mod, entry);
00143 
00144    if (!embedding)
00145       AST_LIST_UNLOCK(&module_list);
00146 
00147    /* give the module a copy of its own handle, for later use in registrations and the like */
00148    *((struct ast_module **) &(info->self)) = mod;
00149 }
00150 
00151 void ast_module_unregister(const struct ast_module_info *info)
00152 {
00153    struct ast_module *mod = NULL;
00154 
00155    /* it is assumed that the users list in the module structure
00156       will already be empty, or we cannot have gotten to this
00157       point
00158    */
00159    AST_LIST_LOCK(&module_list);
00160    AST_LIST_TRAVERSE_SAFE_BEGIN(&module_list, mod, entry) {
00161       if (mod->info == info) {
00162          AST_LIST_REMOVE_CURRENT(&module_list, entry);
00163          break;
00164       }
00165    }
00166    AST_LIST_TRAVERSE_SAFE_END;
00167    AST_LIST_UNLOCK(&module_list);
00168 
00169    if (mod) {
00170       AST_LIST_HEAD_DESTROY(&mod->users);
00171       free(mod);
00172    }
00173 }
00174 
00175 struct ast_module_user *__ast_module_user_add(struct ast_module *mod,
00176                      struct ast_channel *chan)
00177 {
00178    struct ast_module_user *u = ast_calloc(1, sizeof(*u));
00179 
00180    if (!u)
00181       return NULL;
00182 
00183    u->chan = chan;
00184 
00185    AST_LIST_LOCK(&mod->users);
00186    AST_LIST_INSERT_HEAD(&mod->users, u, entry);
00187    AST_LIST_UNLOCK(&mod->users);
00188 
00189    ast_atomic_fetchadd_int(&mod->usecount, +1);
00190 
00191    ast_update_use_count();
00192 
00193    return u;
00194 }
00195 
00196 void __ast_module_user_remove(struct ast_module *mod, struct ast_module_user *u)
00197 {
00198    AST_LIST_LOCK(&mod->users);
00199    AST_LIST_REMOVE(&mod->users, u, entry);
00200    AST_LIST_UNLOCK(&mod->users);
00201    ast_atomic_fetchadd_int(&mod->usecount, -1);
00202    free(u);
00203 
00204    ast_update_use_count();
00205 }
00206 
00207 void __ast_module_user_hangup_all(struct ast_module *mod)
00208 {
00209    struct ast_module_user *u;
00210 
00211    AST_LIST_LOCK(&mod->users);
00212    while ((u = AST_LIST_REMOVE_HEAD(&mod->users, entry))) {
00213       ast_softhangup(u->chan, AST_SOFTHANGUP_APPUNLOAD);
00214       ast_atomic_fetchadd_int(&mod->usecount, -1);
00215       free(u);
00216    }
00217    AST_LIST_UNLOCK(&mod->users);
00218 
00219         ast_update_use_count();
00220 }
00221 
00222 /*! \note
00223  * In addition to modules, the reload command handles some extra keywords
00224  * which are listed here together with the corresponding handlers.
00225  * This table is also used by the command completion code.
00226  */
00227 static struct reload_classes {
00228    const char *name;
00229    int (*reload_fn)(void);
00230 } reload_classes[] = {  /* list in alpha order, longest match first for cli completion */
00231    { "cdr", ast_cdr_engine_reload },
00232    { "dnsmgr", dnsmgr_reload },
00233    { "extconfig", read_config_maps },
00234    { "enum",   ast_enum_reload },
00235    { "manager",   reload_manager },
00236    { "rtp", ast_rtp_reload },
00237    { "http",   ast_http_reload },
00238    { "logger", logger_reload },
00239    { NULL,  NULL }
00240 };
00241 
00242 static int printdigest(const unsigned char *d)
00243 {
00244    int x, pos;
00245    char buf[256]; /* large enough so we don't have to worry */
00246 
00247    for (pos = 0, x = 0; x < 16; x++)
00248       pos += sprintf(buf + pos, " %02x", *d++);
00249 
00250    ast_log(LOG_DEBUG, "Unexpected signature:%s\n", buf);
00251 
00252    return 0;
00253 }
00254 
00255 static int key_matches(const unsigned char *key1, const unsigned char *key2)
00256 {
00257    int x;
00258 
00259    for (x = 0; x < 16; x++) {
00260       if (key1[x] != key2[x])
00261          return 0;
00262    }
00263 
00264    return 1;
00265 }
00266 
00267 static int verify_key(const unsigned char *key)
00268 {
00269    struct MD5Context c;
00270    unsigned char digest[16];
00271 
00272    MD5Init(&c);
00273    MD5Update(&c, key, strlen((char *)key));
00274    MD5Final(digest, &c);
00275 
00276    if (key_matches(expected_key, digest))
00277       return 0;
00278 
00279    printdigest(digest);
00280 
00281    return -1;
00282 }
00283 
00284 static int resource_name_match(const char *name1_in, const char *name2_in)
00285 {
00286    char *name1 = (char *) name1_in;
00287    char *name2 = (char *) name2_in;
00288 
00289    /* trim off any .so extensions */
00290    if (!strcasecmp(name1 + strlen(name1) - 3, ".so")) {
00291       name1 = ast_strdupa(name1);
00292       name1[strlen(name1) - 3] = '\0';
00293    }
00294    if (!strcasecmp(name2 + strlen(name2) - 3, ".so")) {
00295       name2 = ast_strdupa(name2);
00296       name2[strlen(name2) - 3] = '\0';
00297    }
00298 
00299    return strcasecmp(name1, name2);
00300 }
00301 
00302 static struct ast_module *find_resource(const char *resource, int do_lock)
00303 {
00304    struct ast_module *cur;
00305 
00306    if (do_lock)
00307       AST_LIST_LOCK(&module_list);
00308 
00309    AST_LIST_TRAVERSE(&module_list, cur, entry) {
00310       if (!resource_name_match(resource, cur->resource))
00311          break;
00312    }
00313 
00314    if (do_lock)
00315       AST_LIST_UNLOCK(&module_list);
00316 
00317    return cur;
00318 }
00319 
00320 #ifdef LOADABLE_MODULES
00321 static void unload_dynamic_module(struct ast_module *mod)
00322 {
00323    void *lib = mod->lib;
00324 
00325    /* WARNING: the structure pointed to by mod is going to
00326       disappear when this operation succeeds, so we can't
00327       dereference it */
00328 
00329    if (lib)
00330       while (!dlclose(lib));
00331 }
00332 
00333 static struct ast_module *load_dynamic_module(const char *resource_in, unsigned int global_symbols_only)
00334 {
00335    char fn[256];
00336    void *lib;
00337    struct ast_module *mod;
00338    char *resource = (char *) resource_in;
00339    unsigned int wants_global;
00340 
00341    if (strcasecmp(resource + strlen(resource) - 3, ".so")) {
00342       resource = alloca(strlen(resource_in) + 3);
00343            strcpy(resource, resource_in);
00344       strcat(resource, ".so");
00345    }
00346 
00347    snprintf(fn, sizeof(fn), "%s/%s", ast_config_AST_MODULE_DIR, resource);
00348 
00349    /* make a first load of the module in 'quiet' mode... don't try to resolve
00350       any symbols, and don't export any symbols. this will allow us to peek into
00351       the module's info block (if available) to see what flags it has set */
00352 
00353    if (!(resource_being_loaded = ast_calloc(1, sizeof(*resource_being_loaded) + strlen(resource) + 1)))
00354       return NULL;
00355 
00356    strcpy(resource_being_loaded->resource, resource);
00357 
00358    /* libopenh323 is buggy and segfaults on dlclose() when opened with
00359     * RTLD_LAZY. Workaround this until it gets fixed */
00360    if (!strcasecmp(resource, "chan_h323.so") ||
00361          !strcasecmp(resource, "chan_oh323.so"))
00362          lib = dlopen(fn, RTLD_NOW | RTLD_LOCAL);
00363 
00364    if (!(lib = dlopen(fn, RTLD_LAZY | RTLD_LOCAL))) {
00365       ast_log(LOG_WARNING, "Error loading module '%s': %s\n", resource_in, dlerror());
00366       free(resource_being_loaded);
00367       return NULL;
00368    }
00369 
00370    /* the dlopen() succeeded, let's find out if the module
00371       registered itself */
00372    /* note that this will only work properly as long as
00373       ast_module_register() (which is called by the module's
00374       constructor) places the new module at the tail of the
00375       module_list
00376    */
00377    if (resource_being_loaded != (mod = AST_LIST_LAST(&module_list))) {
00378       ast_log(LOG_WARNING, "Module '%s' did not register itself during load\n", resource_in);
00379       /* no, it did not, so close it and return */
00380       while (!dlclose(lib));
00381       /* note that the module's destructor will call ast_module_unregister(),
00382          which will free the structure we allocated in resource_being_loaded */
00383       return NULL;
00384    }
00385 
00386    wants_global = ast_test_flag(mod->info, AST_MODFLAG_GLOBAL_SYMBOLS);
00387 
00388    /* if we are being asked only to load modules that provide global symbols,
00389       and this one does not, then close it and return */
00390    if (global_symbols_only && !wants_global) {
00391       while (!dlclose(lib));
00392       return NULL;
00393    }
00394 
00395    /* if the system supports RTLD_NOLOAD, we can just 'promote' the flags
00396       on the already-opened library to what we want... if not, we have to
00397       close it and start over
00398    */
00399 #if defined(HAVE_RTLD_NOLOAD) && !defined(__Darwin__)
00400    if (!dlopen(fn, RTLD_NOLOAD | (wants_global ? RTLD_LAZY | RTLD_GLOBAL : RTLD_NOW | RTLD_LOCAL))) {
00401       ast_log(LOG_WARNING, "Unable to promote flags on module '%s': %s\n", resource_in, dlerror());
00402       while (!dlclose(lib));
00403       free(resource_being_loaded);
00404       return NULL;
00405    }
00406 #else
00407    while (!dlclose(lib));
00408    resource_being_loaded = NULL;
00409 
00410    /* start the load process again */
00411 
00412    if (!(resource_being_loaded = ast_calloc(1, sizeof(*resource_being_loaded) + strlen(resource) + 1)))
00413       return NULL;
00414 
00415    strcpy(resource_being_loaded->resource, resource);
00416 
00417    if (!(lib = dlopen(fn, wants_global ? RTLD_LAZY | RTLD_GLOBAL : RTLD_NOW | RTLD_LOCAL))) {
00418       ast_log(LOG_WARNING, "Error loading module '%s': %s\n", resource_in, dlerror());
00419       free(resource_being_loaded);
00420       return NULL;
00421    }
00422 
00423    /* since the module was successfully opened, and it registered itself
00424       the previous time we did that, we're going to assume it worked this
00425       time too :) */
00426 #endif
00427 
00428    AST_LIST_LAST(&module_list)->lib = lib;
00429    resource_being_loaded = NULL;
00430 
00431    return AST_LIST_LAST(&module_list);
00432 }
00433 #endif
00434 
00435 void ast_module_shutdown(void)
00436 {
00437    struct ast_module *mod;
00438    AST_LIST_HEAD_NOLOCK_STATIC(local_module_list, ast_module);
00439 
00440    /* We have to call the unload() callbacks in reverse order that the modules
00441     * exist in the module list so it is the reverse order of how they were
00442     * loaded. */
00443 
00444    AST_LIST_LOCK(&module_list);
00445    while ((mod = AST_LIST_REMOVE_HEAD(&module_list, entry)))
00446       AST_LIST_INSERT_HEAD(&local_module_list, mod, entry);
00447    AST_LIST_UNLOCK(&module_list);
00448 
00449    while ((mod = AST_LIST_REMOVE_HEAD(&local_module_list, entry))) {
00450       if (mod->info->unload)
00451          mod->info->unload();
00452       /* Since this should only be called when shutting down "gracefully",
00453        * all channels should be down before we get to this point, meaning
00454        * there will be no module users left. */
00455       AST_LIST_HEAD_DESTROY(&mod->users);
00456       free(mod);
00457    }
00458 }
00459 
00460 int ast_unload_resource(const char *resource_name, enum ast_module_unload_mode force)
00461 {
00462    struct ast_module *mod;
00463    int res = -1;
00464    int error = 0;
00465 
00466    AST_LIST_LOCK(&module_list);
00467 
00468    if (!(mod = find_resource(resource_name, 0))) {
00469       AST_LIST_UNLOCK(&module_list);
00470       return 0;
00471    }
00472 
00473    if (!(mod->flags.running || mod->flags.declined))
00474       error = 1;
00475 
00476    if (!mod->lib) {
00477       ast_log(LOG_WARNING, "Unloading embedded modules is not supported.\n");
00478       error = 1;
00479    }
00480 
00481    if (!error && (mod->usecount > 0)) {
00482       if (force)
00483          ast_log(LOG_WARNING, "Warning:  Forcing removal of module '%s' with use count %d\n",
00484             resource_name, mod->usecount);
00485       else {
00486          ast_log(LOG_WARNING, "Soft unload failed, '%s' has use count %d\n", resource_name,
00487             mod->usecount);
00488          error = 1;
00489       }
00490    }
00491 
00492    if (!error) {
00493       __ast_module_user_hangup_all(mod);
00494       res = mod->info->unload();
00495 
00496       if (res) {
00497          ast_log(LOG_WARNING, "Firm unload failed for %s\n", resource_name);
00498          if (force <= AST_FORCE_FIRM)
00499             error = 1;
00500          else
00501             ast_log(LOG_WARNING, "** Dangerous **: Unloading resource anyway, at user request\n");
00502       }
00503    }
00504 
00505    if (!error)
00506       mod->flags.running = mod->flags.declined = 0;
00507 
00508    AST_LIST_UNLOCK(&module_list);
00509 
00510 #ifdef LOADABLE_MODULES
00511    if (!error)
00512       unload_dynamic_module(mod);
00513 #endif
00514 
00515    if (!error)
00516       ast_update_use_count();
00517 
00518    return res;
00519 }
00520 
00521 char *ast_module_helper(const char *line, const char *word, int pos, int state, int rpos, int needsreload)
00522 {
00523    struct ast_module *cur;
00524    int i, which=0, l = strlen(word);
00525    char *ret = NULL;
00526 
00527    if (pos != rpos)
00528       return NULL;
00529 
00530    AST_LIST_LOCK(&module_list);
00531    AST_LIST_TRAVERSE(&module_list, cur, entry) {
00532       if (!strncasecmp(word, cur->resource, l) &&
00533           (cur->info->reload || !needsreload) &&
00534           ++which > state) {
00535          ret = strdup(cur->resource);
00536          break;
00537       }
00538    }
00539    AST_LIST_UNLOCK(&module_list);
00540 
00541    if (!ret) {
00542       for (i=0; !ret && reload_classes[i].name; i++) {
00543          if (!strncasecmp(word, reload_classes[i].name, l) && ++which > state)
00544             ret = strdup(reload_classes[i].name);
00545       }
00546    }
00547 
00548    return ret;
00549 }
00550 
00551 int ast_module_reload(const char *name)
00552 {
00553    struct ast_module *cur;
00554    int res = 0; /* return value. 0 = not found, others, see below */
00555    int i;
00556 
00557    if (ast_mutex_trylock(&reloadlock)) {
00558       ast_verbose("The previous reload command didn't finish yet\n");
00559       return -1;  /* reload already in progress */
00560    }
00561    ast_lastreloadtime = time(NULL);
00562 
00563    /* Call "predefined" reload here first */
00564    for (i = 0; reload_classes[i].name; i++) {
00565       if (!name || !strcasecmp(name, reload_classes[i].name)) {
00566          reload_classes[i].reload_fn();   /* XXX should check error ? */
00567          res = 2; /* found and reloaded */
00568       }
00569    }
00570 
00571    if (name && res) {
00572       ast_mutex_unlock(&reloadlock);
00573       return res;
00574    }
00575 
00576    AST_LIST_LOCK(&module_list);
00577    AST_LIST_TRAVERSE(&module_list, cur, entry) {
00578       const struct ast_module_info *info = cur->info;
00579 
00580       if (name && resource_name_match(name, cur->resource))
00581          continue;
00582 
00583       if (!cur->flags.running || cur->flags.declined) {
00584          if (!name)
00585             continue;
00586          ast_log(LOG_NOTICE, "The module '%s' was not properly initialized.  "
00587             "Before reloading the module, you must run \"module load %s\" "
00588             "and fix whatever is preventing the module from being initialized.\n",
00589             name, name);
00590          res = 2; /* Don't report that the module was not found */
00591          break;
00592       }
00593 
00594       if (!info->reload) { /* cannot be reloaded */
00595          if (res < 1)   /* store result if possible */
00596             res = 1; /* 1 = no reload() method */
00597          continue;
00598       }
00599 
00600       res = 2;
00601       if (option_verbose > 2)
00602          ast_verbose(VERBOSE_PREFIX_3 "Reloading module '%s' (%s)\n", cur->resource, info->description);
00603       info->reload();
00604    }
00605    AST_LIST_UNLOCK(&module_list);
00606 
00607    ast_mutex_unlock(&reloadlock);
00608 
00609    return res;
00610 }
00611 
00612 static unsigned int inspect_module(const struct ast_module *mod)
00613 {
00614    if (!mod->info->description) {
00615       ast_log(LOG_WARNING, "Module '%s' does not provide a description.\n", mod->resource);
00616       return 1;
00617    }
00618 
00619    if (!mod->info->key) {
00620       ast_log(LOG_WARNING, "Module '%s' does not provide a license key.\n", mod->resource);
00621       return 1;
00622    }
00623 
00624    if (verify_key((unsigned char *) mod->info->key)) {
00625       ast_log(LOG_WARNING, "Module '%s' did not provide a valid license key.\n", mod->resource);
00626       return 1;
00627    }
00628 
00629    if (!ast_test_flag(mod->info, AST_MODFLAG_BUILDSUM)) {
00630       ast_log(LOG_WARNING, "Module '%s' was not compiled against a recent version of Asterisk and may cause instability.\n", mod->resource);
00631    } else if (!ast_strlen_zero(mod->info->buildopt_sum) &&
00632          strcmp(buildopt_sum, mod->info->buildopt_sum)) {
00633       ast_log(LOG_WARNING, "Module '%s' was not compiled with the same compile-time options as this version of Asterisk.\n", mod->resource);
00634       ast_log(LOG_WARNING, "Module '%s' will not be initialized as it may cause instability.\n", mod->resource);
00635       return 1;
00636    }
00637 
00638    return 0;
00639 }
00640 
00641 static enum ast_module_load_result load_resource(const char *resource_name, unsigned int global_symbols_only)
00642 {
00643    struct ast_module *mod;
00644    enum ast_module_load_result res = AST_MODULE_LOAD_SUCCESS;
00645    char tmp[256];
00646 
00647    if ((mod = find_resource(resource_name, 0))) {
00648       if (mod->flags.running) {
00649          ast_log(LOG_WARNING, "Module '%s' already exists.\n", resource_name);
00650          return AST_MODULE_LOAD_DECLINE;
00651       }
00652       if (global_symbols_only && !ast_test_flag(mod->info, AST_MODFLAG_GLOBAL_SYMBOLS))
00653          return AST_MODULE_LOAD_SKIP;
00654    } else {
00655 #ifdef LOADABLE_MODULES
00656       if (!(mod = load_dynamic_module(resource_name, global_symbols_only))) {
00657          /* don't generate a warning message during load_modules() */
00658          if (!global_symbols_only) {
00659             ast_log(LOG_WARNING, "Module '%s' could not be loaded.\n", resource_name);
00660             return AST_MODULE_LOAD_DECLINE;
00661          } else {
00662             return AST_MODULE_LOAD_SKIP;
00663          }
00664       }
00665 #else
00666       ast_log(LOG_WARNING, "Module '%s' could not be loaded.\n", resource_name);
00667       return AST_MODULE_LOAD_DECLINE;
00668 #endif
00669    }
00670 
00671    if (inspect_module(mod)) {
00672       ast_log(LOG_WARNING, "Module '%s' could not be loaded.\n", resource_name);
00673 #ifdef LOADABLE_MODULES
00674       unload_dynamic_module(mod);
00675 #endif
00676       return AST_MODULE_LOAD_DECLINE;
00677    }
00678 
00679    mod->flags.declined = 0;
00680 
00681    if (mod->info->load)
00682       res = mod->info->load();
00683 
00684    switch (res) {
00685    case AST_MODULE_LOAD_SUCCESS:
00686       if (!ast_fully_booted) {
00687          if (option_verbose)
00688             ast_verbose("%s => (%s)\n", resource_name, term_color(tmp, mod->info->description, COLOR_BROWN, COLOR_BLACK, sizeof(tmp)));
00689          if (ast_opt_console && !option_verbose)
00690             ast_verbose( ".");
00691       } else {
00692          if (option_verbose)
00693             ast_verbose(VERBOSE_PREFIX_1 "Loaded %s => (%s)\n", resource_name, mod->info->description);
00694       }
00695 
00696       mod->flags.running = 1;
00697 
00698       ast_update_use_count();
00699       break;
00700    case AST_MODULE_LOAD_DECLINE:
00701       mod->flags.declined = 1;
00702       break;
00703    case AST_MODULE_LOAD_FAILURE:
00704       break;
00705    case AST_MODULE_LOAD_SKIP:
00706       /* modules should never return this value */
00707       break;
00708    }
00709 
00710    return res;
00711 }
00712 
00713 int ast_load_resource(const char *resource_name)
00714 {
00715        AST_LIST_LOCK(&module_list);
00716        load_resource(resource_name, 0);
00717        AST_LIST_UNLOCK(&module_list);
00718 
00719        return 0;
00720 }
00721 
00722 struct load_order_entry {
00723    char *resource;
00724    AST_LIST_ENTRY(load_order_entry) entry;
00725 };
00726 
00727 AST_LIST_HEAD_NOLOCK(load_order, load_order_entry);
00728 
00729 static struct load_order_entry *add_to_load_order(const char *resource, struct load_order *load_order)
00730 {
00731    struct load_order_entry *order;
00732 
00733    AST_LIST_TRAVERSE(load_order, order, entry) {
00734       if (!resource_name_match(order->resource, resource))
00735          return NULL;
00736    }
00737 
00738    if (!(order = ast_calloc(1, sizeof(*order))))
00739       return NULL;
00740 
00741    order->resource = ast_strdup(resource);
00742    AST_LIST_INSERT_TAIL(load_order, order, entry);
00743 
00744    return order;
00745 }
00746 
00747 static int translate_module_name(char *oldname, char *newname)
00748 {
00749    if (!strcasecmp(oldname, "app_zapbarge.so"))
00750       ast_copy_string(newname, "app_dahdibarge.so", 18);
00751    else if(!strcasecmp(oldname, "app_zapras.so"))
00752       ast_copy_string(newname, "app_dahdiras.so", 16);
00753    else if(!strcasecmp(oldname, "app_zapscan.so"))
00754       ast_copy_string(newname, "app_dahdiscan.so", 17);
00755    else if(!strcasecmp(oldname, "codec_zap.so"))
00756       ast_copy_string(newname, "codec_dahdi.so", 16);
00757    else
00758       return -1; /* no use for newname, oldname is fine */
00759 
00760    return 0;
00761 }
00762       
00763 
00764 int load_modules(unsigned int preload_only)
00765 {
00766    struct ast_config *cfg;
00767    struct ast_module *mod;
00768    struct load_order_entry *order;
00769    struct ast_variable *v;
00770    unsigned int load_count;
00771    struct load_order load_order;
00772    int res = 0;
00773 
00774    int translate_status;
00775    char newname[18]; /* although this would normally be 80, max length in translate_module_name is 18 */
00776 #ifdef LOADABLE_MODULES
00777    struct dirent *dirent;
00778    DIR *dir;
00779 #endif
00780 
00781    /* all embedded modules have registered themselves by now */
00782    embedding = 0;
00783 
00784    if (option_verbose)
00785       ast_verbose("Asterisk Dynamic Loader Starting:\n");
00786 
00787    AST_LIST_HEAD_INIT_NOLOCK(&load_order);
00788 
00789    AST_LIST_LOCK(&module_list);
00790 
00791    if (!(cfg = ast_config_load(AST_MODULE_CONFIG))) {
00792       ast_log(LOG_WARNING, "No '%s' found, no modules will be loaded.\n", AST_MODULE_CONFIG);
00793       goto done;
00794    }
00795 
00796    /* first, find all the modules we have been explicitly requested to load */
00797    for (v = ast_variable_browse(cfg, "modules"); v; v = v->next) {
00798       if (!strcasecmp(v->name, preload_only ? "preload" : "load")) {
00799          translate_status = translate_module_name(v->value, newname);
00800             if (!translate_status)
00801                ast_log(LOG_WARNING, "Use of old module name %s is deprecated, please use %s instead.\n", v->value, newname);
00802          add_to_load_order(translate_status ? v->value : newname, &load_order);
00803       }
00804    }
00805 
00806    /* check if 'autoload' is on */
00807    if (!preload_only && ast_true(ast_variable_retrieve(cfg, "modules", "autoload"))) {
00808       /* if so, first add all the embedded modules that are not already running to the load order */
00809       AST_LIST_TRAVERSE(&module_list, mod, entry) {
00810          /* if it's not embedded, skip it */
00811          if (mod->lib)
00812             continue;
00813 
00814          if (mod->flags.running)
00815             continue;
00816 
00817          order = add_to_load_order(mod->resource, &load_order);
00818       }
00819 
00820 #ifdef LOADABLE_MODULES
00821       /* if we are allowed to load dynamic modules, scan the directory for
00822          for all available modules and add them as well */
00823       if ((dir  = opendir(ast_config_AST_MODULE_DIR))) {
00824          while ((dirent = readdir(dir))) {
00825             int ld = strlen(dirent->d_name);
00826 
00827             /* Must end in .so to load it.  */
00828 
00829             if (ld < 4)
00830                continue;
00831 
00832             if (strcasecmp(dirent->d_name + ld - 3, ".so"))
00833                continue;
00834 
00835             /* if there is already a module by this name in the module_list,
00836                skip this file */
00837             if (find_resource(dirent->d_name, 0))
00838                continue;
00839 
00840             add_to_load_order(dirent->d_name, &load_order);
00841          }
00842 
00843          closedir(dir);
00844       } else {
00845          if (!ast_opt_quiet)
00846             ast_log(LOG_WARNING, "Unable to open modules directory '%s'.\n",
00847                ast_config_AST_MODULE_DIR);
00848       }
00849 #endif
00850    }
00851 
00852    /* now scan the config for any modules we are prohibited from loading and
00853       remove them from the load order */
00854    for (v = ast_variable_browse(cfg, "modules"); v; v = v->next) {
00855       if (strcasecmp(v->name, "noload"))
00856          continue;
00857 
00858       AST_LIST_TRAVERSE_SAFE_BEGIN(&load_order, order, entry) {
00859          translate_status = translate_module_name(v->value, newname);
00860          if (!resource_name_match(order->resource, translate_status ? v->value : newname)) {
00861                if (!translate_status)
00862                   ast_log(LOG_WARNING, "Use of old module name %s is deprecated, please use %s instead.\n", v->value, newname);
00863             AST_LIST_REMOVE_CURRENT(&load_order, entry);
00864             free(order->resource);
00865             free(order);
00866          }
00867       }
00868       AST_LIST_TRAVERSE_SAFE_END;
00869    }
00870 
00871    /* we are done with the config now, all the information we need is in the
00872       load_order list */
00873    ast_config_destroy(cfg);
00874 
00875    load_count = 0;
00876    AST_LIST_TRAVERSE(&load_order, order, entry)
00877       load_count++;
00878 
00879    if (load_count)
00880       ast_log(LOG_NOTICE, "%d modules will be loaded.\n", load_count);
00881 
00882    /* first, load only modules that provide global symbols */
00883    AST_LIST_TRAVERSE_SAFE_BEGIN(&load_order, order, entry) {
00884       switch (load_resource(order->resource, 1)) {
00885       case AST_MODULE_LOAD_SUCCESS:
00886       case AST_MODULE_LOAD_DECLINE:
00887          AST_LIST_REMOVE_CURRENT(&load_order, entry);
00888          free(order->resource);
00889          free(order);
00890          break;
00891       case AST_MODULE_LOAD_FAILURE:
00892          res = -1;
00893          goto done;
00894       case AST_MODULE_LOAD_SKIP:
00895          /* try again later */
00896          break;
00897       }
00898    }
00899    AST_LIST_TRAVERSE_SAFE_END;
00900 
00901    /* now load everything else */
00902    AST_LIST_TRAVERSE_SAFE_BEGIN(&load_order, order, entry) {
00903       switch (load_resource(order->resource, 0)) {
00904       case AST_MODULE_LOAD_SUCCESS:
00905       case AST_MODULE_LOAD_DECLINE:
00906          AST_LIST_REMOVE_CURRENT(&load_order, entry);
00907          free(order->resource);
00908          free(order);
00909          break;
00910       case AST_MODULE_LOAD_FAILURE:
00911          res = -1;
00912          goto done;
00913       case AST_MODULE_LOAD_SKIP:
00914          /* should not happen */
00915          break;
00916       }
00917    }
00918    AST_LIST_TRAVERSE_SAFE_END;
00919 
00920 done:
00921    while ((order = AST_LIST_REMOVE_HEAD(&load_order, entry))) {
00922       free(order->resource);
00923       free(order);
00924    }
00925 
00926    AST_LIST_UNLOCK(&module_list);
00927 
00928    return res;
00929 }
00930 
00931 void ast_update_use_count(void)
00932 {
00933    /* Notify any module monitors that the use count for a
00934       resource has changed */
00935    struct loadupdate *m;
00936 
00937    AST_LIST_LOCK(&updaters);
00938    AST_LIST_TRAVERSE(&updaters, m, entry)
00939       m->updater();
00940    AST_LIST_UNLOCK(&updaters);
00941 }
00942 
00943 int ast_update_module_list(int (*modentry)(const char *module, const char *description, int usecnt, const char *like),
00944             const char *like)
00945 {
00946    struct ast_module *cur;
00947    int unlock = -1;
00948    int total_mod_loaded = 0;
00949 
00950    if (AST_LIST_TRYLOCK(&module_list))
00951       unlock = 0;
00952 
00953    AST_LIST_TRAVERSE(&module_list, cur, entry) {
00954       total_mod_loaded += modentry(cur->resource, cur->info->description, cur->usecount, like);
00955    }
00956 
00957    if (unlock)
00958       AST_LIST_UNLOCK(&module_list);
00959 
00960    return total_mod_loaded;
00961 }
00962 
00963 int ast_loader_register(int (*v)(void))
00964 {
00965    struct loadupdate *tmp;
00966 
00967    if (!(tmp = ast_malloc(sizeof(*tmp))))
00968       return -1;
00969 
00970    tmp->updater = v;
00971    AST_LIST_LOCK(&updaters);
00972    AST_LIST_INSERT_HEAD(&updaters, tmp, entry);
00973    AST_LIST_UNLOCK(&updaters);
00974 
00975    return 0;
00976 }
00977 
00978 int ast_loader_unregister(int (*v)(void))
00979 {
00980    struct loadupdate *cur;
00981 
00982    AST_LIST_LOCK(&updaters);
00983    AST_LIST_TRAVERSE_SAFE_BEGIN(&updaters, cur, entry) {
00984       if (cur->updater == v)  {
00985          AST_LIST_REMOVE_CURRENT(&updaters, entry);
00986          break;
00987       }
00988    }
00989    AST_LIST_TRAVERSE_SAFE_END;
00990    AST_LIST_UNLOCK(&updaters);
00991 
00992    return cur ? 0 : -1;
00993 }
00994 
00995 struct ast_module *ast_module_ref(struct ast_module *mod)
00996 {
00997    ast_atomic_fetchadd_int(&mod->usecount, +1);
00998    ast_update_use_count();
00999 
01000    return mod;
01001 }
01002 
01003 void ast_module_unref(struct ast_module *mod)
01004 {
01005    ast_atomic_fetchadd_int(&mod->usecount, -1);
01006    ast_update_use_count();
01007 }

Generated on Thu May 14 14:49:04 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7