Merged revisions 44322 via svnmerge from
[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;
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 HAVE_RTLD_NOLOAD
398         if (!dlopen(fn, RTLD_NOLOAD | (wants_global ? RTLD_LAZY | RTLD_GLOBAL : RTLD_NOW | RTLD_LOCAL))) {
399                 ast_log(LOG_WARNING, "Unable to promot 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         return res;
487 }
488
489 char *ast_module_helper(const char *line, const char *word, int pos, int state, int rpos, int needsreload)
490 {
491         struct ast_module *cur;
492         int i, which=0, l = strlen(word);
493         char *ret = NULL;
494
495         if (pos != rpos)
496                 return NULL;
497
498         AST_LIST_LOCK(&module_list);
499         AST_LIST_TRAVERSE(&module_list, cur, entry) {
500                 if (!strncasecmp(word, cur->resource, l) &&
501                     (cur->info->reload || !needsreload) &&
502                     ++which > state) {
503                         ret = strdup(cur->resource);
504                         break;
505                 }
506         }
507         AST_LIST_UNLOCK(&module_list);
508
509         if (!ret) {
510                 for (i=0; !ret && reload_classes[i].name; i++) {
511                         if (!strncasecmp(word, reload_classes[i].name, l) && ++which > state)
512                                 ret = strdup(reload_classes[i].name);
513                 }
514         }
515
516         return ret;
517 }
518
519 int ast_module_reload(const char *name)
520 {
521         struct ast_module *cur;
522         int res = 0; /* return value. 0 = not found, others, see below */
523         int i;
524
525         if (ast_mutex_trylock(&reloadlock)) {
526                 ast_verbose("The previous reload command didn't finish yet\n");
527                 return -1;      /* reload already in progress */
528         }
529
530         /* Call "predefined" reload here first */
531         for (i = 0; reload_classes[i].name; i++) {
532                 if (!name || !strcasecmp(name, reload_classes[i].name)) {
533                         reload_classes[i].reload_fn();  /* XXX should check error ? */
534                         res = 2;        /* found and reloaded */
535                 }
536         }
537         ast_lastreloadtime = time(NULL);
538
539         if (name && res)
540                 return res;
541
542         AST_LIST_LOCK(&module_list);
543         AST_LIST_TRAVERSE(&module_list, cur, entry) {
544                 const struct ast_module_info *info = cur->info;
545
546                 if (name && resource_name_match(name, cur->resource))
547                         continue;
548
549                 if (!ast_test_flag(cur, FLAG_RUNNING | FLAG_DECLINED))
550                         continue;
551
552                 if (!info->reload) {    /* cannot be reloaded */
553                         if (res < 1)    /* store result if possible */
554                                 res = 1;        /* 1 = no reload() method */
555                         continue;
556                 }
557
558                 res = 2;
559                 if (option_verbose > 2)
560                         ast_verbose(VERBOSE_PREFIX_3 "Reloading module '%s' (%s)\n", cur->resource, info->description);
561                 info->reload();
562         }
563         AST_LIST_UNLOCK(&module_list);
564
565         ast_mutex_unlock(&reloadlock);
566
567         return res;
568 }
569
570 static unsigned int inspect_module(const struct ast_module *mod)
571 {
572         if (!mod->info->description) {
573                 ast_log(LOG_WARNING, "Module '%s' does not provide a description.\n", mod->resource);
574                 return 1;
575         }
576
577         if (!mod->info->key) {
578                 ast_log(LOG_WARNING, "Module '%s' does not provide a license key.\n", mod->resource);
579                 return 1;
580         }
581
582         if (verify_key((unsigned char *) mod->info->key)) {
583                 ast_log(LOG_WARNING, "Module '%s' did not provide a valid license key.\n", mod->resource);
584                 return 1;
585         }
586
587         return 0;
588 }
589
590 static enum ast_module_load_result load_resource(const char *resource_name, unsigned int global_symbols_only)
591 {
592         struct ast_module *mod;
593         enum ast_module_load_result res = AST_MODULE_LOAD_SUCCESS;
594         char tmp[256];
595
596         if ((mod = find_resource(resource_name, 0))) {
597                 if (ast_test_flag(mod, FLAG_RUNNING)) {
598                         ast_log(LOG_WARNING, "Module '%s' already exists.\n", resource_name);
599                         return AST_MODULE_LOAD_DECLINE;
600                 }
601                 if (global_symbols_only && !ast_test_flag(mod->info, AST_MODFLAG_GLOBAL_SYMBOLS))
602                         return AST_MODULE_LOAD_SKIP;
603         } else {
604 #if LOADABLE_MODULES
605                 if (!(mod = load_dynamic_module(resource_name, global_symbols_only))) {
606                         /* don't generate a warning message during load_modules() */
607                         if (!global_symbols_only) {
608                                 ast_log(LOG_WARNING, "Module '%s' could not be loaded.\n", resource_name);
609                                 return AST_MODULE_LOAD_DECLINE;
610                         } else {
611                                 return AST_MODULE_LOAD_SKIP;
612                         }
613                 }
614 #else
615                 ast_log(LOG_WARNING, "Module '%s' could not be loaded.\n", resource_name);
616                 return AST_MODULE_LOAD_DECLINE;
617 #endif
618         }
619
620         if (inspect_module(mod)) {
621                 ast_log(LOG_WARNING, "Module '%s' could not be loaded.\n", resource_name);
622 #if LOADABLE_MODULES
623                 unload_dynamic_module(mod);
624 #endif
625                 return AST_MODULE_LOAD_DECLINE;
626         }
627
628         ast_clear_flag(mod, FLAG_DECLINED);
629
630         if (mod->info->load)
631                 res = mod->info->load();
632
633         switch (res) {
634         case AST_MODULE_LOAD_SUCCESS:
635                 if (!ast_fully_booted) {
636                         if (option_verbose)
637                                 ast_verbose("%s => (%s)\n", resource_name, term_color(tmp, mod->info->description, COLOR_BROWN, COLOR_BLACK, sizeof(tmp)));
638                         if (ast_opt_console && !option_verbose)
639                                 ast_verbose( ".");
640                 } else {
641                         if (option_verbose)
642                                 ast_verbose(VERBOSE_PREFIX_1 "Loaded %s => (%s)\n", resource_name, mod->info->description);
643                 }
644
645                 ast_set_flag(mod, FLAG_RUNNING);
646
647                 ast_update_use_count();
648                 break;
649         case AST_MODULE_LOAD_DECLINE:
650                 ast_set_flag(mod, FLAG_DECLINED);
651                 break;
652         case AST_MODULE_LOAD_FAILURE:
653                 break;
654         case AST_MODULE_LOAD_SKIP:
655                 /* modules should never return this value */
656                 break;
657         }
658
659         return res;
660 }
661
662 int ast_load_resource(const char *resource_name)
663 {
664        AST_LIST_LOCK(&module_list);
665        load_resource(resource_name, 0);
666        AST_LIST_UNLOCK(&module_list);
667
668        return 0;
669 }
670
671 struct load_order_entry {
672         char *resource;
673         AST_LIST_ENTRY(load_order_entry) entry;
674 };
675
676 AST_LIST_HEAD_NOLOCK(load_order, load_order_entry);
677
678 static struct load_order_entry *add_to_load_order(const char *resource, struct load_order *load_order)
679 {
680         struct load_order_entry *order;
681
682         AST_LIST_TRAVERSE(load_order, order, entry) {
683                 if (!resource_name_match(order->resource, resource))
684                         return NULL;
685         }
686
687         if (!(order = ast_calloc(1, sizeof(*order))))
688                 return NULL;
689
690         order->resource = ast_strdup(resource);
691         AST_LIST_INSERT_TAIL(load_order, order, entry);
692
693         return order;
694 }
695
696 int load_modules(unsigned int preload_only)
697 {
698         struct ast_config *cfg;
699         struct ast_module *mod;
700         struct load_order_entry *order;
701         struct ast_variable *v;
702         unsigned int load_count;
703         struct load_order load_order;
704         int res = 0;
705 #if LOADABLE_MODULES
706         struct dirent *dirent;
707         DIR *dir;
708 #endif
709
710         /* all embedded modules have registered themselves by now */
711         embedding = 0;
712
713         if (option_verbose)
714                 ast_verbose("Asterisk Dynamic Loader Starting:\n");
715
716         AST_LIST_TRAVERSE(&module_list, mod, entry) {
717                 if (option_debug > 1)
718                         ast_log(LOG_DEBUG, "Embedded module found: %s\n", mod->resource);
719         }
720
721         if (!(cfg = ast_config_load(AST_MODULE_CONFIG))) {
722                 ast_log(LOG_WARNING, "No '%s' found, no modules will be loaded.\n", AST_MODULE_CONFIG);
723                 return 0;
724         }
725
726         AST_LIST_HEAD_INIT_NOLOCK(&load_order);
727
728         /* first, find all the modules we have been explicitly requested to load */
729         for (v = ast_variable_browse(cfg, "modules"); v; v = v->next) {
730                 if (!strcasecmp(v->name, preload_only ? "preload" : "load"))
731                         add_to_load_order(v->value, &load_order);
732         }
733
734         /* check if 'autoload' is on */
735         if (!preload_only && ast_true(ast_variable_retrieve(cfg, "modules", "autoload"))) {
736                 /* if so, first add all the embedded modules to the load order */
737                 AST_LIST_TRAVERSE(&module_list, mod, entry)
738                         order = add_to_load_order(mod->resource, &load_order);
739
740 #if LOADABLE_MODULES
741                 /* if we are allowed to load dynamic modules, scan the directory for
742                    for all available modules and add them as well */
743                 if ((dir  = opendir(ast_config_AST_MODULE_DIR))) {
744                         while ((dirent = readdir(dir))) {
745                                 int ld = strlen(dirent->d_name);
746
747                                 /* Must end in .so to load it.  */
748
749                                 if (ld < 4)
750                                         continue;
751
752                                 if (strcasecmp(dirent->d_name + ld - 3, ".so"))
753                                     continue;
754
755                                 add_to_load_order(dirent->d_name, &load_order);
756
757                         }
758
759                         closedir(dir);
760                 } else {
761                         if (!ast_opt_quiet)
762                                 ast_log(LOG_WARNING, "Unable to open modules directory '%s'.\n",
763                                         ast_config_AST_MODULE_DIR);
764                 }
765 #endif
766         }
767
768         /* now scan the config for any modules we are prohibited from loading and
769            remove them from the load order */
770         for (v = ast_variable_browse(cfg, "modules"); v; v = v->next) {
771                 if (strcasecmp(v->name, "noload"))
772                         continue;
773
774                 AST_LIST_TRAVERSE_SAFE_BEGIN(&load_order, order, entry) {
775                         if (!resource_name_match(order->resource, v->value)) {
776                                 AST_LIST_REMOVE_CURRENT(&load_order, entry);
777                                 free(order->resource);
778                                 free(order);
779                         }
780                 }
781                 AST_LIST_TRAVERSE_SAFE_END;
782         }
783
784         /* we are done with the config now, all the information we need is in the
785            load_order list */
786         ast_config_destroy(cfg);
787
788         load_count = 0;
789         AST_LIST_TRAVERSE(&load_order, order, entry)
790                 load_count++;
791
792         if (load_count)
793                 ast_log(LOG_NOTICE, "%d modules will be loaded.\n", load_count);
794
795         /* first, load only modules that provide global symbols */
796         AST_LIST_TRAVERSE_SAFE_BEGIN(&load_order, order, entry) {
797                 switch (load_resource(order->resource, 1)) {
798                 case AST_MODULE_LOAD_SUCCESS:
799                 case AST_MODULE_LOAD_DECLINE:
800                         AST_LIST_REMOVE_CURRENT(&load_order, entry);
801                         free(order->resource);
802                         free(order);
803                         break;
804                 case AST_MODULE_LOAD_FAILURE:
805                         res = -1;
806                         goto done;
807                 case AST_MODULE_LOAD_SKIP:
808                         /* try again later */
809                         break;
810                 }
811         }
812         AST_LIST_TRAVERSE_SAFE_END;
813
814         /* now load everything else */
815         AST_LIST_TRAVERSE_SAFE_BEGIN(&load_order, order, entry) {
816                 switch (load_resource(order->resource, 0)) {
817                 case AST_MODULE_LOAD_SUCCESS:
818                 case AST_MODULE_LOAD_DECLINE:
819                         AST_LIST_REMOVE_CURRENT(&load_order, entry);
820                         free(order->resource);
821                         free(order);
822                         break;
823                 case AST_MODULE_LOAD_FAILURE:
824                         res = -1;
825                         goto done;
826                 case AST_MODULE_LOAD_SKIP:
827                         /* should not happen */
828                         break;
829                 }
830         }
831         AST_LIST_TRAVERSE_SAFE_END;
832
833 done:
834         while ((order = AST_LIST_REMOVE_HEAD(&load_order, entry))) {
835                 free(order->resource);
836                 free(order);
837         }
838
839         return res;
840 }
841
842 void ast_update_use_count(void)
843 {
844         /* Notify any module monitors that the use count for a
845            resource has changed */
846         struct loadupdate *m;
847
848         AST_LIST_LOCK(&module_list);
849         AST_LIST_TRAVERSE(&updaters, m, entry)
850                 m->updater();
851         AST_LIST_UNLOCK(&module_list);
852 }
853
854 int ast_update_module_list(int (*modentry)(const char *module, const char *description, int usecnt, const char *like),
855                            const char *like)
856 {
857         struct ast_module *cur;
858         int unlock = -1;
859         int total_mod_loaded = 0;
860
861         if (AST_LIST_TRYLOCK(&module_list))
862                 unlock = 0;
863
864         AST_LIST_TRAVERSE(&module_list, cur, entry) {
865                 total_mod_loaded += modentry(cur->resource, cur->info->description, cur->usecount, like);
866         }
867
868         if (unlock)
869                 AST_LIST_UNLOCK(&module_list);
870
871         return total_mod_loaded;
872 }
873
874 int ast_loader_register(int (*v)(void))
875 {
876         struct loadupdate *tmp;
877
878         if (!(tmp = ast_malloc(sizeof(*tmp))))
879                 return -1;
880
881         tmp->updater = v;
882         AST_LIST_LOCK(&module_list);
883         AST_LIST_INSERT_HEAD(&updaters, tmp, entry);
884         AST_LIST_UNLOCK(&module_list);
885
886         return 0;
887 }
888
889 int ast_loader_unregister(int (*v)(void))
890 {
891         struct loadupdate *cur;
892
893         AST_LIST_LOCK(&module_list);
894         AST_LIST_TRAVERSE_SAFE_BEGIN(&updaters, cur, entry) {
895                 if (cur->updater == v)  {
896                         AST_LIST_REMOVE_CURRENT(&updaters, entry);
897                         break;
898                 }
899         }
900         AST_LIST_TRAVERSE_SAFE_END;
901         AST_LIST_UNLOCK(&module_list);
902
903         return cur ? 0 : -1;
904 }
905
906 struct ast_module *ast_module_ref(struct ast_module *mod)
907 {
908         ast_atomic_fetchadd_int(&mod->usecount, +1);
909         ast_update_use_count();
910
911         return mod;
912 }
913
914 void ast_module_unref(struct ast_module *mod)
915 {
916         ast_atomic_fetchadd_int(&mod->usecount, -1);
917         ast_update_use_count();
918 }