8250f1ffb21a6b739187f9ccceb6a19aa022b324
[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 /*** MODULEINFO
31         <support_level>core</support_level>
32  ***/
33
34 #include "asterisk.h"
35
36 #include "asterisk/_private.h"
37 #include "asterisk/paths.h"     /* use ast_config_AST_MODULE_DIR */
38 #include <dirent.h>
39
40 #include "asterisk/dlinkedlists.h"
41 #include "asterisk/module.h"
42 #include "asterisk/config.h"
43 #include "asterisk/channel.h"
44 #include "asterisk/term.h"
45 #include "asterisk/acl.h"
46 #include "asterisk/manager.h"
47 #include "asterisk/cdr.h"
48 #include "asterisk/enum.h"
49 #include "asterisk/http.h"
50 #include "asterisk/lock.h"
51 #include "asterisk/features_config.h"
52 #include "asterisk/dsp.h"
53 #include "asterisk/udptl.h"
54 #include "asterisk/heap.h"
55 #include "asterisk/app.h"
56 #include "asterisk/test.h"
57 #include "asterisk/sounds_index.h"
58
59 #include <dlfcn.h>
60
61 #include "asterisk/md5.h"
62 #include "asterisk/utils.h"
63
64 /*** DOCUMENTATION
65         <managerEvent language="en_US" name="Reload">
66                 <managerEventInstance class="EVENT_FLAG_SYSTEM">
67                         <synopsis>Raised when a module has been reloaded in Asterisk.</synopsis>
68                         <syntax>
69                                 <parameter name="Module">
70                                         <para>The name of the module that was reloaded, or
71                                         <literal>All</literal> if all modules were reloaded</para>
72                                 </parameter>
73                                 <parameter name="Status">
74                                         <para>The numeric status code denoting the success or failure
75                                         of the reload request.</para>
76                                         <enumlist>
77                                                 <enum name="0"><para>Success</para></enum>
78                                                 <enum name="1"><para>Request queued</para></enum>
79                                                 <enum name="2"><para>Module not found</para></enum>
80                                                 <enum name="3"><para>Error</para></enum>
81                                                 <enum name="4"><para>Reload already in progress</para></enum>
82                                                 <enum name="5"><para>Module uninitialized</para></enum>
83                                                 <enum name="6"><para>Reload not supported</para></enum>
84                                         </enumlist>
85                                 </parameter>
86                         </syntax>
87                 </managerEventInstance>
88         </managerEvent>
89  ***/
90
91 #ifndef RTLD_NOW
92 #define RTLD_NOW 0
93 #endif
94
95 #ifndef RTLD_LOCAL
96 #define RTLD_LOCAL 0
97 #endif
98
99 struct ast_module_user {
100         struct ast_channel *chan;
101         AST_LIST_ENTRY(ast_module_user) entry;
102 };
103
104 AST_DLLIST_HEAD(module_user_list, ast_module_user);
105
106 static const unsigned char expected_key[] =
107 { 0x87, 0x76, 0x79, 0x35, 0x23, 0xea, 0x3a, 0xd3,
108   0x25, 0x2a, 0xbb, 0x35, 0x87, 0xe4, 0x22, 0x24 };
109
110 static char buildopt_sum[33] = AST_BUILDOPT_SUM;
111
112 /*!
113  * \brief Internal flag to indicate all modules have been initially loaded.
114  */
115 static int modules_loaded;
116
117 struct ast_module {
118         const struct ast_module_info *info;
119         /* Used to get module references into refs log */
120         void *ref_debug;
121         void *lib;                                      /* the shared lib, or NULL if embedded */
122         int usecount;                                   /* the number of 'users' currently in this module */
123         struct module_user_list users;                  /* the list of users in the module */
124         struct {
125                 unsigned int running:1;
126                 unsigned int declined:1;
127                 unsigned int keepuntilshutdown:1;
128         } flags;
129         AST_LIST_ENTRY(ast_module) list_entry;
130         AST_DLLIST_ENTRY(ast_module) entry;
131         char resource[0];
132 };
133
134 static AST_DLLIST_HEAD_STATIC(module_list, ast_module);
135
136 const char *ast_module_name(const struct ast_module *mod)
137 {
138         if (!mod || !mod->info) {
139                 return NULL;
140         }
141
142         return mod->info->name;
143 }
144
145 struct loadupdate {
146         int (*updater)(void);
147         AST_LIST_ENTRY(loadupdate) entry;
148 };
149
150 static AST_DLLIST_HEAD_STATIC(updaters, loadupdate);
151
152 AST_MUTEX_DEFINE_STATIC(reloadlock);
153
154 struct reload_queue_item {
155         AST_LIST_ENTRY(reload_queue_item) entry;
156         char module[0];
157 };
158
159 static int do_full_reload = 0;
160
161 static AST_DLLIST_HEAD_STATIC(reload_queue, reload_queue_item);
162
163 /* when dynamic modules are being loaded, ast_module_register() will
164    need to know what filename the module was loaded from while it
165    is being registered
166 */
167 static struct ast_module *resource_being_loaded;
168
169 /* XXX: should we check for duplicate resource names here? */
170
171 void ast_module_register(const struct ast_module_info *info)
172 {
173         struct ast_module *mod = resource_being_loaded;
174
175         ast_debug(5, "Registering module %s\n", info->name);
176
177         mod->info = info;
178         if (ast_opt_ref_debug) {
179                 mod->ref_debug = ao2_t_alloc(0, NULL, info->name);
180         }
181         AST_LIST_HEAD_INIT(&mod->users);
182
183         /* during startup, before the loader has been initialized,
184            there are no threads, so there is no need to take the lock
185            on this list to manipulate it. it is also possible that it
186            might be unsafe to use the list lock at that point... so
187            let's avoid it altogether
188         */
189         AST_DLLIST_LOCK(&module_list);
190         /* it is paramount that the new entry be placed at the tail of
191            the list, otherwise the code that uses dlopen() to load
192            dynamic modules won't be able to find out if the module it
193            just opened was registered or failed to load
194         */
195         AST_DLLIST_INSERT_TAIL(&module_list, mod, entry);
196         AST_DLLIST_UNLOCK(&module_list);
197
198         /* give the module a copy of its own handle, for later use in registrations and the like */
199         *((struct ast_module **) &(info->self)) = mod;
200 }
201
202 void ast_module_unregister(const struct ast_module_info *info)
203 {
204         struct ast_module *mod = NULL;
205
206         /* it is assumed that the users list in the module structure
207            will already be empty, or we cannot have gotten to this
208            point
209         */
210         AST_DLLIST_LOCK(&module_list);
211         AST_DLLIST_TRAVERSE_BACKWARDS_SAFE_BEGIN(&module_list, mod, entry) {
212                 if (mod->info == info) {
213                         AST_DLLIST_REMOVE_CURRENT(entry);
214                         break;
215                 }
216         }
217         AST_DLLIST_TRAVERSE_BACKWARDS_SAFE_END;
218         AST_DLLIST_UNLOCK(&module_list);
219
220         if (mod) {
221                 ast_debug(5, "Unregistering module %s\n", info->name);
222                 AST_LIST_HEAD_DESTROY(&mod->users);
223                 ao2_cleanup(mod->ref_debug);
224                 ast_free(mod);
225         }
226 }
227
228 struct ast_module_user *__ast_module_user_add(struct ast_module *mod, struct ast_channel *chan)
229 {
230         struct ast_module_user *u;
231
232         u = ast_calloc(1, sizeof(*u));
233         if (!u) {
234                 return NULL;
235         }
236
237         u->chan = chan;
238
239         AST_LIST_LOCK(&mod->users);
240         AST_LIST_INSERT_HEAD(&mod->users, u, entry);
241         AST_LIST_UNLOCK(&mod->users);
242
243         if (mod->ref_debug) {
244                 ao2_ref(mod->ref_debug, +1);
245         }
246
247         ast_atomic_fetchadd_int(&mod->usecount, +1);
248
249         ast_update_use_count();
250
251         return u;
252 }
253
254 void __ast_module_user_remove(struct ast_module *mod, struct ast_module_user *u)
255 {
256         if (!u) {
257                 return;
258         }
259
260         AST_LIST_LOCK(&mod->users);
261         u = AST_LIST_REMOVE(&mod->users, u, entry);
262         AST_LIST_UNLOCK(&mod->users);
263         if (!u) {
264                 /*
265                  * Was not in the list.  Either a bad pointer or
266                  * __ast_module_user_hangup_all() has been called.
267                  */
268                 return;
269         }
270
271         if (mod->ref_debug) {
272                 ao2_ref(mod->ref_debug, -1);
273         }
274
275         ast_atomic_fetchadd_int(&mod->usecount, -1);
276         ast_free(u);
277
278         ast_update_use_count();
279 }
280
281 void __ast_module_user_hangup_all(struct ast_module *mod)
282 {
283         struct ast_module_user *u;
284
285         AST_LIST_LOCK(&mod->users);
286         while ((u = AST_LIST_REMOVE_HEAD(&mod->users, entry))) {
287                 if (u->chan) {
288                         ast_softhangup(u->chan, AST_SOFTHANGUP_APPUNLOAD);
289                 }
290
291                 if (mod->ref_debug) {
292                         ao2_ref(mod->ref_debug, -1);
293                 }
294
295                 ast_atomic_fetchadd_int(&mod->usecount, -1);
296                 ast_free(u);
297         }
298         AST_LIST_UNLOCK(&mod->users);
299
300         ast_update_use_count();
301 }
302
303 /*! \note
304  * In addition to modules, the reload command handles some extra keywords
305  * which are listed here together with the corresponding handlers.
306  * This table is also used by the command completion code.
307  */
308 static struct reload_classes {
309         const char *name;
310         int (*reload_fn)(void);
311 } reload_classes[] = {  /* list in alpha order, longest match first for cli completion */
312         { "acl",         ast_named_acl_reload },
313         { "cdr",         ast_cdr_engine_reload },
314         { "cel",         ast_cel_engine_reload },
315         { "dnsmgr",      dnsmgr_reload },
316         { "dsp",         ast_dsp_reload},
317         { "extconfig",   read_config_maps },
318         { "enum",        ast_enum_reload },
319         { "features",    ast_features_config_reload },
320         { "http",        ast_http_reload },
321         { "indications", ast_indications_reload },
322         { "logger",      logger_reload },
323         { "manager",     reload_manager },
324         { "plc",         ast_plc_reload },
325         { "sounds",      ast_sounds_reindex },
326         { "udptl",       ast_udptl_reload },
327         { NULL,          NULL }
328 };
329
330 static int printdigest(const unsigned char *d)
331 {
332         int x, pos;
333         char buf[256]; /* large enough so we don't have to worry */
334
335         for (pos = 0, x = 0; x < 16; x++)
336                 pos += sprintf(buf + pos, " %02hhx", *d++);
337
338         ast_debug(1, "Unexpected signature:%s\n", buf);
339
340         return 0;
341 }
342
343 static int key_matches(const unsigned char *key1, const unsigned char *key2)
344 {
345         int x;
346
347         for (x = 0; x < 16; x++) {
348                 if (key1[x] != key2[x])
349                         return 0;
350         }
351
352         return 1;
353 }
354
355 static int verify_key(const unsigned char *key)
356 {
357         struct MD5Context c;
358         unsigned char digest[16];
359
360         MD5Init(&c);
361         MD5Update(&c, key, strlen((char *)key));
362         MD5Final(digest, &c);
363
364         if (key_matches(expected_key, digest))
365                 return 0;
366
367         printdigest(digest);
368
369         return -1;
370 }
371
372 static int resource_name_match(const char *name1_in, const char *name2_in)
373 {
374         char *name1 = (char *) name1_in;
375         char *name2 = (char *) name2_in;
376
377         /* trim off any .so extensions */
378         if (!strcasecmp(name1 + strlen(name1) - 3, ".so")) {
379                 name1 = ast_strdupa(name1);
380                 name1[strlen(name1) - 3] = '\0';
381         }
382         if (!strcasecmp(name2 + strlen(name2) - 3, ".so")) {
383                 name2 = ast_strdupa(name2);
384                 name2[strlen(name2) - 3] = '\0';
385         }
386
387         return strcasecmp(name1, name2);
388 }
389
390 static struct ast_module *find_resource(const char *resource, int do_lock)
391 {
392         struct ast_module *cur;
393
394         if (do_lock) {
395                 AST_DLLIST_LOCK(&module_list);
396         }
397
398         AST_DLLIST_TRAVERSE(&module_list, cur, entry) {
399                 if (!resource_name_match(resource, cur->resource))
400                         break;
401         }
402
403         if (do_lock) {
404                 AST_DLLIST_UNLOCK(&module_list);
405         }
406
407         return cur;
408 }
409
410 /*!
411  * \brief dlclose(), with failure logging.
412  */
413 static void logged_dlclose(const char *name, void *lib)
414 {
415         char *error;
416
417         if (!lib) {
418                 return;
419         }
420
421         /* Clear any existing error */
422         dlerror();
423         if (dlclose(lib)) {
424                 error = dlerror();
425                 ast_log(AST_LOG_ERROR, "Failure in dlclose for module '%s': %s\n",
426                         S_OR(name, "unknown"), S_OR(error, "Unknown error"));
427         }
428 }
429
430 #if defined(HAVE_RTLD_NOLOAD)
431 /*!
432  * \brief Check to see if the given resource is loaded.
433  *
434  * \param resource_name Name of the resource, including .so suffix.
435  * \return False (0) if module is not loaded.
436  * \return True (non-zero) if module is loaded.
437  */
438 static int is_module_loaded(const char *resource_name)
439 {
440         char fn[PATH_MAX] = "";
441         void *lib;
442
443         snprintf(fn, sizeof(fn), "%s/%s", ast_config_AST_MODULE_DIR,
444                 resource_name);
445
446         lib = dlopen(fn, RTLD_LAZY | RTLD_NOLOAD);
447
448         if (lib) {
449                 logged_dlclose(resource_name, lib);
450                 return 1;
451         }
452
453         return 0;
454 }
455 #endif
456
457 static void unload_dynamic_module(struct ast_module *mod)
458 {
459 #if defined(HAVE_RTLD_NOLOAD)
460         char *name = ast_strdupa(ast_module_name(mod));
461 #endif
462         void *lib = mod->lib;
463
464         /* WARNING: the structure pointed to by mod is going to
465            disappear when this operation succeeds, so we can't
466            dereference it */
467         logged_dlclose(ast_module_name(mod), lib);
468
469         /* There are several situations where the module might still be resident
470          * in memory.
471          *
472          * If somehow there was another dlopen() on the same module (unlikely,
473          * since that all is supposed to happen in loader.c).
474          *
475          * Or the lazy resolution of a global symbol (very likely, since that is
476          * how we load all of our modules that export global symbols).
477          *
478          * Avoid the temptation of repeating the dlclose(). The other code that
479          * dlopened the module still has its module reference, and should close
480          * it itself. In other situations, dlclose() will happily return success
481          * for as many times as you wish to call it.
482          */
483 #if defined(HAVE_RTLD_NOLOAD)
484         if (is_module_loaded(name)) {
485                 ast_log(LOG_WARNING, "Module '%s' could not be completely unloaded\n", name);
486         }
487 #endif
488 }
489
490 static enum ast_module_load_result load_resource(const char *resource_name, unsigned int global_symbols_only, unsigned int suppress_logging, struct ast_heap *resource_heap, int required);
491
492 #define MODULE_LOCAL_ONLY (void *)-1
493
494 static struct ast_module *load_dynamic_module(const char *resource_in, unsigned int global_symbols_only, unsigned int suppress_logging, struct ast_heap *resource_heap)
495 {
496         char fn[PATH_MAX] = "";
497         void *lib = NULL;
498         struct ast_module *mod;
499         unsigned int wants_global;
500         int space;      /* room needed for the descriptor */
501         int missing_so = 0;
502
503         space = sizeof(*resource_being_loaded) + strlen(resource_in) + 1;
504         if (strcasecmp(resource_in + strlen(resource_in) - 3, ".so")) {
505                 missing_so = 1;
506                 space += 3;     /* room for the extra ".so" */
507         }
508
509         snprintf(fn, sizeof(fn), "%s/%s%s", ast_config_AST_MODULE_DIR, resource_in, missing_so ? ".so" : "");
510
511         /* make a first load of the module in 'quiet' mode... don't try to resolve
512            any symbols, and don't export any symbols. this will allow us to peek into
513            the module's info block (if available) to see what flags it has set */
514
515         resource_being_loaded = ast_calloc(1, space);
516         if (!resource_being_loaded)
517                 return NULL;
518         strcpy(resource_being_loaded->resource, resource_in);
519         if (missing_so)
520                 strcat(resource_being_loaded->resource, ".so");
521
522         if (!(lib = dlopen(fn, RTLD_LAZY | RTLD_GLOBAL))) {
523                 if (!suppress_logging) {
524                         ast_log(LOG_WARNING, "Error loading module '%s': %s\n", resource_in, dlerror());
525                 }
526                 ast_free(resource_being_loaded);
527                 return NULL;
528         }
529
530         /* the dlopen() succeeded, let's find out if the module
531            registered itself */
532         /* note that this will only work properly as long as
533            ast_module_register() (which is called by the module's
534            constructor) places the new module at the tail of the
535            module_list
536         */
537         if (resource_being_loaded != (mod = AST_DLLIST_LAST(&module_list))) {
538                 ast_log(LOG_WARNING, "Module '%s' did not register itself during load\n", resource_in);
539                 /* no, it did not, so close it and return */
540                 logged_dlclose(resource_in, lib);
541                 /* note that the module's destructor will call ast_module_unregister(),
542                    which will free the structure we allocated in resource_being_loaded */
543                 return NULL;
544         }
545
546         wants_global = ast_test_flag(mod->info, AST_MODFLAG_GLOBAL_SYMBOLS);
547
548         /* if we are being asked only to load modules that provide global symbols,
549            and this one does not, then close it and return */
550         if (global_symbols_only && !wants_global) {
551                 logged_dlclose(resource_in, lib);
552                 return MODULE_LOCAL_ONLY;
553         }
554
555         logged_dlclose(resource_in, lib);
556         resource_being_loaded = NULL;
557
558         /* start the load process again */
559         resource_being_loaded = ast_calloc(1, space);
560         if (!resource_being_loaded)
561                 return NULL;
562         strcpy(resource_being_loaded->resource, resource_in);
563         if (missing_so)
564                 strcat(resource_being_loaded->resource, ".so");
565
566         if (!(lib = dlopen(fn, wants_global ? RTLD_LAZY | RTLD_GLOBAL : RTLD_NOW | RTLD_LOCAL))) {
567                 ast_log(LOG_WARNING, "Error loading module '%s': %s\n", resource_in, dlerror());
568                 ast_free(resource_being_loaded);
569                 return NULL;
570         }
571
572         /* since the module was successfully opened, and it registered itself
573            the previous time we did that, we're going to assume it worked this
574            time too :) */
575
576         AST_DLLIST_LAST(&module_list)->lib = lib;
577         resource_being_loaded = NULL;
578
579         return AST_DLLIST_LAST(&module_list);
580 }
581
582 int modules_shutdown(void)
583 {
584         struct ast_module *mod;
585         int somethingchanged = 1, final = 0;
586
587         AST_DLLIST_LOCK(&module_list);
588
589         /*!\note Some resources, like timers, are started up dynamically, and thus
590          * may be still in use, even if all channels are dead.  We must therefore
591          * check the usecount before asking modules to unload. */
592         do {
593                 if (!somethingchanged) {
594                         /*!\note If we go through the entire list without changing
595                          * anything, ignore the usecounts and unload, then exit. */
596                         final = 1;
597                 }
598
599                 /* Reset flag before traversing the list */
600                 somethingchanged = 0;
601
602                 AST_DLLIST_TRAVERSE_BACKWARDS_SAFE_BEGIN(&module_list, mod, entry) {
603                         if (!final && mod->usecount) {
604                                 ast_debug(1, "Passing on %s: its use count is %d\n",
605                                         mod->resource, mod->usecount);
606                                 continue;
607                         }
608                         AST_DLLIST_REMOVE_CURRENT(entry);
609                         if (mod->flags.running && !mod->flags.declined && mod->info->unload) {
610                                 ast_verb(1, "Unloading %s\n", mod->resource);
611                                 mod->info->unload();
612                         }
613                         AST_LIST_HEAD_DESTROY(&mod->users);
614                         ao2_cleanup(mod->ref_debug);
615                         ast_free(mod);
616                         somethingchanged = 1;
617                 }
618                 AST_DLLIST_TRAVERSE_BACKWARDS_SAFE_END;
619                 if (!somethingchanged) {
620                         AST_DLLIST_TRAVERSE(&module_list, mod, entry) {
621                                 if (mod->flags.keepuntilshutdown) {
622                                         ast_module_unref(mod);
623                                         mod->flags.keepuntilshutdown = 0;
624                                         somethingchanged = 1;
625                                 }
626                         }
627                 }
628         } while (somethingchanged && !final);
629
630         final = AST_DLLIST_EMPTY(&module_list);
631         AST_DLLIST_UNLOCK(&module_list);
632
633         return !final;
634 }
635
636 int ast_unload_resource(const char *resource_name, enum ast_module_unload_mode force)
637 {
638         struct ast_module *mod;
639         int res = -1;
640         int error = 0;
641
642         AST_DLLIST_LOCK(&module_list);
643
644         if (!(mod = find_resource(resource_name, 0))) {
645                 AST_DLLIST_UNLOCK(&module_list);
646                 ast_log(LOG_WARNING, "Unload failed, '%s' could not be found\n", resource_name);
647                 return -1;
648         }
649
650         if (!mod->flags.running || mod->flags.declined) {
651                 ast_log(LOG_WARNING, "Unload failed, '%s' is not loaded.\n", resource_name);
652                 error = 1;
653         }
654
655         if (!error && (mod->usecount > 0)) {
656                 if (force)
657                         ast_log(LOG_WARNING, "Warning:  Forcing removal of module '%s' with use count %d\n",
658                                 resource_name, mod->usecount);
659                 else {
660                         ast_log(LOG_WARNING, "Soft unload failed, '%s' has use count %d\n", resource_name,
661                                 mod->usecount);
662                         error = 1;
663                 }
664         }
665
666         if (!error) {
667                 /* Request any channels attached to the module to hangup. */
668                 __ast_module_user_hangup_all(mod);
669
670                 ast_verb(1, "Unloading %s\n", mod->resource);
671                 res = mod->info->unload();
672                 if (res) {
673                         ast_log(LOG_WARNING, "Firm unload failed for %s\n", resource_name);
674                         if (force <= AST_FORCE_FIRM) {
675                                 error = 1;
676                         } else {
677                                 ast_log(LOG_WARNING, "** Dangerous **: Unloading resource anyway, at user request\n");
678                         }
679                 }
680
681                 if (!error) {
682                         /*
683                          * Request hangup on any channels that managed to get attached
684                          * while we called the module unload function.
685                          */
686                         __ast_module_user_hangup_all(mod);
687                         sched_yield();
688                 }
689         }
690
691         if (!error)
692                 mod->flags.running = mod->flags.declined = 0;
693
694         AST_DLLIST_UNLOCK(&module_list);
695
696         if (!error) {
697                 unload_dynamic_module(mod);
698                 ast_test_suite_event_notify("MODULE_UNLOAD", "Message: %s", resource_name);
699                 ast_update_use_count();
700         }
701
702         return res;
703 }
704
705 char *ast_module_helper(const char *line, const char *word, int pos, int state, int rpos, int needsreload)
706 {
707         struct ast_module *cur;
708         int i, which=0, l = strlen(word);
709         char *ret = NULL;
710
711         if (pos != rpos) {
712                 return NULL;
713         }
714
715         AST_DLLIST_LOCK(&module_list);
716         AST_DLLIST_TRAVERSE(&module_list, cur, entry) {
717                 if (!strncasecmp(word, cur->resource, l) &&
718                     (cur->info->reload || !needsreload) &&
719                     ++which > state) {
720                         ret = ast_strdup(cur->resource);
721                         break;
722                 }
723         }
724         AST_DLLIST_UNLOCK(&module_list);
725
726         if (!ret && needsreload) {
727                 for (i=0; !ret && reload_classes[i].name; i++) {
728                         if (!strncasecmp(word, reload_classes[i].name, l) && ++which > state) {
729                                 ret = ast_strdup(reload_classes[i].name);
730                         }
731                 }
732         }
733
734         return ret;
735 }
736
737 void ast_process_pending_reloads(void)
738 {
739         struct reload_queue_item *item;
740
741         modules_loaded = 1;
742
743         AST_LIST_LOCK(&reload_queue);
744
745         if (do_full_reload) {
746                 do_full_reload = 0;
747                 AST_LIST_UNLOCK(&reload_queue);
748                 ast_log(LOG_NOTICE, "Executing deferred reload request.\n");
749                 ast_module_reload(NULL);
750                 return;
751         }
752
753         while ((item = AST_LIST_REMOVE_HEAD(&reload_queue, entry))) {
754                 ast_log(LOG_NOTICE, "Executing deferred reload request for module '%s'.\n", item->module);
755                 ast_module_reload(item->module);
756                 ast_free(item);
757         }
758
759         AST_LIST_UNLOCK(&reload_queue);
760 }
761
762 static void queue_reload_request(const char *module)
763 {
764         struct reload_queue_item *item;
765
766         AST_LIST_LOCK(&reload_queue);
767
768         if (do_full_reload) {
769                 AST_LIST_UNLOCK(&reload_queue);
770                 return;
771         }
772
773         if (ast_strlen_zero(module)) {
774                 /* A full reload request (when module is NULL) wipes out any previous
775                    reload requests and causes the queue to ignore future ones */
776                 while ((item = AST_LIST_REMOVE_HEAD(&reload_queue, entry))) {
777                         ast_free(item);
778                 }
779                 do_full_reload = 1;
780         } else {
781                 /* No reason to add the same module twice */
782                 AST_LIST_TRAVERSE(&reload_queue, item, entry) {
783                         if (!strcasecmp(item->module, module)) {
784                                 AST_LIST_UNLOCK(&reload_queue);
785                                 return;
786                         }
787                 }
788                 item = ast_calloc(1, sizeof(*item) + strlen(module) + 1);
789                 if (!item) {
790                         ast_log(LOG_ERROR, "Failed to allocate reload queue item.\n");
791                         AST_LIST_UNLOCK(&reload_queue);
792                         return;
793                 }
794                 strcpy(item->module, module);
795                 AST_LIST_INSERT_TAIL(&reload_queue, item, entry);
796         }
797         AST_LIST_UNLOCK(&reload_queue);
798 }
799
800 /*!
801  * \since 12
802  * \internal
803  * \brief Publish a \ref stasis message regarding the reload result
804  */
805 static void publish_reload_message(const char *name, enum ast_module_reload_result result)
806 {
807         RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
808         RAII_VAR(struct ast_json_payload *, payload, NULL, ao2_cleanup);
809         RAII_VAR(struct ast_json *, json_object, NULL, ast_json_unref);
810         RAII_VAR(struct ast_json *, event_object, NULL, ast_json_unref);
811         char res_buffer[8];
812
813         if (!ast_manager_get_generic_type()) {
814                 return;
815         }
816
817         snprintf(res_buffer, sizeof(res_buffer), "%u", result);
818         event_object = ast_json_pack("{s: s, s: s}",
819                         "Module", S_OR(name, "All"),
820                         "Status", res_buffer);
821         json_object = ast_json_pack("{s: s, s: i, s: o}",
822                         "type", "Reload",
823                         "class_type", EVENT_FLAG_SYSTEM,
824                         "event", ast_json_ref(event_object));
825
826         if (!json_object) {
827                 return;
828         }
829
830         payload = ast_json_payload_create(json_object);
831         if (!payload) {
832                 return;
833         }
834
835         message = stasis_message_create(ast_manager_get_generic_type(), payload);
836         if (!message) {
837                 return;
838         }
839
840         stasis_publish(ast_manager_get_topic(), message);
841 }
842
843 enum ast_module_reload_result ast_module_reload(const char *name)
844 {
845         struct ast_module *cur;
846         enum ast_module_reload_result res = AST_MODULE_RELOAD_NOT_FOUND;
847         int i;
848
849         /* If we aren't fully booted, we just pretend we reloaded but we queue this
850            up to run once we are booted up. */
851         if (!modules_loaded) {
852                 queue_reload_request(name);
853                 res = AST_MODULE_RELOAD_QUEUED;
854                 goto module_reload_exit;
855         }
856
857         if (ast_mutex_trylock(&reloadlock)) {
858                 ast_verb(3, "The previous reload command didn't finish yet\n");
859                 res = AST_MODULE_RELOAD_IN_PROGRESS;
860                 goto module_reload_exit;
861         }
862         ast_sd_notify("RELOAD=1");
863         ast_lastreloadtime = ast_tvnow();
864
865         if (ast_opt_lock_confdir) {
866                 int try;
867                 int res;
868                 for (try = 1, res = AST_LOCK_TIMEOUT; try < 6 && (res == AST_LOCK_TIMEOUT); try++) {
869                         res = ast_lock_path(ast_config_AST_CONFIG_DIR);
870                         if (res == AST_LOCK_TIMEOUT) {
871                                 ast_log(LOG_WARNING, "Failed to grab lock on %s, try %d\n", ast_config_AST_CONFIG_DIR, try);
872                         }
873                 }
874                 if (res != AST_LOCK_SUCCESS) {
875                         ast_log(AST_LOG_WARNING, "Cannot grab lock on %s\n", ast_config_AST_CONFIG_DIR);
876                         res = AST_MODULE_RELOAD_ERROR;
877                         goto module_reload_done;
878                 }
879         }
880
881         /* Call "predefined" reload here first */
882         for (i = 0; reload_classes[i].name; i++) {
883                 if (!name || !strcasecmp(name, reload_classes[i].name)) {
884                         if (reload_classes[i].reload_fn() == AST_MODULE_LOAD_SUCCESS) {
885                                 res = AST_MODULE_RELOAD_SUCCESS;
886                         }
887                 }
888         }
889
890         if (name && res == AST_MODULE_RELOAD_SUCCESS) {
891                 if (ast_opt_lock_confdir) {
892                         ast_unlock_path(ast_config_AST_CONFIG_DIR);
893                 }
894                 goto module_reload_done;
895         }
896
897         AST_DLLIST_LOCK(&module_list);
898         AST_DLLIST_TRAVERSE(&module_list, cur, entry) {
899                 const struct ast_module_info *info = cur->info;
900
901                 if (name && resource_name_match(name, cur->resource))
902                         continue;
903
904                 if (!cur->flags.running || cur->flags.declined) {
905                         if (res == AST_MODULE_RELOAD_NOT_FOUND) {
906                                 res = AST_MODULE_RELOAD_UNINITIALIZED;
907                         }
908                         if (!name) {
909                                 continue;
910                         }
911                         break;
912                 }
913
914                 if (!info->reload) {    /* cannot be reloaded */
915                         if (res == AST_MODULE_RELOAD_NOT_FOUND) {
916                                 res = AST_MODULE_RELOAD_NOT_IMPLEMENTED;
917                         }
918                         if (!name) {
919                                 continue;
920                         }
921                         break;
922                 }
923                 ast_verb(3, "Reloading module '%s' (%s)\n", cur->resource, info->description);
924                 if (info->reload() == AST_MODULE_LOAD_SUCCESS) {
925                         res = AST_MODULE_RELOAD_SUCCESS;
926                 }
927                 if (name) {
928                         break;
929                 }
930         }
931         AST_DLLIST_UNLOCK(&module_list);
932
933         if (ast_opt_lock_confdir) {
934                 ast_unlock_path(ast_config_AST_CONFIG_DIR);
935         }
936 module_reload_done:
937         ast_mutex_unlock(&reloadlock);
938         ast_sd_notify("READY=1");
939
940 module_reload_exit:
941         publish_reload_message(name, res);
942         return res;
943 }
944
945 static unsigned int inspect_module(const struct ast_module *mod)
946 {
947         if (!mod->info->description) {
948                 ast_log(LOG_WARNING, "Module '%s' does not provide a description.\n", mod->resource);
949                 return 1;
950         }
951
952         if (!mod->info->key) {
953                 ast_log(LOG_WARNING, "Module '%s' does not provide a license key.\n", mod->resource);
954                 return 1;
955         }
956
957         if (verify_key((unsigned char *) mod->info->key)) {
958                 ast_log(LOG_WARNING, "Module '%s' did not provide a valid license key.\n", mod->resource);
959                 return 1;
960         }
961
962         if (!ast_strlen_zero(mod->info->buildopt_sum) &&
963             strcmp(buildopt_sum, mod->info->buildopt_sum)) {
964                 ast_log(LOG_WARNING, "Module '%s' was not compiled with the same compile-time options as this version of Asterisk.\n", mod->resource);
965                 ast_log(LOG_WARNING, "Module '%s' will not be initialized as it may cause instability.\n", mod->resource);
966                 return 1;
967         }
968
969         return 0;
970 }
971
972 static enum ast_module_load_result start_resource(struct ast_module *mod)
973 {
974         char tmp[256];
975         enum ast_module_load_result res;
976
977         if (mod->flags.running) {
978                 return AST_MODULE_LOAD_SUCCESS;
979         }
980
981         if (!mod->info->load) {
982                 return AST_MODULE_LOAD_FAILURE;
983         }
984
985         if (!ast_fully_booted) {
986                 ast_verb(1, "Loading %s.\n", mod->resource);
987         }
988         res = mod->info->load();
989
990         switch (res) {
991         case AST_MODULE_LOAD_SUCCESS:
992                 if (!ast_fully_booted) {
993                         ast_verb(2, "%s => (%s)\n", mod->resource, term_color(tmp, mod->info->description, COLOR_BROWN, COLOR_BLACK, sizeof(tmp)));
994                 } else {
995                         ast_verb(1, "Loaded %s => (%s)\n", mod->resource, mod->info->description);
996                 }
997
998                 mod->flags.running = 1;
999
1000                 ast_update_use_count();
1001                 break;
1002         case AST_MODULE_LOAD_DECLINE:
1003                 mod->flags.declined = 1;
1004                 break;
1005         case AST_MODULE_LOAD_FAILURE:
1006         case AST_MODULE_LOAD_SKIP: /* modules should never return this value */
1007         case AST_MODULE_LOAD_PRIORITY:
1008                 break;
1009         }
1010
1011         /* Make sure the newly started module is at the end of the list */
1012         AST_DLLIST_LOCK(&module_list);
1013         AST_DLLIST_REMOVE(&module_list, mod, entry);
1014         AST_DLLIST_INSERT_TAIL(&module_list, mod, entry);
1015         AST_DLLIST_UNLOCK(&module_list);
1016
1017         return res;
1018 }
1019
1020 /*! loads a resource based upon resource_name. If global_symbols_only is set
1021  *  only modules with global symbols will be loaded.
1022  *
1023  *  If the ast_heap is provided (not NULL) the module is found and added to the
1024  *  heap without running the module's load() function.  By doing this, modules
1025  *  added to the resource_heap can be initialized later in order by priority.
1026  *
1027  *  If the ast_heap is not provided, the module's load function will be executed
1028  *  immediately */
1029 static enum ast_module_load_result load_resource(const char *resource_name, unsigned int global_symbols_only, unsigned int suppress_logging, struct ast_heap *resource_heap, int required)
1030 {
1031         struct ast_module *mod;
1032         enum ast_module_load_result res = AST_MODULE_LOAD_SUCCESS;
1033
1034         if ((mod = find_resource(resource_name, 0))) {
1035                 if (mod->flags.running) {
1036                         ast_log(LOG_WARNING, "Module '%s' already exists.\n", resource_name);
1037                         return AST_MODULE_LOAD_DECLINE;
1038                 }
1039                 if (global_symbols_only && !ast_test_flag(mod->info, AST_MODFLAG_GLOBAL_SYMBOLS))
1040                         return AST_MODULE_LOAD_SKIP;
1041         } else {
1042                 mod = load_dynamic_module(resource_name, global_symbols_only, suppress_logging, resource_heap);
1043                 if (mod == MODULE_LOCAL_ONLY) {
1044                                 return AST_MODULE_LOAD_SKIP;
1045                 }
1046                 if (!mod) {
1047                         if (!global_symbols_only) {
1048                                 ast_log(LOG_WARNING, "Module '%s' could not be loaded.\n", resource_name);
1049                         }
1050                         return required ? AST_MODULE_LOAD_FAILURE : AST_MODULE_LOAD_DECLINE;
1051                 }
1052         }
1053
1054         if (inspect_module(mod)) {
1055                 ast_log(LOG_WARNING, "Module '%s' could not be loaded.\n", resource_name);
1056                 unload_dynamic_module(mod);
1057                 return required ? AST_MODULE_LOAD_FAILURE : AST_MODULE_LOAD_DECLINE;
1058         }
1059
1060         mod->flags.declined = 0;
1061
1062         if (resource_heap) {
1063                 ast_heap_push(resource_heap, mod);
1064                 res = AST_MODULE_LOAD_PRIORITY;
1065         } else {
1066                 res = start_resource(mod);
1067         }
1068
1069         return res;
1070 }
1071
1072 int ast_load_resource(const char *resource_name)
1073 {
1074         int res;
1075         AST_DLLIST_LOCK(&module_list);
1076         res = load_resource(resource_name, 0, 0, NULL, 0);
1077         if (!res) {
1078                 ast_test_suite_event_notify("MODULE_LOAD", "Message: %s", resource_name);
1079         }
1080         AST_DLLIST_UNLOCK(&module_list);
1081
1082         return res;
1083 }
1084
1085 struct load_order_entry {
1086         char *resource;
1087         int required;
1088         AST_LIST_ENTRY(load_order_entry) entry;
1089 };
1090
1091 AST_LIST_HEAD_NOLOCK(load_order, load_order_entry);
1092
1093 static struct load_order_entry *add_to_load_order(const char *resource, struct load_order *load_order, int required)
1094 {
1095         struct load_order_entry *order;
1096
1097         AST_LIST_TRAVERSE(load_order, order, entry) {
1098                 if (!resource_name_match(order->resource, resource)) {
1099                         /* Make sure we have the proper setting for the required field
1100                            (we might have both load= and required= lines in modules.conf) */
1101                         order->required |= required;
1102                         return NULL;
1103                 }
1104         }
1105
1106         if (!(order = ast_calloc(1, sizeof(*order))))
1107                 return NULL;
1108
1109         order->resource = ast_strdup(resource);
1110         order->required = required;
1111         AST_LIST_INSERT_TAIL(load_order, order, entry);
1112
1113         return order;
1114 }
1115
1116 static int mod_load_cmp(void *a, void *b)
1117 {
1118         struct ast_module *a_mod = (struct ast_module *) a;
1119         struct ast_module *b_mod = (struct ast_module *) b;
1120         /* if load_pri is not set, default is 128.  Lower is better */
1121         int a_pri = ast_test_flag(a_mod->info, AST_MODFLAG_LOAD_ORDER) ? a_mod->info->load_pri : 128;
1122         int b_pri = ast_test_flag(b_mod->info, AST_MODFLAG_LOAD_ORDER) ? b_mod->info->load_pri : 128;
1123
1124         /*
1125          * Returns comparison values for a min-heap
1126          * <0 a_pri > b_pri
1127          * =0 a_pri == b_pri
1128          * >0 a_pri < b_pri
1129          */
1130         return b_pri - a_pri;
1131 }
1132
1133 AST_LIST_HEAD_NOLOCK(load_retries, load_order_entry);
1134
1135 /*! loads modules in order by load_pri, updates mod_count
1136         \return -1 on failure to load module, -2 on failure to load required module, otherwise 0
1137 */
1138 static int load_resource_list(struct load_order *load_order, unsigned int global_symbols, int *mod_count)
1139 {
1140         struct ast_heap *resource_heap;
1141         struct load_order_entry *order;
1142         struct ast_module *mod;
1143         struct load_retries load_retries;
1144         int count = 0;
1145         int res = 0;
1146         int i = 0;
1147 #define LOAD_RETRIES 4
1148
1149         AST_LIST_HEAD_INIT_NOLOCK(&load_retries);
1150
1151         if(!(resource_heap = ast_heap_create(8, mod_load_cmp, -1))) {
1152                 return -1;
1153         }
1154
1155         /* first, add find and add modules to heap */
1156         AST_LIST_TRAVERSE_SAFE_BEGIN(load_order, order, entry) {
1157                 enum ast_module_load_result lres;
1158
1159                 /* Suppress log messages unless this is the last pass */
1160                 lres = load_resource(order->resource, global_symbols, 1, resource_heap, order->required);
1161                 ast_debug(3, "PASS 0: %-46s %d %d\n", order->resource, lres, global_symbols);
1162                 switch (lres) {
1163                 case AST_MODULE_LOAD_SUCCESS:
1164                         /* We're supplying a heap so SUCCESS isn't possible but we still have to test for it. */
1165                         break;
1166                 case AST_MODULE_LOAD_FAILURE:
1167                 case AST_MODULE_LOAD_DECLINE:
1168                         /*
1169                          * DECLINE or FAILURE means there was an issue with dlopen or module_register
1170                          * which might be retryable.  LOAD_FAILURE only happens for required modules
1171                          * but we're still going to retry.  We need to remove the entry from the
1172                          * load_order list and add it to the load_retries list.
1173                          */
1174                         AST_LIST_REMOVE_CURRENT(entry);
1175                         AST_LIST_INSERT_TAIL(&load_retries, order, entry);
1176                         break;
1177                 case AST_MODULE_LOAD_SKIP:
1178                         /*
1179                          * SKIP means that dlopen worked but global_symbols was set and this module doesn't qualify.
1180                          * Leave it in load_order for the next call of load_resource_list.
1181                          */
1182                         break;
1183                 case AST_MODULE_LOAD_PRIORITY:
1184                         /* load_resource worked and the module was added to the priority heap */
1185                         AST_LIST_REMOVE_CURRENT(entry);
1186                         ast_free(order->resource);
1187                         ast_free(order);
1188                         break;
1189                 }
1190         }
1191         AST_LIST_TRAVERSE_SAFE_END;
1192
1193         /* Retry the failures until the list is empty or we reach LOAD_RETRIES */
1194         for (i = 0; !AST_LIST_EMPTY(&load_retries) && i < LOAD_RETRIES; i++) {
1195                 AST_LIST_TRAVERSE_SAFE_BEGIN(&load_retries, order, entry) {
1196                         enum ast_module_load_result lres;
1197
1198                         /* Suppress log messages unless this is the last pass */
1199                         lres = load_resource(order->resource, global_symbols, (i < LOAD_RETRIES - 1), resource_heap, order->required);
1200                         ast_debug(3, "PASS %d %-46s %d %d\n", i + 1, order->resource, lres, global_symbols);
1201                         switch (lres) {
1202                         /* These are all retryable. */
1203                         case AST_MODULE_LOAD_SUCCESS:
1204                         case AST_MODULE_LOAD_DECLINE:
1205                                 break;
1206                         case AST_MODULE_LOAD_FAILURE:
1207                                 /* LOAD_FAILURE only happens for required modules */
1208                                 if (i == LOAD_RETRIES - 1) {
1209                                         /* This was the last chance to load a required module*/
1210                                         ast_log(LOG_ERROR, "*** Failed to load module %s - Required\n", order->resource);
1211                                         fprintf(stderr, "*** Failed to load module %s - Required\n", order->resource);
1212                                         res =  -2;
1213                                         goto done;
1214                                 }
1215                                 break;;
1216                         case AST_MODULE_LOAD_SKIP:
1217                                 /*
1218                                  * SKIP means that dlopen worked but global_symbols was set and this module
1219                                  * doesn't qualify.  Put it back in load_order for the next call of
1220                                  * load_resource_list.
1221                                  */
1222                                 AST_LIST_REMOVE_CURRENT(entry);
1223                                 AST_LIST_INSERT_TAIL(load_order, order, entry);
1224                                 break;
1225                         case AST_MODULE_LOAD_PRIORITY:
1226                                 /* load_resource worked and the module was added to the priority heap */
1227                                 AST_LIST_REMOVE_CURRENT(entry);
1228                                 ast_free(order->resource);
1229                                 ast_free(order);
1230                                 break;
1231                         }
1232                 }
1233                 AST_LIST_TRAVERSE_SAFE_END;
1234         }
1235
1236         /* second remove modules from heap sorted by priority */
1237         while ((mod = ast_heap_pop(resource_heap))) {
1238                 enum ast_module_load_result lres;
1239
1240                 lres = start_resource(mod);
1241                 ast_debug(3, "START: %-46s %d %d\n", mod->resource, lres, global_symbols);
1242                 switch (lres) {
1243                 case AST_MODULE_LOAD_SUCCESS:
1244                         count++;
1245                 case AST_MODULE_LOAD_DECLINE:
1246                         break;
1247                 case AST_MODULE_LOAD_FAILURE:
1248                         ast_log(LOG_ERROR, "*** Failed to load module %s\n", mod->resource);
1249                         res = -1;
1250                         goto done;
1251                 case AST_MODULE_LOAD_SKIP:
1252                 case AST_MODULE_LOAD_PRIORITY:
1253                         break;
1254                 }
1255         }
1256
1257 done:
1258
1259         while ((order = AST_LIST_REMOVE_HEAD(&load_retries, entry))) {
1260                 ast_free(order->resource);
1261                 ast_free(order);
1262         }
1263
1264         if (mod_count) {
1265                 *mod_count += count;
1266         }
1267         ast_heap_destroy(resource_heap);
1268
1269         return res;
1270 }
1271
1272 int load_modules(unsigned int preload_only)
1273 {
1274         struct ast_config *cfg;
1275         struct load_order_entry *order;
1276         struct ast_variable *v;
1277         unsigned int load_count;
1278         struct load_order load_order;
1279         int res = 0;
1280         struct ast_flags config_flags = { 0 };
1281         int modulecount = 0;
1282         struct dirent *dirent;
1283         DIR *dir;
1284
1285         ast_verb(1, "Asterisk Dynamic Loader Starting:\n");
1286
1287         AST_LIST_HEAD_INIT_NOLOCK(&load_order);
1288
1289         AST_DLLIST_LOCK(&module_list);
1290
1291         cfg = ast_config_load2(AST_MODULE_CONFIG, "" /* core, can't reload */, config_flags);
1292         if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEINVALID) {
1293                 ast_log(LOG_WARNING, "No '%s' found, no modules will be loaded.\n", AST_MODULE_CONFIG);
1294                 goto done;
1295         }
1296
1297         /* first, find all the modules we have been explicitly requested to load */
1298         for (v = ast_variable_browse(cfg, "modules"); v; v = v->next) {
1299                 if (!strcasecmp(v->name, preload_only ? "preload" : "load")) {
1300                         add_to_load_order(v->value, &load_order, 0);
1301                 }
1302                 if (!strcasecmp(v->name, preload_only ? "preload-require" : "require")) {
1303                         /* Add the module to the list and make sure it's required */
1304                         add_to_load_order(v->value, &load_order, 1);
1305                         ast_debug(2, "Adding module to required list: %s (%s)\n", v->value, v->name);
1306                 }
1307
1308         }
1309
1310         /* check if 'autoload' is on */
1311         if (!preload_only && ast_true(ast_variable_retrieve(cfg, "modules", "autoload"))) {
1312                 /* if we are allowed to load dynamic modules, scan the directory for
1313                    for all available modules and add them as well */
1314                 if ((dir = opendir(ast_config_AST_MODULE_DIR))) {
1315                         while ((dirent = readdir(dir))) {
1316                                 int ld = strlen(dirent->d_name);
1317
1318                                 /* Must end in .so to load it.  */
1319
1320                                 if (ld < 4)
1321                                         continue;
1322
1323                                 if (strcasecmp(dirent->d_name + ld - 3, ".so"))
1324                                         continue;
1325
1326                                 /* if there is already a module by this name in the module_list,
1327                                    skip this file */
1328                                 if (find_resource(dirent->d_name, 0))
1329                                         continue;
1330
1331                                 add_to_load_order(dirent->d_name, &load_order, 0);
1332                         }
1333
1334                         closedir(dir);
1335                 } else {
1336                         if (!ast_opt_quiet)
1337                                 ast_log(LOG_WARNING, "Unable to open modules directory '%s'.\n",
1338                                         ast_config_AST_MODULE_DIR);
1339                 }
1340         }
1341
1342         /* now scan the config for any modules we are prohibited from loading and
1343            remove them from the load order */
1344         for (v = ast_variable_browse(cfg, "modules"); v; v = v->next) {
1345                 if (strcasecmp(v->name, "noload"))
1346                         continue;
1347
1348                 AST_LIST_TRAVERSE_SAFE_BEGIN(&load_order, order, entry) {
1349                         if (!resource_name_match(order->resource, v->value)) {
1350                                 AST_LIST_REMOVE_CURRENT(entry);
1351                                 ast_free(order->resource);
1352                                 ast_free(order);
1353                         }
1354                 }
1355                 AST_LIST_TRAVERSE_SAFE_END;
1356         }
1357
1358         /* we are done with the config now, all the information we need is in the
1359            load_order list */
1360         ast_config_destroy(cfg);
1361
1362         load_count = 0;
1363         AST_LIST_TRAVERSE(&load_order, order, entry)
1364                 load_count++;
1365
1366         if (load_count)
1367                 ast_log(LOG_NOTICE, "%u modules will be loaded.\n", load_count);
1368
1369         /* first, load only modules that provide global symbols */
1370         if ((res = load_resource_list(&load_order, 1, &modulecount)) < 0) {
1371                 goto done;
1372         }
1373
1374         /* now load everything else */
1375         if ((res = load_resource_list(&load_order, 0, &modulecount)) < 0) {
1376                 goto done;
1377         }
1378
1379 done:
1380         while ((order = AST_LIST_REMOVE_HEAD(&load_order, entry))) {
1381                 ast_free(order->resource);
1382                 ast_free(order);
1383         }
1384
1385         AST_DLLIST_UNLOCK(&module_list);
1386         return res;
1387 }
1388
1389 void ast_update_use_count(void)
1390 {
1391         /* Notify any module monitors that the use count for a
1392            resource has changed */
1393         struct loadupdate *m;
1394
1395         AST_LIST_LOCK(&updaters);
1396         AST_LIST_TRAVERSE(&updaters, m, entry)
1397                 m->updater();
1398         AST_LIST_UNLOCK(&updaters);
1399 }
1400
1401 int ast_update_module_list(int (*modentry)(const char *module, const char *description,
1402                                            int usecnt, const char *status, const char *like,
1403                                                                                    enum ast_module_support_level support_level),
1404                            const char *like)
1405 {
1406         struct ast_module *cur;
1407         int unlock = -1;
1408         int total_mod_loaded = 0;
1409         AST_LIST_HEAD_NOLOCK(, ast_module) alpha_module_list = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
1410
1411         if (AST_DLLIST_TRYLOCK(&module_list)) {
1412                 unlock = 0;
1413         }
1414
1415         AST_DLLIST_TRAVERSE(&module_list, cur, entry) {
1416                 AST_LIST_INSERT_SORTALPHA(&alpha_module_list, cur, list_entry, resource);
1417         }
1418
1419         while ((cur = AST_LIST_REMOVE_HEAD(&alpha_module_list, list_entry))) {
1420                 total_mod_loaded += modentry(cur->resource, cur->info->description, cur->usecount,
1421                                                 cur->flags.running ? "Running" : "Not Running", like, cur->info->support_level);
1422         }
1423
1424         if (unlock) {
1425                 AST_DLLIST_UNLOCK(&module_list);
1426         }
1427
1428         return total_mod_loaded;
1429 }
1430
1431 int ast_update_module_list_data(int (*modentry)(const char *module, const char *description,
1432                                                 int usecnt, const char *status, const char *like,
1433                                                 enum ast_module_support_level support_level,
1434                                                 void *data),
1435                                 const char *like, void *data)
1436 {
1437         struct ast_module *cur;
1438         int total_mod_loaded = 0;
1439         AST_LIST_HEAD_NOLOCK(, ast_module) alpha_module_list = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
1440
1441         AST_DLLIST_LOCK(&module_list);
1442
1443         AST_DLLIST_TRAVERSE(&module_list, cur, entry) {
1444                 AST_LIST_INSERT_SORTALPHA(&alpha_module_list, cur, list_entry, resource);
1445         }
1446
1447         while ((cur = AST_LIST_REMOVE_HEAD(&alpha_module_list, list_entry))) {
1448                 total_mod_loaded += modentry(cur->resource, cur->info->description, cur->usecount,
1449                         cur->flags.running? "Running" : "Not Running", like, cur->info->support_level, data);
1450         }
1451
1452         AST_DLLIST_UNLOCK(&module_list);
1453
1454         return total_mod_loaded;
1455 }
1456
1457 int ast_update_module_list_condition(int (*modentry)(const char *module, const char *description,
1458                                                      int usecnt, const char *status,
1459                                                      const char *like,
1460                                                      enum ast_module_support_level support_level,
1461                                                      void *data, const char *condition),
1462                                      const char *like, void *data, const char *condition)
1463 {
1464         struct ast_module *cur;
1465         int conditions_met = 0;
1466         AST_LIST_HEAD_NOLOCK(, ast_module) alpha_module_list = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
1467
1468         AST_DLLIST_LOCK(&module_list);
1469
1470         AST_DLLIST_TRAVERSE(&module_list, cur, entry) {
1471                 AST_LIST_INSERT_SORTALPHA(&alpha_module_list, cur, list_entry, resource);
1472         }
1473
1474         while ((cur = AST_LIST_REMOVE_HEAD(&alpha_module_list, list_entry))) {
1475                 conditions_met += modentry(cur->resource, cur->info->description, cur->usecount,
1476                         cur->flags.running? "Running" : "Not Running", like, cur->info->support_level, data,
1477                         condition);
1478         }
1479
1480         AST_DLLIST_UNLOCK(&module_list);
1481
1482         return conditions_met;
1483 }
1484
1485 /*! \brief Check if module exists */
1486 int ast_module_check(const char *name)
1487 {
1488         struct ast_module *cur;
1489
1490         if (ast_strlen_zero(name))
1491                 return 0;       /* FALSE */
1492
1493         cur = find_resource(name, 1);
1494
1495         return (cur != NULL);
1496 }
1497
1498
1499 int ast_loader_register(int (*v)(void))
1500 {
1501         struct loadupdate *tmp;
1502
1503         if (!(tmp = ast_malloc(sizeof(*tmp))))
1504                 return -1;
1505
1506         tmp->updater = v;
1507         AST_LIST_LOCK(&updaters);
1508         AST_LIST_INSERT_HEAD(&updaters, tmp, entry);
1509         AST_LIST_UNLOCK(&updaters);
1510
1511         return 0;
1512 }
1513
1514 int ast_loader_unregister(int (*v)(void))
1515 {
1516         struct loadupdate *cur;
1517
1518         AST_LIST_LOCK(&updaters);
1519         AST_LIST_TRAVERSE_SAFE_BEGIN(&updaters, cur, entry) {
1520                 if (cur->updater == v)  {
1521                         AST_LIST_REMOVE_CURRENT(entry);
1522                         break;
1523                 }
1524         }
1525         AST_LIST_TRAVERSE_SAFE_END;
1526         AST_LIST_UNLOCK(&updaters);
1527
1528         return cur ? 0 : -1;
1529 }
1530
1531 struct ast_module *__ast_module_ref(struct ast_module *mod, const char *file, int line, const char *func)
1532 {
1533         if (!mod) {
1534                 return NULL;
1535         }
1536
1537         if (mod->ref_debug) {
1538                 __ao2_ref(mod->ref_debug, +1, "", file, line, func);
1539         }
1540
1541         ast_atomic_fetchadd_int(&mod->usecount, +1);
1542         ast_update_use_count();
1543
1544         return mod;
1545 }
1546
1547 void __ast_module_shutdown_ref(struct ast_module *mod, const char *file, int line, const char *func)
1548 {
1549         if (!mod || mod->flags.keepuntilshutdown) {
1550                 return;
1551         }
1552
1553         __ast_module_ref(mod, file, line, func);
1554         mod->flags.keepuntilshutdown = 1;
1555 }
1556
1557 void __ast_module_unref(struct ast_module *mod, const char *file, int line, const char *func)
1558 {
1559         if (!mod) {
1560                 return;
1561         }
1562
1563         if (mod->ref_debug) {
1564                 __ao2_ref(mod->ref_debug, -1, "", file, line, func);
1565         }
1566
1567         ast_atomic_fetchadd_int(&mod->usecount, -1);
1568         ast_update_use_count();
1569 }
1570
1571 const char *support_level_map [] = {
1572         [AST_MODULE_SUPPORT_UNKNOWN] = "unknown",
1573         [AST_MODULE_SUPPORT_CORE] = "core",
1574         [AST_MODULE_SUPPORT_EXTENDED] = "extended",
1575         [AST_MODULE_SUPPORT_DEPRECATED] = "deprecated",
1576 };
1577
1578 const char *ast_module_support_level_to_string(enum ast_module_support_level support_level)
1579 {
1580         return support_level_map[support_level];
1581 }