Asterisk - The Open Source Telephony Project GIT-master-f45f878
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
1219/*!
1220 * \brief Whether or not this module should be able to be unloaded successfully,
1221 * if we recursively unload any modules that are dependent on it.
1222 * \note module_list should be locked when calling this
1223 * \retval 0 if not, 1 if likely possible
1224 */
1225static int graceful_unload_possible(struct ast_module *target, struct ast_vector_const_string *dependents)
1226{
1227 struct ast_module *mod;
1228 int usecount = target->usecount;
1229
1230 /* Check the reffed_deps of each module to see if we're one of them. */
1233 const char *name;
1234 /* This module is dependent on the target.
1235 * If we can unload this module gracefully,
1236 * then that would decrement our use count.
1237 * If any single module could not be unloaded gracefully,
1238 * then we don't proceed. */
1239 int unloadable;
1240 if (AST_VECTOR_GET_CMP(dependents, ast_module_name(mod), !strcasecmp)) {
1241 /* Already in our list, we already checked this module,
1242 * and we gave it the green light. */
1243 ast_debug(3, "Skipping duplicate dependent %s\n", ast_module_name(mod));
1244 if (!--usecount) {
1245 break;
1246 }
1247 continue;
1248 }
1249 unloadable = graceful_unload_possible(mod, dependents);
1250 if (!unloadable) {
1251 ast_log(LOG_NOTICE, "Can't unload %s right now because %s is dependent on it\n", ast_module_name(target), ast_module_name(mod));
1252 return 0;
1253 }
1254 /* Insert at beginning, so later if we're loading modules again automatically, we can do so in the same order. */
1256 if (!name) {
1257 return 0;
1258 }
1259 ast_debug(3, "Found new dependent %s\n", ast_module_name(mod));
1260 if (AST_VECTOR_INSERT_AT(dependents, 0, name)) {
1261 ast_log(LOG_ERROR, "Failed to add module '%s' to vector\n", ast_module_name(mod));
1262 return 0;
1263 }
1264 if (!--usecount) {
1265 break;
1266 }
1267 }
1268 }
1269
1270 if (usecount) {
1271 ast_log(LOG_NOTICE, "Module %s cannot be unloaded (would still have use count %d/%d after unloading dependents)\n", ast_module_name(target), usecount, target->usecount);
1272 return 0;
1273 }
1274 return 1;
1275}
1276
1277/*!
1278 * \brief Unload a resource
1279 * \param resource_name Module name
1280 * \param force
1281 * \param recursive Whether to attempt to recursively unload dependents of this module and load them again afterwards
1282 * \param dependents. Can be NULL if autounload is 0.
1283 * \retval 0 on success, -1 on failure
1284 */
1285static int auto_unload_resource(const char *resource_name, enum ast_module_unload_mode force, int recursive, struct ast_vector_const_string *dependents)
1286{
1287 struct ast_module *mod;
1288 int res = -1;
1289 int error = 0;
1290
1292
1293 if (!(mod = find_resource(resource_name, 0))) {
1295 ast_log(LOG_WARNING, "Unload failed, '%s' could not be found\n", resource_name);
1296 return -1;
1297 }
1298
1299 if (!mod->flags.running || mod->flags.declined) {
1300 /* If the user asks to unload a module that didn't load, obey.
1301 * Otherwise, we never dlclose() modules that fail to load,
1302 * which means if the module (shared object) is updated,
1303 * we can't load the updated module since we never dlclose()'d it.
1304 * Accordingly, obey the unload request so we can load the module
1305 * from scratch next time.
1306 */
1307 ast_log(LOG_NOTICE, "Unloading module '%s' that previously declined to load\n", resource_name);
1308 error = 0;
1309 res = 0;
1310 goto exit; /* Skip all the intervening !error checks, only the last one is relevant. */
1311 }
1312
1313 if (!error && mod->usecount > 0 && recursive) {
1314 /* Try automatically unloading all modules dependent on the module we're trying to unload,
1315 * and then, optionally, load them back again if we end up loading this module again.
1316 * If any modules that have us as a dependency can't be unloaded, for whatever reason,
1317 * then the entire unload operation will fail, so to try to make this an atomic operation
1318 * and avoid leaving modules in a partial unload state, first check if we think we're going
1319 * to be able to pull this off, and if not, abort.
1320 *
1321 * A race condition is technically still possible, if some depending module suddenly goes in use
1322 * between this check and trying to unload it, but this takes care of the majority of
1323 * easy-to-avoid cases that would fail eventually anyways.
1324 *
1325 * Note that we can encounter false negatives (e.g. unloading all the dependents would allow
1326 * a module to unload, but graceful_unload_possible returns 0). This is because it's only
1327 * checking direct module dependencies; other dependencies caused by a module registering
1328 * a resource that cause its ref count to get bumped aren't accounted for here.
1329 */
1330 if (graceful_unload_possible(mod, dependents)) {
1331 int i, res = 0;
1332 size_t num_deps = AST_VECTOR_SIZE(dependents);
1333 ast_debug(1, "%lu module%s will need to be unloaded\n", AST_VECTOR_SIZE(dependents), ESS(AST_VECTOR_SIZE(dependents)));
1334 /* Unload from the end, since the last module was the first one added, which means it isn't a dependency of anything else. */
1335 for (i = AST_VECTOR_SIZE(dependents) - 1; i >= 0; i--) {
1336 const char *depname = AST_VECTOR_GET(dependents, i);
1337 res = ast_unload_resource(depname, force);
1338 if (res) {
1339 ast_log(LOG_WARNING, "Failed to unload %lu module%s automatically (%s could not be unloaded)\n", num_deps, ESS(num_deps), depname);
1340 /* To be polite, load modules that we already unloaded,
1341 * to try to leave things the way they were when we started. */
1342 for (i++; i < num_deps; i++) {
1343 const char *depname = AST_VECTOR_GET(dependents, i);
1344 res = ast_load_resource(depname);
1345 if (res) {
1346 ast_log(LOG_WARNING, "Could not load module '%s' again automatically\n", depname);
1347 }
1348 }
1349 break;
1350 }
1351 }
1352 /* Either we failed, or we successfully unloaded everything.
1353 * If we succeeded, we can now proceed and unload ourselves. */
1354 }
1355 }
1356
1357 if (!error && (mod->usecount > 0)) {
1358 if (force) {
1359 ast_log(LOG_WARNING, "Warning: Forcing removal of module '%s' with use count %d\n", resource_name, mod->usecount);
1360 } else {
1361 ast_log(LOG_WARNING, "%s unload failed, '%s' has use count %d\n", recursive ? "Recursive soft" : "Soft", resource_name, mod->usecount);
1362 error = 1;
1363 }
1364 }
1365
1366 if (!error) {
1367 /* Request any channels attached to the module to hangup. */
1369
1370 ast_verb(4, "Unloading %s\n", mod->resource);
1371 res = mod->info->unload();
1372 if (res) {
1373 ast_log(LOG_WARNING, "Firm unload failed for %s\n", resource_name);
1374 if (force <= AST_FORCE_FIRM) {
1375 error = 1;
1376 } else {
1377 ast_log(LOG_WARNING, "** Dangerous **: Unloading resource anyway, at user request\n");
1378 }
1379 }
1380
1381 if (!error) {
1382 /*
1383 * Request hangup on any channels that managed to get attached
1384 * while we called the module unload function.
1385 */
1387 sched_yield();
1388 }
1389 }
1390
1391 if (!error)
1392 mod->flags.running = mod->flags.declined = 0;
1393
1394exit:
1396
1397 if (!error) {
1399 ast_test_suite_event_notify("MODULE_UNLOAD", "Message: %s", resource_name);
1401 publish_unload_message(resource_name, "Success");
1402 }
1403
1404 return res;
1405}
1406
1407int ast_refresh_resource(const char *resource_name, enum ast_module_unload_mode force, int recursive)
1408{
1409 if (recursive) {
1410 /* Recursively unload dependents of this module and then load them back again */
1411 int res, i;
1412 struct ast_vector_const_string dependents;
1413 AST_VECTOR_INIT(&dependents, 0);
1414 res = auto_unload_resource(resource_name, force, recursive, &dependents);
1415 if (res) {
1416 AST_VECTOR_FREE(&dependents);
1417 return 1;
1418 }
1419 /* Start by loading the target again. */
1420 if (ast_load_resource(resource_name)) {
1421 ast_log(LOG_WARNING, "Failed to load module '%s' again automatically\n", resource_name);
1422 AST_VECTOR_FREE(&dependents);
1423 return -1;
1424 }
1425 res = 0;
1426 /* Finally, load again any modules we had to unload in order to refresh the target.
1427 * We must load modules in the reverse order that we unloaded them,
1428 * to preserve dependency requirements. */
1429 for (i = 0; i < AST_VECTOR_SIZE(&dependents); i++) {
1430 const char *depname = AST_VECTOR_GET(&dependents, i);
1431 int mres = ast_load_resource(depname);
1432 if (mres) {
1433 ast_log(LOG_WARNING, "Could not load module '%s' again automatically\n", depname);
1434 }
1435 res |= mres;
1436 }
1437 AST_VECTOR_FREE(&dependents);
1438 return res ? -1 : 0;
1439 }
1440
1441 /* Simple case: just unload and load the module again */
1442 if (ast_unload_resource(resource_name, force)) {
1443 return 1;
1444 }
1445 return ast_load_resource(resource_name);
1446}
1447
1448int ast_unload_resource(const char *resource_name, enum ast_module_unload_mode force)
1449{
1450 return auto_unload_resource(resource_name, force, 0, NULL);
1451}
1452
1454{
1455 switch (type) {
1457 return !mod->usecount && mod->flags.running && !mod->flags.declined;
1458
1460 return mod->flags.running && mod->info->reload;
1461
1463 return mod->flags.running;
1464
1466 /* if we have a 'struct ast_module' then we're loaded. */
1467 return 1;
1468 default:
1469 /* This function is not called for AST_MODULE_HELPER_LOAD. */
1470 /* Unknown ast_module_helper_type. Assume it doesn't match. */
1471 ast_assert(0);
1472
1473 return 0;
1474 }
1475}
1476
1478 const char *word;
1479 size_t len;
1481};
1482
1483static int module_load_helper_on_file(const char *dir_name, const char *filename, void *obj)
1484{
1485 struct module_load_word *word = obj;
1486 struct ast_module *mod;
1487 char *filename_merged = NULL;
1488
1489 /* dir_name will never be shorter than word->moddir_len. */
1490 dir_name += word->moddir_len;
1491 if (!ast_strlen_zero(dir_name)) {
1492 ast_assert(dir_name[0] == '/');
1493
1494 dir_name += 1;
1495 if (ast_asprintf(&filename_merged, "%s/%s", dir_name, filename) < 0) {
1496 /* If we can't allocate the string just give up! */
1497 return -1;
1498 }
1499 filename = filename_merged;
1500 }
1501
1502 if (!strncasecmp(filename, word->word, word->len)) {
1503 /* Don't list files that are already loaded! */
1504 mod = find_resource(filename, 0);
1505 if (!mod || !mod->flags.running) {
1507 }
1508 }
1509
1510 ast_free(filename_merged);
1511
1512 return 0;
1513}
1514
1515static void module_load_helper(const char *word)
1516{
1517 struct module_load_word word_l = {
1518 .word = word,
1519 .len = strlen(word),
1520 .moddir_len = strlen(ast_config_AST_MODULE_DIR),
1521 };
1522
1526}
1527
1528char *ast_module_helper(const char *line, const char *word, int pos, int state, int rpos, enum ast_module_helper_type type)
1529{
1530 struct ast_module *mod;
1531 int which = 0;
1532 int wordlen = strlen(word);
1533 char *ret = NULL;
1534
1535 if (pos != rpos) {
1536 return NULL;
1537 }
1538
1539 /* Tab completion can't be used during startup, or CLI and loader will deadlock. */
1541 return NULL;
1542 }
1543
1546
1547 return NULL;
1548 }
1549
1552 if (!module_matches_helper_type(mod, type)) {
1553 continue;
1554 }
1555
1556 if (!strncasecmp(word, mod->resource, wordlen) && ++which > state) {
1557 ret = ast_strdup(mod->resource);
1558 break;
1559 }
1560 }
1562
1563 return ret;
1564}
1565
1567{
1568 struct reload_queue_item *item;
1569
1570 modules_loaded = 1;
1571
1573
1574 if (do_full_reload) {
1575 do_full_reload = 0;
1577 ast_log(LOG_NOTICE, "Executing deferred reload request.\n");
1579 return;
1580 }
1581
1583 ast_log(LOG_NOTICE, "Executing deferred reload request for module '%s'.\n", item->module);
1584 ast_module_reload(item->module);
1585 ast_free(item);
1586 }
1587
1589}
1590
1591static void queue_reload_request(const char *module)
1592{
1593 struct reload_queue_item *item;
1594
1596
1597 if (do_full_reload) {
1599 return;
1600 }
1601
1602 if (ast_strlen_zero(module)) {
1603 /* A full reload request (when module is NULL) wipes out any previous
1604 reload requests and causes the queue to ignore future ones */
1606 ast_free(item);
1607 }
1608 do_full_reload = 1;
1609 } else {
1610 /* No reason to add the same module twice */
1612 if (!strcasecmp(item->module, module)) {
1614 return;
1615 }
1616 }
1617 item = ast_calloc(1, sizeof(*item) + strlen(module) + 1);
1618 if (!item) {
1619 ast_log(LOG_ERROR, "Failed to allocate reload queue item.\n");
1621 return;
1622 }
1623 strcpy(item->module, module);
1625 }
1627}
1628
1629/*!
1630 * \since 12
1631 * \internal
1632 * \brief Publish a \ref stasis message regarding the type.
1633 */
1634static void publish_load_message_type(const char* type, const char *name, const char *status)
1635{
1637 RAII_VAR(struct ast_json_payload *, payload, NULL, ao2_cleanup);
1638 RAII_VAR(struct ast_json *, json_object, NULL, ast_json_unref);
1639 RAII_VAR(struct ast_json *, event_object, NULL, ast_json_unref);
1640
1641 ast_assert(type != NULL);
1644
1646 return;
1647 }
1648
1649 event_object = ast_json_pack("{s:s, s:s}",
1650 "Module", name,
1651 "Status", status);
1652 json_object = ast_json_pack("{s:s, s:i, s:o}",
1653 "type", type,
1654 "class_type", EVENT_FLAG_SYSTEM,
1655 "event", ast_json_ref(event_object));
1656 if (!json_object) {
1657 return;
1658 }
1659
1660 payload = ast_json_payload_create(json_object);
1661 if (!payload) {
1662 return;
1663 }
1664
1666 if (!message) {
1667 return;
1668 }
1669
1671}
1672
1674{
1675 int i;
1676 for (i = 0; i < ARRAY_LEN(load_results); i++) {
1677 if (load_results[i].result == result) {
1678 return load_results[i].name;
1679 }
1680 }
1681
1682 ast_log(LOG_WARNING, "Failed to find correct load result status. result %d\n", result);
1684}
1685
1686/*!
1687 * \internal
1688 * \brief Publish a \ref stasis message regarding the load result
1689 */
1691{
1692 const char *status;
1693
1695
1697}
1698
1699/*!
1700 * \internal
1701 * \brief Publish a \ref stasis message regarding the unload result
1702 */
1703static void publish_unload_message(const char *name, const char* status)
1704{
1706}
1707
1708/*!
1709 * \since 12
1710 * \internal
1711 * \brief Publish a \ref stasis message regarding the reload result
1712 */
1714{
1715 char res_buffer[8];
1716
1717 snprintf(res_buffer, sizeof(res_buffer), "%u", result);
1718 publish_load_message_type("Reload", S_OR(name, "All"), res_buffer);
1719}
1720
1722{
1723 struct ast_module *cur;
1725 size_t name_baselen = name ? resource_name_baselen(name) : 0;
1726
1727 /* If we aren't fully booted, we just pretend we reloaded but we queue this
1728 up to run once we are booted up. */
1729 if (!modules_loaded) {
1732 goto module_reload_exit;
1733 }
1734
1736 ast_verb(3, "The previous reload command didn't finish yet\n");
1738 goto module_reload_exit;
1739 }
1740 ast_sd_notify("RELOADING=1");
1742
1744 int try;
1745 int lockres;
1746 for (try = 1, lockres = AST_LOCK_TIMEOUT; try < 6 && (lockres == AST_LOCK_TIMEOUT); try++) {
1748 if (lockres == AST_LOCK_TIMEOUT) {
1749 ast_log(LOG_WARNING, "Failed to grab lock on %s, try %d\n", ast_config_AST_CONFIG_DIR, try);
1750 }
1751 }
1752 if (lockres != AST_LOCK_SUCCESS) {
1753 ast_log(AST_LOG_WARNING, "Cannot grab lock on %s\n", ast_config_AST_CONFIG_DIR);
1755 goto module_reload_done;
1756 }
1757 }
1758
1761 const struct ast_module_info *info = cur->info;
1762
1763 if (name && resource_name_match(name, name_baselen, cur->resource)) {
1764 continue;
1765 }
1766
1767 if (!cur->flags.running || cur->flags.declined) {
1768 if (res == AST_MODULE_RELOAD_NOT_FOUND) {
1770 }
1771 if (!name) {
1772 continue;
1773 }
1774 break;
1775 }
1776
1777 if (!info->reload) { /* cannot be reloaded */
1778 if (res == AST_MODULE_RELOAD_NOT_FOUND) {
1780 }
1781 if (!name) {
1782 continue;
1783 }
1784 break;
1785 }
1786 ast_verb(3, "Reloading module '%s' (%s)\n", cur->resource, info->description);
1787 if (info->reload() == AST_MODULE_LOAD_SUCCESS) {
1789 } else if (res == AST_MODULE_RELOAD_NOT_FOUND) {
1791 }
1792 if (name) {
1793 break;
1794 }
1795 }
1797
1800 }
1801module_reload_done:
1803 ast_sd_notify("READY=1");
1804
1805module_reload_exit:
1807 return res;
1808}
1809
1810static unsigned int inspect_module(const struct ast_module *mod)
1811{
1812 if (!mod->info->description) {
1813 module_load_error("Module '%s' does not provide a description.\n", mod->resource);
1814 return 1;
1815 }
1816
1817 if (!mod->info->key) {
1818 module_load_error("Module '%s' does not provide a license key.\n", mod->resource);
1819 return 1;
1820 }
1821
1822 if (verify_key((unsigned char *) mod->info->key)) {
1823 module_load_error("Module '%s' did not provide a valid license key.\n", mod->resource);
1824 return 1;
1825 }
1826
1827 if (!ast_strlen_zero(mod->info->buildopt_sum) &&
1828 strcmp(buildopt_sum, mod->info->buildopt_sum)) {
1829 module_load_error("Module '%s' was not compiled with the same compile-time options as this version of Asterisk.\n", mod->resource);
1830 module_load_error("Module '%s' will not be initialized as it may cause instability.\n", mod->resource);
1831 return 1;
1832 }
1833
1834 return 0;
1835}
1836
1838{
1839 char tmp[256];
1840 enum ast_module_load_result res;
1841
1842 if (mod->flags.running) {
1844 }
1845
1846 if (!mod->info->load) {
1847 mod->flags.declined = 1;
1848
1850 }
1851
1852 if (module_deps_reference(mod, NULL)) {
1853 struct module_vector missing;
1854 int i;
1855
1856 AST_VECTOR_INIT(&missing, 0);
1857 if (module_deps_missing_recursive(mod, &missing)) {
1858 module_load_error("%s has one or more unknown dependencies.\n", mod->info->name);
1859 }
1860 for (i = 0; i < AST_VECTOR_SIZE(&missing); i++) {
1861 module_load_error("%s loaded before dependency %s!\n", mod->info->name,
1862 AST_VECTOR_GET(&missing, i)->info->name);
1863 }
1864 AST_VECTOR_FREE(&missing);
1865
1867 }
1868
1869 if (!ast_fully_booted) {
1870 ast_verb(4, "Loading %s.\n", mod->resource);
1871 }
1872 res = mod->info->load();
1873
1874 switch (res) {
1876 if (!ast_fully_booted) {
1877 ast_verb(5, "%s => (%s)\n", mod->resource, term_color(tmp, mod->info->description, COLOR_BROWN, COLOR_BLACK, sizeof(tmp)));
1878 } else {
1879 ast_verb(4, "Loaded %s => (%s)\n", mod->resource, mod->info->description);
1880 }
1881
1882 mod->flags.running = 1;
1883 if (mod->flags.builtin) {
1884 /* Built-in modules cannot be unloaded. */
1886 }
1887
1889 break;
1891 mod->flags.declined = 1;
1892 if (mod->flags.required) {
1894 }
1895 break;
1897 mod->flags.declined = 1;
1898 break;
1899 case AST_MODULE_LOAD_SKIP: /* modules should never return this value */
1901 break;
1902 }
1903
1904 /* Make sure the newly started module is at the end of the list */
1909
1910 return res;
1911}
1912
1913/*! loads a resource based upon resource_name. If global_symbols_only is set
1914 * only modules with global symbols will be loaded.
1915 *
1916 * If the module_vector is provided (not NULL) the module is found and added to the
1917 * vector without running the module's load() function. By doing this, modules
1918 * can be initialized later in order by priority and dependencies.
1919 *
1920 * If the module_vector is not provided, the module's load function will be executed
1921 * immediately */
1922static enum ast_module_load_result load_resource(const char *resource_name, unsigned int suppress_logging,
1923 struct module_vector *module_priorities, int required, int preload)
1924{
1925 struct ast_module *mod;
1927
1928 if ((mod = find_resource(resource_name, 0))) {
1929 if (mod->flags.running) {
1930 ast_log(LOG_WARNING, "Module '%s' already loaded and running.\n", resource_name);
1932 }
1933 } else {
1934 mod = load_dynamic_module(resource_name, suppress_logging);
1935 if (!mod) {
1937 }
1938
1939 if (module_post_register(mod)) {
1940 goto prestart_error;
1941 }
1942 }
1943
1944 mod->flags.required |= required;
1945 mod->flags.preload |= preload;
1946
1947 if (inspect_module(mod)) {
1948 goto prestart_error;
1949 }
1950
1951 mod->flags.declined = 0;
1952
1953 if (module_priorities) {
1954 if (AST_VECTOR_ADD_SORTED(module_priorities, mod, module_vector_cmp)) {
1955 goto prestart_error;
1956 }
1958 } else {
1959 res = start_resource(mod);
1960 }
1961
1963 publish_load_message(resource_name, res);
1964 }
1965
1966 return res;
1967
1968prestart_error:
1969 module_load_error("Module '%s' could not be loaded.\n", resource_name);
1973 publish_load_message(resource_name, res);
1974 }
1975 return res;
1976}
1977
1978enum ast_module_load_result ast_load_resource(const char *resource_name)
1979{
1980 struct ast_module *mod;
1981 enum ast_module_load_result res;
1982
1983 /* If we're trying to load a module that previously declined to load,
1984 * transparently unload it first so we dlclose, then dlopen it afresh.
1985 * Otherwise, we won't actually load a (potentially) updated module. */
1986 mod = find_resource(resource_name, 0);
1987 if (mod && mod->flags.declined) {
1988 ast_debug(1, "Module %s previously declined to load, unloading it first before loading again\n", resource_name);
1989 ast_unload_resource(resource_name, 0);
1990 }
1991
1993 res = load_resource(resource_name, 0, NULL, 0, 0);
1994 if (!res) {
1995 ast_test_suite_event_notify("MODULE_LOAD", "Message: %s", resource_name);
1996 }
1998
1999 return res;
2000}
2001
2008};
2009
2011
2012static struct load_order_entry *add_to_load_order(const char *resource, struct load_order *load_order, int required, int preload, int builtin)
2013{
2014 struct load_order_entry *order;
2015 size_t resource_baselen = resource_name_baselen(resource);
2016
2018 if (!resource_name_match(resource, resource_baselen, order->resource)) {
2019 /* Make sure we have the proper setting for the required field
2020 (we might have both load= and required= lines in modules.conf) */
2021 order->required |= required;
2022 order->preload |= preload;
2023 return order;
2024 }
2025 }
2026
2027 order = ast_calloc(1, sizeof(*order));
2028 if (!order) {
2029 return NULL;
2030 }
2031
2032 order->resource = ast_strdup(resource);
2033 if (!order->resource) {
2034 ast_free(order);
2035
2036 return NULL;
2037 }
2038 order->required = required;
2039 order->preload = preload;
2040 order->builtin = builtin;
2042
2043 return order;
2044}
2045
2047
2049{
2050 enum ast_module_load_result lres;
2051
2052 /* Try to grab required references. */
2053 if (module_deps_reference(mod, NULL)) {
2054 /* We're likely to retry so not an error. */
2055 ast_debug(1, "Module %s is missing dependencies\n", mod->resource);
2056 return AST_MODULE_LOAD_SKIP;
2057 }
2058
2059 lres = start_resource(mod);
2060 ast_debug(3, "START: %-46s[%d] %d\n",
2061 mod->resource,
2063 lres);
2064
2065 if (lres == AST_MODULE_LOAD_SUCCESS) {
2066 (*count)++;
2067 } else if (lres == AST_MODULE_LOAD_FAILURE) {
2068 module_load_error("*** Failed to load %smodule %s\n",
2069 mod->flags.required ? "required " : "",
2070 mod->resource);
2071 }
2072
2073 return lres;
2074}
2075
2077 struct ast_str **printmissing)
2078{
2079 struct module_vector missingdeps;
2080 struct ast_vector_const_string localdeps;
2081 int i = 0;
2082 int res = -1;
2083
2084 mod->flags.declined = 1;
2085 if (mod->flags.required) {
2086 module_load_error("Required module %s declined to load.\n", ast_module_name(mod));
2087
2088 return -2;
2089 }
2090
2091 module_load_error("%s declined to load.\n", ast_module_name(mod));
2092
2093 if (!*printmissing) {
2094 *printmissing = ast_str_create(64);
2095 if (!*printmissing) {
2096 return -1;
2097 }
2098 } else {
2099 ast_str_reset(*printmissing);
2100 }
2101
2102 AST_VECTOR_INIT(&missingdeps, 0);
2103 AST_VECTOR_INIT(&localdeps, 0);
2104
2105 /* Decline everything that depends on 'mod' from resources so we can
2106 * print a concise list. */
2107 while (res != -2 && i < AST_VECTOR_SIZE(resources)) {
2108 struct ast_module *dep = AST_VECTOR_GET(resources, i);
2109 i++;
2110
2112 if (dep->flags.declined || module_deps_missing_recursive(dep, &missingdeps)) {
2113 continue;
2114 }
2115
2116 if (AST_VECTOR_GET_CMP(&missingdeps, mod, AST_VECTOR_ELEM_DEFAULT_CMP)) {
2117 dep->flags.declined = 1;
2118 if (dep->flags.required) {
2119 module_load_error("Cannot load required module %s that depends on %s\n",
2120 ast_module_name(dep), ast_module_name(mod));
2121 res = -2;
2122 } else {
2123 AST_VECTOR_APPEND(&localdeps, ast_module_name(dep));
2124 }
2125 }
2126 }
2127 AST_VECTOR_FREE(&missingdeps);
2128
2129 if (res != -2 && AST_VECTOR_SIZE(&localdeps)) {
2130 AST_VECTOR_CALLBACK_VOID(&localdeps, STR_APPEND_TEXT, printmissing);
2131 module_load_error("Declined modules which depend on %s: %s\n",
2132 ast_module_name(mod), ast_str_buffer(*printmissing));
2133 }
2134 AST_VECTOR_FREE(&localdeps);
2135
2136 return res;
2137}
2138
2139static int start_resource_list(struct module_vector *resources, int *mod_count)
2140{
2141 struct module_vector missingdeps;
2142 int res = 0;
2143 struct ast_str *printmissing = NULL;
2144
2145 AST_VECTOR_INIT(&missingdeps, 0);
2146 while (res != -2 && AST_VECTOR_SIZE(resources)) {
2147 struct ast_module *mod = AST_VECTOR_REMOVE(resources, 0, 1);
2148 enum ast_module_load_result lres;
2149
2150 if (mod->flags.declined) {
2151 ast_debug(1, "%s is already declined, skipping\n", ast_module_name(mod));
2152 continue;
2153 }
2154
2155retry_load:
2156 lres = start_resource_attempt(mod, mod_count);
2157 if (lres == AST_MODULE_LOAD_SUCCESS) {
2158 /* No missing dependencies, successful. */
2159 continue;
2160 }
2161
2162 if (lres == AST_MODULE_LOAD_FAILURE) {
2163 res = -2;
2164 break;
2165 }
2166
2167 if (lres == AST_MODULE_LOAD_DECLINE) {
2168 res = resource_list_recursive_decline(resources, mod, &printmissing);
2169 continue;
2170 }
2171
2172 if (module_deps_missing_recursive(mod, &missingdeps)) {
2174 module_load_error("Failed to resolve dependencies for %s\n", ast_module_name(mod));
2175 res = resource_list_recursive_decline(resources, mod, &printmissing);
2176 continue;
2177 }
2178
2179 if (!AST_VECTOR_SIZE(&missingdeps)) {
2180 module_load_error("%s load function returned an invalid result. "
2181 "This is a bug in the module.\n", ast_module_name(mod));
2182 /* Dependencies were met but the module failed to start and the result
2183 * code was not AST_MODULE_LOAD_FAILURE or AST_MODULE_LOAD_DECLINE. */
2184 res = resource_list_recursive_decline(resources, mod, &printmissing);
2185 continue;
2186 }
2187
2188 ast_debug(1, "%s has %d dependencies\n",
2189 ast_module_name(mod), (int)AST_VECTOR_SIZE(&missingdeps));
2190 while (AST_VECTOR_SIZE(&missingdeps)) {
2191 int didwork = 0;
2192 int i = 0;
2193
2194 while (i < AST_VECTOR_SIZE(&missingdeps)) {
2195 struct ast_module *dep = AST_VECTOR_GET(&missingdeps, i);
2196
2197 if (dep->flags.declined) {
2198 ast_debug(1, "%s tried to start %s but it's already declined\n",
2199 ast_module_name(mod), ast_module_name(dep));
2200 i++;
2201 continue;
2202 }
2203
2204 ast_debug(1, "%s trying to start %s\n", ast_module_name(mod), ast_module_name(dep));
2205 lres = start_resource_attempt(dep, mod_count);
2206 if (lres == AST_MODULE_LOAD_SUCCESS) {
2207 ast_debug(1, "%s started %s\n", ast_module_name(mod), ast_module_name(dep));
2208 AST_VECTOR_REMOVE(&missingdeps, i, 1);
2211 didwork++;
2212 continue;
2213 }
2214
2215 if (lres == AST_MODULE_LOAD_FAILURE) {
2216 module_load_error("Failed to load %s.\n", ast_module_name(dep));
2217 res = -2;
2218 goto exitpoint;
2219 }
2220
2221 ast_debug(1, "%s failed to start %s\n", ast_module_name(mod), ast_module_name(dep));
2222 i++;
2223 }
2224
2225 if (!didwork) {
2226 break;
2227 }
2228 }
2229
2230 if (AST_VECTOR_SIZE(&missingdeps)) {
2231 if (!printmissing) {
2232 printmissing = ast_str_create(64);
2233 } else {
2234 ast_str_reset(printmissing);
2235 }
2236
2237 if (printmissing) {
2238 struct ast_vector_const_string localdeps;
2239
2240 AST_VECTOR_INIT(&localdeps, 0);
2241 module_deps_reference(mod, &localdeps);
2242 AST_VECTOR_CALLBACK_VOID(&localdeps, STR_APPEND_TEXT, &printmissing);
2243 AST_VECTOR_FREE(&localdeps);
2244 }
2245
2246 module_load_error("Failed to load %s due to dependencies: %s.\n",
2247 ast_module_name(mod),
2248 printmissing ? ast_str_buffer(printmissing) : "allocation failure creating list");
2249 res = resource_list_recursive_decline(resources, mod, &printmissing);
2250
2252
2253 continue;
2254 }
2255
2256 /* If we're here it means that we started with missingdeps and they're all loaded
2257 * now. It's impossible to reach this point a second time for the same module. */
2258 goto retry_load;
2259 }
2260
2261exitpoint:
2262 ast_free(printmissing);
2263 AST_VECTOR_FREE(&missingdeps);
2264
2265 return res;
2266}
2267
2268/*! loads modules in order by load_pri, updates mod_count
2269 \return -1 on failure to load module, -2 on failure to load required module, otherwise 0
2270*/
2271static int load_resource_list(struct load_order *load_order, int *mod_count)
2272{
2273 struct module_vector module_priorities;
2274 struct load_order_entry *order;
2275 int attempt = 0;
2276 int count = 0;
2277 int res = 0;
2278 int didwork;
2279 int lasttry = 0;
2280
2281 if (AST_VECTOR_INIT(&module_priorities, 500)) {
2282 ast_log(LOG_ERROR, "Failed to initialize module loader.\n");
2283
2284 return -1;
2285 }
2286
2287 while (res != -2) {
2288 didwork = 0;
2289
2291 enum ast_module_load_result lres;
2292
2293 /* Suppress log messages unless this is the last pass */
2294 lres = load_resource(order->resource, !lasttry, &module_priorities, order->required, order->preload);
2295 ast_debug(3, "PASS %d: %-46s %d\n", attempt, order->resource, lres);
2296 switch (lres) {
2299 /* We're supplying module_priorities so SUCCESS isn't possible but we
2300 * still have to test for it. SKIP is only used when we try to start a
2301 * module that is missing dependencies. */
2302 break;
2304 res = -1;
2305 break;
2307 /* LOAD_FAILURE only happens for required modules */
2308 if (lasttry) {
2309 /* This run is just to print errors. */
2310 module_load_error("*** Failed to load module %s - Required\n", order->resource);
2311 fprintf(stderr, "*** Failed to load module %s - Required\n", order->resource);
2312 res = -2;
2313 }
2314 break;
2316 /* load_resource worked and the module was added to module_priorities */
2318 ast_free(order->resource);
2319 ast_free(order);
2320 didwork = 1;
2321 break;
2322 }
2323 }
2325
2326 if (!didwork) {
2327 if (lasttry) {
2328 break;
2329 }
2330 /* We know the next try is going to fail, it's only being performed
2331 * so we can print errors. */
2332 lasttry = 1;
2333 }
2334 attempt++;
2335 }
2336
2337 if (res != -2) {
2338 res = start_resource_list(&module_priorities, &count);
2339 }
2340
2341 if (mod_count) {
2342 *mod_count += count;
2343 }
2344 AST_VECTOR_FREE(&module_priorities);
2345
2346 return res;
2347}
2348
2350{
2351 struct ast_module *mod;
2352
2353 /*
2354 * All built-in modules have registered the first time, now it's time to complete
2355 * the registration and add them to the priority list.
2356 */
2357 loader_ready = 1;
2358
2360 /* ast_module_register doesn't finish when first run by built-in modules. */
2362 }
2363
2364 /* Add all built-in modules to the load order. */
2366 if (!mod->flags.builtin) {
2367 continue;
2368 }
2369
2370 /* Parse dependendencies from mod->info. */
2371 if (module_post_register(mod)) {
2372 return -1;
2373 }
2374
2375 /* Built-in modules are not preloaded, most have an early load priority. */
2376 if (!add_to_load_order(mod->resource, load_order, 0, 0, 1)) {
2377 return -1;
2378 }
2379 }
2380
2381 return 0;
2382}
2383
2385{
2386 int res = -1;
2387 struct load_order_entry *order;
2388 struct ast_config *cfg;
2389 struct ast_variable *v;
2390 struct ast_flags config_flags = { 0 };
2391
2392 cfg = ast_config_load2(AST_MODULE_CONFIG, "" /* core, can't reload */, config_flags);
2394 ast_log(LOG_WARNING, "'%s' invalid or missing.\n", AST_MODULE_CONFIG);
2395
2396 return -1;
2397 }
2398
2399 /* first, find all the modules we have been explicitly requested to load */
2400 for (v = ast_variable_browse(cfg, "modules"); v; v = v->next) {
2401 int required;
2402 int preload = 0;
2403
2404 if (!strncasecmp(v->name, "preload", strlen("preload"))) {
2405 preload = 1;
2406 if (!strcasecmp(v->name, "preload")) {
2407 required = 0;
2408 } else if (!strcasecmp(v->name, "preload-require")) {
2409 required = 1;
2410 } else {
2411 ast_log(LOG_ERROR, "Unknown configuration option '%s'", v->name);
2412 goto done;
2413 }
2414 } else if (!strcasecmp(v->name, "load")) {
2415 required = 0;
2416 } else if (!strcasecmp(v->name, "require")) {
2417 required = 1;
2418 } else if (!strcasecmp(v->name, "noload") || !strcasecmp(v->name, "autoload")) {
2419 continue;
2420 } else {
2421 ast_log(LOG_ERROR, "Unknown configuration option '%s'", v->name);
2422 goto done;
2423 }
2424
2425 if (required) {
2426 ast_debug(2, "Adding module to required list: %s (%s)\n", v->value, v->name);
2427 }
2428
2429 if (!add_to_load_order(v->value, load_order, required, preload, 0)) {
2430 goto done;
2431 }
2432 }
2433
2434 /* check if 'autoload' is on */
2435 if (ast_true(ast_variable_retrieve(cfg, "modules", "autoload"))) {
2436 /* if we are allowed to load dynamic modules, scan the directory for
2437 for all available modules and add them as well */
2438 DIR *dir = opendir(ast_config_AST_MODULE_DIR);
2439 struct dirent *dirent;
2440
2441 if (dir) {
2442 while ((dirent = readdir(dir))) {
2443 int ld = strlen(dirent->d_name);
2444
2445 /* Must end in .so to load it. */
2446
2447 if (ld < 4)
2448 continue;
2449
2450 if (strcasecmp(dirent->d_name + ld - 3, ".so"))
2451 continue;
2452
2453 /* if there is already a module by this name in the module_list,
2454 skip this file */
2455 if (find_resource(dirent->d_name, 0))
2456 continue;
2457
2458 if (!add_to_load_order(dirent->d_name, load_order, 0, 0, 0)) {
2459 closedir(dir);
2460 goto done;
2461 }
2462 }
2463
2464 closedir(dir);
2465 } else {
2466 ast_log(LOG_ERROR, "Unable to open modules directory '%s'.\n", ast_config_AST_MODULE_DIR);
2467 goto done;
2468 }
2469 }
2470
2471 /* now scan the config for any modules we are prohibited from loading and
2472 remove them from the load order */
2473 for (v = ast_variable_browse(cfg, "modules"); v; v = v->next) {
2474 size_t baselen;
2475
2476 if (strcasecmp(v->name, "noload")) {
2477 continue;
2478 }
2479
2480 baselen = resource_name_baselen(v->value);
2482 if (!resource_name_match(v->value, baselen, order->resource)) {
2483 if (order->builtin) {
2484 ast_log(LOG_ERROR, "%s is a built-in module, you cannot specify 'noload'.\n", v->value);
2485 goto done;
2486 }
2487
2488 if (order->required) {
2489 ast_log(LOG_ERROR, "%s is configured with '%s' and 'noload', this is impossible.\n",
2490 v->value, order->preload ? "preload-require" : "require");
2491 goto done;
2492 }
2494 ast_free(order->resource);
2495 ast_free(order);
2496 }
2497 }
2499 }
2500
2501 res = 0;
2502done:
2503 ast_config_destroy(cfg);
2504
2505 return res;
2506}
2507
2509{
2510 struct load_order_entry *order;
2511 unsigned int load_count;
2512 struct load_order load_order;
2513 int res = 0;
2514 int modulecount = 0;
2515 int i;
2516 struct ast_module *cur;
2517#ifdef AST_XML_DOCS
2518 struct ast_str *warning_msg;
2519 char deprecated_in[33];
2520 char removed_in[33];
2521 char replacement[129];
2522#endif
2523 struct timeval start_time = ast_tvnow();
2524 struct timeval end_time;
2525 int64_t usElapsed;
2526
2527 ast_verb(1, "Asterisk Dynamic Loader Starting:\n");
2528
2529#if defined(HAVE_PERMANENT_DLOPEN)
2531 info_list_obj_cmp_fn); /* must not be cleaned at shutdown */
2532 if (!info_list) {
2533 fprintf(stderr, "Module info list allocation failure.\n");
2534 return 1;
2535 }
2536#endif
2537
2540
2543
2545 if (res) {
2546 goto done;
2547 }
2548
2550 if (res) {
2551 goto done;
2552 }
2553
2554 load_count = 0;
2556 load_count++;
2557
2558 if (load_count)
2559 ast_log(LOG_NOTICE, "%u modules will be loaded.\n", load_count);
2560
2561 res = load_resource_list(&load_order, &modulecount);
2562 if (res == -1) {
2563 ast_log(LOG_WARNING, "Some non-required modules failed to load.\n");
2564 res = 0;
2565 }
2566
2567done:
2569 ast_free(order->resource);
2570 ast_free(order);
2571 }
2572
2573#ifdef AST_XML_DOCS
2574 warning_msg = ast_str_create(512);
2575#endif
2576
2578#ifdef AST_XML_DOCS
2579 char *mod_name = NULL;
2580 struct ast_xml_xpath_results *results;
2581#endif
2582
2583 if (!cur->flags.running || cur->flags.declined) {
2584 continue;
2585 }
2586
2587#ifdef AST_XML_DOCS
2588 mod_name = get_name_from_resource(cur->resource);
2589 if (!warning_msg || !mod_name) {
2590 /* If we can't allocate memory, we have bigger issues */
2591 ast_free(mod_name);
2592 continue;
2593 }
2594
2595 /* Clear out the previous values */
2596 deprecated_in[0] = removed_in[0] = replacement[0] = 0;
2597
2598 results = ast_xmldoc_query("/docs/module[@name='%s']", mod_name);
2599 if (results) {
2600 struct ast_xml_node *deprecated_node, *removed_node, *replacement_node;
2601 struct ast_xml_node *metadata_nodes = ast_xml_node_get_children(ast_xml_xpath_get_first_result(results));
2602
2603 deprecated_node = ast_xml_find_element(metadata_nodes, "deprecated_in", NULL, NULL);
2604 if (deprecated_node) {
2605 const char *result_tmp = ast_xml_get_text(deprecated_node);
2606 if (!ast_strlen_zero(result_tmp)) {
2607 ast_copy_string(deprecated_in, result_tmp, sizeof(deprecated_in));
2608 }
2609 }
2610
2611 removed_node = ast_xml_find_element(metadata_nodes, "removed_in", NULL, NULL);
2612 if (removed_node) {
2613 const char *result_tmp = ast_xml_get_text(removed_node);
2614 if (!ast_strlen_zero(result_tmp)) {
2615 ast_copy_string(removed_in, result_tmp, sizeof(removed_in));
2616 }
2617 }
2618
2619 replacement_node = ast_xml_find_element(metadata_nodes, "replacement", NULL, NULL);
2620 if (replacement_node) {
2621 const char *result_tmp = ast_xml_get_text(replacement_node);
2622 if (!ast_strlen_zero(result_tmp)) {
2623 ast_copy_string(replacement, result_tmp, sizeof(replacement));
2624 }
2625 }
2626
2628 }
2629
2630 ast_str_reset(warning_msg);
2631
2632 if (cur->info->support_level == AST_MODULE_SUPPORT_DEPRECATED || !ast_strlen_zero(deprecated_in)
2633 || !ast_strlen_zero(removed_in) || !ast_strlen_zero(replacement)) {
2634 int already_butted = 0;
2635
2636 ast_str_append(&warning_msg, -1, "Module '%s' has been loaded", mod_name);
2637 if (!ast_strlen_zero(deprecated_in)) {
2638 ast_str_append(&warning_msg, -1, " but %s deprecated in Asterisk version %s",
2639 cur->info->support_level == AST_MODULE_SUPPORT_DEPRECATED ? "was" : "will be", deprecated_in);
2640 already_butted = 1;
2641 }
2642
2643 if (!ast_strlen_zero(removed_in)) {
2644 ast_str_append(&warning_msg, -1, " %s will be removed in Asterisk version %s", already_butted ? "and" : "but", removed_in);
2645 } else {
2646 ast_str_append(&warning_msg, -1, " %s may be removed in a future release", already_butted ? "and" : "but");
2647 }
2648
2649 ast_str_append(&warning_msg, -1, ".");
2650
2651 if (!ast_strlen_zero(replacement)) {
2652 ast_str_append(&warning_msg, -1, " Its replacement is '%s'.", replacement);
2653 }
2654 }
2655
2656 if (ast_str_strlen(warning_msg)) {
2657 ast_log(LOG_WARNING, "%s\n", ast_str_buffer(warning_msg));
2658 }
2659
2660 ast_free(mod_name);
2661#else
2663 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);
2664 }
2665#endif
2666 }
2667
2668#ifdef AST_XML_DOCS
2669 ast_free(warning_msg);
2670#endif
2671
2673
2674
2675 for (i = 0; i < AST_VECTOR_SIZE(&startup_errors); i++) {
2676 char *str = AST_VECTOR_GET(&startup_errors, i);
2677
2678 ast_log(LOG_ERROR, "%s", str);
2679 ast_free(str);
2680 }
2682
2685
2686 end_time = ast_tvnow();
2687 usElapsed = ast_tvdiff_us(end_time, start_time);
2688
2689#ifdef AST_XML_DOCS
2690 ast_debug(1, "Loader time with AST_XML_DOCS: %" PRId64 ".%06" PRId64 "\n", usElapsed / 1000000, usElapsed % 1000000);
2691#else
2692 ast_debug(1, "Loader time without AST_XML_DOCS: %" PRId64 ".%06" PRId64 "\n", usElapsed / 1000000, usElapsed % 1000000);
2693#endif
2694
2695 return res;
2696}
2697
2699{
2700 /* Notify any module monitors that the use count for a
2701 resource has changed */
2702 struct loadupdate *m;
2703
2706 m->updater();
2708}
2709
2710/*!
2711 * \internal
2712 * \brief Build an alpha sorted list of modules.
2713 *
2714 * \param alpha_module_list Pointer to uninitialized module_vector.
2715 *
2716 * This function always initializes alpha_module_list.
2717 *
2718 * \pre module_list must be locked.
2719 */
2720static int alpha_module_list_create(struct module_vector *alpha_module_list)
2721{
2722 struct ast_module *cur;
2723
2724 if (AST_VECTOR_INIT(alpha_module_list, 32)) {
2725 return -1;
2726 }
2727
2729 if (AST_VECTOR_ADD_SORTED(alpha_module_list, cur, module_vector_strcasecmp)) {
2730 return -1;
2731 }
2732 }
2733
2734 return 0;
2735}
2736
2737int ast_update_module_list(int (*modentry)(const char *module, const char *description,
2738 int usecnt, const char *status, const char *like,
2739 enum ast_module_support_level support_level),
2740 const char *like)
2741{
2742 int total_mod_loaded = 0;
2743 struct module_vector alpha_module_list;
2744
2746
2747 if (!alpha_module_list_create(&alpha_module_list)) {
2748 int idx;
2749
2750 for (idx = 0; idx < AST_VECTOR_SIZE(&alpha_module_list); idx++) {
2751 struct ast_module *cur = AST_VECTOR_GET(&alpha_module_list, idx);
2752
2753 total_mod_loaded += modentry(cur->resource, cur->info->description, cur->usecount,
2754 cur->flags.running ? "Running" : "Not Running", like, cur->info->support_level);
2755 }
2756 }
2757
2759 AST_VECTOR_FREE(&alpha_module_list);
2760
2761 return total_mod_loaded;
2762}
2763
2764int ast_update_module_list_data(int (*modentry)(const char *module, const char *description,
2765 int usecnt, const char *status, const char *like,
2766 enum ast_module_support_level support_level,
2767 void *data),
2768 const char *like, void *data)
2769{
2770 int total_mod_loaded = 0;
2771 struct module_vector alpha_module_list;
2772
2774
2775 if (!alpha_module_list_create(&alpha_module_list)) {
2776 int idx;
2777
2778 for (idx = 0; idx < AST_VECTOR_SIZE(&alpha_module_list); idx++) {
2779 struct ast_module *cur = AST_VECTOR_GET(&alpha_module_list, idx);
2780
2781 total_mod_loaded += modentry(cur->resource, cur->info->description, cur->usecount,
2782 cur->flags.running? "Running" : "Not Running", like, cur->info->support_level, data);
2783 }
2784 }
2785
2787 AST_VECTOR_FREE(&alpha_module_list);
2788
2789 return total_mod_loaded;
2790}
2791
2792int ast_update_module_list_condition(int (*modentry)(const char *module, const char *description,
2793 int usecnt, const char *status,
2794 const char *like,
2795 enum ast_module_support_level support_level,
2796 void *data, const char *condition),
2797 const char *like, void *data, const char *condition)
2798{
2799 int conditions_met = 0;
2800 struct module_vector alpha_module_list;
2801
2803
2804 if (!alpha_module_list_create(&alpha_module_list)) {
2805 int idx;
2806
2807 for (idx = 0; idx < AST_VECTOR_SIZE(&alpha_module_list); idx++) {
2808 struct ast_module *cur = AST_VECTOR_GET(&alpha_module_list, idx);
2809
2810 conditions_met += modentry(cur->resource, cur->info->description, cur->usecount,
2811 cur->flags.running? "Running" : "Not Running", like, cur->info->support_level, data,
2812 condition);
2813 }
2814 }
2815
2817 AST_VECTOR_FREE(&alpha_module_list);
2818
2819 return conditions_met;
2820}
2821
2822/*! \brief Check if module exists */
2823int ast_module_check(const char *name)
2824{
2825 struct ast_module *cur;
2826
2827 if (ast_strlen_zero(name))
2828 return 0; /* FALSE */
2829
2830 cur = find_resource(name, 1);
2831
2832 return (cur != NULL);
2833}
2834
2835
2836int ast_loader_register(int (*v)(void))
2837{
2838 struct loadupdate *tmp;
2839
2840 if (!(tmp = ast_malloc(sizeof(*tmp))))
2841 return -1;
2842
2843 tmp->updater = v;
2847
2848 return 0;
2849}
2850
2851int ast_loader_unregister(int (*v)(void))
2852{
2853 struct loadupdate *cur;
2854
2857 if (cur->updater == v) {
2859 break;
2860 }
2861 }
2864
2865 return cur ? 0 : -1;
2866}
2867
2868struct ast_module *__ast_module_ref(struct ast_module *mod, const char *file, int line, const char *func)
2869{
2870 if (!mod) {
2871 return NULL;
2872 }
2873
2874 if (mod->ref_debug) {
2875 __ao2_ref(mod->ref_debug, +1, "", file, line, func);
2876 }
2877
2880
2881 return mod;
2882}
2883
2885 const char *file, int line, const char *func)
2886{
2887 if (!mod || !mod->flags.running) {
2888 return NULL;
2889 }
2890
2891 return __ast_module_ref(mod, file, line, func);
2892}
2893
2894void __ast_module_shutdown_ref(struct ast_module *mod, const char *file, int line, const char *func)
2895{
2896 if (!mod || mod->flags.keepuntilshutdown) {
2897 return;
2898 }
2899
2900 __ast_module_ref(mod, file, line, func);
2901 mod->flags.keepuntilshutdown = 1;
2902}
2903
2904void __ast_module_unref(struct ast_module *mod, const char *file, int line, const char *func)
2905{
2906 if (!mod) {
2907 return;
2908 }
2909
2910 if (mod->ref_debug) {
2911 __ao2_ref(mod->ref_debug, -1, "", file, line, func);
2912 }
2913
2916}
2917
2918const char *support_level_map [] = {
2919 [AST_MODULE_SUPPORT_UNKNOWN] = "unknown",
2920 [AST_MODULE_SUPPORT_CORE] = "core",
2921 [AST_MODULE_SUPPORT_EXTENDED] = "extended",
2922 [AST_MODULE_SUPPORT_DEPRECATED] = "deprecated",
2923};
2924
2926{
2927 return support_level_map[support_level];
2928}
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:1868
#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:2761
#define ESS(x)
Definition: cli.h:59
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:1880
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:2614
int ast_unlock_path(const char *path)
Unlock a path.
Definition: main/app.c:2630
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:2462
#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:2904
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:2737
static void publish_unload_message(const char *name, const char *status)
Definition: loader.c:1703
void ast_process_pending_reloads(void)
Process reload requests received during startup.
Definition: loader.c:1566
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:2868
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:2012
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:2823
static int start_resource_list(struct module_vector *resources, int *mod_count)
Definition: loader.c:2139
int load_modules(void)
Definition: loader.c:2508
static int module_load_helper_on_file(const char *dir_name, const char *filename, void *obj)
Definition: loader.c:1483
#define RTLD_LOCAL
Definition: loader.c:124
void ast_update_use_count(void)
Notify when usecount has been changed.
Definition: loader.c:2698
const char * ast_module_support_level_to_string(enum ast_module_support_level support_level)
Definition: loader.c:2925
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:2918
static int load_resource_list(struct load_order *load_order, int *mod_count)
Definition: loader.c:2271
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:1634
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:1528
static int do_full_reload
Definition: loader.c:638
static int auto_unload_resource(const char *resource_name, enum ast_module_unload_mode force, int recursive, struct ast_vector_const_string *dependents)
Unload a resource.
Definition: loader.c:1285
enum ast_module_load_result ast_load_resource(const char *resource_name)
Load a module.
Definition: loader.c:1978
static struct ast_str * startup_error_builder
Definition: loader.c:154
static int loader_config_init(struct load_order *load_order)
Definition: loader.c:2384
static const char * loadresult2str(enum ast_module_load_result result)
Definition: loader.c:1673
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
int ast_refresh_resource(const char *resource_name, enum ast_module_unload_mode force, int recursive)
Unload and load a module again.
Definition: loader.c:1407
void __ast_module_shutdown_ref(struct ast_module *mod, const char *file, int line, const char *func)
Definition: loader.c:2894
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:2836
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:1922
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:2076
static void queue_reload_request(const char *module)
Definition: loader.c:1591
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:2048
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:1810
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:2851
#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:1837
static void publish_reload_message(const char *name, enum ast_module_reload_result result)
Definition: loader.c:1713
int ast_unload_resource(const char *resource_name, enum ast_module_unload_mode force)
Unload a module.
Definition: loader.c:1448
static int loader_builtin_init(struct load_order *load_order)
Definition: loader.c:2349
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:2764
static int graceful_unload_possible(struct ast_module *target, struct ast_vector_const_string *dependents)
Whether or not this module should be able to be unloaded successfully, if we recursively unload any m...
Definition: loader.c:1225
#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:1453
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:2792
struct ast_module * __ast_module_running_ref(struct ast_module *mod, const char *file, int line, const char *func)
Definition: loader.c:2884
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:2720
static void publish_load_message(const char *name, enum ast_module_load_result result)
Definition: loader.c:1690
static void module_load_helper(const char *word)
Definition: loader.c:1515
enum ast_module_reload_result ast_module_reload(const char *name)
Reload asterisk modules.
Definition: loader.c:1721
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:331
@ AST_MODFLAG_GLOBAL_SYMBOLS
Definition: module.h:330
#define ast_module_unref(mod)
Release a reference to the module.
Definition: module.h:483
#define ast_module_ref(mod)
Hold a reference to the module.
Definition: module.h:457
#define ast_module_shutdown_ref(mod)
Prevent unload of the module before shutdown.
Definition: module.h:478
#define AST_MODULE_CONFIG
Module configuration file.
Definition: module.h:59
@ AST_MODPRI_DEFAULT
Definition: module.h:346
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:358
enum ast_module_support_level support_level
Definition: module.h:430
const char * description
Definition: module.h:366
const char buildopt_sum[33]
Definition: module.h:377
const char * name
Definition: module.h:364
unsigned char load_pri
Definition: module.h:384
int(* reload)(void)
Definition: module.h:360
const char *const char * optional_modules
Comma-separated list of optionally required modules.
Definition: module.h:397
const char * key
Definition: module.h:373
int(* unload)(void)
Definition: module.h:362
const char * enhances
Modules that we provide enhanced functionality for.
Definition: module.h:420
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:2002
int builtin
Definition: loader.c:2006
int required
Definition: loader.c:2004
int preload
Definition: loader.c:2005
char * resource
Definition: loader.c:2003
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:1480
const char * word
Definition: loader.c:1478
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_INSERT_AT(vec, idx, elem)
Insert an element at a specific position in a vector, growing the vector if needed.
Definition: vector.h:338
#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:395
const char * ast_xml_get_text(struct ast_xml_node *node)
Get an element content string.
Definition: xml.c:353
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:415
void ast_xml_xpath_results_free(struct ast_xml_xpath_results *results)
Free the XPath results.
Definition: xml.c:425
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:297
struct ast_xml_xpath_results * ast_xmldoc_query(const char *fmt,...)
Execute an XPath query on the loaded XML documentation.
Definition: xmldoc.c:2576