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