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 };
138 static char buildopt_sum[33] = AST_BUILDOPT_SUM;
144 #define STR_APPEND_TEXT(txt, str) \
145 ast_str_append(str, 0, "%s%s", \
146 ast_str_strlen(*(str)) > 0 ? ", " : "", \
150 static unsigned int loader_ready;
154 static struct ast_str *startup_error_builder;
156 #if defined(HAVE_PERMANENT_DLOPEN) || defined(AST_XML_DOCS)
157 static char *get_name_from_resource(
const char *resource)
160 const char *last_three;
167 len = strlen(resource);
169 last_three = &resource[len-3];
170 if (!strcasecmp(last_three,
".so")) {
194 #if defined(HAVE_PERMANENT_DLOPEN)
195 #define FIRST_DLOPEN 999
199 struct info_list_obj {
205 static struct info_list_obj *info_list_obj_alloc(
const char *name,
208 struct info_list_obj *new_entry;
210 new_entry = ao2_alloc(
sizeof(*new_entry) + strlen(name) + 1, NULL);
216 strcpy(new_entry->name, name);
217 new_entry->info = info;
218 new_entry->dlopened = FIRST_DLOPEN;
225 static
void manual_mod_reg(const
void *lib, const
char *resource)
227 struct info_list_obj *obj_tmp;
231 mod_name = get_name_from_resource(resource);
235 if (obj_tmp->dlopened == FIRST_DLOPEN) {
236 obj_tmp->dlopened = 1;
238 ast_module_register(obj_tmp->info);
247 static void manual_mod_unreg(
const char *resource)
249 struct info_list_obj *obj_tmp;
257 mod_name = get_name_from_resource(resource);
261 ast_module_unregister(obj_tmp->info);
269 static __attribute__((format(printf, 1, 2))) void module_load_error(const
char *fmt, ...)
275 if (startup_error_builder) {
283 ast_log_ap(LOG_ERROR, fmt, ap);
347 { AST_MODULE_LOAD_SKIP,
"Skip" },
348 { AST_MODULE_LOAD_PRIORITY,
"Priority" },
351 #define AST_MODULE_LOAD_UNKNOWN_STRING "Unknown"
356 static void publish_unload_message(
const char *name,
const char* status);
368 return strcasecmp(a->resource, b->resource);
375 int a_pri = ast_test_flag(a->info, AST_MODFLAG_LOAD_ORDER)
377 int b_pri = ast_test_flag(b->info, AST_MODFLAG_LOAD_ORDER)
393 return a_pri - b_pri;
396 static struct ast_module *find_resource(
const char *resource,
int do_lock);
448 static int module_reffed_deps_add_dep_enhancers(
struct ast_module *mod,
464 if (module_reffed_deps_add(mod, cur, missing)) {
485 static int module_deps_process_reqlist(
struct ast_module *mod,
487 int ref_enhancers,
int isoptional)
493 struct ast_module *dep = find_resource(depname, 0);
495 if (!dep || !dep->flags.
running) {
496 if (isoptional && !dep) {
507 if (module_reffed_deps_add(mod, dep, missing)) {
511 if (ref_enhancers && module_reffed_deps_add_dep_enhancers(mod, dep, missing)) {
539 res |= module_deps_process_reqlist(mod, &mod->
enhances, missing, 0, 0);
542 res |= module_deps_process_reqlist(mod, &mod->
requires, missing, 1, 0);
545 res |= module_deps_process_reqlist(mod, &mod->
optional_modules, missing, 1, 1);
580 if (module_deps_reference(mod, &localdeps)) {
617 if (!mod || !mod->info) {
621 return mod->info->
name;
625 int (*updater)(void);
631 AST_MUTEX_DEFINE_STATIC(reloadlock);
638 static int do_full_reload = 0;
650 static struct ast_module *
volatile resource_being_loaded;
664 mod = ast_std_calloc(1,
sizeof(*mod) + strlen(info->
name) + 1);
668 fprintf(stderr,
"Allocation failure during startup.\n");
671 strcpy(mod->resource, info->
name);
687 mod = resource_being_loaded;
696 resource_being_loaded = NULL;
699 if (ast_opt_ref_debug) {
714 #if defined(HAVE_PERMANENT_DLOPEN)
716 struct info_list_obj *obj_tmp = ao2_find(info_list, info->
name,
720 obj_tmp = info_list_obj_alloc(info->
name, info);
732 static int module_post_register(
struct ast_module *mod)
744 static void module_destroy(
struct ast_module *mod)
778 if (mod->info == info) {
853 void __ast_module_user_hangup_all(
struct ast_module *mod)
875 static int printdigest(
const unsigned char *d)
880 for (pos = 0, x = 0; x < 16; x++)
881 pos += sprintf(buf + pos,
" %02hhx", *d++);
883 ast_debug(1,
"Unexpected signature:%s\n", buf);
888 #define key_matches(a, b) (memcmp((a), (b), 16) == 0)
890 static int verify_key(
const unsigned char *key)
893 unsigned char digest[16];
896 MD5Update(&c, key, strlen((
char *)key));
897 MD5Final(digest, &c);
899 if (key_matches(expected_key, digest))
907 static size_t resource_name_baselen(
const char *name)
909 size_t len = strlen(name);
911 if (len > 3 && !strcasecmp(name + len - 3,
".so")) {
918 static int resource_name_match(
const char *name1,
size_t baselen1,
const char *name2)
920 if (baselen1 != resource_name_baselen(name2)) {
924 return strncasecmp(name1, name2, baselen1);
927 static struct ast_module *find_resource(
const char *resource,
int do_lock)
930 size_t resource_baselen = resource_name_baselen(resource);
937 if (!resource_name_match(resource, resource_baselen, cur->resource)) {
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)
968 manual_mod_unreg(name);
973 #if defined(HAVE_RTLD_NOLOAD)
983 char fn[PATH_MAX] =
"";
986 snprintf(fn,
sizeof(fn),
"%s/%s", ast_config_AST_MODULE_DIR,
989 lib = dlopen(fn, RTLD_LAZY | RTLD_NOLOAD);
1000 static void unload_dynamic_module(
struct ast_module *mod)
1002 #if defined(HAVE_RTLD_NOLOAD)
1005 void *lib = mod->
lib;
1023 #if defined(HAVE_RTLD_NOLOAD)
1025 ast_log(LOG_WARNING,
"Module '%s' could not be completely unloaded\n", name);
1037 if (!find_resource(dep, 0)) {
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)
1065 ast_assert(!resource_being_loaded);
1067 mod =
ast_calloc(1,
sizeof(*mod) + strlen(resource_in) + strlen(so_ext) + 1);
1072 sprintf(mod->resource,
"%s%s", resource_in, so_ext);
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);
1079 if (resource_being_loaded) {
1084 resource_being_loaded = NULL;
1086 module_load_error(
"Module '%s' did not register itself during load\n", resource_in);
1092 if (suppress_logging) {
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);
1101 if (resource_being_loaded) {
1102 resource_being_loaded = NULL;
1104 module_load_error(
"Error loading module '%s': %s\n", resource_in, dlerror_msg);
1112 if (module_post_register(mod)) {
1116 c = load_dlopen_missing(&list, &mod->
requires);
1117 c += load_dlopen_missing(&list, &mod->
enhances);
1118 #ifndef OPTIONAL_API
1124 module_load_error(
"Error loading module '%s', missing %s: %s\n",
1125 resource_in, c == 1 ?
"dependency" :
"dependencies",
ast_str_buffer(list));
1127 module_load_error(
"Error loading module '%s': %s\n", resource_in, dlerror_msg);
1132 unload_dynamic_module(mod);
1145 static struct ast_module *load_dynamic_module(
const char *resource_in,
unsigned int suppress_logging)
1149 size_t resource_in_len = strlen(resource_in);
1150 const char *so_ext =
"";
1152 if (resource_in_len < 4 || strcasecmp(resource_in + resource_in_len - 3,
".so")) {
1156 snprintf(fn,
sizeof(fn),
"%s/%s%s", ast_config_AST_MODULE_DIR, resource_in, so_ext);
1160 mod = load_dlopen(resource_in, so_ext, fn, RTLD_NOW | RTLD_LOCAL, suppress_logging);
1162 if (!mod || !ast_test_flag(mod->info, AST_MODFLAG_GLOBAL_SYMBOLS)) {
1169 return load_dlopen(resource_in, so_ext, fn, RTLD_NOW | RTLD_GLOBAL, 0);
1175 int somethingchanged;
1185 somethingchanged = 0;
1189 ast_debug(1,
"Passing on %s: its use count is %d\n",
1195 ast_verb(4,
"Unloading %s\n", mod->resource);
1198 module_destroy(mod);
1199 somethingchanged = 1;
1202 if (!somethingchanged) {
1207 somethingchanged = 1;
1211 }
while (somethingchanged);
1261 ast_log(LOG_ERROR,
"Failed to add module '%s' to vector\n",
ast_module_name(mod));
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);
1293 if (!(mod = find_resource(resource_name, 0))) {
1295 ast_log(LOG_WARNING,
"Unload failed, '%s' could not be found\n", resource_name);
1307 ast_log(LOG_NOTICE,
"Unloading module '%s' that previously declined to load\n", resource_name);
1313 if (!error && mod->
usecount > 0 && recursive) {
1339 ast_log(LOG_WARNING,
"Failed to unload %lu module%s automatically (%s could not be unloaded)\n", num_deps,
ESS(num_deps), depname);
1342 for (i++; i < num_deps; i++) {
1346 ast_log(LOG_WARNING,
"Could not load module '%s' again automatically\n", depname);
1357 if (!error && (mod->
usecount > 0)) {
1359 ast_log(LOG_WARNING,
"Warning: Forcing removal of module '%s' with use count %d\n", resource_name, mod->
usecount);
1361 ast_log(LOG_WARNING,
"%s unload failed, '%s' has use count %d\n", recursive ?
"Recursive soft" :
"Soft", resource_name, mod->
usecount);
1368 __ast_module_user_hangup_all(mod);
1370 ast_verb(4,
"Unloading %s\n", mod->resource);
1371 res = mod->info->
unload();
1373 ast_log(LOG_WARNING,
"Firm unload failed for %s\n", resource_name);
1377 ast_log(LOG_WARNING,
"** Dangerous **: Unloading resource anyway, at user request\n");
1386 __ast_module_user_hangup_all(mod);
1398 unload_dynamic_module(mod);
1401 publish_unload_message(resource_name,
"Success");
1421 ast_log(LOG_WARNING,
"Failed to load module '%s' again automatically\n", resource_name);
1433 ast_log(LOG_WARNING,
"Could not load module '%s' again automatically\n", depname);
1438 return res ? -1 : 0;
1483 static int module_load_helper_on_file(
const char *dir_name,
const char *filename,
void *obj)
1487 char *filename_merged = NULL;
1490 dir_name += word->moddir_len;
1491 if (!ast_strlen_zero(dir_name)) {
1492 ast_assert(dir_name[0] ==
'/');
1495 if (
ast_asprintf(&filename_merged,
"%s/%s", dir_name, filename) < 0) {
1499 filename = filename_merged;
1502 if (!strncasecmp(filename, word->word, word->len)) {
1504 mod = find_resource(filename, 0);
1505 if (!mod || !mod->flags.
running) {
1510 ast_free(filename_merged);
1515 static void module_load_helper(
const char *word)
1519 .len = strlen(word),
1520 .moddir_len = strlen(ast_config_AST_MODULE_DIR),
1524 ast_file_read_dirs(ast_config_AST_MODULE_DIR, module_load_helper_on_file, &word_l, -1);
1532 int wordlen = strlen(word);
1545 module_load_helper(word);
1552 if (!module_matches_helper_type(mod, type)) {
1556 if (!strncasecmp(word, mod->resource, wordlen) && ++which > state) {
1574 if (do_full_reload) {
1577 ast_log(LOG_NOTICE,
"Executing deferred reload request.\n");
1583 ast_log(LOG_NOTICE,
"Executing deferred reload request for module '%s'.\n", item->module);
1591 static void queue_reload_request(
const char *module)
1597 if (do_full_reload) {
1602 if (ast_strlen_zero(module)) {
1612 if (!strcasecmp(item->module, module)) {
1617 item =
ast_calloc(1,
sizeof(*item) + strlen(module) + 1);
1619 ast_log(LOG_ERROR,
"Failed to allocate reload queue item.\n");
1623 strcpy(item->module, module);
1641 ast_assert(type != NULL);
1642 ast_assert(!ast_strlen_zero(name));
1643 ast_assert(!ast_strlen_zero(status));
1654 "class_type", EVENT_FLAG_SYSTEM,
1676 for (i = 0; i < ARRAY_LEN(load_results); i++) {
1677 if (load_results[i].result == result) {
1678 return load_results[i].name;
1682 ast_log(LOG_WARNING,
"Failed to find correct load result status. result %d\n", result);
1683 return AST_MODULE_LOAD_UNKNOWN_STRING;
1694 status = loadresult2str(result);
1703 static void publish_unload_message(
const char *name,
const char* status)
1717 snprintf(res_buffer,
sizeof(res_buffer),
"%u", result);
1725 size_t name_baselen = name ? resource_name_baselen(name) : 0;
1729 if (!modules_loaded) {
1730 queue_reload_request(name);
1732 goto module_reload_exit;
1735 if (ast_mutex_trylock(&reloadlock)) {
1736 ast_verb(3,
"The previous reload command didn't finish yet\n");
1738 goto module_reload_exit;
1743 if (ast_opt_lock_confdir) {
1746 for (
try = 1, lockres = AST_LOCK_TIMEOUT;
try < 6 && (lockres == AST_LOCK_TIMEOUT);
try++) {
1748 if (lockres == AST_LOCK_TIMEOUT) {
1749 ast_log(LOG_WARNING,
"Failed to grab lock on %s, try %d\n", ast_config_AST_CONFIG_DIR,
try);
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;
1763 if (name && resource_name_match(name, name_baselen, cur->resource)) {
1786 ast_verb(3,
"Reloading module '%s' (%s)\n", cur->resource, info->
description);
1798 if (ast_opt_lock_confdir) {
1802 ast_mutex_unlock(&reloadlock);
1810 static unsigned int inspect_module(
const struct ast_module *mod)
1813 module_load_error(
"Module '%s' does not provide a description.\n", mod->resource);
1817 if (!mod->info->
key) {
1818 module_load_error(
"Module '%s' does not provide a license key.\n", mod->resource);
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);
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);
1846 if (!mod->info->
load) {
1852 if (module_deps_reference(mod, NULL)) {
1858 module_load_error(
"%s has one or more unknown dependencies.\n", mod->info->
name);
1861 module_load_error(
"%s loaded before dependency %s!\n", mod->info->
name,
1869 if (!ast_fully_booted) {
1870 ast_verb(4,
"Loading %s.\n", mod->resource);
1872 res = mod->info->
load();
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)));
1879 ast_verb(4,
"Loaded %s => (%s)\n", mod->resource, mod->info->
description);
1899 case AST_MODULE_LOAD_SKIP:
1900 case AST_MODULE_LOAD_PRIORITY:
1928 if ((mod = find_resource(resource_name, 0))) {
1930 ast_log(LOG_WARNING,
"Module '%s' already loaded and running.\n", resource_name);
1934 mod = load_dynamic_module(resource_name, suppress_logging);
1939 if (module_post_register(mod)) {
1940 goto prestart_error;
1947 if (inspect_module(mod)) {
1948 goto prestart_error;
1953 if (module_priorities) {
1955 goto prestart_error;
1957 res = AST_MODULE_LOAD_PRIORITY;
1959 res = start_resource(mod);
1963 publish_load_message(resource_name, res);
1969 module_load_error(
"Module '%s' could not be loaded.\n", resource_name);
1970 unload_dynamic_module(mod);
1973 publish_load_message(resource_name, res);
1986 mod = find_resource(resource_name, 0);
1988 ast_debug(1,
"Module %s previously declined to load, unloading it first before loading again\n", resource_name);
2015 size_t resource_baselen = resource_name_baselen(resource);
2018 if (!resource_name_match(resource, resource_baselen, order->resource)) {
2033 if (!order->resource) {
2053 if (module_deps_reference(mod, NULL)) {
2055 ast_debug(1,
"Module %s is missing dependencies\n", mod->resource);
2056 return AST_MODULE_LOAD_SKIP;
2059 lres = start_resource(mod);
2068 module_load_error(
"*** Failed to load %smodule %s\n",
2069 mod->flags.
required ?
"required " :
"",
2077 struct ast_str **printmissing)
2086 module_load_error(
"Required module %s declined to load.\n",
ast_module_name(mod));
2093 if (!*printmissing) {
2095 if (!*printmissing) {
2119 module_load_error(
"Cannot load required module %s that depends on %s\n",
2131 module_load_error(
"Declined modules which depend on %s: %s\n",
2139 static int start_resource_list(
struct module_vector *resources,
int *mod_count)
2143 struct ast_str *printmissing = NULL;
2156 lres = start_resource_attempt(mod, mod_count);
2168 res = resource_list_recursive_decline(resources, mod, &printmissing);
2174 module_load_error(
"Failed to resolve dependencies for %s\n",
ast_module_name(mod));
2175 res = resource_list_recursive_decline(resources, mod, &printmissing);
2180 module_load_error(
"%s load function returned an invalid result. "
2184 res = resource_list_recursive_decline(resources, mod, &printmissing);
2188 ast_debug(1,
"%s has %d dependencies\n",
2198 ast_debug(1,
"%s tried to start %s but it's already declined\n",
2205 lres = start_resource_attempt(dep, mod_count);
2231 if (!printmissing) {
2241 module_deps_reference(mod, &localdeps);
2246 module_load_error(
"Failed to load %s due to dependencies: %s.\n",
2248 printmissing ?
ast_str_buffer(printmissing) :
"allocation failure creating list");
2249 res = resource_list_recursive_decline(resources, mod, &printmissing);
2262 ast_free(printmissing);
2282 ast_log(LOG_ERROR,
"Failed to initialize module loader.\n");
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);
2298 case AST_MODULE_LOAD_SKIP:
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);
2315 case AST_MODULE_LOAD_PRIORITY:
2318 ast_free(order->resource);
2338 res = start_resource_list(&module_priorities, &count);
2342 *mod_count += count;
2349 static int loader_builtin_init(
struct load_order *load_order)
2361 ast_module_register(resource_being_loaded->info);
2371 if (module_post_register(mod)) {
2376 if (!add_to_load_order(mod->resource, load_order, 0, 0, 1)) {
2384 static int loader_config_init(
struct load_order *load_order)
2393 if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEINVALID) {
2400 for (v = ast_variable_browse(cfg,
"modules"); v; v = v->
next) {
2404 if (!strncasecmp(v->
name,
"preload", strlen(
"preload"))) {
2406 if (!strcasecmp(v->
name,
"preload")) {
2408 }
else if (!strcasecmp(v->
name,
"preload-require")) {
2411 ast_log(LOG_ERROR,
"Unknown configuration option '%s'", v->
name);
2414 }
else if (!strcasecmp(v->
name,
"load")) {
2416 }
else if (!strcasecmp(v->
name,
"require")) {
2418 }
else if (!strcasecmp(v->
name,
"noload") || !strcasecmp(v->
name,
"autoload")) {
2421 ast_log(LOG_ERROR,
"Unknown configuration option '%s'", v->
name);
2429 if (!add_to_load_order(v->
value, load_order, required, preload, 0)) {
2435 if (
ast_true(ast_variable_retrieve(cfg,
"modules",
"autoload"))) {
2438 DIR *dir = opendir(ast_config_AST_MODULE_DIR);
2439 struct dirent *dirent;
2442 while ((dirent = readdir(dir))) {
2443 int ld = strlen(dirent->d_name);
2450 if (strcasecmp(dirent->d_name + ld - 3,
".so"))
2455 if (find_resource(dirent->d_name, 0))
2458 if (!add_to_load_order(dirent->d_name, load_order, 0, 0, 0)) {
2466 ast_log(LOG_ERROR,
"Unable to open modules directory '%s'.\n", ast_config_AST_MODULE_DIR);
2473 for (v = ast_variable_browse(cfg,
"modules"); v; v = v->
next) {
2476 if (strcasecmp(v->
name,
"noload")) {
2480 baselen = resource_name_baselen(v->
value);
2482 if (!resource_name_match(v->
value, baselen, order->resource)) {
2483 if (order->builtin) {
2484 ast_log(LOG_ERROR,
"%s is a built-in module, you cannot specify 'noload'.\n", v->
value);
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");
2494 ast_free(order->resource);
2511 unsigned int load_count;
2512 struct load_order load_order;
2514 int modulecount = 0;
2519 char deprecated_in[33];
2520 char removed_in[33];
2521 char replacement[129];
2523 struct timeval start_time =
ast_tvnow();
2524 struct timeval end_time;
2527 ast_verb(1,
"Asterisk Dynamic Loader Starting:\n");
2529 #if defined(HAVE_PERMANENT_DLOPEN)
2531 info_list_obj_cmp_fn);
2533 fprintf(stderr,
"Module info list allocation failure.\n");
2544 res = loader_builtin_init(&load_order);
2549 res = loader_config_init(&load_order);
2559 ast_log(LOG_NOTICE,
"%u modules will be loaded.\n", load_count);
2563 ast_log(LOG_WARNING,
"Some non-required modules failed to load.\n");
2569 ast_free(order->resource);
2579 char *mod_name = NULL;
2580 struct ast_xml_xpath_results *results;
2588 mod_name = get_name_from_resource(cur->resource);
2589 if (!warning_msg || !mod_name) {
2596 deprecated_in[0] = removed_in[0] = replacement[0] = 0;
2600 struct ast_xml_node *deprecated_node, *removed_node, *replacement_node;
2604 if (deprecated_node) {
2606 if (!ast_strlen_zero(result_tmp)) {
2614 if (!ast_strlen_zero(result_tmp)) {
2620 if (replacement_node) {
2622 if (!ast_strlen_zero(result_tmp)) {
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;
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);
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);
2646 ast_str_append(&warning_msg, -1,
" %s may be removed in a future release", already_butted ?
"and" :
"but");
2651 if (!ast_strlen_zero(replacement)) {
2652 ast_str_append(&warning_msg, -1,
" Its replacement is '%s'.", replacement);
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);
2669 ast_free(warning_msg);
2678 ast_log(LOG_ERROR,
"%s", str);
2683 ast_free(startup_error_builder);
2684 startup_error_builder = NULL;
2690 ast_debug(1,
"Loader time with AST_XML_DOCS: %" PRId64
".%06" PRId64
"\n", usElapsed / 1000000, usElapsed % 1000000);
2692 ast_debug(1,
"Loader time without AST_XML_DOCS: %" PRId64
".%06" PRId64
"\n", usElapsed / 1000000, usElapsed % 1000000);
2720 static int alpha_module_list_create(
struct module_vector *alpha_module_list)
2738 int usecnt,
const char *status,
const char *like,
2739 enum ast_module_support_level support_level),
2742 int total_mod_loaded = 0;
2747 if (!alpha_module_list_create(&alpha_module_list)) {
2761 return total_mod_loaded;
2765 int usecnt,
const char *status,
const char *like,
2766 enum ast_module_support_level support_level,
2768 const char *like,
void *data)
2770 int total_mod_loaded = 0;
2775 if (!alpha_module_list_create(&alpha_module_list)) {
2789 return total_mod_loaded;
2793 int usecnt,
const char *status,
2795 enum ast_module_support_level support_level,
2796 void *data,
const char *condition),
2797 const char *like,
void *data,
const char *condition)
2799 int conditions_met = 0;
2804 if (!alpha_module_list_create(&alpha_module_list)) {
2819 return conditions_met;
2827 if (ast_strlen_zero(name))
2830 cur = find_resource(name, 1);
2832 return (cur != NULL);
2857 if (cur->updater == v) {
2865 return cur ? 0 : -1;
2868 struct ast_module *__ast_module_ref(
struct ast_module *mod,
const char *file,
int line,
const char *func)
2875 __ao2_ref(mod->
ref_debug, +1,
"", file, line, func);
2885 const char *file,
int line,
const char *func)
2887 if (!mod || !mod->flags.
running) {
2891 return __ast_module_ref(mod, file, line, func);
2894 void __ast_module_shutdown_ref(
struct ast_module *mod,
const char *file,
int line,
const char *func)
2900 __ast_module_ref(mod, file, line, func);
2904 void __ast_module_unref(
struct ast_module *mod,
const char *file,
int line,
const char *func)
2911 __ao2_ref(mod->
ref_debug, -1,
"", file, line, func);
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",
2925 const char *ast_module_support_level_to_string(
enum ast_module_support_level support_level)
2927 return support_level_map[support_level];
static void publish_load_message_type(const char *type, const char *name, const char *status)
#define AST_VECTOR_FREE(vec)
Deallocates this vector.
struct ast_variable * next
Main Channel structure associated with a channel.
#define AST_VECTOR_ADD_SORTED(vec, elem, cmp)
Add an element into a sorted vector.
struct ast_json * ast_json_ref(struct ast_json *value)
Increase refcount on value.
struct module_user_list users
#define AST_LIST_LOCK(head)
Locks a list.
void ast_update_use_count(void)
Notify when usecount has been changed.
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.
The arg parameter is a search key, but is not an object.
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.
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
int ast_softhangup(struct ast_channel *chan, int cause)
Softly hangup up a channel.
#define AST_VECTOR_ELEM_DEFAULT_CMP(elem, value)
Default comparator for AST_VECTOR_REMOVE_ELEM_UNORDERED()
ast_module_reload_result
Possible return types for ast_module_reload.
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
#define AST_DLLIST_UNLOCK(head)
Attempts to unlock a list.
static void publish_reload_message(const char *name, enum ast_module_reload_result result)
#define ao2_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn)
Allocate and initialize a list container.
struct ast_config * ast_config_load2(const char *filename, const char *who_asked, struct ast_flags flags)
Load a config file.
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.
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.
#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.
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.
enum ast_module_reload_result ast_module_reload(const char *name)
Reload asterisk modules.
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.
struct ast_xml_xpath_results * ast_xmldoc_query(const char *fmt,...)
Execute an XPath query on the loaded XML documentation.
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().
#define AST_DLLIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
#define ao2_t_alloc_options(data_size, destructor_fn, options, debug_msg)
Allocate and initialize an object.
#define ast_strdup(str)
A wrapper for strdup()
int ast_unlock_path(const char *path)
Unlock a path.
I/O Management (derived from Cheops-NG)
#define AST_LIST_REMOVE(head, elm, field)
Removes a specific entry from a list.
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.
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
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.
int ast_atomic_fetchadd_int(volatile int *p, int v)
Atomically add v to *p and return the previous value of *p.
enum ast_module_load_result ast_load_resource(const char *resource_name)
Load a module.
A vector of strings commonly used throughout this module.
const char * enhances
Modules that we provide enhanced functionality for.
int ast_refresh_resource(const char *resource_name, enum ast_module_unload_mode force, int recursive)
Unload and load a module again.
#define ast_asprintf(ret, fmt,...)
A wrapper for asprintf()
#define AST_LIST_HEAD_DESTROY(head)
Destroys a list head structure.
#define STR_APPEND_TEXT(txt, str)
enum AST_LOCK_RESULT ast_lock_path(const char *path)
Lock a filesystem path.
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
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
const char * optional_modules
Comma-separated list of optionally required modules.
A set of macros to manage doubly-linked lists.
int ast_module_check(const char *name)
Check if module exists.
General Asterisk PBX channel definitions.
void ast_process_pending_reloads(void)
Process reload requests received during startup.
Asterisk file paths, configured in asterisk.conf.
#define AST_VECTOR_ELEM_CLEANUP_NOOP(elem)
Vector element cleanup that does nothing.
#define AST_DLLIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
int ast_sd_notify(const char *state)
a wrapper for sd_notify(): notify systemd of any state changes.
#define ast_strdupa(s)
duplicate a string in memory from the stack
static int modules_loaded
Internal flag to indicate all modules have been initially loaded.
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
struct ast_vector_string optional_modules
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.
#define ast_malloc(len)
A wrapper for malloc()
#define ast_debug(level,...)
Log a DEBUG message.
#define AST_VECTOR(name, type)
Define a vector structure.
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
#define ast_test_suite_event_notify(s, f,...)
char * term_color(char *outbuf, const char *inbuf, int fgcolor, int bgcolor, int maxout)
Colorize a specified string by adding terminal color codes.
static int load_resource_list(struct load_order *load_order, int *mod_count)
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.
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).
int ast_shutdown_final(void)
static void logged_dlclose(const char *name, void *lib)
dlclose(), with failure logging.
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
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".
Support for dynamic strings.
int ast_unload_resource(const char *resource_name, enum ast_module_unload_mode force)
Unload a module.
struct ast_vector_string requires
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.
#define ast_module_ref(mod)
Hold a reference to the module.
int modules_shutdown(void)
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
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.
#define AST_LIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
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.
void stasis_publish(struct stasis_topic *topic, struct stasis_message *message)
Publish a message to a topic's subscribers.
#define AST_LIST_HEAD_INIT(head)
Initializes a list head structure.
#define ast_calloc(num, len)
A wrapper for calloc()
#define AST_VECTOR_RESET(vec, cleanup)
Reset vector.
#define AST_DLLIST_HEAD(name, type)
Defines a structure to be used to hold a list of specified type.
Module could not be loaded properly.
int ast_loader_register(int(*v)(void))
Add a procedure to be run when modules have been updated.
#define AST_DLLIST_EMPTY(head)
Checks whether the specified list contains any entries.
Prototypes for public functions only of internal interest,.
Module has failed to load, may be in an inconsistent state.
Vector container support.
void ast_xml_xpath_results_free(struct ast_xml_xpath_results *results)
Free the XPath results.
#define AST_VECTOR_GET_CMP(vec, value, cmp)
Get an element from a vector that matches the given comparison.
Structure used to handle boolean flags.
struct stasis_topic * ast_manager_get_topic(void)
Get the Stasis Message Bus API topic for AMI.
#define AST_VECTOR_REMOVE_CMP_ORDERED(vec, value, cmp, cleanup)
Remove an element from a vector that matches the given comparison while maintaining order...
#define ast_module_unref(mod)
Release a reference to the module.
void ast_str_reset(struct ast_str *buf)
Reset the content of a dynamic string. Useful before a series of ast_str_append.
#define AST_MODULE_CONFIG
Module configuration file.
size_t ast_str_strlen(const struct ast_str *buf)
Returns the current length of the string stored within buf.
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
#define AST_LIST_HEAD_INIT_NOLOCK(head)
Initializes a list head structure.
#define AST_DLLIST_TRAVERSE_BACKWARDS_SAFE_END
Closes a safe loop traversal block.
Standard Command Line Interface.
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
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.
const char * ast_module_name(const struct ast_module *mod)
Get the name of a module.
int ast_loader_unregister(int(*v)(void))
Remove a procedure to be run when modules are updated.
const char * ast_xml_get_text(struct ast_xml_node *node)
Get an element content string.
unsigned int keepuntilshutdown
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.
#define AST_DLLIST_REMOVE(head, elm, field)
Removes a specific entry from a list.
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.
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
static struct ast_vector_string startup_errors
String vector definitions.
void ast_config_destroy(struct ast_config *cfg)
Destroys a config.
int ast_cli_completion_add(char *value)
Add a result to a request for completion options.
enum ast_module_load_result(* load)(void)
#define AST_VECTOR_REMOVE(vec, idx, preserve_ordered)
Remove an element from a vector by index.
Asterisk module definitions.
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
enum ast_module_support_level support_level
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...
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.
const char buildopt_sum[33]
#define AST_DLLIST_LOCK(head)
Locks a list.
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
struct ast_xml_node * ast_xml_node_get_children(struct ast_xml_node *node)
Get the node's children.
struct module_vector reffed_deps
Vector holding pointers to modules we have a reference to.
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)
#define AST_VECTOR_CALLBACK_VOID(vec, callback,...)
Execute a callback on every element in a vector disregarding callback return.
static int is_module_loaded(const char *resource_name)
Check to see if the given resource is loaded.
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
#define AST_DLLIST_ENTRY(type)
Declare previous/forward links inside a list entry.
#define AST_DLLIST_HEAD_STATIC(name, type)
Defines a structure to be used to hold a list of specified type, statically initialized.
#define ao2_link(container, obj)
Add an object to a container.