#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"
Include dependency graph for loader.c:
Go to the source code of this file.
Data Structures | |
struct | ast_module |
struct | ast_module_user |
struct | load_order_entry |
struct | loadupdate |
struct | reload_classes |
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) |
AST_LIST_HEAD (module_user_list, ast_module_user) | |
AST_LIST_HEAD_NOLOCK (load_order, load_order_entry) | |
static | AST_LIST_HEAD_STATIC (updaters, loadupdate) |
static | AST_LIST_HEAD_STATIC (module_list, ast_module) |
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. | |
int | ast_module_check (char *name) |
Check if module with the name given is loaded. | |
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) |
AST_MUTEX_DEFINE_STATIC (reloadlock) | |
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) |
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 | verify_key (const unsigned char *key) |
Variables | |
static unsigned int | embedding = 1 |
static unsigned char | expected_key [] |
ast_module * | resource_being_loaded |
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 177 of file loader.c.
References ast_calloc, AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_update_use_count(), ast_module_user::chan, ast_module::usecount, and ast_module::users.
00179 { 00180 struct ast_module_user *u = ast_calloc(1, sizeof(*u)); 00181 00182 if (!u) 00183 return NULL; 00184 00185 u->chan = chan; 00186 00187 AST_LIST_LOCK(&mod->users); 00188 AST_LIST_INSERT_HEAD(&mod->users, u, entry); 00189 AST_LIST_UNLOCK(&mod->users); 00190 00191 ast_atomic_fetchadd_int(&mod->usecount, +1); 00192 00193 ast_update_use_count(); 00194 00195 return u; 00196 }
void __ast_module_user_hangup_all | ( | struct ast_module * | mod | ) |
Definition at line 209 of file loader.c.
References AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, ast_softhangup(), AST_SOFTHANGUP_APPUNLOAD, ast_update_use_count(), ast_module_user::chan, free, ast_module::usecount, and ast_module::users.
Referenced by ast_unload_resource().
00210 { 00211 struct ast_module_user *u; 00212 00213 AST_LIST_LOCK(&mod->users); 00214 while ((u = AST_LIST_REMOVE_HEAD(&mod->users, entry))) { 00215 ast_softhangup(u->chan, AST_SOFTHANGUP_APPUNLOAD); 00216 ast_atomic_fetchadd_int(&mod->usecount, -1); 00217 free(u); 00218 } 00219 AST_LIST_UNLOCK(&mod->users); 00220 00221 ast_update_use_count(); 00222 }
void __ast_module_user_remove | ( | struct ast_module * | mod, | |
struct ast_module_user * | u | |||
) |
Definition at line 198 of file loader.c.
References AST_LIST_LOCK, AST_LIST_REMOVE, AST_LIST_UNLOCK, ast_update_use_count(), free, ast_module::usecount, and ast_module::users.
00199 { 00200 AST_LIST_LOCK(&mod->users); 00201 AST_LIST_REMOVE(&mod->users, u, entry); 00202 AST_LIST_UNLOCK(&mod->users); 00203 ast_atomic_fetchadd_int(&mod->usecount, -1); 00204 free(u); 00205 00206 ast_update_use_count(); 00207 }
static struct load_order_entry* add_to_load_order | ( | const char * | resource, | |
struct load_order * | load_order | |||
) | [static] |
Definition at line 707 of file loader.c.
References ast_calloc, AST_LIST_INSERT_TAIL, AST_LIST_TRAVERSE, ast_strdup, load_order_entry::resource, and resource_name_match().
Referenced by load_modules().
00708 { 00709 struct load_order_entry *order; 00710 00711 AST_LIST_TRAVERSE(load_order, order, entry) { 00712 if (!resource_name_match(order->resource, resource)) 00713 return NULL; 00714 } 00715 00716 if (!(order = ast_calloc(1, sizeof(*order)))) 00717 return NULL; 00718 00719 order->resource = ast_strdup(resource); 00720 AST_LIST_INSERT_TAIL(load_order, order, entry); 00721 00722 return order; 00723 }
AST_LIST_HEAD | ( | module_user_list | , | |
ast_module_user | ||||
) |
AST_LIST_HEAD_NOLOCK | ( | load_order | , | |
load_order_entry | ||||
) |
static AST_LIST_HEAD_STATIC | ( | updaters | , | |
loadupdate | ||||
) | [static] |
static AST_LIST_HEAD_STATIC | ( | module_list | , | |
ast_module | ||||
) | [static] |
int ast_load_resource | ( | const char * | resource_name | ) |
Load a module.
resource_name | The name of the module to load. |
Definition at line 691 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_module().
00692 { 00693 AST_LIST_LOCK(&module_list); 00694 load_resource(resource_name, 0); 00695 AST_LIST_UNLOCK(&module_list); 00696 00697 return 0; 00698 }
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 933 of file loader.c.
References AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_UNLOCK, and ast_malloc.
Referenced by show_console().
00934 { 00935 struct loadupdate *tmp; 00936 00937 if (!(tmp = ast_malloc(sizeof(*tmp)))) 00938 return -1; 00939 00940 tmp->updater = v; 00941 AST_LIST_LOCK(&module_list); 00942 AST_LIST_INSERT_HEAD(&updaters, tmp, entry); 00943 AST_LIST_UNLOCK(&module_list); 00944 00945 return 0; 00946 }
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 948 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().
00949 { 00950 struct loadupdate *cur; 00951 00952 AST_LIST_LOCK(&module_list); 00953 AST_LIST_TRAVERSE_SAFE_BEGIN(&updaters, cur, entry) { 00954 if (cur->updater == v) { 00955 AST_LIST_REMOVE_CURRENT(&updaters, entry); 00956 break; 00957 } 00958 } 00959 AST_LIST_TRAVERSE_SAFE_END; 00960 AST_LIST_UNLOCK(&module_list); 00961 00962 return cur ? 0 : -1; 00963 }
int ast_module_check | ( | char * | name | ) |
Check if module with the name given is loaded.
name | Module name, like "chan_sip.so" |
Definition at line 914 of file loader.c.
References AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_mutex_trylock(), and ast_strlen_zero().
Referenced by ifmodule_read().
00915 { 00916 struct ast_module *cur; 00917 int unlock = -1; 00918 int res = 0; 00919 00920 if (ast_strlen_zero(name)) 00921 return 0; /* FALSE */ 00922 00923 if (ast_mutex_trylock(&module_list.lock)) 00924 unlock = 0; 00925 AST_LIST_TRAVERSE(&module_list, cur, entry) 00926 if (!res && !strcasecmp(name, cur->resource)) 00927 res = 1; 00928 if (unlock) 00929 AST_LIST_UNLOCK(&module_list); 00930 return res; 00931 }
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 516 of file loader.c.
References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_module::info, name, ast_module_info::reload, and strdup.
Referenced by complete_mod_2(), complete_mod_3(), complete_mod_3_nr(), and complete_mod_4().
00517 { 00518 struct ast_module *cur; 00519 int i, which=0, l = strlen(word); 00520 char *ret = NULL; 00521 00522 if (pos != rpos) 00523 return NULL; 00524 00525 AST_LIST_LOCK(&module_list); 00526 AST_LIST_TRAVERSE(&module_list, cur, entry) { 00527 if (!strncasecmp(word, cur->resource, l) && 00528 (cur->info->reload || !needsreload) && 00529 ++which > state) { 00530 ret = strdup(cur->resource); 00531 break; 00532 } 00533 } 00534 AST_LIST_UNLOCK(&module_list); 00535 00536 if (!ret) { 00537 for (i=0; !ret && reload_classes[i].name; i++) { 00538 if (!strncasecmp(word, reload_classes[i].name, l) && ++which > state) 00539 ret = strdup(reload_classes[i].name); 00540 } 00541 } 00542 00543 return ret; 00544 }
struct ast_module* ast_module_ref | ( | struct ast_module * | mod | ) |
Definition at line 965 of file loader.c.
References 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(), features_new(), fn_wrapper(), gtalk_new(), handle_orig(), mgcp_new(), newpvt(), oss_new(), phone_check_exception(), phone_new(), sip_new(), skinny_new(), and zt_new().
00966 { 00967 ast_atomic_fetchadd_int(&mod->usecount, +1); 00968 ast_update_use_count(); 00969 00970 return mod; 00971 }
void ast_module_register | ( | const struct ast_module_info * | info | ) |
Definition at line 115 of file loader.c.
References ast_calloc, AST_LIST_HEAD_INIT, AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_UNLOCK, embedding, ast_module::info, ast_module_info::name, resource_being_loaded, ast_module_info::self, and ast_module::users.
00116 { 00117 struct ast_module *mod; 00118 00119 if (embedding) { 00120 if (!(mod = ast_calloc(1, sizeof(*mod) + strlen(info->name) + 1))) 00121 return; 00122 strcpy(mod->resource, info->name); 00123 } else { 00124 mod = resource_being_loaded; 00125 } 00126 00127 mod->info = info; 00128 AST_LIST_HEAD_INIT(&mod->users); 00129 00130 /* during startup, before the loader has been initialized, 00131 there are no threads, so there is no need to take the lock 00132 on this list to manipulate it. it is also possible that it 00133 might be unsafe to use the list lock at that point... so 00134 let's avoid it altogether 00135 */ 00136 if (!embedding) 00137 AST_LIST_LOCK(&module_list); 00138 00139 /* it is paramount that the new entry be placed at the tail of 00140 the list, otherwise the code that uses dlopen() to load 00141 dynamic modules won't be able to find out if the module it 00142 just opened was registered or failed to load 00143 */ 00144 AST_LIST_INSERT_TAIL(&module_list, mod, entry); 00145 00146 if (!embedding) 00147 AST_LIST_UNLOCK(&module_list); 00148 00149 /* give the module a copy of its own handle, for later use in registrations and the like */ 00150 *((struct ast_module **) &(info->self)) = mod; 00151 }
int ast_module_reload | ( | const char * | name | ) |
Reload asterisk modules.
name | the name of the module to reload |
Definition at line 546 of file loader.c.
References ast_lastreloadtime, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_mutex_trylock(), ast_mutex_unlock(), ast_verbose(), ast_module::declined, ast_module_info::description, ast_module::flags, ast_module::info, option_verbose, ast_module_info::reload, resource_name_match(), ast_module::running, and VERBOSE_PREFIX_3.
Referenced by action_updateconfig(), handle_reload(), handle_reload_deprecated(), and monitor_sig_flags().
00547 { 00548 struct ast_module *cur; 00549 int res = 0; /* return value. 0 = not found, others, see below */ 00550 int i; 00551 00552 if (ast_mutex_trylock(&reloadlock)) { 00553 ast_verbose("The previous reload command didn't finish yet\n"); 00554 return -1; /* reload already in progress */ 00555 } 00556 ast_lastreloadtime = time(NULL); 00557 00558 /* Call "predefined" reload here first */ 00559 for (i = 0; reload_classes[i].name; i++) { 00560 if (!name || !strcasecmp(name, reload_classes[i].name)) { 00561 reload_classes[i].reload_fn(); /* XXX should check error ? */ 00562 res = 2; /* found and reloaded */ 00563 } 00564 } 00565 00566 if (name && res) { 00567 ast_mutex_unlock(&reloadlock); 00568 return res; 00569 } 00570 00571 AST_LIST_LOCK(&module_list); 00572 AST_LIST_TRAVERSE(&module_list, cur, entry) { 00573 const struct ast_module_info *info = cur->info; 00574 00575 if (name && resource_name_match(name, cur->resource)) 00576 continue; 00577 00578 if (!(cur->flags.running || cur->flags.declined)) 00579 continue; 00580 00581 if (!info->reload) { /* cannot be reloaded */ 00582 if (res < 1) /* store result if possible */ 00583 res = 1; /* 1 = no reload() method */ 00584 continue; 00585 } 00586 00587 res = 2; 00588 if (option_verbose > 2) 00589 ast_verbose(VERBOSE_PREFIX_3 "Reloading module '%s' (%s)\n", cur->resource, info->description); 00590 info->reload(); 00591 } 00592 AST_LIST_UNLOCK(&module_list); 00593 00594 ast_mutex_unlock(&reloadlock); 00595 00596 return res; 00597 }
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 430 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, free, ast_module::info, ast_module_info::unload, and ast_module::users.
Referenced by quit_handler().
00431 { 00432 struct ast_module *mod; 00433 AST_LIST_HEAD_NOLOCK_STATIC(local_module_list, ast_module); 00434 00435 /* We have to call the unload() callbacks in reverse order that the modules 00436 * exist in the module list so it is the reverse order of how they were 00437 * loaded. */ 00438 00439 AST_LIST_LOCK(&module_list); 00440 while ((mod = AST_LIST_REMOVE_HEAD(&module_list, entry))) 00441 AST_LIST_INSERT_HEAD(&local_module_list, mod, entry); 00442 AST_LIST_UNLOCK(&module_list); 00443 00444 while ((mod = AST_LIST_REMOVE_HEAD(&local_module_list, entry))) { 00445 if (mod->info->unload) 00446 mod->info->unload(); 00447 /* Since this should only be called when shutting down "gracefully", 00448 * all channels should be down before we get to this point, meaning 00449 * there will be no module users left. */ 00450 AST_LIST_HEAD_DESTROY(&mod->users); 00451 free(mod); 00452 } 00453 }
void ast_module_unref | ( | struct ast_module * | mod | ) |
Definition at line 973 of file loader.c.
References ast_update_use_count(), and ast_module::usecount.
Referenced by alsa_hangup(), ast_closestream(), ast_smdi_interface_destroy(), cli_audio_convert(), cli_audio_convert_deprecated(), complete_orig(), destroy(), gtalk_hangup(), handle_orig(), iax2_predestroy(), mgcp_hangup(), oh323_hangup(), oss_hangup(), phone_check_exception(), phone_hangup(), sip_hangup(), and zt_hangup().
00974 { 00975 ast_atomic_fetchadd_int(&mod->usecount, -1); 00976 ast_update_use_count(); 00977 }
void ast_module_unregister | ( | const struct ast_module_info * | info | ) |
Definition at line 153 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, free, ast_module::info, and ast_module::users.
00154 { 00155 struct ast_module *mod = NULL; 00156 00157 /* it is assumed that the users list in the module structure 00158 will already be empty, or we cannot have gotten to this 00159 point 00160 */ 00161 AST_LIST_LOCK(&module_list); 00162 AST_LIST_TRAVERSE_SAFE_BEGIN(&module_list, mod, entry) { 00163 if (mod->info == info) { 00164 AST_LIST_REMOVE_CURRENT(&module_list, entry); 00165 break; 00166 } 00167 } 00168 AST_LIST_TRAVERSE_SAFE_END; 00169 AST_LIST_UNLOCK(&module_list); 00170 00171 if (mod) { 00172 AST_LIST_HEAD_DESTROY(&mod->users); 00173 free(mod); 00174 } 00175 }
AST_MUTEX_DEFINE_STATIC | ( | reloadlock | ) |
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 455 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, error(), find_resource(), ast_module::flags, ast_module::lib, ast_module::running, and ast_module::usecount.
Referenced by exit_now(), handle_unload(), handle_unload_deprecated(), reload_module(), and remove_module().
00456 { 00457 struct ast_module *mod; 00458 int res = -1; 00459 int error = 0; 00460 00461 AST_LIST_LOCK(&module_list); 00462 00463 if (!(mod = find_resource(resource_name, 0))) { 00464 AST_LIST_UNLOCK(&module_list); 00465 return 0; 00466 } 00467 00468 if (!(mod->flags.running || mod->flags.declined)) 00469 error = 1; 00470 00471 if (!mod->lib) { 00472 ast_log(LOG_WARNING, "Unloading embedded modules is not supported.\n"); 00473 error = 1; 00474 } 00475 00476 if (!error && (mod->usecount > 0)) { 00477 if (force) 00478 ast_log(LOG_WARNING, "Warning: Forcing removal of module '%s' with use count %d\n", 00479 resource_name, mod->usecount); 00480 else { 00481 ast_log(LOG_WARNING, "Soft unload failed, '%s' has use count %d\n", resource_name, 00482 mod->usecount); 00483 error = 1; 00484 } 00485 } 00486 00487 if (!error) { 00488 __ast_module_user_hangup_all(mod); 00489 res = mod->info->unload(); 00490 00491 if (res) { 00492 ast_log(LOG_WARNING, "Firm unload failed for %s\n", resource_name); 00493 if (force <= AST_FORCE_FIRM) 00494 error = 1; 00495 else 00496 ast_log(LOG_WARNING, "** Dangerous **: Unloading resource anyway, at user request\n"); 00497 } 00498 } 00499 00500 if (!error) 00501 mod->flags.running = mod->flags.declined = 0; 00502 00503 AST_LIST_UNLOCK(&module_list); 00504 00505 #if LOADABLE_MODULES 00506 if (!error) 00507 unload_dynamic_module(mod); 00508 #endif 00509 00510 if (!error) 00511 ast_update_use_count(); 00512 00513 return res; 00514 }
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 894 of file loader.c.
References AST_LIST_TRAVERSE, AST_LIST_TRYLOCK, AST_LIST_UNLOCK, ast_module_info::description, ast_module::info, and ast_module::usecount.
Referenced by handle_modlist(), and mod_update().
00896 { 00897 struct ast_module *cur; 00898 int unlock = -1; 00899 int total_mod_loaded = 0; 00900 00901 if (AST_LIST_TRYLOCK(&module_list)) 00902 unlock = 0; 00903 00904 AST_LIST_TRAVERSE(&module_list, cur, entry) { 00905 total_mod_loaded += modentry(cur->resource, cur->info->description, cur->usecount, like); 00906 } 00907 00908 if (unlock) 00909 AST_LIST_UNLOCK(&module_list); 00910 00911 return total_mod_loaded; 00912 }
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 882 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().
00883 { 00884 /* Notify any module monitors that the use count for a 00885 resource has changed */ 00886 struct loadupdate *m; 00887 00888 AST_LIST_LOCK(&module_list); 00889 AST_LIST_TRAVERSE(&updaters, m, entry) 00890 m->updater(); 00891 AST_LIST_UNLOCK(&module_list); 00892 }
static struct ast_module* find_resource | ( | const char * | resource, | |
int | do_lock | |||
) | [static] |
Definition at line 303 of file loader.c.
References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, and resource_name_match().
Referenced by ast_unload_resource(), load_modules(), and load_resource().
00304 { 00305 struct ast_module *cur; 00306 00307 if (do_lock) 00308 AST_LIST_LOCK(&module_list); 00309 00310 AST_LIST_TRAVERSE(&module_list, cur, entry) { 00311 if (!resource_name_match(resource, cur->resource)) 00312 break; 00313 } 00314 00315 if (do_lock) 00316 AST_LIST_UNLOCK(&module_list); 00317 00318 return cur; 00319 }
static unsigned int inspect_module | ( | const struct ast_module * | mod | ) | [static] |
Definition at line 599 of file loader.c.
References ast_log(), ast_module_info::description, ast_module::info, ast_module_info::key, and verify_key().
Referenced by load_resource().
00600 { 00601 if (!mod->info->description) { 00602 ast_log(LOG_WARNING, "Module '%s' does not provide a description.\n", mod->resource); 00603 return 1; 00604 } 00605 00606 if (!mod->info->key) { 00607 ast_log(LOG_WARNING, "Module '%s' does not provide a license key.\n", mod->resource); 00608 return 1; 00609 } 00610 00611 if (verify_key((unsigned char *) mod->info->key)) { 00612 ast_log(LOG_WARNING, "Module '%s' did not provide a valid license key.\n", mod->resource); 00613 return 1; 00614 } 00615 00616 return 0; 00617 }
static int key_matches | ( | const unsigned char * | key1, | |
const unsigned char * | key2 | |||
) | [static] |
Definition at line 256 of file loader.c.
Referenced by verify_key().
00257 { 00258 int x; 00259 00260 for (x = 0; x < 16; x++) { 00261 if (key1[x] != key2[x]) 00262 return 0; 00263 } 00264 00265 return 1; 00266 }
int load_modules | ( | unsigned | int | ) |
Provided by loader.c
Definition at line 725 of file loader.c.
References add_to_load_order(), ast_config_AST_MODULE_DIR, ast_config_load(), AST_LIST_HEAD_INIT_NOLOCK, AST_LIST_LOCK, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_log(), AST_MODULE_CONFIG, ast_opt_quiet, ast_true(), ast_variable_browse(), ast_variable_retrieve(), ast_verbose(), embedding, find_resource(), ast_module::flags, free, ast_module::lib, ast_variable::name, ast_variable::next, option_verbose, load_order_entry::resource, resource_name_match(), ast_module::running, and ast_variable::value.
Referenced by main().
00726 { 00727 struct ast_config *cfg; 00728 struct ast_module *mod; 00729 struct load_order_entry *order; 00730 struct ast_variable *v; 00731 unsigned int load_count; 00732 struct load_order load_order; 00733 int res = 0; 00734 #if LOADABLE_MODULES 00735 struct dirent *dirent; 00736 DIR *dir; 00737 #endif 00738 00739 /* all embedded modules have registered themselves by now */ 00740 embedding = 0; 00741 00742 if (option_verbose) 00743 ast_verbose("Asterisk Dynamic Loader Starting:\n"); 00744 00745 AST_LIST_HEAD_INIT_NOLOCK(&load_order); 00746 00747 AST_LIST_LOCK(&module_list); 00748 00749 if (!(cfg = ast_config_load(AST_MODULE_CONFIG))) { 00750 ast_log(LOG_WARNING, "No '%s' found, no modules will be loaded.\n", AST_MODULE_CONFIG); 00751 goto done; 00752 } 00753 00754 /* first, find all the modules we have been explicitly requested to load */ 00755 for (v = ast_variable_browse(cfg, "modules"); v; v = v->next) { 00756 if (!strcasecmp(v->name, preload_only ? "preload" : "load")) 00757 add_to_load_order(v->value, &load_order); 00758 } 00759 00760 /* check if 'autoload' is on */ 00761 if (!preload_only && ast_true(ast_variable_retrieve(cfg, "modules", "autoload"))) { 00762 /* if so, first add all the embedded modules that are not already running to the load order */ 00763 AST_LIST_TRAVERSE(&module_list, mod, entry) { 00764 /* if it's not embedded, skip it */ 00765 if (mod->lib) 00766 continue; 00767 00768 if (mod->flags.running) 00769 continue; 00770 00771 order = add_to_load_order(mod->resource, &load_order); 00772 } 00773 00774 #if LOADABLE_MODULES 00775 /* if we are allowed to load dynamic modules, scan the directory for 00776 for all available modules and add them as well */ 00777 if ((dir = opendir(ast_config_AST_MODULE_DIR))) { 00778 while ((dirent = readdir(dir))) { 00779 int ld = strlen(dirent->d_name); 00780 00781 /* Must end in .so to load it. */ 00782 00783 if (ld < 4) 00784 continue; 00785 00786 if (strcasecmp(dirent->d_name + ld - 3, ".so")) 00787 continue; 00788 00789 /* if there is already a module by this name in the module_list, 00790 skip this file */ 00791 if (find_resource(dirent->d_name, 0)) 00792 continue; 00793 00794 add_to_load_order(dirent->d_name, &load_order); 00795 } 00796 00797 closedir(dir); 00798 } else { 00799 if (!ast_opt_quiet) 00800 ast_log(LOG_WARNING, "Unable to open modules directory '%s'.\n", 00801 ast_config_AST_MODULE_DIR); 00802 } 00803 #endif 00804 } 00805 00806 /* now scan the config for any modules we are prohibited from loading and 00807 remove them from the load order */ 00808 for (v = ast_variable_browse(cfg, "modules"); v; v = v->next) { 00809 if (strcasecmp(v->name, "noload")) 00810 continue; 00811 00812 AST_LIST_TRAVERSE_SAFE_BEGIN(&load_order, order, entry) { 00813 if (!resource_name_match(order->resource, v->value)) { 00814 AST_LIST_REMOVE_CURRENT(&load_order, entry); 00815 free(order->resource); 00816 free(order); 00817 } 00818 } 00819 AST_LIST_TRAVERSE_SAFE_END; 00820 } 00821 00822 /* we are done with the config now, all the information we need is in the 00823 load_order list */ 00824 ast_config_destroy(cfg); 00825 00826 load_count = 0; 00827 AST_LIST_TRAVERSE(&load_order, order, entry) 00828 load_count++; 00829 00830 if (load_count) 00831 ast_log(LOG_NOTICE, "%d modules will be loaded.\n", load_count); 00832 00833 /* first, load only modules that provide global symbols */ 00834 AST_LIST_TRAVERSE_SAFE_BEGIN(&load_order, order, entry) { 00835 switch (load_resource(order->resource, 1)) { 00836 case AST_MODULE_LOAD_SUCCESS: 00837 case AST_MODULE_LOAD_DECLINE: 00838 AST_LIST_REMOVE_CURRENT(&load_order, entry); 00839 free(order->resource); 00840 free(order); 00841 break; 00842 case AST_MODULE_LOAD_FAILURE: 00843 res = -1; 00844 goto done; 00845 case AST_MODULE_LOAD_SKIP: 00846 /* try again later */ 00847 break; 00848 } 00849 } 00850 AST_LIST_TRAVERSE_SAFE_END; 00851 00852 /* now load everything else */ 00853 AST_LIST_TRAVERSE_SAFE_BEGIN(&load_order, order, entry) { 00854 switch (load_resource(order->resource, 0)) { 00855 case AST_MODULE_LOAD_SUCCESS: 00856 case AST_MODULE_LOAD_DECLINE: 00857 AST_LIST_REMOVE_CURRENT(&load_order, entry); 00858 free(order->resource); 00859 free(order); 00860 break; 00861 case AST_MODULE_LOAD_FAILURE: 00862 res = -1; 00863 goto done; 00864 case AST_MODULE_LOAD_SKIP: 00865 /* should not happen */ 00866 break; 00867 } 00868 } 00869 AST_LIST_TRAVERSE_SAFE_END; 00870 00871 done: 00872 while ((order = AST_LIST_REMOVE_HEAD(&load_order, entry))) { 00873 free(order->resource); 00874 free(order); 00875 } 00876 00877 AST_LIST_UNLOCK(&module_list); 00878 00879 return res; 00880 }
static enum ast_module_load_result load_resource | ( | const char * | resource_name, | |
unsigned int | global_symbols_only | |||
) | [static] |
Definition at line 619 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, option_verbose, ast_module::running, term_color(), and VERBOSE_PREFIX_1.
Referenced by ast_load_resource().
00620 { 00621 struct ast_module *mod; 00622 enum ast_module_load_result res = AST_MODULE_LOAD_SUCCESS; 00623 char tmp[256]; 00624 00625 if ((mod = find_resource(resource_name, 0))) { 00626 if (mod->flags.running) { 00627 ast_log(LOG_WARNING, "Module '%s' already exists.\n", resource_name); 00628 return AST_MODULE_LOAD_DECLINE; 00629 } 00630 if (global_symbols_only && !ast_test_flag(mod->info, AST_MODFLAG_GLOBAL_SYMBOLS)) 00631 return AST_MODULE_LOAD_SKIP; 00632 } else { 00633 #if LOADABLE_MODULES 00634 if (!(mod = load_dynamic_module(resource_name, global_symbols_only))) { 00635 /* don't generate a warning message during load_modules() */ 00636 if (!global_symbols_only) { 00637 ast_log(LOG_WARNING, "Module '%s' could not be loaded.\n", resource_name); 00638 return AST_MODULE_LOAD_DECLINE; 00639 } else { 00640 return AST_MODULE_LOAD_SKIP; 00641 } 00642 } 00643 #else 00644 ast_log(LOG_WARNING, "Module '%s' could not be loaded.\n", resource_name); 00645 return AST_MODULE_LOAD_DECLINE; 00646 #endif 00647 } 00648 00649 if (inspect_module(mod)) { 00650 ast_log(LOG_WARNING, "Module '%s' could not be loaded.\n", resource_name); 00651 #if LOADABLE_MODULES 00652 unload_dynamic_module(mod); 00653 #endif 00654 return AST_MODULE_LOAD_DECLINE; 00655 } 00656 00657 mod->flags.declined = 0; 00658 00659 if (mod->info->load) 00660 res = mod->info->load(); 00661 00662 switch (res) { 00663 case AST_MODULE_LOAD_SUCCESS: 00664 if (!ast_fully_booted) { 00665 if (option_verbose) 00666 ast_verbose("%s => (%s)\n", resource_name, term_color(tmp, mod->info->description, COLOR_BROWN, COLOR_BLACK, sizeof(tmp))); 00667 if (ast_opt_console && !option_verbose) 00668 ast_verbose( "."); 00669 } else { 00670 if (option_verbose) 00671 ast_verbose(VERBOSE_PREFIX_1 "Loaded %s => (%s)\n", resource_name, mod->info->description); 00672 } 00673 00674 mod->flags.running = 1; 00675 00676 ast_update_use_count(); 00677 break; 00678 case AST_MODULE_LOAD_DECLINE: 00679 mod->flags.declined = 1; 00680 break; 00681 case AST_MODULE_LOAD_FAILURE: 00682 break; 00683 case AST_MODULE_LOAD_SKIP: 00684 /* modules should never return this value */ 00685 break; 00686 } 00687 00688 return res; 00689 }
static int printdigest | ( | const unsigned char * | d | ) | [static] |
Definition at line 243 of file loader.c.
References ast_log(), and LOG_DEBUG.
Referenced by verify_key().
00244 { 00245 int x, pos; 00246 char buf[256]; /* large enough so we don't have to worry */ 00247 00248 for (pos = 0, x = 0; x < 16; x++) 00249 pos += sprintf(buf + pos, " %02x", *d++); 00250 00251 ast_log(LOG_DEBUG, "Unexpected signature:%s\n", buf); 00252 00253 return 0; 00254 }
static int resource_name_match | ( | const char * | name1_in, | |
const char * | name2_in | |||
) | [static] |
Definition at line 285 of file loader.c.
References ast_strdupa.
Referenced by add_to_load_order(), ast_module_reload(), find_resource(), and load_modules().
00286 { 00287 char *name1 = (char *) name1_in; 00288 char *name2 = (char *) name2_in; 00289 00290 /* trim off any .so extensions */ 00291 if (!strcasecmp(name1 + strlen(name1) - 3, ".so")) { 00292 name1 = ast_strdupa(name1); 00293 name1[strlen(name1) - 3] = '\0'; 00294 } 00295 if (!strcasecmp(name2 + strlen(name2) - 3, ".so")) { 00296 name2 = ast_strdupa(name2); 00297 name2[strlen(name2) - 3] = '\0'; 00298 } 00299 00300 return strcasecmp(name1, name2); 00301 }
static int verify_key | ( | const unsigned char * | key | ) | [static] |
Definition at line 268 of file loader.c.
References expected_key, key_matches(), MD5Final(), MD5Init(), MD5Update(), and printdigest().
Referenced by inspect_module().
00269 { 00270 struct MD5Context c; 00271 unsigned char digest[16]; 00272 00273 MD5Init(&c); 00274 MD5Update(&c, key, strlen((char *)key)); 00275 MD5Final(digest, &c); 00276 00277 if (key_matches(expected_key, digest)) 00278 return 0; 00279 00280 printdigest(digest); 00281 00282 return -1; 00283 }
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 75 of file loader.c.
Referenced by verify_key().
struct ast_module* resource_being_loaded |