conf-files: introduce struct ConfFile to store information of found conf file

It is currently unused, will be used later. Preparation for later changes.
This commit is contained in:
Yu Watanabe
2025-07-11 10:41:07 +09:00
parent 628f45f4a3
commit 31b7616420
3 changed files with 200 additions and 43 deletions
+181 -43
View File
@@ -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,
+18
View 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);
+1
View 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;