]> git.alsa-project.org Git - alsa-lib.git/commitdiff
snd_dlopen: implement the relocatable version for glibc
authorJaroslav Kysela <perex@perex.cz>
Thu, 4 Jun 2020 17:06:08 +0000 (19:06 +0200)
committerJaroslav Kysela <perex@perex.cz>
Thu, 4 Jun 2020 17:09:58 +0000 (19:09 +0200)
BugLink: https://github.com/alsa-project/alsa-lib/issues/34
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
include/global.h
modules/mixer/simple/python.c
src/dlmisc.c

index d73d333aae19d916243a7a87343cb55705652a2b..71a1b12fa682d3596006ecf5401ef2cd307e5c7e 100644 (file)
@@ -97,6 +97,7 @@ extern struct snd_dlsym_link *snd_dlsym_start;
 /** \brief Returns the version of a dynamic symbol as a string. */
 #define SND_DLSYM_VERSION(version) __STRING(version)
 
+int snd_dlpath(char *path, size_t path_len, const char *name);
 void *snd_dlopen(const char *file, int mode, char *errbuf, size_t errbuflen);
 void *snd_dlsym(void *handle, const char *name, const char *version);
 int snd_dlclose(void *handle);
index 3a627ab6d2d3f7b29b543c96a65c426f13a5a0c7..8a7264d435cef31061f8c98045ea8438b5bebec1 100644 (file)
@@ -21,6 +21,7 @@
 
 #include "Python.h"
 #include <stddef.h>
+#include <limits.h>
 #include "config.h"
 #include "asoundlib.h"
 #include "mixer_abst.h"
@@ -36,7 +37,7 @@ struct python_priv {
        PyObject *py_mixer;
 };
 
-#define SCRIPT ALSA_PLUGIN_DIR "/smixer/python/main.py"
+#define SCRIPT "smixer/python/main.py"
 
 struct pymelem {
        PyObject_HEAD
@@ -1110,6 +1111,7 @@ int alsa_mixer_simple_finit(snd_mixer_class_t *class,
        FILE *fp;
        const char *file;
        PyObject *obj, *py_mod;
+       char path[PATH_MAX];
 
        priv = calloc(1, sizeof(*priv));
        if (priv == NULL)
@@ -1119,8 +1121,10 @@ int alsa_mixer_simple_finit(snd_mixer_class_t *class,
        snd_mixer_sbasic_set_private_free(class, alsa_mixer_simple_free);
 
        file = getenv("ALSA_MIXER_SIMPLE_MPYTHON");
-       if (file == NULL)
-               file = SCRIPT;
+       if (file == NULL) {
+               snd_dlpath(path, sizeof(path), SCRIPT);
+               file = path;
+       }
 
        fp = fopen(file, "r");
        if (fp == NULL) {
index 8c8f3ff72fd3c7aaefa75c0ad1c81d36e1775cee..87a8fa001d87e489ead36510aa9c64a3abb9a95c 100644 (file)
@@ -32,6 +32,7 @@
 #ifdef HAVE_LIBPTHREAD
 #include <pthread.h>
 #endif
+#include <limits.h>
 
 #ifndef DOC_HIDDEN
 #ifndef PIC
@@ -39,6 +40,42 @@ struct snd_dlsym_link *snd_dlsym_start = NULL;
 #endif
 #endif
 
+/**
+ *
+ * \brief Compose the dynamic path
+ * \param path Returned path (string)
+ * \param path_len Returned path max size (with trailing zero)
+ * \param name Plugin name (relative)
+ * \return Zero on success, otherwise a negative error code
+ */
+int snd_dlpath(char *path, size_t path_len, const char *name)
+{
+       static const char *origin_dir = NULL;
+#ifdef HAVE_LIBDL
+#ifdef __GLIBC__
+       static int plugin_dir_set = 0;
+       if (!plugin_dir_set) {
+               struct link_map *links;
+               Dl_info info;
+               char origin[PATH_MAX];
+               if (dladdr1(&snd_dlpath, &info, (void**)&links, RTLD_DL_LINKMAP) == 0)
+                       links = NULL;
+               if (links != NULL && dlinfo(links, RTLD_DI_ORIGIN, origin) == 0) {
+                       snprintf(path, path_len, "%s/alsa-lib", origin);
+                       if (access(path, X_OK) == 0)
+                               origin_dir = origin;
+               }
+               plugin_dir_set = 1;
+       }
+#endif
+#endif
+       if (origin_dir)
+               snprintf(path, path_len, "%s/alsa-lib/%s", origin_dir, name);
+       else
+               snprintf(path, path_len, "%s/%s", ALSA_PLUGIN_DIR, name);
+       return 0;
+}
+
 /**
  * \brief Opens a dynamic library - ALSA wrapper for \c dlopen.
  * \param name name of the library, similar to \c dlopen.
@@ -79,14 +116,12 @@ void *snd_dlopen(const char *name, int mode, char *errbuf, size_t errbuflen)
         * via ld.so.conf.
         */
        void *handle = NULL;
-       char *filename = NULL;
+       const char *filename = NULL;
+       char path[PATH_MAX];
 
        if (name && name[0] != '/') {
-               filename = alloca(sizeof(ALSA_PLUGIN_DIR) + 1 + strlen(name) + 1);
-               if (filename) {
-                       strcpy(filename, ALSA_PLUGIN_DIR);
-                       strcat(filename, "/");
-                       strcat(filename, name);
+               if (snd_dlpath(path, sizeof(path), name) == 0) {
+                       filename = name;
                        handle = dlopen(filename, mode);
                        if (!handle) {
                                /* if the filename exists and cannot be opened */
@@ -97,6 +132,7 @@ void *snd_dlopen(const char *name, int mode, char *errbuf, size_t errbuflen)
                }
        }
        if (!handle) {
+               filename = name;
                handle = dlopen(name, mode);
                if (!handle)
                        goto errpath;