123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422 |
- #include "asterisk.h"
- ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
- #include "asterisk/_private.h"
- #include "asterisk/paths.h"
- #include <dirent.h>
- #include "asterisk/linkedlists.h"
- #include "asterisk/module.h"
- #include "asterisk/config.h"
- #include "asterisk/channel.h"
- #include "asterisk/term.h"
- #include "asterisk/acl.h"
- #include "asterisk/manager.h"
- #include "asterisk/cdr.h"
- #include "asterisk/enum.h"
- #include "asterisk/http.h"
- #include "asterisk/lock.h"
- #include "asterisk/features.h"
- #include "asterisk/dsp.h"
- #include "asterisk/udptl.h"
- #include "asterisk/heap.h"
- #include "asterisk/app.h"
- #include "asterisk/test.h"
- #include <dlfcn.h>
- #include "asterisk/md5.h"
- #include "asterisk/utils.h"
- #ifndef RTLD_NOW
- #define RTLD_NOW 0
- #endif
- #ifndef RTLD_LOCAL
- #define RTLD_LOCAL 0
- #endif
- struct ast_module_user {
- struct ast_channel *chan;
- AST_LIST_ENTRY(ast_module_user) entry;
- };
- AST_LIST_HEAD(module_user_list, ast_module_user);
- static const unsigned char expected_key[] =
- { 0x87, 0x76, 0x79, 0x35, 0x23, 0xea, 0x3a, 0xd3,
- 0x25, 0x2a, 0xbb, 0x35, 0x87, 0xe4, 0x22, 0x24 };
- static char buildopt_sum[33] = AST_BUILDOPT_SUM;
- static unsigned int embedding = 1;
- struct ast_module {
- const struct ast_module_info *info;
- #ifdef REF_DEBUG
-
- void *ref_debug;
- #endif
- void *lib;
- int usecount;
- struct module_user_list users;
- struct {
- unsigned int running:1;
- unsigned int declined:1;
- unsigned int keepuntilshutdown:1;
- } flags;
- AST_LIST_ENTRY(ast_module) entry;
- char resource[0];
- };
- static AST_LIST_HEAD_STATIC(module_list, ast_module);
- const char *ast_module_name(const struct ast_module *mod)
- {
- if (!mod || !mod->info) {
- return NULL;
- }
- return mod->info->name;
- }
- static struct module_list embedded_module_list;
- struct loadupdate {
- int (*updater)(void);
- AST_LIST_ENTRY(loadupdate) entry;
- };
- static AST_LIST_HEAD_STATIC(updaters, loadupdate);
- AST_MUTEX_DEFINE_STATIC(reloadlock);
- struct reload_queue_item {
- AST_LIST_ENTRY(reload_queue_item) entry;
- char module[0];
- };
- static int do_full_reload = 0;
- static AST_LIST_HEAD_STATIC(reload_queue, reload_queue_item);
- static struct ast_module *resource_being_loaded;
- void ast_module_register(const struct ast_module_info *info)
- {
- struct ast_module *mod;
- if (embedding) {
- if (!(mod = ast_calloc(1, sizeof(*mod) + strlen(info->name) + 1)))
- return;
- strcpy(mod->resource, info->name);
- } else {
- mod = resource_being_loaded;
- }
- mod->info = info;
- #ifdef REF_DEBUG
- mod->ref_debug = ao2_t_alloc(0, NULL, info->name);
- #endif
- AST_LIST_HEAD_INIT(&mod->users);
-
- if (embedding) {
- AST_LIST_INSERT_TAIL(&embedded_module_list, mod, entry);
- } else {
- AST_LIST_LOCK(&module_list);
-
- AST_LIST_INSERT_TAIL(&module_list, mod, entry);
- AST_LIST_UNLOCK(&module_list);
- }
-
- *((struct ast_module **) &(info->self)) = mod;
- }
- void ast_module_unregister(const struct ast_module_info *info)
- {
- struct ast_module *mod = NULL;
-
- AST_LIST_LOCK(&module_list);
- AST_LIST_TRAVERSE_SAFE_BEGIN(&module_list, mod, entry) {
- if (mod->info == info) {
- AST_LIST_REMOVE_CURRENT(entry);
- break;
- }
- }
- AST_LIST_TRAVERSE_SAFE_END;
- AST_LIST_UNLOCK(&module_list);
- if (mod) {
- AST_LIST_HEAD_DESTROY(&mod->users);
- #ifdef REF_DEBUG
- ao2_cleanup(mod->ref_debug);
- #endif
- ast_free(mod);
- }
- }
- struct ast_module_user *__ast_module_user_add(struct ast_module *mod, struct ast_channel *chan)
- {
- struct ast_module_user *u;
- u = ast_calloc(1, sizeof(*u));
- if (!u) {
- return NULL;
- }
- u->chan = chan;
- AST_LIST_LOCK(&mod->users);
- AST_LIST_INSERT_HEAD(&mod->users, u, entry);
- AST_LIST_UNLOCK(&mod->users);
- #ifdef REF_DEBUG
- ao2_ref(mod->ref_debug, +1);
- #endif
- ast_atomic_fetchadd_int(&mod->usecount, +1);
- ast_update_use_count();
- return u;
- }
- void __ast_module_user_remove(struct ast_module *mod, struct ast_module_user *u)
- {
- if (!u) {
- return;
- }
- AST_LIST_LOCK(&mod->users);
- u = AST_LIST_REMOVE(&mod->users, u, entry);
- AST_LIST_UNLOCK(&mod->users);
- if (!u) {
-
- return;
- }
- #ifdef REF_DEBUG
- ao2_ref(mod->ref_debug, -1);
- #endif
- ast_atomic_fetchadd_int(&mod->usecount, -1);
- ast_free(u);
- ast_update_use_count();
- }
- void __ast_module_user_hangup_all(struct ast_module *mod)
- {
- struct ast_module_user *u;
- AST_LIST_LOCK(&mod->users);
- while ((u = AST_LIST_REMOVE_HEAD(&mod->users, entry))) {
- if (u->chan) {
- ast_softhangup(u->chan, AST_SOFTHANGUP_APPUNLOAD);
- }
- #ifdef REF_DEBUG
- ao2_ref(mod->ref_debug, -1);
- #endif
- ast_atomic_fetchadd_int(&mod->usecount, -1);
- ast_free(u);
- }
- AST_LIST_UNLOCK(&mod->users);
- ast_update_use_count();
- }
- static struct reload_classes {
- const char *name;
- int (*reload_fn)(void);
- } reload_classes[] = {
- { "cdr", ast_cdr_engine_reload },
- { "dnsmgr", dnsmgr_reload },
- { "extconfig", read_config_maps },
- { "enum", ast_enum_reload },
- { "acl", ast_named_acl_reload },
- { "manager", reload_manager },
- { "http", ast_http_reload },
- { "logger", logger_reload },
- { "features", ast_features_reload },
- { "dsp", ast_dsp_reload},
- { "udptl", ast_udptl_reload },
- { "indications", ast_indications_reload },
- { "cel", ast_cel_engine_reload },
- { "plc", ast_plc_reload },
- { NULL, NULL }
- };
- static int printdigest(const unsigned char *d)
- {
- int x, pos;
- char buf[256];
- for (pos = 0, x = 0; x < 16; x++)
- pos += sprintf(buf + pos, " %02hhx", *d++);
- ast_debug(1, "Unexpected signature:%s\n", buf);
- return 0;
- }
- static int key_matches(const unsigned char *key1, const unsigned char *key2)
- {
- int x;
- for (x = 0; x < 16; x++) {
- if (key1[x] != key2[x])
- return 0;
- }
- return 1;
- }
- static int verify_key(const unsigned char *key)
- {
- struct MD5Context c;
- unsigned char digest[16];
- MD5Init(&c);
- MD5Update(&c, key, strlen((char *)key));
- MD5Final(digest, &c);
- if (key_matches(expected_key, digest))
- return 0;
- printdigest(digest);
- return -1;
- }
- static int resource_name_match(const char *name1_in, const char *name2_in)
- {
- char *name1 = (char *) name1_in;
- char *name2 = (char *) name2_in;
-
- if (!strcasecmp(name1 + strlen(name1) - 3, ".so")) {
- name1 = ast_strdupa(name1);
- name1[strlen(name1) - 3] = '\0';
- }
- if (!strcasecmp(name2 + strlen(name2) - 3, ".so")) {
- name2 = ast_strdupa(name2);
- name2[strlen(name2) - 3] = '\0';
- }
- return strcasecmp(name1, name2);
- }
- static struct ast_module *find_resource(const char *resource, int do_lock)
- {
- struct ast_module *cur;
- if (do_lock)
- AST_LIST_LOCK(&module_list);
- AST_LIST_TRAVERSE(&module_list, cur, entry) {
- if (!resource_name_match(resource, cur->resource))
- break;
- }
- if (do_lock)
- AST_LIST_UNLOCK(&module_list);
- return cur;
- }
- #ifdef LOADABLE_MODULES
- static void close_lib(const char *name, void *lib)
- {
- char *error;
- if (!lib) {
- return;
- }
-
- dlerror();
- if (dlclose(lib)) {
- error = dlerror();
- ast_log(AST_LOG_ERROR, "Failure in dlclose for module '%s': %s\n",
- S_OR(name, "unknown"), S_OR(error, "Unknown error"));
- }
- }
- static void unload_dynamic_module(struct ast_module *mod)
- {
- void *lib = mod->lib;
-
- close_lib(ast_module_name(mod), lib);
- }
- static enum ast_module_load_result load_resource(const char *resource_name, unsigned int global_symbols_only, struct ast_heap *resource_heap, int required);
- static struct ast_module *load_dynamic_module(const char *resource_in, unsigned int global_symbols_only, struct ast_heap *resource_heap)
- {
- char fn[PATH_MAX] = "";
- void *lib = NULL;
- struct ast_module *mod;
- unsigned int wants_global;
- int space;
- int missing_so = 0;
- space = sizeof(*resource_being_loaded) + strlen(resource_in) + 1;
- if (strcasecmp(resource_in + strlen(resource_in) - 3, ".so")) {
- missing_so = 1;
- space += 3;
- }
- snprintf(fn, sizeof(fn), "%s/%s%s", ast_config_AST_MODULE_DIR, resource_in, missing_so ? ".so" : "");
-
- resource_being_loaded = ast_calloc(1, space);
- if (!resource_being_loaded)
- return NULL;
- strcpy(resource_being_loaded->resource, resource_in);
- if (missing_so)
- strcat(resource_being_loaded->resource, ".so");
- if (!(lib = dlopen(fn, RTLD_LAZY | RTLD_LOCAL))) {
- ast_log(LOG_WARNING, "Error loading module '%s': %s\n", resource_in, dlerror());
- ast_free(resource_being_loaded);
- return NULL;
- }
-
-
- if (resource_being_loaded != (mod = AST_LIST_LAST(&module_list))) {
- ast_log(LOG_WARNING, "Module '%s' did not register itself during load\n", resource_in);
-
- close_lib(resource_in, lib);
-
- return NULL;
- }
- wants_global = ast_test_flag(mod->info, AST_MODFLAG_GLOBAL_SYMBOLS);
-
- if (global_symbols_only && !wants_global) {
- close_lib(resource_in, lib);
- return NULL;
- }
-
- #if !defined(HAVE_ATTRIBUTE_weak_import) && !defined(HAVE_ATTRIBUTE_weakref)
- if (!ast_strlen_zero(mod->info->nonoptreq)) {
-
- char *each, *required_resource = ast_strdupa(mod->info->nonoptreq);
- while ((each = strsep(&required_resource, ","))) {
- struct ast_module *dependency;
- each = ast_strip(each);
- dependency = find_resource(each, 0);
-
- if (!dependency) {
- load_resource(each, global_symbols_only, resource_heap, 1);
- }
- }
- }
- #endif
- close_lib(resource_in, lib);
- resource_being_loaded = NULL;
-
- resource_being_loaded = ast_calloc(1, space);
- if (!resource_being_loaded)
- return NULL;
- strcpy(resource_being_loaded->resource, resource_in);
- if (missing_so)
- strcat(resource_being_loaded->resource, ".so");
- if (!(lib = dlopen(fn, wants_global ? RTLD_LAZY | RTLD_GLOBAL : RTLD_NOW | RTLD_LOCAL))) {
- ast_log(LOG_WARNING, "Error loading module '%s': %s\n", resource_in, dlerror());
- ast_free(resource_being_loaded);
- return NULL;
- }
-
- AST_LIST_LAST(&module_list)->lib = lib;
- resource_being_loaded = NULL;
- return AST_LIST_LAST(&module_list);
- }
- #endif
- void ast_module_shutdown(void)
- {
- struct ast_module *mod;
- int somethingchanged = 1, final = 0;
- AST_LIST_LOCK(&module_list);
-
- do {
- if (!somethingchanged) {
-
- final = 1;
- }
-
- somethingchanged = 0;
- AST_LIST_TRAVERSE_SAFE_BEGIN(&module_list, mod, entry) {
- if (!final && mod->usecount) {
- continue;
- }
- AST_LIST_REMOVE_CURRENT(entry);
- if (mod->flags.running && !mod->flags.declined && mod->info->unload) {
- mod->info->unload();
- }
- AST_LIST_HEAD_DESTROY(&mod->users);
- #ifdef REF_DEBUG
- ao2_cleanup(mod->ref_debug);
- #endif
- free(mod);
- somethingchanged = 1;
- }
- AST_LIST_TRAVERSE_SAFE_END;
- if (!somethingchanged) {
- AST_LIST_TRAVERSE(&module_list, mod, entry) {
- if (mod->flags.keepuntilshutdown) {
- ast_module_unref(mod);
- mod->flags.keepuntilshutdown = 0;
- somethingchanged = 1;
- }
- }
- }
- } while (somethingchanged && !final);
- AST_LIST_UNLOCK(&module_list);
- }
- int ast_unload_resource(const char *resource_name, enum ast_module_unload_mode force)
- {
- struct ast_module *mod;
- int res = -1;
- int error = 0;
- AST_LIST_LOCK(&module_list);
- if (!(mod = find_resource(resource_name, 0))) {
- AST_LIST_UNLOCK(&module_list);
- ast_log(LOG_WARNING, "Unload failed, '%s' could not be found\n", resource_name);
- return -1;
- }
- if (!mod->flags.running || mod->flags.declined) {
- ast_log(LOG_WARNING, "Unload failed, '%s' is not loaded.\n", resource_name);
- error = 1;
- }
- if (!error && (mod->usecount > 0)) {
- if (force)
- ast_log(LOG_WARNING, "Warning: Forcing removal of module '%s' with use count %d\n",
- resource_name, mod->usecount);
- else {
- ast_log(LOG_WARNING, "Soft unload failed, '%s' has use count %d\n", resource_name,
- mod->usecount);
- error = 1;
- }
- }
- if (!error) {
-
- __ast_module_user_hangup_all(mod);
- res = mod->info->unload();
- if (res) {
- ast_log(LOG_WARNING, "Firm unload failed for %s\n", resource_name);
- if (force <= AST_FORCE_FIRM) {
- error = 1;
- } else {
- ast_log(LOG_WARNING, "** Dangerous **: Unloading resource anyway, at user request\n");
- }
- }
- if (!error) {
-
- __ast_module_user_hangup_all(mod);
- sched_yield();
- }
- }
- if (!error)
- mod->flags.running = mod->flags.declined = 0;
- AST_LIST_UNLOCK(&module_list);
- if (!error && !mod->lib && mod->info && mod->info->restore_globals)
- mod->info->restore_globals();
- #ifdef LOADABLE_MODULES
- if (!error) {
- unload_dynamic_module(mod);
- ast_test_suite_event_notify("MODULE_UNLOAD", "Message: %s", resource_name);
- }
- #endif
- if (!error)
- ast_update_use_count();
- return res;
- }
- char *ast_module_helper(const char *line, const char *word, int pos, int state, int rpos, int needsreload)
- {
- struct ast_module *cur;
- int i, which=0, l = strlen(word);
- char *ret = NULL;
- if (pos != rpos)
- return NULL;
- AST_LIST_LOCK(&module_list);
- AST_LIST_TRAVERSE(&module_list, cur, entry) {
- if (!strncasecmp(word, cur->resource, l) &&
- (cur->info->reload || !needsreload) &&
- ++which > state) {
- ret = ast_strdup(cur->resource);
- break;
- }
- }
- AST_LIST_UNLOCK(&module_list);
- if (!ret) {
- for (i=0; !ret && reload_classes[i].name; i++) {
- if (!strncasecmp(word, reload_classes[i].name, l) && ++which > state)
- ret = ast_strdup(reload_classes[i].name);
- }
- }
- return ret;
- }
- void ast_process_pending_reloads(void)
- {
- struct reload_queue_item *item;
- if (!ast_fully_booted) {
- return;
- }
- AST_LIST_LOCK(&reload_queue);
- if (do_full_reload) {
- do_full_reload = 0;
- AST_LIST_UNLOCK(&reload_queue);
- ast_log(LOG_NOTICE, "Executing deferred reload request.\n");
- ast_module_reload(NULL);
- return;
- }
- while ((item = AST_LIST_REMOVE_HEAD(&reload_queue, entry))) {
- ast_log(LOG_NOTICE, "Executing deferred reload request for module '%s'.\n", item->module);
- ast_module_reload(item->module);
- ast_free(item);
- }
- AST_LIST_UNLOCK(&reload_queue);
- }
- static void queue_reload_request(const char *module)
- {
- struct reload_queue_item *item;
- AST_LIST_LOCK(&reload_queue);
- if (do_full_reload) {
- AST_LIST_UNLOCK(&reload_queue);
- return;
- }
- if (ast_strlen_zero(module)) {
-
- while ((item = AST_LIST_REMOVE_HEAD(&reload_queue, entry))) {
- ast_free(item);
- }
- do_full_reload = 1;
- } else {
-
- AST_LIST_TRAVERSE(&reload_queue, item, entry) {
- if (!strcasecmp(item->module, module)) {
- AST_LIST_UNLOCK(&reload_queue);
- return;
- }
- }
- item = ast_calloc(1, sizeof(*item) + strlen(module) + 1);
- if (!item) {
- ast_log(LOG_ERROR, "Failed to allocate reload queue item.\n");
- AST_LIST_UNLOCK(&reload_queue);
- return;
- }
- strcpy(item->module, module);
- AST_LIST_INSERT_TAIL(&reload_queue, item, entry);
- }
- AST_LIST_UNLOCK(&reload_queue);
- }
- int ast_module_reload(const char *name)
- {
- struct ast_module *cur;
- int res = 0;
- int i;
-
- if (!ast_fully_booted) {
- queue_reload_request(name);
- return 0;
- }
- if (ast_mutex_trylock(&reloadlock)) {
- ast_verbose("The previous reload command didn't finish yet\n");
- return -1;
- }
- ast_lastreloadtime = ast_tvnow();
- if (ast_opt_lock_confdir) {
- int try;
- int res;
- for (try = 1, res = AST_LOCK_TIMEOUT; try < 6 && (res == AST_LOCK_TIMEOUT); try++) {
- res = ast_lock_path(ast_config_AST_CONFIG_DIR);
- if (res == AST_LOCK_TIMEOUT) {
- ast_log(LOG_WARNING, "Failed to grab lock on %s, try %d\n", ast_config_AST_CONFIG_DIR, try);
- }
- }
- if (res != AST_LOCK_SUCCESS) {
- ast_verbose("Cannot grab lock on %s\n", ast_config_AST_CONFIG_DIR);
- ast_mutex_unlock(&reloadlock);
- return -1;
- }
- }
-
- for (i = 0; reload_classes[i].name; i++) {
- if (!name || !strcasecmp(name, reload_classes[i].name)) {
- if (!reload_classes[i].reload_fn()) {
- ast_test_suite_event_notify("MODULE_RELOAD", "Message: %s", name);
- }
- res = 2;
- }
- }
- if (name && res) {
- if (ast_opt_lock_confdir) {
- ast_unlock_path(ast_config_AST_CONFIG_DIR);
- }
- ast_mutex_unlock(&reloadlock);
- return res;
- }
- AST_LIST_LOCK(&module_list);
- AST_LIST_TRAVERSE(&module_list, cur, entry) {
- const struct ast_module_info *info = cur->info;
- if (name && resource_name_match(name, cur->resource))
- continue;
- if (!cur->flags.running || cur->flags.declined) {
- if (!name)
- continue;
- ast_log(LOG_NOTICE, "The module '%s' was not properly initialized. "
- "Before reloading the module, you must run \"module load %s\" "
- "and fix whatever is preventing the module from being initialized.\n",
- name, name);
- res = 2;
- break;
- }
- if (!info->reload) {
-
- ast_test_suite_event_notify("MODULE_RELOAD", "Message: %s", cur->resource);
- if (res < 1)
- res = 1;
- continue;
- }
- res = 2;
- ast_verb(3, "Reloading module '%s' (%s)\n", cur->resource, info->description);
- if (!info->reload()) {
- ast_test_suite_event_notify("MODULE_RELOAD", "Message: %s", cur->resource);
- }
- }
- AST_LIST_UNLOCK(&module_list);
- if (ast_opt_lock_confdir) {
- ast_unlock_path(ast_config_AST_CONFIG_DIR);
- }
- ast_mutex_unlock(&reloadlock);
- return res;
- }
- static unsigned int inspect_module(const struct ast_module *mod)
- {
- if (!mod->info->description) {
- ast_log(LOG_WARNING, "Module '%s' does not provide a description.\n", mod->resource);
- return 1;
- }
- if (!mod->info->key) {
- ast_log(LOG_WARNING, "Module '%s' does not provide a license key.\n", mod->resource);
- return 1;
- }
- if (verify_key((unsigned char *) mod->info->key)) {
- ast_log(LOG_WARNING, "Module '%s' did not provide a valid license key.\n", mod->resource);
- return 1;
- }
- if (!ast_strlen_zero(mod->info->buildopt_sum) &&
- strcmp(buildopt_sum, mod->info->buildopt_sum)) {
- ast_log(LOG_WARNING, "Module '%s' was not compiled with the same compile-time options as this version of Asterisk.\n", mod->resource);
- ast_log(LOG_WARNING, "Module '%s' will not be initialized as it may cause instability.\n", mod->resource);
- return 1;
- }
- return 0;
- }
- static enum ast_module_load_result start_resource(struct ast_module *mod)
- {
- char tmp[256];
- enum ast_module_load_result res;
- if (mod->flags.running) {
- return AST_MODULE_LOAD_SUCCESS;
- }
- if (!mod->info->load) {
- return AST_MODULE_LOAD_FAILURE;
- }
- res = mod->info->load();
- switch (res) {
- case AST_MODULE_LOAD_SUCCESS:
- if (!ast_fully_booted) {
- ast_verb(1, "%s => (%s)\n", mod->resource, term_color(tmp, mod->info->description, COLOR_BROWN, COLOR_BLACK, sizeof(tmp)));
- if (ast_opt_console && !option_verbose) {
-
- fprintf(stdout, ".");
- }
- } else {
- ast_verb(1, "Loaded %s => (%s)\n", mod->resource, mod->info->description);
- }
- mod->flags.running = 1;
- ast_update_use_count();
- break;
- case AST_MODULE_LOAD_DECLINE:
- mod->flags.declined = 1;
- break;
- case AST_MODULE_LOAD_FAILURE:
- case AST_MODULE_LOAD_SKIP:
- case AST_MODULE_LOAD_PRIORITY:
- break;
- }
- return res;
- }
- static enum ast_module_load_result load_resource(const char *resource_name, unsigned int global_symbols_only, struct ast_heap *resource_heap, int required)
- {
- struct ast_module *mod;
- enum ast_module_load_result res = AST_MODULE_LOAD_SUCCESS;
- if ((mod = find_resource(resource_name, 0))) {
- if (mod->flags.running) {
- ast_log(LOG_WARNING, "Module '%s' already exists.\n", resource_name);
- return AST_MODULE_LOAD_DECLINE;
- }
- if (global_symbols_only && !ast_test_flag(mod->info, AST_MODFLAG_GLOBAL_SYMBOLS))
- return AST_MODULE_LOAD_SKIP;
- } else {
- #ifdef LOADABLE_MODULES
- if (!(mod = load_dynamic_module(resource_name, global_symbols_only, resource_heap))) {
-
- if (!global_symbols_only) {
- ast_log(LOG_WARNING, "Module '%s' could not be loaded.\n", resource_name);
- return required ? AST_MODULE_LOAD_FAILURE : AST_MODULE_LOAD_DECLINE;
- } else {
- return required ? AST_MODULE_LOAD_FAILURE : AST_MODULE_LOAD_SKIP;
- }
- }
- #else
- ast_log(LOG_WARNING, "Module support is not available. Module '%s' could not be loaded.\n", resource_name);
- return required ? AST_MODULE_LOAD_FAILURE : AST_MODULE_LOAD_DECLINE;
- #endif
- }
- if (inspect_module(mod)) {
- ast_log(LOG_WARNING, "Module '%s' could not be loaded.\n", resource_name);
- #ifdef LOADABLE_MODULES
- unload_dynamic_module(mod);
- #endif
- return required ? AST_MODULE_LOAD_FAILURE : AST_MODULE_LOAD_DECLINE;
- }
- if (!mod->lib && mod->info->backup_globals && mod->info->backup_globals()) {
- ast_log(LOG_WARNING, "Module '%s' was unable to backup its global data.\n", resource_name);
- return required ? AST_MODULE_LOAD_FAILURE : AST_MODULE_LOAD_DECLINE;
- }
- mod->flags.declined = 0;
- if (resource_heap) {
- ast_heap_push(resource_heap, mod);
- res = AST_MODULE_LOAD_PRIORITY;
- } else {
- res = start_resource(mod);
- }
-
- AST_LIST_LOCK(&module_list);
- AST_LIST_REMOVE(&module_list, mod, entry);
- AST_LIST_INSERT_SORTALPHA(&module_list, mod, entry, resource);
- AST_LIST_UNLOCK(&module_list);
- return res;
- }
- int ast_load_resource(const char *resource_name)
- {
- int res;
- AST_LIST_LOCK(&module_list);
- res = load_resource(resource_name, 0, NULL, 0);
- if (!res) {
- ast_test_suite_event_notify("MODULE_LOAD", "Message: %s", resource_name);
- }
- AST_LIST_UNLOCK(&module_list);
- return res;
- }
- struct load_order_entry {
- char *resource;
- int required;
- AST_LIST_ENTRY(load_order_entry) entry;
- };
- AST_LIST_HEAD_NOLOCK(load_order, load_order_entry);
- static struct load_order_entry *add_to_load_order(const char *resource, struct load_order *load_order, int required)
- {
- struct load_order_entry *order;
- AST_LIST_TRAVERSE(load_order, order, entry) {
- if (!resource_name_match(order->resource, resource)) {
-
- order->required |= required;
- return NULL;
- }
- }
- if (!(order = ast_calloc(1, sizeof(*order))))
- return NULL;
- order->resource = ast_strdup(resource);
- order->required = required;
- AST_LIST_INSERT_TAIL(load_order, order, entry);
- return order;
- }
- static int mod_load_cmp(void *a, void *b)
- {
- struct ast_module *a_mod = (struct ast_module *) a;
- struct ast_module *b_mod = (struct ast_module *) b;
- int res = -1;
-
- unsigned char a_pri = ast_test_flag(a_mod->info, AST_MODFLAG_LOAD_ORDER) ? a_mod->info->load_pri : 128;
- unsigned char b_pri = ast_test_flag(b_mod->info, AST_MODFLAG_LOAD_ORDER) ? b_mod->info->load_pri : 128;
- if (a_pri == b_pri) {
- res = 0;
- } else if (a_pri < b_pri) {
- res = 1;
- }
- return res;
- }
- static int load_resource_list(struct load_order *load_order, unsigned int global_symbols, int *mod_count)
- {
- struct ast_heap *resource_heap;
- struct load_order_entry *order;
- struct ast_module *mod;
- int count = 0;
- int res = 0;
- if(!(resource_heap = ast_heap_create(8, mod_load_cmp, -1))) {
- return -1;
- }
-
- AST_LIST_TRAVERSE_SAFE_BEGIN(load_order, order, entry) {
- switch (load_resource(order->resource, global_symbols, resource_heap, order->required)) {
- case AST_MODULE_LOAD_SUCCESS:
- case AST_MODULE_LOAD_DECLINE:
- AST_LIST_REMOVE_CURRENT(entry);
- ast_free(order->resource);
- ast_free(order);
- break;
- case AST_MODULE_LOAD_FAILURE:
- ast_log(LOG_ERROR, "*** Failed to load module %s - %s\n", order->resource, order->required ? "Required" : "Not required");
- fprintf(stderr, "*** Failed to load module %s - %s\n", order->resource, order->required ? "Required" : "Not required");
- res = order->required ? -2 : -1;
- goto done;
- case AST_MODULE_LOAD_SKIP:
- break;
- case AST_MODULE_LOAD_PRIORITY:
- AST_LIST_REMOVE_CURRENT(entry);
- ast_free(order->resource);
- ast_free(order);
- break;
- }
- }
- AST_LIST_TRAVERSE_SAFE_END;
-
- while ((mod = ast_heap_pop(resource_heap))) {
- switch (start_resource(mod)) {
- case AST_MODULE_LOAD_SUCCESS:
- count++;
- case AST_MODULE_LOAD_DECLINE:
- break;
- case AST_MODULE_LOAD_FAILURE:
- res = -1;
- goto done;
- case AST_MODULE_LOAD_SKIP:
- case AST_MODULE_LOAD_PRIORITY:
- break;
- }
- }
- done:
- if (mod_count) {
- *mod_count += count;
- }
- ast_heap_destroy(resource_heap);
- return res;
- }
- int load_modules(unsigned int preload_only)
- {
- struct ast_config *cfg;
- struct ast_module *mod;
- struct load_order_entry *order;
- struct ast_variable *v;
- unsigned int load_count;
- struct load_order load_order;
- int res = 0;
- struct ast_flags config_flags = { 0 };
- int modulecount = 0;
- #ifdef LOADABLE_MODULES
- struct dirent *dirent;
- DIR *dir;
- #endif
-
- embedding = 0;
- ast_verb(1, "Asterisk Dynamic Loader Starting:\n");
- AST_LIST_HEAD_INIT_NOLOCK(&load_order);
- AST_LIST_LOCK(&module_list);
- if (embedded_module_list.first) {
- module_list.first = embedded_module_list.first;
- module_list.last = embedded_module_list.last;
- embedded_module_list.first = NULL;
- }
- cfg = ast_config_load2(AST_MODULE_CONFIG, "" , config_flags);
- if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEINVALID) {
- ast_log(LOG_WARNING, "No '%s' found, no modules will be loaded.\n", AST_MODULE_CONFIG);
- goto done;
- }
-
- for (v = ast_variable_browse(cfg, "modules"); v; v = v->next) {
- if (!strcasecmp(v->name, preload_only ? "preload" : "load")) {
- add_to_load_order(v->value, &load_order, 0);
- }
- if (!strcasecmp(v->name, preload_only ? "preload-require" : "require")) {
-
- add_to_load_order(v->value, &load_order, 1);
- ast_debug(2, "Adding module to required list: %s (%s)\n", v->value, v->name);
- }
- }
-
- if (!preload_only && ast_true(ast_variable_retrieve(cfg, "modules", "autoload"))) {
-
- AST_LIST_TRAVERSE(&module_list, mod, entry) {
-
- if (mod->lib)
- continue;
- if (mod->flags.running)
- continue;
- add_to_load_order(mod->resource, &load_order, 0);
- }
- #ifdef LOADABLE_MODULES
-
- if ((dir = opendir(ast_config_AST_MODULE_DIR))) {
- while ((dirent = readdir(dir))) {
- int ld = strlen(dirent->d_name);
-
- if (ld < 4)
- continue;
- if (strcasecmp(dirent->d_name + ld - 3, ".so"))
- continue;
-
- if (find_resource(dirent->d_name, 0))
- continue;
- add_to_load_order(dirent->d_name, &load_order, 0);
- }
- closedir(dir);
- } else {
- if (!ast_opt_quiet)
- ast_log(LOG_WARNING, "Unable to open modules directory '%s'.\n",
- ast_config_AST_MODULE_DIR);
- }
- #endif
- }
-
- for (v = ast_variable_browse(cfg, "modules"); v; v = v->next) {
- if (strcasecmp(v->name, "noload"))
- continue;
- AST_LIST_TRAVERSE_SAFE_BEGIN(&load_order, order, entry) {
- if (!resource_name_match(order->resource, v->value)) {
- AST_LIST_REMOVE_CURRENT(entry);
- ast_free(order->resource);
- ast_free(order);
- }
- }
- AST_LIST_TRAVERSE_SAFE_END;
- }
-
- ast_config_destroy(cfg);
- load_count = 0;
- AST_LIST_TRAVERSE(&load_order, order, entry)
- load_count++;
- if (load_count)
- ast_log(LOG_NOTICE, "%u modules will be loaded.\n", load_count);
-
- if ((res = load_resource_list(&load_order, 1, &modulecount)) < 0) {
- goto done;
- }
-
- if ((res = load_resource_list(&load_order, 0, &modulecount)) < 0) {
- goto done;
- }
- done:
- while ((order = AST_LIST_REMOVE_HEAD(&load_order, entry))) {
- ast_free(order->resource);
- ast_free(order);
- }
- AST_LIST_UNLOCK(&module_list);
-
-
- manager_event(EVENT_FLAG_SYSTEM, "ModuleLoadReport", "ModuleLoadStatus: Done\r\nModuleSelection: %s\r\nModuleCount: %d\r\n", preload_only ? "Preload" : "All", modulecount);
- return res;
- }
- void ast_update_use_count(void)
- {
-
- struct loadupdate *m;
- AST_LIST_LOCK(&updaters);
- AST_LIST_TRAVERSE(&updaters, m, entry)
- m->updater();
- AST_LIST_UNLOCK(&updaters);
- }
- int ast_update_module_list(int (*modentry)(const char *module, const char *description, int usecnt, const char *like),
- const char *like)
- {
- struct ast_module *cur;
- int unlock = -1;
- int total_mod_loaded = 0;
- if (AST_LIST_TRYLOCK(&module_list))
- unlock = 0;
- AST_LIST_TRAVERSE(&module_list, cur, entry) {
- total_mod_loaded += modentry(cur->resource, cur->info->description, cur->usecount, like);
- }
- if (unlock)
- AST_LIST_UNLOCK(&module_list);
- return total_mod_loaded;
- }
- int ast_module_check(const char *name)
- {
- struct ast_module *cur;
- if (ast_strlen_zero(name))
- return 0;
- cur = find_resource(name, 1);
- return (cur != NULL);
- }
- int ast_loader_register(int (*v)(void))
- {
- struct loadupdate *tmp;
- if (!(tmp = ast_malloc(sizeof(*tmp))))
- return -1;
- tmp->updater = v;
- AST_LIST_LOCK(&updaters);
- AST_LIST_INSERT_HEAD(&updaters, tmp, entry);
- AST_LIST_UNLOCK(&updaters);
- return 0;
- }
- int ast_loader_unregister(int (*v)(void))
- {
- struct loadupdate *cur;
- AST_LIST_LOCK(&updaters);
- AST_LIST_TRAVERSE_SAFE_BEGIN(&updaters, cur, entry) {
- if (cur->updater == v) {
- AST_LIST_REMOVE_CURRENT(entry);
- break;
- }
- }
- AST_LIST_TRAVERSE_SAFE_END;
- AST_LIST_UNLOCK(&updaters);
- return cur ? 0 : -1;
- }
- struct ast_module *__ast_module_ref(struct ast_module *mod, const char *file, int line, const char *func)
- {
- if (!mod) {
- return NULL;
- }
- #ifdef REF_DEBUG
- __ao2_ref_debug(mod->ref_debug, +1, "", file, line, func);
- #endif
- ast_atomic_fetchadd_int(&mod->usecount, +1);
- ast_update_use_count();
- return mod;
- }
- void __ast_module_shutdown_ref(struct ast_module *mod, const char *file, int line, const char *func)
- {
- if (!mod || mod->flags.keepuntilshutdown) {
- return;
- }
- __ast_module_ref(mod, file, line, func);
- mod->flags.keepuntilshutdown = 1;
- }
- void __ast_module_unref(struct ast_module *mod, const char *file, int line, const char *func)
- {
- if (!mod) {
- return;
- }
- #ifdef REF_DEBUG
- __ao2_ref_debug(mod->ref_debug, -1, "", file, line, func);
- #endif
- ast_atomic_fetchadd_int(&mod->usecount, -1);
- ast_update_use_count();
- }
- #undef ast_module_ref
- #undef ast_module_unref
- struct ast_module *ast_module_ref(struct ast_module *mod);
- void ast_module_unref(struct ast_module *mod);
- struct ast_module *ast_module_ref(struct ast_module *mod)
- {
- return __ast_module_ref(mod, __FILE__, __LINE__, __PRETTY_FUNCTION__);
- }
- void ast_module_unref(struct ast_module *mod)
- {
- __ast_module_unref(mod, __FILE__, __LINE__, __PRETTY_FUNCTION__);
- }
|