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