Subject: [PATCH 2/2] gnu: Help alsa-lib find its plugins on foreign distros.

From: Leo Famulari <[email-masked]>
Date: Sat, 16 May 2020 15:34:01 -0400

Fixes <https://bugs.gnu.org/40832>.

* gnu/packages/linux.scm (alsa-lib)[replacement]: New field.
(alsa-lib/fixed): New variable.
* gnu/packages/patches/alsa-lib-plugin-dirs.patch: New file.
* gnu/local.mk (dist_patch_DATA): Add it.
---
 gnu/local.mk                                  |   1 +
 gnu/packages/linux.scm                        |  10 ++
 .../patches/alsa-lib-plugin-dirs.patch        | 149 ++++++++++++++++++
 3 files changed, 160 insertions(+)
 create mode 100644 gnu/packages/patches/alsa-lib-plugin-dirs.patch

diff --git a/gnu/local.mk b/gnu/local.mk
index 39267f2765..78e63fe7ff 100644
--- a/gnu/local.mk
+++ b/gnu/local.mk
@@ -741,6 +741,7 @@ dist_patch_DATA =						\
   %D%/packages/patches/akonadi-not-relocatable.patch		\
   %D%/packages/patches/akonadi-timestamps.patch		\
   %D%/packages/patches/allegro-mesa-18.2.5-and-later.patch	\
+  %D%/packages/patches/alsa-lib-plugin-dirs.patch		\
   %D%/packages/patches/amule-crypto-6.patch			\
   %D%/packages/patches/anki-mpv-args.patch			\
   %D%/packages/patches/antiword-CVE-2014-8123.patch			\
