#include "asterisk.h"
#include <stdio.h>
#include <dirent.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include "asterisk/linkedlists.h"
#include "asterisk/module.h"
#include "asterisk/options.h"
#include "asterisk/config.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/term.h"
#include "asterisk/manager.h"
#include "asterisk/cdr.h"
#include "asterisk/enum.h"
#include "asterisk/rtp.h"
#include "asterisk/http.h"
#include "asterisk/lock.h"
#include <dlfcn.h>
#include "asterisk/md5.h"
#include "asterisk/utils.h"
Go to the source code of this file.
Data Structures | |
struct | ast_module |
struct | ast_module_user |
struct | load_order |
struct | load_order_entry |
struct | loadupdate |
struct | module_list |
struct | module_user_list |
struct | reload_classes |
struct | updaters |
Defines | |
#define | RTLD_NOW 0 |
Functions | |
ast_module_user * | __ast_module_user_add (struct ast_module *mod, struct ast_channel *chan) |
void | __ast_module_user_hangup_all (struct ast_module *mod) |
void | __ast_module_user_remove (struct ast_module *mod, struct ast_module_user *u) |
static struct load_order_entry * | add_to_load_order (const char *resource, struct load_order *load_order) |
int | ast_load_resource (const char *resource_name) |
Load a module. | |
int | ast_loader_register (int(*v)(void)) |
Add a procedure to be run when modules have been updated. | |
int | ast_loader_unregister (int(*v)(void)) |
Remove a procedure to be run when modules are updated. | |
char * | ast_module_helper (const char *line, const char *word, int pos, int state, int rpos, int needsreload) |
Match modules names for the Asterisk cli. | |
ast_module * | ast_module_ref (struct ast_module *mod) |
void | ast_module_register (const struct ast_module_info *info) |
int | ast_module_reload (const char *name) |
Reload asterisk modules. | |
void | ast_module_shutdown (void) |
Run the unload() callback for all loaded modules. | |
void | ast_module_unref (struct ast_module *mod) |
void | ast_module_unregister (const struct ast_module_info *info) |
int | ast_unload_resource (const char *resource_name, enum ast_module_unload_mode force) |
Unload a module. | |
int | ast_update_module_list (int(*modentry)(const char *module, const char *description, int usecnt, const char *like), const char *like) |
Ask for a list of modules, descriptions, and use counts. | |
void | ast_update_use_count (void) |
Notify when usecount has been changed. | |
static struct ast_module * | find_resource (const char *resource, int do_lock) |
static unsigned int | inspect_module (const struct ast_module *mod) |
static int | key_matches (const unsigned char *key1, const unsigned char *key2) |
static struct ast_module * | load_dynamic_module (const char *resource_in, unsigned int global_symbols_only) |
int | load_modules (unsigned int preload_only) |
static enum ast_module_load_result | load_resource (const char *resource_name, unsigned int global_symbols_only) |
static int | printdigest (const unsigned char *d) |
static int | resource_name_match (const char *name1_in, const char *name2_in) |
static int | translate_module_name (char *oldname, char *newname) |
static void | unload_dynamic_module (struct ast_module *mod) |
static int | verify_key (const unsigned char *key) |
Variables | |
static char | buildopt_sum [33] = AST_BUILDOPT_SUM |
static unsigned int | embedding = 1 |
static unsigned char | expected_key [] |
static ast_mutex_t | reloadlock = ((ast_mutex_t) PTHREAD_MUTEX_INITIALIZER ) |
ast_module * | resource_being_loaded |
Kevin P. Fleming <kpfleming@digium.com>
Luigi Rizzo <rizzo@icir.org>
Definition in file loader.c.
#define RTLD_NOW 0 |
struct ast_module_user* __ast_module_user_add | ( | struct ast_module * | mod, | |
struct ast_channel * | chan | |||
) |
Definition at line 175 of file loader.c.
References ast_atomic_fetchadd_int(), ast_calloc, AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_update_use_count(), ast_module_user::chan, ast_module_user::entry, ast_module::usecount, and ast_module::users.
00177 { 00178 struct ast_module_user *u = ast_calloc(1, sizeof(*u)); 00179 00180 if (!u) 00181 return NULL; 00182 00183 u->chan = chan; 00184 00185 AST_LIST_LOCK(&mod->users); 00186 AST_LIST_INSERT_HEAD(&mod->users, u, entry); 00187 AST_LIST_UNLOCK(&mod->users); 00188 00189 ast_atomic_fetchadd_int(&mod->usecount, +1); 00190 00191 ast_update_use_count(); 00192 00193 return u; 00194 }
void __ast_module_user_hangup_all | ( | struct ast_module * | mod | ) |
Definition at line 207 of file loader.c.
References ast_atomic_fetchadd_int(), AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, ast_softhangup(), AST_SOFTHANGUP_APPUNLOAD, ast_update_use_count(), ast_module_user::chan, ast_module_user::entry, free, ast_module::usecount, and ast_module::users.
Referenced by ast_unload_resource().
00208 { 00209 struct ast_module_user *u; 00210 00211 AST_LIST_LOCK(&mod->users); 00212 while ((u = AST_LIST_REMOVE_HEAD(&mod->users, entry))) { 00213 ast_softhangup(u->chan, AST_SOFTHANGUP_APPUNLOAD); 00214 ast_atomic_fetchadd_int(&mod->usecount, -1); 00215 free(u); 00216 } 00217 AST_LIST_UNLOCK(&mod->users); 00218 00219 ast_update_use_count(); 00220 }
void __ast_module_user_remove | ( | struct ast_module * | mod, | |
struct ast_module_user * | u | |||
) |
Definition at line 196 of file loader.c.
References ast_atomic_fetchadd_int(), AST_LIST_LOCK, AST_LIST_REMOVE, AST_LIST_UNLOCK, ast_update_use_count(), ast_module_user::entry, free, ast_module::usecount, and ast_module::users.
00197 { 00198 AST_LIST_LOCK(&mod->users); 00199 AST_LIST_REMOVE(&mod->users, u, entry); 00200 AST_LIST_UNLOCK(&mod->users); 00201 ast_atomic_fetchadd_int(&mod->usecount, -1); 00202 free(u); 00203 00204 ast_update_use_count(); 00205 }
static struct load_order_entry* add_to_load_order | ( | const char * | resource, | |
struct load_order * | load_order | |||
) | [static] |
Definition at line 729 of file loader.c.
References ast_calloc, AST_LIST_INSERT_TAIL, AST_LIST_TRAVERSE, ast_strdup, ast_module_user::entry, load_order_entry::resource, and resource_name_match().
Referenced by load_modules().
00730 { 00731 struct load_order_entry *order; 00732 00733 AST_LIST_TRAVERSE(load_order, order, entry) { 00734 if (!resource_name_match(order->resource, resource)) 00735 return NULL; 00736 } 00737 00738 if (!(order = ast_calloc(1, sizeof(*order)))) 00739 return NULL; 00740 00741 order->resource = ast_strdup(resource); 00742 AST_LIST_INSERT_TAIL(load_order, order, entry); 00743 00744 return order; 00745 }
int ast_load_resource | ( | const char * | resource_name | ) |
Load a module.
resource_name | The name of the module to load. |
Definition at line 713 of file loader.c.
References AST_LIST_LOCK, AST_LIST_UNLOCK, and load_resource().
Referenced by file_ok_sel(), handle_load(), handle_load_deprecated(), and reload().
00714 { 00715 AST_LIST_LOCK(&module_list); 00716 load_resource(resource_name, 0); 00717 AST_LIST_UNLOCK(&module_list); 00718 00719 return 0; 00720 }
int ast_loader_register | ( | int(*)(void) | updater | ) |
Add a procedure to be run when modules have been updated.
updater | The function to run when modules have been updated. |
Definition at line 963 of file loader.c.
References AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_UNLOCK, and ast_malloc.
Referenced by show_console().
00964 { 00965 struct loadupdate *tmp; 00966 00967 if (!(tmp = ast_malloc(sizeof(*tmp)))) 00968 return -1; 00969 00970 tmp->updater = v; 00971 AST_LIST_LOCK(&updaters); 00972 AST_LIST_INSERT_HEAD(&updaters, tmp, entry); 00973 AST_LIST_UNLOCK(&updaters); 00974 00975 return 0; 00976 }
int ast_loader_unregister | ( | int(*)(void) | updater | ) |
Remove a procedure to be run when modules are updated.
updater | The updater function to unregister. |
Definition at line 978 of file loader.c.
References AST_LIST_LOCK, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_LIST_UNLOCK, and loadupdate::updater.
Referenced by exit_now().
00979 { 00980 struct loadupdate *cur; 00981 00982 AST_LIST_LOCK(&updaters); 00983 AST_LIST_TRAVERSE_SAFE_BEGIN(&updaters, cur, entry) { 00984 if (cur->updater == v) { 00985 AST_LIST_REMOVE_CURRENT(&updaters, entry); 00986 break; 00987 } 00988 } 00989 AST_LIST_TRAVERSE_SAFE_END; 00990 AST_LIST_UNLOCK(&updaters); 00991 00992 return cur ? 0 : -1; 00993 }
char* ast_module_helper | ( | const char * | line, | |
const char * | word, | |||
int | pos, | |||
int | state, | |||
int | rpos, | |||
int | needsreload | |||
) |
Match modules names for the Asterisk cli.
line | Unused by this function, but this should be the line we are matching. | |
word | The partial name to match. | |
pos | The position the word we are completing is in. | |
state | The possible match to return. | |
rpos | The position we should be matching. This should be the same as pos. | |
needsreload | This should be 1 if we need to reload this module and 0 otherwise. This function will only return modules that are reloadble if this is 1. |
Definition at line 521 of file loader.c.
References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_module_user::entry, ast_module::info, name, ast_module_info::reload, ast_module::resource, and strdup.
Referenced by complete_mod_2(), complete_mod_3(), complete_mod_3_nr(), complete_mod_4(), and load_module().
00522 { 00523 struct ast_module *cur; 00524 int i, which=0, l = strlen(word); 00525 char *ret = NULL; 00526 00527 if (pos != rpos) 00528 return NULL; 00529 00530 AST_LIST_LOCK(&module_list); 00531 AST_LIST_TRAVERSE(&module_list, cur, entry) { 00532 if (!strncasecmp(word, cur->resource, l) && 00533 (cur->info->reload || !needsreload) && 00534 ++which > state) { 00535 ret = strdup(cur->resource); 00536 break; 00537 } 00538 } 00539 AST_LIST_UNLOCK(&module_list); 00540 00541 if (!ret) { 00542 for (i=0; !ret && reload_classes[i].name; i++) { 00543 if (!strncasecmp(word, reload_classes[i].name, l) && ++which > state) 00544 ret = strdup(reload_classes[i].name); 00545 } 00546 } 00547 00548 return ret; 00549 }
struct ast_module* ast_module_ref | ( | struct ast_module * | mod | ) |
Definition at line 995 of file loader.c.
References ast_atomic_fetchadd_int(), ast_update_use_count(), and ast_module::usecount.
Referenced by __oh323_new(), alsa_new(), ast_iax2_new(), cli_audio_convert(), cli_audio_convert_deprecated(), complete_orig(), dahdi_new(), features_new(), fn_wrapper(), gtalk_new(), handle_orig(), mgcp_new(), newpvt(), oss_new(), phone_check_exception(), phone_new(), sip_new(), and skinny_new().
00996 { 00997 ast_atomic_fetchadd_int(&mod->usecount, +1); 00998 ast_update_use_count(); 00999 01000 return mod; 01001 }
void ast_module_register | ( | const struct ast_module_info * | info | ) |
Definition at line 113 of file loader.c.
References ast_calloc, AST_LIST_HEAD_INIT, AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_UNLOCK, embedding, ast_module_user::entry, ast_module::info, resource_being_loaded, and ast_module::users.
00114 { 00115 struct ast_module *mod; 00116 00117 if (embedding) { 00118 if (!(mod = ast_calloc(1, sizeof(*mod) + strlen(info->name) + 1))) 00119 return; 00120 strcpy(mod->resource, info->name); 00121 } else { 00122 mod = resource_being_loaded; 00123 } 00124 00125 mod->info = info; 00126 AST_LIST_HEAD_INIT(&mod->users); 00127 00128 /* during startup, before the loader has been initialized, 00129 there are no threads, so there is no need to take the lock 00130 on this list to manipulate it. it is also possible that it 00131 might be unsafe to use the list lock at that point... so 00132 let's avoid it altogether 00133 */ 00134 if (!embedding) 00135 AST_LIST_LOCK(&module_list); 00136 00137 /* it is paramount that the new entry be placed at the tail of 00138 the list, otherwise the code that uses dlopen() to load 00139 dynamic modules won't be able to find out if the module it 00140 just opened was registered or failed to load 00141 */ 00142 AST_LIST_INSERT_TAIL(&module_list, mod, entry); 00143 00144 if (!embedding) 00145 AST_LIST_UNLOCK(&module_list); 00146 00147 /* give the module a copy of its own handle, for later use in registrations and the like */ 00148 *((struct ast_module **) &(info->self)) = mod; 00149 }
int ast_module_reload | ( | const char * | name | ) |
Reload asterisk modules.
name | the name of the module to reload |
Definition at line 551 of file loader.c.
References ast_lastreloadtime, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_mutex_trylock(), ast_mutex_unlock(), ast_verbose(), ast_module::declined, ast_module_info::description, ast_module_user::entry, ast_module::flags, ast_module::info, LOG_NOTICE, option_verbose, ast_module_info::reload, reloadlock, ast_module::resource, resource_name_match(), ast_module::running, and VERBOSE_PREFIX_3.
Referenced by action_updateconfig(), handle_reload(), handle_reload_deprecated(), and monitor_sig_flags().
00552 { 00553 struct ast_module *cur; 00554 int res = 0; /* return value. 0 = not found, others, see below */ 00555 int i; 00556 00557 if (ast_mutex_trylock(&reloadlock)) { 00558 ast_verbose("The previous reload command didn't finish yet\n"); 00559 return -1; /* reload already in progress */ 00560 } 00561 ast_lastreloadtime = time(NULL); 00562 00563 /* Call "predefined" reload here first */ 00564 for (i = 0; reload_classes[i].name; i++) { 00565 if (!name || !strcasecmp(name, reload_classes[i].name)) { 00566 reload_classes[i].reload_fn(); /* XXX should check error ? */ 00567 res = 2; /* found and reloaded */ 00568 } 00569 } 00570 00571 if (name && res) { 00572 ast_mutex_unlock(&reloadlock); 00573 return res; 00574 } 00575 00576 AST_LIST_LOCK(&module_list); 00577 AST_LIST_TRAVERSE(&module_list, cur, entry) { 00578 const struct ast_module_info *info = cur->info; 00579 00580 if (name && resource_name_match(name, cur->resource)) 00581 continue; 00582 00583 if (!cur->flags.running || cur->flags.declined) { 00584 if (!name) 00585 continue; 00586 ast_log(LOG_NOTICE, "The module '%s' was not properly initialized. " 00587 "Before reloading the module, you must run \"module load %s\" " 00588 "and fix whatever is preventing the module from being initialized.\n", 00589 name, name); 00590 res = 2; /* Don't report that the module was not found */ 00591 break; 00592 } 00593 00594 if (!info->reload) { /* cannot be reloaded */ 00595 if (res < 1) /* store result if possible */ 00596 res = 1; /* 1 = no reload() method */ 00597 continue; 00598 } 00599 00600 res = 2; 00601 if (option_verbose > 2) 00602 ast_verbose(VERBOSE_PREFIX_3 "Reloading module '%s' (%s)\n", cur->resource, info->description); 00603 info->reload(); 00604 } 00605 AST_LIST_UNLOCK(&module_list); 00606 00607 ast_mutex_unlock(&reloadlock); 00608 00609 return res; 00610 }
void ast_module_shutdown | ( | void | ) |
Run the unload() callback for all loaded modules.
This function should be called when Asterisk is shutting down gracefully.
Definition at line 435 of file loader.c.
References AST_LIST_HEAD_DESTROY, AST_LIST_HEAD_NOLOCK_STATIC, AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, ast_module_user::entry, free, ast_module::info, ast_module_info::unload, and ast_module::users.
Referenced by quit_handler().
00436 { 00437 struct ast_module *mod; 00438 AST_LIST_HEAD_NOLOCK_STATIC(local_module_list, ast_module); 00439 00440 /* We have to call the unload() callbacks in reverse order that the modules 00441 * exist in the module list so it is the reverse order of how they were 00442 * loaded. */ 00443 00444 AST_LIST_LOCK(&module_list); 00445 while ((mod = AST_LIST_REMOVE_HEAD(&module_list, entry))) 00446 AST_LIST_INSERT_HEAD(&local_module_list, mod, entry); 00447 AST_LIST_UNLOCK(&module_list); 00448 00449 while ((mod = AST_LIST_REMOVE_HEAD(&local_module_list, entry))) { 00450 if (mod->info->unload) 00451 mod->info->unload(); 00452 /* Since this should only be called when shutting down "gracefully", 00453 * all channels should be down before we get to this point, meaning 00454 * there will be no module users left. */ 00455 AST_LIST_HEAD_DESTROY(&mod->users); 00456 free(mod); 00457 } 00458 }
void ast_module_unref | ( | struct ast_module * | mod | ) |
Definition at line 1003 of file loader.c.
References ast_atomic_fetchadd_int(), ast_update_use_count(), and ast_module::usecount.
Referenced by alsa_hangup(), ast_smdi_interface_destroy(), cli_audio_convert(), cli_audio_convert_deprecated(), complete_orig(), dahdi_destroy_channel_bynum(), dahdi_hangup(), destroy(), filestream_destructor(), gtalk_hangup(), handle_orig(), iax2_predestroy(), mgcp_hangup(), oh323_hangup(), oss_hangup(), phone_check_exception(), phone_hangup(), and sip_hangup().
01004 { 01005 ast_atomic_fetchadd_int(&mod->usecount, -1); 01006 ast_update_use_count(); 01007 }
void ast_module_unregister | ( | const struct ast_module_info * | info | ) |
Definition at line 151 of file loader.c.
References AST_LIST_HEAD_DESTROY, AST_LIST_LOCK, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_LIST_UNLOCK, ast_module_user::entry, free, ast_module::info, and ast_module::users.
00152 { 00153 struct ast_module *mod = NULL; 00154 00155 /* it is assumed that the users list in the module structure 00156 will already be empty, or we cannot have gotten to this 00157 point 00158 */ 00159 AST_LIST_LOCK(&module_list); 00160 AST_LIST_TRAVERSE_SAFE_BEGIN(&module_list, mod, entry) { 00161 if (mod->info == info) { 00162 AST_LIST_REMOVE_CURRENT(&module_list, entry); 00163 break; 00164 } 00165 } 00166 AST_LIST_TRAVERSE_SAFE_END; 00167 AST_LIST_UNLOCK(&module_list); 00168 00169 if (mod) { 00170 AST_LIST_HEAD_DESTROY(&mod->users); 00171 free(mod); 00172 } 00173 }
int ast_unload_resource | ( | const char * | resource_name, | |
enum | ast_module_unload_mode | |||
) |
Unload a module.
resource_name | The name of the module to unload. | |
ast_module_unload_mode | The force flag. This should be set using one of the AST_FORCE flags. |
Definition at line 460 of file loader.c.
References __ast_module_user_hangup_all(), AST_FORCE_FIRM, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), ast_update_use_count(), ast_module::declined, find_resource(), ast_module::flags, ast_module::lib, LOG_WARNING, ast_module::running, unload_dynamic_module(), and ast_module::usecount.
Referenced by exit_now(), handle_unload(), handle_unload_deprecated(), reload(), and remove_module().
00461 { 00462 struct ast_module *mod; 00463 int res = -1; 00464 int error = 0; 00465 00466 AST_LIST_LOCK(&module_list); 00467 00468 if (!(mod = find_resource(resource_name, 0))) { 00469 AST_LIST_UNLOCK(&module_list); 00470 return 0; 00471 } 00472 00473 if (!(mod->flags.running || mod->flags.declined)) 00474 error = 1; 00475 00476 if (!mod->lib) { 00477 ast_log(LOG_WARNING, "Unloading embedded modules is not supported.\n"); 00478 error = 1; 00479 } 00480 00481 if (!error && (mod->usecount > 0)) { 00482 if (force) 00483 ast_log(LOG_WARNING, "Warning: Forcing removal of module '%s' with use count %d\n", 00484 resource_name, mod->usecount); 00485 else { 00486 ast_log(LOG_WARNING, "Soft unload failed, '%s' has use count %d\n", resource_name, 00487 mod->usecount); 00488 error = 1; 00489 } 00490 } 00491 00492 if (!error) { 00493 __ast_module_user_hangup_all(mod); 00494 res = mod->info->unload(); 00495 00496 if (res) { 00497 ast_log(LOG_WARNING, "Firm unload failed for %s\n", resource_name); 00498 if (force <= AST_FORCE_FIRM) 00499 error = 1; 00500 else 00501 ast_log(LOG_WARNING, "** Dangerous **: Unloading resource anyway, at user request\n"); 00502 } 00503 } 00504 00505 if (!error) 00506 mod->flags.running = mod->flags.declined = 0; 00507 00508 AST_LIST_UNLOCK(&module_list); 00509 00510 #ifdef LOADABLE_MODULES 00511 if (!error) 00512 unload_dynamic_module(mod); 00513 #endif 00514 00515 if (!error) 00516 ast_update_use_count(); 00517 00518 return res; 00519 }
int ast_update_module_list | ( | int(*)(const char *module, const char *description, int usecnt, const char *like) | modentry, | |
const char * | like | |||
) |
Ask for a list of modules, descriptions, and use counts.
modentry | A callback to an updater function. | |
like | For each of the modules loaded, modentry will be executed with the resource, description, and usecount values of each particular module. |
Definition at line 943 of file loader.c.
References AST_LIST_TRAVERSE, AST_LIST_TRYLOCK, AST_LIST_UNLOCK, ast_module_info::description, ast_module::info, ast_module::resource, and ast_module::usecount.
Referenced by handle_modlist(), and mod_update().
00945 { 00946 struct ast_module *cur; 00947 int unlock = -1; 00948 int total_mod_loaded = 0; 00949 00950 if (AST_LIST_TRYLOCK(&module_list)) 00951 unlock = 0; 00952 00953 AST_LIST_TRAVERSE(&module_list, cur, entry) { 00954 total_mod_loaded += modentry(cur->resource, cur->info->description, cur->usecount, like); 00955 } 00956 00957 if (unlock) 00958 AST_LIST_UNLOCK(&module_list); 00959 00960 return total_mod_loaded; 00961 }
void ast_update_use_count | ( | void | ) |
Notify when usecount has been changed.
This function calulates use counts and notifies anyone trying to keep track of them. It should be called whenever your module's usecount changes.
Definition at line 931 of file loader.c.
References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, and loadupdate::updater.
Referenced by __ast_module_user_add(), __ast_module_user_hangup_all(), __ast_module_user_remove(), agent_new(), ast_module_ref(), ast_module_unref(), ast_unload_resource(), exit_now(), load_module(), load_resource(), oh323_request(), sip_request_call(), and sipsock_read().
00932 { 00933 /* Notify any module monitors that the use count for a 00934 resource has changed */ 00935 struct loadupdate *m; 00936 00937 AST_LIST_LOCK(&updaters); 00938 AST_LIST_TRAVERSE(&updaters, m, entry) 00939 m->updater(); 00940 AST_LIST_UNLOCK(&updaters); 00941 }
static struct ast_module* find_resource | ( | const char * | resource, | |
int | do_lock | |||
) | [static] |
Definition at line 302 of file loader.c.
References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_module_user::entry, ast_module::resource, and resource_name_match().
Referenced by ast_unload_resource(), and load_resource().
00303 { 00304 struct ast_module *cur; 00305 00306 if (do_lock) 00307 AST_LIST_LOCK(&module_list); 00308 00309 AST_LIST_TRAVERSE(&module_list, cur, entry) { 00310 if (!resource_name_match(resource, cur->resource)) 00311 break; 00312 } 00313 00314 if (do_lock) 00315 AST_LIST_UNLOCK(&module_list); 00316 00317 return cur; 00318 }
static unsigned int inspect_module | ( | const struct ast_module * | mod | ) | [static] |
Definition at line 612 of file loader.c.
References ast_log(), AST_MODFLAG_BUILDSUM, ast_strlen_zero(), ast_test_flag, buildopt_sum, ast_module_info::buildopt_sum, ast_module_info::description, ast_module::info, ast_module_info::key, LOG_WARNING, ast_module::resource, and verify_key().
Referenced by load_resource().
00613 { 00614 if (!mod->info->description) { 00615 ast_log(LOG_WARNING, "Module '%s' does not provide a description.\n", mod->resource); 00616 return 1; 00617 } 00618 00619 if (!mod->info->key) { 00620 ast_log(LOG_WARNING, "Module '%s' does not provide a license key.\n", mod->resource); 00621 return 1; 00622 } 00623 00624 if (verify_key((unsigned char *) mod->info->key)) { 00625 ast_log(LOG_WARNING, "Module '%s' did not provide a valid license key.\n", mod->resource); 00626 return 1; 00627 } 00628 00629 if (!ast_test_flag(mod->info, AST_MODFLAG_BUILDSUM)) { 00630 ast_log(LOG_WARNING, "Module '%s' was not compiled against a recent version of Asterisk and may cause instability.\n", mod->resource); 00631 } else if (!ast_strlen_zero(mod->info->buildopt_sum) && 00632 strcmp(buildopt_sum, mod->info->buildopt_sum)) { 00633 ast_log(LOG_WARNING, "Module '%s' was not compiled with the same compile-time options as this version of Asterisk.\n", mod->resource); 00634 ast_log(LOG_WARNING, "Module '%s' will not be initialized as it may cause instability.\n", mod->resource); 00635 return 1; 00636 } 00637 00638 return 0; 00639 }
static int key_matches | ( | const unsigned char * | key1, | |
const unsigned char * | key2 | |||
) | [static] |
Definition at line 255 of file loader.c.
Referenced by verify_key().
00256 { 00257 int x; 00258 00259 for (x = 0; x < 16; x++) { 00260 if (key1[x] != key2[x]) 00261 return 0; 00262 } 00263 00264 return 1; 00265 }
static struct ast_module* load_dynamic_module | ( | const char * | resource_in, | |
unsigned int | global_symbols_only | |||
) | [static] |
Definition at line 333 of file loader.c.
References ast_calloc, ast_config_AST_MODULE_DIR, AST_LIST_LAST, ast_log(), AST_MODFLAG_GLOBAL_SYMBOLS, ast_test_flag, free, ast_module::info, ast_module::lib, LOG_WARNING, resource_being_loaded, and RTLD_NOW.
Referenced by load_resource().
00334 { 00335 char fn[256]; 00336 void *lib; 00337 struct ast_module *mod; 00338 char *resource = (char *) resource_in; 00339 unsigned int wants_global; 00340 00341 if (strcasecmp(resource + strlen(resource) - 3, ".so")) { 00342 resource = alloca(strlen(resource_in) + 3); 00343 strcpy(resource, resource_in); 00344 strcat(resource, ".so"); 00345 } 00346 00347 snprintf(fn, sizeof(fn), "%s/%s", ast_config_AST_MODULE_DIR, resource); 00348 00349 /* make a first load of the module in 'quiet' mode... don't try to resolve 00350 any symbols, and don't export any symbols. this will allow us to peek into 00351 the module's info block (if available) to see what flags it has set */ 00352 00353 if (!(resource_being_loaded = ast_calloc(1, sizeof(*resource_being_loaded) + strlen(resource) + 1))) 00354 return NULL; 00355 00356 strcpy(resource_being_loaded->resource, resource); 00357 00358 /* libopenh323 is buggy and segfaults on dlclose() when opened with 00359 * RTLD_LAZY. Workaround this until it gets fixed */ 00360 if (!strcasecmp(resource, "chan_h323.so") || 00361 !strcasecmp(resource, "chan_oh323.so")) 00362 lib = dlopen(fn, RTLD_NOW | RTLD_LOCAL); 00363 00364 if (!(lib = dlopen(fn, RTLD_LAZY | RTLD_LOCAL))) { 00365 ast_log(LOG_WARNING, "Error loading module '%s': %s\n", resource_in, dlerror()); 00366 free(resource_being_loaded); 00367 return NULL; 00368 } 00369 00370 /* the dlopen() succeeded, let's find out if the module 00371 registered itself */ 00372 /* note that this will only work properly as long as 00373 ast_module_register() (which is called by the module's 00374 constructor) places the new module at the tail of the 00375 module_list 00376 */ 00377 if (resource_being_loaded != (mod = AST_LIST_LAST(&module_list))) { 00378 ast_log(LOG_WARNING, "Module '%s' did not register itself during load\n", resource_in); 00379 /* no, it did not, so close it and return */ 00380 while (!dlclose(lib)); 00381 /* note that the module's destructor will call ast_module_unregister(), 00382 which will free the structure we allocated in resource_being_loaded */ 00383 return NULL; 00384 } 00385 00386 wants_global = ast_test_flag(mod->info, AST_MODFLAG_GLOBAL_SYMBOLS); 00387 00388 /* if we are being asked only to load modules that provide global symbols, 00389 and this one does not, then close it and return */ 00390 if (global_symbols_only && !wants_global) { 00391 while (!dlclose(lib)); 00392 return NULL; 00393 } 00394 00395 /* if the system supports RTLD_NOLOAD, we can just 'promote' the flags 00396 on the already-opened library to what we want... if not, we have to 00397 close it and start over 00398 */ 00399 #if defined(HAVE_RTLD_NOLOAD) && !defined(__Darwin__) 00400 if (!dlopen(fn, RTLD_NOLOAD | (wants_global ? RTLD_LAZY | RTLD_GLOBAL : RTLD_NOW | RTLD_LOCAL))) { 00401 ast_log(LOG_WARNING, "Unable to promote flags on module '%s': %s\n", resource_in, dlerror()); 00402 while (!dlclose(lib)); 00403 free(resource_being_loaded); 00404 return NULL; 00405 } 00406 #else 00407 while (!dlclose(lib)); 00408 resource_being_loaded = NULL; 00409 00410 /* start the load process again */ 00411 00412 if (!(resource_being_loaded = ast_calloc(1, sizeof(*resource_being_loaded) + strlen(resource) + 1))) 00413 return NULL; 00414 00415 strcpy(resource_being_loaded->resource, resource); 00416 00417 if (!(lib = dlopen(fn, wants_global ? RTLD_LAZY | RTLD_GLOBAL : RTLD_NOW | RTLD_LOCAL))) { 00418 ast_log(LOG_WARNING, "Error loading module '%s': %s\n", resource_in, dlerror()); 00419 free(resource_being_loaded); 00420 return NULL; 00421 } 00422 00423 /* since the module was successfully opened, and it registered itself 00424 the previous time we did that, we're going to assume it worked this 00425 time too :) */ 00426 #endif 00427 00428 AST_LIST_LAST(&module_list)->lib = lib; 00429 resource_being_loaded = NULL; 00430 00431 return AST_LIST_LAST(&module_list); 00432 }
int load_modules | ( | unsigned | int | ) |
Provided by loader.c
Definition at line 764 of file loader.c.
References add_to_load_order(), ast_config_load(), AST_LIST_HEAD_INIT_NOLOCK, AST_LIST_LOCK, ast_log(), AST_MODULE_CONFIG, ast_variable_browse(), ast_verbose(), embedding, LOG_WARNING, ast_variable::name, ast_variable::next, option_verbose, translate_module_name(), and ast_variable::value.
Referenced by main().
00765 { 00766 struct ast_config *cfg; 00767 struct ast_module *mod; 00768 struct load_order_entry *order; 00769 struct ast_variable *v; 00770 unsigned int load_count; 00771 struct load_order load_order; 00772 int res = 0; 00773 00774 int translate_status; 00775 char newname[18]; /* although this would normally be 80, max length in translate_module_name is 18 */ 00776 #ifdef LOADABLE_MODULES 00777 struct dirent *dirent; 00778 DIR *dir; 00779 #endif 00780 00781 /* all embedded modules have registered themselves by now */ 00782 embedding = 0; 00783 00784 if (option_verbose) 00785 ast_verbose("Asterisk Dynamic Loader Starting:\n"); 00786 00787 AST_LIST_HEAD_INIT_NOLOCK(&load_order); 00788 00789 AST_LIST_LOCK(&module_list); 00790 00791 if (!(cfg = ast_config_load(AST_MODULE_CONFIG))) { 00792 ast_log(LOG_WARNING, "No '%s' found, no modules will be loaded.\n", AST_MODULE_CONFIG); 00793 goto done; 00794 } 00795 00796 /* first, find all the modules we have been explicitly requested to load */ 00797 for (v = ast_variable_browse(cfg, "modules"); v; v = v->next) { 00798 if (!strcasecmp(v->name, preload_only ? "preload" : "load")) { 00799 translate_status = translate_module_name(v->value, newname); 00800 if (!translate_status) 00801 ast_log(LOG_WARNING, "Use of old module name %s is deprecated, please use %s instead.\n", v->value, newname); 00802 add_to_load_order(translate_status ? v->value : newname, &load_order); 00803 } 00804 } 00805 00806 /* check if 'autoload' is on */ 00807 if (!preload_only && ast_true(ast_variable_retrieve(cfg, "modules", "autoload"))) { 00808 /* if so, first add all the embedded modules that are not already running to the load order */ 00809 AST_LIST_TRAVERSE(&module_list, mod, entry) { 00810 /* if it's not embedded, skip it */ 00811 if (mod->lib) 00812 continue; 00813 00814 if (mod->flags.running) 00815 continue; 00816 00817 order = add_to_load_order(mod->resource, &load_order); 00818 } 00819 00820 #ifdef LOADABLE_MODULES 00821 /* if we are allowed to load dynamic modules, scan the directory for 00822 for all available modules and add them as well */ 00823 if ((dir = opendir(ast_config_AST_MODULE_DIR))) { 00824 while ((dirent = readdir(dir))) { 00825 int ld = strlen(dirent->d_name); 00826 00827 /* Must end in .so to load it. */ 00828 00829 if (ld < 4) 00830 continue; 00831 00832 if (strcasecmp(dirent->d_name + ld - 3, ".so")) 00833 continue; 00834 00835 /* if there is already a module by this name in the module_list, 00836 skip this file */ 00837 if (find_resource(dirent->d_name, 0)) 00838 continue; 00839 00840 add_to_load_order(dirent->d_name, &load_order); 00841 } 00842 00843 closedir(dir); 00844 } else { 00845 if (!ast_opt_quiet) 00846 ast_log(LOG_WARNING, "Unable to open modules directory '%s'.\n", 00847 ast_config_AST_MODULE_DIR); 00848 } 00849 #endif 00850 } 00851 00852 /* now scan the config for any modules we are prohibited from loading and 00853 remove them from the load order */ 00854 for (v = ast_variable_browse(cfg, "modules"); v; v = v->next) { 00855 if (strcasecmp(v->name, "noload")) 00856 continue; 00857 00858 AST_LIST_TRAVERSE_SAFE_BEGIN(&load_order, order, entry) { 00859 translate_status = translate_module_name(v->value, newname); 00860 if (!resource_name_match(order->resource, translate_status ? v->value : newname)) { 00861 if (!translate_status) 00862 ast_log(LOG_WARNING, "Use of old module name %s is deprecated, please use %s instead.\n", v->value, newname); 00863 AST_LIST_REMOVE_CURRENT(&load_order, entry); 00864 free(order->resource); 00865 free(order); 00866 } 00867 } 00868 AST_LIST_TRAVERSE_SAFE_END; 00869 } 00870 00871 /* we are done with the config now, all the information we need is in the 00872 load_order list */ 00873 ast_config_destroy(cfg); 00874 00875 load_count = 0; 00876 AST_LIST_TRAVERSE(&load_order, order, entry) 00877 load_count++; 00878 00879 if (load_count) 00880 ast_log(LOG_NOTICE, "%d modules will be loaded.\n", load_count); 00881 00882 /* first, load only modules that provide global symbols */ 00883 AST_LIST_TRAVERSE_SAFE_BEGIN(&load_order, order, entry) { 00884 switch (load_resource(order->resource, 1)) { 00885 case AST_MODULE_LOAD_SUCCESS: 00886 case AST_MODULE_LOAD_DECLINE: 00887 AST_LIST_REMOVE_CURRENT(&load_order, entry); 00888 free(order->resource); 00889 free(order); 00890 break; 00891 case AST_MODULE_LOAD_FAILURE: 00892 res = -1; 00893 goto done; 00894 case AST_MODULE_LOAD_SKIP: 00895 /* try again later */ 00896 break; 00897 } 00898 } 00899 AST_LIST_TRAVERSE_SAFE_END; 00900 00901 /* now load everything else */ 00902 AST_LIST_TRAVERSE_SAFE_BEGIN(&load_order, order, entry) { 00903 switch (load_resource(order->resource, 0)) { 00904 case AST_MODULE_LOAD_SUCCESS: 00905 case AST_MODULE_LOAD_DECLINE: 00906 AST_LIST_REMOVE_CURRENT(&load_order, entry); 00907 free(order->resource); 00908 free(order); 00909 break; 00910 case AST_MODULE_LOAD_FAILURE: 00911 res = -1; 00912 goto done; 00913 case AST_MODULE_LOAD_SKIP: 00914 /* should not happen */ 00915 break; 00916 } 00917 } 00918 AST_LIST_TRAVERSE_SAFE_END; 00919 00920 done: 00921 while ((order = AST_LIST_REMOVE_HEAD(&load_order, entry))) { 00922 free(order->resource); 00923 free(order); 00924 } 00925 00926 AST_LIST_UNLOCK(&module_list); 00927 00928 return res; 00929 }
static enum ast_module_load_result load_resource | ( | const char * | resource_name, | |
unsigned int | global_symbols_only | |||
) | [static] |
Definition at line 641 of file loader.c.
References ast_fully_booted, ast_log(), AST_MODFLAG_GLOBAL_SYMBOLS, AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_SKIP, AST_MODULE_LOAD_SUCCESS, ast_opt_console, ast_test_flag, ast_update_use_count(), ast_verbose(), COLOR_BLACK, COLOR_BROWN, ast_module::declined, ast_module_info::description, find_resource(), ast_module::flags, ast_module::info, inspect_module(), ast_module_info::load, load_dynamic_module(), LOG_WARNING, option_verbose, ast_module::running, term_color(), unload_dynamic_module(), and VERBOSE_PREFIX_1.
Referenced by ast_load_resource().
00642 { 00643 struct ast_module *mod; 00644 enum ast_module_load_result res = AST_MODULE_LOAD_SUCCESS; 00645 char tmp[256]; 00646 00647 if ((mod = find_resource(resource_name, 0))) { 00648 if (mod->flags.running) { 00649 ast_log(LOG_WARNING, "Module '%s' already exists.\n", resource_name); 00650 return AST_MODULE_LOAD_DECLINE; 00651 } 00652 if (global_symbols_only && !ast_test_flag(mod->info, AST_MODFLAG_GLOBAL_SYMBOLS)) 00653 return AST_MODULE_LOAD_SKIP; 00654 } else { 00655 #ifdef LOADABLE_MODULES 00656 if (!(mod = load_dynamic_module(resource_name, global_symbols_only))) { 00657 /* don't generate a warning message during load_modules() */ 00658 if (!global_symbols_only) { 00659 ast_log(LOG_WARNING, "Module '%s' could not be loaded.\n", resource_name); 00660 return AST_MODULE_LOAD_DECLINE; 00661 } else { 00662 return AST_MODULE_LOAD_SKIP; 00663 } 00664 } 00665 #else 00666 ast_log(LOG_WARNING, "Module '%s' could not be loaded.\n", resource_name); 00667 return AST_MODULE_LOAD_DECLINE; 00668 #endif 00669 } 00670 00671 if (inspect_module(mod)) { 00672 ast_log(LOG_WARNING, "Module '%s' could not be loaded.\n", resource_name); 00673 #ifdef LOADABLE_MODULES 00674 unload_dynamic_module(mod); 00675 #endif 00676 return AST_MODULE_LOAD_DECLINE; 00677 } 00678 00679 mod->flags.declined = 0; 00680 00681 if (mod->info->load) 00682 res = mod->info->load(); 00683 00684 switch (res) { 00685 case AST_MODULE_LOAD_SUCCESS: 00686 if (!ast_fully_booted) { 00687 if (option_verbose) 00688 ast_verbose("%s => (%s)\n", resource_name, term_color(tmp, mod->info->description, COLOR_BROWN, COLOR_BLACK, sizeof(tmp))); 00689 if (ast_opt_console && !option_verbose) 00690 ast_verbose( "."); 00691 } else { 00692 if (option_verbose) 00693 ast_verbose(VERBOSE_PREFIX_1 "Loaded %s => (%s)\n", resource_name, mod->info->description); 00694 } 00695 00696 mod->flags.running = 1; 00697 00698 ast_update_use_count(); 00699 break; 00700 case AST_MODULE_LOAD_DECLINE: 00701 mod->flags.declined = 1; 00702 break; 00703 case AST_MODULE_LOAD_FAILURE: 00704 break; 00705 case AST_MODULE_LOAD_SKIP: 00706 /* modules should never return this value */ 00707 break; 00708 } 00709 00710 return res; 00711 }
static int printdigest | ( | const unsigned char * | d | ) | [static] |
Definition at line 242 of file loader.c.
References ast_log(), and LOG_DEBUG.
Referenced by verify_key().
00243 { 00244 int x, pos; 00245 char buf[256]; /* large enough so we don't have to worry */ 00246 00247 for (pos = 0, x = 0; x < 16; x++) 00248 pos += sprintf(buf + pos, " %02x", *d++); 00249 00250 ast_log(LOG_DEBUG, "Unexpected signature:%s\n", buf); 00251 00252 return 0; 00253 }
static int resource_name_match | ( | const char * | name1_in, | |
const char * | name2_in | |||
) | [static] |
Definition at line 284 of file loader.c.
References ast_strdupa.
Referenced by add_to_load_order(), ast_module_reload(), and find_resource().
00285 { 00286 char *name1 = (char *) name1_in; 00287 char *name2 = (char *) name2_in; 00288 00289 /* trim off any .so extensions */ 00290 if (!strcasecmp(name1 + strlen(name1) - 3, ".so")) { 00291 name1 = ast_strdupa(name1); 00292 name1[strlen(name1) - 3] = '\0'; 00293 } 00294 if (!strcasecmp(name2 + strlen(name2) - 3, ".so")) { 00295 name2 = ast_strdupa(name2); 00296 name2[strlen(name2) - 3] = '\0'; 00297 } 00298 00299 return strcasecmp(name1, name2); 00300 }
static int translate_module_name | ( | char * | oldname, | |
char * | newname | |||
) | [static] |
Definition at line 747 of file loader.c.
References ast_copy_string().
Referenced by load_modules().
00748 { 00749 if (!strcasecmp(oldname, "app_zapbarge.so")) 00750 ast_copy_string(newname, "app_dahdibarge.so", 18); 00751 else if(!strcasecmp(oldname, "app_zapras.so")) 00752 ast_copy_string(newname, "app_dahdiras.so", 16); 00753 else if(!strcasecmp(oldname, "app_zapscan.so")) 00754 ast_copy_string(newname, "app_dahdiscan.so", 17); 00755 else if(!strcasecmp(oldname, "codec_zap.so")) 00756 ast_copy_string(newname, "codec_dahdi.so", 16); 00757 else 00758 return -1; /* no use for newname, oldname is fine */ 00759 00760 return 0; 00761 }
static void unload_dynamic_module | ( | struct ast_module * | mod | ) | [static] |
Definition at line 321 of file loader.c.
References ast_module::lib.
Referenced by ast_unload_resource(), and load_resource().
00322 { 00323 void *lib = mod->lib; 00324 00325 /* WARNING: the structure pointed to by mod is going to 00326 disappear when this operation succeeds, so we can't 00327 dereference it */ 00328 00329 if (lib) 00330 while (!dlclose(lib)); 00331 }
static int verify_key | ( | const unsigned char * | key | ) | [static] |
Definition at line 267 of file loader.c.
References expected_key, key_matches(), MD5Final(), MD5Init(), MD5Update(), and printdigest().
Referenced by inspect_module().
00268 { 00269 struct MD5Context c; 00270 unsigned char digest[16]; 00271 00272 MD5Init(&c); 00273 MD5Update(&c, key, strlen((char *)key)); 00274 MD5Final(digest, &c); 00275 00276 if (key_matches(expected_key, digest)) 00277 return 0; 00278 00279 printdigest(digest); 00280 00281 return -1; 00282 }
char buildopt_sum[33] = AST_BUILDOPT_SUM [static] |
unsigned int embedding = 1 [static] |
unsigned char expected_key[] [static] |
Initial value:
{ 0x87, 0x76, 0x79, 0x35, 0x23, 0xea, 0x3a, 0xd3, 0x25, 0x2a, 0xbb, 0x35, 0x87, 0xe4, 0x22, 0x24 }
Definition at line 71 of file loader.c.
Referenced by verify_key().
ast_mutex_t reloadlock = ((ast_mutex_t) PTHREAD_MUTEX_INITIALIZER ) [static] |
struct ast_module* resource_being_loaded |
Definition at line 109 of file loader.c.
Referenced by ast_module_register(), and load_dynamic_module().