generate a message when a module cannot be found and loadable modules are disabled
[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                 ast_log(LOG_WARNING, "Module '%s' could not be loaded.\n", resource_name);
595                 return AST_MODULE_LOAD_DECLINE;
596 #endif
597         }
598
599         if (inspect_module(mod)) {
600                 ast_log(LOG_WARNING, "Module '%s' could not be loaded.\n", resource_name);
601 #if LOADABLE_MODULES
602                 unload_dynamic_module(mod);
603 #endif
604                 return AST_MODULE_LOAD_DECLINE;
605         }
606
607         ast_clear_flag(mod, FLAG_DECLINED);
608
609         if (mod->info->load)
610                 res = mod->info->load();
611
612         switch (res) {
613         case AST_MODULE_LOAD_SUCCESS:
614                 if (!ast_fully_booted) {
615                         if (option_verbose) 
616                                 ast_verbose("%s => (%s)\n", resource_name, term_color(tmp, mod->info->description, COLOR_BROWN, COLOR_BLACK, sizeof(tmp)));
617                         if (ast_opt_console && !option_verbose)
618                                 ast_verbose( ".");
619                 } else {
620                         if (option_verbose)
621                                 ast_verbose(VERBOSE_PREFIX_1 "Loaded %s => (%s)\n", resource_name, mod->info->description);
622                 }
623
624                 ast_set_flag(mod, FLAG_RUNNING);
625                 
626                 ast_update_use_count();
627                 break;
628         case AST_MODULE_LOAD_DECLINE:
629                 ast_set_flag(mod, FLAG_DECLINED);
630                 break;
631         case AST_MODULE_LOAD_FAILURE:
632                 break;
633         case AST_MODULE_LOAD_SKIP:
634                 /* modules should never return this value */
635                 break;
636         }
637
638         return res;
639 }
640
641 int ast_load_resource(const char *resource_name)
642 {
643        AST_LIST_LOCK(&module_list);
644        load_resource(resource_name, 0);
645        AST_LIST_UNLOCK(&module_list);
646
647        return 0;
648 }
649
650 struct load_order_entry {
651         char *resource;
652         AST_LIST_ENTRY(load_order_entry) entry;
653 };
654
655 AST_LIST_HEAD_NOLOCK(load_order, load_order_entry);
656
657 static struct load_order_entry *add_to_load_order(const char *resource, struct load_order *load_order)
658 {
659         struct load_order_entry *order;
660
661         AST_LIST_TRAVERSE(load_order, order, entry) {
662                 if (!resource_name_match(order->resource, resource))
663                         return NULL;
664         }
665
666         if (!(order = ast_calloc(1, sizeof(*order))))
667                 return NULL;
668
669         order->resource = ast_strdup(resource);
670         AST_LIST_INSERT_TAIL(load_order, order, entry);
671
672         return order;
673 }
674
675 int load_modules(unsigned int preload_only)
676 {
677         struct ast_config *cfg;
678         struct ast_module *mod;
679         struct load_order_entry *order;
680         struct ast_variable *v;
681         unsigned int load_count;
682         struct load_order load_order;
683         int res = 0;
684 #if LOADABLE_MODULES
685         struct dirent *dirent;
686         DIR *dir;
687 #endif
688
689         /* all embedded modules have registered themselves by now */
690         embedding = 0;
691
692         if (option_verbose)
693                 ast_verbose("Asterisk Dynamic Loader Starting:\n");
694
695         AST_LIST_TRAVERSE(&module_list, mod, entry) {
696                 if (option_debug > 1)
697                         ast_log(LOG_DEBUG, "Embedded module found: %s\n", mod->resource);
698         }
699
700         if (!(cfg = ast_config_load(AST_MODULE_CONFIG))) {
701                 ast_log(LOG_WARNING, "No '%s' found, no modules will be loaded.\n", AST_MODULE_CONFIG);
702                 return 0;
703         }
704
705         AST_LIST_HEAD_INIT_NOLOCK(&load_order);
706
707         /* first, find all the modules we have been explicitly requested to load */
708         for (v = ast_variable_browse(cfg, "modules"); v; v = v->next) {
709                 if (!strcasecmp(v->name, preload_only ? "preload" : "load"))
710                         add_to_load_order(v->value, &load_order);
711         }
712
713         /* check if 'autoload' is on */
714         if (!preload_only && ast_true(ast_variable_retrieve(cfg, "modules", "autoload"))) {
715                 /* if so, first add all the embedded modules to the load order */
716                 AST_LIST_TRAVERSE(&module_list, mod, entry)
717                         order = add_to_load_order(mod->resource, &load_order);
718
719 #if LOADABLE_MODULES
720                 /* if we are allowed to load dynamic modules, scan the directory for
721                    for all available modules and add them as well */
722                 if ((dir  = opendir(ast_config_AST_MODULE_DIR))) {
723                         while ((dirent = readdir(dir))) {
724                                 int ld = strlen(dirent->d_name);
725                                 
726                                 /* Must end in .so to load it.  */
727
728                                 if (ld < 4)
729                                         continue;
730
731                                 if (strcasecmp(dirent->d_name + ld - 3, ".so"))
732                                     continue;
733
734                                 add_to_load_order(dirent->d_name, &load_order);
735
736                         }
737
738                         closedir(dir);
739                 } else {
740                         if (!ast_opt_quiet)
741                                 ast_log(LOG_WARNING, "Unable to open modules directory '%s'.\n",
742                                         ast_config_AST_MODULE_DIR);
743                 }
744 #endif
745         }
746
747         /* now scan the config for any modules we are prohibited from loading and
748            remove them from the load order */
749         for (v = ast_variable_browse(cfg, "modules"); v; v = v->next) {
750                 if (strcasecmp(v->name, "noload"))
751                         continue;
752
753                 AST_LIST_TRAVERSE_SAFE_BEGIN(&load_order, order, entry) {
754                         if (!resource_name_match(order->resource, v->value)) {
755                                 AST_LIST_REMOVE_CURRENT(&load_order, entry);
756                                 free(order->resource);
757                                 free(order);
758                         }
759                 }
760                 AST_LIST_TRAVERSE_SAFE_END;
761         }
762
763         /* we are done with the config now, all the information we need is in the
764            load_order list */
765         ast_config_destroy(cfg);
766
767         load_count = 0;
768         AST_LIST_TRAVERSE(&load_order, order, entry)
769                 load_count++;
770
771         if (load_count)
772                 ast_log(LOG_NOTICE, "%d modules will be loaded.\n", load_count);
773
774         /* first, load only modules that provide global symbols */
775         AST_LIST_TRAVERSE_SAFE_BEGIN(&load_order, order, entry) {
776                 switch (load_resource(order->resource, 1)) {
777                 case AST_MODULE_LOAD_SUCCESS:
778                 case AST_MODULE_LOAD_DECLINE:
779                         AST_LIST_REMOVE_CURRENT(&load_order, entry);
780                         free(order->resource);
781                         free(order);
782                         break;
783                 case AST_MODULE_LOAD_FAILURE:
784                         res = -1;
785                         goto done;
786                 case AST_MODULE_LOAD_SKIP:
787                         /* try again later */
788                         break;
789                 }
790         }
791         AST_LIST_TRAVERSE_SAFE_END;
792
793         /* now load everything else */
794         AST_LIST_TRAVERSE_SAFE_BEGIN(&load_order, order, entry) {
795                 switch (load_resource(order->resource, 0)) {
796                 case AST_MODULE_LOAD_SUCCESS:
797                 case AST_MODULE_LOAD_DECLINE:
798                         AST_LIST_REMOVE_CURRENT(&load_order, entry);
799                         free(order->resource);
800                         free(order);
801                         break;
802                 case AST_MODULE_LOAD_FAILURE:
803                         res = -1;
804                         goto done;
805                 case AST_MODULE_LOAD_SKIP:
806                         /* should not happen */
807                         break;
808                 }
809         }
810         AST_LIST_TRAVERSE_SAFE_END;
811
812 done:
813         while ((order = AST_LIST_REMOVE_HEAD(&load_order, entry))) {
814                 free(order->resource);
815                 free(order);
816         }
817
818         return res;
819 }
820
821 void ast_update_use_count(void)
822 {
823         /* Notify any module monitors that the use count for a 
824            resource has changed */
825         struct loadupdate *m;
826
827         AST_LIST_LOCK(&module_list);
828         AST_LIST_TRAVERSE(&updaters, m, entry)
829                 m->updater();
830         AST_LIST_UNLOCK(&module_list);
831 }
832
833 int ast_update_module_list(int (*modentry)(const char *module, const char *description, int usecnt, const char *like),
834                            const char *like)
835 {
836         struct ast_module *cur;
837         int unlock = -1;
838         int total_mod_loaded = 0;
839
840         if (AST_LIST_TRYLOCK(&module_list))
841                 unlock = 0;
842
843         AST_LIST_TRAVERSE(&module_list, cur, entry) {
844                 total_mod_loaded += modentry(cur->resource, cur->info->description, cur->usecount, like);
845         }
846
847         if (unlock)
848                 AST_LIST_UNLOCK(&module_list);
849
850         return total_mod_loaded;
851 }
852
853 int ast_loader_register(int (*v)(void)) 
854 {
855         struct loadupdate *tmp; 
856
857         if (!(tmp = ast_malloc(sizeof(*tmp))))
858                 return -1;
859
860         tmp->updater = v;
861         AST_LIST_LOCK(&module_list);
862         AST_LIST_INSERT_HEAD(&updaters, tmp, entry);
863         AST_LIST_UNLOCK(&module_list);
864
865         return 0;
866 }
867
868 int ast_loader_unregister(int (*v)(void))
869 {
870         struct loadupdate *cur;
871
872         AST_LIST_LOCK(&module_list);
873         AST_LIST_TRAVERSE_SAFE_BEGIN(&updaters, cur, entry) {
874                 if (cur->updater == v)  {
875                         AST_LIST_REMOVE_CURRENT(&updaters, entry);
876                         break;
877                 }
878         }
879         AST_LIST_TRAVERSE_SAFE_END;
880         AST_LIST_UNLOCK(&module_list);
881
882         return cur ? 0 : -1;
883 }
884
885 struct ast_module *ast_module_ref(struct ast_module *mod)
886 {
887         ast_atomic_fetchadd_int(&mod->usecount, +1);
888         ast_update_use_count();
889
890         return mod;
891 }
892
893 void ast_module_unref(struct ast_module *mod)
894 {
895         ast_atomic_fetchadd_int(&mod->usecount, -1);
896         ast_update_use_count();
897 }