alsa-mixer: Respect XDG base directory spec when loading path configs
authorSimonP <simonp.git@gmail.com>
Thu, 7 May 2020 15:13:27 +0000 (16:13 +0100)
committerPulseAudio Marge Bot <pulseaudio-maintainers@lists.freedesktop.org>
Mon, 14 Dec 2020 19:25:12 +0000 (19:25 +0000)
Try $XDG_DATA_HOME, then $XDG_DATA_DIRS, and finally fall back to old
behaviour (prefix-defined directory).

core-util: Ignore non-absolute XDG base dirs

These are invalid per the spec.

Fixes: https://gitlab.freedesktop.org/pulseaudio/pulseaudio/issues/862
Part-of: <https://gitlab.freedesktop.org/pulseaudio/pulseaudio/-/merge_requests/293>

src/modules/alsa/alsa-mixer.c
src/pulsecore/core-util.c
src/pulsecore/core-util.h
src/tests/alsa-mixer-path-test.c

index f978f71..c406297 100644 (file)
@@ -2763,13 +2763,66 @@ static int path_verify(pa_alsa_path *p) {
     return 0;
 }
 
-static const char *get_default_paths_dir(void) {
+static char *get_path_config_path(const char *paths_dir, const char *fname) {
+    char *path_config_path;
+    char *dir;
+    char *data_home;
+    pa_dynarray *data_dirs;
+
+    if (paths_dir) {
+        path_config_path = pa_maybe_prefix_path(fname, paths_dir);
+        if (access(path_config_path, R_OK) == 0)
+            return path_config_path;
+        else
+            pa_xfree(path_config_path);
+    }
+
 #ifdef HAVE_RUNNING_FROM_BUILD_TREE
-    if (pa_run_from_build_tree())
-        return PA_SRCDIR "/modules/alsa/mixer/paths/";
-    else
+    if (pa_run_from_build_tree()) {
+        path_config_path = pa_maybe_prefix_path(fname, PA_SRCDIR "/modules/alsa/mixer/paths/");
+        if (access(path_config_path, R_OK) == 0)
+            return path_config_path;
+        else
+            pa_xfree(path_config_path);
+    }
 #endif
-        return PA_ALSA_PATHS_DIR;
+
+    if (pa_get_data_home_dir(&data_home) == 0) {
+        dir = pa_sprintf_malloc("%s" PA_PATH_SEP "alsa-mixer" PA_PATH_SEP "paths", data_home);
+        pa_xfree(data_home);
+
+        path_config_path = pa_maybe_prefix_path(fname, dir);
+        pa_xfree(dir);
+
+        if (access(path_config_path, R_OK) == 0)
+            return path_config_path;
+        else
+            pa_xfree(path_config_path);
+    }
+
+    if (pa_get_data_dirs(&data_dirs) == 0) {
+        int idx;
+        const char *n;
+
+        PA_DYNARRAY_FOREACH(n, data_dirs, idx) {
+            dir = pa_sprintf_malloc("%s" PA_PATH_SEP "alsa-mixer" PA_PATH_SEP "paths", n);
+            path_config_path = pa_maybe_prefix_path(fname, dir);
+            pa_xfree(dir);
+
+            if (access(path_config_path, R_OK) == 0) {
+                pa_dynarray_free(data_dirs);
+                return path_config_path;
+            }
+            else {
+                pa_xfree(path_config_path);
+            }
+        }
+
+        pa_dynarray_free(data_dirs);
+    }
+
+    path_config_path = pa_maybe_prefix_path(fname, PA_ALSA_PATHS_DIR);
+    return path_config_path;
 }
 
 pa_alsa_path* pa_alsa_path_new(const char *paths_dir, const char *fname, pa_alsa_direction_t direction) {
@@ -2827,10 +2880,9 @@ pa_alsa_path* pa_alsa_path_new(const char *paths_dir, const char *fname, pa_alsa
     items[2].data = &p->description;
     items[3].data = &mute_during_activation;
 
-    if (!paths_dir)
-        paths_dir = get_default_paths_dir();
+    fn = get_path_config_path(paths_dir, fname);
 
-    fn = pa_maybe_prefix_path(fname, paths_dir);
+    pa_log_info("Loading path config: %s", fn);
 
     r = pa_config_parse(fn, NULL, items, p->proplist, false, p);
     pa_xfree(fn);
index 25498c5..0da5c09 100644 (file)
@@ -1568,6 +1568,70 @@ int pa_get_config_home_dir(char **_r) {
     return 0;
 }
 
+int pa_get_data_home_dir(char **_r) {
+    const char *e;
+    char *home_dir;
+
+    pa_assert(_r);
+
+    e = getenv("XDG_DATA_HOME");
+    if (e && *e) {
+        if (pa_is_path_absolute(e)) {
+            *_r = pa_sprintf_malloc("%s" PA_PATH_SEP "pulseaudio", e);
+            return 0;
+        }
+        else
+            pa_log_warn("Ignored non-absolute XDG_DATA_HOME value '%s'", e);
+    }
+
+    home_dir = pa_get_home_dir_malloc();
+    if (!home_dir)
+        return -PA_ERR_NOENTITY;
+
+    *_r = pa_sprintf_malloc("%s" PA_PATH_SEP ".local" PA_PATH_SEP "share" PA_PATH_SEP "pulseaudio", home_dir);
+    pa_xfree(home_dir);
+    return 0;
+}
+
+int pa_get_data_dirs(pa_dynarray **_r) {
+    const char *e;
+    const char *def = "/usr/local/share/:/usr/share/";
+    const char *p;
+    const char *split_state = NULL;
+    char *n;
+    pa_dynarray *paths;
+
+    pa_assert(_r);
+
+    e = getenv("XDG_DATA_DIRS");
+    p = e && *e ? e : def;
+
+    paths = pa_dynarray_new((pa_free_cb_t) pa_xfree);
+
+    while ((n = pa_split(p, ":", &split_state))) {
+        char *path;
+
+        if (!pa_is_path_absolute(n)) {
+            pa_log_warn("Ignored non-absolute path '%s' in XDG_DATA_DIRS", n);
+            pa_xfree(n);
+            continue;
+        }
+
+        path = pa_sprintf_malloc("%s" PA_PATH_SEP "pulseaudio", n);
+        pa_xfree(n);
+        pa_dynarray_append(paths, path);
+    }
+
+    if (pa_dynarray_size(paths) == 0) {
+        pa_log_warn("XDG_DATA_DIRS contains no valid paths");
+        pa_dynarray_free(paths);
+        return -PA_ERR_INVALID;
+    }
+
+    *_r = paths;
+    return 0;
+}
+
 int pa_append_to_config_home_dir(const char *path, char **_r) {
     int r;
     char *config_home_dir;
index 3117df8..ed123c7 100644 (file)
@@ -37,6 +37,7 @@
 #include <pulsecore/i18n.h>
 #include <pulsecore/macro.h>
 #include <pulsecore/socket.h>
+#include <pulsecore/dynarray.h>
 
 #ifndef PACKAGE
 #error "Please include config.h before including this file!"
@@ -142,6 +143,8 @@ char *pa_get_state_dir(void);
 char *pa_get_home_dir_malloc(void);
 int pa_append_to_home_dir(const char *path, char **_r);
 int pa_get_config_home_dir(char **_r);
+int pa_get_data_home_dir(char **_r);
+int pa_get_data_dirs(pa_dynarray **_r);
 int pa_append_to_config_home_dir(const char *path, char **_r);
 char *pa_get_binary_name_malloc(void);
 char *pa_runtime_path(const char *fn);
index 75cf086..91e4d0d 100644 (file)
@@ -17,7 +17,6 @@
  * Meson. */
 #ifndef MESON_BUILD
 
-/* This function was copied from alsa-mixer.c */
 static const char *get_default_paths_dir(void) {
     if (pa_run_from_build_tree())
         return PA_SRCDIR "/modules/alsa/mixer/paths/";