Asterisk - The Open Source Telephony Project  21.4.1
Data Structures | Macros | Functions | Variables
loader.c File Reference

Module Loader. More...

#include "asterisk.h"
#include "asterisk/_private.h"
#include "asterisk/paths.h"
#include <dirent.h>
#include "asterisk/dlinkedlists.h"
#include "asterisk/module.h"
#include "asterisk/config.h"
#include "asterisk/channel.h"
#include "asterisk/term.h"
#include "asterisk/manager.h"
#include "asterisk/io.h"
#include "asterisk/lock.h"
#include "asterisk/vector.h"
#include "asterisk/app.h"
#include "asterisk/test.h"
#include "asterisk/cli.h"
#include <dlfcn.h>
#include "asterisk/md5.h"
#include "asterisk/utils.h"

Go to the source code of this file.

Data Structures

struct  ast_module
 
struct  ast_module_user
 
struct  load_order
 
struct  load_order_entry
 
struct  load_results_map
 
struct  load_retries
 
struct  loadupdate
 
struct  module_list
 
struct  module_load_word
 
struct  module_user_list
 
struct  module_vector
 
struct  reload_queue
 
struct  reload_queue_item
 
struct  updaters
 

Macros

#define AST_MODULE_LOAD_UNKNOWN_STRING   "Unknown" /* Status string for unknown load status */
 
#define key_matches(a, b)   (memcmp((a), (b), 16) == 0)
 
#define RTLD_LOCAL   0
 
#define RTLD_NOW   0
 
#define STR_APPEND_TEXT(txt, str)
 

Functions

struct ast_module__ast_module_ref (struct ast_module *mod, const char *file, int line, const char *func)
 
struct ast_module__ast_module_running_ref (struct ast_module *mod, const char *file, int line, const char *func)
 
void __ast_module_shutdown_ref (struct ast_module *mod, const char *file, int line, const char *func)
 
void __ast_module_unref (struct ast_module *mod, const char *file, int line, const char *func)
 
struct ast_module_user__ast_module_user_add (struct ast_module *mod, struct ast_channel *chan)
 
void __ast_module_user_hangup_all (struct ast_module *mod)
 
void __ast_module_user_remove (struct ast_module *mod, struct ast_module_user *u)
 
static struct load_order_entryadd_to_load_order (const char *resource, struct load_order *load_order, int required, int preload, int builtin)
 
static int alpha_module_list_create (struct module_vector *alpha_module_list)
 
enum ast_module_load_result ast_load_resource (const char *resource_name)
 Load a module. More...
 
int ast_loader_register (int(*v)(void))
 Add a procedure to be run when modules have been updated. More...
 
int ast_loader_unregister (int(*v)(void))
 Remove a procedure to be run when modules are updated. More...
 
int ast_module_check (const char *name)
 Check if module exists. More...
 
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. More...
 
const char * ast_module_name (const struct ast_module *mod)
 Get the name of a module. More...
 
void ast_module_register (const struct ast_module_info *info)
 
enum ast_module_reload_result ast_module_reload (const char *name)
 Reload asterisk modules. More...
 
const char * ast_module_support_level_to_string (enum ast_module_support_level support_level)
 
void ast_module_unregister (const struct ast_module_info *info)
 
void ast_process_pending_reloads (void)
 Process reload requests received during startup. More...
 
int ast_refresh_resource (const char *resource_name, enum ast_module_unload_mode force, int recursive)
 Unload and load a module again. More...
 
int ast_unload_resource (const char *resource_name, enum ast_module_unload_mode force)
 Unload a module. More...
 
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)
 
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)
 
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. More...
 
void ast_update_use_count (void)
 Notify when usecount has been changed. More...
 
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. More...
 
static struct ast_modulefind_resource (const char *resource, int do_lock)
 
static char * get_name_from_resource (const char *resource)
 
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 modules that are dependent on it. More...
 
static unsigned int inspect_module (const struct ast_module *mod)
 
static int is_module_loaded (const char *resource_name)
 Check to see if the given resource is loaded. More...
 
static struct ast_moduleload_dlopen (const char *resource_in, const char *so_ext, const char *filename, int flags, unsigned int suppress_logging)
 
static int load_dlopen_missing (struct ast_str **list, struct ast_vector_string *deps)
 
static struct ast_moduleload_dynamic_module (const char *resource_in, unsigned int suppress_logging)
 
