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