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