int load_modules (void)
 
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)
 
static int load_resource_list (struct load_order *load_order, int *mod_count)
 
static int loader_builtin_init (struct load_order *load_order)
 
static int loader_config_init (struct load_order *load_order)
 
static const char * loadresult2str (enum ast_module_load_result result)
 
static void logged_dlclose (const char *name, void *lib)
 dlclose(), with failure logging.
 
static int module_deps_missing_recursive (struct ast_module *mod, struct module_vector *missingdeps)
 Recursively find required dependencies that are not running. More...
 
static int module_deps_process_reqlist (struct ast_module *mod, struct ast_vector_string *vec, struct ast_vector_const_string *missing, int ref_enhancers, int isoptional)
 
static int module_deps_reference (struct ast_module *mod, struct ast_vector_const_string *missing)
 
static void module_destroy (struct ast_module *mod)
 
static void module_load_error (const char *fmt,...)
 
static void module_load_helper (const char *word)
 
static int module_load_helper_on_file (const char *dir_name, const char *filename, void *obj)
 
static int module_matches_helper_type (struct ast_module *mod, enum ast_module_helper_type type)
 
static int module_post_register (struct ast_module *mod)
 
static int module_reffed_deps_add (struct ast_module *mod, struct ast_module *dep, struct ast_vector_const_string *missing)
 
static int module_reffed_deps_add_dep_enhancers (struct ast_module *mod, struct ast_module *dep, struct ast_vector_const_string *missing)
 
static int module_vector_cmp (struct ast_module *a, struct ast_module *b)
 
static int module_vector_strcasecmp (struct ast_module *a, struct ast_module *b)
 
int modules_shutdown (void)
 
static int printdigest (const unsigned char *d)
 
static void publish_load_message (const char *name, enum ast_module_load_result result)
 
static void publish_load_message_type (const char *type, const char *name, const char *status)
 
static void publish_reload_message (const char *name, enum ast_module_reload_result result)
 
static void publish_unload_message (const char *name, const char *status)
 
static void queue_reload_request (const char *module)
 
static int resource_list_recursive_decline (struct module_vector *resources, struct ast_module *mod, struct ast_str **printmissing)
 
static size_t resource_name_baselen (const char *name)
 
static int resource_name_match (const char *name1, size_t baselen1, const char *name2)
 
static enum ast_module_load_result start_resource (struct ast_module *mod)
 
static enum ast_module_load_result start_resource_attempt (struct ast_module *mod, int *count)
 
static int start_resource_list (struct module_vector *resources, int *mod_count)
 
static void unload_dynamic_module (struct ast_module *mod)
 
static int verify_key (const unsigned char *key)
 

Variables

static char buildopt_sum [33] = AST_BUILDOPT_SUM
 
static struct module_list builtin_module_list
 
static int do_full_reload = 0
 
static const unsigned char expected_key []
 
static const struct load_results_map load_results []
 
static unsigned int loader_ready
 
static struct module_list module_list = { .first = NULL, .last = NULL, .lock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, {1, 0} } , }
 
static int modules_loaded
 Internal flag to indicate all modules have been initially loaded.
 
static struct reload_queue reload_queue = { .first = NULL, .last = NULL, .lock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, {1, 0} } , }
 
static ast_mutex_t reloadlock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, {1, 0} }
 
static struct ast_module *volatile resource_being_loaded
 
static struct ast_strstartup_error_builder
 
static struct ast_vector_string startup_errors
 
const char * support_level_map []
 
static struct updaters updaters = { .first = NULL, .last = NULL, .lock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, {1, 0} } , }
 

Detailed Description

Module Loader.

Author
Mark Spencer marks.nosp@m.ter@.nosp@m.digiu.nosp@m.m.co.nosp@m.m
Kevin P. Fleming kpfle.nosp@m.ming.nosp@m.@digi.nosp@m.um.c.nosp@m.om
Luigi Rizzo rizzo.nosp@m.@ici.nosp@m.r.org
  • See ModMngMnt

Definition in file loader.c.

Macro Definition Documentation

#define STR_APPEND_TEXT (   txt,
  str 
)
Value:
ast_str_append(str, 0, "%s%s", \
ast_str_strlen(*(str)) > 0 ? ", " : "", \
txt)
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
size_t ast_str_strlen(const struct ast_str *buf)
Returns the current length of the string stored within buf.
Definition: strings.h:730

