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