merge new_loader_completion branch, including (at least):
[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 dirent *dirent;
664         DIR *dir;
665         struct ast_module *mod;
666         struct load_order_entry *order;
667         struct ast_variable *v;
668         unsigned int load_count;
669         struct load_order load_order;
670         int res = 0;
671
672         /* all embedded modules have registered themselves by now */
673         embedding = 0;
674
675         if (option_verbose)
676                 ast_verbose("Asterisk Dynamic Loader Starting:\n");
677
678         AST_LIST_TRAVERSE(&module_list, mod, entry) {
679                 if (option_debug > 1)
680                         ast_log(LOG_DEBUG, "Embedded module found: %s\n", mod->resource);
681         }
682
683         if (!(cfg = ast_config_load(AST_MODULE_CONFIG))) {
684                 ast_log(LOG_WARNING, "No '%s' found, no modules will be loaded.\n", AST_MODULE_CONFIG);
685                 return 0;
686         }
687
688         AST_LIST_HEAD_INIT_NOLOCK(&load_order);
689
690         /* first, find all the modules we have been explicitly requested to load */
691         for (v = ast_variable_browse(cfg, "modules"); v; v = v->next) {
692                 if (!strcasecmp(v->name, "load"))
693                         add_to_load_order(v->value, &load_order);
694         }
695
696         /* check if 'autoload' is on */
697         if (ast_true(ast_variable_retrieve(cfg, "modules", "autoload"))) {
698                 /* if so, first add all the embedded modules to the load order */
699                 AST_LIST_TRAVERSE(&module_list, mod, entry) {
700                         order = add_to_load_order(mod->resource, &load_order);
701
702                         if (order)
703                                 order->embedded = 1;
704                 }
705
706                 /* if we are allowed to load dynamic modules, scan the directory for
707                    for all available modules and add them as well */
708 #if LOADABLE_MODULES
709                 if ((dir  = opendir(ast_config_AST_MODULE_DIR))) {
710                         while ((dirent = readdir(dir))) {
711                                 int ld = strlen(dirent->d_name);
712                                 
713                                 /* Must end in .so to load it.  */
714
715                                 if (ld < 4)
716                                         continue;
717
718                                 if (strcasecmp(dirent->d_name + ld - 3, ".so"))
719                                     continue;
720
721                                 add_to_load_order(dirent->d_name, &load_order);
722
723                         }
724
725                         closedir(dir);
726                 } else {
727                         if (!ast_opt_quiet)
728                                 ast_log(LOG_WARNING, "Unable to open modules directory '%s'.\n",
729                                         ast_config_AST_MODULE_DIR);
730                 }
731 #endif
732         }
733
734         /* now scan the config for any modules we are prohibited from loading and
735            remove them from the load order */
736         for (v = ast_variable_browse(cfg, "modules"); v; v = v->next) {
737                 if (strcasecmp(v->name, "noload"))
738                         continue;
739
740                 AST_LIST_TRAVERSE_SAFE_BEGIN(&load_order, order, entry) {
741                         if (!resource_name_match(order->resource, v->value)) {
742                                 AST_LIST_REMOVE_CURRENT(&load_order, entry);
743                                 free(order->resource);
744                                 free(order);
745                         }
746                 }
747                 AST_LIST_TRAVERSE_SAFE_END;
748         }
749
750         /* we are done with the config now, all the information we need is in the
751            load_order list */
752         ast_config_destroy(cfg);
753
754         load_count = 0;
755         AST_LIST_TRAVERSE(&load_order, order, entry)
756                 load_count++;
757
758         ast_log(LOG_NOTICE, "%d modules will be loaded.\n", load_count);
759
760         /* first, load only modules that provide global symbols */
761         AST_LIST_TRAVERSE_SAFE_BEGIN(&load_order, order, entry) {
762                 switch (load_resource(order->resource, 1)) {
763                 case AST_MODULE_LOAD_SUCCESS:
764                 case AST_MODULE_LOAD_DECLINE:
765                         AST_LIST_REMOVE_CURRENT(&load_order, entry);
766                         free(order->resource);
767                         free(order);
768                         break;
769                 case AST_MODULE_LOAD_FAILURE:
770                         res = -1;
771                         goto done;
772                 case AST_MODULE_LOAD_SKIP:
773                         /* try again later */
774                         break;
775                 }
776         }
777         AST_LIST_TRAVERSE_SAFE_END;
778
779         /* now load everything else */
780         AST_LIST_TRAVERSE_SAFE_BEGIN(&load_order, order, entry) {
781                 switch (load_resource(order->resource, 0)) {
782                 case AST_MODULE_LOAD_SUCCESS:
783                 case AST_MODULE_LOAD_DECLINE:
784                         AST_LIST_REMOVE_CURRENT(&load_order, entry);
785                         free(order->resource);
786                         free(order);
787                         break;
788                 case AST_MODULE_LOAD_FAILURE:
789                         res = -1;
790                         goto done;
791                 case AST_MODULE_LOAD_SKIP:
792                         /* should not happen */
793                         break;
794                 }
795         }
796         AST_LIST_TRAVERSE_SAFE_END;
797
798 done:
799         while ((order = AST_LIST_REMOVE_HEAD(&load_order, entry))) {
800                 free(order->resource);
801                 free(order);
802         }
803
804         return res;
805 }
806
807 void ast_update_use_count(void)
808 {
809         /* Notify any module monitors that the use count for a 
810            resource has changed */
811         struct loadupdate *m;
812
813         AST_LIST_LOCK(&module_list);
814         AST_LIST_TRAVERSE(&updaters, m, entry)
815                 m->updater();
816         AST_LIST_UNLOCK(&module_list);
817 }
818
819 int ast_update_module_list(int (*modentry)(const char *module, const char *description, int usecnt, const char *like),
820                            const char *like)
821 {
822         struct ast_module *cur;
823         int unlock = -1;
824         int total_mod_loaded = 0;
825
826         if (AST_LIST_TRYLOCK(&module_list))
827                 unlock = 0;
828
829         AST_LIST_TRAVERSE(&module_list, cur, entry) {
830                 total_mod_loaded += modentry(cur->resource, cur->info->description, cur->usecount, like);
831         }
832
833         if (unlock)
834                 AST_LIST_UNLOCK(&module_list);
835
836         return total_mod_loaded;
837 }
838
839 int ast_loader_register(int (*v)(void)) 
840 {
841         struct loadupdate *tmp; 
842
843         if (!(tmp = ast_malloc(sizeof(*tmp))))
844                 return -1;
845
846         tmp->updater = v;
847         AST_LIST_LOCK(&module_list);
848         AST_LIST_INSERT_HEAD(&updaters, tmp, entry);
849         AST_LIST_UNLOCK(&module_list);
850
851         return 0;
852 }
853
854 int ast_loader_unregister(int (*v)(void))
855 {
856         struct loadupdate *cur;
857
858         AST_LIST_LOCK(&module_list);
859         AST_LIST_TRAVERSE_SAFE_BEGIN(&updaters, cur, entry) {
860                 if (cur->updater == v)  {
861                         AST_LIST_REMOVE_CURRENT(&updaters, entry);
862                         break;
863                 }
864         }
865         AST_LIST_TRAVERSE_SAFE_END;
866         AST_LIST_UNLOCK(&module_list);
867
868         return cur ? 0 : -1;
869 }
870
871 struct ast_module *ast_module_ref(struct ast_module *mod)
872 {
873         ast_atomic_fetchadd_int(&mod->usecount, +1);
874         ast_update_use_count();
875
876         return mod;
877 }
878
879 void ast_module_unref(struct ast_module *mod)
880 {
881         ast_atomic_fetchadd_int(&mod->usecount, -1);
882         ast_update_use_count();
883 }