Used with AST_VECTOR_CALLBACK_VOID to create a comma separated list of module names for error messages.

Definition at line 144 of file loader.c.

Function Documentation

enum ast_module_load_result ast_load_resource ( const char *  resource_name)

Load a module.

Parameters
resource_nameThe name of the module to load.

This function is run by the PBX to load the modules. It performs all loading and initialization tasks. Basically, to load a module, just give it the name of the module and it will do the rest.

Returns
See possible enum values for ast_module_load_result.

Definition at line 1978 of file loader.c.

References ast_debug, AST_DLLIST_LOCK, AST_DLLIST_UNLOCK, ast_test_suite_event_notify, ast_unload_resource(), ast_module::declined, and load_resource().

Referenced by ast_ari_asterisk_load_module(), ast_refresh_resource(), and auto_unload_resource().

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 }
ast_module_load_result
Definition: module.h:68
#define AST_DLLIST_UNLOCK(head)
Attempts to unlock a list.
Definition: dlinkedlists.h:123
unsigned int declined
Definition: loader.c:322
#define ast_debug(level,...)
Log a DEBUG message.
#define ast_test_suite_event_notify(s, f,...)
Definition: test.h:189
int ast_unload_resource(const char *resource_name, enum ast_module_unload_mode force)
Unload a module.
Definition: loader.c:1448
#define AST_DLLIST_LOCK(head)
Locks a list.
Definition: dlinkedlists.h:46
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
int ast_loader_register ( int(*)(void)  updater)

Add a procedure to be run when modules have been updated.

Parameters
updaterThe function to run when modules have been updated.

This function adds the given function to a linked list of functions to be run when the modules are updated.

Return values
0on success
-1on failure.

Definition at line 2836 of file loader.c.

References AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_UNLOCK, and ast_malloc.

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 }
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:40
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:140
#define ast_malloc(len)
A wrapper for malloc()
Definition: astmm.h:191
#define AST_LIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
Definition: linkedlists.h:711
Definition: search.h:40
int ast_loader_unregister ( int(*)(void)  updater)

Remove a procedure to be run when modules are updated.

Parameters
updaterThe updater function to unregister.

This removes the given function from the updater list.

Return values
0on success
-1on failure.

Definition at line 2851 of file loader.c.

References AST_LIST_LOCK, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, and AST_LIST_UNLOCK.

2852 {
2853  struct loadupdate *cur;
2854 
2857  if (cur->updater == v) {
2859  break;
2860  }
2861  }
2864 
2865  return cur ? 0 : -1;
2866 }
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:40
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:140
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
Definition: linkedlists.h:615
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
Definition: linkedlists.h:557
Definition: search.h:40
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
Definition: linkedlists.h:529
int ast_module_check ( const char *  name)

Check if module exists.

Check if module with the name given is loaded.

Definition at line 2823 of file loader.c.

Referenced by ast_ari_asterisk_get_module(), ast_ari_asterisk_load_module(), ast_ari_asterisk_reload_module(), ast_ari_asterisk_unload_module(), and manager_modulecheck().

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 }
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.

Parameters
lineUnused by this function, but this should be the line we are matching.
wordThe partial name to match.
posThe position the word we are completing is in.
stateThe possible match to return.
rposThe position we should be matching. This should be the same as pos.
typeThe type of action that will be performed by CLI.
Return values
Apossible completion of the partial match.
NULLif no matches were found or Asterisk is not yet fully booted.

Definition at line 1528 of file loader.c.

References AST_DLLIST_LOCK, AST_DLLIST_TRAVERSE, AST_DLLIST_UNLOCK, AST_MODULE_HELPER_LOAD, AST_OPT_FLAG_FULLY_BOOTED, and ast_strdup.

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 }
#define AST_DLLIST_UNLOCK(head)
Attempts to unlock a list.
Definition: dlinkedlists.h:123
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:241
#define AST_DLLIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: dlinkedlists.h:576
Definition: search.h:40
#define AST_DLLIST_LOCK(head)
Locks a list.
Definition: dlinkedlists.h:46
const char* ast_module_name ( const struct ast_module mod)

Get the name of a module.

Parameters
modA pointer to the module.
Returns
the name of the module
Return values
NULLif mod or mod->info is NULL

Definition at line 615 of file loader.c.

References ast_module_info::name.

Referenced by ast_register_application2(), and graceful_unload_possible().

