diff options
author | Jaroslav Kysela <perex@perex.cz> | 2020-06-04 19:06:08 +0200 |
---|---|---|
committer | Jaroslav Kysela <perex@perex.cz> | 2020-06-04 19:09:58 +0200 |
commit | 33089f30a316060094dfa95a2949fd479299c7bc (patch) | |
tree | 71489f8d69bcdc8e0e84b8508ce5dbbbb9149345 | |
parent | b2a4272ecb40d84556d8e043d0b6e89439acbc33 (diff) | |
download | alsa-lib-33089f30a316060094dfa95a2949fd479299c7bc.tar.gz |
snd_dlopen: implement the relocatable version for glibc
BugLink: https://github.com/alsa-project/alsa-lib/issues/34
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
-rw-r--r-- | include/global.h | 1 | ||||
-rw-r--r-- | modules/mixer/simple/python.c | 10 | ||||
-rw-r--r-- | src/dlmisc.c | 48 |
3 files changed, 50 insertions, 9 deletions
diff --git a/include/global.h b/include/global.h index d73d333a..71a1b12f 100644 --- a/include/global.h +++ b/include/global.h @@ -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); diff --git a/modules/mixer/simple/python.c b/modules/mixer/simple/python.c index 3a627ab6..8a7264d4 100644 --- a/modules/mixer/simple/python.c +++ b/modules/mixer/simple/python.c @@ -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) { diff --git a/src/dlmisc.c b/src/dlmisc.c index 8c8f3ff7..87a8fa00 100644 --- a/src/dlmisc.c +++ b/src/dlmisc.c @@ -32,6 +32,7 @@ #ifdef HAVE_LIBPTHREAD #include <pthread.h> #endif +#include <limits.h> #ifndef DOC_HIDDEN #ifndef PIC @@ -40,6 +41,42 @@ struct snd_dlsym_link *snd_dlsym_start = NULL; #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. * \param mode mode flags, 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; |