From: Lennart Poettering Date: Fri, 5 Sep 2025 12:21:53 +0000 (+0200) Subject: conf-files: add support for root_fd based operation X-Git-Tag: v260-rc1~311^2~4 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=6ecfa12af05ca181a12e1ecde6ba5e35e139a16c;p=thirdparty%2Fsystemd.git 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) --- diff --git a/src/basic/conf-files.c b/src/basic/conf-files.c index 76ff20f07b9..4d4cf27952f 100644 --- a/src/basic/conf-files.c +++ b/src/basic/conf-files.c @@ -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); } /** diff --git a/src/basic/conf-files.h b/src/basic/conf-files.h index 90e5b1bec52..444627b8d04 100644 --- a/src/basic/conf-files.h +++ b/src/basic/conf-files.h @@ -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); diff --git a/src/core/main.c b/src/core/main.c index 687b397e621..3a6284b456b 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -842,11 +842,10 @@ static int parse_config_file(void) { (const char* const*) files, (const char* const*) dirs, "user.conf.d", - /* root= */ NULL, "Manager\0", config_item_table_lookup, items, CONFIG_PARSE_WARN, - NULL, NULL, NULL); + /* userdata= */ NULL); } /* Traditionally "0" was used to turn off the default unit timeouts. Fix this up so that we use diff --git a/src/kernel-install/kernel-install.c b/src/kernel-install/kernel-install.c index b80f8d50ee0..b79e830844e 100644 --- a/src/kernel-install/kernel-install.c +++ b/src/kernel-install/kernel-install.c @@ -460,13 +460,15 @@ static int context_load_install_conf(Context *c) { assert(c); - r = load_kernel_install_conf(arg_root, - c->conf_root, - &machine_id, - &boot_root, - &layout, - &initrd_generator, - &uki_generator); + r = load_kernel_install_conf_at( + c->conf_root ? NULL : arg_root, + c->conf_root ? XAT_FDROOT : c->rfd, + c->conf_root, + &machine_id, + &boot_root, + &layout, + &initrd_generator, + &uki_generator); if (r <= 0) return r; diff --git a/src/network/netdev/netdev.c b/src/network/netdev/netdev.c index be35c59fd9c..393114aa7ba 100644 --- a/src/network/netdev/netdev.c +++ b/src/network/netdev/netdev.c @@ -1031,13 +1031,14 @@ int netdev_load_one(Manager *manager, const char *filename, NetDev **ret) { dropin_dirname = strjoina(file_basename, ".d"); r = config_parse_many( - STRV_MAKE_CONST(filename), NETWORK_DIRS, dropin_dirname, /* root= */ NULL, + STRV_MAKE_CONST(filename), + NETWORK_DIRS, + dropin_dirname, NETDEV_COMMON_SECTIONS NETDEV_OTHER_SECTIONS, - config_item_perf_lookup, network_netdev_gperf_lookup, + config_item_perf_lookup, + network_netdev_gperf_lookup, CONFIG_PARSE_WARN, - netdev_raw, - NULL, - NULL); + netdev_raw); if (r < 0) return r; /* config_parse_many() logs internally. */ @@ -1064,10 +1065,15 @@ int netdev_load_one(Manager *manager, const char *filename, NetDev **ret) { if (NETDEV_VTABLE(netdev)->init) NETDEV_VTABLE(netdev)->init(netdev); - r = config_parse_many( - STRV_MAKE_CONST(filename), NETWORK_DIRS, dropin_dirname, /* root= */ NULL, + r = config_parse_many_full( + STRV_MAKE_CONST(filename), + NETWORK_DIRS, + dropin_dirname, + /* root= */ NULL, + /* root_fd= */ -EBADF, NETDEV_VTABLE(netdev)->sections, - config_item_perf_lookup, network_netdev_gperf_lookup, + config_item_perf_lookup, + network_netdev_gperf_lookup, CONFIG_PARSE_WARN, netdev, &netdev->stats_by_path, diff --git a/src/network/networkctl-config-file.c b/src/network/networkctl-config-file.c index 36c6c0e8e1c..9f0236b5406 100644 --- a/src/network/networkctl-config-file.c +++ b/src/network/networkctl-config-file.c @@ -17,6 +17,7 @@ #include "edit-util.h" #include "errno-util.h" #include "extract-word.h" +#include "fd-util.h" #include "log.h" #include "mkdir-label.h" #include "netlink-util.h" @@ -106,7 +107,13 @@ static int get_config_files_by_name( if (!dropin_dirname) return -ENOMEM; - r = conf_files_list_dropins(ret_dropins, dropin_dirname, /* root= */ NULL, CONF_FILES_WARN, NETWORK_DIRS); + r = conf_files_list_dropins( + ret_dropins, + dropin_dirname, + /* root= */ NULL, + /* root_fd= */ XAT_FDROOT, + CONF_FILES_WARN, + NETWORK_DIRS); if (r < 0) return r; } diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index 4d1ed4ccca9..45456d677d2 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -514,8 +514,12 @@ int network_load_one(Manager *manager, OrderedHashmap **networks, const char *fi .ipoib_umcast = -1, }; - r = config_parse_many( - STRV_MAKE_CONST(filename), NETWORK_DIRS, dropin_dirname, /* root= */ NULL, + r = config_parse_many_full( + STRV_MAKE_CONST(filename), + NETWORK_DIRS, + dropin_dirname, + /* root= */ NULL, + /* root_fd= */ -EBADF, "Match\0" "Link\0" "SR-IOV\0" @@ -574,7 +578,8 @@ int network_load_one(Manager *manager, OrderedHashmap **networks, const char *fi "StochasticFairnessQueueing\0" "TokenBucketFilter\0" "TrivialLinkEqualizer\0", - config_item_perf_lookup, network_network_gperf_lookup, + config_item_perf_lookup, + network_network_gperf_lookup, CONFIG_PARSE_WARN, network, &network->stats_by_path, diff --git a/src/repart/repart.c b/src/repart/repart.c index 100e03aab55..97cc60c95b2 100644 --- a/src/repart/repart.c +++ b/src/repart/repart.c @@ -2871,16 +2871,17 @@ static int partition_read_definition( dropin_dirname = strjoina(filename, ".d"); - r = config_parse_many( + r = config_parse_many_full( STRV_MAKE_CONST(path), conf_file_dirs, dropin_dirname, c->definitions ? NULL : arg_root, + /* root_fd= */ -EBADF, "Partition\0", config_item_table_lookup, table, CONFIG_PARSE_WARN, p, - NULL, + /* ret_stats_by_path= */ NULL, &p->drop_in_files); if (r < 0) return r; diff --git a/src/resolve/resolved-dns-delegate.c b/src/resolve/resolved-dns-delegate.c index b866a5838db..eee2daab94b 100644 --- a/src/resolve/resolved-dns-delegate.c +++ b/src/resolve/resolved-dns-delegate.c @@ -188,14 +188,11 @@ static int dns_delegate_load(Manager *m, const char *path) { STRV_MAKE_CONST(path), DNS_DELEGATE_SEARCH_DIRS, dropin_dirname, - /* root= */ NULL, "Delegate\0", config_item_perf_lookup, resolved_dns_delegate_gperf_lookup, /* flags= */ 0, - d, - /* ret_stats_by_path= */ NULL, - /* ret_drop_in_files= */ NULL); + d); if (r < 0) return r; diff --git a/src/resolve/resolved-dnssd.c b/src/resolve/resolved-dnssd.c index 977f7869132..6cc0f86796a 100644 --- a/src/resolve/resolved-dnssd.c +++ b/src/resolve/resolved-dnssd.c @@ -125,13 +125,13 @@ static int dnssd_registered_service_load(Manager *manager, const char *path) { return log_oom(); r = config_parse_many( - STRV_MAKE_CONST(path), DNSSD_SERVICE_DIRS, dropin_dirname, /* root= */ NULL, + STRV_MAKE_CONST(path), + DNSSD_SERVICE_DIRS, + dropin_dirname, "Service\0", config_item_perf_lookup, resolved_dnssd_gperf_lookup, CONFIG_PARSE_WARN, - service, - NULL, - NULL); + service); if (r < 0) return r; diff --git a/src/shared/conf-parser.c b/src/shared/conf-parser.c index e5e18558927..1d1d8a10ccd 100644 --- a/src/shared/conf-parser.c +++ b/src/shared/conf-parser.c @@ -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; diff --git a/src/shared/conf-parser.h b/src/shared/conf-parser.h index b394131b649..0d1324b67d8 100644 --- a/src/shared/conf-parser.h +++ b/src/shared/conf-parser.h @@ -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, diff --git a/src/shared/kernel-config.c b/src/shared/kernel-config.c index 9bc984e9190..415730bf1a3 100644 --- a/src/shared/kernel-config.c +++ b/src/shared/kernel-config.c @@ -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, diff --git a/src/shared/kernel-config.h b/src/shared/kernel-config.h index 5d0f00c9290..eab3fe46410 100644 --- a/src/shared/kernel-config.h +++ b/src/shared/kernel-config.h @@ -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); +} diff --git a/src/sysext/sysext.c b/src/sysext/sysext.c index 072181ea46f..340d762b13f 100644 --- a/src/sysext/sysext.c +++ b/src/sysext/sysext.c @@ -191,6 +191,7 @@ static int parse_config_file(ImageClass image_class) { r = config_parse_standard_file_with_dropins_full( arg_root, + /* root_fd= */ -EBADF, config_file, sections, config_item_table_lookup, items, diff --git a/src/sysupdate/sysupdate-feature.c b/src/sysupdate/sysupdate-feature.c index 2771b58a8ad..795d4ef90a3 100644 --- a/src/sysupdate/sysupdate-feature.c +++ b/src/sysupdate/sysupdate-feature.c @@ -101,11 +101,12 @@ int feature_read_definition(Feature *f, const char *path, const char *const *dir if (r < 0) return log_error_errno(r, "Failed to extract filename from path '%s': %m", path); - r = config_parse_many( + r = config_parse_many_full( STRV_MAKE_CONST(path), dirs, strjoina(filename, ".d"), arg_root, + /* root_fd= */ -EBADF, "Feature\0", config_item_table_lookup, table, CONFIG_PARSE_WARN, diff --git a/src/sysupdate/sysupdate-transfer.c b/src/sysupdate/sysupdate-transfer.c index d6009d5e4c1..51ae49f4076 100644 --- a/src/sysupdate/sysupdate-transfer.c +++ b/src/sysupdate/sysupdate-transfer.c @@ -543,11 +543,12 @@ int transfer_read_definition(Transfer *t, const char *path, const char **dirs, H if (r < 0) return log_error_errno(r, "Failed to extract filename from path '%s': %m", path); - r = config_parse_many( + r = config_parse_many_full( STRV_MAKE_CONST(path), dirs, strjoina(filename, ".d"), arg_root, + /* root_fd= */ -EBADF, "Transfer\0" "Source\0" "Target\0", diff --git a/src/test/test-conf-parser.c b/src/test/test-conf-parser.c index e2f9f28792e..5cae59ce717 100644 --- a/src/test/test-conf-parser.c +++ b/src/test/test-conf-parser.c @@ -444,7 +444,9 @@ TEST(config_parse_standard_file_with_dropins_full) { }; r = config_parse_standard_file_with_dropins_full( - root, "kernel/install.conf", + root, + /* root_fd= */ -EBADF, + "kernel/install.conf", /* sections= */ NULL, config_item_table_lookup, items, CONFIG_PARSE_WARN, @@ -483,7 +485,9 @@ TEST(config_parse_standard_file_with_dropins_full) { assert_se(symlinkat("/etc/kernel/install.conf.d/drop4.conf", rfd, "etc/kernel/install2.conf.d/drop4.conf") == 0); r = config_parse_standard_file_with_dropins_full( - root, "kernel/install2.conf", + root, + /* root_fd= */ -EBADF, + "kernel/install2.conf", /* sections= */ NULL, config_item_table_lookup, items, CONFIG_PARSE_WARN, diff --git a/src/udev/net/link-config.c b/src/udev/net/link-config.c index 378e909b9be..eefa95dc5f6 100644 --- a/src/udev/net/link-config.c +++ b/src/udev/net/link-config.c @@ -280,17 +280,20 @@ int link_load_one(LinkConfigContext *ctx, const char *filename) { return log_error_errno(r, "Failed to extract file name of '%s': %m", filename); dropin_dirname = strjoina(file_basename, ".d"); - r = config_parse_many( + r = config_parse_many_full( STRV_MAKE_CONST(filename), NETWORK_DIRS, dropin_dirname, /* root= */ NULL, + /* root_fd= */ -EBADF, "Match\0" "Link\0" "SR-IOV\0" "EnergyEfficientEthernet\0", config_item_perf_lookup, link_config_gperf_lookup, - CONFIG_PARSE_WARN, config, &stats_by_path, + CONFIG_PARSE_WARN, + config, + &stats_by_path, &config->dropins); if (r < 0) return r; /* config_parse_many() logs internally. */