616 {
617  if (!mod || !mod->info) {
618  return NULL;
619  }
620 
621  return mod->info->name;
622 }
const char * name
Definition: module.h:364
enum ast_module_reload_result ast_module_reload ( const char *  name)

Reload asterisk modules.

Parameters
namethe name of the module to reload

This function reloads the specified module, or if no modules are specified, it will reload all loaded modules.

Note
Modules are reloaded using their reload() functions, not unloading them and loading them again.
Return values
Theast_module_reload_result status of the module load request

Definition at line 1721 of file loader.c.

References AST_DLLIST_LOCK, AST_DLLIST_TRAVERSE, AST_DLLIST_UNLOCK, ast_lock_path(), AST_MODULE_LOAD_SUCCESS, AST_MODULE_RELOAD_ERROR, AST_MODULE_RELOAD_IN_PROGRESS, AST_MODULE_RELOAD_NOT_FOUND, AST_MODULE_RELOAD_NOT_IMPLEMENTED, AST_MODULE_RELOAD_QUEUED, AST_MODULE_RELOAD_SUCCESS, AST_MODULE_RELOAD_UNINITIALIZED, ast_sd_notify(), ast_tvnow(), ast_unlock_path(), ast_module::declined, ast_module_info::description, publish_reload_message(), ast_module_info::reload, and ast_module::running.

Referenced by action_reload(), ast_ari_asterisk_reload_module(), and ast_process_pending_reloads().

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:
1807  return res;
1808 }
const char * description
Definition: module.h:366
unsigned int running
Definition: loader.c:320
ast_module_reload_result
Possible return types for ast_module_reload.
Definition: module.h:109
#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
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:159
int ast_unlock_path(const char *path)
Unlock a path.
Definition: main/app.c:2630
enum AST_LOCK_RESULT ast_lock_path(const char *path)
Lock a filesystem path.
Definition: main/app.c:2614
const char * name
Definition: module.h:364
#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
static int modules_loaded
Internal flag to indicate all modules have been initially loaded.
Definition: loader.c:291
unsigned int declined
Definition: loader.c:322
int(* reload)(void)
Definition: module.h:360
Definition: search.h:40
#define AST_DLLIST_LOCK(head)
Locks a list.
Definition: dlinkedlists.h:46
void ast_process_pending_reloads ( void  )

Process reload requests received during startup.

This function requests that the loader execute the pending reload requests that were queued during server startup.

Note
This function will do nothing if the server has not completely started up. Once called, the reload queue is emptied, and further invocations will have no affect.

Definition at line 1566 of file loader.c.

References AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, and ast_module_reload().

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 }
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:40
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:140
enum ast_module_reload_result ast_module_reload(const char *name)
Reload asterisk modules.
Definition: loader.c:1721
static int modules_loaded
Internal flag to indicate all modules have been initially loaded.
Definition: loader.c:291
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:833
Definition: search.h:40
int ast_refresh_resource ( const char *  resource_name,
enum ast_module_unload_mode  force,
int  recursive 
)

Unload and load a module again.

Parameters
resource_nameThe name of the module to unload.
ast_module_unload_modeThe force flag. This should be set using one of the AST_FORCE flags.
recursiveAttempt to recursively unload any dependents of this module if that will allow the module to unload, and load them back again afterwards.
Return values
0on success.
1on error unloading modules.
-1on error loading modules back.

Definition at line 1407 of file loader.c.

References ast_load_resource(), ast_unload_resource(), AST_VECTOR_FREE, AST_VECTOR_GET, AST_VECTOR_INIT, AST_VECTOR_SIZE, and auto_unload_resource().

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 }
#define AST_VECTOR_FREE(vec)
Deallocates this vector.
Definition: vector.h:174
enum ast_module_load_result ast_load_resource(const char *resource_name)
Load a module.
Definition: loader.c:1978
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
Definition: vector.h:113
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
int ast_unload_resource(const char *resource_name, enum ast_module_unload_mode force)
Unload a module.
Definition: loader.c:1448
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition: vector.h:680
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:609
int ast_unload_resource ( const char *  resource_name,
enum  ast_module_unload_mode 
)

Unload a module.

Parameters
resource_nameThe name of the module to unload.
ast_module_unload_modeThe force flag. This should be set using one of the AST_FORCE flags.

