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
00031
00032
00033
00034 #include "asterisk.h"
00035
00036 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 369001 $")
00037
00038 #include "asterisk/_private.h"
00039 #include "asterisk/paths.h"
00040 #include <dirent.h>
00041
00042 #include "asterisk/linkedlists.h"
00043 #include "asterisk/module.h"
00044 #include "asterisk/config.h"
00045 #include "asterisk/channel.h"
00046 #include "asterisk/term.h"
00047 #include "asterisk/manager.h"
00048 #include "asterisk/cdr.h"
00049 #include "asterisk/enum.h"
00050 #include "asterisk/http.h"
00051 #include "asterisk/lock.h"
00052 #include "asterisk/features.h"
00053 #include "asterisk/dsp.h"
00054 #include "asterisk/udptl.h"
00055 #include "asterisk/heap.h"
00056 #include "asterisk/app.h"
00057
00058 #include <dlfcn.h>
00059
00060 #include "asterisk/md5.h"
00061 #include "asterisk/utils.h"
00062
00063 #ifndef RTLD_NOW
00064 #define RTLD_NOW 0
00065 #endif
00066
00067 #ifndef RTLD_LOCAL
00068 #define RTLD_LOCAL 0
00069 #endif
00070
00071 struct ast_module_user {
00072 struct ast_channel *chan;
00073 AST_LIST_ENTRY(ast_module_user) entry;
00074 };
00075
00076 AST_LIST_HEAD(module_user_list, ast_module_user);
00077
00078 static const unsigned char expected_key[] =
00079 { 0x87, 0x76, 0x79, 0x35, 0x23, 0xea, 0x3a, 0xd3,
00080 0x25, 0x2a, 0xbb, 0x35, 0x87, 0xe4, 0x22, 0x24 };
00081
00082 static char buildopt_sum[33] = AST_BUILDOPT_SUM;
00083
00084 static unsigned int embedding = 1;
00085
00086
00087
00088 struct ast_module {
00089 const struct ast_module_info *info;
00090 void *lib;
00091 int usecount;
00092 struct module_user_list users;
00093 struct {
00094 unsigned int running:1;
00095 unsigned int declined:1;
00096 } flags;
00097 AST_LIST_ENTRY(ast_module) entry;
00098 char resource[0];
00099 };
00100
00101 static AST_LIST_HEAD_STATIC(module_list, ast_module);
00102
00103 const char *ast_module_name(const struct ast_module *mod)
00104 {
00105 if (!mod || !mod->info) {
00106 return NULL;
00107 }
00108
00109 return mod->info->name;
00110 }
00111
00112
00113
00114
00115
00116
00117
00118 static struct module_list embedded_module_list;
00119
00120 struct loadupdate {
00121 int (*updater)(void);
00122 AST_LIST_ENTRY(loadupdate) entry;
00123 };
00124
00125 static AST_LIST_HEAD_STATIC(updaters, loadupdate);
00126
00127 AST_MUTEX_DEFINE_STATIC(reloadlock);
00128
00129 struct reload_queue_item {
00130 AST_LIST_ENTRY(reload_queue_item) entry;
00131 char module[0];
00132 };
00133
00134 static int do_full_reload = 0;
00135
00136 static AST_LIST_HEAD_STATIC(reload_queue, reload_queue_item);
00137
00138
00139
00140
00141
00142 static struct ast_module *resource_being_loaded;
00143
00144
00145
00146 void ast_module_register(const struct ast_module_info *info)
00147 {
00148 struct ast_module *mod;
00149
00150 if (embedding) {
00151 if (!(mod = ast_calloc(1, sizeof(*mod) + strlen(info->name) + 1)))
00152 return;
00153 strcpy(mod->resource, info->name);
00154 } else {
00155 mod = resource_being_loaded;
00156 }
00157
00158 mod->info = info;
00159 AST_LIST_HEAD_INIT(&mod->users);
00160
00161
00162
00163
00164
00165
00166
00167 if (embedding) {
00168 AST_LIST_INSERT_TAIL(&embedded_module_list, mod, entry);
00169 } else {
00170 AST_LIST_LOCK(&module_list);
00171
00172
00173
00174
00175
00176 AST_LIST_INSERT_TAIL(&module_list, mod, entry);
00177 AST_LIST_UNLOCK(&module_list);
00178 }
00179
00180
00181 *((struct ast_module **) &(info->self)) = mod;
00182 }
00183
00184 void ast_module_unregister(const struct ast_module_info *info)
00185 {
00186 struct ast_module *mod = NULL;
00187
00188
00189
00190
00191
00192 AST_LIST_LOCK(&module_list);
00193 AST_LIST_TRAVERSE_SAFE_BEGIN(&module_list, mod, entry) {
00194 if (mod->info == info) {
00195 AST_LIST_REMOVE_CURRENT(entry);
00196 break;
00197 }
00198 }
00199 AST_LIST_TRAVERSE_SAFE_END;
00200 AST_LIST_UNLOCK(&module_list);
00201
00202 if (mod) {
00203 AST_LIST_HEAD_DESTROY(&mod->users);
00204 ast_free(mod);
00205 }
00206 }
00207
00208 struct ast_module_user *__ast_module_user_add(struct ast_module *mod,
00209 struct ast_channel *chan)
00210 {
00211 struct ast_module_user *u = ast_calloc(1, sizeof(*u));
00212
00213 if (!u)
00214 return NULL;
00215
00216 u->chan = chan;
00217
00218 AST_LIST_LOCK(&mod->users);
00219 AST_LIST_INSERT_HEAD(&mod->users, u, entry);
00220 AST_LIST_UNLOCK(&mod->users);
00221
00222 ast_atomic_fetchadd_int(&mod->usecount, +1);
00223
00224 ast_update_use_count();
00225
00226 return u;
00227 }
00228
00229 void __ast_module_user_remove(struct ast_module *mod, struct ast_module_user *u)
00230 {
00231 AST_LIST_LOCK(&mod->users);
00232 AST_LIST_REMOVE(&mod->users, u, entry);
00233 AST_LIST_UNLOCK(&mod->users);
00234 ast_atomic_fetchadd_int(&mod->usecount, -1);
00235 ast_free(u);
00236
00237 ast_update_use_count();
00238 }
00239
00240 void __ast_module_user_hangup_all(struct ast_module *mod)
00241 {
00242 struct ast_module_user *u;
00243
00244 AST_LIST_LOCK(&mod->users);
00245 while ((u = AST_LIST_REMOVE_HEAD(&mod->users, entry))) {
00246 if (u->chan) {
00247 ast_softhangup(u->chan, AST_SOFTHANGUP_APPUNLOAD);
00248 }
00249 ast_atomic_fetchadd_int(&mod->usecount, -1);
00250 ast_free(u);
00251 }
00252 AST_LIST_UNLOCK(&mod->users);
00253
00254 ast_update_use_count();
00255 }
00256
00257
00258
00259
00260
00261
00262 static struct reload_classes {
00263 const char *name;
00264 int (*reload_fn)(void);
00265 } reload_classes[] = {
00266 { "cdr", ast_cdr_engine_reload },
00267 { "dnsmgr", dnsmgr_reload },
00268 { "extconfig", read_config_maps },
00269 { "enum", ast_enum_reload },
00270 { "manager", reload_manager },
00271 { "http", ast_http_reload },
00272 { "logger", logger_reload },
00273 { "features", ast_features_reload },
00274 { "dsp", ast_dsp_reload},
00275 { "udptl", ast_udptl_reload },
00276 { "indications", ast_indications_reload },
00277 { "cel", ast_cel_engine_reload },
00278 { "plc", ast_plc_reload },
00279 { NULL, NULL }
00280 };
00281
00282 static int printdigest(const unsigned char *d)
00283 {
00284 int x, pos;
00285 char buf[256];
00286
00287 for (pos = 0, x = 0; x < 16; x++)
00288 pos += sprintf(buf + pos, " %02x", *d++);
00289
00290 ast_debug(1, "Unexpected signature:%s\n", buf);
00291
00292 return 0;
00293 }
00294
00295 static int key_matches(const unsigned char *key1, const unsigned char *key2)
00296 {
00297 int x;
00298
00299 for (x = 0; x < 16; x++) {
00300 if (key1[x] != key2[x])
00301 return 0;
00302 }
00303
00304 return 1;
00305 }
00306
00307 static int verify_key(const unsigned char *key)
00308 {
00309 struct MD5Context c;
00310 unsigned char digest[16];
00311
00312 MD5Init(&c);
00313 MD5Update(&c, key, strlen((char *)key));
00314 MD5Final(digest, &c);
00315
00316 if (key_matches(expected_key, digest))
00317 return 0;
00318
00319 printdigest(digest);
00320
00321 return -1;
00322 }
00323
00324 static int resource_name_match(const char *name1_in, const char *name2_in)
00325 {
00326 char *name1 = (char *) name1_in;
00327 char *name2 = (char *) name2_in;
00328
00329
00330 if (!strcasecmp(name1 + strlen(name1) - 3, ".so")) {
00331 name1 = ast_strdupa(name1);
00332 name1[strlen(name1) - 3] = '\0';
00333 }
00334 if (!strcasecmp(name2 + strlen(name2) - 3, ".so")) {
00335 name2 = ast_strdupa(name2);
00336 name2[strlen(name2) - 3] = '\0';
00337 }
00338
00339 return strcasecmp(name1, name2);
00340 }
00341
00342 static struct ast_module *find_resource(const char *resource, int do_lock)
00343 {
00344 struct ast_module *cur;
00345
00346 if (do_lock)
00347 AST_LIST_LOCK(&module_list);
00348
00349 AST_LIST_TRAVERSE(&module_list, cur, entry) {
00350 if (!resource_name_match(resource, cur->resource))
00351 break;
00352 }
00353
00354 if (do_lock)
00355 AST_LIST_UNLOCK(&module_list);
00356
00357 return cur;
00358 }
00359
00360 #ifdef LOADABLE_MODULES
00361 static void unload_dynamic_module(struct ast_module *mod)
00362 {
00363 void *lib = mod->lib;
00364
00365
00366
00367
00368
00369 if (lib)
00370 while (!dlclose(lib));
00371 }
00372
00373 static struct ast_module *load_dynamic_module(const char *resource_in, unsigned int global_symbols_only)
00374 {
00375 char fn[PATH_MAX] = "";
00376 void *lib = NULL;
00377 struct ast_module *mod;
00378 unsigned int wants_global;
00379 int space;
00380 int missing_so = 0;
00381
00382 space = sizeof(*resource_being_loaded) + strlen(resource_in) + 1;
00383 if (strcasecmp(resource_in + strlen(resource_in) - 3, ".so")) {
00384 missing_so = 1;
00385 space += 3;
00386 }
00387
00388 snprintf(fn, sizeof(fn), "%s/%s%s", ast_config_AST_MODULE_DIR, resource_in, missing_so ? ".so" : "");
00389
00390
00391
00392
00393
00394 resource_being_loaded = ast_calloc(1, space);
00395 if (!resource_being_loaded)
00396 return NULL;
00397 strcpy(resource_being_loaded->resource, resource_in);
00398 if (missing_so)
00399 strcat(resource_being_loaded->resource, ".so");
00400
00401 if (!(lib = dlopen(fn, RTLD_LAZY | RTLD_LOCAL))) {
00402 ast_log(LOG_WARNING, "Error loading module '%s': %s\n", resource_in, dlerror());
00403 ast_free(resource_being_loaded);
00404 return NULL;
00405 }
00406
00407
00408
00409
00410
00411
00412
00413
00414 if (resource_being_loaded != (mod = AST_LIST_LAST(&module_list))) {
00415 ast_log(LOG_WARNING, "Module '%s' did not register itself during load\n", resource_in);
00416
00417 while (!dlclose(lib));
00418
00419
00420 return NULL;
00421 }
00422
00423 wants_global = ast_test_flag(mod->info, AST_MODFLAG_GLOBAL_SYMBOLS);
00424
00425
00426
00427 if (global_symbols_only && !wants_global) {
00428 while (!dlclose(lib));
00429 return NULL;
00430 }
00431
00432
00433
00434
00435
00436
00437 #if !defined(HAVE_ATTRIBUTE_weak_import) && !defined(HAVE_ATTRIBUTE_weakref)
00438 if (!ast_strlen_zero(mod->info->nonoptreq)) {
00439
00440 char *each, *required_resource = ast_strdupa(mod->info->nonoptreq);
00441 while ((each = strsep(&required_resource, ","))) {
00442 each = ast_strip(each);
00443
00444
00445 if (!find_resource(each, 0)) {
00446 load_dynamic_module(each, global_symbols_only);
00447 }
00448 }
00449 }
00450 #endif
00451
00452 while (!dlclose(lib));
00453 resource_being_loaded = NULL;
00454
00455
00456 resource_being_loaded = ast_calloc(1, space);
00457 if (!resource_being_loaded)
00458 return NULL;
00459 strcpy(resource_being_loaded->resource, resource_in);
00460 if (missing_so)
00461 strcat(resource_being_loaded->resource, ".so");
00462
00463 if (!(lib = dlopen(fn, wants_global ? RTLD_LAZY | RTLD_GLOBAL : RTLD_NOW | RTLD_LOCAL))) {
00464 ast_log(LOG_WARNING, "Error loading module '%s': %s\n", resource_in, dlerror());
00465 ast_free(resource_being_loaded);
00466 return NULL;
00467 }
00468
00469
00470
00471
00472
00473 AST_LIST_LAST(&module_list)->lib = lib;
00474 resource_being_loaded = NULL;
00475
00476 return AST_LIST_LAST(&module_list);
00477 }
00478 #endif
00479
00480 void ast_module_shutdown(void)
00481 {
00482 struct ast_module *mod;
00483 int somethingchanged = 1, final = 0;
00484
00485 AST_LIST_LOCK(&module_list);
00486
00487
00488
00489
00490 do {
00491 if (!somethingchanged) {
00492
00493
00494 final = 1;
00495 }
00496
00497
00498 somethingchanged = 0;
00499
00500 AST_LIST_TRAVERSE_SAFE_BEGIN(&module_list, mod, entry) {
00501 if (!final && mod->usecount) {
00502 continue;
00503 }
00504 AST_LIST_REMOVE_CURRENT(entry);
00505 if (mod->flags.running && !mod->flags.declined && mod->info->unload) {
00506 mod->info->unload();
00507 }
00508 AST_LIST_HEAD_DESTROY(&mod->users);
00509 free(mod);
00510 somethingchanged = 1;
00511 }
00512 AST_LIST_TRAVERSE_SAFE_END;
00513 } while (somethingchanged && !final);
00514
00515 AST_LIST_UNLOCK(&module_list);
00516 }
00517
00518 int ast_unload_resource(const char *resource_name, enum ast_module_unload_mode force)
00519 {
00520 struct ast_module *mod;
00521 int res = -1;
00522 int error = 0;
00523
00524 AST_LIST_LOCK(&module_list);
00525
00526 if (!(mod = find_resource(resource_name, 0))) {
00527 AST_LIST_UNLOCK(&module_list);
00528 ast_log(LOG_WARNING, "Unload failed, '%s' could not be found\n", resource_name);
00529 return -1;
00530 }
00531
00532 if (!mod->flags.running || mod->flags.declined) {
00533 ast_log(LOG_WARNING, "Unload failed, '%s' is not loaded.\n", resource_name);
00534 error = 1;
00535 }
00536
00537 if (!error && (mod->usecount > 0)) {
00538 if (force)
00539 ast_log(LOG_WARNING, "Warning: Forcing removal of module '%s' with use count %d\n",
00540 resource_name, mod->usecount);
00541 else {
00542 ast_log(LOG_WARNING, "Soft unload failed, '%s' has use count %d\n", resource_name,
00543 mod->usecount);
00544 error = 1;
00545 }
00546 }
00547
00548 if (!error) {
00549 __ast_module_user_hangup_all(mod);
00550 res = mod->info->unload();
00551
00552 if (res) {
00553 ast_log(LOG_WARNING, "Firm unload failed for %s\n", resource_name);
00554 if (force <= AST_FORCE_FIRM)
00555 error = 1;
00556 else
00557 ast_log(LOG_WARNING, "** Dangerous **: Unloading resource anyway, at user request\n");
00558 }
00559 }
00560
00561 if (!error)
00562 mod->flags.running = mod->flags.declined = 0;
00563
00564 AST_LIST_UNLOCK(&module_list);
00565
00566 if (!error && !mod->lib && mod->info && mod->info->restore_globals)
00567 mod->info->restore_globals();
00568
00569 #ifdef LOADABLE_MODULES
00570 if (!error)
00571 unload_dynamic_module(mod);
00572 #endif
00573
00574 if (!error)
00575 ast_update_use_count();
00576
00577 return res;
00578 }
00579
00580 char *ast_module_helper(const char *line, const char *word, int pos, int state, int rpos, int needsreload)
00581 {
00582 struct ast_module *cur;
00583 int i, which=0, l = strlen(word);
00584 char *ret = NULL;
00585
00586 if (pos != rpos)
00587 return NULL;
00588
00589 AST_LIST_LOCK(&module_list);
00590 AST_LIST_TRAVERSE(&module_list, cur, entry) {
00591 if (!strncasecmp(word, cur->resource, l) &&
00592 (cur->info->reload || !needsreload) &&
00593 ++which > state) {
00594 ret = ast_strdup(cur->resource);
00595 break;
00596 }
00597 }
00598 AST_LIST_UNLOCK(&module_list);
00599
00600 if (!ret) {
00601 for (i=0; !ret && reload_classes[i].name; i++) {
00602 if (!strncasecmp(word, reload_classes[i].name, l) && ++which > state)
00603 ret = ast_strdup(reload_classes[i].name);
00604 }
00605 }
00606
00607 return ret;
00608 }
00609
00610 void ast_process_pending_reloads(void)
00611 {
00612 struct reload_queue_item *item;
00613
00614 if (!ast_fully_booted) {
00615 return;
00616 }
00617
00618 AST_LIST_LOCK(&reload_queue);
00619
00620 if (do_full_reload) {
00621 do_full_reload = 0;
00622 AST_LIST_UNLOCK(&reload_queue);
00623 ast_log(LOG_NOTICE, "Executing deferred reload request.\n");
00624 ast_module_reload(NULL);
00625 return;
00626 }
00627
00628 while ((item = AST_LIST_REMOVE_HEAD(&reload_queue, entry))) {
00629 ast_log(LOG_NOTICE, "Executing deferred reload request for module '%s'.\n", item->module);
00630 ast_module_reload(item->module);
00631 ast_free(item);
00632 }
00633
00634 AST_LIST_UNLOCK(&reload_queue);
00635 }
00636
00637 static void queue_reload_request(const char *module)
00638 {
00639 struct reload_queue_item *item;
00640
00641 AST_LIST_LOCK(&reload_queue);
00642
00643 if (do_full_reload) {
00644 AST_LIST_UNLOCK(&reload_queue);
00645 return;
00646 }
00647
00648 if (ast_strlen_zero(module)) {
00649
00650
00651 while ((item = AST_LIST_REMOVE_HEAD(&reload_queue, entry))) {
00652 ast_free(item);
00653 }
00654 do_full_reload = 1;
00655 } else {
00656
00657 AST_LIST_TRAVERSE(&reload_queue, item, entry) {
00658 if (!strcasecmp(item->module, module)) {
00659 AST_LIST_UNLOCK(&reload_queue);
00660 return;
00661 }
00662 }
00663 item = ast_calloc(1, sizeof(*item) + strlen(module) + 1);
00664 if (!item) {
00665 ast_log(LOG_ERROR, "Failed to allocate reload queue item.\n");
00666 AST_LIST_UNLOCK(&reload_queue);
00667 return;
00668 }
00669 strcpy(item->module, module);
00670 AST_LIST_INSERT_TAIL(&reload_queue, item, entry);
00671 }
00672 AST_LIST_UNLOCK(&reload_queue);
00673 }
00674
00675 int ast_module_reload(const char *name)
00676 {
00677 struct ast_module *cur;
00678 int res = 0;
00679 int i;
00680
00681
00682
00683 if (!ast_fully_booted) {
00684 queue_reload_request(name);
00685 return 0;
00686 }
00687
00688 if (ast_mutex_trylock(&reloadlock)) {
00689 ast_verbose("The previous reload command didn't finish yet\n");
00690 return -1;
00691 }
00692 ast_lastreloadtime = ast_tvnow();
00693
00694 if (ast_opt_lock_confdir) {
00695 int try;
00696 int res;
00697 for (try = 1, res = AST_LOCK_TIMEOUT; try < 6 && (res == AST_LOCK_TIMEOUT); try++) {
00698 res = ast_lock_path(ast_config_AST_CONFIG_DIR);
00699 if (res == AST_LOCK_TIMEOUT) {
00700 ast_log(LOG_WARNING, "Failed to grab lock on %s, try %d\n", ast_config_AST_CONFIG_DIR, try);
00701 }
00702 }
00703 if (res != AST_LOCK_SUCCESS) {
00704 ast_verbose("Cannot grab lock on %s\n", ast_config_AST_CONFIG_DIR);
00705 ast_mutex_unlock(&reloadlock);
00706 return -1;
00707 }
00708 }
00709
00710
00711 for (i = 0; reload_classes[i].name; i++) {
00712 if (!name || !strcasecmp(name, reload_classes[i].name)) {
00713 reload_classes[i].reload_fn();
00714 res = 2;
00715 }
00716 }
00717
00718 if (name && res) {
00719 if (ast_opt_lock_confdir) {
00720 ast_unlock_path(ast_config_AST_CONFIG_DIR);
00721 }
00722 ast_mutex_unlock(&reloadlock);
00723 return res;
00724 }
00725
00726 AST_LIST_LOCK(&module_list);
00727 AST_LIST_TRAVERSE(&module_list, cur, entry) {
00728 const struct ast_module_info *info = cur->info;
00729
00730 if (name && resource_name_match(name, cur->resource))
00731 continue;
00732
00733 if (!cur->flags.running || cur->flags.declined) {
00734 if (!name)
00735 continue;
00736 ast_log(LOG_NOTICE, "The module '%s' was not properly initialized. "
00737 "Before reloading the module, you must run \"module load %s\" "
00738 "and fix whatever is preventing the module from being initialized.\n",
00739 name, name);
00740 res = 2;
00741 break;
00742 }
00743
00744 if (!info->reload) {
00745 if (res < 1)
00746 res = 1;
00747 continue;
00748 }
00749
00750 res = 2;
00751 ast_verb(3, "Reloading module '%s' (%s)\n", cur->resource, info->description);
00752 info->reload();
00753 }
00754 AST_LIST_UNLOCK(&module_list);
00755
00756 if (ast_opt_lock_confdir) {
00757 ast_unlock_path(ast_config_AST_CONFIG_DIR);
00758 }
00759 ast_mutex_unlock(&reloadlock);
00760
00761 return res;
00762 }
00763
00764 static unsigned int inspect_module(const struct ast_module *mod)
00765 {
00766 if (!mod->info->description) {
00767 ast_log(LOG_WARNING, "Module '%s' does not provide a description.\n", mod->resource);
00768 return 1;
00769 }
00770
00771 if (!mod->info->key) {
00772 ast_log(LOG_WARNING, "Module '%s' does not provide a license key.\n", mod->resource);
00773 return 1;
00774 }
00775
00776 if (verify_key((unsigned char *) mod->info->key)) {
00777 ast_log(LOG_WARNING, "Module '%s' did not provide a valid license key.\n", mod->resource);
00778 return 1;
00779 }
00780
00781 if (!ast_strlen_zero(mod->info->buildopt_sum) &&
00782 strcmp(buildopt_sum, mod->info->buildopt_sum)) {
00783 ast_log(LOG_WARNING, "Module '%s' was not compiled with the same compile-time options as this version of Asterisk.\n", mod->resource);
00784 ast_log(LOG_WARNING, "Module '%s' will not be initialized as it may cause instability.\n", mod->resource);
00785 return 1;
00786 }
00787
00788 return 0;
00789 }
00790
00791 static enum ast_module_load_result start_resource(struct ast_module *mod)
00792 {
00793 char tmp[256];
00794 enum ast_module_load_result res;
00795
00796 if (!mod->info->load) {
00797 return AST_MODULE_LOAD_FAILURE;
00798 }
00799
00800 res = mod->info->load();
00801
00802 switch (res) {
00803 case AST_MODULE_LOAD_SUCCESS:
00804 if (!ast_fully_booted) {
00805 ast_verb(1, "%s => (%s)\n", mod->resource, term_color(tmp, mod->info->description, COLOR_BROWN, COLOR_BLACK, sizeof(tmp)));
00806 if (ast_opt_console && !option_verbose)
00807 ast_verbose( ".");
00808 } else {
00809 ast_verb(1, "Loaded %s => (%s)\n", mod->resource, mod->info->description);
00810 }
00811
00812 mod->flags.running = 1;
00813
00814 ast_update_use_count();
00815 break;
00816 case AST_MODULE_LOAD_DECLINE:
00817 mod->flags.declined = 1;
00818 break;
00819 case AST_MODULE_LOAD_FAILURE:
00820 case AST_MODULE_LOAD_SKIP:
00821 case AST_MODULE_LOAD_PRIORITY:
00822 break;
00823 }
00824
00825 return res;
00826 }
00827
00828
00829
00830
00831
00832
00833
00834
00835
00836
00837 static enum ast_module_load_result load_resource(const char *resource_name, unsigned int global_symbols_only, struct ast_heap *resource_heap, int required)
00838 {
00839 struct ast_module *mod;
00840 enum ast_module_load_result res = AST_MODULE_LOAD_SUCCESS;
00841
00842 if ((mod = find_resource(resource_name, 0))) {
00843 if (mod->flags.running) {
00844 ast_log(LOG_WARNING, "Module '%s' already exists.\n", resource_name);
00845 return AST_MODULE_LOAD_DECLINE;
00846 }
00847 if (global_symbols_only && !ast_test_flag(mod->info, AST_MODFLAG_GLOBAL_SYMBOLS))
00848 return AST_MODULE_LOAD_SKIP;
00849 } else {
00850 #ifdef LOADABLE_MODULES
00851 if (!(mod = load_dynamic_module(resource_name, global_symbols_only))) {
00852
00853 if (!global_symbols_only) {
00854 ast_log(LOG_WARNING, "Module '%s' could not be loaded.\n", resource_name);
00855 return required ? AST_MODULE_LOAD_FAILURE : AST_MODULE_LOAD_DECLINE;
00856 } else {
00857 return required ? AST_MODULE_LOAD_FAILURE : AST_MODULE_LOAD_SKIP;
00858 }
00859 }
00860 #else
00861 ast_log(LOG_WARNING, "Module '%s' could not be loaded.\n", resource_name);
00862 return required ? AST_MODULE_LOAD_FAILURE : AST_MODULE_LOAD_DECLINE;
00863 #endif
00864 }
00865
00866 if (inspect_module(mod)) {
00867 ast_log(LOG_WARNING, "Module '%s' could not be loaded.\n", resource_name);
00868 #ifdef LOADABLE_MODULES
00869 unload_dynamic_module(mod);
00870 #endif
00871 return required ? AST_MODULE_LOAD_FAILURE : AST_MODULE_LOAD_DECLINE;
00872 }
00873
00874 if (!mod->lib && mod->info->backup_globals && mod->info->backup_globals()) {
00875 ast_log(LOG_WARNING, "Module '%s' was unable to backup its global data.\n", resource_name);
00876 return required ? AST_MODULE_LOAD_FAILURE : AST_MODULE_LOAD_DECLINE;
00877 }
00878
00879 mod->flags.declined = 0;
00880
00881 if (resource_heap) {
00882 ast_heap_push(resource_heap, mod);
00883 res = AST_MODULE_LOAD_PRIORITY;
00884 } else {
00885 res = start_resource(mod);
00886 }
00887
00888 return res;
00889 }
00890
00891 int ast_load_resource(const char *resource_name)
00892 {
00893 int res;
00894 AST_LIST_LOCK(&module_list);
00895 res = load_resource(resource_name, 0, NULL, 0);
00896 AST_LIST_UNLOCK(&module_list);
00897
00898 return res;
00899 }
00900
00901 struct load_order_entry {
00902 char *resource;
00903 int required;
00904 AST_LIST_ENTRY(load_order_entry) entry;
00905 };
00906
00907 AST_LIST_HEAD_NOLOCK(load_order, load_order_entry);
00908
00909 static struct load_order_entry *add_to_load_order(const char *resource, struct load_order *load_order, int required)
00910 {
00911 struct load_order_entry *order;
00912
00913 AST_LIST_TRAVERSE(load_order, order, entry) {
00914 if (!resource_name_match(order->resource, resource)) {
00915
00916
00917 order->required |= required;
00918 return NULL;
00919 }
00920 }
00921
00922 if (!(order = ast_calloc(1, sizeof(*order))))
00923 return NULL;
00924
00925 order->resource = ast_strdup(resource);
00926 order->required = required;
00927 AST_LIST_INSERT_TAIL(load_order, order, entry);
00928
00929 return order;
00930 }
00931
00932 static int mod_load_cmp(void *a, void *b)
00933 {
00934 struct ast_module *a_mod = (struct ast_module *) a;
00935 struct ast_module *b_mod = (struct ast_module *) b;
00936 int res = -1;
00937
00938 unsigned char a_pri = ast_test_flag(a_mod->info, AST_MODFLAG_LOAD_ORDER) ? a_mod->info->load_pri : 128;
00939 unsigned char b_pri = ast_test_flag(b_mod->info, AST_MODFLAG_LOAD_ORDER) ? b_mod->info->load_pri : 128;
00940 if (a_pri == b_pri) {
00941 res = 0;
00942 } else if (a_pri < b_pri) {
00943 res = 1;
00944 }
00945 return res;
00946 }
00947
00948
00949
00950
00951 static int load_resource_list(struct load_order *load_order, unsigned int global_symbols, int *mod_count)
00952 {
00953 struct ast_heap *resource_heap;
00954 struct load_order_entry *order;
00955 struct ast_module *mod;
00956 int count = 0;
00957 int res = 0;
00958
00959 if(!(resource_heap = ast_heap_create(8, mod_load_cmp, -1))) {
00960 return -1;
00961 }
00962
00963
00964 AST_LIST_TRAVERSE_SAFE_BEGIN(load_order, order, entry) {
00965 switch (load_resource(order->resource, global_symbols, resource_heap, order->required)) {
00966 case AST_MODULE_LOAD_SUCCESS:
00967 case AST_MODULE_LOAD_DECLINE:
00968 AST_LIST_REMOVE_CURRENT(entry);
00969 ast_free(order->resource);
00970 ast_free(order);
00971 break;
00972 case AST_MODULE_LOAD_FAILURE:
00973 ast_log(LOG_ERROR, "*** Failed to load module %s - %s\n", order->resource, order->required ? "Required" : "Not required");
00974 fprintf(stderr, "*** Failed to load module %s - %s\n", order->resource, order->required ? "Required" : "Not required");
00975 res = order->required ? -2 : -1;
00976 goto done;
00977 case AST_MODULE_LOAD_SKIP:
00978 break;
00979 case AST_MODULE_LOAD_PRIORITY:
00980 AST_LIST_REMOVE_CURRENT(entry);
00981 break;
00982 }
00983 }
00984 AST_LIST_TRAVERSE_SAFE_END;
00985
00986
00987 while ((mod = ast_heap_pop(resource_heap))) {
00988 switch (start_resource(mod)) {
00989 case AST_MODULE_LOAD_SUCCESS:
00990 count++;
00991 case AST_MODULE_LOAD_DECLINE:
00992 break;
00993 case AST_MODULE_LOAD_FAILURE:
00994 res = -1;
00995 goto done;
00996 case AST_MODULE_LOAD_SKIP:
00997 case AST_MODULE_LOAD_PRIORITY:
00998 break;
00999 }
01000 }
01001
01002 done:
01003 if (mod_count) {
01004 *mod_count += count;
01005 }
01006 ast_heap_destroy(resource_heap);
01007
01008 return res;
01009 }
01010
01011 int load_modules(unsigned int preload_only)
01012 {
01013 struct ast_config *cfg;
01014 struct ast_module *mod;
01015 struct load_order_entry *order;
01016 struct ast_variable *v;
01017 unsigned int load_count;
01018 struct load_order load_order;
01019 int res = 0;
01020 struct ast_flags config_flags = { 0 };
01021 int modulecount = 0;
01022
01023 #ifdef LOADABLE_MODULES
01024 struct dirent *dirent;
01025 DIR *dir;
01026 #endif
01027
01028
01029 embedding = 0;
01030
01031 ast_verb(1, "Asterisk Dynamic Loader Starting:\n");
01032
01033 AST_LIST_HEAD_INIT_NOLOCK(&load_order);
01034
01035 AST_LIST_LOCK(&module_list);
01036
01037 if (embedded_module_list.first) {
01038 module_list.first = embedded_module_list.first;
01039 module_list.last = embedded_module_list.last;
01040 embedded_module_list.first = NULL;
01041 }
01042
01043 cfg = ast_config_load2(AST_MODULE_CONFIG, "" , config_flags);
01044 if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEINVALID) {
01045 ast_log(LOG_WARNING, "No '%s' found, no modules will be loaded.\n", AST_MODULE_CONFIG);
01046 goto done;
01047 }
01048
01049
01050 for (v = ast_variable_browse(cfg, "modules"); v; v = v->next) {
01051 if (!strcasecmp(v->name, preload_only ? "preload" : "load")) {
01052 add_to_load_order(v->value, &load_order, 0);
01053 }
01054 if (!strcasecmp(v->name, preload_only ? "preload-require" : "require")) {
01055
01056 add_to_load_order(v->value, &load_order, 1);
01057 ast_debug(2, "Adding module to required list: %s (%s)\n", v->value, v->name);
01058 }
01059
01060 }
01061
01062
01063 if (!preload_only && ast_true(ast_variable_retrieve(cfg, "modules", "autoload"))) {
01064
01065 AST_LIST_TRAVERSE(&module_list, mod, entry) {
01066
01067 if (mod->lib)
01068 continue;
01069
01070 if (mod->flags.running)
01071 continue;
01072
01073 add_to_load_order(mod->resource, &load_order, 0);
01074 }
01075
01076 #ifdef LOADABLE_MODULES
01077
01078
01079 if ((dir = opendir(ast_config_AST_MODULE_DIR))) {
01080 while ((dirent = readdir(dir))) {
01081 int ld = strlen(dirent->d_name);
01082
01083
01084
01085 if (ld < 4)
01086 continue;
01087
01088 if (strcasecmp(dirent->d_name + ld - 3, ".so"))
01089 continue;
01090
01091
01092
01093 if (find_resource(dirent->d_name, 0))
01094 continue;
01095
01096 add_to_load_order(dirent->d_name, &load_order, 0);
01097 }
01098
01099 closedir(dir);
01100 } else {
01101 if (!ast_opt_quiet)
01102 ast_log(LOG_WARNING, "Unable to open modules directory '%s'.\n",
01103 ast_config_AST_MODULE_DIR);
01104 }
01105 #endif
01106 }
01107
01108
01109
01110 for (v = ast_variable_browse(cfg, "modules"); v; v = v->next) {
01111 if (strcasecmp(v->name, "noload"))
01112 continue;
01113
01114 AST_LIST_TRAVERSE_SAFE_BEGIN(&load_order, order, entry) {
01115 if (!resource_name_match(order->resource, v->value)) {
01116 AST_LIST_REMOVE_CURRENT(entry);
01117 ast_free(order->resource);
01118 ast_free(order);
01119 }
01120 }
01121 AST_LIST_TRAVERSE_SAFE_END;
01122 }
01123
01124
01125
01126 ast_config_destroy(cfg);
01127
01128 load_count = 0;
01129 AST_LIST_TRAVERSE(&load_order, order, entry)
01130 load_count++;
01131
01132 if (load_count)
01133 ast_log(LOG_NOTICE, "%d modules will be loaded.\n", load_count);
01134
01135
01136 if ((res = load_resource_list(&load_order, 1, &modulecount)) < 0) {
01137 goto done;
01138 }
01139
01140
01141 if ((res = load_resource_list(&load_order, 0, &modulecount)) < 0) {
01142 goto done;
01143 }
01144
01145 done:
01146 while ((order = AST_LIST_REMOVE_HEAD(&load_order, entry))) {
01147 ast_free(order->resource);
01148 ast_free(order);
01149 }
01150
01151 AST_LIST_UNLOCK(&module_list);
01152
01153
01154
01155
01156 manager_event(EVENT_FLAG_SYSTEM, "ModuleLoadReport", "ModuleLoadStatus: Done\r\nModuleSelection: %s\r\nModuleCount: %d\r\n", preload_only ? "Preload" : "All", modulecount);
01157
01158 return res;
01159 }
01160
01161 void ast_update_use_count(void)
01162 {
01163
01164
01165 struct loadupdate *m;
01166
01167 AST_LIST_LOCK(&updaters);
01168 AST_LIST_TRAVERSE(&updaters, m, entry)
01169 m->updater();
01170 AST_LIST_UNLOCK(&updaters);
01171 }
01172
01173 int ast_update_module_list(int (*modentry)(const char *module, const char *description, int usecnt, const char *like),
01174 const char *like)
01175 {
01176 struct ast_module *cur;
01177 int unlock = -1;
01178 int total_mod_loaded = 0;
01179
01180 if (AST_LIST_TRYLOCK(&module_list))
01181 unlock = 0;
01182
01183 AST_LIST_TRAVERSE(&module_list, cur, entry) {
01184 total_mod_loaded += modentry(cur->resource, cur->info->description, cur->usecount, like);
01185 }
01186
01187 if (unlock)
01188 AST_LIST_UNLOCK(&module_list);
01189
01190 return total_mod_loaded;
01191 }
01192
01193
01194 int ast_module_check(const char *name)
01195 {
01196 struct ast_module *cur;
01197
01198 if (ast_strlen_zero(name))
01199 return 0;
01200
01201 cur = find_resource(name, 1);
01202
01203 return (cur != NULL);
01204 }
01205
01206
01207 int ast_loader_register(int (*v)(void))
01208 {
01209 struct loadupdate *tmp;
01210
01211 if (!(tmp = ast_malloc(sizeof(*tmp))))
01212 return -1;
01213
01214 tmp->updater = v;
01215 AST_LIST_LOCK(&updaters);
01216 AST_LIST_INSERT_HEAD(&updaters, tmp, entry);
01217 AST_LIST_UNLOCK(&updaters);
01218
01219 return 0;
01220 }
01221
01222 int ast_loader_unregister(int (*v)(void))
01223 {
01224 struct loadupdate *cur;
01225
01226 AST_LIST_LOCK(&updaters);
01227 AST_LIST_TRAVERSE_SAFE_BEGIN(&updaters, cur, entry) {
01228 if (cur->updater == v) {
01229 AST_LIST_REMOVE_CURRENT(entry);
01230 break;
01231 }
01232 }
01233 AST_LIST_TRAVERSE_SAFE_END;
01234 AST_LIST_UNLOCK(&updaters);
01235
01236 return cur ? 0 : -1;
01237 }
01238
01239 struct ast_module *ast_module_ref(struct ast_module *mod)
01240 {
01241 if (!mod) {
01242 return NULL;
01243 }
01244
01245 ast_atomic_fetchadd_int(&mod->usecount, +1);
01246 ast_update_use_count();
01247
01248 return mod;
01249 }
01250
01251 void ast_module_unref(struct ast_module *mod)
01252 {
01253 if (!mod) {
01254 return;
01255 }
01256
01257 ast_atomic_fetchadd_int(&mod->usecount, -1);
01258 ast_update_use_count();
01259 }