Merge "loader: support for permanent dlopen()"
authorFriendly Automation <jenkins2@gerrit.asterisk.org>
Fri, 19 Apr 2019 14:06:03 +0000 (09:06 -0500)
committerGerrit Code Review <gerrit2@gerrit.digium.api>
Fri, 19 Apr 2019 14:06:03 +0000 (09:06 -0500)
configure
configure.ac
include/asterisk/autoconfig.h.in
main/loader.c

index d0d60f8..2a704b5 100755 (executable)
--- 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
 
 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
 for ac_header in xlocale.h
 do :
@@ -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
index 1ec7765..e65f159 100644 (file)
@@ -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])
 
index 46e92df..71df798 100644 (file)
 /* 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
 
index 3749c95..b46f745 100644 (file)
@@ -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);