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