2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 1999 - 2006, Digium, Inc.
6 * Mark Spencer <markster@digium.com>
7 * Kevin P. Fleming <kpfleming@digium.com>
8 * Luigi Rizzo <rizzo@icir.org>
10 * See http://www.asterisk.org for more information about
11 * the Asterisk project. Please do not directly contact
12 * any of the maintainers of this project for assistance;
13 * the project provides a web site, mailing lists and IRC
14 * channels for your use.
16 * This program is free software, distributed under the terms of
17 * the GNU General Public License Version 2. See the LICENSE file
18 * at the top of the source tree.
23 * \brief Module Loader
24 * \author Mark Spencer <markster@digium.com>
25 * \author Kevin P. Fleming <kpfleming@digium.com>
26 * \author Luigi Rizzo <rizzo@icir.org>
32 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
34 #include "asterisk/_private.h"
35 #include "asterisk/paths.h" /* use ast_config_AST_MODULE_DIR */
38 #include "asterisk/linkedlists.h"
39 #include "asterisk/module.h"
40 #include "asterisk/config.h"
41 #include "asterisk/channel.h"
42 #include "asterisk/term.h"
43 #include "asterisk/manager.h"
44 #include "asterisk/cdr.h"
45 #include "asterisk/enum.h"
46 #include "asterisk/rtp.h"
47 #include "asterisk/http.h"
48 #include "asterisk/lock.h"
49 #include "asterisk/features.h"
52 #include "asterisk/dlfcn-compat.h"
57 #include "asterisk/md5.h"
58 #include "asterisk/utils.h"
68 struct ast_module_user {
69 struct ast_channel *chan;
70 AST_LIST_ENTRY(ast_module_user) entry;
73 AST_LIST_HEAD(module_user_list, ast_module_user);
75 static unsigned char expected_key[] =
76 { 0x87, 0x76, 0x79, 0x35, 0x23, 0xea, 0x3a, 0xd3,
77 0x25, 0x2a, 0xbb, 0x35, 0x87, 0xe4, 0x22, 0x24 };
79 static char buildopt_sum[33] = AST_BUILDOPT_SUM;
81 static unsigned int embedding = 1; /* we always start out by registering embedded modules,
82 since they are here before we dlopen() any
86 const struct ast_module_info *info;
87 void *lib; /* the shared lib, or NULL if embedded */
88 int usecount; /* the number of 'users' currently in this module */
89 struct module_user_list users; /* the list of users in the module */
91 unsigned int running:1;
92 unsigned int declined:1;
94 AST_LIST_ENTRY(ast_module) entry;
98 static AST_LIST_HEAD_STATIC(module_list, ast_module);
101 * module_list is cleared by its constructor possibly after
102 * we start accumulating embedded modules, so we need to
103 * use another list (without the lock) to accumulate them.
104 * Then we update the main list when embedding is done.
106 static struct module_list embedded_module_list;
109 int (*updater)(void);
110 AST_LIST_ENTRY(loadupdate) entry;
113 static AST_LIST_HEAD_STATIC(updaters, loadupdate);
115 AST_MUTEX_DEFINE_STATIC(reloadlock);
117 /* when dynamic modules are being loaded, ast_module_register() will
118 need to know what filename the module was loaded from while it
121 struct ast_module *resource_being_loaded;
123 /* XXX: should we check for duplicate resource names here? */
125 void ast_module_register(const struct ast_module_info *info)
127 struct ast_module *mod;
130 if (!(mod = ast_calloc(1, sizeof(*mod) + strlen(info->name) + 1)))
132 strcpy(mod->resource, info->name);
134 mod = resource_being_loaded;
138 AST_LIST_HEAD_INIT(&mod->users);
140 /* during startup, before the loader has been initialized,
141 there are no threads, so there is no need to take the lock
142 on this list to manipulate it. it is also possible that it
143 might be unsafe to use the list lock at that point... so
144 let's avoid it altogether
147 AST_LIST_INSERT_TAIL(&embedded_module_list, mod, entry);
149 AST_LIST_LOCK(&module_list);
150 /* it is paramount that the new entry be placed at the tail of
151 the list, otherwise the code that uses dlopen() to load
152 dynamic modules won't be able to find out if the module it
153 just opened was registered or failed to load
155 AST_LIST_INSERT_TAIL(&module_list, mod, entry);
156 AST_LIST_UNLOCK(&module_list);
159 /* give the module a copy of its own handle, for later use in registrations and the like */
160 *((struct ast_module **) &(info->self)) = mod;
163 void ast_module_unregister(const struct ast_module_info *info)
165 struct ast_module *mod = NULL;
167 /* it is assumed that the users list in the module structure
168 will already be empty, or we cannot have gotten to this
171 AST_LIST_LOCK(&module_list);
172 AST_LIST_TRAVERSE_SAFE_BEGIN(&module_list, mod, entry) {
173 if (mod->info == info) {
174 AST_LIST_REMOVE_CURRENT(entry);
178 AST_LIST_TRAVERSE_SAFE_END;
179 AST_LIST_UNLOCK(&module_list);
182 AST_LIST_HEAD_DESTROY(&mod->users);
187 struct ast_module_user *__ast_module_user_add(struct ast_module *mod,
188 struct ast_channel *chan)
190 struct ast_module_user *u = ast_calloc(1, sizeof(*u));
197 AST_LIST_LOCK(&mod->users);
198 AST_LIST_INSERT_HEAD(&mod->users, u, entry);
199 AST_LIST_UNLOCK(&mod->users);
201 ast_atomic_fetchadd_int(&mod->usecount, +1);
203 ast_update_use_count();
208 void __ast_module_user_remove(struct ast_module *mod, struct ast_module_user *u)
210 AST_LIST_LOCK(&mod->users);
211 AST_LIST_REMOVE(&mod->users, u, entry);
212 AST_LIST_UNLOCK(&mod->users);
213 ast_atomic_fetchadd_int(&mod->usecount, -1);
216 ast_update_use_count();
219 void __ast_module_user_hangup_all(struct ast_module *mod)
221 struct ast_module_user *u;
223 AST_LIST_LOCK(&mod->users);
224 while ((u = AST_LIST_REMOVE_HEAD(&mod->users, entry))) {
225 ast_softhangup(u->chan, AST_SOFTHANGUP_APPUNLOAD);
226 ast_atomic_fetchadd_int(&mod->usecount, -1);
229 AST_LIST_UNLOCK(&mod->users);
231 ast_update_use_count();
235 * In addition to modules, the reload command handles some extra keywords
236 * which are listed here together with the corresponding handlers.
237 * This table is also used by the command completion code.
239 static struct reload_classes {
241 int (*reload_fn)(void);
242 } reload_classes[] = { /* list in alpha order, longest match first for cli completion */
243 { "cdr", ast_cdr_engine_reload },
244 { "dnsmgr", dnsmgr_reload },
245 { "extconfig", read_config_maps },
246 { "enum", ast_enum_reload },
247 { "manager", reload_manager },
248 { "rtp", ast_rtp_reload },
249 { "http", ast_http_reload },
250 { "logger", logger_reload },
251 { "features", ast_features_reload },
255 static int printdigest(const unsigned char *d)
258 char buf[256]; /* large enough so we don't have to worry */
260 for (pos = 0, x = 0; x < 16; x++)
261 pos += sprintf(buf + pos, " %02x", *d++);
263 ast_debug(1, "Unexpected signature:%s\n", buf);
268 static int key_matches(const unsigned char *key1, const unsigned char *key2)
272 for (x = 0; x < 16; x++) {
273 if (key1[x] != key2[x])
280 static int verify_key(const unsigned char *key)
283 unsigned char digest[16];
286 MD5Update(&c, key, strlen((char *)key));
287 MD5Final(digest, &c);
289 if (key_matches(expected_key, digest))
297 static int resource_name_match(const char *name1_in, const char *name2_in)
299 char *name1 = (char *) name1_in;
300 char *name2 = (char *) name2_in;
302 /* trim off any .so extensions */
303 if (!strcasecmp(name1 + strlen(name1) - 3, ".so")) {
304 name1 = ast_strdupa(name1);
305 name1[strlen(name1) - 3] = '\0';
307 if (!strcasecmp(name2 + strlen(name2) - 3, ".so")) {
308 name2 = ast_strdupa(name2);
309 name2[strlen(name2) - 3] = '\0';
312 return strcasecmp(name1, name2);
315 static struct ast_module *find_resource(const char *resource, int do_lock)
317 struct ast_module *cur;
320 AST_LIST_LOCK(&module_list);
322 AST_LIST_TRAVERSE(&module_list, cur, entry) {
323 if (!resource_name_match(resource, cur->resource))
328 AST_LIST_UNLOCK(&module_list);
333 #ifdef LOADABLE_MODULES
334 static void unload_dynamic_module(struct ast_module *mod)
336 void *lib = mod->lib;
338 /* WARNING: the structure pointed to by mod is going to
339 disappear when this operation succeeds, so we can't
343 while (!dlclose(lib));
346 static struct ast_module *load_dynamic_module(const char *resource_in, unsigned int global_symbols_only)
348 char fn[PATH_MAX] = "";
350 struct ast_module *mod;
351 unsigned int wants_global;
352 int space; /* room needed for the descriptor */
355 space = sizeof(*resource_being_loaded) + strlen(resource_in) + 1;
356 if (strcasecmp(resource_in + strlen(resource_in) - 3, ".so")) {
358 space += 3; /* room for the extra ".so" */
361 snprintf(fn, sizeof(fn), "%s/%s%s", ast_config_AST_MODULE_DIR, resource_in, missing_so ? ".so" : "");
363 /* make a first load of the module in 'quiet' mode... don't try to resolve
364 any symbols, and don't export any symbols. this will allow us to peek into
365 the module's info block (if available) to see what flags it has set */
367 resource_being_loaded = ast_calloc(1, space);
368 if (!resource_being_loaded)
370 strcpy(resource_being_loaded->resource, resource_in);
372 strcat(resource_being_loaded->resource, ".so");
374 if (!(lib = dlopen(fn, RTLD_LAZY | RTLD_LOCAL))) {
375 ast_log(LOG_WARNING, "Error loading module '%s': %s\n", resource_in, dlerror());
376 ast_free(resource_being_loaded);
380 /* the dlopen() succeeded, let's find out if the module
382 /* note that this will only work properly as long as
383 ast_module_register() (which is called by the module's
384 constructor) places the new module at the tail of the
387 if (resource_being_loaded != (mod = AST_LIST_LAST(&module_list))) {
388 ast_log(LOG_WARNING, "Module '%s' did not register itself during load\n", resource_in);
389 /* no, it did not, so close it and return */
390 while (!dlclose(lib));
391 /* note that the module's destructor will call ast_module_unregister(),
392 which will free the structure we allocated in resource_being_loaded */
396 wants_global = ast_test_flag(mod->info, AST_MODFLAG_GLOBAL_SYMBOLS);
398 /* if we are being asked only to load modules that provide global symbols,
399 and this one does not, then close it and return */
400 if (global_symbols_only && !wants_global) {
401 while (!dlclose(lib));
405 /* if the system supports RTLD_NOLOAD, we can just 'promote' the flags
406 on the already-opened library to what we want... if not, we have to
407 close it and start over
409 #if defined(HAVE_RTLD_NOLOAD) && !defined(__Darwin__)
410 if (!dlopen(fn, RTLD_NOLOAD | (wants_global ? RTLD_LAZY | RTLD_GLOBAL : RTLD_NOW | RTLD_LOCAL))) {
411 ast_log(LOG_WARNING, "Unable to promote flags on module '%s': %s\n", resource_in, dlerror());
412 while (!dlclose(lib));
413 ast_free(resource_being_loaded);
417 while (!dlclose(lib));
418 resource_being_loaded = NULL;
420 /* start the load process again */
421 resource_being_loaded = ast_calloc(1, space);
422 if (!resource_being_loaded)
424 strcpy(resource_being_loaded->resource, resource_in);
426 strcat(resource_being_loaded->resource, ".so");
428 if (!(lib = dlopen(fn, wants_global ? RTLD_LAZY | RTLD_GLOBAL : RTLD_NOW | RTLD_LOCAL))) {
429 ast_log(LOG_WARNING, "Error loading module '%s': %s\n", resource_in, dlerror());
430 ast_free(resource_being_loaded);
434 /* since the module was successfully opened, and it registered itself
435 the previous time we did that, we're going to assume it worked this
439 AST_LIST_LAST(&module_list)->lib = lib;
440 resource_being_loaded = NULL;
442 return AST_LIST_LAST(&module_list);
446 void ast_module_shutdown(void)
448 struct ast_module *mod;
449 AST_LIST_HEAD_NOLOCK_STATIC(local_module_list, ast_module);
451 /* We have to call the unload() callbacks in reverse order that the modules
452 * exist in the module list so it is the reverse order of how they were
455 AST_LIST_LOCK(&module_list);
456 while ((mod = AST_LIST_REMOVE_HEAD(&module_list, entry)))
457 AST_LIST_INSERT_HEAD(&local_module_list, mod, entry);
458 AST_LIST_UNLOCK(&module_list);
460 while ((mod = AST_LIST_REMOVE_HEAD(&local_module_list, entry))) {
461 if (mod->info->unload)
463 /* Since this should only be called when shutting down "gracefully",
464 * all channels should be down before we get to this point, meaning
465 * there will be no module users left. */
466 AST_LIST_HEAD_DESTROY(&mod->users);
471 int ast_unload_resource(const char *resource_name, enum ast_module_unload_mode force)
473 struct ast_module *mod;
477 AST_LIST_LOCK(&module_list);
479 if (!(mod = find_resource(resource_name, 0))) {
480 AST_LIST_UNLOCK(&module_list);
481 ast_log(LOG_WARNING, "Unload failed, '%s' could not be found\n", resource_name);
485 if (!(mod->flags.running || mod->flags.declined))
488 if (!error && (mod->usecount > 0)) {
490 ast_log(LOG_WARNING, "Warning: Forcing removal of module '%s' with use count %d\n",
491 resource_name, mod->usecount);
493 ast_log(LOG_WARNING, "Soft unload failed, '%s' has use count %d\n", resource_name,
500 __ast_module_user_hangup_all(mod);
501 res = mod->info->unload();
504 ast_log(LOG_WARNING, "Firm unload failed for %s\n", resource_name);
505 if (force <= AST_FORCE_FIRM)
508 ast_log(LOG_WARNING, "** Dangerous **: Unloading resource anyway, at user request\n");
513 mod->flags.running = mod->flags.declined = 0;
515 AST_LIST_UNLOCK(&module_list);
517 if (!error && !mod->lib && mod->info && mod->info->restore_globals)
518 mod->info->restore_globals();
520 #ifdef LOADABLE_MODULES
522 unload_dynamic_module(mod);
526 ast_update_use_count();
531 char *ast_module_helper(const char *line, const char *word, int pos, int state, int rpos, int needsreload)
533 struct ast_module *cur;
534 int i, which=0, l = strlen(word);
540 AST_LIST_LOCK(&module_list);
541 AST_LIST_TRAVERSE(&module_list, cur, entry) {
542 if (!strncasecmp(word, cur->resource, l) &&
543 (cur->info->reload || !needsreload) &&
545 ret = ast_strdup(cur->resource);
549 AST_LIST_UNLOCK(&module_list);
552 for (i=0; !ret && reload_classes[i].name; i++) {
553 if (!strncasecmp(word, reload_classes[i].name, l) && ++which > state)
554 ret = ast_strdup(reload_classes[i].name);
561 int ast_module_reload(const char *name)
563 struct ast_module *cur;
564 int res = 0; /* return value. 0 = not found, others, see below */
567 if (ast_mutex_trylock(&reloadlock)) {
568 ast_verbose("The previous reload command didn't finish yet\n");
569 return -1; /* reload already in progress */
571 ast_lastreloadtime = ast_tvnow();
573 /* Call "predefined" reload here first */
574 for (i = 0; reload_classes[i].name; i++) {
575 if (!name || !strcasecmp(name, reload_classes[i].name)) {
576 reload_classes[i].reload_fn(); /* XXX should check error ? */
577 res = 2; /* found and reloaded */
582 ast_mutex_unlock(&reloadlock);
586 AST_LIST_LOCK(&module_list);
587 AST_LIST_TRAVERSE(&module_list, cur, entry) {
588 const struct ast_module_info *info = cur->info;
590 if (name && resource_name_match(name, cur->resource))
593 if (!cur->flags.running || cur->flags.declined) {
596 ast_log(LOG_NOTICE, "The module '%s' was not properly initialized. "
597 "Before reloading the module, you must run \"module load %s\" "
598 "and fix whatever is preventing the module from being initialized.\n",
600 res = 2; /* Don't report that the module was not found */
604 if (!info->reload) { /* cannot be reloaded */
605 if (res < 1) /* store result if possible */
606 res = 1; /* 1 = no reload() method */
611 ast_verb(3, "Reloading module '%s' (%s)\n", cur->resource, info->description);
614 AST_LIST_UNLOCK(&module_list);
616 ast_mutex_unlock(&reloadlock);
621 static unsigned int inspect_module(const struct ast_module *mod)
623 if (!mod->info->description) {
624 ast_log(LOG_WARNING, "Module '%s' does not provide a description.\n", mod->resource);
628 if (!mod->info->key) {
629 ast_log(LOG_WARNING, "Module '%s' does not provide a license key.\n", mod->resource);
633 if (verify_key((unsigned char *) mod->info->key)) {
634 ast_log(LOG_WARNING, "Module '%s' did not provide a valid license key.\n", mod->resource);
638 if (!ast_strlen_zero(mod->info->buildopt_sum) &&
639 strcmp(buildopt_sum, mod->info->buildopt_sum)) {
640 ast_log(LOG_WARNING, "Module '%s' was not compiled with the same compile-time options as this version of Asterisk.\n", mod->resource);
641 ast_log(LOG_WARNING, "Module '%s' will not be initialized as it may cause instability.\n", mod->resource);
648 static enum ast_module_load_result load_resource(const char *resource_name, unsigned int global_symbols_only)
650 struct ast_module *mod;
651 enum ast_module_load_result res = AST_MODULE_LOAD_SUCCESS;
654 if ((mod = find_resource(resource_name, 0))) {
655 if (mod->flags.running) {
656 ast_log(LOG_WARNING, "Module '%s' already exists.\n", resource_name);
657 return AST_MODULE_LOAD_DECLINE;
659 if (global_symbols_only && !ast_test_flag(mod->info, AST_MODFLAG_GLOBAL_SYMBOLS))
660 return AST_MODULE_LOAD_SKIP;
662 #ifdef LOADABLE_MODULES
663 if (!(mod = load_dynamic_module(resource_name, global_symbols_only))) {
664 /* don't generate a warning message during load_modules() */
665 if (!global_symbols_only) {
666 ast_log(LOG_WARNING, "Module '%s' could not be loaded.\n", resource_name);
667 return AST_MODULE_LOAD_DECLINE;
669 return AST_MODULE_LOAD_SKIP;
673 ast_log(LOG_WARNING, "Module '%s' could not be loaded.\n", resource_name);
674 return AST_MODULE_LOAD_DECLINE;
678 if (inspect_module(mod)) {
679 ast_log(LOG_WARNING, "Module '%s' could not be loaded.\n", resource_name);
680 #ifdef LOADABLE_MODULES
681 unload_dynamic_module(mod);
683 return AST_MODULE_LOAD_DECLINE;
686 if (!mod->lib && mod->info->backup_globals()) {
687 ast_log(LOG_WARNING, "Module '%s' was unable to backup its global data.\n", resource_name);
688 return AST_MODULE_LOAD_DECLINE;
691 mod->flags.declined = 0;
694 res = mod->info->load();
697 case AST_MODULE_LOAD_SUCCESS:
698 if (!ast_fully_booted) {
699 ast_verb(1, "%s => (%s)\n", resource_name, term_color(tmp, mod->info->description, COLOR_BROWN, COLOR_BLACK, sizeof(tmp)));
703 ast_verb(1, "Loaded %s => (%s)\n", resource_name, mod->info->description);
706 mod->flags.running = 1;
708 ast_update_use_count();
710 case AST_MODULE_LOAD_DECLINE:
711 mod->flags.declined = 1;
713 case AST_MODULE_LOAD_FAILURE:
715 case AST_MODULE_LOAD_SKIP:
716 /* modules should never return this value */
723 int ast_load_resource(const char *resource_name)
725 AST_LIST_LOCK(&module_list);
726 load_resource(resource_name, 0);
727 AST_LIST_UNLOCK(&module_list);
732 struct load_order_entry {
734 AST_LIST_ENTRY(load_order_entry) entry;
737 AST_LIST_HEAD_NOLOCK(load_order, load_order_entry);
739 static struct load_order_entry *add_to_load_order(const char *resource, struct load_order *load_order)
741 struct load_order_entry *order;
743 AST_LIST_TRAVERSE(load_order, order, entry) {
744 if (!resource_name_match(order->resource, resource))
748 if (!(order = ast_calloc(1, sizeof(*order))))
751 order->resource = ast_strdup(resource);
752 AST_LIST_INSERT_TAIL(load_order, order, entry);
756 int load_modules(unsigned int preload_only)
758 struct ast_config *cfg;
759 struct ast_module *mod;
760 struct load_order_entry *order;
761 struct ast_variable *v;
762 unsigned int load_count;
763 struct load_order load_order;
765 struct ast_flags config_flags = { 0 };
767 #ifdef LOADABLE_MODULES
768 struct dirent *dirent;
772 /* all embedded modules have registered themselves by now */
775 ast_verb(1, "Asterisk Dynamic Loader Starting:\n");
777 AST_LIST_HEAD_INIT_NOLOCK(&load_order);
779 AST_LIST_LOCK(&module_list);
781 if (embedded_module_list.first) {
782 module_list.first = embedded_module_list.first;
783 module_list.last = embedded_module_list.last;
784 embedded_module_list.first = NULL;
787 if (!(cfg = ast_config_load(AST_MODULE_CONFIG, config_flags))) {
788 ast_log(LOG_WARNING, "No '%s' found, no modules will be loaded.\n", AST_MODULE_CONFIG);
792 /* first, find all the modules we have been explicitly requested to load */
793 for (v = ast_variable_browse(cfg, "modules"); v; v = v->next) {
794 if (!strcasecmp(v->name, preload_only ? "preload" : "load"))
795 add_to_load_order(v->value, &load_order);
798 /* check if 'autoload' is on */
799 if (!preload_only && ast_true(ast_variable_retrieve(cfg, "modules", "autoload"))) {
800 /* if so, first add all the embedded modules that are not already running to the load order */
801 AST_LIST_TRAVERSE(&module_list, mod, entry) {
802 /* if it's not embedded, skip it */
806 if (mod->flags.running)
809 order = add_to_load_order(mod->resource, &load_order);
812 #ifdef LOADABLE_MODULES
813 /* if we are allowed to load dynamic modules, scan the directory for
814 for all available modules and add them as well */
815 if ((dir = opendir(ast_config_AST_MODULE_DIR))) {
816 while ((dirent = readdir(dir))) {
817 int ld = strlen(dirent->d_name);
819 /* Must end in .so to load it. */
824 if (strcasecmp(dirent->d_name + ld - 3, ".so"))
827 /* if there is already a module by this name in the module_list,
829 if (find_resource(dirent->d_name, 0))
832 add_to_load_order(dirent->d_name, &load_order);
838 ast_log(LOG_WARNING, "Unable to open modules directory '%s'.\n",
839 ast_config_AST_MODULE_DIR);
844 /* now scan the config for any modules we are prohibited from loading and
845 remove them from the load order */
846 for (v = ast_variable_browse(cfg, "modules"); v; v = v->next) {
847 if (strcasecmp(v->name, "noload"))
850 AST_LIST_TRAVERSE_SAFE_BEGIN(&load_order, order, entry) {
851 if (!resource_name_match(order->resource, v->value)) {
852 AST_LIST_REMOVE_CURRENT(entry);
853 ast_free(order->resource);
857 AST_LIST_TRAVERSE_SAFE_END;
860 /* we are done with the config now, all the information we need is in the
862 ast_config_destroy(cfg);
865 AST_LIST_TRAVERSE(&load_order, order, entry)
869 ast_log(LOG_NOTICE, "%d modules will be loaded.\n", load_count);
871 /* first, load only modules that provide global symbols */
872 AST_LIST_TRAVERSE_SAFE_BEGIN(&load_order, order, entry) {
873 switch (load_resource(order->resource, 1)) {
874 case AST_MODULE_LOAD_SUCCESS:
876 case AST_MODULE_LOAD_DECLINE:
877 AST_LIST_REMOVE_CURRENT(entry);
878 ast_free(order->resource);
881 case AST_MODULE_LOAD_FAILURE:
884 case AST_MODULE_LOAD_SKIP:
885 /* try again later */
889 AST_LIST_TRAVERSE_SAFE_END;
891 /* now load everything else */
892 AST_LIST_TRAVERSE_SAFE_BEGIN(&load_order, order, entry) {
893 switch (load_resource(order->resource, 0)) {
894 case AST_MODULE_LOAD_SUCCESS:
896 case AST_MODULE_LOAD_DECLINE:
897 AST_LIST_REMOVE_CURRENT(entry);
898 ast_free(order->resource);
901 case AST_MODULE_LOAD_FAILURE:
904 case AST_MODULE_LOAD_SKIP:
905 /* should not happen */
909 AST_LIST_TRAVERSE_SAFE_END;
912 while ((order = AST_LIST_REMOVE_HEAD(&load_order, entry))) {
913 ast_free(order->resource);
917 AST_LIST_UNLOCK(&module_list);
919 /* Tell manager clients that are aggressive at logging in that we're done
920 loading modules. If there's a DNS problem in chan_sip, we might not
922 manager_event(EVENT_FLAG_SYSTEM, "ModuleLoadReport", "ModuleLoadStatus: Done\r\nModuleSelection: %s\r\nModuleCount: %d\r\n", preload_only ? "Preload" : "All", modulecount);
927 void ast_update_use_count(void)
929 /* Notify any module monitors that the use count for a
930 resource has changed */
931 struct loadupdate *m;
933 AST_LIST_LOCK(&module_list);
934 AST_LIST_TRAVERSE(&updaters, m, entry)
936 AST_LIST_UNLOCK(&module_list);
939 int ast_update_module_list(int (*modentry)(const char *module, const char *description, int usecnt, const char *like),
942 struct ast_module *cur;
944 int total_mod_loaded = 0;
946 if (AST_LIST_TRYLOCK(&module_list))
949 AST_LIST_TRAVERSE(&module_list, cur, entry) {
950 total_mod_loaded += modentry(cur->resource, cur->info->description, cur->usecount, like);
954 AST_LIST_UNLOCK(&module_list);
956 return total_mod_loaded;
959 /*! \brief Check if module exists */
960 int ast_module_check(const char *name)
962 struct ast_module *cur;
964 if (ast_strlen_zero(name))
965 return 0; /* FALSE */
967 cur = find_resource(name, 1);
969 return (cur != NULL);
973 int ast_loader_register(int (*v)(void))
975 struct loadupdate *tmp;
977 if (!(tmp = ast_malloc(sizeof(*tmp))))
981 AST_LIST_LOCK(&module_list);
982 AST_LIST_INSERT_HEAD(&updaters, tmp, entry);
983 AST_LIST_UNLOCK(&module_list);
988 int ast_loader_unregister(int (*v)(void))
990 struct loadupdate *cur;
992 AST_LIST_LOCK(&module_list);
993 AST_LIST_TRAVERSE_SAFE_BEGIN(&updaters, cur, entry) {
994 if (cur->updater == v) {
995 AST_LIST_REMOVE_CURRENT(entry);
999 AST_LIST_TRAVERSE_SAFE_END;
1000 AST_LIST_UNLOCK(&module_list);
1002 return cur ? 0 : -1;
1005 struct ast_module *ast_module_ref(struct ast_module *mod)
1007 ast_atomic_fetchadd_int(&mod->usecount, +1);
1008 ast_update_use_count();
1013 void ast_module_unref(struct ast_module *mod)
1015 ast_atomic_fetchadd_int(&mod->usecount, -1);
1016 ast_update_use_count();