Asterisk - The Open Source Telephony Project GIT-master-754dea3
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros Modules Pages
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 <since>
62 <version>12.0.0</version>
63 </since>
64 <synopsis>Raised when a module has been reloaded in Asterisk.</synopsis>
65 <syntax>
66 <parameter name="Module">
67 <para>The name of the module that was reloaded, or
68 <literal>All</literal> if all modules were reloaded</para>
69 </parameter>
70 <parameter name="Status">
71 <para>The numeric status code denoting the success or failure
72 of the reload request.</para>
73 <enumlist>
74 <enum name="0"><para>Success</para></enum>
75 <enum name="1"><para>Request queued</para></enum>
76 <enum name="2"><para>Module not found</para></enum>
77 <enum name="3"><para>Error</para></enum>
78 <enum name="4"><para>Reload already in progress</para></enum>
79 <enum name="5"><para>Module uninitialized</para></enum>
80 <enum name="6"><para>Reload not supported</para></enum>
81 </enumlist>
82 </parameter>
83 </syntax>
84 </managerEventInstance>
85 </managerEvent>
86 <managerEvent language="en_US" name="Load">
87 <managerEventInstance class="EVENT_FLAG_SYSTEM">
88 <since>
89 <version>16.0.0</version>
90 </since>
91 <synopsis>Raised when a module has been loaded in Asterisk.</synopsis>
92 <syntax>
93 <parameter name="Module">
94 <para>The name of the module that was loaded</para>
95 </parameter>
96 <parameter name="Status">
97 <para>The result of the load request.</para>
98 <enumlist>
99 <enum name="Failure"><para>Module could not be loaded properly</para></enum>
100 <enum name="Success"><para>Module loaded and configured</para></enum>
101 <enum name="Decline"><para>Module is not configured</para></enum>
102 </enumlist>
103 </parameter>
104 </syntax>
105 </managerEventInstance>
106 </managerEvent>
107 <managerEvent language="en_US" name="Unload">
108 <managerEventInstance class="EVENT_FLAG_SYSTEM">
109 <since>
110 <version>16.0.0</version>
111 </since>
112 <synopsis>Raised when a module has been unloaded in Asterisk.</synopsis>
113 <syntax>
114 <parameter name="Module">
115 <para>The name of the module that was unloaded</para>
116 </parameter>
117 <parameter name="Status">
118 <para>The result of the unload request.</para>
119 <enumlist>
120 <enum name="Success"><para>Module unloaded successfully</para></enum>
121 </enumlist>
122 </parameter>
123 </syntax>
124 </managerEventInstance>
125 </managerEvent>
126 ***/
127
128#ifndef RTLD_NOW
129#define RTLD_NOW 0
130#endif
131
132#ifndef RTLD_LOCAL
133#define RTLD_LOCAL 0
134#endif
135
139};
140
142
143static const unsigned char expected_key[] =
144{ 0x87, 0x76, 0x79, 0x35, 0x23, 0xea, 0x3a, 0xd3,
145 0x25, 0x2a, 0xbb, 0x35, 0x87, 0xe4, 0x22, 0x24 };
146
148
150
151/*! Used with AST_VECTOR_CALLBACK_VOID to create a
152 * comma separated list of module names for error messages. */
153#define STR_APPEND_TEXT(txt, str) \
154 ast_str_append(str, 0, "%s%s", \
155 ast_str_strlen(*(str)) > 0 ? ", " : "", \
156 txt)
157
158/* Built-in module registrations need special handling at startup */
159static unsigned int loader_ready;
160
161/*! String container for deferring output of startup errors. */
164
165#if defined(HAVE_PERMANENT_DLOPEN) || defined(AST_XML_DOCS)
166static char *get_name_from_resource(const char *resource)
167{
168 int len;
169 const char *last_three;
170 char *mod_name;
171
172 if (!resource) {
173 return NULL;
174 }
175
176 len = strlen(resource);
177 if (len > 3) {
178 last_three = &resource[len-3];
179 if (!strcasecmp(last_three, ".so")) {
180 mod_name = ast_calloc(1, len - 2);
181 if (mod_name) {
182 ast_copy_string(mod_name, resource, len - 2);
183 return mod_name;
184 } else {
185 /* Unable to allocate memory. */
186 return NULL;
187 }
188 }
189 }
190
191 /* Resource is the name - happens when manually unloading a module. */
192 mod_name = ast_calloc(1, len + 1);
193 if (mod_name) {
194 ast_copy_string(mod_name, resource, len + 1);
195 return mod_name;
196 }
197
198 /* Unable to allocate memory. */
199 return NULL;
200}
201#endif
202
203#if defined(HAVE_PERMANENT_DLOPEN)
204#define FIRST_DLOPEN 999
205
206struct ao2_container *info_list = NULL;
207
208struct info_list_obj {
209 const struct ast_module_info *info;
210 int dlopened;
211 char name[0];
212};
213
214static struct info_list_obj *info_list_obj_alloc(const char *name,
215 const struct ast_module_info *info)
216{
217 struct info_list_obj *new_entry;
218
219 new_entry = ao2_alloc(sizeof(*new_entry) + strlen(name) + 1, NULL);
220
221 if (!new_entry) {
222 return NULL;
223 }
224
225 strcpy(new_entry->name, name); /* SAFE */
226 new_entry->info = info;
227 new_entry->dlopened = FIRST_DLOPEN;
228
229 return new_entry;
230}
231
232AO2_STRING_FIELD_CMP_FN(info_list_obj, name)
233
234static void manual_mod_reg(const void *lib, const char *resource)
235{
236 struct info_list_obj *obj_tmp;
237 char *mod_name;
238
239 if (lib) {
240 mod_name = get_name_from_resource(resource);
241 if (mod_name) {
242 obj_tmp = ao2_find(info_list, mod_name, OBJ_SEARCH_KEY);
243 if (obj_tmp) {
244 if (obj_tmp->dlopened == FIRST_DLOPEN) {
245 obj_tmp->dlopened = 1;
246 } else {
247 ast_module_register(obj_tmp->info);
248 }
249 ao2_ref(obj_tmp, -1);
250 }
251 ast_free(mod_name);
252 }
253 }
254}
255
256static void manual_mod_unreg(const char *resource)
257{
258 struct info_list_obj *obj_tmp;
259 char *mod_name;
260
261 /* When Asterisk shuts down the destructor is called automatically. */
262 if (ast_shutdown_final()) {
263 return;
264 }
265
266 mod_name = get_name_from_resource(resource);
267 if (mod_name) {
268 obj_tmp = ao2_find(info_list, mod_name, OBJ_SEARCH_KEY);
269 if (obj_tmp) {
270 ast_module_unregister(obj_tmp->info);
271 ao2_ref(obj_tmp, -1);
272 }
273 ast_free(mod_name);
274 }
275}
276#endif
277
278static __attribute__((format(printf, 1, 2))) void module_load_error(const char *fmt, ...)
279{
280 char *copy = NULL;
281 va_list ap;
282
283 va_start(ap, fmt);
289 ast_free(copy);
290 }
291 } else {
292 ast_log_ap(LOG_ERROR, fmt, ap);
293 }
294 va_end(ap);
295}
296
297/*!
298 * \brief Internal flag to indicate all modules have been initially loaded.
299 */
300static int modules_loaded;
301
303 const struct ast_module_info *info;
304 /*! Used to get module references into refs log */
306 /*! The shared lib. */
307 void *lib;
308 /*! Number of 'users' and other references currently holding the module. */
310 /*! List of users holding the module. */
312
313 /*! List of required module names. */
315 /*! List of optional api modules. */
317 /*! List of modules this enhances. */
319
320 /*!
321 * \brief Vector holding pointers to modules we have a reference to.
322 *
323 * When one module requires another, the required module gets added
324 * to this list with a reference.
325 */
327 struct {
328 /*! The module running and ready to accept requests. */
329 unsigned int running:1;
330 /*! The module has declined to start. */
331 unsigned int declined:1;
332 /*! This module is being held open until it's time to shutdown. */
333 unsigned int keepuntilshutdown:1;
334 /*! The module is built-in. */
335 unsigned int builtin:1;
336 /*! The admin has declared this module is required. */
337 unsigned int required:1;
338 /*! This module is marked for preload. */
339 unsigned int preload:1;
342 char resource[0];
343};
344
346
347
350 const char *name;
351};
352
353static const struct load_results_map load_results[] = {
354 { AST_MODULE_LOAD_SUCCESS, "Success" },
355 { AST_MODULE_LOAD_DECLINE, "Decline" },
356 { AST_MODULE_LOAD_SKIP, "Skip" },
357 { AST_MODULE_LOAD_PRIORITY, "Priority" },
358 { AST_MODULE_LOAD_FAILURE, "Failure" },
359};
360#define AST_MODULE_LOAD_UNKNOWN_STRING "Unknown" /* Status string for unknown load status */
361
362static void publish_load_message_type(const char* type, const char *name, const char *status);
363static void publish_reload_message(const char *name, enum ast_module_reload_result result);
364static void publish_load_message(const char *name, enum ast_module_load_result result);
365static void publish_unload_message(const char *name, const char* status);
366
367
368/*
369 * module_list is cleared by its constructor possibly after
370 * we start accumulating built-in modules, so we need to
371 * use another list (without the lock) to accumulate them.
372 */
374
376{
377 return strcasecmp(a->resource, b->resource);
378}
379
380static int module_vector_cmp(struct ast_module *a, struct ast_module *b)
381{
382 int preload_diff = (int)b->flags.preload - (int)a->flags.preload;
383 /* if load_pri is not set, default is 128. Lower is better */
384 int a_pri = ast_test_flag(a->info, AST_MODFLAG_LOAD_ORDER)
385 ? a->info->load_pri : AST_MODPRI_DEFAULT;
386 int b_pri = ast_test_flag(b->info, AST_MODFLAG_LOAD_ORDER)
387 ? b->info->load_pri : AST_MODPRI_DEFAULT;
388
389 if (preload_diff) {
390 /* -1 preload a but not b */
391 /* 0 preload both or neither */
392 /* 1 preload b but not a */
393 return preload_diff;
394 }
395
396 /*
397 * Returns comparison values for a vector sorted by priority.
398 * <0 a_pri < b_pri
399 * =0 a_pri == b_pri
400 * >0 a_pri > b_pri
401 */
402 return a_pri - b_pri;
403}
404
405static struct ast_module *find_resource(const char *resource, int do_lock);
406
407/*!
408 * \internal
409 * \brief Add a reference from mod to dep.
410 *
411 * \param mod Owner of the new reference.
412 * \param dep Module to reference
413 * \param missing Vector to store name of \a dep if it is not running.
414 *
415 * This function returns failure if \a dep is not running and \a missing
416 * is NULL. If \a missing is not NULL errors will only be returned for
417 * allocation failures.
418 *
419 * \retval 0 Success
420 * \retval -1 Failure
421 *
422 * \note Adding a second reference to the same dep will return success
423 * without doing anything.
424 */
425static int module_reffed_deps_add(struct ast_module *mod, struct ast_module *dep,
426 struct ast_vector_const_string *missing)
427{
428 if (!dep->flags.running) {
429 return !missing ? -1 : AST_VECTOR_APPEND(missing, dep->info->name);
430 }
431
433 /* Skip duplicate. */
434 return 0;
435 }
436
437 if (AST_VECTOR_APPEND(&mod->reffed_deps, dep)) {
438 return -1;
439 }
440
441 ast_module_ref(dep);
442
443 return 0;
444}
445
446/*!
447 * \internal
448 * \brief Add references for modules that enhance a dependency.
449 *
450 * \param mod Owner of the new references.
451 * \param dep Module to check for enhancers.
452 * \param missing Vector to store name of any enhancer that is not running or declined.
453 *
454 * \retval 0 Success
455 * \retval -1 Failure
456 */
458 struct ast_module *dep, struct ast_vector_const_string *missing)
459{
460 struct ast_module *cur;
461
463 if (cur->flags.declined) {
464 continue;
465 }
466
467 if (!AST_VECTOR_GET_CMP(&cur->enhances, dep->info->name, !strcasecmp)) {
468 /* dep is not enhanced by cur. */
469 continue;
470 }
471
472 /* dep is enhanced by cur, therefore mod requires cur. */
473 if (module_reffed_deps_add(mod, cur, missing)) {
474 return -1;
475 }
476 }
477
478 return 0;
479}
480
481/*!
482 * \internal
483 * \brief Add references to a list of dependencies.
484 *
485 * \param mod Owner of the new references.
486 * \param vec List of required modules to process
487 * \param missing Vector to store names of modules that are not running.
488 * \param ref_enhancers Reference all enhancers of each required module.
489 * \param isoptional Modules that are not loaded can be ignored.
490 *
491 * \retval 0 Success
492 * \retval -1 Failure
493 */
495 struct ast_vector_string *vec, struct ast_vector_const_string *missing,
496 int ref_enhancers, int isoptional)
497{
498 int idx;
499
500 for (idx = 0; idx < AST_VECTOR_SIZE(vec); idx++) {
501 const char *depname = AST_VECTOR_GET(vec, idx);
502 struct ast_module *dep = find_resource(depname, 0);
503
504 if (!dep || !dep->flags.running) {
505 if (isoptional && !dep) {
506 continue;
507 }
508
509 if (missing && !AST_VECTOR_APPEND(missing, depname)) {
510 continue;
511 }
512
513 return -1;
514 }
515
516 if (module_reffed_deps_add(mod, dep, missing)) {
517 return -1;
518 }
519
520 if (ref_enhancers && module_reffed_deps_add_dep_enhancers(mod, dep, missing)) {
521 return -1;
522 }
523 }
524
525 return 0;
526}
527
528/*!
529 * \internal
530 * \brief Grab all references required to start the module.
531 *
532 * \param mod The module we're trying to start.
533 * \param missing Vector to store a list of missing dependencies.
534 *
535 * \retval 0 Success
536 * \retval -1 Failure
537 *
538 * \note module_list must be locked.
539 *
540 * \note Caller is responsible for initializing and freeing the vector.
541 * Elements are safely read only while module_list remains locked.
542 */
543static int module_deps_reference(struct ast_module *mod, struct ast_vector_const_string *missing)
544{
545 int res = 0;
546
547 /* Grab references to modules we enhance but not other enhancements. */
548 res |= module_deps_process_reqlist(mod, &mod->enhances, missing, 0, 0);
549
550 /* Grab references to modules we require plus enhancements. */
551 res |= module_deps_process_reqlist(mod, &mod->requires, missing, 1, 0);
552
553 /* Grab references to optional modules including enhancements. */
554 res |= module_deps_process_reqlist(mod, &mod->optional_modules, missing, 1, 1);
555
556 return res;
557}
558
559/*!
560 * \brief Recursively find required dependencies that are not running.
561 *
562 * \param mod Module to scan for dependencies.
563 * \param missingdeps Vector listing modules that must be started first.
564 *
565 * \retval 0 All dependencies resolved.
566 * \retval -1 Failed to resolve some dependencies.
567 *
568 * An error from this function usually means a required module is not even
569 * loaded. This function is safe from infinite recursion, but dependency
570 * loops are not reported as an error from here. On success missingdeps
571 * will contain a list of every module that needs to be running before this
572 * module can start. missingdeps is sorted by load priority so any missing
573 * dependencies can be started if needed.
574 */
575static int module_deps_missing_recursive(struct ast_module *mod, struct module_vector *missingdeps)
576{
577 int i = 0;
578 int res = -1;
579 struct ast_vector_const_string localdeps;
580 struct ast_module *dep;
581
582 /*
583 * localdeps stores a copy of all dependencies that mod could not reference.
584 * First we discard modules that we've already found. We add all newly found
585 * modules to the missingdeps vector then scan them recursively. This will
586 * ensure we quickly run out of stuff to do.
587 */
588 AST_VECTOR_INIT(&localdeps, 0);
589 if (module_deps_reference(mod, &localdeps)) {
590 goto clean_return;
591 }
592
593 while (i < AST_VECTOR_SIZE(&localdeps)) {
594 dep = find_resource(AST_VECTOR_GET(&localdeps, i), 0);
595 if (!dep) {
596 goto clean_return;
597 }
598
599 if (AST_VECTOR_GET_CMP(missingdeps, dep, AST_VECTOR_ELEM_DEFAULT_CMP)) {
600 /* Skip common dependency. We have already searched it. */
601 AST_VECTOR_REMOVE(&localdeps, i, 0);
602 } else {
603 /* missingdeps is the real list so keep it sorted. */
604 if (AST_VECTOR_ADD_SORTED(missingdeps, dep, module_vector_cmp)) {
605 goto clean_return;
606 }
607 i++;
608 }
609 }
610
611 res = 0;
612 for (i = 0; !res && i < AST_VECTOR_SIZE(&localdeps); i++) {
613 dep = find_resource(AST_VECTOR_GET(&localdeps, i), 0);
614 /* We've already confirmed dep is loaded in the first loop. */
615 res = module_deps_missing_recursive(dep, missingdeps);
616 }
617
618clean_return:
619 AST_VECTOR_FREE(&localdeps);
620
621 return res;
622}
623
624const char *ast_module_name(const struct ast_module *mod)
625{
626 if (!mod || !mod->info) {
627 return NULL;
628 }
629
630 return mod->info->name;
631}
632
634 int (*updater)(void);
636};
637
639
641
644 char module[0];
645};
646
647static int do_full_reload = 0;
648
650
651/*!
652 * \internal
653 *
654 * This variable is set by load_dynamic_module so ast_module_register
655 * can know what pointer is being registered.
656 *
657 * This is protected by the module_list lock.
658 */
659static struct ast_module * volatile resource_being_loaded;
660
661/*!
662 * \internal
663 * \brief Used by AST_MODULE_INFO to register with the module loader.
664 *
665 * This function is automatically called when each module is opened.
666 * It must never be used from outside AST_MODULE_INFO.
667 */
669{
670 struct ast_module *mod;
671
672 if (!loader_ready) {
673 mod = ast_std_calloc(1, sizeof(*mod) + strlen(info->name) + 1);
674 if (!mod) {
675 /* We haven't even reached main() yet, if we can't
676 * allocate memory at this point just give up. */
677 fprintf(stderr, "Allocation failure during startup.\n");
678 exit(2);
679 }
680 strcpy(mod->resource, info->name); /* safe */
681 mod->info = info;
682 mod->flags.builtin = 1;
684
685 /* ast_module_register for built-in modules is run again during module preload. */
686 return;
687 }
688
689 /*
690 * This lock protects resource_being_loaded as well as the module
691 * list. Normally we already have a lock on module_list when we
692 * begin the load but locking again from here prevents corruption
693 * if an asterisk module is dlopen'ed from outside the module loader.
694 */
697 if (!mod) {
699 return;
700 }
701
702 ast_debug(5, "Registering module %s\n", info->name);
703
704 /* This tells load_dynamic_module that we're registered. */
706
707 mod->info = info;
708 if (ast_opt_ref_debug) {
710 }
712 AST_VECTOR_INIT(&mod->requires, 0);
714 AST_VECTOR_INIT(&mod->enhances, 0);
716
719
720 /* give the module a copy of its own handle, for later use in registrations and the like */
721 *((struct ast_module **) &(info->self)) = mod;
722
723#if defined(HAVE_PERMANENT_DLOPEN)
724 if (mod->flags.builtin != 1) {
725 struct info_list_obj *obj_tmp = ao2_find(info_list, info->name,
727
728 if (!obj_tmp) {
729 obj_tmp = info_list_obj_alloc(info->name, info);
730 if (obj_tmp) {
731 ao2_link(info_list, obj_tmp);
732 ao2_ref(obj_tmp, -1);
733 }
734 } else {
735 ao2_ref(obj_tmp, -1);
736 }
737 }
738#endif
739}
740
741static int module_post_register(struct ast_module *mod)
742{
743 int res;
744
745 /* Split lists from mod->info. */
746 res = ast_vector_string_split(&mod->requires, mod->info->requires, ",", 0, strcasecmp);
747 res |= ast_vector_string_split(&mod->optional_modules, mod->info->optional_modules, ",", 0, strcasecmp);
748 res |= ast_vector_string_split(&mod->enhances, mod->info->enhances, ",", 0, strcasecmp);
749
750 return res;
751}
752
753static void module_destroy(struct ast_module *mod)
754{
757
760
763
764 /* Release references to all dependencies. */
767
770 if (mod->flags.builtin) {
771 ast_std_free(mod);
772 } else {
773 ast_free(mod);
774 }
775}
776
778{
779 struct ast_module *mod = NULL;
780
781 /* it is assumed that the users list in the module structure
782 will already be empty, or we cannot have gotten to this
783 point
784 */
787 if (mod->info == info) {
789 break;
790 }
791 }
794
795 if (mod && !mod->usecount) {
796 /*
797 * We are intentionally leaking mod if usecount is not zero.
798 * This is necessary if the module is being forcefully unloaded.
799 * In addition module_destroy is not safe to run after exit()
800 * is called. ast_module_unregister is run during cleanup of
801 * the process when libc releases each module's shared object
802 * library.
803 */
804 ast_debug(5, "Unregistering module %s\n", info->name);
805 module_destroy(mod);
806 }
807}
808
810{
811 struct ast_module_user *u;
812
813 u = ast_calloc(1, sizeof(*u));
814 if (!u) {
815 return NULL;
816 }
817
818 u->chan = chan;
819
820 AST_LIST_LOCK(&mod->users);
822 AST_LIST_UNLOCK(&mod->users);
823
824 if (mod->ref_debug) {
825 ao2_ref(mod->ref_debug, +1);
826 }
827
829
831
832 return u;
833}
834
836{
837 if (!u) {
838 return;
839 }
840
841 AST_LIST_LOCK(&mod->users);
842 u = AST_LIST_REMOVE(&mod->users, u, entry);
843 AST_LIST_UNLOCK(&mod->users);
844 if (!u) {
845 /*
846 * Was not in the list. Either a bad pointer or
847 * __ast_module_user_hangup_all() has been called.
848 */
849 return;
850 }
851
852 if (mod->ref_debug) {
853 ao2_ref(mod->ref_debug, -1);
854 }
855
857 ast_free(u);
858
860}
861
863{
864 struct ast_module_user *u;
865
866 AST_LIST_LOCK(&mod->users);
867 while ((u = AST_LIST_REMOVE_HEAD(&mod->users, entry))) {
868 if (u->chan) {
870 }
871
872 if (mod->ref_debug) {
873 ao2_ref(mod->ref_debug, -1);
874 }
875
877 ast_free(u);
878 }
879 AST_LIST_UNLOCK(&mod->users);
880
882}
883
884static int printdigest(const unsigned char *d)
885{
886 int x, pos;
887 char buf[256]; /* large enough so we don't have to worry */
888
889 for (pos = 0, x = 0; x < 16; x++)
890 pos += sprintf(buf + pos, " %02hhx", *d++);
891
892 ast_debug(1, "Unexpected signature:%s\n", buf);
893
894 return 0;
895}
896
897#define key_matches(a, b) (memcmp((a), (b), 16) == 0)
898
899static int verify_key(const unsigned char *key)
900{
901 struct MD5Context c;
902 unsigned char digest[16];
903
904 MD5Init(&c);
905 MD5Update(&c, key, strlen((char *)key));
906 MD5Final(digest, &c);
907
908 if (key_matches(expected_key, digest))
909 return 0;
910
911 printdigest(digest);
912
913 return -1;
914}
915
916static size_t resource_name_baselen(const char *name)
917{
918 size_t len = strlen(name);
919
920 if (len > 3 && !strcasecmp(name + len - 3, ".so")) {
921 return len - 3;
922 }
923
924 return len;
925}
926
927static int resource_name_match(const char *name1, size_t baselen1, const char *name2)
928{
929 if (baselen1 != resource_name_baselen(name2)) {
930 return -1;
931 }
932
933 return strncasecmp(name1, name2, baselen1);
934}
935
936static struct ast_module *find_resource(const char *resource, int do_lock)
937{
938 struct ast_module *cur;
939 size_t resource_baselen = resource_name_baselen(resource);
940
941 if (do_lock) {
943 }
944
946 if (!resource_name_match(resource, resource_baselen, cur->resource)) {
947 break;
948 }
949 }
950
951 if (do_lock) {
953 }
954
955 return cur;
956}
957
958/*!
959 * \brief dlclose(), with failure logging.
960 */
961static void logged_dlclose(const char *name, void *lib)
962{
963 char *error;
964
965 if (!lib) {
966 return;
967 }
968
969 /* Clear any existing error */
970 dlerror();
971 if (dlclose(lib)) {
972 error = dlerror();
973 ast_log(AST_LOG_ERROR, "Failure in dlclose for module '%s': %s\n",
974 S_OR(name, "unknown"), S_OR(error, "Unknown error"));
975#if defined(HAVE_PERMANENT_DLOPEN)
976 } else {
977 manual_mod_unreg(name);
978#endif
979 }
980}
981
982#if defined(HAVE_RTLD_NOLOAD)
983/*!
984 * \brief Check to see if the given resource is loaded.
985 *
986 * \param resource_name Name of the resource, including .so suffix.
987 * \return False (0) if module is not loaded.
988 * \return True (non-zero) if module is loaded.
989 */
990static int is_module_loaded(const char *resource_name)
991{
992 char fn[PATH_MAX] = "";
993 void *lib;
994
995 snprintf(fn, sizeof(fn), "%s/%s", ast_config_AST_MODULE_DIR,
996 resource_name);
997
998 lib = dlopen(fn, RTLD_LAZY | RTLD_NOLOAD);
999
1000 if (lib) {
1001 logged_dlclose(resource_name, lib);
1002 return 1;
1003 }
1004
1005 return 0;
1006}
1007#endif
1008
1009static void unload_dynamic_module(struct ast_module *mod)
1010{
1011#if defined(HAVE_RTLD_NOLOAD)
1012 char *name = ast_strdupa(ast_module_name(mod));
1013#endif
1014 void *lib = mod->lib;
1015
1016 /* WARNING: the structure pointed to by mod is going to
1017 disappear when this operation succeeds, so we can't
1018 dereference it */
1020
1021 /* There are several situations where the module might still be resident
1022 * in memory.
1023 *
1024 * If somehow there was another dlopen() on the same module (unlikely,
1025 * since that all is supposed to happen in loader.c).
1026 *
1027 * Avoid the temptation of repeating the dlclose(). The other code that
1028 * dlopened the module still has its module reference, and should close
1029 * it itself. In other situations, dlclose() will happily return success
1030 * for as many times as you wish to call it.
1031 */
1032#if defined(HAVE_RTLD_NOLOAD)
1033 if (is_module_loaded(name)) {
1034 ast_log(LOG_WARNING, "Module '%s' could not be completely unloaded\n", name);
1035 }
1036#endif
1037}
1038
1039static int load_dlopen_missing(struct ast_str **list, struct ast_vector_string *deps)
1040{
1041 int i;
1042 int c = 0;
1043
1044 for (i = 0; i < AST_VECTOR_SIZE(deps); i++) {
1045 const char *dep = AST_VECTOR_GET(deps, i);
1046 if (!find_resource(dep, 0)) {
1047 STR_APPEND_TEXT(dep, list);
1048 c++;
1049 }
1050 }
1051
1052 return c;
1053}
1054
1055/*!
1056 * \internal
1057 * \brief Attempt to dlopen a module.
1058 *
1059 * \param resource_in The module name to load.
1060 * \param so_ext ".so" or blank if ".so" is already part of resource_in.
1061 * \param filename Passed directly to dlopen.
1062 * \param flags Passed directly to dlopen.
1063 * \param suppress_logging Do not log any error from dlopen.
1064 *
1065 * \return Pointer to opened module, NULL on error.
1066 *
1067 * \warning module_list must be locked before calling this function.
1068 */
1069static struct ast_module *load_dlopen(const char *resource_in, const char *so_ext,
1070 const char *filename, int flags, unsigned int suppress_logging)
1071{
1072 struct ast_module *mod;
1073
1075
1076 mod = ast_calloc(1, sizeof(*mod) + strlen(resource_in) + strlen(so_ext) + 1);
1077 if (!mod) {
1078 return NULL;
1079 }
1080
1081 sprintf(mod->resource, "%s%s", resource_in, so_ext); /* safe */
1082
1084 mod->lib = dlopen(filename, flags);
1085#if defined(HAVE_PERMANENT_DLOPEN)
1086 manual_mod_reg(mod->lib, mod->resource);
1087#endif
1089 struct ast_str *list;
1090 int c = 0;
1091 const char *dlerror_msg = ast_strdupa(S_OR(dlerror(), ""));
1092
1094 if (mod->lib) {
1095 module_load_error("Module '%s' did not register itself during load\n", resource_in);
1096 logged_dlclose(resource_in, mod->lib);
1097
1098 goto error_return;
1099 }
1100
1101 if (suppress_logging) {
1102 goto error_return;
1103 }
1104
1106 mod->lib = dlopen(filename, RTLD_LAZY | RTLD_LOCAL);
1107#if defined(HAVE_PERMANENT_DLOPEN)
1108 manual_mod_reg(mod->lib, mod->resource);
1109#endif
1112
1113 module_load_error("Error loading module '%s': %s\n", resource_in, dlerror_msg);
1114 logged_dlclose(resource_in, mod->lib);
1115
1116 goto error_return;
1117 }
1118
1119 list = ast_str_create(64);
1120 if (list) {
1121 if (module_post_register(mod)) {
1122 goto loaded_error;
1123 }
1124
1125 c = load_dlopen_missing(&list, &mod->requires);
1126 c += load_dlopen_missing(&list, &mod->enhances);
1127#ifndef OPTIONAL_API
1128 c += load_dlopen_missing(&list, &mod->optional_modules);
1129#endif
1130 }
1131
1132 if (list && ast_str_strlen(list)) {
1133 module_load_error("Error loading module '%s', missing %s: %s\n",
1134 resource_in, c == 1 ? "dependency" : "dependencies", ast_str_buffer(list));
1135 } else {
1136 module_load_error("Error loading module '%s': %s\n", resource_in, dlerror_msg);
1137 }
1138
1139loaded_error:
1140 ast_free(list);
1142
1143 return NULL;
1144
1145error_return:
1146 ast_free(mod);
1147
1148 return NULL;
1149 }
1150
1151 return mod;
1152}
1153
1154static struct ast_module *load_dynamic_module(const char *resource_in, unsigned int suppress_logging)
1155{
1156 char fn[PATH_MAX];
1157 struct ast_module *mod;
1158 size_t resource_in_len = strlen(resource_in);
1159 const char *so_ext = "";
1160
1161 if (resource_in_len < 4 || strcasecmp(resource_in + resource_in_len - 3, ".so")) {
1162 so_ext = ".so";
1163 }
1164
1165 snprintf(fn, sizeof(fn), "%s/%s%s", ast_config_AST_MODULE_DIR, resource_in, so_ext);
1166
1167 /* Try loading in quiet mode first with RTLD_LOCAL. The majority of modules do not
1168 * export symbols so this allows the least number of calls to dlopen. */
1169 mod = load_dlopen(resource_in, so_ext, fn, RTLD_NOW | RTLD_LOCAL, suppress_logging);
1170
1171 if (!mod || !ast_test_flag(mod->info, AST_MODFLAG_GLOBAL_SYMBOLS)) {
1172 return mod;
1173 }
1174
1175 /* Close the module so we can reopen with correct flags. */
1176 logged_dlclose(resource_in, mod->lib);
1177
1178 return load_dlopen(resource_in, so_ext, fn, RTLD_NOW | RTLD_GLOBAL, 0);
1179}
1180
1182{
1183 struct ast_module *mod;
1184 int somethingchanged;
1185 int res;
1186
1188
1189 /*!\note Some resources, like timers, are started up dynamically, and thus
1190 * may be still in use, even if all channels are dead. We must therefore
1191 * check the usecount before asking modules to unload. */
1192 do {
1193 /* Reset flag before traversing the list */
1194 somethingchanged = 0;
1195
1197 if (mod->usecount) {
1198 ast_debug(1, "Passing on %s: its use count is %d\n",
1199 mod->resource, mod->usecount);
1200 continue;
1201 }
1203 if (mod->flags.running && !mod->flags.declined && mod->info->unload) {
1204 ast_verb(4, "Unloading %s\n", mod->resource);
1205 mod->info->unload();
1206 }
1207 module_destroy(mod);
1208 somethingchanged = 1;
1209 }
1211 if (!somethingchanged) {
1213 if (mod->flags.keepuntilshutdown) {
1214 ast_module_unref(mod);
1215 mod->flags.keepuntilshutdown = 0;
1216 somethingchanged = 1;
1217 }
1218 }
1219 }
1220 } while (somethingchanged);
1221
1224
1225 return !res;
1226}
1227
1228/*!
1229 * \brief Whether or not this module should be able to be unloaded successfully,
1230 * if we recursively unload any modules that are dependent on it.
1231 * \note module_list should be locked when calling this
1232 * \retval 0 if not, 1 if likely possible
1233 */
1234static int graceful_unload_possible(struct ast_module *target, struct ast_vector_const_string *dependents)
1235{
1236 struct ast_module *mod;
1237 int usecount = target->usecount;
1238
1239 /* Check the reffed_deps of each module to see if we're one of them. */
1242 const char *name;
1243 /* This module is dependent on the target.
1244 * If we can unload this module gracefully,
1245 * then that would decrement our use count.
1246 * If any single module could not be unloaded gracefully,
1247 * then we don't proceed. */
1248 int unloadable;
1249 if (AST_VECTOR_GET_CMP(dependents, ast_module_name(mod), !strcasecmp)) {
1250 /* Already in our list, we already checked this module,
1251 * and we gave it the green light. */
1252 ast_debug(3, "Skipping duplicate dependent %s\n", ast_module_name(mod));
1253 if (!--usecount) {
1254 break;
1255 }
1256 continue;
1257 }
1258 unloadable = graceful_unload_possible(mod, dependents);
1259 if (!unloadable) {
1260 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));
1261 return 0;
1262 }
1263 /* Insert at beginning, so later if we're loading modules again automatically, we can do so in the same order. */
1265 if (!name) {
1266 return 0;
1267 }
1268 ast_debug(3, "Found new dependent %s\n", ast_module_name(mod));
1269 if (AST_VECTOR_INSERT_AT(dependents, 0, name)) {
1270 ast_log(LOG_ERROR, "Failed to add module '%s' to vector\n", ast_module_name(mod));
1271 return 0;
1272 }
1273 if (!--usecount) {
1274 break;
1275 }
1276 }
1277 }
1278
1279 if (usecount) {
1280 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);
1281 return 0;
1282 }
1283 return 1;
1284}
1285
1286/*!
1287 * \brief Unload a resource
1288 * \param resource_name Module name
1289 * \param force
1290 * \param recursive Whether to attempt to recursively unload dependents of this module and load them again afterwards
1291 * \param dependents. Can be NULL if autounload is 0.
1292 * \retval 0 on success, -1 on failure
1293 */
1294static int auto_unload_resource(const char *resource_name, enum ast_module_unload_mode force, int recursive, struct ast_vector_const_string *dependents)
1295{
1296 struct ast_module *mod;
1297 int res = -1;
1298 int error = 0;
1299
1301
1302 if (!(mod = find_resource(resource_name, 0))) {
1304 ast_log(LOG_WARNING, "Unload failed, '%s' could not be found\n", resource_name);
1305 return -1;
1306 }
1307
1308 if (!mod->flags.running || mod->flags.declined) {
1309 /* If the user asks to unload a module that didn't load, obey.
1310 * Otherwise, we never dlclose() modules that fail to load,
1311 * which means if the module (shared object) is updated,
1312 * we can't load the updated module since we never dlclose()'d it.
1313 * Accordingly, obey the unload request so we can load the module
1314 * from scratch next time.
1315 */
1316 ast_log(LOG_NOTICE, "Unloading module '%s' that previously declined to load\n", resource_name);
1317 error = 0;
1318 res = 0;
1319 goto exit; /* Skip all the intervening !error checks, only the last one is relevant. */
1320 }
1321
1322 if (!error && mod->usecount > 0 && recursive) {
1323 /* Try automatically unloading all modules dependent on the module we're trying to unload,
1324 * and then, optionally, load them back again if we end up loading this module again.
1325 * If any modules that have us as a dependency can't be unloaded, for whatever reason,
1326 * then the entire unload operation will fail, so to try to make this an atomic operation
1327 * and avoid leaving modules in a partial unload state, first check if we think we're going
1328 * to be able to pull this off, and if not, abort.
1329 *
1330 * A race condition is technically still possible, if some depending module suddenly goes in use
1331 * between this check and trying to unload it, but this takes care of the majority of
1332 * easy-to-avoid cases that would fail eventually anyways.
1333 *
1334 * Note that we can encounter false negatives (e.g. unloading all the dependents would allow
1335 * a module to unload, but graceful_unload_possible returns 0). This is because it's only
1336 * checking direct module dependencies; other dependencies caused by a module registering
1337 * a resource that cause its ref count to get bumped aren't accounted for here.
1338 */
1339 if (graceful_unload_possible(mod, dependents)) {
1340 int i, res = 0;
1341 size_t num_deps = AST_VECTOR_SIZE(dependents);
1342 ast_debug(1, "%lu module%s will need to be unloaded\n", AST_VECTOR_SIZE(dependents), ESS(AST_VECTOR_SIZE(dependents)));
1343 /* Unload from the end, since the last module was the first one added, which means it isn't a dependency of anything else. */
1344 for (i = AST_VECTOR_SIZE(dependents) - 1; i >= 0; i--) {
1345 const char *depname = AST_VECTOR_GET(dependents, i);
1346 res = ast_unload_resource(depname, force);
1347 if (res) {
1348 ast_log(LOG_WARNING, "Failed to unload %lu module%s automatically (%s could not be unloaded)\n", num_deps, ESS(num_deps), depname);
1349 /* To be polite, load modules that we already unloaded,
1350 * to try to leave things the way they were when we started. */
1351 for (i++; i < num_deps; i++) {
1352 const char *depname = AST_VECTOR_GET(dependents, i);
1353 res = ast_load_resource(depname);
1354 if (res) {
1355 ast_log(LOG_WARNING, "Could not load module '%s' again automatically\n", depname);
1356 }
1357 }
1358 break;
1359 }
1360 }
1361 /* Either we failed, or we successfully unloaded everything.
1362 * If we succeeded, we can now proceed and unload ourselves. */
1363 }
1364 }
1365
1366 if (!error && (mod->usecount > 0)) {
1367 if (force) {
1368 ast_log(LOG_WARNING, "Warning: Forcing removal of module '%s' with use count %d\n", resource_name, mod->usecount);
1369 } else {
1370 ast_log(LOG_WARNING, "%s unload failed, '%s' has use count %d\n", recursive ? "Recursive soft" : "Soft", resource_name, mod->usecount);
1371 error = 1;
1372 }
1373 }
1374
1375 if (!error) {
1376 /* Request any channels attached to the module to hangup. */
1378
1379 ast_verb(4, "Unloading %s\n", mod->resource);
1380 res = mod->info->unload();
1381 if (res) {
1382 ast_log(LOG_WARNING, "Firm unload failed for %s\n", resource_name);
1383 if (force <= AST_FORCE_FIRM) {
1384 error = 1;
1385 } else {
1386 ast_log(LOG_WARNING, "** Dangerous **: Unloading resource anyway, at user request\n");
1387 }
1388 }
1389
1390 if (!error) {
1391 /*
1392 * Request hangup on any channels that managed to get attached
1393 * while we called the module unload function.
1394 */
1396 sched_yield();
1397 }
1398 }
1399
1400 if (!error)
1401 mod->flags.running = mod->flags.declined = 0;
1402
1403exit:
1405
1406 if (!error) {
1408 ast_test_suite_event_notify("MODULE_UNLOAD", "Message: %s", resource_name);
1410 publish_unload_message(resource_name, "Success");
1411 }
1412
1413 return res;
1414}
1415
1416int ast_refresh_resource(const char *resource_name, enum ast_module_unload_mode force, int recursive)
1417{
1418 if (recursive) {
1419 /* Recursively unload dependents of this module and then load them back again */
1420 int res, i;
1421 struct ast_vector_const_string dependents;
1422 AST_VECTOR_INIT(&dependents, 0);
1423 res = auto_unload_resource(resource_name, force, recursive, &dependents);
1424 if (res) {
1425 AST_VECTOR_FREE(&dependents);
1426 return 1;
1427 }
1428 /* Start by loading the target again. */
1429 if (ast_load_resource(resource_name)) {
1430 ast_log(LOG_WARNING, "Failed to load module '%s' again automatically\n", resource_name);
1431 AST_VECTOR_FREE(&dependents);
1432 return -1;
1433 }
1434 res = 0;
1435 /* Finally, load again any modules we had to unload in order to refresh the target.
1436 * We must load modules in the reverse order that we unloaded them,
1437 * to preserve dependency requirements. */
1438 for (i = 0; i < AST_VECTOR_SIZE(&dependents); i++) {
1439 const char *depname = AST_VECTOR_GET(&dependents, i);
1440 int mres = ast_load_resource(depname);
1441 if (mres) {
1442 ast_log(LOG_WARNING, "Could not load module '%s' again automatically\n", depname);
1443 }
1444 res |= mres;
1445 }
1446 AST_VECTOR_FREE(&dependents);
1447 return res ? -1 : 0;
1448 }
1449
1450 /* Simple case: just unload and load the module again */
1451 if (ast_unload_resource(resource_name, force)) {
1452 return 1;
1453 }
1454 return ast_load_resource(resource_name);
1455}
1456
1457int ast_unload_resource(const char *resource_name, enum ast_module_unload_mode force)
1458{
1459 return auto_unload_resource(resource_name, force, 0, NULL);
1460}
1461
1463{
1464 switch (type) {
1466 return !mod->usecount && mod->flags.running && !mod->flags.declined;
1467
1469 return mod->flags.running && mod->info->reload;
1470
1472 return mod->flags.running;
1473
1475 /* if we have a 'struct ast_module' then we're loaded. */
1476 return 1;
1477 default:
1478 /* This function is not called for AST_MODULE_HELPER_LOAD. */
1479 /* Unknown ast_module_helper_type. Assume it doesn't match. */
1480 ast_assert(0);
1481
1482 return 0;
1483 }
1484}
1485
1487 const char *word;
1488 size_t len;
1490};
1491
1492static int module_load_helper_on_file(const char *dir_name, const char *filename, void *obj)
1493{
1494 struct module_load_word *word = obj;
1495 struct ast_module *mod;
1496 char *filename_merged = NULL;
1497
1498 /* dir_name will never be shorter than word->moddir_len. */
1499 dir_name += word->moddir_len;
1500 if (!ast_strlen_zero(dir_name)) {
1501 ast_assert(dir_name[0] == '/');
1502
1503 dir_name += 1;
1504 if (ast_asprintf(&filename_merged, "%s/%s", dir_name, filename) < 0) {
1505 /* If we can't allocate the string just give up! */
1506 return -1;
1507 }
1508 filename = filename_merged;
1509 }
1510
1511 if (!strncasecmp(filename, word->word, word->len)) {
1512 /* Don't list files that are already loaded! */
1513 mod = find_resource(filename, 0);
1514 if (!mod || !mod->flags.running) {
1516 }
1517 }
1518
1519 ast_free(filename_merged);
1520
1521 return 0;
1522}
1523
1524static void module_load_helper(const char *word)
1525{
1526 struct module_load_word word_l = {
1527 .word = word,
1528 .len = strlen(word),
1529 .moddir_len = strlen(ast_config_AST_MODULE_DIR),
1530 };
1531
1535}
1536
1537char *ast_module_helper(const char *line, const char *word, int pos, int state, int rpos, enum ast_module_helper_type type)
1538{
1539 struct ast_module *mod;
1540 int which = 0;
1541 int wordlen = strlen(word);
1542 char *ret = NULL;
1543
1544 if (pos != rpos) {
1545 return NULL;
1546 }
1547
1548 /* Tab completion can't be used during startup, or CLI and loader will deadlock. */
1550 return NULL;
1551 }
1552
1555
1556 return NULL;
1557 }
1558
1561 if (!module_matches_helper_type(mod, type)) {
1562 continue;
1563 }
1564
1565 if (!strncasecmp(word, mod->resource, wordlen) && ++which > state) {
1566 ret = ast_strdup(mod->resource);
1567 break;
1568 }
1569 }
1571
1572 return ret;
1573}
1574
1576{
1577 struct reload_queue_item *item;
1578
1579 modules_loaded = 1;
1580
1582
1583 if (do_full_reload) {
1584 do_full_reload = 0;
1586 ast_log(LOG_NOTICE, "Executing deferred reload request.\n");
1588 return;
1589 }
1590
1592 ast_log(LOG_NOTICE, "Executing deferred reload request for module '%s'.\n", item->module);
1593 ast_module_reload(item->module);
1594 ast_free(item);
1595 }
1596
1598}
1599
1600static void queue_reload_request(const char *module)
1601{
1602 struct reload_queue_item *item;
1603
1605
1606 if (do_full_reload) {
1608 return;
1609 }
1610
1611 if (ast_strlen_zero(module)) {
1612 /* A full reload request (when module is NULL) wipes out any previous
1613 reload requests and causes the queue to ignore future ones */
1615 ast_free(item);
1616 }
1617 do_full_reload = 1;
1618 } else {
1619 /* No reason to add the same module twice */
1621 if (!strcasecmp(item->module, module)) {
1623 return;
1624 }
1625 }
1626 item = ast_calloc(1, sizeof(*item) + strlen(module) + 1);
1627 if (!item) {
1628 ast_log(LOG_ERROR, "Failed to allocate reload queue item.\n");
1630 return;
1631 }
1632 strcpy(item->module, module);
1634 }
1636}
1637
1638/*!
1639 * \since 12
1640 * \internal
1641 * \brief Publish a \ref stasis message regarding the type.
1642 */
1643static void publish_load_message_type(const char* type, const char *name, const char *status)
1644{
1646 RAII_VAR(struct ast_json_payload *, payload, NULL, ao2_cleanup);
1647 RAII_VAR(struct ast_json *, json_object, NULL, ast_json_unref);
1648 RAII_VAR(struct ast_json *, event_object, NULL, ast_json_unref);
1649
1650 ast_assert(type != NULL);
1653
1655 return;
1656 }
1657
1658 event_object = ast_json_pack("{s:s, s:s}",
1659 "Module", name,
1660 "Status", status);
1661 json_object = ast_json_pack("{s:s, s:i, s:o}",
1662 "type", type,
1663 "class_type", EVENT_FLAG_SYSTEM,
1664 "event", ast_json_ref(event_object));
1665 if (!json_object) {
1666 return;
1667 }
1668
1669 payload = ast_json_payload_create(json_object);
1670 if (!payload) {
1671 return;
1672 }
1673
1675 if (!message) {
1676 return;
1677 }
1678
1680}
1681
1683{
1684 int i;
1685 for (i = 0; i < ARRAY_LEN(load_results); i++) {
1686 if (load_results[i].result == result) {
1687 return load_results[i].name;
1688 }
1689 }
1690
1691 ast_log(LOG_WARNING, "Failed to find correct load result status. result %d\n", result);
1693}
1694
1695/*!
1696 * \internal
1697 * \brief Publish a \ref stasis message regarding the load result
1698 */
1700{
1701 const char *status;
1702
1704
1706}
1707
1708/*!
1709 * \internal
1710 * \brief Publish a \ref stasis message regarding the unload result
1711 */
1712static void publish_unload_message(const char *name, const char* status)
1713{
1715}
1716
1717/*!
1718 * \since 12
1719 * \internal
1720 * \brief Publish a \ref stasis message regarding the reload result
1721 */
1723{
1724 char res_buffer[8];
1725
1726 snprintf(res_buffer, sizeof(res_buffer), "%u", result);
1727 publish_load_message_type("Reload", S_OR(name, "All"), res_buffer);
1728}
1729
1731{
1732 struct ast_module *cur;
1734 size_t name_baselen = name ? resource_name_baselen(name) : 0;
1735
1736 /* If we aren't fully booted, we just pretend we reloaded but we queue this
1737 up to run once we are booted up. */
1738 if (!modules_loaded) {
1741 goto module_reload_exit;
1742 }
1743
1745 ast_verb(3, "The previous reload command didn't finish yet\n");
1747 goto module_reload_exit;
1748 }
1749 ast_sd_notify("RELOADING=1");
1751
1753 int try;
1754 int lockres;
1755 for (try = 1, lockres = AST_LOCK_TIMEOUT; try < 6 && (lockres == AST_LOCK_TIMEOUT); try++) {
1757 if (lockres == AST_LOCK_TIMEOUT) {
1758 ast_log(LOG_WARNING, "Failed to grab lock on %s, try %d\n", ast_config_AST_CONFIG_DIR, try);
1759 }
1760 }
1761 if (lockres != AST_LOCK_SUCCESS) {
1762 ast_log(AST_LOG_WARNING, "Cannot grab lock on %s\n", ast_config_AST_CONFIG_DIR);
1764 goto module_reload_done;
1765 }
1766 }
1767
1770 const struct ast_module_info *info = cur->info;
1771
1772 if (name && resource_name_match(name, name_baselen, cur->resource)) {
1773 continue;
1774 }
1775
1776 if (!cur->flags.running || cur->flags.declined) {
1777 if (res == AST_MODULE_RELOAD_NOT_FOUND) {
1779 }
1780 if (!name) {
1781 continue;
1782 }
1783 break;
1784 }
1785
1786 if (!info->reload) { /* cannot be reloaded */
1787 if (res == AST_MODULE_RELOAD_NOT_FOUND) {
1789 }
1790 if (!name) {
1791 continue;
1792 }
1793 break;
1794 }
1795 ast_verb(3, "Reloading module '%s' (%s)\n", cur->resource, info->description);
1796 if (info->reload() == AST_MODULE_LOAD_SUCCESS) {
1798 } else if (res == AST_MODULE_RELOAD_NOT_FOUND) {
1800 }
1801 if (name) {
1802 break;
1803 }
1804 }
1806
1809 }
1810module_reload_done:
1812 ast_sd_notify("READY=1");
1813
1814module_reload_exit:
1816 return res;
1817}
1818
1819static unsigned int inspect_module(const struct ast_module *mod)
1820{
1821 if (!mod->info->description) {
1822 module_load_error("Module '%s' does not provide a description.\n", mod->resource);
1823 return 1;
1824 }
1825
1826 if (!mod->info->key) {
1827 module_load_error("Module '%s' does not provide a license key.\n", mod->resource);
1828 return 1;
1829 }
1830
1831 if (verify_key((unsigned char *) mod->info->key)) {
1832 module_load_error("Module '%s' did not provide a valid license key.\n", mod->resource);
1833 return 1;
1834 }
1835
1836 if (!ast_strlen_zero(mod->info->buildopt_sum) &&
1837 strcmp(buildopt_sum, mod->info->buildopt_sum)) {
1838 module_load_error("Module '%s' was not compiled with the same compile-time options as this version of Asterisk.\n", mod->resource);
1839 module_load_error("Module '%s' will not be initialized as it may cause instability.\n", mod->resource);
1840 return 1;
1841 }
1842
1843 return 0;
1844}
1845
1847{
1848 char tmp[256];
1849 enum ast_module_load_result res;
1850
1851 if (mod->flags.running) {
1853 }
1854
1855 if (!mod->info->load) {
1856 mod->flags.declined = 1;
1857
1859 }
1860
1861 if (module_deps_reference(mod, NULL)) {
1862 struct module_vector missing;
1863 int i;
1864
1865 AST_VECTOR_INIT(&missing, 0);
1866 if (module_deps_missing_recursive(mod, &missing)) {
1867 module_load_error("%s has one or more unknown dependencies.\n", mod->info->name);
1868 }
1869 for (i = 0; i < AST_VECTOR_SIZE(&missing); i++) {
1870 module_load_error("%s loaded before dependency %s!\n", mod->info->name,
1871 AST_VECTOR_GET(&missing, i)->info->name);
1872 }
1873 AST_VECTOR_FREE(&missing);
1874
1876 }
1877
1878 if (!ast_fully_booted) {
1879 ast_verb(4, "Loading %s.\n", mod->resource);
1880 }
1881 res = mod->info->load();
1882
1883 switch (res) {
1885 if (!ast_fully_booted) {
1886 ast_verb(5, "%s => (%s)\n", mod->resource, term_color(tmp, mod->info->description, COLOR_BROWN, COLOR_BLACK, sizeof(tmp)));
1887 } else {
1888 ast_verb(4, "Loaded %s => (%s)\n", mod->resource, mod->info->description);
1889 }
1890
1891 mod->flags.running = 1;
1892 if (mod->flags.builtin) {
1893 /* Built-in modules cannot be unloaded. */
1895 }
1896
1898 break;
1900 mod->flags.declined = 1;
1901 if (mod->flags.required) {
1903 }
1904 break;
1906 mod->flags.declined = 1;
1907 break;
1908 case AST_MODULE_LOAD_SKIP: /* modules should never return this value */
1910 break;
1911 }
1912
1913 /* Make sure the newly started module is at the end of the list */
1915 AST_DLLIST_REMOVE(&module_list, mod, entry);
1916 AST_DLLIST_INSERT_TAIL(&module_list, mod, entry);
1918
1919 return res;
1920}
1921
1922/*! loads a resource based upon resource_name. If global_symbols_only is set
1923 * only modules with global symbols will be loaded.
1924 *
1925 * If the module_vector is provided (not NULL) the module is found and added to the
1926 * vector without running the module's load() function. By doing this, modules
1927 * can be initialized later in order by priority and dependencies.
1928 *
1929 * If the module_vector is not provided, the module's load function will be executed
1930 * immediately */
1931static enum ast_module_load_result load_resource(const char *resource_name, unsigned int suppress_logging,
1932 struct module_vector *module_priorities, int required, int preload)
1933{
1934 struct ast_module *mod;
1936
1937 if ((mod = find_resource(resource_name, 0))) {
1938 if (mod->flags.running) {
1939 ast_log(LOG_WARNING, "Module '%s' already loaded and running.\n", resource_name);
1941 }
1942 } else {
1943 mod = load_dynamic_module(resource_name, suppress_logging);
1944 if (!mod) {
1946 }
1947
1948 if (module_post_register(mod)) {
1949 goto prestart_error;
1950 }
1951 }
1952
1953 mod->flags.required |= required;
1954 mod->flags.preload |= preload;
1955
1956 if (inspect_module(mod)) {
1957 goto prestart_error;
1958 }
1959
1960 mod->flags.declined = 0;
1961
1962 if (module_priorities) {
1963 if (AST_VECTOR_ADD_SORTED(module_priorities, mod, module_vector_cmp)) {
1964 goto prestart_error;
1965 }
1967 } else {
1968 res = start_resource(mod);
1969 }
1970
1972 publish_load_message(resource_name, res);
1973 }
1974
1975 return res;
1976
1977prestart_error:
1978 module_load_error("Module '%s' could not be loaded.\n", resource_name);
1982 publish_load_message(resource_name, res);
1983 }
1984 return res;
1985}
1986
1987enum ast_module_load_result ast_load_resource(const char *resource_name)
1988{
1989 struct ast_module *mod;
1990 enum ast_module_load_result res;
1991
1992 /* If we're trying to load a module that previously declined to load,
1993 * transparently unload it first so we dlclose, then dlopen it afresh.
1994 * Otherwise, we won't actually load a (potentially) updated module. */
1995 mod = find_resource(resource_name, 0);
1996 if (mod && mod->flags.declined) {
1997 ast_debug(1, "Module %s previously declined to load, unloading it first before loading again\n", resource_name);
1998 ast_unload_resource(resource_name, 0);
1999 }
2000
2002 res = load_resource(resource_name, 0, NULL, 0, 0);
2003 if (!res) {
2004 ast_test_suite_event_notify("MODULE_LOAD", "Message: %s", resource_name);
2005 }
2007
2008 return res;
2009}
2010
2017};
2018
2020
2021static struct load_order_entry *add_to_load_order(const char *resource, struct load_order *load_order, int required, int preload, int builtin)
2022{
2023 struct load_order_entry *order;
2024 size_t resource_baselen = resource_name_baselen(resource);
2025
2027 if (!resource_name_match(resource, resource_baselen, order->resource)) {
2028 /* Make sure we have the proper setting for the required field
2029 (we might have both load= and required= lines in modules.conf) */
2030 order->required |= required;
2031 order->preload |= preload;
2032 return order;
2033 }
2034 }
2035
2036 order = ast_calloc(1, sizeof(*order));
2037 if (!order) {
2038 return NULL;
2039 }
2040
2041 order->resource = ast_strdup(resource);
2042 if (!order->resource) {
2043 ast_free(order);
2044
2045 return NULL;
2046 }
2047 order->required = required;
2048 order->preload = preload;
2049 order->builtin = builtin;
2051
2052 return order;
2053}
2054
2056
2058{
2059 enum ast_module_load_result lres;
2060
2061 /* Try to grab required references. */
2062 if (module_deps_reference(mod, NULL)) {
2063 /* We're likely to retry so not an error. */
2064 ast_debug(1, "Module %s is missing dependencies\n", mod->resource);
2065 return AST_MODULE_LOAD_SKIP;
2066 }
2067
2068 lres = start_resource(mod);
2069 ast_debug(3, "START: %-46s[%d] %d\n",
2070 mod->resource,
2072 lres);
2073
2074 if (lres == AST_MODULE_LOAD_SUCCESS) {
2075 (*count)++;
2076 } else if (lres == AST_MODULE_LOAD_FAILURE) {
2077 module_load_error("*** Failed to load %smodule %s\n",
2078 mod->flags.required ? "required " : "",
2079 mod->resource);
2080 }
2081
2082 return lres;
2083}
2084
2086 struct ast_str **printmissing)
2087{
2088 struct module_vector missingdeps;
2089 struct ast_vector_const_string localdeps;
2090 int i = 0;
2091 int res = -1;
2092
2093 mod->flags.declined = 1;
2094 if (mod->flags.required) {
2095 module_load_error("Required module %s declined to load.\n", ast_module_name(mod));
2096
2097 return -2;
2098 }
2099
2100 module_load_error("%s declined to load.\n", ast_module_name(mod));
2101
2102 if (!*printmissing) {
2103 *printmissing = ast_str_create(64);
2104 if (!*printmissing) {
2105 return -1;
2106 }
2107 } else {
2108 ast_str_reset(*printmissing);
2109 }
2110
2111 AST_VECTOR_INIT(&missingdeps, 0);
2112 AST_VECTOR_INIT(&localdeps, 0);
2113
2114 /* Decline everything that depends on 'mod' from resources so we can
2115 * print a concise list. */
2116 while (res != -2 && i < AST_VECTOR_SIZE(resources)) {
2117 struct ast_module *dep = AST_VECTOR_GET(resources, i);
2118 i++;
2119
2121 if (dep->flags.declined || module_deps_missing_recursive(dep, &missingdeps)) {
2122 continue;
2123 }
2124
2125 if (AST_VECTOR_GET_CMP(&missingdeps, mod, AST_VECTOR_ELEM_DEFAULT_CMP)) {
2126 dep->flags.declined = 1;
2127 if (dep->flags.required) {
2128 module_load_error("Cannot load required module %s that depends on %s\n",
2129 ast_module_name(dep), ast_module_name(mod));
2130 res = -2;
2131 } else {
2132 AST_VECTOR_APPEND(&localdeps, ast_module_name(dep));
2133 }
2134 }
2135 }
2136 AST_VECTOR_FREE(&missingdeps);
2137
2138 if (res != -2 && AST_VECTOR_SIZE(&localdeps)) {
2139 AST_VECTOR_CALLBACK_VOID(&localdeps, STR_APPEND_TEXT, printmissing);
2140 module_load_error("Declined modules which depend on %s: %s\n",
2141 ast_module_name(mod), ast_str_buffer(*printmissing));
2142 }
2143 AST_VECTOR_FREE(&localdeps);
2144
2145 return res;
2146}
2147
2148static int start_resource_list(struct module_vector *resources, int *mod_count)
2149{
2150 struct module_vector missingdeps;
2151 int res = 0;
2152 struct ast_str *printmissing = NULL;
2153
2154 AST_VECTOR_INIT(&missingdeps, 0);
2155 while (res != -2 && AST_VECTOR_SIZE(resources)) {
2156 struct ast_module *mod = AST_VECTOR_REMOVE(resources, 0, 1);
2157 enum ast_module_load_result lres;
2158
2159 if (mod->flags.declined) {
2160 ast_debug(1, "%s is already declined, skipping\n", ast_module_name(mod));
2161 continue;
2162 }
2163
2164retry_load:
2165 lres = start_resource_attempt(mod, mod_count);
2166 if (lres == AST_MODULE_LOAD_SUCCESS) {
2167 /* No missing dependencies, successful. */
2168 continue;
2169 }
2170
2171 if (lres == AST_MODULE_LOAD_FAILURE) {
2172 res = -2;
2173 break;
2174 }
2175
2176 if (lres == AST_MODULE_LOAD_DECLINE) {
2177 res = resource_list_recursive_decline(resources, mod, &printmissing);
2178 continue;
2179 }
2180
2181 if (module_deps_missing_recursive(mod, &missingdeps)) {
2183 module_load_error("Failed to resolve dependencies for %s\n", ast_module_name(mod));
2184 res = resource_list_recursive_decline(resources, mod, &printmissing);
2185 continue;
2186 }
2187
2188 if (!AST_VECTOR_SIZE(&missingdeps)) {
2189 module_load_error("%s load function returned an invalid result. "
2190 "This is a bug in the module.\n", ast_module_name(mod));
2191 /* Dependencies were met but the module failed to start and the result
2192 * code was not AST_MODULE_LOAD_FAILURE or AST_MODULE_LOAD_DECLINE. */
2193 res = resource_list_recursive_decline(resources, mod, &printmissing);
2194 continue;
2195 }
2196
2197 ast_debug(1, "%s has %d dependencies\n",
2198 ast_module_name(mod), (int)AST_VECTOR_SIZE(&missingdeps));
2199 while (AST_VECTOR_SIZE(&missingdeps)) {
2200 int didwork = 0;
2201 int i = 0;
2202
2203 while (i < AST_VECTOR_SIZE(&missingdeps)) {
2204 struct ast_module *dep = AST_VECTOR_GET(&missingdeps, i);
2205
2206 if (dep->flags.declined) {
2207 ast_debug(1, "%s tried to start %s but it's already declined\n",
2208 ast_module_name(mod), ast_module_name(dep));
2209 i++;
2210 continue;
2211 }
2212
2213 ast_debug(1, "%s trying to start %s\n", ast_module_name(mod), ast_module_name(dep));
2214 lres = start_resource_attempt(dep, mod_count);
2215 if (lres == AST_MODULE_LOAD_SUCCESS) {
2216 ast_debug(1, "%s started %s\n", ast_module_name(mod), ast_module_name(dep));
2217 AST_VECTOR_REMOVE(&missingdeps, i, 1);
2220 didwork++;
2221 continue;
2222 }
2223
2224 if (lres == AST_MODULE_LOAD_FAILURE) {
2225 module_load_error("Failed to load %s.\n", ast_module_name(dep));
2226 res = -2;
2227 goto exitpoint;
2228 }
2229
2230 ast_debug(1, "%s failed to start %s\n", ast_module_name(mod), ast_module_name(dep));
2231 i++;
2232 }
2233
2234 if (!didwork) {
2235 break;
2236 }
2237 }
2238
2239 if (AST_VECTOR_SIZE(&missingdeps)) {
2240 if (!printmissing) {
2241 printmissing = ast_str_create(64);
2242 } else {
2243 ast_str_reset(printmissing);
2244 }
2245
2246 if (printmissing) {
2247 struct ast_vector_const_string localdeps;
2248
2249 AST_VECTOR_INIT(&localdeps, 0);
2250 module_deps_reference(mod, &localdeps);
2251 AST_VECTOR_CALLBACK_VOID(&localdeps, STR_APPEND_TEXT, &printmissing);
2252 AST_VECTOR_FREE(&localdeps);
2253 }
2254
2255 module_load_error("Failed to load %s due to dependencies: %s.\n",
2256 ast_module_name(mod),
2257 printmissing ? ast_str_buffer(printmissing) : "allocation failure creating list");
2258 res = resource_list_recursive_decline(resources, mod, &printmissing);
2259
2261
2262 continue;
2263 }
2264
2265 /* If we're here it means that we started with missingdeps and they're all loaded
2266 * now. It's impossible to reach this point a second time for the same module. */
2267 goto retry_load;
2268 }
2269
2270exitpoint:
2271 ast_free(printmissing);
2272 AST_VECTOR_FREE(&missingdeps);
2273
2274 return res;
2275}
2276
2277/*! loads modules in order by load_pri, updates mod_count
2278 \return -1 on failure to load module, -2 on failure to load required module, otherwise 0
2279*/
2280static int load_resource_list(struct load_order *load_order, int *mod_count)
2281{
2282 struct module_vector module_priorities;
2283 struct load_order_entry *order;
2284 int attempt = 0;
2285 int count = 0;
2286 int res = 0;
2287 int didwork;
2288 int lasttry = 0;
2289
2290 if (AST_VECTOR_INIT(&module_priorities, 500)) {
2291 ast_log(LOG_ERROR, "Failed to initialize module loader.\n");
2292
2293 return -1;
2294 }
2295
2296 while (res != -2) {
2297 didwork = 0;
2298
2300 enum ast_module_load_result lres;
2301
2302 /* Suppress log messages unless this is the last pass */
2303 lres = load_resource(order->resource, !lasttry, &module_priorities, order->required, order->preload);
2304 ast_debug(3, "PASS %d: %-46s %d\n", attempt, order->resource, lres);
2305 switch (lres) {
2308 /* We're supplying module_priorities so SUCCESS isn't possible but we
2309 * still have to test for it. SKIP is only used when we try to start a
2310 * module that is missing dependencies. */
2311 break;
2313 res = -1;
2314 break;
2316 /* LOAD_FAILURE only happens for required modules */
2317 if (lasttry) {
2318 /* This run is just to print errors. */
2319 module_load_error("*** Failed to load module %s - Required\n", order->resource);
2320 fprintf(stderr, "*** Failed to load module %s - Required\n", order->resource);
2321 res = -2;
2322 }
2323 break;
2325 /* load_resource worked and the module was added to module_priorities */
2327 ast_free(order->resource);
2328 ast_free(order);
2329 didwork = 1;
2330 break;
2331 }
2332 }
2334
2335 if (!didwork) {
2336 if (lasttry) {
2337 break;
2338 }
2339 /* We know the next try is going to fail, it's only being performed
2340 * so we can print errors. */
2341 lasttry = 1;
2342 }
2343 attempt++;
2344 }
2345
2346 if (res != -2) {
2347 res = start_resource_list(&module_priorities, &count);
2348 }
2349
2350 if (mod_count) {
2351 *mod_count += count;
2352 }
2353 AST_VECTOR_FREE(&module_priorities);
2354
2355 return res;
2356}
2357
2359{
2360 struct ast_module *mod;
2361
2362 /*
2363 * All built-in modules have registered the first time, now it's time to complete
2364 * the registration and add them to the priority list.
2365 */
2366 loader_ready = 1;
2367
2369 /* ast_module_register doesn't finish when first run by built-in modules. */
2371 }
2372
2373 /* Add all built-in modules to the load order. */
2375 if (!mod->flags.builtin) {
2376 continue;
2377 }
2378
2379 /* Parse dependencies from mod->info. */
2380 if (module_post_register(mod)) {
2381 return -1;
2382 }
2383
2384 /* Built-in modules are not preloaded, most have an early load priority. */
2385 if (!add_to_load_order(mod->resource, load_order, 0, 0, 1)) {
2386 return -1;
2387 }
2388 }
2389
2390 return 0;
2391}
2392
2394{
2395 int res = -1;
2396 struct load_order_entry *order;
2397 struct ast_config *cfg;
2398 struct ast_variable *v;
2399 struct ast_flags config_flags = { 0 };
2400
2401 cfg = ast_config_load2(AST_MODULE_CONFIG, "" /* core, can't reload */, config_flags);
2403 ast_log(LOG_WARNING, "'%s' invalid or missing.\n", AST_MODULE_CONFIG);
2404
2405 return -1;
2406 }
2407
2408 /* first, find all the modules we have been explicitly requested to load */
2409 for (v = ast_variable_browse(cfg, "modules"); v; v = v->next) {
2410 int required;
2411 int preload = 0;
2412
2413 if (!strncasecmp(v->name, "preload", strlen("preload"))) {
2414 preload = 1;
2415 if (!strcasecmp(v->name, "preload")) {
2416 required = 0;
2417 } else if (!strcasecmp(v->name, "preload-require")) {
2418 required = 1;
2419 } else {
2420 ast_log(LOG_ERROR, "Unknown configuration option '%s'", v->name);
2421 goto done;
2422 }
2423 } else if (!strcasecmp(v->name, "load")) {
2424 required = 0;
2425 } else if (!strcasecmp(v->name, "require")) {
2426 required = 1;
2427 } else if (!strcasecmp(v->name, "noload") || !strcasecmp(v->name, "autoload")) {
2428 continue;
2429 } else {
2430 ast_log(LOG_ERROR, "Unknown configuration option '%s'", v->name);
2431 goto done;
2432 }
2433
2434 if (required) {
2435 ast_debug(2, "Adding module to required list: %s (%s)\n", v->value, v->name);
2436 }
2437
2438 if (!add_to_load_order(v->value, load_order, required, preload, 0)) {
2439 goto done;
2440 }
2441 }
2442
2443 /* check if 'autoload' is on */
2444 if (ast_true(ast_variable_retrieve(cfg, "modules", "autoload"))) {
2445 /* if we are allowed to load dynamic modules, scan the directory for
2446 for all available modules and add them as well */
2447 DIR *dir = opendir(ast_config_AST_MODULE_DIR);
2448 struct dirent *dirent;
2449
2450 if (dir) {
2451 while ((dirent = readdir(dir))) {
2452 int ld = strlen(dirent->d_name);
2453
2454 /* Must end in .so to load it. */
2455
2456 if (ld < 4)
2457 continue;
2458
2459 if (strcasecmp(dirent->d_name + ld - 3, ".so"))
2460 continue;
2461
2462 /* if there is already a module by this name in the module_list,
2463 skip this file */
2464 if (find_resource(dirent->d_name, 0))
2465 continue;
2466
2467 if (!add_to_load_order(dirent->d_name, load_order, 0, 0, 0)) {
2468 closedir(dir);
2469 goto done;
2470 }
2471 }
2472
2473 closedir(dir);
2474 } else {
2475 ast_log(LOG_ERROR, "Unable to open modules directory '%s'.\n", ast_config_AST_MODULE_DIR);
2476 goto done;
2477 }
2478 }
2479
2480 /* now scan the config for any modules we are prohibited from loading and
2481 remove them from the load order */
2482 for (v = ast_variable_browse(cfg, "modules"); v; v = v->next) {
2483 size_t baselen;
2484
2485 if (strcasecmp(v->name, "noload")) {
2486 continue;
2487 }
2488
2489 baselen = resource_name_baselen(v->value);
2491 if (!resource_name_match(v->value, baselen, order->resource)) {
2492 if (order->builtin) {
2493 ast_log(LOG_ERROR, "%s is a built-in module, you cannot specify 'noload'.\n", v->value);
2494 goto done;
2495 }
2496
2497 if (order->required) {
2498 ast_log(LOG_ERROR, "%s is configured with '%s' and 'noload', this is impossible.\n",
2499 v->value, order->preload ? "preload-require" : "require");
2500 goto done;
2501 }
2503 ast_free(order->resource);
2504 ast_free(order);
2505 }
2506 }
2508 }
2509
2510 res = 0;
2511done:
2512 ast_config_destroy(cfg);
2513
2514 return res;
2515}
2516
2518{
2519 struct load_order_entry *order;
2520 unsigned int load_count;
2521 struct load_order load_order;
2522 int res = 0;
2523 int modulecount = 0;
2524 int i;
2525 struct ast_module *cur;
2526#ifdef AST_XML_DOCS
2527 struct ast_str *warning_msg;
2528 char deprecated_in[33];
2529 char removed_in[33];
2530 char replacement[129];
2531#endif
2532 struct timeval start_time = ast_tvnow();
2533 struct timeval end_time;
2534 int64_t usElapsed;
2535
2536 ast_verb(1, "Asterisk Dynamic Loader Starting:\n");
2537
2538#if defined(HAVE_PERMANENT_DLOPEN)
2540 info_list_obj_cmp_fn); /* must not be cleaned at shutdown */
2541 if (!info_list) {
2542 fprintf(stderr, "Module info list allocation failure.\n");
2543 return 1;
2544 }
2545#endif
2546
2549
2552
2554 if (res) {
2555 goto done;
2556 }
2557
2559 if (res) {
2560 goto done;
2561 }
2562
2563 load_count = 0;
2565 load_count++;
2566
2567 if (load_count)
2568 ast_log(LOG_NOTICE, "%u modules will be loaded.\n", load_count);
2569
2570 res = load_resource_list(&load_order, &modulecount);
2571 if (res == -1) {
2572 ast_log(LOG_WARNING, "Some non-required modules failed to load.\n");
2573 res = 0;
2574 }
2575
2576done:
2577 while ((order = AST_LIST_REMOVE_HEAD(&load_order, entry))) {
2578 ast_free(order->resource);
2579 ast_free(order);
2580 }
2581
2582#ifdef AST_XML_DOCS
2583 warning_msg = ast_str_create(512);
2584#endif
2585
2586 AST_DLLIST_TRAVERSE(&module_list, cur, entry) {
2587#ifdef AST_XML_DOCS
2588 char *mod_name = NULL;
2589 struct ast_xml_xpath_results *results;
2590#endif
2591
2592 if (!cur->flags.running || cur->flags.declined) {
2593 continue;
2594 }
2595
2596#ifdef AST_XML_DOCS
2597 mod_name = get_name_from_resource(cur->resource);
2598 if (!warning_msg || !mod_name) {
2599 /* If we can't allocate memory, we have bigger issues */
2600 ast_free(mod_name);
2601 continue;
2602 }
2603
2604 /* Clear out the previous values */
2605 deprecated_in[0] = removed_in[0] = replacement[0] = 0;
2606
2607 results = ast_xmldoc_query("/docs/module[@name='%s']", mod_name);
2608 if (results) {
2609 struct ast_xml_node *deprecated_node, *removed_node, *replacement_node;
2610 struct ast_xml_node *metadata_nodes = ast_xml_node_get_children(ast_xml_xpath_get_first_result(results));
2611
2612 deprecated_node = ast_xml_find_element(metadata_nodes, "deprecated_in", NULL, NULL);
2613 if (deprecated_node) {
2614 const char *result_tmp = ast_xml_get_text(deprecated_node);
2615 if (!ast_strlen_zero(result_tmp)) {
2616 ast_copy_string(deprecated_in, result_tmp, sizeof(deprecated_in));
2617 }
2618 }
2619
2620 removed_node = ast_xml_find_element(metadata_nodes, "removed_in", NULL, NULL);
2621 if (removed_node) {
2622 const char *result_tmp = ast_xml_get_text(removed_node);
2623 if (!ast_strlen_zero(result_tmp)) {
2624 ast_copy_string(removed_in, result_tmp, sizeof(removed_in));
2625 }
2626 }
2627
2628 replacement_node = ast_xml_find_element(metadata_nodes, "replacement", NULL, NULL);
2629 if (replacement_node) {
2630 const char *result_tmp = ast_xml_get_text(replacement_node);
2631 if (!ast_strlen_zero(result_tmp)) {
2632 ast_copy_string(replacement, result_tmp, sizeof(replacement));
2633 }
2634 }
2635
2637 }
2638
2639 ast_str_reset(warning_msg);
2640
2641 if (cur->info->support_level == AST_MODULE_SUPPORT_DEPRECATED || !ast_strlen_zero(deprecated_in)
2642 || !ast_strlen_zero(removed_in) || !ast_strlen_zero(replacement)) {
2643 int already_butted = 0;
2644
2645 ast_str_append(&warning_msg, -1, "Module '%s' has been loaded", mod_name);
2646 if (!ast_strlen_zero(deprecated_in)) {
2647 ast_str_append(&warning_msg, -1, " but %s deprecated in Asterisk version %s",
2648 cur->info->support_level == AST_MODULE_SUPPORT_DEPRECATED ? "was" : "will be", deprecated_in);
2649 already_butted = 1;
2650 }
2651
2652 if (!ast_strlen_zero(removed_in)) {
2653 ast_str_append(&warning_msg, -1, " %s will be removed in Asterisk version %s", already_butted ? "and" : "but", removed_in);
2654 } else {
2655 ast_str_append(&warning_msg, -1, " %s may be removed in a future release", already_butted ? "and" : "but");
2656 }
2657
2658 ast_str_append(&warning_msg, -1, ".");
2659
2660 if (!ast_strlen_zero(replacement)) {
2661 ast_str_append(&warning_msg, -1, " Its replacement is '%s'.", replacement);
2662 }
2663 }
2664
2665 if (ast_str_strlen(warning_msg)) {
2666 ast_log(LOG_WARNING, "%s\n", ast_str_buffer(warning_msg));
2667 }
2668
2669 ast_free(mod_name);
2670#else
2672 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);
2673 }
2674#endif
2675 }
2676
2677#ifdef AST_XML_DOCS
2678 ast_free(warning_msg);
2679#endif
2680
2682
2683
2684 for (i = 0; i < AST_VECTOR_SIZE(&startup_errors); i++) {
2685 char *str = AST_VECTOR_GET(&startup_errors, i);
2686
2687 ast_log(LOG_ERROR, "%s", str);
2688 ast_free(str);
2689 }
2691
2694
2695 end_time = ast_tvnow();
2696 usElapsed = ast_tvdiff_us(end_time, start_time);
2697
2698#ifdef AST_XML_DOCS
2699 ast_debug(1, "Loader time with AST_XML_DOCS: %" PRId64 ".%06" PRId64 "\n", usElapsed / 1000000, usElapsed % 1000000);
2700#else
2701 ast_debug(1, "Loader time without AST_XML_DOCS: %" PRId64 ".%06" PRId64 "\n", usElapsed / 1000000, usElapsed % 1000000);
2702#endif
2703
2704 return res;
2705}
2706
2708{
2709 /* Notify any module monitors that the use count for a
2710 resource has changed */
2711 struct loadupdate *m;
2712
2715 m->updater();
2717}
2718
2719/*!
2720 * \internal
2721 * \brief Build an alpha sorted list of modules.
2722 *
2723 * \param alpha_module_list Pointer to uninitialized module_vector.
2724 *
2725 * This function always initializes alpha_module_list.
2726 *
2727 * \pre module_list must be locked.
2728 */
2729static int alpha_module_list_create(struct module_vector *alpha_module_list)
2730{
2731 struct ast_module *cur;
2732
2733 if (AST_VECTOR_INIT(alpha_module_list, 32)) {
2734 return -1;
2735 }
2736
2738 if (AST_VECTOR_ADD_SORTED(alpha_module_list, cur, module_vector_strcasecmp)) {
2739 return -1;
2740 }
2741 }
2742
2743 return 0;
2744}
2745
2746int ast_update_module_list(int (*modentry)(const char *module, const char *description,
2747 int usecnt, const char *status, const char *like,
2748 enum ast_module_support_level support_level),
2749 const char *like)
2750{
2751 int total_mod_loaded = 0;
2752 struct module_vector alpha_module_list;
2753
2755
2756 if (!alpha_module_list_create(&alpha_module_list)) {
2757 int idx;
2758
2759 for (idx = 0; idx < AST_VECTOR_SIZE(&alpha_module_list); idx++) {
2760 struct ast_module *cur = AST_VECTOR_GET(&alpha_module_list, idx);
2761
2762 total_mod_loaded += modentry(cur->resource, cur->info->description, cur->usecount,
2763 cur->flags.running ? "Running" : "Not Running", like, cur->info->support_level);
2764 }
2765 }
2766
2768 AST_VECTOR_FREE(&alpha_module_list);
2769
2770 return total_mod_loaded;
2771}
2772
2773int ast_update_module_list_data(int (*modentry)(const char *module, const char *description,
2774 int usecnt, const char *status, const char *like,
2775 enum ast_module_support_level support_level,
2776 void *data),
2777 const char *like, void *data)
2778{
2779 int total_mod_loaded = 0;
2780 struct module_vector alpha_module_list;
2781
2783
2784 if (!alpha_module_list_create(&alpha_module_list)) {
2785 int idx;
2786
2787 for (idx = 0; idx < AST_VECTOR_SIZE(&alpha_module_list); idx++) {
2788 struct ast_module *cur = AST_VECTOR_GET(&alpha_module_list, idx);
2789
2790 total_mod_loaded += modentry(cur->resource, cur->info->description, cur->usecount,
2791 cur->flags.running? "Running" : "Not Running", like, cur->info->support_level, data);
2792 }
2793 }
2794
2796 AST_VECTOR_FREE(&alpha_module_list);
2797
2798 return total_mod_loaded;
2799}
2800
2801int ast_update_module_list_condition(int (*modentry)(const char *module, const char *description,
2802 int usecnt, const char *status,
2803 const char *like,
2804 enum ast_module_support_level support_level,
2805 void *data, const char *condition),
2806 const char *like, void *data, const char *condition)
2807{
2808 int conditions_met = 0;
2809 struct module_vector alpha_module_list;
2810
2812
2813 if (!alpha_module_list_create(&alpha_module_list)) {
2814 int idx;
2815
2816 for (idx = 0; idx < AST_VECTOR_SIZE(&alpha_module_list); idx++) {
2817 struct ast_module *cur = AST_VECTOR_GET(&alpha_module_list, idx);
2818
2819 conditions_met += modentry(cur->resource, cur->info->description, cur->usecount,
2820 cur->flags.running? "Running" : "Not Running", like, cur->info->support_level, data,
2821 condition);
2822 }
2823 }
2824
2826 AST_VECTOR_FREE(&alpha_module_list);
2827
2828 return conditions_met;
2829}
2830
2831/*! \brief Check if module exists */
2832int ast_module_check(const char *name)
2833{
2834 struct ast_module *cur;
2835
2836 if (ast_strlen_zero(name))
2837 return 0; /* FALSE */
2838
2839 cur = find_resource(name, 1);
2840
2841 return (cur != NULL);
2842}
2843
2844
2845int ast_loader_register(int (*v)(void))
2846{
2847 struct loadupdate *tmp;
2848
2849 if (!(tmp = ast_malloc(sizeof(*tmp))))
2850 return -1;
2851
2852 tmp->updater = v;
2856
2857 return 0;
2858}
2859
2860int ast_loader_unregister(int (*v)(void))
2861{
2862 struct loadupdate *cur;
2863
2866 if (cur->updater == v) {
2868 break;
2869 }
2870 }
2873
2874 return cur ? 0 : -1;
2875}
2876
2877struct ast_module *__ast_module_ref(struct ast_module *mod, const char *file, int line, const char *func)
2878{
2879 if (!mod) {
2880 return NULL;
2881 }
2882
2883 if (mod->ref_debug) {
2884 __ao2_ref(mod->ref_debug, +1, "", file, line, func);
2885 }
2886
2889
2890 return mod;
2891}
2892
2894 const char *file, int line, const char *func)
2895{
2896 if (!mod || !mod->flags.running) {
2897 return NULL;
2898 }
2899
2900 return __ast_module_ref(mod, file, line, func);
2901}
2902
2903void __ast_module_shutdown_ref(struct ast_module *mod, const char *file, int line, const char *func)
2904{
2905 if (!mod || mod->flags.keepuntilshutdown) {
2906 return;
2907 }
2908
2909 __ast_module_ref(mod, file, line, func);
2910 mod->flags.keepuntilshutdown = 1;
2911}
2912
2913void __ast_module_unref(struct ast_module *mod, const char *file, int line, const char *func)
2914{
2915 if (!mod) {
2916 return;
2917 }
2918
2919 if (mod->ref_debug) {
2920 __ao2_ref(mod->ref_debug, -1, "", file, line, func);
2921 }
2922
2925}
2926
2927const char *support_level_map [] = {
2928 [AST_MODULE_SUPPORT_UNKNOWN] = "unknown",
2929 [AST_MODULE_SUPPORT_CORE] = "core",
2930 [AST_MODULE_SUPPORT_EXTENDED] = "extended",
2931 [AST_MODULE_SUPPORT_DEPRECATED] = "deprecated",
2932};
2933
2935{
2936 return support_level_map[support_level];
2937}
Prototypes for public functions only of internal interest,.
integer order
Definition: analys.c:66
jack_status_t status
Definition: app_jack.c:149
const char * str
Definition: app_jack.c:150
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:1878
#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 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:2500
@ AST_SOFTHANGUP_APPUNLOAD
Definition: channel.h:1163
Standard Command Line Interface.
int ast_cli_completion_add(char *value)
Add a result to a request for completion options.
Definition: main/cli.c:2768
#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:1282
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:454
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:3541
#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:869
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:2437
#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:2913
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:2746
static void publish_unload_message(const char *name, const char *status)
Definition: loader.c:1712
void ast_process_pending_reloads(void)
Process reload requests received during startup.
Definition: loader.c:1575
int modules_shutdown(void)
Definition: loader.c:1181
struct ast_module * __ast_module_ref(struct ast_module *mod, const char *file, int line, const char *func)
Definition: loader.c:2877
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:2021
void __ast_module_user_remove(struct ast_module *mod, struct ast_module_user *u)
Definition: loader.c:835
void __ast_module_user_hangup_all(struct ast_module *mod)
Definition: loader.c:862
int ast_module_check(const char *name)
Check if module exists.
Definition: loader.c:2832
static int start_resource_list(struct module_vector *resources, int *mod_count)
Definition: loader.c:2148
int load_modules(void)
Definition: loader.c:2517
static int module_load_helper_on_file(const char *dir_name, const char *filename, void *obj)
Definition: loader.c:1492
#define RTLD_LOCAL
Definition: loader.c:133
void ast_update_use_count(void)
Notify when usecount has been changed.
Definition: loader.c:2707
const char * ast_module_support_level_to_string(enum ast_module_support_level support_level)
Definition: loader.c:2934
static void logged_dlclose(const char *name, void *lib)
dlclose(), with failure logging.
Definition: loader.c:961
void ast_module_register(const struct ast_module_info *info)
Definition: loader.c:668
void ast_module_unregister(const struct ast_module_info *info)
Definition: loader.c:777
static int modules_loaded
Internal flag to indicate all modules have been initially loaded.
Definition: loader.c:300
static int module_post_register(struct ast_module *mod)
Definition: loader.c:741
static ast_mutex_t reloadlock
Definition: loader.c:640
const char * support_level_map[]
Definition: loader.c:2927
static int load_resource_list(struct load_order *load_order, int *mod_count)
Definition: loader.c:2280
static struct ast_module * load_dynamic_module(const char *resource_in, unsigned int suppress_logging)
Definition: loader.c:1154
static void publish_load_message_type(const char *type, const char *name, const char *status)
Definition: loader.c:1643
static int module_deps_reference(struct ast_module *mod, struct ast_vector_const_string *missing)
Definition: loader.c:543
static struct ast_module * find_resource(const char *resource, int do_lock)
Definition: loader.c:936
static void unload_dynamic_module(struct ast_module *mod)
Definition: loader.c:1009
static int resource_name_match(const char *name1, size_t baselen1, const char *name2)
Definition: loader.c:927
static unsigned int loader_ready
Definition: loader.c:159
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:575
static char buildopt_sum[33]
Definition: loader.c:147
static struct ast_vector_string startup_errors
Definition: loader.c:162
static const unsigned char expected_key[]
Definition: loader.c:143
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:1537
static int do_full_reload
Definition: loader.c:647
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:1294
enum ast_module_load_result ast_load_resource(const char *resource_name)
Load a module.
Definition: loader.c:1987
static struct ast_str * startup_error_builder
Definition: loader.c:163
static int loader_config_init(struct load_order *load_order)
Definition: loader.c:2393
static const char * loadresult2str(enum ast_module_load_result result)
Definition: loader.c:1682
static void module_destroy(struct ast_module *mod)
Definition: loader.c:753
static int load_dlopen_missing(struct ast_str **list, struct ast_vector_string *deps)
Definition: loader.c:1039
#define RTLD_NOW
Definition: loader.c:129
static int module_reffed_deps_add(struct ast_module *mod, struct ast_module *dep, struct ast_vector_const_string *missing)
Definition: loader.c:425
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:1416
void __ast_module_shutdown_ref(struct ast_module *mod, const char *file, int line, const char *func)
Definition: loader.c:2903
static const struct load_results_map load_results[]
Definition: loader.c:353
int ast_loader_register(int(*v)(void))
Add a procedure to be run when modules have been updated.
Definition: loader.c:2845
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:1931
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:457
#define AST_MODULE_LOAD_UNKNOWN_STRING
Definition: loader.c:360
static int module_vector_cmp(struct ast_module *a, struct ast_module *b)
Definition: loader.c:380
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:494
static struct module_list builtin_module_list
Definition: loader.c:373
static int resource_list_recursive_decline(struct module_vector *resources, struct ast_module *mod, struct ast_str **printmissing)
Definition: loader.c:2085
static void queue_reload_request(const char *module)
Definition: loader.c:1600
struct ast_module_user * __ast_module_user_add(struct ast_module *mod, struct ast_channel *chan)
Definition: loader.c:809
static enum ast_module_load_result start_resource_attempt(struct ast_module *mod, int *count)
Definition: loader.c:2057
static void module_load_error(const char *fmt,...)
Definition: loader.c:278
static unsigned int inspect_module(const struct ast_module *mod)
Definition: loader.c:1819
static int printdigest(const unsigned char *d)
Definition: loader.c:884
int ast_loader_unregister(int(*v)(void))
Remove a procedure to be run when modules are updated.
Definition: loader.c:2860
#define STR_APPEND_TEXT(txt, str)
Definition: loader.c:153
static enum ast_module_load_result start_resource(struct ast_module *mod)
Definition: loader.c:1846
static void publish_reload_message(const char *name, enum ast_module_reload_result result)
Definition: loader.c:1722
int ast_unload_resource(const char *resource_name, enum ast_module_unload_mode force)
Unload a module.
Definition: loader.c:1457
static int loader_builtin_init(struct load_order *load_order)
Definition: loader.c:2358
static size_t resource_name_baselen(const char *name)
Definition: loader.c:916
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:2773
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:1234
#define key_matches(a, b)
Definition: loader.c:897
static char * get_name_from_resource(const char *resource)
Definition: loader.c:166
static int module_matches_helper_type(struct ast_module *mod, enum ast_module_helper_type type)
Definition: loader.c:1462
static int verify_key(const unsigned char *key)
Definition: loader.c:899
const char * ast_module_name(const struct ast_module *mod)
Get the name of a module.
Definition: loader.c:624
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:2801
struct ast_module * __ast_module_running_ref(struct ast_module *mod, const char *file, int line, const char *func)
Definition: loader.c:2893
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:1069
static int is_module_loaded(const char *resource_name)
Check to see if the given resource is loaded.
Definition: loader.c:990
static int alpha_module_list_create(struct module_vector *alpha_module_list)
Definition: loader.c:2729
static void publish_load_message(const char *name, enum ast_module_load_result result)
Definition: loader.c:1699
static void module_load_helper(const char *word)
Definition: loader.c:1524
enum ast_module_reload_result ast_module_reload(const char *name)
Reload asterisk modules.
Definition: loader.c:1730
static int module_vector_strcasecmp(struct ast_module *a, struct ast_module *b)
Definition: loader.c:375
static struct ast_module *volatile resource_being_loaded
Definition: loader.c:659
Asterisk locking-related definitions:
#define ast_mutex_unlock(a)
Definition: lock.h:194
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:761
#define ast_mutex_trylock(a)
Definition: lock.h:195
#define AST_MUTEX_DEFINE_STATIC(mutex)
Definition: lock.h:524
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[MD5_DIGEST_LENGTH], 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:343
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:1538
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:30
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::@364 entry
struct ast_channel * chan
Definition: loader.c:137
struct module_user_list users
Definition: loader.c:311
unsigned int running
Definition: loader.c:329
void * ref_debug
Definition: loader.c:305
struct ast_vector_string requires
Definition: loader.c:314
struct ast_module::@365 flags
struct ast_vector_string optional_modules
Definition: loader.c:316
unsigned int required
Definition: loader.c:337
void * lib
Definition: loader.c:307
struct module_vector reffed_deps
Vector holding pointers to modules we have a reference to.
Definition: loader.c:326
unsigned int builtin
Definition: loader.c:335
unsigned int keepuntilshutdown
Definition: loader.c:333
unsigned int declined
Definition: loader.c:331
const struct ast_module_info * info
Definition: loader.c:303
int usecount
Definition: loader.c:309
unsigned int preload
Definition: loader.c:339
char resource[0]
Definition: loader.c:342
struct ast_module::@366 entry
struct ast_vector_string enhances
Definition: loader.c:318
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: loader.c:2011
int builtin
Definition: loader.c:2015
int required
Definition: loader.c:2013
int preload
Definition: loader.c:2014
char * resource
Definition: loader.c:2012
struct load_order_entry::@369 entry
const char * name
Definition: loader.c:350
struct loadupdate::@367 entry
int(* updater)(void)
Definition: loader.c:634
size_t moddir_len
Definition: loader.c:1489
const char * word
Definition: loader.c:1487
struct reload_queue_item::@368 entry
char module[0]
Definition: loader.c:644
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:406
#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:2670