Mon Jun 18 2012 03:55:35

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: 356291 $")
00033 
00034 #include "asterisk/_private.h"
00035 #include "asterisk/paths.h"   /* use ast_config_AST_MODULE_DIR */
00036 #include <dirent.h>
00037 
00038 #include "asterisk/linkedlists.h"
00039 #include "asterisk/module.h"
00040 #include "asterisk/config.h"
00041 #include "asterisk/channel.h"
00042 #include "asterisk/term.h"
00043 #include "asterisk/manager.h"
00044 #include "asterisk/cdr.h"
00045 #include "asterisk/enum.h"
00046 #include "asterisk/http.h"
00047 #include "asterisk/lock.h"
00048 #include "asterisk/features.h"
00049 #include "asterisk/dsp.h"
00050 #include "asterisk/udptl.h"
00051 #include "asterisk/heap.h"
00052 #include "asterisk/app.h"
00053 
00054 #include <dlfcn.h>
00055 
00056 #include "asterisk/md5.h"
00057 #include "asterisk/utils.h"
00058 
00059 #ifndef RTLD_NOW
00060 #define RTLD_NOW 0
00061 #endif
00062 
00063 #ifndef RTLD_LOCAL
00064 #define RTLD_LOCAL 0
00065 #endif
00066 
00067 struct ast_module_user {
00068    struct ast_channel *chan;
00069    AST_LIST_ENTRY(ast_module_user) entry;
00070 };
00071 
00072 AST_LIST_HEAD(module_user_list, ast_module_user);
00073 
00074 static const unsigned char expected_key[] =
00075 { 0x87, 0x76, 0x79, 0x35, 0x23, 0xea, 0x3a, 0xd3,
00076   0x25, 0x2a, 0xbb, 0x35, 0x87, 0xe4, 0x22, 0x24 };
00077 
00078 static char buildopt_sum[33] = AST_BUILDOPT_SUM;
00079 
00080 static unsigned int embedding = 1; /* we always start out by registering embedded modules,
00081                   since they are here before we dlopen() any
00082                */
00083 
00084 struct ast_module {
00085    const struct ast_module_info *info;
00086    void *lib;              /* the shared lib, or NULL if embedded */
00087    int usecount;              /* the number of 'users' currently in this module */
00088    struct module_user_list users;         /* the list of users in the module */
00089    struct {
00090       unsigned int running:1;
00091       unsigned int declined:1;
00092    } flags;
00093    AST_LIST_ENTRY(ast_module) entry;
00094    char resource[0];
00095 };
00096 
00097 static AST_LIST_HEAD_STATIC(module_list, ast_module);
00098 
00099 const char *ast_module_name(const struct ast_module *mod)
00100 {
00101    if (!mod || !mod->info) {
00102       return NULL;
00103    }
00104 
00105    return mod->info->name;
00106 }
00107 
00108 /*
00109  * module_list is cleared by its constructor possibly after
00110  * we start accumulating embedded modules, so we need to
00111  * use another list (without the lock) to accumulate them.
00112  * Then we update the main list when embedding is done.
00113  */
00114 static struct module_list embedded_module_list;
00115 
00116 struct loadupdate {
00117    int (*updater)(void);
00118    AST_LIST_ENTRY(loadupdate) entry;
00119 };
00120 
00121 static AST_LIST_HEAD_STATIC(updaters, loadupdate);
00122 
00123 AST_MUTEX_DEFINE_STATIC(reloadlock);
00124 
00125 struct reload_queue_item {
00126    AST_LIST_ENTRY(reload_queue_item) entry;
00127    char module[0];
00128 };
00129 
00130 static int do_full_reload = 0;
00131 
00132 static AST_LIST_HEAD_STATIC(reload_queue, reload_queue_item);
00133 
00134 /* when dynamic modules are being loaded, ast_module_register() will
00135    need to know what filename the module was loaded from while it
00136    is being registered
00137 */
00138 static struct ast_module *resource_being_loaded;
00139 
00140 /* XXX: should we check for duplicate resource names here? */
00141 
00142 void ast_module_register(const struct ast_module_info *info)
00143 {
00144    struct ast_module *mod;
00145 
00146    if (embedding) {
00147       if (!(mod = ast_calloc(1, sizeof(*mod) + strlen(info->name) + 1)))
00148          return;
00149       strcpy(mod->resource, info->name);
00150    } else {
00151       mod = resource_being_loaded;
00152    }
00153 
00154    mod->info = info;
00155    AST_LIST_HEAD_INIT(&mod->users);
00156 
00157    /* during startup, before the loader has been initialized,
00158       there are no threads, so there is no need to take the lock
00159       on this list to manipulate it. it is also possible that it
00160       might be unsafe to use the list lock at that point... so
00161       let's avoid it altogether
00162    */
00163    if (embedding) {
00164       AST_LIST_INSERT_TAIL(&embedded_module_list, mod, entry);
00165    } else {
00166       AST_LIST_LOCK(&module_list);
00167       /* it is paramount that the new entry be placed at the tail of
00168          the list, otherwise the code that uses dlopen() to load
00169          dynamic modules won't be able to find out if the module it
00170          just opened was registered or failed to load
00171       */
00172       AST_LIST_INSERT_TAIL(&module_list, mod, entry);
00173       AST_LIST_UNLOCK(&module_list);
00174    }
00175 
00176    /* give the module a copy of its own handle, for later use in registrations and the like */
00177    *((struct ast_module **) &(info->self)) = mod;
00178 }
00179 
00180 void ast_module_unregister(const struct ast_module_info *info)
00181 {
00182    struct ast_module *mod = NULL;
00183 
00184    /* it is assumed that the users list in the module structure
00185       will already be empty, or we cannot have gotten to this
00186       point
00187    */
00188    AST_LIST_LOCK(&module_list);
00189    AST_LIST_TRAVERSE_SAFE_BEGIN(&module_list, mod, entry) {
00190       if (mod->info == info) {
00191          AST_LIST_REMOVE_CURRENT(entry);
00192          break;
00193       }
00194    }
00195    AST_LIST_TRAVERSE_SAFE_END;
00196    AST_LIST_UNLOCK(&module_list);
00197 
00198    if (mod) {
00199       AST_LIST_HEAD_DESTROY(&mod->users);
00200       ast_free(mod);
00201    }
00202 }
00203 
00204 struct ast_module_user *__ast_module_user_add(struct ast_module *mod,
00205                      struct ast_channel *chan)
00206 {
00207    struct ast_module_user *u = ast_calloc(1, sizeof(*u));
00208 
00209    if (!u)
00210       return NULL;
00211 
00212    u->chan = chan;
00213 
00214    AST_LIST_LOCK(&mod->users);
00215    AST_LIST_INSERT_HEAD(&mod->users, u, entry);
00216    AST_LIST_UNLOCK(&mod->users);
00217 
00218    ast_atomic_fetchadd_int(&mod->usecount, +1);
00219 
00220    ast_update_use_count();
00221 
00222    return u;
00223 }
00224 
00225 void __ast_module_user_remove(struct ast_module *mod, struct ast_module_user *u)
00226 {
00227    AST_LIST_LOCK(&mod->users);
00228    AST_LIST_REMOVE(&mod->users, u, entry);
00229    AST_LIST_UNLOCK(&mod->users);
00230    ast_atomic_fetchadd_int(&mod->usecount, -1);
00231    ast_free(u);
00232 
00233    ast_update_use_count();
00234 }
00235 
00236 void __ast_module_user_hangup_all(struct ast_module *mod)
00237 {
00238    struct ast_module_user *u;
00239 
00240    AST_LIST_LOCK(&mod->users);
00241    while ((u = AST_LIST_REMOVE_HEAD(&mod->users, entry))) {
00242       if (u->chan) {
00243          ast_softhangup(u->chan, AST_SOFTHANGUP_APPUNLOAD);
00244       }
00245       ast_atomic_fetchadd_int(&mod->usecount, -1);
00246       ast_free(u);
00247    }
00248    AST_LIST_UNLOCK(&mod->users);
00249 
00250    ast_update_use_count();
00251 }
00252 
00253 /*! \note
00254  * In addition to modules, the reload command handles some extra keywords
00255  * which are listed here together with the corresponding handlers.
00256  * This table is also used by the command completion code.
00257  */
00258 static struct reload_classes {
00259    const char *name;
00260    int (*reload_fn)(void);
00261 } reload_classes[] = {  /* list in alpha order, longest match first for cli completion */
00262    { "cdr", ast_cdr_engine_reload },
00263    { "dnsmgr", dnsmgr_reload },
00264    { "extconfig", read_config_maps },
00265    { "enum",   ast_enum_reload },
00266    { "manager",   reload_manager },
00267    { "http",   ast_http_reload },
00268    { "logger", logger_reload },
00269    { "features",  ast_features_reload },
00270    { "dsp", ast_dsp_reload},
00271    { "udptl",  ast_udptl_reload },
00272    { "indications", ast_indications_reload },
00273    { "cel",        ast_cel_engine_reload },
00274    { "plc",        ast_plc_reload },
00275    { NULL,  NULL }
00276 };
00277 
00278 static int printdigest(const unsigned char *d)
00279 {
00280    int x, pos;
00281    char buf[256]; /* large enough so we don't have to worry */
00282 
00283    for (pos = 0, x = 0; x < 16; x++)
00284       pos += sprintf(buf + pos, " %02x", *d++);
00285 
00286    ast_debug(1, "Unexpected signature:%s\n", buf);
00287 
00288    return 0;
00289 }
00290 
00291 static int key_matches(const unsigned char *key1, const unsigned char *key2)
00292 {
00293    int x;
00294 
00295    for (x = 0; x < 16; x++) {
00296       if (key1[x] != key2[x])
00297          return 0;
00298    }
00299 
00300    return 1;
00301 }
00302 
00303 static int verify_key(const unsigned char *key)
00304 {
00305    struct MD5Context c;
00306    unsigned char digest[16];
00307 
00308    MD5Init(&c);
00309    MD5Update(&c, key, strlen((char *)key));
00310    MD5Final(digest, &c);
00311 
00312    if (key_matches(expected_key, digest))
00313       return 0;
00314 
00315    printdigest(digest);
00316 
00317    return -1;
00318 }
00319 
00320 static int resource_name_match(const char *name1_in, const char *name2_in)
00321 {
00322    char *name1 = (char *) name1_in;
00323    char *name2 = (char *) name2_in;
00324 
00325    /* trim off any .so extensions */
00326    if (!strcasecmp(name1 + strlen(name1) - 3, ".so")) {
00327       name1 = ast_strdupa(name1);
00328       name1[strlen(name1) - 3] = '\0';
00329    }
00330    if (!strcasecmp(name2 + strlen(name2) - 3, ".so")) {
00331       name2 = ast_strdupa(name2);
00332       name2[strlen(name2) - 3] = '\0';
00333    }
00334 
00335    return strcasecmp(name1, name2);
00336 }
00337 
00338 static struct ast_module *find_resource(const char *resource, int do_lock)
00339 {
00340    struct ast_module *cur;
00341 
00342    if (do_lock)
00343       AST_LIST_LOCK(&module_list);
00344 
00345    AST_LIST_TRAVERSE(&module_list, cur, entry) {
00346       if (!resource_name_match(resource, cur->resource))
00347          break;
00348    }
00349 
00350    if (do_lock)
00351       AST_LIST_UNLOCK(&module_list);
00352 
00353    return cur;
00354 }
00355 
00356 #ifdef LOADABLE_MODULES
00357 static void unload_dynamic_module(struct ast_module *mod)
00358 {
00359    void *lib = mod->lib;
00360 
00361    /* WARNING: the structure pointed to by mod is going to
00362       disappear when this operation succeeds, so we can't
00363       dereference it */
00364 
00365    if (lib)
00366       while (!dlclose(lib));
00367 }
00368 
00369 static struct ast_module *load_dynamic_module(const char *resource_in, unsigned int global_symbols_only)
00370 {
00371    char fn[PATH_MAX] = "";
00372    void *lib = NULL;
00373    struct ast_module *mod;
00374    unsigned int wants_global;
00375    int space;  /* room needed for the descriptor */
00376    int missing_so = 0;
00377 
00378    space = sizeof(*resource_being_loaded) + strlen(resource_in) + 1;
00379    if (strcasecmp(resource_in + strlen(resource_in) - 3, ".so")) {
00380       missing_so = 1;
00381       space += 3; /* room for the extra ".so" */
00382    }
00383 
00384    snprintf(fn, sizeof(fn), "%s/%s%s", ast_config_AST_MODULE_DIR, resource_in, missing_so ? ".so" : "");
00385 
00386    /* make a first load of the module in 'quiet' mode... don't try to resolve
00387       any symbols, and don't export any symbols. this will allow us to peek into
00388       the module's info block (if available) to see what flags it has set */
00389 
00390    resource_being_loaded = ast_calloc(1, space);
00391    if (!resource_being_loaded)
00392       return NULL;
00393    strcpy(resource_being_loaded->resource, resource_in);
00394    if (missing_so)
00395       strcat(resource_being_loaded->resource, ".so");
00396 
00397    if (!(lib = dlopen(fn, RTLD_LAZY | RTLD_LOCAL))) {
00398       ast_log(LOG_WARNING, "Error loading module '%s': %s\n", resource_in, dlerror());
00399       ast_free(resource_being_loaded);
00400       return NULL;
00401    }
00402 
00403    /* the dlopen() succeeded, let's find out if the module
00404       registered itself */
00405    /* note that this will only work properly as long as
00406       ast_module_register() (which is called by the module's
00407       constructor) places the new module at the tail of the
00408       module_list
00409    */
00410    if (resource_being_loaded != (mod = AST_LIST_LAST(&module_list))) {
00411       ast_log(LOG_WARNING, "Module '%s' did not register itself during load\n", resource_in);
00412       /* no, it did not, so close it and return */
00413       while (!dlclose(lib));
00414       /* note that the module's destructor will call ast_module_unregister(),
00415          which will free the structure we allocated in resource_being_loaded */
00416       return NULL;
00417    }
00418 
00419    wants_global = ast_test_flag(mod->info, AST_MODFLAG_GLOBAL_SYMBOLS);
00420 
00421    /* if we are being asked only to load modules that provide global symbols,
00422       and this one does not, then close it and return */
00423    if (global_symbols_only && !wants_global) {
00424       while (!dlclose(lib));
00425       return NULL;
00426    }
00427 
00428    /* This section is a workaround for a gcc 4.1 bug that has already been
00429     * fixed in later versions.  Unfortunately, some distributions, such as
00430     * RHEL/CentOS 5, distribute gcc 4.1, so we're stuck with having to deal
00431     * with this issue.  This basically ensures that optional_api modules are
00432     * loaded before any module which requires their functionality. */
00433 #if !defined(HAVE_ATTRIBUTE_weak_import) && !defined(HAVE_ATTRIBUTE_weakref)
00434    if (!ast_strlen_zero(mod->info->nonoptreq)) {
00435       /* Force any required dependencies to load */
00436       char *each, *required_resource = ast_strdupa(mod->info->nonoptreq);
00437       while ((each = strsep(&required_resource, ","))) {
00438          each = ast_strip(each);
00439 
00440          /* Is it already loaded? */
00441          if (!find_resource(each, 0)) {
00442             load_dynamic_module(each, global_symbols_only);
00443          }
00444       }
00445    }
00446 #endif
00447 
00448    while (!dlclose(lib));
00449    resource_being_loaded = NULL;
00450 
00451    /* start the load process again */
00452    resource_being_loaded = ast_calloc(1, space);
00453    if (!resource_being_loaded)
00454       return NULL;
00455    strcpy(resource_being_loaded->resource, resource_in);
00456    if (missing_so)
00457       strcat(resource_being_loaded->resource, ".so");
00458 
00459    if (!(lib = dlopen(fn, wants_global ? RTLD_LAZY | RTLD_GLOBAL : RTLD_NOW | RTLD_LOCAL))) {
00460       ast_log(LOG_WARNING, "Error loading module '%s': %s\n", resource_in, dlerror());
00461       ast_free(resource_being_loaded);
00462       return NULL;
00463    }
00464 
00465    /* since the module was successfully opened, and it registered itself
00466       the previous time we did that, we're going to assume it worked this
00467       time too :) */
00468 
00469    AST_LIST_LAST(&module_list)->lib = lib;
00470    resource_being_loaded = NULL;
00471 
00472    return AST_LIST_LAST(&module_list);
00473 }
00474 #endif
00475 
00476 void ast_module_shutdown(void)
00477 {
00478    struct ast_module *mod;
00479    int somethingchanged = 1, final = 0;
00480 
00481    AST_LIST_LOCK(&module_list);
00482 
00483    /*!\note Some resources, like timers, are started up dynamically, and thus
00484     * may be still in use, even if all channels are dead.  We must therefore
00485     * check the usecount before asking modules to unload. */
00486    do {
00487       if (!somethingchanged) {
00488          /*!\note If we go through the entire list without changing
00489           * anything, ignore the usecounts and unload, then exit. */
00490          final = 1;
00491       }
00492 
00493       /* Reset flag before traversing the list */
00494       somethingchanged = 0;
00495 
00496       AST_LIST_TRAVERSE_SAFE_BEGIN(&module_list, mod, entry) {
00497          if (!final && mod->usecount) {
00498             continue;
00499          }
00500          AST_LIST_REMOVE_CURRENT(entry);
00501          if (mod->flags.running && !mod->flags.declined && mod->info->unload) {
00502             mod->info->unload();
00503          }
00504          AST_LIST_HEAD_DESTROY(&mod->users);
00505          free(mod);
00506          somethingchanged = 1;
00507       }
00508       AST_LIST_TRAVERSE_SAFE_END;
00509    } while (somethingchanged && !final);
00510 
00511    AST_LIST_UNLOCK(&module_list);
00512 }
00513 
00514 int ast_unload_resource(const char *resource_name, enum ast_module_unload_mode force)
00515 {
00516    struct ast_module *mod;
00517    int res = -1;
00518    int error = 0;
00519 
00520    AST_LIST_LOCK(&module_list);
00521 
00522    if (!(mod = find_resource(resource_name, 0))) {
00523       AST_LIST_UNLOCK(&module_list);
00524       ast_log(LOG_WARNING, "Unload failed, '%s' could not be found\n", resource_name);
00525       return -1;
00526    }
00527 
00528    if (!mod->flags.running || mod->flags.declined) {
00529       ast_log(LOG_WARNING, "Unload failed, '%s' is not loaded.\n", resource_name);
00530       error = 1;
00531    }
00532 
00533    if (!error && (mod->usecount > 0)) {
00534       if (force)
00535          ast_log(LOG_WARNING, "Warning:  Forcing removal of module '%s' with use count %d\n",
00536             resource_name, mod->usecount);
00537       else {
00538          ast_log(LOG_WARNING, "Soft unload failed, '%s' has use count %d\n", resource_name,
00539             mod->usecount);
00540          error = 1;
00541       }
00542    }
00543 
00544    if (!error) {
00545       __ast_module_user_hangup_all(mod);
00546       res = mod->info->unload();
00547 
00548       if (res) {
00549          ast_log(LOG_WARNING, "Firm unload failed for %s\n", resource_name);
00550          if (force <= AST_FORCE_FIRM)
00551             error = 1;
00552          else
00553             ast_log(LOG_WARNING, "** Dangerous **: Unloading resource anyway, at user request\n");
00554       }
00555    }
00556 
00557    if (!error)
00558       mod->flags.running = mod->flags.declined = 0;
00559 
00560    AST_LIST_UNLOCK(&module_list);
00561 
00562    if (!error && !mod->lib && mod->info && mod->info->restore_globals)
00563       mod->info->restore_globals();
00564 
00565 #ifdef LOADABLE_MODULES
00566    if (!error)
00567       unload_dynamic_module(mod);
00568 #endif
00569 
00570    if (!error)
00571       ast_update_use_count();
00572 
00573    return res;
00574 }
00575 
00576 char *ast_module_helper(const char *line, const char *word, int pos, int state, int rpos, int needsreload)
00577 {
00578    struct ast_module *cur;
00579    int i, which=0, l = strlen(word);
00580    char *ret = NULL;
00581 
00582    if (pos != rpos)
00583       return NULL;
00584 
00585    AST_LIST_LOCK(&module_list);
00586    AST_LIST_TRAVERSE(&module_list, cur, entry) {
00587       if (!strncasecmp(word, cur->resource, l) &&
00588           (cur->info->reload || !needsreload) &&
00589           ++which > state) {
00590          ret = ast_strdup(cur->resource);
00591          break;
00592       }
00593    }
00594    AST_LIST_UNLOCK(&module_list);
00595 
00596    if (!ret) {
00597       for (i=0; !ret && reload_classes[i].name; i++) {
00598          if (!strncasecmp(word, reload_classes[i].name, l) && ++which > state)
00599             ret = ast_strdup(reload_classes[i].name);
00600       }
00601    }
00602 
00603    return ret;
00604 }
00605 
00606 void ast_process_pending_reloads(void)
00607 {
00608    struct reload_queue_item *item;
00609 
00610    if (!ast_fully_booted) {
00611       return;
00612    }
00613 
00614    AST_LIST_LOCK(&reload_queue);
00615 
00616    if (do_full_reload) {
00617       do_full_reload = 0;
00618       AST_LIST_UNLOCK(&reload_queue);
00619       ast_log(LOG_NOTICE, "Executing deferred reload request.\n");
00620       ast_module_reload(NULL);
00621       return;
00622    }
00623 
00624    while ((item = AST_LIST_REMOVE_HEAD(&reload_queue, entry))) {
00625       ast_log(LOG_NOTICE, "Executing deferred reload request for module '%s'.\n", item->module);
00626       ast_module_reload(item->module);
00627       ast_free(item);
00628    }
00629 
00630    AST_LIST_UNLOCK(&reload_queue);
00631 }
00632 
00633 static void queue_reload_request(const char *module)
00634 {
00635    struct reload_queue_item *item;
00636 
00637    AST_LIST_LOCK(&reload_queue);
00638 
00639    if (do_full_reload) {
00640       AST_LIST_UNLOCK(&reload_queue);
00641       return;
00642    }
00643 
00644    if (ast_strlen_zero(module)) {
00645       /* A full reload request (when module is NULL) wipes out any previous
00646          reload requests and causes the queue to ignore future ones */
00647       while ((item = AST_LIST_REMOVE_HEAD(&reload_queue, entry))) {
00648          ast_free(item);
00649       }
00650       do_full_reload = 1;
00651    } else {
00652       /* No reason to add the same module twice */
00653       AST_LIST_TRAVERSE(&reload_queue, item, entry) {
00654          if (!strcasecmp(item->module, module)) {
00655             AST_LIST_UNLOCK(&reload_queue);
00656             return;
00657          }
00658       }
00659       item = ast_calloc(1, sizeof(*item) + strlen(module) + 1);
00660       if (!item) {
00661          ast_log(LOG_ERROR, "Failed to allocate reload queue item.\n");
00662          AST_LIST_UNLOCK(&reload_queue);
00663          return;
00664       }
00665       strcpy(item->module, module);
00666       AST_LIST_INSERT_TAIL(&reload_queue, item, entry);
00667    }
00668    AST_LIST_UNLOCK(&reload_queue);
00669 }
00670 
00671 int ast_module_reload(const char *name)
00672 {
00673    struct ast_module *cur;
00674    int res = 0; /* return value. 0 = not found, others, see below */
00675    int i;
00676 
00677    /* If we aren't fully booted, we just pretend we reloaded but we queue this
00678       up to run once we are booted up. */
00679    if (!ast_fully_booted) {
00680       queue_reload_request(name);
00681       return 0;
00682    }
00683 
00684    if (ast_mutex_trylock(&reloadlock)) {
00685       ast_verbose("The previous reload command didn't finish yet\n");
00686       return -1;  /* reload already in progress */
00687    }
00688    ast_lastreloadtime = ast_tvnow();
00689 
00690    if (ast_opt_lock_confdir) {
00691       int try;
00692       int res;
00693       for (try = 1, res = AST_LOCK_TIMEOUT; try < 6 && (res == AST_LOCK_TIMEOUT); try++) {
00694          res = ast_lock_path(ast_config_AST_CONFIG_DIR);
00695          if (res == AST_LOCK_TIMEOUT) {
00696             ast_log(LOG_WARNING, "Failed to grab lock on %s, try %d\n", ast_config_AST_CONFIG_DIR, try);
00697          }
00698       }
00699       if (res != AST_LOCK_SUCCESS) {
00700          ast_verbose("Cannot grab lock on %s\n", ast_config_AST_CONFIG_DIR);
00701          ast_mutex_unlock(&reloadlock);
00702          return -1;
00703       }
00704    }
00705 
00706    /* Call "predefined" reload here first */
00707    for (i = 0; reload_classes[i].name; i++) {
00708       if (!name || !strcasecmp(name, reload_classes[i].name)) {
00709          reload_classes[i].reload_fn();   /* XXX should check error ? */
00710          res = 2; /* found and reloaded */
00711       }
00712    }
00713 
00714    if (name && res) {
00715       if (ast_opt_lock_confdir) {
00716          ast_unlock_path(ast_config_AST_CONFIG_DIR);
00717       }
00718       ast_mutex_unlock(&reloadlock);
00719       return res;
00720    }
00721 
00722    AST_LIST_LOCK(&module_list);
00723    AST_LIST_TRAVERSE(&module_list, cur, entry) {
00724       const struct ast_module_info *info = cur->info;
00725 
00726       if (name && resource_name_match(name, cur->resource))
00727          continue;
00728 
00729       if (!cur->flags.running || cur->flags.declined) {
00730          if (!name)
00731             continue;
00732          ast_log(LOG_NOTICE, "The module '%s' was not properly initialized.  "
00733             "Before reloading the module, you must run \"module load %s\" "
00734             "and fix whatever is preventing the module from being initialized.\n",
00735             name, name);
00736          res = 2; /* Don't report that the module was not found */
00737          break;
00738       }
00739 
00740       if (!info->reload) { /* cannot be reloaded */
00741          if (res < 1)   /* store result if possible */
00742             res = 1; /* 1 = no reload() method */
00743          continue;
00744       }
00745 
00746       res = 2;
00747       ast_verb(3, "Reloading module '%s' (%s)\n", cur->resource, info->description);
00748       info->reload();
00749    }
00750    AST_LIST_UNLOCK(&module_list);
00751 
00752    if (ast_opt_lock_confdir) {
00753       ast_unlock_path(ast_config_AST_CONFIG_DIR);
00754    }
00755    ast_mutex_unlock(&reloadlock);
00756 
00757    return res;
00758 }
00759 
00760 static unsigned int inspect_module(const struct ast_module *mod)
00761 {
00762    if (!mod->info->description) {
00763       ast_log(LOG_WARNING, "Module '%s' does not provide a description.\n", mod->resource);
00764       return 1;
00765    }
00766 
00767    if (!mod->info->key) {
00768       ast_log(LOG_WARNING, "Module '%s' does not provide a license key.\n", mod->resource);
00769       return 1;
00770    }
00771 
00772    if (verify_key((unsigned char *) mod->info->key)) {
00773       ast_log(LOG_WARNING, "Module '%s' did not provide a valid license key.\n", mod->resource);
00774       return 1;
00775    }
00776 
00777    if (!ast_strlen_zero(mod->info->buildopt_sum) &&
00778        strcmp(buildopt_sum, mod->info->buildopt_sum)) {
00779       ast_log(LOG_WARNING, "Module '%s' was not compiled with the same compile-time options as this version of Asterisk.\n", mod->resource);
00780       ast_log(LOG_WARNING, "Module '%s' will not be initialized as it may cause instability.\n", mod->resource);
00781       return 1;
00782    }
00783 
00784    return 0;
00785 }
00786 
00787 static enum ast_module_load_result start_resource(struct ast_module *mod)
00788 {
00789    char tmp[256];
00790    enum ast_module_load_result res;
00791 
00792    if (!mod->info->load) {
00793       return AST_MODULE_LOAD_FAILURE;
00794    }
00795 
00796    res = mod->info->load();
00797 
00798    switch (res) {
00799    case AST_MODULE_LOAD_SUCCESS:
00800       if (!ast_fully_booted) {
00801          ast_verb(1, "%s => (%s)\n", mod->resource, term_color(tmp, mod->info->description, COLOR_BROWN, COLOR_BLACK, sizeof(tmp)));
00802          if (ast_opt_console && !option_verbose)
00803             ast_verbose( ".");
00804       } else {
00805          ast_verb(1, "Loaded %s => (%s)\n", mod->resource, mod->info->description);
00806       }
00807 
00808       mod->flags.running = 1;
00809 
00810       ast_update_use_count();
00811       break;
00812    case AST_MODULE_LOAD_DECLINE:
00813       mod->flags.declined = 1;
00814       break;
00815    case AST_MODULE_LOAD_FAILURE:
00816    case AST_MODULE_LOAD_SKIP: /* modules should never return this value */
00817    case AST_MODULE_LOAD_PRIORITY:
00818       break;
00819    }
00820 
00821    return res;
00822 }
00823 
00824 /*! loads a resource based upon resource_name. If global_symbols_only is set
00825  *  only modules with global symbols will be loaded.
00826  *
00827  *  If the ast_heap is provided (not NULL) the module is found and added to the
00828  *  heap without running the module's load() function.  By doing this, modules
00829  *  added to the resource_heap can be initialized later in order by priority. 
00830  *
00831  *  If the ast_heap is not provided, the module's load function will be executed
00832  *  immediately */
00833 static enum ast_module_load_result load_resource(const char *resource_name, unsigned int global_symbols_only, struct ast_heap *resource_heap, int required)
00834 {
00835    struct ast_module *mod;
00836    enum ast_module_load_result res = AST_MODULE_LOAD_SUCCESS;
00837 
00838    if ((mod = find_resource(resource_name, 0))) {
00839       if (mod->flags.running) {
00840          ast_log(LOG_WARNING, "Module '%s' already exists.\n", resource_name);
00841          return AST_MODULE_LOAD_DECLINE;
00842       }
00843       if (global_symbols_only && !ast_test_flag(mod->info, AST_MODFLAG_GLOBAL_SYMBOLS))
00844          return AST_MODULE_LOAD_SKIP;
00845    } else {
00846 #ifdef LOADABLE_MODULES
00847       if (!(mod = load_dynamic_module(resource_name, global_symbols_only))) {
00848          /* don't generate a warning message during load_modules() */
00849          if (!global_symbols_only) {
00850             ast_log(LOG_WARNING, "Module '%s' could not be loaded.\n", resource_name);
00851             return required ? AST_MODULE_LOAD_FAILURE : AST_MODULE_LOAD_DECLINE;
00852          } else {
00853             return required ? AST_MODULE_LOAD_FAILURE : AST_MODULE_LOAD_SKIP;
00854          }
00855       }
00856 #else
00857       ast_log(LOG_WARNING, "Module '%s' could not be loaded.\n", resource_name);
00858       return required ? AST_MODULE_LOAD_FAILURE : AST_MODULE_LOAD_DECLINE;
00859 #endif
00860    }
00861 
00862    if (inspect_module(mod)) {
00863       ast_log(LOG_WARNING, "Module '%s' could not be loaded.\n", resource_name);
00864 #ifdef LOADABLE_MODULES
00865       unload_dynamic_module(mod);
00866 #endif
00867       return required ? AST_MODULE_LOAD_FAILURE : AST_MODULE_LOAD_DECLINE;
00868    }
00869 
00870    if (!mod->lib && mod->info->backup_globals && mod->info->backup_globals()) {
00871       ast_log(LOG_WARNING, "Module '%s' was unable to backup its global data.\n", resource_name);
00872       return required ? AST_MODULE_LOAD_FAILURE : AST_MODULE_LOAD_DECLINE;
00873    }
00874 
00875    mod->flags.declined = 0;
00876 
00877    if (resource_heap) {
00878       ast_heap_push(resource_heap, mod);
00879       res = AST_MODULE_LOAD_PRIORITY;
00880    } else {
00881       res = start_resource(mod);
00882    }
00883 
00884    return res;
00885 }
00886 
00887 int ast_load_resource(const char *resource_name)
00888 {
00889    int res;
00890    AST_LIST_LOCK(&module_list);
00891    res = load_resource(resource_name, 0, NULL, 0);
00892    AST_LIST_UNLOCK(&module_list);
00893 
00894    return res;
00895 }
00896 
00897 struct load_order_entry {
00898    char *resource;
00899    int required;
00900    AST_LIST_ENTRY(load_order_entry) entry;
00901 };
00902 
00903 AST_LIST_HEAD_NOLOCK(load_order, load_order_entry);
00904 
00905 static struct load_order_entry *add_to_load_order(const char *resource, struct load_order *load_order, int required)
00906 {
00907    struct load_order_entry *order;
00908 
00909    AST_LIST_TRAVERSE(load_order, order, entry) {
00910       if (!resource_name_match(order->resource, resource)) {
00911          /* Make sure we have the proper setting for the required field 
00912             (we might have both load= and required= lines in modules.conf) */
00913          order->required |= required;
00914          return NULL;
00915       }
00916    }
00917 
00918    if (!(order = ast_calloc(1, sizeof(*order))))
00919       return NULL;
00920 
00921    order->resource = ast_strdup(resource);
00922    order->required = required;
00923    AST_LIST_INSERT_TAIL(load_order, order, entry);
00924 
00925    return order;
00926 }
00927 
00928 static int mod_load_cmp(void *a, void *b)
00929 {
00930    struct ast_module *a_mod = (struct ast_module *) a;
00931    struct ast_module *b_mod = (struct ast_module *) b;
00932    int res = -1;
00933    /* if load_pri is not set, default is 128.  Lower is better*/
00934    unsigned char a_pri = ast_test_flag(a_mod->info, AST_MODFLAG_LOAD_ORDER) ? a_mod->info->load_pri : 128;
00935    unsigned char b_pri = ast_test_flag(b_mod->info, AST_MODFLAG_LOAD_ORDER) ? b_mod->info->load_pri : 128;
00936    if (a_pri == b_pri) {
00937       res = 0;
00938    } else if (a_pri < b_pri) {
00939       res = 1;
00940    }
00941    return res;
00942 }
00943 
00944 /*! loads modules in order by load_pri, updates mod_count 
00945    \return -1 on failure to load module, -2 on failure to load required module, otherwise 0
00946 */
00947 static int load_resource_list(struct load_order *load_order, unsigned int global_symbols, int *mod_count)
00948 {
00949    struct ast_heap *resource_heap;
00950    struct load_order_entry *order;
00951    struct ast_module *mod;
00952    int count = 0;
00953    int res = 0;
00954 
00955    if(!(resource_heap = ast_heap_create(8, mod_load_cmp, -1))) {
00956       return -1;
00957    }
00958 
00959    /* first, add find and add modules to heap */
00960    AST_LIST_TRAVERSE_SAFE_BEGIN(load_order, order, entry) {
00961       switch (load_resource(order->resource, global_symbols, resource_heap, order->required)) {
00962       case AST_MODULE_LOAD_SUCCESS:
00963       case AST_MODULE_LOAD_DECLINE:
00964          AST_LIST_REMOVE_CURRENT(entry);
00965          ast_free(order->resource);
00966          ast_free(order);
00967          break;
00968       case AST_MODULE_LOAD_FAILURE:
00969          ast_log(LOG_ERROR, "*** Failed to load module %s - %s\n", order->resource, order->required ? "Required" : "Not required");
00970          fprintf(stderr, "*** Failed to load module %s - %s\n", order->resource, order->required ? "Required" : "Not required");
00971          res = order->required ? -2 : -1;
00972          goto done;
00973       case AST_MODULE_LOAD_SKIP:
00974          break;
00975       case AST_MODULE_LOAD_PRIORITY:
00976          AST_LIST_REMOVE_CURRENT(entry);
00977          break;
00978       }
00979    }
00980    AST_LIST_TRAVERSE_SAFE_END;
00981 
00982    /* second remove modules from heap sorted by priority */
00983    while ((mod = ast_heap_pop(resource_heap))) {
00984       switch (start_resource(mod)) {
00985       case AST_MODULE_LOAD_SUCCESS:
00986          count++;
00987       case AST_MODULE_LOAD_DECLINE:
00988          break;
00989       case AST_MODULE_LOAD_FAILURE:
00990          res = -1;
00991          goto done;
00992       case AST_MODULE_LOAD_SKIP:
00993       case AST_MODULE_LOAD_PRIORITY:
00994          break;
00995       }
00996    }
00997 
00998 done:
00999    if (mod_count) {
01000       *mod_count += count;
01001    }
01002    ast_heap_destroy(resource_heap);
01003 
01004    return res;
01005 }
01006 
01007 int load_modules(unsigned int preload_only)
01008 {
01009    struct ast_config *cfg;
01010    struct ast_module *mod;
01011    struct load_order_entry *order;
01012    struct ast_variable *v;
01013    unsigned int load_count;
01014    struct load_order load_order;
01015    int res = 0;
01016    struct ast_flags config_flags = { 0 };
01017    int modulecount = 0;
01018 
01019 #ifdef LOADABLE_MODULES
01020    struct dirent *dirent;
01021    DIR *dir;
01022 #endif
01023 
01024    /* all embedded modules have registered themselves by now */
01025    embedding = 0;
01026 
01027    ast_verb(1, "Asterisk Dynamic Loader Starting:\n");
01028 
01029    AST_LIST_HEAD_INIT_NOLOCK(&load_order);
01030 
01031    AST_LIST_LOCK(&module_list);
01032 
01033    if (embedded_module_list.first) {
01034       module_list.first = embedded_module_list.first;
01035       module_list.last = embedded_module_list.last;
01036       embedded_module_list.first = NULL;
01037    }
01038 
01039    cfg = ast_config_load2(AST_MODULE_CONFIG, "" /* core, can't reload */, config_flags);
01040    if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEINVALID) {
01041       ast_log(LOG_WARNING, "No '%s' found, no modules will be loaded.\n", AST_MODULE_CONFIG);
01042       goto done;
01043    }
01044 
01045    /* first, find all the modules we have been explicitly requested to load */
01046    for (v = ast_variable_browse(cfg, "modules"); v; v = v->next) {
01047       if (!strcasecmp(v->name, preload_only ? "preload" : "load")) {
01048          add_to_load_order(v->value, &load_order, 0);
01049       }
01050       if (!strcasecmp(v->name, preload_only ? "preload-require" : "require")) {
01051          /* Add the module to the list and make sure it's required */
01052          add_to_load_order(v->value, &load_order, 1);
01053          ast_debug(2, "Adding module to required list: %s (%s)\n", v->value, v->name);
01054       }
01055 
01056    }
01057 
01058    /* check if 'autoload' is on */
01059    if (!preload_only && ast_true(ast_variable_retrieve(cfg, "modules", "autoload"))) {
01060       /* if so, first add all the embedded modules that are not already running to the load order */
01061       AST_LIST_TRAVERSE(&module_list, mod, entry) {
01062          /* if it's not embedded, skip it */
01063          if (mod->lib)
01064             continue;
01065 
01066          if (mod->flags.running)
01067             continue;
01068 
01069          order = add_to_load_order(mod->resource, &load_order, 0);
01070       }
01071 
01072 #ifdef LOADABLE_MODULES
01073       /* if we are allowed to load dynamic modules, scan the directory for
01074          for all available modules and add them as well */
01075       if ((dir  = opendir(ast_config_AST_MODULE_DIR))) {
01076          while ((dirent = readdir(dir))) {
01077             int ld = strlen(dirent->d_name);
01078 
01079             /* Must end in .so to load it.  */
01080 
01081             if (ld < 4)
01082                continue;
01083 
01084             if (strcasecmp(dirent->d_name + ld - 3, ".so"))
01085                continue;
01086 
01087             /* if there is already a module by this name in the module_list,
01088                skip this file */
01089             if (find_resource(dirent->d_name, 0))
01090                continue;
01091 
01092             add_to_load_order(dirent->d_name, &load_order, 0);
01093          }
01094 
01095          closedir(dir);
01096       } else {
01097          if (!ast_opt_quiet)
01098             ast_log(LOG_WARNING, "Unable to open modules directory '%s'.\n",
01099                ast_config_AST_MODULE_DIR);
01100       }
01101 #endif
01102    }
01103 
01104    /* now scan the config for any modules we are prohibited from loading and
01105       remove them from the load order */
01106    for (v = ast_variable_browse(cfg, "modules"); v; v = v->next) {
01107       if (strcasecmp(v->name, "noload"))
01108          continue;
01109 
01110       AST_LIST_TRAVERSE_SAFE_BEGIN(&load_order, order, entry) {
01111          if (!resource_name_match(order->resource, v->value)) {
01112             AST_LIST_REMOVE_CURRENT(entry);
01113             ast_free(order->resource);
01114             ast_free(order);
01115          }
01116       }
01117       AST_LIST_TRAVERSE_SAFE_END;
01118    }
01119 
01120    /* we are done with the config now, all the information we need is in the
01121       load_order list */
01122    ast_config_destroy(cfg);
01123 
01124    load_count = 0;
01125    AST_LIST_TRAVERSE(&load_order, order, entry)
01126       load_count++;
01127 
01128    if (load_count)
01129       ast_log(LOG_NOTICE, "%d modules will be loaded.\n", load_count);
01130 
01131    /* first, load only modules that provide global symbols */
01132    if ((res = load_resource_list(&load_order, 1, &modulecount)) < 0) {
01133       goto done;
01134    }
01135 
01136    /* now load everything else */
01137    if ((res = load_resource_list(&load_order, 0, &modulecount)) < 0) {
01138       goto done;
01139    }
01140 
01141 done:
01142    while ((order = AST_LIST_REMOVE_HEAD(&load_order, entry))) {
01143       ast_free(order->resource);
01144       ast_free(order);
01145    }
01146 
01147    AST_LIST_UNLOCK(&module_list);
01148    
01149    /* Tell manager clients that are aggressive at logging in that we're done
01150       loading modules. If there's a DNS problem in chan_sip, we might not
01151       even reach this */
01152    manager_event(EVENT_FLAG_SYSTEM, "ModuleLoadReport", "ModuleLoadStatus: Done\r\nModuleSelection: %s\r\nModuleCount: %d\r\n", preload_only ? "Preload" : "All", modulecount);
01153    
01154    return res;
01155 }
01156 
01157 void ast_update_use_count(void)
01158 {
01159    /* Notify any module monitors that the use count for a
01160       resource has changed */
01161    struct loadupdate *m;
01162 
01163    AST_LIST_LOCK(&updaters);
01164    AST_LIST_TRAVERSE(&updaters, m, entry)
01165       m->updater();
01166    AST_LIST_UNLOCK(&updaters);
01167 }
01168 
01169 int ast_update_module_list(int (*modentry)(const char *module, const char *description, int usecnt, const char *like),
01170             const char *like)
01171 {
01172    struct ast_module *cur;
01173    int unlock = -1;
01174    int total_mod_loaded = 0;
01175 
01176    if (AST_LIST_TRYLOCK(&module_list))
01177       unlock = 0;
01178  
01179    AST_LIST_TRAVERSE(&module_list, cur, entry) {
01180       total_mod_loaded += modentry(cur->resource, cur->info->description, cur->usecount, like);
01181    }
01182 
01183    if (unlock)
01184       AST_LIST_UNLOCK(&module_list);
01185 
01186    return total_mod_loaded;
01187 }
01188 
01189 /*! \brief Check if module exists */
01190 int ast_module_check(const char *name)
01191 {
01192    struct ast_module *cur;
01193 
01194    if (ast_strlen_zero(name))
01195       return 0;       /* FALSE */
01196 
01197    cur = find_resource(name, 1);
01198 
01199    return (cur != NULL);
01200 }
01201 
01202 
01203 int ast_loader_register(int (*v)(void))
01204 {
01205    struct loadupdate *tmp;
01206 
01207    if (!(tmp = ast_malloc(sizeof(*tmp))))
01208       return -1;
01209 
01210    tmp->updater = v;
01211    AST_LIST_LOCK(&updaters);
01212    AST_LIST_INSERT_HEAD(&updaters, tmp, entry);
01213    AST_LIST_UNLOCK(&updaters);
01214 
01215    return 0;
01216 }
01217 
01218 int ast_loader_unregister(int (*v)(void))
01219 {
01220    struct loadupdate *cur;
01221 
01222    AST_LIST_LOCK(&updaters);
01223    AST_LIST_TRAVERSE_SAFE_BEGIN(&updaters, cur, entry) {
01224       if (cur->updater == v)  {
01225          AST_LIST_REMOVE_CURRENT(entry);
01226          break;
01227       }
01228    }
01229    AST_LIST_TRAVERSE_SAFE_END;
01230    AST_LIST_UNLOCK(&updaters);
01231 
01232    return cur ? 0 : -1;
01233 }
01234 
01235 struct ast_module *ast_module_ref(struct ast_module *mod)
01236 {
01237    if (!mod) {
01238       return NULL;
01239    }
01240 
01241    ast_atomic_fetchadd_int(&mod->usecount, +1);
01242    ast_update_use_count();
01243 
01244    return mod;
01245 }
01246 
01247 void ast_module_unref(struct ast_module *mod)
01248 {
01249    if (!mod) {
01250       return;
01251    }
01252 
01253    ast_atomic_fetchadd_int(&mod->usecount, -1);
01254    ast_update_use_count();
01255 }