Add the ability to dynamically specify weights for responses to DUNDi queries.
[asterisk/asterisk.git] / main / loader.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2006, Digium, Inc.
5  *
6  * Mark Spencer <markster@digium.com>
7  * Kevin P. Fleming <kpfleming@digium.com>
8  * Luigi Rizzo <rizzo@icir.org>
9  *
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.
15  *
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.
19  */
20
21 /*! \file
22  *
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
28  */
29
30 #include "asterisk.h"
31
32 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
33
34 #include <stdio.h>
35 #include <dirent.h>
36 #include <unistd.h>
37 #include <stdlib.h>
38 #include <errno.h>
39 #include <string.h>
40
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"
54
55 #ifdef DLFCNCOMPAT
56 #include "asterisk/dlfcn-compat.h"
57 #else
58 #include <dlfcn.h>
59 #endif
60
61 #include "asterisk/md5.h"
62 #include "asterisk/utils.h"
63
64 #ifndef RTLD_NOW
65 #define RTLD_NOW 0
66 #endif
67
68 struct ast_module_user {
69         struct ast_channel *chan;
70         AST_LIST_ENTRY(ast_module_user) entry;
71 };
72
73 AST_LIST_HEAD(module_user_list, ast_module_user);
74
75 static unsigned char expected_key[] =
76 { 0x87, 0x76, 0x79, 0x35, 0x23, 0xea, 0x3a, 0xd3,
77   0x25, 0x2a, 0xbb, 0x35, 0x87, 0xe4, 0x22, 0x24 };
78
79 static unsigned int embedding = 1; /* we always start out by registering embedded modules,
80                                       since they are here before we dlopen() any
81                                    */
82
83 enum flags {
84         FLAG_RUNNING = (1 << 1),                /* module successfully initialized */
85         FLAG_DECLINED = (1 << 2),               /* module declined to initialize */
86 };
87
88 struct ast_module {
89         const struct ast_module_info *info;
90         void *lib;                                      /* the shared lib, or NULL if embedded */
91         int usecount;                                   /* the number of 'users' currently in this module */
92         struct module_user_list users;                  /* the list of users in the module */
93         unsigned int flags;                             /* flags for this module */
94         AST_LIST_ENTRY(ast_module) entry;
95         char resource[0];
96 };
97
98 static AST_LIST_HEAD_STATIC(module_list, ast_module);
99
100 struct loadupdate {
101         int (*updater)(void);
102         AST_LIST_ENTRY(loadupdate) entry;
103 };
104
105 static AST_LIST_HEAD_STATIC(updaters, loadupdate);
106
107 AST_MUTEX_DEFINE_STATIC(reloadlock);
108
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
112 */
113 struct ast_module *resource_being_loaded;
114
115 /* XXX: should we check for duplicate resource names here? */
116
117 void ast_module_register(const struct ast_module_info *info)
118 {
119         struct ast_module *mod;
120
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;
127         }
128
129         mod->info = info;
130         AST_LIST_HEAD_INIT(&mod->users);
131
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
137         */
138         if (!embedding)
139                 AST_LIST_LOCK(&module_list);
140
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
145         */
146         AST_LIST_INSERT_TAIL(&module_list, mod, entry);
147
148         if (!embedding)
149                 AST_LIST_UNLOCK(&module_list);
150
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;
153 }
154
155 void ast_module_unregister(const struct ast_module_info *info)
156 {
157         struct ast_module *mod = NULL;
158
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
162         */
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;
168                 }
169         }
170         AST_LIST_TRAVERSE_SAFE_END;
171         AST_LIST_UNLOCK(&module_list);
172
173         if (mod) {
174                 AST_LIST_HEAD_DESTROY(&mod->users);
175                 free(mod);
176         }
177 }
178
179 struct ast_module_user *__ast_module_user_add(struct ast_module *mod,
180                                               struct ast_channel *chan)
181 {
182         struct ast_module_user *u = ast_calloc(1, sizeof(*u));
183
184         if (!u)
185                 return NULL;
186
187         u->chan = chan;
188
189         AST_LIST_LOCK(&mod->users);
190         AST_LIST_INSERT_HEAD(&mod->users, u, entry);
191         AST_LIST_UNLOCK(&mod->users);
192
193         ast_atomic_fetchadd_int(&mod->usecount, +1);
194
195         ast_update_use_count();
196
197         return u;
198 }
199
200 void __ast_module_user_remove(struct ast_module *mod, struct ast_module_user *u)
201 {
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);
207
208         ast_update_use_count();
209 }
210
211 void __ast_module_user_hangup_all(struct ast_module *mod)
212 {
213         struct ast_module_user *u;
214
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);
220         }
221         AST_LIST_UNLOCK(&mod->users);
222
223         ast_update_use_count();
224 }
225
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.
230  */
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 }
243 };
244
245 static int printdigest(const unsigned char *d)
246 {
247         int x, pos;
248         char buf[256]; /* large enough so we don't have to worry */
249
250         for (pos = 0, x = 0; x < 16; x++)
251                 pos += sprintf(buf + pos, " %02x", *d++);
252
253         if (option_debug)
254                 ast_log(LOG_DEBUG, "Unexpected signature:%s\n", buf);
255
256         return 0;
257 }
258
259 static int key_matches(const unsigned char *key1, const unsigned char *key2)
260 {
261         int x;
262
263         for (x = 0; x < 16; x++) {
264                 if (key1[x] != key2[x])
265                         return 0;
266         }
267
268         return 1;
269 }
270
271 static int verify_key(const unsigned char *key)
272 {
273         struct MD5Context c;
274         unsigned char digest[16];
275
276         MD5Init(&c);
277         MD5Update(&c, key, strlen((char *)key));
278         MD5Final(digest, &c);
279
280         if (key_matches(expected_key, digest))
281                 return 0;
282
283         printdigest(digest);
284
285         return -1;
286 }
287
288 static int resource_name_match(const char *name1_in, const char *name2_in)
289 {
290         char *name1 = (char *) name1_in;
291         char *name2 = (char *) name2_in;
292
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';
297         }
298         if (!strcasecmp(name2 + strlen(name2) - 3, ".so")) {
299                 name2 = ast_strdupa(name2);
300                 name2[strlen(name2) - 3] = '\0';
301         }
302
303         return strcasecmp(name1, name2);
304 }
305
306 static struct ast_module *find_resource(const char *resource, int do_lock)
307 {
308         struct ast_module *cur;
309
310         if (do_lock)
311                 AST_LIST_LOCK(&module_list);
312
313         AST_LIST_TRAVERSE(&module_list, cur, entry) {
314                 if (!resource_name_match(resource, cur->resource))
315                         break;
316         }
317
318         if (do_lock)
319                 AST_LIST_UNLOCK(&module_list);
320
321         return cur;
322 }
323
324 #if LOADABLE_MODULES
325 static void unload_dynamic_module(struct ast_module *mod)
326 {
327         void *lib = mod->lib;
328
329         /* WARNING: the structure pointed to by mod is going to
330            disappear when this operation succeeds, so we can't
331            dereference it */
332
333         if (lib)
334                 while (!dlclose(lib));
335 }
336
337 static struct ast_module *load_dynamic_module(const char *resource_in, unsigned int global_symbols_only)
338 {
339         char fn[256] = "";
340         void *lib = NULL;
341         struct ast_module *mod;
342         char *resource = (char *) resource_in;
343         unsigned int wants_global;
344
345         if (strcasecmp(resource + strlen(resource) - 3, ".so")) {
346                 resource = alloca(strlen(resource_in) + 3);
347                 strcpy(resource, resource_in);
348                 strcat(resource, ".so");
349         }
350
351         snprintf(fn, sizeof(fn), "%s/%s", ast_config_AST_MODULE_DIR, resource);
352
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 */
356
357         if (!(resource_being_loaded = ast_calloc(1, sizeof(*resource_being_loaded) + strlen(resource) + 1)))
358                 return NULL;
359
360         strcpy(resource_being_loaded->resource, resource);
361
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;
366         }
367
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
374         */
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;
382         }
383
384         wants_global = ast_test_flag(mod->info, AST_MODFLAG_GLOBAL_SYMBOLS);
385
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;
391         }
392
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
396         */
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;
403         }
404 #else
405         while (!dlclose(lib));
406         resource_being_loaded = NULL;
407
408         /* start the load process again */
409
410         if (!(resource_being_loaded = ast_calloc(1, sizeof(*resource_being_loaded) + strlen(resource) + 1)))
411                 return NULL;
412
413         strcpy(resource_being_loaded->resource, resource);
414
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;
419         }
420
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
425
426         AST_LIST_LAST(&module_list)->lib = lib;
427         resource_being_loaded = NULL;
428
429         return AST_LIST_LAST(&module_list);
430 }
431 #endif
432
433 int ast_unload_resource(const char *resource_name, enum ast_module_unload_mode force)
434 {
435         struct ast_module *mod;
436         int res = -1;
437         int error = 0;
438
439         AST_LIST_LOCK(&module_list);
440
441         if (!(mod = find_resource(resource_name, 0))) {
442                 AST_LIST_UNLOCK(&module_list);
443                 return 0;
444         }
445
446         if (!ast_test_flag(mod, FLAG_RUNNING | FLAG_DECLINED))
447                 error = 1;
448
449         if (!error && (mod->usecount > 0)) {
450                 if (force)
451                         ast_log(LOG_WARNING, "Warning:  Forcing removal of module '%s' with use count %d\n",
452                                 resource_name, mod->usecount);
453                 else {
454                         ast_log(LOG_WARNING, "Soft unload failed, '%s' has use count %d\n", resource_name,
455                                 mod->usecount);
456                         error = 1;
457                 }
458         }
459
460         if (!error) {
461                 __ast_module_user_hangup_all(mod);
462                 res = mod->info->unload();
463
464                 if (res) {
465                         ast_log(LOG_WARNING, "Firm unload failed for %s\n", resource_name);
466                         if (force <= AST_FORCE_FIRM)
467                                 error = 1;
468                         else
469                                 ast_log(LOG_WARNING, "** Dangerous **: Unloading resource anyway, at user request\n");
470                 }
471         }
472
473         if (!error)
474                 ast_clear_flag(mod, FLAG_RUNNING | FLAG_DECLINED);
475
476         AST_LIST_UNLOCK(&module_list);
477
478 #if LOADABLE_MODULES
479         if (!error)
480                 unload_dynamic_module(mod);
481 #endif
482
483         if (!error)
484                 ast_update_use_count();
485
486         if (!error && !mod->lib)
487                 mod->info->restore_globals();
488
489         return res;
490 }
491
492 char *ast_module_helper(const char *line, const char *word, int pos, int state, int rpos, int needsreload)
493 {
494         struct ast_module *cur;
495         int i, which=0, l = strlen(word);
496         char *ret = NULL;
497
498         if (pos != rpos)
499                 return NULL;
500
501         AST_LIST_LOCK(&module_list);
502         AST_LIST_TRAVERSE(&module_list, cur, entry) {
503                 if (!strncasecmp(word, cur->resource, l) &&
504                     (cur->info->reload || !needsreload) &&
505                     ++which > state) {
506                         ret = strdup(cur->resource);
507                         break;
508                 }
509         }
510         AST_LIST_UNLOCK(&module_list);
511
512         if (!ret) {
513                 for (i=0; !ret && reload_classes[i].name; i++) {
514                         if (!strncasecmp(word, reload_classes[i].name, l) && ++which > state)
515                                 ret = strdup(reload_classes[i].name);
516                 }
517         }
518
519         return ret;
520 }
521
522 int ast_module_reload(const char *name)
523 {
524         struct ast_module *cur;
525         int res = 0; /* return value. 0 = not found, others, see below */
526         int i;
527
528         if (ast_mutex_trylock(&reloadlock)) {
529                 ast_verbose("The previous reload command didn't finish yet\n");
530                 return -1;      /* reload already in progress */
531         }
532
533         /* Call "predefined" reload here first */
534         for (i = 0; reload_classes[i].name; i++) {
535                 if (!name || !strcasecmp(name, reload_classes[i].name)) {
536                         reload_classes[i].reload_fn();  /* XXX should check error ? */
537                         res = 2;        /* found and reloaded */
538                 }
539         }
540         ast_lastreloadtime = time(NULL);
541
542         if (name && res) {
543                 ast_mutex_unlock(&reloadlock);
544                 return res;
545         }
546
547         AST_LIST_LOCK(&module_list);
548         AST_LIST_TRAVERSE(&module_list, cur, entry) {
549                 const struct ast_module_info *info = cur->info;
550
551                 if (name && resource_name_match(name, cur->resource))
552                         continue;
553
554                 if (!ast_test_flag(cur, FLAG_RUNNING | FLAG_DECLINED))
555                         continue;
556
557                 if (!info->reload) {    /* cannot be reloaded */
558                         if (res < 1)    /* store result if possible */
559                                 res = 1;        /* 1 = no reload() method */
560                         continue;
561                 }
562
563                 res = 2;
564                 if (option_verbose > 2)
565                         ast_verbose(VERBOSE_PREFIX_3 "Reloading module '%s' (%s)\n", cur->resource, info->description);
566                 info->reload();
567         }
568         AST_LIST_UNLOCK(&module_list);
569
570         ast_mutex_unlock(&reloadlock);
571
572         return res;
573 }
574
575 static unsigned int inspect_module(const struct ast_module *mod)
576 {
577         if (!mod->info->description) {
578                 ast_log(LOG_WARNING, "Module '%s' does not provide a description.\n", mod->resource);
579                 return 1;
580         }
581
582         if (!mod->info->key) {
583                 ast_log(LOG_WARNING, "Module '%s' does not provide a license key.\n", mod->resource);
584                 return 1;
585         }
586
587         if (verify_key((unsigned char *) mod->info->key)) {
588                 ast_log(LOG_WARNING, "Module '%s' did not provide a valid license key.\n", mod->resource);
589                 return 1;
590         }
591
592         return 0;
593 }
594
595 static enum ast_module_load_result load_resource(const char *resource_name, unsigned int global_symbols_only)
596 {
597         struct ast_module *mod;
598         enum ast_module_load_result res = AST_MODULE_LOAD_SUCCESS;
599         char tmp[256];
600
601         if ((mod = find_resource(resource_name, 0))) {
602                 if (ast_test_flag(mod, FLAG_RUNNING)) {
603                         ast_log(LOG_WARNING, "Module '%s' already exists.\n", resource_name);
604                         return AST_MODULE_LOAD_DECLINE;
605                 }
606                 if (global_symbols_only && !ast_test_flag(mod->info, AST_MODFLAG_GLOBAL_SYMBOLS))
607                         return AST_MODULE_LOAD_SKIP;
608         } else {
609 #if LOADABLE_MODULES
610                 if (!(mod = load_dynamic_module(resource_name, global_symbols_only))) {
611                         /* don't generate a warning message during load_modules() */
612                         if (!global_symbols_only) {
613                                 ast_log(LOG_WARNING, "Module '%s' could not be loaded.\n", resource_name);
614                                 return AST_MODULE_LOAD_DECLINE;
615                         } else {
616                                 return AST_MODULE_LOAD_SKIP;
617                         }
618                 }
619 #else
620                 ast_log(LOG_WARNING, "Module '%s' could not be loaded.\n", resource_name);
621                 return AST_MODULE_LOAD_DECLINE;
622 #endif
623         }
624
625         if (inspect_module(mod)) {
626                 ast_log(LOG_WARNING, "Module '%s' could not be loaded.\n", resource_name);
627 #if LOADABLE_MODULES
628                 unload_dynamic_module(mod);
629 #endif
630                 return AST_MODULE_LOAD_DECLINE;
631         }
632
633         if (!mod->lib && mod->info->backup_globals()) {
634                 ast_log(LOG_WARNING, "Module '%s' was unable to backup its global data.\n", resource_name);
635                 return AST_MODULE_LOAD_DECLINE;
636         }
637
638         ast_clear_flag(mod, FLAG_DECLINED);
639
640         if (mod->info->load)
641                 res = mod->info->load();
642
643         switch (res) {
644         case AST_MODULE_LOAD_SUCCESS:
645                 if (!ast_fully_booted) {
646                         if (option_verbose)
647                                 ast_verbose("%s => (%s)\n", resource_name, term_color(tmp, mod->info->description, COLOR_BROWN, COLOR_BLACK, sizeof(tmp)));
648                         if (ast_opt_console && !option_verbose)
649                                 ast_verbose( ".");
650                 } else {
651                         if (option_verbose)
652                                 ast_verbose(VERBOSE_PREFIX_1 "Loaded %s => (%s)\n", resource_name, mod->info->description);
653                 }
654
655                 ast_set_flag(mod, FLAG_RUNNING);
656
657                 ast_update_use_count();
658                 break;
659         case AST_MODULE_LOAD_DECLINE:
660                 ast_set_flag(mod, FLAG_DECLINED);
661                 break;
662         case AST_MODULE_LOAD_FAILURE:
663                 break;
664         case AST_MODULE_LOAD_SKIP:
665                 /* modules should never return this value */
666                 break;
667         }
668
669         return res;
670 }
671
672 int ast_load_resource(const char *resource_name)
673 {
674        AST_LIST_LOCK(&module_list);
675        load_resource(resource_name, 0);
676        AST_LIST_UNLOCK(&module_list);
677
678        return 0;
679 }
680
681 struct load_order_entry {
682         char *resource;
683         AST_LIST_ENTRY(load_order_entry) entry;
684 };
685
686 AST_LIST_HEAD_NOLOCK(load_order, load_order_entry);
687
688 static struct load_order_entry *add_to_load_order(const char *resource, struct load_order *load_order)
689 {
690         struct load_order_entry *order;
691
692         AST_LIST_TRAVERSE(load_order, order, entry) {
693                 if (!resource_name_match(order->resource, resource))
694                         return NULL;
695         }
696
697         if (!(order = ast_calloc(1, sizeof(*order))))
698                 return NULL;
699
700         order->resource = ast_strdup(resource);
701         AST_LIST_INSERT_TAIL(load_order, order, entry);
702
703         return order;
704 }
705
706 int load_modules(unsigned int preload_only)
707 {
708         struct ast_config *cfg;
709         struct ast_module *mod;
710         struct load_order_entry *order;
711         struct ast_variable *v;
712         unsigned int load_count;
713         struct load_order load_order;
714         int res = 0;
715 #if LOADABLE_MODULES
716         struct dirent *dirent;
717         DIR *dir;
718 #endif
719
720         /* all embedded modules have registered themselves by now */
721         embedding = 0;
722
723         if (option_verbose)
724                 ast_verbose("Asterisk Dynamic Loader Starting:\n");
725
726         AST_LIST_TRAVERSE(&module_list, mod, entry) {
727                 if (option_debug > 1)
728                         ast_log(LOG_DEBUG, "Embedded module found: %s\n", mod->resource);
729         }
730
731         if (!(cfg = ast_config_load(AST_MODULE_CONFIG))) {
732                 ast_log(LOG_WARNING, "No '%s' found, no modules will be loaded.\n", AST_MODULE_CONFIG);
733                 return 0;
734         }
735
736         AST_LIST_HEAD_INIT_NOLOCK(&load_order);
737
738         /* first, find all the modules we have been explicitly requested to load */
739         for (v = ast_variable_browse(cfg, "modules"); v; v = v->next) {
740                 if (!strcasecmp(v->name, preload_only ? "preload" : "load"))
741                         add_to_load_order(v->value, &load_order);
742         }
743
744         /* check if 'autoload' is on */
745         if (!preload_only && ast_true(ast_variable_retrieve(cfg, "modules", "autoload"))) {
746                 /* if so, first add all the embedded modules to the load order */
747                 AST_LIST_TRAVERSE(&module_list, mod, entry)
748                         order = add_to_load_order(mod->resource, &load_order);
749
750 #if LOADABLE_MODULES
751                 /* if we are allowed to load dynamic modules, scan the directory for
752                    for all available modules and add them as well */
753                 if ((dir  = opendir(ast_config_AST_MODULE_DIR))) {
754                         while ((dirent = readdir(dir))) {
755                                 int ld = strlen(dirent->d_name);
756
757                                 /* Must end in .so to load it.  */
758
759                                 if (ld < 4)
760                                         continue;
761
762                                 if (strcasecmp(dirent->d_name + ld - 3, ".so"))
763                                     continue;
764
765                                 add_to_load_order(dirent->d_name, &load_order);
766
767                         }
768
769                         closedir(dir);
770                 } else {
771                         if (!ast_opt_quiet)
772                                 ast_log(LOG_WARNING, "Unable to open modules directory '%s'.\n",
773                                         ast_config_AST_MODULE_DIR);
774                 }
775 #endif
776         }
777
778         /* now scan the config for any modules we are prohibited from loading and
779            remove them from the load order */
780         for (v = ast_variable_browse(cfg, "modules"); v; v = v->next) {
781                 if (strcasecmp(v->name, "noload"))
782                         continue;
783
784                 AST_LIST_TRAVERSE_SAFE_BEGIN(&load_order, order, entry) {
785                         if (!resource_name_match(order->resource, v->value)) {
786                                 AST_LIST_REMOVE_CURRENT(&load_order, entry);
787                                 free(order->resource);
788                                 free(order);
789                         }
790                 }
791                 AST_LIST_TRAVERSE_SAFE_END;
792         }
793
794         /* we are done with the config now, all the information we need is in the
795            load_order list */
796         ast_config_destroy(cfg);
797
798         load_count = 0;
799         AST_LIST_TRAVERSE(&load_order, order, entry)
800                 load_count++;
801
802         if (load_count)
803                 ast_log(LOG_NOTICE, "%d modules will be loaded.\n", load_count);
804
805         /* first, load only modules that provide global symbols */
806         AST_LIST_TRAVERSE_SAFE_BEGIN(&load_order, order, entry) {
807                 switch (load_resource(order->resource, 1)) {
808                 case AST_MODULE_LOAD_SUCCESS:
809                 case AST_MODULE_LOAD_DECLINE:
810                         AST_LIST_REMOVE_CURRENT(&load_order, entry);
811                         free(order->resource);
812                         free(order);
813                         break;
814                 case AST_MODULE_LOAD_FAILURE:
815                         res = -1;
816                         goto done;
817                 case AST_MODULE_LOAD_SKIP:
818                         /* try again later */
819                         break;
820                 }
821         }
822         AST_LIST_TRAVERSE_SAFE_END;
823
824         /* now load everything else */
825         AST_LIST_TRAVERSE_SAFE_BEGIN(&load_order, order, entry) {
826                 switch (load_resource(order->resource, 0)) {
827                 case AST_MODULE_LOAD_SUCCESS:
828                 case AST_MODULE_LOAD_DECLINE:
829                         AST_LIST_REMOVE_CURRENT(&load_order, entry);
830                         free(order->resource);
831                         free(order);
832                         break;
833                 case AST_MODULE_LOAD_FAILURE:
834                         res = -1;
835                         goto done;
836                 case AST_MODULE_LOAD_SKIP:
837                         /* should not happen */
838                         break;
839                 }
840         }
841         AST_LIST_TRAVERSE_SAFE_END;
842
843 done:
844         while ((order = AST_LIST_REMOVE_HEAD(&load_order, entry))) {
845                 free(order->resource);
846                 free(order);
847         }
848
849         return res;
850 }
851
852 void ast_update_use_count(void)
853 {
854         /* Notify any module monitors that the use count for a
855            resource has changed */
856         struct loadupdate *m;
857
858         AST_LIST_LOCK(&module_list);
859         AST_LIST_TRAVERSE(&updaters, m, entry)
860                 m->updater();
861         AST_LIST_UNLOCK(&module_list);
862 }
863
864 int ast_update_module_list(int (*modentry)(const char *module, const char *description, int usecnt, const char *like),
865                            const char *like)
866 {
867         struct ast_module *cur;
868         int unlock = -1;
869         int total_mod_loaded = 0;
870
871         if (AST_LIST_TRYLOCK(&module_list))
872                 unlock = 0;
873
874         AST_LIST_TRAVERSE(&module_list, cur, entry) {
875                 total_mod_loaded += modentry(cur->resource, cur->info->description, cur->usecount, like);
876         }
877
878         if (unlock)
879                 AST_LIST_UNLOCK(&module_list);
880
881         return total_mod_loaded;
882 }
883
884 /*! \brief Check if module exists */
885 int ast_module_check(char *name)
886 {
887         struct ast_module *cur;
888
889         if (ast_strlen_zero(name))
890                 return 0;       /* FALSE */
891
892         cur = find_resource(name, 1);
893
894         return (cur != NULL);
895 }
896
897
898 int ast_loader_register(int (*v)(void))
899 {
900         struct loadupdate *tmp;
901
902         if (!(tmp = ast_malloc(sizeof(*tmp))))
903                 return -1;
904
905         tmp->updater = v;
906         AST_LIST_LOCK(&module_list);
907         AST_LIST_INSERT_HEAD(&updaters, tmp, entry);
908         AST_LIST_UNLOCK(&module_list);
909
910         return 0;
911 }
912
913 int ast_loader_unregister(int (*v)(void))
914 {
915         struct loadupdate *cur;
916
917         AST_LIST_LOCK(&module_list);
918         AST_LIST_TRAVERSE_SAFE_BEGIN(&updaters, cur, entry) {
919                 if (cur->updater == v)  {
920                         AST_LIST_REMOVE_CURRENT(&updaters, entry);
921                         break;
922                 }
923         }
924         AST_LIST_TRAVERSE_SAFE_END;
925         AST_LIST_UNLOCK(&module_list);
926
927         return cur ? 0 : -1;
928 }
929
930 struct ast_module *ast_module_ref(struct ast_module *mod)
931 {
932         ast_atomic_fetchadd_int(&mod->usecount, +1);
933         ast_update_use_count();
934
935         return mod;
936 }
937
938 void ast_module_unref(struct ast_module *mod)
939 {
940         ast_atomic_fetchadd_int(&mod->usecount, -1);
941         ast_update_use_count();
942 }