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
00359
00360 if (!strcasecmp(resource, "chan_h323.so") ||
00361 !strcasecmp(resource, "chan_oh323.so"))
00362 lib = dlopen(fn, RTLD_NOW | RTLD_LOCAL);
00363
00364 if (!(lib = dlopen(fn, RTLD_LAZY | RTLD_LOCAL))) {
00365 ast_log(LOG_WARNING, "Error loading module '%s': %s\n", resource_in, dlerror());
00366 free(resource_being_loaded);
00367 return NULL;
00368 }
00369
00370
00371
00372
00373
00374
00375
00376
00377 if (resource_being_loaded != (mod = AST_LIST_LAST(&module_list))) {
00378 ast_log(LOG_WARNING, "Module '%s' did not register itself during load\n", resource_in);
00379
00380 while (!dlclose(lib));
00381
00382
00383 return NULL;
00384 }
00385
00386 wants_global = ast_test_flag(mod->info, AST_MODFLAG_GLOBAL_SYMBOLS);
00387
00388
00389
00390 if (global_symbols_only && !wants_global) {
00391 while (!dlclose(lib));
00392 return NULL;
00393 }
00394
00395
00396
00397
00398
00399 #if defined(HAVE_RTLD_NOLOAD) && !defined(__Darwin__)
00400 if (!dlopen(fn, RTLD_NOLOAD | (wants_global ? RTLD_LAZY | RTLD_GLOBAL : RTLD_NOW | RTLD_LOCAL))) {
00401 ast_log(LOG_WARNING, "Unable to promote flags on module '%s': %s\n", resource_in, dlerror());
00402 while (!dlclose(lib));
00403 free(resource_being_loaded);
00404 return NULL;
00405 }
00406 #else
00407 while (!dlclose(lib));
00408 resource_being_loaded = NULL;
00409
00410
00411
00412 if (!(resource_being_loaded = ast_calloc(1, sizeof(*resource_being_loaded) + strlen(resource) + 1)))
00413 return NULL;
00414
00415 strcpy(resource_being_loaded->resource, resource);
00416
00417 if (!(lib = dlopen(fn, wants_global ? RTLD_LAZY | RTLD_GLOBAL : RTLD_NOW | RTLD_LOCAL))) {
00418 ast_log(LOG_WARNING, "Error loading module '%s': %s\n", resource_in, dlerror());
00419 free(resource_being_loaded);
00420 return NULL;
00421 }
00422
00423
00424
00425
00426 #endif
00427
00428 AST_LIST_LAST(&module_list)->lib = lib;
00429 resource_being_loaded = NULL;
00430
00431 return AST_LIST_LAST(&module_list);
00432 }
00433 #endif
00434
00435 void ast_module_shutdown(void)
00436 {
00437 struct ast_module *mod;
00438 AST_LIST_HEAD_NOLOCK_STATIC(local_module_list, ast_module);
00439
00440
00441
00442
00443
00444 AST_LIST_LOCK(&module_list);
00445 while ((mod = AST_LIST_REMOVE_HEAD(&module_list, entry)))
00446 AST_LIST_INSERT_HEAD(&local_module_list, mod, entry);
00447 AST_LIST_UNLOCK(&module_list);
00448
00449 while ((mod = AST_LIST_REMOVE_HEAD(&local_module_list, entry))) {
00450 if (mod->info->unload)
00451 mod->info->unload();
00452
00453
00454
00455 AST_LIST_HEAD_DESTROY(&mod->users);
00456 free(mod);
00457 }
00458 }
00459
00460 int ast_unload_resource(const char *resource_name, enum ast_module_unload_mode force)
00461 {
00462 struct ast_module *mod;
00463 int res = -1;
00464 int error = 0;
00465
00466 AST_LIST_LOCK(&module_list);
00467
00468 if (!(mod = find_resource(resource_name, 0))) {
00469 AST_LIST_UNLOCK(&module_list);
00470 return 0;
00471 }
00472
00473 if (!(mod->flags.running || mod->flags.declined))
00474 error = 1;
00475
00476 if (!mod->lib) {
00477 ast_log(LOG_WARNING, "Unloading embedded modules is not supported.\n");
00478 error = 1;
00479 }
00480
00481 if (!error && (mod->usecount > 0)) {
00482 if (force)
00483 ast_log(LOG_WARNING, "Warning: Forcing removal of module '%s' with use count %d\n",
00484 resource_name, mod->usecount);
00485 else {
00486 ast_log(LOG_WARNING, "Soft unload failed, '%s' has use count %d\n", resource_name,
00487 mod->usecount);
00488 error = 1;
00489 }
00490 }
00491
00492 if (!error) {
00493 __ast_module_user_hangup_all(mod);
00494 res = mod->info->unload();
00495
00496 if (res) {
00497 ast_log(LOG_WARNING, "Firm unload failed for %s\n", resource_name);
00498 if (force <= AST_FORCE_FIRM)
00499 error = 1;
00500 else
00501 ast_log(LOG_WARNING, "** Dangerous **: Unloading resource anyway, at user request\n");
00502 }
00503 }
00504
00505 if (!error)
00506 mod->flags.running = mod->flags.declined = 0;
00507
00508 AST_LIST_UNLOCK(&module_list);
00509
00510 #ifdef LOADABLE_MODULES
00511 if (!error)
00512 unload_dynamic_module(mod);
00513 #endif
00514
00515 if (!error)
00516 ast_update_use_count();
00517
00518 return res;
00519 }
00520
00521 char *ast_module_helper(const char *line, const char *word, int pos, int state, int rpos, int needsreload)
00522 {
00523 struct ast_module *cur;
00524 int i, which=0, l = strlen(word);
00525 char *ret = NULL;
00526
00527 if (pos != rpos)
00528 return NULL;
00529
00530 AST_LIST_LOCK(&module_list);
00531 AST_LIST_TRAVERSE(&module_list, cur, entry) {
00532 if (!strncasecmp(word, cur->resource, l) &&
00533 (cur->info->reload || !needsreload) &&
00534 ++which > state) {
00535 ret = strdup(cur->resource);
00536 break;
00537 }
00538 }
00539 AST_LIST_UNLOCK(&module_list);
00540
00541 if (!ret) {
00542 for (i=0; !ret && reload_classes[i].name; i++) {
00543 if (!strncasecmp(word, reload_classes[i].name, l) && ++which > state)
00544 ret = strdup(reload_classes[i].name);
00545 }
00546 }
00547
00548 return ret;
00549 }
00550
00551 int ast_module_reload(const char *name)
00552 {
00553 struct ast_module *cur;
00554 int res = 0;
00555 int i;
00556
00557 if (ast_mutex_trylock(&reloadlock)) {
00558 ast_verbose("The previous reload command didn't finish yet\n");
00559 return -1;
00560 }
00561 ast_lastreloadtime = time(NULL);
00562
00563
00564 for (i = 0; reload_classes[i].name; i++) {
00565 if (!name || !strcasecmp(name, reload_classes[i].name)) {
00566 reload_classes[i].reload_fn();
00567 res = 2;
00568 }
00569 }
00570
00571 if (name && res) {
00572 ast_mutex_unlock(&reloadlock);
00573 return res;
00574 }
00575
00576 AST_LIST_LOCK(&module_list);
00577 AST_LIST_TRAVERSE(&module_list, cur, entry) {
00578 const struct ast_module_info *info = cur->info;
00579
00580 if (name && resource_name_match(name, cur->resource))
00581 continue;
00582
00583 if (!cur->flags.running || cur->flags.declined) {
00584 if (!name)
00585 continue;
00586 ast_log(LOG_NOTICE, "The module '%s' was not properly initialized. "
00587 "Before reloading the module, you must run \"module load %s\" "
00588 "and fix whatever is preventing the module from being initialized.\n",
00589 name, name);
00590 res = 2;
00591 break;
00592 }
00593
00594 if (!info->reload) {
00595 if (res < 1)
00596 res = 1;
00597 continue;
00598 }
00599
00600 res = 2;
00601 if (option_verbose > 2)
00602 ast_verbose(VERBOSE_PREFIX_3 "Reloading module '%s' (%s)\n", cur->resource, info->description);
00603 info->reload();
00604 }
00605 AST_LIST_UNLOCK(&module_list);
00606
00607 ast_mutex_unlock(&reloadlock);
00608
00609 return res;
00610 }
00611
00612 static unsigned int inspect_module(const struct ast_module *mod)
00613 {
00614 if (!mod->info->description) {
00615 ast_log(LOG_WARNING, "Module '%s' does not provide a description.\n", mod->resource);
00616 return 1;
00617 }
00618
00619 if (!mod->info->key) {
00620 ast_log(LOG_WARNING, "Module '%s' does not provide a license key.\n", mod->resource);
00621 return 1;
00622 }
00623
00624 if (verify_key((unsigned char *) mod->info->key)) {
00625 ast_log(LOG_WARNING, "Module '%s' did not provide a valid license key.\n", mod->resource);
00626 return 1;
00627 }
00628
00629 if (!ast_test_flag(mod->info, AST_MODFLAG_BUILDSUM)) {
00630 ast_log(LOG_WARNING, "Module '%s' was not compiled against a recent version of Asterisk and may cause instability.\n", mod->resource);
00631 } else if (!ast_strlen_zero(mod->info->buildopt_sum) &&
00632 strcmp(buildopt_sum, mod->info->buildopt_sum)) {
00633 ast_log(LOG_WARNING, "Module '%s' was not compiled with the same compile-time options as this version of Asterisk.\n", mod->resource);
00634 ast_log(LOG_WARNING, "Module '%s' will not be initialized as it may cause instability.\n", mod->resource);
00635 return 1;
00636 }
00637
00638 return 0;
00639 }
00640
00641 static enum ast_module_load_result load_resource(const char *resource_name, unsigned int global_symbols_only)
00642 {
00643 struct ast_module *mod;
00644 enum ast_module_load_result res = AST_MODULE_LOAD_SUCCESS;
00645 char tmp[256];
00646
00647 if ((mod = find_resource(resource_name, 0))) {
00648 if (mod->flags.running) {
00649 ast_log(LOG_WARNING, "Module '%s' already exists.\n", resource_name);
00650 return AST_MODULE_LOAD_DECLINE;
00651 }
00652 if (global_symbols_only && !ast_test_flag(mod->info, AST_MODFLAG_GLOBAL_SYMBOLS))
00653 return AST_MODULE_LOAD_SKIP;
00654 } else {
00655 #ifdef LOADABLE_MODULES
00656 if (!(mod = load_dynamic_module(resource_name, global_symbols_only))) {
00657
00658 if (!global_symbols_only) {
00659 ast_log(LOG_WARNING, "Module '%s' could not be loaded.\n", resource_name);
00660 return AST_MODULE_LOAD_DECLINE;
00661 } else {
00662 return AST_MODULE_LOAD_SKIP;
00663 }
00664 }
00665 #else
00666 ast_log(LOG_WARNING, "Module '%s' could not be loaded.\n", resource_name);
00667 return AST_MODULE_LOAD_DECLINE;
00668 #endif
00669 }
00670
00671 if (inspect_module(mod)) {
00672 ast_log(LOG_WARNING, "Module '%s' could not be loaded.\n", resource_name);
00673 #ifdef LOADABLE_MODULES
00674 unload_dynamic_module(mod);
00675 #endif
00676 return AST_MODULE_LOAD_DECLINE;
00677 }
00678
00679 mod->flags.declined = 0;
00680
00681 if (mod->info->load)
00682 res = mod->info->load();
00683
00684 switch (res) {
00685 case AST_MODULE_LOAD_SUCCESS:
00686 if (!ast_fully_booted) {
00687 if (option_verbose)
00688 ast_verbose("%s => (%s)\n", resource_name, term_color(tmp, mod->info->description, COLOR_BROWN, COLOR_BLACK, sizeof(tmp)));
00689 if (ast_opt_console && !option_verbose)
00690 ast_verbose( ".");
00691 } else {
00692 if (option_verbose)
00693 ast_verbose(VERBOSE_PREFIX_1 "Loaded %s => (%s)\n", resource_name, mod->info->description);
00694 }
00695
00696 mod->flags.running = 1;
00697
00698 ast_update_use_count();
00699 break;
00700 case AST_MODULE_LOAD_DECLINE:
00701 mod->flags.declined = 1;
00702 break;
00703 case AST_MODULE_LOAD_FAILURE:
00704 break;
00705 case AST_MODULE_LOAD_SKIP:
00706
00707 break;
00708 }
00709
00710 return res;
00711 }
00712
00713 int ast_load_resource(const char *resource_name)
00714 {
00715 AST_LIST_LOCK(&module_list);
00716 load_resource(resource_name, 0);
00717 AST_LIST_UNLOCK(&module_list);
00718
00719 return 0;
00720 }
00721
00722 struct load_order_entry {
00723 char *resource;
00724 AST_LIST_ENTRY(load_order_entry) entry;
00725 };
00726
00727 AST_LIST_HEAD_NOLOCK(load_order, load_order_entry);
00728
00729 static struct load_order_entry *add_to_load_order(const char *resource, struct load_order *load_order)
00730 {
00731 struct load_order_entry *order;
00732
00733 AST_LIST_TRAVERSE(load_order, order, entry) {
00734 if (!resource_name_match(order->resource, resource))
00735 return NULL;
00736 }
00737
00738 if (!(order = ast_calloc(1, sizeof(*order))))
00739 return NULL;
00740
00741 order->resource = ast_strdup(resource);
00742 AST_LIST_INSERT_TAIL(load_order, order, entry);
00743
00744 return order;
00745 }
00746
00747 static int translate_module_name(char *oldname, char *newname)
00748 {
00749 if (!strcasecmp(oldname, "app_zapbarge.so"))
00750 ast_copy_string(newname, "app_dahdibarge.so", 18);
00751 else if(!strcasecmp(oldname, "app_zapras.so"))
00752 ast_copy_string(newname, "app_dahdiras.so", 16);
00753 else if(!strcasecmp(oldname, "app_zapscan.so"))
00754 ast_copy_string(newname, "app_dahdiscan.so", 17);
00755 else if(!strcasecmp(oldname, "codec_zap.so"))
00756 ast_copy_string(newname, "codec_dahdi.so", 16);
00757 else
00758 return -1;
00759
00760 return 0;
00761 }
00762
00763
00764 int load_modules(unsigned int preload_only)
00765 {
00766 struct ast_config *cfg;
00767 struct ast_module *mod;
00768 struct load_order_entry *order;
00769 struct ast_variable *v;
00770 unsigned int load_count;
00771 struct load_order load_order;
00772 int res = 0;
00773
00774 int translate_status;
00775 char newname[18];
00776 #ifdef LOADABLE_MODULES
00777 struct dirent *dirent;
00778 DIR *dir;
00779 #endif
00780
00781
00782 embedding = 0;
00783
00784 if (option_verbose)
00785 ast_verbose("Asterisk Dynamic Loader Starting:\n");
00786
00787 AST_LIST_HEAD_INIT_NOLOCK(&load_order);
00788
00789 AST_LIST_LOCK(&module_list);
00790
00791 if (!(cfg = ast_config_load(AST_MODULE_CONFIG))) {
00792 ast_log(LOG_WARNING, "No '%s' found, no modules will be loaded.\n", AST_MODULE_CONFIG);
00793 goto done;
00794 }
00795
00796
00797 for (v = ast_variable_browse(cfg, "modules"); v; v = v->next) {
00798 if (!strcasecmp(v->name, preload_only ? "preload" : "load")) {
00799 translate_status = translate_module_name(v->value, newname);
00800 if (!translate_status)
00801 ast_log(LOG_WARNING, "Use of old module name %s is deprecated, please use %s instead.\n", v->value, newname);
00802 add_to_load_order(translate_status ? v->value : newname, &load_order);
00803 }
00804 }
00805
00806
00807 if (!preload_only && ast_true(ast_variable_retrieve(cfg, "modules", "autoload"))) {
00808
00809 AST_LIST_TRAVERSE(&module_list, mod, entry) {
00810
00811 if (mod->lib)
00812 continue;
00813
00814 if (mod->flags.running)
00815 continue;
00816
00817 order = add_to_load_order(mod->resource, &load_order);
00818 }
00819
00820 #ifdef LOADABLE_MODULES
00821
00822
00823 if ((dir = opendir(ast_config_AST_MODULE_DIR))) {
00824 while ((dirent = readdir(dir))) {
00825 int ld = strlen(dirent->d_name);
00826
00827
00828
00829 if (ld < 4)
00830 continue;
00831
00832 if (strcasecmp(dirent->d_name + ld - 3, ".so"))
00833 continue;
00834
00835
00836
00837 if (find_resource(dirent->d_name, 0))
00838 continue;
00839
00840 add_to_load_order(dirent->d_name, &load_order);
00841 }
00842
00843 closedir(dir);
00844 } else {
00845 if (!ast_opt_quiet)
00846 ast_log(LOG_WARNING, "Unable to open modules directory '%s'.\n",
00847 ast_config_AST_MODULE_DIR);
00848 }
00849 #endif
00850 }
00851
00852
00853
00854 for (v = ast_variable_browse(cfg, "modules"); v; v = v->next) {
00855 if (strcasecmp(v->name, "noload"))
00856 continue;
00857
00858 AST_LIST_TRAVERSE_SAFE_BEGIN(&load_order, order, entry) {
00859 translate_status = translate_module_name(v->value, newname);
00860 if (!resource_name_match(order->resource, translate_status ? v->value : newname)) {
00861 if (!translate_status)
00862 ast_log(LOG_WARNING, "Use of old module name %s is deprecated, please use %s instead.\n", v->value, newname);
00863 AST_LIST_REMOVE_CURRENT(&load_order, entry);
00864 free(order->resource);
00865 free(order);
00866 }
00867 }
00868 AST_LIST_TRAVERSE_SAFE_END;
00869 }
00870
00871
00872
00873 ast_config_destroy(cfg);
00874
00875 load_count = 0;
00876 AST_LIST_TRAVERSE(&load_order, order, entry)
00877 load_count++;
00878
00879 if (load_count)
00880 ast_log(LOG_NOTICE, "%d modules will be loaded.\n", load_count);
00881
00882
00883 AST_LIST_TRAVERSE_SAFE_BEGIN(&load_order, order, entry) {
00884 switch (load_resource(order->resource, 1)) {
00885 case AST_MODULE_LOAD_SUCCESS:
00886 case AST_MODULE_LOAD_DECLINE:
00887 AST_LIST_REMOVE_CURRENT(&load_order, entry);
00888 free(order->resource);
00889 free(order);
00890 break;
00891 case AST_MODULE_LOAD_FAILURE:
00892 res = -1;
00893 goto done;
00894 case AST_MODULE_LOAD_SKIP:
00895
00896 break;
00897 }
00898 }
00899 AST_LIST_TRAVERSE_SAFE_END;
00900
00901
00902 AST_LIST_TRAVERSE_SAFE_BEGIN(&load_order, order, entry) {
00903 switch (load_resource(order->resource, 0)) {
00904 case AST_MODULE_LOAD_SUCCESS:
00905 case AST_MODULE_LOAD_DECLINE:
00906 AST_LIST_REMOVE_CURRENT(&load_order, entry);
00907 free(order->resource);
00908 free(order);
00909 break;
00910 case AST_MODULE_LOAD_FAILURE:
00911 res = -1;
00912 goto done;
00913 case AST_MODULE_LOAD_SKIP:
00914
00915 break;
00916 }
00917 }
00918 AST_LIST_TRAVERSE_SAFE_END;
00919
00920 done:
00921 while ((order = AST_LIST_REMOVE_HEAD(&load_order, entry))) {
00922 free(order->resource);
00923 free(order);
00924 }
00925
00926 AST_LIST_UNLOCK(&module_list);
00927
00928 return res;
00929 }
00930
00931 void ast_update_use_count(void)
00932 {
00933
00934
00935 struct loadupdate *m;
00936
00937 AST_LIST_LOCK(&updaters);
00938 AST_LIST_TRAVERSE(&updaters, m, entry)
00939 m->updater();
00940 AST_LIST_UNLOCK(&updaters);
00941 }
00942
00943 int ast_update_module_list(int (*modentry)(const char *module, const char *description, int usecnt, const char *like),
00944 const char *like)
00945 {
00946 struct ast_module *cur;
00947 int unlock = -1;
00948 int total_mod_loaded = 0;
00949
00950 if (AST_LIST_TRYLOCK(&module_list))
00951 unlock = 0;
00952
00953 AST_LIST_TRAVERSE(&module_list, cur, entry) {
00954 total_mod_loaded += modentry(cur->resource, cur->info->description, cur->usecount, like);
00955 }
00956
00957 if (unlock)
00958 AST_LIST_UNLOCK(&module_list);
00959
00960 return total_mod_loaded;
00961 }
00962
00963 int ast_loader_register(int (*v)(void))
00964 {
00965 struct loadupdate *tmp;
00966
00967 if (!(tmp = ast_malloc(sizeof(*tmp))))
00968 return -1;
00969
00970 tmp->updater = v;
00971 AST_LIST_LOCK(&updaters);
00972 AST_LIST_INSERT_HEAD(&updaters, tmp, entry);
00973 AST_LIST_UNLOCK(&updaters);
00974
00975 return 0;
00976 }
00977
00978 int ast_loader_unregister(int (*v)(void))
00979 {
00980 struct loadupdate *cur;
00981
00982 AST_LIST_LOCK(&updaters);
00983 AST_LIST_TRAVERSE_SAFE_BEGIN(&updaters, cur, entry) {
00984 if (cur->updater == v) {
00985 AST_LIST_REMOVE_CURRENT(&updaters, entry);
00986 break;
00987 }
00988 }
00989 AST_LIST_TRAVERSE_SAFE_END;
00990 AST_LIST_UNLOCK(&updaters);
00991
00992 return cur ? 0 : -1;
00993 }
00994
00995 struct ast_module *ast_module_ref(struct ast_module *mod)
00996 {
00997 ast_atomic_fetchadd_int(&mod->usecount, +1);
00998 ast_update_use_count();
00999
01000 return mod;
01001 }
01002
01003 void ast_module_unref(struct ast_module *mod)
01004 {
01005 ast_atomic_fetchadd_int(&mod->usecount, -1);
01006 ast_update_use_count();
01007 }