4ece4ae6b62ac3f33987b33a021ff9e07bace4df
[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         ast_log(LOG_DEBUG, "Unexpected signature:%s\n", buf);
254
255         return 0;
256 }
257
258 static int key_matches(const unsigned char *key1, const unsigned char *key2)
259 {
260         int x;
261
262         for (x = 0; x < 16; x++) {
263                 if (key1[x] != key2[x])
264                         return 0;
265         }
266
267         return 1;
268 }
269
270 static int verify_key(const unsigned char *key)
271 {
272         struct MD5Context c;
273         unsigned char digest[16];
274
275         MD5Init(&c);
276         MD5Update(&c, key, strlen((char *)key));
277         MD5Final(digest, &c);
278
279         if (key_matches(expected_key, digest))
280                 return 0;
281
282         printdigest(digest);
283
284         return -1;
285 }
286
287 static int resource_name_match(const char *name1_in, const char *name2_in)
288 {
289         char *name1 = (char *) name1_in;
290         char *name2 = (char *) name2_in;
291
292         /* trim off any .so extensions */
293         if (!strcasecmp(name1 + strlen(name1) - 3, ".so")) {
294                 name1 = ast_strdupa(name1);
295                 name1[strlen(name1) - 3] = '\0';
296         }
297         if (!strcasecmp(name2 + strlen(name2) - 3, ".so")) {
298                 name2 = ast_strdupa(name2);
299                 name2[strlen(name2) - 3] = '\0';
300         }
301
302         return strcasecmp(name1, name2);
303 }
304
305 static struct ast_module *find_resource(const char *resource, int do_lock)
306 {
307         struct ast_module *cur;
308
309         if (do_lock)
310                 AST_LIST_LOCK(&module_list);
311
312         AST_LIST_TRAVERSE(&module_list, cur, entry) {
313                 if (!resource_name_match(resource, cur->resource))
314                         break;
315         }
316
317         if (do_lock)
318                 AST_LIST_UNLOCK(&module_list);
319
320         return cur;
321 }
322
323 #if LOADABLE_MODULES
324 static void unload_dynamic_module(struct ast_module *mod)
325 {
326         if (mod->lib)
327                 while (!dlclose(mod->lib));
328         /* WARNING: the structure pointed to by mod is now gone! */
329 }
330
331 static struct ast_module *load_dynamic_module(const char *resource_in, unsigned int global_symbols_only)
332 {
333         char fn[256];
334         void *lib;
335         struct ast_module *mod;
336         char *resource = (char *) resource_in;
337         unsigned int wants_global;
338
339         if (strcasecmp(resource + strlen(resource) - 3, ".so")) {
340                 resource = alloca(strlen(resource_in) + 3);
341                 strcpy(resource, resource_in);
342                 strcat(resource, ".so");
343         }
344
345         snprintf(fn, sizeof(fn), "%s/%s", ast_config_AST_MODULE_DIR, resource);
346
347         /* make a first load of the module in 'quiet' mode... don't try to resolve
348            any symbols, and don't export any symbols. this will allow us to peek into
349            the module's info block (if available) to see what flags it has set */
350
351         if (!(resource_being_loaded = ast_calloc(1, sizeof(*resource_being_loaded) + strlen(resource) + 1)))
352                 return NULL;
353
354         strcpy(resource_being_loaded->resource, resource);
355
356         if (!(lib = dlopen(fn, RTLD_LAZY | RTLD_LOCAL))) {
357                 ast_log(LOG_WARNING, "%s\n", dlerror());
358                 free(resource_being_loaded);
359                 return NULL;
360         }
361
362         /* the dlopen() succeeded, let's find out if the module
363            registered itself */
364         /* note that this will only work properly as long as
365            ast_module_register() (which is called by the module's
366            constructor) places the new module at the tail of the
367            module_list
368         */
369         if (resource_being_loaded != (mod = AST_LIST_LAST(&module_list))) {
370                 /* no, it did not, so close it and return */
371                 while (!dlclose(lib));
372                 /* note that the module's destructor will call ast_module_unregister(),
373                    which will free the structure we allocated in resource_being_loaded */
374                 return NULL;
375         }
376
377         wants_global = ast_test_flag(mod->info, AST_MODFLAG_GLOBAL_SYMBOLS);
378
379         /* if we are being asked only to load modules that provide global symbols,
380            and this one does not, then close it and return */
381         if (global_symbols_only && !wants_global) {
382                 while (!dlclose(lib));
383                 return NULL;
384         }
385
386         /* if the system supports RTLD_NOLOAD, we can just 'promote' the flags
387            on the already-opened library to what we want... if not, we have to
388            close it and start over
389         */
390 #if HAVE_RTLD_NOLOAD
391         if (!dlopen(fn, RTLD_NOLOAD | (wants_global ? RTLD_LAZY | RTLD_GLOBAL : RTLD_NOW | RTLD_LOCAL))) {
392                 ast_log(LOG_WARNING, "%s\n", dlerror());
393                 while (!dlclose(lib));
394                 free(resource_being_loaded);
395                 return NULL;
396         }
397 #else
398         while (!dlclose(lib));
399         resource_being_loaded = NULL;
400
401         /* start the load process again */
402
403         if (!(resource_being_loaded = ast_calloc(1, sizeof(*resource_being_loaded) + strlen(resource) + 1)))
404                 return NULL;
405
406         strcpy(resource_being_loaded->resource, resource);
407
408         if (!(lib = dlopen(fn, wants_global ? RTLD_LAZY | RTLD_GLOBAL : RTLD_NOW | RTLD_LOCAL))) {
409                 ast_log(LOG_WARNING, "%s\n", dlerror());
410                 free(resource_being_loaded);
411                 return NULL;
412         }
413
414         /* since the module was successfully opened, and it registered itself
415            the previous time we did that, we're going to assume it worked this
416            time too :) */
417 #endif
418
419         AST_LIST_LAST(&module_list)->lib = lib;
420         resource_being_loaded = NULL;
421
422         return AST_LIST_LAST(&module_list);
423 }
424 #endif
425
426 int ast_unload_resource(const char *resource_name, enum ast_module_unload_mode force)
427 {
428         struct ast_module *mod;
429         int res = -1;
430         int error = 0;
431
432         AST_LIST_LOCK(&module_list);
433
434         if (!(mod = find_resource(resource_name, 0))) {
435                 AST_LIST_UNLOCK(&module_list);
436                 return 0;
437         }
438
439         if (!ast_test_flag(mod, FLAG_RUNNING | FLAG_DECLINED))
440                 error = 1;
441
442         if (!error && (mod->usecount > 0)) {
443                 if (force) 
444                         ast_log(LOG_WARNING, "Warning:  Forcing removal of module '%s' with use count %d\n",
445                                 resource_name, mod->usecount);
446                 else {
447                         ast_log(LOG_WARNING, "Soft unload failed, '%s' has use count %d\n", resource_name,
448                                 mod->usecount);
449                         error = 1;
450                 }
451         }
452
453         if (!error) {
454                 __ast_module_user_hangup_all(mod);
455                 res = mod->info->unload();
456
457                 if (res) {
458                         ast_log(LOG_WARNING, "Firm unload failed for %s\n", resource_name);
459                         if (force <= AST_FORCE_FIRM)
460                                 error = 1;
461                         else
462                                 ast_log(LOG_WARNING, "** Dangerous **: Unloading resource anyway, at user request\n");
463                 }
464         }
465
466         if (!error)
467                 ast_clear_flag(mod, FLAG_RUNNING | FLAG_DECLINED);
468
469         AST_LIST_UNLOCK(&module_list);
470
471 #if LOADABLE_MODULES
472         if (!error)
473                 unload_dynamic_module(mod);
474 #endif
475
476         if (!error)
477                 ast_update_use_count();
478
479         return res;
480 }
481
482 char *ast_module_helper(const char *line, const char *word, int pos, int state, int rpos, int needsreload)
483 {
484         struct ast_module *cur;
485         int i, which=0, l = strlen(word);
486         char *ret = NULL;
487
488         if (pos != rpos)
489                 return NULL;
490
491         AST_LIST_LOCK(&module_list);
492         AST_LIST_TRAVERSE(&module_list, cur, entry) {
493                 if (!strncasecmp(word, cur->resource, l) &&
494                     (cur->info->reload || !needsreload) &&
495                     ++which > state) {
496                         ret = strdup(cur->resource);
497                         break;
498                 }
499         }
500         AST_LIST_UNLOCK(&module_list);
501
502         if (!ret) {
503                 for (i=0; !ret && reload_classes[i].name; i++) {
504                         if (!strncasecmp(word, reload_classes[i].name, l) && ++which > state)
505                                 ret = strdup(reload_classes[i].name);
506                 }
507         }
508
509         return ret;
510 }
511
512 int ast_module_reload(const char *name)
513 {
514         struct ast_module *cur;
515         int res = 0; /* return value. 0 = not found, others, see below */
516         int i;
517
518         if (ast_mutex_trylock(&reloadlock)) {
519                 ast_verbose("The previous reload command didn't finish yet\n");
520                 return -1;      /* reload already in progress */
521         }
522
523         /* Call "predefined" reload here first */
524         for (i = 0; reload_classes[i].name; i++) {
525                 if (!name || !strcasecmp(name, reload_classes[i].name)) {
526                         reload_classes[i].reload_fn();  /* XXX should check error ? */
527                         res = 2;        /* found and reloaded */
528                 }
529         }
530         ast_lastreloadtime = time(NULL);
531
532         if (name && res)
533                 return res;
534
535         AST_LIST_LOCK(&module_list);
536         AST_LIST_TRAVERSE(&module_list, cur, entry) {
537                 const struct ast_module_info *info = cur->info;
538
539                 if (name && resource_name_match(name, cur->resource))
540                         continue;
541
542                 if (!ast_test_flag(cur, FLAG_RUNNING | FLAG_DECLINED))
543                         continue;
544
545                 if (!info->reload) {    /* cannot be reloaded */
546                         if (res < 1)    /* store result if possible */
547                                 res = 1;        /* 1 = no reload() method */
548                         continue;
549                 }
550
551                 res = 2;
552                 if (option_verbose > 2) 
553                         ast_verbose(VERBOSE_PREFIX_3 "Reloading module '%s' (%s)\n", cur->resource, info->description);
554                 info->reload();
555         }
556         AST_LIST_UNLOCK(&module_list);
557
558         ast_mutex_unlock(&reloadlock);
559
560         return res;
561 }
562
563 static unsigned int inspect_module(const struct ast_module *mod)
564 {
565         if (!mod->info->description) {
566                 ast_log(LOG_WARNING, "Module '%s' does not provide a description.\n", mod->resource);
567                 return 1;
568         }
569
570         if (!mod->info->key) {
571                 ast_log(LOG_WARNING, "Module '%s' does not provide a license key.\n", mod->resource);
572                 return 1;
573         }
574
575         if (verify_key((unsigned char *) mod->info->key)) {
576                 ast_log(LOG_WARNING, "Module '%s' did not provide a valid license key.\n", mod->resource);
577                 return 1;
578         }
579
580         return 0;
581 }
582
583 static enum ast_module_load_result load_resource(const char *resource_name, unsigned int global_symbols_only)
584 {
585         struct ast_module *mod;
586         enum ast_module_load_result res = AST_MODULE_LOAD_SUCCESS;
587         char tmp[256];
588
589         if ((mod = find_resource(resource_name, 0))) {
590                 if (ast_test_flag(mod, FLAG_RUNNING)) {
591                         ast_log(LOG_WARNING, "Module '%s' already exists.\n", resource_name);
592                         return AST_MODULE_LOAD_DECLINE;
593                 }
594                 if (global_symbols_only && !ast_test_flag(mod->info, AST_MODFLAG_GLOBAL_SYMBOLS))
595                         return AST_MODULE_LOAD_SKIP;
596         } else {
597 #if LOADABLE_MODULES
598                 if (!(mod = load_dynamic_module(resource_name, global_symbols_only))) {
599                         /* don't generate a warning message during load_modules() */
600                         if (!global_symbols_only) {
601                                 ast_log(LOG_WARNING, "Module '%s' could not be loaded.\n", resource_name);
602                                 return AST_MODULE_LOAD_DECLINE;
603                         } else {
604                                 return AST_MODULE_LOAD_SKIP;
605                         }
606                 }
607 #else
608                 ast_log(LOG_WARNING, "Module '%s' could not be loaded.\n", resource_name);
609                 return AST_MODULE_LOAD_DECLINE;
610 #endif
611         }
612
613         if (inspect_module(mod)) {
614                 ast_log(LOG_WARNING, "Module '%s' could not be loaded.\n", resource_name);
615 #if LOADABLE_MODULES
616                 unload_dynamic_module(mod);
617 #endif
618                 return AST_MODULE_LOAD_DECLINE;
619         }
620
621         ast_clear_flag(mod, FLAG_DECLINED);
622
623         if (mod->info->load)
624                 res = mod->info->load();
625
626         switch (res) {
627         case AST_MODULE_LOAD_SUCCESS:
628                 if (!ast_fully_booted) {
629                         if (option_verbose) 
630                                 ast_verbose("%s => (%s)\n", resource_name, term_color(tmp, mod->info->description, COLOR_BROWN, COLOR_BLACK, sizeof(tmp)));
631                         if (ast_opt_console && !option_verbose)
632                                 ast_verbose( ".");
633                 } else {
634                         if (option_verbose)
635                                 ast_verbose(VERBOSE_PREFIX_1 "Loaded %s => (%s)\n", resource_name, mod->info->description);
636                 }
637
638                 ast_set_flag(mod, FLAG_RUNNING);
639                 
640                 ast_update_use_count();
641                 break;
642         case AST_MODULE_LOAD_DECLINE:
643                 ast_set_flag(mod, FLAG_DECLINED);
644                 break;
645         case AST_MODULE_LOAD_FAILURE:
646                 break;
647         case AST_MODULE_LOAD_SKIP:
648                 /* modules should never return this value */
649                 break;
650         }
651
652         return res;
653 }
654
655 int ast_load_resource(const char *resource_name)
656 {
657        AST_LIST_LOCK(&module_list);
658        load_resource(resource_name, 0);
659        AST_LIST_UNLOCK(&module_list);
660
661        return 0;
662 }
663
664 struct load_order_entry {
665         char *resource;
666         AST_LIST_ENTRY(load_order_entry) entry;
667 };
668
669 AST_LIST_HEAD_NOLOCK(load_order, load_order_entry);
670
671 static struct load_order_entry *add_to_load_order(const char *resource, struct load_order *load_order)
672 {
673         struct load_order_entry *order;
674
675         AST_LIST_TRAVERSE(load_order, order, entry) {
676                 if (!resource_name_match(order->resource, resource))
677                         return NULL;
678         }
679
680         if (!(order = ast_calloc(1, sizeof(*order))))
681                 return NULL;
682
683         order->resource = ast_strdup(resource);
684         AST_LIST_INSERT_TAIL(load_order, order, entry);
685
686         return order;
687 }
688
689 int load_modules(unsigned int preload_only)
690 {
691         struct ast_config *cfg;
692         struct ast_module *mod;
693         struct load_order_entry *order;
694         struct ast_variable *v;
695         unsigned int load_count;
696         struct load_order load_order;
697         int res = 0;
698 #if LOADABLE_MODULES
699         struct dirent *dirent;
700         DIR *dir;
701 #endif
702
703         /* all embedded modules have registered themselves by now */
704         embedding = 0;
705
706         if (option_verbose)
707                 ast_verbose("Asterisk Dynamic Loader Starting:\n");
708
709         AST_LIST_TRAVERSE(&module_list, mod, entry) {
710                 if (option_debug > 1)
711                         ast_log(LOG_DEBUG, "Embedded module found: %s\n", mod->resource);
712         }
713
714         if (!(cfg = ast_config_load(AST_MODULE_CONFIG))) {
715                 ast_log(LOG_WARNING, "No '%s' found, no modules will be loaded.\n", AST_MODULE_CONFIG);
716                 return 0;
717         }
718
719         AST_LIST_HEAD_INIT_NOLOCK(&load_order);
720
721         /* first, find all the modules we have been explicitly requested to load */
722         for (v = ast_variable_browse(cfg, "modules"); v; v = v->next) {
723                 if (!strcasecmp(v->name, preload_only ? "preload" : "load"))
724                         add_to_load_order(v->value, &load_order);
725         }
726
727         /* check if 'autoload' is on */
728         if (!preload_only && ast_true(ast_variable_retrieve(cfg, "modules", "autoload"))) {
729                 /* if so, first add all the embedded modules to the load order */
730                 AST_LIST_TRAVERSE(&module_list, mod, entry)
731                         order = add_to_load_order(mod->resource, &load_order);
732
733 #if LOADABLE_MODULES
734                 /* if we are allowed to load dynamic modules, scan the directory for
735                    for all available modules and add them as well */
736                 if ((dir  = opendir(ast_config_AST_MODULE_DIR))) {
737                         while ((dirent = readdir(dir))) {
738                                 int ld = strlen(dirent->d_name);
739                                 
740                                 /* Must end in .so to load it.  */
741
742                                 if (ld < 4)
743                                         continue;
744
745                                 if (strcasecmp(dirent->d_name + ld - 3, ".so"))
746                                     continue;
747
748                                 add_to_load_order(dirent->d_name, &load_order);
749
750                         }
751
752                         closedir(dir);
753                 } else {
754                         if (!ast_opt_quiet)
755                                 ast_log(LOG_WARNING, "Unable to open modules directory '%s'.\n",
756                                         ast_config_AST_MODULE_DIR);
757                 }
758 #endif
759         }
760
761         /* now scan the config for any modules we are prohibited from loading and
762            remove them from the load order */
763         for (v = ast_variable_browse(cfg, "modules"); v; v = v->next) {
764                 if (strcasecmp(v->name, "noload"))
765                         continue;
766
767                 AST_LIST_TRAVERSE_SAFE_BEGIN(&load_order, order, entry) {
768                         if (!resource_name_match(order->resource, v->value)) {
769                                 AST_LIST_REMOVE_CURRENT(&load_order, entry);
770                                 free(order->resource);
771                                 free(order);
772                         }
773                 }
774                 AST_LIST_TRAVERSE_SAFE_END;
775         }
776
777         /* we are done with the config now, all the information we need is in the
778            load_order list */
779         ast_config_destroy(cfg);
780
781         load_count = 0;
782         AST_LIST_TRAVERSE(&load_order, order, entry)
783                 load_count++;
784
785         if (load_count)
786                 ast_log(LOG_NOTICE, "%d modules will be loaded.\n", load_count);
787
788         /* first, load only modules that provide global symbols */
789         AST_LIST_TRAVERSE_SAFE_BEGIN(&load_order, order, entry) {
790                 switch (load_resource(order->resource, 1)) {
791                 case AST_MODULE_LOAD_SUCCESS:
792                 case AST_MODULE_LOAD_DECLINE:
793                         AST_LIST_REMOVE_CURRENT(&load_order, entry);
794                         free(order->resource);
795                         free(order);
796                         break;
797                 case AST_MODULE_LOAD_FAILURE:
798                         res = -1;
799                         goto done;
800                 case AST_MODULE_LOAD_SKIP:
801                         /* try again later */
802                         break;
803                 }
804         }
805         AST_LIST_TRAVERSE_SAFE_END;
806
807         /* now load everything else */
808         AST_LIST_TRAVERSE_SAFE_BEGIN(&load_order, order, entry) {
809                 switch (load_resource(order->resource, 0)) {
810                 case AST_MODULE_LOAD_SUCCESS:
811                 case AST_MODULE_LOAD_DECLINE:
812                         AST_LIST_REMOVE_CURRENT(&load_order, entry);
813                         free(order->resource);
814                         free(order);
815                         break;
816                 case AST_MODULE_LOAD_FAILURE:
817                         res = -1;
818                         goto done;
819                 case AST_MODULE_LOAD_SKIP:
820                         /* should not happen */
821                         break;
822                 }
823         }
824         AST_LIST_TRAVERSE_SAFE_END;
825
826 done:
827         while ((order = AST_LIST_REMOVE_HEAD(&load_order, entry))) {
828                 free(order->resource);
829                 free(order);
830         }
831
832         return res;
833 }
834
835 void ast_update_use_count(void)
836 {
837         /* Notify any module monitors that the use count for a 
838            resource has changed */
839         struct loadupdate *m;
840
841         AST_LIST_LOCK(&module_list);
842         AST_LIST_TRAVERSE(&updaters, m, entry)
843                 m->updater();
844         AST_LIST_UNLOCK(&module_list);
845 }
846
847 int ast_update_module_list(int (*modentry)(const char *module, const char *description, int usecnt, const char *like),
848                            const char *like)
849 {
850         struct ast_module *cur;
851         int unlock = -1;
852         int total_mod_loaded = 0;
853
854         if (AST_LIST_TRYLOCK(&module_list))
855                 unlock = 0;
856
857         AST_LIST_TRAVERSE(&module_list, cur, entry) {
858                 total_mod_loaded += modentry(cur->resource, cur->info->description, cur->usecount, like);
859         }
860
861         if (unlock)
862                 AST_LIST_UNLOCK(&module_list);
863
864         return total_mod_loaded;
865 }
866
867 int ast_loader_register(int (*v)(void)) 
868 {
869         struct loadupdate *tmp; 
870
871         if (!(tmp = ast_malloc(sizeof(*tmp))))
872                 return -1;
873
874         tmp->updater = v;
875         AST_LIST_LOCK(&module_list);
876         AST_LIST_INSERT_HEAD(&updaters, tmp, entry);
877         AST_LIST_UNLOCK(&module_list);
878
879         return 0;
880 }
881
882 int ast_loader_unregister(int (*v)(void))
883 {
884         struct loadupdate *cur;
885
886         AST_LIST_LOCK(&module_list);
887         AST_LIST_TRAVERSE_SAFE_BEGIN(&updaters, cur, entry) {
888                 if (cur->updater == v)  {
889                         AST_LIST_REMOVE_CURRENT(&updaters, entry);
890                         break;
891                 }
892         }
893         AST_LIST_TRAVERSE_SAFE_END;
894         AST_LIST_UNLOCK(&module_list);
895
896         return cur ? 0 : -1;
897 }
898
899 struct ast_module *ast_module_ref(struct ast_module *mod)
900 {
901         ast_atomic_fetchadd_int(&mod->usecount, +1);
902         ast_update_use_count();
903
904         return mod;
905 }
906
907 void ast_module_unref(struct ast_module *mod)
908 {
909         ast_atomic_fetchadd_int(&mod->usecount, -1);
910         ast_update_use_count();
911 }