diff --git a/configure b/configure index d0d60f8e560d4e4723bb2a161726c4182cfe6869..2a704b544e78f517b954327ba7373f76caf08275 100755 --- a/configure +++ b/configure @@ -702,6 +702,7 @@ PBX_DYNAMIC_LIST POW_LIB PBX_WORKING_FORK LIBOBJS +PERMANENT_DLOPEN DISABLE_XMLDOC CONFIG_LIBXML2 JANSSON_LIBS @@ -1345,7 +1346,6 @@ infodir docdir oldincludedir includedir -runstatedir localstatedir sharedstatedir sysconfdir @@ -1454,6 +1454,7 @@ with_vpb with_x11 with_z enable_xmldoc +enable_permanent_dlopen enable_largefile enable_internal_poll enable_asteriskssl @@ -1533,7 +1534,6 @@ datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' -runstatedir='${localstatedir}/run' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' @@ -1786,15 +1786,6 @@ do | -silent | --silent | --silen | --sile | --sil) silent=yes ;; - -runstatedir | --runstatedir | --runstatedi | --runstated \ - | --runstate | --runstat | --runsta | --runst | --runs \ - | --run | --ru | --r) - ac_prev=runstatedir ;; - -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ - | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ - | --run=* | --ru=* | --r=*) - runstatedir=$ac_optarg ;; - -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ @@ -1932,7 +1923,7 @@ fi for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ - libdir localedir mandir runstatedir + libdir localedir mandir do eval ac_val=\$$ac_var # Remove trailing slashes. @@ -2085,7 +2076,6 @@ Fine tuning of the installation directories: --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] - --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] @@ -2124,6 +2114,9 @@ Optional Features: --enable-dev-mode Turn on developer mode --enable-coverage Turn on code coverage tracking (for gcov) --disable-xmldoc Explicitly disable XML documentation + --enable-permanent-dlopen + Enable when your libc has a permanent dlopen like + musl --disable-largefile omit support for large files --enable-internal-poll Use Asterisk's poll implementation --disable-asteriskssl Disable Asterisk's SSL wrapper library @@ -14852,6 +14845,25 @@ fi +fi + +# Check whether --enable-permanent-dlopen was given. +if test "${enable_permanent_dlopen+set}" = set; then : + enableval=$enable_permanent_dlopen; case "${enableval}" in + y|ye|yes) PERMANENT_DLOPEN=yes ;; + n|no) PERMANENT_DLOPEN=no ;; + *) as_fn_error $? "bad value ${enableval} for --enable-permanent-dlopen" "$LINENO" 5 ;; + esac +else + PERMANENT_DLOPEN=no +fi + + + +if test "${PERMANENT_DLOPEN}" == "yes"; then + +$as_echo "#define HAVE_PERMANENT_DLOPEN 1" >>confdefs.h + fi # some embedded systems omit internationalization (locale) support @@ -14918,7 +14930,7 @@ else We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -14964,7 +14976,7 @@ else We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -14988,7 +15000,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -15033,7 +15045,7 @@ else We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -15057,7 +15069,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -16357,8 +16369,6 @@ main () if (*(data + i) != *(data3 + i)) return 14; close (fd); - free (data); - free (data3); return 0; } _ACEOF diff --git a/configure.ac b/configure.ac index 1ec7765058466e7d1d884773ff726b8d1bb6606d..e65f1598030371f90c3fc7fb8f6d15a5331a4b44 100644 --- a/configure.ac +++ b/configure.ac @@ -729,6 +729,20 @@ if test "${DISABLE_XMLDOC}" != "yes"; then fi +AC_ARG_ENABLE([permanent-dlopen], + [AS_HELP_STRING([--enable-permanent-dlopen], + [Enable when your libc has a permanent dlopen like musl])], + [case "${enableval}" in + y|ye|yes) PERMANENT_DLOPEN=yes ;; + n|no) PERMANENT_DLOPEN=no ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-permanent-dlopen) ;; + esac], [PERMANENT_DLOPEN=no]) + +AC_SUBST([PERMANENT_DLOPEN]) +if test "${PERMANENT_DLOPEN}" == "yes"; then + AC_DEFINE([HAVE_PERMANENT_DLOPEN], 1, [Define to support libc with permanent dlopen.]) +fi + # some embedded systems omit internationalization (locale) support AC_CHECK_HEADERS([xlocale.h]) diff --git a/include/asterisk/autoconfig.h.in b/include/asterisk/autoconfig.h.in index 46e92dfb56adbc89410dcc34d7e42c557e76052f..71df798c1208a7e1b445fd4d8c42cb7d8e5768d8 100644 --- a/include/asterisk/autoconfig.h.in +++ b/include/asterisk/autoconfig.h.in @@ -603,6 +603,9 @@ /* Define to 1 if your system defines the file flag O_SYMLINK in fcntl.h */ #undef HAVE_O_SYMLINK +/* Define to support libc with permanent dlopen. */ +#undef HAVE_PERMANENT_DLOPEN + /* Define to indicate the PostgreSQL library */ #undef HAVE_PGSQL diff --git a/main/loader.c b/main/loader.c index 3749c9599359b75be2b3dcdbbc554db0d94765f1..b46f745af8fdcec7ca6a211b9324e1da441ec944 100644 --- a/main/loader.c +++ b/main/loader.c @@ -153,6 +153,117 @@ static unsigned int loader_ready; static struct ast_vector_string startup_errors; static struct ast_str *startup_error_builder; +#if defined(HAVE_PERMANENT_DLOPEN) +#define FIRST_DLOPEN 999 + +struct ao2_container *info_list = NULL; + +struct info_list_obj { + const struct ast_module_info *info; + int dlopened; + char name[0]; +}; + +static struct info_list_obj *info_list_obj_alloc(const char *name, + const struct ast_module_info *info) +{ + struct info_list_obj *new_entry; + + new_entry = ao2_alloc(sizeof(*new_entry) + strlen(name) + 1, NULL); + + if (!new_entry) { + return NULL; + } + + strcpy(new_entry->name, name); /* SAFE */ + new_entry->info = info; + new_entry->dlopened = FIRST_DLOPEN; + + return new_entry; +} + +AO2_STRING_FIELD_CMP_FN(info_list_obj, name) + +static char *get_name_from_resource(const char *resource) +{ + int len; + const char *last_three; + char *mod_name; + + if (!resource) { + return NULL; + } + + len = strlen(resource); + if (len > 3) { + last_three = &resource[len-3]; + if (!strcasecmp(last_three, ".so")) { + mod_name = ast_calloc(1, len - 2); + if (mod_name) { + ast_copy_string(mod_name, resource, len - 2); + return mod_name; + } else { + /* Unable to allocate memory. */ + return NULL; + } + } + } + + /* Resource is the name - happens when manually unloading a module. */ + mod_name = ast_calloc(1, len + 1); + if (mod_name) { + ast_copy_string(mod_name, resource, len + 1); + return mod_name; + } + + /* Unable to allocate memory. */ + return NULL; +} + +static void manual_mod_reg(const void *lib, const char *resource) +{ + struct info_list_obj *obj_tmp; + char *mod_name; + + if (lib) { + mod_name = get_name_from_resource(resource); + if (mod_name) { + obj_tmp = ao2_find(info_list, mod_name, OBJ_SEARCH_KEY); + if (obj_tmp) { + if (obj_tmp->dlopened == FIRST_DLOPEN) { + obj_tmp->dlopened = 1; + } else { + ast_module_register(obj_tmp->info); + } + ao2_ref(obj_tmp, -1); + } + ast_free(mod_name); + } + } +} + +static void manual_mod_unreg(const char *resource) +{ + struct info_list_obj *obj_tmp; + char *mod_name; + + /* When Asterisk shuts down the destructor is called automatically. */ + if (ast_shutdown_final()) { + return; + } + + mod_name = get_name_from_resource(resource); + if (mod_name) { + obj_tmp = ao2_find(info_list, mod_name, OBJ_SEARCH_KEY); + if (obj_tmp) { + ast_module_unregister(obj_tmp->info); + ao2_ref(obj_tmp, -1); + } + ast_free(mod_name); + } +} +#endif + static __attribute__((format(printf, 1, 2))) void module_load_error(const char *fmt, ...) { char *copy = NULL; @@ -597,6 +708,23 @@ void ast_module_register(const struct ast_module_info *info) /* give the module a copy of its own handle, for later use in registrations and the like */ *((struct ast_module **) &(info->self)) = mod; + +#if defined(HAVE_PERMANENT_DLOPEN) + if (mod->flags.builtin != 1) { + struct info_list_obj *obj_tmp = ao2_find(info_list, info->name, + OBJ_SEARCH_KEY); + + if (!obj_tmp) { + obj_tmp = info_list_obj_alloc(info->name, info); + if (obj_tmp) { + ao2_link(info_list, obj_tmp); + ao2_ref(obj_tmp, -1); + } + } else { + ao2_ref(obj_tmp, -1); + } + } +#endif } static int module_post_register(struct ast_module *mod) @@ -843,6 +971,10 @@ static void logged_dlclose(const char *name, void *lib) error = dlerror(); ast_log(AST_LOG_ERROR, "Failure in dlclose for module '%s': %s\n", S_OR(name, "unknown"), S_OR(error, "Unknown error")); +#if defined(HAVE_PERMANENT_DLOPEN) + } else { + manual_mod_unreg(name); +#endif } } @@ -949,6 +1081,9 @@ static struct ast_module *load_dlopen(const char *resource_in, const char *so_ex resource_being_loaded = mod; mod->lib = dlopen(filename, flags); +#if defined(HAVE_PERMANENT_DLOPEN) + manual_mod_reg(mod->lib, mod->resource); +#endif if (resource_being_loaded) { struct ast_str *list; int c = 0; @@ -968,6 +1103,9 @@ static struct ast_module *load_dlopen(const char *resource_in, const char *so_ex resource_being_loaded = mod; mod->lib = dlopen(filename, RTLD_LAZY | RTLD_LOCAL); +#if defined(HAVE_PERMANENT_DLOPEN) + manual_mod_reg(mod->lib, mod->resource); +#endif if (resource_being_loaded) { resource_being_loaded = NULL; @@ -2206,6 +2344,15 @@ int load_modules(void) ast_verb(1, "Asterisk Dynamic Loader Starting:\n"); +#if defined(HAVE_PERMANENT_DLOPEN) + info_list = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK, 0, NULL, + info_list_obj_cmp_fn); /* must not be cleaned at shutdown */ + if (!info_list) { + fprintf(stderr, "Module info list allocation failure.\n"); + return 1; + } +#endif + AST_LIST_HEAD_INIT_NOLOCK(&load_order); AST_DLLIST_LOCK(&module_list);