mirror of
https://github.com/systemd/systemd
synced 2026-03-17 18:44:46 +01:00
Compare commits
No commits in common. "a35965f85436f2c30f1b3344ee7ee829a9f28a65" and "85213a70701e15efd0d7d7a95398caab8911325a" have entirely different histories.
a35965f854
...
85213a7070
@ -112,147 +112,7 @@ static int conf_file_prefix_root(ConfFile *c, const char *root) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool conf_files_need_stat(ConfFilesFlags flags) {
|
int conf_file_new_at(const char *path, int rfd, ChaseFlags chase_flags, ConfFile **ret) {
|
||||||
return (flags & (CONF_FILES_FILTER_MASKED | CONF_FILES_REGULAR | CONF_FILES_DIRECTORY | CONF_FILES_EXECUTABLE)) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static ChaseFlags conf_files_chase_flags(ConfFilesFlags flags) {
|
|
||||||
ChaseFlags chase_flags = CHASE_AT_RESOLVE_IN_ROOT;
|
|
||||||
|
|
||||||
if (!conf_files_need_stat(flags) || FLAGS_SET(flags, CONF_FILES_FILTER_MASKED_BY_SYMLINK))
|
|
||||||
/* Even if no verification is requested, let's unconditionally call chaseat(),
|
|
||||||
* to drop unsafe symlinks. */
|
|
||||||
chase_flags |= CHASE_NONEXISTENT;
|
|
||||||
|
|
||||||
return chase_flags;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int conf_file_chase_and_verify(
|
|
||||||
int rfd,
|
|
||||||
const char *root, /* for logging, can be NULL */
|
|
||||||
const char *original_path, /* for logging */
|
|
||||||
const char *path,
|
|
||||||
const char *name,
|
|
||||||
Set **masked, /* optional */
|
|
||||||
ConfFilesFlags flags,
|
|
||||||
char **ret_path,
|
|
||||||
int *ret_fd,
|
|
||||||
struct stat *ret_stat) {
|
|
||||||
|
|
||||||
_cleanup_free_ char *resolved_path = NULL;
|
|
||||||
_cleanup_close_ int fd = -EBADF;
|
|
||||||
struct stat st = {};
|
|
||||||
int r;
|
|
||||||
|
|
||||||
assert(rfd >= 0 || rfd == AT_FDCWD);
|
|
||||||
assert(original_path);
|
|
||||||
assert(path);
|
|
||||||
assert(name);
|
|
||||||
|
|
||||||
root = empty_to_root(root);
|
|
||||||
|
|
||||||
r = chaseat(rfd, path, conf_files_chase_flags(flags), &resolved_path, &fd);
|
|
||||||
if (r < 0)
|
|
||||||
return log_debug_errno(r, "Failed to chase '%s%s': %m",
|
|
||||||
root, skip_leading_slash(original_path));
|
|
||||||
if (r == 0) {
|
|
||||||
if (FLAGS_SET(flags, CONF_FILES_FILTER_MASKED_BY_SYMLINK)) {
|
|
||||||
/* If the path points to /dev/null in a image or so, then the device node may not exist. */
|
|
||||||
if (path_equal(skip_leading_slash(resolved_path), "dev/null")) {
|
|
||||||
if (masked) {
|
|
||||||
/* Mark this one as masked */
|
|
||||||
r = set_put_strdup(masked, name);
|
|
||||||
if (r < 0)
|
|
||||||
return log_oom_debug();
|
|
||||||
}
|
|
||||||
|
|
||||||
return log_debug_errno(SYNTHETIC_ERRNO(ERFKILL),
|
|
||||||
"File '%s%s' is a mask (symlink to /dev/null).",
|
|
||||||
root, skip_leading_slash(original_path));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (conf_files_need_stat(flags))
|
|
||||||
/* If we need to have stat, skip the entry. */
|
|
||||||
return log_debug_errno(SYNTHETIC_ERRNO(ENOENT), "Failed to chase '%s%s': %m",
|
|
||||||
root, skip_leading_slash(original_path));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Even if we do not need stat, let's take stat now. The caller may use the info later. */
|
|
||||||
if (fd >= 0 && fstat(fd, &st) < 0)
|
|
||||||
return log_debug_errno(errno, "Failed to stat '%s%s': %m",
|
|
||||||
root, skip_leading_slash(original_path));
|
|
||||||
|
|
||||||
/* Is this a masking entry? */
|
|
||||||
if (FLAGS_SET(flags, CONF_FILES_FILTER_MASKED_BY_SYMLINK) && stat_may_be_dev_null(&st)) {
|
|
||||||
if (masked) {
|
|
||||||
/* Mark this one as masked */
|
|
||||||
r = set_put_strdup(masked, name);
|
|
||||||
if (r < 0)
|
|
||||||
return log_oom_debug();
|
|
||||||
}
|
|
||||||
|
|
||||||
return log_debug_errno(SYNTHETIC_ERRNO(ERFKILL),
|
|
||||||
"File '%s%s' is a mask (symlink to /dev/null).",
|
|
||||||
root, skip_leading_slash(original_path));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (FLAGS_SET(flags, CONF_FILES_FILTER_MASKED_BY_EMPTY) && stat_is_empty(&st)) {
|
|
||||||
if (masked) {
|
|
||||||
/* Mark this one as masked */
|
|
||||||
r = set_put_strdup(masked, name);
|
|
||||||
if (r < 0)
|
|
||||||
return log_oom_debug();
|
|
||||||
}
|
|
||||||
|
|
||||||
return log_debug_errno(SYNTHETIC_ERRNO(ERFKILL),
|
|
||||||
"File '%s%s' is a mask (an empty file).",
|
|
||||||
root, skip_leading_slash(original_path));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (FLAGS_SET(flags, CONF_FILES_REGULAR|CONF_FILES_DIRECTORY)) {
|
|
||||||
if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode))
|
|
||||||
return log_debug_errno(SYNTHETIC_ERRNO(EBADFD),
|
|
||||||
"File '%s%s' is neither a regular file or directory.",
|
|
||||||
root, skip_leading_slash(original_path));
|
|
||||||
} else {
|
|
||||||
/* Is this node a regular file? */
|
|
||||||
if (FLAGS_SET(flags, CONF_FILES_REGULAR)) {
|
|
||||||
r = stat_verify_regular(&st);
|
|
||||||
if (r < 0)
|
|
||||||
return log_debug_errno(r, "File '%s%s' is not a regular file: %m",
|
|
||||||
root, skip_leading_slash(original_path));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Is this node a directory? */
|
|
||||||
if (FLAGS_SET(flags, CONF_FILES_DIRECTORY)) {
|
|
||||||
r = stat_verify_directory(&st);
|
|
||||||
if (r < 0)
|
|
||||||
return log_debug_errno(r, "File '%s%s' is not a directory: %m",
|
|
||||||
root, skip_leading_slash(original_path));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Does this node have the executable bit set?
|
|
||||||
* As requested: check if the file is marked executable. Note that we don't check access(X_OK) here,
|
|
||||||
* as we care about whether the file is marked executable at all, and not whether it is executable
|
|
||||||
* for us, because if so, such errors are stuff we should log about. */
|
|
||||||
if (FLAGS_SET(flags, CONF_FILES_EXECUTABLE) && (st.st_mode & 0111) == 0)
|
|
||||||
return log_debug_errno(SYNTHETIC_ERRNO(ENOEXEC),
|
|
||||||
"File '%s%s' is not marked executable.",
|
|
||||||
root, skip_leading_slash(original_path));
|
|
||||||
|
|
||||||
if (ret_path)
|
|
||||||
*ret_path = TAKE_PTR(resolved_path);
|
|
||||||
if (ret_fd)
|
|
||||||
*ret_fd = TAKE_FD(fd);
|
|
||||||
if (ret_stat)
|
|
||||||
*ret_stat = st;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int conf_file_new_at(const char *path, int rfd, ConfFilesFlags flags, ConfFile **ret) {
|
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(path);
|
assert(path);
|
||||||
@ -285,8 +145,10 @@ int conf_file_new_at(const char *path, int rfd, ConfFilesFlags flags, ConfFile *
|
|||||||
return log_debug_errno(r, "Failed to extract directory from '%s': %m", path);
|
return log_debug_errno(r, "Failed to extract directory from '%s': %m", path);
|
||||||
if (r >= 0) {
|
if (r >= 0) {
|
||||||
r = chaseat(rfd, dirpath,
|
r = chaseat(rfd, dirpath,
|
||||||
CHASE_MUST_BE_DIRECTORY | conf_files_chase_flags(flags),
|
CHASE_AT_RESOLVE_IN_ROOT |
|
||||||
&resolved_dirpath, /* ret_fd= */ NULL);
|
CHASE_MUST_BE_DIRECTORY |
|
||||||
|
(FLAGS_SET(chase_flags, CHASE_NONEXISTENT) ? CHASE_NONEXISTENT : 0),
|
||||||
|
&resolved_dirpath, /* ret_fd = */ NULL);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_debug_errno(r, "Failed to chase '%s%s': %m", empty_to_root(root), skip_leading_slash(dirpath));
|
return log_debug_errno(r, "Failed to chase '%s%s': %m", empty_to_root(root), skip_leading_slash(dirpath));
|
||||||
}
|
}
|
||||||
@ -295,28 +157,22 @@ int conf_file_new_at(const char *path, int rfd, ConfFilesFlags flags, ConfFile *
|
|||||||
if (!c->result)
|
if (!c->result)
|
||||||
return log_oom_debug();
|
return log_oom_debug();
|
||||||
|
|
||||||
r = conf_file_chase_and_verify(
|
r = chaseat(rfd, c->result, CHASE_AT_RESOLVE_IN_ROOT | chase_flags, &c->resolved_path, &c->fd);
|
||||||
rfd,
|
|
||||||
root,
|
|
||||||
c->original_path,
|
|
||||||
c->result,
|
|
||||||
c->name,
|
|
||||||
/* masked= */ NULL,
|
|
||||||
flags,
|
|
||||||
&c->resolved_path,
|
|
||||||
&c->fd,
|
|
||||||
&c->st);
|
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
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);
|
*ret = TAKE_PTR(c);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int conf_file_new(const char *path, const char *root, ConfFilesFlags flags, ConfFile **ret) {
|
int conf_file_new(const char *path, const char *root, ChaseFlags chase_flags, ConfFile **ret) {
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(path);
|
assert(path);
|
||||||
|
assert((chase_flags & (CHASE_PREFIX_ROOT | CHASE_STEP)) == 0);
|
||||||
assert(ret);
|
assert(ret);
|
||||||
|
|
||||||
_cleanup_free_ char *root_abs = NULL;
|
_cleanup_free_ char *root_abs = NULL;
|
||||||
@ -335,7 +191,7 @@ int conf_file_new(const char *path, const char *root, ConfFilesFlags flags, Conf
|
|||||||
}
|
}
|
||||||
|
|
||||||
_cleanup_(conf_file_freep) ConfFile *c = NULL;
|
_cleanup_(conf_file_freep) ConfFile *c = NULL;
|
||||||
r = conf_file_new_at(path, rfd, flags, &c);
|
r = conf_file_new_at(path, rfd, chase_flags, &c);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
@ -372,9 +228,9 @@ static int files_add(
|
|||||||
assert(files);
|
assert(files);
|
||||||
assert(masked);
|
assert(masked);
|
||||||
|
|
||||||
root = empty_to_root(root);
|
root = strempty(root);
|
||||||
|
|
||||||
FOREACH_DIRENT(de, dir, return log_debug_errno(errno, "Failed to read directory '%s%s': %m",
|
FOREACH_DIRENT(de, dir, return log_debug_errno(errno, "Failed to read directory '%s/%s': %m",
|
||||||
root, skip_leading_slash(original_dirpath))) {
|
root, skip_leading_slash(original_dirpath))) {
|
||||||
|
|
||||||
_cleanup_free_ char *original_path = path_join(original_dirpath, de->d_name);
|
_cleanup_free_ char *original_path = path_join(original_dirpath, de->d_name);
|
||||||
@ -383,19 +239,19 @@ static int files_add(
|
|||||||
|
|
||||||
/* Does this match the suffix? */
|
/* Does this match the suffix? */
|
||||||
if (suffix && !endswith(de->d_name, suffix)) {
|
if (suffix && !endswith(de->d_name, suffix)) {
|
||||||
log_debug("Skipping file '%s%s', suffix is not '%s'.", root, skip_leading_slash(original_path), suffix);
|
log_debug("Skipping file '%s/%s' with unexpected suffix.", root, skip_leading_slash(original_path));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Has this file already been found in an earlier directory? */
|
/* Has this file already been found in an earlier directory? */
|
||||||
if (hashmap_contains(*files, de->d_name)) {
|
if (hashmap_contains(*files, de->d_name)) {
|
||||||
log_debug("Skipping overridden file '%s%s'.", root, skip_leading_slash(original_path));
|
log_debug("Skipping overridden file '%s/%s'.", root, skip_leading_slash(original_path));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Has this been masked in an earlier directory? */
|
/* Has this been masked in an earlier directory? */
|
||||||
if ((flags & CONF_FILES_FILTER_MASKED) != 0 && set_contains(*masked, de->d_name)) {
|
if ((flags & CONF_FILES_FILTER_MASKED) != 0 && set_contains(*masked, de->d_name)) {
|
||||||
log_debug("File '%s%s' is masked by previous entry.", root, skip_leading_slash(original_path));
|
log_debug("File '%s/%s' is masked by previous entry.", root, skip_leading_slash(original_path));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -405,22 +261,100 @@ static int files_add(
|
|||||||
|
|
||||||
_cleanup_free_ char *resolved_path = NULL;
|
_cleanup_free_ char *resolved_path = NULL;
|
||||||
_cleanup_close_ int fd = -EBADF;
|
_cleanup_close_ int fd = -EBADF;
|
||||||
struct stat st;
|
bool need_stat = (flags & (CONF_FILES_FILTER_MASKED | CONF_FILES_REGULAR | CONF_FILES_DIRECTORY | CONF_FILES_EXECUTABLE)) != 0;
|
||||||
r = conf_file_chase_and_verify(
|
ChaseFlags chase_flags = CHASE_AT_RESOLVE_IN_ROOT;
|
||||||
rfd,
|
|
||||||
root,
|
if (!need_stat || FLAGS_SET(flags, CONF_FILES_FILTER_MASKED_BY_SYMLINK))
|
||||||
original_path,
|
/* Even if no verification is requested, let's unconditionally call chaseat(),
|
||||||
p,
|
* to drop unsafe symlinks. */
|
||||||
de->d_name,
|
chase_flags |= CHASE_NONEXISTENT;
|
||||||
masked,
|
|
||||||
flags,
|
r = chaseat(rfd, p, chase_flags, &resolved_path, &fd);
|
||||||
&resolved_path,
|
if (r < 0) {
|
||||||
&fd,
|
log_debug_errno(r, "Failed to chase '%s/%s', ignoring: %m",
|
||||||
&st);
|
root, skip_leading_slash(original_path));
|
||||||
if (r == -ENOMEM)
|
|
||||||
return r;
|
|
||||||
if (r < 0)
|
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
if (r == 0) {
|
||||||
|
if (FLAGS_SET(flags, CONF_FILES_FILTER_MASKED_BY_SYMLINK)) {
|
||||||
|
|
||||||
|
/* If the path points to /dev/null in a image or so, then the device node may not exist. */
|
||||||
|
if (path_equal(skip_leading_slash(resolved_path), "dev/null")) {
|
||||||
|
/* Mark this one as masked */
|
||||||
|
r = set_put_strdup(masked, de->d_name);
|
||||||
|
if (r < 0)
|
||||||
|
return log_oom_debug();
|
||||||
|
|
||||||
|
log_debug("File '%s/%s' is a mask (symlink to /dev/null).",
|
||||||
|
root, skip_leading_slash(original_path));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (need_stat) {
|
||||||
|
/* If we need to have stat, skip the entry. */
|
||||||
|
log_debug_errno(SYNTHETIC_ERRNO(ENOENT), "Failed to chase '%s/%s', ignoring.",
|
||||||
|
root, skip_leading_slash(original_path));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Even if we do not need stat, let's take stat now. The caller may use the info later. */
|
||||||
|
struct stat st = {};
|
||||||
|
if (fd >= 0 && fstat(fd, &st) < 0) {
|
||||||
|
log_debug_errno(errno, "Failed to stat '%s/%s', ignoring: %m",
|
||||||
|
root, skip_leading_slash(original_path));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Is this a masking entry? */
|
||||||
|
if (FLAGS_SET(flags, CONF_FILES_FILTER_MASKED_BY_SYMLINK) && stat_may_be_dev_null(&st)) {
|
||||||
|
/* Mark this one as masked */
|
||||||
|
r = set_put_strdup(masked, de->d_name);
|
||||||
|
if (r < 0)
|
||||||
|
return log_oom_debug();
|
||||||
|
|
||||||
|
log_debug("File '%s/%s' is a mask (symlink to /dev/null).", root, skip_leading_slash(original_path));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FLAGS_SET(flags, CONF_FILES_FILTER_MASKED_BY_EMPTY) && stat_is_empty(&st)) {
|
||||||
|
/* Mark this one as masked */
|
||||||
|
r = set_put_strdup(masked, de->d_name);
|
||||||
|
if (r < 0)
|
||||||
|
return log_oom_debug();
|
||||||
|
|
||||||
|
log_debug("File '%s/%s' is a mask (an empty file).", root, skip_leading_slash(original_path));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FLAGS_SET(flags, CONF_FILES_REGULAR|CONF_FILES_DIRECTORY)) {
|
||||||
|
if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode)) {
|
||||||
|
log_debug("Ignoring '%s/%s', as it is neither a regular file or directory.", root, skip_leading_slash(original_path));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* Is this node a regular file? */
|
||||||
|
if (FLAGS_SET(flags, CONF_FILES_REGULAR) && !S_ISREG(st.st_mode)) {
|
||||||
|
log_debug("Ignoring '%s/%s', as it is not a regular file.", root, skip_leading_slash(original_path));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Is this node a directory? */
|
||||||
|
if (FLAGS_SET(flags, CONF_FILES_DIRECTORY) && !S_ISDIR(st.st_mode)) {
|
||||||
|
log_debug("Ignoring '%s/%s', as it is not a directory.", root, skip_leading_slash(original_path));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Does this node have the executable bit set?
|
||||||
|
* As requested: check if the file is marked executable. Note that we don't check access(X_OK)
|
||||||
|
* here, as we care about whether the file is marked executable at all, and not whether it is
|
||||||
|
* executable for us, because if so, such errors are stuff we should log about. */
|
||||||
|
if (FLAGS_SET(flags, CONF_FILES_EXECUTABLE) && (st.st_mode & 0111) == 0) {
|
||||||
|
log_debug("Ignoring '%s/%s', as it is not marked executable.", root, skip_leading_slash(original_path));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
_cleanup_(conf_file_freep) ConfFile *c = new(ConfFile, 1);
|
_cleanup_(conf_file_freep) ConfFile *c = new(ConfFile, 1);
|
||||||
if (!c)
|
if (!c)
|
||||||
@ -482,13 +416,7 @@ static int dump_files(Hashmap *fh, const char *root, ConfFile ***ret_files, size
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int copy_and_sort_files_from_hashmap(
|
static int copy_and_sort_files_from_hashmap(Hashmap *fh, const char *root, ConfFilesFlags flags, char ***ret) {
|
||||||
Hashmap *fh,
|
|
||||||
const char *suffix,
|
|
||||||
const char *root,
|
|
||||||
ConfFilesFlags flags,
|
|
||||||
char ***ret) {
|
|
||||||
|
|
||||||
_cleanup_strv_free_ char **results = NULL;
|
_cleanup_strv_free_ char **results = NULL;
|
||||||
_cleanup_free_ ConfFile **files = NULL;
|
_cleanup_free_ ConfFile **files = NULL;
|
||||||
size_t n_files = 0, n_results = 0;
|
size_t n_files = 0, n_results = 0;
|
||||||
@ -504,44 +432,19 @@ static int copy_and_sort_files_from_hashmap(
|
|||||||
|
|
||||||
FOREACH_ARRAY(i, files, n_files) {
|
FOREACH_ARRAY(i, files, n_files) {
|
||||||
ConfFile *c = *i;
|
ConfFile *c = *i;
|
||||||
const char *add = NULL;
|
|
||||||
|
|
||||||
if (FLAGS_SET(flags, CONF_FILES_BASENAME))
|
if (FLAGS_SET(flags, CONF_FILES_BASENAME))
|
||||||
add = c->name;
|
r = strv_extend_with_size(&results, &n_results, c->name);
|
||||||
else if (root) {
|
else if (root) {
|
||||||
_cleanup_free_ char *p = NULL;
|
char *p;
|
||||||
|
|
||||||
r = chaseat_prefix_root(c->result, root, &p);
|
r = chaseat_prefix_root(c->result, root, &p);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_debug_errno(r, "Failed to prefix '%s' with root '%s': %m", c->result, root);
|
return log_debug_errno(r, "Failed to prefix '%s' with root '%s': %m", c->result, root);
|
||||||
|
|
||||||
if (FLAGS_SET(flags, CONF_FILES_TRUNCATE_SUFFIX) && suffix) {
|
r = strv_consume_with_size(&results, &n_results, TAKE_PTR(p));
|
||||||
char *e = endswith(p, suffix);
|
|
||||||
if (!e)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
*e = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strv_consume_with_size(&results, &n_results, TAKE_PTR(p)) < 0)
|
|
||||||
return log_oom_debug();
|
|
||||||
|
|
||||||
continue;
|
|
||||||
} else
|
} else
|
||||||
add = c->result;
|
r = strv_extend_with_size(&results, &n_results, c->result);
|
||||||
|
|
||||||
if (FLAGS_SET(flags, CONF_FILES_TRUNCATE_SUFFIX)) {
|
|
||||||
const char *e = endswith(add, suffix);
|
|
||||||
if (!e)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
_cleanup_free_ char *n = strndup(add, e - add);
|
|
||||||
if (!n)
|
|
||||||
return log_oom_debug();
|
|
||||||
|
|
||||||
r = strv_consume_with_size(&results, &n_results, TAKE_PTR(n));
|
|
||||||
} else
|
|
||||||
r = strv_extend_with_size(&results, &n_results, add);
|
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_oom_debug();
|
return log_oom_debug();
|
||||||
}
|
}
|
||||||
@ -599,10 +502,8 @@ static int conf_files_list_impl(
|
|||||||
assert(rfd >= 0 || rfd == AT_FDCWD);
|
assert(rfd >= 0 || rfd == AT_FDCWD);
|
||||||
assert(ret);
|
assert(ret);
|
||||||
|
|
||||||
root = empty_to_root(root);
|
|
||||||
|
|
||||||
if (replacement) {
|
if (replacement) {
|
||||||
r = conf_file_new_at(replacement, rfd, /* flags= */ 0, &c);
|
r = conf_file_new_at(replacement, rfd, CHASE_NONEXISTENT, &c);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
@ -614,8 +515,7 @@ static int conf_files_list_impl(
|
|||||||
r = chase_and_opendirat(rfd, *p, CHASE_AT_RESOLVE_IN_ROOT, &path, &dir);
|
r = chase_and_opendirat(rfd, *p, CHASE_AT_RESOLVE_IN_ROOT, &path, &dir);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
if (r != -ENOENT)
|
if (r != -ENOENT)
|
||||||
log_debug_errno(r, "Failed to chase and open directory '%s%s', ignoring: %m",
|
log_debug_errno(r, "Failed to chase and open directory '%s/%s', ignoring: %m", strempty(root), skip_leading_slash(*p));
|
||||||
root, skip_leading_slash(*p));
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -666,7 +566,7 @@ int conf_files_list_strv(
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
return copy_and_sort_files_from_hashmap(fh, suffix, empty_to_root(root_abs), flags, ret);
|
return copy_and_sort_files_from_hashmap(fh, empty_to_root(root_abs), flags, ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
int conf_files_list_strv_full(
|
int conf_files_list_strv_full(
|
||||||
@ -719,7 +619,7 @@ int conf_files_list_strv_at(
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
return copy_and_sort_files_from_hashmap(fh, suffix, /* root = */ NULL, flags, ret);
|
return copy_and_sort_files_from_hashmap(fh, /* root = */ NULL, flags, ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
int conf_files_list_strv_at_full(
|
int conf_files_list_strv_at_full(
|
||||||
@ -847,7 +747,7 @@ int conf_files_list_with_replacement(
|
|||||||
return log_debug_errno(r, "Failed to prefix '%s' with root '%s': %m", c->result, empty_to_root(root_abs));
|
return log_debug_errno(r, "Failed to prefix '%s' with root '%s': %m", c->result, empty_to_root(root_abs));
|
||||||
}
|
}
|
||||||
|
|
||||||
r = copy_and_sort_files_from_hashmap(fh, ".conf", empty_to_root(root_abs), flags, ret_files);
|
r = copy_and_sort_files_from_hashmap(fh, empty_to_root(root_abs), flags, ret_files);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
|||||||
@ -6,14 +6,13 @@
|
|||||||
#include "forward.h"
|
#include "forward.h"
|
||||||
|
|
||||||
typedef enum ConfFilesFlags {
|
typedef enum ConfFilesFlags {
|
||||||
CONF_FILES_EXECUTABLE = 1 << 0, /* inode must be marked executable */
|
CONF_FILES_EXECUTABLE = 1 << 0,
|
||||||
CONF_FILES_REGULAR = 1 << 1, /* inode must be regular file */
|
CONF_FILES_REGULAR = 1 << 1,
|
||||||
CONF_FILES_DIRECTORY = 1 << 2, /* inode must be directory */
|
CONF_FILES_DIRECTORY = 1 << 2,
|
||||||
CONF_FILES_BASENAME = 1 << 3, /* only return basename of file, not full path */
|
CONF_FILES_BASENAME = 1 << 3,
|
||||||
CONF_FILES_FILTER_MASKED_BY_SYMLINK = 1 << 4, /* implement /dev/null symlink based masking */
|
CONF_FILES_FILTER_MASKED_BY_SYMLINK = 1 << 4,
|
||||||
CONF_FILES_FILTER_MASKED_BY_EMPTY = 1 << 5, /* implement masking by empty file */
|
CONF_FILES_FILTER_MASKED_BY_EMPTY = 1 << 5,
|
||||||
CONF_FILES_FILTER_MASKED = CONF_FILES_FILTER_MASKED_BY_SYMLINK | CONF_FILES_FILTER_MASKED_BY_EMPTY,
|
CONF_FILES_FILTER_MASKED = CONF_FILES_FILTER_MASKED_BY_SYMLINK | CONF_FILES_FILTER_MASKED_BY_EMPTY,
|
||||||
CONF_FILES_TRUNCATE_SUFFIX = 1 << 6, /* truncate specified suffix from return filename or path */
|
|
||||||
} ConfFilesFlags;
|
} ConfFilesFlags;
|
||||||
|
|
||||||
typedef struct ConfFile {
|
typedef struct ConfFile {
|
||||||
@ -29,8 +28,8 @@ ConfFile* conf_file_free(ConfFile *c);
|
|||||||
DEFINE_TRIVIAL_CLEANUP_FUNC(ConfFile*, conf_file_free);
|
DEFINE_TRIVIAL_CLEANUP_FUNC(ConfFile*, conf_file_free);
|
||||||
void conf_file_free_many(ConfFile **array, size_t n);
|
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, int rfd, ChaseFlags chase_flags, ConfFile **ret);
|
||||||
int conf_file_new(const char *path, const char *root, ConfFilesFlags 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(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_at(char ***ret, const char *suffix, int rfd, ConfFilesFlags flags, const char *dir);
|
||||||
|
|||||||
@ -6,6 +6,7 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "alloc-util.h"
|
#include "alloc-util.h"
|
||||||
|
#include "chase.h"
|
||||||
#include "color-util.h"
|
#include "color-util.h"
|
||||||
#include "conf-files.h"
|
#include "conf-files.h"
|
||||||
#include "constants.h"
|
#include "constants.h"
|
||||||
@ -325,20 +326,7 @@ static int cat_file_by_path(const char *p, bool *newline, CatFlags flags) {
|
|||||||
|
|
||||||
assert(p);
|
assert(p);
|
||||||
|
|
||||||
r = conf_file_new(p, /* root= */ NULL, CONF_FILES_REGULAR | CONF_FILES_FILTER_MASKED, &c);
|
r = conf_file_new(p, /* root = */ NULL, CHASE_MUST_BE_REGULAR, &c);
|
||||||
if (r == -ERFKILL) { /* masked */
|
|
||||||
if (newline) {
|
|
||||||
if (*newline)
|
|
||||||
putc('\n', stdout);
|
|
||||||
*newline = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("%s# %s is a mask.%s\n",
|
|
||||||
ansi_highlight_magenta(),
|
|
||||||
p,
|
|
||||||
ansi_normal());
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to chase '%s': %m", p);
|
return log_error_errno(r, "Failed to chase '%s': %m", p);
|
||||||
|
|
||||||
@ -471,8 +459,7 @@ int conf_files_cat(const char *root, const char *name, CatFlags flags) {
|
|||||||
if (!p)
|
if (!p)
|
||||||
return log_oom();
|
return log_oom();
|
||||||
|
|
||||||
r = conf_file_new(p, root, CONF_FILES_REGULAR | CONF_FILES_FILTER_MASKED, &c);
|
if (conf_file_new(p, root, CHASE_MUST_BE_REGULAR, &c) >= 0)
|
||||||
if (r >= 0 || r == -ERFKILL) /* Found a regular file or masked file */
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -4,11 +4,8 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "alloc-util.h"
|
#include "alloc-util.h"
|
||||||
#include "path-util.h"
|
|
||||||
#include "pretty-print.h"
|
#include "pretty-print.h"
|
||||||
#include "rm-rf.h"
|
|
||||||
#include "tests.h"
|
#include "tests.h"
|
||||||
#include "tmpfile-util.h"
|
|
||||||
|
|
||||||
#define CYLON_WIDTH 6
|
#define CYLON_WIDTH 6
|
||||||
|
|
||||||
@ -56,13 +53,6 @@ TEST(cat_files) {
|
|||||||
|
|
||||||
if (access("/etc/fstab", R_OK) >= 0)
|
if (access("/etc/fstab", R_OK) >= 0)
|
||||||
assert_se(cat_files("/etc/fstab", STRV_MAKE("/etc/fstab", "/etc/fstab"), 0) == 0);
|
assert_se(cat_files("/etc/fstab", STRV_MAKE("/etc/fstab", "/etc/fstab"), 0) == 0);
|
||||||
|
|
||||||
/* Test masked file (symlink to /dev/null) - should succeed with exit code 0 */
|
|
||||||
_cleanup_(rm_rf_physical_and_freep) char *tmp = NULL;
|
|
||||||
ASSERT_OK(mkdtemp_malloc("/tmp/test-cat-files-XXXXXX", &tmp));
|
|
||||||
_cleanup_free_ char *masked_file = ASSERT_NOT_NULL(path_join(tmp, "masked.conf"));
|
|
||||||
ASSERT_OK_ERRNO(symlink("/dev/null", masked_file));
|
|
||||||
ASSERT_OK(cat_files(masked_file, /* dropins= */ NULL, /* flags= */ 0));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(red_green_cross_check_mark) {
|
TEST(red_green_cross_check_mark) {
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "chase.h"
|
||||||
#include "conf-files.h"
|
#include "conf-files.h"
|
||||||
#include "fd-util.h"
|
#include "fd-util.h"
|
||||||
#include "fuzz.h"
|
#include "fuzz.h"
|
||||||
@ -28,7 +29,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
|||||||
assert_se(rules = udev_rules_new(RESOLVE_NAME_EARLY));
|
assert_se(rules = udev_rules_new(RESOLVE_NAME_EARLY));
|
||||||
|
|
||||||
_cleanup_(conf_file_freep) ConfFile *c = NULL;
|
_cleanup_(conf_file_freep) ConfFile *c = NULL;
|
||||||
ASSERT_OK(conf_file_new(filename, /* root= */ NULL, CONF_FILES_REGULAR, &c));
|
ASSERT_OK(conf_file_new(filename, /* root = */ NULL, CHASE_MUST_BE_REGULAR, &c));
|
||||||
|
|
||||||
r = udev_rules_parse_file(rules, c, /* extra_checks = */ false, /* ret = */ NULL);
|
r = udev_rules_parse_file(rules, c, /* extra_checks = */ false, /* ret = */ NULL);
|
||||||
log_info_errno(r, "Parsing %s: %m", filename);
|
log_info_errno(r, "Parsing %s: %m", filename);
|
||||||
|
|||||||
@ -7,6 +7,7 @@
|
|||||||
#include "alloc-util.h"
|
#include "alloc-util.h"
|
||||||
#include "bus-error.h"
|
#include "bus-error.h"
|
||||||
#include "bus-util.h"
|
#include "bus-util.h"
|
||||||
|
#include "chase.h"
|
||||||
#include "conf-files.h"
|
#include "conf-files.h"
|
||||||
#include "constants.h"
|
#include "constants.h"
|
||||||
#include "device-private.h"
|
#include "device-private.h"
|
||||||
@ -249,7 +250,7 @@ static int search_rules_file_in_conf_dirs(const char *s, const char *root, ConfF
|
|||||||
return log_oom();
|
return log_oom();
|
||||||
|
|
||||||
_cleanup_(conf_file_freep) ConfFile *c = NULL;
|
_cleanup_(conf_file_freep) ConfFile *c = NULL;
|
||||||
r = conf_file_new(path, root, CONF_FILES_REGULAR, &c);
|
r = conf_file_new(path, root, CHASE_MUST_BE_REGULAR, &c);
|
||||||
if (r == -ENOENT)
|
if (r == -ENOENT)
|
||||||
continue;
|
continue;
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
@ -279,7 +280,7 @@ static int search_rules_file(const char *s, const char *root, ConfFile ***files,
|
|||||||
|
|
||||||
/* If not found, or if it is a path, then chase it. */
|
/* If not found, or if it is a path, then chase it. */
|
||||||
_cleanup_(conf_file_freep) ConfFile *c = NULL;
|
_cleanup_(conf_file_freep) ConfFile *c = NULL;
|
||||||
r = conf_file_new(s, root, CONF_FILES_REGULAR, &c);
|
r = conf_file_new(s, root, CHASE_MUST_BE_REGULAR, &c);
|
||||||
if (r >= 0) {
|
if (r >= 0) {
|
||||||
if (!GREEDY_REALLOC_APPEND(*files, *n_files, &c, 1))
|
if (!GREEDY_REALLOC_APPEND(*files, *n_files, &c, 1))
|
||||||
return log_oom();
|
return log_oom();
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user