conf-files: add support for root_fd based operation

Let's make sure we can safely load configuration files based on a root
fd, including XAT_FDROOT.

(While we are at it, always pass path to root fs before fd to root fs,
following our recently updated CODING_STYLE)
This commit is contained in:
Lennart Poettering
2026-01-25 20:51:50 +01:00
parent 17ade5b2af
commit 6ecfa12af0
19 changed files with 249 additions and 100 deletions
+54 -37
View File
@@ -44,13 +44,20 @@ static int conf_files_log_level(ConfFilesFlags flags) {
return FLAGS_SET(flags, CONF_FILES_WARN) ? LOG_WARNING : LOG_DEBUG;
}
static int prepare_dirs(const char *root, ConfFilesFlags flags, char * const *dirs, int *ret_rfd, char **ret_root, char ***ret_dirs) {
static int prepare_dirs(
const char *root,
ConfFilesFlags flags,
char * const *dirs,
char **ret_root,
int *ret_rfd,
char ***ret_dirs) {
_cleanup_free_ char *root_abs = NULL;
_cleanup_strv_free_ char **dirs_abs = NULL;
int r;
assert(ret_rfd);
assert(ret_root);
assert(ret_rfd);
assert(ret_dirs || strv_isempty(dirs));
int log_level = conf_files_log_level(flags);
@@ -65,6 +72,7 @@ static int prepare_dirs(const char *root, ConfFilesFlags flags, char * const *di
return log_oom_full(log_level);
}
_cleanup_close_ int rfd = XAT_FDROOT;
if (root) {
/* When a non-trivial root is specified, we will prefix the result later. Hence, it is not
* necessary to modify each config directories here. but needs to normalize the root directory. */
@@ -73,6 +81,11 @@ static int prepare_dirs(const char *root, ConfFilesFlags flags, char * const *di
return log_full_errno(log_level, r, "Failed to make '%s' absolute: %m", root);
path_simplify(root_abs);
rfd = open(root, O_CLOEXEC|O_DIRECTORY|O_PATH);
if (rfd < 0)
return log_full_errno(log_level, errno, "Failed to open '%s': %m", root_abs);
} else if (ret_dirs) {
/* When an empty root or "/" is specified, we will open "/" below, hence we need to make
* each config directory absolute if relative. */
@@ -81,12 +94,8 @@ static int prepare_dirs(const char *root, ConfFilesFlags flags, char * const *di
return log_full_errno(log_level, r, "Failed to make directories absolute: %m");
}
_cleanup_close_ int rfd = open(empty_to_root(root_abs), O_CLOEXEC|O_DIRECTORY|O_PATH);
if (rfd < 0)
return log_full_errno(log_level, errno, "Failed to open '%s': %m", empty_to_root(root_abs));
*ret_rfd = TAKE_FD(rfd);
*ret_root = TAKE_PTR(root_abs);
*ret_rfd = TAKE_FD(rfd);
if (ret_dirs)
*ret_dirs = TAKE_PTR(dirs_abs);
return 0;
@@ -135,8 +144,8 @@ static ChaseFlags conf_files_chase_flags(ConfFilesFlags flags) {
}
static int conf_file_chase_and_verify(
int rfd,
const char *root, /* for logging, can be NULL */
int rfd,
const char *original_path, /* for logging */
const char *path,
const char *name,
@@ -151,7 +160,7 @@ static int conf_file_chase_and_verify(
struct stat st = {};
int r;
assert(rfd >= 0 || rfd == AT_FDCWD);
assert(rfd >= 0 || IN_SET(rfd, AT_FDCWD, XAT_FDROOT));
assert(original_path);
assert(path);
assert(name);
@@ -261,18 +270,25 @@ static int conf_file_chase_and_verify(
return 0;
}
int conf_file_new_at(const char *path, int rfd, ConfFilesFlags flags, ConfFile **ret) {
int conf_file_new_at(
const char *path,
const char *root,
int rfd,
ConfFilesFlags flags,
ConfFile **ret) {
int r;
assert(path);
assert(rfd >= 0 || rfd == AT_FDCWD);
assert(rfd >= 0 || IN_SET(rfd, AT_FDCWD, XAT_FDROOT));
assert(ret);
int log_level = conf_files_log_level(flags);
_cleanup_free_ char *root = NULL;
if (rfd >= 0)
(void) fd_get_path(rfd, &root);
_cleanup_free_ char *_root = NULL;
if (DEBUG_LOGGING && !root) {
(void) fd_get_path(rfd, &_root);
root = _root;
}
_cleanup_(conf_file_freep) ConfFile *c = new(ConfFile, 1);
if (!c)
@@ -307,8 +323,8 @@ int conf_file_new_at(const char *path, int rfd, ConfFilesFlags flags, ConfFile *
return log_oom_full(log_level);
r = conf_file_chase_and_verify(
rfd,
root,
rfd,
c->original_path,
c->result,
c->name,
@@ -332,7 +348,7 @@ int conf_file_new(const char *path, const char *root, ConfFilesFlags flags, Conf
_cleanup_free_ char *root_abs = NULL;
_cleanup_close_ int rfd = -EBADF;
r = prepare_dirs(root, flags, /* dirs= */ NULL, &rfd, &root_abs, /* ret_dirs= */ NULL);
r = prepare_dirs(root, flags, /* dirs= */ NULL, &root_abs, &rfd, /* ret_dirs= */ NULL);
if (r < 0)
return r;
@@ -346,7 +362,7 @@ int conf_file_new(const char *path, const char *root, ConfFilesFlags flags, Conf
}
_cleanup_(conf_file_freep) ConfFile *c = NULL;
r = conf_file_new_at(path, rfd, flags, &c);
r = conf_file_new_at(path, root_abs, rfd, flags, &c);
if (r < 0)
return r;
@@ -367,8 +383,8 @@ static int files_add(
DIR *dir,
const char *original_dirpath,
const char *resolved_dirpath,
int rfd,
const char *root, /* for logging, can be NULL */
int rfd,
Hashmap **files,
Set **masked,
const char *suffix,
@@ -379,7 +395,7 @@ static int files_add(
assert(dir);
assert(original_dirpath);
assert(resolved_dirpath);
assert(rfd >= 0 || rfd == AT_FDCWD);
assert(rfd >= 0 || IN_SET(rfd, AT_FDCWD, XAT_FDROOT));
assert(files);
assert(masked);
@@ -420,8 +436,8 @@ static int files_add(
_cleanup_close_ int fd = -EBADF;
struct stat st;
r = conf_file_chase_and_verify(
rfd,
root,
rfd,
original_path,
p,
de->d_name,
@@ -597,8 +613,8 @@ static int insert_replacement(Hashmap **fh, ConfFile *replacement, ConfFilesFlag
static int conf_files_list_impl(
const char *suffix,
int rfd,
const char *root, /* for logging, can be NULL */
int rfd,
ConfFilesFlags flags,
const char * const *dirs,
const char *replacement,
@@ -611,13 +627,13 @@ static int conf_files_list_impl(
const ConfFile *inserted = NULL;
int r;
assert(rfd >= 0 || rfd == AT_FDCWD);
assert(rfd >= 0 || IN_SET(rfd, AT_FDCWD, XAT_FDROOT));
assert(ret);
root = empty_to_root(root);
if (replacement) {
r = conf_file_new_at(replacement, rfd, flags & CONF_FILES_WARN, &c);
r = conf_file_new_at(replacement, root, rfd, flags & CONF_FILES_WARN, &c);
if (r < 0)
return r;
}
@@ -641,7 +657,7 @@ static int conf_files_list_impl(
return r;
}
r = files_add(dir, *p, path, rfd, root, &fh, &masked, suffix, flags);
r = files_add(dir, *p, path, root, rfd, &fh, &masked, suffix, flags);
if (r == -ENOMEM)
return r;
}
@@ -673,11 +689,11 @@ int conf_files_list_strv(
assert(ret);
r = prepare_dirs(root, flags, (char**) dirs, &rfd, &root_abs, &dirs_abs);
r = prepare_dirs(root, flags, (char**) dirs, &root_abs, &rfd, &dirs_abs);
if (r < 0)
return r;
r = conf_files_list_impl(suffix, rfd, root_abs, flags, (const char * const *) dirs_abs,
r = conf_files_list_impl(suffix, root_abs, rfd, flags, (const char * const *) dirs_abs,
/* replacement= */ NULL, &fh, /* ret_inserted= */ NULL);
if (r < 0)
return r;
@@ -702,11 +718,11 @@ int conf_files_list_strv_full(
assert(ret_files);
assert(ret_n_files);
r = prepare_dirs(root, flags, (char**) dirs, &rfd, &root_abs, &dirs_abs);
r = prepare_dirs(root, flags, (char**) dirs, &root_abs, &rfd, &dirs_abs);
if (r < 0)
return r;
r = conf_files_list_impl(suffix, rfd, root_abs, flags, (const char * const *) dirs_abs,
r = conf_files_list_impl(suffix, root_abs, rfd, flags, (const char * const *) dirs_abs,
/* replacement= */ NULL, &fh, /* ret_inserted= */ NULL);
if (r < 0)
return r;
@@ -725,13 +741,13 @@ int conf_files_list_strv_at(
_cleanup_free_ char *root = NULL;
int r;
assert(rfd >= 0 || rfd == AT_FDCWD);
assert(rfd >= 0 || IN_SET(rfd, AT_FDCWD, XAT_FDROOT));
assert(ret);
if (rfd >= 0)
if (DEBUG_LOGGING)
(void) fd_get_path(rfd, &root); /* for logging */
r = conf_files_list_impl(suffix, rfd, root, flags, dirs, /* replacement= */ NULL, &fh, /* ret_inserted= */ NULL);
r = conf_files_list_impl(suffix, root, rfd, flags, dirs, /* replacement= */ NULL, &fh, /* ret_inserted= */ NULL);
if (r < 0)
return r;
@@ -750,14 +766,14 @@ int conf_files_list_strv_at_full(
_cleanup_free_ char *root = NULL;
int r;
assert(rfd >= 0 || rfd == AT_FDCWD);
assert(rfd >= 0 || IN_SET(rfd, AT_FDCWD, XAT_FDROOT));
assert(ret_files);
assert(ret_n_files);
if (rfd >= 0)
if (DEBUG_LOGGING)
(void) fd_get_path(rfd, &root); /* for logging */
r = conf_files_list_impl(suffix, rfd, root, flags, dirs, /* replacement= */ NULL, &fh, /* ret_inserted= */ NULL);
r = conf_files_list_impl(suffix, root, rfd, flags, dirs, /* replacement= */ NULL, &fh, /* ret_inserted= */ NULL);
if (r < 0)
return r;
@@ -848,11 +864,11 @@ int conf_files_list_with_replacement(
assert(ret_files);
r = prepare_dirs(root, flags, config_dirs, &rfd, &root_abs, &dirs_abs);
r = prepare_dirs(root, flags, config_dirs, &root_abs, &rfd, &dirs_abs);
if (r < 0)
return r;
r = conf_files_list_impl(".conf", rfd, root_abs, flags, (const char * const *) dirs_abs,
r = conf_files_list_impl(".conf", root_abs, rfd, flags, (const char * const *) dirs_abs,
replacement, &fh, ret_inserted ? &c : NULL);
if (r < 0)
return r;
@@ -878,6 +894,7 @@ int conf_files_list_dropins(
char ***ret,
const char *dropin_dirname,
const char *root,
int root_fd,
ConfFilesFlags flags,
const char * const *dirs) {
@@ -894,7 +911,7 @@ int conf_files_list_dropins(
if (r < 0)
return log_oom_full(conf_files_log_level(flags));
return conf_files_list_strv(ret, ".conf", root, flags, (const char* const*) dropin_dirs);
return conf_files_list_strv_at(ret, ".conf", root_fd, flags, (const char* const*) dropin_dirs);
}
/**
+2 -1
View File
@@ -30,7 +30,7 @@ ConfFile* conf_file_free(ConfFile *c);
DEFINE_TRIVIAL_CLEANUP_FUNC(ConfFile*, conf_file_free);
void conf_file_free_many(ConfFile **array, size_t n);
int conf_file_new_at(const char *path, int rfd, ConfFilesFlags flags, ConfFile **ret);
int conf_file_new_at(const char *path, const char *root, int rfd, ConfFilesFlags flags, ConfFile **ret);
int conf_file_new(const char *path, const char *root, ConfFilesFlags flags, ConfFile **ret);
int conf_files_list(char ***ret, const char *suffix, const char *root, ConfFilesFlags flags, const char *dir);
@@ -57,6 +57,7 @@ int conf_files_list_dropins(
char ***ret,
const char *dropin_dirname,
const char *root,
int root_fd,
ConfFilesFlags flags,
const char * const *dirs);