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