mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-11-01 22:58:50 -04:00
Implement config/state file handling
Make methods to load_config and load/save state. For now the config and state directories are the same but it might not be. Implement the search path for all config/state files as: $XDG_CONFIG_HOME/[$prefix]/$name $HOME/.config/[$prefix]/$name $PIPEWIRE_CONFIG_DIR/pipewire/[$prefix]/$name /etc/pipewire/[$prefix]/$name Make some config files for jack and RT clients. Make pw-cat use the client-rt config. Use core state and config management in media-session. Move all session manager state and config files to the build dir and set the PIPEWIRE_CONFIG_DIR to this build dir.
This commit is contained in:
parent
c605672d43
commit
fc90a4e48a
13 changed files with 380 additions and 216 deletions
|
|
@ -22,6 +22,8 @@
|
|||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <signal.h>
|
||||
#include <getopt.h>
|
||||
#include <limits.h>
|
||||
|
|
@ -31,38 +33,205 @@
|
|||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/wait.h>
|
||||
#if HAVE_PWD_H
|
||||
#include <pwd.h>
|
||||
#endif
|
||||
|
||||
#include <spa/utils/result.h>
|
||||
#include <spa/utils/json.h>
|
||||
|
||||
#include <pipewire/impl.h>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#define NAME "config"
|
||||
|
||||
SPA_EXPORT
|
||||
int pw_conf_load(const char *prefix, const char *name, struct pw_properties *conf)
|
||||
static int make_path(char *path, int size, const char *paths[])
|
||||
{
|
||||
int i, len;
|
||||
char *p = path;
|
||||
for (i = 0; paths[i] != NULL; i++) {
|
||||
len = snprintf(p, size, "%s%s", i == 0 ? "" : "/", paths[i]);
|
||||
if (len < 0)
|
||||
return -errno;
|
||||
if (len >= size)
|
||||
return -ENOSPC;
|
||||
p += len;
|
||||
size -= len;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_read_path(char *path, size_t size, const char *prefix, const char *name)
|
||||
{
|
||||
const char *path;
|
||||
char filename[PATH_MAX], *data;
|
||||
struct stat sbuf;
|
||||
int fd;
|
||||
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;
|
||||
}
|
||||
|
||||
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 = getenv("PIPEWIRE_CONFIG_DIR");
|
||||
if (dir == NULL)
|
||||
dir = PIPEWIRE_CONFIG_DIR;
|
||||
if (dir == NULL)
|
||||
if (dir != NULL) {
|
||||
const char *paths[] = { dir, prefix, name, NULL };
|
||||
if (make_path(path, size, paths) == 0 &&
|
||||
access(path, R_OK) == 0)
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ensure_path(char *path, int size, const char *paths[])
|
||||
{
|
||||
int i, len, res;
|
||||
char *p = path;
|
||||
|
||||
for (i = 0; paths[i] != NULL; i++) {
|
||||
len = snprintf(p, size, "%s/", paths[i]);
|
||||
if (len < 0)
|
||||
return -errno;
|
||||
if (len >= size)
|
||||
return -ENOSPC;
|
||||
|
||||
p += len;
|
||||
size -= len;
|
||||
|
||||
if ((res = access(path, R_OK | W_OK | X_OK)) < 0) {
|
||||
if (errno != ENOENT)
|
||||
return -errno;
|
||||
if ((res = mkdir(path, 0700)) < 0) {
|
||||
pw_log_info("Can't create directory %s: %m", path);
|
||||
return -errno;
|
||||
}
|
||||
if ((res = access(path, R_OK | W_OK | X_OK)) < 0)
|
||||
return -errno;
|
||||
|
||||
pw_log_info("created directory %s", path);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int open_write_dir(char *path, int size, const char *prefix)
|
||||
{
|
||||
const char *dir;
|
||||
char buffer[4096];
|
||||
int res;
|
||||
|
||||
if (prefix != NULL && prefix[0] == '/') {
|
||||
const char *paths[] = { prefix, NULL };
|
||||
if (ensure_path(path, size, paths) == 0)
|
||||
goto found;
|
||||
}
|
||||
dir = getenv("XDG_CONFIG_HOME");
|
||||
if (dir != NULL) {
|
||||
const char *paths[] = { dir, "pipewire", prefix, NULL };
|
||||
if (ensure_path(path, size, paths) == 0)
|
||||
goto found;
|
||||
}
|
||||
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, NULL };
|
||||
if (ensure_path(path, size, paths) == 0)
|
||||
goto found;
|
||||
}
|
||||
return -ENOENT;
|
||||
found:
|
||||
if ((res = open(path, O_CLOEXEC | O_DIRECTORY | O_PATH)) < 0) {
|
||||
pw_log_error("Can't open state directory %s: %m", path);
|
||||
return -errno;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
SPA_EXPORT
|
||||
int pw_conf_save_state(const char *prefix, const char *name, struct pw_properties *conf)
|
||||
{
|
||||
const struct spa_dict_item *it;
|
||||
char path[PATH_MAX];
|
||||
char *tmp_name;
|
||||
int res, sfd, fd;
|
||||
FILE *f;
|
||||
|
||||
if ((sfd = open_write_dir(path, sizeof(path), prefix)) < 0)
|
||||
return sfd;
|
||||
|
||||
tmp_name = alloca(strlen(name)+5);
|
||||
sprintf(tmp_name, "%s.tmp", name);
|
||||
if ((fd = openat(sfd, tmp_name, O_CLOEXEC | O_CREAT | O_WRONLY | O_TRUNC, 0700)) < 0) {
|
||||
pw_log_error("can't open file '%s': %m", tmp_name);
|
||||
res = -errno;
|
||||
goto error;
|
||||
}
|
||||
|
||||
f = fdopen(fd, "w");
|
||||
fprintf(f, "{ \n");
|
||||
spa_dict_for_each(it, &conf->dict) {
|
||||
char key[1024];
|
||||
|
||||
if (spa_json_encode_string(key, sizeof(key)-1, it->key) >= (int)sizeof(key)-1)
|
||||
continue;
|
||||
|
||||
fprintf(f, " %s: %s\n", key, it->value);
|
||||
}
|
||||
fprintf(f, "}\n");
|
||||
fclose(f);
|
||||
|
||||
if (renameat(sfd, tmp_name, sfd, name) < 0) {
|
||||
pw_log_error("can't rename temp file '%s': %m", tmp_name);
|
||||
res = -errno;
|
||||
goto error;
|
||||
}
|
||||
res = 0;
|
||||
pw_log_info(NAME" %p: saved state '%s%s'", conf, path, name);
|
||||
error:
|
||||
close(sfd);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int conf_load(const char *prefix, const char *name, struct pw_properties *conf)
|
||||
{
|
||||
char path[PATH_MAX], *data;
|
||||
struct stat sbuf;
|
||||
int fd;
|
||||
|
||||
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);
|
||||
return -ENOENT;
|
||||
|
||||
if (prefix)
|
||||
snprintf(filename, sizeof(filename), "%s/%s/%s",
|
||||
dir, prefix, name);
|
||||
else
|
||||
snprintf(filename, sizeof(filename), "%s/%s",
|
||||
dir, name);
|
||||
path = filename;
|
||||
|
||||
}
|
||||
if ((fd = open(path, O_CLOEXEC | O_RDONLY)) < 0) {
|
||||
pw_log_warn(NAME" %p: error loading config '%s': %m", conf, path);
|
||||
return -errno;
|
||||
|
|
@ -85,6 +254,18 @@ error_close:
|
|||
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);
|
||||
}
|
||||
|
||||
SPA_EXPORT
|
||||
int pw_conf_load_state(const char *prefix, const char *name, struct pw_properties *conf)
|
||||
{
|
||||
return conf_load(prefix, name, conf);
|
||||
}
|
||||
|
||||
static int parse_spa_libs(struct pw_context *context, const char *str)
|
||||
{
|
||||
struct spa_json it[2];
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue