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