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