]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
conf-files: introduce struct ConfFile to store information of found conf file
authorYu Watanabe <watanabe.yu+github@gmail.com>
Sun, 29 Jun 2025 01:12:09 +0000 (10:12 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Fri, 11 Jul 2025 01:41:07 +0000 (10:41 +0900)
It is currently unused, will be used later. Preparation for later changes.

src/basic/conf-files.c
src/basic/conf-files.h
src/basic/forward.h

index 8b4d3d7548656e92d86579fcd56c06175b944e03..0c5b464318a15abc1abf28547956e3c2de422bb8 100644 (file)
 #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,
index 710e74c959fb776df95c050c82267e1af00cc3c3..3941dead24822b222819368ce1eb2c9808cbaa3e 100644 (file)
@@ -1,6 +1,8 @@
 /* SPDX-License-Identifier: LGPL-2.1-or-later */
 #pragma once
 
+#include <sys/stat.h>
+
 #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);
index 7b8ce78b9886f707e47d46d3becf2788d72970cb..7175120e5b4979c856530e1734cf42342a5a088d 100644 (file)
@@ -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;