From 6f2e274b15762fe3e845ca6c7de017c6816d3edd Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 31 Jul 2020 12:46:58 +0200 Subject: [PATCH] protocol: add a few more options for XDG_RUNTIME_DIR PIPEWIRE_CORE can be used to specify a server name. PIPEWIRE_REMOTE can be used to specify what server name to connect to. Either use the absolute path of the name to create and connect to a server, or use a relative path. For a relative path, the server name will be completed by prefixing the following paths in order: PIPEWIRE_RUNTIME_DIR environment variable, XDG_RUNTIME_DIR environment variable, HOME environment variable, USERPROFILE environment variable, home directory as stored in the password database. Fixes #259 --- config.h.meson | 3 + meson.build | 1 + src/modules/module-protocol-native.c | 39 +++++++-- .../module-protocol-native/local-socket.c | 79 ++++++++++++++----- 4 files changed, 98 insertions(+), 24 deletions(-) diff --git a/config.h.meson b/config.h.meson index 3c0a699a3..207e33790 100644 --- a/config.h.meson +++ b/config.h.meson @@ -311,6 +311,9 @@ /* Define to 1 if you have the header file. */ #mesondefine HAVE_VALGRIND_VALGRIND_H +/* Define to 1 if you have the header file. */ +#mesondefine HAVE_PWD_H + /* Defined if compiling for Windows */ #mesondefine HAVE_WIN32 diff --git a/meson.build b/meson.build index ad4a1c08e..6fabce7ea 100644 --- a/meson.build +++ b/meson.build @@ -204,6 +204,7 @@ check_headers = [['dlfcn.h','HAVE_DLFCN_H'], ['sys/types.h', 'HAVE_SYS_TYPES_H'], ['sys/utsname.h', 'HAVE_SYS_UTSNAME_H'], ['sys/wait.h', 'HAVE_SYS_WAIT_H'], + ['pwd.h', 'HAVE_PWD_H'], ['ucontext.h', 'HAVE_UCONTEXT_H'], ['unistd.h', 'HAVE_UNISTD_H'], ['valgrind/valgrind.h', 'HAVE_VALGRIND_VALGRIND_H'], diff --git a/src/modules/module-protocol-native.c b/src/modules/module-protocol-native.c index 854372a74..2fc2e16f6 100644 --- a/src/modules/module-protocol-native.c +++ b/src/modules/module-protocol-native.c @@ -22,6 +22,8 @@ * DEALINGS IN THE SOFTWARE. */ +#include "config.h" + #include #include #include @@ -31,13 +33,13 @@ #include #include #include +#if HAVE_PWD_H +#include +#endif #include #include - -#include "config.h" - #ifdef HAVE_SYSTEMD_DAEMON #include #endif @@ -432,6 +434,28 @@ exit: return NULL; } +static const char * +get_runtime_dir(void) +{ + const char *runtime_dir; + + runtime_dir = getenv("PIPEWIRE_RUNTIME_DIR"); + if (runtime_dir == NULL) + runtime_dir = getenv("XDG_RUNTIME_DIR"); + if (runtime_dir == NULL) + runtime_dir = getenv("HOME"); + if (runtime_dir == NULL) + runtime_dir = getenv("USERPROFILE"); + if (runtime_dir == NULL) { + struct passwd pwd, *result = NULL; + char buffer[4096]; + if (getpwuid_r(getuid(), &pwd, buffer, sizeof(buffer), &result) == 0) + runtime_dir = result ? result->pw_dir : NULL; + } + return runtime_dir; +} + + static int init_socket_name(struct server *s, const char *name) { int name_size; @@ -440,9 +464,14 @@ static int init_socket_name(struct server *s, const char *name) path_is_absolute = name[0] == '/'; - runtime_dir = getenv("XDG_RUNTIME_DIR"); + runtime_dir = get_runtime_dir(); + + pw_log_debug("name:%s runtime_dir:%s", name, runtime_dir); + if (runtime_dir == NULL && !path_is_absolute) { - pw_log_error("server %p: XDG_RUNTIME_DIR not set in the environment", s); + pw_log_error("server %p: name %s is not an absolute path and no runtime dir found." + "set one of PIPEWIRE_RUNTIME_DIR, XDG_RUNTIME_DIR, HOME or " + "USERPROFILE in the environment", s, name); return -ENOENT; } diff --git a/src/modules/module-protocol-native/local-socket.c b/src/modules/module-protocol-native/local-socket.c index 34ed1eb66..2dfe79515 100644 --- a/src/modules/module-protocol-native/local-socket.c +++ b/src/modules/module-protocol-native/local-socket.c @@ -22,6 +22,8 @@ * DEALINGS IN THE SOFTWARE. */ +#include "config.h" + #include #include #include @@ -33,6 +35,9 @@ #include #include #include +#if HAVE_PWD_H +#include +#endif #include @@ -50,6 +55,27 @@ get_remote(const struct spa_dict *props) return name; } +static const char * +get_runtime_dir(void) +{ + const char *runtime_dir; + + runtime_dir = getenv("PIPEWIRE_RUNTIME_DIR"); + if (runtime_dir == NULL) + runtime_dir = getenv("XDG_RUNTIME_DIR"); + if (runtime_dir == NULL) + runtime_dir = getenv("HOME"); + if (runtime_dir == NULL) + runtime_dir = getenv("USERPROFILE"); + if (runtime_dir == NULL) { + struct passwd pwd, *result = NULL; + char buffer[4096]; + if (getpwuid_r(getuid(), &pwd, buffer, sizeof(buffer), &result) == 0) + runtime_dir = result ? result->pw_dir : NULL; + } + return runtime_dir; +} + int pw_protocol_native_connect_local_socket(struct pw_protocol_client *client, const struct spa_dict *props, void (*done_callback) (void *data, int res), @@ -57,42 +83,57 @@ int pw_protocol_native_connect_local_socket(struct pw_protocol_client *client, { struct sockaddr_un addr; socklen_t size; - const char *runtime_dir, *name = NULL; + const char *runtime_dir, *name; int res, name_size, fd; - - if ((runtime_dir = getenv("XDG_RUNTIME_DIR")) == NULL) { - pw_log_error("connect failed: XDG_RUNTIME_DIR not set in the environment"); - res = -ENOENT; - goto error; - } + bool path_is_absolute; name = get_remote(props); - pw_log_info("connecting to '%s'", name); - if ((fd = socket(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0)) < 0) { + path_is_absolute = name[0] == '/'; + + runtime_dir = get_runtime_dir(); + + pw_log_info("connecting to '%s' runtime_dir:%s", name, runtime_dir); + + if (runtime_dir == NULL && !path_is_absolute) { + pw_log_error("client %p: name %s is not an absolute path and no runtime dir found." + "set one of PIPEWIRE_RUNTIME_DIR, XDG_RUNTIME_DIR, HOME or " + "USERPROFILE in the environment", client, name); + res = -ENOENT; + goto error; + } + + if ((fd = socket(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0)) < 0) { res = -errno; goto error; } - memset(&addr, 0, sizeof(addr)); - addr.sun_family = AF_LOCAL; - name_size = snprintf(addr.sun_path, sizeof(addr.sun_path), "%s/%s", runtime_dir, name) + 1; + memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_LOCAL; + if (!path_is_absolute) + name_size = snprintf(addr.sun_path, sizeof(addr.sun_path), "%s/%s", runtime_dir, name) + 1; + else + name_size = snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", name) + 1; - if (name_size > (int) sizeof addr.sun_path) { - pw_log_error("socket path \"%s/%s\" plus null terminator exceeds 108 bytes", - runtime_dir, name); + if (name_size > (int) sizeof addr.sun_path) { + if (path_is_absolute) + pw_log_error("client %p: socket path \"%s\" plus null terminator exceeds %i bytes", + client, name, (int) sizeof(addr.sun_path)); + else + pw_log_error("client %p: socket path \"%s/%s\" plus null terminator exceeds %i bytes", + client, runtime_dir, name, (int) sizeof(addr.sun_path)); res = -ENAMETOOLONG; goto error_close; - }; + }; - size = offsetof(struct sockaddr_un, sun_path) + name_size; + size = offsetof(struct sockaddr_un, sun_path) + name_size; - if (connect(fd, (struct sockaddr *) &addr, size) < 0) { + if (connect(fd, (struct sockaddr *) &addr, size) < 0) { pw_log_debug("connect to '%s' failed: %m", name); if (errno == ENOENT) errno = EHOSTDOWN; res = -errno; - goto error_close; + goto error_close; } res = pw_protocol_client_connect_fd(client, fd, true);