This function unloads a module. It will only unload modules that are not in use (usecount not zero), unless AST_FORCE_FIRM or AST_FORCE_HARD is specified. Setting AST_FORCE_FIRM or AST_FORCE_HARD will unload the module regardless of consequences (NOT RECOMMENDED).

Return values
0on success.
-1on error.

Definition at line 1448 of file loader.c.

References auto_unload_resource().

Referenced by ast_ari_asterisk_unload_module(), ast_load_resource(), ast_refresh_resource(), and auto_unload_resource().

1449 {
1450  return auto_unload_resource(resource_name, force, 0, NULL);
1451 }
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
int ast_update_module_list_data ( int(*)(const char *module, const char *description, int usecnt, const char *status, const char *like, enum ast_module_support_level support_level, void *data)  modentry,
const char *  like,
void *  data 
)

Ask for a list of modules, descriptions, use counts and status.

Parameters
modentryA callback to an updater function
like
dataData passed into the callback for manipulation

For each of the modules loaded, modentry will be executed with the resource, description, and usecount values of each particular module.

Returns
the number of modules loaded
Since
13.5.0

Definition at line 2764 of file loader.c.

References AST_DLLIST_LOCK, AST_DLLIST_UNLOCK, AST_VECTOR_FREE, AST_VECTOR_GET, AST_VECTOR_SIZE, ast_module_info::description, ast_module::running, ast_module_info::support_level, and ast_module::usecount.

Referenced by ast_ari_asterisk_list_modules().

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 }
const char * description
Definition: module.h:366
#define AST_VECTOR_FREE(vec)
Deallocates this vector.
Definition: vector.h:174
unsigned int running
Definition: loader.c:320
#define AST_DLLIST_UNLOCK(head)
Attempts to unlock a list.
Definition: dlinkedlists.h:123
int usecount
Definition: loader.c:300
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition: vector.h:680
enum ast_module_support_level support_level
Definition: module.h:430
#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
void ast_update_use_count ( void  )

Notify when usecount has been changed.

This function calculates use counts and notifies anyone trying to keep track of them. It should be called whenever your module's usecount changes.

Note
The ast_module_user_* functions take care of calling this function for you.

Definition at line 2698 of file loader.c.

References AST_LIST_LOCK, AST_LIST_TRAVERSE, and AST_LIST_UNLOCK.

Referenced by auto_unload_resource(), and unistim_new().

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 }
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:40
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:140
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:491
Definition: search.h:40
static int auto_unload_resource ( const char *  resource_name,
enum ast_module_unload_mode  force,
int  recursive,
struct ast_vector_const_string dependents 
)
static

Unload a resource.

Parameters
resource_nameModule name
force
recursiveWhether to attempt to recursively unload dependents of this module and load them again afterwards
dependents.Can be NULL if autounload is 0.
Return values
0on success, -1 on failure

Definition at line 1285 of file loader.c.

References ast_debug, AST_DLLIST_LOCK, AST_DLLIST_UNLOCK, AST_FORCE_FIRM, ast_load_resource(), ast_test_suite_event_notify, ast_unload_resource(), ast_update_use_count(), AST_VECTOR_GET, AST_VECTOR_SIZE, ast_module::declined, ESS, graceful_unload_possible(), ast_module::running, ast_module_info::unload, and ast_module::usecount.

Referenced by ast_refresh_resource(), and ast_unload_resource().

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 }
unsigned int running
Definition: loader.c:320
void ast_update_use_count(void)
Notify when usecount has been changed.
Definition: loader.c:2698
#define AST_DLLIST_UNLOCK(head)
Attempts to unlock a list.
Definition: dlinkedlists.h:123
int usecount
Definition: loader.c:300
enum ast_module_load_result ast_load_resource(const char *resource_name)
Load a module.
Definition: loader.c:1978
int(* unload)(void)
Definition: module.h:362
unsigned int declined
Definition: loader.c:322
#define ast_debug(level,...)
Log a DEBUG message.
#define ast_test_suite_event_notify(s, f,...)
Definition: test.h:189
int ast_unload_resource(const char *resource_name, enum ast_module_unload_mode force)
Unload a module.
Definition: loader.c:1448
#define ESS(x)
Definition: cli.h:59
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition: vector.h:680
static int graceful_unload_possible(struct ast_module *target, struct ast_vector_const_string *dependents)
Whether or not this module should be able to be unloaded successfully, if we recursively unload any m...
Definition: loader.c:1225
#define 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
static int graceful_unload_possible ( struct ast_module target,
struct ast_vector_const_string dependents 
)
static

