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