Asterisk - The Open Source Telephony Project  21.4.1
loader.c
Go to the documentation of this file.
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2006, Digium, Inc.
5  *
6  * Mark Spencer <markster@digium.com>
7  * Kevin P. Fleming <kpfleming@digium.com>
8  * Luigi Rizzo <rizzo@icir.org>
9  *
10  * See http://www.asterisk.org for more information about
11  * the Asterisk project. Please do not directly contact
12  * any of the maintainers of this project for assistance;
13  * the project provides a web site, mailing lists and IRC
14  * channels for your use.
15  *
16  * This program is free software, distributed under the terms of
17  * the GNU General Public License Version 2. See the LICENSE file
18  * at the top of the source tree.
19  */
20 
21 /*! \file
22  *
23  * \brief Module Loader
24  * \author Mark Spencer <markster@digium.com>
25  * \author Kevin P. Fleming <kpfleming@digium.com>
26  * \author Luigi Rizzo <rizzo@icir.org>
27  * - See ModMngMnt
28  */
29 
30 /*** MODULEINFO
31  <support_level>core</support_level>
32  ***/
33 
34 #include "asterisk.h"
35 
36 #include "asterisk/_private.h"
37 #include "asterisk/paths.h" /* use ast_config_AST_MODULE_DIR */
38 #include <dirent.h>
39 
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 
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. */
154 static struct ast_str *startup_error_builder;
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. */
306  /*! List of optional api modules. */
308  /*! List of modules this enhances. */
310 
311  /*!
312  * \brief Vector holding pointers to modules we have a reference to.
313  *
314  * When one module requires another, the required module gets added
315  * to this list with a reference.
316  */
318  struct {
319  /*! The module running and ready to accept requests. */
320  unsigned int running:1;
321  /*! The module has declined to start. */
322  unsigned int declined:1;
323  /*! This module is being held open until it's time to shutdown. */
324  unsigned int keepuntilshutdown:1;
325  /*! The module is built-in. */
326  unsigned int builtin:1;
327  /*! The admin has declared this module is required. */
328  unsigned int required:1;
329  /*! This module is marked for preload. */
330  unsigned int preload:1;
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  */
364 static struct module_list builtin_module_list;
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)
376  ? a->info->load_pri : AST_MODPRI_DEFAULT;
377  int b_pri = ast_test_flag(b->info, AST_MODFLAG_LOAD_ORDER)
378  ? b->info->load_pri : AST_MODPRI_DEFAULT;
379 
380  if (preload_diff) {
381  /* -1 preload a but not b */
382  /* 0 preload both or neither */
383  /* 1 preload b but not a */
384  return preload_diff;
385  }
386 
387  /*
388  * Returns comparison values for a vector sorted by priority.
389  * <0 a_pri < b_pri
390  * =0 a_pri == b_pri
391  * >0 a_pri > b_pri
392  */
393  return a_pri - b_pri;
394 }
395 
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  */
448 static int module_reffed_deps_add_dep_enhancers(struct ast_module *mod,
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  */
485 static int module_deps_process_reqlist(struct ast_module *mod,
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 
631 AST_MUTEX_DEFINE_STATIC(reloadlock);
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;
674  AST_DLLIST_INSERT_TAIL(&builtin_module_list, mod, entry);
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 {
746  AST_VECTOR_CALLBACK_VOID(&mod->requires, ast_free);
747  AST_VECTOR_FREE(&mod->requires);
748 
751 
752  AST_VECTOR_CALLBACK_VOID(&mod->enhances, ast_free);
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 
800 struct ast_module_user *__ast_module_user_add(struct ast_module *mod, struct ast_channel *chan)
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 
826 void __ast_module_user_remove(struct ast_module *mod, struct ast_module_user *u)
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 
853 void __ast_module_user_hangup_all(struct ast_module *mod)
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 #define key_matches(a, b) (memcmp((a), (b), 16) == 0)
889 
890 static int verify_key(const unsigned char *key)
891 {
892  struct MD5Context c;
893  unsigned char digest[16];
894 
895  MD5Init(&c);
896  MD5Update(&c, key, strlen((char *)key));
897  MD5Final(digest, &c);
898 
899  if (key_matches(expected_key, digest))
900  return 0;
901 
902  printdigest(digest);
903 
904  return -1;
905 }
906 
907 static size_t resource_name_baselen(const char *name)
908 {
909  size_t len = strlen(name);
910 
911  if (len > 3 && !strcasecmp(name + len - 3, ".so")) {
912  return len - 3;
913  }
914 
915  return len;
916 }
917 
918 static int resource_name_match(const char *name1, size_t baselen1, const char *name2)
919 {
920  if (baselen1 != resource_name_baselen(name2)) {
921  return -1;
922  }
923 
924  return strncasecmp(name1, name2, baselen1);
925 }
926 
927 static struct ast_module *find_resource(const char *resource, int do_lock)
928 {
929  struct ast_module *cur;
930  size_t resource_baselen = resource_name_baselen(resource);
931 
932  if (do_lock) {
934  }
935 
937  if (!resource_name_match(resource, resource_baselen, cur->resource)) {
938  break;
939  }
940  }
941 
942  if (do_lock) {
944  }
945 
946  return cur;
947 }
948 
949 /*!
950  * \brief dlclose(), with failure logging.
951  */
952 static void logged_dlclose(const char *name, void *lib)
953 {
954  char *error;
955 
956  if (!lib) {
957  return;
958  }
959 
960  /* Clear any existing error */
961  dlerror();
962  if (dlclose(lib)) {
963  error = dlerror();
964  ast_log(AST_LOG_ERROR, "Failure in dlclose for module '%s': %s\n",
965  S_OR(name, "unknown"), S_OR(error, "Unknown error"));
966 #if defined(HAVE_PERMANENT_DLOPEN)
967  } else {
968  manual_mod_unreg(name);
969 #endif
970  }
971 }
972 
973 #if defined(HAVE_RTLD_NOLOAD)
974 /*!
975  * \brief Check to see if the given resource is loaded.
976  *
977  * \param resource_name Name of the resource, including .so suffix.
978  * \return False (0) if module is not loaded.
979  * \return True (non-zero) if module is loaded.
980  */
981 static int is_module_loaded(const char *resource_name)
982 {
983  char fn[PATH_MAX] = "";
984  void *lib;
985 
986  snprintf(fn, sizeof(fn), "%s/%s", ast_config_AST_MODULE_DIR,
987  resource_name);
988 
989  lib = dlopen(fn, RTLD_LAZY | RTLD_NOLOAD);
990 
991  if (lib) {
992  logged_dlclose(resource_name, lib);
993  return 1;
994  }
995 
996  return 0;
997 }
998 #endif
999 
1000 static void unload_dynamic_module(struct ast_module *mod)
1001 {
1002 #if defined(HAVE_RTLD_NOLOAD)
1003  char *name = ast_strdupa(ast_module_name(mod));
1004 #endif
1005  void *lib = mod->lib;
1006 
1007  /* WARNING: the structure pointed to by mod is going to
1008  disappear when this operation succeeds, so we can't
1009  dereference it */
1010  logged_dlclose(ast_module_name(mod), lib);
1011 
1012  /* There are several situations where the module might still be resident
1013  * in memory.
1014  *
1015  * If somehow there was another dlopen() on the same module (unlikely,
1016  * since that all is supposed to happen in loader.c).
1017  *
1018  * Avoid the temptation of repeating the dlclose(). The other code that
1019  * dlopened the module still has its module reference, and should close
1020  * it itself. In other situations, dlclose() will happily return success
1021  * for as many times as you wish to call it.
1022  */
1023 #if defined(HAVE_RTLD_NOLOAD)
1024  if (is_module_loaded(name)) {
1025  ast_log(LOG_WARNING, "Module '%s' could not be completely unloaded\n", name);
1026  }
1027 #endif
1028 }
1029 
1030 static int load_dlopen_missing(struct ast_str **list, struct ast_vector_string *deps)
1031 {
1032  int i;
1033  int c = 0;
1034 
1035  for (i = 0; i < AST_VECTOR_SIZE(deps); i++) {
1036  const char *dep = AST_VECTOR_GET(deps, i);
1037  if (!find_resource(dep, 0)) {
1038  STR_APPEND_TEXT(dep, list);
1039  c++;
1040  }
1041  }
1042 
1043  return c;
1044 }
1045 
1046 /*!
1047  * \internal
1048  * \brief Attempt to dlopen a module.
1049  *
1050  * \param resource_in The module name to load.
1051  * \param so_ext ".so" or blank if ".so" is already part of resource_in.
1052  * \param filename Passed directly to dlopen.
1053  * \param flags Passed directly to dlopen.
1054  * \param suppress_logging Do not log any error from dlopen.
1055  *
1056  * \return Pointer to opened module, NULL on error.
1057  *
1058  * \warning module_list must be locked before calling this function.
1059  */
1060 static struct ast_module *load_dlopen(const char *resource_in, const char *so_ext,
1061  const char *filename, int flags, unsigned int suppress_logging)
1062 {
1063  struct ast_module *mod;
1064 
1065  ast_assert(!resource_being_loaded);
1066 
1067  mod = ast_calloc(1, sizeof(*mod) + strlen(resource_in) + strlen(so_ext) + 1);
1068  if (!mod) {
1069  return NULL;
1070  }
1071 
1072  sprintf(mod->resource, "%s%s", resource_in, so_ext); /* safe */
1073 
1074  resource_being_loaded = mod;
1075  mod->lib = dlopen(filename, flags);
1076 #if defined(HAVE_PERMANENT_DLOPEN)
1077  manual_mod_reg(mod->lib, mod->resource);
1078 #endif
1079  if (resource_being_loaded) {
1080  struct ast_str *list;
1081  int c = 0;
1082  const char *dlerror_msg = ast_strdupa(S_OR(dlerror(), ""));
1083 
1084  resource_being_loaded = NULL;
1085  if (mod->lib) {
1086  module_load_error("Module '%s' did not register itself during load\n", resource_in);
1087  logged_dlclose(resource_in, mod->lib);
1088 
1089  goto error_return;
1090  }
1091 
1092  if (suppress_logging) {
1093  goto error_return;
1094  }
1095 
1096  resource_being_loaded = mod;
1097  mod->lib = dlopen(filename, RTLD_LAZY | RTLD_LOCAL);
1098 #if defined(HAVE_PERMANENT_DLOPEN)
1099  manual_mod_reg(mod->lib, mod->resource);
1100 #endif
1101  if (resource_being_loaded) {
1102  resource_being_loaded = NULL;
1103 
1104  module_load_error("Error loading module '%s': %s\n", resource_in, dlerror_msg);
1105  logged_dlclose(resource_in, mod->lib);
1106 
1107  goto error_return;
1108  }
1109 
1110  list = ast_str_create(64);
1111  if (list) {
1112  if (module_post_register(mod)) {
1113  goto loaded_error;
1114  }
1115 
1116  c = load_dlopen_missing(&list, &mod->requires);
1117  c += load_dlopen_missing(&list, &mod->enhances);
1118 #ifndef OPTIONAL_API
1119  c += load_dlopen_missing(&list, &mod->optional_modules);
1120 #endif
1121  }
1122 
1123  if (list && ast_str_strlen(list)) {
1124  module_load_error("Error loading module '%s', missing %s: %s\n",
1125  resource_in, c == 1 ? "dependency" : "dependencies", ast_str_buffer(list));
1126  } else {
1127  module_load_error("Error loading module '%s': %s\n", resource_in, dlerror_msg);
1128  }
1129 
1130 loaded_error:
1131  ast_free(list);
1132  unload_dynamic_module(mod);
1133 
1134  return NULL;
1135 
1136 error_return:
1137  ast_free(mod);
1138 
1139  return NULL;
1140  }
1141 
1142  return mod;
1143 }
1144 
1145 static struct ast_module *load_dynamic_module(const char *resource_in, unsigned int suppress_logging)
1146 {
1147  char fn[PATH_MAX];
1148  struct ast_module *mod;
1149  size_t resource_in_len = strlen(resource_in);
1150  const char *so_ext = "";
1151 
1152  if (resource_in_len < 4 || strcasecmp(resource_in + resource_in_len - 3, ".so")) {
1153  so_ext = ".so";
1154  }
1155 
1156  snprintf(fn, sizeof(fn), "%s/%s%s", ast_config_AST_MODULE_DIR, resource_in, so_ext);
1157 
1158  /* Try loading in quiet mode first with RTLD_LOCAL. The majority of modules do not
1159  * export symbols so this allows the least number of calls to dlopen. */
1160  mod = load_dlopen(resource_in, so_ext, fn, RTLD_NOW | RTLD_LOCAL, suppress_logging);
1161 
1162  if (!mod || !ast_test_flag(mod->info, AST_MODFLAG_GLOBAL_SYMBOLS)) {
1163  return mod;
1164  }
1165 
1166  /* Close the module so we can reopen with correct flags. */
1167  logged_dlclose(resource_in, mod->lib);
1168 
1169  return load_dlopen(resource_in, so_ext, fn, RTLD_NOW | RTLD_GLOBAL, 0);
1170 }
1171 
1173 {
1174  struct ast_module *mod;
1175  int somethingchanged;
1176  int res;
1177 
1179 
1180  /*!\note Some resources, like timers, are started up dynamically, and thus
1181  * may be still in use, even if all channels are dead. We must therefore
1182  * check the usecount before asking modules to unload. */
1183  do {
1184  /* Reset flag before traversing the list */
1185  somethingchanged = 0;
1186 
1188  if (mod->usecount) {
1189  ast_debug(1, "Passing on %s: its use count is %d\n",
1190  mod->resource, mod->usecount);
1191  continue;
1192  }
1194  if (mod->flags.running && !mod->flags.declined && mod->info->unload) {
1195  ast_verb(4, "Unloading %s\n", mod->resource);
1196  mod->info->unload();
1197  }
1198  module_destroy(mod);
1199  somethingchanged = 1;
1200  }
1202  if (!somethingchanged) {
1204  if (mod->flags.keepuntilshutdown) {
1205  ast_module_unref(mod);
1206  mod->flags.keepuntilshutdown = 0;
1207  somethingchanged = 1;
1208  }
1209  }
1210  }
1211  } while (somethingchanged);
1212 
1213  res = AST_DLLIST_EMPTY(&module_list);
1215 
1216  return !res;
1217 }
1218 
1219 /*!
1220  * \brief Whether or not this module should be able to be unloaded successfully,
1221  * if we recursively unload any modules that are dependent on it.
1222  * \note module_list should be locked when calling this
1223  * \retval 0 if not, 1 if likely possible
1224  */
1225 static int graceful_unload_possible(struct ast_module *target, struct ast_vector_const_string *dependents)
1226 {
1227  struct ast_module *mod;
1228  int usecount = target->usecount;
1229 
1230  /* Check the reffed_deps of each module to see if we're one of them. */
1233  const char *name;
1234  /* This module is dependent on the target.
1235  * If we can unload this module gracefully,
1236  * then that would decrement our use count.
1237  * If any single module could not be unloaded gracefully,
1238  * then we don't proceed. */
1239  int unloadable;
1240  if (AST_VECTOR_GET_CMP(dependents, ast_module_name(mod), !strcasecmp)) {
1241  /* Already in our list, we already checked this module,
1242  * and we gave it the green light. */
1243  ast_debug(3, "Skipping duplicate dependent %s\n", ast_module_name(mod));
1244  if (!--usecount) {
1245  break;
1246  }
1247  continue;
1248  }
1249  unloadable = graceful_unload_possible(mod, dependents);
1250  if (!unloadable) {
1251  ast_log(LOG_NOTICE, "Can't unload %s right now because %s is dependent on it\n", ast_module_name(target), ast_module_name(mod));
1252  return 0;
1253  }
1254  /* Insert at beginning, so later if we're loading modules again automatically, we can do so in the same order. */
1255  name = ast_strdup(ast_module_name(mod));
1256  if (!name) {
1257  return 0;
1258  }
1259  ast_debug(3, "Found new dependent %s\n", ast_module_name(mod));
1260  if (AST_VECTOR_INSERT_AT(dependents, 0, name)) {
1261  ast_log(LOG_ERROR, "Failed to add module '%s' to vector\n", ast_module_name(mod));
1262  return 0;
1263  }
1264  if (!--usecount) {
1265  break;
1266  }
1267  }
1268  }
1269 
1270  if (usecount) {
1271  ast_log(LOG_NOTICE, "Module %s cannot be unloaded (would still have use count %d/%d after unloading dependents)\n", ast_module_name(target), usecount, target->usecount);
1272  return 0;
1273  }
1274  return 1;
1275 }
1276 
1277 /*!
1278  * \brief Unload a resource
1279  * \param resource_name Module name
1280  * \param force
1281  * \param recursive Whether to attempt to recursively unload dependents of this module and load them again afterwards
1282  * \param dependents. Can be NULL if autounload is 0.
1283  * \retval 0 on success, -1 on failure
1284  */
1285 static int auto_unload_resource(const char *resource_name, enum ast_module_unload_mode force, int recursive, struct ast_vector_const_string *dependents)
1286 {
1287  struct ast_module *mod;
1288  int res = -1;
1289  int error = 0;
1290 
1292 
1293  if (!(mod = find_resource(resource_name, 0))) {
1295  ast_log(LOG_WARNING, "Unload failed, '%s' could not be found\n", resource_name);
1296  return -1;
1297  }
1298 
1299  if (!mod->flags.running || mod->flags.declined) {
1300  /* If the user asks to unload a module that didn't load, obey.
1301  * Otherwise, we never dlclose() modules that fail to load,
1302  * which means if the module (shared object) is updated,
1303  * we can't load the updated module since we never dlclose()'d it.
1304  * Accordingly, obey the unload request so we can load the module
1305  * from scratch next time.
1306  */
1307  ast_log(LOG_NOTICE, "Unloading module '%s' that previously declined to load\n", resource_name);
1308  error = 0;
1309  res = 0;
1310  goto exit; /* Skip all the intervening !error checks, only the last one is relevant. */
1311  }
1312 
1313  if (!error && mod->usecount > 0 && recursive) {
1314  /* Try automatically unloading all modules dependent on the module we're trying to unload,
1315  * and then, optionally, load them back again if we end up loading this module again.
1316  * If any modules that have us as a dependency can't be unloaded, for whatever reason,
1317  * then the entire unload operation will fail, so to try to make this an atomic operation
1318  * and avoid leaving modules in a partial unload state, first check if we think we're going
1319  * to be able to pull this off, and if not, abort.
1320  *
1321  * A race condition is technically still possible, if some depending module suddenly goes in use
1322  * between this check and trying to unload it, but this takes care of the majority of
1323  * easy-to-avoid cases that would fail eventually anyways.
1324  *
1325  * Note that we can encounter false negatives (e.g. unloading all the dependents would allow
1326  * a module to unload, but graceful_unload_possible returns 0). This is because it's only
1327  * checking direct module dependencies; other dependencies caused by a module registering
1328  * a resource that cause its ref count to get bumped aren't accounted for here.
1329  */
1330  if (graceful_unload_possible(mod, dependents)) {
1331  int i, res = 0;
1332  size_t num_deps = AST_VECTOR_SIZE(dependents);
1333  ast_debug(1, "%lu module%s will need to be unloaded\n", AST_VECTOR_SIZE(dependents), ESS(AST_VECTOR_SIZE(dependents)));
1334  /* Unload from the end, since the last module was the first one added, which means it isn't a dependency of anything else. */
1335  for (i = AST_VECTOR_SIZE(dependents) - 1; i >= 0; i--) {
1336  const char *depname = AST_VECTOR_GET(dependents, i);
1337  res = ast_unload_resource(depname, force);
1338  if (res) {
1339  ast_log(LOG_WARNING, "Failed to unload %lu module%s automatically (%s could not be unloaded)\n", num_deps, ESS(num_deps), depname);
1340  /* To be polite, load modules that we already unloaded,
1341  * to try to leave things the way they were when we started. */
1342  for (i++; i < num_deps; i++) {
1343  const char *depname = AST_VECTOR_GET(dependents, i);
1344  res = ast_load_resource(depname);
1345  if (res) {
1346  ast_log(LOG_WARNING, "Could not load module '%s' again automatically\n", depname);
1347  }
1348  }
1349  break;
1350  }
1351  }
1352  /* Either we failed, or we successfully unloaded everything.
1353  * If we succeeded, we can now proceed and unload ourselves. */
1354  }
1355  }
1356 
1357  if (!error && (mod->usecount > 0)) {
1358  if (force) {
1359  ast_log(LOG_WARNING, "Warning: Forcing removal of module '%s' with use count %d\n", resource_name, mod->usecount);
1360  } else {
1361  ast_log(LOG_WARNING, "%s unload failed, '%s' has use count %d\n", recursive ? "Recursive soft" : "Soft", resource_name, mod->usecount);
1362  error = 1;
1363  }
1364  }
1365 
1366  if (!error) {
1367  /* Request any channels attached to the module to hangup. */
1368  __ast_module_user_hangup_all(mod);
1369 
1370  ast_verb(4, "Unloading %s\n", mod->resource);
1371  res = mod->info->unload();
1372  if (res) {
1373  ast_log(LOG_WARNING, "Firm unload failed for %s\n", resource_name);
1374  if (force <= AST_FORCE_FIRM) {
1375  error = 1;
1376  } else {
1377  ast_log(LOG_WARNING, "** Dangerous **: Unloading resource anyway, at user request\n");
1378  }
1379  }
1380 
1381  if (!error) {
1382  /*
1383  * Request hangup on any channels that managed to get attached
1384  * while we called the module unload function.
1385  */
1386  __ast_module_user_hangup_all(mod);
1387  sched_yield();
1388  }
1389  }
1390 
1391  if (!error)
1392  mod->flags.running = mod->flags.declined = 0;
1393 
1394 exit:
1396 
1397  if (!error) {
1398  unload_dynamic_module(mod);
1399  ast_test_suite_event_notify("MODULE_UNLOAD", "Message: %s", resource_name);
1401  publish_unload_message(resource_name, "Success");
1402  }
1403 
1404  return res;
1405 }
1406 
1407 int ast_refresh_resource(const char *resource_name, enum ast_module_unload_mode force, int recursive)
1408 {
1409  if (recursive) {
1410  /* Recursively unload dependents of this module and then load them back again */
1411  int res, i;
1412  struct ast_vector_const_string dependents;
1413  AST_VECTOR_INIT(&dependents, 0);
1414  res = auto_unload_resource(resource_name, force, recursive, &dependents);
1415  if (res) {
1416  AST_VECTOR_FREE(&dependents);
1417  return 1;
1418  }
1419  /* Start by loading the target again. */
1420  if (ast_load_resource(resource_name)) {
1421  ast_log(LOG_WARNING, "Failed to load module '%s' again automatically\n", resource_name);
1422  AST_VECTOR_FREE(&dependents);
1423  return -1;
1424  }
1425  res = 0;
1426  /* Finally, load again any modules we had to unload in order to refresh the target.
1427  * We must load modules in the reverse order that we unloaded them,
1428  * to preserve dependency requirements. */
1429  for (i = 0; i < AST_VECTOR_SIZE(&dependents); i++) {
1430  const char *depname = AST_VECTOR_GET(&dependents, i);
1431  int mres = ast_load_resource(depname);
1432  if (mres) {
1433  ast_log(LOG_WARNING, "Could not load module '%s' again automatically\n", depname);
1434  }
1435  res |= mres;
1436  }
1437  AST_VECTOR_FREE(&dependents);
1438  return res ? -1 : 0;
1439  }
1440 
1441  /* Simple case: just unload and load the module again */
1442  if (ast_unload_resource(resource_name, force)) {
1443  return 1;
1444  }
1445  return ast_load_resource(resource_name);
1446 }
1447 
1448 int ast_unload_resource(const char *resource_name, enum ast_module_unload_mode force)
1449 {
1450  return auto_unload_resource(resource_name, force, 0, NULL);
1451 }
1452 
1453 static int module_matches_helper_type(struct ast_module *mod, enum ast_module_helper_type type)
1454 {
1455  switch (type) {
1457  return !mod->usecount && mod->flags.running && !mod->flags.declined;
1458 
1460  return mod->flags.running && mod->info->reload;
1461 
1463  return mod->flags.running;
1464 
1466  /* if we have a 'struct ast_module' then we're loaded. */
1467  return 1;
1468  default:
1469  /* This function is not called for AST_MODULE_HELPER_LOAD. */
1470  /* Unknown ast_module_helper_type. Assume it doesn't match. */
1471  ast_assert(0);
1472 
1473  return 0;
1474  }
1475 }
1476 
1478  const char *word;
1479  size_t len;
1480  size_t moddir_len;
1481 };
1482 
1483 static int module_load_helper_on_file(const char *dir_name, const char *filename, void *obj)
1484 {
1485  struct module_load_word *word = obj;
1486  struct ast_module *mod;
1487  char *filename_merged = NULL;
1488 
1489  /* dir_name will never be shorter than word->moddir_len. */
1490  dir_name += word->moddir_len;
1491  if (!ast_strlen_zero(dir_name)) {
1492  ast_assert(dir_name[0] == '/');
1493 
1494  dir_name += 1;
1495  if (ast_asprintf(&filename_merged, "%s/%s", dir_name, filename) < 0) {
1496  /* If we can't allocate the string just give up! */
1497  return -1;
1498  }
1499  filename = filename_merged;
1500  }
1501 
1502  if (!strncasecmp(filename, word->word, word->len)) {
1503  /* Don't list files that are already loaded! */
1504  mod = find_resource(filename, 0);
1505  if (!mod || !mod->flags.running) {
1507  }
1508  }
1509 
1510  ast_free(filename_merged);
1511 
1512  return 0;
1513 }
1514 
1515 static void module_load_helper(const char *word)
1516 {
1517  struct module_load_word word_l = {
1518  .word = word,
1519  .len = strlen(word),
1520  .moddir_len = strlen(ast_config_AST_MODULE_DIR),
1521  };
1522 
1524  ast_file_read_dirs(ast_config_AST_MODULE_DIR, module_load_helper_on_file, &word_l, -1);
1526 }
1527 
1528 char *ast_module_helper(const char *line, const char *word, int pos, int state, int rpos, enum ast_module_helper_type type)
1529 {
1530  struct ast_module *mod;
1531  int which = 0;
1532  int wordlen = strlen(word);
1533  char *ret = NULL;
1534 
1535  if (pos != rpos) {
1536  return NULL;
1537  }
1538 
1539  /* Tab completion can't be used during startup, or CLI and loader will deadlock. */
1540  if (!ast_test_flag(&ast_options, AST_OPT_FLAG_FULLY_BOOTED)) {
1541  return NULL;
1542  }
1543 
1544  if (type == AST_MODULE_HELPER_LOAD) {
1545  module_load_helper(word);
1546 
1547  return NULL;
1548  }
1549 
1552  if (!module_matches_helper_type(mod, type)) {
1553  continue;
1554  }
1555 
1556  if (!strncasecmp(word, mod->resource, wordlen) && ++which > state) {
1557  ret = ast_strdup(mod->resource);
1558  break;
1559  }
1560  }
1562 
1563  return ret;
1564 }
1565 
1567 {
1568  struct reload_queue_item *item;
1569 
1570  modules_loaded = 1;
1571 
1573 
1574  if (do_full_reload) {
1575  do_full_reload = 0;
1577  ast_log(LOG_NOTICE, "Executing deferred reload request.\n");
1578  ast_module_reload(NULL);
1579  return;
1580  }
1581 
1582  while ((item = AST_LIST_REMOVE_HEAD(&reload_queue, entry))) {
1583  ast_log(LOG_NOTICE, "Executing deferred reload request for module '%s'.\n", item->module);
1584  ast_module_reload(item->module);
1585  ast_free(item);
1586  }
1587 
1589 }
1590 
1591 static void queue_reload_request(const char *module)
1592 {
1593  struct reload_queue_item *item;
1594 
1596 
1597  if (do_full_reload) {
1599  return;
1600  }
1601 
1602  if (ast_strlen_zero(module)) {
1603  /* A full reload request (when module is NULL) wipes out any previous
1604  reload requests and causes the queue to ignore future ones */
1605  while ((item = AST_LIST_REMOVE_HEAD(&reload_queue, entry))) {
1606  ast_free(item);
1607  }
1608  do_full_reload = 1;
1609  } else {
1610  /* No reason to add the same module twice */
1612  if (!strcasecmp(item->module, module)) {
1614  return;
1615  }
1616  }
1617  item = ast_calloc(1, sizeof(*item) + strlen(module) + 1);
1618  if (!item) {
1619  ast_log(LOG_ERROR, "Failed to allocate reload queue item.\n");
1621  return;
1622  }
1623  strcpy(item->module, module);
1625  }
1627 }
1628 
1629 /*!
1630  * \since 12
1631  * \internal
1632  * \brief Publish a \ref stasis message regarding the type.
1633  */
1634 static void publish_load_message_type(const char* type, const char *name, const char *status)
1635 {
1636  RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
1637  RAII_VAR(struct ast_json_payload *, payload, NULL, ao2_cleanup);
1638  RAII_VAR(struct ast_json *, json_object, NULL, ast_json_unref);
1639  RAII_VAR(struct ast_json *, event_object, NULL, ast_json_unref);
1640 
1641  ast_assert(type != NULL);
1642  ast_assert(!ast_strlen_zero(name));
1643  ast_assert(!ast_strlen_zero(status));
1644 
1646  return;
1647  }
1648 
1649  event_object = ast_json_pack("{s:s, s:s}",
1650  "Module", name,
1651  "Status", status);
1652  json_object = ast_json_pack("{s:s, s:i, s:o}",
1653  "type", type,
1654  "class_type", EVENT_FLAG_SYSTEM,
1655  "event", ast_json_ref(event_object));
1656  if (!json_object) {
1657  return;
1658  }
1659 
1660  payload = ast_json_payload_create(json_object);
1661  if (!payload) {
1662  return;
1663  }
1664 
1666  if (!message) {
1667  return;
1668  }
1669 
1671 }
1672 
1673 static const char* loadresult2str(enum ast_module_load_result result)
1674 {
1675  int i;
1676  for (i = 0; i < ARRAY_LEN(load_results); i++) {
1677  if (load_results[i].result == result) {
1678  return load_results[i].name;
1679  }
1680  }
1681 
1682  ast_log(LOG_WARNING, "Failed to find correct load result status. result %d\n", result);
1683  return AST_MODULE_LOAD_UNKNOWN_STRING;
1684 }
1685 
1686 /*!
1687  * \internal
1688  * \brief Publish a \ref stasis message regarding the load result
1689  */
1690 static void publish_load_message(const char *name, enum ast_module_load_result result)
1691 {
1692  const char *status;
1693 
1694  status = loadresult2str(result);
1695 
1696  publish_load_message_type("Load", name, status);
1697 }
1698 
1699 /*!
1700  * \internal
1701  * \brief Publish a \ref stasis message regarding the unload result
1702  */
1703 static void publish_unload_message(const char *name, const char* status)
1704 {
1705  publish_load_message_type("Unload", name, status);
1706 }
1707 
1708 /*!
1709  * \since 12
1710  * \internal
1711  * \brief Publish a \ref stasis message regarding the reload result
1712  */
1713 static void publish_reload_message(const char *name, enum ast_module_reload_result result)
1714 {
1715  char res_buffer[8];
1716 
1717  snprintf(res_buffer, sizeof(res_buffer), "%u", result);
1718  publish_load_message_type("Reload", S_OR(name, "All"), res_buffer);
1719 }
1720 
1722 {
1723  struct ast_module *cur;
1725  size_t name_baselen = name ? resource_name_baselen(name) : 0;
1726 
1727  /* If we aren't fully booted, we just pretend we reloaded but we queue this
1728  up to run once we are booted up. */
1729  if (!modules_loaded) {
1730  queue_reload_request(name);
1732  goto module_reload_exit;
1733  }
1734 
1735  if (ast_mutex_trylock(&reloadlock)) {
1736  ast_verb(3, "The previous reload command didn't finish yet\n");
1738  goto module_reload_exit;
1739  }
1740  ast_sd_notify("RELOADING=1");
1741  ast_lastreloadtime = ast_tvnow();
1742 
1743  if (ast_opt_lock_confdir) {
1744  int try;
1745  int lockres;
1746  for (try = 1, lockres = AST_LOCK_TIMEOUT; try < 6 && (lockres == AST_LOCK_TIMEOUT); try++) {
1747  lockres = ast_lock_path(ast_config_AST_CONFIG_DIR);
1748  if (lockres == AST_LOCK_TIMEOUT) {
1749  ast_log(LOG_WARNING, "Failed to grab lock on %s, try %d\n", ast_config_AST_CONFIG_DIR, try);
1750  }
1751  }
1752  if (lockres != AST_LOCK_SUCCESS) {
1753  ast_log(AST_LOG_WARNING, "Cannot grab lock on %s\n", ast_config_AST_CONFIG_DIR);
1755  goto module_reload_done;
1756  }
1757  }
1758 
1761  const struct ast_module_info *info = cur->info;
1762 
1763  if (name && resource_name_match(name, name_baselen, cur->resource)) {
1764  continue;
1765  }
1766 
1767  if (!cur->flags.running || cur->flags.declined) {
1768  if (res == AST_MODULE_RELOAD_NOT_FOUND) {
1770  }
1771  if (!name) {
1772  continue;
1773  }
1774  break;
1775  }
1776 
1777  if (!info->reload) { /* cannot be reloaded */
1778  if (res == AST_MODULE_RELOAD_NOT_FOUND) {
1780  }
1781  if (!name) {
1782  continue;
1783  }
1784  break;
1785  }
1786  ast_verb(3, "Reloading module '%s' (%s)\n", cur->resource, info->description);
1787  if (info->reload() == AST_MODULE_LOAD_SUCCESS) {
1789  } else if (res == AST_MODULE_RELOAD_NOT_FOUND) {
1791  }
1792  if (name) {
1793  break;
1794  }
1795  }
1797 
1798  if (ast_opt_lock_confdir) {
1799  ast_unlock_path(ast_config_AST_CONFIG_DIR);
1800  }
1801 module_reload_done:
1802  ast_mutex_unlock(&reloadlock);
1803  ast_sd_notify("READY=1");
1804 
1805 module_reload_exit:
1806  publish_reload_message(name, res);
1807  return res;
1808 }
1809 
1810 static unsigned int inspect_module(const struct ast_module *mod)
1811 {
1812  if (!mod->info->description) {
1813  module_load_error("Module '%s' does not provide a description.\n", mod->resource);
1814  return 1;
1815  }
1816 
1817  if (!mod->info->key) {
1818  module_load_error("Module '%s' does not provide a license key.\n", mod->resource);
1819  return 1;
1820  }
1821 
1822  if (verify_key((unsigned char *) mod->info->key)) {
1823  module_load_error("Module '%s' did not provide a valid license key.\n", mod->resource);
1824  return 1;
1825  }
1826 
1827  if (!ast_strlen_zero(mod->info->buildopt_sum) &&
1828  strcmp(buildopt_sum, mod->info->buildopt_sum)) {
1829  module_load_error("Module '%s' was not compiled with the same compile-time options as this version of Asterisk.\n", mod->resource);
1830  module_load_error("Module '%s' will not be initialized as it may cause instability.\n", mod->resource);
1831  return 1;
1832  }
1833 
1834  return 0;
1835 }
1836 
1837 static enum ast_module_load_result start_resource(struct ast_module *mod)
1838 {
1839  char tmp[256];
1840  enum ast_module_load_result res;
1841 
1842  if (mod->flags.running) {
1843  return AST_MODULE_LOAD_SUCCESS;
1844  }
1845 
1846  if (!mod->info->load) {
1847  mod->flags.declined = 1;
1848 
1850  }
1851 
1852  if (module_deps_reference(mod, NULL)) {
1853  struct module_vector missing;
1854  int i;
1855 
1856  AST_VECTOR_INIT(&missing, 0);
1857  if (module_deps_missing_recursive(mod, &missing)) {
1858  module_load_error("%s has one or more unknown dependencies.\n", mod->info->name);
1859  }
1860  for (i = 0; i < AST_VECTOR_SIZE(&missing); i++) {
1861  module_load_error("%s loaded before dependency %s!\n", mod->info->name,
1862  AST_VECTOR_GET(&missing, i)->info->name);
1863  }
1864  AST_VECTOR_FREE(&missing);
1865 
1866  return AST_MODULE_LOAD_DECLINE;
1867  }
1868 
1869  if (!ast_fully_booted) {
1870  ast_verb(4, "Loading %s.\n", mod->resource);
1871  }
1872  res = mod->info->load();
1873 
1874  switch (res) {
1876  if (!ast_fully_booted) {
1877  ast_verb(5, "%s => (%s)\n", mod->resource, term_color(tmp, mod->info->description, COLOR_BROWN, COLOR_BLACK, sizeof(tmp)));
1878  } else {
1879  ast_verb(4, "Loaded %s => (%s)\n", mod->resource, mod->info->description);
1880  }
1881 
1882  mod->flags.running = 1;
1883  if (mod->flags.builtin) {
1884  /* Built-in modules cannot be unloaded. */
1886  }
1887 
1889  break;
1891  mod->flags.declined = 1;
1892  if (mod->flags.required) {
1894  }
1895  break;
1897  mod->flags.declined = 1;
1898  break;
1899  case AST_MODULE_LOAD_SKIP: /* modules should never return this value */
1900  case AST_MODULE_LOAD_PRIORITY:
1901  break;
1902  }
1903 
1904  /* Make sure the newly started module is at the end of the list */
1909 
1910  return res;
1911 }
1912 
1913 /*! loads a resource based upon resource_name. If global_symbols_only is set
1914  * only modules with global symbols will be loaded.
1915  *
1916  * If the module_vector is provided (not NULL) the module is found and added to the
1917  * vector without running the module's load() function. By doing this, modules
1918  * can be initialized later in order by priority and dependencies.
1919  *
1920  * If the module_vector is not provided, the module's load function will be executed
1921  * immediately */
1922 static enum ast_module_load_result load_resource(const char *resource_name, unsigned int suppress_logging,
1923  struct module_vector *module_priorities, int required, int preload)
1924 {
1925  struct ast_module *mod;
1927 
1928  if ((mod = find_resource(resource_name, 0))) {
1929  if (mod->flags.running) {
1930  ast_log(LOG_WARNING, "Module '%s' already loaded and running.\n", resource_name);
1931  return AST_MODULE_LOAD_DECLINE;
1932  }
1933  } else {
1934  mod = load_dynamic_module(resource_name, suppress_logging);
1935  if (!mod) {
1937  }
1938 
1939  if (module_post_register(mod)) {
1940  goto prestart_error;
1941  }
1942  }
1943 
1944  mod->flags.required |= required;
1945  mod->flags.preload |= preload;
1946 
1947  if (inspect_module(mod)) {
1948  goto prestart_error;
1949  }
1950 
1951  mod->flags.declined = 0;
1952 
1953  if (module_priorities) {
1954  if (AST_VECTOR_ADD_SORTED(module_priorities, mod, module_vector_cmp)) {
1955  goto prestart_error;
1956  }
1957  res = AST_MODULE_LOAD_PRIORITY;
1958  } else {
1959  res = start_resource(mod);
1960  }
1961 
1962  if (ast_fully_booted && !ast_shutdown_final()) {
1963  publish_load_message(resource_name, res);
1964  }
1965 
1966  return res;
1967 
1968 prestart_error:
1969  module_load_error("Module '%s' could not be loaded.\n", resource_name);
1970  unload_dynamic_module(mod);
1972  if (ast_fully_booted && !ast_shutdown_final()) {
1973  publish_load_message(resource_name, res);
1974  }
1975  return res;
1976 }
1977 
1978 enum ast_module_load_result ast_load_resource(const char *resource_name)
1979 {
1980  struct ast_module *mod;
1981  enum ast_module_load_result res;
1982 
1983  /* If we're trying to load a module that previously declined to load,
1984  * transparently unload it first so we dlclose, then dlopen it afresh.
1985  * Otherwise, we won't actually load a (potentially) updated module. */
1986  mod = find_resource(resource_name, 0);
1987  if (mod && mod->flags.declined) {
1988  ast_debug(1, "Module %s previously declined to load, unloading it first before loading again\n", resource_name);
1989  ast_unload_resource(resource_name, 0);
1990  }
1991 
1993  res = load_resource(resource_name, 0, NULL, 0, 0);
1994  if (!res) {
1995  ast_test_suite_event_notify("MODULE_LOAD", "Message: %s", resource_name);
1996  }
1998 
1999  return res;
2000 }
2001 
2003  char *resource;
2004  int required;
2005  int preload;
2006  int builtin;
2008 };
2009 
2011 
2012 static struct load_order_entry *add_to_load_order(const char *resource, struct load_order *load_order, int required, int preload, int builtin)
2013 {
2014  struct load_order_entry *order;
2015  size_t resource_baselen = resource_name_baselen(resource);
2016 
2017  AST_LIST_TRAVERSE(load_order, order, entry) {
2018  if (!resource_name_match(resource, resource_baselen, order->resource)) {
2019  /* Make sure we have the proper setting for the required field
2020  (we might have both load= and required= lines in modules.conf) */
2021  order->required |= required;
2022  order->preload |= preload;
2023  return order;
2024  }
2025  }
2026 
2027  order = ast_calloc(1, sizeof(*order));
2028  if (!order) {
2029  return NULL;
2030  }
2031 
2032  order->resource = ast_strdup(resource);
2033  if (!order->resource) {
2034  ast_free(order);
2035 
2036  return NULL;
2037  }
2038  order->required = required;
2039  order->preload = preload;
2040  order->builtin = builtin;
2041  AST_LIST_INSERT_TAIL(load_order, order, entry);
2042 
2043  return order;
2044 }
2045 
2047 
2048 static enum ast_module_load_result start_resource_attempt(struct ast_module *mod, int *count)
2049 {
2050  enum ast_module_load_result lres;
2051 
2052  /* Try to grab required references. */
2053  if (module_deps_reference(mod, NULL)) {
2054  /* We're likely to retry so not an error. */
2055  ast_debug(1, "Module %s is missing dependencies\n", mod->resource);
2056  return AST_MODULE_LOAD_SKIP;
2057  }
2058 
2059  lres = start_resource(mod);
2060  ast_debug(3, "START: %-46s[%d] %d\n",
2061  mod->resource,
2062  ast_test_flag(mod->info, AST_MODFLAG_LOAD_ORDER) ? mod->info->load_pri : AST_MODPRI_DEFAULT,
2063  lres);
2064 
2065  if (lres == AST_MODULE_LOAD_SUCCESS) {
2066  (*count)++;
2067  } else if (lres == AST_MODULE_LOAD_FAILURE) {
2068  module_load_error("*** Failed to load %smodule %s\n",
2069  mod->flags.required ? "required " : "",
2070  mod->resource);
2071  }
2072 
2073  return lres;
2074 }
2075 
2076 static int resource_list_recursive_decline(struct module_vector *resources, struct ast_module *mod,
2077  struct ast_str **printmissing)
2078 {
2079  struct module_vector missingdeps;
2080  struct ast_vector_const_string localdeps;
2081  int i = 0;
2082  int res = -1;
2083 
2084  mod->flags.declined = 1;
2085  if (mod->flags.required) {
2086  module_load_error("Required module %s declined to load.\n", ast_module_name(mod));
2087 
2088  return -2;
2089  }
2090 
2091  module_load_error("%s declined to load.\n", ast_module_name(mod));
2092 
2093  if (!*printmissing) {
2094  *printmissing = ast_str_create(64);
2095  if (!*printmissing) {
2096  return -1;
2097  }
2098  } else {
2099  ast_str_reset(*printmissing);
2100  }
2101 
2102  AST_VECTOR_INIT(&missingdeps, 0);
2103  AST_VECTOR_INIT(&localdeps, 0);
2104 
2105  /* Decline everything that depends on 'mod' from resources so we can
2106  * print a concise list. */
2107  while (res != -2 && i < AST_VECTOR_SIZE(resources)) {
2108  struct ast_module *dep = AST_VECTOR_GET(resources, i);
2109  i++;
2110 
2112  if (dep->flags.declined || module_deps_missing_recursive(dep, &missingdeps)) {
2113  continue;
2114  }
2115 
2116  if (AST_VECTOR_GET_CMP(&missingdeps, mod, AST_VECTOR_ELEM_DEFAULT_CMP)) {
2117  dep->flags.declined = 1;
2118  if (dep->flags.required) {
2119  module_load_error("Cannot load required module %s that depends on %s\n",
2120  ast_module_name(dep), ast_module_name(mod));
2121  res = -2;
2122  } else {
2123  AST_VECTOR_APPEND(&localdeps, ast_module_name(dep));
2124  }
2125  }
2126  }
2127  AST_VECTOR_FREE(&missingdeps);
2128 
2129  if (res != -2 && AST_VECTOR_SIZE(&localdeps)) {
2130  AST_VECTOR_CALLBACK_VOID(&localdeps, STR_APPEND_TEXT, printmissing);
2131  module_load_error("Declined modules which depend on %s: %s\n",
2132  ast_module_name(mod), ast_str_buffer(*printmissing));
2133  }
2134  AST_VECTOR_FREE(&localdeps);
2135 
2136  return res;
2137 }
2138 
2139 static int start_resource_list(struct module_vector *resources, int *mod_count)
2140 {
2141  struct module_vector missingdeps;
2142  int res = 0;
2143  struct ast_str *printmissing = NULL;
2144 
2145  AST_VECTOR_INIT(&missingdeps, 0);
2146  while (res != -2 && AST_VECTOR_SIZE(resources)) {
2147  struct ast_module *mod = AST_VECTOR_REMOVE(resources, 0, 1);
2148  enum ast_module_load_result lres;
2149 
2150  if (mod->flags.declined) {
2151  ast_debug(1, "%s is already declined, skipping\n", ast_module_name(mod));
2152  continue;
2153  }
2154 
2155 retry_load:
2156  lres = start_resource_attempt(mod, mod_count);
2157  if (lres == AST_MODULE_LOAD_SUCCESS) {
2158  /* No missing dependencies, successful. */
2159  continue;
2160  }
2161 
2162  if (lres == AST_MODULE_LOAD_FAILURE) {
2163  res = -2;
2164  break;
2165  }
2166 
2167  if (lres == AST_MODULE_LOAD_DECLINE) {
2168  res = resource_list_recursive_decline(resources, mod, &printmissing);
2169  continue;
2170  }
2171 
2172  if (module_deps_missing_recursive(mod, &missingdeps)) {
2174  module_load_error("Failed to resolve dependencies for %s\n", ast_module_name(mod));
2175  res = resource_list_recursive_decline(resources, mod, &printmissing);
2176  continue;
2177  }
2178 
2179  if (!AST_VECTOR_SIZE(&missingdeps)) {
2180  module_load_error("%s load function returned an invalid result. "
2181  "This is a bug in the module.\n", ast_module_name(mod));
2182  /* Dependencies were met but the module failed to start and the result
2183  * code was not AST_MODULE_LOAD_FAILURE or AST_MODULE_LOAD_DECLINE. */
2184  res = resource_list_recursive_decline(resources, mod, &printmissing);
2185  continue;
2186  }
2187 
2188  ast_debug(1, "%s has %d dependencies\n",
2189  ast_module_name(mod), (int)AST_VECTOR_SIZE(&missingdeps));
2190  while (AST_VECTOR_SIZE(&missingdeps)) {
2191  int didwork = 0;
2192  int i = 0;
2193 
2194  while (i < AST_VECTOR_SIZE(&missingdeps)) {
2195  struct ast_module *dep = AST_VECTOR_GET(&missingdeps, i);
2196 
2197  if (dep->flags.declined) {
2198  ast_debug(1, "%s tried to start %s but it's already declined\n",
2199  ast_module_name(mod), ast_module_name(dep));
2200  i++;
2201  continue;
2202  }
2203 
2204  ast_debug(1, "%s trying to start %s\n", ast_module_name(mod), ast_module_name(dep));
2205  lres = start_resource_attempt(dep, mod_count);
2206  if (lres == AST_MODULE_LOAD_SUCCESS) {
2207  ast_debug(1, "%s started %s\n", ast_module_name(mod), ast_module_name(dep));
2208  AST_VECTOR_REMOVE(&missingdeps, i, 1);
2209  AST_VECTOR_REMOVE_CMP_ORDERED(resources, dep,
2211  didwork++;
2212  continue;
2213  }
2214 
2215  if (lres == AST_MODULE_LOAD_FAILURE) {
2216  module_load_error("Failed to load %s.\n", ast_module_name(dep));
2217  res = -2;
2218  goto exitpoint;
2219  }
2220 
2221  ast_debug(1, "%s failed to start %s\n", ast_module_name(mod), ast_module_name(dep));
2222  i++;
2223  }
2224 
2225  if (!didwork) {
2226  break;
2227  }
2228  }
2229 
2230  if (AST_VECTOR_SIZE(&missingdeps)) {
2231  if (!printmissing) {
2232  printmissing = ast_str_create(64);
2233  } else {
2234  ast_str_reset(printmissing);
2235  }
2236 
2237  if (printmissing) {
2238  struct ast_vector_const_string localdeps;
2239 
2240  AST_VECTOR_INIT(&localdeps, 0);
2241  module_deps_reference(mod, &localdeps);
2242  AST_VECTOR_CALLBACK_VOID(&localdeps, STR_APPEND_TEXT, &printmissing);
2243  AST_VECTOR_FREE(&localdeps);
2244  }
2245 
2246  module_load_error("Failed to load %s due to dependencies: %s.\n",
2247  ast_module_name(mod),
2248  printmissing ? ast_str_buffer(printmissing) : "allocation failure creating list");
2249  res = resource_list_recursive_decline(resources, mod, &printmissing);
2250 
2252 
2253  continue;
2254  }
2255 
2256  /* If we're here it means that we started with missingdeps and they're all loaded
2257  * now. It's impossible to reach this point a second time for the same module. */
2258  goto retry_load;
2259  }
2260 
2261 exitpoint:
2262  ast_free(printmissing);
2263  AST_VECTOR_FREE(&missingdeps);
2264 
2265  return res;
2266 }
2267 
2268 /*! loads modules in order by load_pri, updates mod_count
2269  \return -1 on failure to load module, -2 on failure to load required module, otherwise 0
2270 */
2271 static int load_resource_list(struct load_order *load_order, int *mod_count)
2272 {
2273  struct module_vector module_priorities;
2274  struct load_order_entry *order;
2275  int attempt = 0;
2276  int count = 0;
2277  int res = 0;
2278  int didwork;
2279  int lasttry = 0;
2280 
2281  if (AST_VECTOR_INIT(&module_priorities, 500)) {
2282  ast_log(LOG_ERROR, "Failed to initialize module loader.\n");
2283 
2284  return -1;
2285  }
2286 
2287  while (res != -2) {
2288  didwork = 0;
2289 
2290  AST_LIST_TRAVERSE_SAFE_BEGIN(load_order, order, entry) {
2291  enum ast_module_load_result lres;
2292 
2293  /* Suppress log messages unless this is the last pass */
2294  lres = load_resource(order->resource, !lasttry, &module_priorities, order->required, order->preload);
2295  ast_debug(3, "PASS %d: %-46s %d\n", attempt, order->resource, lres);
2296  switch (lres) {
2298  case AST_MODULE_LOAD_SKIP:
2299  /* We're supplying module_priorities so SUCCESS isn't possible but we
2300  * still have to test for it. SKIP is only used when we try to start a
2301  * module that is missing dependencies. */
2302  break;
2304  res = -1;
2305  break;
2307  /* LOAD_FAILURE only happens for required modules */
2308  if (lasttry) {
2309  /* This run is just to print errors. */
2310  module_load_error("*** Failed to load module %s - Required\n", order->resource);
2311  fprintf(stderr, "*** Failed to load module %s - Required\n", order->resource);
2312  res = -2;
2313  }
2314  break;
2315  case AST_MODULE_LOAD_PRIORITY:
2316  /* load_resource worked and the module was added to module_priorities */
2318  ast_free(order->resource);
2319  ast_free(order);
2320  didwork = 1;
2321  break;
2322  }
2323  }
2325 
2326  if (!didwork) {
2327  if (lasttry) {
2328  break;
2329  }
2330  /* We know the next try is going to fail, it's only being performed
2331  * so we can print errors. */
2332  lasttry = 1;
2333  }
2334  attempt++;
2335  }
2336 
2337  if (res != -2) {
2338  res = start_resource_list(&module_priorities, &count);
2339  }
2340 
2341  if (mod_count) {
2342  *mod_count += count;
2343  }
2344  AST_VECTOR_FREE(&module_priorities);
2345 
2346  return res;
2347 }
2348 
2349 static int loader_builtin_init(struct load_order *load_order)
2350 {
2351  struct ast_module *mod;
2352 
2353  /*
2354  * All built-in modules have registered the first time, now it's time to complete
2355  * the registration and add them to the priority list.
2356  */
2357  loader_ready = 1;
2358 
2359  while ((resource_being_loaded = AST_DLLIST_REMOVE_HEAD(&builtin_module_list, entry))) {
2360  /* ast_module_register doesn't finish when first run by built-in modules. */
2361  ast_module_register(resource_being_loaded->info);
2362  }
2363 
2364  /* Add all built-in modules to the load order. */
2366  if (!mod->flags.builtin) {
2367  continue;
2368  }
2369 
2370  /* Parse dependendencies from mod->info. */
2371  if (module_post_register(mod)) {
2372  return -1;
2373  }
2374 
2375  /* Built-in modules are not preloaded, most have an early load priority. */
2376  if (!add_to_load_order(mod->resource, load_order, 0, 0, 1)) {
2377  return -1;
2378  }
2379  }
2380 
2381  return 0;
2382 }
2383 
2384 static int loader_config_init(struct load_order *load_order)
2385 {
2386  int res = -1;
2387  struct load_order_entry *order;
2388  struct ast_config *cfg;
2389  struct ast_variable *v;
2390  struct ast_flags config_flags = { 0 };
2391 
2392  cfg = ast_config_load2(AST_MODULE_CONFIG, "" /* core, can't reload */, config_flags);
2393  if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEINVALID) {
2394  ast_log(LOG_WARNING, "'%s' invalid or missing.\n", AST_MODULE_CONFIG);
2395 
2396  return -1;
2397  }
2398 
2399  /* first, find all the modules we have been explicitly requested to load */
2400  for (v = ast_variable_browse(cfg, "modules"); v; v = v->next) {
2401  int required;
2402  int preload = 0;
2403 
2404  if (!strncasecmp(v->name, "preload", strlen("preload"))) {
2405  preload = 1;
2406  if (!strcasecmp(v->name, "preload")) {
2407  required = 0;
2408  } else if (!strcasecmp(v->name, "preload-require")) {
2409  required = 1;
2410  } else {
2411  ast_log(LOG_ERROR, "Unknown configuration option '%s'", v->name);
2412  goto done;
2413  }
2414  } else if (!strcasecmp(v->name, "load")) {
2415  required = 0;
2416  } else if (!strcasecmp(v->name, "require")) {
2417  required = 1;
2418  } else if (!strcasecmp(v->name, "noload") || !strcasecmp(v->name, "autoload")) {
2419  continue;
2420  } else {
2421  ast_log(LOG_ERROR, "Unknown configuration option '%s'", v->name);
2422  goto done;
2423  }
2424 
2425  if (required) {
2426  ast_debug(2, "Adding module to required list: %s (%s)\n", v->value, v->name);
2427  }
2428 
2429  if (!add_to_load_order(v->value, load_order, required, preload, 0)) {
2430  goto done;
2431  }
2432  }
2433 
2434  /* check if 'autoload' is on */
2435  if (ast_true(ast_variable_retrieve(cfg, "modules", "autoload"))) {
2436  /* if we are allowed to load dynamic modules, scan the directory for
2437  for all available modules and add them as well */
2438  DIR *dir = opendir(ast_config_AST_MODULE_DIR);
2439  struct dirent *dirent;
2440 
2441  if (dir) {
2442  while ((dirent = readdir(dir))) {
2443  int ld = strlen(dirent->d_name);
2444 
2445  /* Must end in .so to load it. */
2446 
2447  if (ld < 4)
2448  continue;
2449 
2450  if (strcasecmp(dirent->d_name + ld - 3, ".so"))
2451  continue;
2452 
2453  /* if there is already a module by this name in the module_list,
2454  skip this file */
2455  if (find_resource(dirent->d_name, 0))
2456  continue;
2457 
2458  if (!add_to_load_order(dirent->d_name, load_order, 0, 0, 0)) {
2459  closedir(dir);
2460  goto done;
2461  }
2462  }
2463 
2464  closedir(dir);
2465  } else {
2466  ast_log(LOG_ERROR, "Unable to open modules directory '%s'.\n", ast_config_AST_MODULE_DIR);
2467  goto done;
2468  }
2469  }
2470 
2471  /* now scan the config for any modules we are prohibited from loading and
2472  remove them from the load order */
2473  for (v = ast_variable_browse(cfg, "modules"); v; v = v->next) {
2474  size_t baselen;
2475 
2476  if (strcasecmp(v->name, "noload")) {
2477  continue;
2478  }
2479 
2480  baselen = resource_name_baselen(v->value);
2481  AST_LIST_TRAVERSE_SAFE_BEGIN(load_order, order, entry) {
2482  if (!resource_name_match(v->value, baselen, order->resource)) {
2483  if (order->builtin) {
2484  ast_log(LOG_ERROR, "%s is a built-in module, you cannot specify 'noload'.\n", v->value);
2485  goto done;
2486  }
2487 
2488  if (order->required) {
2489  ast_log(LOG_ERROR, "%s is configured with '%s' and 'noload', this is impossible.\n",
2490  v->value, order->preload ? "preload-require" : "require");
2491  goto done;
2492  }
2494  ast_free(order->resource);
2495  ast_free(order);
2496  }
2497  }
2499  }
2500 
2501  res = 0;
2502 done:
2503  ast_config_destroy(cfg);
2504 
2505  return res;
2506 }
2507 
2508 int load_modules(void)
2509 {
2510  struct load_order_entry *order;
2511  unsigned int load_count;
2512  struct load_order load_order;
2513  int res = 0;
2514  int modulecount = 0;
2515  int i;
2516  struct ast_module *cur;
2517 #ifdef AST_XML_DOCS
2518  struct ast_str *warning_msg;
2519  char deprecated_in[33];
2520  char removed_in[33];
2521  char replacement[129];
2522 #endif
2523  struct timeval start_time = ast_tvnow();
2524  struct timeval end_time;
2525  int64_t usElapsed;
2526 
2527  ast_verb(1, "Asterisk Dynamic Loader Starting:\n");
2528 
2529 #if defined(HAVE_PERMANENT_DLOPEN)
2531  info_list_obj_cmp_fn); /* must not be cleaned at shutdown */
2532  if (!info_list) {
2533  fprintf(stderr, "Module info list allocation failure.\n");
2534  return 1;
2535  }
2536 #endif
2537 
2538  AST_LIST_HEAD_INIT_NOLOCK(&load_order);
2540 
2542  startup_error_builder = ast_str_create(64);
2543 
2544  res = loader_builtin_init(&load_order);
2545  if (res) {
2546  goto done;
2547  }
2548 
2549  res = loader_config_init(&load_order);
2550  if (res) {
2551  goto done;
2552  }
2553 
2554  load_count = 0;
2555  AST_LIST_TRAVERSE(&load_order, order, entry)
2556  load_count++;
2557 
2558  if (load_count)
2559  ast_log(LOG_NOTICE, "%u modules will be loaded.\n", load_count);
2560 
2561  res = load_resource_list(&load_order, &modulecount);
2562  if (res == -1) {
2563  ast_log(LOG_WARNING, "Some non-required modules failed to load.\n");
2564  res = 0;
2565  }
2566 
2567 done:
2568  while ((order = AST_LIST_REMOVE_HEAD(&load_order, entry))) {
2569  ast_free(order->resource);
2570  ast_free(order);
2571  }
2572 
2573 #ifdef AST_XML_DOCS
2574  warning_msg = ast_str_create(512);
2575 #endif
2576 
2578 #ifdef AST_XML_DOCS
2579  char *mod_name = NULL;
2580  struct ast_xml_xpath_results *results;
2581 #endif
2582 
2583  if (!cur->flags.running || cur->flags.declined) {
2584  continue;
2585  }
2586 
2587 #ifdef AST_XML_DOCS
2588  mod_name = get_name_from_resource(cur->resource);
2589  if (!warning_msg || !mod_name) {
2590  /* If we can't allocate memory, we have bigger issues */
2591  ast_free(mod_name);
2592  continue;
2593  }
2594 
2595  /* Clear out the previous values */
2596  deprecated_in[0] = removed_in[0] = replacement[0] = 0;
2597 
2598  results = ast_xmldoc_query("/docs/module[@name='%s']", mod_name);
2599  if (results) {
2600  struct ast_xml_node *deprecated_node, *removed_node, *replacement_node;
2601  struct ast_xml_node *metadata_nodes = ast_xml_node_get_children(ast_xml_xpath_get_first_result(results));
2602 
2603  deprecated_node = ast_xml_find_element(metadata_nodes, "deprecated_in", NULL, NULL);
2604  if (deprecated_node) {
2605  const char *result_tmp = ast_xml_get_text(deprecated_node);
2606  if (!ast_strlen_zero(result_tmp)) {
2607  ast_copy_string(deprecated_in, result_tmp, sizeof(deprecated_in));
2608  }
2609  }
2610 
2611  removed_node = ast_xml_find_element(metadata_nodes, "removed_in", NULL, NULL);
2612  if (removed_node) {
2613  const char *result_tmp = ast_xml_get_text(removed_node);
2614  if (!ast_strlen_zero(result_tmp)) {
2615  ast_copy_string(removed_in, result_tmp, sizeof(removed_in));
2616  }
2617  }
2618 
2619  replacement_node = ast_xml_find_element(metadata_nodes, "replacement", NULL, NULL);
2620  if (replacement_node) {
2621  const char *result_tmp = ast_xml_get_text(replacement_node);
2622  if (!ast_strlen_zero(result_tmp)) {
2623  ast_copy_string(replacement, result_tmp, sizeof(replacement));
2624  }
2625  }
2626 
2627  ast_xml_xpath_results_free(results);
2628  }
2629 
2630  ast_str_reset(warning_msg);
2631 
2632  if (cur->info->support_level == AST_MODULE_SUPPORT_DEPRECATED || !ast_strlen_zero(deprecated_in)
2633  || !ast_strlen_zero(removed_in) || !ast_strlen_zero(replacement)) {
2634  int already_butted = 0;
2635 
2636  ast_str_append(&warning_msg, -1, "Module '%s' has been loaded", mod_name);
2637  if (!ast_strlen_zero(deprecated_in)) {
2638  ast_str_append(&warning_msg, -1, " but %s deprecated in Asterisk version %s",
2639  cur->info->support_level == AST_MODULE_SUPPORT_DEPRECATED ? "was" : "will be", deprecated_in);
2640  already_butted = 1;
2641  }
2642 
2643  if (!ast_strlen_zero(removed_in)) {
2644  ast_str_append(&warning_msg, -1, " %s will be removed in Asterisk version %s", already_butted ? "and" : "but", removed_in);
2645  } else {
2646  ast_str_append(&warning_msg, -1, " %s may be removed in a future release", already_butted ? "and" : "but");
2647  }
2648 
2649  ast_str_append(&warning_msg, -1, ".");
2650 
2651  if (!ast_strlen_zero(replacement)) {
2652  ast_str_append(&warning_msg, -1, " Its replacement is '%s'.", replacement);
2653  }
2654  }
2655 
2656  if (ast_str_strlen(warning_msg)) {
2657  ast_log(LOG_WARNING, "%s\n", ast_str_buffer(warning_msg));
2658  }
2659 
2660  ast_free(mod_name);
2661 #else
2662  if (cur->info->support_level == AST_MODULE_SUPPORT_DEPRECATED) {
2663  ast_log(LOG_WARNING, "The deprecated module '%s' has been loaded and is running, it may be removed in a future version\n", cur->resource);
2664  }
2665 #endif
2666  }
2667 
2668 #ifdef AST_XML_DOCS
2669  ast_free(warning_msg);
2670 #endif
2671 
2673 
2674 
2675  for (i = 0; i < AST_VECTOR_SIZE(&startup_errors); i++) {
2676  char *str = AST_VECTOR_GET(&startup_errors, i);
2677 
2678  ast_log(LOG_ERROR, "%s", str);
2679  ast_free(str);
2680  }
2682 
2683  ast_free(startup_error_builder);
2684  startup_error_builder = NULL;
2685 
2686  end_time = ast_tvnow();
2687  usElapsed = ast_tvdiff_us(end_time, start_time);
2688 
2689 #ifdef AST_XML_DOCS
2690  ast_debug(1, "Loader time with AST_XML_DOCS: %" PRId64 ".%06" PRId64 "\n", usElapsed / 1000000, usElapsed % 1000000);
2691 #else
2692  ast_debug(1, "Loader time without AST_XML_DOCS: %" PRId64 ".%06" PRId64 "\n", usElapsed / 1000000, usElapsed % 1000000);
2693 #endif
2694 
2695  return res;
2696 }
2697 
2699 {
2700  /* Notify any module monitors that the use count for a
2701  resource has changed */
2702  struct loadupdate *m;
2703 
2706  m->updater();
2708 }
2709 
2710 /*!
2711  * \internal
2712  * \brief Build an alpha sorted list of modules.
2713  *
2714  * \param alpha_module_list Pointer to uninitialized module_vector.
2715  *
2716  * This function always initializes alpha_module_list.
2717  *
2718  * \pre module_list must be locked.
2719  */
2720 static int alpha_module_list_create(struct module_vector *alpha_module_list)
2721 {
2722  struct ast_module *cur;
2723 
2724  if (AST_VECTOR_INIT(alpha_module_list, 32)) {
2725  return -1;
2726  }
2727 
2729  if (AST_VECTOR_ADD_SORTED(alpha_module_list, cur, module_vector_strcasecmp)) {
2730  return -1;
2731  }
2732  }
2733 
2734  return 0;
2735 }
2736 
2737 int ast_update_module_list(int (*modentry)(const char *module, const char *description,
2738  int usecnt, const char *status, const char *like,
2739  enum ast_module_support_level support_level),
2740  const char *like)
2741 {
2742  int total_mod_loaded = 0;
2743  struct module_vector alpha_module_list;
2744 
2746 
2747  if (!alpha_module_list_create(&alpha_module_list)) {
2748  int idx;
2749 
2750  for (idx = 0; idx < AST_VECTOR_SIZE(&alpha_module_list); idx++) {
2751  struct ast_module *cur = AST_VECTOR_GET(&alpha_module_list, idx);
2752 
2753  total_mod_loaded += modentry(cur->resource, cur->info->description, cur->usecount,
2754  cur->flags.running ? "Running" : "Not Running", like, cur->info->support_level);
2755  }
2756  }
2757 
2759  AST_VECTOR_FREE(&alpha_module_list);
2760 
2761  return total_mod_loaded;
2762 }
2763 
2764 int ast_update_module_list_data(int (*modentry)(const char *module, const char *description,
2765  int usecnt, const char *status, const char *like,
2766  enum ast_module_support_level support_level,
2767  void *data),
2768  const char *like, void *data)
2769 {
2770  int total_mod_loaded = 0;
2771  struct module_vector alpha_module_list;
2772 
2774 
2775  if (!alpha_module_list_create(&alpha_module_list)) {
2776  int idx;
2777 
2778  for (idx = 0; idx < AST_VECTOR_SIZE(&alpha_module_list); idx++) {
2779  struct ast_module *cur = AST_VECTOR_GET(&alpha_module_list, idx);
2780 
2781  total_mod_loaded += modentry(cur->resource, cur->info->description, cur->usecount,
2782  cur->flags.running? "Running" : "Not Running", like, cur->info->support_level, data);
2783  }
2784  }
2785 
2787  AST_VECTOR_FREE(&alpha_module_list);
2788 
2789  return total_mod_loaded;
2790 }
2791 
2792 int ast_update_module_list_condition(int (*modentry)(const char *module, const char *description,
2793  int usecnt, const char *status,
2794  const char *like,
2795  enum ast_module_support_level support_level,
2796  void *data, const char *condition),
2797  const char *like, void *data, const char *condition)
2798 {
2799  int conditions_met = 0;
2800  struct module_vector alpha_module_list;
2801 
2803 
2804  if (!alpha_module_list_create(&alpha_module_list)) {
2805  int idx;
2806 
2807  for (idx = 0; idx < AST_VECTOR_SIZE(&alpha_module_list); idx++) {
2808  struct ast_module *cur = AST_VECTOR_GET(&alpha_module_list, idx);
2809 
2810  conditions_met += modentry(cur->resource, cur->info->description, cur->usecount,
2811  cur->flags.running? "Running" : "Not Running", like, cur->info->support_level, data,
2812  condition);
2813  }
2814  }
2815 
2817  AST_VECTOR_FREE(&alpha_module_list);
2818 
2819  return conditions_met;
2820 }
2821 
2822 /*! \brief Check if module exists */
2823 int ast_module_check(const char *name)
2824 {
2825  struct ast_module *cur;
2826 
2827  if (ast_strlen_zero(name))
2828  return 0; /* FALSE */
2829 
2830  cur = find_resource(name, 1);
2831 
2832  return (cur != NULL);
2833 }
2834 
2835 
2836 int ast_loader_register(int (*v)(void))
2837 {
2838  struct loadupdate *tmp;
2839 
2840  if (!(tmp = ast_malloc(sizeof(*tmp))))
2841  return -1;
2842 
2843  tmp->updater = v;
2847 
2848  return 0;
2849 }
2850 
2851 int ast_loader_unregister(int (*v)(void))
2852 {
2853  struct loadupdate *cur;
2854 
2857  if (cur->updater == v) {
2859  break;
2860  }
2861  }
2864 
2865  return cur ? 0 : -1;
2866 }
2867 
2868 struct ast_module *__ast_module_ref(struct ast_module *mod, const char *file, int line, const char *func)
2869 {
2870  if (!mod) {
2871  return NULL;
2872  }
2873 
2874  if (mod->ref_debug) {
2875  __ao2_ref(mod->ref_debug, +1, "", file, line, func);
2876  }
2877 
2878  ast_atomic_fetchadd_int(&mod->usecount, +1);
2880 
2881  return mod;
2882 }
2883 
2884 struct ast_module *__ast_module_running_ref(struct ast_module *mod,
2885  const char *file, int line, const char *func)
2886 {
2887  if (!mod || !mod->flags.running) {
2888  return NULL;
2889  }
2890 
2891  return __ast_module_ref(mod, file, line, func);
2892 }
2893 
2894 void __ast_module_shutdown_ref(struct ast_module *mod, const char *file, int line, const char *func)
2895 {
2896  if (!mod || mod->flags.keepuntilshutdown) {
2897  return;
2898  }
2899 
2900  __ast_module_ref(mod, file, line, func);
2901  mod->flags.keepuntilshutdown = 1;
2902 }
2903 
2904 void __ast_module_unref(struct ast_module *mod, const char *file, int line, const char *func)
2905 {
2906  if (!mod) {
2907  return;
2908  }
2909 
2910  if (mod->ref_debug) {
2911  __ao2_ref(mod->ref_debug, -1, "", file, line, func);
2912  }
2913 
2914  ast_atomic_fetchadd_int(&mod->usecount, -1);
2916 }
2917 
2918 const char *support_level_map [] = {
2919  [AST_MODULE_SUPPORT_UNKNOWN] = "unknown",
2920  [AST_MODULE_SUPPORT_CORE] = "core",
2921  [AST_MODULE_SUPPORT_EXTENDED] = "extended",
2922  [AST_MODULE_SUPPORT_DEPRECATED] = "deprecated",
2923 };
2924 
2925 const char *ast_module_support_level_to_string(enum ast_module_support_level support_level)
2926 {
2927  return support_level_map[support_level];
2928 }
static void publish_load_message_type(const char *type, const char *name, const char *status)
Definition: loader.c:1634
const char * description
Definition: module.h:366
#define AST_VECTOR_FREE(vec)
Deallocates this vector.
Definition: vector.h:174
struct ast_variable * next
int load_modules(void)
Definition: loader.c:2508
ast_module_load_result
Definition: module.h:68
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:40
void ast_update_use_count(void)
Notify when usecount has been changed.
Definition: loader.c:2698
Asterisk locking-related definitions:
Asterisk main include file. File version handling, generic pbx functions.
struct ast_json * ast_json_pack(char const *format,...)
Helper for creating complex JSON values.
Definition: json.c:612
unsigned int required
Definition: loader.c:328
The arg parameter is a search key, but is not an object.
Definition: astobj2.h:1101
struct ast_json_payload * ast_json_payload_create(struct ast_json *json)
Create an ao2 object to pass json blobs as data payloads for stasis.
Definition: json.c:756
unsigned int preload
Definition: loader.c:330
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
Definition: json.c:73
int ast_softhangup(struct ast_channel *chan, int cause)
Softly hangup up a channel.
Definition: channel.c:2471
#define AST_VECTOR_ELEM_DEFAULT_CMP(elem, value)
Default comparator for AST_VECTOR_REMOVE_ELEM_UNORDERED()
Definition: vector.h:564
ast_module_reload_result
Possible return types for ast_module_reload.
Definition: module.h:109
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:140
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:761
unsigned char load_pri
Definition: module.h:384
#define AST_DLLIST_UNLOCK(head)
Attempts to unlock a list.
Definition: dlinkedlists.h:123
static void publish_reload_message(const char *name, enum ast_module_reload_result result)
Definition: loader.c:1713
#define ao2_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn)
Allocate and initialize a list container.
Definition: astobj2.h:1327
struct ast_config * ast_config_load2(const char *filename, const char *who_asked, struct ast_flags flags)
Load a config file.
Definition: main/config.c:3321
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
int ast_str_set_va(struct ast_str **buf, ssize_t max_len, const char *fmt, va_list ap)
Set a dynamic string from a va_list.
Definition: strings.h:1030
#define 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:888
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:1528
enum ast_module_reload_result ast_module_reload(const char *name)
Reload asterisk modules.
Definition: loader.c:1721
Definition: loader.c:2002
AO2_STRING_FIELD_CMP_FN(transport_monitor, key)
Comparison function for struct transport_monitor.
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition: strings.h:1139
struct ast_xml_xpath_results * ast_xmldoc_query(const char *fmt,...)
Execute an XPath query on the loaded XML documentation.
Definition: xmldoc.c:2576
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:159
int usecount
Definition: loader.c:300
#define AST_DLLIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
Definition: dlinkedlists.h:753
#define ao2_t_alloc_options(data_size, destructor_fn, options, debug_msg)
Allocate and initialize an object.
Definition: astobj2.h:402
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:241
int ast_unlock_path(const char *path)
Unlock a path.
Definition: main/app.c:2630
I/O Management (derived from Cheops-NG)
#define AST_LIST_REMOVE(head, elm, field)
Removes a specific entry from a list.
Definition: linkedlists.h:856
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:615
int ast_file_read_dirs(const char *dir_name, ast_file_on_file on_file, void *obj, int max_depth)
Recursively iterate through files and directories up to max_depth.
Definition: file.c:1274
int ast_atomic_fetchadd_int(volatile int *p, int v)
Atomically add v to *p and return the previous value of *p.
Definition: lock.h:757
ast_module_helper_type
Definition: module.h:127
enum ast_module_load_result ast_load_resource(const char *resource_name)
Load a module.
Definition: loader.c:1978
A vector of strings commonly used throughout this module.
const char * enhances
Modules that we provide enhanced functionality for.
Definition: module.h:420
int ast_refresh_resource(const char *resource_name, enum ast_module_unload_mode force, int recursive)
Unload and load a module again.
Definition: loader.c:1407
Utility functions.
#define ast_asprintf(ret, fmt,...)
A wrapper for asprintf()
Definition: astmm.h:267
const char * requires
Definition: module.h:387
#define AST_LIST_HEAD_DESTROY(head)
Destroys a list head structure.
Definition: linkedlists.h:653
#define STR_APPEND_TEXT(txt, str)
Definition: loader.c:144
enum AST_LOCK_RESULT ast_lock_path(const char *path)
Lock a filesystem path.
Definition: main/app.c:2614
Configuration File Parser.
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.
#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.
struct ast_vector_string enhances
Definition: loader.c:309
const char * name
Definition: module.h:364
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
Definition: vector.h:113
struct ast_module * self
Definition: module.h:356
const char * optional_modules
Comma-separated list of optionally required modules.
Definition: module.h:397
A set of macros to manage doubly-linked lists.
int ast_module_check(const char *name)
Check if module exists.
Definition: loader.c:2823
General Asterisk PBX channel definitions.
void ast_process_pending_reloads(void)
Process reload requests received during startup.
Definition: loader.c:1566
Asterisk file paths, configured in asterisk.conf.
#define AST_VECTOR_ELEM_CLEANUP_NOOP(elem)
Vector element cleanup that does nothing.
Definition: vector.h:571
#define AST_DLLIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: dlinkedlists.h:576
int ast_sd_notify(const char *state)
a wrapper for sd_notify(): notify systemd of any state changes.
Definition: io.c:392
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
int(* unload)(void)
Definition: module.h:362
static int modules_loaded
Internal flag to indicate all modules have been initially loaded.
Definition: loader.c:291
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
Definition: linkedlists.h:557
struct ast_vector_string optional_modules
Definition: loader.c:307
ast_module_unload_mode
Definition: module.h:61
struct ast_xml_node * ast_xml_find_element(struct ast_xml_node *root_node, const char *name, const char *attrname, const char *attrvalue)
Find a node element by name.
Definition: xml.c:297
unsigned int declined
Definition: loader.c:322
#define ast_malloc(len)
A wrapper for malloc()
Definition: astmm.h:191
#define ast_debug(level,...)
Log a DEBUG message.
#define AST_VECTOR(name, type)
Define a vector structure.
Definition: vector.h:44
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:833
int(* reload)(void)
Definition: module.h:360
#define ast_test_suite_event_notify(s, f,...)
Definition: test.h:189
char * term_color(char *outbuf, const char *inbuf, int fgcolor, int bgcolor, int maxout)
Colorize a specified string by adding terminal color codes.
Definition: term.c:235
static int load_resource_list(struct load_order *load_order, int *mod_count)
Definition: loader.c:2271
static int auto_unload_resource(const char *resource_name, enum ast_module_unload_mode force, int recursive, struct ast_vector_const_string *dependents)
Unload a resource.
Definition: loader.c:1285
The AMI - Asterisk Manager Interface - is a TCP protocol created to manage Asterisk with third-party ...
#define AST_LIST_HEAD_NOLOCK(name, type)
Defines a structure to be used to hold a list of specified type (with no lock).
Definition: linkedlists.h:225
int ast_shutdown_final(void)
Definition: asterisk.c:1871
static void logged_dlclose(const char *name, void *lib)
dlclose(), with failure logging.
Definition: loader.c:952
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:731
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: utils.c:2199
Support for dynamic strings.
Definition: strings.h:623
int ast_unload_resource(const char *resource_name, enum ast_module_unload_mode force)
Unload a module.
Definition: loader.c:1448
struct ast_vector_string requires
Definition: loader.c:305
struct stasis_message * stasis_message_create(struct stasis_message_type *type, void *data)
Create a new message.
#define ast_module_shutdown_ref(mod)
Prevent unload of the module before shutdown.
Definition: module.h:478
void * ref_debug
Definition: loader.c:296
#define ast_module_ref(mod)
Hold a reference to the module.
Definition: module.h:457
int modules_shutdown(void)
Definition: loader.c:1172
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:491
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
Definition: linkedlists.h:410
int ast_vector_string_split(struct ast_vector_string *dest, const char *input, const char *delim, int flags, int(*excludes_cmp)(const char *s1, const char *s2))
Append a string vector by splitting a string.
Definition: strings.c:392
#define AST_LIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
Definition: linkedlists.h:711
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.
#define ESS(x)
Definition: cli.h:59
void stasis_publish(struct stasis_topic *topic, struct stasis_message *message)
Publish a message to a topic's subscribers.
Definition: stasis.c:1511
#define AST_LIST_HEAD_INIT(head)
Initializes a list head structure.
Definition: linkedlists.h:626
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
#define AST_VECTOR_RESET(vec, cleanup)
Reset vector.
Definition: vector.h:625
#define AST_DLLIST_HEAD(name, type)
Defines a structure to be used to hold a list of specified type.
Definition: dlinkedlists.h:158
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:2836
#define AST_DLLIST_EMPTY(head)
Checks whether the specified list contains any entries.
Definition: dlinkedlists.h:469
Prototypes for public functions only of internal interest,.
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:425
#define AST_VECTOR_GET_CMP(vec, value, cmp)
Get an element from a vector that matches the given comparison.
Definition: vector.h:731
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:1880
#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
Definition: md5.h:26
#define ast_module_unref(mod)
Release a reference to the module.
Definition: module.h:483
void ast_str_reset(struct ast_str *buf)
Reset the content of a dynamic string. Useful before a series of ast_str_append.
Definition: strings.h:693
#define AST_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:730
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition: vector.h:680
#define AST_LIST_HEAD_INIT_NOLOCK(head)
Initializes a list head structure.
Definition: linkedlists.h:681
unsigned int builtin
Definition: loader.c:326
#define AST_DLLIST_TRAVERSE_BACKWARDS_SAFE_END
Closes a safe loop traversal block.
Definition: dlinkedlists.h:921
Standard Command Line Interface.
const char * key
Definition: module.h:373
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:80
int ast_update_module_list_data(int(*modentry)(const char *module, const char *description, int usecnt, const char *status, const char *like, enum ast_module_support_level support_level, void *data), const char *like, void *data)
Ask for a list of modules, descriptions, use counts and status.
Definition: loader.c:2764
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:2851
const char * ast_xml_get_text(struct ast_xml_node *node)
Get an element content string.
Definition: xml.c:353
unsigned int keepuntilshutdown
Definition: loader.c:324
Abstract JSON element (object, array, string, int, ...).
#define AST_VECTOR_INSERT_AT(vec, idx, elem)
Insert an element at a specific position in a vector, growing the vector if needed.
Definition: vector.h:338
#define AST_DLLIST_REMOVE(head, elm, field)
Removes a specific entry from a list.
Definition: search.h:40
Handy terminal functions for vt* terms.
int64_t ast_tvdiff_us(struct timeval end, struct timeval start)
Computes the difference (in microseconds) between two struct timeval instances.
Definition: time.h:87
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
Definition: linkedlists.h:529
static struct ast_vector_string startup_errors
Definition: loader.c:153
Generic container type.
String vector definitions.
Definition: vector.h:55
void ast_config_destroy(struct ast_config *cfg)
Destroys a config.
Definition: extconf.c:1289
int ast_cli_completion_add(char *value)
Add a result to a request for completion options.
Definition: main/cli.c:2761
enum ast_module_load_result(* load)(void)
Definition: module.h:358
#define AST_VECTOR_REMOVE(vec, idx, preserve_ordered)
Remove an element from a vector by index.
Definition: vector.h:412
Asterisk module definitions.
MD5 digest functions.
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:941
void * lib
Definition: loader.c:298
enum ast_module_support_level support_level
Definition: module.h:430
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
static int graceful_unload_possible(struct ast_module *target, struct ast_vector_const_string *dependents)
Whether or not this module should be able to be unloaded successfully, if we recursively unload any m...
Definition: loader.c:1225
struct ast_xml_node * ast_xml_xpath_get_first_result(struct ast_xml_xpath_results *results)
Return the first result node of an XPath query.
Definition: xml.c:415
const char buildopt_sum[33]
Definition: module.h:377
#define AST_DLLIST_LOCK(head)
Locks a list.
Definition: dlinkedlists.h:46
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:609
struct ast_xml_node * ast_xml_node_get_children(struct ast_xml_node *node)
Get the node's children.
Definition: xml.c:395
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:1922
#define AST_VECTOR_CALLBACK_VOID(vec, callback,...)
Execute a callback on every element in a vector disregarding callback return.
Definition: vector.h:862
static int is_module_loaded(const char *resource_name)
Check to see if the given resource is loaded.
Definition: loader.c:981
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
Definition: strings.h:659
#define AST_DLLIST_ENTRY(type)
Declare previous/forward links inside a list entry.
Definition: dlinkedlists.h:413
#define AST_DLLIST_HEAD_STATIC(name, type)
Defines a structure to be used to hold a list of specified type, statically initialized.
Definition: dlinkedlists.h:285
#define ao2_link(container, obj)
Add an object to a container.
Definition: astobj2.h:1532