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