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