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