| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Asterisk -- An open source telephony toolkit. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Copyright (C) 1999 - 2006, Digium, Inc. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Mark Spencer <markster@digium.com> | 
					
						
							|  |  |  |  * Kevin P. Fleming <kpfleming@digium.com> | 
					
						
							|  |  |  |  * Luigi Rizzo <rizzo@icir.org> | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * See http://www.asterisk.org for more information about
 | 
					
						
							|  |  |  |  * the Asterisk project. Please do not directly contact | 
					
						
							|  |  |  |  * any of the maintainers of this project for assistance; | 
					
						
							|  |  |  |  * the project provides a web site, mailing lists and IRC | 
					
						
							|  |  |  |  * channels for your use. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This program is free software, distributed under the terms of | 
					
						
							|  |  |  |  * the GNU General Public License Version 2. See the LICENSE file | 
					
						
							|  |  |  |  * at the top of the source tree. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*! \file
 | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \brief Module Loader | 
					
						
							| 
									
										
										
										
											2006-09-15 05:00:27 +00:00
										 |  |  |  * \author Mark Spencer <markster@digium.com> | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  |  * \author Kevin P. Fleming <kpfleming@digium.com> | 
					
						
							|  |  |  |  * \author Luigi Rizzo <rizzo@icir.org> | 
					
						
							|  |  |  |  * - See ModMngMnt | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "asterisk.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ASTERISK_FILE_VERSION(__FILE__, "$Revision$") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-20 22:18:21 +00:00
										 |  |  | #include "asterisk/_private.h"
 | 
					
						
							| 
									
										
										
										
											2007-11-20 23:16:15 +00:00
										 |  |  | #include "asterisk/paths.h"	/* use ast_config_AST_MODULE_DIR */
 | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | #include <dirent.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "asterisk/linkedlists.h"
 | 
					
						
							|  |  |  | #include "asterisk/module.h"
 | 
					
						
							|  |  |  | #include "asterisk/config.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"
 | 
					
						
							| 
									
										
										
										
											2008-01-23 23:09:11 +00:00
										 |  |  | #include "asterisk/features.h"
 | 
					
						
							| 
									
										
										
										
											2008-03-05 16:23:44 +00:00
										 |  |  | #include "asterisk/dsp.h"
 | 
					
						
							| 
									
										
										
										
											2008-03-26 18:39:06 +00:00
										 |  |  | #include "asterisk/udptl.h"
 | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | #include <dlfcn.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "asterisk/md5.h"
 | 
					
						
							|  |  |  | #include "asterisk/utils.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-10-22 14:56:05 +00:00
										 |  |  | #ifndef RTLD_NOW
 | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | #define RTLD_NOW 0
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-17 09:51:45 +00:00
										 |  |  | #ifndef RTLD_LOCAL
 | 
					
						
							|  |  |  | #define RTLD_LOCAL 0
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | struct ast_module_user { | 
					
						
							|  |  |  | 	struct ast_channel *chan; | 
					
						
							|  |  |  | 	AST_LIST_ENTRY(ast_module_user) entry; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | AST_LIST_HEAD(module_user_list, ast_module_user); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static unsigned char expected_key[] = | 
					
						
							|  |  |  | { 0x87, 0x76, 0x79, 0x35, 0x23, 0xea, 0x3a, 0xd3, | 
					
						
							|  |  |  |   0x25, 0x2a, 0xbb, 0x35, 0x87, 0xe4, 0x22, 0x24 }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-20 19:28:10 +00:00
										 |  |  | static char buildopt_sum[33] = AST_BUILDOPT_SUM; | 
					
						
							| 
									
										
										
										
											2007-11-16 16:56:59 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | static unsigned int embedding = 1; /* we always start out by registering embedded modules,
 | 
					
						
							|  |  |  | 				      since they are here before we dlopen() any | 
					
						
							|  |  |  | 				   */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct ast_module { | 
					
						
							|  |  |  | 	const struct ast_module_info *info; | 
					
						
							|  |  |  | 	void *lib;					/* the shared lib, or NULL if embedded */ | 
					
						
							|  |  |  | 	int usecount;					/* the number of 'users' currently in this module */ | 
					
						
							|  |  |  | 	struct module_user_list users;			/* the list of users in the module */ | 
					
						
							| 
									
										
										
										
											2007-05-03 16:43:49 +00:00
										 |  |  | 	struct { | 
					
						
							| 
									
										
										
											
												After some study, thought, comparing, etc. I've backed out the previous universal mod to make ast_flags a 64 bit thing. Instead, I added a 64-bit version of ast_flags (ast_flags64), and 64-bit versions of the test-flag, set-flag, etc. macros, and an app_parse_options64 routine, and I use these in app_dial alone, to eliminate the 30-option limit it had grown to meet. There is room now for 32 more options and flags. I was heavily tempted to implement some of the other ideas that were presented, but this solution does not intro any new versions of dial, doesn't have a different API, has a minimal/zero impact on code outside of dial, and doesn't seriously (I hope) affect the code structure of dial. It's the best I can think of right now. My goal was NOT to rewrite dial. I leave that to a future, coordinated effort.
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@75983 65c4cc65-6c06-0410-ace0-fbb531ad65f3
											
										 
											2007-07-19 23:24:27 +00:00
										 |  |  | 		unsigned int running:1; | 
					
						
							|  |  |  | 		unsigned int declined:1; | 
					
						
							| 
									
										
										
										
											2007-05-03 16:43:49 +00:00
										 |  |  | 	} flags; | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | 	AST_LIST_ENTRY(ast_module) entry; | 
					
						
							|  |  |  | 	char resource[0]; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static AST_LIST_HEAD_STATIC(module_list, ast_module); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-06 17:05:13 +00:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * module_list is cleared by its constructor possibly after | 
					
						
							|  |  |  |  * we start accumulating embedded modules, so we need to | 
					
						
							|  |  |  |  * use another list (without the lock) to accumulate them. | 
					
						
							|  |  |  |  * Then we update the main list when embedding is done. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static struct module_list embedded_module_list; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | struct loadupdate { | 
					
						
							|  |  |  | 	int (*updater)(void); | 
					
						
							|  |  |  | 	AST_LIST_ENTRY(loadupdate) entry; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static AST_LIST_HEAD_STATIC(updaters, loadupdate); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | AST_MUTEX_DEFINE_STATIC(reloadlock); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* when dynamic modules are being loaded, ast_module_register() will
 | 
					
						
							|  |  |  |    need to know what filename the module was loaded from while it | 
					
						
							|  |  |  |    is being registered | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | struct ast_module *resource_being_loaded; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* XXX: should we check for duplicate resource names here? */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ast_module_register(const struct ast_module_info *info) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct ast_module *mod; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (embedding) { | 
					
						
							|  |  |  | 		if (!(mod = ast_calloc(1, sizeof(*mod) + strlen(info->name) + 1))) | 
					
						
							|  |  |  | 			return; | 
					
						
							|  |  |  | 		strcpy(mod->resource, info->name); | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		mod = resource_being_loaded; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	mod->info = info; | 
					
						
							|  |  |  | 	AST_LIST_HEAD_INIT(&mod->users); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* during startup, before the loader has been initialized,
 | 
					
						
							|  |  |  | 	   there are no threads, so there is no need to take the lock | 
					
						
							|  |  |  | 	   on this list to manipulate it. it is also possible that it | 
					
						
							|  |  |  | 	   might be unsafe to use the list lock at that point... so | 
					
						
							|  |  |  | 	   let's avoid it altogether | 
					
						
							|  |  |  | 	*/ | 
					
						
							| 
									
										
										
										
											2007-11-06 17:05:13 +00:00
										 |  |  | 	if (embedding) { | 
					
						
							|  |  |  | 		AST_LIST_INSERT_TAIL(&embedded_module_list, mod, entry); | 
					
						
							|  |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | 		AST_LIST_LOCK(&module_list); | 
					
						
							| 
									
										
										
										
											2007-11-06 17:05:13 +00:00
										 |  |  | 		/* it is paramount that the new entry be placed at the tail of
 | 
					
						
							|  |  |  | 		   the list, otherwise the code that uses dlopen() to load | 
					
						
							|  |  |  | 		   dynamic modules won't be able to find out if the module it | 
					
						
							|  |  |  | 		   just opened was registered or failed to load | 
					
						
							|  |  |  | 		*/ | 
					
						
							|  |  |  | 		AST_LIST_INSERT_TAIL(&module_list, mod, entry); | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | 		AST_LIST_UNLOCK(&module_list); | 
					
						
							| 
									
										
										
										
											2007-11-06 17:05:13 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* give the module a copy of its own handle, for later use in registrations and the like */ | 
					
						
							|  |  |  | 	*((struct ast_module **) &(info->self)) = mod; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ast_module_unregister(const struct ast_module_info *info) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct ast_module *mod = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* it is assumed that the users list in the module structure
 | 
					
						
							|  |  |  | 	   will already be empty, or we cannot have gotten to this | 
					
						
							|  |  |  | 	   point | 
					
						
							|  |  |  | 	*/ | 
					
						
							|  |  |  | 	AST_LIST_LOCK(&module_list); | 
					
						
							|  |  |  | 	AST_LIST_TRAVERSE_SAFE_BEGIN(&module_list, mod, entry) { | 
					
						
							|  |  |  | 		if (mod->info == info) { | 
					
						
							| 
									
										
										
										
											2007-11-08 05:28:47 +00:00
										 |  |  | 			AST_LIST_REMOVE_CURRENT(entry); | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	AST_LIST_TRAVERSE_SAFE_END; | 
					
						
							|  |  |  | 	AST_LIST_UNLOCK(&module_list); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (mod) { | 
					
						
							|  |  |  | 		AST_LIST_HEAD_DESTROY(&mod->users); | 
					
						
							| 
									
										
										
										
											2007-06-06 21:20:11 +00:00
										 |  |  | 		ast_free(mod); | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct ast_module_user *__ast_module_user_add(struct ast_module *mod, | 
					
						
							|  |  |  | 					      struct ast_channel *chan) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct ast_module_user *u = ast_calloc(1, sizeof(*u)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!u) | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	u->chan = chan; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	AST_LIST_LOCK(&mod->users); | 
					
						
							|  |  |  | 	AST_LIST_INSERT_HEAD(&mod->users, u, entry); | 
					
						
							|  |  |  | 	AST_LIST_UNLOCK(&mod->users); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ast_atomic_fetchadd_int(&mod->usecount, +1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ast_update_use_count(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return u; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void __ast_module_user_remove(struct ast_module *mod, struct ast_module_user *u) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	AST_LIST_LOCK(&mod->users); | 
					
						
							|  |  |  | 	AST_LIST_REMOVE(&mod->users, u, entry); | 
					
						
							|  |  |  | 	AST_LIST_UNLOCK(&mod->users); | 
					
						
							|  |  |  | 	ast_atomic_fetchadd_int(&mod->usecount, -1); | 
					
						
							| 
									
										
										
										
											2007-06-06 21:20:11 +00:00
										 |  |  | 	ast_free(u); | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	ast_update_use_count(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void __ast_module_user_hangup_all(struct ast_module *mod) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct ast_module_user *u; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	AST_LIST_LOCK(&mod->users); | 
					
						
							|  |  |  | 	while ((u = AST_LIST_REMOVE_HEAD(&mod->users, entry))) { | 
					
						
							|  |  |  | 		ast_softhangup(u->chan, AST_SOFTHANGUP_APPUNLOAD); | 
					
						
							|  |  |  | 		ast_atomic_fetchadd_int(&mod->usecount, -1); | 
					
						
							| 
									
										
										
										
											2007-06-06 21:20:11 +00:00
										 |  |  | 		ast_free(u); | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	AST_LIST_UNLOCK(&mod->users); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-03-04 23:04:29 +00:00
										 |  |  | 	ast_update_use_count(); | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*! \note
 | 
					
						
							|  |  |  |  * In addition to modules, the reload command handles some extra keywords | 
					
						
							|  |  |  |  * which are listed here together with the corresponding handlers. | 
					
						
							|  |  |  |  * This table is also used by the command completion code. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static struct reload_classes { | 
					
						
							|  |  |  | 	const char *name; | 
					
						
							|  |  |  | 	int (*reload_fn)(void); | 
					
						
							|  |  |  | } reload_classes[] = {	/* list in alpha order, longest match first for cli completion */ | 
					
						
							|  |  |  | 	{ "cdr",	ast_cdr_engine_reload }, | 
					
						
							|  |  |  | 	{ "dnsmgr",	dnsmgr_reload }, | 
					
						
							|  |  |  | 	{ "extconfig",	read_config_maps }, | 
					
						
							|  |  |  | 	{ "enum",	ast_enum_reload }, | 
					
						
							|  |  |  | 	{ "manager",	reload_manager }, | 
					
						
							|  |  |  | 	{ "rtp",	ast_rtp_reload }, | 
					
						
							|  |  |  | 	{ "http",	ast_http_reload }, | 
					
						
							| 
									
										
										
										
											2007-12-06 14:23:12 +00:00
										 |  |  | 	{ "logger",	logger_reload }, | 
					
						
							| 
									
										
										
										
											2008-01-23 23:09:11 +00:00
										 |  |  | 	{ "features",	ast_features_reload }, | 
					
						
							| 
									
										
										
										
											2008-03-05 16:23:44 +00:00
										 |  |  | 	{ "dsp",	ast_dsp_reload}, | 
					
						
							| 
									
										
										
										
											2008-03-26 18:39:06 +00:00
										 |  |  | 	{ "udptl",	ast_udptl_reload }, | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | 	{ NULL, 	NULL } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int printdigest(const unsigned char *d) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int x, pos; | 
					
						
							|  |  |  | 	char buf[256]; /* large enough so we don't have to worry */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (pos = 0, x = 0; x < 16; x++) | 
					
						
							|  |  |  | 		pos += sprintf(buf + pos, " %02x", *d++); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-06-24 18:51:41 +00:00
										 |  |  | 	ast_debug(1, "Unexpected signature:%s\n", buf); | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int key_matches(const unsigned char *key1, const unsigned char *key2) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int x; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (x = 0; x < 16; x++) { | 
					
						
							|  |  |  | 		if (key1[x] != key2[x]) | 
					
						
							|  |  |  | 			return 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int verify_key(const unsigned char *key) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct MD5Context c; | 
					
						
							|  |  |  | 	unsigned char digest[16]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	MD5Init(&c); | 
					
						
							|  |  |  | 	MD5Update(&c, key, strlen((char *)key)); | 
					
						
							|  |  |  | 	MD5Final(digest, &c); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (key_matches(expected_key, digest)) | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	printdigest(digest); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return -1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int resource_name_match(const char *name1_in, const char *name2_in) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	char *name1 = (char *) name1_in; | 
					
						
							|  |  |  | 	char *name2 = (char *) name2_in; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* trim off any .so extensions */ | 
					
						
							|  |  |  | 	if (!strcasecmp(name1 + strlen(name1) - 3, ".so")) { | 
					
						
							|  |  |  | 		name1 = ast_strdupa(name1); | 
					
						
							|  |  |  | 		name1[strlen(name1) - 3] = '\0'; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (!strcasecmp(name2 + strlen(name2) - 3, ".so")) { | 
					
						
							|  |  |  | 		name2 = ast_strdupa(name2); | 
					
						
							|  |  |  | 		name2[strlen(name2) - 3] = '\0'; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return strcasecmp(name1, name2); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct ast_module *find_resource(const char *resource, int do_lock) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct ast_module *cur; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (do_lock) | 
					
						
							|  |  |  | 		AST_LIST_LOCK(&module_list); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	AST_LIST_TRAVERSE(&module_list, cur, entry) { | 
					
						
							|  |  |  | 		if (!resource_name_match(resource, cur->resource)) | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (do_lock) | 
					
						
							|  |  |  | 		AST_LIST_UNLOCK(&module_list); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return cur; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-10-22 13:36:13 +00:00
										 |  |  | #ifdef LOADABLE_MODULES
 | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | static void unload_dynamic_module(struct ast_module *mod) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2006-08-26 19:45:16 +00:00
										 |  |  | 	void *lib = mod->lib; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* WARNING: the structure pointed to by mod is going to
 | 
					
						
							|  |  |  | 	   disappear when this operation succeeds, so we can't | 
					
						
							|  |  |  | 	   dereference it */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (lib) | 
					
						
							|  |  |  | 		while (!dlclose(lib)); | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct ast_module *load_dynamic_module(const char *resource_in, unsigned int global_symbols_only) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2008-01-02 09:16:17 +00:00
										 |  |  | 	char fn[PATH_MAX] = ""; | 
					
						
							| 
									
										
										
										
											2007-03-07 20:05:05 +00:00
										 |  |  | 	void *lib = NULL; | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | 	struct ast_module *mod; | 
					
						
							| 
									
										
										
										
											2006-08-21 14:42:03 +00:00
										 |  |  | 	unsigned int wants_global; | 
					
						
							| 
									
										
										
										
											2008-01-02 09:16:17 +00:00
										 |  |  | 	int space;	/* room needed for the descriptor */ | 
					
						
							|  |  |  | 	int missing_so = 0; | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-01-02 09:16:17 +00:00
										 |  |  | 	space = sizeof(*resource_being_loaded) + strlen(resource_in) + 1; | 
					
						
							|  |  |  | 	if (strcasecmp(resource_in + strlen(resource_in) - 3, ".so")) { | 
					
						
							|  |  |  | 		missing_so = 1; | 
					
						
							|  |  |  | 		space += 3;	/* room for the extra ".so" */ | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-01-02 09:16:17 +00:00
										 |  |  | 	snprintf(fn, sizeof(fn), "%s/%s%s", ast_config_AST_MODULE_DIR, resource_in, missing_so ? ".so" : ""); | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-08-21 14:42:03 +00:00
										 |  |  | 	/* make a first load of the module in 'quiet' mode... don't try to resolve
 | 
					
						
							|  |  |  | 	   any symbols, and don't export any symbols. this will allow us to peek into | 
					
						
							|  |  |  | 	   the module's info block (if available) to see what flags it has set */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-01-02 09:16:17 +00:00
										 |  |  | 	resource_being_loaded = ast_calloc(1, space); | 
					
						
							|  |  |  | 	if (!resource_being_loaded) | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | 		return NULL; | 
					
						
							| 
									
										
										
										
											2008-01-02 09:16:17 +00:00
										 |  |  | 	strcpy(resource_being_loaded->resource, resource_in); | 
					
						
							|  |  |  | 	if (missing_so) | 
					
						
							|  |  |  | 		strcat(resource_being_loaded->resource, ".so"); | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-08-21 14:42:03 +00:00
										 |  |  | 	if (!(lib = dlopen(fn, RTLD_LAZY | RTLD_LOCAL))) { | 
					
						
							| 
									
										
										
										
											2006-10-04 00:26:21 +00:00
										 |  |  | 		ast_log(LOG_WARNING, "Error loading module '%s': %s\n", resource_in, dlerror()); | 
					
						
							| 
									
										
										
										
											2007-06-06 21:20:11 +00:00
										 |  |  | 		ast_free(resource_being_loaded); | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | 		return NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* the dlopen() succeeded, let's find out if the module
 | 
					
						
							|  |  |  | 	   registered itself */ | 
					
						
							|  |  |  | 	/* note that this will only work properly as long as
 | 
					
						
							|  |  |  | 	   ast_module_register() (which is called by the module's | 
					
						
							|  |  |  | 	   constructor) places the new module at the tail of the | 
					
						
							|  |  |  | 	   module_list | 
					
						
							|  |  |  | 	*/ | 
					
						
							|  |  |  | 	if (resource_being_loaded != (mod = AST_LIST_LAST(&module_list))) { | 
					
						
							| 
									
										
										
										
											2006-10-04 00:26:21 +00:00
										 |  |  | 		ast_log(LOG_WARNING, "Module '%s' did not register itself during load\n", resource_in); | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | 		/* no, it did not, so close it and return */ | 
					
						
							| 
									
										
										
										
											2006-08-23 19:28:13 +00:00
										 |  |  | 		while (!dlclose(lib)); | 
					
						
							| 
									
										
										
										
											2006-08-21 14:42:03 +00:00
										 |  |  | 		/* note that the module's destructor will call ast_module_unregister(),
 | 
					
						
							|  |  |  | 		   which will free the structure we allocated in resource_being_loaded */ | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | 		return NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-08-21 14:42:03 +00:00
										 |  |  | 	wants_global = ast_test_flag(mod->info, AST_MODFLAG_GLOBAL_SYMBOLS); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | 	/* if we are being asked only to load modules that provide global symbols,
 | 
					
						
							|  |  |  | 	   and this one does not, then close it and return */ | 
					
						
							| 
									
										
										
										
											2006-08-23 19:28:13 +00:00
										 |  |  | 	if (global_symbols_only && !wants_global) { | 
					
						
							|  |  |  | 		while (!dlclose(lib)); | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* if the system supports RTLD_NOLOAD, we can just 'promote' the flags
 | 
					
						
							|  |  |  | 	   on the already-opened library to what we want... if not, we have to | 
					
						
							|  |  |  | 	   close it and start over | 
					
						
							|  |  |  | 	*/ | 
					
						
							| 
									
										
										
										
											2007-10-22 14:56:05 +00:00
										 |  |  | #if defined(HAVE_RTLD_NOLOAD) && !defined(__Darwin__)
 | 
					
						
							| 
									
										
										
										
											2006-08-25 16:14:00 +00:00
										 |  |  | 	if (!dlopen(fn, RTLD_NOLOAD | (wants_global ? RTLD_LAZY | RTLD_GLOBAL : RTLD_NOW | RTLD_LOCAL))) { | 
					
						
							| 
									
										
										
										
											2006-10-21 18:52:33 +00:00
										 |  |  | 		ast_log(LOG_WARNING, "Unable to promote flags on module '%s': %s\n", resource_in, dlerror()); | 
					
						
							| 
									
										
										
										
											2006-08-25 16:14:00 +00:00
										 |  |  | 		while (!dlclose(lib)); | 
					
						
							| 
									
										
										
										
											2007-06-06 21:20:11 +00:00
										 |  |  | 		ast_free(resource_being_loaded); | 
					
						
							| 
									
										
										
										
											2006-08-25 16:14:00 +00:00
										 |  |  | 		return NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | #else
 | 
					
						
							| 
									
										
										
										
											2006-08-23 19:28:13 +00:00
										 |  |  | 	while (!dlclose(lib)); | 
					
						
							|  |  |  | 	resource_being_loaded = NULL; | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-08-21 14:42:03 +00:00
										 |  |  | 	/* start the load process again */ | 
					
						
							| 
									
										
										
										
											2008-01-02 09:16:17 +00:00
										 |  |  | 	resource_being_loaded = ast_calloc(1, space); | 
					
						
							|  |  |  | 	if (!resource_being_loaded) | 
					
						
							| 
									
										
										
										
											2006-08-21 14:42:03 +00:00
										 |  |  | 		return NULL; | 
					
						
							| 
									
										
										
										
											2008-01-02 09:16:17 +00:00
										 |  |  | 	strcpy(resource_being_loaded->resource, resource_in); | 
					
						
							|  |  |  | 	if (missing_so) | 
					
						
							|  |  |  | 		strcat(resource_being_loaded->resource, ".so"); | 
					
						
							| 
									
										
										
										
											2006-08-21 14:42:03 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (!(lib = dlopen(fn, wants_global ? RTLD_LAZY | RTLD_GLOBAL : RTLD_NOW | RTLD_LOCAL))) { | 
					
						
							| 
									
										
										
										
											2006-10-04 00:26:21 +00:00
										 |  |  | 		ast_log(LOG_WARNING, "Error loading module '%s': %s\n", resource_in, dlerror()); | 
					
						
							| 
									
										
										
										
											2007-06-06 21:20:11 +00:00
										 |  |  | 		ast_free(resource_being_loaded); | 
					
						
							| 
									
										
										
										
											2006-08-21 14:42:03 +00:00
										 |  |  | 		return NULL; | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-08-21 14:42:03 +00:00
										 |  |  | 	/* since the module was successfully opened, and it registered itself
 | 
					
						
							|  |  |  | 	   the previous time we did that, we're going to assume it worked this | 
					
						
							|  |  |  | 	   time too :) */ | 
					
						
							| 
									
										
										
										
											2006-08-25 16:14:00 +00:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2006-08-23 19:28:13 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-08-21 14:42:03 +00:00
										 |  |  | 	AST_LIST_LAST(&module_list)->lib = lib; | 
					
						
							|  |  |  | 	resource_being_loaded = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return AST_LIST_LAST(&module_list); | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | } | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-06-05 15:54:36 +00:00
										 |  |  | void ast_module_shutdown(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct ast_module *mod; | 
					
						
							|  |  |  | 	AST_LIST_HEAD_NOLOCK_STATIC(local_module_list, ast_module); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* We have to call the unload() callbacks in reverse order that the modules
 | 
					
						
							|  |  |  | 	 * exist in the module list so it is the reverse order of how they were | 
					
						
							|  |  |  | 	 * loaded. */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	AST_LIST_LOCK(&module_list); | 
					
						
							|  |  |  | 	while ((mod = AST_LIST_REMOVE_HEAD(&module_list, entry))) | 
					
						
							|  |  |  | 		AST_LIST_INSERT_HEAD(&local_module_list, mod, entry); | 
					
						
							|  |  |  | 	AST_LIST_UNLOCK(&module_list); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	while ((mod = AST_LIST_REMOVE_HEAD(&local_module_list, entry))) { | 
					
						
							|  |  |  | 		if (mod->info->unload) | 
					
						
							|  |  |  | 			mod->info->unload(); | 
					
						
							|  |  |  | 		/* Since this should only be called when shutting down "gracefully",
 | 
					
						
							|  |  |  | 		 * all channels should be down before we get to this point, meaning | 
					
						
							|  |  |  | 		 * there will be no module users left. */ | 
					
						
							|  |  |  | 		AST_LIST_HEAD_DESTROY(&mod->users); | 
					
						
							|  |  |  | 		free(mod); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | int ast_unload_resource(const char *resource_name, enum ast_module_unload_mode force) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct ast_module *mod; | 
					
						
							|  |  |  | 	int res = -1; | 
					
						
							|  |  |  | 	int error = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	AST_LIST_LOCK(&module_list); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-08-22 23:06:13 +00:00
										 |  |  | 	if (!(mod = find_resource(resource_name, 0))) { | 
					
						
							|  |  |  | 		AST_LIST_UNLOCK(&module_list); | 
					
						
							| 
									
										
										
										
											2008-02-19 21:54:09 +00:00
										 |  |  | 		ast_log(LOG_WARNING, "Unload failed, '%s' could not be found\n", resource_name); | 
					
						
							| 
									
										
										
										
											2006-08-22 23:06:13 +00:00
										 |  |  | 		return 0; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-05-03 16:43:49 +00:00
										 |  |  | 	if (!(mod->flags.running || mod->flags.declined)) | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | 		error = 1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!error && (mod->usecount > 0)) { | 
					
						
							| 
									
										
										
										
											2006-09-15 05:00:27 +00:00
										 |  |  | 		if (force) | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | 			ast_log(LOG_WARNING, "Warning:  Forcing removal of module '%s' with use count %d\n", | 
					
						
							|  |  |  | 				resource_name, mod->usecount); | 
					
						
							|  |  |  | 		else { | 
					
						
							|  |  |  | 			ast_log(LOG_WARNING, "Soft unload failed, '%s' has use count %d\n", resource_name, | 
					
						
							|  |  |  | 				mod->usecount); | 
					
						
							|  |  |  | 			error = 1; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!error) { | 
					
						
							|  |  |  | 		__ast_module_user_hangup_all(mod); | 
					
						
							|  |  |  | 		res = mod->info->unload(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (res) { | 
					
						
							|  |  |  | 			ast_log(LOG_WARNING, "Firm unload failed for %s\n", resource_name); | 
					
						
							|  |  |  | 			if (force <= AST_FORCE_FIRM) | 
					
						
							|  |  |  | 				error = 1; | 
					
						
							|  |  |  | 			else | 
					
						
							|  |  |  | 				ast_log(LOG_WARNING, "** Dangerous **: Unloading resource anyway, at user request\n"); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!error) | 
					
						
							| 
									
										
										
										
											2007-05-03 16:43:49 +00:00
										 |  |  | 		mod->flags.running = mod->flags.declined = 0; | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	AST_LIST_UNLOCK(&module_list); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-01-02 09:16:17 +00:00
										 |  |  | 	if (!error && !mod->lib && mod->info && mod->info->restore_globals) | 
					
						
							| 
									
										
										
										
											2007-03-19 22:32:40 +00:00
										 |  |  | 		mod->info->restore_globals(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-10-22 13:36:13 +00:00
										 |  |  | #ifdef LOADABLE_MODULES
 | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | 	if (!error) | 
					
						
							|  |  |  | 		unload_dynamic_module(mod); | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!error) | 
					
						
							|  |  |  | 		ast_update_use_count(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return res; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | char *ast_module_helper(const char *line, const char *word, int pos, int state, int rpos, int needsreload) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct ast_module *cur; | 
					
						
							|  |  |  | 	int i, which=0, l = strlen(word); | 
					
						
							|  |  |  | 	char *ret = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (pos != rpos) | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	AST_LIST_LOCK(&module_list); | 
					
						
							|  |  |  | 	AST_LIST_TRAVERSE(&module_list, cur, entry) { | 
					
						
							|  |  |  | 		if (!strncasecmp(word, cur->resource, l) && | 
					
						
							|  |  |  | 		    (cur->info->reload || !needsreload) && | 
					
						
							|  |  |  | 		    ++which > state) { | 
					
						
							| 
									
										
										
										
											2007-06-14 23:01:01 +00:00
										 |  |  | 			ret = ast_strdup(cur->resource); | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	AST_LIST_UNLOCK(&module_list); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!ret) { | 
					
						
							|  |  |  | 		for (i=0; !ret && reload_classes[i].name; i++) { | 
					
						
							|  |  |  | 			if (!strncasecmp(word, reload_classes[i].name, l) && ++which > state) | 
					
						
							| 
									
										
										
										
											2007-06-14 23:01:01 +00:00
										 |  |  | 				ret = ast_strdup(reload_classes[i].name); | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int ast_module_reload(const char *name) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct ast_module *cur; | 
					
						
							|  |  |  | 	int res = 0; /* return value. 0 = not found, others, see below */ | 
					
						
							|  |  |  | 	int i; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (ast_mutex_trylock(&reloadlock)) { | 
					
						
							|  |  |  | 		ast_verbose("The previous reload command didn't finish yet\n"); | 
					
						
							|  |  |  | 		return -1;	/* reload already in progress */ | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2007-07-18 19:47:20 +00:00
										 |  |  | 	ast_lastreloadtime = ast_tvnow(); | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* Call "predefined" reload here first */ | 
					
						
							|  |  |  | 	for (i = 0; reload_classes[i].name; i++) { | 
					
						
							|  |  |  | 		if (!name || !strcasecmp(name, reload_classes[i].name)) { | 
					
						
							|  |  |  | 			reload_classes[i].reload_fn();	/* XXX should check error ? */ | 
					
						
							|  |  |  | 			res = 2;	/* found and reloaded */ | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-02-08 13:50:33 +00:00
										 |  |  | 	if (name && res) { | 
					
						
							|  |  |  | 		ast_mutex_unlock(&reloadlock); | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | 		return res; | 
					
						
							| 
									
										
										
										
											2007-02-08 13:50:33 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	AST_LIST_LOCK(&module_list); | 
					
						
							|  |  |  | 	AST_LIST_TRAVERSE(&module_list, cur, entry) { | 
					
						
							|  |  |  | 		const struct ast_module_info *info = cur->info; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (name && resource_name_match(name, cur->resource)) | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-15 19:50:47 +00:00
										 |  |  | 		if (!cur->flags.running || cur->flags.declined) { | 
					
						
							|  |  |  | 			if (!name) | 
					
						
							|  |  |  | 				continue; | 
					
						
							|  |  |  | 			ast_log(LOG_NOTICE, "The module '%s' was not properly initialized.  " | 
					
						
							|  |  |  | 				"Before reloading the module, you must run \"module load %s\" " | 
					
						
							|  |  |  | 				"and fix whatever is preventing the module from being initialized.\n", | 
					
						
							|  |  |  | 				name, name); | 
					
						
							|  |  |  | 			res = 2; /* Don't report that the module was not found */ | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		if (!info->reload) {	/* cannot be reloaded */ | 
					
						
							|  |  |  | 			if (res < 1)	/* store result if possible */ | 
					
						
							|  |  |  | 				res = 1;	/* 1 = no reload() method */ | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		res = 2; | 
					
						
							| 
									
										
										
										
											2007-07-26 15:49:18 +00:00
										 |  |  | 		ast_verb(3, "Reloading module '%s' (%s)\n", cur->resource, info->description); | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | 		info->reload(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	AST_LIST_UNLOCK(&module_list); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ast_mutex_unlock(&reloadlock); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return res; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static unsigned int inspect_module(const struct ast_module *mod) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (!mod->info->description) { | 
					
						
							|  |  |  | 		ast_log(LOG_WARNING, "Module '%s' does not provide a description.\n", mod->resource); | 
					
						
							|  |  |  | 		return 1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!mod->info->key) { | 
					
						
							|  |  |  | 		ast_log(LOG_WARNING, "Module '%s' does not provide a license key.\n", mod->resource); | 
					
						
							|  |  |  | 		return 1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (verify_key((unsigned char *) mod->info->key)) { | 
					
						
							|  |  |  | 		ast_log(LOG_WARNING, "Module '%s' did not provide a valid license key.\n", mod->resource); | 
					
						
							|  |  |  | 		return 1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-20 19:28:10 +00:00
										 |  |  | 	if (!ast_strlen_zero(mod->info->buildopt_sum) && | 
					
						
							|  |  |  | 	    strcmp(buildopt_sum, mod->info->buildopt_sum)) { | 
					
						
							| 
									
										
										
										
											2007-11-16 16:56:59 +00:00
										 |  |  | 		ast_log(LOG_WARNING, "Module '%s' was not compiled with the same compile-time options as this version of Asterisk.\n", mod->resource); | 
					
						
							|  |  |  | 		ast_log(LOG_WARNING, "Module '%s' will not be initialized as it may cause instability.\n", mod->resource); | 
					
						
							|  |  |  | 		return 1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static enum ast_module_load_result load_resource(const char *resource_name, unsigned int global_symbols_only) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct ast_module *mod; | 
					
						
							|  |  |  | 	enum ast_module_load_result res = AST_MODULE_LOAD_SUCCESS; | 
					
						
							|  |  |  | 	char tmp[256]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if ((mod = find_resource(resource_name, 0))) { | 
					
						
							| 
									
										
										
										
											2007-05-03 16:43:49 +00:00
										 |  |  | 		if (mod->flags.running) { | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | 			ast_log(LOG_WARNING, "Module '%s' already exists.\n", resource_name); | 
					
						
							|  |  |  | 			return AST_MODULE_LOAD_DECLINE; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if (global_symbols_only && !ast_test_flag(mod->info, AST_MODFLAG_GLOBAL_SYMBOLS)) | 
					
						
							|  |  |  | 			return AST_MODULE_LOAD_SKIP; | 
					
						
							|  |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2007-10-22 13:36:13 +00:00
										 |  |  | #ifdef LOADABLE_MODULES
 | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | 		if (!(mod = load_dynamic_module(resource_name, global_symbols_only))) { | 
					
						
							|  |  |  | 			/* don't generate a warning message during load_modules() */ | 
					
						
							|  |  |  | 			if (!global_symbols_only) { | 
					
						
							|  |  |  | 				ast_log(LOG_WARNING, "Module '%s' could not be loaded.\n", resource_name); | 
					
						
							|  |  |  | 				return AST_MODULE_LOAD_DECLINE; | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				return AST_MODULE_LOAD_SKIP; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2006-08-22 21:57:16 +00:00
										 |  |  | #else
 | 
					
						
							| 
									
										
										
										
											2006-08-22 23:55:16 +00:00
										 |  |  | 		ast_log(LOG_WARNING, "Module '%s' could not be loaded.\n", resource_name); | 
					
						
							| 
									
										
										
										
											2006-08-22 21:57:16 +00:00
										 |  |  | 		return AST_MODULE_LOAD_DECLINE; | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | #endif
 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (inspect_module(mod)) { | 
					
						
							|  |  |  | 		ast_log(LOG_WARNING, "Module '%s' could not be loaded.\n", resource_name); | 
					
						
							| 
									
										
										
										
											2007-10-22 13:36:13 +00:00
										 |  |  | #ifdef LOADABLE_MODULES
 | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | 		unload_dynamic_module(mod); | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 		return AST_MODULE_LOAD_DECLINE; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-02-22 02:36:00 +00:00
										 |  |  | 	if (!mod->lib && mod->info->backup_globals()) { | 
					
						
							|  |  |  | 		ast_log(LOG_WARNING, "Module '%s' was unable to backup its global data.\n", resource_name); | 
					
						
							|  |  |  | 		return AST_MODULE_LOAD_DECLINE; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-05-03 16:43:49 +00:00
										 |  |  | 	mod->flags.declined = 0; | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (mod->info->load) | 
					
						
							|  |  |  | 		res = mod->info->load(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	switch (res) { | 
					
						
							|  |  |  | 	case AST_MODULE_LOAD_SUCCESS: | 
					
						
							|  |  |  | 		if (!ast_fully_booted) { | 
					
						
							| 
									
										
										
										
											2007-07-26 15:49:18 +00:00
										 |  |  | 			ast_verb(1, "%s => (%s)\n", resource_name, term_color(tmp, mod->info->description, COLOR_BROWN, COLOR_BLACK, sizeof(tmp))); | 
					
						
							| 
									
										
										
										
											2008-03-12 05:46:39 +00:00
										 |  |  | 			if (ast_opt_console && !option_verbose) | 
					
						
							|  |  |  | 				ast_verbose( "."); | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2007-07-26 15:49:18 +00:00
										 |  |  | 			ast_verb(1, "Loaded %s => (%s)\n", resource_name, mod->info->description); | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-05-03 16:43:49 +00:00
										 |  |  | 		mod->flags.running = 1; | 
					
						
							| 
									
										
										
										
											2006-09-15 05:00:27 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | 		ast_update_use_count(); | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case AST_MODULE_LOAD_DECLINE: | 
					
						
							| 
									
										
										
										
											2007-05-03 16:43:49 +00:00
										 |  |  | 		mod->flags.declined = 1; | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | 		break; | 
					
						
							|  |  |  | 	case AST_MODULE_LOAD_FAILURE: | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case AST_MODULE_LOAD_SKIP: | 
					
						
							|  |  |  | 		/* modules should never return this value */ | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return res; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int ast_load_resource(const char *resource_name) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2008-06-05 15:58:11 +00:00
										 |  |  | 	int res; | 
					
						
							| 
									
										
										
										
											2008-03-04 23:04:29 +00:00
										 |  |  | 	AST_LIST_LOCK(&module_list); | 
					
						
							| 
									
										
										
										
											2008-06-05 15:58:11 +00:00
										 |  |  | 	res = load_resource(resource_name, 0); | 
					
						
							| 
									
										
										
										
											2008-03-04 23:04:29 +00:00
										 |  |  | 	AST_LIST_UNLOCK(&module_list); | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-06-05 15:58:11 +00:00
										 |  |  | 	return res; | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct load_order_entry { | 
					
						
							|  |  |  | 	char *resource; | 
					
						
							|  |  |  | 	AST_LIST_ENTRY(load_order_entry) entry; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | AST_LIST_HEAD_NOLOCK(load_order, load_order_entry); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct load_order_entry *add_to_load_order(const char *resource, struct load_order *load_order) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct load_order_entry *order; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	AST_LIST_TRAVERSE(load_order, order, entry) { | 
					
						
							|  |  |  | 		if (!resource_name_match(order->resource, resource)) | 
					
						
							|  |  |  | 			return NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!(order = ast_calloc(1, sizeof(*order)))) | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	order->resource = ast_strdup(resource); | 
					
						
							|  |  |  | 	AST_LIST_INSERT_TAIL(load_order, order, entry); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return order; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2008-06-12 17:27:55 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-08-21 22:23:26 +00:00
										 |  |  | int load_modules(unsigned int preload_only) | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct ast_config *cfg; | 
					
						
							|  |  |  | 	struct ast_module *mod; | 
					
						
							|  |  |  | 	struct load_order_entry *order; | 
					
						
							|  |  |  | 	struct ast_variable *v; | 
					
						
							|  |  |  | 	unsigned int load_count; | 
					
						
							|  |  |  | 	struct load_order load_order; | 
					
						
							|  |  |  | 	int res = 0; | 
					
						
							| 
									
										
										
										
											2007-08-16 21:09:46 +00:00
										 |  |  | 	struct ast_flags config_flags = { 0 }; | 
					
						
							| 
									
										
										
										
											2007-11-27 21:04:29 +00:00
										 |  |  | 	int modulecount = 0; | 
					
						
							| 
									
										
										
										
											2008-06-12 17:27:55 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-10-22 13:36:13 +00:00
										 |  |  | #ifdef LOADABLE_MODULES
 | 
					
						
							| 
									
										
										
										
											2006-08-21 03:06:41 +00:00
										 |  |  | 	struct dirent *dirent; | 
					
						
							|  |  |  | 	DIR *dir; | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* all embedded modules have registered themselves by now */ | 
					
						
							|  |  |  | 	embedding = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-07-26 15:49:18 +00:00
										 |  |  | 	ast_verb(1, "Asterisk Dynamic Loader Starting:\n"); | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-05-03 16:43:49 +00:00
										 |  |  | 	AST_LIST_HEAD_INIT_NOLOCK(&load_order); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	AST_LIST_LOCK(&module_list); | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-06 17:05:13 +00:00
										 |  |  | 	if (embedded_module_list.first) { | 
					
						
							|  |  |  | 		module_list.first = embedded_module_list.first; | 
					
						
							|  |  |  | 		module_list.last = embedded_module_list.last; | 
					
						
							|  |  |  | 		embedded_module_list.first = NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-03-26 18:39:06 +00:00
										 |  |  | 	if (!(cfg = ast_config_load2(AST_MODULE_CONFIG, "" /* core, can't reload */, config_flags))) { | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | 		ast_log(LOG_WARNING, "No '%s' found, no modules will be loaded.\n", AST_MODULE_CONFIG); | 
					
						
							| 
									
										
										
										
											2007-05-03 16:43:49 +00:00
										 |  |  | 		goto done; | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-08-22 23:06:13 +00:00
										 |  |  | 	/* first, find all the modules we have been explicitly requested to load */ | 
					
						
							|  |  |  | 	for (v = ast_variable_browse(cfg, "modules"); v; v = v->next) { | 
					
						
							| 
									
										
										
										
											2008-06-12 17:27:55 +00:00
										 |  |  | 		if (!strcasecmp(v->name, preload_only ? "preload" : "load")) { | 
					
						
							| 
									
										
										
										
											2008-07-28 16:42:00 +00:00
										 |  |  | 			add_to_load_order(v->value, &load_order); | 
					
						
							| 
									
										
										
										
											2008-06-12 17:27:55 +00:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* check if 'autoload' is on */ | 
					
						
							| 
									
										
										
										
											2006-08-21 22:23:26 +00:00
										 |  |  | 	if (!preload_only && ast_true(ast_variable_retrieve(cfg, "modules", "autoload"))) { | 
					
						
							| 
									
										
										
										
											2007-05-03 16:43:49 +00:00
										 |  |  | 		/* if so, first add all the embedded modules that are not already running to the load order */ | 
					
						
							|  |  |  | 		AST_LIST_TRAVERSE(&module_list, mod, entry) { | 
					
						
							|  |  |  | 			/* if it's not embedded, skip it */ | 
					
						
							|  |  |  | 			if (mod->lib) | 
					
						
							|  |  |  | 				continue; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if (mod->flags.running) | 
					
						
							|  |  |  | 				continue; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | 			order = add_to_load_order(mod->resource, &load_order); | 
					
						
							| 
									
										
										
										
											2007-05-03 16:43:49 +00:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-10-22 13:36:13 +00:00
										 |  |  | #ifdef LOADABLE_MODULES
 | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | 		/* if we are allowed to load dynamic modules, scan the directory for
 | 
					
						
							|  |  |  | 		   for all available modules and add them as well */ | 
					
						
							|  |  |  | 		if ((dir  = opendir(ast_config_AST_MODULE_DIR))) { | 
					
						
							|  |  |  | 			while ((dirent = readdir(dir))) { | 
					
						
							|  |  |  | 				int ld = strlen(dirent->d_name); | 
					
						
							| 
									
										
										
										
											2006-09-15 05:00:27 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | 				/* Must end in .so to load it.  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				if (ld < 4) | 
					
						
							|  |  |  | 					continue; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				if (strcasecmp(dirent->d_name + ld - 3, ".so")) | 
					
						
							| 
									
										
										
										
											2007-05-03 16:43:49 +00:00
										 |  |  | 					continue; | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-05-03 16:43:49 +00:00
										 |  |  | 				/* if there is already a module by this name in the module_list,
 | 
					
						
							|  |  |  | 				   skip this file */ | 
					
						
							|  |  |  | 				if (find_resource(dirent->d_name, 0)) | 
					
						
							|  |  |  | 					continue; | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-05-03 16:43:49 +00:00
										 |  |  | 				add_to_load_order(dirent->d_name, &load_order); | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			closedir(dir); | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			if (!ast_opt_quiet) | 
					
						
							|  |  |  | 				ast_log(LOG_WARNING, "Unable to open modules directory '%s'.\n", | 
					
						
							|  |  |  | 					ast_config_AST_MODULE_DIR); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* now scan the config for any modules we are prohibited from loading and
 | 
					
						
							|  |  |  | 	   remove them from the load order */ | 
					
						
							|  |  |  | 	for (v = ast_variable_browse(cfg, "modules"); v; v = v->next) { | 
					
						
							|  |  |  | 		if (strcasecmp(v->name, "noload")) | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		AST_LIST_TRAVERSE_SAFE_BEGIN(&load_order, order, entry) { | 
					
						
							| 
									
										
										
										
											2008-07-28 16:42:00 +00:00
										 |  |  | 			if (!resource_name_match(order->resource, v->value)) { | 
					
						
							| 
									
										
										
										
											2007-11-08 05:28:47 +00:00
										 |  |  | 				AST_LIST_REMOVE_CURRENT(entry); | 
					
						
							| 
									
										
										
										
											2007-06-06 21:20:11 +00:00
										 |  |  | 				ast_free(order->resource); | 
					
						
							|  |  |  | 				ast_free(order); | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		AST_LIST_TRAVERSE_SAFE_END; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* we are done with the config now, all the information we need is in the
 | 
					
						
							|  |  |  | 	   load_order list */ | 
					
						
							|  |  |  | 	ast_config_destroy(cfg); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	load_count = 0; | 
					
						
							|  |  |  | 	AST_LIST_TRAVERSE(&load_order, order, entry) | 
					
						
							|  |  |  | 		load_count++; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-08-22 23:06:13 +00:00
										 |  |  | 	if (load_count) | 
					
						
							|  |  |  | 		ast_log(LOG_NOTICE, "%d modules will be loaded.\n", load_count); | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* first, load only modules that provide global symbols */ | 
					
						
							|  |  |  | 	AST_LIST_TRAVERSE_SAFE_BEGIN(&load_order, order, entry) { | 
					
						
							|  |  |  | 		switch (load_resource(order->resource, 1)) { | 
					
						
							|  |  |  | 		case AST_MODULE_LOAD_SUCCESS: | 
					
						
							| 
									
										
										
										
											2007-11-27 21:04:29 +00:00
										 |  |  | 			modulecount++; | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | 		case AST_MODULE_LOAD_DECLINE: | 
					
						
							| 
									
										
										
										
											2007-11-08 05:28:47 +00:00
										 |  |  | 			AST_LIST_REMOVE_CURRENT(entry); | 
					
						
							| 
									
										
										
										
											2007-06-06 21:20:11 +00:00
										 |  |  | 			ast_free(order->resource); | 
					
						
							|  |  |  | 			ast_free(order); | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | 			break; | 
					
						
							|  |  |  | 		case AST_MODULE_LOAD_FAILURE: | 
					
						
							|  |  |  | 			res = -1; | 
					
						
							|  |  |  | 			goto done; | 
					
						
							|  |  |  | 		case AST_MODULE_LOAD_SKIP: | 
					
						
							|  |  |  | 			/* try again later */ | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	AST_LIST_TRAVERSE_SAFE_END; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* now load everything else */ | 
					
						
							|  |  |  | 	AST_LIST_TRAVERSE_SAFE_BEGIN(&load_order, order, entry) { | 
					
						
							|  |  |  | 		switch (load_resource(order->resource, 0)) { | 
					
						
							|  |  |  | 		case AST_MODULE_LOAD_SUCCESS: | 
					
						
							| 
									
										
										
										
											2007-11-27 21:04:29 +00:00
										 |  |  | 			modulecount++; | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | 		case AST_MODULE_LOAD_DECLINE: | 
					
						
							| 
									
										
										
										
											2007-11-08 05:28:47 +00:00
										 |  |  | 			AST_LIST_REMOVE_CURRENT(entry); | 
					
						
							| 
									
										
										
										
											2007-06-06 21:20:11 +00:00
										 |  |  | 			ast_free(order->resource); | 
					
						
							|  |  |  | 			ast_free(order); | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | 			break; | 
					
						
							|  |  |  | 		case AST_MODULE_LOAD_FAILURE: | 
					
						
							|  |  |  | 			res = -1; | 
					
						
							|  |  |  | 			goto done; | 
					
						
							|  |  |  | 		case AST_MODULE_LOAD_SKIP: | 
					
						
							|  |  |  | 			/* should not happen */ | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	AST_LIST_TRAVERSE_SAFE_END; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | done: | 
					
						
							|  |  |  | 	while ((order = AST_LIST_REMOVE_HEAD(&load_order, entry))) { | 
					
						
							| 
									
										
										
										
											2007-06-06 21:20:11 +00:00
										 |  |  | 		ast_free(order->resource); | 
					
						
							|  |  |  | 		ast_free(order); | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-05-03 16:43:49 +00:00
										 |  |  | 	AST_LIST_UNLOCK(&module_list); | 
					
						
							| 
									
										
										
										
											2008-01-07 15:52:55 +00:00
										 |  |  | 	 | 
					
						
							| 
									
										
										
										
											2007-11-27 21:04:29 +00:00
										 |  |  | 	/* Tell manager clients that are aggressive at logging in that we're done
 | 
					
						
							|  |  |  | 	   loading modules. If there's a DNS problem in chan_sip, we might not | 
					
						
							|  |  |  | 	   even reach this */ | 
					
						
							|  |  |  | 	manager_event(EVENT_FLAG_SYSTEM, "ModuleLoadReport", "ModuleLoadStatus: Done\r\nModuleSelection: %s\r\nModuleCount: %d\r\n", preload_only ? "Preload" : "All", modulecount); | 
					
						
							| 
									
										
										
										
											2008-01-07 15:52:55 +00:00
										 |  |  | 	 | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | 	return res; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ast_update_use_count(void) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2006-09-15 05:00:27 +00:00
										 |  |  | 	/* Notify any module monitors that the use count for a
 | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | 	   resource has changed */ | 
					
						
							|  |  |  | 	struct loadupdate *m; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-27 17:12:08 +00:00
										 |  |  | 	AST_LIST_LOCK(&updaters); | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | 	AST_LIST_TRAVERSE(&updaters, m, entry) | 
					
						
							|  |  |  | 		m->updater(); | 
					
						
							| 
									
										
										
										
											2008-02-27 17:12:08 +00:00
										 |  |  | 	AST_LIST_UNLOCK(&updaters); | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int ast_update_module_list(int (*modentry)(const char *module, const char *description, int usecnt, const char *like), | 
					
						
							|  |  |  | 			   const char *like) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct ast_module *cur; | 
					
						
							|  |  |  | 	int unlock = -1; | 
					
						
							|  |  |  | 	int total_mod_loaded = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (AST_LIST_TRYLOCK(&module_list)) | 
					
						
							|  |  |  | 		unlock = 0; | 
					
						
							| 
									
										
										
										
											2007-11-06 17:05:13 +00:00
										 |  |  |   | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | 	AST_LIST_TRAVERSE(&module_list, cur, entry) { | 
					
						
							|  |  |  | 		total_mod_loaded += modentry(cur->resource, cur->info->description, cur->usecount, like); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (unlock) | 
					
						
							|  |  |  | 		AST_LIST_UNLOCK(&module_list); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return total_mod_loaded; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-10-31 08:08:56 +00:00
										 |  |  | /*! \brief Check if module exists */ | 
					
						
							| 
									
										
										
										
											2007-05-07 19:03:53 +00:00
										 |  |  | int ast_module_check(const char *name) | 
					
						
							| 
									
										
										
										
											2006-10-30 21:48:41 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct ast_module *cur; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (ast_strlen_zero(name)) | 
					
						
							|  |  |  | 		return 0;       /* FALSE */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-10-31 08:08:56 +00:00
										 |  |  | 	cur = find_resource(name, 1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return (cur != NULL); | 
					
						
							| 
									
										
										
										
											2006-10-30 21:48:41 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-09-15 05:00:27 +00:00
										 |  |  | int ast_loader_register(int (*v)(void)) | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2006-09-15 05:00:27 +00:00
										 |  |  | 	struct loadupdate *tmp; | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (!(tmp = ast_malloc(sizeof(*tmp)))) | 
					
						
							|  |  |  | 		return -1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	tmp->updater = v; | 
					
						
							| 
									
										
										
										
											2008-02-27 17:12:08 +00:00
										 |  |  | 	AST_LIST_LOCK(&updaters); | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | 	AST_LIST_INSERT_HEAD(&updaters, tmp, entry); | 
					
						
							| 
									
										
										
										
											2008-02-27 17:12:08 +00:00
										 |  |  | 	AST_LIST_UNLOCK(&updaters); | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int ast_loader_unregister(int (*v)(void)) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct loadupdate *cur; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-27 17:12:08 +00:00
										 |  |  | 	AST_LIST_LOCK(&updaters); | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | 	AST_LIST_TRAVERSE_SAFE_BEGIN(&updaters, cur, entry) { | 
					
						
							|  |  |  | 		if (cur->updater == v)	{ | 
					
						
							| 
									
										
										
										
											2007-11-08 05:28:47 +00:00
										 |  |  | 			AST_LIST_REMOVE_CURRENT(entry); | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	AST_LIST_TRAVERSE_SAFE_END; | 
					
						
							| 
									
										
										
										
											2008-02-27 17:12:08 +00:00
										 |  |  | 	AST_LIST_UNLOCK(&updaters); | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return cur ? 0 : -1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct ast_module *ast_module_ref(struct ast_module *mod) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	ast_atomic_fetchadd_int(&mod->usecount, +1); | 
					
						
							|  |  |  | 	ast_update_use_count(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return mod; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ast_module_unref(struct ast_module *mod) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	ast_atomic_fetchadd_int(&mod->usecount, -1); | 
					
						
							|  |  |  | 	ast_update_use_count(); | 
					
						
							|  |  |  | } |