From db44fe47ee771101819c8350e8a69edb9471cb38 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 9 Jun 2021 12:15:39 +0200 Subject: [PATCH] conf: Load and stack all config files. Load and parse config files in the following order: $PIPEWIRE_CONFIG_DIR or /usr/share/pipewire /etc/pipewire $XDG_CONFIG_DIR or ~/.config/pipewire This ensure we always load a working base config and reduce the chances of failing because of a back user config file. The user config file now only needs to contain the section that needs the be changed. See #207 --- src/pipewire/conf.c | 176 ++++++++++++++++++++++++-------------------- 1 file changed, 98 insertions(+), 78 deletions(-) diff --git a/src/pipewire/conf.c b/src/pipewire/conf.c index 829105202..1604fdef7 100644 --- a/src/pipewire/conf.c +++ b/src/pipewire/conf.c @@ -64,63 +64,78 @@ static int make_path(char *path, int size, const char *paths[]) return 0; } -static int get_read_path(char *path, size_t size, const char *prefix, const char *name) +static int get_read_path(char *path, size_t size, const char *prefix, const char *name, + bool useronly, uint32_t *state) { const char *dir; char buffer[4096]; - if (prefix[0] == '/') { - const char *paths[] = { prefix, name, NULL }; - if (make_path(path, size, paths) == 0 && - access(path, R_OK) == 0) - return 1; - return -ENOENT; - } - if (pw_check_option("no-config", "true")) - goto no_config; - - dir = getenv("PIPEWIRE_CONFIG_DIR"); - if (dir != NULL) { - const char *paths[] = { dir, prefix, name, NULL }; - if (make_path(path, size, paths) == 0 && - access(path, R_OK) == 0) - return 1; - } - - dir = getenv("XDG_CONFIG_HOME"); - if (dir != NULL) { - const char *paths[] = { dir, "pipewire", prefix, name, NULL }; - if (make_path(path, size, paths) == 0 && - access(path, R_OK) == 0) - return 1; - } - dir = getenv("HOME"); - if (dir == NULL) { - struct passwd pwd, *result = NULL; - if (getpwuid_r(getuid(), &pwd, buffer, sizeof(buffer), &result) == 0) - dir = result ? result->pw_dir : NULL; - } - if (dir != NULL) { - const char *paths[] = { dir, ".config", "pipewire", prefix, name, NULL }; - if (make_path(path, size, paths) == 0 && - access(path, R_OK) == 0) - return 1; - } - - dir = PIPEWIRE_CONFIG_DIR; - if (dir != NULL) { - const char *paths[] = { dir, prefix, name, NULL }; - if (make_path(path, size, paths) == 0 && - access(path, R_OK) == 0) - return 1; - } -no_config: - dir = PIPEWIRE_CONFDATADIR; - if (dir != NULL) { - const char *paths[] = { dir, prefix, name, NULL }; - if (make_path(path, size, paths) == 0 && - access(path, R_OK) == 0) - return 1; + while (true) { + switch ((*state)++) { + case 0: + if (prefix[0] == '/') { + const char *paths[] = { prefix, name, NULL }; + if (make_path(path, size, paths) == 0 && + access(path, R_OK) == 0) + return 1; + return -ENOENT; + } + break; + case 1: + if (useronly) + break; + dir = getenv("PIPEWIRE_CONFIG_DIR"); + if (dir != NULL) { + const char *paths[] = { dir, prefix, name, NULL }; + if (make_path(path, size, paths) == 0 && + access(path, R_OK) == 0) + return 1; + } + dir = PIPEWIRE_CONFDATADIR; + if (dir != NULL) { + const char *paths[] = { dir, prefix, name, NULL }; + if (make_path(path, size, paths) == 0 && + access(path, R_OK) == 0) + return 1; + } + break; + case 2: + if (pw_check_option("no-config", "true")) + return 0; + if (useronly) + break; + dir = PIPEWIRE_CONFIG_DIR; + if (dir != NULL) { + const char *paths[] = { dir, prefix, name, NULL }; + if (make_path(path, size, paths) == 0 && + access(path, R_OK) == 0) + return 1; + } + break; + case 3: + dir = getenv("XDG_CONFIG_HOME"); + if (dir != NULL) { + const char *paths[] = { dir, "pipewire", prefix, name, NULL }; + if (make_path(path, size, paths) == 0 && + access(path, R_OK) == 0) + return 1; + } + dir = getenv("HOME"); + if (dir == NULL) { + struct passwd pwd, *result = NULL; + if (getpwuid_r(getuid(), &pwd, buffer, sizeof(buffer), &result) == 0) + dir = result ? result->pw_dir : NULL; + } + if (dir != NULL) { + const char *paths[] = { dir, ".config", "pipewire", prefix, name, NULL }; + if (make_path(path, size, paths) == 0 && + access(path, R_OK) == 0) + return 1; + } + break; + default: + return 0; + } } return 0; } @@ -242,53 +257,58 @@ error: return res; } -static int conf_load(const char *prefix, const char *name, struct pw_properties *conf) +static int conf_load(const char *prefix, const char *name, bool useronly, struct pw_properties *conf) { char path[PATH_MAX], *data; struct stat sbuf; - int fd; + int fd, count = 0; + uint32_t state = 0; if (prefix == NULL) { prefix = name; name = NULL; } - if (get_read_path(path, sizeof(path), prefix, name) == 0) { - pw_log_debug(NAME" %p: can't load config '%s': %m", conf, path); + while (true) { + if (get_read_path(path, sizeof(path), prefix, name, useronly, &state) <= 0) + break; + + pw_log_info(NAME" %p: loading config '%s'", conf, path); + if ((fd = open(path, O_CLOEXEC | O_RDONLY)) < 0) { + pw_log_warn(NAME" %p: error opening '%s': %m", conf, path); + continue; + } + + data = NULL; + if (fstat(fd, &sbuf) < 0) { + pw_log_warn(NAME" %p: error stat '%s': %m", conf, path); + } else if ((data = mmap(NULL, sbuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0)) == MAP_FAILED) { + pw_log_warn(NAME" %p: error mmap '%s': %m", conf, path); + data = NULL; + } + close(fd); + + if (data != NULL) { + count += pw_properties_update_string(conf, data, sbuf.st_size); + munmap(data, sbuf.st_size); + } + } + if (count == 0) return -ENOENT; - } - if ((fd = open(path, O_CLOEXEC | O_RDONLY)) < 0) { - pw_log_warn(NAME" %p: error loading config '%s': %m", conf, path); - return -errno; - } - - pw_log_info(NAME" %p: loading config '%s'", conf, path); - if (fstat(fd, &sbuf) < 0) - goto error_close; - if ((data = mmap(NULL, sbuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0)) == MAP_FAILED) - goto error_close; - close(fd); - - pw_properties_update_string(conf, data, sbuf.st_size); - munmap(data, sbuf.st_size); return 0; - -error_close: - close(fd); - return -errno; } SPA_EXPORT int pw_conf_load_conf(const char *prefix, const char *name, struct pw_properties *conf) { - return conf_load(prefix, name, conf); + return conf_load(prefix, name, false, conf); } SPA_EXPORT int pw_conf_load_state(const char *prefix, const char *name, struct pw_properties *conf) { - return conf_load(prefix, name, conf); + return conf_load(prefix, name, true, conf); } /* context.spa-libs = {