Merged revisions 86630 via svnmerge from
[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 #ifdefdef 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 #ifdefndef 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 #ifdef 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 #ifdef 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 #ifdef 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 = ast_tvnow();
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                 ast_verb(3, "Reloading module '%s' (%s)\n", cur->resource, info->description);
587                 info->reload();
588         }
589         AST_LIST_UNLOCK(&module_list);
590
591         ast_mutex_unlock(&reloadlock);
592
593         return res;
594 }
595
596 static unsigned int inspect_module(const struct ast_module *mod)
597 {
598         if (!mod->info->description) {
599                 ast_log(LOG_WARNING, "Module '%s' does not provide a description.\n", mod->resource);
600                 return 1;
601         }
602
603         if (!mod->info->key) {
604                 ast_log(LOG_WARNING, "Module '%s' does not provide a license key.\n", mod->resource);
605                 return 1;
606         }
607
608         if (verify_key((unsigned char *) mod->info->key)) {
609                 ast_log(LOG_WARNING, "Module '%s' did not provide a valid license key.\n", mod->resource);
610                 return 1;
611         }
612
613         return 0;
614 }
615
616 static enum ast_module_load_result load_resource(const char *resource_name, unsigned int global_symbols_only)
617 {
618         struct ast_module *mod;
619         enum ast_module_load_result res = AST_MODULE_LOAD_SUCCESS;
620         char tmp[256];
621
622         if ((mod = find_resource(resource_name, 0))) {
623                 if (mod->flags.running) {
624                         ast_log(LOG_WARNING, "Module '%s' already exists.\n", resource_name);
625                         return AST_MODULE_LOAD_DECLINE;
626                 }
627                 if (global_symbols_only && !ast_test_flag(mod->info, AST_MODFLAG_GLOBAL_SYMBOLS))
628                         return AST_MODULE_LOAD_SKIP;
629         } else {
630 #ifdef LOADABLE_MODULES
631                 if (!(mod = load_dynamic_module(resource_name, global_symbols_only))) {
632                         /* don't generate a warning message during load_modules() */
633                         if (!global_symbols_only) {
634                                 ast_log(LOG_WARNING, "Module '%s' could not be loaded.\n", resource_name);
635                                 return AST_MODULE_LOAD_DECLINE;
636                         } else {
637                                 return AST_MODULE_LOAD_SKIP;
638                         }
639                 }
640 #else
641                 ast_log(LOG_WARNING, "Module '%s' could not be loaded.\n", resource_name);
642                 return AST_MODULE_LOAD_DECLINE;
643 #endif
644         }
645
646         if (inspect_module(mod)) {
647                 ast_log(LOG_WARNING, "Module '%s' could not be loaded.\n", resource_name);
648 #ifdef LOADABLE_MODULES
649                 unload_dynamic_module(mod);
650 #endif
651                 return AST_MODULE_LOAD_DECLINE;
652         }
653
654         if (!mod->lib && mod->info->backup_globals()) {
655                 ast_log(LOG_WARNING, "Module '%s' was unable to backup its global data.\n", resource_name);
656                 return AST_MODULE_LOAD_DECLINE;
657         }
658
659         mod->flags.declined = 0;
660
661         if (mod->info->load)
662                 res = mod->info->load();
663
664         switch (res) {
665         case AST_MODULE_LOAD_SUCCESS:
666                 if (!ast_fully_booted) {
667                         ast_verb(1, "%s => (%s)\n", resource_name, term_color(tmp, mod->info->description, COLOR_BROWN, COLOR_BLACK, sizeof(tmp)));
668                         if (ast_opt_console && !option_verbose)
669                                 ast_verbose( ".");
670                 } else {
671                         ast_verb(1, "Loaded %s => (%s)\n", resource_name, mod->info->description);
672                 }
673
674                 mod->flags.running = 1;
675
676                 ast_update_use_count();
677                 break;
678         case AST_MODULE_LOAD_DECLINE:
679                 mod->flags.declined = 1;
680                 break;
681         case AST_MODULE_LOAD_FAILURE:
682                 break;
683         case AST_MODULE_LOAD_SKIP:
684                 /* modules should never return this value */
685                 break;
686         }
687
688         return res;
689 }
690
691 int ast_load_resource(const char *resource_name)
692 {
693        AST_LIST_LOCK(&module_list);
694        load_resource(resource_name, 0);
695        AST_LIST_UNLOCK(&module_list);
696
697        return 0;
698 }
699
700 struct load_order_entry {
701         char *resource;
702         AST_LIST_ENTRY(load_order_entry) entry;
703 };
704
705 AST_LIST_HEAD_NOLOCK(load_order, load_order_entry);
706
707 static struct load_order_entry *add_to_load_order(const char *resource, struct load_order *load_order)
708 {
709         struct load_order_entry *order;
710
711         AST_LIST_TRAVERSE(load_order, order, entry) {
712                 if (!resource_name_match(order->resource, resource))
713                         return NULL;
714         }
715
716         if (!(order = ast_calloc(1, sizeof(*order))))
717                 return NULL;
718
719         order->resource = ast_strdup(resource);
720         AST_LIST_INSERT_TAIL(load_order, order, entry);
721
722         return order;
723 }
724
725 int load_modules(unsigned int preload_only)
726 {
727         struct ast_config *cfg;
728         struct ast_module *mod;
729         struct load_order_entry *order;
730         struct ast_variable *v;
731         unsigned int load_count;
732         struct load_order load_order;
733         int res = 0;
734         struct ast_flags config_flags = { 0 };
735 #ifdef LOADABLE_MODULES
736         struct dirent *dirent;
737         DIR *dir;
738 #endif
739
740         /* all embedded modules have registered themselves by now */
741         embedding = 0;
742
743         ast_verb(1, "Asterisk Dynamic Loader Starting:\n");
744
745         AST_LIST_HEAD_INIT_NOLOCK(&load_order);
746
747         AST_LIST_LOCK(&module_list);
748
749         if (!(cfg = ast_config_load(AST_MODULE_CONFIG, config_flags))) {
750                 ast_log(LOG_WARNING, "No '%s' found, no modules will be loaded.\n", AST_MODULE_CONFIG);
751                 goto done;
752         }
753
754         /* first, find all the modules we have been explicitly requested to load */
755         for (v = ast_variable_browse(cfg, "modules"); v; v = v->next) {
756                 if (!strcasecmp(v->name, preload_only ? "preload" : "load"))
757                         add_to_load_order(v->value, &load_order);
758         }
759
760         /* check if 'autoload' is on */
761         if (!preload_only && ast_true(ast_variable_retrieve(cfg, "modules", "autoload"))) {
762                 /* if so, first add all the embedded modules that are not already running to the load order */
763                 AST_LIST_TRAVERSE(&module_list, mod, entry) {
764                         /* if it's not embedded, skip it */
765                         if (mod->lib)
766                                 continue;
767
768                         if (mod->flags.running)
769                                 continue;
770
771                         order = add_to_load_order(mod->resource, &load_order);
772                 }
773
774 #ifdef LOADABLE_MODULES
775                 /* if we are allowed to load dynamic modules, scan the directory for
776                    for all available modules and add them as well */
777                 if ((dir  = opendir(ast_config_AST_MODULE_DIR))) {
778                         while ((dirent = readdir(dir))) {
779                                 int ld = strlen(dirent->d_name);
780
781                                 /* Must end in .so to load it.  */
782
783                                 if (ld < 4)
784                                         continue;
785
786                                 if (strcasecmp(dirent->d_name + ld - 3, ".so"))
787                                         continue;
788
789                                 /* if there is already a module by this name in the module_list,
790                                    skip this file */
791                                 if (find_resource(dirent->d_name, 0))
792                                         continue;
793
794                                 add_to_load_order(dirent->d_name, &load_order);
795                         }
796
797                         closedir(dir);
798                 } else {
799                         if (!ast_opt_quiet)
800                                 ast_log(LOG_WARNING, "Unable to open modules directory '%s'.\n",
801                                         ast_config_AST_MODULE_DIR);
802                 }
803 #endif
804         }
805
806         /* now scan the config for any modules we are prohibited from loading and
807            remove them from the load order */
808         for (v = ast_variable_browse(cfg, "modules"); v; v = v->next) {
809                 if (strcasecmp(v->name, "noload"))
810                         continue;
811
812                 AST_LIST_TRAVERSE_SAFE_BEGIN(&load_order, order, entry) {
813                         if (!resource_name_match(order->resource, v->value)) {
814                                 AST_LIST_REMOVE_CURRENT(&load_order, entry);
815                                 ast_free(order->resource);
816                                 ast_free(order);
817                         }
818                 }
819                 AST_LIST_TRAVERSE_SAFE_END;
820         }
821
822         /* we are done with the config now, all the information we need is in the
823            load_order list */
824         ast_config_destroy(cfg);
825
826         load_count = 0;
827         AST_LIST_TRAVERSE(&load_order, order, entry)
828                 load_count++;
829
830         if (load_count)
831                 ast_log(LOG_NOTICE, "%d modules will be loaded.\n", load_count);
832
833         /* first, load only modules that provide global symbols */
834         AST_LIST_TRAVERSE_SAFE_BEGIN(&load_order, order, entry) {
835                 switch (load_resource(order->resource, 1)) {
836                 case AST_MODULE_LOAD_SUCCESS:
837                 case AST_MODULE_LOAD_DECLINE:
838                         AST_LIST_REMOVE_CURRENT(&load_order, entry);
839                         ast_free(order->resource);
840                         ast_free(order);
841                         break;
842                 case AST_MODULE_LOAD_FAILURE:
843                         res = -1;
844                         goto done;
845                 case AST_MODULE_LOAD_SKIP:
846                         /* try again later */
847                         break;
848                 }
849         }
850         AST_LIST_TRAVERSE_SAFE_END;
851
852         /* now load everything else */
853         AST_LIST_TRAVERSE_SAFE_BEGIN(&load_order, order, entry) {
854                 switch (load_resource(order->resource, 0)) {
855                 case AST_MODULE_LOAD_SUCCESS:
856                 case AST_MODULE_LOAD_DECLINE:
857                         AST_LIST_REMOVE_CURRENT(&load_order, entry);
858                         ast_free(order->resource);
859                         ast_free(order);
860                         break;
861                 case AST_MODULE_LOAD_FAILURE:
862                         res = -1;
863                         goto done;
864                 case AST_MODULE_LOAD_SKIP:
865                         /* should not happen */
866                         break;
867                 }
868         }
869         AST_LIST_TRAVERSE_SAFE_END;
870
871 done:
872         while ((order = AST_LIST_REMOVE_HEAD(&load_order, entry))) {
873                 ast_free(order->resource);
874                 ast_free(order);
875         }
876
877         AST_LIST_UNLOCK(&module_list);
878
879         return res;
880 }
881
882 void ast_update_use_count(void)
883 {
884         /* Notify any module monitors that the use count for a
885            resource has changed */
886         struct loadupdate *m;
887
888         AST_LIST_LOCK(&module_list);
889         AST_LIST_TRAVERSE(&updaters, m, entry)
890                 m->updater();
891         AST_LIST_UNLOCK(&module_list);
892 }
893
894 int ast_update_module_list(int (*modentry)(const char *module, const char *description, int usecnt, const char *like),
895                            const char *like)
896 {
897         struct ast_module *cur;
898         int unlock = -1;
899         int total_mod_loaded = 0;
900
901         if (AST_LIST_TRYLOCK(&module_list))
902                 unlock = 0;
903
904         AST_LIST_TRAVERSE(&module_list, cur, entry) {
905                 total_mod_loaded += modentry(cur->resource, cur->info->description, cur->usecount, like);
906         }
907
908         if (unlock)
909                 AST_LIST_UNLOCK(&module_list);
910
911         return total_mod_loaded;
912 }
913
914 /*! \brief Check if module exists */
915 int ast_module_check(const char *name)
916 {
917         struct ast_module *cur;
918
919         if (ast_strlen_zero(name))
920                 return 0;       /* FALSE */
921
922         cur = find_resource(name, 1);
923
924         return (cur != NULL);
925 }
926
927
928 int ast_loader_register(int (*v)(void))
929 {
930         struct loadupdate *tmp;
931
932         if (!(tmp = ast_malloc(sizeof(*tmp))))
933                 return -1;
934
935         tmp->updater = v;
936         AST_LIST_LOCK(&module_list);
937         AST_LIST_INSERT_HEAD(&updaters, tmp, entry);
938         AST_LIST_UNLOCK(&module_list);
939
940         return 0;
941 }
942
943 int ast_loader_unregister(int (*v)(void))
944 {
945         struct loadupdate *cur;
946
947         AST_LIST_LOCK(&module_list);
948         AST_LIST_TRAVERSE_SAFE_BEGIN(&updaters, cur, entry) {
949                 if (cur->updater == v)  {
950                         AST_LIST_REMOVE_CURRENT(&updaters, entry);
951                         break;
952                 }
953         }
954         AST_LIST_TRAVERSE_SAFE_END;
955         AST_LIST_UNLOCK(&module_list);
956
957         return cur ? 0 : -1;
958 }
959
960 struct ast_module *ast_module_ref(struct ast_module *mod)
961 {
962         ast_atomic_fetchadd_int(&mod->usecount, +1);
963         ast_update_use_count();
964
965         return mod;
966 }
967
968 void ast_module_unref(struct ast_module *mod)
969 {
970         ast_atomic_fetchadd_int(&mod->usecount, -1);
971         ast_update_use_count();
972 }