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