![]() |
Home page |
Mailing list |
Docs
Asterisk developer's documentation :: Codename Pineapple
loader.c
Go to the documentation of this file.
00001 /* 00002 * Asterisk -- An open source telephony toolkit. 00003 * 00004 * Copyright (C) 1999 - 2006, Digium, Inc. 00005 * 00006 * Mark Spencer <markster@digium.com> 00007 * Kevin P. Fleming <kpfleming@digium.com> 00008 * Luigi Rizzo <rizzo@icir.org> 00009 * 00010 * See http://www.asterisk.org for more information about 00011 * the Asterisk project. Please do not directly contact 00012 * any of the maintainers of this project for assistance; 00013 * the project provides a web site, mailing lists and IRC 00014 * channels for your use. 00015 * 00016 * This program is free software, distributed under the terms of 00017 * the GNU General Public License Version 2. See the LICENSE file 00018 * at the top of the source tree. 00019 */ 00020 00021 /*! \file 00022 * 00023 * \brief Module Loader 00024 * \author Mark Spencer <markster@digium.com> 00025 * \author Kevin P. Fleming <kpfleming@digium.com> 00026 * \author Luigi Rizzo <rizzo@icir.org> 00027 * - See ModMngMnt 00028 */ 00029 00030 #include "asterisk.h" 00031 00032 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 46594 $") 00033 00034 #include <stdio.h> 00035 #include <dirent.h> 00036 #include <unistd.h> 00037 #include <stdlib.h> 00038 #include <errno.h> 00039 #include <string.h> 00040 00041 #include "asterisk/linkedlists.h" 00042 #include "asterisk/module.h" 00043 #include "asterisk/options.h" 00044 #include "asterisk/config.h" 00045 #include "asterisk/logger.h" 00046 #include "asterisk/channel.h" 00047 #include "asterisk/term.h" 00048 #include "asterisk/manager.h" 00049 #include "asterisk/cdr.h" 00050 #include "asterisk/enum.h" 00051 #include "asterisk/rtp.h" 00052 #include "asterisk/http.h" 00053 #include "asterisk/lock.h" 00054 00055 #ifdef DLFCNCOMPAT 00056 #include "asterisk/dlfcn-compat.h" 00057 #else 00058 #include <dlfcn.h> 00059 #endif 00060 00061 #include "asterisk/md5.h" 00062 #include "asterisk/utils.h" 00063 00064 #ifndef RTLD_NOW 00065 #define RTLD_NOW 0 00066 #endif 00067 00068 struct ast_module_user { 00069 struct ast_channel *chan; 00070 AST_LIST_ENTRY(ast_module_user) entry; 00071 }; 00072 00073 AST_LIST_HEAD(module_user_list, ast_module_user); 00074 00075 static unsigned char expected_key[] = 00076 { 0x87, 0x76, 0x79, 0x35, 0x23, 0xea, 0x3a, 0xd3, 00077 0x25, 0x2a, 0xbb, 0x35, 0x87, 0xe4, 0x22, 0x24 }; 00078 00079 static unsigned int embedding = 1; /* we always start out by registering embedded modules, 00080 since they are here before we dlopen() any 00081 */ 00082 00083 enum flags { 00084 FLAG_RUNNING = (1 << 1), /* module successfully initialized */ 00085 FLAG_DECLINED = (1 << 2), /* module declined to initialize */ 00086 }; 00087 00088 struct ast_module { 00089 const struct ast_module_info *info; 00090 void *lib; /* the shared lib, or NULL if embedded */ 00091 int usecount; /* the number of 'users' currently in this module */ 00092 struct module_user_list users; /* the list of users in the module */ 00093 unsigned int flags; /* flags for this module */ 00094 AST_LIST_ENTRY(ast_module) entry; 00095 char resource[0]; 00096 }; 00097 00098 static AST_LIST_HEAD_STATIC(module_list, ast_module); 00099 00100 struct loadupdate { 00101 int (*updater)(void); 00102 AST_LIST_ENTRY(loadupdate) entry; 00103 }; 00104 00105 static AST_LIST_HEAD_STATIC(updaters, loadupdate); 00106 00107 AST_MUTEX_DEFINE_STATIC(reloadlock); 00108 00109 /* when dynamic modules are being loaded, ast_module_register() will 00110 need to know what filename the module was loaded from while it 00111 is being registered 00112 */ 00113 struct ast_module *resource_being_loaded; 00114 00115 /* XXX: should we check for duplicate resource names here? */ 00116 00117 void ast_module_register(const struct ast_module_info *info) 00118 { 00119 struct ast_module *mod; 00120 00121 if (embedding) { 00122 if (!(mod = ast_calloc(1, sizeof(*mod) + strlen(info->name) + 1))) 00123 return; 00124 strcpy(mod->resource, info->name); 00125 } else { 00126 mod = resource_being_loaded; 00127 } 00128 00129 mod->info = info; 00130 AST_LIST_HEAD_INIT(&mod->users); 00131 00132 /* during startup, before the loader has been initialized, 00133 there are no threads, so there is no need to take the lock 00134 on this list to manipulate it. it is also possible that it 00135 might be unsafe to use the list lock at that point... so 00136 let's avoid it altogether 00137 */ 00138 if (!embedding) 00139 AST_LIST_LOCK(&module_list); 00140 00141 /* it is paramount that the new entry be placed at the tail of 00142 the list, otherwise the code that uses dlopen() to load 00143 dynamic modules won't be able to find out if the module it 00144 just opened was registered or failed to load 00145 */ 00146 AST_LIST_INSERT_TAIL(&module_list, mod, entry); 00147 00148 if (!embedding) 00149 AST_LIST_UNLOCK(&module_list); 00150 00151 /* give the module a copy of its own handle, for later use in registrations and the like */ 00152 *((struct ast_module **) &(info->self)) = mod; 00153 } 00154 00155 void ast_module_unregister(const struct ast_module_info *info) 00156 { 00157 struct ast_module *mod = NULL; 00158 00159 /* it is assumed that the users list in the module structure 00160 will already be empty, or we cannot have gotten to this 00161 point 00162 */ 00163 AST_LIST_LOCK(&module_list); 00164 AST_LIST_TRAVERSE_SAFE_BEGIN(&module_list, mod, entry) { 00165 if (mod->info == info) { 00166 AST_LIST_REMOVE_CURRENT(&module_list, entry); 00167 break; 00168 } 00169 } 00170 AST_LIST_TRAVERSE_SAFE_END; 00171 AST_LIST_UNLOCK(&module_list); 00172 00173 if (mod) { 00174 AST_LIST_HEAD_DESTROY(&mod->users); 00175 free(mod); 00176 } 00177 } 00178 00179 struct ast_module_user *__ast_module_user_add(struct ast_module *mod, 00180 struct ast_channel *chan) 00181 { 00182 struct ast_module_user *u = ast_calloc(1, sizeof(*u)); 00183 00184 if (!u) 00185 return NULL; 00186 00187 u->chan = chan; 00188 00189 AST_LIST_LOCK(&mod->users); 00190 AST_LIST_INSERT_HEAD(&mod->users, u, entry); 00191 AST_LIST_UNLOCK(&mod->users); 00192 00193 ast_atomic_fetchadd_int(&mod->usecount, +1); 00194 00195 ast_update_use_count(); 00196 00197 return u; 00198 } 00199 00200 void __ast_module_user_remove(struct ast_module *mod, struct ast_module_user *u) 00201 { 00202 AST_LIST_LOCK(&mod->users); 00203 AST_LIST_REMOVE(&mod->users, u, entry); 00204 AST_LIST_UNLOCK(&mod->users); 00205 ast_atomic_fetchadd_int(&mod->usecount, -1); 00206 free(u); 00207 00208 ast_update_use_count(); 00209 } 00210 00211 void __ast_module_user_hangup_all(struct ast_module *mod) 00212 { 00213 struct ast_module_user *u; 00214 00215 AST_LIST_LOCK(&mod->users); 00216 while ((u = AST_LIST_REMOVE_HEAD(&mod->users, entry))) { 00217 ast_softhangup(u->chan, AST_SOFTHANGUP_APPUNLOAD); 00218 ast_atomic_fetchadd_int(&mod->usecount, -1); 00219 free(u); 00220 } 00221 AST_LIST_UNLOCK(&mod->users); 00222 00223 ast_update_use_count(); 00224 } 00225 00226 /*! \note 00227 * In addition to modules, the reload command handles some extra keywords 00228 * which are listed here together with the corresponding handlers. 00229 * This table is also used by the command completion code. 00230 */ 00231 static struct reload_classes { 00232 const char *name; 00233 int (*reload_fn)(void); 00234 } reload_classes[] = { /* list in alpha order, longest match first for cli completion */ 00235 { "cdr", ast_cdr_engine_reload }, 00236 { "dnsmgr", dnsmgr_reload }, 00237 { "extconfig", read_config_maps }, 00238 { "enum", ast_enum_reload }, 00239 { "manager", reload_manager }, 00240 { "rtp", ast_rtp_reload }, 00241 { "http", ast_http_reload }, 00242 { NULL, NULL } 00243 }; 00244 00245 static int printdigest(const unsigned char *d) 00246 { 00247 int x, pos; 00248 char buf[256]; /* large enough so we don't have to worry */ 00249 00250 for (pos = 0, x = 0; x < 16; x++) 00251 pos += sprintf(buf + pos, " %02x", *d++); 00252 00253 if (option_debug) 00254 ast_log(LOG_DEBUG, "Unexpected signature:%s\n", buf); 00255 00256 return 0; 00257 } 00258 00259 static int key_matches(const unsigned char *key1, const unsigned char *key2) 00260 { 00261 int x; 00262 00263 for (x = 0; x < 16; x++) { 00264 if (key1[x] != key2[x]) 00265 return 0; 00266 } 00267 00268 return 1; 00269 } 00270 00271 static int verify_key(const unsigned char *key) 00272 { 00273 struct MD5Context c; 00274 unsigned char digest[16]; 00275 00276 MD5Init(&c); 00277 MD5Update(&c, key, strlen((char *)key)); 00278 MD5Final(digest, &c); 00279 00280 if (key_matches(expected_key, digest)) 00281 return 0; 00282 00283 printdigest(digest); 00284 00285 return -1; 00286 } 00287 00288 static int resource_name_match(const char *name1_in, const char *name2_in) 00289 { 00290 char *name1 = (char *) name1_in; 00291 char *name2 = (char *) name2_in; 00292 00293 /* trim off any .so extensions */ 00294 if (!strcasecmp(name1 + strlen(name1) - 3, ".so")) { 00295 name1 = ast_strdupa(name1); 00296 name1[strlen(name1) - 3] = '\0'; 00297 } 00298 if (!strcasecmp(name2 + strlen(name2) - 3, ".so")) { 00299 name2 = ast_strdupa(name2); 00300 name2[strlen(name2) - 3] = '\0'; 00301 } 00302 00303 return strcasecmp(name1, name2); 00304 } 00305 00306 static struct ast_module *find_resource(const char *resource, int do_lock) 00307 { 00308 struct ast_module *cur; 00309 00310 if (do_lock) 00311 AST_LIST_LOCK(&module_list); 00312 00313 AST_LIST_TRAVERSE(&module_list, cur, entry) { 00314 if (!resource_name_match(resource, cur->resource)) 00315 break; 00316 } 00317 00318 if (do_lock) 00319 AST_LIST_UNLOCK(&module_list); 00320 00321 return cur; 00322 } 00323 00324 #if LOADABLE_MODULES 00325 static void unload_dynamic_module(struct ast_module *mod) 00326 { 00327 void *lib = mod->lib; 00328 00329 /* WARNING: the structure pointed to by mod is going to 00330 disappear when this operation succeeds, so we can't 00331 dereference it */ 00332 00333 if (lib) 00334 while (!dlclose(lib)); 00335 } 00336 00337 static struct ast_module *load_dynamic_module(const char *resource_in, unsigned int global_symbols_only) 00338 { 00339 char fn[256]; 00340 void *lib; 00341 struct ast_module *mod; 00342 char *resource = (char *) resource_in; 00343 unsigned int wants_global; 00344 00345 if (strcasecmp(resource + strlen(resource) - 3, ".so")) { 00346 resource = alloca(strlen(resource_in) + 3); 00347 strcpy(resource, resource_in); 00348 strcat(resource, ".so"); 00349 } 00350 00351 snprintf(fn, sizeof(fn), "%s/%s", ast_config_AST_MODULE_DIR, resource); 00352 00353 /* make a first load of the module in 'quiet' mode... don't try to resolve 00354 any symbols, and don't export any symbols. this will allow us to peek into 00355 the module's info block (if available) to see what flags it has set */ 00356 00357 if (!(resource_being_loaded = ast_calloc(1, sizeof(*resource_being_loaded) + strlen(resource) + 1))) 00358 return NULL; 00359 00360 strcpy(resource_being_loaded->resource, resource); 00361 00362 if (!(lib = dlopen(fn, RTLD_LAZY | RTLD_LOCAL))) { 00363 ast_log(LOG_WARNING, "Error loading module '%s': %s\n", resource_in, dlerror()); 00364 free(resource_being_loaded); 00365 return NULL; 00366 } 00367 00368 /* the dlopen() succeeded, let's find out if the module 00369 registered itself */ 00370 /* note that this will only work properly as long as 00371 ast_module_register() (which is called by the module's 00372 constructor) places the new module at the tail of the 00373 module_list 00374 */ 00375 if (resource_being_loaded != (mod = AST_LIST_LAST(&module_list))) { 00376 ast_log(LOG_WARNING, "Module '%s' did not register itself during load\n", resource_in); 00377 /* no, it did not, so close it and return */ 00378 while (!dlclose(lib)); 00379 /* note that the module's destructor will call ast_module_unregister(), 00380 which will free the structure we allocated in resource_being_loaded */ 00381 return NULL; 00382 } 00383 00384 wants_global = ast_test_flag(mod->info, AST_MODFLAG_GLOBAL_SYMBOLS); 00385 00386 /* if we are being asked only to load modules that provide global symbols, 00387 and this one does not, then close it and return */ 00388 if (global_symbols_only && !wants_global) { 00389 while (!dlclose(lib)); 00390 return NULL; 00391 } 00392 00393 /* if the system supports RTLD_NOLOAD, we can just 'promote' the flags 00394 on the already-opened library to what we want... if not, we have to 00395 close it and start over 00396 */ 00397 #if defined(HAVE_RTLD_NOLOAD) && !defined(__Darwin__) 00398 if (!dlopen(fn, RTLD_NOLOAD | (wants_global ? RTLD_LAZY | RTLD_GLOBAL : RTLD_NOW | RTLD_LOCAL))) { 00399 ast_log(LOG_WARNING, "Unable to promote flags on module '%s': %s\n", resource_in, dlerror()); 00400 while (!dlclose(lib)); 00401 free(resource_being_loaded); 00402 return NULL; 00403 } 00404 #else 00405 while (!dlclose(lib)); 00406 resource_being_loaded = NULL; 00407 00408 /* start the load process again */ 00409 00410 if (!(resource_being_loaded = ast_calloc(1, sizeof(*resource_being_loaded) + strlen(resource) + 1))) 00411 return NULL; 00412 00413 strcpy(resource_being_loaded->resource, resource); 00414 00415 if (!(lib = dlopen(fn, wants_global ? RTLD_LAZY | RTLD_GLOBAL : RTLD_NOW | RTLD_LOCAL))) { 00416 ast_log(LOG_WARNING, "Error loading module '%s': %s\n", resource_in, dlerror()); 00417 free(resource_being_loaded); 00418 return NULL; 00419 } 00420 00421 /* since the module was successfully opened, and it registered itself 00422 the previous time we did that, we're going to assume it worked this 00423 time too :) */ 00424 #endif 00425 00426 AST_LIST_LAST(&module_list)->lib = lib; 00427 resource_being_loaded = NULL; 00428 00429 return AST_LIST_LAST(&module_list); 00430 } 00431 #endif 00432 00433 int ast_unload_resource(const char *resource_name, enum ast_module_unload_mode force) 00434 { 00435 struct ast_module *mod; 00436 int res = -1; 00437 int error = 0; 00438 00439 AST_LIST_LOCK(&module_list); 00440 00441 if (!(mod = find_resource(resource_name, 0))) { 00442 AST_LIST_UNLOCK(&module_list); 00443 return 0; 00444 } 00445 00446 if (!ast_test_flag(mod, FLAG_RUNNING | FLAG_DECLINED)) 00447 error = 1; 00448 00449 if (!error && (mod->usecount > 0)) { 00450 if (force) 00451 ast_log(LOG_WARNING, "Warning: Forcing removal of module '%s' with use count %d\n", 00452 resource_name, mod->usecount); 00453 else { 00454 ast_log(LOG_WARNING, "Soft unload failed, '%s' has use count %d\n", resource_name, 00455 mod->usecount); 00456 error = 1; 00457 } 00458 } 00459 00460 if (!error) { 00461 __ast_module_user_hangup_all(mod); 00462 res = mod->info->unload(); 00463 00464 if (res) { 00465 ast_log(LOG_WARNING, "Firm unload failed for %s\n", resource_name); 00466 if (force <= AST_FORCE_FIRM) 00467 error = 1; 00468 else 00469 ast_log(LOG_WARNING, "** Dangerous **: Unloading resource anyway, at user request\n"); 00470 } 00471 } 00472 00473 if (!error) 00474 ast_clear_flag(mod, FLAG_RUNNING | FLAG_DECLINED); 00475 00476 AST_LIST_UNLOCK(&module_list); 00477 00478 #if LOADABLE_MODULES 00479 if (!error) 00480 unload_dynamic_module(mod); 00481 #endif 00482 00483 if (!error) 00484 ast_update_use_count(); 00485 00486 return res; 00487 } 00488 00489 char *ast_module_helper(const char *line, const char *word, int pos, int state, int rpos, int needsreload) 00490 { 00491 struct ast_module *cur; 00492 int i, which=0, l = strlen(word); 00493 char *ret = NULL; 00494 00495 if (pos != rpos) 00496 return NULL; 00497 00498 AST_LIST_LOCK(&module_list); 00499 AST_LIST_TRAVERSE(&module_list, cur, entry) { 00500 if (!strncasecmp(word, cur->resource, l) && 00501 (cur->info->reload || !needsreload) && 00502 ++which > state) { 00503 ret = strdup(cur->resource); 00504 break; 00505 } 00506 } 00507 AST_LIST_UNLOCK(&module_list); 00508 00509 if (!ret) { 00510 for (i=0; !ret && reload_classes[i].name; i++) { 00511 if (!strncasecmp(word, reload_classes[i].name, l) && ++which > state) 00512 ret = strdup(reload_classes[i].name); 00513 } 00514 } 00515 00516 return ret; 00517 } 00518 00519 int ast_module_reload(const char *name) 00520 { 00521 struct ast_module *cur; 00522 int res = 0; /* return value. 0 = not found, others, see below */ 00523 int i; 00524 00525 if (ast_mutex_trylock(&reloadlock)) { 00526 ast_verbose("The previous reload command didn't finish yet\n"); 00527 return -1; /* reload already in progress */ 00528 } 00529 00530 /* Call "predefined" reload here first */ 00531 for (i = 0; reload_classes[i].name; i++) { 00532 if (!name || !strcasecmp(name, reload_classes[i].name)) { 00533 reload_classes[i].reload_fn(); /* XXX should check error ? */ 00534 res = 2; /* found and reloaded */ 00535 } 00536 } 00537 ast_lastreloadtime = time(NULL); 00538 00539 if (name && res) 00540 return res; 00541 00542 AST_LIST_LOCK(&module_list); 00543 AST_LIST_TRAVERSE(&module_list, cur, entry) { 00544 const struct ast_module_info *info = cur->info; 00545 00546 if (name && resource_name_match(name, cur->resource)) 00547 continue; 00548 00549 if (!ast_test_flag(cur, FLAG_RUNNING | FLAG_DECLINED)) 00550 continue; 00551 00552 if (!info->reload) { /* cannot be reloaded */ 00553 if (res < 1) /* store result if possible */ 00554 res = 1; /* 1 = no reload() method */ 00555 continue; 00556 } 00557 00558 res = 2; 00559 if (option_verbose > 2) 00560 ast_verbose(VERBOSE_PREFIX_3 "Reloading module '%s' (%s)\n", cur->resource, info->description); 00561 info->reload(); 00562 } 00563 AST_LIST_UNLOCK(&module_list); 00564 00565 ast_mutex_unlock(&reloadlock); 00566 00567 return res; 00568 } 00569 00570 static unsigned int inspect_module(const struct ast_module *mod) 00571 { 00572 if (!mod->info->description) { 00573 ast_log(LOG_WARNING, "Module '%s' does not provide a description.\n", mod->resource); 00574 return 1; 00575 } 00576 00577 if (!mod->info->key) { 00578 ast_log(LOG_WARNING, "Module '%s' does not provide a license key.\n", mod->resource); 00579 return 1; 00580 } 00581 00582 if (verify_key((unsigned char *) mod->info->key)) { 00583 ast_log(LOG_WARNING, "Module '%s' did not provide a valid license key.\n", mod->resource); 00584 return 1; 00585 } 00586 00587 return 0; 00588 } 00589 00590 static enum ast_module_load_result load_resource(const char *resource_name, unsigned int global_symbols_only) 00591 { 00592 struct ast_module *mod; 00593 enum ast_module_load_result res = AST_MODULE_LOAD_SUCCESS; 00594 char tmp[256]; 00595 00596 if ((mod = find_resource(resource_name, 0))) { 00597 if (ast_test_flag(mod, FLAG_RUNNING)) { 00598 ast_log(LOG_WARNING, "Module '%s' already exists.\n", resource_name); 00599 return AST_MODULE_LOAD_DECLINE; 00600 } 00601 if (global_symbols_only && !ast_test_flag(mod->info, AST_MODFLAG_GLOBAL_SYMBOLS)) 00602 return AST_MODULE_LOAD_SKIP; 00603 } else { 00604 #if LOADABLE_MODULES 00605 if (!(mod = load_dynamic_module(resource_name, global_symbols_only))) { 00606 /* don't generate a warning message during load_modules() */ 00607 if (!global_symbols_only) { 00608 ast_log(LOG_WARNING, "Module '%s' could not be loaded.\n", resource_name); 00609 return AST_MODULE_LOAD_DECLINE; 00610 } else { 00611 return AST_MODULE_LOAD_SKIP; 00612 } 00613 } 00614 #else 00615 ast_log(LOG_WARNING, "Module '%s' could not be loaded.\n", resource_name); 00616 return AST_MODULE_LOAD_DECLINE; 00617 #endif 00618 } 00619 00620 if (inspect_module(mod)) { 00621 ast_log(LOG_WARNING, "Module '%s' could not be loaded.\n", resource_name); 00622 #if LOADABLE_MODULES 00623 unload_dynamic_module(mod); 00624 #endif 00625 return AST_MODULE_LOAD_DECLINE; 00626 } 00627 00628 ast_clear_flag(mod, FLAG_DECLINED); 00629 00630 if (mod->info->load) 00631 res = mod->info->load(); 00632 00633 switch (res) { 00634 case AST_MODULE_LOAD_SUCCESS: 00635 if (!ast_fully_booted) { 00636 if (option_verbose) 00637 ast_verbose("%s => (%s)\n", resource_name, term_color(tmp, mod->info->description, COLOR_BROWN, COLOR_BLACK, sizeof(tmp))); 00638 if (ast_opt_console && !option_verbose) 00639 ast_verbose( "."); 00640 } else { 00641 if (option_verbose) 00642 ast_verbose(VERBOSE_PREFIX_1 "Loaded %s => (%s)\n", resource_name, mod->info->description); 00643 } 00644 00645 ast_set_flag(mod, FLAG_RUNNING); 00646 00647 ast_update_use_count(); 00648 break; 00649 case AST_MODULE_LOAD_DECLINE: 00650 ast_set_flag(mod, FLAG_DECLINED); 00651 break; 00652 case AST_MODULE_LOAD_FAILURE: 00653 break; 00654 case AST_MODULE_LOAD_SKIP: 00655 /* modules should never return this value */ 00656 break; 00657 } 00658 00659 return res; 00660 } 00661 00662 int ast_load_resource(const char *resource_name) 00663 { 00664 AST_LIST_LOCK(&module_list); 00665 load_resource(resource_name, 0); 00666 AST_LIST_UNLOCK(&module_list); 00667 00668 return 0; 00669 } 00670 00671 struct load_order_entry { 00672 char *resource; 00673 AST_LIST_ENTRY(load_order_entry) entry; 00674 }; 00675 00676 AST_LIST_HEAD_NOLOCK(load_order, load_order_entry); 00677 00678 static struct load_order_entry *add_to_load_order(const char *resource, struct load_order *load_order) 00679 { 00680 struct load_order_entry *order; 00681 00682 AST_LIST_TRAVERSE(load_order, order, entry) { 00683 if (!resource_name_match(order->resource, resource)) 00684 return NULL; 00685 } 00686 00687 if (!(order = ast_calloc(1, sizeof(*order)))) 00688 return NULL; 00689 00690 order->resource = ast_strdup(resource); 00691 AST_LIST_INSERT_TAIL(load_order, order, entry); 00692 00693 return order; 00694 } 00695 00696 int load_modules(unsigned int preload_only) 00697 { 00698 struct ast_config *cfg; 00699 struct ast_module *mod; 00700 struct load_order_entry *order; 00701 struct ast_variable *v; 00702 unsigned int load_count; 00703 struct load_order load_order; 00704 int res = 0; 00705 #if LOADABLE_MODULES 00706 struct dirent *dirent; 00707 DIR *dir; 00708 #endif 00709 00710 /* all embedded modules have registered themselves by now */ 00711 embedding = 0; 00712 00713 if (option_verbose) 00714 ast_verbose("Asterisk Dynamic Loader Starting:\n"); 00715 00716 AST_LIST_TRAVERSE(&module_list, mod, entry) { 00717 if (option_debug > 1) 00718 ast_log(LOG_DEBUG, "Embedded module found: %s\n", mod->resource); 00719 } 00720 00721 if (!(cfg = ast_config_load(AST_MODULE_CONFIG))) { 00722 ast_log(LOG_WARNING, "No '%s' found, no modules will be loaded.\n", AST_MODULE_CONFIG); 00723 return 0; 00724 } 00725 00726 AST_LIST_HEAD_INIT_NOLOCK(&load_order); 00727 00728 /* first, find all the modules we have been explicitly requested to load */ 00729 for (v = ast_variable_browse(cfg, "modules"); v; v = v->next) { 00730 if (!strcasecmp(v->name, preload_only ? "preload" : "load")) 00731 add_to_load_order(v->value, &load_order); 00732 } 00733 00734 /* check if 'autoload' is on */ 00735 if (!preload_only && ast_true(ast_variable_retrieve(cfg, "modules", "autoload"))) { 00736 /* if so, first add all the embedded modules to the load order */ 00737 AST_LIST_TRAVERSE(&module_list, mod, entry) 00738 order = add_to_load_order(mod->resource, &load_order); 00739 00740 #if LOADABLE_MODULES 00741 /* if we are allowed to load dynamic modules, scan the directory for 00742 for all available modules and add them as well */ 00743 if ((dir = opendir(ast_config_AST_MODULE_DIR))) { 00744 while ((dirent = readdir(dir))) { 00745 int ld = strlen(dirent->d_name); 00746 00747 /* Must end in .so to load it. */ 00748 00749 if (ld < 4) 00750 continue; 00751 00752 if (strcasecmp(dirent->d_name + ld - 3, ".so")) 00753 continue; 00754 00755 add_to_load_order(dirent->d_name, &load_order); 00756 00757 } 00758 00759 closedir(dir); 00760 } else { 00761 if (!ast_opt_quiet) 00762 ast_log(LOG_WARNING, "Unable to open modules directory '%s'.\n", 00763 ast_config_AST_MODULE_DIR); 00764 } 00765 #endif 00766 } 00767 00768 /* now scan the config for any modules we are prohibited from loading and 00769 remove them from the load order */ 00770 for (v = ast_variable_browse(cfg, "modules"); v; v = v->next) { 00771 if (strcasecmp(v->name, "noload")) 00772 continue; 00773 00774 AST_LIST_TRAVERSE_SAFE_BEGIN(&load_order, order, entry) { 00775 if (!resource_name_match(order->resource, v->value)) { 00776 AST_LIST_REMOVE_CURRENT(&load_order, entry); 00777 free(order->resource); 00778 free(order); 00779 } 00780 } 00781 AST_LIST_TRAVERSE_SAFE_END; 00782 } 00783 00784 /* we are done with the config now, all the information we need is in the 00785 load_order list */ 00786 ast_config_destroy(cfg); 00787 00788 load_count = 0; 00789 AST_LIST_TRAVERSE(&load_order, order, entry) 00790 load_count++; 00791 00792 if (load_count) 00793 ast_log(LOG_NOTICE, "%d modules will be loaded.\n", load_count); 00794 00795 /* first, load only modules that provide global symbols */ 00796 AST_LIST_TRAVERSE_SAFE_BEGIN(&load_order, order, entry) { 00797 switch (load_resource(order->resource, 1)) { 00798 case AST_MODULE_LOAD_SUCCESS: 00799 case AST_MODULE_LOAD_DECLINE: 00800 AST_LIST_REMOVE_CURRENT(&load_order, entry); 00801 free(order->resource); 00802 free(order); 00803 break; 00804 case AST_MODULE_LOAD_FAILURE: 00805 res = -1; 00806 goto done; 00807 case AST_MODULE_LOAD_SKIP: 00808 /* try again later */ 00809 break; 00810 } 00811 } 00812 AST_LIST_TRAVERSE_SAFE_END; 00813 00814 /* now load everything else */ 00815 AST_LIST_TRAVERSE_SAFE_BEGIN(&load_order, order, entry) { 00816 switch (load_resource(order->resource, 0)) { 00817 case AST_MODULE_LOAD_SUCCESS: 00818 case AST_MODULE_LOAD_DECLINE: 00819 AST_LIST_REMOVE_CURRENT(&load_order, entry); 00820 free(order->resource); 00821 free(order); 00822 break; 00823 case AST_MODULE_LOAD_FAILURE: 00824 res = -1; 00825 goto done; 00826 case AST_MODULE_LOAD_SKIP: 00827 /* should not happen */ 00828 break; 00829 } 00830 } 00831 AST_LIST_TRAVERSE_SAFE_END; 00832 00833 done: 00834 while ((order = AST_LIST_REMOVE_HEAD(&load_order, entry))) { 00835 free(order->resource); 00836 free(order); 00837 } 00838 00839 return res; 00840 } 00841 00842 void ast_update_use_count(void) 00843 { 00844 /* Notify any module monitors that the use count for a 00845 resource has changed */ 00846 struct loadupdate *m; 00847 00848 AST_LIST_LOCK(&module_list); 00849 AST_LIST_TRAVERSE(&updaters, m, entry) 00850 m->updater(); 00851 AST_LIST_UNLOCK(&module_list); 00852 } 00853 00854 int ast_update_module_list(int (*modentry)(const char *module, const char *description, int usecnt, const char *like), 00855 const char *like) 00856 { 00857 struct ast_module *cur; 00858 int unlock = -1; 00859 int total_mod_loaded = 0; 00860 00861 if (AST_LIST_TRYLOCK(&module_list)) 00862 unlock = 0; 00863 00864 AST_LIST_TRAVERSE(&module_list, cur, entry) { 00865 total_mod_loaded += modentry(cur->resource, cur->info->description, cur->usecount, like); 00866 } 00867 00868 if (unlock) 00869 AST_LIST_UNLOCK(&module_list); 00870 00871 return total_mod_loaded; 00872 } 00873 00874 /*! \brief Check if module exists */ 00875 int ast_module_check(char *name) 00876 { 00877 struct ast_module *cur; 00878 00879 if (ast_strlen_zero(name)) 00880 return 0; /* FALSE */ 00881 00882 cur = find_resource(name, 1); 00883 00884 return (cur != NULL); 00885 } 00886 00887 00888 int ast_loader_register(int (*v)(void)) 00889 { 00890 struct loadupdate *tmp; 00891 00892 if (!(tmp = ast_malloc(sizeof(*tmp)))) 00893 return -1; 00894 00895 tmp->updater = v; 00896 AST_LIST_LOCK(&module_list); 00897 AST_LIST_INSERT_HEAD(&updaters, tmp, entry); 00898 AST_LIST_UNLOCK(&module_list); 00899 00900 return 0; 00901 } 00902 00903 int ast_loader_unregister(int (*v)(void)) 00904 { 00905 struct loadupdate *cur; 00906 00907 AST_LIST_LOCK(&module_list); 00908 AST_LIST_TRAVERSE_SAFE_BEGIN(&updaters, cur, entry) { 00909 if (cur->updater == v) { 00910 AST_LIST_REMOVE_CURRENT(&updaters, entry); 00911 break; 00912 } 00913 } 00914 AST_LIST_TRAVERSE_SAFE_END; 00915 AST_LIST_UNLOCK(&module_list); 00916 00917 return cur ? 0 : -1; 00918 } 00919 00920 struct ast_module *ast_module_ref(struct ast_module *mod) 00921 { 00922 ast_atomic_fetchadd_int(&mod->usecount, +1); 00923 ast_update_use_count(); 00924 00925 return mod; 00926 } 00927 00928 void ast_module_unref(struct ast_module *mod) 00929 { 00930 ast_atomic_fetchadd_int(&mod->usecount, -1); 00931 ast_update_use_count(); 00932 }