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