| /*** | |
| This file is part of PulseAudio. | |
| Copyright 2004-2006 Lennart Poettering | |
| Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB | |
| PulseAudio is free software; you can redistribute it and/or modify | |
| it under the terms of the GNU Lesser General Public License as published | |
| by the Free Software Foundation; either version 2.1 of the License, | |
| or (at your option) any later version. | |
| PulseAudio is distributed in the hope that it will be useful, but | |
| WITHOUT ANY WARRANTY; without even the implied warranty of | |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| General Public License for more details. | |
| You should have received a copy of the GNU Lesser General Public License | |
| along with PulseAudio; if not, see <http://www.gnu.org/licenses/>. | |
| ***/ | |
| #ifdef HAVE_CONFIG_H | |
| #include <config.h> | |
| #endif | |
| #include <stdlib.h> | |
| #include <unistd.h> | |
| #include <errno.h> | |
| #include <pulse/xmalloc.h> | |
| #include <pulsecore/i18n.h> | |
| #include <pulsecore/macro.h> | |
| #include <pulsecore/core-error.h> | |
| #include <pulsecore/log.h> | |
| #include <pulsecore/conf-parser.h> | |
| #include <pulsecore/core-util.h> | |
| #include <pulsecore/authkey.h> | |
| #include "client-conf.h" | |
| #ifdef HAVE_X11 | |
| #include <pulse/client-conf-x11.h> | |
| #endif | |
| #define DEFAULT_CLIENT_CONFIG_FILE PA_DEFAULT_CONFIG_DIR PA_PATH_SEP "client.conf" | |
| #define DEFAULT_CLIENT_CONFIG_FILE_USER "client.conf" | |
| #define ENV_CLIENT_CONFIG_FILE "PULSE_CLIENTCONFIG" | |
| #define ENV_DEFAULT_SINK "PULSE_SINK" | |
| #define ENV_DEFAULT_SOURCE "PULSE_SOURCE" | |
| #define ENV_DEFAULT_SERVER "PULSE_SERVER" | |
| #define ENV_DAEMON_BINARY "PULSE_BINARY" | |
| #define ENV_COOKIE_FILE "PULSE_COOKIE" | |
| static const pa_client_conf default_conf = { | |
| .daemon_binary = NULL, | |
| .extra_arguments = NULL, | |
| .default_sink = NULL, | |
| .default_source = NULL, | |
| .default_server = NULL, | |
| .default_dbus_server = NULL, | |
| .cookie_file_from_env = NULL, | |
| .cookie_from_x11_valid = false, | |
| .cookie_file_from_application = NULL, | |
| .cookie_file_from_client_conf = NULL, | |
| .autospawn = true, | |
| .disable_shm = false, | |
| .disable_memfd = false, | |
| .shm_size = 0, | |
| .auto_connect_localhost = false, | |
| .auto_connect_display = false | |
| }; | |
| pa_client_conf *pa_client_conf_new(void) { | |
| pa_client_conf *c = pa_xmemdup(&default_conf, sizeof(default_conf)); | |
| c->daemon_binary = pa_xstrdup(PA_BINARY); | |
| c->extra_arguments = pa_xstrdup("--log-target=syslog"); | |
| return c; | |
| } | |
| void pa_client_conf_free(pa_client_conf *c) { | |
| pa_assert(c); | |
| pa_xfree(c->daemon_binary); | |
| pa_xfree(c->extra_arguments); | |
| pa_xfree(c->default_sink); | |
| pa_xfree(c->default_source); | |
| pa_xfree(c->default_server); | |
| pa_xfree(c->default_dbus_server); | |
| pa_xfree(c->cookie_file_from_env); | |
| pa_xfree(c->cookie_file_from_application); | |
| pa_xfree(c->cookie_file_from_client_conf); | |
| pa_xfree(c); | |
| } | |
| static void load_env(pa_client_conf *c) { | |
| char *e; | |
| if ((e = getenv(ENV_DEFAULT_SINK))) { | |
| pa_xfree(c->default_sink); | |
| c->default_sink = pa_xstrdup(e); | |
| } | |
| if ((e = getenv(ENV_DEFAULT_SOURCE))) { | |
| pa_xfree(c->default_source); | |
| c->default_source = pa_xstrdup(e); | |
| } | |
| if ((e = getenv(ENV_DEFAULT_SERVER))) { | |
| pa_xfree(c->default_server); | |
| c->default_server = pa_xstrdup(e); | |
| /* We disable autospawning automatically if a specific server was set */ | |
| c->autospawn = false; | |
| } | |
| if ((e = getenv(ENV_DAEMON_BINARY))) { | |
| pa_xfree(c->daemon_binary); | |
| c->daemon_binary = pa_xstrdup(e); | |
| } | |
| if ((e = getenv(ENV_COOKIE_FILE)) && *e) { | |
| pa_xfree(c->cookie_file_from_env); | |
| c->cookie_file_from_env = pa_xstrdup(e); | |
| } | |
| } | |
| void pa_client_conf_load(pa_client_conf *c, bool load_from_x11, bool load_from_env) { | |
| FILE *f = NULL; | |
| char *fn = NULL; | |
| /* Prepare the configuration parse table */ | |
| pa_config_item table[] = { | |
| { "daemon-binary", pa_config_parse_string, &c->daemon_binary, NULL }, | |
| { "extra-arguments", pa_config_parse_string, &c->extra_arguments, NULL }, | |
| { "default-sink", pa_config_parse_string, &c->default_sink, NULL }, | |
| { "default-source", pa_config_parse_string, &c->default_source, NULL }, | |
| { "default-server", pa_config_parse_string, &c->default_server, NULL }, | |
| { "default-dbus-server", pa_config_parse_string, &c->default_dbus_server, NULL }, | |
| { "autospawn", pa_config_parse_bool, &c->autospawn, NULL }, | |
| { "cookie-file", pa_config_parse_string, &c->cookie_file_from_client_conf, NULL }, | |
| { "disable-shm", pa_config_parse_bool, &c->disable_shm, NULL }, | |
| { "enable-shm", pa_config_parse_not_bool, &c->disable_shm, NULL }, | |
| { "enable-memfd", pa_config_parse_not_bool, &c->disable_memfd, NULL }, | |
| { "shm-size-bytes", pa_config_parse_size, &c->shm_size, NULL }, | |
| { "auto-connect-localhost", pa_config_parse_bool, &c->auto_connect_localhost, NULL }, | |
| { "auto-connect-display", pa_config_parse_bool, &c->auto_connect_display, NULL }, | |
| { NULL, NULL, NULL, NULL }, | |
| }; | |
| f = pa_open_config_file(DEFAULT_CLIENT_CONFIG_FILE, DEFAULT_CLIENT_CONFIG_FILE_USER, ENV_CLIENT_CONFIG_FILE, &fn); | |
| if (f) { | |
| pa_config_parse(fn, f, table, NULL, true, NULL); | |
| pa_xfree(fn); | |
| fclose(f); | |
| } | |
| if (load_from_x11) { | |
| #ifdef HAVE_X11 | |
| pa_client_conf_from_x11(c); | |
| #endif | |
| } | |
| if (load_from_env) | |
| load_env(c); | |
| } | |
| int pa_client_conf_load_cookie(pa_client_conf *c, uint8_t *cookie, size_t cookie_length) { | |
| int r; | |
| char *fallback_path; | |
| pa_assert(c); | |
| pa_assert(cookie); | |
| pa_assert(cookie_length > 0); | |
| if (c->cookie_file_from_env) { | |
| r = pa_authkey_load(c->cookie_file_from_env, true, cookie, cookie_length); | |
| if (r >= 0) | |
| return 0; | |
| pa_log_warn("Failed to load cookie from %s (configured with environment variable PULSE_COOKIE): %s", | |
| c->cookie_file_from_env, pa_cstrerror(errno)); | |
| } | |
| if (c->cookie_from_x11_valid) { | |
| if (cookie_length == sizeof(c->cookie_from_x11)) { | |
| memcpy(cookie, c->cookie_from_x11, cookie_length); | |
| return 0; | |
| } | |
| pa_log_warn("Failed to load cookie from X11 root window property PULSE_COOKIE: size mismatch."); | |
| } | |
| if (c->cookie_file_from_application) { | |
| r = pa_authkey_load(c->cookie_file_from_application, true, cookie, cookie_length); | |
| if (r >= 0) | |
| return 0; | |
| pa_log_warn("Failed to load cookie from %s (configured by the application): %s", c->cookie_file_from_application, | |
| pa_cstrerror(errno)); | |
| } | |
| if (c->cookie_file_from_client_conf) { | |
| r = pa_authkey_load(c->cookie_file_from_client_conf, true, cookie, cookie_length); | |
| if (r >= 0) | |
| return 0; | |
| pa_log_warn("Failed to load cookie from %s (configured in client.conf): %s", c->cookie_file_from_client_conf, | |
| pa_cstrerror(errno)); | |
| } | |
| r = pa_authkey_load(PA_NATIVE_COOKIE_FILE, false, cookie, cookie_length); | |
| if (r >= 0) | |
| return 0; | |
| if (pa_append_to_home_dir(PA_NATIVE_COOKIE_FILE_FALLBACK, &fallback_path) >= 0) { | |
| r = pa_authkey_load(fallback_path, false, cookie, cookie_length); | |
| pa_xfree(fallback_path); | |
| if (r >= 0) | |
| return 0; | |
| } | |
| r = pa_authkey_load(PA_NATIVE_COOKIE_FILE, true, cookie, cookie_length); | |
| if (r >= 0) | |
| return 0; | |
| pa_log("Failed to load cookie file from %s: %s", PA_NATIVE_COOKIE_FILE, pa_cstrerror(errno)); | |
| memset(cookie, 0, cookie_length); | |
| return -1; | |
| } | |
| void pa_client_conf_set_cookie_file_from_application(pa_client_conf *c, const char *cookie_file) { | |
| pa_assert(c); | |
| pa_assert(!cookie_file || *cookie_file); | |
| pa_xfree(c->cookie_file_from_application); | |
| c->cookie_file_from_application = pa_xstrdup(cookie_file); | |
| } |