ARI: Add ability to raise arbitrary User Events
[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", (unsigned)*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         char *error;
416
417         if (!lib) {
418                 return;
419         }
420
421         /* Clear any existing error */
422         dlerror();
423         if (dlclose(lib)) {
424                 error = dlerror();
425                 ast_log(AST_LOG_ERROR, "Failure in dlclose for module '%s': %s\n",
426                         S_OR(name, "unknown"), S_OR(error, "Unknown error"));
427         }
428 }
429
430 #if defined(HAVE_RTLD_NOLOAD)
431 /*!
432  * \brief Check to see if the given resource is loaded.
433  *
434  * \param resource_name Name of the resource, including .so suffix.
435  * \return False (0) if module is not loaded.
436  * \return True (non-zero) if module is loaded.
437  */
438 static int is_module_loaded(const char *resource_name)
439 {
440         char fn[PATH_MAX] = "";
441         void *lib;
442
443         ast_verb(10, "Checking if %s is loaded\n", resource_name);
444
445         snprintf(fn, sizeof(fn), "%s/%s", ast_config_AST_MODULE_DIR,
446                 resource_name);
447
448         lib = dlopen(fn, RTLD_LAZY | RTLD_NOLOAD);
449
450         if (lib) {
451                 ast_verb(10, "  %s loaded\n", resource_name);
452                 logged_dlclose(resource_name, lib);
453                 return 1;
454         }
455
456         ast_verb(10, "  %s not loaded\n", resource_name);
457         return 0;
458 }
459 #endif
460
461 static void unload_dynamic_module(struct ast_module *mod)
462 {
463         char *name = ast_strdupa(ast_module_name(mod));
464         void *lib = mod->lib;
465
466         /* WARNING: the structure pointed to by mod is going to
467            disappear when this operation succeeds, so we can't
468            dereference it */
469         logged_dlclose(ast_module_name(mod), lib);
470
471         /* There are several situations where the module might still be resident
472          * in memory.
473          *
474          * If somehow there was another dlopen() on the same module (unlikely,
475          * since that all is supposed to happen in loader.c).
476          *
477          * Or the lazy resolution of a global symbol (very likely, since that is
478          * how we load all of our modules that export global symbols).
479          *
480          * Avoid the temptation of repeating the dlclose(). The other code that
481          * dlopened the module still has its module reference, and should close
482          * it itself. In other situations, dlclose() will happily return success
483          * for as many times as you wish to call it.
484          */
485 #if defined(HAVE_RTLD_NOLOAD)
486         if (is_module_loaded(name)) {
487                 ast_log(LOG_WARNING, "Module '%s' could not be completely unloaded\n", name);
488         }
489 #endif
490 }
491
492 static enum ast_module_load_result load_resource(const char *resource_name, unsigned int global_symbols_only, struct ast_heap *resource_heap, int required);
493
494 static struct ast_module *load_dynamic_module(const char *resource_in, unsigned int global_symbols_only, struct ast_heap *resource_heap)
495 {
496         char fn[PATH_MAX] = "";
497         void *lib = NULL;
498         struct ast_module *mod;
499         unsigned int wants_global;
500         int space;      /* room needed for the descriptor */
501         int missing_so = 0;
502
503         space = sizeof(*resource_being_loaded) + strlen(resource_in) + 1;
504         if (strcasecmp(resource_in + strlen(resource_in) - 3, ".so")) {
505                 missing_so = 1;
506                 space += 3;     /* room for the extra ".so" */
507         }
508
509         snprintf(fn, sizeof(fn), "%s/%s%s", ast_config_AST_MODULE_DIR, resource_in, missing_so ? ".so" : "");
510
511         /* make a first load of the module in 'quiet' mode... don't try to resolve
512            any symbols, and don't export any symbols. this will allow us to peek into
513            the module's info block (if available) to see what flags it has set */
514
515         resource_being_loaded = ast_calloc(1, space);
516         if (!resource_being_loaded)
517                 return NULL;
518         strcpy(resource_being_loaded->resource, resource_in);
519         if (missing_so)
520                 strcat(resource_being_loaded->resource, ".so");
521
522         if (!(lib = dlopen(fn, RTLD_LAZY | RTLD_LOCAL))) {
523                 ast_log(LOG_WARNING, "Error loading module '%s': %s\n", resource_in, dlerror());
524                 ast_free(resource_being_loaded);
525                 return NULL;
526         }
527
528         /* the dlopen() succeeded, let's find out if the module
529            registered itself */
530         /* note that this will only work properly as long as
531            ast_module_register() (which is called by the module's
532            constructor) places the new module at the tail of the
533            module_list
534         */
535         if (resource_being_loaded != (mod = AST_LIST_LAST(&module_list))) {
536                 ast_log(LOG_WARNING, "Module '%s' did not register itself during load\n", resource_in);
537                 /* no, it did not, so close it and return */
538                 logged_dlclose(resource_in, lib);
539                 /* note that the module's destructor will call ast_module_unregister(),
540                    which will free the structure we allocated in resource_being_loaded */
541                 return NULL;
542         }
543
544         wants_global = ast_test_flag(mod->info, AST_MODFLAG_GLOBAL_SYMBOLS);
545
546         /* if we are being asked only to load modules that provide global symbols,
547            and this one does not, then close it and return */
548         if (global_symbols_only && !wants_global) {
549                 logged_dlclose(resource_in, lib);
550                 return NULL;
551         }
552
553         logged_dlclose(resource_in, lib);
554         resource_being_loaded = NULL;
555
556         /* start the load process again */
557         resource_being_loaded = ast_calloc(1, space);
558         if (!resource_being_loaded)
559                 return NULL;
560         strcpy(resource_being_loaded->resource, resource_in);
561         if (missing_so)
562                 strcat(resource_being_loaded->resource, ".so");
563
564         if (!(lib = dlopen(fn, wants_global ? RTLD_LAZY | RTLD_GLOBAL : RTLD_NOW | RTLD_LOCAL))) {
565                 ast_log(LOG_WARNING, "Error loading module '%s': %s\n", resource_in, dlerror());
566                 ast_free(resource_being_loaded);
567                 return NULL;
568         }
569
570         /* since the module was successfully opened, and it registered itself
571            the previous time we did that, we're going to assume it worked this
572            time too :) */
573
574         AST_LIST_LAST(&module_list)->lib = lib;
575         resource_being_loaded = NULL;
576
577         return AST_LIST_LAST(&module_list);
578 }
579
580 #endif
581
582 void ast_module_shutdown(void)
583 {
584         struct ast_module *mod;
585         int somethingchanged = 1, final = 0;
586
587         AST_LIST_LOCK(&module_list);
588
589         /*!\note Some resources, like timers, are started up dynamically, and thus
590          * may be still in use, even if all channels are dead.  We must therefore
591          * check the usecount before asking modules to unload. */
592         do {
593                 if (!somethingchanged) {
594                         /*!\note If we go through the entire list without changing
595                          * anything, ignore the usecounts and unload, then exit. */
596                         final = 1;
597                 }
598
599                 /* Reset flag before traversing the list */
600                 somethingchanged = 0;
601
602                 AST_LIST_TRAVERSE_SAFE_BEGIN(&module_list, mod, entry) {
603                         if (!final && mod->usecount) {
604                                 continue;
605                         }
606                         AST_LIST_REMOVE_CURRENT(entry);
607                         if (mod->flags.running && !mod->flags.declined && mod->info->unload) {
608                                 ast_verb(1, "Unloading %s\n", mod->resource);
609                                 mod->info->unload();
610                         }
611                         AST_LIST_HEAD_DESTROY(&mod->users);
612                         free(mod);
613                         somethingchanged = 1;
614                 }
615                 AST_LIST_TRAVERSE_SAFE_END;
616         } while (somethingchanged && !final);
617
618         AST_LIST_UNLOCK(&module_list);
619 }
620
621 int ast_unload_resource(const char *resource_name, enum ast_module_unload_mode force)
622 {
623         struct ast_module *mod;
624         int res = -1;
625         int error = 0;
626
627         AST_LIST_LOCK(&module_list);
628
629         if (!(mod = find_resource(resource_name, 0))) {
630                 AST_LIST_UNLOCK(&module_list);
631                 ast_log(LOG_WARNING, "Unload failed, '%s' could not be found\n", resource_name);
632                 return -1;
633         }
634
635         if (!mod->flags.running || mod->flags.declined) {
636                 ast_log(LOG_WARNING, "Unload failed, '%s' is not loaded.\n", resource_name);
637                 error = 1;
638         }
639
640         if (!error && (mod->usecount > 0)) {
641                 if (force)
642                         ast_log(LOG_WARNING, "Warning:  Forcing removal of module '%s' with use count %d\n",
643                                 resource_name, mod->usecount);
644                 else {
645                         ast_log(LOG_WARNING, "Soft unload failed, '%s' has use count %d\n", resource_name,
646                                 mod->usecount);
647                         error = 1;
648                 }
649         }
650
651         if (!error) {
652                 /* Request any channels attached to the module to hangup. */
653                 __ast_module_user_hangup_all(mod);
654
655                 ast_verb(1, "Unloading %s\n", mod->resource);
656                 res = mod->info->unload();
657                 if (res) {
658                         ast_log(LOG_WARNING, "Firm unload failed for %s\n", resource_name);
659                         if (force <= AST_FORCE_FIRM) {
660                                 error = 1;
661                         } else {
662                                 ast_log(LOG_WARNING, "** Dangerous **: Unloading resource anyway, at user request\n");
663                         }
664                 }
665
666                 if (!error) {
667                         /*
668                          * Request hangup on any channels that managed to get attached
669                          * while we called the module unload function.
670                          */
671                         __ast_module_user_hangup_all(mod);
672                         sched_yield();
673                 }
674         }
675
676         if (!error)
677                 mod->flags.running = mod->flags.declined = 0;
678
679         AST_LIST_UNLOCK(&module_list);
680
681         if (!error && !mod->lib && mod->info && mod->info->restore_globals)
682                 mod->info->restore_globals();
683
684 #ifdef LOADABLE_MODULES
685         if (!error) {
686                 unload_dynamic_module(mod);
687                 ast_test_suite_event_notify("MODULE_UNLOAD", "Message: %s", resource_name);
688         }
689 #endif
690
691         if (!error)
692                 ast_update_use_count();
693
694         return res;
695 }
696
697 char *ast_module_helper(const char *line, const char *word, int pos, int state, int rpos, int needsreload)
698 {
699         struct ast_module *cur;
700         int i, which=0, l = strlen(word);
701         char *ret = NULL;
702
703         if (pos != rpos)
704                 return NULL;
705
706         AST_LIST_LOCK(&module_list);
707         AST_LIST_TRAVERSE(&module_list, cur, entry) {
708                 if (!strncasecmp(word, cur->resource, l) &&
709                     (cur->info->reload || !needsreload) &&
710                     ++which > state) {
711                         ret = ast_strdup(cur->resource);
712                         break;
713                 }
714         }
715         AST_LIST_UNLOCK(&module_list);
716
717         if (!ret) {
718                 for (i=0; !ret && reload_classes[i].name; i++) {
719                         if (!strncasecmp(word, reload_classes[i].name, l) && ++which > state)
720                                 ret = ast_strdup(reload_classes[i].name);
721                 }
722         }
723
724         return ret;
725 }
726
727 void ast_process_pending_reloads(void)
728 {
729         struct reload_queue_item *item;
730
731         if (!ast_fully_booted) {
732                 return;
733         }
734
735         AST_LIST_LOCK(&reload_queue);
736
737         if (do_full_reload) {
738                 do_full_reload = 0;
739                 AST_LIST_UNLOCK(&reload_queue);
740                 ast_log(LOG_NOTICE, "Executing deferred reload request.\n");
741                 ast_module_reload(NULL);
742                 return;
743         }
744
745         while ((item = AST_LIST_REMOVE_HEAD(&reload_queue, entry))) {
746                 ast_log(LOG_NOTICE, "Executing deferred reload request for module '%s'.\n", item->module);
747                 ast_module_reload(item->module);
748                 ast_free(item);
749         }
750
751         AST_LIST_UNLOCK(&reload_queue);
752 }
753
754 static void queue_reload_request(const char *module)
755 {
756         struct reload_queue_item *item;
757
758         AST_LIST_LOCK(&reload_queue);
759
760         if (do_full_reload) {
761                 AST_LIST_UNLOCK(&reload_queue);
762                 return;
763         }
764
765         if (ast_strlen_zero(module)) {
766                 /* A full reload request (when module is NULL) wipes out any previous
767                    reload requests and causes the queue to ignore future ones */
768                 while ((item = AST_LIST_REMOVE_HEAD(&reload_queue, entry))) {
769                         ast_free(item);
770                 }
771                 do_full_reload = 1;
772         } else {
773                 /* No reason to add the same module twice */
774                 AST_LIST_TRAVERSE(&reload_queue, item, entry) {
775                         if (!strcasecmp(item->module, module)) {
776                                 AST_LIST_UNLOCK(&reload_queue);
777                                 return;
778                         }
779                 }
780                 item = ast_calloc(1, sizeof(*item) + strlen(module) + 1);
781                 if (!item) {
782                         ast_log(LOG_ERROR, "Failed to allocate reload queue item.\n");
783                         AST_LIST_UNLOCK(&reload_queue);
784                         return;
785                 }
786                 strcpy(item->module, module);
787                 AST_LIST_INSERT_TAIL(&reload_queue, item, entry);
788         }
789         AST_LIST_UNLOCK(&reload_queue);
790 }
791
792 /*!
793  * \since 12
794  * \internal
795  * \brief Publish a \ref stasis message regarding the reload result
796  */
797 static void publish_reload_message(const char *name, enum ast_module_reload_result result)
798 {
799         RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
800         RAII_VAR(struct ast_json_payload *, payload, NULL, ao2_cleanup);
801         RAII_VAR(struct ast_json *, json_object, NULL, ast_json_unref);
802         RAII_VAR(struct ast_json *, event_object, NULL, ast_json_unref);
803         char res_buffer[8];
804
805         snprintf(res_buffer, sizeof(res_buffer), "%u", result);
806         event_object = ast_json_pack("{s: s, s: s}",
807                         "Module", S_OR(name, "All"),
808                         "Status", res_buffer);
809         json_object = ast_json_pack("{s: s, s: i, s: O}",
810                         "type", "Reload",
811                         "class_type", EVENT_FLAG_SYSTEM,
812                         "event", event_object);
813
814         if (!json_object) {
815                 return;
816         }
817
818         payload = ast_json_payload_create(json_object);
819         if (!payload) {
820                 return;
821         }
822
823         message = stasis_message_create(ast_manager_get_generic_type(), payload);
824         if (!message) {
825                 return;
826         }
827
828         stasis_publish(ast_manager_get_topic(), message);
829 }
830
831 enum ast_module_reload_result ast_module_reload(const char *name)
832 {
833         struct ast_module *cur;
834         enum ast_module_reload_result res = AST_MODULE_RELOAD_NOT_FOUND;
835         int i;
836
837         /* If we aren't fully booted, we just pretend we reloaded but we queue this
838            up to run once we are booted up. */
839         if (!ast_fully_booted) {
840                 queue_reload_request(name);
841                 res = AST_MODULE_RELOAD_QUEUED;
842                 goto module_reload_exit;
843         }
844
845         if (ast_mutex_trylock(&reloadlock)) {
846                 ast_verbose("The previous reload command didn't finish yet\n");
847                 res = AST_MODULE_RELOAD_IN_PROGRESS;
848                 goto module_reload_exit;
849         }
850         ast_lastreloadtime = ast_tvnow();
851
852         if (ast_opt_lock_confdir) {
853                 int try;
854                 int res;
855                 for (try = 1, res = AST_LOCK_TIMEOUT; try < 6 && (res == AST_LOCK_TIMEOUT); try++) {
856                         res = ast_lock_path(ast_config_AST_CONFIG_DIR);
857                         if (res == AST_LOCK_TIMEOUT) {
858                                 ast_log(LOG_WARNING, "Failed to grab lock on %s, try %d\n", ast_config_AST_CONFIG_DIR, try);
859                         }
860                 }
861                 if (res != AST_LOCK_SUCCESS) {
862                         ast_verbose("Cannot grab lock on %s\n", ast_config_AST_CONFIG_DIR);
863                         ast_mutex_unlock(&reloadlock);
864                         res = AST_MODULE_RELOAD_ERROR;
865                         goto module_reload_exit;
866                 }
867         }
868
869         /* Call "predefined" reload here first */
870         for (i = 0; reload_classes[i].name; i++) {
871                 if (!name || !strcasecmp(name, reload_classes[i].name)) {
872                         if (reload_classes[i].reload_fn() == AST_MODULE_LOAD_SUCCESS) {
873                                 res = AST_MODULE_RELOAD_SUCCESS;
874                         }
875                 }
876         }
877
878         if (name && res == AST_MODULE_RELOAD_SUCCESS) {
879                 if (ast_opt_lock_confdir) {
880                         ast_unlock_path(ast_config_AST_CONFIG_DIR);
881                 }
882                 ast_mutex_unlock(&reloadlock);
883                 goto module_reload_exit;
884         }
885
886         AST_LIST_LOCK(&module_list);
887         AST_LIST_TRAVERSE(&module_list, cur, entry) {
888                 const struct ast_module_info *info = cur->info;
889
890                 if (name && resource_name_match(name, cur->resource))
891                         continue;
892
893                 if (!cur->flags.running || cur->flags.declined) {
894                         if (res == AST_MODULE_RELOAD_NOT_FOUND) {
895                                 res = AST_MODULE_RELOAD_UNINITIALIZED;
896                         }
897                         if (!name) {
898                                 continue;
899                         }
900                         break;
901                 }
902
903                 if (!info->reload) {    /* cannot be reloaded */
904                         if (res == AST_MODULE_RELOAD_NOT_FOUND) {
905                                 res = AST_MODULE_RELOAD_NOT_IMPLEMENTED;
906                         }
907                         if (!name) {
908                                 continue;
909                         }
910                         break;
911                 }
912                 ast_verb(3, "Reloading module '%s' (%s)\n", cur->resource, info->description);
913                 if (info->reload() == AST_MODULE_LOAD_SUCCESS) {
914                         res = AST_MODULE_RELOAD_SUCCESS;
915                 }
916                 if (name) {
917                         break;
918                 }
919         }
920         AST_LIST_UNLOCK(&module_list);
921
922         if (ast_opt_lock_confdir) {
923                 ast_unlock_path(ast_config_AST_CONFIG_DIR);
924         }
925         ast_mutex_unlock(&reloadlock);
926
927 module_reload_exit:
928         publish_reload_message(name, res);
929         return res;
930 }
931
932 static unsigned int inspect_module(const struct ast_module *mod)
933 {
934         if (!mod->info->description) {
935                 ast_log(LOG_WARNING, "Module '%s' does not provide a description.\n", mod->resource);
936                 return 1;
937         }
938
939         if (!mod->info->key) {
940                 ast_log(LOG_WARNING, "Module '%s' does not provide a license key.\n", mod->resource);
941                 return 1;
942         }
943
944         if (verify_key((unsigned char *) mod->info->key)) {
945                 ast_log(LOG_WARNING, "Module '%s' did not provide a valid license key.\n", mod->resource);
946                 return 1;
947         }
948
949         if (!ast_strlen_zero(mod->info->buildopt_sum) &&
950             strcmp(buildopt_sum, mod->info->buildopt_sum)) {
951                 ast_log(LOG_WARNING, "Module '%s' was not compiled with the same compile-time options as this version of Asterisk.\n", mod->resource);
952                 ast_log(LOG_WARNING, "Module '%s' will not be initialized as it may cause instability.\n", mod->resource);
953                 return 1;
954         }
955
956         return 0;
957 }
958
959 static enum ast_module_load_result start_resource(struct ast_module *mod)
960 {
961         char tmp[256];
962         enum ast_module_load_result res;
963
964         if (mod->flags.running) {
965                 return AST_MODULE_LOAD_SUCCESS;
966         }
967
968         if (!mod->info->load) {
969                 return AST_MODULE_LOAD_FAILURE;
970         }
971
972         if (!ast_fully_booted) {
973                 ast_verb(1, "Loading %s.\n", mod->resource);
974         }
975         res = mod->info->load();
976
977         switch (res) {
978         case AST_MODULE_LOAD_SUCCESS:
979                 if (!ast_fully_booted) {
980                         ast_verb(1, "%s => (%s)\n", mod->resource, term_color(tmp, mod->info->description, COLOR_BROWN, COLOR_BLACK, sizeof(tmp)));
981                         if (ast_opt_console && !option_verbose) {
982                                 /* This never looks good on anything but the root console, so
983                                  * it's best not to try to funnel it through the logger. */
984                                 fprintf(stdout, ".");
985                         }
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         return res;
1004 }
1005
1006 /*! loads a resource based upon resource_name. If global_symbols_only is set
1007  *  only modules with global symbols will be loaded.
1008  *
1009  *  If the ast_heap is provided (not NULL) the module is found and added to the
1010  *  heap without running the module's load() function.  By doing this, modules
1011  *  added to the resource_heap can be initialized later in order by priority.
1012  *
1013  *  If the ast_heap is not provided, the module's load function will be executed
1014  *  immediately */
1015 static enum ast_module_load_result load_resource(const char *resource_name, unsigned int global_symbols_only, struct ast_heap *resource_heap, int required)
1016 {
1017         struct ast_module *mod;
1018         enum ast_module_load_result res = AST_MODULE_LOAD_SUCCESS;
1019
1020         if ((mod = find_resource(resource_name, 0))) {
1021                 if (mod->flags.running) {
1022                         ast_log(LOG_WARNING, "Module '%s' already exists.\n", resource_name);
1023                         return AST_MODULE_LOAD_DECLINE;
1024                 }
1025                 if (global_symbols_only && !ast_test_flag(mod->info, AST_MODFLAG_GLOBAL_SYMBOLS))
1026                         return AST_MODULE_LOAD_SKIP;
1027         } else {
1028 #ifdef LOADABLE_MODULES
1029                 if (!(mod = load_dynamic_module(resource_name, global_symbols_only, resource_heap))) {
1030                         /* don't generate a warning message during load_modules() */
1031                         if (!global_symbols_only) {
1032                                 ast_log(LOG_WARNING, "Module '%s' could not be loaded.\n", resource_name);
1033                                 return required ? AST_MODULE_LOAD_FAILURE : AST_MODULE_LOAD_DECLINE;
1034                         } else {
1035                                 return required ? AST_MODULE_LOAD_FAILURE : AST_MODULE_LOAD_SKIP;
1036                         }
1037                 }
1038 #else
1039                 ast_log(LOG_WARNING, "Module support is not available. Module '%s' could not be loaded.\n", resource_name);
1040                 return required ? AST_MODULE_LOAD_FAILURE : AST_MODULE_LOAD_DECLINE;
1041 #endif
1042         }
1043
1044         if (inspect_module(mod)) {
1045                 ast_log(LOG_WARNING, "Module '%s' could not be loaded.\n", resource_name);
1046 #ifdef LOADABLE_MODULES
1047                 unload_dynamic_module(mod);
1048 #endif
1049                 return required ? AST_MODULE_LOAD_FAILURE : AST_MODULE_LOAD_DECLINE;
1050         }
1051
1052         if (!mod->lib && mod->info->backup_globals && mod->info->backup_globals()) {
1053                 ast_log(LOG_WARNING, "Module '%s' was unable to backup its global data.\n", resource_name);
1054                 return required ? AST_MODULE_LOAD_FAILURE : AST_MODULE_LOAD_DECLINE;
1055         }
1056
1057         mod->flags.declined = 0;
1058
1059         if (resource_heap) {
1060                 ast_heap_push(resource_heap, mod);
1061                 res = AST_MODULE_LOAD_PRIORITY;
1062         } else {
1063                 res = start_resource(mod);
1064         }
1065
1066         /* Now make sure that the list is sorted */
1067         AST_LIST_LOCK(&module_list);
1068         AST_LIST_REMOVE(&module_list, mod, entry);
1069         AST_LIST_INSERT_SORTALPHA(&module_list, mod, entry, resource);
1070         AST_LIST_UNLOCK(&module_list);
1071
1072         return res;
1073 }
1074
1075 int ast_load_resource(const char *resource_name)
1076 {
1077         int res;
1078         AST_LIST_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_LIST_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_LIST_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_LIST_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_LIST_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, int usecnt, const char *status, const char *like),
1358                            const char *like)
1359 {
1360         struct ast_module *cur;
1361         int unlock = -1;
1362         int total_mod_loaded = 0;
1363
1364         if (AST_LIST_TRYLOCK(&module_list))
1365                 unlock = 0;
1366
1367         AST_LIST_TRAVERSE(&module_list, cur, entry) {
1368                 total_mod_loaded += modentry(cur->resource, cur->info->description, cur->usecount,
1369                                                 cur->flags.running ? "Running" : "Not Running", like);
1370         }
1371
1372         if (unlock)
1373                 AST_LIST_UNLOCK(&module_list);
1374
1375         return total_mod_loaded;
1376 }
1377
1378 /*! \brief Check if module exists */
1379 int ast_module_check(const char *name)
1380 {
1381         struct ast_module *cur;
1382
1383         if (ast_strlen_zero(name))
1384                 return 0;       /* FALSE */
1385
1386         cur = find_resource(name, 1);
1387
1388         return (cur != NULL);
1389 }
1390
1391
1392 int ast_loader_register(int (*v)(void))
1393 {
1394         struct loadupdate *tmp;
1395
1396         if (!(tmp = ast_malloc(sizeof(*tmp))))
1397                 return -1;
1398
1399         tmp->updater = v;
1400         AST_LIST_LOCK(&updaters);
1401         AST_LIST_INSERT_HEAD(&updaters, tmp, entry);
1402         AST_LIST_UNLOCK(&updaters);
1403
1404         return 0;
1405 }
1406
1407 int ast_loader_unregister(int (*v)(void))
1408 {
1409         struct loadupdate *cur;
1410
1411         AST_LIST_LOCK(&updaters);
1412         AST_LIST_TRAVERSE_SAFE_BEGIN(&updaters, cur, entry) {
1413                 if (cur->updater == v)  {
1414                         AST_LIST_REMOVE_CURRENT(entry);
1415                         break;
1416                 }
1417         }
1418         AST_LIST_TRAVERSE_SAFE_END;
1419         AST_LIST_UNLOCK(&updaters);
1420
1421         return cur ? 0 : -1;
1422 }
1423
1424 struct ast_module *ast_module_ref(struct ast_module *mod)
1425 {
1426         if (!mod) {
1427                 return NULL;
1428         }
1429
1430         ast_atomic_fetchadd_int(&mod->usecount, +1);
1431         ast_update_use_count();
1432
1433         return mod;
1434 }
1435
1436 void ast_module_unref(struct ast_module *mod)
1437 {
1438         if (!mod) {
1439                 return;
1440         }
1441
1442         ast_atomic_fetchadd_int(&mod->usecount, -1);
1443         ast_update_use_count();
1444 }