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 /*** MODULEINFO
00031    <support_level>core</support_level>
00032  ***/
00033 
00034 #include "asterisk.h"
00035 
00036 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 434546 $")
00037 
00038 #include "asterisk/_private.h"
00039 #include "asterisk/paths.h"   /* use ast_config_AST_MODULE_DIR */
00040 #include <dirent.h>
00041 
00042 #include "asterisk/dlinkedlists.h"
00043 #include "asterisk/module.h"
00044 #include "asterisk/config.h"
00045 #include "asterisk/channel.h"
00046 #include "asterisk/term.h"
00047 #include "asterisk/acl.h"
00048 #include "asterisk/manager.h"
00049 #include "asterisk/cdr.h"
00050 #include "asterisk/enum.h"
00051 #include "asterisk/http.h"
00052 #include "asterisk/lock.h"
00053 #include "asterisk/features_config.h"
00054 #include "asterisk/dsp.h"
00055 #include "asterisk/udptl.h"
00056 #include "asterisk/heap.h"
00057 #include "asterisk/app.h"
00058 #include "asterisk/test.h"
00059 #include "asterisk/sounds_index.h"
00060 
00061 #include <dlfcn.h>
00062 
00063 #include "asterisk/md5.h"
00064 #include "asterisk/utils.h"
00065 
00066 /*** DOCUMENTATION
00067    <managerEvent language="en_US" name="Reload">
00068       <managerEventInstance class="EVENT_FLAG_SYSTEM">
00069          <synopsis>Raised when a module has been reloaded in Asterisk.</synopsis>
00070          <syntax>
00071             <parameter name="Module">
00072                <para>The name of the module that was reloaded, or
00073                <literal>All</literal> if all modules were reloaded</para>
00074             </parameter>
00075             <parameter name="Status">
00076                <para>The numeric status code denoting the success or failure
00077                of the reload request.</para>
00078                <enumlist>
00079                   <enum name="0"><para>Success</para></enum>
00080                   <enum name="1"><para>Request queued</para></enum>
00081                   <enum name="2"><para>Module not found</para></enum>
00082                   <enum name="3"><para>Error</para></enum>
00083                   <enum name="4"><para>Reload already in progress</para></enum>
00084                   <enum name="5"><para>Module uninitialized</para></enum>
00085                   <enum name="6"><para>Reload not supported</para></enum>
00086                </enumlist>
00087             </parameter>
00088          </syntax>
00089       </managerEventInstance>
00090    </managerEvent>
00091  ***/
00092 
00093 #ifndef RTLD_NOW
00094 #define RTLD_NOW 0
00095 #endif
00096 
00097 #ifndef RTLD_LOCAL
00098 #define RTLD_LOCAL 0
00099 #endif
00100 
00101 struct ast_module_user {
00102    struct ast_channel *chan;
00103    AST_LIST_ENTRY(ast_module_user) entry;
00104 };
00105 
00106 AST_DLLIST_HEAD(module_user_list, ast_module_user);
00107 
00108 static const unsigned char expected_key[] =
00109 { 0x87, 0x76, 0x79, 0x35, 0x23, 0xea, 0x3a, 0xd3,
00110   0x25, 0x2a, 0xbb, 0x35, 0x87, 0xe4, 0x22, 0x24 };
00111 
00112 static char buildopt_sum[33] = AST_BUILDOPT_SUM;
00113 
00114 static unsigned int embedding = 1; /* we always start out by registering embedded modules,
00115                   since they are here before we dlopen() any
00116                */
00117 
00118 /*!
00119  * \brief Internal flag to indicate all modules have been initially loaded.
00120  */
00121 static int modules_loaded;
00122 
00123 struct ast_module {
00124    const struct ast_module_info *info;
00125 #ifdef REF_DEBUG
00126    /* Used to get module references into REF_DEBUG logs */
00127    void *ref_debug;
00128 #endif
00129    void *lib;              /* the shared lib, or NULL if embedded */
00130    int usecount;              /* the number of 'users' currently in this module */
00131    struct module_user_list users;         /* the list of users in the module */
00132    struct {
00133       unsigned int running:1;
00134       unsigned int declined:1;
00135       unsigned int keepuntilshutdown:1;
00136    } flags;
00137    AST_LIST_ENTRY(ast_module) list_entry;
00138    AST_DLLIST_ENTRY(ast_module) entry;
00139    char resource[0];
00140 };
00141 
00142 static AST_DLLIST_HEAD_STATIC(module_list, ast_module);
00143 
00144 const char *ast_module_name(const struct ast_module *mod)
00145 {
00146    if (!mod || !mod->info) {
00147       return NULL;
00148    }
00149 
00150    return mod->info->name;
00151 }
00152 
00153 /*
00154  * module_list is cleared by its constructor possibly after
00155  * we start accumulating embedded modules, so we need to
00156  * use another list (without the lock) to accumulate them.
00157  * Then we update the main list when embedding is done.
00158  */
00159 static struct module_list embedded_module_list;
00160 
00161 struct loadupdate {
00162    int (*updater)(void);
00163    AST_LIST_ENTRY(loadupdate) entry;
00164 };
00165 
00166 static AST_DLLIST_HEAD_STATIC(updaters, loadupdate);
00167 
00168 AST_MUTEX_DEFINE_STATIC(reloadlock);
00169 
00170 struct reload_queue_item {
00171    AST_LIST_ENTRY(reload_queue_item) entry;
00172    char module[0];
00173 };
00174 
00175 static int do_full_reload = 0;
00176 
00177 static AST_DLLIST_HEAD_STATIC(reload_queue, reload_queue_item);
00178 
00179 /* when dynamic modules are being loaded, ast_module_register() will
00180    need to know what filename the module was loaded from while it
00181    is being registered
00182 */
00183 static struct ast_module *resource_being_loaded;
00184 
00185 /* XXX: should we check for duplicate resource names here? */
00186 
00187 void ast_module_register(const struct ast_module_info *info)
00188 {
00189    struct ast_module *mod;
00190 
00191    if (embedding) {
00192       if (!(mod = ast_calloc(1, sizeof(*mod) + strlen(info->name) + 1)))
00193          return;
00194       strcpy(mod->resource, info->name);
00195    } else {
00196       mod = resource_being_loaded;
00197    }
00198 
00199    ast_debug(5, "Registering module %s\n", info->name);
00200 
00201    mod->info = info;
00202 #ifdef REF_DEBUG
00203    mod->ref_debug = ao2_t_alloc(0, NULL, info->name);
00204 #endif
00205    AST_LIST_HEAD_INIT(&mod->users);
00206 
00207    /* during startup, before the loader has been initialized,
00208       there are no threads, so there is no need to take the lock
00209       on this list to manipulate it. it is also possible that it
00210       might be unsafe to use the list lock at that point... so
00211       let's avoid it altogether
00212    */
00213    if (embedding) {
00214       AST_DLLIST_INSERT_TAIL(&embedded_module_list, mod, entry);
00215    } else {
00216       AST_DLLIST_LOCK(&module_list);
00217       /* it is paramount that the new entry be placed at the tail of
00218          the list, otherwise the code that uses dlopen() to load
00219          dynamic modules won't be able to find out if the module it
00220          just opened was registered or failed to load
00221       */
00222       AST_DLLIST_INSERT_TAIL(&module_list, mod, entry);
00223       AST_DLLIST_UNLOCK(&module_list);
00224    }
00225 
00226    /* give the module a copy of its own handle, for later use in registrations and the like */
00227    *((struct ast_module **) &(info->self)) = mod;
00228 }
00229 
00230 void ast_module_unregister(const struct ast_module_info *info)
00231 {
00232    struct ast_module *mod = NULL;
00233 
00234    /* it is assumed that the users list in the module structure
00235       will already be empty, or we cannot have gotten to this
00236       point
00237    */
00238    AST_DLLIST_LOCK(&module_list);
00239    AST_DLLIST_TRAVERSE_BACKWARDS_SAFE_BEGIN(&module_list, mod, entry) {
00240       if (mod->info == info) {
00241          AST_DLLIST_REMOVE_CURRENT(entry);
00242          break;
00243       }
00244    }
00245    AST_DLLIST_TRAVERSE_BACKWARDS_SAFE_END;
00246    AST_DLLIST_UNLOCK(&module_list);
00247 
00248    if (mod) {
00249       ast_debug(5, "Unregistering module %s\n", info->name);
00250       AST_LIST_HEAD_DESTROY(&mod->users);
00251 #ifdef REF_DEBUG
00252       ao2_cleanup(mod->ref_debug);
00253 #endif
00254       ast_free(mod);
00255    }
00256 }
00257 
00258 struct ast_module_user *__ast_module_user_add(struct ast_module *mod, struct ast_channel *chan)
00259 {
00260    struct ast_module_user *u;
00261 
00262    u = ast_calloc(1, sizeof(*u));
00263    if (!u) {
00264       return NULL;
00265    }
00266 
00267    u->chan = chan;
00268 
00269    AST_LIST_LOCK(&mod->users);
00270    AST_LIST_INSERT_HEAD(&mod->users, u, entry);
00271    AST_LIST_UNLOCK(&mod->users);
00272 
00273 #ifdef REF_DEBUG
00274    ao2_ref(mod->ref_debug, +1);
00275 #endif
00276 
00277    ast_atomic_fetchadd_int(&mod->usecount, +1);
00278 
00279    ast_update_use_count();
00280 
00281    return u;
00282 }
00283 
00284 void __ast_module_user_remove(struct ast_module *mod, struct ast_module_user *u)
00285 {
00286    if (!u) {
00287       return;
00288    }
00289 
00290    AST_LIST_LOCK(&mod->users);
00291    u = AST_LIST_REMOVE(&mod->users, u, entry);
00292    AST_LIST_UNLOCK(&mod->users);
00293    if (!u) {
00294       /*
00295        * Was not in the list.  Either a bad pointer or
00296        * __ast_module_user_hangup_all() has been called.
00297        */
00298       return;
00299    }
00300 
00301 #ifdef REF_DEBUG
00302    ao2_ref(mod->ref_debug, -1);
00303 #endif
00304 
00305    ast_atomic_fetchadd_int(&mod->usecount, -1);
00306    ast_free(u);
00307 
00308    ast_update_use_count();
00309 }
00310 
00311 void __ast_module_user_hangup_all(struct ast_module *mod)
00312 {
00313    struct ast_module_user *u;
00314 
00315    AST_LIST_LOCK(&mod->users);
00316    while ((u = AST_LIST_REMOVE_HEAD(&mod->users, entry))) {
00317       if (u->chan) {
00318          ast_softhangup(u->chan, AST_SOFTHANGUP_APPUNLOAD);
00319       }
00320 
00321 #ifdef REF_DEBUG
00322       ao2_ref(mod->ref_debug, -1);
00323 #endif
00324 
00325       ast_atomic_fetchadd_int(&mod->usecount, -1);
00326       ast_free(u);
00327    }
00328    AST_LIST_UNLOCK(&mod->users);
00329 
00330    ast_update_use_count();
00331 }
00332 
00333 /*! \note
00334  * In addition to modules, the reload command handles some extra keywords
00335  * which are listed here together with the corresponding handlers.
00336  * This table is also used by the command completion code.
00337  */
00338 static struct reload_classes {
00339    const char *name;
00340    int (*reload_fn)(void);
00341 } reload_classes[] = {  /* list in alpha order, longest match first for cli completion */
00342    { "acl",         ast_named_acl_reload },
00343    { "cdr",         ast_cdr_engine_reload },
00344    { "cel",         ast_cel_engine_reload },
00345    { "dnsmgr",      dnsmgr_reload },
00346    { "dsp",         ast_dsp_reload},
00347    { "extconfig",   read_config_maps },
00348    { "enum",        ast_enum_reload },
00349    { "features",    ast_features_config_reload },
00350    { "http",        ast_http_reload },
00351    { "indications", ast_indications_reload },
00352    { "logger",      logger_reload },
00353    { "manager",     reload_manager },
00354    { "plc",         ast_plc_reload },
00355    { "sounds",      ast_sounds_reindex },
00356    { "udptl",       ast_udptl_reload },
00357    { NULL,          NULL }
00358 };
00359 
00360 static int printdigest(const unsigned char *d)
00361 {
00362    int x, pos;
00363    char buf[256]; /* large enough so we don't have to worry */
00364 
00365    for (pos = 0, x = 0; x < 16; x++)
00366       pos += sprintf(buf + pos, " %02hhx", *d++);
00367 
00368    ast_debug(1, "Unexpected signature:%s\n", buf);
00369 
00370    return 0;
00371 }
00372 
00373 static int key_matches(const unsigned char *key1, const unsigned char *key2)
00374 {
00375    int x;
00376 
00377    for (x = 0; x < 16; x++) {
00378       if (key1[x] != key2[x])
00379          return 0;
00380    }
00381 
00382    return 1;
00383 }
00384 
00385 static int verify_key(const unsigned char *key)
00386 {
00387    struct MD5Context c;
00388    unsigned char digest[16];
00389 
00390    MD5Init(&c);
00391    MD5Update(&c, key, strlen((char *)key));
00392    MD5Final(digest, &c);
00393 
00394    if (key_matches(expected_key, digest))
00395       return 0;
00396 
00397    printdigest(digest);
00398 
00399    return -1;
00400 }
00401 
00402 static int resource_name_match(const char *name1_in, const char *name2_in)
00403 {
00404    char *name1 = (char *) name1_in;
00405    char *name2 = (char *) name2_in;
00406 
00407    /* trim off any .so extensions */
00408    if (!strcasecmp(name1 + strlen(name1) - 3, ".so")) {
00409       name1 = ast_strdupa(name1);
00410       name1[strlen(name1) - 3] = '\0';
00411    }
00412    if (!strcasecmp(name2 + strlen(name2) - 3, ".so")) {
00413       name2 = ast_strdupa(name2);
00414       name2[strlen(name2) - 3] = '\0';
00415    }
00416 
00417    return strcasecmp(name1, name2);
00418 }
00419 
00420 static struct ast_module *find_resource(const char *resource, int do_lock)
00421 {
00422    struct ast_module *cur;
00423 
00424    if (do_lock) {
00425       AST_DLLIST_LOCK(&module_list);
00426    }
00427 
00428    AST_DLLIST_TRAVERSE(&module_list, cur, entry) {
00429       if (!resource_name_match(resource, cur->resource))
00430          break;
00431    }
00432 
00433    if (do_lock) {
00434       AST_DLLIST_UNLOCK(&module_list);
00435    }
00436 
00437    return cur;
00438 }
00439 
00440 #ifdef LOADABLE_MODULES
00441 
00442 /*!
00443  * \brief dlclose(), with failure logging.
00444  */
00445 static void logged_dlclose(const char *name, void *lib)
00446 {
00447    char *error;
00448 
00449    if (!lib) {
00450       return;
00451    }
00452 
00453    /* Clear any existing error */
00454    dlerror();
00455    if (dlclose(lib)) {
00456       error = dlerror();
00457       ast_log(AST_LOG_ERROR, "Failure in dlclose for module '%s': %s\n",
00458          S_OR(name, "unknown"), S_OR(error, "Unknown error"));
00459    }
00460 }
00461 
00462 #if defined(HAVE_RTLD_NOLOAD)
00463 /*!
00464  * \brief Check to see if the given resource is loaded.
00465  *
00466  * \param resource_name Name of the resource, including .so suffix.
00467  * \return False (0) if module is not loaded.
00468  * \return True (non-zero) if module is loaded.
00469  */
00470 static int is_module_loaded(const char *resource_name)
00471 {
00472    char fn[PATH_MAX] = "";
00473    void *lib;
00474 
00475    snprintf(fn, sizeof(fn), "%s/%s", ast_config_AST_MODULE_DIR,
00476       resource_name);
00477 
00478    lib = dlopen(fn, RTLD_LAZY | RTLD_NOLOAD);
00479 
00480    if (lib) {
00481       logged_dlclose(resource_name, lib);
00482       return 1;
00483    }
00484 
00485    return 0;
00486 }
00487 #endif
00488 
00489 static void unload_dynamic_module(struct ast_module *mod)
00490 {
00491 #if defined(HAVE_RTLD_NOLOAD)
00492    char *name = ast_strdupa(ast_module_name(mod));
00493 #endif
00494    void *lib = mod->lib;
00495 
00496    /* WARNING: the structure pointed to by mod is going to
00497       disappear when this operation succeeds, so we can't
00498       dereference it */
00499    logged_dlclose(ast_module_name(mod), lib);
00500 
00501    /* There are several situations where the module might still be resident
00502     * in memory.
00503     *
00504     * If somehow there was another dlopen() on the same module (unlikely,
00505     * since that all is supposed to happen in loader.c).
00506     *
00507     * Or the lazy resolution of a global symbol (very likely, since that is
00508     * how we load all of our modules that export global symbols).
00509     *
00510     * Avoid the temptation of repeating the dlclose(). The other code that
00511     * dlopened the module still has its module reference, and should close
00512     * it itself. In other situations, dlclose() will happily return success
00513     * for as many times as you wish to call it.
00514     */
00515 #if defined(HAVE_RTLD_NOLOAD)
00516    if (is_module_loaded(name)) {
00517       ast_log(LOG_WARNING, "Module '%s' could not be completely unloaded\n", name);
00518    }
00519 #endif
00520 }
00521 
00522 static enum ast_module_load_result load_resource(const char *resource_name, unsigned int global_symbols_only, struct ast_heap *resource_heap, int required);
00523 
00524 static struct ast_module *load_dynamic_module(const char *resource_in, unsigned int global_symbols_only, struct ast_heap *resource_heap)
00525 {
00526    char fn[PATH_MAX] = "";
00527    void *lib = NULL;
00528    struct ast_module *mod;
00529    unsigned int wants_global;
00530    int space;  /* room needed for the descriptor */
00531    int missing_so = 0;
00532 
00533    space = sizeof(*resource_being_loaded) + strlen(resource_in) + 1;
00534    if (strcasecmp(resource_in + strlen(resource_in) - 3, ".so")) {
00535       missing_so = 1;
00536       space += 3; /* room for the extra ".so" */
00537    }
00538 
00539    snprintf(fn, sizeof(fn), "%s/%s%s", ast_config_AST_MODULE_DIR, resource_in, missing_so ? ".so" : "");
00540 
00541    /* make a first load of the module in 'quiet' mode... don't try to resolve
00542       any symbols, and don't export any symbols. this will allow us to peek into
00543       the module's info block (if available) to see what flags it has set */
00544 
00545    resource_being_loaded = ast_calloc(1, space);
00546    if (!resource_being_loaded)
00547       return NULL;
00548    strcpy(resource_being_loaded->resource, resource_in);
00549    if (missing_so)
00550       strcat(resource_being_loaded->resource, ".so");
00551 
00552    if (!(lib = dlopen(fn, RTLD_LAZY | RTLD_LOCAL))) {
00553       ast_log(LOG_WARNING, "Error loading module '%s': %s\n", resource_in, dlerror());
00554       ast_free(resource_being_loaded);
00555       return NULL;
00556    }
00557 
00558    /* the dlopen() succeeded, let's find out if the module
00559       registered itself */
00560    /* note that this will only work properly as long as
00561       ast_module_register() (which is called by the module's
00562       constructor) places the new module at the tail of the
00563       module_list
00564    */
00565    if (resource_being_loaded != (mod = AST_DLLIST_LAST(&module_list))) {
00566       ast_log(LOG_WARNING, "Module '%s' did not register itself during load\n", resource_in);
00567       /* no, it did not, so close it and return */
00568       logged_dlclose(resource_in, lib);
00569       /* note that the module's destructor will call ast_module_unregister(),
00570          which will free the structure we allocated in resource_being_loaded */
00571       return NULL;
00572    }
00573 
00574    wants_global = ast_test_flag(mod->info, AST_MODFLAG_GLOBAL_SYMBOLS);
00575 
00576    /* if we are being asked only to load modules that provide global symbols,
00577       and this one does not, then close it and return */
00578    if (global_symbols_only && !wants_global) {
00579       logged_dlclose(resource_in, lib);
00580       return NULL;
00581    }
00582 
00583    logged_dlclose(resource_in, lib);
00584    resource_being_loaded = NULL;
00585 
00586    /* start the load process again */
00587    resource_being_loaded = ast_calloc(1, space);
00588    if (!resource_being_loaded)
00589       return NULL;
00590    strcpy(resource_being_loaded->resource, resource_in);
00591    if (missing_so)
00592       strcat(resource_being_loaded->resource, ".so");
00593 
00594    if (!(lib = dlopen(fn, wants_global ? RTLD_LAZY | RTLD_GLOBAL : RTLD_NOW | RTLD_LOCAL))) {
00595       ast_log(LOG_WARNING, "Error loading module '%s': %s\n", resource_in, dlerror());
00596       ast_free(resource_being_loaded);
00597       return NULL;
00598    }
00599 
00600    /* since the module was successfully opened, and it registered itself
00601       the previous time we did that, we're going to assume it worked this
00602       time too :) */
00603 
00604    AST_DLLIST_LAST(&module_list)->lib = lib;
00605    resource_being_loaded = NULL;
00606 
00607    return AST_DLLIST_LAST(&module_list);
00608 }
00609 
00610 #endif
00611 
00612 void ast_module_shutdown(void)
00613 {
00614    struct ast_module *mod;
00615    int somethingchanged = 1, final = 0;
00616 
00617    AST_DLLIST_LOCK(&module_list);
00618 
00619    /*!\note Some resources, like timers, are started up dynamically, and thus
00620     * may be still in use, even if all channels are dead.  We must therefore
00621     * check the usecount before asking modules to unload. */
00622    do {
00623       if (!somethingchanged) {
00624          /*!\note If we go through the entire list without changing
00625           * anything, ignore the usecounts and unload, then exit. */
00626          final = 1;
00627       }
00628 
00629       /* Reset flag before traversing the list */
00630       somethingchanged = 0;
00631 
00632       AST_DLLIST_TRAVERSE_BACKWARDS_SAFE_BEGIN(&module_list, mod, entry) {
00633          if (!final && mod->usecount) {
00634             ast_debug(1, "Passing on %s: its use count is %d\n",
00635                mod->resource, mod->usecount);
00636             continue;
00637          }
00638          AST_DLLIST_REMOVE_CURRENT(entry);
00639          if (mod->flags.running && !mod->flags.declined && mod->info->unload) {
00640             ast_verb(1, "Unloading %s\n", mod->resource);
00641             mod->info->unload();
00642          }
00643          AST_LIST_HEAD_DESTROY(&mod->users);
00644 #ifdef REF_DEBUG
00645          ao2_cleanup(mod->ref_debug);
00646 #endif
00647          ast_free(mod);
00648          somethingchanged = 1;
00649       }
00650       AST_DLLIST_TRAVERSE_BACKWARDS_SAFE_END;
00651       if (!somethingchanged) {
00652          AST_DLLIST_TRAVERSE(&module_list, mod, entry) {
00653             if (mod->flags.keepuntilshutdown) {
00654                ast_module_unref(mod);
00655                mod->flags.keepuntilshutdown = 0;
00656                somethingchanged = 1;
00657             }
00658          }
00659       }
00660    } while (somethingchanged && !final);
00661 
00662    AST_DLLIST_UNLOCK(&module_list);
00663 }
00664 
00665 int ast_unload_resource(const char *resource_name, enum ast_module_unload_mode force)
00666 {
00667    struct ast_module *mod;
00668    int res = -1;
00669    int error = 0;
00670 
00671    AST_DLLIST_LOCK(&module_list);
00672 
00673    if (!(mod = find_resource(resource_name, 0))) {
00674       AST_DLLIST_UNLOCK(&module_list);
00675       ast_log(LOG_WARNING, "Unload failed, '%s' could not be found\n", resource_name);
00676       return -1;
00677    }
00678 
00679    if (!mod->flags.running || mod->flags.declined) {
00680       ast_log(LOG_WARNING, "Unload failed, '%s' is not loaded.\n", resource_name);
00681       error = 1;
00682    }
00683 
00684    if (!error && (mod->usecount > 0)) {
00685       if (force)
00686          ast_log(LOG_WARNING, "Warning:  Forcing removal of module '%s' with use count %d\n",
00687             resource_name, mod->usecount);
00688       else {
00689          ast_log(LOG_WARNING, "Soft unload failed, '%s' has use count %d\n", resource_name,
00690             mod->usecount);
00691          error = 1;
00692       }
00693    }
00694 
00695    if (!error) {
00696       /* Request any channels attached to the module to hangup. */
00697       __ast_module_user_hangup_all(mod);
00698 
00699       ast_verb(1, "Unloading %s\n", mod->resource);
00700       res = mod->info->unload();
00701       if (res) {
00702          ast_log(LOG_WARNING, "Firm unload failed for %s\n", resource_name);
00703          if (force <= AST_FORCE_FIRM) {
00704             error = 1;
00705          } else {
00706             ast_log(LOG_WARNING, "** Dangerous **: Unloading resource anyway, at user request\n");
00707          }
00708       }
00709 
00710       if (!error) {
00711          /*
00712           * Request hangup on any channels that managed to get attached
00713           * while we called the module unload function.
00714           */
00715          __ast_module_user_hangup_all(mod);
00716          sched_yield();
00717       }
00718    }
00719 
00720    if (!error)
00721       mod->flags.running = mod->flags.declined = 0;
00722 
00723    AST_DLLIST_UNLOCK(&module_list);
00724 
00725    if (!error && !mod->lib && mod->info && mod->info->restore_globals)
00726       mod->info->restore_globals();
00727 
00728 #ifdef LOADABLE_MODULES
00729    if (!error) {
00730       unload_dynamic_module(mod);
00731       ast_test_suite_event_notify("MODULE_UNLOAD", "Message: %s", resource_name);
00732    }
00733 #endif
00734 
00735    if (!error)
00736       ast_update_use_count();
00737 
00738    return res;
00739 }
00740 
00741 char *ast_module_helper(const char *line, const char *word, int pos, int state, int rpos, int needsreload)
00742 {
00743    struct ast_module *cur;
00744    int i, which=0, l = strlen(word);
00745    char *ret = NULL;
00746 
00747    if (pos != rpos)
00748       return NULL;
00749 
00750    AST_DLLIST_LOCK(&module_list);
00751    AST_DLLIST_TRAVERSE(&module_list, cur, entry) {
00752       if (!strncasecmp(word, cur->resource, l) &&
00753           (cur->info->reload || !needsreload) &&
00754           ++which > state) {
00755          ret = ast_strdup(cur->resource);
00756          break;
00757       }
00758    }
00759    AST_DLLIST_UNLOCK(&module_list);
00760 
00761    if (!ret) {
00762       for (i=0; !ret && reload_classes[i].name; i++) {
00763          if (!strncasecmp(word, reload_classes[i].name, l) && ++which > state)
00764             ret = ast_strdup(reload_classes[i].name);
00765       }
00766    }
00767 
00768    return ret;
00769 }
00770 
00771 void ast_process_pending_reloads(void)
00772 {
00773    struct reload_queue_item *item;
00774 
00775    modules_loaded = 1;
00776 
00777    AST_LIST_LOCK(&reload_queue);
00778 
00779    if (do_full_reload) {
00780       do_full_reload = 0;
00781       AST_LIST_UNLOCK(&reload_queue);
00782       ast_log(LOG_NOTICE, "Executing deferred reload request.\n");
00783       ast_module_reload(NULL);
00784       return;
00785    }
00786 
00787    while ((item = AST_LIST_REMOVE_HEAD(&reload_queue, entry))) {
00788       ast_log(LOG_NOTICE, "Executing deferred reload request for module '%s'.\n", item->module);
00789       ast_module_reload(item->module);
00790       ast_free(item);
00791    }
00792 
00793    AST_LIST_UNLOCK(&reload_queue);
00794 }
00795 
00796 static void queue_reload_request(const char *module)
00797 {
00798    struct reload_queue_item *item;
00799 
00800    AST_LIST_LOCK(&reload_queue);
00801 
00802    if (do_full_reload) {
00803       AST_LIST_UNLOCK(&reload_queue);
00804       return;
00805    }
00806 
00807    if (ast_strlen_zero(module)) {
00808       /* A full reload request (when module is NULL) wipes out any previous
00809          reload requests and causes the queue to ignore future ones */
00810       while ((item = AST_LIST_REMOVE_HEAD(&reload_queue, entry))) {
00811          ast_free(item);
00812       }
00813       do_full_reload = 1;
00814    } else {
00815       /* No reason to add the same module twice */
00816       AST_LIST_TRAVERSE(&reload_queue, item, entry) {
00817          if (!strcasecmp(item->module, module)) {
00818             AST_LIST_UNLOCK(&reload_queue);
00819             return;
00820          }
00821       }
00822       item = ast_calloc(1, sizeof(*item) + strlen(module) + 1);
00823       if (!item) {
00824          ast_log(LOG_ERROR, "Failed to allocate reload queue item.\n");
00825          AST_LIST_UNLOCK(&reload_queue);
00826          return;
00827       }
00828       strcpy(item->module, module);
00829       AST_LIST_INSERT_TAIL(&reload_queue, item, entry);
00830    }
00831    AST_LIST_UNLOCK(&reload_queue);
00832 }
00833 
00834 /*!
00835  * \since 12
00836  * \internal
00837  * \brief Publish a \ref stasis message regarding the reload result
00838  */
00839 static void publish_reload_message(const char *name, enum ast_module_reload_result result)
00840 {
00841    RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
00842    RAII_VAR(struct ast_json_payload *, payload, NULL, ao2_cleanup);
00843    RAII_VAR(struct ast_json *, json_object, NULL, ast_json_unref);
00844    RAII_VAR(struct ast_json *, event_object, NULL, ast_json_unref);
00845    char res_buffer[8];
00846 
00847    if (!ast_manager_get_generic_type()) {
00848       return;
00849    }
00850 
00851    snprintf(res_buffer, sizeof(res_buffer), "%u", result);
00852    event_object = ast_json_pack("{s: s, s: s}",
00853          "Module", S_OR(name, "All"),
00854          "Status", res_buffer);
00855    json_object = ast_json_pack("{s: s, s: i, s: O}",
00856          "type", "Reload",
00857          "class_type", EVENT_FLAG_SYSTEM,
00858          "event", event_object);
00859 
00860    if (!json_object) {
00861       return;
00862    }
00863 
00864    payload = ast_json_payload_create(json_object);
00865    if (!payload) {
00866       return;
00867    }
00868 
00869    message = stasis_message_create(ast_manager_get_generic_type(), payload);
00870    if (!message) {
00871       return;
00872    }
00873 
00874    stasis_publish(ast_manager_get_topic(), message);
00875 }
00876 
00877 enum ast_module_reload_result ast_module_reload(const char *name)
00878 {
00879    struct ast_module *cur;
00880    enum ast_module_reload_result res = AST_MODULE_RELOAD_NOT_FOUND;
00881    int i;
00882 
00883    /* If we aren't fully booted, we just pretend we reloaded but we queue this
00884       up to run once we are booted up. */
00885    if (!modules_loaded) {
00886       queue_reload_request(name);
00887       res = AST_MODULE_RELOAD_QUEUED;
00888       goto module_reload_exit;
00889    }
00890 
00891    if (ast_mutex_trylock(&reloadlock)) {
00892       ast_verb(3, "The previous reload command didn't finish yet\n");
00893       res = AST_MODULE_RELOAD_IN_PROGRESS;
00894       goto module_reload_exit;
00895    }
00896    ast_lastreloadtime = ast_tvnow();
00897 
00898    if (ast_opt_lock_confdir) {
00899       int try;
00900       int res;
00901       for (try = 1, res = AST_LOCK_TIMEOUT; try < 6 && (res == AST_LOCK_TIMEOUT); try++) {
00902          res = ast_lock_path(ast_config_AST_CONFIG_DIR);
00903          if (res == AST_LOCK_TIMEOUT) {
00904             ast_log(LOG_WARNING, "Failed to grab lock on %s, try %d\n", ast_config_AST_CONFIG_DIR, try);
00905          }
00906       }
00907       if (res != AST_LOCK_SUCCESS) {
00908          ast_log(AST_LOG_WARNING, "Cannot grab lock on %s\n", ast_config_AST_CONFIG_DIR);
00909          ast_mutex_unlock(&reloadlock);
00910          res = AST_MODULE_RELOAD_ERROR;
00911          goto module_reload_exit;
00912       }
00913    }
00914 
00915    /* Call "predefined" reload here first */
00916    for (i = 0; reload_classes[i].name; i++) {
00917       if (!name || !strcasecmp(name, reload_classes[i].name)) {
00918          if (reload_classes[i].reload_fn() == AST_MODULE_LOAD_SUCCESS) {
00919             res = AST_MODULE_RELOAD_SUCCESS;
00920          }
00921       }
00922    }
00923 
00924    if (name && res == AST_MODULE_RELOAD_SUCCESS) {
00925       if (ast_opt_lock_confdir) {
00926          ast_unlock_path(ast_config_AST_CONFIG_DIR);
00927       }
00928       ast_mutex_unlock(&reloadlock);
00929       goto module_reload_exit;
00930    }
00931 
00932    AST_DLLIST_LOCK(&module_list);
00933    AST_DLLIST_TRAVERSE(&module_list, cur, entry) {
00934       const struct ast_module_info *info = cur->info;
00935 
00936       if (name && resource_name_match(name, cur->resource))
00937          continue;
00938 
00939       if (!cur->flags.running || cur->flags.declined) {
00940          if (res == AST_MODULE_RELOAD_NOT_FOUND) {
00941             res = AST_MODULE_RELOAD_UNINITIALIZED;
00942          }
00943          if (!name) {
00944             continue;
00945          }
00946          break;
00947       }
00948 
00949       if (!info->reload) { /* cannot be reloaded */
00950          if (res == AST_MODULE_RELOAD_NOT_FOUND) {
00951             res = AST_MODULE_RELOAD_NOT_IMPLEMENTED;
00952          }
00953          if (!name) {
00954             continue;
00955          }
00956          break;
00957       }
00958       ast_verb(3, "Reloading module '%s' (%s)\n", cur->resource, info->description);
00959       if (info->reload() == AST_MODULE_LOAD_SUCCESS) {
00960          res = AST_MODULE_RELOAD_SUCCESS;
00961       }
00962       if (name) {
00963          break;
00964       }
00965    }
00966    AST_DLLIST_UNLOCK(&module_list);
00967 
00968    if (ast_opt_lock_confdir) {
00969       ast_unlock_path(ast_config_AST_CONFIG_DIR);
00970    }
00971    ast_mutex_unlock(&reloadlock);
00972 
00973 module_reload_exit:
00974    publish_reload_message(name, res);
00975    return res;
00976 }
00977 
00978 static unsigned int inspect_module(const struct ast_module *mod)
00979 {
00980    if (!mod->info->description) {
00981       ast_log(LOG_WARNING, "Module '%s' does not provide a description.\n", mod->resource);
00982       return 1;
00983    }
00984 
00985    if (!mod->info->key) {
00986       ast_log(LOG_WARNING, "Module '%s' does not provide a license key.\n", mod->resource);
00987       return 1;
00988    }
00989 
00990    if (verify_key((unsigned char *) mod->info->key)) {
00991       ast_log(LOG_WARNING, "Module '%s' did not provide a valid license key.\n", mod->resource);
00992       return 1;
00993    }
00994 
00995    if (!ast_strlen_zero(mod->info->buildopt_sum) &&
00996        strcmp(buildopt_sum, mod->info->buildopt_sum)) {
00997       ast_log(LOG_WARNING, "Module '%s' was not compiled with the same compile-time options as this version of Asterisk.\n", mod->resource);
00998       ast_log(LOG_WARNING, "Module '%s' will not be initialized as it may cause instability.\n", mod->resource);
00999       return 1;
01000    }
01001 
01002    return 0;
01003 }
01004 
01005 static enum ast_module_load_result start_resource(struct ast_module *mod)
01006 {
01007    char tmp[256];
01008    enum ast_module_load_result res;
01009 
01010    if (mod->flags.running) {
01011       return AST_MODULE_LOAD_SUCCESS;
01012    }
01013 
01014    if (!mod->info->load) {
01015       return AST_MODULE_LOAD_FAILURE;
01016    }
01017 
01018    if (!ast_fully_booted) {
01019       ast_verb(1, "Loading %s.\n", mod->resource);
01020    }
01021    res = mod->info->load();
01022 
01023    switch (res) {
01024    case AST_MODULE_LOAD_SUCCESS:
01025       if (!ast_fully_booted) {
01026          ast_verb(2, "%s => (%s)\n", mod->resource, term_color(tmp, mod->info->description, COLOR_BROWN, COLOR_BLACK, sizeof(tmp)));
01027       } else {
01028          ast_verb(1, "Loaded %s => (%s)\n", mod->resource, mod->info->description);
01029       }
01030 
01031       mod->flags.running = 1;
01032 
01033       ast_update_use_count();
01034       break;
01035    case AST_MODULE_LOAD_DECLINE:
01036       mod->flags.declined = 1;
01037       break;
01038    case AST_MODULE_LOAD_FAILURE:
01039    case AST_MODULE_LOAD_SKIP: /* modules should never return this value */
01040    case AST_MODULE_LOAD_PRIORITY:
01041       break;
01042    }
01043 
01044    /* Make sure the newly started module is at the end of the list */
01045    AST_DLLIST_LOCK(&module_list);
01046    AST_DLLIST_REMOVE(&module_list, mod, entry);
01047    AST_DLLIST_INSERT_TAIL(&module_list, mod, entry);
01048    AST_DLLIST_UNLOCK(&module_list);
01049 
01050    return res;
01051 }
01052 
01053 /*! loads a resource based upon resource_name. If global_symbols_only is set
01054  *  only modules with global symbols will be loaded.
01055  *
01056  *  If the ast_heap is provided (not NULL) the module is found and added to the
01057  *  heap without running the module's load() function.  By doing this, modules
01058  *  added to the resource_heap can be initialized later in order by priority.
01059  *
01060  *  If the ast_heap is not provided, the module's load function will be executed
01061  *  immediately */
01062 static enum ast_module_load_result load_resource(const char *resource_name, unsigned int global_symbols_only, struct ast_heap *resource_heap, int required)
01063 {
01064    struct ast_module *mod;
01065    enum ast_module_load_result res = AST_MODULE_LOAD_SUCCESS;
01066 
01067    if ((mod = find_resource(resource_name, 0))) {
01068       if (mod->flags.running) {
01069          ast_log(LOG_WARNING, "Module '%s' already exists.\n", resource_name);
01070          return AST_MODULE_LOAD_DECLINE;
01071       }
01072       if (global_symbols_only && !ast_test_flag(mod->info, AST_MODFLAG_GLOBAL_SYMBOLS))
01073          return AST_MODULE_LOAD_SKIP;
01074    } else {
01075 #ifdef LOADABLE_MODULES
01076       if (!(mod = load_dynamic_module(resource_name, global_symbols_only, resource_heap))) {
01077          /* don't generate a warning message during load_modules() */
01078          if (!global_symbols_only) {
01079             ast_log(LOG_WARNING, "Module '%s' could not be loaded.\n", resource_name);
01080             return required ? AST_MODULE_LOAD_FAILURE : AST_MODULE_LOAD_DECLINE;
01081          } else {
01082             return required ? AST_MODULE_LOAD_FAILURE : AST_MODULE_LOAD_SKIP;
01083          }
01084       }
01085 #else
01086       ast_log(LOG_WARNING, "Module support is not available. Module '%s' could not be loaded.\n", resource_name);
01087       return required ? AST_MODULE_LOAD_FAILURE : AST_MODULE_LOAD_DECLINE;
01088 #endif
01089    }
01090 
01091    if (inspect_module(mod)) {
01092       ast_log(LOG_WARNING, "Module '%s' could not be loaded.\n", resource_name);
01093 #ifdef LOADABLE_MODULES
01094       unload_dynamic_module(mod);
01095 #endif
01096       return required ? AST_MODULE_LOAD_FAILURE : AST_MODULE_LOAD_DECLINE;
01097    }
01098 
01099    if (!mod->lib && mod->info->backup_globals && mod->info->backup_globals()) {
01100       ast_log(LOG_WARNING, "Module '%s' was unable to backup its global data.\n", resource_name);
01101       return required ? AST_MODULE_LOAD_FAILURE : AST_MODULE_LOAD_DECLINE;
01102    }
01103 
01104    mod->flags.declined = 0;
01105 
01106    if (resource_heap) {
01107       ast_heap_push(resource_heap, mod);
01108       res = AST_MODULE_LOAD_PRIORITY;
01109    } else {
01110       res = start_resource(mod);
01111    }
01112 
01113    return res;
01114 }
01115 
01116 int ast_load_resource(const char *resource_name)
01117 {
01118    int res;
01119    AST_DLLIST_LOCK(&module_list);
01120    res = load_resource(resource_name, 0, NULL, 0);
01121    if (!res) {
01122       ast_test_suite_event_notify("MODULE_LOAD", "Message: %s", resource_name);
01123    }
01124    AST_DLLIST_UNLOCK(&module_list);
01125 
01126    return res;
01127 }
01128 
01129 struct load_order_entry {
01130    char *resource;
01131    int required;
01132    AST_LIST_ENTRY(load_order_entry) entry;
01133 };
01134 
01135 AST_LIST_HEAD_NOLOCK(load_order, load_order_entry);
01136 
01137 static struct load_order_entry *add_to_load_order(const char *resource, struct load_order *load_order, int required)
01138 {
01139    struct load_order_entry *order;
01140 
01141    AST_LIST_TRAVERSE(load_order, order, entry) {
01142       if (!resource_name_match(order->resource, resource)) {
01143          /* Make sure we have the proper setting for the required field
01144             (we might have both load= and required= lines in modules.conf) */
01145          order->required |= required;
01146          return NULL;
01147       }
01148    }
01149 
01150    if (!(order = ast_calloc(1, sizeof(*order))))
01151       return NULL;
01152 
01153    order->resource = ast_strdup(resource);
01154    order->required = required;
01155    AST_LIST_INSERT_TAIL(load_order, order, entry);
01156 
01157    return order;
01158 }
01159 
01160 static int mod_load_cmp(void *a, void *b)
01161 {
01162    struct ast_module *a_mod = (struct ast_module *) a;
01163    struct ast_module *b_mod = (struct ast_module *) b;
01164    /* if load_pri is not set, default is 128.  Lower is better */
01165    int a_pri = ast_test_flag(a_mod->info, AST_MODFLAG_LOAD_ORDER) ? a_mod->info->load_pri : 128;
01166    int b_pri = ast_test_flag(b_mod->info, AST_MODFLAG_LOAD_ORDER) ? b_mod->info->load_pri : 128;
01167 
01168    /*
01169     * Returns comparison values for a min-heap
01170     * <0 a_pri > b_pri
01171     * =0 a_pri == b_pri
01172     * >0 a_pri < b_pri
01173     */
01174    return b_pri - a_pri;
01175 }
01176 
01177 /*! loads modules in order by load_pri, updates mod_count
01178    \return -1 on failure to load module, -2 on failure to load required module, otherwise 0
01179 */
01180 static int load_resource_list(struct load_order *load_order, unsigned int global_symbols, int *mod_count)
01181 {
01182    struct ast_heap *resource_heap;
01183    struct load_order_entry *order;
01184    struct ast_module *mod;
01185    int count = 0;
01186    int res = 0;
01187 
01188    if(!(resource_heap = ast_heap_create(8, mod_load_cmp, -1))) {
01189       return -1;
01190    }
01191 
01192    /* first, add find and add modules to heap */
01193    AST_LIST_TRAVERSE_SAFE_BEGIN(load_order, order, entry) {
01194       switch (load_resource(order->resource, global_symbols, resource_heap, order->required)) {
01195       case AST_MODULE_LOAD_SUCCESS:
01196       case AST_MODULE_LOAD_DECLINE:
01197          AST_LIST_REMOVE_CURRENT(entry);
01198          ast_free(order->resource);
01199          ast_free(order);
01200          break;
01201       case AST_MODULE_LOAD_FAILURE:
01202          ast_log(LOG_ERROR, "*** Failed to load module %s - %s\n", order->resource, order->required ? "Required" : "Not required");
01203          fprintf(stderr, "*** Failed to load module %s - %s\n", order->resource, order->required ? "Required" : "Not required");
01204          res = order->required ? -2 : -1;
01205          goto done;
01206       case AST_MODULE_LOAD_SKIP:
01207          break;
01208       case AST_MODULE_LOAD_PRIORITY:
01209          AST_LIST_REMOVE_CURRENT(entry);
01210          ast_free(order->resource);
01211          ast_free(order);
01212          break;
01213       }
01214    }
01215    AST_LIST_TRAVERSE_SAFE_END;
01216 
01217    /* second remove modules from heap sorted by priority */
01218    while ((mod = ast_heap_pop(resource_heap))) {
01219       switch (start_resource(mod)) {
01220       case AST_MODULE_LOAD_SUCCESS:
01221          count++;
01222       case AST_MODULE_LOAD_DECLINE:
01223          break;
01224       case AST_MODULE_LOAD_FAILURE:
01225          res = -1;
01226          goto done;
01227       case AST_MODULE_LOAD_SKIP:
01228       case AST_MODULE_LOAD_PRIORITY:
01229          break;
01230       }
01231    }
01232 
01233 done:
01234    if (mod_count) {
01235       *mod_count += count;
01236    }
01237    ast_heap_destroy(resource_heap);
01238 
01239    return res;
01240 }
01241 
01242 int load_modules(unsigned int preload_only)
01243 {
01244    struct ast_config *cfg;
01245    struct ast_module *mod;
01246    struct load_order_entry *order;
01247    struct ast_variable *v;
01248    unsigned int load_count;
01249    struct load_order load_order;
01250    int res = 0;
01251    struct ast_flags config_flags = { 0 };
01252    int modulecount = 0;
01253 
01254 #ifdef LOADABLE_MODULES
01255    struct dirent *dirent;
01256    DIR *dir;
01257 #endif
01258 
01259    /* all embedded modules have registered themselves by now */
01260    embedding = 0;
01261 
01262    ast_verb(1, "Asterisk Dynamic Loader Starting:\n");
01263 
01264    AST_LIST_HEAD_INIT_NOLOCK(&load_order);
01265 
01266    AST_DLLIST_LOCK(&module_list);
01267 
01268    if (embedded_module_list.first) {
01269       module_list.first = embedded_module_list.first;
01270       module_list.last = embedded_module_list.last;
01271       embedded_module_list.first = NULL;
01272    }
01273 
01274    cfg = ast_config_load2(AST_MODULE_CONFIG, "" /* core, can't reload */, config_flags);
01275    if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEINVALID) {
01276       ast_log(LOG_WARNING, "No '%s' found, no modules will be loaded.\n", AST_MODULE_CONFIG);
01277       goto done;
01278    }
01279 
01280    /* first, find all the modules we have been explicitly requested to load */
01281    for (v = ast_variable_browse(cfg, "modules"); v; v = v->next) {
01282       if (!strcasecmp(v->name, preload_only ? "preload" : "load")) {
01283          add_to_load_order(v->value, &load_order, 0);
01284       }
01285       if (!strcasecmp(v->name, preload_only ? "preload-require" : "require")) {
01286          /* Add the module to the list and make sure it's required */
01287          add_to_load_order(v->value, &load_order, 1);
01288          ast_debug(2, "Adding module to required list: %s (%s)\n", v->value, v->name);
01289       }
01290 
01291    }
01292 
01293    /* check if 'autoload' is on */
01294    if (!preload_only && ast_true(ast_variable_retrieve(cfg, "modules", "autoload"))) {
01295       /* if so, first add all the embedded modules that are not already running to the load order */
01296       AST_DLLIST_TRAVERSE(&module_list, mod, entry) {
01297          /* if it's not embedded, skip it */
01298          if (mod->lib)
01299             continue;
01300 
01301          if (mod->flags.running)
01302             continue;
01303 
01304          add_to_load_order(mod->resource, &load_order, 0);
01305       }
01306 
01307 #ifdef LOADABLE_MODULES
01308       /* if we are allowed to load dynamic modules, scan the directory for
01309          for all available modules and add them as well */
01310       if ((dir = opendir(ast_config_AST_MODULE_DIR))) {
01311          while ((dirent = readdir(dir))) {
01312             int ld = strlen(dirent->d_name);
01313 
01314             /* Must end in .so to load it.  */
01315 
01316             if (ld < 4)
01317                continue;
01318 
01319             if (strcasecmp(dirent->d_name + ld - 3, ".so"))
01320                continue;
01321 
01322             /* if there is already a module by this name in the module_list,
01323                skip this file */
01324             if (find_resource(dirent->d_name, 0))
01325                continue;
01326 
01327             add_to_load_order(dirent->d_name, &load_order, 0);
01328          }
01329 
01330          closedir(dir);
01331       } else {
01332          if (!ast_opt_quiet)
01333             ast_log(LOG_WARNING, "Unable to open modules directory '%s'.\n",
01334                ast_config_AST_MODULE_DIR);
01335       }
01336 #endif
01337    }
01338 
01339    /* now scan the config for any modules we are prohibited from loading and
01340       remove them from the load order */
01341    for (v = ast_variable_browse(cfg, "modules"); v; v = v->next) {
01342       if (strcasecmp(v->name, "noload"))
01343          continue;
01344 
01345       AST_LIST_TRAVERSE_SAFE_BEGIN(&load_order, order, entry) {
01346          if (!resource_name_match(order->resource, v->value)) {
01347             AST_LIST_REMOVE_CURRENT(entry);
01348             ast_free(order->resource);
01349             ast_free(order);
01350          }
01351       }
01352       AST_LIST_TRAVERSE_SAFE_END;
01353    }
01354 
01355    /* we are done with the config now, all the information we need is in the
01356       load_order list */
01357    ast_config_destroy(cfg);
01358 
01359    load_count = 0;
01360    AST_LIST_TRAVERSE(&load_order, order, entry)
01361       load_count++;
01362 
01363    if (load_count)
01364       ast_log(LOG_NOTICE, "%u modules will be loaded.\n", load_count);
01365 
01366    /* first, load only modules that provide global symbols */
01367    if ((res = load_resource_list(&load_order, 1, &modulecount)) < 0) {
01368       goto done;
01369    }
01370 
01371    /* now load everything else */
01372    if ((res = load_resource_list(&load_order, 0, &modulecount)) < 0) {
01373       goto done;
01374    }
01375 
01376 done:
01377    while ((order = AST_LIST_REMOVE_HEAD(&load_order, entry))) {
01378       ast_free(order->resource);
01379       ast_free(order);
01380    }
01381 
01382    AST_DLLIST_UNLOCK(&module_list);
01383    return res;
01384 }
01385 
01386 void ast_update_use_count(void)
01387 {
01388    /* Notify any module monitors that the use count for a
01389       resource has changed */
01390    struct loadupdate *m;
01391 
01392    AST_LIST_LOCK(&updaters);
01393    AST_LIST_TRAVERSE(&updaters, m, entry)
01394       m->updater();
01395    AST_LIST_UNLOCK(&updaters);
01396 }
01397 
01398 int ast_update_module_list(int (*modentry)(const char *module, const char *description,
01399                                            int usecnt, const char *status, const char *like,
01400                                  enum ast_module_support_level support_level),
01401                            const char *like)
01402 {
01403    struct ast_module *cur;
01404    int unlock = -1;
01405    int total_mod_loaded = 0;
01406    AST_LIST_HEAD_NOLOCK(, ast_module) alpha_module_list = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
01407 
01408    if (AST_DLLIST_TRYLOCK(&module_list)) {
01409       unlock = 0;
01410    }
01411 
01412    AST_DLLIST_TRAVERSE(&module_list, cur, entry) {
01413       AST_LIST_INSERT_SORTALPHA(&alpha_module_list, cur, list_entry, resource);
01414    }
01415 
01416    while ((cur = AST_LIST_REMOVE_HEAD(&alpha_module_list, list_entry))) {
01417       total_mod_loaded += modentry(cur->resource, cur->info->description, cur->usecount,
01418                   cur->flags.running ? "Running" : "Not Running", like, cur->info->support_level);
01419    }
01420 
01421    if (unlock) {
01422       AST_DLLIST_UNLOCK(&module_list);
01423    }
01424 
01425    return total_mod_loaded;
01426 }
01427 
01428 /*! \brief Check if module exists */
01429 int ast_module_check(const char *name)
01430 {
01431    struct ast_module *cur;
01432 
01433    if (ast_strlen_zero(name))
01434       return 0;       /* FALSE */
01435 
01436    cur = find_resource(name, 1);
01437 
01438    return (cur != NULL);
01439 }
01440 
01441 
01442 int ast_loader_register(int (*v)(void))
01443 {
01444    struct loadupdate *tmp;
01445 
01446    if (!(tmp = ast_malloc(sizeof(*tmp))))
01447       return -1;
01448 
01449    tmp->updater = v;
01450    AST_LIST_LOCK(&updaters);
01451    AST_LIST_INSERT_HEAD(&updaters, tmp, entry);
01452    AST_LIST_UNLOCK(&updaters);
01453 
01454    return 0;
01455 }
01456 
01457 int ast_loader_unregister(int (*v)(void))
01458 {
01459    struct loadupdate *cur;
01460 
01461    AST_LIST_LOCK(&updaters);
01462    AST_LIST_TRAVERSE_SAFE_BEGIN(&updaters, cur, entry) {
01463       if (cur->updater == v)  {
01464          AST_LIST_REMOVE_CURRENT(entry);
01465          break;
01466       }
01467    }
01468    AST_LIST_TRAVERSE_SAFE_END;
01469    AST_LIST_UNLOCK(&updaters);
01470 
01471    return cur ? 0 : -1;
01472 }
01473 
01474 struct ast_module *__ast_module_ref(struct ast_module *mod, const char *file, int line, const char *func)
01475 {
01476    if (!mod) {
01477       return NULL;
01478    }
01479 
01480 #ifdef REF_DEBUG
01481    __ao2_ref_debug(mod->ref_debug, +1, "", file, line, func);
01482 #endif
01483 
01484    ast_atomic_fetchadd_int(&mod->usecount, +1);
01485    ast_update_use_count();
01486 
01487    return mod;
01488 }
01489 
01490 void __ast_module_shutdown_ref(struct ast_module *mod, const char *file, int line, const char *func)
01491 {
01492    if (!mod || mod->flags.keepuntilshutdown) {
01493       return;
01494    }
01495 
01496    __ast_module_ref(mod, file, line, func);
01497    mod->flags.keepuntilshutdown = 1;
01498 }
01499 
01500 void __ast_module_unref(struct ast_module *mod, const char *file, int line, const char *func)
01501 {
01502    if (!mod) {
01503       return;
01504    }
01505 
01506 #ifdef REF_DEBUG
01507    __ao2_ref_debug(mod->ref_debug, -1, "", file, line, func);
01508 #endif
01509 
01510    ast_atomic_fetchadd_int(&mod->usecount, -1);
01511    ast_update_use_count();
01512 }
01513 
01514 const char *support_level_map [] = {
01515    [AST_MODULE_SUPPORT_UNKNOWN] = "unknown",
01516    [AST_MODULE_SUPPORT_CORE] = "core",
01517    [AST_MODULE_SUPPORT_EXTENDED] = "extended",
01518    [AST_MODULE_SUPPORT_DEPRECATED] = "deprecated",
01519 };
01520 
01521 const char *ast_module_support_level_to_string(enum ast_module_support_level support_level)
01522 {
01523    return support_level_map[support_level];
01524 }

Generated on Thu Apr 16 06:27:38 2015 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6