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