Whether or not this module should be able to be unloaded successfully, if we recursively unload any modules that are dependent on it.

Note
module_list should be locked when calling this
Return values
0if not, 1 if likely possible

Definition at line 1225 of file loader.c.

References ast_debug, AST_DLLIST_TRAVERSE, ast_module_name(), ast_strdup, AST_VECTOR_ELEM_DEFAULT_CMP, AST_VECTOR_GET_CMP, AST_VECTOR_INSERT_AT, ast_module::reffed_deps, and ast_module::usecount.

Referenced by auto_unload_resource().

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 }
#define AST_VECTOR_ELEM_DEFAULT_CMP(elem, value)
Default comparator for AST_VECTOR_REMOVE_ELEM_UNORDERED()
Definition: vector.h:564
int usecount
Definition: loader.c:300
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:241
#define AST_DLLIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: dlinkedlists.h:576
#define ast_debug(level,...)
Log a DEBUG message.
#define AST_VECTOR_GET_CMP(vec, value, cmp)
Get an element from a vector that matches the given comparison.
Definition: vector.h:731
const char * ast_module_name(const struct ast_module *mod)
Get the name of a module.
Definition: loader.c:615
#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
Definition: search.h:40
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 module_vector reffed_deps
Vector holding pointers to modules we have a reference to.
Definition: loader.c:317
static int is_module_loaded ( const char *  resource_name)
static

Check to see if the given resource is loaded.

Parameters
resource_nameName of the resource, including .so suffix.
Returns
False (0) if module is not loaded.
True (non-zero) if module is loaded.

Definition at line 981 of file loader.c.

References ast_module::lib, and logged_dlclose().

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 }
static void logged_dlclose(const char *name, void *lib)
dlclose(), with failure logging.
Definition: loader.c:952
void * lib
Definition: loader.c:298
int load_modules ( void  )

Provided by loader.c

Definition at line 2508 of file loader.c.

References AO2_ALLOC_OPT_LOCK_NOLOCK, ao2_container_alloc_list, ast_copy_string(), ast_debug, AST_DLLIST_LOCK, AST_DLLIST_TRAVERSE, AST_DLLIST_UNLOCK, AST_LIST_HEAD_INIT_NOLOCK, AST_LIST_REMOVE_HEAD, AST_LIST_TRAVERSE, ast_str_append(), ast_str_buffer(), ast_str_create, ast_str_reset(), ast_str_strlen(), ast_tvdiff_us(), ast_tvnow(), AST_VECTOR_FREE, AST_VECTOR_GET, AST_VECTOR_INIT, AST_VECTOR_SIZE, ast_xml_find_element(), ast_xml_get_text(), ast_xml_node_get_children(), ast_xml_xpath_get_first_result(), ast_xml_xpath_results_free(), ast_xmldoc_query(), ast_module::declined, load_resource_list(), ast_module::running, startup_errors, and ast_module_info::support_level.

2509 {
2510  struct load_order_entry *order;
2511  unsigned int load_count;
2512  struct load_order load_order;
2513  int res = 0;
2514  int modulecount = 0;
2515  int i;
2516  struct ast_module *cur;
2517 #ifdef AST_XML_DOCS
2518  struct ast_str *warning_msg;
2519  char deprecated_in[33];
2520  char removed_in[33];
2521  char replacement[129];
2522 #endif
2523  struct timeval start_time = ast_tvnow();
2524  struct timeval end_time;
2525  int64_t usElapsed;
2526 
2527  ast_verb(1, "Asterisk Dynamic Loader Starting:\n");
2528 
2529 #if defined(HAVE_PERMANENT_DLOPEN)
2531  info_list_obj_cmp_fn); /* must not be cleaned at shutdown */
2532  if (!info_list) {
2533  fprintf(stderr, "Module info list allocation failure.\n");
2534  return 1;
2535  }
2536 #endif
2537 
2540 
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;
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 }
#define AST_VECTOR_FREE(vec)
Deallocates this vector.
Definition: vector.h:174
unsigned int running
Definition: loader.c:320
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:761
#define AST_DLLIST_UNLOCK(head)
Attempts to unlock a list.
Definition: dlinkedlists.h:123
#define ao2_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn)
Allocate and initialize a list container.
Definition: astobj2.h:1327
Definition: loader.c:2002
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
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:159
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
Definition: vector.h:113
#define AST_DLLIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: dlinkedlists.h:576
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_debug(level,...)
Log a DEBUG message.
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:833
static int load_resource_list(struct load_order *load_order, int *mod_count)
Definition: loader.c:2271
Support for dynamic strings.
Definition: strings.h:623
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:491
void ast_xml_xpath_results_free(struct ast_xml_xpath_results *results)
Free the XPath results.
Definition: xml.c:425
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
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
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
const char * ast_xml_get_text(struct ast_xml_node *node)
Get an element content string.
Definition: xml.c:353
Definition: search.h:40
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
static struct ast_vector_string startup_errors
Definition: loader.c:153
enum ast_module_support_level support_level
Definition: module.h:430
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
#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
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
Definition: strings.h:659
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 
)
static

