Conversions to ast_debug()
[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 struct ast_module {
84         const struct ast_module_info *info;
85         void *lib;                                      /* the shared lib, or NULL if embedded */
86         int usecount;                                   /* the number of 'users' currently in this module */
87         struct module_user_list users;                  /* the list of users in the module */
88         struct {
89                 unsigned int running:1;
90                 unsigned int declined:1;
91         } flags;
92         AST_LIST_ENTRY(ast_module) entry;
93         char resource[0];
94 };
95
96 static AST_LIST_HEAD_STATIC(module_list, ast_module);
97
98 struct loadupdate {
99         int (*updater)(void);
100         AST_LIST_ENTRY(loadupdate) entry;
101 };
102
103 static AST_LIST_HEAD_STATIC(updaters, loadupdate);
104
105 AST_MUTEX_DEFINE_STATIC(reloadlock);
106
107 /* when dynamic modules are being loaded, ast_module_register() will
108    need to know what filename the module was loaded from while it
109    is being registered
110 */
111 struct ast_module *resource_being_loaded;
112
113 /* XXX: should we check for duplicate resource names here? */
114
115 void ast_module_register(const struct ast_module_info *info)
116 {
117         struct ast_module *mod;
118
119         if (embedding) {
120                 if (!(mod = ast_calloc(1, sizeof(*mod) + strlen(info->name) + 1)))
121                         return;
122                 strcpy(mod->resource, info->name);
123         } else {
124                 mod = resource_being_loaded;
125         }
126
127         mod->info = info;
128         AST_LIST_HEAD_INIT(&mod->users);
129
130         /* during startup, before the loader has been initialized,
131            there are no threads, so there is no need to take the lock
132            on this list to manipulate it. it is also possible that it
133            might be unsafe to use the list lock at that point... so
134            let's avoid it altogether
135         */
136         if (!embedding)
137                 AST_LIST_LOCK(&module_list);
138
139         /* it is paramount that the new entry be placed at the tail of
140            the list, otherwise the code that uses dlopen() to load
141            dynamic modules won't be able to find out if the module it
142            just opened was registered or failed to load
143         */
144         AST_LIST_INSERT_TAIL(&module_list, mod, entry);
145
146         if (!embedding)
147                 AST_LIST_UNLOCK(&module_list);
148
149         /* give the module a copy of its own handle, for later use in registrations and the like */
150         *((struct ast_module **) &(info->self)) = mod;
151 }
152
153 void ast_module_unregister(const struct ast_module_info *info)
154 {
155         struct ast_module *mod = NULL;
156
157         /* it is assumed that the users list in the module structure
158            will already be empty, or we cannot have gotten to this
159            point
160         */
161         AST_LIST_LOCK(&module_list);
162         AST_LIST_TRAVERSE_SAFE_BEGIN(&module_list, mod, entry) {
163                 if (mod->info == info) {
164                         AST_LIST_REMOVE_CURRENT(&module_list, entry);
165                         break;
166                 }
167         }
168         AST_LIST_TRAVERSE_SAFE_END;
169         AST_LIST_UNLOCK(&module_list);
170
171         if (mod) {
172                 AST_LIST_HEAD_DESTROY(&mod->users);
173                 ast_free(mod);
174         }
175 }
176
177 struct ast_module_user *__ast_module_user_add(struct ast_module *mod,
178                                               struct ast_channel *chan)
179 {
180         struct ast_module_user *u = ast_calloc(1, sizeof(*u));
181
182         if (!u)
183                 return NULL;
184
185         u->chan = chan;
186
187         AST_LIST_LOCK(&mod->users);
188         AST_LIST_INSERT_HEAD(&mod->users, u, entry);
189         AST_LIST_UNLOCK(&mod->users);
190
191         ast_atomic_fetchadd_int(&mod->usecount, +1);
192
193         ast_update_use_count();
194
195         return u;
196 }
197
198 void __ast_module_user_remove(struct ast_module *mod, struct ast_module_user *u)
199 {
200         AST_LIST_LOCK(&mod->users);
201         AST_LIST_REMOVE(&mod->users, u, entry);
202         AST_LIST_UNLOCK(&mod->users);
203         ast_atomic_fetchadd_int(&mod->usecount, -1);
204         ast_free(u);
205
206         ast_update_use_count();
207 }
208
209 void __ast_module_user_hangup_all(struct ast_module *mod)
210 {
211         struct ast_module_user *u;
212
213         AST_LIST_LOCK(&mod->users);
214         while ((u = AST_LIST_REMOVE_HEAD(&mod->users, entry))) {
215                 ast_softhangup(u->chan, AST_SOFTHANGUP_APPUNLOAD);
216                 ast_atomic_fetchadd_int(&mod->usecount, -1);
217                 ast_free(u);
218         }
219         AST_LIST_UNLOCK(&mod->users);
220
221         ast_update_use_count();
222 }
223
224 /*! \note
225  * In addition to modules, the reload command handles some extra keywords
226  * which are listed here together with the corresponding handlers.
227  * This table is also used by the command completion code.
228  */
229 static struct reload_classes {
230         const char *name;
231         int (*reload_fn)(void);
232 } reload_classes[] = {  /* list in alpha order, longest match first for cli completion */
233         { "cdr",        ast_cdr_engine_reload },
234         { "dnsmgr",     dnsmgr_reload },
235         { "extconfig",  read_config_maps },
236         { "enum",       ast_enum_reload },
237         { "manager",    reload_manager },
238         { "rtp",        ast_rtp_reload },
239         { "http",       ast_http_reload },
240         { NULL,         NULL }
241 };
242
243 static int printdigest(const unsigned char *d)
244 {
245         int x, pos;
246         char buf[256]; /* large enough so we don't have to worry */
247
248         for (pos = 0, x = 0; x < 16; x++)
249                 pos += sprintf(buf + pos, " %02x", *d++);
250
251         ast_debug(1, "Unexpected signature:%s\n", buf);
252
253         return 0;
254 }
255
256 static int key_matches(const unsigned char *key1, const unsigned char *key2)
257 {
258         int x;
259
260         for (x = 0; x < 16; x++) {
261                 if (key1[x] != key2[x])
262                         return 0;
263         }
264
265         return 1;
266 }
267
268 static int verify_key(const unsigned char *key)
269 {
270         struct MD5Context c;
271         unsigned char digest[16];
272
273         MD5Init(&c);
274         MD5Update(&c, key, strlen((char *)key));
275         MD5Final(digest, &c);
276
277         if (key_matches(expected_key, digest))
278                 return 0;
279
280         printdigest(digest);
281
282         return -1;
283 }
284
285 static int resource_name_match(const char *name1_in, const char *name2_in)
286 {
287         char *name1 = (char *) name1_in;
288         char *name2 = (char *) name2_in;
289
290         /* trim off any .so extensions */
291         if (!strcasecmp(name1 + strlen(name1) - 3, ".so")) {
292                 name1 = ast_strdupa(name1);
293                 name1[strlen(name1) - 3] = '\0';
294         }
295         if (!strcasecmp(name2 + strlen(name2) - 3, ".so")) {
296                 name2 = ast_strdupa(name2);
297                 name2[strlen(name2) - 3] = '\0';
298         }
299
300         return strcasecmp(name1, name2);
301 }
302
303 static struct ast_module *find_resource(const char *resource, int do_lock)
304 {
305         struct ast_module *cur;
306
307         if (do_lock)
308                 AST_LIST_LOCK(&module_list);
309
310         AST_LIST_TRAVERSE(&module_list, cur, entry) {
311                 if (!resource_name_match(resource, cur->resource))
312                         break;
313         }
314
315         if (do_lock)
316                 AST_LIST_UNLOCK(&module_list);
317
318         return cur;
319 }
320
321 #if LOADABLE_MODULES
322 static void unload_dynamic_module(struct ast_module *mod)
323 {
324         void *lib = mod->lib;
325
326         /* WARNING: the structure pointed to by mod is going to
327            disappear when this operation succeeds, so we can't
328            dereference it */
329
330         if (lib)
331                 while (!dlclose(lib));
332 }
333
334 static struct ast_module *load_dynamic_module(const char *resource_in, unsigned int global_symbols_only)
335 {
336         char fn[256] = "";
337         void *lib = NULL;
338         struct ast_module *mod;
339         char *resource = (char *) resource_in;
340         unsigned int wants_global;
341
342         if (strcasecmp(resource + strlen(resource) - 3, ".so")) {
343                 resource = alloca(strlen(resource_in) + 3);
344                 strcpy(resource, resource_in);
345                 strcat(resource, ".so");
346         }
347
348         snprintf(fn, sizeof(fn), "%s/%s", ast_config_AST_MODULE_DIR, resource);
349
350         /* make a first load of the module in 'quiet' mode... don't try to resolve
351            any symbols, and don't export any symbols. this will allow us to peek into
352            the module's info block (if available) to see what flags it has set */
353
354         if (!(resource_being_loaded = ast_calloc(1, sizeof(*resource_being_loaded) + strlen(resource) + 1)))
355                 return NULL;
356
357         strcpy(resource_being_loaded->resource, resource);
358
359         if (!(lib = dlopen(fn, RTLD_LAZY | RTLD_LOCAL))) {
360                 ast_log(LOG_WARNING, "Error loading module '%s': %s\n", resource_in, dlerror());
361                 ast_free(resource_being_loaded);
362                 return NULL;
363         }
364
365         /* the dlopen() succeeded, let's find out if the module
366            registered itself */
367         /* note that this will only work properly as long as
368            ast_module_register() (which is called by the module's
369            constructor) places the new module at the tail of the
370            module_list
371         */
372         if (resource_being_loaded != (mod = AST_LIST_LAST(&module_list))) {
373                 ast_log(LOG_WARNING, "Module '%s' did not register itself during load\n", resource_in);
374                 /* no, it did not, so close it and return */
375                 while (!dlclose(lib));
376                 /* note that the module's destructor will call ast_module_unregister(),
377                    which will free the structure we allocated in resource_being_loaded */
378                 return NULL;
379         }
380
381         wants_global = ast_test_flag(mod->info, AST_MODFLAG_GLOBAL_SYMBOLS);
382
383         /* if we are being asked only to load modules that provide global symbols,
384            and this one does not, then close it and return */
385         if (global_symbols_only && !wants_global) {
386                 while (!dlclose(lib));
387                 return NULL;
388         }
389
390         /* if the system supports RTLD_NOLOAD, we can just 'promote' the flags
391            on the already-opened library to what we want... if not, we have to
392            close it and start over
393         */
394 #if defined(HAVE_RTLD_NOLOAD) && !defined(__Darwin__)
395         if (!dlopen(fn, RTLD_NOLOAD | (wants_global ? RTLD_LAZY | RTLD_GLOBAL : RTLD_NOW | RTLD_LOCAL))) {
396                 ast_log(LOG_WARNING, "Unable to promote flags on module '%s': %s\n", resource_in, dlerror());
397                 while (!dlclose(lib));
398                 ast_free(resource_being_loaded);
399                 return NULL;
400         }
401 #else
402         while (!dlclose(lib));
403         resource_being_loaded = NULL;
404
405         /* start the load process again */
406
407         if (!(resource_being_loaded = ast_calloc(1, sizeof(*resource_being_loaded) + strlen(resource) + 1)))
408                 return NULL;
409
410         strcpy(resource_being_loaded->resource, resource);
411
412         if (!(lib = dlopen(fn, wants_global ? RTLD_LAZY | RTLD_GLOBAL : RTLD_NOW | RTLD_LOCAL))) {
413                 ast_log(LOG_WARNING, "Error loading module '%s': %s\n", resource_in, dlerror());
414                 ast_free(resource_being_loaded);
415                 return NULL;
416         }
417
418         /* since the module was successfully opened, and it registered itself
419            the previous time we did that, we're going to assume it worked this
420            time too :) */
421 #endif
422
423         AST_LIST_LAST(&module_list)->lib = lib;
424         resource_being_loaded = NULL;
425
426         return AST_LIST_LAST(&module_list);
427 }
428 #endif
429
430 void ast_module_shutdown(void)
431 {
432         struct ast_module *mod;
433         AST_LIST_HEAD_NOLOCK_STATIC(local_module_list, ast_module);
434
435         /* We have to call the unload() callbacks in reverse order that the modules
436          * exist in the module list so it is the reverse order of how they were
437          * loaded. */
438
439         AST_LIST_LOCK(&module_list);
440         while ((mod = AST_LIST_REMOVE_HEAD(&module_list, entry)))
441                 AST_LIST_INSERT_HEAD(&local_module_list, mod, entry);
442         AST_LIST_UNLOCK(&module_list);
443
444         while ((mod = AST_LIST_REMOVE_HEAD(&local_module_list, entry))) {
445                 if (mod->info->unload)
446                         mod->info->unload();
447                 /* Since this should only be called when shutting down "gracefully",
448                  * all channels should be down before we get to this point, meaning
449                  * there will be no module users left. */
450                 AST_LIST_HEAD_DESTROY(&mod->users);
451                 free(mod);
452         }
453 }
454
455 int ast_unload_resource(const char *resource_name, enum ast_module_unload_mode force)
456 {
457         struct ast_module *mod;
458         int res = -1;
459         int error = 0;
460
461         AST_LIST_LOCK(&module_list);
462
463         if (!(mod = find_resource(resource_name, 0))) {
464                 AST_LIST_UNLOCK(&module_list);
465                 return 0;
466         }
467
468         if (!(mod->flags.running || mod->flags.declined))
469                 error = 1;
470
471         if (!error && (mod->usecount > 0)) {
472                 if (force)
473                         ast_log(LOG_WARNING, "Warning:  Forcing removal of module '%s' with use count %d\n",
474                                 resource_name, mod->usecount);
475                 else {
476                         ast_log(LOG_WARNING, "Soft unload failed, '%s' has use count %d\n", resource_name,
477                                 mod->usecount);
478                         error = 1;
479                 }
480         }
481
482         if (!error) {
483                 __ast_module_user_hangup_all(mod);
484                 res = mod->info->unload();
485
486                 if (res) {
487                         ast_log(LOG_WARNING, "Firm unload failed for %s\n", resource_name);
488                         if (force <= AST_FORCE_FIRM)
489                                 error = 1;
490                         else
491                                 ast_log(LOG_WARNING, "** Dangerous **: Unloading resource anyway, at user request\n");
492                 }
493         }
494
495         if (!error)
496                 mod->flags.running = mod->flags.declined = 0;
497
498         AST_LIST_UNLOCK(&module_list);
499
500         if (!error && !mod->lib)
501                 mod->info->restore_globals();
502
503 #if LOADABLE_MODULES
504         if (!error)
505                 unload_dynamic_module(mod);
506 #endif
507
508         if (!error)
509                 ast_update_use_count();
510
511         return res;
512 }
513
514 char *ast_module_helper(const char *line, const char *word, int pos, int state, int rpos, int needsreload)
515 {
516         struct ast_module *cur;
517         int i, which=0, l = strlen(word);
518         char *ret = NULL;
519
520         if (pos != rpos)
521                 return NULL;
522
523         AST_LIST_LOCK(&module_list);
524         AST_LIST_TRAVERSE(&module_list, cur, entry) {
525                 if (!strncasecmp(word, cur->resource, l) &&
526                     (cur->info->reload || !needsreload) &&
527                     ++which > state) {
528                         ret = ast_strdup(cur->resource);
529                         break;
530                 }
531         }
532         AST_LIST_UNLOCK(&module_list);
533
534         if (!ret) {
535                 for (i=0; !ret && reload_classes[i].name; i++) {
536                         if (!strncasecmp(word, reload_classes[i].name, l) && ++which > state)
537                                 ret = ast_strdup(reload_classes[i].name);
538                 }
539         }
540
541         return ret;
542 }
543
544 int ast_module_reload(const char *name)
545 {
546         struct ast_module *cur;
547         int res = 0; /* return value. 0 = not found, others, see below */
548         int i;
549
550         if (ast_mutex_trylock(&reloadlock)) {
551                 ast_verbose("The previous reload command didn't finish yet\n");
552                 return -1;      /* reload already in progress */
553         }
554         ast_lastreloadtime = time(NULL);
555
556         /* Call "predefined" reload here first */
557         for (i = 0; reload_classes[i].name; i++) {
558                 if (!name || !strcasecmp(name, reload_classes[i].name)) {
559                         reload_classes[i].reload_fn();  /* XXX should check error ? */
560                         res = 2;        /* found and reloaded */
561                 }
562         }
563
564         if (name && res) {
565                 ast_mutex_unlock(&reloadlock);
566                 return res;
567         }
568
569         AST_LIST_LOCK(&module_list);
570         AST_LIST_TRAVERSE(&module_list, cur, entry) {
571                 const struct ast_module_info *info = cur->info;
572
573                 if (name && resource_name_match(name, cur->resource))
574                         continue;
575
576                 if (!(cur->flags.running || cur->flags.declined))
577                         continue;
578
579                 if (!info->reload) {    /* cannot be reloaded */
580                         if (res < 1)    /* store result if possible */
581                                 res = 1;        /* 1 = no reload() method */
582                         continue;
583                 }
584
585                 res = 2;
586                 if (option_verbose > 2)
587                         ast_verbose(VERBOSE_PREFIX_3 "Reloading module '%s' (%s)\n", cur->resource, info->description);
588                 info->reload();
589         }
590         AST_LIST_UNLOCK(&module_list);
591
592         ast_mutex_unlock(&reloadlock);
593
594         return res;
595 }
596
597 static unsigned int inspect_module(const struct ast_module *mod)
598 {
599         if (!mod->info->description) {
600                 ast_log(LOG_WARNING, "Module '%s' does not provide a description.\n", mod->resource);
601                 return 1;
602         }
603
604         if (!mod->info->key) {
605                 ast_log(LOG_WARNING, "Module '%s' does not provide a license key.\n", mod->resource);
606                 return 1;
607         }
608
609         if (verify_key((unsigned char *) mod->info->key)) {
610                 ast_log(LOG_WARNING, "Module '%s' did not provide a valid license key.\n", mod->resource);
611                 return 1;
612         }
613
614         return 0;
615 }
616
617 static enum ast_module_load_result load_resource(const char *resource_name, unsigned int global_symbols_only)
618 {
619         struct ast_module *mod;
620         enum ast_module_load_result res = AST_MODULE_LOAD_SUCCESS;
621         char tmp[256];
622
623         if ((mod = find_resource(resource_name, 0))) {
624                 if (mod->flags.running) {
625                         ast_log(LOG_WARNING, "Module '%s' already exists.\n", resource_name);
626                         return AST_MODULE_LOAD_DECLINE;
627                 }
628                 if (global_symbols_only && !ast_test_flag(mod->info, AST_MODFLAG_GLOBAL_SYMBOLS))
629                         return AST_MODULE_LOAD_SKIP;
630         } else {
631 #if LOADABLE_MODULES
632                 if (!(mod = load_dynamic_module(resource_name, global_symbols_only))) {
633                         /* don't generate a warning message during load_modules() */
634                         if (!global_symbols_only) {
635                                 ast_log(LOG_WARNING, "Module '%s' could not be loaded.\n", resource_name);
636                                 return AST_MODULE_LOAD_DECLINE;
637                         } else {
638                                 return AST_MODULE_LOAD_SKIP;
639                         }
640                 }
641 #else
642                 ast_log(LOG_WARNING, "Module '%s' could not be loaded.\n", resource_name);
643                 return AST_MODULE_LOAD_DECLINE;
644 #endif
645         }
646
647         if (inspect_module(mod)) {
648                 ast_log(LOG_WARNING, "Module '%s' could not be loaded.\n", resource_name);
649 #if LOADABLE_MODULES
650                 unload_dynamic_module(mod);
651 #endif
652                 return AST_MODULE_LOAD_DECLINE;
653         }
654
655         if (!mod->lib && mod->info->backup_globals()) {
656                 ast_log(LOG_WARNING, "Module '%s' was unable to backup its global data.\n", resource_name);
657                 return AST_MODULE_LOAD_DECLINE;
658         }
659
660         mod->flags.declined = 0;
661
662         if (mod->info->load)
663                 res = mod->info->load();
664
665         switch (res) {
666         case AST_MODULE_LOAD_SUCCESS:
667                 if (!ast_fully_booted) {
668                         if (option_verbose)
669                                 ast_verbose("%s => (%s)\n", resource_name, term_color(tmp, mod->info->description, COLOR_BROWN, COLOR_BLACK, sizeof(tmp)));
670                         if (ast_opt_console && !option_verbose)
671                                 ast_verbose( ".");
672                 } else {
673                         if (option_verbose)
674                                 ast_verbose(VERBOSE_PREFIX_1 "Loaded %s => (%s)\n", resource_name, mod->info->description);
675                 }
676
677                 mod->flags.running = 1;
678
679                 ast_update_use_count();
680                 break;
681         case AST_MODULE_LOAD_DECLINE:
682                 mod->flags.declined = 1;
683                 break;
684         case AST_MODULE_LOAD_FAILURE:
685                 break;
686         case AST_MODULE_LOAD_SKIP:
687                 /* modules should never return this value */
688                 break;
689         }
690
691         return res;
692 }
693
694 int ast_load_resource(const char *resource_name)
695 {
696        AST_LIST_LOCK(&module_list);
697        load_resource(resource_name, 0);
698        AST_LIST_UNLOCK(&module_list);
699
700        return 0;
701 }
702
703 struct load_order_entry {
704         char *resource;
705         AST_LIST_ENTRY(load_order_entry) entry;
706 };
707
708 AST_LIST_HEAD_NOLOCK(load_order, load_order_entry);
709
710 static struct load_order_entry *add_to_load_order(const char *resource, struct load_order *load_order)
711 {
712         struct load_order_entry *order;
713
714         AST_LIST_TRAVERSE(load_order, order, entry) {
715                 if (!resource_name_match(order->resource, resource))
716                         return NULL;
717         }
718
719         if (!(order = ast_calloc(1, sizeof(*order))))
720                 return NULL;
721
722         order->resource = ast_strdup(resource);
723         AST_LIST_INSERT_TAIL(load_order, order, entry);
724
725         return order;
726 }
727
728 int load_modules(unsigned int preload_only)
729 {
730         struct ast_config *cfg;
731         struct ast_module *mod;
732         struct load_order_entry *order;
733         struct ast_variable *v;
734         unsigned int load_count;
735         struct load_order load_order;
736         int res = 0;
737 #if LOADABLE_MODULES
738         struct dirent *dirent;
739         DIR *dir;
740 #endif
741
742         /* all embedded modules have registered themselves by now */
743         embedding = 0;
744
745         if (option_verbose)
746                 ast_verbose("Asterisk Dynamic Loader Starting:\n");
747
748         AST_LIST_HEAD_INIT_NOLOCK(&load_order);
749
750         AST_LIST_LOCK(&module_list);
751
752         if (!(cfg = ast_config_load(AST_MODULE_CONFIG))) {
753                 ast_log(LOG_WARNING, "No '%s' found, no modules will be loaded.\n", AST_MODULE_CONFIG);
754                 goto done;
755         }
756
757         /* first, find all the modules we have been explicitly requested to load */
758         for (v = ast_variable_browse(cfg, "modules"); v; v = v->next) {
759                 if (!strcasecmp(v->name, preload_only ? "preload" : "load"))
760                         add_to_load_order(v->value, &load_order);
761         }
762
763         /* check if 'autoload' is on */
764         if (!preload_only && ast_true(ast_variable_retrieve(cfg, "modules", "autoload"))) {
765                 /* if so, first add all the embedded modules that are not already running to the load order */
766                 AST_LIST_TRAVERSE(&module_list, mod, entry) {
767                         /* if it's not embedded, skip it */
768                         if (mod->lib)
769                                 continue;
770
771                         if (mod->flags.running)
772                                 continue;
773
774                         order = add_to_load_order(mod->resource, &load_order);
775                 }
776
777 #if LOADABLE_MODULES
778                 /* if we are allowed to load dynamic modules, scan the directory for
779                    for all available modules and add them as well */
780                 if ((dir  = opendir(ast_config_AST_MODULE_DIR))) {
781                         while ((dirent = readdir(dir))) {
782                                 int ld = strlen(dirent->d_name);
783
784                                 /* Must end in .so to load it.  */
785
786                                 if (ld < 4)
787                                         continue;
788
789                                 if (strcasecmp(dirent->d_name + ld - 3, ".so"))
790                                         continue;
791
792                                 /* if there is already a module by this name in the module_list,
793                                    skip this file */
794                                 if (find_resource(dirent->d_name, 0))
795                                         continue;
796
797                                 add_to_load_order(dirent->d_name, &load_order);
798                         }
799
800                         closedir(dir);
801                 } else {
802                         if (!ast_opt_quiet)
803                                 ast_log(LOG_WARNING, "Unable to open modules directory '%s'.\n",
804                                         ast_config_AST_MODULE_DIR);
805                 }
806 #endif
807         }
808
809         /* now scan the config for any modules we are prohibited from loading and
810            remove them from the load order */
811         for (v = ast_variable_browse(cfg, "modules"); v; v = v->next) {
812                 if (strcasecmp(v->name, "noload"))
813                         continue;
814
815                 AST_LIST_TRAVERSE_SAFE_BEGIN(&load_order, order, entry) {
816                         if (!resource_name_match(order->resource, v->value)) {
817                                 AST_LIST_REMOVE_CURRENT(&load_order, entry);
818                                 ast_free(order->resource);
819                                 ast_free(order);
820                         }
821                 }
822                 AST_LIST_TRAVERSE_SAFE_END;
823         }
824
825         /* we are done with the config now, all the information we need is in the
826            load_order list */
827         ast_config_destroy(cfg);
828
829         load_count = 0;
830         AST_LIST_TRAVERSE(&load_order, order, entry)
831                 load_count++;
832
833         if (load_count)
834                 ast_log(LOG_NOTICE, "%d modules will be loaded.\n", load_count);
835
836         /* first, load only modules that provide global symbols */
837         AST_LIST_TRAVERSE_SAFE_BEGIN(&load_order, order, entry) {
838                 switch (load_resource(order->resource, 1)) {
839                 case AST_MODULE_LOAD_SUCCESS:
840                 case AST_MODULE_LOAD_DECLINE:
841                         AST_LIST_REMOVE_CURRENT(&load_order, entry);
842                         ast_free(order->resource);
843                         ast_free(order);
844                         break;
845                 case AST_MODULE_LOAD_FAILURE:
846                         res = -1;
847                         goto done;
848                 case AST_MODULE_LOAD_SKIP:
849                         /* try again later */
850                         break;
851                 }
852         }
853         AST_LIST_TRAVERSE_SAFE_END;
854
855         /* now load everything else */
856         AST_LIST_TRAVERSE_SAFE_BEGIN(&load_order, order, entry) {
857                 switch (load_resource(order->resource, 0)) {
858                 case AST_MODULE_LOAD_SUCCESS:
859                 case AST_MODULE_LOAD_DECLINE:
860                         AST_LIST_REMOVE_CURRENT(&load_order, entry);
861                         ast_free(order->resource);
862                         ast_free(order);
863                         break;
864                 case AST_MODULE_LOAD_FAILURE:
865                         res = -1;
866                         goto done;
867                 case AST_MODULE_LOAD_SKIP:
868                         /* should not happen */
869                         break;
870                 }
871         }
872         AST_LIST_TRAVERSE_SAFE_END;
873
874 done:
875         while ((order = AST_LIST_REMOVE_HEAD(&load_order, entry))) {
876                 ast_free(order->resource);
877                 ast_free(order);
878         }
879
880         AST_LIST_UNLOCK(&module_list);
881
882         return res;
883 }
884
885 void ast_update_use_count(void)
886 {
887         /* Notify any module monitors that the use count for a
888            resource has changed */
889         struct loadupdate *m;
890
891         AST_LIST_LOCK(&module_list);
892         AST_LIST_TRAVERSE(&updaters, m, entry)
893                 m->updater();
894         AST_LIST_UNLOCK(&module_list);
895 }
896
897 int ast_update_module_list(int (*modentry)(const char *module, const char *description, int usecnt, const char *like),
898                            const char *like)
899 {
900         struct ast_module *cur;
901         int unlock = -1;
902         int total_mod_loaded = 0;
903
904         if (AST_LIST_TRYLOCK(&module_list))
905                 unlock = 0;
906
907         AST_LIST_TRAVERSE(&module_list, cur, entry) {
908                 total_mod_loaded += modentry(cur->resource, cur->info->description, cur->usecount, like);
909         }
910
911         if (unlock)
912                 AST_LIST_UNLOCK(&module_list);
913
914         return total_mod_loaded;
915 }
916
917 /*! \brief Check if module exists */
918 int ast_module_check(const char *name)
919 {
920         struct ast_module *cur;
921
922         if (ast_strlen_zero(name))
923                 return 0;       /* FALSE */
924
925         cur = find_resource(name, 1);
926
927         return (cur != NULL);
928 }
929
930
931 int ast_loader_register(int (*v)(void))
932 {
933         struct loadupdate *tmp;
934
935         if (!(tmp = ast_malloc(sizeof(*tmp))))
936                 return -1;
937
938         tmp->updater = v;
939         AST_LIST_LOCK(&module_list);
940         AST_LIST_INSERT_HEAD(&updaters, tmp, entry);
941         AST_LIST_UNLOCK(&module_list);
942
943         return 0;
944 }
945
946 int ast_loader_unregister(int (*v)(void))
947 {
948         struct loadupdate *cur;
949
950         AST_LIST_LOCK(&module_list);
951         AST_LIST_TRAVERSE_SAFE_BEGIN(&updaters, cur, entry) {
952                 if (cur->updater == v)  {
953                         AST_LIST_REMOVE_CURRENT(&updaters, entry);
954                         break;
955                 }
956         }
957         AST_LIST_TRAVERSE_SAFE_END;
958         AST_LIST_UNLOCK(&module_list);
959
960         return cur ? 0 : -1;
961 }
962
963 struct ast_module *ast_module_ref(struct ast_module *mod)
964 {
965         ast_atomic_fetchadd_int(&mod->usecount, +1);
966         ast_update_use_count();
967
968         return mod;
969 }
970
971 void ast_module_unref(struct ast_module *mod)
972 {
973         ast_atomic_fetchadd_int(&mod->usecount, -1);
974         ast_update_use_count();
975 }