Let's also include aclocal.m4
[asterisk-bristuff.git] / main / loader.c
blob60c8a7676f52c2095a54bcd474a95bb886976949
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 #include <dlfcn.h>
57 #include "asterisk/md5.h"
58 #include "asterisk/utils.h"
60 #ifndef RTLD_NOW
61 #define RTLD_NOW 0
62 #endif
64 struct ast_module_user {
65 struct ast_channel *chan;
66 AST_LIST_ENTRY(ast_module_user) entry;
69 AST_LIST_HEAD(module_user_list, ast_module_user);
71 static unsigned char expected_key[] =
72 { 0x87, 0x76, 0x79, 0x35, 0x23, 0xea, 0x3a, 0xd3,
73 0x25, 0x2a, 0xbb, 0x35, 0x87, 0xe4, 0x22, 0x24 };
75 static char buildopt_sum[33] = AST_BUILDOPT_SUM;
77 static unsigned int embedding = 1; /* we always start out by registering embedded modules,
78 since they are here before we dlopen() any
81 struct ast_module {
82 const struct ast_module_info *info;
83 void *lib; /* the shared lib, or NULL if embedded */
84 int usecount; /* the number of 'users' currently in this module */
85 struct module_user_list users; /* the list of users in the module */
86 struct {
87 unsigned int running:1;
88 unsigned int declined:1;
89 } flags;
90 AST_LIST_ENTRY(ast_module) entry;
91 char resource[0];
94 static AST_LIST_HEAD_STATIC(module_list, ast_module);
96 struct loadupdate {
97 int (*updater)(void);
98 AST_LIST_ENTRY(loadupdate) entry;
101 static AST_LIST_HEAD_STATIC(updaters, loadupdate);
103 AST_MUTEX_DEFINE_STATIC(reloadlock);
105 /* when dynamic modules are being loaded, ast_module_register() will
106 need to know what filename the module was loaded from while it
107 is being registered
109 struct ast_module *resource_being_loaded;
111 /* XXX: should we check for duplicate resource names here? */
113 void ast_module_register(const struct ast_module_info *info)
115 struct ast_module *mod;
117 if (embedding) {
118 if (!(mod = ast_calloc(1, sizeof(*mod) + strlen(info->name) + 1)))
119 return;
120 strcpy(mod->resource, info->name);
121 } else {
122 mod = resource_being_loaded;
125 mod->info = info;
126 AST_LIST_HEAD_INIT(&mod->users);
128 /* during startup, before the loader has been initialized,
129 there are no threads, so there is no need to take the lock
130 on this list to manipulate it. it is also possible that it
131 might be unsafe to use the list lock at that point... so
132 let's avoid it altogether
134 if (!embedding)
135 AST_LIST_LOCK(&module_list);
137 /* it is paramount that the new entry be placed at the tail of
138 the list, otherwise the code that uses dlopen() to load
139 dynamic modules won't be able to find out if the module it
140 just opened was registered or failed to load
142 AST_LIST_INSERT_TAIL(&module_list, mod, entry);
144 if (!embedding)
145 AST_LIST_UNLOCK(&module_list);
147 /* give the module a copy of its own handle, for later use in registrations and the like */
148 *((struct ast_module **) &(info->self)) = mod;
151 void ast_module_unregister(const struct ast_module_info *info)
153 struct ast_module *mod = NULL;
155 /* it is assumed that the users list in the module structure
156 will already be empty, or we cannot have gotten to this
157 point
159 AST_LIST_LOCK(&module_list);
160 AST_LIST_TRAVERSE_SAFE_BEGIN(&module_list, mod, entry) {
161 if (mod->info == info) {
162 AST_LIST_REMOVE_CURRENT(&module_list, entry);
163 break;
166 AST_LIST_TRAVERSE_SAFE_END;
167 AST_LIST_UNLOCK(&module_list);
169 if (mod) {
170 AST_LIST_HEAD_DESTROY(&mod->users);
171 free(mod);
175 struct ast_module_user *__ast_module_user_add(struct ast_module *mod,
176 struct ast_channel *chan)
178 struct ast_module_user *u = ast_calloc(1, sizeof(*u));
180 if (!u)
181 return NULL;
183 u->chan = chan;
185 AST_LIST_LOCK(&mod->users);
186 AST_LIST_INSERT_HEAD(&mod->users, u, entry);
187 AST_LIST_UNLOCK(&mod->users);
189 ast_atomic_fetchadd_int(&mod->usecount, +1);
191 ast_update_use_count();
193 return u;
196 void __ast_module_user_remove(struct ast_module *mod, struct ast_module_user *u)
198 AST_LIST_LOCK(&mod->users);
199 AST_LIST_REMOVE(&mod->users, u, entry);
200 AST_LIST_UNLOCK(&mod->users);
201 ast_atomic_fetchadd_int(&mod->usecount, -1);
202 free(u);
204 ast_update_use_count();
207 void __ast_module_user_hangup_all(struct ast_module *mod)
209 struct ast_module_user *u;
211 AST_LIST_LOCK(&mod->users);
212 while ((u = AST_LIST_REMOVE_HEAD(&mod->users, entry))) {
213 ast_softhangup(u->chan, AST_SOFTHANGUP_APPUNLOAD);
214 ast_atomic_fetchadd_int(&mod->usecount, -1);
215 free(u);
217 AST_LIST_UNLOCK(&mod->users);
219 ast_update_use_count();
222 /*! \note
223 * In addition to modules, the reload command handles some extra keywords
224 * which are listed here together with the corresponding handlers.
225 * This table is also used by the command completion code.
227 static struct reload_classes {
228 const char *name;
229 int (*reload_fn)(void);
230 } reload_classes[] = { /* list in alpha order, longest match first for cli completion */
231 { "cdr", ast_cdr_engine_reload },
232 { "dnsmgr", dnsmgr_reload },
233 { "extconfig", read_config_maps },
234 { "enum", ast_enum_reload },
235 { "manager", reload_manager },
236 { "rtp", ast_rtp_reload },
237 { "http", ast_http_reload },
238 { "logger", logger_reload },
239 { NULL, NULL }
242 static int printdigest(const unsigned char *d)
244 int x, pos;
245 char buf[256]; /* large enough so we don't have to worry */
247 for (pos = 0, x = 0; x < 16; x++)
248 pos += sprintf(buf + pos, " %02x", *d++);
250 ast_log(LOG_DEBUG, "Unexpected signature:%s\n", buf);
252 return 0;
255 static int key_matches(const unsigned char *key1, const unsigned char *key2)
257 int x;
259 for (x = 0; x < 16; x++) {
260 if (key1[x] != key2[x])
261 return 0;
264 return 1;
267 static int verify_key(const unsigned char *key)
269 struct MD5Context c;
270 unsigned char digest[16];
272 MD5Init(&c);
273 MD5Update(&c, key, strlen((char *)key));
274 MD5Final(digest, &c);
276 if (key_matches(expected_key, digest))
277 return 0;
279 printdigest(digest);
281 return -1;
284 static int resource_name_match(const char *name1_in, const char *name2_in)
286 char *name1 = (char *) name1_in;
287 char *name2 = (char *) name2_in;
289 /* trim off any .so extensions */
290 if (!strcasecmp(name1 + strlen(name1) - 3, ".so")) {
291 name1 = ast_strdupa(name1);
292 name1[strlen(name1) - 3] = '\0';
294 if (!strcasecmp(name2 + strlen(name2) - 3, ".so")) {
295 name2 = ast_strdupa(name2);
296 name2[strlen(name2) - 3] = '\0';
299 return strcasecmp(name1, name2);
302 static struct ast_module *find_resource(const char *resource, int do_lock)
304 struct ast_module *cur;
306 if (do_lock)
307 AST_LIST_LOCK(&module_list);
309 AST_LIST_TRAVERSE(&module_list, cur, entry) {
310 if (!resource_name_match(resource, cur->resource))
311 break;
314 if (do_lock)
315 AST_LIST_UNLOCK(&module_list);
317 return cur;
320 #ifdef LOADABLE_MODULES
321 static void unload_dynamic_module(struct ast_module *mod)
323 void *lib = mod->lib;
325 /* WARNING: the structure pointed to by mod is going to
326 disappear when this operation succeeds, so we can't
327 dereference it */
329 if (lib)
330 while (!dlclose(lib));
333 static struct ast_module *load_dynamic_module(const char *resource_in, unsigned int global_symbols_only)
335 char fn[256];
336 void *lib;
337 struct ast_module *mod;
338 char *resource = (char *) resource_in;
339 unsigned int wants_global;
341 if (strcasecmp(resource + strlen(resource) - 3, ".so")) {
342 resource = alloca(strlen(resource_in) + 3);
343 strcpy(resource, resource_in);
344 strcat(resource, ".so");
347 snprintf(fn, sizeof(fn), "%s/%s", ast_config_AST_MODULE_DIR, resource);
349 /* make a first load of the module in 'quiet' mode... don't try to resolve
350 any symbols, and don't export any symbols. this will allow us to peek into
351 the module's info block (if available) to see what flags it has set */
353 if (!(resource_being_loaded = ast_calloc(1, sizeof(*resource_being_loaded) + strlen(resource) + 1)))
354 return NULL;
356 strcpy(resource_being_loaded->resource, resource);
358 if (!(lib = dlopen(fn, RTLD_LAZY | RTLD_LOCAL))) {
359 ast_log(LOG_WARNING, "Error loading module '%s': %s\n", resource_in, dlerror());
360 free(resource_being_loaded);
361 return NULL;
364 /* the dlopen() succeeded, let's find out if the module
365 registered itself */
366 /* note that this will only work properly as long as
367 ast_module_register() (which is called by the module's
368 constructor) places the new module at the tail of the
369 module_list
371 if (resource_being_loaded != (mod = AST_LIST_LAST(&module_list))) {
372 ast_log(LOG_WARNING, "Module '%s' did not register itself during load\n", resource_in);
373 /* no, it did not, so close it and return */
374 while (!dlclose(lib));
375 /* note that the module's destructor will call ast_module_unregister(),
376 which will free the structure we allocated in resource_being_loaded */
377 return NULL;
380 wants_global = ast_test_flag(mod->info, AST_MODFLAG_GLOBAL_SYMBOLS);
382 /* if we are being asked only to load modules that provide global symbols,
383 and this one does not, then close it and return */
384 if (global_symbols_only && !wants_global) {
385 while (!dlclose(lib));
386 return NULL;
389 /* if the system supports RTLD_NOLOAD, we can just 'promote' the flags
390 on the already-opened library to what we want... if not, we have to
391 close it and start over
393 #if defined(HAVE_RTLD_NOLOAD) && !defined(__Darwin__)
394 if (!dlopen(fn, RTLD_NOLOAD | (wants_global ? RTLD_LAZY | RTLD_GLOBAL : RTLD_NOW | RTLD_LOCAL))) {
395 ast_log(LOG_WARNING, "Unable to promote flags on module '%s': %s\n", resource_in, dlerror());
396 while (!dlclose(lib));
397 free(resource_being_loaded);
398 return NULL;
400 #else
401 while (!dlclose(lib));
402 resource_being_loaded = NULL;
404 /* start the load process again */
406 if (!(resource_being_loaded = ast_calloc(1, sizeof(*resource_being_loaded) + strlen(resource) + 1)))
407 return NULL;
409 strcpy(resource_being_loaded->resource, resource);
411 if (!(lib = dlopen(fn, wants_global ? RTLD_LAZY | RTLD_GLOBAL : RTLD_NOW | RTLD_LOCAL))) {
412 ast_log(LOG_WARNING, "Error loading module '%s': %s\n", resource_in, dlerror());
413 free(resource_being_loaded);
414 return NULL;
417 /* since the module was successfully opened, and it registered itself
418 the previous time we did that, we're going to assume it worked this
419 time too :) */
420 #endif
422 AST_LIST_LAST(&module_list)->lib = lib;
423 resource_being_loaded = NULL;
425 return AST_LIST_LAST(&module_list);
427 #endif
429 void ast_module_shutdown(void)
431 struct ast_module *mod;
432 AST_LIST_HEAD_NOLOCK_STATIC(local_module_list, ast_module);
434 /* We have to call the unload() callbacks in reverse order that the modules
435 * exist in the module list so it is the reverse order of how they were
436 * loaded. */
438 AST_LIST_LOCK(&module_list);
439 while ((mod = AST_LIST_REMOVE_HEAD(&module_list, entry)))
440 AST_LIST_INSERT_HEAD(&local_module_list, mod, entry);
441 AST_LIST_UNLOCK(&module_list);
443 while ((mod = AST_LIST_REMOVE_HEAD(&local_module_list, entry))) {
444 if (mod->info->unload)
445 mod->info->unload();
446 /* Since this should only be called when shutting down "gracefully",
447 * all channels should be down before we get to this point, meaning
448 * there will be no module users left. */
449 AST_LIST_HEAD_DESTROY(&mod->users);
450 free(mod);
454 int ast_unload_resource(const char *resource_name, enum ast_module_unload_mode force)
456 struct ast_module *mod;
457 int res = -1;
458 int error = 0;
460 AST_LIST_LOCK(&module_list);
462 if (!(mod = find_resource(resource_name, 0))) {
463 AST_LIST_UNLOCK(&module_list);
464 return 0;
467 if (!(mod->flags.running || mod->flags.declined))
468 error = 1;
470 if (!mod->lib) {
471 ast_log(LOG_WARNING, "Unloading embedded modules is not supported.\n");
472 error = 1;
475 if (!error && (mod->usecount > 0)) {
476 if (force)
477 ast_log(LOG_WARNING, "Warning: Forcing removal of module '%s' with use count %d\n",
478 resource_name, mod->usecount);
479 else {
480 ast_log(LOG_WARNING, "Soft unload failed, '%s' has use count %d\n", resource_name,
481 mod->usecount);
482 error = 1;
486 if (!error) {
487 __ast_module_user_hangup_all(mod);
488 res = mod->info->unload();
490 if (res) {
491 ast_log(LOG_WARNING, "Firm unload failed for %s\n", resource_name);
492 if (force <= AST_FORCE_FIRM)
493 error = 1;
494 else
495 ast_log(LOG_WARNING, "** Dangerous **: Unloading resource anyway, at user request\n");
499 if (!error)
500 mod->flags.running = mod->flags.declined = 0;
502 AST_LIST_UNLOCK(&module_list);
504 #ifdef LOADABLE_MODULES
505 if (!error)
506 unload_dynamic_module(mod);
507 #endif
509 if (!error)
510 ast_update_use_count();
512 return res;
515 char *ast_module_helper(const char *line, const char *word, int pos, int state, int rpos, int needsreload)
517 struct ast_module *cur;
518 int i, which=0, l = strlen(word);
519 char *ret = NULL;
521 if (pos != rpos)
522 return NULL;
524 AST_LIST_LOCK(&module_list);
525 AST_LIST_TRAVERSE(&module_list, cur, entry) {
526 if (!strncasecmp(word, cur->resource, l) &&
527 (cur->info->reload || !needsreload) &&
528 ++which > state) {
529 ret = strdup(cur->resource);
530 break;
533 AST_LIST_UNLOCK(&module_list);
535 if (!ret) {
536 for (i=0; !ret && reload_classes[i].name; i++) {
537 if (!strncasecmp(word, reload_classes[i].name, l) && ++which > state)
538 ret = strdup(reload_classes[i].name);
542 return ret;
545 int ast_module_reload(const char *name)
547 struct ast_module *cur;
548 int res = 0; /* return value. 0 = not found, others, see below */
549 int i;
551 if (ast_mutex_trylock(&reloadlock)) {
552 ast_verbose("The previous reload command didn't finish yet\n");
553 return -1; /* reload already in progress */
555 ast_lastreloadtime = time(NULL);
557 /* Call "predefined" reload here first */
558 for (i = 0; reload_classes[i].name; i++) {
559 if (!name || !strcasecmp(name, reload_classes[i].name)) {
560 reload_classes[i].reload_fn(); /* XXX should check error ? */
561 res = 2; /* found and reloaded */
565 if (name && res) {
566 ast_mutex_unlock(&reloadlock);
567 return res;
570 AST_LIST_LOCK(&module_list);
571 AST_LIST_TRAVERSE(&module_list, cur, entry) {
572 const struct ast_module_info *info = cur->info;
574 if (name && resource_name_match(name, cur->resource))
575 continue;
577 if (!cur->flags.running || cur->flags.declined) {
578 if (!name)
579 continue;
580 ast_log(LOG_NOTICE, "The module '%s' was not properly initialized. "
581 "Before reloading the module, you must run \"module load %s\" "
582 "and fix whatever is preventing the module from being initialized.\n",
583 name, name);
584 res = 2; /* Don't report that the module was not found */
585 break;
588 if (!info->reload) { /* cannot be reloaded */
589 if (res < 1) /* store result if possible */
590 res = 1; /* 1 = no reload() method */
591 continue;
594 res = 2;
595 if (option_verbose > 2)
596 ast_verbose(VERBOSE_PREFIX_3 "Reloading module '%s' (%s)\n", cur->resource, info->description);
597 info->reload();
599 AST_LIST_UNLOCK(&module_list);
601 ast_mutex_unlock(&reloadlock);
603 return res;
606 static unsigned int inspect_module(const struct ast_module *mod)
608 if (!mod->info->description) {
609 ast_log(LOG_WARNING, "Module '%s' does not provide a description.\n", mod->resource);
610 return 1;
613 if (!mod->info->key) {
614 ast_log(LOG_WARNING, "Module '%s' does not provide a license key.\n", mod->resource);
615 return 1;
618 if (verify_key((unsigned char *) mod->info->key)) {
619 ast_log(LOG_WARNING, "Module '%s' did not provide a valid license key.\n", mod->resource);
620 return 1;
623 if (!ast_test_flag(mod->info, AST_MODFLAG_BUILDSUM)) {
624 ast_log(LOG_WARNING, "Module '%s' was not compiled against a recent version of Asterisk and may cause instability.\n", mod->resource);
625 } else if (!ast_strlen_zero(mod->info->buildopt_sum) &&
626 strcmp(buildopt_sum, mod->info->buildopt_sum)) {
627 ast_log(LOG_WARNING, "Module '%s' was not compiled with the same compile-time options as this version of Asterisk.\n", mod->resource);
628 ast_log(LOG_WARNING, "Module '%s' will not be initialized as it may cause instability.\n", mod->resource);
629 return 1;
632 return 0;
635 static enum ast_module_load_result load_resource(const char *resource_name, unsigned int global_symbols_only)
637 struct ast_module *mod;
638 enum ast_module_load_result res = AST_MODULE_LOAD_SUCCESS;
639 char tmp[256];
641 if ((mod = find_resource(resource_name, 0))) {
642 if (mod->flags.running) {
643 ast_log(LOG_WARNING, "Module '%s' already exists.\n", resource_name);
644 return AST_MODULE_LOAD_DECLINE;
646 if (global_symbols_only && !ast_test_flag(mod->info, AST_MODFLAG_GLOBAL_SYMBOLS))
647 return AST_MODULE_LOAD_SKIP;
648 } else {
649 #ifdef LOADABLE_MODULES
650 if (!(mod = load_dynamic_module(resource_name, global_symbols_only))) {
651 /* don't generate a warning message during load_modules() */
652 if (!global_symbols_only) {
653 ast_log(LOG_WARNING, "Module '%s' could not be loaded.\n", resource_name);
654 return AST_MODULE_LOAD_DECLINE;
655 } else {
656 return AST_MODULE_LOAD_SKIP;
659 #else
660 ast_log(LOG_WARNING, "Module '%s' could not be loaded.\n", resource_name);
661 return AST_MODULE_LOAD_DECLINE;
662 #endif
665 if (inspect_module(mod)) {
666 ast_log(LOG_WARNING, "Module '%s' could not be loaded.\n", resource_name);
667 #ifdef LOADABLE_MODULES
668 unload_dynamic_module(mod);
669 #endif
670 return AST_MODULE_LOAD_DECLINE;
673 mod->flags.declined = 0;
675 if (mod->info->load)
676 res = mod->info->load();
678 switch (res) {
679 case AST_MODULE_LOAD_SUCCESS:
680 if (!ast_fully_booted) {
681 if (option_verbose)
682 ast_verbose("%s => (%s)\n", resource_name, term_color(tmp, mod->info->description, COLOR_BROWN, COLOR_BLACK, sizeof(tmp)));
683 if (ast_opt_console && !option_verbose)
684 ast_verbose( ".");
685 } else {
686 if (option_verbose)
687 ast_verbose(VERBOSE_PREFIX_1 "Loaded %s => (%s)\n", resource_name, mod->info->description);
690 mod->flags.running = 1;
692 ast_update_use_count();
693 break;
694 case AST_MODULE_LOAD_DECLINE:
695 mod->flags.declined = 1;
696 break;
697 case AST_MODULE_LOAD_FAILURE:
698 break;
699 case AST_MODULE_LOAD_SKIP:
700 /* modules should never return this value */
701 break;
704 return res;
707 int ast_load_resource(const char *resource_name)
709 AST_LIST_LOCK(&module_list);
710 load_resource(resource_name, 0);
711 AST_LIST_UNLOCK(&module_list);
713 return 0;
716 struct load_order_entry {
717 char *resource;
718 AST_LIST_ENTRY(load_order_entry) entry;
721 AST_LIST_HEAD_NOLOCK(load_order, load_order_entry);
723 static struct load_order_entry *add_to_load_order(const char *resource, struct load_order *load_order)
725 struct load_order_entry *order;
727 AST_LIST_TRAVERSE(load_order, order, entry) {
728 if (!resource_name_match(order->resource, resource))
729 return NULL;
732 if (!(order = ast_calloc(1, sizeof(*order))))
733 return NULL;
735 order->resource = ast_strdup(resource);
736 AST_LIST_INSERT_TAIL(load_order, order, entry);
738 return order;
741 static int translate_module_name(char *oldname, char *newname)
743 if (!strcasecmp(oldname, "app_zapbarge.so"))
744 ast_copy_string(newname, "app_dahdibarge.so", 18);
745 else if(!strcasecmp(oldname, "app_zapras.so"))
746 ast_copy_string(newname, "app_dahdiras.so", 16);
747 else if(!strcasecmp(oldname, "app_zapscan.so"))
748 ast_copy_string(newname, "app_dahdiscan.so", 17);
749 else if(!strcasecmp(oldname, "codec_zap.so"))
750 ast_copy_string(newname, "codec_dahdi.so", 16);
751 else
752 return -1; /* no use for newname, oldname is fine */
754 return 0;
758 int load_modules(unsigned int preload_only)
760 struct ast_config *cfg;
761 struct ast_module *mod;
762 struct load_order_entry *order;
763 struct ast_variable *v;
764 unsigned int load_count;
765 struct load_order load_order;
766 int res = 0;
768 int translate_status;
769 char newname[18]; /* although this would normally be 80, max length in translate_module_name is 18 */
770 #ifdef LOADABLE_MODULES
771 struct dirent *dirent;
772 DIR *dir;
773 #endif
775 /* all embedded modules have registered themselves by now */
776 embedding = 0;
778 if (option_verbose)
779 ast_verbose("Asterisk Dynamic Loader Starting:\n");
781 AST_LIST_HEAD_INIT_NOLOCK(&load_order);
783 AST_LIST_LOCK(&module_list);
785 if (!(cfg = ast_config_load(AST_MODULE_CONFIG))) {
786 ast_log(LOG_WARNING, "No '%s' found, no modules will be loaded.\n", AST_MODULE_CONFIG);
787 goto done;
790 /* first, find all the modules we have been explicitly requested to load */
791 for (v = ast_variable_browse(cfg, "modules"); v; v = v->next) {
792 if (!strcasecmp(v->name, preload_only ? "preload" : "load")) {
793 translate_status = translate_module_name(v->value, newname);
794 if (!translate_status)
795 ast_log(LOG_WARNING, "Use of old module name %s is deprecated, please use %s instead.\n", v->value, newname);
796 add_to_load_order(translate_status ? v->value : newname, &load_order);
800 /* check if 'autoload' is on */
801 if (!preload_only && ast_true(ast_variable_retrieve(cfg, "modules", "autoload"))) {
802 /* if so, first add all the embedded modules that are not already running to the load order */
803 AST_LIST_TRAVERSE(&module_list, mod, entry) {
804 /* if it's not embedded, skip it */
805 if (mod->lib)
806 continue;
808 if (mod->flags.running)
809 continue;
811 order = add_to_load_order(mod->resource, &load_order);
814 #ifdef LOADABLE_MODULES
815 /* if we are allowed to load dynamic modules, scan the directory for
816 for all available modules and add them as well */
817 if ((dir = opendir(ast_config_AST_MODULE_DIR))) {
818 while ((dirent = readdir(dir))) {
819 int ld = strlen(dirent->d_name);
821 /* Must end in .so to load it. */
823 if (ld < 4)
824 continue;
826 if (strcasecmp(dirent->d_name + ld - 3, ".so"))
827 continue;
829 /* if there is already a module by this name in the module_list,
830 skip this file */
831 if (find_resource(dirent->d_name, 0))
832 continue;
834 add_to_load_order(dirent->d_name, &load_order);
837 closedir(dir);
838 } else {
839 if (!ast_opt_quiet)
840 ast_log(LOG_WARNING, "Unable to open modules directory '%s'.\n",
841 ast_config_AST_MODULE_DIR);
843 #endif
846 /* now scan the config for any modules we are prohibited from loading and
847 remove them from the load order */
848 for (v = ast_variable_browse(cfg, "modules"); v; v = v->next) {
849 if (strcasecmp(v->name, "noload"))
850 continue;
852 AST_LIST_TRAVERSE_SAFE_BEGIN(&load_order, order, entry) {
853 translate_status = translate_module_name(v->value, newname);
854 if (!resource_name_match(order->resource, translate_status ? v->value : newname)) {
855 if (!translate_status)
856 ast_log(LOG_WARNING, "Use of old module name %s is deprecated, please use %s instead.\n", v->value, newname);
857 AST_LIST_REMOVE_CURRENT(&load_order, entry);
858 free(order->resource);
859 free(order);
862 AST_LIST_TRAVERSE_SAFE_END;
865 /* we are done with the config now, all the information we need is in the
866 load_order list */
867 ast_config_destroy(cfg);
869 load_count = 0;
870 AST_LIST_TRAVERSE(&load_order, order, entry)
871 load_count++;
873 if (load_count)
874 ast_log(LOG_NOTICE, "%d modules will be loaded.\n", load_count);
876 /* first, load only modules that provide global symbols */
877 AST_LIST_TRAVERSE_SAFE_BEGIN(&load_order, order, entry) {
878 switch (load_resource(order->resource, 1)) {
879 case AST_MODULE_LOAD_SUCCESS:
880 case AST_MODULE_LOAD_DECLINE:
881 AST_LIST_REMOVE_CURRENT(&load_order, entry);
882 free(order->resource);
883 free(order);
884 break;
885 case AST_MODULE_LOAD_FAILURE:
886 res = -1;
887 goto done;
888 case AST_MODULE_LOAD_SKIP:
889 /* try again later */
890 break;
893 AST_LIST_TRAVERSE_SAFE_END;
895 /* now load everything else */
896 AST_LIST_TRAVERSE_SAFE_BEGIN(&load_order, order, entry) {
897 switch (load_resource(order->resource, 0)) {
898 case AST_MODULE_LOAD_SUCCESS:
899 case AST_MODULE_LOAD_DECLINE:
900 AST_LIST_REMOVE_CURRENT(&load_order, entry);
901 free(order->resource);
902 free(order);
903 break;
904 case AST_MODULE_LOAD_FAILURE:
905 res = -1;
906 goto done;
907 case AST_MODULE_LOAD_SKIP:
908 /* should not happen */
909 break;
912 AST_LIST_TRAVERSE_SAFE_END;
914 done:
915 while ((order = AST_LIST_REMOVE_HEAD(&load_order, entry))) {
916 free(order->resource);
917 free(order);
920 AST_LIST_UNLOCK(&module_list);
922 return res;
925 void ast_update_use_count(void)
927 /* Notify any module monitors that the use count for a
928 resource has changed */
929 struct loadupdate *m;
931 AST_LIST_LOCK(&updaters);
932 AST_LIST_TRAVERSE(&updaters, m, entry)
933 m->updater();
934 AST_LIST_UNLOCK(&updaters);
937 int ast_update_module_list(int (*modentry)(const char *module, const char *description, int usecnt, const char *like),
938 const char *like)
940 struct ast_module *cur;
941 int unlock = -1;
942 int total_mod_loaded = 0;
944 if (AST_LIST_TRYLOCK(&module_list))
945 unlock = 0;
947 AST_LIST_TRAVERSE(&module_list, cur, entry) {
948 total_mod_loaded += modentry(cur->resource, cur->info->description, cur->usecount, like);
951 if (unlock)
952 AST_LIST_UNLOCK(&module_list);
954 return total_mod_loaded;
957 int ast_loader_register(int (*v)(void))
959 struct loadupdate *tmp;
961 if (!(tmp = ast_malloc(sizeof(*tmp))))
962 return -1;
964 tmp->updater = v;
965 AST_LIST_LOCK(&updaters);
966 AST_LIST_INSERT_HEAD(&updaters, tmp, entry);
967 AST_LIST_UNLOCK(&updaters);
969 return 0;
972 int ast_loader_unregister(int (*v)(void))
974 struct loadupdate *cur;
976 AST_LIST_LOCK(&updaters);
977 AST_LIST_TRAVERSE_SAFE_BEGIN(&updaters, cur, entry) {
978 if (cur->updater == v) {
979 AST_LIST_REMOVE_CURRENT(&updaters, entry);
980 break;
983 AST_LIST_TRAVERSE_SAFE_END;
984 AST_LIST_UNLOCK(&updaters);
986 return cur ? 0 : -1;
989 struct ast_module *ast_module_ref(struct ast_module *mod)
991 ast_atomic_fetchadd_int(&mod->usecount, +1);
992 ast_update_use_count();
994 return mod;
997 void ast_module_unref(struct ast_module *mod)
999 ast_atomic_fetchadd_int(&mod->usecount, -1);
1000 ast_update_use_count();