Bring in the new loader code as described in mantis #4377
[asterisk/asterisk.git] / loader.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2005, Digium, Inc.
5  *
6  * Mark Spencer <markster@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 /*! \file
20  *
21  * \brief Module Loader
22  *
23  * \author Mark Spencer <markster@digium.com> 
24  */
25
26 #include <stdio.h>
27 #include <dirent.h>
28 #include <unistd.h>
29 #include <stdlib.h>
30 #include <string.h>
31
32 #include "asterisk.h"
33
34 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
35
36 #include "asterisk/linkedlists.h"
37 #include "asterisk/module.h"
38 #include "asterisk/options.h"
39 #include "asterisk/config.h"
40 #include "asterisk/logger.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 #ifdef DLFCNCOMPAT
50 #include "asterisk/dlfcn-compat.h"
51 #else
52 #include <dlfcn.h>
53 #endif
54 #include "asterisk/md5.h"
55 #include "asterisk/utils.h"
56
57 #ifndef RTLD_NOW
58 #define RTLD_NOW 0
59 #endif
60
61 static int modlistver = 0; /* increase whenever the list changes, to protect reload */
62
63 static unsigned char expected_key[] =
64 { 0x8e, 0x93, 0x22, 0x83, 0xf5, 0xc3, 0xc0, 0x75,
65   0xff, 0x8b, 0xa9, 0xbe, 0x7c, 0x43, 0x74, 0x63 };
66
67 /*
68  * Modules can be in a number of different states, as below:
69  * MS_FAILED    attempt to load failed. This is final.
70  * MS_NEW       just added to the list, symbols unresolved.
71  * MS_RESOLVED  all symbols resolved, but supplier modules not active yet.
72  * MS_CANLOAD   all symbols resolved and suppliers are all active
73  *              (or we are in a cyclic dependency and we are breaking a loop)
74  * MS_ACTIVE    load() returned successfully.
75  */
76 enum st_t {  /* possible states of a module */
77         MS_FAILED = 0,              /* cannot load */
78         MS_NEW = 1,                 /* nothing known */
79         MS_RESOLVED = 2,            /* all required resolved */
80         MS_CANLOAD = 3,             /* as above, plus cyclic depend.*/
81         MS_ACTIVE = 4,              /* all done */
82 };
83
84 /*
85  * All module symbols are in module_symbols.
86  * Modules are then linked in a list of struct module,
87  * whereas updaters are in a list of struct loadupdate.
88  *
89  * Both lists (basically, the entire loader) are protected by
90  * the lock in module_list.
91  *
92  * A second lock, reloadlock, is used to prevent concurrent reloads
93  */
94 struct module {
95         AST_LIST_ENTRY(module) next;
96         struct module_symbols cb;
97         void *lib;              /* the shared lib */
98         char resource[256];
99
100         enum st_t state;
101         int export_refcount;    /* how many users of exported symbols */
102
103         ast_mutex_t mtx;        /* XXX use yet ? */
104         struct localuser *lu;
105         int localusecnt;
106 };
107
108
109 struct loadupdate {
110         AST_LIST_ENTRY(loadupdate) next;
111         int (*updater)(void);
112 };
113
114 static AST_LIST_HEAD_STATIC(module_list, module);
115 static AST_LIST_HEAD_STATIC(updaters, loadupdate);
116 AST_MUTEX_DEFINE_STATIC(reloadlock);
117
118 /*
119  * helper localuser routines.
120  * All of these routines are extremely expensive, so the use of
121  * macros is totally unnecessary from the point of view of performance:
122  * the extra function call will be totally negligible in all cases.
123  */
124
125 struct localuser *ast_localuser_add(struct ast_module_lock *m,
126         struct ast_channel *chan)
127 {
128         struct localuser *u = ast_calloc(1, sizeof(*u));
129         if (u == NULL)
130                 return NULL;
131         u->chan = chan;
132         ast_mutex_lock(&m->lock);
133         AST_LIST_INSERT_HEAD(&m->u, u, next);
134         m->usecnt++;
135         ast_mutex_unlock(&m->lock);
136         ast_update_use_count();
137         return u;
138 }
139
140 void ast_localuser_remove(struct ast_module_lock *m, struct localuser *u)
141 {
142         ast_mutex_lock(&m->lock);
143         AST_LIST_REMOVE(&m->u, u, next);
144         m->usecnt--;
145         free(u);
146         ast_mutex_unlock(&m->lock);
147         ast_update_use_count();
148 }
149
150 void ast_hangup_localusers(struct ast_module_lock *m)
151 {
152         struct localuser *u;
153         ast_mutex_lock(&m->lock);
154         AST_LIST_TRAVERSE_SAFE_BEGIN(&m->u, u, next) {
155                 ast_softhangup(u->chan, AST_SOFTHANGUP_APPUNLOAD);
156                 free(u);
157                 AST_LIST_REMOVE_CURRENT(&m->u, next);
158         }
159         AST_LIST_TRAVERSE_SAFE_END
160         m->usecnt = 0;
161         ast_mutex_unlock(&m->lock);
162         ast_update_use_count();
163 }
164
165 /*--- new-style loader routines ---*/
166
167 /*
168  * For backward compatibility, we have 3 types of loadable modules:
169  *
170  * MOD_0 these are the 'old style' modules, which export a number
171  *       of callbacks, and their full interface, as globally visible
172  *       symbols. The module needs to be loaded with RTLD_LAZY and
173  *       RTLD_GLOBAL to make symbols visible to other modules, and
174  *       to avoid load failures due to cross dependencies.
175  *
176  * MOD_1 almost as above, but the generic callbacks are all into a
177  *       a structure, mod_data. Same load requirements as above.
178  *
179  * MOD_2 this is the 'new style' format for modules. The module must
180  *       explictly declare which simbols are exported and which
181  *       symbols from other modules are used, and the code in this
182  *       loader will implement appropriate checks to load the modules
183  *       in the correct order. Also this allows to load modules
184  *       with RTLD_NOW and RTLD_LOCAL so there is no chance of run-time
185  *       bugs due to unresolved symbols or name conflicts.
186  */
187
188 /*
189  * helper routine to print the symbolic name associated to a state
190  */
191 static const char *st_name(enum st_t state)
192 {
193         /* try to resolve required symbols */
194         const char *st;
195         switch (state) {
196 #define ST(x)  case x: st = # x; break;
197         ST(MS_NEW);
198         ST(MS_FAILED);
199         ST(MS_RESOLVED);
200         ST(MS_ACTIVE);
201         ST(MS_CANLOAD);
202         default:
203                 st = "unknown";
204         }
205         return st;
206 #undef ST
207 }
208
209 /*! \brief
210  * Fetch/release an exported symbol - modify export_refcount by delta
211  * \param delta 1 to fetch a symbol, -1 to release it.
212  * on success, return symbol value.
213  * Note, modules in MS_FAIL will never match in a 'get' request.
214  * If src is non-NULL, on exit *src points to the source module.
215  *
216  * Must be called with the lock held.
217  */
218 static void *module_symbol_helper(const char *name,
219                 int delta, struct module **src)
220 {
221         void *ret = NULL;
222         struct module *m;
223
224         AST_LIST_TRAVERSE(&module_list, m, next) {
225                 struct symbol_entry *es;
226                 if (delta > 0 && m->state == MS_FAILED)
227                         continue; /* cannot 'get' a symbol from a failed module */
228                 for (es = m->cb.exported_symbols; ret == NULL && es && es->name; es++) {
229                         if (!strcmp(es->name, name)) {
230                                 ret = es->value;
231                                 m->export_refcount += delta;
232                                 if (src)
233                                         *src = m;
234                                 break;
235                         }
236                 }
237                 if (ret)
238                         break;
239         }
240         if (ret == NULL)
241                 ast_log(LOG_WARNING, "symbol %s not found\n", name);
242         return ret;
243 }
244
245 static void *release_module_symbol(const char *name)
246 {
247         return module_symbol_helper(name, -1, NULL);
248 }
249
250 static void *get_module_symbol(const char *name, struct module **src)
251 {
252         return module_symbol_helper(name, +1, src);
253 }
254
255 /*!
256  * \brief Release refcounts to all imported symbols,
257  * and change module state to MS_FAILED.
258  */
259 static void release_module(struct module *m)
260 {
261         struct symbol_entry *s;
262
263         for (s = m->cb.required_symbols; s && s->name != NULL; s++) {
264                 if (s->value != NULL) {
265                         release_module_symbol(s->name);
266                         s->value = NULL;
267                 }
268         }
269         m->state = MS_FAILED;
270 }
271
272 /*! \brief check that no NULL symbols are exported  - the algorithms rely on that. */
273 static int check_exported(struct module *m)
274 {
275         struct symbol_entry *es = m->cb.exported_symbols;
276         int errors = 0;
277
278         if (es == NULL)
279                 return 0;
280         ast_log(LOG_WARNING, "module %s exports the following symbols\n",
281                 es->name);
282         for (; es->name; es++) {
283                 void **p = es->value;
284                 int i;
285
286                 ast_log(LOG_WARNING, "\taddr %p size %8d %s\n",
287                         es->value, es->size, es->name);
288                 for (i = 0; i <  es->size / sizeof(void *); i++, p++) {
289                         if (*p == NULL) {
290                                 ast_log(LOG_WARNING, "\t *** null field at offset %d\n", i);
291                                         errors++;
292                         }
293                 }
294         }
295         return errors;
296 }
297
298 /*!
299  * \brief Resolve symbols and change state accordingly.
300  * Return 1 if state changed, 0 otherwise.
301  * If MS_FAILED, MS_ACTIVE or MS_CANLOAD there is nothing to do.
302  * If a symbol cannot be resolved (no supplier or supplier in MS_FAIL),
303  * move to MS_FAIL and release all symbols;
304  * If all suppliers are MS_ACTIVE, move to MS_CANLOAD
305  * otherwise move to MS_RESOLVED.
306  */
307 static int resolve(struct module *m)
308 {
309         struct symbol_entry *s;
310
311         if (m->state == MS_FAILED || m->state == MS_ACTIVE || m->state == MS_CANLOAD)
312                 return 0;       /* already decided what to do */
313         /* now it's either MS_NEW or MS_RESOLVED.
314          * Be optimistic and put it in MS_CANLOAD, then try to
315          * resolve and verify symbols, and downgrade as appropriate.
316          */
317         m->state = MS_CANLOAD;
318         for (s = m->cb.required_symbols; s && s->name != NULL; s++) {
319                 void **p = (void **)(s->value);
320
321                 if (*p == NULL)         /* symbol not resolved yet */
322                         *p = get_module_symbol(s->name, &s->src);
323                 if (*p == NULL || s->src->state == MS_FAILED) {        /* fail */
324                         ast_log(LOG_WARNING,
325                                 "Unresolved symbol %s for module %s\n",
326                                 s->name, m->resource);
327                         release_module(m); /* and set to MS_FAILED */
328                         break;
329                 }
330                 if (s->src->state != MS_ACTIVE)
331                         m->state = MS_RESOLVED; /* downgrade */
332         }
333         return 1;
334 }
335
336 /*
337  * Fixup references and load modules according to their dependency order.
338  * Called when new modules are added to the list.
339  * The algorithm is as follows:
340  * - all modules MS_FAILED are changed to MS_NEW, in case something
341  *      happened that could help them.
342  * - first try to resolve symbols. If successful, change the
343  *   module's state to MS_RESOLVED otherwise to MS_FAILED
344  * - repeat on all modules until there is progress:
345  *    . if it is MS_ACTIVE or MS_FAILED, continue (no progress)
346  *    . if one has all required modules in MS_ACTIVE, try to load it.
347  *      If successful it becomes MS_ACTIVE itself, otherwise
348  *             MS_FAILED and releases all symbols.
349  *             In any case, we have progress.
350  *    . if one of the dependencies is MS_FAILED, release and set to
351  *      MS_FAILED here too. We have progress.
352  * - if we have no progress there is a cyclic dependency.
353  *      Take first and change to MS_CANLOAD, i.e. as if all required are
354  *      MS_ACTIVE. we have progress, so repeat.
355  * NOTE:
356  *   must be called with lock held
357  *   recursive calls simply return success.
358  */
359 static int fixup(const char *caller)
360 {
361         struct module *m;
362         int total = 0, new = 0, cycle = 0;
363         static int in_fixup = 0;        /* disable recursive calls */
364
365         if (in_fixup)
366                 return 0;
367         in_fixup++;
368         AST_LIST_TRAVERSE(&module_list, m, next) {
369                 total++;
370                 if (m->state == MS_FAILED)
371                         m->state = MS_NEW;
372                 if (m->state == MS_NEW)
373                         new++;
374                 /* print some debugging info for new modules */
375                 if (m->state == MS_NEW &&
376                     (m->cb.exported_symbols || m->cb.required_symbols))
377                         ast_log(LOG_WARNING,
378                             "module %-30s exports %p requires %p state %s(%d)\n",
379                                 m->resource, m->cb.exported_symbols,
380                                 m->cb.required_symbols,
381                                 st_name(m->state), m->state);
382         }
383         ast_log(LOG_WARNING, "---- fixup (%s): %d modules, %d new ---\n",
384                 caller, total, new);
385         for (;;cycle++) {
386                 int again = 0;  /* set if we need another round */
387                 
388                 ast_log(LOG_WARNING, "---- fixup: cycle %d ---\n", cycle);
389                 AST_LIST_TRAVERSE(&module_list, m, next) {
390                         if (resolve(m))
391                                 again = 1;      /* something changed */
392                         if (m->state != MS_CANLOAD)     /* for now, done with this module */
393                                 continue;
394                         /* try to run the load routine */
395                         if (m->cb.load_module()) { /* error */
396                                 ast_log(LOG_WARNING, "load_module %s fail\n",
397                                         m->resource);
398                                 release_module(m); /* and set to MS_FAIL */
399                         } else {
400                                 ast_log(LOG_WARNING, "load_module %s success\n",
401                                         m->resource);
402                                 m->state = MS_ACTIVE;
403                         }
404                         again = 1;      /* something has changed */
405                 }
406                 /* Modules in MS_RESOLVED mean a possible cyclic dependency.
407                  * Break the indecision by setting one to CANLOAD, and repeat.
408                  */
409                 AST_LIST_TRAVERSE(&module_list, m, next) {
410                         if (m->state == MS_RESOLVED) {
411                                 m->state = MS_CANLOAD;
412                                 again = 1;
413                                 break;
414                         }
415                 }
416                 if (!again)     /* we are done */
417                         break;
418         }
419         ast_log(LOG_WARNING, "---- fixup complete ---\n");
420         in_fixup--;
421         return 0;
422 }
423
424 /* test routines to see which modules depend on global symbols
425  * exported by other modules.
426  */
427 static void check_symbols(void)
428 {
429         struct dirent *d;
430         DIR *mods = opendir(ast_config_AST_MODULE_DIR);
431         void *lib;
432         char buf[1024];
433
434         ast_log(LOG_WARNING, "module dir <%s>\n", ast_config_AST_MODULE_DIR);
435         if (!mods)
436                 return;
437         while((d = readdir(mods))) {
438                 int ld = strlen(d->d_name);
439                 /* Must end in .so to load it.  */
440                 if (ld <= 3 || strcasecmp(d->d_name + ld - 3, ".so"))
441                         continue;
442                 snprintf(buf, sizeof(buf), "%s/%s", ast_config_AST_MODULE_DIR, d->d_name);
443                 lib = dlopen(buf, RTLD_NOW | RTLD_LOCAL);
444                 if (lib == NULL) {
445                         ast_log(LOG_WARNING, "(notice only) module %s error %s\n", d->d_name, dlerror());
446                 }
447                 dlclose(lib);
448         }
449 }
450 /*--- end new-style routines ---*/
451
452 /*
453  * In addition to modules, the reload command handles some extra keywords
454  * which are listed here together with the corresponding handlers.
455  * This table is also used by the command completion code.
456  */
457 static struct reload_classes_t {
458         const char *name;
459         int (*reload_fn)(void);
460 } reload_classes[] = {  /* list in alpha order, longest match first */
461         { "cdr",        ast_cdr_engine_reload },
462         { "dnsmgr",     dnsmgr_reload },
463         { "extconfig",  read_config_maps },
464         { "enum",       ast_enum_reload },
465         { "manager",    reload_manager },
466         { "rtp",        ast_rtp_reload },
467         { "http",       ast_http_reload },
468         { NULL, NULL }
469 };
470
471 static int printdigest(const unsigned char *d)
472 {
473         int x, pos;
474         char buf[256]; /* large enough so we don't have to worry */
475
476         for (pos = 0, x=0; x<16; x++)
477                 pos += sprintf(buf + pos, " %02x", *d++);
478         ast_log(LOG_DEBUG, "Unexpected signature:%s\n", buf);
479         return 0;
480 }
481
482 static int key_matches(const unsigned char *key1, const unsigned char *key2)
483 {
484         int x;
485         for (x=0; x<16; x++) {
486                 if (key1[x] != key2[x]) /* mismatch - fail now. */
487                         return 0;
488         }
489         return 1;
490 }
491
492 static int verify_key(const unsigned char *key)
493 {
494         struct MD5Context c;
495         unsigned char digest[16];
496         MD5Init(&c);
497         MD5Update(&c, key, strlen((char *)key));
498         MD5Final(digest, &c);
499         if (key_matches(expected_key, digest))
500                 return 0;
501         printdigest(digest);
502         return -1;
503 }
504
505 int ast_unload_resource(const char *resource_name, int force)
506 {
507         struct module *cur;
508         int res = -1;
509         int error = 0;
510         if (AST_LIST_LOCK(&module_list)) /* XXX should fail here ? */
511                 ast_log(LOG_WARNING, "Failed to lock\n");
512         AST_LIST_TRAVERSE_SAFE_BEGIN(&module_list, cur, next) {
513                 struct module_symbols *m = &cur->cb;
514                 
515                 if (strcasecmp(cur->resource, resource_name))   /* not us */
516                         continue;
517                 if ((res = m->usecount()) > 0)  {
518                         if (force) 
519                                 ast_log(LOG_WARNING, "Warning:  Forcing removal of module %s with use count %d\n", resource_name, res);
520                         else {
521                                 ast_log(LOG_WARNING, "Soft unload failed, '%s' has use count %d\n", resource_name, res);
522                                 error = 1;
523                                 break;
524                         }
525                 }
526                 res = m->unload_module();
527                 if (res) {
528                         ast_log(LOG_WARNING, "Firm unload failed for %s\n", resource_name);
529                         if (force <= AST_FORCE_FIRM) {
530                                 error = 1;
531                                 break;
532                         } else
533                                 ast_log(LOG_WARNING, "** Dangerous **: Unloading resource anyway, at user request\n");
534                 }
535                 release_module(cur);    /* XXX */
536                 AST_LIST_REMOVE_CURRENT(&module_list, next);
537                 dlclose(cur->lib);
538                 free(cur);
539                 break;
540         }
541         AST_LIST_TRAVERSE_SAFE_END;
542         if (!error)
543                 modlistver++;
544         AST_LIST_UNLOCK(&module_list);
545         if (!error)     /* XXX maybe within the lock ? */
546                 ast_update_use_count();
547         return res;
548 }
549
550 char *ast_module_helper(const char *line, const char *word, int pos, int state, int rpos, int needsreload)
551 {
552         struct module *cur;
553         int i, which=0, l = strlen(word);
554         char *ret = NULL;
555
556         if (pos != rpos)
557                 return NULL;
558         AST_LIST_LOCK(&module_list);
559         AST_LIST_TRAVERSE(&module_list, cur, next) {
560                 if (!strncasecmp(word, cur->resource, l) && (cur->cb.reload || !needsreload) &&
561                                 ++which > state) {
562                         ret = strdup(cur->resource);
563                         break;
564                 }
565         }
566         AST_LIST_UNLOCK(&module_list);
567         if (!ret) {
568                 for (i=0; !ret && reload_classes[i].name; i++) {
569                         if (!strncasecmp(word, reload_classes[i].name, l) && ++which > state)
570                                 ret = strdup(reload_classes[i].name);
571                 }
572         }
573         return ret;
574 }
575
576 /*!
577  * \brief Given a function address, find the corresponding module.
578  * This is required as a workaround to the fact that we do not
579  * have a module argument to the load_module() function.
580  * Hopefully the performance implications are small.
581  */
582 struct module *ast_find_module(int (*load_fn)(void))
583 {
584         struct module *cur;
585         AST_LIST_LOCK(&module_list);
586         AST_LIST_TRAVERSE(&module_list, cur, next) {
587                 if (cur->cb.load_module == load_fn)
588                         break;
589         }
590         AST_LIST_UNLOCK(&module_list);
591         return cur;
592 }
593
594 int ast_module_reload(const char *name)
595 {
596         struct module *cur;
597         int res = 0; /* return value. 0 = not found, others, see below */
598         int i, oldversion;
599         int (*reload)(void);
600
601         if (ast_mutex_trylock(&reloadlock)) {
602                 ast_verbose("The previous reload command didn't finish yet\n");
603                 return -1;      /* reload already in progress */
604         }
605         /* Call "predefined" reload here first */
606         for (i = 0; reload_classes[i].name; i++) {
607                 if (!name || !strcasecmp(name, reload_classes[i].name)) {
608                         reload_classes[i].reload_fn();  /* XXX should check error ? */
609                         res = 2;        /* found and reloaded */
610                 }
611         }
612         ast_lastreloadtime = time(NULL);
613
614         AST_LIST_LOCK(&module_list);
615         oldversion = modlistver;
616         AST_LIST_TRAVERSE(&module_list, cur, next) {
617                 struct module_symbols *m = &cur->cb;
618                 if (name && strcasecmp(name, cur->resource))    /* not ours */
619                         continue;
620                 reload = m->reload;
621                 if (!reload) {  /* cannot be reloaded */
622                         if (res < 1)    /* store result if possible */
623                                 res = 1;        /* 1 = no reload() method */
624                         continue;
625                 }
626                 /* drop the lock and try a reload. if successful, break */
627                 AST_LIST_UNLOCK(&module_list);
628                 res = 2;
629                 if (option_verbose > 2) 
630                         ast_verbose(VERBOSE_PREFIX_3 "Reloading module '%s' (%s)\n", cur->resource, m->description());
631                 reload();
632                 AST_LIST_LOCK(&module_list);
633                 if (oldversion != modlistver) /* something changed, abort */
634                         break;
635         }
636         AST_LIST_UNLOCK(&module_list);
637         ast_mutex_unlock(&reloadlock);
638         return res;
639 }
640
641 static int resource_exists(const char *resource, int do_lock)
642 {
643         struct module *cur;
644         if (do_lock && AST_LIST_LOCK(&module_list))
645                 ast_log(LOG_WARNING, "Failed to lock\n");
646         AST_LIST_TRAVERSE(&module_list, cur, next) {
647                 if (!strcasecmp(resource, cur->resource))
648                         break;
649         }
650         if (do_lock)
651                 AST_LIST_UNLOCK(&module_list);
652         return cur ? -1 : 0;
653 }
654
655 /* lookup a symbol with or without leading '_', accept either form in input */
656 static void *find_symbol(struct module *m, const char *name, int verbose)
657 {
658         char *n1;
659         void *s;
660
661         if (name[0] == '_')
662                 name++;
663         if (!(n1 = alloca(strlen(name) + 2))) /* room for leading '_' and final '\0' */
664                 return NULL;
665         n1[0] = '_';
666         strcpy(n1+1, name);
667         s = dlsym(m->lib, n1+1);        /* try without '_' */
668         if (s == NULL)
669                 s = dlsym(m->lib, n1);
670         if (verbose && s == NULL)
671                 ast_log(LOG_WARNING, "No symbol '%s' in module '%s\n",
672                         n1, m->resource);
673         return s;
674 }
675
676 /* XXX cfg is only used for !res_* and #ifdef RTLD_GLOBAL */
677 static struct module * __load_resource(const char *resource_name,
678         const struct ast_config *cfg)
679 {
680         static char fn[256];
681         int errors=0;
682         int res;
683         struct module *cur;
684         struct module_symbols *m, *m1;
685         int flags=RTLD_NOW;
686         unsigned char *key;
687         char tmp[80];
688
689         if (strncasecmp(resource_name, "res_", 4)) {
690 #ifdef RTLD_GLOBAL
691                 if (cfg) {
692                         char *val;
693                         if ((val = ast_variable_retrieve(cfg, "global", resource_name))
694                                         && ast_true(val))
695                                 flags |= RTLD_GLOBAL;
696                 }
697 #endif
698         } else {
699                 /* Resource modules are always loaded global and lazy */
700 #ifdef RTLD_GLOBAL
701                 flags = (RTLD_GLOBAL | RTLD_LAZY);
702 #else
703                 flags = RTLD_LAZY;
704 #endif
705         }
706         
707         if (AST_LIST_LOCK(&module_list))
708                 ast_log(LOG_WARNING, "Failed to lock\n");
709         if (resource_exists(resource_name, 0)) {
710                 ast_log(LOG_WARNING, "Module '%s' already exists\n", resource_name);
711                 AST_LIST_UNLOCK(&module_list);
712                 return NULL;
713         }
714         if (!(cur = ast_calloc(1, sizeof(*cur)))) {
715                 AST_LIST_UNLOCK(&module_list);
716                 return NULL;
717         }
718         m = &cur->cb;
719         ast_copy_string(cur->resource, resource_name, sizeof(cur->resource));
720         if (resource_name[0] == '/')
721                 ast_copy_string(fn, resource_name, sizeof(fn));
722         else
723                 snprintf(fn, sizeof(fn), "%s/%s", ast_config_AST_MODULE_DIR, resource_name);
724 #if 0
725         /* XXX test, open in a sane way */
726         cur->lib = dlopen(fn, RTLD_NOW | RTLD_LOCAL);
727         if (cur->lib == NULL) {
728                 ast_log(LOG_WARNING, "test %s\n", dlerror());
729         } else
730                 dlclose(cur->lib);
731 #endif
732
733         cur->lib = dlopen(fn, flags);
734         if (!cur->lib) {
735                 ast_log(LOG_WARNING, "%s\n", dlerror());
736                 free(cur);
737                 AST_LIST_UNLOCK(&module_list);
738                 return NULL;
739         }
740         m1 = find_symbol(cur, "mod_data", 0);
741         if (m1 != NULL) {       /* new style module */
742                 errors = check_exported(cur);
743                 *m = *m1;
744                 if (m->type == MOD_2)
745                         ast_log(LOG_WARNING, "new style %s, should unload and reload with RTLD_LOCAL\n", resource_name);
746         } else {
747                 m->type = MOD_0;
748                 m->load_module = find_symbol(cur, "load_module", 1);
749                 m->unload_module = find_symbol(cur, "unload_module", 1);
750                 m->usecount = find_symbol(cur, "usecount", 1);
751                 m->description = find_symbol(cur, "description", 1);
752                 m->key = find_symbol(cur, "key", 1);
753                 m->reload = find_symbol(cur, "reload", 0);
754         }
755         if (!m->load_module)
756                 errors++;
757         if (!m->unload_module)
758                 errors++;
759         if (!m->usecount)
760                 errors++;
761         if (!m->description)
762                 errors++;
763         if (!m->key)
764                 errors++;
765         if (!m->key || !(key = (unsigned char *) m->key())) {
766                 ast_log(LOG_WARNING, "Key routine returned NULL in module %s\n", fn);
767                 key = NULL;
768                 errors++;
769         }
770         if (key && verify_key(key)) {
771                 ast_log(LOG_WARNING, "Unexpected key returned by module %s\n", fn);
772                 errors++;
773         }
774         if (errors) {
775                 ast_log(LOG_WARNING, "%d error%s loading module %s, aborted\n", errors, (errors != 1) ? "s" : "", fn);
776                 dlclose(cur->lib);
777                 free(cur);
778                 AST_LIST_UNLOCK(&module_list);
779                 return NULL;
780         }
781         if (!ast_fully_booted) {
782                 if (option_verbose) 
783                         ast_verbose( " => (%s)\n", term_color(tmp, m->description(), COLOR_BROWN, COLOR_BLACK, sizeof(tmp)));
784                 if (ast_opt_console && !option_verbose)
785                         ast_verbose( ".");
786         } else {
787                 if (option_verbose)
788                         ast_verbose(VERBOSE_PREFIX_1 "Loaded %s => (%s)\n", fn, m->description());
789         }
790
791         AST_LIST_INSERT_TAIL(&module_list, cur, next);
792         /* add module to end of module_list chain
793            so reload commands will be issued in same order modules were loaded */
794         
795         modlistver++;
796         if (m->type == MOD_2) {
797                 ast_log(LOG_WARNING, "new-style module %s, deferring load()\n",
798                         resource_name);
799                 cur->state = MS_NEW;
800         } else
801                 cur->state = MS_CANLOAD;
802         /* XXX make sure the usecount is 1 before releasing the lock */
803         AST_LIST_UNLOCK(&module_list);
804         
805         if (cur->state == MS_CANLOAD && (res = m->load_module())) {
806                 ast_log(LOG_WARNING, "%s: load_module failed, returning %d\n", resource_name, res);
807                 ast_unload_resource(resource_name, 0);
808                 return NULL;
809         }
810         cur->state = MS_ACTIVE;
811         ast_update_use_count();
812         return cur;
813 }
814
815 /*
816  * load a single module (API call).
817  * (recursive calls from load_module() succeed.
818  * Returns 0 on success, -1 on error.
819  */
820 int ast_load_resource(const char *resource_name)
821 {
822         int o = option_verbose;
823         struct ast_config *cfg = NULL;
824         struct module *m;
825
826         option_verbose = 0;     /* Keep the module file parsing silent */
827         cfg = ast_config_load(AST_MODULE_CONFIG);
828         option_verbose = o;     /* restore verbosity */
829         m = __load_resource(resource_name, cfg);
830         if (cfg)
831                 ast_config_destroy(cfg);
832         return m ? 0 : -1;
833 }       
834
835 #if 0
836 +/*
837 + * load a single module (API call).
838 + * (recursive calls from load_module() succeed.
839 + */
840 +int ast_load_resource(const char *resource_name)
841 +{
842 +       struct module *m;
843 +       int ret;
844 +
845 +       ast_mutex_lock(&modlock);
846 +       m = __load_resource(resource_name, 0);
847 +       fixup(resource_name);
848 +       ret = (m->state == MS_FAILED) ? -1 : 0;
849 +       ast_mutex_unlock(&modlock);
850 +       return ret;
851 +}
852 #endif
853
854 /* if enabled, log and output on console the module's name, and try load it */
855 static int print_and_load(const char *s, struct ast_config *cfg)
856 {
857         char tmp[80];
858
859         if (option_debug && !option_verbose)
860                 ast_log(LOG_DEBUG, "Loading module %s\n", s);
861         if (option_verbose) {
862                 ast_verbose(VERBOSE_PREFIX_1 "[%s]",
863                         term_color(tmp, s, COLOR_BRWHITE, 0, sizeof(tmp)));
864                 fflush(stdout);
865         }
866         if (__load_resource(s, cfg))
867                 return 0; /* success */
868         ast_log(LOG_WARNING, "Loading module %s failed!\n", s);
869         return -1;
870 }
871
872 static const char *loadorder[] =
873 {
874         "res_",
875         "pbx_",
876         "chan_",
877         NULL,
878 };
879
880 int load_modules(const int preload_only)
881 {
882         struct ast_config *cfg;
883         int x;
884
885         if (option_verbose) {
886                 ast_verbose(preload_only ?
887                         "Asterisk Dynamic Loader loading preload modules:\n" :
888                         "Asterisk Dynamic Loader Starting:\n");
889         }
890
891         if (0)
892                 check_symbols();
893
894         cfg = ast_config_load(AST_MODULE_CONFIG);
895
896         if (cfg) {
897                 const char *cmd = preload_only ? "preload" : "load";
898                 struct ast_variable *v;
899                 /* Load explicitly defined modules */
900                 for (v = ast_variable_browse(cfg, "modules"); v; v = v->next) {
901                         if (strcasecmp(v->name, cmd)) /* not what we are looking for */
902                                 continue;
903                         if (print_and_load(v->value, cfg)) {    /* XXX really fatal ? */
904                                 ast_config_destroy(cfg);
905                                 return -1;
906                         }
907                 }
908         }
909
910         if (preload_only)
911                 goto done;
912
913         if (cfg && !ast_true(ast_variable_retrieve(cfg, "modules", "autoload")))
914                 /* no autoload */
915                 goto done;
916         /*
917          * Load all modules. To help resolving dependencies, we load modules
918          * in the order defined by loadorder[], with the final step for
919          * all modules with other prefixes.
920          * (XXX the new loader does not need this).
921          */
922
923         for (x=0; x<sizeof(loadorder) / sizeof(loadorder[0]); x++) {
924                 struct dirent *d;
925                 DIR *mods = opendir(ast_config_AST_MODULE_DIR);
926                 const char *base = loadorder[x];
927                 int lx = base ? strlen(base) : 0;
928
929                 if (!mods) {
930                         if (!ast_opt_quiet)
931                                 ast_log(LOG_WARNING, "Unable to open modules directory %s.\n",
932                                         ast_config_AST_MODULE_DIR);
933                         break; /* suffices to try once! */
934                 }
935                 while((d = readdir(mods))) {
936                         int ld = strlen(d->d_name);
937                         /* Must end in .so to load it.  */
938                         if (ld > 3 && (!base || !strncasecmp(d->d_name, base, lx)) && 
939                                         !strcasecmp(d->d_name + ld - 3, ".so") &&
940                                         !resource_exists(d->d_name, 1)) {
941                                 /* It's a shared library, check if we are allowed to load it
942                                  * (very inefficient, but oh well).
943                                  */
944                                 if (cfg) {
945                                         struct ast_variable *v;
946                                         for (v = ast_variable_browse(cfg, "modules"); v; v = v->next) {
947                                                 if (!strcasecmp(v->name, "noload") &&
948                                                                 !strcasecmp(v->value, d->d_name)) 
949                                                         break;
950                                         }
951                                         if (v) {
952                                                 if (option_verbose) {
953                                                         ast_verbose( VERBOSE_PREFIX_1 "[skipping %s]\n",
954                                                                         d->d_name);
955                                                         fflush(stdout);
956                                                 }
957                                                 continue;
958                                         }
959                                         
960                                 }
961                                 if (print_and_load(d->d_name, cfg)) {
962                                         ast_config_destroy(cfg);
963                                         return -1;
964                                 }
965                         }
966                 }
967                 closedir(mods);
968         }
969 done:
970         fixup("load_modules");
971         ast_config_destroy(cfg);
972         return 0;
973 }
974
975 void ast_update_use_count(void)
976 {
977         /* Notify any module monitors that the use count for a 
978            resource has changed */
979         struct loadupdate *m;
980         if (AST_LIST_LOCK(&module_list))
981                 ast_log(LOG_WARNING, "Failed to lock\n");
982         AST_LIST_TRAVERSE(&updaters, m, next)
983                 m->updater();
984         AST_LIST_UNLOCK(&module_list);
985 }
986
987 int ast_update_module_list(int (*modentry)(const char *module, const char *description, int usecnt, const char *like),
988                            const char *like)
989 {
990         struct module *cur;
991         int unlock = -1;
992         int total_mod_loaded = 0;
993
994         if (ast_mutex_trylock(&module_list.lock))
995                 unlock = 0;
996         AST_LIST_TRAVERSE(&module_list, cur, next)
997                 total_mod_loaded += modentry(cur->resource, cur->cb.description(), cur->cb.usecount(), like);
998         if (unlock)
999                 AST_LIST_UNLOCK(&module_list);
1000
1001         return total_mod_loaded;
1002 }
1003
1004 int ast_loader_register(int (*v)(void)) 
1005 {
1006         /* XXX Should be more flexible here, taking > 1 verboser XXX */
1007         struct loadupdate *tmp; 
1008         if (!(tmp = ast_malloc(sizeof(*tmp))))
1009                 return -1;
1010         tmp->updater = v;
1011         if (AST_LIST_LOCK(&module_list))
1012                 ast_log(LOG_WARNING, "Failed to lock\n");
1013         AST_LIST_INSERT_HEAD(&updaters, tmp, next);
1014         AST_LIST_UNLOCK(&module_list);
1015         return 0;
1016 }
1017
1018 int ast_loader_unregister(int (*v)(void))
1019 {
1020         struct loadupdate *cur;
1021
1022         if (AST_LIST_LOCK(&module_list))
1023                 ast_log(LOG_WARNING, "Failed to lock\n");
1024         AST_LIST_TRAVERSE_SAFE_BEGIN(&updaters, cur, next) {
1025                 if (cur->updater == v)  {
1026                         AST_LIST_REMOVE_CURRENT(&updaters, next);
1027                         break;
1028                 }
1029         }
1030         AST_LIST_TRAVERSE_SAFE_END;
1031         AST_LIST_UNLOCK(&module_list);
1032         return cur ? 0 : -1;
1033 }