loads a resource based upon resource_name. If global_symbols_only is set only modules with global symbols will be loaded.

If the module_vector is provided (not NULL) the module is found and added to the vector without running the module's load() function. By doing this, modules can be initialized later in order by priority and dependencies.

If the module_vector is not provided, the module's load function will be executed immediately

Definition at line 1922 of file loader.c.

References AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_SUCCESS, ast_shutdown_final(), AST_VECTOR_ADD_SORTED, ast_module::declined, ast_module::preload, ast_module::required, and ast_module::running.

Referenced by ast_load_resource(), and load_resource_list().

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 }
ast_module_load_result
Definition: module.h:68
#define AST_VECTOR_ADD_SORTED(vec, elem, cmp)
Add an element into a sorted vector.
Definition: vector.h:371
unsigned int running
Definition: loader.c:320
unsigned int required
Definition: loader.c:328
unsigned int preload
Definition: loader.c:330
unsigned int declined
Definition: loader.c:322
int ast_shutdown_final(void)
Definition: asterisk.c:1871
Module could not be loaded properly.
Definition: module.h:102
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
static int load_resource_list ( struct load_order load_order,
int *  mod_count 
)
static

loads modules in order by load_pri, updates mod_count

Returns
-1 on failure to load module, -2 on failure to load required module, otherwise 0

Definition at line 2271 of file loader.c.

References ast_debug, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_SUCCESS, AST_VECTOR_FREE, AST_VECTOR_INIT, and load_resource().

Referenced by load_modules().

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 }
#define AST_VECTOR_FREE(vec)
Deallocates this vector.
Definition: vector.h:174
ast_module_load_result
Definition: module.h:68
Definition: loader.c:2002
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
Definition: linkedlists.h:615
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
Definition: vector.h:113
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
Definition: linkedlists.h:557
#define ast_debug(level,...)
Log a DEBUG message.
Module could not be loaded properly.
Definition: module.h:102
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
Definition: search.h:40
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
Definition: linkedlists.h:529
static enum ast_module_load_result load_resource(const char *resource_name, unsigned int suppress_logging, struct module_vector *module_priorities, int required, int preload)
Definition: loader.c:1922
static int module_deps_missing_recursive ( struct ast_module mod,
struct module_vector missingdeps 
)
static

Recursively find required dependencies that are not running.

Parameters
modModule to scan for dependencies.
missingdepsVector listing modules that must be started first.
Return values
0All dependencies resolved.
-1Failed to resolve some dependencies.

An error from this function usually means a required module is not even loaded. This function is safe from infinite recursion, but dependency loops are not reported as an error from here. On success missingdeps will contain a list of every module that needs to be running before this module can start. missingdeps is sorted by load priority so any missing dependencies can be started if needed.

Definition at line 566 of file loader.c.

References AST_VECTOR_ADD_SORTED, AST_VECTOR_ELEM_DEFAULT_CMP, AST_VECTOR_FREE, AST_VECTOR_GET, AST_VECTOR_GET_CMP, AST_VECTOR_INIT, AST_VECTOR_REMOVE, and AST_VECTOR_SIZE.

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 }
#define AST_VECTOR_FREE(vec)
Deallocates this vector.
Definition: vector.h:174
#define AST_VECTOR_ADD_SORTED(vec, elem, cmp)
Add an element into a sorted vector.
Definition: vector.h:371
#define AST_VECTOR_ELEM_DEFAULT_CMP(elem, value)
Default comparator for AST_VECTOR_REMOVE_ELEM_UNORDERED()
Definition: vector.h:564
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_VECTOR_INIT(vec, size)
Initialize a vector.
Definition: vector.h:113
#define AST_VECTOR_GET_CMP(vec, value, cmp)
Get an element from a vector that matches the given comparison.
Definition: vector.h:731
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition: vector.h:680
#define AST_VECTOR_REMOVE(vec, idx, preserve_ordered)
Remove an element from a vector by index.
Definition: vector.h:412
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:609
int modules_shutdown ( void  )

