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
+75 -19
View File
@@ -481,6 +481,7 @@ int hashmap_put_stats_by_path(Hashmap **stats_by_path, const char *path, const s
static int config_parse_many_files(
const char *root,
int root_fd,
const char* const* conf_files,
char **files,
const char *sections,
@@ -502,17 +503,17 @@ static int config_parse_many_files(
return log_oom_full(level);
}
/* Pin and stat() all dropins */
STRV_FOREACH(fn, files) {
_cleanup_fclose_ FILE *f = NULL;
_cleanup_free_ char *fname = NULL;
r = chase_and_fopen_unlocked(*fn, root, CHASE_AT_RESOLVE_IN_ROOT, "re", &fname, &f);
r = chase_and_fopenat_unlocked(root_fd, *fn, CHASE_AT_RESOLVE_IN_ROOT|CHASE_MUST_BE_REGULAR, "re", /* ret_path= */ NULL, &f);
if (r == -ENOENT)
continue;
if (r < 0)
return log_full_errno(level, r, "Failed to open %s: %m", *fn);
int fd = fileno(f);
assert(fd >= 0);
r = ordered_hashmap_ensure_put(&dropins, &config_file_hash_ops_fclose, *fn, f);
if (r < 0) {
@@ -537,11 +538,10 @@ static int config_parse_many_files(
return log_oom_full(level);
}
/* First read the first found main config file. */
/* First process the first found main config file. */
STRV_FOREACH(fn, conf_files) {
_cleanup_fclose_ FILE *f = NULL;
r = chase_and_fopen_unlocked(*fn, root, CHASE_AT_RESOLVE_IN_ROOT, "re", NULL, &f);
r = chase_and_fopenat_unlocked(root_fd, *fn, CHASE_AT_RESOLVE_IN_ROOT|CHASE_MUST_BE_REGULAR, "re", /* ret_path= */ NULL, &f);
if (r == -ENOENT)
continue;
if (r < 0)
@@ -572,7 +572,6 @@ static int config_parse_many_files(
}
/* Then read all the drop-ins. */
const char *path_dropin;
FILE *f_dropin;
ORDERED_HASHMAP_FOREACH_KEY(f_dropin, path_dropin, dropins) {
@@ -594,12 +593,39 @@ static int config_parse_many_files(
return 0;
}
static int normalize_root_fd(const char *root, int *root_fd, int *ret_opened_fd) {
assert(root_fd);
assert(ret_opened_fd);
/* Normalizes a root dir specification: if root_fd is already valid, keep it. Otherwise, we open the
* specified dir */
if (*root_fd >= 0 || IN_SET(*root_fd, AT_FDCWD, XAT_FDROOT)) {
*ret_opened_fd = -EBADF;
return 0;
}
if (empty_or_root(root)) {
*root_fd = XAT_FDROOT;
*ret_opened_fd = -EBADF;
return 0;
}
int fd = open(root, O_CLOEXEC|O_PATH|O_DIRECTORY);
if (fd < 0)
return log_error_errno(errno, "Failed to open root directory '%s': %m", root);
*ret_opened_fd = *root_fd = fd;
return 0;
}
/* Parse each config file in the directories specified as strv. */
int config_parse_many(
int config_parse_many_full(
const char* const* conf_files,
const char* const* conf_file_dirs,
const char *dropin_dirname,
const char *root,
int root_fd,
const char *sections,
ConfigItemLookup lookup,
const void *table,
@@ -615,14 +641,33 @@ int config_parse_many(
assert(dropin_dirname);
assert(table);
r = conf_files_list_dropins(&files, dropin_dirname, root,
FLAGS_SET(flags, CONFIG_PARSE_WARN) ? CONF_FILES_WARN : 0,
conf_file_dirs);
_cleanup_close_ int opened_root_fd = -EBADF;
r = normalize_root_fd(root, &root_fd, &opened_root_fd);
if (r < 0)
return r;
r = conf_files_list_dropins(
&files,
dropin_dirname,
root,
root_fd,
FLAGS_SET(flags, CONFIG_PARSE_WARN) ? CONF_FILES_WARN : 0,
conf_file_dirs);
if (r < 0)
return log_full_errno(FLAGS_SET(flags, CONFIG_PARSE_WARN) ? LOG_WARNING : LOG_DEBUG, r,
"Failed to list drop-ins in %s: %m", dropin_dirname);
r = config_parse_many_files(root, conf_files, files, sections, lookup, table, flags, userdata, ret_stats_by_path);
r = config_parse_many_files(
root,
root_fd,
conf_files,
files,
sections,
lookup,
table,
flags,
userdata,
ret_stats_by_path);
if (r < 0)
return r; /* config_parse_many_files() logs internally. */
@@ -634,6 +679,7 @@ int config_parse_many(
int config_parse_standard_file_with_dropins_full(
const char *root,
int root_fd,
const char *main_file, /* A path like "systemd/frobnicator.conf" */
const char *sections,
ConfigItemLookup lookup,
@@ -643,12 +689,15 @@ int config_parse_standard_file_with_dropins_full(
Hashmap **ret_stats_by_path,
char ***ret_dropin_files) {
const char* const *conf_paths = (const char* const*) CONF_PATHS_STRV("");
_cleanup_strv_free_ char **configs = NULL;
const char* const *conf_file_dirs = (const char* const*) CONF_PATHS_STRV("");
_cleanup_strv_free_ char **conf_files = NULL;
int r, level = FLAGS_SET(flags, CONFIG_PARSE_WARN) ? LOG_WARNING : LOG_DEBUG;
/* Build the list of main config files */
r = strv_extend_strv_biconcat(&configs, root, conf_paths, main_file);
r = strv_extend_strv_concat(
&conf_files,
conf_file_dirs,
main_file);
if (r < 0)
return log_oom_full(level);
@@ -656,11 +705,12 @@ int config_parse_standard_file_with_dropins_full(
if (!dropin_dirname)
return log_oom_full(level);
return config_parse_many(
(const char* const*) configs,
conf_paths,
return config_parse_many_full(
(const char* const*) conf_files,
conf_file_dirs,
dropin_dirname,
root,
root_fd,
sections,
lookup,
table,
@@ -692,7 +742,13 @@ static int dropins_get_stats_by_path(
if (!strextend(&dropin_dirname, ".d"))
return -ENOMEM;
r = conf_files_list_dropins(&files, dropin_dirname, /* root= */ NULL, /* flags= */ 0, conf_file_dirs);
r = conf_files_list_dropins(
&files,
dropin_dirname,
/* root= */ NULL,
/* root_fd= */ XAT_FDROOT,
/* flags= */ 0,
conf_file_dirs);
if (r < 0)
return r;
+30 -2
View File
@@ -5,7 +5,7 @@
#include "alloc-util.h"
#include "conf-parser-forward.h"
#include "shared-forward.h"
#include "fd-util.h"
#include "log.h"
/* An abstract parser for simple, line based, shallow configuration files consisting of variable assignments only. */
@@ -66,11 +66,12 @@ int config_parse(
void *userdata,
struct stat *ret_stat); /* possibly NULL */
int config_parse_many(
int config_parse_many_full(
const char* const* conf_files, /* possibly empty */
const char* const* conf_file_dirs,
const char *dropin_dirname,
const char *root,
int root_fd,
const char *sections, /* nulstr */
ConfigItemLookup lookup,
const void *table,
@@ -79,8 +80,34 @@ int config_parse_many(
Hashmap **ret_stats_by_path, /* possibly NULL */
char ***ret_dropin_files); /* possibly NULL */
static inline int config_parse_many(
const char* const* conf_files, /* possibly empty */
const char* const* conf_file_dirs,
const char *dropin_dirname,
const char *sections, /* nulstr */
ConfigItemLookup lookup,
const void *table,
ConfigParseFlags flags,
void *userdata) {
return config_parse_many_full(
conf_files,
conf_file_dirs,
dropin_dirname,
/* root= */ NULL,
/* root_fd= */ XAT_FDROOT,
sections,
lookup,
table,
flags,
userdata,
/* ret_stats_by_path= */ NULL,
/* ret_drop_in_files= */ NULL);
}
int config_parse_standard_file_with_dropins_full(
const char *root,
int root_fd,
const char *main_file, /* A path like "systemd/frobnicator.conf" */
const char *sections,
ConfigItemLookup lookup,
@@ -99,6 +126,7 @@ static inline int config_parse_standard_file_with_dropins(
void *userdata) {
return config_parse_standard_file_with_dropins_full(
/* root= */ NULL,
/* root_fd= */ XAT_FDROOT,
main_file,
sections,
lookup,
+9 -3
View File
@@ -2,11 +2,13 @@
#include "alloc-util.h"
#include "conf-parser.h"
#include "fd-util.h"
#include "kernel-config.h"
#include "path-util.h"
int load_kernel_install_conf(
int load_kernel_install_conf_at(
const char *root,
int root_fd,
const char *conf_root,
char **ret_machine_id,
char **ret_boot_root,
@@ -26,16 +28,19 @@ int load_kernel_install_conf(
};
int r;
assert(root_fd >= 0 || IN_SET(root_fd, AT_FDCWD, XAT_FDROOT));
if (conf_root) {
_cleanup_free_ char *conf = path_join(conf_root, "install.conf");
if (!conf)
return log_oom();
r = config_parse_many(
r = config_parse_many_full(
STRV_MAKE_CONST(conf),
STRV_MAKE_CONST(conf_root),
"install.conf.d",
/* root= */ NULL, /* $KERNEL_INSTALL_CONF_ROOT and --root are independent */
root,
root_fd,
/* sections= */ NULL,
config_item_table_lookup, items,
CONFIG_PARSE_WARN,
@@ -45,6 +50,7 @@ int load_kernel_install_conf(
} else
r = config_parse_standard_file_with_dropins_full(
root,
root_fd,
"kernel/install.conf",
/* sections= */ NULL,
config_item_table_lookup, items,
+15 -1
View File
@@ -1,13 +1,27 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include "fd-util.h"
#include "shared-forward.h"
int load_kernel_install_conf(
int load_kernel_install_conf_at(
const char *root,
int root_fd,
const char *conf_root,
char **ret_machine_id,
char **ret_boot_root,
char **ret_layout,
char **ret_initrd_generator,
char **ret_uki_generator);
static inline int load_kernel_install_conf(
const char *root,
const char *conf_root,
char **ret_machine_id,
char **ret_boot_root,
char **ret_layout,
char **ret_initrd_generator,
char **ret_uki_generator) {
return load_kernel_install_conf_at(root, XAT_FDROOT, conf_root, ret_machine_id, ret_boot_root, ret_layout, ret_initrd_generator, ret_uki_generator);
}