From: Yu Watanabe Date: Sun, 29 Jun 2025 01:12:09 +0000 (+0900) Subject: conf-files: introduce struct ConfFile to store information of found conf file X-Git-Tag: v258-rc1~101^2~10 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=31b7616420b9a76273520966e28699651497e496;p=thirdparty%2Fsystemd.git conf-files: introduce struct ConfFile to store information of found conf file It is currently unused, will be used later. Preparation for later changes. --- diff --git a/src/basic/conf-files.c b/src/basic/conf-files.c index 8b4d3d75486..0c5b464318a 100644 --- a/src/basic/conf-files.c +++ b/src/basic/conf-files.c @@ -20,6 +20,187 @@ #include "string-util.h" #include "strv.h" +ConfFile* conf_file_free(ConfFile *c) { + if (!c) + return NULL; + + free(c->name); + free(c->result); + free(c->original_path); + free(c->resolved_path); + safe_close(c->fd); + + return mfree(c); +} + +void conf_file_free_many(ConfFile **array, size_t n) { + FOREACH_ARRAY(i, array, n) + conf_file_free(*i); + + free(array); +} + +static int prepare_dirs(const char *root, char * const *dirs, int *ret_rfd, char **ret_root, 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_dirs || strv_isempty(dirs)); + + r = empty_or_root_harder_to_null(&root); + if (r < 0) + return log_debug_errno(r, "Failed to determine if '%s' points to the root directory: %m", strempty(root)); + + if (ret_dirs) { + dirs_abs = strv_copy(dirs); + if (!dirs_abs) + return log_oom(); + } + + 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. */ + r = path_make_absolute_cwd(root, &root_abs); + if (r < 0) + return log_debug_errno(r, "Failed to make '%s' absolute: %m", root); + + path_simplify(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. */ + r = path_strv_make_absolute_cwd(dirs_abs); + if (r < 0) + return log_debug_errno(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_debug_errno(errno, "Failed to open '%s': %m", empty_to_root(root_abs)); + + *ret_rfd = TAKE_FD(rfd); + *ret_root = TAKE_PTR(root_abs); + if (ret_dirs) + *ret_dirs = TAKE_PTR(dirs_abs); + return 0; +} + +static int conf_file_prefix_root(ConfFile *c, const char *root) { + char *p; + int r; + + assert(c); + + r = chaseat_prefix_root(c->result, root, &p); + if (r < 0) + return log_debug_errno(r, "Failed to prefix '%s' with root '%s': %m", c->result, root); + free_and_replace(c->result, p); + + r = chaseat_prefix_root(c->resolved_path, root, &p); + if (r < 0) + return log_debug_errno(r, "Failed to prefix '%s' with root '%s': %m", c->resolved_path, root); + free_and_replace(c->resolved_path, p); + + /* Do not use chaseat_prefix_root(), as it is for the result of chaseat(), but the path is not chased. */ + p = path_join(empty_to_root(root), skip_leading_slash(c->original_path)); + if (!p) + return log_oom_debug(); + path_simplify(p); + free_and_replace(c->original_path, p); + + return 0; +} + +int conf_file_new_at(const char *path, int rfd, ChaseFlags chase_flags, ConfFile **ret) { + int r; + + assert(path); + assert(rfd >= 0 || rfd == AT_FDCWD); + assert(ret); + + _cleanup_free_ char *root = NULL; + if (rfd >= 0 && DEBUG_LOGGING) + (void) fd_get_path(rfd, &root); + + _cleanup_(conf_file_freep) ConfFile *c = new(ConfFile, 1); + if (!c) + return log_oom_debug(); + + *c = (ConfFile) { + .original_path = strdup(path), + .fd = -EBADF, + }; + + if (!c->original_path) + return log_oom_debug(); + + r = path_extract_filename(path, &c->name); + if (r < 0) + return log_debug_errno(r, "Failed to extract filename from '%s': %m", path); + + _cleanup_free_ char *dirpath = NULL, *resolved_dirpath = NULL; + r = path_extract_directory(path, &dirpath); + if (r < 0 && r != -EDESTADDRREQ) + return log_debug_errno(r, "Failed to extract directory from '%s': %m", path); + if (r >= 0) { + r = chaseat(rfd, dirpath, + CHASE_AT_RESOLVE_IN_ROOT | (FLAGS_SET(chase_flags, CHASE_NONEXISTENT) ? CHASE_NONEXISTENT : CHASE_MUST_BE_DIRECTORY), + &resolved_dirpath, /* ret_fd = */ NULL); + if (r < 0) + return log_debug_errno(r, "Failed to chase '%s%s': %m", empty_to_root(root), skip_leading_slash(dirpath)); + } + + c->result = path_join(resolved_dirpath, c->name); + if (!c->result) + return log_oom_debug(); + + r = chaseat(rfd, c->result, CHASE_AT_RESOLVE_IN_ROOT | chase_flags, &c->resolved_path, &c->fd); + if (r < 0) + return log_debug_errno(r, "Failed to chase '%s%s': %m", empty_to_root(root), skip_leading_slash(c->original_path)); + + if (c->fd >= 0 && fstat(c->fd, &c->st) < 0) + return log_debug_errno(r, "Failed to stat '%s%s': %m", empty_to_root(root), skip_leading_slash(c->resolved_path)); + + *ret = TAKE_PTR(c); + return 0; +} + +int conf_file_new(const char *path, const char *root, ChaseFlags chase_flags, ConfFile **ret) { + int r; + + assert(path); + assert((chase_flags & (CHASE_PREFIX_ROOT | CHASE_STEP)) == 0); + assert(ret); + + _cleanup_free_ char *root_abs = NULL; + _cleanup_close_ int rfd = -EBADF; + r = prepare_dirs(root, /* dirs = */ NULL, &rfd, &root_abs, /* ret_dirs = */ NULL); + if (r < 0) + return r; + + _cleanup_free_ char *path_abs = NULL; + if (!root_abs) { + r = path_make_absolute_cwd(path, &path_abs); + if (r < 0) + return log_debug_errno(r, "Failed to make '%s' absolute: %m", path); + + path = path_abs; + } + + _cleanup_(conf_file_freep) ConfFile *c = NULL; + r = conf_file_new_at(path, rfd, chase_flags, &c); + if (r < 0) + return r; + + r = conf_file_prefix_root(c, root_abs); + if (r < 0) + return r; + + *ret = TAKE_PTR(c); + return 0; +} + static int files_add( DIR *dir, const char *dirpath, @@ -332,49 +513,6 @@ static int conf_files_list_impl( return 0; } -static int prepare_dirs(const char *root, char * const *dirs, int *ret_rfd, char **ret_root, 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_dirs); - - r = empty_or_root_harder_to_null(&root); - if (r < 0) - return log_debug_errno(r, "Failed to determine if '%s' points to the root directory: %m", strempty(root)); - - dirs_abs = strv_copy(dirs); - if (!dirs_abs) - return log_oom(); - - 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. */ - r = path_make_absolute_cwd(root, &root_abs); - if (r < 0) - return log_debug_errno(r, "Failed to make '%s' absolute: %m", root); - - path_simplify(root_abs); - } else { - /* When an empty root or "/" is specified, we will open "/" below, hence we need to make - * each config directory absolute if relative. */ - r = path_strv_make_absolute_cwd(dirs_abs); - if (r < 0) - return log_debug_errno(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_debug_errno(errno, "Failed to open '%s': %m", empty_to_root(root_abs)); - - *ret_rfd = TAKE_FD(rfd); - *ret_root = TAKE_PTR(root_abs); - *ret_dirs = TAKE_PTR(dirs_abs); - return 0; -} - int conf_files_list_strv( char ***ret, const char *suffix, diff --git a/src/basic/conf-files.h b/src/basic/conf-files.h index 710e74c959f..3941dead248 100644 --- a/src/basic/conf-files.h +++ b/src/basic/conf-files.h @@ -1,6 +1,8 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once +#include + #include "forward.h" typedef enum ConfFilesFlags { @@ -13,6 +15,22 @@ typedef enum ConfFilesFlags { CONF_FILES_FILTER_MASKED = CONF_FILES_FILTER_MASKED_BY_SYMLINK | CONF_FILES_FILTER_MASKED_BY_EMPTY, } ConfFilesFlags; +typedef struct ConfFile { + char *name; /* name of a file found in config directories */ + char *result; /* resolved config directory with the original file name found in the directory */ + char *original_path; /* original config directory with the original file name found in the directory */ + char *resolved_path; /* fully resolved path, where the filename part of the path may be different from the original name */ + int fd; /* O_PATH fd to resolved_path, -EBADF if the resolved_path does not exist */ + struct stat st; /* stat of the file. */ +} ConfFile; + +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, ChaseFlags chase_flags, ConfFile **ret); +int conf_file_new(const char *path, const char *root, ChaseFlags chase_flags, ConfFile **ret); + int conf_files_list(char ***ret, const char *suffix, const char *root, ConfFilesFlags flags, const char *dir); int conf_files_list_at(char ***ret, const char *suffix, int rfd, ConfFilesFlags flags, const char *dir); int conf_files_list_strv(char ***ret, const char *suffix, const char *root, ConfFilesFlags flags, const char* const* dirs); diff --git a/src/basic/forward.h b/src/basic/forward.h index 7b8ce78b988..7175120e5b4 100644 --- a/src/basic/forward.h +++ b/src/basic/forward.h @@ -104,6 +104,7 @@ typedef struct Set Set; typedef struct dual_timestamp dual_timestamp; typedef struct triple_timestamp triple_timestamp; +typedef struct ConfFile ConfFile; typedef struct LockFile LockFile; typedef struct PidRef PidRef; typedef struct Prioq Prioq;