Provided by loader.c

Note
Some resources, like timers, are started up dynamically, and thus may be still in use, even if all channels are dead. We must therefore check the usecount before asking modules to unload.

Definition at line 1172 of file loader.c.

References ast_debug, AST_DLLIST_EMPTY, AST_DLLIST_LOCK, AST_DLLIST_REMOVE_CURRENT, AST_DLLIST_TRAVERSE, AST_DLLIST_TRAVERSE_BACKWARDS_SAFE_BEGIN, AST_DLLIST_TRAVERSE_BACKWARDS_SAFE_END, AST_DLLIST_UNLOCK, ast_module_unref, ast_module::declined, ast_module::keepuntilshutdown, ast_module::running, ast_module_info::unload, and ast_module::usecount.

Referenced by really_quit().

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 }
unsigned int running
Definition: loader.c:320
#define AST_DLLIST_UNLOCK(head)
Attempts to unlock a list.
Definition: dlinkedlists.h:123
#define AST_DLLIST_TRAVERSE_BACKWARDS_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
Definition: dlinkedlists.h:888
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 AST_DLLIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: dlinkedlists.h:576
int(* unload)(void)
Definition: module.h:362
unsigned int declined
Definition: loader.c:322
#define ast_debug(level,...)
Log a DEBUG message.
#define AST_DLLIST_EMPTY(head)
Checks whether the specified list contains any entries.
Definition: dlinkedlists.h:469
#define ast_module_unref(mod)
Release a reference to the module.
Definition: module.h:483
#define AST_DLLIST_TRAVERSE_BACKWARDS_SAFE_END
Closes a safe loop traversal block.
Definition: dlinkedlists.h:921
unsigned int keepuntilshutdown
Definition: loader.c:324
Definition: search.h:40
#define AST_DLLIST_LOCK(head)
Locks a list.
Definition: dlinkedlists.h:46
static void publish_load_message_type ( const char *  type,
const char *  name,
const char *  status 
)
static
Since
12

Definition at line 1634 of file loader.c.

References ast_json_pack(), ast_json_payload_create(), ast_json_ref(), ast_json_unref(), ast_manager_get_generic_type(), ast_manager_get_topic(), RAII_VAR, stasis_message_create(), and stasis_publish().

Referenced by publish_reload_message().

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 }
struct ast_json * ast_json_ref(struct ast_json *value)
Increase refcount on value.
Definition: json.c:67
struct ast_json * ast_json_pack(char const *format,...)
Helper for creating complex JSON values.
Definition: json.c:612
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
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
Definition: json.c:73
struct stasis_message_type * ast_manager_get_generic_type(void)
Get the stasis_message_type for generic messages.
struct stasis_message * stasis_message_create(struct stasis_message_type *type, void *data)
Create a new message.
void stasis_publish(struct stasis_topic *topic, struct stasis_message *message)
Publish a message to a topic's subscribers.
Definition: stasis.c:1511
struct stasis_topic * ast_manager_get_topic(void)
Get the Stasis Message Bus API topic for AMI.
Definition: manager.c:1880
Abstract JSON element (object, array, string, int, ...).
#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
static void publish_reload_message ( const char *  name,
enum ast_module_reload_result  result 
)
static
Since
12

Definition at line 1713 of file loader.c.

References publish_load_message_type(), and S_OR.

Referenced by ast_module_reload().

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 }
static void publish_load_message_type(const char *type, const char *name, const char *status)
Definition: loader.c:1634
#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

Variable Documentation

const unsigned char expected_key[]
static
Initial value:
=
{ 0x87, 0x76, 0x79, 0x35, 0x23, 0xea, 0x3a, 0xd3,
0x25, 0x2a, 0xbb, 0x35, 0x87, 0xe4, 0x22, 0x24 }

Definition at line 134 of file loader.c.

struct ast_vector_string startup_errors
static

String container for deferring output of startup errors.

Definition at line 153 of file loader.c.

Referenced by load_modules().