Asterisk - The Open Source Telephony Project GIT-master-a358458
loader.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 1999 - 2006, Digium, Inc.
5 *
6 * Mark Spencer <markster@digium.com>
7 * Kevin P. Fleming <kpfleming@digium.com>
8 * Luigi Rizzo <rizzo@icir.org>
9 *
10 * See http://www.asterisk.org for more information about
11 * the Asterisk project. Please do not directly contact
12 * any of the maintainers of this project for assistance;
13 * the project provides a web site, mailing lists and IRC
14 * channels for your use.
15 *
16 * This program is free software, distributed under the terms of
17 * the GNU General Public License Version 2. See the LICENSE file
18 * at the top of the source tree.
19 */
20
21/*! \file
22 *
23 * \brief Module Loader
24 * \author Mark Spencer <markster@digium.com>
25 * \author Kevin P. Fleming <kpfleming@digium.com>
26 * \author Luigi Rizzo <rizzo@icir.org>
27 * - See ModMngMnt
28 */
29
30/*** MODULEINFO
31 <support_level>core</support_level>
32 ***/
33
34#include "asterisk.h"
35
36#include "asterisk/_private.h"
37#include "asterisk/paths.h" /* use ast_config_AST_MODULE_DIR */
38#include <dirent.h>
39
41#include "asterisk/module.h"
42#include "asterisk/config.h"
43#include "asterisk/channel.h"
44#include "asterisk/term.h"
45#include "asterisk/manager.h"
46#include "asterisk/io.h"
47#include "asterisk/lock.h"
48#include "asterisk/vector.h"
49#include "asterisk/app.h"
50#include "asterisk/test.h"
51#include "asterisk/cli.h"
52
53#include <dlfcn.h>
54
55#include "asterisk/md5.h"
56#include "asterisk/utils.h"
57
58/*** DOCUMENTATION
59 <managerEvent language="en_US" name="Reload">
60 <managerEventInstance class="EVENT_FLAG_SYSTEM">
61 <synopsis>Raised when a module has been reloaded in Asterisk.</synopsis>
62 <syntax>
63 <parameter name="Module">
64 <para>The name of the module that was reloaded, or
65 <literal>All</literal> if all modules were reloaded</para>
66 </parameter>
67 <parameter name="Status">
68 <para>The numeric status code denoting the success or failure
69 of the reload request.</para>
70 <enumlist>
71 <enum name="0"><para>Success</para></enum>
72 <enum name="1"><para>Request queued</para></enum>
73 <enum name="2"><para>Module not found</para></enum>
74 <enum name="3"><para>Error</para></enum>
75 <enum name="4"><para>Reload already in progress</para></enum>
76 <enum name="5"><para>Module uninitialized</para></enum>
77 <enum name="6"><para>Reload not supported</para></enum>
78 </enumlist>
79 </parameter>
80 </syntax>
81 </managerEventInstance>
82 </managerEvent>
83 <managerEvent language="en_US" name="Load">
84 <managerEventInstance class="EVENT_FLAG_SYSTEM">
85 <synopsis>Raised when a module has been loaded in Asterisk.</synopsis>
86 <syntax>
87 <parameter name="Module">
88 <para>The name of the module that was loaded</para>
89 </parameter>
90 <parameter name="Status">
91 <para>The result of the load request.</para>
92 <enumlist>
93 <enum name="Failure"><para>Module could not be loaded properly</para></enum>
94 <enum name="Success"><para>Module loaded and configured</para></enum>
95 <enum name="Decline"><para>Module is not configured</para></enum>
96 </enumlist>
97 </parameter>
98 </syntax>
99 </managerEventInstance>
100 </managerEvent>
101 <managerEvent language="en_US" name="Unload">
102 <managerEventInstance class="EVENT_FLAG_SYSTEM">
103 <synopsis>Raised when a module has been unloaded in Asterisk.</synopsis>
104 <syntax>
105 <parameter name="Module">
106 <para>The name of the module that was unloaded</para>
107 </parameter>
108 <parameter name="Status">
109 <para>The result of the unload request.</para>
110 <enumlist>
111 <enum name="Success"><para>Module unloaded successfully</para></enum>
112 </enumlist>
113 </parameter>
114 </syntax>
115 </managerEventInstance>
116 </managerEvent>
117 ***/
118
119#ifndef RTLD_NOW
120#define RTLD_NOW 0
121#endif
122
123#ifndef RTLD_LOCAL
124#define RTLD_LOCAL 0
125#endif
126
130};
131
133
134static const unsigned char expected_key[] =
135{ 0x87, 0x76, 0x79, 0x35, 0x23, 0xea, 0x3a, 0xd3,
136 0x25, 0x2a, 0xbb, 0x35, 0x87, 0xe4, 0x22, 0x24 };
137
139
141
142/*! Used with AST_VECTOR_CALLBACK_VOID to create a
143 * comma separated list of module names for error messages. */
144#define STR_APPEND_TEXT(txt, str) \
145 ast_str_append(str, 0, "%s%s", \
146 ast_str_strlen(*(str)) > 0 ? ", " : "", \
147 txt)
148
149/* Built-in module registrations need special handling at startup */
150static unsigned int loader_ready;
151
152/*! String container for deferring output of startup errors. */
155
156#if defined(HAVE_PERMANENT_DLOPEN) || defined(AST_XML_DOCS)
157static char *get_name_from_resource(const char *resource)
158{
159 int len;
160 const char *last_three;
161 char *mod_name;
162
163 if (!resource) {
164 return NULL;
165 }
166
167 len = strlen(resource);
168 if (len > 3) {
169 last_three = &resource[len-3];
170 if (!strcasecmp(last_three, ".so")) {
171 mod_name = ast_calloc(1, len - 2);
172 if (mod_name) {
173 ast_copy_string(mod_name, resource, len - 2);
174 return mod_name;
175 } else {
176 /* Unable to allocate memory. */
177 return NULL;
178 }
179 }
180 }
181
182 /* Resource is the name - happens when manually unloading a module. */
183 mod_name = ast_calloc(1, len + 1);
184 if (mod_name) {
185 ast_copy_string(mod_name, resource, len + 1);
186 return mod_name;
187 }
188
189 /* Unable to allocate memory. */
190 return NULL;
191}
192#endif
193
194#if defined(HAVE_PERMANENT_DLOPEN)
195#define FIRST_DLOPEN 999
196
197struct ao2_container *info_list = NULL;
198
199struct info_list_obj {
200 const struct ast_module_info *info;
201 int dlopened;
202 char name[0];
203};
204
205static struct info_list_obj *info_list_obj_alloc(const char *name,
206 const struct ast_module_info *info)
207{
208 struct info_list_obj *new_entry;
209
210 new_entry = ao2_alloc(sizeof(*new_entry) + strlen(name) + 1, NULL);
211
212 if (!new_entry) {
213 return NULL;
214 }
215
216 strcpy(new_entry->name, name); /* SAFE */
217 new_entry->info = info;
218 new_entry->dlopened = FIRST_DLOPEN;
219
220 return new_entry;
221}
222
223AO2_STRING_FIELD_CMP_FN(info_list_obj, name)
224
225static void manual_mod_reg(const void *lib, const char *resource)
226{
227 struct info_list_obj *obj_tmp;
228 char *mod_name;
229
230 if (lib) {
231 mod_name = get_name_from_resource(resource);
232 if (mod_name) {
233 obj_tmp = ao2_find(info_list, mod_name, OBJ_SEARCH_KEY);
234 if (obj_tmp) {
235 if (obj_tmp->dlopened == FIRST_DLOPEN) {
236 obj_tmp->dlopened = 1;
237 } else {
238 ast_module_register(obj_tmp->info);
239 }
240 ao2_ref(obj_tmp, -1);
241 }
242 ast_free(mod_name);
243 }
244 }
245}
246
247static void manual_mod_unreg(const char *resource)
248{
249 struct info_list_obj *obj_tmp;
250 char *mod_name;
251
252 /* When Asterisk shuts down the destructor is called automatically. */
253 if (ast_shutdown_final()) {
254 return;
255 }
256
257 mod_name = get_name_from_resource(resource);
258 if (mod_name) {
259 obj_tmp = ao2_find(info_list, mod_name, OBJ_SEARCH_KEY);
260 if (obj_tmp) {
261 ast_module_unregister(obj_tmp->info);
262 ao2_ref(obj_tmp, -1);
263 }
264 ast_free(mod_name);
265 }
266}
267#endif
268
269static __attribute__((format(printf, 1, 2))) void module_load_error(const char *fmt, ...)
270{
271 char *copy = NULL;
272 va_list ap;
273
274 va_start(ap, fmt);
280 ast_free(copy);
281 }
282 } else {
283 ast_log_ap(LOG_ERROR, fmt, ap);
284 }
285 va_end(ap);
286}
287
288/*!
289 * \brief Internal flag to indicate all modules have been initially loaded.
290 */
291static int modules_loaded;
292
294 const struct ast_module_info *info;
295 /*! Used to get module references into refs log */
297 /*! The shared lib. */
298 void *lib;
299 /*! Number of 'users' and other references currently holding the module. */
301 /*! List of users holding the module. */
303
304 /*! List of required module names. */
306 /*! List of optional api modules. */
308 /*! List of modules this enhances. */
310
311 /*!
312 * \brief Vector holding pointers to modules we have a reference to.
313 *
314 * When one module requires another, the required module gets added
315 * to this list with a reference.
316 */
318 struct {
319 /*! The module running and ready to accept requests. */
320 unsigned int running:1;
321 /*! The module has declined to start. */
322 unsigned int declined:1;
323 /*! This module is being held open until it's time to shutdown. */
324 unsigned int keepuntilshutdown:1;
325 /*! The module is built-in. */
326 unsigned int builtin:1;
327 /*! The admin has declared this module is required. */
328 unsigned int required:1;
329 /*! This module is marked for preload. */
330 unsigned int preload:1;
333 char resource[0];
334};
335
337
338
341 const char *name;
342};
343
344static const struct load_results_map load_results[] = {
345 { AST_MODULE_LOAD_SUCCESS, "Success" },
346 { AST_MODULE_LOAD_DECLINE, "Decline" },
347 { AST_MODULE_LOAD_SKIP, "Skip" },
348 { AST_MODULE_LOAD_PRIORITY, "Priority" },
349 { AST_MODULE_LOAD_FAILURE, "Failure" },
350};
351#define AST_MODULE_LOAD_UNKNOWN_STRING "Unknown" /* Status string for unknown load status */
352
353static void publish_load_message_type(const char* type, const char *name, const char *status);
354static void publish_reload_message(const char *name, enum ast_module_reload_result result);
355static void publish_load_message(const char *name, enum ast_module_load_result result);
356static void publish_unload_message(const char *name, const char* status);
357
358
359/*
360 * module_list is cleared by its constructor possibly after
361 * we start accumulating built-in modules, so we need to
362 * use another list (without the lock) to accumulate them.
363 */
365
367{
368 return strcasecmp(a->resource, b->resource);
369}
370
371static int module_vector_cmp(struct ast_module *a, struct ast_module *b)
372{
373 int preload_diff = (int)b->flags.preload - (int)a->flags.preload;
374 /* if load_pri is not set, default is 128. Lower is better */
375 int a_pri = ast_test_flag(a->info, AST_MODFLAG_LOAD_ORDER)
376 ? a->info->load_pri : AST_MODPRI_DEFAULT;
377 int b_pri = ast_test_flag(b->info, AST_MODFLAG_LOAD_ORDER)
378 ? b->info->load_pri : AST_MODPRI_DEFAULT;
379
380 if (preload_diff) {
381 /* -1 preload a but not b */
382 /* 0 preload both or neither */
383 /* 1 preload b but not a */
384 return preload_diff;
385 }
386
387 /*
388 * Returns comparison values for a vector sorted by priority.
389 * <0 a_pri < b_pri
390 * =0 a_pri == b_pri
391 * >0 a_pri > b_pri
392 */
393 return a_pri - b_pri;
394}
395
396static struct ast_module *find_resource(const char *resource, int do_lock);
397
398/*!
399 * \internal
400 * \brief Add a reference from mod to dep.
401 *
402 * \param mod Owner of the new reference.
403 * \param dep Module to reference
404 * \param missing Vector to store name of \a dep if it is not running.
405 *
406 * This function returns failure if \a dep is not running and \a missing
407 * is NULL. If \a missing is not NULL errors will only be returned for
408 * allocation failures.
409 *
410 * \retval 0 Success
411 * \retval -1 Failure
412 *
413 * \note Adding a second reference to the same dep will return success
414 * without doing anything.
415 */
416static int module_reffed_deps_add(struct ast_module *mod, struct ast_module *dep,
417 struct ast_vector_const_string *missing)
418{
419 if (!dep->flags.running) {
420 return !missing ? -1 : AST_VECTOR_APPEND(missing, dep->info->name);
421 }
422
424 /* Skip duplicate. */
425 return 0;
426 }
427
428 if (AST_VECTOR_APPEND(&mod->reffed_deps, dep)) {
429 return -1;
430 }
431
432 ast_module_ref(dep);
433
434 return 0;
435}
436
437/*!
438 * \internal
439 * \brief Add references for modules that enhance a dependency.
440 *
441 * \param mod Owner of the new references.
442 * \param dep Module to check for enhancers.
443 * \param missing Vector to store name of any enhancer that is not running or declined.
444 *
445 * \retval 0 Success
446 * \retval -1 Failure
447 */
449 struct ast_module *dep, struct ast_vector_const_string *missing)
450{
451 struct ast_module *cur;
452
454 if (cur->flags.declined) {
455 continue;
456 }
457
458 if (!AST_VECTOR_GET_CMP(&cur->enhances, dep->info->name, !strcasecmp)) {
459 /* dep is not enhanced by cur. */
460 continue;
461 }
462
463 /* dep is enhanced by cur, therefore mod requires cur. */
464 if (module_reffed_deps_add(mod, cur, missing)) {
465 return -1;
466 }
467 }
468
469 return 0;
470}
471
472/*!
473 * \internal
474 * \brief Add references to a list of dependencies.
475 *
476 * \param mod Owner of the new references.
477 * \param vec List of required modules to process
478 * \param missing Vector to store names of modules that are not running.
479 * \param ref_enhancers Reference all enhancers of each required module.
480 * \param isoptional Modules that are not loaded can be ignored.
481 *
482 * \retval 0 Success
483 * \retval -1 Failure
484 */
486 struct ast_vector_string *vec, struct ast_vector_const_string *missing,
487 int ref_enhancers, int isoptional)
488{
489 int idx;
490
491 for (idx = 0; idx < AST_VECTOR_SIZE(vec); idx++) {
492 const char *depname = AST_VECTOR_GET(vec, idx);
493 struct ast_module *dep = find_resource(depname, 0);
494
495 if (!dep || !dep->flags.running) {
496 if (isoptional && !dep) {
497 continue;
498 }
499
500 if (missing && !AST_VECTOR_APPEND(missing, depname)) {
501 continue;
502 }
503
504 return -1;
505 }
506
507 if (module_reffed_deps_add(mod, dep, missing)) {
508 return -1;
509 }
510
511 if (ref_enhancers && module_reffed_deps_add_dep_enhancers(mod, dep, missing)) {
512 return -1;
513 }
514 }
515
516 return 0;
517}
518
519/*!
520 * \internal
521 * \brief Grab all references required to start the module.
522 *
523 * \param mod The module we're trying to start.
524 * \param missing Vector to store a list of missing dependencies.
525 *
526 * \retval 0 Success
527 * \retval -1 Failure
528 *
529 * \note module_list must be locked.
530 *
531 * \note Caller is responsible for initializing and freeing the vector.
532 * Elements are safely read only while module_list remains locked.
533 */
534static int module_deps_reference(struct ast_module *mod, struct ast_vector_const_string *missing)
535{
536 int res = 0;
537
538 /* Grab references to modules we enhance but not other enhancements. */
539 res |= module_deps_process_reqlist(mod, &mod->enhances, missing, 0, 0);
540
541 /* Grab references to modules we require plus enhancements. */
542 res |= module_deps_process_reqlist(mod, &mod->requires, missing, 1, 0);
543
544 /* Grab references to optional modules including enhancements. */
545 res |= module_deps_process_reqlist(mod, &mod->optional_modules, missing, 1, 1);
546
547 return res;
548}
549
550/*!
551 * \brief Recursively find required dependencies that are not running.
552 *
553 * \param mod Module to scan for dependencies.
554 * \param missingdeps Vector listing modules that must be started first.
555 *
556 * \retval 0 All dependencies resolved.
557 * \retval -1 Failed to resolve some dependencies.
558 *
559 * An error from this function usually means a required module is not even
560 * loaded. This function is safe from infinite recursion, but dependency
561 * loops are not reported as an error from here. On success missingdeps
562 * will contain a list of every module that needs to be running before this
563 * module can start. missingdeps is sorted by load priority so any missing
564 * dependencies can be started if needed.
565 */
566static int module_deps_missing_recursive(struct ast_module *mod, struct module_vector *missingdeps)
567{
568 int i = 0;
569 int res = -1;
570 struct ast_vector_const_string localdeps;
571 struct ast_module *dep;
572
573 /*
574 * localdeps stores a copy of all dependencies that mod could not reference.
575 * First we discard modules that we've already found. We add all newly found
576 * modules to the missingdeps vector then scan them recursively. This will
577 * ensure we quickly run out of stuff to do.
578 */
579 AST_VECTOR_INIT(&localdeps, 0);
580 if (module_deps_reference(mod, &localdeps)) {
581 goto clean_return;
582 }
583
584 while (i < AST_VECTOR_SIZE(&localdeps)) {
585 dep = find_resource(AST_VECTOR_GET(&localdeps, i), 0);
586 if (!dep) {
587 goto clean_return;
588 }
589
590 if (AST_VECTOR_GET_CMP(missingdeps, dep, AST_VECTOR_ELEM_DEFAULT_CMP)) {
591 /* Skip common dependency. We have already searched it. */
592 AST_VECTOR_REMOVE(&localdeps, i, 0);
593 } else {
594 /* missingdeps is the real list so keep it sorted. */
595 if (AST_VECTOR_ADD_SORTED(missingdeps, dep, module_vector_cmp)) {
596 goto clean_return;
597 }
598 i++;
599 }
600 }
601
602 res = 0;
603 for (i = 0; !res && i < AST_VECTOR_SIZE(&localdeps); i++) {
604 dep = find_resource(AST_VECTOR_GET(&localdeps, i), 0);
605 /* We've already confirmed dep is loaded in the first loop. */
606 res = module_deps_missing_recursive(dep, missingdeps);
607 }
608
609clean_return:
610 AST_VECTOR_FREE(&localdeps);
611
612 return res;
613}
614
615const char *ast_module_name(const struct ast_module *mod)
616{
617 if (!mod || !mod->info) {
618 return NULL;
619 }
620
621 return mod->info->name;
622}
623
625 int (*updater)(void);
627};
628
630
632
635 char module[0];
636};
637
638static int do_full_reload = 0;
639
641
642/*!
643 * \internal
644 *
645 * This variable is set by load_dynamic_module so ast_module_register
646 * can know what pointer is being registered.
647 *
648 * This is protected by the module_list lock.
649 */
650static struct ast_module * volatile resource_being_loaded;
651
652/*!
653 * \internal
654 * \brief Used by AST_MODULE_INFO to register with the module loader.
655 *
656 * This function is automatically called when each module is opened.
657 * It must never be used from outside AST_MODULE_INFO.
658 */
660{
661 struct ast_module *mod;
662
663 if (!loader_ready) {
664 mod = ast_std_calloc(1, sizeof(*mod) + strlen(info->name) + 1);
665 if (!mod) {
666 /* We haven't even reached main() yet, if we can't
667 * allocate memory at this point just give up. */
668 fprintf(stderr, "Allocation failure during startup.\n");
669 exit(2);
670 }
671 strcpy(mod->resource, info->name); /* safe */
672 mod->info = info;
673 mod->flags.builtin = 1;
675
676 /* ast_module_register for built-in modules is run again during module preload. */
677 return;
678 }
679
680 /*
681 * This lock protects resource_being_loaded as well as the module
682 * list. Normally we already have a lock on module_list when we
683 * begin the load but locking again from here prevents corruption
684 * if an asterisk module is dlopen'ed from outside the module loader.
685 */
688 if (!mod) {
690 return;
691 }
692
693 ast_debug(5, "Registering module %s\n", info->name);
694
695 /* This tells load_dynamic_module that we're registered. */
697
698 mod->info = info;
699 if (ast_opt_ref_debug) {
701 }
703 AST_VECTOR_INIT(&mod->requires, 0);
705 AST_VECTOR_INIT(&mod->enhances, 0);
707
710
711 /* give the module a copy of its own handle, for later use in registrations and the like */
712 *((struct ast_module **) &(info->self)) = mod;
713
714#if defined(HAVE_PERMANENT_DLOPEN)
715 if (mod->flags.builtin != 1) {
716 struct info_list_obj *obj_tmp = ao2_find(info_list, info->name,
718
719 if (!obj_tmp) {
720 obj_tmp = info_list_obj_alloc(info->name, info);
721 if (obj_tmp) {
722 ao2_link(info_list, obj_tmp);
723 ao2_ref(obj_tmp, -1);
724 }
725 } else {
726 ao2_ref(obj_tmp, -1);
727 }
728 }
729#endif
730}
731
732static int module_post_register(struct ast_module *mod)
733{
734 int res;
735
736 /* Split lists from mod->info. */
737 res = ast_vector_string_split(&mod->requires, mod->info->requires, ",", 0, strcasecmp);
738 res |= ast_vector_string_split(&mod->optional_modules, mod->info->optional_modules, ",", 0, strcasecmp);
739 res |= ast_vector_string_split(&mod->enhances, mod->info->enhances, ",", 0, strcasecmp);
740
741 return res;
742}
743
744static void module_destroy(struct ast_module *mod)
745{
748
751
754
755 /* Release references to all dependencies. */
758
761 if (mod->flags.builtin) {
762 ast_std_free(mod);
763 } else {
764 ast_free(mod);
765 }
766}
767
769{
770 struct ast_module *mod = NULL;
771
772 /* it is assumed that the users list in the module structure
773 will already be empty, or we cannot have gotten to this
774 point
775 */
778 if (mod->info == info) {
780 break;
781 }
782 }
785
786 if (mod && !mod->usecount) {
787 /*
788 * We are intentionally leaking mod if usecount is not zero.
789 * This is necessary if the module is being forcefully unloaded.
790 * In addition module_destroy is not safe to run after exit()
791 * is called. ast_module_unregister is run during cleanup of
792 * the process when libc releases each module's shared object
793 * library.
794 */
795 ast_debug(5, "Unregistering module %s\n", info->name);
796 module_destroy(mod);
797 }
798}
799
801{
802 struct ast_module_user *u;
803
804 u = ast_calloc(1, sizeof(*u));
805 if (!u) {
806 return NULL;
807 }
808
809 u->chan = chan;
810
811 AST_LIST_LOCK(&mod->users);
813 AST_LIST_UNLOCK(&mod->users);
814
815 if (mod->ref_debug) {
816 ao2_ref(mod->ref_debug, +1);
817 }
818
820
822
823 return u;
824}
825
827{
828 if (!u) {
829 return;
830 }
831
832 AST_LIST_LOCK(&mod->users);
833 u = AST_LIST_REMOVE(&mod->users, u, entry);
834 AST_LIST_UNLOCK(&mod->users);
835 if (!u) {
836 /*
837 * Was not in the list. Either a bad pointer or
838 * __ast_module_user_hangup_all() has been called.
839 */
840 return;
841 }
842
843 if (mod->ref_debug) {
844 ao2_ref(mod->ref_debug, -1);
845 }
846
848 ast_free(u);
849
851}
852
854{
855 struct ast_module_user *u;
856
857 AST_LIST_LOCK(&mod->users);
858 while ((u = AST_LIST_REMOVE_HEAD(&mod->users, entry))) {
859 if (u->chan) {
861 }
862
863 if (mod->ref_debug) {
864 ao2_ref(mod->ref_debug, -1);
865 }
866
868 ast_free(u);
869 }
870 AST_LIST_UNLOCK(&mod->users);
871
873}
874
875static int printdigest(const unsigned char *d)
876{
877 int x, pos;
878 char buf[256]; /* large enough so we don't have to worry */
879
880 for (pos = 0, x = 0; x < 16; x++)
881 pos += sprintf(buf + pos, " %02hhx", *d++);
882
883 ast_debug(1, "Unexpected signature:%s\n", buf);
884
885 return 0;
886}
887
888#define key_matches(a, b) (memcmp((a), (b), 16) == 0)
889
890static int verify_key(const unsigned char *key)
891{
892 struct MD5Context c;
893 unsigned char digest[16];
894
895 MD5Init(&c);
896 MD5Update(&c, key, strlen((char *)key));
897 MD5Final(digest, &c);
898
899 if (key_matches(expected_key, digest))
900 return 0;
901
902 printdigest(digest);
903
904 return -1;
905}
906
907static size_t resource_name_baselen(const char *name)
908{
909 size_t len = strlen(name);
910
911 if (len > 3 && !strcasecmp(name + len - 3, ".so")) {
912 return len - 3;
913 }
914
915 return len;
916}
917
918static int resource_name_match(const char *name1, size_t baselen1, const char *name2)
919{
920 if (baselen1 != resource_name_baselen(name2)) {
921 return -1;
922 }
923
924 return strncasecmp(name1, name2, baselen1);
925}
926
927static struct ast_module *find_resource(const char *resource, int do_lock)
928{
929 struct ast_module *cur;
930 size_t resource_baselen = resource_name_baselen(resource);
931
932 if (do_lock) {
934 }
935
937 if (!resource_name_match(resource, resource_baselen, cur->resource)) {
938 break;
939 }
940 }
941
942 if (do_lock) {
944 }
945
946 return cur;
947}
948
949/*!
950 * \brief dlclose(), with failure logging.
951 */
952static void logged_dlclose(const char *name, void *lib)
953{
954 char *error;
955
956 if (!lib) {
957 return;
958 }
959
960 /* Clear any existing error */
961 dlerror();
962 if (dlclose(lib)) {
963 error = dlerror();
964 ast_log(AST_LOG_ERROR, "Failure in dlclose for module '%s': %s\n",
965 S_OR(name, "unknown"), S_OR(error, "Unknown error"));
966#if defined(HAVE_PERMANENT_DLOPEN)
967 } else {
968 manual_mod_unreg(name);
969#endif
970 }
971}
972
973#if defined(HAVE_RTLD_NOLOAD)
974/*!
975 * \brief Check to see if the given resource is loaded.
976 *
977 * \param resource_name Name of the resource, including .so suffix.
978 * \return False (0) if module is not loaded.
979 * \return True (non-zero) if module is loaded.
980 */
981static int is_module_loaded(const char *resource_name)
982{
983 char fn[PATH_MAX] = "";
984 void *lib;
985
986 snprintf(fn, sizeof(fn), "%s/%s", ast_config_AST_MODULE_DIR,
987 resource_name);
988
989 lib = dlopen(fn, RTLD_LAZY | RTLD_NOLOAD);
990
991 if (lib) {
992 logged_dlclose(resource_name, lib);
993 return 1;
994 }
995
996 return 0;
997}
998#endif
999
1000static void unload_dynamic_module(struct ast_module *mod)
1001{
1002#if defined(HAVE_RTLD_NOLOAD)
1003 char *name = ast_strdupa(ast_module_name(mod));
1004#endif
1005 void *lib = mod->lib;
1006
1007 /* WARNING: the structure pointed to by mod is going to
1008 disappear when this operation succeeds, so we can't
1009 dereference it */
1011
1012 /* There are several situations where the module might still be resident
1013 * in memory.
1014 *
1015 * If somehow there was another dlopen() on the same module (unlikely,
1016 * since that all is supposed to happen in loader.c).
1017 *
1018 * Avoid the temptation of repeating the dlclose(). The other code that
1019 * dlopened the module still has its module reference, and should close
1020 * it itself. In other situations, dlclose() will happily return success
1021 * for as many times as you wish to call it.
1022 */
1023#if defined(HAVE_RTLD_NOLOAD)
1024 if (is_module_loaded(name)) {
1025 ast_log(LOG_WARNING, "Module '%s' could not be completely unloaded\n", name);
1026 }
1027#endif
1028}
1029
1030static int load_dlopen_missing(struct ast_str **list, struct ast_vector_string *deps)
1031{
1032 int i;
1033 int c = 0;
1034
1035 for (i = 0; i < AST_VECTOR_SIZE(deps); i++) {
1036 const char *dep = AST_VECTOR_GET(deps, i);
1037 if (!find_resource(dep, 0)) {
1038 STR_APPEND_TEXT(dep, list);
1039 c++;
1040 }
1041 }
1042
1043 return c;
1044}
1045
1046/*!
1047 * \internal
1048 * \brief Attempt to dlopen a module.
1049 *
1050 * \param resource_in The module name to load.
1051 * \param so_ext ".so" or blank if ".so" is already part of resource_in.
1052 * \param filename Passed directly to dlopen.
1053 * \param flags Passed directly to dlopen.
1054 * \param suppress_logging Do not log any error from dlopen.
1055 *
1056 * \return Pointer to opened module, NULL on error.
1057 *
1058 * \warning module_list must be locked before calling this function.
1059 */
1060static struct ast_module *load_dlopen(const char *resource_in, const char *so_ext,
1061 const char *filename, int flags, unsigned int suppress_logging)
1062{
1063 struct ast_module *mod;
1064
1066
1067 mod = ast_calloc(1, sizeof(*mod) + strlen(resource_in) + strlen(so_ext) + 1);
1068 if (!mod) {
1069 return NULL;
1070 }
1071
1072 sprintf(mod->resource, "%s%s", resource_in, so_ext); /* safe */
1073
1075 mod->lib = dlopen(filename, flags);
1076#if defined(HAVE_PERMANENT_DLOPEN)
1077 manual_mod_reg(mod->lib, mod->resource);
1078#endif
1080 struct ast_str *list;
1081 int c = 0;
1082 const char *dlerror_msg = ast_strdupa(S_OR(dlerror(), ""));
1083
1085 if (mod->lib) {
1086 module_load_error("Module '%s' did not register itself during load\n", resource_in);
1087 logged_dlclose(resource_in, mod->lib);
1088
1089 goto error_return;
1090 }
1091
1092 if (suppress_logging) {
1093 goto error_return;
1094 }
1095
1097 mod->lib = dlopen(filename, RTLD_LAZY | RTLD_LOCAL);
1098#if defined(HAVE_PERMANENT_DLOPEN)
1099 manual_mod_reg(mod->lib, mod->resource);
1100#endif
1103
1104 module_load_error("Error loading module '%s': %s\n", resource_in, dlerror_msg);
1105 logged_dlclose(resource_in, mod->lib);
1106
1107 goto error_return;
1108 }
1109
1110 list = ast_str_create(64);
1111 if (list) {
1112 if (module_post_register(mod)) {
1113 goto loaded_error;
1114 }
1115
1116 c = load_dlopen_missing(&list, &mod->requires);
1117 c += load_dlopen_missing(&list, &mod->enhances);
1118#ifndef OPTIONAL_API
1119 c += load_dlopen_missing(&list, &mod->optional_modules);
1120#endif
1121 }
1122
1123 if (list && ast_str_strlen(list)) {
1124 module_load_error("Error loading module '%s', missing %s: %s\n",
1125 resource_in, c == 1 ? "dependency" : "dependencies", ast_str_buffer(list));
1126 } else {
1127 module_load_error("Error loading module '%s': %s\n", resource_in, dlerror_msg);
1128 }
1129
1130loaded_error:
1131 ast_free(list);
1133
1134 return NULL;
1135
1136error_return:
1137 ast_free(mod);
1138
1139 return NULL;
1140 }
1141
1142 return mod;
1143}
1144
1145static struct ast_module *load_dynamic_module(const char *resource_in, unsigned int suppress_logging)
1146{
1147 char fn[PATH_MAX];
1148 struct ast_module *mod;
1149 size_t resource_in_len = strlen(resource_in);
1150 const char *so_ext = "";
1151
1152 if (resource_in_len < 4 || strcasecmp(resource_in + resource_in_len - 3, ".so")) {
1153 so_ext = ".so";
1154 }
1155
1156 snprintf(fn, sizeof(fn), "%s/%s%s", ast_config_AST_MODULE_DIR, resource_in, so_ext);
1157
1158 /* Try loading in quiet mode first with RTLD_LOCAL. The majority of modules do not
1159 * export symbols so this allows the least number of calls to dlopen. */
1160 mod = load_dlopen(resource_in, so_ext, fn, RTLD_NOW | RTLD_LOCAL, suppress_logging);
1161
1162 if (!mod || !ast_test_flag(mod->info, AST_MODFLAG_GLOBAL_SYMBOLS)) {
1163 return mod;
1164 }
1165
1166 /* Close the module so we can reopen with correct flags. */
1167 logged_dlclose(resource_in, mod->lib);
1168
1169 return load_dlopen(resource_in, so_ext, fn, RTLD_NOW | RTLD_GLOBAL, 0);
1170}
1171
1173{
1174 struct ast_module *mod;
1175 int somethingchanged;
1176 int res;
1177
1179
1180 /*!\note Some resources, like timers, are started up dynamically, and thus
1181 * may be still in use, even if all channels are dead. We must therefore
1182 * check the usecount before asking modules to unload. */
1183 do {
1184 /* Reset flag before traversing the list */
1185 somethingchanged = 0;
1186
1188 if (mod->usecount) {
1189 ast_debug(1, "Passing on %s: its use count is %d\n",
1190 mod->resource, mod->usecount);
1191 continue;
1192 }
1194 if (mod->flags.running && !mod->flags.declined && mod->info->unload) {
1195 ast_verb(4, "Unloading %s\n", mod->resource);
1196 mod->info->unload();
1197 }
1198 module_destroy(mod);
1199 somethingchanged = 1;
1200 }
1202 if (!somethingchanged) {
1204 if (mod->flags.keepuntilshutdown) {
1205 ast_module_unref(mod);
1206 mod->flags.keepuntilshutdown = 0;
1207 somethingchanged = 1;
1208 }
1209 }
1210 }
1211 } while (somethingchanged);
1212
1215
1216 return !res;
1217}
1218
1219int ast_unload_resource(const char *resource_name, enum ast_module_unload_mode force)
1220{
1221 struct ast_module *mod;
1222 int res = -1;
1223 int error = 0;
1224
1226
1227 if (!(mod = find_resource(resource_name, 0))) {
1229 ast_log(LOG_WARNING, "Unload failed, '%s' could not be found\n", resource_name);
1230 return -1;
1231 }
1232
1233 if (!mod->flags.running || mod->flags.declined) {
1234 /* If the user asks to unload a module that didn't load, obey.
1235 * Otherwise, we never dlclose() modules that fail to load,
1236 * which means if the module (shared object) is updated,
1237 * we can't load the updated module since we never dlclose()'d it.
1238 * Accordingly, obey the unload request so we can load the module
1239 * from scratch next time.
1240 */
1241 ast_log(LOG_NOTICE, "Unloading module '%s' that previously declined to load\n", resource_name);
1242 error = 0;
1243 res = 0;
1244 goto exit; /* Skip all the intervening !error checks, only the last one is relevant. */
1245 }
1246
1247 if (!error && (mod->usecount > 0)) {
1248 if (force)
1249 ast_log(LOG_WARNING, "Warning: Forcing removal of module '%s' with use count %d\n",
1250 resource_name, mod->usecount);
1251 else {
1252 ast_log(LOG_WARNING, "Soft unload failed, '%s' has use count %d\n", resource_name,
1253 mod->usecount);
1254 error = 1;
1255 }
1256 }
1257
1258 if (!error) {
1259 /* Request any channels attached to the module to hangup. */
1261
1262 ast_verb(4, "Unloading %s\n", mod->resource);
1263 res = mod->info->unload();
1264 if (res) {
1265 ast_log(LOG_WARNING, "Firm unload failed for %s\n", resource_name);
1266 if (force <= AST_FORCE_FIRM) {
1267 error = 1;
1268 } else {
1269 ast_log(LOG_WARNING, "** Dangerous **: Unloading resource anyway, at user request\n");
1270 }
1271 }
1272
1273 if (!error) {
1274 /*
1275 * Request hangup on any channels that managed to get attached
1276 * while we called the module unload function.
1277 */
1279 sched_yield();
1280 }
1281 }
1282
1283 if (!error)
1284 mod->flags.running = mod->flags.declined = 0;
1285
1286exit:
1288
1289 if (!error) {
1291 ast_test_suite_event_notify("MODULE_UNLOAD", "Message: %s", resource_name);
1293 publish_unload_message(resource_name, "Success");
1294 }
1295
1296 return res;
1297}
1298
1300{
1301 switch (type) {
1303 return !mod->usecount && mod->flags.running && !mod->flags.declined;
1304
1306 return mod->flags.running && mod->info->reload;
1307
1309 return mod->flags.running;
1310
1312 /* if we have a 'struct ast_module' then we're loaded. */
1313 return 1;
1314 default:
1315 /* This function is not called for AST_MODULE_HELPER_LOAD. */
1316 /* Unknown ast_module_helper_type. Assume it doesn't match. */
1317 ast_assert(0);
1318
1319 return 0;
1320 }
1321}
1322
1324 const char *word;
1325 size_t len;
1327};
1328
1329static int module_load_helper_on_file(const char *dir_name, const char *filename, void *obj)
1330{
1331 struct module_load_word *word = obj;
1332 struct ast_module *mod;
1333 char *filename_merged = NULL;
1334
1335 /* dir_name will never be shorter than word->moddir_len. */
1336 dir_name += word->moddir_len;
1337 if (!ast_strlen_zero(dir_name)) {
1338 ast_assert(dir_name[0] == '/');
1339
1340 dir_name += 1;
1341 if (ast_asprintf(&filename_merged, "%s/%s", dir_name, filename) < 0) {
1342 /* If we can't allocate the string just give up! */
1343 return -1;
1344 }
1345 filename = filename_merged;
1346 }
1347
1348 if (!strncasecmp(filename, word->word, word->len)) {
1349 /* Don't list files that are already loaded! */
1350 mod = find_resource(filename, 0);
1351 if (!mod || !mod->flags.running) {
1353 }
1354 }
1355
1356 ast_free(filename_merged);
1357
1358 return 0;
1359}
1360
1361static void module_load_helper(const char *word)
1362{
1363 struct module_load_word word_l = {
1364 .word = word,
1365 .len = strlen(word),
1366 .moddir_len = strlen(ast_config_AST_MODULE_DIR),
1367 };
1368
1372}
1373
1374char *ast_module_helper(const char *line, const char *word, int pos, int state, int rpos, enum ast_module_helper_type type)
1375{
1376 struct ast_module *mod;
1377 int which = 0;
1378 int wordlen = strlen(word);
1379 char *ret = NULL;
1380
1381 if (pos != rpos) {
1382 return NULL;
1383 }
1384
1385 /* Tab completion can't be used during startup, or CLI and loader will deadlock. */
1387 return NULL;
1388 }
1389
1392
1393 return NULL;
1394 }
1395
1398 if (!module_matches_helper_type(mod, type)) {
1399 continue;
1400 }
1401
1402 if (!strncasecmp(word, mod->resource, wordlen) && ++which > state) {
1403 ret = ast_strdup(mod->resource);
1404 break;
1405 }
1406 }
1408
1409 return ret;
1410}
1411
1413{
1414 struct reload_queue_item *item;
1415
1416 modules_loaded = 1;
1417
1419
1420 if (do_full_reload) {
1421 do_full_reload = 0;
1423 ast_log(LOG_NOTICE, "Executing deferred reload request.\n");
1425 return;
1426 }
1427
1429 ast_log(LOG_NOTICE, "Executing deferred reload request for module '%s'.\n", item->module);
1430 ast_module_reload(item->module);
1431 ast_free(item);
1432 }
1433
1435}
1436
1437static void queue_reload_request(const char *module)
1438{
1439 struct reload_queue_item *item;
1440
1442
1443 if (do_full_reload) {
1445 return;
1446 }
1447
1448 if (ast_strlen_zero(module)) {
1449 /* A full reload request (when module is NULL) wipes out any previous
1450 reload requests and causes the queue to ignore future ones */
1452 ast_free(item);
1453 }
1454 do_full_reload = 1;
1455 } else {
1456 /* No reason to add the same module twice */
1458 if (!strcasecmp(item->module, module)) {
1460 return;
1461 }
1462 }
1463 item = ast_calloc(1, sizeof(*item) + strlen(module) + 1);
1464 if (!item) {
1465 ast_log(LOG_ERROR, "Failed to allocate reload queue item.\n");
1467 return;
1468 }
1469 strcpy(item->module, module);
1471 }
1473}
1474
1475/*!
1476 * \since 12
1477 * \internal
1478 * \brief Publish a \ref stasis message regarding the type.
1479 */
1480static void publish_load_message_type(const char* type, const char *name, const char *status)
1481{
1483 RAII_VAR(struct ast_json_payload *, payload, NULL, ao2_cleanup);
1484 RAII_VAR(struct ast_json *, json_object, NULL, ast_json_unref);
1485 RAII_VAR(struct ast_json *, event_object, NULL, ast_json_unref);
1486
1487 ast_assert(type != NULL);
1490
1492 return;
1493 }
1494
1495 event_object = ast_json_pack("{s:s, s:s}",
1496 "Module", name,
1497 "Status", status);
1498 json_object = ast_json_pack("{s:s, s:i, s:o}",
1499 "type", type,
1500 "class_type", EVENT_FLAG_SYSTEM,
1501 "event", ast_json_ref(event_object));
1502 if (!json_object) {
1503 return;
1504 }
1505
1506 payload = ast_json_payload_create(json_object);
1507 if (!payload) {
1508 return;
1509 }
1510
1512 if (!message) {
1513 return;
1514 }
1515
1517}
1518
1520{
1521 int i;
1522 for (i = 0; i < ARRAY_LEN(load_results); i++) {
1523 if (load_results[i].result == result) {
1524 return load_results[i].name;
1525 }
1526 }
1527
1528 ast_log(LOG_WARNING, "Failed to find correct load result status. result %d\n", result);
1530}
1531
1532/*!
1533 * \internal
1534 * \brief Publish a \ref stasis message regarding the load result
1535 */
1537{
1538 const char *status;
1539
1541
1543}
1544
1545/*!
1546 * \internal
1547 * \brief Publish a \ref stasis message regarding the unload result
1548 */
1549static void publish_unload_message(const char *name, const char* status)
1550{
1552}
1553
1554/*!
1555 * \since 12
1556 * \internal
1557 * \brief Publish a \ref stasis message regarding the reload result
1558 */
1560{
1561 char res_buffer[8];
1562
1563 snprintf(res_buffer, sizeof(res_buffer), "%u", result);
1564 publish_load_message_type("Reload", S_OR(name, "All"), res_buffer);
1565}
1566
1568{
1569 struct ast_module *cur;
1571 size_t name_baselen = name ? resource_name_baselen(name) : 0;
1572
1573 /* If we aren't fully booted, we just pretend we reloaded but we queue this
1574 up to run once we are booted up. */
1575 if (!modules_loaded) {
1578 goto module_reload_exit;
1579 }
1580
1582 ast_verb(3, "The previous reload command didn't finish yet\n");
1584 goto module_reload_exit;
1585 }
1586 ast_sd_notify("RELOAD=1");
1588
1590 int try;
1591 int lockres;
1592 for (try = 1, lockres = AST_LOCK_TIMEOUT; try < 6 && (lockres == AST_LOCK_TIMEOUT); try++) {
1594 if (lockres == AST_LOCK_TIMEOUT) {
1595 ast_log(LOG_WARNING, "Failed to grab lock on %s, try %d\n", ast_config_AST_CONFIG_DIR, try);
1596 }
1597 }
1598 if (lockres != AST_LOCK_SUCCESS) {
1599 ast_log(AST_LOG_WARNING, "Cannot grab lock on %s\n", ast_config_AST_CONFIG_DIR);
1601 goto module_reload_done;
1602 }
1603 }
1604
1607 const struct ast_module_info *info = cur->info;
1608
1609 if (name && resource_name_match(name, name_baselen, cur->resource)) {
1610 continue;
1611 }
1612
1613 if (!cur->flags.running || cur->flags.declined) {
1614 if (res == AST_MODULE_RELOAD_NOT_FOUND) {
1616 }
1617 if (!name) {
1618 continue;
1619 }
1620 break;
1621 }
1622
1623 if (!info->reload) { /* cannot be reloaded */
1624 if (res == AST_MODULE_RELOAD_NOT_FOUND) {
1626 }
1627 if (!name) {
1628 continue;
1629 }
1630 break;
1631 }
1632 ast_verb(3, "Reloading module '%s' (%s)\n", cur->resource, info->description);
1633 if (info->reload() == AST_MODULE_LOAD_SUCCESS) {
1635 } else if (res == AST_MODULE_RELOAD_NOT_FOUND) {
1637 }
1638 if (name) {
1639 break;
1640 }
1641 }
1643
1646 }
1647module_reload_done:
1649 ast_sd_notify("READY=1");
1650
1651module_reload_exit:
1653 return res;
1654}
1655
1656static unsigned int inspect_module(const struct ast_module *mod)
1657{
1658 if (!mod->info->description) {
1659 module_load_error("Module '%s' does not provide a description.\n", mod->resource);
1660 return 1;
1661 }
1662
1663 if (!mod->info->key) {
1664 module_load_error("Module '%s' does not provide a license key.\n", mod->resource);
1665 return 1;
1666 }
1667
1668 if (verify_key((unsigned char *) mod->info->key)) {
1669 module_load_error("Module '%s' did not provide a valid license key.\n", mod->resource);
1670 return 1;
1671 }
1672
1673 if (!ast_strlen_zero(mod->info->buildopt_sum) &&
1674 strcmp(buildopt_sum, mod->info->buildopt_sum)) {
1675 module_load_error("Module '%s' was not compiled with the same compile-time options as this version of Asterisk.\n", mod->resource);
1676 module_load_error("Module '%s' will not be initialized as it may cause instability.\n", mod->resource);
1677 return 1;
1678 }
1679
1680 return 0;
1681}
1682
1684{
1685 char tmp[256];
1686 enum ast_module_load_result res;
1687
1688 if (mod->flags.running) {
1690 }
1691
1692 if (!mod->info->load) {
1693 mod->flags.declined = 1;
1694
1696 }
1697
1698 if (module_deps_reference(mod, NULL)) {
1699 struct module_vector missing;
1700 int i;
1701
1702 AST_VECTOR_INIT(&missing, 0);
1703 if (module_deps_missing_recursive(mod, &missing)) {
1704 module_load_error("%s has one or more unknown dependencies.\n", mod->info->name);
1705 }
1706 for (i = 0; i < AST_VECTOR_SIZE(&missing); i++) {
1707 module_load_error("%s loaded before dependency %s!\n", mod->info->name,
1708 AST_VECTOR_GET(&missing, i)->info->name);
1709 }
1710 AST_VECTOR_FREE(&missing);
1711
1713 }
1714
1715 if (!ast_fully_booted) {
1716 ast_verb(4, "Loading %s.\n", mod->resource);
1717 }
1718 res = mod->info->load();
1719
1720 switch (res) {
1722 if (!ast_fully_booted) {
1723 ast_verb(5, "%s => (%s)\n", mod->resource, term_color(tmp, mod->info->description, COLOR_BROWN, COLOR_BLACK, sizeof(tmp)));
1724 } else {
1725 ast_verb(4, "Loaded %s => (%s)\n", mod->resource, mod->info->description);
1726 }
1727
1728 mod->flags.running = 1;
1729 if (mod->flags.builtin) {
1730 /* Built-in modules cannot be unloaded. */
1732 }
1733
1735 break;
1737 mod->flags.declined = 1;
1738 if (mod->flags.required) {
1740 }
1741 break;
1743 mod->flags.declined = 1;
1744 break;
1745 case AST_MODULE_LOAD_SKIP: /* modules should never return this value */
1747 break;
1748 }
1749
1750 /* Make sure the newly started module is at the end of the list */
1755
1756 return res;
1757}
1758
1759/*! loads a resource based upon resource_name. If global_symbols_only is set
1760 * only modules with global symbols will be loaded.
1761 *
1762 * If the module_vector is provided (not NULL) the module is found and added to the
1763 * vector without running the module's load() function. By doing this, modules
1764 * can be initialized later in order by priority and dependencies.
1765 *
1766 * If the module_vector is not provided, the module's load function will be executed
1767 * immediately */
1768static enum ast_module_load_result load_resource(const char *resource_name, unsigned int suppress_logging,
1769 struct module_vector *module_priorities, int required, int preload)
1770{
1771 struct ast_module *mod;
1773
1774 if ((mod = find_resource(resource_name, 0))) {
1775 if (mod->flags.running) {
1776 ast_log(LOG_WARNING, "Module '%s' already loaded and running.\n", resource_name);
1778 }
1779 } else {
1780 mod = load_dynamic_module(resource_name, suppress_logging);
1781 if (!mod) {
1783 }
1784
1785 if (module_post_register(mod)) {
1786 goto prestart_error;
1787 }
1788 }
1789
1790 mod->flags.required |= required;
1791 mod->flags.preload |= preload;
1792
1793 if (inspect_module(mod)) {
1794 goto prestart_error;
1795 }
1796
1797 mod->flags.declined = 0;
1798
1799 if (module_priorities) {
1800 if (AST_VECTOR_ADD_SORTED(module_priorities, mod, module_vector_cmp)) {
1801 goto prestart_error;
1802 }
1804 } else {
1805 res = start_resource(mod);
1806 }
1807
1809 publish_load_message(resource_name, res);
1810 }
1811
1812 return res;
1813
1814prestart_error:
1815 module_load_error("Module '%s' could not be loaded.\n", resource_name);
1819 publish_load_message(resource_name, res);
1820 }
1821 return res;
1822}
1823
1824enum ast_module_load_result ast_load_resource(const char *resource_name)
1825{
1826 struct ast_module *mod;
1827 enum ast_module_load_result res;
1828
1829 /* If we're trying to load a module that previously declined to load,
1830 * transparently unload it first so we dlclose, then dlopen it afresh.
1831 * Otherwise, we won't actually load a (potentially) updated module. */
1832 mod = find_resource(resource_name, 0);
1833 if (mod && mod->flags.declined) {
1834 ast_debug(1, "Module %s previously declined to load, unloading it first before loading again\n", resource_name);
1835 ast_unload_resource(resource_name, 0);
1836 }
1837
1839 res = load_resource(resource_name, 0, NULL, 0, 0);
1840 if (!res) {
1841 ast_test_suite_event_notify("MODULE_LOAD", "Message: %s", resource_name);
1842 }
1844
1845 return res;
1846}
1847
1854};
1855
1857
1858static struct load_order_entry *add_to_load_order(const char *resource, struct load_order *load_order, int required, int preload, int builtin)
1859{
1860 struct load_order_entry *order;
1861 size_t resource_baselen = resource_name_baselen(resource);
1862
1864 if (!resource_name_match(resource, resource_baselen, order->resource)) {
1865 /* Make sure we have the proper setting for the required field
1866 (we might have both load= and required= lines in modules.conf) */
1867 order->required |= required;
1868 order->preload |= preload;
1869 return order;
1870 }
1871 }
1872
1873 order = ast_calloc(1, sizeof(*order));
1874 if (!order) {
1875 return NULL;
1876 }
1877
1878 order->resource = ast_strdup(resource);
1879 if (!order->resource) {
1880 ast_free(order);
1881
1882 return NULL;
1883 }
1884 order->required = required;
1885 order->preload = preload;
1886 order->builtin = builtin;
1888
1889 return order;
1890}
1891
1893
1895{
1896 enum ast_module_load_result lres;
1897
1898 /* Try to grab required references. */
1899 if (module_deps_reference(mod, NULL)) {
1900 /* We're likely to retry so not an error. */
1901 ast_debug(1, "Module %s is missing dependencies\n", mod->resource);
1902 return AST_MODULE_LOAD_SKIP;
1903 }
1904
1905 lres = start_resource(mod);
1906 ast_debug(3, "START: %-46s[%d] %d\n",
1907 mod->resource,
1909 lres);
1910
1911 if (lres == AST_MODULE_LOAD_SUCCESS) {
1912 (*count)++;
1913 } else if (lres == AST_MODULE_LOAD_FAILURE) {
1914 module_load_error("*** Failed to load %smodule %s\n",
1915 mod->flags.required ? "required " : "",
1916 mod->resource);
1917 }
1918
1919 return lres;
1920}
1921
1923 struct ast_str **printmissing)
1924{
1925 struct module_vector missingdeps;
1926 struct ast_vector_const_string localdeps;
1927 int i = 0;
1928 int res = -1;
1929
1930 mod->flags.declined = 1;
1931 if (mod->flags.required) {
1932 module_load_error("Required module %s declined to load.\n", ast_module_name(mod));
1933
1934 return -2;
1935 }
1936
1937 module_load_error("%s declined to load.\n", ast_module_name(mod));
1938
1939 if (!*printmissing) {
1940 *printmissing = ast_str_create(64);
1941 if (!*printmissing) {
1942 return -1;
1943 }
1944 } else {
1945 ast_str_reset(*printmissing);
1946 }
1947
1948 AST_VECTOR_INIT(&missingdeps, 0);
1949 AST_VECTOR_INIT(&localdeps, 0);
1950
1951 /* Decline everything that depends on 'mod' from resources so we can
1952 * print a concise list. */
1953 while (res != -2 && i < AST_VECTOR_SIZE(resources)) {
1954 struct ast_module *dep = AST_VECTOR_GET(resources, i);
1955 i++;
1956
1958 if (dep->flags.declined || module_deps_missing_recursive(dep, &missingdeps)) {
1959 continue;
1960 }
1961
1962 if (AST_VECTOR_GET_CMP(&missingdeps, mod, AST_VECTOR_ELEM_DEFAULT_CMP)) {
1963 dep->flags.declined = 1;
1964 if (dep->flags.required) {
1965 module_load_error("Cannot load required module %s that depends on %s\n",
1966 ast_module_name(dep), ast_module_name(mod));
1967 res = -2;
1968 } else {
1969 AST_VECTOR_APPEND(&localdeps, ast_module_name(dep));
1970 }
1971 }
1972 }
1973 AST_VECTOR_FREE(&missingdeps);
1974
1975 if (res != -2 && AST_VECTOR_SIZE(&localdeps)) {
1976 AST_VECTOR_CALLBACK_VOID(&localdeps, STR_APPEND_TEXT, printmissing);
1977 module_load_error("Declined modules which depend on %s: %s\n",
1978 ast_module_name(mod), ast_str_buffer(*printmissing));
1979 }
1980 AST_VECTOR_FREE(&localdeps);
1981
1982 return res;
1983}
1984
1985static int start_resource_list(struct module_vector *resources, int *mod_count)
1986{
1987 struct module_vector missingdeps;
1988 int res = 0;
1989 struct ast_str *printmissing = NULL;
1990
1991 AST_VECTOR_INIT(&missingdeps, 0);
1992 while (res != -2 && AST_VECTOR_SIZE(resources)) {
1993 struct ast_module *mod = AST_VECTOR_REMOVE(resources, 0, 1);
1994 enum ast_module_load_result lres;
1995
1996 if (mod->flags.declined) {
1997 ast_debug(1, "%s is already declined, skipping\n", ast_module_name(mod));
1998 continue;
1999 }
2000
2001retry_load:
2002 lres = start_resource_attempt(mod, mod_count);
2003 if (lres == AST_MODULE_LOAD_SUCCESS) {
2004 /* No missing dependencies, successful. */
2005 continue;
2006 }
2007
2008 if (lres == AST_MODULE_LOAD_FAILURE) {
2009 res = -2;
2010 break;
2011 }
2012
2013 if (lres == AST_MODULE_LOAD_DECLINE) {
2014 res = resource_list_recursive_decline(resources, mod, &printmissing);
2015 continue;
2016 }
2017
2018 if (module_deps_missing_recursive(mod, &missingdeps)) {
2020 module_load_error("Failed to resolve dependencies for %s\n", ast_module_name(mod));
2021 res = resource_list_recursive_decline(resources, mod, &printmissing);
2022 continue;
2023 }
2024
2025 if (!AST_VECTOR_SIZE(&missingdeps)) {
2026 module_load_error("%s load function returned an invalid result. "
2027 "This is a bug in the module.\n", ast_module_name(mod));
2028 /* Dependencies were met but the module failed to start and the result
2029 * code was not AST_MODULE_LOAD_FAILURE or AST_MODULE_LOAD_DECLINE. */
2030 res = resource_list_recursive_decline(resources, mod, &printmissing);
2031 continue;
2032 }
2033
2034 ast_debug(1, "%s has %d dependencies\n",
2035 ast_module_name(mod), (int)AST_VECTOR_SIZE(&missingdeps));
2036 while (AST_VECTOR_SIZE(&missingdeps)) {
2037 int didwork = 0;
2038 int i = 0;
2039
2040 while (i < AST_VECTOR_SIZE(&missingdeps)) {
2041 struct ast_module *dep = AST_VECTOR_GET(&missingdeps, i);
2042
2043 if (dep->flags.declined) {
2044 ast_debug(1, "%s tried to start %s but it's already declined\n",
2045 ast_module_name(mod), ast_module_name(dep));
2046 i++;
2047 continue;
2048 }
2049
2050 ast_debug(1, "%s trying to start %s\n", ast_module_name(mod), ast_module_name(dep));
2051 lres = start_resource_attempt(dep, mod_count);
2052 if (lres == AST_MODULE_LOAD_SUCCESS) {
2053 ast_debug(1, "%s started %s\n", ast_module_name(mod), ast_module_name(dep));
2054 AST_VECTOR_REMOVE(&missingdeps, i, 1);
2057 didwork++;
2058 continue;
2059 }
2060
2061 if (lres == AST_MODULE_LOAD_FAILURE) {
2062 module_load_error("Failed to load %s.\n", ast_module_name(dep));
2063 res = -2;
2064 goto exitpoint;
2065 }
2066
2067 ast_debug(1, "%s failed to start %s\n", ast_module_name(mod), ast_module_name(dep));
2068 i++;
2069 }
2070
2071 if (!didwork) {
2072 break;
2073 }
2074 }
2075
2076 if (AST_VECTOR_SIZE(&missingdeps)) {
2077 if (!printmissing) {
2078 printmissing = ast_str_create(64);
2079 } else {
2080 ast_str_reset(printmissing);
2081 }
2082
2083 if (printmissing) {
2084 struct ast_vector_const_string localdeps;
2085
2086 AST_VECTOR_INIT(&localdeps, 0);
2087 module_deps_reference(mod, &localdeps);
2088 AST_VECTOR_CALLBACK_VOID(&localdeps, STR_APPEND_TEXT, &printmissing);
2089 AST_VECTOR_FREE(&localdeps);
2090 }
2091
2092 module_load_error("Failed to load %s due to dependencies: %s.\n",
2093 ast_module_name(mod),
2094 printmissing ? ast_str_buffer(printmissing) : "allocation failure creating list");
2095 res = resource_list_recursive_decline(resources, mod, &printmissing);
2096
2098
2099 continue;
2100 }
2101
2102 /* If we're here it means that we started with missingdeps and they're all loaded
2103 * now. It's impossible to reach this point a second time for the same module. */
2104 goto retry_load;
2105 }
2106
2107exitpoint:
2108 ast_free(printmissing);
2109 AST_VECTOR_FREE(&missingdeps);
2110
2111 return res;
2112}
2113
2114/*! loads modules in order by load_pri, updates mod_count
2115 \return -1 on failure to load module, -2 on failure to load required module, otherwise 0
2116*/
2117static int load_resource_list(struct load_order *load_order, int *mod_count)
2118{
2119 struct module_vector module_priorities;
2120 struct load_order_entry *order;
2121 int attempt = 0;
2122 int count = 0;
2123 int res = 0;
2124 int didwork;
2125 int lasttry = 0;
2126
2127 if (AST_VECTOR_INIT(&module_priorities, 500)) {
2128 ast_log(LOG_ERROR, "Failed to initialize module loader.\n");
2129
2130 return -1;
2131 }
2132
2133 while (res != -2) {
2134 didwork = 0;
2135
2137 enum ast_module_load_result lres;
2138
2139 /* Suppress log messages unless this is the last pass */
2140 lres = load_resource(order->resource, !lasttry, &module_priorities, order->required, order->preload);
2141 ast_debug(3, "PASS %d: %-46s %d\n", attempt, order->resource, lres);
2142 switch (lres) {
2145 /* We're supplying module_priorities so SUCCESS isn't possible but we
2146 * still have to test for it. SKIP is only used when we try to start a
2147 * module that is missing dependencies. */
2148 break;
2150 res = -1;
2151 break;
2153 /* LOAD_FAILURE only happens for required modules */
2154 if (lasttry) {
2155 /* This run is just to print errors. */
2156 module_load_error("*** Failed to load module %s - Required\n", order->resource);
2157 fprintf(stderr, "*** Failed to load module %s - Required\n", order->resource);
2158 res = -2;
2159 }
2160 break;
2162 /* load_resource worked and the module was added to module_priorities */
2164 ast_free(order->resource);
2165 ast_free(order);
2166 didwork = 1;
2167 break;
2168 }
2169 }
2171
2172 if (!didwork) {
2173 if (lasttry) {
2174 break;
2175 }
2176 /* We know the next try is going to fail, it's only being performed
2177 * so we can print errors. */
2178 lasttry = 1;
2179 }
2180 attempt++;
2181 }
2182
2183 if (res != -2) {
2184 res = start_resource_list(&module_priorities, &count);
2185 }
2186
2187 if (mod_count) {
2188 *mod_count += count;
2189 }
2190 AST_VECTOR_FREE(&module_priorities);
2191
2192 return res;
2193}
2194
2196{
2197 struct ast_module *mod;
2198
2199 /*
2200 * All built-in modules have registered the first time, now it's time to complete
2201 * the registration and add them to the priority list.
2202 */
2203 loader_ready = 1;
2204
2206 /* ast_module_register doesn't finish when first run by built-in modules. */
2208 }
2209
2210 /* Add all built-in modules to the load order. */
2212 if (!mod->flags.builtin) {
2213 continue;
2214 }
2215
2216 /* Parse dependendencies from mod->info. */
2217 if (module_post_register(mod)) {
2218 return -1;
2219 }
2220
2221 /* Built-in modules are not preloaded, most have an early load priority. */
2222 if (!add_to_load_order(mod->resource, load_order, 0, 0, 1)) {
2223 return -1;
2224 }
2225 }
2226
2227 return 0;
2228}
2229
2231{
2232 int res = -1;
2233 struct load_order_entry *order;
2234 struct ast_config *cfg;
2235 struct ast_variable *v;
2236 struct ast_flags config_flags = { 0 };
2237
2238 cfg = ast_config_load2(AST_MODULE_CONFIG, "" /* core, can't reload */, config_flags);
2240 ast_log(LOG_WARNING, "'%s' invalid or missing.\n", AST_MODULE_CONFIG);
2241
2242 return -1;
2243 }
2244
2245 /* first, find all the modules we have been explicitly requested to load */
2246 for (v = ast_variable_browse(cfg, "modules"); v; v = v->next) {
2247 int required;
2248 int preload = 0;
2249
2250 if (!strncasecmp(v->name, "preload", strlen("preload"))) {
2251 preload = 1;
2252 if (!strcasecmp(v->name, "preload")) {
2253 required = 0;
2254 } else if (!strcasecmp(v->name, "preload-require")) {
2255 required = 1;
2256 } else {
2257 ast_log(LOG_ERROR, "Unknown configuration option '%s'", v->name);
2258 goto done;
2259 }
2260 } else if (!strcasecmp(v->name, "load")) {
2261 required = 0;
2262 } else if (!strcasecmp(v->name, "require")) {
2263 required = 1;
2264 } else if (!strcasecmp(v->name, "noload") || !strcasecmp(v->name, "autoload")) {
2265 continue;
2266 } else {
2267 ast_log(LOG_ERROR, "Unknown configuration option '%s'", v->name);
2268 goto done;
2269 }
2270
2271 if (required) {
2272 ast_debug(2, "Adding module to required list: %s (%s)\n", v->value, v->name);
2273 }
2274
2275 if (!add_to_load_order(v->value, load_order, required, preload, 0)) {
2276 goto done;
2277 }
2278 }
2279
2280 /* check if 'autoload' is on */
2281 if (ast_true(ast_variable_retrieve(cfg, "modules", "autoload"))) {
2282 /* if we are allowed to load dynamic modules, scan the directory for
2283 for all available modules and add them as well */
2284 DIR *dir = opendir(ast_config_AST_MODULE_DIR);
2285 struct dirent *dirent;
2286
2287 if (dir) {
2288 while ((dirent = readdir(dir))) {
2289 int ld = strlen(dirent->d_name);
2290
2291 /* Must end in .so to load it. */
2292
2293 if (ld < 4)
2294 continue;
2295
2296 if (strcasecmp(dirent->d_name + ld - 3, ".so"))
2297 continue;
2298
2299 /* if there is already a module by this name in the module_list,
2300 skip this file */
2301 if (find_resource(dirent->d_name, 0))
2302 continue;
2303
2304 if (!add_to_load_order(dirent->d_name, load_order, 0, 0, 0)) {
2305 closedir(dir);
2306 goto done;
2307 }
2308 }
2309
2310 closedir(dir);
2311 } else {
2312 ast_log(LOG_ERROR, "Unable to open modules directory '%s'.\n", ast_config_AST_MODULE_DIR);
2313 goto done;
2314 }
2315 }
2316
2317 /* now scan the config for any modules we are prohibited from loading and
2318 remove them from the load order */
2319 for (v = ast_variable_browse(cfg, "modules"); v; v = v->next) {
2320 size_t baselen;
2321
2322 if (strcasecmp(v->name, "noload")) {
2323 continue;
2324 }
2325
2326 baselen = resource_name_baselen(v->value);
2328 if (!resource_name_match(v->value, baselen, order->resource)) {
2329 if (order->builtin) {
2330 ast_log(LOG_ERROR, "%s is a built-in module, you cannot specify 'noload'.\n", v->value);
2331 goto done;
2332 }
2333
2334 if (order->required) {
2335 ast_log(LOG_ERROR, "%s is configured with '%s' and 'noload', this is impossible.\n",
2336 v->value, order->preload ? "preload-require" : "require");
2337 goto done;
2338 }
2340 ast_free(order->resource);
2341 ast_free(order);
2342 }
2343 }
2345 }
2346
2347 res = 0;
2348done:
2349 ast_config_destroy(cfg);
2350
2351 return res;
2352}
2353
2355{
2356 struct load_order_entry *order;
2357 unsigned int load_count;
2358 struct load_order load_order;
2359 int res = 0;
2360 int modulecount = 0;
2361 int i;
2362 struct ast_module *cur;
2363#ifdef AST_XML_DOCS
2364 struct ast_str *warning_msg;
2365 char deprecated_in[33];
2366 char removed_in[33];
2367 char replacement[129];
2368#endif
2369 struct timeval start_time = ast_tvnow();
2370 struct timeval end_time;
2371 int64_t usElapsed;
2372
2373 ast_verb(1, "Asterisk Dynamic Loader Starting:\n");
2374
2375#if defined(HAVE_PERMANENT_DLOPEN)
2377 info_list_obj_cmp_fn); /* must not be cleaned at shutdown */
2378 if (!info_list) {
2379 fprintf(stderr, "Module info list allocation failure.\n");
2380 return 1;
2381 }
2382#endif
2383
2386
2389
2391 if (res) {
2392 goto done;
2393 }
2394
2396 if (res) {
2397 goto done;
2398 }
2399
2400 load_count = 0;
2402 load_count++;
2403
2404 if (load_count)
2405 ast_log(LOG_NOTICE, "%u modules will be loaded.\n", load_count);
2406
2407 res = load_resource_list(&load_order, &modulecount);
2408 if (res == -1) {
2409 ast_log(LOG_WARNING, "Some non-required modules failed to load.\n");
2410 res = 0;
2411 }
2412
2413done:
2415 ast_free(order->resource);
2416 ast_free(order);
2417 }
2418
2419#ifdef AST_XML_DOCS
2420 warning_msg = ast_str_create(512);
2421#endif
2422
2424#ifdef AST_XML_DOCS
2425 char *mod_name = NULL;
2426 struct ast_xml_xpath_results *results;
2427#endif
2428
2429 if (!cur->flags.running || cur->flags.declined) {
2430 continue;
2431 }
2432
2433#ifdef AST_XML_DOCS
2434 mod_name = get_name_from_resource(cur->resource);
2435 if (!warning_msg || !mod_name) {
2436 /* If we can't allocate memory, we have bigger issues */
2437 ast_free(mod_name);
2438 continue;
2439 }
2440
2441 /* Clear out the previous values */
2442 deprecated_in[0] = removed_in[0] = replacement[0] = 0;
2443
2444 results = ast_xmldoc_query("/docs/module[@name='%s']", mod_name);
2445 if (results) {
2446 struct ast_xml_node *deprecated_node, *removed_node, *replacement_node;
2447 struct ast_xml_node *metadata_nodes = ast_xml_node_get_children(ast_xml_xpath_get_first_result(results));
2448
2449 deprecated_node = ast_xml_find_element(metadata_nodes, "deprecated_in", NULL, NULL);
2450 if (deprecated_node) {
2451 const char *result_tmp = ast_xml_get_text(deprecated_node);
2452 if (!ast_strlen_zero(result_tmp)) {
2453 ast_copy_string(deprecated_in, result_tmp, sizeof(deprecated_in));
2454 }
2455 }
2456
2457 removed_node = ast_xml_find_element(metadata_nodes, "removed_in", NULL, NULL);
2458 if (removed_node) {
2459 const char *result_tmp = ast_xml_get_text(removed_node);
2460 if (!ast_strlen_zero(result_tmp)) {
2461 ast_copy_string(removed_in, result_tmp, sizeof(removed_in));
2462 }
2463 }
2464
2465 replacement_node = ast_xml_find_element(metadata_nodes, "replacement", NULL, NULL);
2466 if (replacement_node) {
2467 const char *result_tmp = ast_xml_get_text(replacement_node);
2468 if (!ast_strlen_zero(result_tmp)) {
2469 ast_copy_string(replacement, result_tmp, sizeof(replacement));
2470 }
2471 }
2472
2474 }
2475
2476 ast_str_reset(warning_msg);
2477
2478 if (cur->info->support_level == AST_MODULE_SUPPORT_DEPRECATED || !ast_strlen_zero(deprecated_in)
2479 || !ast_strlen_zero(removed_in) || !ast_strlen_zero(replacement)) {
2480 int already_butted = 0;
2481
2482 ast_str_append(&warning_msg, -1, "Module '%s' has been loaded", mod_name);
2483 if (!ast_strlen_zero(deprecated_in)) {
2484 ast_str_append(&warning_msg, -1, " but %s deprecated in Asterisk version %s",
2485 cur->info->support_level == AST_MODULE_SUPPORT_DEPRECATED ? "was" : "will be", deprecated_in);
2486 already_butted = 1;
2487 }
2488
2489 if (!ast_strlen_zero(removed_in)) {
2490 ast_str_append(&warning_msg, -1, " %s will be removed in Asterisk version %s", already_butted ? "and" : "but", removed_in);
2491 } else {
2492 ast_str_append(&warning_msg, -1, " %s may be removed in a future release", already_butted ? "and" : "but");
2493 }
2494
2495 ast_str_append(&warning_msg, -1, ".");
2496
2497 if (!ast_strlen_zero(replacement)) {
2498 ast_str_append(&warning_msg, -1, " Its replacement is '%s'.", replacement);
2499 }
2500 }
2501
2502 if (ast_str_strlen(warning_msg)) {
2503 ast_log(LOG_WARNING, "%s\n", ast_str_buffer(warning_msg));
2504 }
2505
2506 ast_free(mod_name);
2507#else
2509 ast_log(LOG_WARNING, "The deprecated module '%s' has been loaded and is running, it may be removed in a future version\n", cur->resource);
2510 }
2511#endif
2512 }
2513
2514#ifdef AST_XML_DOCS
2515 ast_free(warning_msg);
2516#endif
2517
2519
2520
2521 for (i = 0; i < AST_VECTOR_SIZE(&startup_errors); i++) {
2522 char *str = AST_VECTOR_GET(&startup_errors, i);
2523
2524 ast_log(LOG_ERROR, "%s", str);
2525 ast_free(str);
2526 }
2528
2531
2532 end_time = ast_tvnow();
2533 usElapsed = ast_tvdiff_us(end_time, start_time);
2534
2535#ifdef AST_XML_DOCS
2536 ast_debug(1, "Loader time with AST_XML_DOCS: %" PRId64 ".%06" PRId64 "\n", usElapsed / 1000000, usElapsed % 1000000);
2537#else
2538 ast_debug(1, "Loader time without AST_XML_DOCS: %" PRId64 ".%06" PRId64 "\n", usElapsed / 1000000, usElapsed % 1000000);
2539#endif
2540
2541 return res;
2542}
2543
2545{
2546 /* Notify any module monitors that the use count for a
2547 resource has changed */
2548 struct loadupdate *m;
2549
2552 m->updater();
2554}
2555
2556/*!
2557 * \internal
2558 * \brief Build an alpha sorted list of modules.
2559 *
2560 * \param alpha_module_list Pointer to uninitialized module_vector.
2561 *
2562 * This function always initializes alpha_module_list.
2563 *
2564 * \pre module_list must be locked.
2565 */
2566static int alpha_module_list_create(struct module_vector *alpha_module_list)
2567{
2568 struct ast_module *cur;
2569
2570 if (AST_VECTOR_INIT(alpha_module_list, 32)) {
2571 return -1;
2572 }
2573
2575 if (AST_VECTOR_ADD_SORTED(alpha_module_list, cur, module_vector_strcasecmp)) {
2576 return -1;
2577 }
2578 }
2579
2580 return 0;
2581}
2582
2583int ast_update_module_list(int (*modentry)(const char *module, const char *description,
2584 int usecnt, const char *status, const char *like,
2585 enum ast_module_support_level support_level),
2586 const char *like)
2587{
2588 int total_mod_loaded = 0;
2589 struct module_vector alpha_module_list;
2590
2592
2593 if (!alpha_module_list_create(&alpha_module_list)) {
2594 int idx;
2595
2596 for (idx = 0; idx < AST_VECTOR_SIZE(&alpha_module_list); idx++) {
2597 struct ast_module *cur = AST_VECTOR_GET(&alpha_module_list, idx);
2598
2599 total_mod_loaded += modentry(cur->resource, cur->info->description, cur->usecount,
2600 cur->flags.running ? "Running" : "Not Running", like, cur->info->support_level);
2601 }
2602 }
2603
2605 AST_VECTOR_FREE(&alpha_module_list);
2606
2607 return total_mod_loaded;
2608}
2609
2610int ast_update_module_list_data(int (*modentry)(const char *module, const char *description,
2611 int usecnt, const char *status, const char *like,
2612 enum ast_module_support_level support_level,
2613 void *data),
2614 const char *like, void *data)
2615{
2616 int total_mod_loaded = 0;
2617 struct module_vector alpha_module_list;
2618
2620
2621 if (!alpha_module_list_create(&alpha_module_list)) {
2622 int idx;
2623
2624 for (idx = 0; idx < AST_VECTOR_SIZE(&alpha_module_list); idx++) {
2625 struct ast_module *cur = AST_VECTOR_GET(&alpha_module_list, idx);
2626
2627 total_mod_loaded += modentry(cur->resource, cur->info->description, cur->usecount,
2628 cur->flags.running? "Running" : "Not Running", like, cur->info->support_level, data);
2629 }
2630 }
2631
2633 AST_VECTOR_FREE(&alpha_module_list);
2634
2635 return total_mod_loaded;
2636}
2637
2638int ast_update_module_list_condition(int (*modentry)(const char *module, const char *description,
2639 int usecnt, const char *status,
2640 const char *like,
2641 enum ast_module_support_level support_level,
2642 void *data, const char *condition),
2643 const char *like, void *data, const char *condition)
2644{
2645 int conditions_met = 0;
2646 struct module_vector alpha_module_list;
2647
2649
2650 if (!alpha_module_list_create(&alpha_module_list)) {
2651 int idx;
2652
2653 for (idx = 0; idx < AST_VECTOR_SIZE(&alpha_module_list); idx++) {
2654 struct ast_module *cur = AST_VECTOR_GET(&alpha_module_list, idx);
2655
2656 conditions_met += modentry(cur->resource, cur->info->description, cur->usecount,
2657 cur->flags.running? "Running" : "Not Running", like, cur->info->support_level, data,
2658 condition);
2659 }
2660 }
2661
2663 AST_VECTOR_FREE(&alpha_module_list);
2664
2665 return conditions_met;
2666}
2667
2668/*! \brief Check if module exists */
2669int ast_module_check(const char *name)
2670{
2671 struct ast_module *cur;
2672
2673 if (ast_strlen_zero(name))
2674 return 0; /* FALSE */
2675
2676 cur = find_resource(name, 1);
2677
2678 return (cur != NULL);
2679}
2680
2681
2682int ast_loader_register(int (*v)(void))
2683{
2684 struct loadupdate *tmp;
2685
2686 if (!(tmp = ast_malloc(sizeof(*tmp))))
2687 return -1;
2688
2689 tmp->updater = v;
2693
2694 return 0;
2695}
2696
2697int ast_loader_unregister(int (*v)(void))
2698{
2699 struct loadupdate *cur;
2700
2703 if (cur->updater == v) {
2705 break;
2706 }
2707 }
2710
2711 return cur ? 0 : -1;
2712}
2713
2714struct ast_module *__ast_module_ref(struct ast_module *mod, const char *file, int line, const char *func)
2715{
2716 if (!mod) {
2717 return NULL;
2718 }
2719
2720 if (mod->ref_debug) {
2721 __ao2_ref(mod->ref_debug, +1, "", file, line, func);
2722 }
2723
2726
2727 return mod;
2728}
2729
2731 const char *file, int line, const char *func)
2732{
2733 if (!mod || !mod->flags.running) {
2734 return NULL;
2735 }
2736
2737 return __ast_module_ref(mod, file, line, func);
2738}
2739
2740void __ast_module_shutdown_ref(struct ast_module *mod, const char *file, int line, const char *func)
2741{
2742 if (!mod || mod->flags.keepuntilshutdown) {
2743 return;
2744 }
2745
2746 __ast_module_ref(mod, file, line, func);
2747 mod->flags.keepuntilshutdown = 1;
2748}
2749
2750void __ast_module_unref(struct ast_module *mod, const char *file, int line, const char *func)
2751{
2752 if (!mod) {
2753 return;
2754 }
2755
2756 if (mod->ref_debug) {
2757 __ao2_ref(mod->ref_debug, -1, "", file, line, func);
2758 }
2759
2762}
2763
2764const char *support_level_map [] = {
2765 [AST_MODULE_SUPPORT_UNKNOWN] = "unknown",
2766 [AST_MODULE_SUPPORT_CORE] = "core",
2767 [AST_MODULE_SUPPORT_EXTENDED] = "extended",
2768 [AST_MODULE_SUPPORT_DEPRECATED] = "deprecated",
2769};
2770
2772{
2773 return support_level_map[support_level];
2774}
Prototypes for public functions only of internal interest,.
integer order
Definition: analys.c:66
jack_status_t status
Definition: app_jack.c:146
const char * str
Definition: app_jack.c:147
static int copy(char *infile, char *outfile)
Utility function to copy a file.
Asterisk main include file. File version handling, generic pbx functions.
int ast_shutdown_final(void)
Definition: asterisk.c:1867
#define PATH_MAX
Definition: asterisk.h:40
void ast_std_free(void *ptr)
Definition: astmm.c:1734
#define ast_free(a)
Definition: astmm.h:180
void * ast_std_calloc(size_t nmemb, size_t size) attribute_malloc
Definition: astmm.c:1724
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:241
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
#define ast_asprintf(ret, fmt,...)
A wrapper for asprintf()
Definition: astmm.h:267
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
#define ast_malloc(len)
A wrapper for malloc()
Definition: astmm.h:191
#define ast_log
Definition: astobj2.c:42
#define ao2_link(container, obj)
Add an object to a container.
Definition: astobj2.h:1532
@ AO2_ALLOC_OPT_LOCK_NOLOCK
Definition: astobj2.h:367
#define AO2_STRING_FIELD_CMP_FN(stype, field)
Creates a compare function for a structure string field.
Definition: astobj2.h:2048
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
#define ao2_t_alloc_options(data_size, destructor_fn, options, debug_msg)
Allocate and initialize an object.
Definition: astobj2.h:402
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1736
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
int __ao2_ref(void *o, int delta, const char *tag, const char *file, int line, const char *func)
Definition: astobj2.c:498
@ OBJ_SEARCH_KEY
The arg parameter is a search key, but is not an object.
Definition: astobj2.h:1101
#define ao2_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn)
Allocate and initialize a list container.
Definition: astobj2.h:1327
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:409
static int tmp()
Definition: bt_open.c:389
static PGresult * result
Definition: cel_pgsql.c:84
static int usecnt
Definition: chan_ooh323.c:332
static const char type[]
Definition: chan_ooh323.c:109
General Asterisk PBX channel definitions.
int ast_softhangup(struct ast_channel *chan, int cause)
Softly hangup up a channel.
Definition: channel.c:2471
@ AST_SOFTHANGUP_APPUNLOAD
Definition: channel.h:1143
Standard Command Line Interface.
int ast_cli_completion_add(char *value)
Add a result to a request for completion options.
Definition: main/cli.c:2756
short word
A set of macros to manage doubly-linked lists.
#define AST_DLLIST_TRAVERSE_BACKWARDS_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
Definition: dlinkedlists.h:888
#define AST_DLLIST_EMPTY(head)
Checks whether the specified list contains any entries.
Definition: dlinkedlists.h:469
#define AST_DLLIST_ENTRY(type)
Declare previous/forward links inside a list entry.
Definition: dlinkedlists.h:413
#define AST_DLLIST_LOCK(head)
Locks a list.
Definition: dlinkedlists.h:46
#define AST_DLLIST_HEAD_STATIC(name, type)
Defines a structure to be used to hold a list of specified type, statically initialized.
Definition: dlinkedlists.h:285
#define AST_DLLIST_REMOVE(head, elm, field)
Removes a specific entry from a list.
#define AST_DLLIST_UNLOCK(head)
Attempts to unlock a list.
Definition: dlinkedlists.h:123
#define AST_DLLIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
#define AST_DLLIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: dlinkedlists.h:576
#define AST_DLLIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
Definition: dlinkedlists.h:753
#define AST_DLLIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
#define AST_DLLIST_HEAD(name, type)
Defines a structure to be used to hold a list of specified type.
Definition: dlinkedlists.h:158
#define AST_DLLIST_TRAVERSE_BACKWARDS_SAFE_END
Closes a safe loop traversal block.
Definition: dlinkedlists.h:921
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
int ast_file_read_dirs(const char *dir_name, ast_file_on_file on_file, void *obj, int max_depth)
Recursively iterate through files and directories up to max_depth.
Definition: file.c:1274
static const char name[]
Definition: format_mp3.c:68
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
struct stasis_topic * ast_manager_get_topic(void)
Get the Stasis Message Bus API topic for AMI.
Definition: manager.c:1872
struct ast_flags ast_options
Definition: options.c:61
@ AST_OPT_FLAG_FULLY_BOOTED
Definition: options.h:58
Application convenience functions, designed to give consistent look and feel to Asterisk apps.
@ AST_LOCK_SUCCESS
@ AST_LOCK_TIMEOUT
enum AST_LOCK_RESULT ast_lock_path(const char *path)
Lock a filesystem path.
Definition: main/app.c:2604
int ast_unlock_path(const char *path)
Unlock a path.
Definition: main/app.c:2620
Configuration File Parser.
struct ast_config * ast_config_load2(const char *filename, const char *who_asked, struct ast_flags flags)
Load a config file.
Definition: main/config.c:3321
#define CONFIG_STATUS_FILEMISSING
#define CONFIG_STATUS_FILEINVALID
void ast_config_destroy(struct ast_config *cfg)
Destroys a config.
Definition: extconf.c:1289
const char * ast_variable_retrieve(struct ast_config *config, const char *category, const char *variable)
Definition: main/config.c:783
struct ast_variable * ast_variable_browse(const struct ast_config *config, const char *category_name)
Definition: extconf.c:1215
#define AST_LOG_WARNING
#define AST_LOG_ERROR
#define ast_debug(level,...)
Log a DEBUG message.
void ast_log_ap(int level, const char *file, int line, const char *function, const char *fmt, va_list ap)
Definition: logger.c:2450
#define LOG_ERROR
#define ast_verb(level,...)
#define LOG_NOTICE
#define LOG_WARNING
I/O Management (derived from Cheops-NG)
int ast_sd_notify(const char *state)
a wrapper for sd_notify(): notify systemd of any state changes.
Definition: io.c:392
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
Definition: json.c:73
struct ast_json_payload * ast_json_payload_create(struct ast_json *json)
Create an ao2 object to pass json blobs as data payloads for stasis.
Definition: json.c:756
struct ast_json * ast_json_pack(char const *format,...)
Helper for creating complex JSON values.
Definition: json.c:612
struct ast_json * ast_json_ref(struct ast_json *value)
Increase refcount on value.
Definition: json.c:67
#define AST_LIST_HEAD_INIT_NOLOCK(head)
Initializes a list head structure.
Definition: linkedlists.h:681
#define AST_LIST_HEAD_NOLOCK(name, type)
Defines a structure to be used to hold a list of specified type (with no lock).
Definition: linkedlists.h:225
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:491
#define AST_LIST_HEAD_DESTROY(head)
Destroys a list head structure.
Definition: linkedlists.h:653
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:731
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
Definition: linkedlists.h:410
#define AST_LIST_HEAD_INIT(head)
Initializes a list head structure.
Definition: linkedlists.h:626
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
Definition: linkedlists.h:615
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:40
#define AST_LIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
Definition: linkedlists.h:711
#define AST_LIST_REMOVE(head, elm, field)
Removes a specific entry from a list.
Definition: linkedlists.h:856
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
Definition: linkedlists.h:529
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
Definition: linkedlists.h:557
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:833
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:140
void __ast_module_unref(struct ast_module *mod, const char *file, int line, const char *func)
Definition: loader.c:2750
int ast_update_module_list(int(*modentry)(const char *module, const char *description, int usecnt, const char *status, const char *like, enum ast_module_support_level support_level), const char *like)
Ask for a list of modules, descriptions, use counts and status.
Definition: loader.c:2583
static void publish_unload_message(const char *name, const char *status)
Definition: loader.c:1549
void ast_process_pending_reloads(void)
Process reload requests received during startup.
Definition: loader.c:1412
int modules_shutdown(void)
Definition: loader.c:1172
struct ast_module * __ast_module_ref(struct ast_module *mod, const char *file, int line, const char *func)
Definition: loader.c:2714
static struct load_order_entry * add_to_load_order(const char *resource, struct load_order *load_order, int required, int preload, int builtin)
Definition: loader.c:1858
void __ast_module_user_remove(struct ast_module *mod, struct ast_module_user *u)
Definition: loader.c:826
void __ast_module_user_hangup_all(struct ast_module *mod)
Definition: loader.c:853
int ast_module_check(const char *name)
Check if module exists.
Definition: loader.c:2669
static int start_resource_list(struct module_vector *resources, int *mod_count)
Definition: loader.c:1985
int load_modules(void)
Definition: loader.c:2354
static int module_load_helper_on_file(const char *dir_name, const char *filename, void *obj)
Definition: loader.c:1329
#define RTLD_LOCAL
Definition: loader.c:124
void ast_update_use_count(void)
Notify when usecount has been changed.
Definition: loader.c:2544
const char * ast_module_support_level_to_string(enum ast_module_support_level support_level)
Definition: loader.c:2771
static void logged_dlclose(const char *name, void *lib)
dlclose(), with failure logging.
Definition: loader.c:952
void ast_module_register(const struct ast_module_info *info)
Definition: loader.c:659
void ast_module_unregister(const struct ast_module_info *info)
Definition: loader.c:768
static int modules_loaded
Internal flag to indicate all modules have been initially loaded.
Definition: loader.c:291
static int module_post_register(struct ast_module *mod)
Definition: loader.c:732
static ast_mutex_t reloadlock
Definition: loader.c:631
const char * support_level_map[]
Definition: loader.c:2764
static int load_resource_list(struct load_order *load_order, int *mod_count)
Definition: loader.c:2117
static struct ast_module * load_dynamic_module(const char *resource_in, unsigned int suppress_logging)
Definition: loader.c:1145
static void publish_load_message_type(const char *type, const char *name, const char *status)
Definition: loader.c:1480
static int module_deps_reference(struct ast_module *mod, struct ast_vector_const_string *missing)
Definition: loader.c:534
static struct ast_module * find_resource(const char *resource, int do_lock)
Definition: loader.c:927
static void unload_dynamic_module(struct ast_module *mod)
Definition: loader.c:1000
static int resource_name_match(const char *name1, size_t baselen1, const char *name2)
Definition: loader.c:918
static unsigned int loader_ready
Definition: loader.c:150
static int module_deps_missing_recursive(struct ast_module *mod, struct module_vector *missingdeps)
Recursively find required dependencies that are not running.
Definition: loader.c:566
static char buildopt_sum[33]
Definition: loader.c:138
static struct ast_vector_string startup_errors
Definition: loader.c:153
static const unsigned char expected_key[]
Definition: loader.c:134
char * ast_module_helper(const char *line, const char *word, int pos, int state, int rpos, enum ast_module_helper_type type)
Match modules names for the Asterisk cli.
Definition: loader.c:1374
static int do_full_reload
Definition: loader.c:638
enum ast_module_load_result ast_load_resource(const char *resource_name)
Load a module.
Definition: loader.c:1824
static struct ast_str * startup_error_builder
Definition: loader.c:154
static int loader_config_init(struct load_order *load_order)
Definition: loader.c:2230
static const char * loadresult2str(enum ast_module_load_result result)
Definition: loader.c:1519
static void module_destroy(struct ast_module *mod)
Definition: loader.c:744
static int load_dlopen_missing(struct ast_str **list, struct ast_vector_string *deps)
Definition: loader.c:1030
#define RTLD_NOW
Definition: loader.c:120
static int module_reffed_deps_add(struct ast_module *mod, struct ast_module *dep, struct ast_vector_const_string *missing)
Definition: loader.c:416
void __ast_module_shutdown_ref(struct ast_module *mod, const char *file, int line, const char *func)
Definition: loader.c:2740
static const struct load_results_map load_results[]
Definition: loader.c:344
int ast_loader_register(int(*v)(void))
Add a procedure to be run when modules have been updated.
Definition: loader.c:2682
static enum ast_module_load_result load_resource(const char *resource_name, unsigned int suppress_logging, struct module_vector *module_priorities, int required, int preload)
Definition: loader.c:1768
static int module_reffed_deps_add_dep_enhancers(struct ast_module *mod, struct ast_module *dep, struct ast_vector_const_string *missing)
Definition: loader.c:448
#define AST_MODULE_LOAD_UNKNOWN_STRING
Definition: loader.c:351
static int module_vector_cmp(struct ast_module *a, struct ast_module *b)
Definition: loader.c:371
static int module_deps_process_reqlist(struct ast_module *mod, struct ast_vector_string *vec, struct ast_vector_const_string *missing, int ref_enhancers, int isoptional)
Definition: loader.c:485
static struct module_list builtin_module_list
Definition: loader.c:364
static int resource_list_recursive_decline(struct module_vector *resources, struct ast_module *mod, struct ast_str **printmissing)
Definition: loader.c:1922
static void queue_reload_request(const char *module)
Definition: loader.c:1437
struct ast_module_user * __ast_module_user_add(struct ast_module *mod, struct ast_channel *chan)
Definition: loader.c:800
static enum ast_module_load_result start_resource_attempt(struct ast_module *mod, int *count)
Definition: loader.c:1894
static void module_load_error(const char *fmt,...)
Definition: loader.c:269
static unsigned int inspect_module(const struct ast_module *mod)
Definition: loader.c:1656
static int printdigest(const unsigned char *d)
Definition: loader.c:875
int ast_loader_unregister(int(*v)(void))
Remove a procedure to be run when modules are updated.
Definition: loader.c:2697
#define STR_APPEND_TEXT(txt, str)
Definition: loader.c:144
static enum ast_module_load_result start_resource(struct ast_module *mod)
Definition: loader.c:1683
static void publish_reload_message(const char *name, enum ast_module_reload_result result)
Definition: loader.c:1559
int ast_unload_resource(const char *resource_name, enum ast_module_unload_mode force)
Unload a module.
Definition: loader.c:1219
static int loader_builtin_init(struct load_order *load_order)
Definition: loader.c:2195
static size_t resource_name_baselen(const char *name)
Definition: loader.c:907
int ast_update_module_list_data(int(*modentry)(const char *module, const char *description, int usecnt, const char *status, const char *like, enum ast_module_support_level support_level, void *data), const char *like, void *data)
Ask for a list of modules, descriptions, use counts and status.
Definition: loader.c:2610
#define key_matches(a, b)
Definition: loader.c:888
static char * get_name_from_resource(const char *resource)
Definition: loader.c:157
static int module_matches_helper_type(struct ast_module *mod, enum ast_module_helper_type type)
Definition: loader.c:1299
static int verify_key(const unsigned char *key)
Definition: loader.c:890
const char * ast_module_name(const struct ast_module *mod)
Get the name of a module.
Definition: loader.c:615
int ast_update_module_list_condition(int(*modentry)(const char *module, const char *description, int usecnt, const char *status, const char *like, enum ast_module_support_level support_level, void *data, const char *condition), const char *like, void *data, const char *condition)
Ask for a list of modules, descriptions, use counts and status.
Definition: loader.c:2638
struct ast_module * __ast_module_running_ref(struct ast_module *mod, const char *file, int line, const char *func)
Definition: loader.c:2730
static struct ast_module * load_dlopen(const char *resource_in, const char *so_ext, const char *filename, int flags, unsigned int suppress_logging)
Definition: loader.c:1060
static int is_module_loaded(const char *resource_name)
Check to see if the given resource is loaded.
Definition: loader.c:981
static int alpha_module_list_create(struct module_vector *alpha_module_list)
Definition: loader.c:2566
static void publish_load_message(const char *name, enum ast_module_load_result result)
Definition: loader.c:1536
static void module_load_helper(const char *word)
Definition: loader.c:1361
enum ast_module_reload_result ast_module_reload(const char *name)
Reload asterisk modules.
Definition: loader.c:1567
static int module_vector_strcasecmp(struct ast_module *a, struct ast_module *b)
Definition: loader.c:366
static struct ast_module *volatile resource_being_loaded
Definition: loader.c:650
Asterisk locking-related definitions:
#define ast_mutex_unlock(a)
Definition: lock.h:190
int ast_atomic_fetchadd_int(volatile int *p, int v)
Atomically add v to *p and return the previous value of *p.
Definition: lock.h:757
#define ast_mutex_trylock(a)
Definition: lock.h:191
#define AST_MUTEX_DEFINE_STATIC(mutex)
Definition: lock.h:520
The AMI - Asterisk Manager Interface - is a TCP protocol created to manage Asterisk with third-party ...
#define EVENT_FLAG_SYSTEM
Definition: manager.h:75
struct stasis_message_type * ast_manager_get_generic_type(void)
Get the stasis_message_type for generic messages.
MD5 digest functions.
void MD5Update(struct MD5Context *context, unsigned char const *buf, unsigned len)
Definition: md5.c:72
void MD5Init(struct MD5Context *context)
Definition: md5.c:57
void MD5Final(unsigned char digest[16], struct MD5Context *context)
Definition: md5.c:120
Asterisk module definitions.
@ AST_MODFLAG_LOAD_ORDER
Definition: module.h:317
@ AST_MODFLAG_GLOBAL_SYMBOLS
Definition: module.h:316
#define ast_module_unref(mod)
Release a reference to the module.
Definition: module.h:469
#define ast_module_ref(mod)
Hold a reference to the module.
Definition: module.h:443
#define ast_module_shutdown_ref(mod)
Prevent unload of the module before shutdown.
Definition: module.h:464
#define AST_MODULE_CONFIG
Module configuration file.
Definition: module.h:59
@ AST_MODPRI_DEFAULT
Definition: module.h:332
ast_module_support_level
Definition: module.h:119
@ AST_MODULE_SUPPORT_DEPRECATED
Definition: module.h:123
@ AST_MODULE_SUPPORT_CORE
Definition: module.h:121
@ AST_MODULE_SUPPORT_EXTENDED
Definition: module.h:122
@ AST_MODULE_SUPPORT_UNKNOWN
Definition: module.h:120
ast_module_unload_mode
Definition: module.h:61
@ AST_FORCE_FIRM
Definition: module.h:63
ast_module_reload_result
Possible return types for ast_module_reload.
Definition: module.h:109
@ AST_MODULE_RELOAD_IN_PROGRESS
Definition: module.h:114
@ AST_MODULE_RELOAD_QUEUED
Definition: module.h:111
@ AST_MODULE_RELOAD_SUCCESS
Definition: module.h:110
@ AST_MODULE_RELOAD_ERROR
Definition: module.h:113
@ AST_MODULE_RELOAD_NOT_IMPLEMENTED
Definition: module.h:116
@ AST_MODULE_RELOAD_NOT_FOUND
Definition: module.h:112
@ AST_MODULE_RELOAD_UNINITIALIZED
Definition: module.h:115
ast_module_load_result
Definition: module.h:68
@ AST_MODULE_LOAD_PRIORITY
Definition: module.h:90
@ AST_MODULE_LOAD_FAILURE
Module could not be loaded properly.
Definition: module.h:102
@ AST_MODULE_LOAD_SUCCESS
Definition: module.h:70
@ AST_MODULE_LOAD_DECLINE
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
@ AST_MODULE_LOAD_SKIP
Definition: module.h:84
ast_module_helper_type
Definition: module.h:127
@ AST_MODULE_HELPER_RELOAD
Definition: module.h:131
@ AST_MODULE_HELPER_LOADED
Definition: module.h:129
@ AST_MODULE_HELPER_UNLOAD
Definition: module.h:135
@ AST_MODULE_HELPER_LOAD
Definition: module.h:133
@ AST_MODULE_HELPER_RUNNING
Definition: module.h:137
def info(msg)
#define ast_opt_lock_confdir
Definition: options.h:133
#define ast_opt_ref_debug
Definition: options.h:135
#define ast_fully_booted
Definition: options.h:117
struct timeval ast_lastreloadtime
Definition: asterisk.c:337
Asterisk file paths, configured in asterisk.conf.
const char * ast_config_AST_MODULE_DIR
Definition: options.c:153
const char * ast_config_AST_CONFIG_DIR
Definition: options.c:151
#define AST_BUILDOPT_SUM
#define NULL
Definition: resample.c:96
struct stasis_message * stasis_message_create(struct stasis_message_type *type, void *data)
Create a new message.
void stasis_publish(struct stasis_topic *topic, struct stasis_message *message)
Publish a message to a topic's subscribers.
Definition: stasis.c:1511
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition: strings.h:1139
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:761
int ast_str_set_va(struct ast_str **buf, ssize_t max_len, const char *fmt, va_list ap)
Set a dynamic string from a va_list.
Definition: strings.h:1030
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one.
Definition: strings.h:80
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true"....
Definition: utils.c:2199
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
void ast_str_reset(struct ast_str *buf)
Reset the content of a dynamic string. Useful before a series of ast_str_append.
Definition: strings.h:693
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
Definition: strings.h:659
size_t ast_str_strlen(const struct ast_str *buf)
Returns the current length of the string stored within buf.
Definition: strings.h:730
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
Definition: md5.h:26
Generic container type.
Main Channel structure associated with a channel.
Structure used to handle boolean flags.
Definition: utils.h:199
Abstract JSON element (object, array, string, int, ...).
enum ast_module_load_result(* load)(void)
Definition: module.h:344
enum ast_module_support_level support_level
Definition: module.h:416
const char * description
Definition: module.h:352
const char buildopt_sum[33]
Definition: module.h:363
const char * name
Definition: module.h:350
unsigned char load_pri
Definition: module.h:370
int(* reload)(void)
Definition: module.h:346
const char *const char * optional_modules
Comma-separated list of optionally required modules.
Definition: module.h:383
const char * key
Definition: module.h:359
int(* unload)(void)
Definition: module.h:348
const char * enhances
Modules that we provide enhanced functionality for.
Definition: module.h:406
struct ast_module_user::@361 entry
struct ast_channel * chan
Definition: loader.c:128
struct module_user_list users
Definition: loader.c:302
unsigned int running
Definition: loader.c:320
void * ref_debug
Definition: loader.c:296
struct ast_module::@363 entry
struct ast_vector_string requires
Definition: loader.c:305
struct ast_vector_string optional_modules
Definition: loader.c:307
unsigned int required
Definition: loader.c:328
void * lib
Definition: loader.c:298
struct module_vector reffed_deps
Vector holding pointers to modules we have a reference to.
Definition: loader.c:317
unsigned int builtin
Definition: loader.c:326
unsigned int keepuntilshutdown
Definition: loader.c:324
unsigned int declined
Definition: loader.c:322
const struct ast_module_info * info
Definition: loader.c:294
int usecount
Definition: loader.c:300
unsigned int preload
Definition: loader.c:330
char resource[0]
Definition: loader.c:333
struct ast_module::@362 flags
struct ast_vector_string enhances
Definition: loader.c:309
Support for dynamic strings.
Definition: strings.h:623
Structure for variables, used for configurations and for channel variables.
struct ast_variable * next
String vector definitions.
Definition: vector.h:55
Definition: search.h:40
Definition: loader.c:1848
int builtin
Definition: loader.c:1852
int required
Definition: loader.c:1850
int preload
Definition: loader.c:1851
char * resource
Definition: loader.c:1849
struct load_order_entry::@366 entry
const char * name
Definition: loader.c:341
struct loadupdate::@364 entry
int(* updater)(void)
Definition: loader.c:625
size_t moddir_len
Definition: loader.c:1326
const char * word
Definition: loader.c:1324
struct reload_queue_item::@365 entry
char module[0]
Definition: loader.c:635
A vector of strings commonly used throughout this module.
list of users found in the config file
Handy terminal functions for vt* terms.
#define COLOR_BROWN
Definition: term.h:56
#define COLOR_BLACK
Definition: term.h:50
char * term_color(char *outbuf, const char *inbuf, int fgcolor, int bgcolor, int maxout)
Colorize a specified string by adding terminal color codes.
Definition: term.c:235
Test Framework API.
#define ast_test_suite_event_notify(s, f,...)
Definition: test.h:189
int done
Definition: test_amihooks.c:48
static struct aco_type item
Definition: test_config.c:1463
static struct test_val b
static struct test_val a
static struct test_val d
static struct test_val c
int64_t ast_tvdiff_us(struct timeval end, struct timeval start)
Computes the difference (in microseconds) between two struct timeval instances.
Definition: time.h:87
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:159
int error(const char *format,...)
Definition: utils/frame.c:999
Utility functions.
#define ast_test_flag(p, flag)
Definition: utils.h:63
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:941
#define ast_assert(a)
Definition: utils.h:739
#define ARRAY_LEN(a)
Definition: utils.h:666
Vector container support.
#define AST_VECTOR_RESET(vec, cleanup)
Reset vector.
Definition: vector.h:625
#define AST_VECTOR_ELEM_CLEANUP_NOOP(elem)
Vector element cleanup that does nothing.
Definition: vector.h:571
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:609
#define AST_VECTOR_REMOVE_CMP_ORDERED(vec, value, cmp, cleanup)
Remove an element from a vector that matches the given comparison while maintaining order.
Definition: vector.h:540
#define AST_VECTOR_FREE(vec)
Deallocates this vector.
Definition: vector.h:174
#define AST_VECTOR_GET_CMP(vec, value, cmp)
Get an element from a vector that matches the given comparison.
Definition: vector.h:731
#define AST_VECTOR_ELEM_DEFAULT_CMP(elem, value)
Default comparator for AST_VECTOR_REMOVE_ELEM_UNORDERED()
Definition: vector.h:564
#define AST_VECTOR_ADD_SORTED(vec, elem, cmp)
Add an element into a sorted vector.
Definition: vector.h:371
#define AST_VECTOR_REMOVE(vec, idx, preserve_ordered)
Remove an element from a vector by index.
Definition: vector.h:412
int ast_vector_string_split(struct ast_vector_string *dest, const char *input, const char *delim, int flags, int(*excludes_cmp)(const char *s1, const char *s2))
Append a string vector by splitting a string.
Definition: strings.c:392
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
Definition: vector.h:113
#define AST_VECTOR_APPEND(vec, elem)
Append an element to a vector, growing the vector if needed.
Definition: vector.h:256
#define AST_VECTOR_CALLBACK_VOID(vec, callback,...)
Execute a callback on every element in a vector disregarding callback return.
Definition: vector.h:862
#define AST_VECTOR(name, type)
Define a vector structure.
Definition: vector.h:44
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition: vector.h:680
struct ast_xml_node * ast_xml_node_get_children(struct ast_xml_node *node)
Get the node's children.
Definition: xml.c:397
const char * ast_xml_get_text(struct ast_xml_node *node)
Get an element content string.
Definition: xml.c:355
struct ast_xml_node * ast_xml_xpath_get_first_result(struct ast_xml_xpath_results *results)
Return the first result node of an XPath query.
Definition: xml.c:417
void ast_xml_xpath_results_free(struct ast_xml_xpath_results *results)
Free the XPath results.
Definition: xml.c:427
struct ast_xml_node * ast_xml_find_element(struct ast_xml_node *root_node, const char *name, const char *attrname, const char *attrvalue)
Find a node element by name.
Definition: xml.c:299
struct ast_xml_xpath_results * ast_xmldoc_query(const char *fmt,...)
Execute an XPath query on the loaded XML documentation.
Definition: xmldoc.c:2576