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