diff --git a/gnu/packages/linux.scm b/gnu/packages/linux.scm
index 4fb29b8490..8ea5bb909a 100644
--- a/gnu/packages/linux.scm
+++ b/gnu/packages/linux.scm
@@ -1771,6 +1771,7 @@ intercept and print the system calls executed by the program.")
 (define-public alsa-lib
   (package
     (name "alsa-lib")
+    (replacement alsa-lib/fixed)
     (version "1.2.2")
     (source (origin
              (method url-fetch)
@@ -1792,6 +1793,15 @@ intercept and print the system calls executed by the program.")
 MIDI functionality to the Linux-based operating system.")
     (license license:lgpl2.1+)))
 
+(define alsa-lib/fixed
+  (package
+    (inherit alsa-lib)
+    (source (origin
+              (inherit (package-source alsa-lib))
+              (patches (append
+                         (origin-patches (package-source alsa-lib))
+                         (search-patches "alsa-lib-plugin-dirs.patch")))))))
+
 (define-public alsa-utils
   (package
     (name "alsa-utils")
diff --git a/gnu/packages/patches/alsa-lib-plugin-dirs.patch b/gnu/packages/patches/alsa-lib-plugin-dirs.patch
new file mode 100644
index 0000000000..0d6cb57f4e
--- /dev/null
+++ b/gnu/packages/patches/alsa-lib-plugin-dirs.patch
@@ -0,0 +1,149 @@
+From 5bc1a490fa68187bce15eb9e8305b88ff6fbdbe5 Mon Sep 17 00:00:00 2001
+From: Leo Famulari <[email-masked]>
+Date: Mon, 27 Apr 2020 13:09:54 -0400
+Subject: [PATCH] Search for plugins in $GUIX_ALSA_PLUGIN_DIRS.
+
+* src/control/control.c (snd_ctl_open_conf): If ALSA plugins cannot be found in
+the default locations, look in the directories in $GUIX_ALSA_PLUGIN_DIRS.
+* src/dlmisc.c (snd_dlopen): Likewise.
+* src/pcm/pcm.c (snd_pcm_open_conf): Likewise.
+---
+ src/control/control.c | 35 ++++++++++++++++++++++++++++++++++-
+ src/dlmisc.c          | 26 +++++++++++++++++++++-----
+ src/pcm/pcm.c         | 35 ++++++++++++++++++++++++++++++++++-
+ 3 files changed, 89 insertions(+), 7 deletions(-)
+
+diff --git a/src/control/control.c b/src/control/control.c
+index 27f42135..108a560b 100644
+--- a/src/control/control.c
++++ b/src/control/control.c
+@@ -1342,8 +1342,41 @@ static int snd_ctl_open_conf(snd_ctl_t **ctlp, const char *name,
+ 				err = -ENOMEM;
+ 				goto _err;
+ 			}
++			sprintf(buf1, "%s/libasound_module_pcm_%s.so", ALSA_PLUGIN_DIR, str);
++			if (access(buf1, F_OK) != 0) {
++				const char *plugindirs = getenv("GUIX_ALSA_PLUGIN_DIRS");
++
++				if (plugindirs) {
++					char *plugindirs_copy = alloca(strlen(plugindirs) + 1);
++					if (plugindirs_copy == NULL) {
++						err = -ENOMEM;
++						goto _err;
++					}
++					strcpy(plugindirs_copy, plugindirs);
++					char *saveptr;
++					while (1) {
++						char *dir_tok = strtok_r(plugindirs_copy, ":", &saveptr);
++						if (dir_tok == NULL)
++							break;
++						char *so_file = malloc(strlen(dir_tok) + 1 + strlen(str) + 32);
++						if (so_file == NULL) {
++							err = -ENOMEM;
++							goto _err;
++						}
++
++						sprintf(so_file, "%s/libasound_module_ctl_%s.so", dir_tok, str);
++
++						if (access(so_file, F_OK) == 0) {
++							buf1 = so_file;
++							break;
++						} else {
++							free (so_file);
++						}
++						plugindirs_copy = NULL;
++					}
++				}
++			}
+ 			lib = buf1;
+-			sprintf(buf1, "%s/libasound_module_ctl_%s.so", ALSA_PLUGIN_DIR, str);
+ 		}
+ 	}
+ #ifndef PIC
+diff --git a/src/dlmisc.c b/src/dlmisc.c
+index 8c8f3ff7..b115447c 100644
+--- a/src/dlmisc.c
++++ b/src/dlmisc.c
+@@ -82,11 +82,27 @@ void *snd_dlopen(const char *name, int mode, char *errbuf, size_t errbuflen)
+ 	char *filename = NULL;
+ 
+ 	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);
++		const char *plugindirs = getenv("GUIX_ALSA_PLUGIN_DIRS");
++		if (plugindirs) {
++			char *plugindirs_copy = alloca(strlen(plugindirs) + 1);
++			if (plugindirs_copy == NULL)
++				goto errpath;
++			strcpy(plugindirs_copy, plugindirs);
++			char *saveptr;
++			while (1) {
++				char *dir_tok = strtok_r(plugindirs_copy, ":", &saveptr);
++				if (dir_tok == NULL)
++					break;
++				char *sofilename = malloc(strlen(dir_tok) + 1 + strlen(name) + 1);
++				sprintf(sofilename, "%s/%s" ,dir_tok, name);
++				if (access(sofilename, F_OK) == 0) {
++					filename = sofilename;
++					break;
++				} else {
++					free (sofilename);
++				}
++				plugindirs_copy = NULL;
++			}
+ 			handle = dlopen(filename, mode);
+ 			if (!handle) {
+ 				/* if the filename exists and cannot be opened */
+diff --git a/src/pcm/pcm.c b/src/pcm/pcm.c
+index 1064044c..90ba00ac 100644
+--- a/src/pcm/pcm.c
++++ b/src/pcm/pcm.c
+@@ -2578,8 +2578,41 @@ static int snd_pcm_open_conf(snd_pcm_t **pcmp, const char *name,
+ 				err = -ENOMEM;
+ 				goto _err;
+ 			}
+-			lib = buf1;
+ 			sprintf(buf1, "%s/libasound_module_pcm_%s.so", ALSA_PLUGIN_DIR, str);
++			if (access(buf1, F_OK) != 0) {
++				const char *plugindirs = getenv("GUIX_ALSA_PLUGIN_DIRS");
++
++				if (plugindirs) {
++					char *plugindirs_copy = alloca(strlen(plugindirs) + 1);
++					if (plugindirs_copy == NULL) {
++						err = -ENOMEM;
++						goto _err;
++					}
++					strcpy(plugindirs_copy, plugindirs);
++					char *saveptr;
++					while (1) {
++						char *dir_tok = strtok_r(plugindirs_copy, ":", &saveptr);
++						if (dir_tok == NULL)
++							break;
++						char *so_file = malloc(strlen(dir_tok) + 1 + strlen(str) + 32);
++						if (so_file == NULL) {
++							err = -ENOMEM;
++							goto _err;
++						}
++
++						sprintf(so_file, "%s/libasound_module_pcm_%s.so", dir_tok, str);
++
++						if (access(so_file, F_OK) == 0) {
++							buf1 = so_file;
++							break;
++						} else {
++							free (so_file);
++						}
++						plugindirs_copy = NULL;
++					}
++				}
++			}
++			lib = buf1;
+ 		}
+ 	}
+ #ifndef PIC
+-- 
+2.26.2
+
-- 
2.26.2