fix a flaw found while experimenting with structure alignment and padding; low-fence...
[asterisk-bristuff.git] / main / loader.c
blob7203ded21f63b2b64fbfbb908c4de8e8b1014c66
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 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
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 { "logger", logger_reload },
243 { NULL, NULL }
246 static int printdigest(const unsigned char *d)
248 int x, pos;
249 char buf[256]; /* large enough so we don't have to worry */
251 for (pos = 0, x = 0; x < 16; x++)
252 pos += sprintf(buf + pos, " %02x", *d++);
254 ast_log(LOG_DEBUG, "Unexpected signature:%s\n", buf);
256 return 0;
259 static int key_matches(const unsigned char *key1, const unsigned char *key2)
261 int x;
263 for (x = 0; x < 16; x++) {
264 if (key1[x] != key2[x])
265 return 0;
268 return 1;
271 static int verify_key(const unsigned char *key)
273 struct MD5Context c;
274 unsigned char digest[16];
276 MD5Init(&c);
277 MD5Update(&c, key, strlen((char *)key));
278 MD5Final(digest, &c);
280 if (key_matches(expected_key, digest))
281 return 0;
283 printdigest(digest);
285 return -1;
288 static int resource_name_match(const char *name1_in, const char *name2_in)
290 char *name1 = (char *) name1_in;
291 char *name2 = (char *) name2_in;
293 /* trim off any .so extensions */
294 if (!strcasecmp(name1 + strlen(name1) - 3, ".so")) {
295 name1 = ast_strdupa(name1);
296 name1[strlen(name1) - 3] = '\0';
298 if (!strcasecmp(name2 + strlen(name2) - 3, ".so")) {
299 name2 = ast_strdupa(name2);
300 name2[strlen(name2) - 3] = '\0';
303 return strcasecmp(name1, name2);
306 static struct ast_module *find_resource(const char *resource, int do_lock)
308 struct ast_module *cur;
310 if (do_lock)
311 AST_LIST_LOCK(&module_list);
313 AST_LIST_TRAVERSE(&module_list, cur, entry) {
314 if (!resource_name_match(resource, cur->resource))
315 break;
318 if (do_lock)
319 AST_LIST_UNLOCK(&module_list);
321 return cur;
324 #ifdef LOADABLE_MODULES
325 static void unload_dynamic_module(struct ast_module *mod)
327 void *lib = mod->lib;
329 /* WARNING: the structure pointed to by mod is going to
330 disappear when this operation succeeds, so we can't
331 dereference it */
333 if (lib)
334 while (!dlclose(lib));
337 static struct ast_module *load_dynamic_module(const char *resource_in, unsigned int global_symbols_only)
339 char fn[256];
340 void *lib;
341 struct ast_module *mod;
342 char *resource = (char *) resource_in;
343 unsigned int wants_global;
345 if (strcasecmp(resource + strlen(resource) - 3, ".so")) {
346 resource = alloca(strlen(resource_in) + 3);
347 strcpy(resource, resource_in);
348 strcat(resource, ".so");
351 snprintf(fn, sizeof(fn), "%s/%s", ast_config_AST_MODULE_DIR, resource);
353 /* make a first load of the module in 'quiet' mode... don't try to resolve
354 any symbols, and don't export any symbols. this will allow us to peek into
355 the module's info block (if available) to see what flags it has set */
357 if (!(resource_being_loaded = ast_calloc(1, sizeof(*resource_being_loaded) + strlen(resource) + 1)))
358 return NULL;
360 strcpy(resource_being_loaded->resource, resource);
362 if (!(lib = dlopen(fn, RTLD_LAZY | RTLD_LOCAL))) {
363 ast_log(LOG_WARNING, "Error loading module '%s': %s\n", resource_in, dlerror());
364 free(resource_being_loaded);
365 return NULL;
368 /* the dlopen() succeeded, let's find out if the module
369 registered itself */
370 /* note that this will only work properly as long as
371 ast_module_register() (which is called by the module's
372 constructor) places the new module at the tail of the
373 module_list
375 if (resource_being_loaded != (mod = AST_LIST_LAST(&module_list))) {
376 ast_log(LOG_WARNING, "Module '%s' did not register itself during load\n", resource_in);
377 /* no, it did not, so close it and return */
378 while (!dlclose(lib));
379 /* note that the module's destructor will call ast_module_unregister(),
380 which will free the structure we allocated in resource_being_loaded */
381 return NULL;
384 wants_global = ast_test_flag(mod->info, AST_MODFLAG_GLOBAL_SYMBOLS);
386 /* if we are being asked only to load modules that provide global symbols,
387 and this one does not, then close it and return */
388 if (global_symbols_only && !wants_global) {
389 while (!dlclose(lib));
390 return NULL;
393 /* if the system supports RTLD_NOLOAD, we can just 'promote' the flags
394 on the already-opened library to what we want... if not, we have to
395 close it and start over
397 #if defined(HAVE_RTLD_NOLOAD) && !defined(__Darwin__)
398 if (!dlopen(fn, RTLD_NOLOAD | (wants_global ? RTLD_LAZY | RTLD_GLOBAL : RTLD_NOW | RTLD_LOCAL))) {
399 ast_log(LOG_WARNING, "Unable to promote flags on module '%s': %s\n", resource_in, dlerror());
400 while (!dlclose(lib));
401 free(resource_being_loaded);
402 return NULL;
404 #else
405 while (!dlclose(lib));
406 resource_being_loaded = NULL;
408 /* start the load process again */
410 if (!(resource_being_loaded = ast_calloc(1, sizeof(*resource_being_loaded) + strlen(resource) + 1)))
411 return NULL;
413 strcpy(resource_being_loaded->resource, resource);
415 if (!(lib = dlopen(fn, wants_global ? RTLD_LAZY | RTLD_GLOBAL : RTLD_NOW | RTLD_LOCAL))) {
416 ast_log(LOG_WARNING, "Error loading module '%s': %s\n", resource_in, dlerror());
417 free(resource_being_loaded);
418 return NULL;
421 /* since the module was successfully opened, and it registered itself
422 the previous time we did that, we're going to assume it worked this
423 time too :) */
424 #endif
426 AST_LIST_LAST(&module_list)->lib = lib;
427 resource_being_loaded = NULL;
429 return AST_LIST_LAST(&module_list);
431 #endif
433 void ast_module_shutdown(void)
435 struct ast_module *mod;
436 AST_LIST_HEAD_NOLOCK_STATIC(local_module_list, ast_module);
438 /* We have to call the unload() callbacks in reverse order that the modules
439 * exist in the module list so it is the reverse order of how they were
440 * loaded. */
442 AST_LIST_LOCK(&module_list);
443 while ((mod = AST_LIST_REMOVE_HEAD(&module_list, entry)))
444 AST_LIST_INSERT_HEAD(&local_module_list, mod, entry);
445 AST_LIST_UNLOCK(&module_list);
447 while ((mod = AST_LIST_REMOVE_HEAD(&local_module_list, entry))) {
448 if (mod->info->unload)
449 mod->info->unload();
450 /* Since this should only be called when shutting down "gracefully",
451 * all channels should be down before we get to this point, meaning
452 * there will be no module users left. */
453 AST_LIST_HEAD_DESTROY(&mod->users);
454 free(mod);
458 int ast_unload_resource(const char *resource_name, enum ast_module_unload_mode force)
460 struct ast_module *mod;
461 int res = -1;
462 int error = 0;
464 AST_LIST_LOCK(&module_list);
466 if (!(mod = find_resource(resource_name, 0))) {
467 AST_LIST_UNLOCK(&module_list);
468 return 0;
471 if (!(mod->flags.running || mod->flags.declined))
472 error = 1;
474 if (!mod->lib) {
475 ast_log(LOG_WARNING, "Unloading embedded modules is not supported.\n");
476 error = 1;
479 if (!error && (mod->usecount > 0)) {
480 if (force)
481 ast_log(LOG_WARNING, "Warning: Forcing removal of module '%s' with use count %d\n",
482 resource_name, mod->usecount);
483 else {
484 ast_log(LOG_WARNING, "Soft unload failed, '%s' has use count %d\n", resource_name,
485 mod->usecount);
486 error = 1;
490 if (!error) {
491 __ast_module_user_hangup_all(mod);
492 res = mod->info->unload();
494 if (res) {
495 ast_log(LOG_WARNING, "Firm unload failed for %s\n", resource_name);
496 if (force <= AST_FORCE_FIRM)
497 error = 1;
498 else
499 ast_log(LOG_WARNING, "** Dangerous **: Unloading resource anyway, at user request\n");
503 if (!error)
504 mod->flags.running = mod->flags.declined = 0;
506 AST_LIST_UNLOCK(&module_list);
508 #ifdef LOADABLE_MODULES
509 if (!error)
510 unload_dynamic_module(mod);
511 #endif
513 if (!error)
514 ast_update_use_count();
516 return res;
519 char *ast_module_helper(const char *line, const char *word, int pos, int state, int rpos, int needsreload)
521 struct ast_module *cur;
522 int i, which=0, l = strlen(word);
523 char *ret = NULL;
525 if (pos != rpos)
526 return NULL;
528 AST_LIST_LOCK(&module_list);
529 AST_LIST_TRAVERSE(&module_list, cur, entry) {
530 if (!strncasecmp(word, cur->resource, l) &&
531 (cur->info->reload || !needsreload) &&
532 ++which > state) {
533 ret = strdup(cur->resource);
534 break;
537 AST_LIST_UNLOCK(&module_list);
539 if (!ret) {
540 for (i=0; !ret && reload_classes[i].name; i++) {
541 if (!strncasecmp(word, reload_classes[i].name, l) && ++which > state)
542 ret = strdup(reload_classes[i].name);
546 return ret;
549 int ast_module_reload(const char *name)
551 struct ast_module *cur;
552 int res = 0; /* return value. 0 = not found, others, see below */
553 int i;
555 if (ast_mutex_trylock(&reloadlock)) {
556 ast_verbose("The previous reload command didn't finish yet\n");
557 return -1; /* reload already in progress */
559 ast_lastreloadtime = time(NULL);
561 /* Call "predefined" reload here first */
562 for (i = 0; reload_classes[i].name; i++) {
563 if (!name || !strcasecmp(name, reload_classes[i].name)) {
564 reload_classes[i].reload_fn(); /* XXX should check error ? */
565 res = 2; /* found and reloaded */
569 if (name && res) {
570 ast_mutex_unlock(&reloadlock);
571 return res;
574 AST_LIST_LOCK(&module_list);
575 AST_LIST_TRAVERSE(&module_list, cur, entry) {
576 const struct ast_module_info *info = cur->info;
578 if (name && resource_name_match(name, cur->resource))
579 continue;
581 if (!cur->flags.running || cur->flags.declined) {
582 if (!name)
583 continue;
584 ast_log(LOG_NOTICE, "The module '%s' was not properly initialized. "
585 "Before reloading the module, you must run \"module load %s\" "
586 "and fix whatever is preventing the module from being initialized.\n",
587 name, name);
588 res = 2; /* Don't report that the module was not found */
589 break;
592 if (!info->reload) { /* cannot be reloaded */
593 if (res < 1) /* store result if possible */
594 res = 1; /* 1 = no reload() method */
595 continue;
598 res = 2;
599 if (option_verbose > 2)
600 ast_verbose(VERBOSE_PREFIX_3 "Reloading module '%s' (%s)\n", cur->resource, info->description);
601 info->reload();
603 AST_LIST_UNLOCK(&module_list);
605 ast_mutex_unlock(&reloadlock);
607 return res;
610 static unsigned int inspect_module(const struct ast_module *mod)
612 if (!mod->info->description) {
613 ast_log(LOG_WARNING, "Module '%s' does not provide a description.\n", mod->resource);
614 return 1;
617 if (!mod->info->key) {
618 ast_log(LOG_WARNING, "Module '%s' does not provide a license key.\n", mod->resource);
619 return 1;
622 if (verify_key((unsigned char *) mod->info->key)) {
623 ast_log(LOG_WARNING, "Module '%s' did not provide a valid license key.\n", mod->resource);
624 return 1;
627 if (!ast_test_flag(mod->info, AST_MODFLAG_BUILDSUM)) {
628 ast_log(LOG_WARNING, "Module '%s' was not compiled against a recent version of Asterisk and may cause instability.\n", mod->resource);
629 } else if (!ast_strlen_zero(mod->info->buildopt_sum) &&
630 strcmp(buildopt_sum, mod->info->buildopt_sum)) {
631 ast_log(LOG_WARNING, "Module '%s' was not compiled with the same compile-time options as this version of Asterisk.\n", mod->resource);
632 ast_log(LOG_WARNING, "Module '%s' will not be initialized as it may cause instability.\n", mod->resource);
633 return 1;
636 return 0;
639 static enum ast_module_load_result load_resource(const char *resource_name, unsigned int global_symbols_only)
641 struct ast_module *mod;
642 enum ast_module_load_result res = AST_MODULE_LOAD_SUCCESS;
643 char tmp[256];
645 if ((mod = find_resource(resource_name, 0))) {
646 if (mod->flags.running) {
647 ast_log(LOG_WARNING, "Module '%s' already exists.\n", resource_name);
648 return AST_MODULE_LOAD_DECLINE;
650 if (global_symbols_only && !ast_test_flag(mod->info, AST_MODFLAG_GLOBAL_SYMBOLS))
651 return AST_MODULE_LOAD_SKIP;
652 } else {
653 #ifdef LOADABLE_MODULES
654 if (!(mod = load_dynamic_module(resource_name, global_symbols_only))) {
655 /* don't generate a warning message during load_modules() */
656 if (!global_symbols_only) {
657 ast_log(LOG_WARNING, "Module '%s' could not be loaded.\n", resource_name);
658 return AST_MODULE_LOAD_DECLINE;
659 } else {
660 return AST_MODULE_LOAD_SKIP;
663 #else
664 ast_log(LOG_WARNING, "Module '%s' could not be loaded.\n", resource_name);
665 return AST_MODULE_LOAD_DECLINE;
666 #endif
669 if (inspect_module(mod)) {
670 ast_log(LOG_WARNING, "Module '%s' could not be loaded.\n", resource_name);
671 #ifdef LOADABLE_MODULES
672 unload_dynamic_module(mod);
673 #endif
674 return AST_MODULE_LOAD_DECLINE;
677 mod->flags.declined = 0;
679 if (mod->info->load)
680 res = mod->info->load();
682 switch (res) {
683 case AST_MODULE_LOAD_SUCCESS:
684 if (!ast_fully_booted) {
685 if (option_verbose)
686 ast_verbose("%s => (%s)\n", resource_name, term_color(tmp, mod->info->description, COLOR_BROWN, COLOR_BLACK, sizeof(tmp)));
687 if (ast_opt_console && !option_verbose)
688 ast_verbose( ".");
689 } else {
690 if (option_verbose)
691 ast_verbose(VERBOSE_PREFIX_1 "Loaded %s => (%s)\n", resource_name, mod->info->description);
694 mod->flags.running = 1;
696 ast_update_use_count();
697 break;
698 case AST_MODULE_LOAD_DECLINE:
699 mod->flags.declined = 1;
700 break;
701 case AST_MODULE_LOAD_FAILURE:
702 break;
703 case AST_MODULE_LOAD_SKIP:
704 /* modules should never return this value */
705 break;
708 return res;
711 int ast_load_resource(const char *resource_name)
713 AST_LIST_LOCK(&module_list);
714 load_resource(resource_name, 0);
715 AST_LIST_UNLOCK(&module_list);
717 return 0;
720 struct load_order_entry {
721 char *resource;
722 AST_LIST_ENTRY(load_order_entry) entry;
725 AST_LIST_HEAD_NOLOCK(load_order, load_order_entry);
727 static struct load_order_entry *add_to_load_order(const char *resource, struct load_order *load_order)
729 struct load_order_entry *order;
731 AST_LIST_TRAVERSE(load_order, order, entry) {
732 if (!resource_name_match(order->resource, resource))
733 return NULL;
736 if (!(order = ast_calloc(1, sizeof(*order))))
737 return NULL;
739 order->resource = ast_strdup(resource);
740 AST_LIST_INSERT_TAIL(load_order, order, entry);
742 return order;
745 static int translate_module_name(char *oldname, char *newname)
747 if (!strcasecmp(oldname, "app_zapbarge.so"))
748 ast_copy_string(newname, "app_dahdibarge.so", 18);
749 else if(!strcasecmp(oldname, "app_zapras.so"))
750 ast_copy_string(newname, "app_dahdiras.so", 16);
751 else if(!strcasecmp(oldname, "app_zapscan.so"))
752 ast_copy_string(newname, "app_dahdiscan.so", 17);
753 else if(!strcasecmp(oldname, "codec_zap.so"))
754 ast_copy_string(newname, "codec_dahdi.so", 16);
755 else
756 return -1; /* no use for newname, oldname is fine */
758 return 0;
762 int load_modules(unsigned int preload_only)
764 struct ast_config *cfg;
765 struct ast_module *mod;
766 struct load_order_entry *order;
767 struct ast_variable *v;
768 unsigned int load_count;
769 struct load_order load_order;
770 int res = 0;
772 int translate_status;
773 char newname[18]; /* although this would normally be 80, max length in translate_module_name is 18 */
774 #ifdef LOADABLE_MODULES
775 struct dirent *dirent;
776 DIR *dir;
777 #endif
779 /* all embedded modules have registered themselves by now */
780 embedding = 0;
782 if (option_verbose)
783 ast_verbose("Asterisk Dynamic Loader Starting:\n");
785 AST_LIST_HEAD_INIT_NOLOCK(&load_order);
787 AST_LIST_LOCK(&module_list);
789 if (!(cfg = ast_config_load(AST_MODULE_CONFIG))) {
790 ast_log(LOG_WARNING, "No '%s' found, no modules will be loaded.\n", AST_MODULE_CONFIG);
791 goto done;
794 /* first, find all the modules we have been explicitly requested to load */
795 for (v = ast_variable_browse(cfg, "modules"); v; v = v->next) {
796 if (!strcasecmp(v->name, preload_only ? "preload" : "load")) {
797 translate_status = translate_module_name(v->value, newname);
798 if (!translate_status)
799 ast_log(LOG_WARNING, "Use of old module name %s is deprecated, please use %s instead.\n", v->value, newname);
800 add_to_load_order(translate_status ? v->value : newname, &load_order);
804 /* check if 'autoload' is on */
805 if (!preload_only && ast_true(ast_variable_retrieve(cfg, "modules", "autoload"))) {
806 /* if so, first add all the embedded modules that are not already running to the load order */
807 AST_LIST_TRAVERSE(&module_list, mod, entry) {
808 /* if it's not embedded, skip it */
809 if (mod->lib)
810 continue;
812 if (mod->flags.running)
813 continue;
815 order = add_to_load_order(mod->resource, &load_order);
818 #ifdef LOADABLE_MODULES
819 /* if we are allowed to load dynamic modules, scan the directory for
820 for all available modules and add them as well */
821 if ((dir = opendir(ast_config_AST_MODULE_DIR))) {
822 while ((dirent = readdir(dir))) {
823 int ld = strlen(dirent->d_name);
825 /* Must end in .so to load it. */
827 if (ld < 4)
828 continue;
830 if (strcasecmp(dirent->d_name + ld - 3, ".so"))
831 continue;
833 /* if there is already a module by this name in the module_list,
834 skip this file */
835 if (find_resource(dirent->d_name, 0))
836 continue;
838 add_to_load_order(dirent->d_name, &load_order);
841 closedir(dir);
842 } else {
843 if (!ast_opt_quiet)
844 ast_log(LOG_WARNING, "Unable to open modules directory '%s'.\n",
845 ast_config_AST_MODULE_DIR);
847 #endif
850 /* now scan the config for any modules we are prohibited from loading and
851 remove them from the load order */
852 for (v = ast_variable_browse(cfg, "modules"); v; v = v->next) {
853 if (strcasecmp(v->name, "noload"))
854 continue;
856 AST_LIST_TRAVERSE_SAFE_BEGIN(&load_order, order, entry) {
857 translate_status = translate_module_name(v->value, newname);
858 if (!resource_name_match(order->resource, translate_status ? v->value : newname)) {
859 if (!translate_status)
860 ast_log(LOG_WARNING, "Use of old module name %s is deprecated, please use %s instead.\n", v->value, newname);
861 AST_LIST_REMOVE_CURRENT(&load_order, entry);
862 free(order->resource);
863 free(order);
866 AST_LIST_TRAVERSE_SAFE_END;
869 /* we are done with the config now, all the information we need is in the
870 load_order list */
871 ast_config_destroy(cfg);
873 load_count = 0;
874 AST_LIST_TRAVERSE(&load_order, order, entry)
875 load_count++;
877 if (load_count)
878 ast_log(LOG_NOTICE, "%d modules will be loaded.\n", load_count);
880 /* first, load only modules that provide global symbols */
881 AST_LIST_TRAVERSE_SAFE_BEGIN(&load_order, order, entry) {
882 switch (load_resource(order->resource, 1)) {
883 case AST_MODULE_LOAD_SUCCESS:
884 case AST_MODULE_LOAD_DECLINE:
885 AST_LIST_REMOVE_CURRENT(&load_order, entry);
886 free(order->resource);
887 free(order);
888 break;
889 case AST_MODULE_LOAD_FAILURE:
890 res = -1;
891 goto done;
892 case AST_MODULE_LOAD_SKIP:
893 /* try again later */
894 break;
897 AST_LIST_TRAVERSE_SAFE_END;
899 /* now load everything else */
900 AST_LIST_TRAVERSE_SAFE_BEGIN(&load_order, order, entry) {
901 switch (load_resource(order->resource, 0)) {
902 case AST_MODULE_LOAD_SUCCESS:
903 case AST_MODULE_LOAD_DECLINE:
904 AST_LIST_REMOVE_CURRENT(&load_order, entry);
905 free(order->resource);
906 free(order);
907 break;
908 case AST_MODULE_LOAD_FAILURE:
909 res = -1;
910 goto done;
911 case AST_MODULE_LOAD_SKIP:
912 /* should not happen */
913 break;
916 AST_LIST_TRAVERSE_SAFE_END;
918 done:
919 while ((order = AST_LIST_REMOVE_HEAD(&load_order, entry))) {
920 free(order->resource);
921 free(order);
924 AST_LIST_UNLOCK(&module_list);
926 return res;
929 void ast_update_use_count(void)
931 /* Notify any module monitors that the use count for a
932 resource has changed */
933 struct loadupdate *m;
935 AST_LIST_LOCK(&updaters);
936 AST_LIST_TRAVERSE(&updaters, m, entry)
937 m->updater();
938 AST_LIST_UNLOCK(&updaters);
941 int ast_update_module_list(int (*modentry)(const char *module, const char *description, int usecnt, const char *like),
942 const char *like)
944 struct ast_module *cur;
945 int unlock = -1;
946 int total_mod_loaded = 0;
948 if (AST_LIST_TRYLOCK(&module_list))
949 unlock = 0;
951 AST_LIST_TRAVERSE(&module_list, cur, entry) {
952 total_mod_loaded += modentry(cur->resource, cur->info->description, cur->usecount, like);
955 if (unlock)
956 AST_LIST_UNLOCK(&module_list);
958 return total_mod_loaded;
961 int ast_loader_register(int (*v)(void))
963 struct loadupdate *tmp;
965 if (!(tmp = ast_malloc(sizeof(*tmp))))
966 return -1;
968 tmp->updater = v;
969 AST_LIST_LOCK(&updaters);
970 AST_LIST_INSERT_HEAD(&updaters, tmp, entry);
971 AST_LIST_UNLOCK(&updaters);
973 return 0;
976 int ast_loader_unregister(int (*v)(void))
978 struct loadupdate *cur;
980 AST_LIST_LOCK(&updaters);
981 AST_LIST_TRAVERSE_SAFE_BEGIN(&updaters, cur, entry) {
982 if (cur->updater == v) {
983 AST_LIST_REMOVE_CURRENT(&updaters, entry);
984 break;
987 AST_LIST_TRAVERSE_SAFE_END;
988 AST_LIST_UNLOCK(&updaters);
990 return cur ? 0 : -1;
993 struct ast_module *ast_module_ref(struct ast_module *mod)
995 ast_atomic_fetchadd_int(&mod->usecount, +1);
996 ast_update_use_count();
998 return mod;
1001 void ast_module_unref(struct ast_module *mod)
1003 ast_atomic_fetchadd_int(&mod->usecount, -1);
1004 ast_update_use_count();