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