To help combat problems where people build external modules (asterisk-addons or other...
[asterisk-bristuff.git] / main / loader.c
blobf0b98f9b94bc08f6a0c64697acf218d1874d2b57
1 /*
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.
21 /*! \file
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>
27 * - See ModMngMnt
30 #include "asterisk.h"
32 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
34 #include <stdio.h>
35 #include <dirent.h>
36 #include <unistd.h>
37 #include <stdlib.h>
38 #include <errno.h>
39 #include <string.h>
41 #include "asterisk/linkedlists.h"
42 #include "asterisk/module.h"
43 #include "asterisk/options.h"
44 #include "asterisk/config.h"
45 #include "asterisk/logger.h"
46 #include "asterisk/channel.h"
47 #include "asterisk/term.h"
48 #include "asterisk/manager.h"
49 #include "asterisk/cdr.h"
50 #include "asterisk/enum.h"
51 #include "asterisk/rtp.h"
52 #include "asterisk/http.h"
53 #include "asterisk/lock.h"
55 #ifdef DLFCNCOMPAT
56 #include "asterisk/dlfcn-compat.h"
57 #else
58 #include <dlfcn.h>
59 #endif
61 #include "asterisk/md5.h"
62 #include "asterisk/utils.h"
64 #ifndef RTLD_NOW
65 #define RTLD_NOW 0
66 #endif
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 unsigned int buildopt_sum[4] = 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
85 struct ast_module {
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 */
90 struct {
91 unsigned int running:1;
92 unsigned int declined:1;
93 } flags;
94 AST_LIST_ENTRY(ast_module) entry;
95 char resource[0];
98 static AST_LIST_HEAD_STATIC(module_list, ast_module);
100 struct loadupdate {
101 int (*updater)(void);
102 AST_LIST_ENTRY(loadupdate) entry;
105 static AST_LIST_HEAD_STATIC(updaters, loadupdate);
107 AST_MUTEX_DEFINE_STATIC(reloadlock);
109 /* when dynamic modules are being loaded, ast_module_register() will
110 need to know what filename the module was loaded from while it
111 is being registered
113 struct ast_module *resource_being_loaded;
115 /* XXX: should we check for duplicate resource names here? */
117 void ast_module_register(const struct ast_module_info *info)
119 struct ast_module *mod;
121 if (embedding) {
122 if (!(mod = ast_calloc(1, sizeof(*mod) + strlen(info->name) + 1)))
123 return;
124 strcpy(mod->resource, info->name);
125 } else {
126 mod = resource_being_loaded;
129 mod->info = info;
130 AST_LIST_HEAD_INIT(&mod->users);
132 /* during startup, before the loader has been initialized,
133 there are no threads, so there is no need to take the lock
134 on this list to manipulate it. it is also possible that it
135 might be unsafe to use the list lock at that point... so
136 let's avoid it altogether
138 if (!embedding)
139 AST_LIST_LOCK(&module_list);
141 /* it is paramount that the new entry be placed at the tail of
142 the list, otherwise the code that uses dlopen() to load
143 dynamic modules won't be able to find out if the module it
144 just opened was registered or failed to load
146 AST_LIST_INSERT_TAIL(&module_list, mod, entry);
148 if (!embedding)
149 AST_LIST_UNLOCK(&module_list);
151 /* give the module a copy of its own handle, for later use in registrations and the like */
152 *((struct ast_module **) &(info->self)) = mod;
155 void ast_module_unregister(const struct ast_module_info *info)
157 struct ast_module *mod = NULL;
159 /* it is assumed that the users list in the module structure
160 will already be empty, or we cannot have gotten to this
161 point
163 AST_LIST_LOCK(&module_list);
164 AST_LIST_TRAVERSE_SAFE_BEGIN(&module_list, mod, entry) {
165 if (mod->info == info) {
166 AST_LIST_REMOVE_CURRENT(&module_list, entry);
167 break;
170 AST_LIST_TRAVERSE_SAFE_END;
171 AST_LIST_UNLOCK(&module_list);
173 if (mod) {
174 AST_LIST_HEAD_DESTROY(&mod->users);
175 free(mod);
179 struct ast_module_user *__ast_module_user_add(struct ast_module *mod,
180 struct ast_channel *chan)
182 struct ast_module_user *u = ast_calloc(1, sizeof(*u));
184 if (!u)
185 return NULL;
187 u->chan = chan;
189 AST_LIST_LOCK(&mod->users);
190 AST_LIST_INSERT_HEAD(&mod->users, u, entry);
191 AST_LIST_UNLOCK(&mod->users);
193 ast_atomic_fetchadd_int(&mod->usecount, +1);
195 ast_update_use_count();
197 return u;
200 void __ast_module_user_remove(struct ast_module *mod, struct ast_module_user *u)
202 AST_LIST_LOCK(&mod->users);
203 AST_LIST_REMOVE(&mod->users, u, entry);
204 AST_LIST_UNLOCK(&mod->users);
205 ast_atomic_fetchadd_int(&mod->usecount, -1);
206 free(u);
208 ast_update_use_count();
211 void __ast_module_user_hangup_all(struct ast_module *mod)
213 struct ast_module_user *u;
215 AST_LIST_LOCK(&mod->users);
216 while ((u = AST_LIST_REMOVE_HEAD(&mod->users, entry))) {
217 ast_softhangup(u->chan, AST_SOFTHANGUP_APPUNLOAD);
218 ast_atomic_fetchadd_int(&mod->usecount, -1);
219 free(u);
221 AST_LIST_UNLOCK(&mod->users);
223 ast_update_use_count();
226 /*! \note
227 * In addition to modules, the reload command handles some extra keywords
228 * which are listed here together with the corresponding handlers.
229 * This table is also used by the command completion code.
231 static struct reload_classes {
232 const char *name;
233 int (*reload_fn)(void);
234 } reload_classes[] = { /* list in alpha order, longest match first for cli completion */
235 { "cdr", ast_cdr_engine_reload },
236 { "dnsmgr", dnsmgr_reload },
237 { "extconfig", read_config_maps },
238 { "enum", ast_enum_reload },
239 { "manager", reload_manager },
240 { "rtp", ast_rtp_reload },
241 { "http", ast_http_reload },
242 { NULL, NULL }
245 static int printdigest(const unsigned char *d)
247 int x, pos;
248 char buf[256]; /* large enough so we don't have to worry */
250 for (pos = 0, x = 0; x < 16; x++)
251 pos += sprintf(buf + pos, " %02x", *d++);
253 ast_log(LOG_DEBUG, "Unexpected signature:%s\n", buf);
255 return 0;
258 static int key_matches(const unsigned char *key1, const unsigned char *key2)
260 int x;
262 for (x = 0; x < 16; x++) {
263 if (key1[x] != key2[x])
264 return 0;
267 return 1;
270 static int verify_key(const unsigned char *key)
272 struct MD5Context c;
273 unsigned char digest[16];
275 MD5Init(&c);
276 MD5Update(&c, key, strlen((char *)key));
277 MD5Final(digest, &c);
279 if (key_matches(expected_key, digest))
280 return 0;
282 printdigest(digest);
284 return -1;
287 static int resource_name_match(const char *name1_in, const char *name2_in)
289 char *name1 = (char *) name1_in;
290 char *name2 = (char *) name2_in;
292 /* trim off any .so extensions */
293 if (!strcasecmp(name1 + strlen(name1) - 3, ".so")) {
294 name1 = ast_strdupa(name1);
295 name1[strlen(name1) - 3] = '\0';
297 if (!strcasecmp(name2 + strlen(name2) - 3, ".so")) {
298 name2 = ast_strdupa(name2);
299 name2[strlen(name2) - 3] = '\0';
302 return strcasecmp(name1, name2);
305 static struct ast_module *find_resource(const char *resource, int do_lock)
307 struct ast_module *cur;
309 if (do_lock)
310 AST_LIST_LOCK(&module_list);
312 AST_LIST_TRAVERSE(&module_list, cur, entry) {
313 if (!resource_name_match(resource, cur->resource))
314 break;
317 if (do_lock)
318 AST_LIST_UNLOCK(&module_list);
320 return cur;
323 #ifdef LOADABLE_MODULES
324 static void unload_dynamic_module(struct ast_module *mod)
326 void *lib = mod->lib;
328 /* WARNING: the structure pointed to by mod is going to
329 disappear when this operation succeeds, so we can't
330 dereference it */
332 if (lib)
333 while (!dlclose(lib));
336 static struct ast_module *load_dynamic_module(const char *resource_in, unsigned int global_symbols_only)
338 char fn[256];
339 void *lib;
340 struct ast_module *mod;
341 char *resource = (char *) resource_in;
342 unsigned int wants_global;
344 if (strcasecmp(resource + strlen(resource) - 3, ".so")) {
345 resource = alloca(strlen(resource_in) + 3);
346 strcpy(resource, resource_in);
347 strcat(resource, ".so");
350 snprintf(fn, sizeof(fn), "%s/%s", ast_config_AST_MODULE_DIR, resource);
352 /* make a first load of the module in 'quiet' mode... don't try to resolve
353 any symbols, and don't export any symbols. this will allow us to peek into
354 the module's info block (if available) to see what flags it has set */
356 if (!(resource_being_loaded = ast_calloc(1, sizeof(*resource_being_loaded) + strlen(resource) + 1)))
357 return NULL;
359 strcpy(resource_being_loaded->resource, resource);
361 if (!(lib = dlopen(fn, RTLD_LAZY | RTLD_LOCAL))) {
362 ast_log(LOG_WARNING, "Error loading module '%s': %s\n", resource_in, dlerror());
363 free(resource_being_loaded);
364 return NULL;
367 /* the dlopen() succeeded, let's find out if the module
368 registered itself */
369 /* note that this will only work properly as long as
370 ast_module_register() (which is called by the module's
371 constructor) places the new module at the tail of the
372 module_list
374 if (resource_being_loaded != (mod = AST_LIST_LAST(&module_list))) {
375 ast_log(LOG_WARNING, "Module '%s' did not register itself during load\n", resource_in);
376 /* no, it did not, so close it and return */
377 while (!dlclose(lib));
378 /* note that the module's destructor will call ast_module_unregister(),
379 which will free the structure we allocated in resource_being_loaded */
380 return NULL;
383 wants_global = ast_test_flag(mod->info, AST_MODFLAG_GLOBAL_SYMBOLS);
385 /* if we are being asked only to load modules that provide global symbols,
386 and this one does not, then close it and return */
387 if (global_symbols_only && !wants_global) {
388 while (!dlclose(lib));
389 return NULL;
392 /* if the system supports RTLD_NOLOAD, we can just 'promote' the flags
393 on the already-opened library to what we want... if not, we have to
394 close it and start over
396 #if defined(HAVE_RTLD_NOLOAD) && !defined(__Darwin__)
397 if (!dlopen(fn, RTLD_NOLOAD | (wants_global ? RTLD_LAZY | RTLD_GLOBAL : RTLD_NOW | RTLD_LOCAL))) {
398 ast_log(LOG_WARNING, "Unable to promote flags on module '%s': %s\n", resource_in, dlerror());
399 while (!dlclose(lib));
400 free(resource_being_loaded);
401 return NULL;
403 #else
404 while (!dlclose(lib));
405 resource_being_loaded = NULL;
407 /* start the load process again */
409 if (!(resource_being_loaded = ast_calloc(1, sizeof(*resource_being_loaded) + strlen(resource) + 1)))
410 return NULL;
412 strcpy(resource_being_loaded->resource, resource);
414 if (!(lib = dlopen(fn, wants_global ? RTLD_LAZY | RTLD_GLOBAL : RTLD_NOW | RTLD_LOCAL))) {
415 ast_log(LOG_WARNING, "Error loading module '%s': %s\n", resource_in, dlerror());
416 free(resource_being_loaded);
417 return NULL;
420 /* since the module was successfully opened, and it registered itself
421 the previous time we did that, we're going to assume it worked this
422 time too :) */
423 #endif
425 AST_LIST_LAST(&module_list)->lib = lib;
426 resource_being_loaded = NULL;
428 return AST_LIST_LAST(&module_list);
430 #endif
432 void ast_module_shutdown(void)
434 struct ast_module *mod;
435 AST_LIST_HEAD_NOLOCK_STATIC(local_module_list, ast_module);
437 /* We have to call the unload() callbacks in reverse order that the modules
438 * exist in the module list so it is the reverse order of how they were
439 * loaded. */
441 AST_LIST_LOCK(&module_list);
442 while ((mod = AST_LIST_REMOVE_HEAD(&module_list, entry)))
443 AST_LIST_INSERT_HEAD(&local_module_list, mod, entry);
444 AST_LIST_UNLOCK(&module_list);
446 while ((mod = AST_LIST_REMOVE_HEAD(&local_module_list, entry))) {
447 if (mod->info->unload)
448 mod->info->unload();
449 /* Since this should only be called when shutting down "gracefully",
450 * all channels should be down before we get to this point, meaning
451 * there will be no module users left. */
452 AST_LIST_HEAD_DESTROY(&mod->users);
453 free(mod);
457 int ast_unload_resource(const char *resource_name, enum ast_module_unload_mode force)
459 struct ast_module *mod;
460 int res = -1;
461 int error = 0;
463 AST_LIST_LOCK(&module_list);
465 if (!(mod = find_resource(resource_name, 0))) {
466 AST_LIST_UNLOCK(&module_list);
467 return 0;
470 if (!(mod->flags.running || mod->flags.declined))
471 error = 1;
473 if (!mod->lib) {
474 ast_log(LOG_WARNING, "Unloading embedded modules is not supported.\n");
475 error = 1;
478 if (!error && (mod->usecount > 0)) {
479 if (force)
480 ast_log(LOG_WARNING, "Warning: Forcing removal of module '%s' with use count %d\n",
481 resource_name, mod->usecount);
482 else {
483 ast_log(LOG_WARNING, "Soft unload failed, '%s' has use count %d\n", resource_name,
484 mod->usecount);
485 error = 1;
489 if (!error) {
490 __ast_module_user_hangup_all(mod);
491 res = mod->info->unload();
493 if (res) {
494 ast_log(LOG_WARNING, "Firm unload failed for %s\n", resource_name);
495 if (force <= AST_FORCE_FIRM)
496 error = 1;
497 else
498 ast_log(LOG_WARNING, "** Dangerous **: Unloading resource anyway, at user request\n");
502 if (!error)
503 mod->flags.running = mod->flags.declined = 0;
505 AST_LIST_UNLOCK(&module_list);
507 #ifdef LOADABLE_MODULES
508 if (!error)
509 unload_dynamic_module(mod);
510 #endif
512 if (!error)
513 ast_update_use_count();
515 return res;
518 char *ast_module_helper(const char *line, const char *word, int pos, int state, int rpos, int needsreload)
520 struct ast_module *cur;
521 int i, which=0, l = strlen(word);
522 char *ret = NULL;
524 if (pos != rpos)
525 return NULL;
527 AST_LIST_LOCK(&module_list);
528 AST_LIST_TRAVERSE(&module_list, cur, entry) {
529 if (!strncasecmp(word, cur->resource, l) &&
530 (cur->info->reload || !needsreload) &&
531 ++which > state) {
532 ret = strdup(cur->resource);
533 break;
536 AST_LIST_UNLOCK(&module_list);
538 if (!ret) {
539 for (i=0; !ret && reload_classes[i].name; i++) {
540 if (!strncasecmp(word, reload_classes[i].name, l) && ++which > state)
541 ret = strdup(reload_classes[i].name);
545 return ret;
548 int ast_module_reload(const char *name)
550 struct ast_module *cur;
551 int res = 0; /* return value. 0 = not found, others, see below */
552 int i;
554 if (ast_mutex_trylock(&reloadlock)) {
555 ast_verbose("The previous reload command didn't finish yet\n");
556 return -1; /* reload already in progress */
558 ast_lastreloadtime = time(NULL);
560 /* Call "predefined" reload here first */
561 for (i = 0; reload_classes[i].name; i++) {
562 if (!name || !strcasecmp(name, reload_classes[i].name)) {
563 reload_classes[i].reload_fn(); /* XXX should check error ? */
564 res = 2; /* found and reloaded */
568 if (name && res) {
569 ast_mutex_unlock(&reloadlock);
570 return res;
573 AST_LIST_LOCK(&module_list);
574 AST_LIST_TRAVERSE(&module_list, cur, entry) {
575 const struct ast_module_info *info = cur->info;
577 if (name && resource_name_match(name, cur->resource))
578 continue;
580 if (!(cur->flags.running || cur->flags.declined))
581 continue;
583 if (!info->reload) { /* cannot be reloaded */
584 if (res < 1) /* store result if possible */
585 res = 1; /* 1 = no reload() method */
586 continue;
589 res = 2;
590 if (option_verbose > 2)
591 ast_verbose(VERBOSE_PREFIX_3 "Reloading module '%s' (%s)\n", cur->resource, info->description);
592 info->reload();
594 AST_LIST_UNLOCK(&module_list);
596 ast_mutex_unlock(&reloadlock);
598 return res;
601 static unsigned int inspect_module(const struct ast_module *mod)
603 unsigned int buildopt_empty[4] = { 0, };
605 if (!mod->info->description) {
606 ast_log(LOG_WARNING, "Module '%s' does not provide a description.\n", mod->resource);
607 return 1;
610 if (!mod->info->key) {
611 ast_log(LOG_WARNING, "Module '%s' does not provide a license key.\n", mod->resource);
612 return 1;
615 if (verify_key((unsigned char *) mod->info->key)) {
616 ast_log(LOG_WARNING, "Module '%s' did not provide a valid license key.\n", mod->resource);
617 return 1;
620 if (memcmp(buildopt_empty, mod->info->buildopt_sum, sizeof(buildopt_empty)) &&
621 memcmp(buildopt_sum, mod->info->buildopt_sum, sizeof(buildopt_sum))) {
622 ast_log(LOG_WARNING, "Module '%s' was not compiled with the same compile-time options as this version of Asterisk.\n", mod->resource);
623 ast_log(LOG_WARNING, "Module '%s' will not be initialized as it may cause instability.\n", mod->resource);
624 return 1;
627 return 0;
630 static enum ast_module_load_result load_resource(const char *resource_name, unsigned int global_symbols_only)
632 struct ast_module *mod;
633 enum ast_module_load_result res = AST_MODULE_LOAD_SUCCESS;
634 char tmp[256];
636 if ((mod = find_resource(resource_name, 0))) {
637 if (mod->flags.running) {
638 ast_log(LOG_WARNING, "Module '%s' already exists.\n", resource_name);
639 return AST_MODULE_LOAD_DECLINE;
641 if (global_symbols_only && !ast_test_flag(mod->info, AST_MODFLAG_GLOBAL_SYMBOLS))
642 return AST_MODULE_LOAD_SKIP;
643 } else {
644 #ifdef LOADABLE_MODULES
645 if (!(mod = load_dynamic_module(resource_name, global_symbols_only))) {
646 /* don't generate a warning message during load_modules() */
647 if (!global_symbols_only) {
648 ast_log(LOG_WARNING, "Module '%s' could not be loaded.\n", resource_name);
649 return AST_MODULE_LOAD_DECLINE;
650 } else {
651 return AST_MODULE_LOAD_SKIP;
654 #else
655 ast_log(LOG_WARNING, "Module '%s' could not be loaded.\n", resource_name);
656 return AST_MODULE_LOAD_DECLINE;
657 #endif
660 if (inspect_module(mod)) {
661 ast_log(LOG_WARNING, "Module '%s' could not be loaded.\n", resource_name);
662 #ifdef LOADABLE_MODULES
663 unload_dynamic_module(mod);
664 #endif
665 return AST_MODULE_LOAD_DECLINE;
668 mod->flags.declined = 0;
670 if (mod->info->load)
671 res = mod->info->load();
673 switch (res) {
674 case AST_MODULE_LOAD_SUCCESS:
675 if (!ast_fully_booted) {
676 if (option_verbose)
677 ast_verbose("%s => (%s)\n", resource_name, term_color(tmp, mod->info->description, COLOR_BROWN, COLOR_BLACK, sizeof(tmp)));
678 if (ast_opt_console && !option_verbose)
679 ast_verbose( ".");
680 } else {
681 if (option_verbose)
682 ast_verbose(VERBOSE_PREFIX_1 "Loaded %s => (%s)\n", resource_name, mod->info->description);
685 mod->flags.running = 1;
687 ast_update_use_count();
688 break;
689 case AST_MODULE_LOAD_DECLINE:
690 mod->flags.declined = 1;
691 break;
692 case AST_MODULE_LOAD_FAILURE:
693 break;
694 case AST_MODULE_LOAD_SKIP:
695 /* modules should never return this value */
696 break;
699 return res;
702 int ast_load_resource(const char *resource_name)
704 AST_LIST_LOCK(&module_list);
705 load_resource(resource_name, 0);
706 AST_LIST_UNLOCK(&module_list);
708 return 0;
711 struct load_order_entry {
712 char *resource;
713 AST_LIST_ENTRY(load_order_entry) entry;
716 AST_LIST_HEAD_NOLOCK(load_order, load_order_entry);
718 static struct load_order_entry *add_to_load_order(const char *resource, struct load_order *load_order)
720 struct load_order_entry *order;
722 AST_LIST_TRAVERSE(load_order, order, entry) {
723 if (!resource_name_match(order->resource, resource))
724 return NULL;
727 if (!(order = ast_calloc(1, sizeof(*order))))
728 return NULL;
730 order->resource = ast_strdup(resource);
731 AST_LIST_INSERT_TAIL(load_order, order, entry);
733 return order;
736 int load_modules(unsigned int preload_only)
738 struct ast_config *cfg;
739 struct ast_module *mod;
740 struct load_order_entry *order;
741 struct ast_variable *v;
742 unsigned int load_count;
743 struct load_order load_order;
744 int res = 0;
745 #ifdef LOADABLE_MODULES
746 struct dirent *dirent;
747 DIR *dir;
748 #endif
750 /* all embedded modules have registered themselves by now */
751 embedding = 0;
753 if (option_verbose)
754 ast_verbose("Asterisk Dynamic Loader Starting:\n");
756 AST_LIST_HEAD_INIT_NOLOCK(&load_order);
758 AST_LIST_LOCK(&module_list);
760 if (!(cfg = ast_config_load(AST_MODULE_CONFIG))) {
761 ast_log(LOG_WARNING, "No '%s' found, no modules will be loaded.\n", AST_MODULE_CONFIG);
762 goto done;
765 /* first, find all the modules we have been explicitly requested to load */
766 for (v = ast_variable_browse(cfg, "modules"); v; v = v->next) {
767 if (!strcasecmp(v->name, preload_only ? "preload" : "load"))
768 add_to_load_order(v->value, &load_order);
771 /* check if 'autoload' is on */
772 if (!preload_only && ast_true(ast_variable_retrieve(cfg, "modules", "autoload"))) {
773 /* if so, first add all the embedded modules that are not already running to the load order */
774 AST_LIST_TRAVERSE(&module_list, mod, entry) {
775 /* if it's not embedded, skip it */
776 if (mod->lib)
777 continue;
779 if (mod->flags.running)
780 continue;
782 order = add_to_load_order(mod->resource, &load_order);
785 #ifdef LOADABLE_MODULES
786 /* if we are allowed to load dynamic modules, scan the directory for
787 for all available modules and add them as well */
788 if ((dir = opendir(ast_config_AST_MODULE_DIR))) {
789 while ((dirent = readdir(dir))) {
790 int ld = strlen(dirent->d_name);
792 /* Must end in .so to load it. */
794 if (ld < 4)
795 continue;
797 if (strcasecmp(dirent->d_name + ld - 3, ".so"))
798 continue;
800 /* if there is already a module by this name in the module_list,
801 skip this file */
802 if (find_resource(dirent->d_name, 0))
803 continue;
805 add_to_load_order(dirent->d_name, &load_order);
808 closedir(dir);
809 } else {
810 if (!ast_opt_quiet)
811 ast_log(LOG_WARNING, "Unable to open modules directory '%s'.\n",
812 ast_config_AST_MODULE_DIR);
814 #endif
817 /* now scan the config for any modules we are prohibited from loading and
818 remove them from the load order */
819 for (v = ast_variable_browse(cfg, "modules"); v; v = v->next) {
820 if (strcasecmp(v->name, "noload"))
821 continue;
823 AST_LIST_TRAVERSE_SAFE_BEGIN(&load_order, order, entry) {
824 if (!resource_name_match(order->resource, v->value)) {
825 AST_LIST_REMOVE_CURRENT(&load_order, entry);
826 free(order->resource);
827 free(order);
830 AST_LIST_TRAVERSE_SAFE_END;
833 /* we are done with the config now, all the information we need is in the
834 load_order list */
835 ast_config_destroy(cfg);
837 load_count = 0;
838 AST_LIST_TRAVERSE(&load_order, order, entry)
839 load_count++;
841 if (load_count)
842 ast_log(LOG_NOTICE, "%d modules will be loaded.\n", load_count);
844 /* first, load only modules that provide global symbols */
845 AST_LIST_TRAVERSE_SAFE_BEGIN(&load_order, order, entry) {
846 switch (load_resource(order->resource, 1)) {
847 case AST_MODULE_LOAD_SUCCESS:
848 case AST_MODULE_LOAD_DECLINE:
849 AST_LIST_REMOVE_CURRENT(&load_order, entry);
850 free(order->resource);
851 free(order);
852 break;
853 case AST_MODULE_LOAD_FAILURE:
854 res = -1;
855 goto done;
856 case AST_MODULE_LOAD_SKIP:
857 /* try again later */
858 break;
861 AST_LIST_TRAVERSE_SAFE_END;
863 /* now load everything else */
864 AST_LIST_TRAVERSE_SAFE_BEGIN(&load_order, order, entry) {
865 switch (load_resource(order->resource, 0)) {
866 case AST_MODULE_LOAD_SUCCESS:
867 case AST_MODULE_LOAD_DECLINE:
868 AST_LIST_REMOVE_CURRENT(&load_order, entry);
869 free(order->resource);
870 free(order);
871 break;
872 case AST_MODULE_LOAD_FAILURE:
873 res = -1;
874 goto done;
875 case AST_MODULE_LOAD_SKIP:
876 /* should not happen */
877 break;
880 AST_LIST_TRAVERSE_SAFE_END;
882 done:
883 while ((order = AST_LIST_REMOVE_HEAD(&load_order, entry))) {
884 free(order->resource);
885 free(order);
888 AST_LIST_UNLOCK(&module_list);
890 return res;
893 void ast_update_use_count(void)
895 /* Notify any module monitors that the use count for a
896 resource has changed */
897 struct loadupdate *m;
899 AST_LIST_LOCK(&module_list);
900 AST_LIST_TRAVERSE(&updaters, m, entry)
901 m->updater();
902 AST_LIST_UNLOCK(&module_list);
905 int ast_update_module_list(int (*modentry)(const char *module, const char *description, int usecnt, const char *like),
906 const char *like)
908 struct ast_module *cur;
909 int unlock = -1;
910 int total_mod_loaded = 0;
912 if (AST_LIST_TRYLOCK(&module_list))
913 unlock = 0;
915 AST_LIST_TRAVERSE(&module_list, cur, entry) {
916 total_mod_loaded += modentry(cur->resource, cur->info->description, cur->usecount, like);
919 if (unlock)
920 AST_LIST_UNLOCK(&module_list);
922 return total_mod_loaded;
925 int ast_loader_register(int (*v)(void))
927 struct loadupdate *tmp;
929 if (!(tmp = ast_malloc(sizeof(*tmp))))
930 return -1;
932 tmp->updater = v;
933 AST_LIST_LOCK(&module_list);
934 AST_LIST_INSERT_HEAD(&updaters, tmp, entry);
935 AST_LIST_UNLOCK(&module_list);
937 return 0;
940 int ast_loader_unregister(int (*v)(void))
942 struct loadupdate *cur;
944 AST_LIST_LOCK(&module_list);
945 AST_LIST_TRAVERSE_SAFE_BEGIN(&updaters, cur, entry) {
946 if (cur->updater == v) {
947 AST_LIST_REMOVE_CURRENT(&updaters, entry);
948 break;
951 AST_LIST_TRAVERSE_SAFE_END;
952 AST_LIST_UNLOCK(&module_list);
954 return cur ? 0 : -1;
957 struct ast_module *ast_module_ref(struct ast_module *mod)
959 ast_atomic_fetchadd_int(&mod->usecount, +1);
960 ast_update_use_count();
962 return mod;
965 void ast_module_unref(struct ast_module *mod)
967 ast_atomic_fetchadd_int(&mod->usecount, -1);
968 ast_update_use_count();