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