Merged revisions 116463 via svnmerge from
[asterisk-bristuff.git] / main / loader.c
blobbaddec707462e67f49637e4e199c78129e85cbe2
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 "asterisk/_private.h"
35 #include "asterisk/paths.h" /* use ast_config_AST_MODULE_DIR */
36 #include <dirent.h>
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"
50 #include "asterisk/dsp.h"
51 #include "asterisk/udptl.h"
53 #ifdef DLFCNCOMPAT
54 #include "asterisk/dlfcn-compat.h"
55 #else
56 #include <dlfcn.h>
57 #endif
59 #include "asterisk/md5.h"
60 #include "asterisk/utils.h"
62 #ifndef RTLD_NOW
63 #define RTLD_NOW 0
64 #endif
66 #ifndef RTLD_LOCAL
67 #define RTLD_LOCAL 0
68 #endif
70 struct ast_module_user {
71 struct ast_channel *chan;
72 AST_LIST_ENTRY(ast_module_user) entry;
75 AST_LIST_HEAD(module_user_list, ast_module_user);
77 static unsigned char expected_key[] =
78 { 0x87, 0x76, 0x79, 0x35, 0x23, 0xea, 0x3a, 0xd3,
79 0x25, 0x2a, 0xbb, 0x35, 0x87, 0xe4, 0x22, 0x24 };
81 static char buildopt_sum[33] = AST_BUILDOPT_SUM;
83 static unsigned int embedding = 1; /* we always start out by registering embedded modules,
84 since they are here before we dlopen() any
87 struct ast_module {
88 const struct ast_module_info *info;
89 void *lib; /* the shared lib, or NULL if embedded */
90 int usecount; /* the number of 'users' currently in this module */
91 struct module_user_list users; /* the list of users in the module */
92 struct {
93 unsigned int running:1;
94 unsigned int declined:1;
95 } flags;
96 AST_LIST_ENTRY(ast_module) entry;
97 char resource[0];
100 static AST_LIST_HEAD_STATIC(module_list, ast_module);
103 * module_list is cleared by its constructor possibly after
104 * we start accumulating embedded modules, so we need to
105 * use another list (without the lock) to accumulate them.
106 * Then we update the main list when embedding is done.
108 static struct module_list embedded_module_list;
110 struct loadupdate {
111 int (*updater)(void);
112 AST_LIST_ENTRY(loadupdate) entry;
115 static AST_LIST_HEAD_STATIC(updaters, loadupdate);
117 AST_MUTEX_DEFINE_STATIC(reloadlock);
119 /* when dynamic modules are being loaded, ast_module_register() will
120 need to know what filename the module was loaded from while it
121 is being registered
123 struct ast_module *resource_being_loaded;
125 /* XXX: should we check for duplicate resource names here? */
127 void ast_module_register(const struct ast_module_info *info)
129 struct ast_module *mod;
131 if (embedding) {
132 if (!(mod = ast_calloc(1, sizeof(*mod) + strlen(info->name) + 1)))
133 return;
134 strcpy(mod->resource, info->name);
135 } else {
136 mod = resource_being_loaded;
139 mod->info = info;
140 AST_LIST_HEAD_INIT(&mod->users);
142 /* during startup, before the loader has been initialized,
143 there are no threads, so there is no need to take the lock
144 on this list to manipulate it. it is also possible that it
145 might be unsafe to use the list lock at that point... so
146 let's avoid it altogether
148 if (embedding) {
149 AST_LIST_INSERT_TAIL(&embedded_module_list, mod, entry);
150 } else {
151 AST_LIST_LOCK(&module_list);
152 /* it is paramount that the new entry be placed at the tail of
153 the list, otherwise the code that uses dlopen() to load
154 dynamic modules won't be able to find out if the module it
155 just opened was registered or failed to load
157 AST_LIST_INSERT_TAIL(&module_list, mod, entry);
158 AST_LIST_UNLOCK(&module_list);
161 /* give the module a copy of its own handle, for later use in registrations and the like */
162 *((struct ast_module **) &(info->self)) = mod;
165 void ast_module_unregister(const struct ast_module_info *info)
167 struct ast_module *mod = NULL;
169 /* it is assumed that the users list in the module structure
170 will already be empty, or we cannot have gotten to this
171 point
173 AST_LIST_LOCK(&module_list);
174 AST_LIST_TRAVERSE_SAFE_BEGIN(&module_list, mod, entry) {
175 if (mod->info == info) {
176 AST_LIST_REMOVE_CURRENT(entry);
177 break;
180 AST_LIST_TRAVERSE_SAFE_END;
181 AST_LIST_UNLOCK(&module_list);
183 if (mod) {
184 AST_LIST_HEAD_DESTROY(&mod->users);
185 ast_free(mod);
189 struct ast_module_user *__ast_module_user_add(struct ast_module *mod,
190 struct ast_channel *chan)
192 struct ast_module_user *u = ast_calloc(1, sizeof(*u));
194 if (!u)
195 return NULL;
197 u->chan = chan;
199 AST_LIST_LOCK(&mod->users);
200 AST_LIST_INSERT_HEAD(&mod->users, u, entry);
201 AST_LIST_UNLOCK(&mod->users);
203 ast_atomic_fetchadd_int(&mod->usecount, +1);
205 ast_update_use_count();
207 return u;
210 void __ast_module_user_remove(struct ast_module *mod, struct ast_module_user *u)
212 AST_LIST_LOCK(&mod->users);
213 AST_LIST_REMOVE(&mod->users, u, entry);
214 AST_LIST_UNLOCK(&mod->users);
215 ast_atomic_fetchadd_int(&mod->usecount, -1);
216 ast_free(u);
218 ast_update_use_count();
221 void __ast_module_user_hangup_all(struct ast_module *mod)
223 struct ast_module_user *u;
225 AST_LIST_LOCK(&mod->users);
226 while ((u = AST_LIST_REMOVE_HEAD(&mod->users, entry))) {
227 ast_softhangup(u->chan, AST_SOFTHANGUP_APPUNLOAD);
228 ast_atomic_fetchadd_int(&mod->usecount, -1);
229 ast_free(u);
231 AST_LIST_UNLOCK(&mod->users);
233 ast_update_use_count();
236 /*! \note
237 * In addition to modules, the reload command handles some extra keywords
238 * which are listed here together with the corresponding handlers.
239 * This table is also used by the command completion code.
241 static struct reload_classes {
242 const char *name;
243 int (*reload_fn)(void);
244 } reload_classes[] = { /* list in alpha order, longest match first for cli completion */
245 { "cdr", ast_cdr_engine_reload },
246 { "dnsmgr", dnsmgr_reload },
247 { "extconfig", read_config_maps },
248 { "enum", ast_enum_reload },
249 { "manager", reload_manager },
250 { "rtp", ast_rtp_reload },
251 { "http", ast_http_reload },
252 { "logger", logger_reload },
253 { "features", ast_features_reload },
254 { "dsp", ast_dsp_reload},
255 { "udptl", ast_udptl_reload },
256 { NULL, NULL }
259 static int printdigest(const unsigned char *d)
261 int x, pos;
262 char buf[256]; /* large enough so we don't have to worry */
264 for (pos = 0, x = 0; x < 16; x++)
265 pos += sprintf(buf + pos, " %02x", *d++);
267 ast_debug(1, "Unexpected signature:%s\n", buf);
269 return 0;
272 static int key_matches(const unsigned char *key1, const unsigned char *key2)
274 int x;
276 for (x = 0; x < 16; x++) {
277 if (key1[x] != key2[x])
278 return 0;
281 return 1;
284 static int verify_key(const unsigned char *key)
286 struct MD5Context c;
287 unsigned char digest[16];
289 MD5Init(&c);
290 MD5Update(&c, key, strlen((char *)key));
291 MD5Final(digest, &c);
293 if (key_matches(expected_key, digest))
294 return 0;
296 printdigest(digest);
298 return -1;
301 static int resource_name_match(const char *name1_in, const char *name2_in)
303 char *name1 = (char *) name1_in;
304 char *name2 = (char *) name2_in;
306 /* trim off any .so extensions */
307 if (!strcasecmp(name1 + strlen(name1) - 3, ".so")) {
308 name1 = ast_strdupa(name1);
309 name1[strlen(name1) - 3] = '\0';
311 if (!strcasecmp(name2 + strlen(name2) - 3, ".so")) {
312 name2 = ast_strdupa(name2);
313 name2[strlen(name2) - 3] = '\0';
316 return strcasecmp(name1, name2);
319 static struct ast_module *find_resource(const char *resource, int do_lock)
321 struct ast_module *cur;
323 if (do_lock)
324 AST_LIST_LOCK(&module_list);
326 AST_LIST_TRAVERSE(&module_list, cur, entry) {
327 if (!resource_name_match(resource, cur->resource))
328 break;
331 if (do_lock)
332 AST_LIST_UNLOCK(&module_list);
334 return cur;
337 #ifdef LOADABLE_MODULES
338 static void unload_dynamic_module(struct ast_module *mod)
340 void *lib = mod->lib;
342 /* WARNING: the structure pointed to by mod is going to
343 disappear when this operation succeeds, so we can't
344 dereference it */
346 if (lib)
347 while (!dlclose(lib));
350 static struct ast_module *load_dynamic_module(const char *resource_in, unsigned int global_symbols_only)
352 char fn[PATH_MAX] = "";
353 void *lib = NULL;
354 struct ast_module *mod;
355 unsigned int wants_global;
356 int space; /* room needed for the descriptor */
357 int missing_so = 0;
359 space = sizeof(*resource_being_loaded) + strlen(resource_in) + 1;
360 if (strcasecmp(resource_in + strlen(resource_in) - 3, ".so")) {
361 missing_so = 1;
362 space += 3; /* room for the extra ".so" */
365 snprintf(fn, sizeof(fn), "%s/%s%s", ast_config_AST_MODULE_DIR, resource_in, missing_so ? ".so" : "");
367 /* make a first load of the module in 'quiet' mode... don't try to resolve
368 any symbols, and don't export any symbols. this will allow us to peek into
369 the module's info block (if available) to see what flags it has set */
371 resource_being_loaded = ast_calloc(1, space);
372 if (!resource_being_loaded)
373 return NULL;
374 strcpy(resource_being_loaded->resource, resource_in);
375 if (missing_so)
376 strcat(resource_being_loaded->resource, ".so");
378 if (!(lib = dlopen(fn, RTLD_LAZY | RTLD_LOCAL))) {
379 ast_log(LOG_WARNING, "Error loading module '%s': %s\n", resource_in, dlerror());
380 ast_free(resource_being_loaded);
381 return NULL;
384 /* the dlopen() succeeded, let's find out if the module
385 registered itself */
386 /* note that this will only work properly as long as
387 ast_module_register() (which is called by the module's
388 constructor) places the new module at the tail of the
389 module_list
391 if (resource_being_loaded != (mod = AST_LIST_LAST(&module_list))) {
392 ast_log(LOG_WARNING, "Module '%s' did not register itself during load\n", resource_in);
393 /* no, it did not, so close it and return */
394 while (!dlclose(lib));
395 /* note that the module's destructor will call ast_module_unregister(),
396 which will free the structure we allocated in resource_being_loaded */
397 return NULL;
400 wants_global = ast_test_flag(mod->info, AST_MODFLAG_GLOBAL_SYMBOLS);
402 /* if we are being asked only to load modules that provide global symbols,
403 and this one does not, then close it and return */
404 if (global_symbols_only && !wants_global) {
405 while (!dlclose(lib));
406 return NULL;
409 /* if the system supports RTLD_NOLOAD, we can just 'promote' the flags
410 on the already-opened library to what we want... if not, we have to
411 close it and start over
413 #if defined(HAVE_RTLD_NOLOAD) && !defined(__Darwin__)
414 if (!dlopen(fn, RTLD_NOLOAD | (wants_global ? RTLD_LAZY | RTLD_GLOBAL : RTLD_NOW | RTLD_LOCAL))) {
415 ast_log(LOG_WARNING, "Unable to promote flags on module '%s': %s\n", resource_in, dlerror());
416 while (!dlclose(lib));
417 ast_free(resource_being_loaded);
418 return NULL;
420 #else
421 while (!dlclose(lib));
422 resource_being_loaded = NULL;
424 /* start the load process again */
425 resource_being_loaded = ast_calloc(1, space);
426 if (!resource_being_loaded)
427 return NULL;
428 strcpy(resource_being_loaded->resource, resource_in);
429 if (missing_so)
430 strcat(resource_being_loaded->resource, ".so");
432 if (!(lib = dlopen(fn, wants_global ? RTLD_LAZY | RTLD_GLOBAL : RTLD_NOW | RTLD_LOCAL))) {
433 ast_log(LOG_WARNING, "Error loading module '%s': %s\n", resource_in, dlerror());
434 ast_free(resource_being_loaded);
435 return NULL;
438 /* since the module was successfully opened, and it registered itself
439 the previous time we did that, we're going to assume it worked this
440 time too :) */
441 #endif
443 AST_LIST_LAST(&module_list)->lib = lib;
444 resource_being_loaded = NULL;
446 return AST_LIST_LAST(&module_list);
448 #endif
450 void ast_module_shutdown(void)
452 struct ast_module *mod;
453 AST_LIST_HEAD_NOLOCK_STATIC(local_module_list, ast_module);
455 /* We have to call the unload() callbacks in reverse order that the modules
456 * exist in the module list so it is the reverse order of how they were
457 * loaded. */
459 AST_LIST_LOCK(&module_list);
460 while ((mod = AST_LIST_REMOVE_HEAD(&module_list, entry)))
461 AST_LIST_INSERT_HEAD(&local_module_list, mod, entry);
462 AST_LIST_UNLOCK(&module_list);
464 while ((mod = AST_LIST_REMOVE_HEAD(&local_module_list, entry))) {
465 if (mod->info->unload)
466 mod->info->unload();
467 /* Since this should only be called when shutting down "gracefully",
468 * all channels should be down before we get to this point, meaning
469 * there will be no module users left. */
470 AST_LIST_HEAD_DESTROY(&mod->users);
471 free(mod);
475 int ast_unload_resource(const char *resource_name, enum ast_module_unload_mode force)
477 struct ast_module *mod;
478 int res = -1;
479 int error = 0;
481 AST_LIST_LOCK(&module_list);
483 if (!(mod = find_resource(resource_name, 0))) {
484 AST_LIST_UNLOCK(&module_list);
485 ast_log(LOG_WARNING, "Unload failed, '%s' could not be found\n", resource_name);
486 return 0;
489 if (!(mod->flags.running || mod->flags.declined))
490 error = 1;
492 if (!error && (mod->usecount > 0)) {
493 if (force)
494 ast_log(LOG_WARNING, "Warning: Forcing removal of module '%s' with use count %d\n",
495 resource_name, mod->usecount);
496 else {
497 ast_log(LOG_WARNING, "Soft unload failed, '%s' has use count %d\n", resource_name,
498 mod->usecount);
499 error = 1;
503 if (!error) {
504 __ast_module_user_hangup_all(mod);
505 res = mod->info->unload();
507 if (res) {
508 ast_log(LOG_WARNING, "Firm unload failed for %s\n", resource_name);
509 if (force <= AST_FORCE_FIRM)
510 error = 1;
511 else
512 ast_log(LOG_WARNING, "** Dangerous **: Unloading resource anyway, at user request\n");
516 if (!error)
517 mod->flags.running = mod->flags.declined = 0;
519 AST_LIST_UNLOCK(&module_list);
521 if (!error && !mod->lib && mod->info && mod->info->restore_globals)
522 mod->info->restore_globals();
524 #ifdef LOADABLE_MODULES
525 if (!error)
526 unload_dynamic_module(mod);
527 #endif
529 if (!error)
530 ast_update_use_count();
532 return res;
535 char *ast_module_helper(const char *line, const char *word, int pos, int state, int rpos, int needsreload)
537 struct ast_module *cur;
538 int i, which=0, l = strlen(word);
539 char *ret = NULL;
541 if (pos != rpos)
542 return NULL;
544 AST_LIST_LOCK(&module_list);
545 AST_LIST_TRAVERSE(&module_list, cur, entry) {
546 if (!strncasecmp(word, cur->resource, l) &&
547 (cur->info->reload || !needsreload) &&
548 ++which > state) {
549 ret = ast_strdup(cur->resource);
550 break;
553 AST_LIST_UNLOCK(&module_list);
555 if (!ret) {
556 for (i=0; !ret && reload_classes[i].name; i++) {
557 if (!strncasecmp(word, reload_classes[i].name, l) && ++which > state)
558 ret = ast_strdup(reload_classes[i].name);
562 return ret;
565 int ast_module_reload(const char *name)
567 struct ast_module *cur;
568 int res = 0; /* return value. 0 = not found, others, see below */
569 int i;
571 if (ast_mutex_trylock(&reloadlock)) {
572 ast_verbose("The previous reload command didn't finish yet\n");
573 return -1; /* reload already in progress */
575 ast_lastreloadtime = ast_tvnow();
577 /* Call "predefined" reload here first */
578 for (i = 0; reload_classes[i].name; i++) {
579 if (!name || !strcasecmp(name, reload_classes[i].name)) {
580 reload_classes[i].reload_fn(); /* XXX should check error ? */
581 res = 2; /* found and reloaded */
585 if (name && res) {
586 ast_mutex_unlock(&reloadlock);
587 return res;
590 AST_LIST_LOCK(&module_list);
591 AST_LIST_TRAVERSE(&module_list, cur, entry) {
592 const struct ast_module_info *info = cur->info;
594 if (name && resource_name_match(name, cur->resource))
595 continue;
597 if (!cur->flags.running || cur->flags.declined) {
598 if (!name)
599 continue;
600 ast_log(LOG_NOTICE, "The module '%s' was not properly initialized. "
601 "Before reloading the module, you must run \"module load %s\" "
602 "and fix whatever is preventing the module from being initialized.\n",
603 name, name);
604 res = 2; /* Don't report that the module was not found */
605 break;
608 if (!info->reload) { /* cannot be reloaded */
609 if (res < 1) /* store result if possible */
610 res = 1; /* 1 = no reload() method */
611 continue;
614 res = 2;
615 ast_verb(3, "Reloading module '%s' (%s)\n", cur->resource, info->description);
616 info->reload();
618 AST_LIST_UNLOCK(&module_list);
620 ast_mutex_unlock(&reloadlock);
622 return res;
625 static unsigned int inspect_module(const struct ast_module *mod)
627 if (!mod->info->description) {
628 ast_log(LOG_WARNING, "Module '%s' does not provide a description.\n", mod->resource);
629 return 1;
632 if (!mod->info->key) {
633 ast_log(LOG_WARNING, "Module '%s' does not provide a license key.\n", mod->resource);
634 return 1;
637 if (verify_key((unsigned char *) mod->info->key)) {
638 ast_log(LOG_WARNING, "Module '%s' did not provide a valid license key.\n", mod->resource);
639 return 1;
642 if (!ast_strlen_zero(mod->info->buildopt_sum) &&
643 strcmp(buildopt_sum, mod->info->buildopt_sum)) {
644 ast_log(LOG_WARNING, "Module '%s' was not compiled with the same compile-time options as this version of Asterisk.\n", mod->resource);
645 ast_log(LOG_WARNING, "Module '%s' will not be initialized as it may cause instability.\n", mod->resource);
646 return 1;
649 return 0;
652 static enum ast_module_load_result load_resource(const char *resource_name, unsigned int global_symbols_only)
654 struct ast_module *mod;
655 enum ast_module_load_result res = AST_MODULE_LOAD_SUCCESS;
656 char tmp[256];
658 if ((mod = find_resource(resource_name, 0))) {
659 if (mod->flags.running) {
660 ast_log(LOG_WARNING, "Module '%s' already exists.\n", resource_name);
661 return AST_MODULE_LOAD_DECLINE;
663 if (global_symbols_only && !ast_test_flag(mod->info, AST_MODFLAG_GLOBAL_SYMBOLS))
664 return AST_MODULE_LOAD_SKIP;
665 } else {
666 #ifdef LOADABLE_MODULES
667 if (!(mod = load_dynamic_module(resource_name, global_symbols_only))) {
668 /* don't generate a warning message during load_modules() */
669 if (!global_symbols_only) {
670 ast_log(LOG_WARNING, "Module '%s' could not be loaded.\n", resource_name);
671 return AST_MODULE_LOAD_DECLINE;
672 } else {
673 return AST_MODULE_LOAD_SKIP;
676 #else
677 ast_log(LOG_WARNING, "Module '%s' could not be loaded.\n", resource_name);
678 return AST_MODULE_LOAD_DECLINE;
679 #endif
682 if (inspect_module(mod)) {
683 ast_log(LOG_WARNING, "Module '%s' could not be loaded.\n", resource_name);
684 #ifdef LOADABLE_MODULES
685 unload_dynamic_module(mod);
686 #endif
687 return AST_MODULE_LOAD_DECLINE;
690 if (!mod->lib && mod->info->backup_globals()) {
691 ast_log(LOG_WARNING, "Module '%s' was unable to backup its global data.\n", resource_name);
692 return AST_MODULE_LOAD_DECLINE;
695 mod->flags.declined = 0;
697 if (mod->info->load)
698 res = mod->info->load();
700 switch (res) {
701 case AST_MODULE_LOAD_SUCCESS:
702 if (!ast_fully_booted) {
703 ast_verb(1, "%s => (%s)\n", resource_name, term_color(tmp, mod->info->description, COLOR_BROWN, COLOR_BLACK, sizeof(tmp)));
704 if (ast_opt_console && !option_verbose)
705 ast_verbose( ".");
706 } else {
707 ast_verb(1, "Loaded %s => (%s)\n", resource_name, mod->info->description);
710 mod->flags.running = 1;
712 ast_update_use_count();
713 break;
714 case AST_MODULE_LOAD_DECLINE:
715 mod->flags.declined = 1;
716 break;
717 case AST_MODULE_LOAD_FAILURE:
718 break;
719 case AST_MODULE_LOAD_SKIP:
720 /* modules should never return this value */
721 break;
724 return res;
727 int ast_load_resource(const char *resource_name)
729 AST_LIST_LOCK(&module_list);
730 load_resource(resource_name, 0);
731 AST_LIST_UNLOCK(&module_list);
733 return 0;
736 struct load_order_entry {
737 char *resource;
738 AST_LIST_ENTRY(load_order_entry) entry;
741 AST_LIST_HEAD_NOLOCK(load_order, load_order_entry);
743 static struct load_order_entry *add_to_load_order(const char *resource, struct load_order *load_order)
745 struct load_order_entry *order;
747 AST_LIST_TRAVERSE(load_order, order, entry) {
748 if (!resource_name_match(order->resource, resource))
749 return NULL;
752 if (!(order = ast_calloc(1, sizeof(*order))))
753 return NULL;
755 order->resource = ast_strdup(resource);
756 AST_LIST_INSERT_TAIL(load_order, order, entry);
758 return order;
760 int load_modules(unsigned int preload_only)
762 struct ast_config *cfg;
763 struct ast_module *mod;
764 struct load_order_entry *order;
765 struct ast_variable *v;
766 unsigned int load_count;
767 struct load_order load_order;
768 int res = 0;
769 struct ast_flags config_flags = { 0 };
770 int modulecount = 0;
771 #ifdef LOADABLE_MODULES
772 struct dirent *dirent;
773 DIR *dir;
774 #endif
776 /* all embedded modules have registered themselves by now */
777 embedding = 0;
779 ast_verb(1, "Asterisk Dynamic Loader Starting:\n");
781 AST_LIST_HEAD_INIT_NOLOCK(&load_order);
783 AST_LIST_LOCK(&module_list);
785 if (embedded_module_list.first) {
786 module_list.first = embedded_module_list.first;
787 module_list.last = embedded_module_list.last;
788 embedded_module_list.first = NULL;
791 if (!(cfg = ast_config_load2(AST_MODULE_CONFIG, "" /* core, can't reload */, config_flags))) {
792 ast_log(LOG_WARNING, "No '%s' found, no modules will be loaded.\n", AST_MODULE_CONFIG);
793 goto done;
796 /* first, find all the modules we have been explicitly requested to load */
797 for (v = ast_variable_browse(cfg, "modules"); v; v = v->next) {
798 if (!strcasecmp(v->name, preload_only ? "preload" : "load"))
799 add_to_load_order(v->value, &load_order);
802 /* check if 'autoload' is on */
803 if (!preload_only && ast_true(ast_variable_retrieve(cfg, "modules", "autoload"))) {
804 /* if so, first add all the embedded modules that are not already running to the load order */
805 AST_LIST_TRAVERSE(&module_list, mod, entry) {
806 /* if it's not embedded, skip it */
807 if (mod->lib)
808 continue;
810 if (mod->flags.running)
811 continue;
813 order = add_to_load_order(mod->resource, &load_order);
816 #ifdef LOADABLE_MODULES
817 /* if we are allowed to load dynamic modules, scan the directory for
818 for all available modules and add them as well */
819 if ((dir = opendir(ast_config_AST_MODULE_DIR))) {
820 while ((dirent = readdir(dir))) {
821 int ld = strlen(dirent->d_name);
823 /* Must end in .so to load it. */
825 if (ld < 4)
826 continue;
828 if (strcasecmp(dirent->d_name + ld - 3, ".so"))
829 continue;
831 /* if there is already a module by this name in the module_list,
832 skip this file */
833 if (find_resource(dirent->d_name, 0))
834 continue;
836 add_to_load_order(dirent->d_name, &load_order);
839 closedir(dir);
840 } else {
841 if (!ast_opt_quiet)
842 ast_log(LOG_WARNING, "Unable to open modules directory '%s'.\n",
843 ast_config_AST_MODULE_DIR);
845 #endif
848 /* now scan the config for any modules we are prohibited from loading and
849 remove them from the load order */
850 for (v = ast_variable_browse(cfg, "modules"); v; v = v->next) {
851 if (strcasecmp(v->name, "noload"))
852 continue;
854 AST_LIST_TRAVERSE_SAFE_BEGIN(&load_order, order, entry) {
855 if (!resource_name_match(order->resource, v->value)) {
856 AST_LIST_REMOVE_CURRENT(entry);
857 ast_free(order->resource);
858 ast_free(order);
861 AST_LIST_TRAVERSE_SAFE_END;
864 /* we are done with the config now, all the information we need is in the
865 load_order list */
866 ast_config_destroy(cfg);
868 load_count = 0;
869 AST_LIST_TRAVERSE(&load_order, order, entry)
870 load_count++;
872 if (load_count)
873 ast_log(LOG_NOTICE, "%d modules will be loaded.\n", load_count);
875 /* first, load only modules that provide global symbols */
876 AST_LIST_TRAVERSE_SAFE_BEGIN(&load_order, order, entry) {
877 switch (load_resource(order->resource, 1)) {
878 case AST_MODULE_LOAD_SUCCESS:
879 modulecount++;
880 case AST_MODULE_LOAD_DECLINE:
881 AST_LIST_REMOVE_CURRENT(entry);
882 ast_free(order->resource);
883 ast_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 modulecount++;
900 case AST_MODULE_LOAD_DECLINE:
901 AST_LIST_REMOVE_CURRENT(entry);
902 ast_free(order->resource);
903 ast_free(order);
904 break;
905 case AST_MODULE_LOAD_FAILURE:
906 res = -1;
907 goto done;
908 case AST_MODULE_LOAD_SKIP:
909 /* should not happen */
910 break;
913 AST_LIST_TRAVERSE_SAFE_END;
915 done:
916 while ((order = AST_LIST_REMOVE_HEAD(&load_order, entry))) {
917 ast_free(order->resource);
918 ast_free(order);
921 AST_LIST_UNLOCK(&module_list);
923 /* Tell manager clients that are aggressive at logging in that we're done
924 loading modules. If there's a DNS problem in chan_sip, we might not
925 even reach this */
926 manager_event(EVENT_FLAG_SYSTEM, "ModuleLoadReport", "ModuleLoadStatus: Done\r\nModuleSelection: %s\r\nModuleCount: %d\r\n", preload_only ? "Preload" : "All", modulecount);
928 return res;
931 void ast_update_use_count(void)
933 /* Notify any module monitors that the use count for a
934 resource has changed */
935 struct loadupdate *m;
937 AST_LIST_LOCK(&updaters);
938 AST_LIST_TRAVERSE(&updaters, m, entry)
939 m->updater();
940 AST_LIST_UNLOCK(&updaters);
943 int ast_update_module_list(int (*modentry)(const char *module, const char *description, int usecnt, const char *like),
944 const char *like)
946 struct ast_module *cur;
947 int unlock = -1;
948 int total_mod_loaded = 0;
950 if (AST_LIST_TRYLOCK(&module_list))
951 unlock = 0;
953 AST_LIST_TRAVERSE(&module_list, cur, entry) {
954 total_mod_loaded += modentry(cur->resource, cur->info->description, cur->usecount, like);
957 if (unlock)
958 AST_LIST_UNLOCK(&module_list);
960 return total_mod_loaded;
963 /*! \brief Check if module exists */
964 int ast_module_check(const char *name)
966 struct ast_module *cur;
968 if (ast_strlen_zero(name))
969 return 0; /* FALSE */
971 cur = find_resource(name, 1);
973 return (cur != NULL);
977 int ast_loader_register(int (*v)(void))
979 struct loadupdate *tmp;
981 if (!(tmp = ast_malloc(sizeof(*tmp))))
982 return -1;
984 tmp->updater = v;
985 AST_LIST_LOCK(&updaters);
986 AST_LIST_INSERT_HEAD(&updaters, tmp, entry);
987 AST_LIST_UNLOCK(&updaters);
989 return 0;
992 int ast_loader_unregister(int (*v)(void))
994 struct loadupdate *cur;
996 AST_LIST_LOCK(&updaters);
997 AST_LIST_TRAVERSE_SAFE_BEGIN(&updaters, cur, entry) {
998 if (cur->updater == v) {
999 AST_LIST_REMOVE_CURRENT(entry);
1000 break;
1003 AST_LIST_TRAVERSE_SAFE_END;
1004 AST_LIST_UNLOCK(&updaters);
1006 return cur ? 0 : -1;
1009 struct ast_module *ast_module_ref(struct ast_module *mod)
1011 ast_atomic_fetchadd_int(&mod->usecount, +1);
1012 ast_update_use_count();
1014 return mod;
1017 void ast_module_unref(struct ast_module *mod)
1019 ast_atomic_fetchadd_int(&mod->usecount, -1);
1020 ast_update_use_count();