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