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