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