diff --git a/src/analyze/analyze-nvpcrs.c b/src/analyze/analyze-nvpcrs.c index ae134dfc2b..ddb850fcef 100644 --- a/src/analyze/analyze-nvpcrs.c +++ b/src/analyze/analyze-nvpcrs.c @@ -78,7 +78,7 @@ int verb_nvpcrs(int argc, char *argv[], void *userdata) { &l, ".nvpcr", /* root= */ NULL, - CONF_FILES_REGULAR|CONF_FILES_BASENAME|CONF_FILES_FILTER_MASKED|CONF_FILES_TRUNCATE_SUFFIX, + CONF_FILES_REGULAR|CONF_FILES_BASENAME|CONF_FILES_FILTER_MASKED|CONF_FILES_TRUNCATE_SUFFIX|CONF_FILES_WARN, CONF_PATHS_NULSTR("nvpcr")); if (r < 0) return log_error_errno(r, "Failed to find .nvpcr files: %m"); diff --git a/src/basic/basic-forward.h b/src/basic/basic-forward.h index 4231f10a59..adfe85eca0 100644 --- a/src/basic/basic-forward.h +++ b/src/basic/basic-forward.h @@ -86,6 +86,7 @@ union sockaddr_union; typedef enum CGroupFlags CGroupFlags; typedef enum CGroupMask CGroupMask; typedef enum ChaseFlags ChaseFlags; +typedef enum ConfFilesFlags ConfFilesFlags; typedef enum ExtractFlags ExtractFlags; typedef enum ForkFlags ForkFlags; typedef enum Glyph Glyph; diff --git a/src/basic/conf-files.c b/src/basic/conf-files.c index ea41c4da4a..76ff20f07b 100644 --- a/src/basic/conf-files.c +++ b/src/basic/conf-files.c @@ -40,7 +40,11 @@ void conf_file_free_many(ConfFile **array, size_t n) { free(array); } -static int prepare_dirs(const char *root, char * const *dirs, int *ret_rfd, char **ret_root, char ***ret_dirs) { +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) { _cleanup_free_ char *root_abs = NULL; _cleanup_strv_free_ char **dirs_abs = NULL; int r; @@ -49,14 +53,16 @@ static int prepare_dirs(const char *root, char * const *dirs, int *ret_rfd, char assert(ret_root); assert(ret_dirs || strv_isempty(dirs)); + int log_level = conf_files_log_level(flags); + 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)); + return log_full_errno(log_level, 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(); + return log_oom_full(log_level); } if (root) { @@ -64,7 +70,7 @@ static int prepare_dirs(const char *root, char * const *dirs, int *ret_rfd, char * 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); + return log_full_errno(log_level, r, "Failed to make '%s' absolute: %m", root); path_simplify(root_abs); } else if (ret_dirs) { @@ -72,12 +78,12 @@ static int prepare_dirs(const char *root, char * const *dirs, int *ret_rfd, char * 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"); + 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_debug_errno(errno, "Failed to open '%s': %m", empty_to_root(root_abs)); + 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); @@ -86,46 +92,191 @@ static int prepare_dirs(const char *root, char * const *dirs, int *ret_rfd, char return 0; } -static int conf_file_prefix_root(ConfFile *c, const char *root) { +static int conf_file_prefix_root(ConfFile *c, const char *root, ConfFilesFlags flags) { char *p; int r; assert(c); + int log_level = conf_files_log_level(flags); + 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); + return log_full_errno(log_level, 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); + return log_full_errno(log_level, 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(); + return log_oom_full(log_level); + path_simplify(p); - free_and_replace(c->original_path, p); + return free_and_replace(c->original_path, p); +} + +static bool conf_files_need_stat(ConfFilesFlags flags) { + 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); + + int log_level = conf_files_log_level(flags); + + root = empty_to_root(root); + + r = chaseat(rfd, path, conf_files_chase_flags(flags), &resolved_path, &fd); + if (r < 0) + return log_full_errno(log_level, 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_full(log_level); + } + + 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_full_errno(log_level, 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_full_errno(log_level, 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_full(log_level); + } + + 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_full(log_level); + } + + 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, ChaseFlags chase_flags, ConfFile **ret) { +int conf_file_new_at(const char *path, int rfd, ConfFilesFlags flags, ConfFile **ret) { int r; assert(path); assert(rfd >= 0 || rfd == AT_FDCWD); assert(ret); + int log_level = conf_files_log_level(flags); + _cleanup_free_ char *root = NULL; - if (rfd >= 0 && DEBUG_LOGGING) + if (rfd >= 0) (void) fd_get_path(rfd, &root); _cleanup_(conf_file_freep) ConfFile *c = new(ConfFile, 1); if (!c) - return log_oom_debug(); + return log_oom_full(log_level); *c = (ConfFile) { .original_path = strdup(path), @@ -133,51 +284,55 @@ int conf_file_new_at(const char *path, int rfd, ChaseFlags chase_flags, ConfFile }; if (!c->original_path) - return log_oom_debug(); + return log_oom_full(log_level); r = path_extract_filename(path, &c->name); if (r < 0) - return log_debug_errno(r, "Failed to extract filename from '%s': %m", path); + return log_full_errno(log_level, 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); + return log_full_errno(log_level, r, "Failed to extract directory from '%s': %m", path); if (r >= 0) { r = chaseat(rfd, dirpath, - CHASE_AT_RESOLVE_IN_ROOT | - CHASE_MUST_BE_DIRECTORY | - (FLAGS_SET(chase_flags, CHASE_NONEXISTENT) ? CHASE_NONEXISTENT : 0), + CHASE_MUST_BE_DIRECTORY | conf_files_chase_flags(flags), &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)); + return log_full_errno(log_level, 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(); + return log_oom_full(log_level); - r = chaseat(rfd, c->result, CHASE_AT_RESOLVE_IN_ROOT | chase_flags, &c->resolved_path, &c->fd); + r = conf_file_chase_and_verify( + rfd, + root, + c->original_path, + c->result, + c->name, + /* masked= */ NULL, + flags, + &c->resolved_path, + &c->fd, + &c->st); 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)); + return r; *ret = TAKE_PTR(c); return 0; } -int conf_file_new(const char *path, const char *root, ChaseFlags chase_flags, ConfFile **ret) { +int conf_file_new(const char *path, const char *root, ConfFilesFlags 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); + r = prepare_dirs(root, flags, /* dirs= */ NULL, &rfd, &root_abs, /* ret_dirs= */ NULL); if (r < 0) return r; @@ -185,17 +340,17 @@ int conf_file_new(const char *path, const char *root, ChaseFlags chase_flags, Co 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); + return log_full_errno(conf_files_log_level(flags), 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); + r = conf_file_new_at(path, rfd, flags, &c); if (r < 0) return r; - r = conf_file_prefix_root(c, root_abs); + r = conf_file_prefix_root(c, root_abs, flags); if (r < 0) return r; @@ -228,137 +383,61 @@ static int files_add( assert(files); assert(masked); - root = strempty(root); + int log_level = conf_files_log_level(flags); - FOREACH_DIRENT(de, dir, return log_debug_errno(errno, "Failed to read directory '%s/%s': %m", - root, skip_leading_slash(original_dirpath))) { + root = empty_to_root(root); + + FOREACH_DIRENT(de, dir, return log_full_errno(log_level, errno, "Failed to read directory '%s%s': %m", + root, skip_leading_slash(original_dirpath))) { _cleanup_free_ char *original_path = path_join(original_dirpath, de->d_name); if (!original_path) - return log_oom_debug(); + return log_oom_full(log_level); /* Does this match the 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', suffix is not '%s'.", root, skip_leading_slash(original_path), suffix); continue; } /* Has this file already been found in an earlier directory? */ 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; } /* Has this been masked in an earlier directory? */ 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; } _cleanup_free_ char *p = path_join(resolved_dirpath, de->d_name); if (!p) - return log_oom_debug(); + return log_oom_full(log_level); _cleanup_free_ char *resolved_path = NULL; _cleanup_close_ int fd = -EBADF; - bool need_stat = (flags & (CONF_FILES_FILTER_MASKED | CONF_FILES_REGULAR | CONF_FILES_DIRECTORY | CONF_FILES_EXECUTABLE)) != 0; - ChaseFlags chase_flags = CHASE_AT_RESOLVE_IN_ROOT; - - if (!need_stat || 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; - - r = chaseat(rfd, p, chase_flags, &resolved_path, &fd); - if (r < 0) { - log_debug_errno(r, "Failed to chase '%s/%s', ignoring: %m", - root, skip_leading_slash(original_path)); + struct stat st; + r = conf_file_chase_and_verify( + rfd, + root, + original_path, + p, + de->d_name, + masked, + flags, + &resolved_path, + &fd, + &st); + if (r == -ENOMEM) + return r; + if (r < 0) 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); if (!c) - return log_oom_debug(); + return log_oom_full(log_level); *c = (ConfFile) { .name = strdup(de->d_name), @@ -370,12 +449,12 @@ static int files_add( }; if (!c->name) - return log_oom_debug(); + return log_oom_full(log_level); r = hashmap_ensure_put(files, &conf_file_hash_ops, c->name, c); if (r < 0) { assert(r == -ENOMEM); - return log_oom_debug(); + return log_oom_full(log_level); } assert(r > 0); @@ -385,7 +464,7 @@ static int files_add( return 0; } -static int dump_files(Hashmap *fh, const char *root, ConfFile ***ret_files, size_t *ret_n_files) { +static int dump_files(Hashmap *fh, const char *root, ConfFilesFlags flags, ConfFile ***ret_files, size_t *ret_n_files) { ConfFile **files = NULL; size_t n_files = 0; int r; @@ -398,7 +477,7 @@ static int dump_files(Hashmap *fh, const char *root, ConfFile ***ret_files, size /* The entries in the array given by hashmap_dump_sorted() are still owned by the hashmap. */ r = hashmap_dump_sorted(fh, (void***) &files, &n_files); if (r < 0) - return log_oom_debug(); + return log_oom_full(conf_files_log_level(flags)); /* Hence, we need to remove them from the hashmap. */ FOREACH_ARRAY(i, files, n_files) @@ -406,7 +485,7 @@ static int dump_files(Hashmap *fh, const char *root, ConfFile ***ret_files, size if (root) FOREACH_ARRAY(i, files, n_files) { - r = conf_file_prefix_root(*i, root); + r = conf_file_prefix_root(*i, root, flags); if (r < 0) return r; } @@ -430,11 +509,13 @@ static int copy_and_sort_files_from_hashmap( assert(ret); + int log_level = conf_files_log_level(flags); + /* The entries in the array given by hashmap_dump_sorted() are still owned by the hashmap. * Hence, do not use conf_file_free_many() for 'entries' */ r = hashmap_dump_sorted(fh, (void***) &files, &n_files); if (r < 0) - return log_oom_debug(); + return log_oom_full(log_level); FOREACH_ARRAY(i, files, n_files) { ConfFile *c = *i; @@ -447,7 +528,7 @@ static int copy_and_sort_files_from_hashmap( 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); + return log_full_errno(log_level, r, "Failed to prefix '%s' with root '%s': %m", c->result, root); if (FLAGS_SET(flags, CONF_FILES_TRUNCATE_SUFFIX) && suffix) { char *e = endswith(p, suffix); @@ -458,7 +539,7 @@ static int copy_and_sort_files_from_hashmap( } if (strv_consume_with_size(&results, &n_results, TAKE_PTR(p)) < 0) - return log_oom_debug(); + return log_oom_full(log_level); continue; } else @@ -471,20 +552,20 @@ static int copy_and_sort_files_from_hashmap( _cleanup_free_ char *n = strndup(add, e - add); if (!n) - return log_oom_debug(); + return log_oom_full(log_level); r = strv_consume_with_size(&results, &n_results, TAKE_PTR(n)); } else r = strv_extend_with_size(&results, &n_results, add); if (r < 0) - return log_oom_debug(); + return log_oom_full(log_level); } *ret = TAKE_PTR(results); return 0; } -static int insert_replacement(Hashmap **fh, ConfFile *replacement, const ConfFile **ret) { +static int insert_replacement(Hashmap **fh, ConfFile *replacement, ConfFilesFlags flags, const ConfFile **ret) { _cleanup_(conf_file_freep) ConfFile *c = ASSERT_PTR(replacement); int r; @@ -504,7 +585,7 @@ static int insert_replacement(Hashmap **fh, ConfFile *replacement, const ConfFil r = hashmap_ensure_put(fh, &conf_file_hash_ops, c->name, c); if (r < 0) { assert(r == -ENOMEM); - return log_oom_debug(); + return log_oom_full(conf_files_log_level(flags)); } assert(r > 0); @@ -533,8 +614,10 @@ static int conf_files_list_impl( assert(rfd >= 0 || rfd == AT_FDCWD); assert(ret); + root = empty_to_root(root); + if (replacement) { - r = conf_file_new_at(replacement, rfd, CHASE_NONEXISTENT, &c); + r = conf_file_new_at(replacement, rfd, flags & CONF_FILES_WARN, &c); if (r < 0) return r; } @@ -546,12 +629,14 @@ static int conf_files_list_impl( r = chase_and_opendirat(rfd, *p, CHASE_AT_RESOLVE_IN_ROOT, &path, &dir); if (r < 0) { if (r != -ENOENT) - log_debug_errno(r, "Failed to chase and open directory '%s/%s', ignoring: %m", strempty(root), skip_leading_slash(*p)); + log_full_errno(conf_files_log_level(flags), r, + "Failed to chase and open directory '%s%s', ignoring: %m", + root, skip_leading_slash(*p)); continue; } if (c && streq_ptr(path_startswith(c->result, path), c->name)) { - r = insert_replacement(&fh, TAKE_PTR(c), &inserted); + r = insert_replacement(&fh, TAKE_PTR(c), flags, &inserted); if (r < 0) return r; } @@ -562,7 +647,7 @@ static int conf_files_list_impl( } if (c) { - r = insert_replacement(&fh, TAKE_PTR(c), &inserted); + r = insert_replacement(&fh, TAKE_PTR(c), flags, &inserted); if (r < 0) return r; } @@ -588,7 +673,7 @@ int conf_files_list_strv( assert(ret); - r = prepare_dirs(root, (char**) dirs, &rfd, &root_abs, &dirs_abs); + r = prepare_dirs(root, flags, (char**) dirs, &rfd, &root_abs, &dirs_abs); if (r < 0) return r; @@ -617,7 +702,7 @@ int conf_files_list_strv_full( assert(ret_files); assert(ret_n_files); - r = prepare_dirs(root, (char**) dirs, &rfd, &root_abs, &dirs_abs); + r = prepare_dirs(root, flags, (char**) dirs, &rfd, &root_abs, &dirs_abs); if (r < 0) return r; @@ -626,7 +711,7 @@ int conf_files_list_strv_full( if (r < 0) return r; - return dump_files(fh, empty_to_root(root_abs), ret_files, ret_n_files); + return dump_files(fh, empty_to_root(root_abs), flags, ret_files, ret_n_files); } int conf_files_list_strv_at( @@ -643,7 +728,7 @@ int conf_files_list_strv_at( assert(rfd >= 0 || rfd == AT_FDCWD); assert(ret); - if (rfd >= 0 && DEBUG_LOGGING) + if (rfd >= 0) (void) fd_get_path(rfd, &root); /* for logging */ r = conf_files_list_impl(suffix, rfd, root, flags, dirs, /* replacement= */ NULL, &fh, /* ret_inserted= */ NULL); @@ -669,14 +754,14 @@ int conf_files_list_strv_at_full( assert(ret_files); assert(ret_n_files); - if (rfd >= 0 && DEBUG_LOGGING) + if (rfd >= 0) (void) fd_get_path(rfd, &root); /* for logging */ r = conf_files_list_impl(suffix, rfd, root, flags, dirs, /* replacement= */ NULL, &fh, /* ret_inserted= */ NULL); if (r < 0) return r; - return dump_files(fh, /* root= */ NULL, ret_files, ret_n_files); + return dump_files(fh, /* root= */ NULL, flags, ret_files, ret_n_files); } int conf_files_list(char ***ret, const char *suffix, const char *root, ConfFilesFlags flags, const char *dir) { @@ -702,7 +787,7 @@ int conf_files_list_nulstr(char ***ret, const char *suffix, const char *root, Co d = strv_split_nulstr(dirs); if (!d) - return -ENOMEM; + return log_oom_full(conf_files_log_level(flags)); return conf_files_list_strv(ret, suffix, root, flags, (const char**) d); } @@ -715,7 +800,7 @@ int conf_files_list_nulstr_full(const char *suffix, const char *root, ConfFilesF d = strv_split_nulstr(dirs); if (!d) - return -ENOMEM; + return log_oom_full(conf_files_log_level(flags)); return conf_files_list_strv_full(suffix, root, flags, (const char**) d, ret_files, ret_n_files); } @@ -727,7 +812,7 @@ int conf_files_list_nulstr_at(char ***ret, const char *suffix, int rfd, ConfFile d = strv_split_nulstr(dirs); if (!d) - return -ENOMEM; + return log_oom_full(conf_files_log_level(flags)); return conf_files_list_strv_at(ret, suffix, rfd, flags, (const char**) d); } @@ -740,7 +825,7 @@ int conf_files_list_nulstr_at_full(const char *suffix, int rfd, ConfFilesFlags f d = strv_split_nulstr(dirs); if (!d) - return -ENOMEM; + return log_oom_full(conf_files_log_level(flags)); return conf_files_list_strv_at_full(suffix, rfd, flags, (const char**) d, ret_files, ret_n_files); } @@ -754,7 +839,7 @@ int conf_files_list_with_replacement( _cleanup_hashmap_free_ Hashmap *fh = NULL; _cleanup_free_ char *inserted = NULL; - ConfFilesFlags flags = CONF_FILES_REGULAR | CONF_FILES_FILTER_MASKED_BY_SYMLINK; + ConfFilesFlags flags = CONF_FILES_REGULAR | CONF_FILES_FILTER_MASKED_BY_SYMLINK | CONF_FILES_WARN; _cleanup_close_ int rfd = -EBADF; _cleanup_free_ char *root_abs = NULL; _cleanup_strv_free_ char **dirs_abs = NULL; @@ -763,7 +848,7 @@ int conf_files_list_with_replacement( assert(ret_files); - r = prepare_dirs(root, config_dirs, &rfd, &root_abs, &dirs_abs); + r = prepare_dirs(root, flags, config_dirs, &rfd, &root_abs, &dirs_abs); if (r < 0) return r; @@ -775,7 +860,9 @@ int conf_files_list_with_replacement( if (c) { r = chaseat_prefix_root(c->result, root_abs, &inserted); if (r < 0) - return log_debug_errno(r, "Failed to prefix '%s' with root '%s': %m", c->result, empty_to_root(root_abs)); + return log_full_errno(conf_files_log_level(flags), 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); @@ -791,6 +878,7 @@ int conf_files_list_dropins( char ***ret, const char *dropin_dirname, const char *root, + ConfFilesFlags flags, const char * const *dirs) { _cleanup_strv_free_ char **dropin_dirs = NULL; @@ -804,9 +892,9 @@ int conf_files_list_dropins( suffix = strjoina("/", dropin_dirname); r = strv_extend_strv_concat(&dropin_dirs, dirs, suffix); if (r < 0) - return r; + return log_oom_full(conf_files_log_level(flags)); - return conf_files_list_strv(ret, ".conf", root, 0, (const char* const*) dropin_dirs); + return conf_files_list_strv(ret, ".conf", root, flags, (const char* const*) dropin_dirs); } /** diff --git a/src/basic/conf-files.h b/src/basic/conf-files.h index 05a2966e21..90e5b1bec5 100644 --- a/src/basic/conf-files.h +++ b/src/basic/conf-files.h @@ -14,6 +14,7 @@ typedef enum ConfFilesFlags { CONF_FILES_FILTER_MASKED_BY_EMPTY = 1 << 5, /* implement masking by empty file */ 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 */ + CONF_FILES_WARN = 1 << 7, /* warn on some errors */ } ConfFilesFlags; typedef struct ConfFile { @@ -29,8 +30,8 @@ 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_file_new_at(const char *path, 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); int conf_files_list_at(char ***ret, const char *suffix, int rfd, ConfFilesFlags flags, const char *dir); @@ -56,6 +57,7 @@ int conf_files_list_dropins( char ***ret, const char *dropin_dirname, const char *root, + ConfFilesFlags flags, const char * const *dirs); typedef int parse_line_t( diff --git a/src/binfmt/binfmt.c b/src/binfmt/binfmt.c index 88af4e8699..ee7d2a4d07 100644 --- a/src/binfmt/binfmt.c +++ b/src/binfmt/binfmt.c @@ -232,7 +232,7 @@ static int run(int argc, char *argv[]) { } else { _cleanup_strv_free_ char **files = NULL; - r = conf_files_list_strv(&files, ".conf", NULL, 0, (const char**) CONF_PATHS_STRV("binfmt.d")); + r = conf_files_list_strv(&files, ".conf", /* root= */ NULL, CONF_FILES_WARN, (const char**) CONF_PATHS_STRV("binfmt.d")); if (r < 0) return log_error_errno(r, "Failed to enumerate binfmt.d files: %m"); diff --git a/src/core/ipe-setup.c b/src/core/ipe-setup.c index b266a9274e..f263117018 100644 --- a/src/core/ipe-setup.c +++ b/src/core/ipe-setup.c @@ -36,7 +36,7 @@ int ipe_setup(void) { &policies, ".p7b", /* root= */ NULL, - CONF_FILES_REGULAR|CONF_FILES_FILTER_MASKED, + CONF_FILES_REGULAR|CONF_FILES_FILTER_MASKED|CONF_FILES_WARN, CONF_PATHS_NULSTR("ipe")); if (r < 0) return log_error_errno(r, "Failed to assemble list of IPE policies: %m"); diff --git a/src/environment-d-generator/environment-d-generator.c b/src/environment-d-generator/environment-d-generator.c index 91ffaa24ea..3b2384682c 100644 --- a/src/environment-d-generator/environment-d-generator.c +++ b/src/environment-d-generator/environment-d-generator.c @@ -52,7 +52,7 @@ static int load_and_print(void) { if (r < 0) return r; - r = conf_files_list_strv(&files, ".conf", NULL, 0, (const char **) dirs); + r = conf_files_list_strv(&files, ".conf", /* root= */ NULL, CONF_FILES_WARN, (const char **) dirs); if (r < 0) return r; diff --git a/src/home/homed-manager.c b/src/home/homed-manager.c index ce4bedddc1..85c92192f4 100644 --- a/src/home/homed-manager.c +++ b/src/home/homed-manager.c @@ -1521,7 +1521,7 @@ static int manager_load_public_keys(Manager *m) { &files, ".public", NULL, - CONF_FILES_REGULAR|CONF_FILES_FILTER_MASKED, + CONF_FILES_REGULAR|CONF_FILES_FILTER_MASKED|CONF_FILES_WARN, KEY_PATHS_NULSTR); if (r < 0) return log_error_errno(r, "Failed to assemble list of public key directories: %m"); diff --git a/src/kernel-install/kernel-install.c b/src/kernel-install/kernel-install.c index a9b148d98c..b80f8d50ee 100644 --- a/src/kernel-install/kernel-install.c +++ b/src/kernel-install/kernel-install.c @@ -685,7 +685,7 @@ static int context_load_plugins(Context *c) { &c->plugins, ".install", c->rfd, - CONF_FILES_EXECUTABLE | CONF_FILES_REGULAR | CONF_FILES_FILTER_MASKED, + CONF_FILES_EXECUTABLE | CONF_FILES_REGULAR | CONF_FILES_FILTER_MASKED | CONF_FILES_WARN, STRV_MAKE_CONST("/etc/kernel/install.d", "/usr/lib/kernel/install.d")); if (r < 0) return log_error_errno(r, "Failed to find plugins: %m"); diff --git a/src/libsystemd/sd-journal/catalog.c b/src/libsystemd/sd-journal/catalog.c index 0751480fe5..9ddbc11089 100644 --- a/src/libsystemd/sd-journal/catalog.c +++ b/src/libsystemd/sd-journal/catalog.c @@ -453,7 +453,9 @@ int catalog_update(const char *database, const char *root, const char* const *di CLEANUP_ARRAY(files, n_files, conf_file_free_many); - r = conf_files_list_strv_full(".catalog", root, CONF_FILES_REGULAR | CONF_FILES_FILTER_MASKED, dirs, &files, &n_files); + r = conf_files_list_strv_full(".catalog", root, + CONF_FILES_REGULAR | CONF_FILES_FILTER_MASKED | CONF_FILES_WARN, + dirs, &files, &n_files); if (r < 0) return log_error_errno(r, "Failed to get catalog files: %m"); diff --git a/src/modules-load/modules-load.c b/src/modules-load/modules-load.c index a42e1222cf..f644c9f0f0 100644 --- a/src/modules-load/modules-load.c +++ b/src/modules-load/modules-load.c @@ -423,7 +423,7 @@ static int run(int argc, char *argv[]) { RET_GATHER(ret, modules_list_append_dup(&module_set, *i)); r = conf_files_list_nulstr_full(".conf", /* root= */ NULL, - CONF_FILES_REGULAR | CONF_FILES_FILTER_MASKED, + CONF_FILES_REGULAR | CONF_FILES_FILTER_MASKED | CONF_FILES_WARN, conf_file_dirs, &files, &n_files); if (r < 0) RET_GATHER(ret, log_error_errno(r, "Failed to enumerate modules-load.d files: %m")); diff --git a/src/network/netdev/netdev.c b/src/network/netdev/netdev.c index 945b04e967..be35c59fd9 100644 --- a/src/network/netdev/netdev.c +++ b/src/network/netdev/netdev.c @@ -1098,7 +1098,7 @@ int netdev_load(Manager *manager) { assert(manager); - r = conf_files_list_strv(&files, ".netdev", NULL, 0, NETWORK_DIRS); + r = conf_files_list_strv(&files, ".netdev", /* root= */ NULL, CONF_FILES_WARN, NETWORK_DIRS); if (r < 0) return log_error_errno(r, "Failed to enumerate netdev files: %m"); @@ -1127,7 +1127,7 @@ int netdev_reload(Manager *manager) { assert(manager); - r = conf_files_list_strv(&files, ".netdev", NULL, 0, NETWORK_DIRS); + r = conf_files_list_strv(&files, ".netdev", /* root= */ NULL, CONF_FILES_WARN, NETWORK_DIRS); if (r < 0) return log_error_errno(r, "Failed to enumerate netdev files: %m"); diff --git a/src/network/networkctl-config-file.c b/src/network/networkctl-config-file.c index e4c09b7f7c..36c6c0e8e1 100644 --- a/src/network/networkctl-config-file.c +++ b/src/network/networkctl-config-file.c @@ -106,7 +106,7 @@ static int get_config_files_by_name( if (!dropin_dirname) return -ENOMEM; - r = conf_files_list_dropins(ret_dropins, dropin_dirname, /* root= */ NULL, NETWORK_DIRS); + r = conf_files_list_dropins(ret_dropins, dropin_dirname, /* root= */ NULL, 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 14c51a8e64..4d1ed4ccca 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -612,7 +612,7 @@ int network_load(Manager *manager, OrderedHashmap **ret) { assert(manager); assert(ret); - r = conf_files_list_strv(&files, ".network", NULL, 0, NETWORK_DIRS); + r = conf_files_list_strv(&files, ".network", /* root= */ NULL, CONF_FILES_WARN, NETWORK_DIRS); if (r < 0) return log_error_errno(r, "Failed to enumerate network files: %m"); diff --git a/src/pcrlock/pcrlock.c b/src/pcrlock/pcrlock.c index d8150e8b2d..65fbce1de5 100644 --- a/src/pcrlock/pcrlock.c +++ b/src/pcrlock/pcrlock.c @@ -1802,7 +1802,9 @@ static int event_log_add_component_dir(EventLog *el, const char *path, char **ba return log_oom(); } - r = conf_files_list_strv(&files, ".pcrlock", /* root= */ NULL, CONF_FILES_REGULAR, (const char*const*) search); + r = conf_files_list_strv(&files, ".pcrlock", /* root= */ NULL, + CONF_FILES_REGULAR|CONF_FILES_WARN, + (const char*const*) search); if (r < 0) return log_error_errno(r, "Failed to enumerate .pcrlock files for component '%s': %m", id); @@ -1829,7 +1831,9 @@ static int event_log_load_components(EventLog *el) { "/usr/local/lib/pcrlock.d", "/usr/lib/pcrlock.d"); - r = conf_files_list_strv(&files, NULL, NULL, CONF_FILES_REGULAR|CONF_FILES_DIRECTORY|CONF_FILES_FILTER_MASKED, (const char*const*) dirs); + r = conf_files_list_strv(&files, /* suffix= */ NULL, /* root= */ NULL, + CONF_FILES_REGULAR|CONF_FILES_DIRECTORY|CONF_FILES_FILTER_MASKED|CONF_FILES_WARN, + (const char*const*) dirs); if (r < 0) return log_error_errno(r, "Failed to enumerate .pcrlock files: %m"); diff --git a/src/repart/repart.c b/src/repart/repart.c index cc7955a64f..19bd3441ca 100644 --- a/src/repart/repart.c +++ b/src/repart/repart.c @@ -3375,7 +3375,7 @@ static int context_read_definitions(Context *context) { &files, ".conf", context->definitions ? NULL : arg_root, - CONF_FILES_REGULAR|CONF_FILES_FILTER_MASKED, + CONF_FILES_REGULAR|CONF_FILES_FILTER_MASKED|CONF_FILES_WARN, dirs); if (r < 0) return log_error_errno(r, "Failed to enumerate *.conf files: %m"); diff --git a/src/resolve/resolved-dns-delegate.c b/src/resolve/resolved-dns-delegate.c index 287f9ad131..b866a5838d 100644 --- a/src/resolve/resolved-dns-delegate.c +++ b/src/resolve/resolved-dns-delegate.c @@ -211,7 +211,7 @@ int manager_load_delegates(Manager *m) { assert(m); - r = conf_files_list_strv(&files, ".dns-delegate", /* root= */ NULL, /* flags= */ 0, DNS_DELEGATE_SEARCH_DIRS); + r = conf_files_list_strv(&files, ".dns-delegate", /* root= */ NULL, CONF_FILES_WARN, DNS_DELEGATE_SEARCH_DIRS); if (r < 0) return log_error_errno(r, "Failed to enumerate .dns-delegate files: %m"); diff --git a/src/resolve/resolved-dns-trust-anchor.c b/src/resolve/resolved-dns-trust-anchor.c index 970fe1ea54..0896dc870c 100644 --- a/src/resolve/resolved-dns-trust-anchor.c +++ b/src/resolve/resolved-dns-trust-anchor.c @@ -437,7 +437,7 @@ static int dns_trust_anchor_load_files( assert(suffix); assert(loader); - r = conf_files_list_nulstr(&files, suffix, NULL, 0, trust_anchor_dirs); + r = conf_files_list_nulstr(&files, suffix, /* root= */ NULL, CONF_FILES_WARN, trust_anchor_dirs); if (r < 0) return log_error_errno(r, "Failed to enumerate %s trust anchor files: %m", suffix); diff --git a/src/resolve/resolved-dnssd.c b/src/resolve/resolved-dnssd.c index d6491ea64f..977f786913 100644 --- a/src/resolve/resolved-dnssd.c +++ b/src/resolve/resolved-dnssd.c @@ -225,7 +225,7 @@ int dnssd_load(Manager *manager) { if (manager->mdns_support != RESOLVE_SUPPORT_YES) return 0; - r = conf_files_list_strv(&files, ".dnssd", NULL, 0, DNSSD_SERVICE_DIRS); + r = conf_files_list_strv(&files, ".dnssd", /* root= */ NULL, CONF_FILES_WARN, DNSSD_SERVICE_DIRS); if (r < 0) return log_error_errno(r, "Failed to enumerate .dnssd files: %m"); diff --git a/src/shared/conf-parser.c b/src/shared/conf-parser.c index a9afd51d0e..e5e1855892 100644 --- a/src/shared/conf-parser.c +++ b/src/shared/conf-parser.c @@ -615,7 +615,9 @@ int config_parse_many( assert(dropin_dirname); assert(table); - r = conf_files_list_dropins(&files, dropin_dirname, root, conf_file_dirs); + r = conf_files_list_dropins(&files, dropin_dirname, root, + 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); @@ -690,7 +692,7 @@ static int dropins_get_stats_by_path( if (!strextend(&dropin_dirname, ".d")) return -ENOMEM; - r = conf_files_list_dropins(&files, dropin_dirname, /* root= */ NULL, conf_file_dirs); + r = conf_files_list_dropins(&files, dropin_dirname, /* root= */ NULL, /* flags= */ 0, conf_file_dirs); if (r < 0) return r; @@ -715,7 +717,7 @@ static int dropins_get_stats_by_path( int config_get_stats_by_path( const char *suffix, const char *root, - unsigned flags, + ConfFilesFlags flags, const char* const* dirs, bool check_dropins, Hashmap **ret) { diff --git a/src/shared/conf-parser.h b/src/shared/conf-parser.h index ce47ae3173..b394131b64 100644 --- a/src/shared/conf-parser.h +++ b/src/shared/conf-parser.h @@ -112,7 +112,7 @@ static inline int config_parse_standard_file_with_dropins( int config_get_stats_by_path( const char *suffix, const char *root, - unsigned flags, + ConfFilesFlags flags, const char* const* dirs, bool check_dropins, Hashmap **ret); diff --git a/src/shared/dropin.c b/src/shared/dropin.c index f540f48933..405a3c0e5d 100644 --- a/src/shared/dropin.c +++ b/src/shared/dropin.c @@ -287,7 +287,7 @@ int unit_file_find_dropin_paths( return 0; } - r = conf_files_list_strv(ret, file_suffix, NULL, 0, (const char**) dirs); + r = conf_files_list_strv(ret, file_suffix, /* root= */ NULL, CONF_FILES_WARN, (const char**) dirs); if (r < 0) return log_warning_errno(r, "Failed to create the list of configuration files: %m"); diff --git a/src/shared/exec-util.c b/src/shared/exec-util.c index 9221350fdc..2e15f311b8 100644 --- a/src/shared/exec-util.c +++ b/src/shared/exec-util.c @@ -323,7 +323,7 @@ int execute_directories( &paths, /* suffix= */ NULL, /* root= */ NULL, - CONF_FILES_EXECUTABLE|CONF_FILES_REGULAR|CONF_FILES_FILTER_MASKED, + CONF_FILES_EXECUTABLE|CONF_FILES_REGULAR|CONF_FILES_FILTER_MASKED|CONF_FILES_WARN, directories); if (r < 0) return log_error_errno(r, "%s: failed to enumerate executables: %m", name); diff --git a/src/shared/hwdb-util.c b/src/shared/hwdb-util.c index 1eab1fb881..29942254f3 100644 --- a/src/shared/hwdb-util.c +++ b/src/shared/hwdb-util.c @@ -610,7 +610,9 @@ int hwdb_update(const char *root, const char *hwdb_bin_dir, bool strict, bool co CLEANUP_ARRAY(files, n_files, conf_file_free_many); - r = conf_files_list_strv_full(".hwdb", root, CONF_FILES_REGULAR | CONF_FILES_FILTER_MASKED, conf_file_dirs, &files, &n_files); + r = conf_files_list_strv_full(".hwdb", root, + CONF_FILES_REGULAR | CONF_FILES_FILTER_MASKED | CONF_FILES_WARN, + conf_file_dirs, &files, &n_files); if (r < 0) return log_error_errno(r, "Failed to enumerate hwdb files: %m"); diff --git a/src/shared/mount-setup.c b/src/shared/mount-setup.c index 9077d08691..8c6cd2b12b 100644 --- a/src/shared/mount-setup.c +++ b/src/shared/mount-setup.c @@ -418,7 +418,7 @@ static int relabel_extra(void) { */ r = conf_files_list(&files, ".relabel", NULL, - CONF_FILES_FILTER_MASKED | CONF_FILES_REGULAR, + CONF_FILES_FILTER_MASKED | CONF_FILES_REGULAR | CONF_FILES_WARN, "/run/systemd/relabel-extra.d/"); if (r < 0) return log_error_errno(r, "Failed to enumerate /run/systemd/relabel-extra.d/, ignoring: %m"); diff --git a/src/shared/pretty-print.c b/src/shared/pretty-print.c index 36f552960b..7e04acbcfc 100644 --- a/src/shared/pretty-print.c +++ b/src/shared/pretty-print.c @@ -6,7 +6,6 @@ #include #include "alloc-util.h" -#include "chase.h" #include "color-util.h" #include "conf-files.h" #include "constants.h" @@ -325,9 +324,22 @@ static int cat_file_by_path(const char *p, bool *newline, CatFlags flags) { assert(p); - r = conf_file_new(p, /* root= */ NULL, CHASE_MUST_BE_REGULAR, &c); + r = conf_file_new(p, /* root= */ NULL, CONF_FILES_REGULAR | CONF_FILES_FILTER_MASKED | CONF_FILES_WARN, &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) - return log_error_errno(r, "Failed to chase '%s': %m", p); + return r; return cat_file(c, newline, flags); } @@ -458,7 +470,8 @@ int conf_files_cat(const char *root, const char *name, CatFlags flags) { if (!p) return log_oom(); - if (conf_file_new(p, root, CHASE_MUST_BE_REGULAR, &c) >= 0) + r = conf_file_new(p, root, CONF_FILES_REGULAR | CONF_FILES_FILTER_MASKED, &c); + if (r >= 0 || r == -ERFKILL) /* Found a regular file or masked file */ break; } @@ -473,7 +486,7 @@ int conf_files_cat(const char *root, const char *name, CatFlags flags) { ConfFile **dropins = NULL; size_t n_dropins = 0; CLEANUP_ARRAY(dropins, n_dropins, conf_file_free_many); - r = conf_files_list_strv_full(extension, root, CONF_FILES_REGULAR | CONF_FILES_FILTER_MASKED, (const char* const*) dirs, &dropins, &n_dropins); + r = conf_files_list_strv_full(extension, root, CONF_FILES_REGULAR | CONF_FILES_FILTER_MASKED | CONF_FILES_WARN, (const char* const*) dirs, &dropins, &n_dropins); if (r < 0) return log_error_errno(r, "Failed to query file list: %m"); diff --git a/src/sysctl/sysctl.c b/src/sysctl/sysctl.c index 912e18a95c..cf7dea24f5 100644 --- a/src/sysctl/sysctl.c +++ b/src/sysctl/sysctl.c @@ -461,7 +461,8 @@ static int run(int argc, char *argv[]) { } else { _cleanup_strv_free_ char **files = NULL; - r = conf_files_list_strv(&files, ".conf", NULL, 0, (const char**) CONF_PATHS_STRV("sysctl.d")); + r = conf_files_list_strv(&files, ".conf", /* root= */ NULL, CONF_FILES_WARN, + (const char**) CONF_PATHS_STRV("sysctl.d")); if (r < 0) return log_error_errno(r, "Failed to enumerate sysctl.d files: %m"); diff --git a/src/sysupdate/sysupdate.c b/src/sysupdate/sysupdate.c index de3a9d2c48..6702358ccc 100644 --- a/src/sysupdate/sysupdate.c +++ b/src/sysupdate/sysupdate.c @@ -136,7 +136,9 @@ static int read_definitions( assert(dirs); assert(suffix); - r = conf_files_list_strv_full(suffix, arg_root, CONF_FILES_REGULAR|CONF_FILES_FILTER_MASKED, dirs, &files, &n_files); + r = conf_files_list_strv_full(suffix, arg_root, + CONF_FILES_REGULAR|CONF_FILES_FILTER_MASKED|CONF_FILES_WARN, + dirs, &files, &n_files); if (r < 0) return log_error_errno(r, "Failed to enumerate sysupdate.d/*%s definitions: %m", suffix); @@ -209,7 +211,7 @@ static int context_read_definitions(Context *c, const char* node, bool requires_ CLEANUP_ARRAY(files, n_files, conf_file_free_many); r = conf_files_list_strv_full(".feature", arg_root, - CONF_FILES_REGULAR|CONF_FILES_FILTER_MASKED, + CONF_FILES_REGULAR|CONF_FILES_FILTER_MASKED|CONF_FILES_WARN, (const char**) dirs, &files, &n_files); if (r < 0) return log_error_errno(r, "Failed to enumerate sysupdate.d/*.feature definitions: %m"); @@ -1558,7 +1560,8 @@ static int verb_components(int argc, char **argv, void *userdata) { CLEANUP_ARRAY(directories, n_directories, conf_file_free_many); - r = conf_files_list_strv_full(".d", arg_root, CONF_FILES_DIRECTORY, (const char * const *) CONF_PATHS_STRV(""), &directories, &n_directories); + r = conf_files_list_strv_full(".d", arg_root, CONF_FILES_DIRECTORY|CONF_FILES_WARN, + (const char * const *) CONF_PATHS_STRV(""), &directories, &n_directories); if (r < 0) return log_error_errno(r, "Failed to enumerate directories: %m"); diff --git a/src/test/test-pretty-print.c b/src/test/test-pretty-print.c index 71d8799cbf..073930df09 100644 --- a/src/test/test-pretty-print.c +++ b/src/test/test-pretty-print.c @@ -4,8 +4,11 @@ #include #include "alloc-util.h" +#include "path-util.h" #include "pretty-print.h" +#include "rm-rf.h" #include "tests.h" +#include "tmpfile-util.h" #define CYLON_WIDTH 6 @@ -53,6 +56,13 @@ TEST(cat_files) { if (access("/etc/fstab", R_OK) >= 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) { diff --git a/src/timedate/timedated.c b/src/timedate/timedated.c index d1ef772b56..5ba8644334 100644 --- a/src/timedate/timedated.c +++ b/src/timedate/timedated.c @@ -184,7 +184,9 @@ static int context_parse_ntp_services_from_disk(Context *c) { _cleanup_strv_free_ char **files = NULL; int r; - r = conf_files_list_strv(&files, ".list", NULL, CONF_FILES_FILTER_MASKED, UNIT_LIST_DIRS); + r = conf_files_list_strv(&files, ".list", /* root= */ NULL, + CONF_FILES_FILTER_MASKED | CONF_FILES_WARN, + UNIT_LIST_DIRS); if (r < 0) return log_error_errno(r, "Failed to enumerate .list files: %m"); diff --git a/src/tpm2-setup/tpm2-setup.c b/src/tpm2-setup/tpm2-setup.c index c73dd377ed..1d057ea0e2 100644 --- a/src/tpm2-setup/tpm2-setup.c +++ b/src/tpm2-setup/tpm2-setup.c @@ -450,7 +450,7 @@ static int setup_nvpcr(void) { &l, ".nvpcr", /* root= */ NULL, - CONF_FILES_REGULAR|CONF_FILES_BASENAME|CONF_FILES_FILTER_MASKED|CONF_FILES_TRUNCATE_SUFFIX, + CONF_FILES_REGULAR|CONF_FILES_BASENAME|CONF_FILES_FILTER_MASKED|CONF_FILES_TRUNCATE_SUFFIX|CONF_FILES_WARN, CONF_PATHS_NULSTR("nvpcr")); if (r < 0) return log_error_errno(r, "Failed to find .nvpcr files: %m"); diff --git a/src/udev/fuzz-udev-rules.c b/src/udev/fuzz-udev-rules.c index e91954311d..b3387e8856 100644 --- a/src/udev/fuzz-udev-rules.c +++ b/src/udev/fuzz-udev-rules.c @@ -2,7 +2,6 @@ #include -#include "chase.h" #include "conf-files.h" #include "fd-util.h" #include "fuzz.h" @@ -29,7 +28,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { assert_se(rules = udev_rules_new(RESOLVE_NAME_EARLY)); _cleanup_(conf_file_freep) ConfFile *c = NULL; - ASSERT_OK(conf_file_new(filename, /* root= */ NULL, CHASE_MUST_BE_REGULAR, &c)); + ASSERT_OK(conf_file_new(filename, /* root= */ NULL, CONF_FILES_REGULAR, &c)); r = udev_rules_parse_file(rules, c, /* extra_checks= */ false, /* ret= */ NULL); log_info_errno(r, "Parsing %s: %m", filename); diff --git a/src/udev/net/link-config.c b/src/udev/net/link-config.c index 35dfa0d95a..378e909b9b 100644 --- a/src/udev/net/link-config.c +++ b/src/udev/net/link-config.c @@ -342,7 +342,7 @@ int link_config_load(LinkConfigContext *ctx) { link_configs_free(ctx); - r = conf_files_list_strv(&files, ".link", NULL, 0, NETWORK_DIRS); + r = conf_files_list_strv(&files, ".link", /* root= */ NULL, CONF_FILES_WARN, NETWORK_DIRS); if (r < 0) return log_error_errno(r, "failed to enumerate link files: %m"); diff --git a/src/udev/udevadm-util.c b/src/udev/udevadm-util.c index a171060471..14b508007f 100644 --- a/src/udev/udevadm-util.c +++ b/src/udev/udevadm-util.c @@ -7,7 +7,6 @@ #include "alloc-util.h" #include "bus-error.h" #include "bus-util.h" -#include "chase.h" #include "conf-files.h" #include "constants.h" #include "device-private.h" @@ -249,11 +248,15 @@ static int search_rules_file_in_conf_dirs(const char *s, const char *root, ConfF return log_oom(); _cleanup_(conf_file_freep) ConfFile *c = NULL; - r = conf_file_new(path, root, CHASE_MUST_BE_REGULAR, &c); + r = conf_file_new(path, root, CONF_FILES_REGULAR | CONF_FILES_FILTER_MASKED, &c); + if (r == -ERFKILL) { + log_warning_errno(r, "File '%s%s' is a mask, ignoring.", empty_to_root(root), skip_leading_slash(path)); + return 1; /* Found masked file. */ + } if (r == -ENOENT) continue; if (r < 0) - return log_error_errno(r, "Failed to chase \"%s\": %m", path); + return log_error_errno(r, "Failed to chase '%s%s': %m", empty_to_root(root), skip_leading_slash(path)); if (!GREEDY_REALLOC_APPEND(*files, *n_files, &c, 1)) return log_oom(); @@ -279,7 +282,11 @@ 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. */ _cleanup_(conf_file_freep) ConfFile *c = NULL; - r = conf_file_new(s, root, CHASE_MUST_BE_REGULAR, &c); + r = conf_file_new(s, root, CONF_FILES_REGULAR | CONF_FILES_FILTER_MASKED, &c); + if (r == -ERFKILL) { + log_warning_errno(r, "File '%s%s' is a mask, ignoring.", empty_to_root(root), skip_leading_slash(s)); + return 0; /* Found masked file. */ + } if (r >= 0) { if (!GREEDY_REALLOC_APPEND(*files, *n_files, &c, 1)) return log_oom(); @@ -289,7 +296,7 @@ static int search_rules_file(const char *s, const char *root, ConfFile ***files, } if (r != -EISDIR) - return log_error_errno(r, "Failed to chase \"%s\": %m", s); + return log_error_errno(r, "Failed to chase '%s%s': %m", empty_to_root(root), skip_leading_slash(s)); /* If a directory is specified, then find all rules file in the directory. */ ConfFile **f = NULL; @@ -297,9 +304,9 @@ static int search_rules_file(const char *s, const char *root, ConfFile ***files, CLEANUP_ARRAY(f, n, conf_file_free_many); - r = conf_files_list_strv_full(".rules", root, CONF_FILES_REGULAR, (const char* const*) STRV_MAKE_CONST(s), &f, &n); + r = conf_files_list_strv_full(".rules", root, CONF_FILES_REGULAR | CONF_FILES_WARN, (const char* const*) STRV_MAKE_CONST(s), &f, &n); if (r < 0) - return log_error_errno(r, "Failed to enumerate rules files in '%s': %m", s); + return log_error_errno(r, "Failed to enumerate rules files in '%s%s': %m", empty_to_root(root), skip_leading_slash(s)); if (!GREEDY_REALLOC_APPEND(*files, *n_files, f, n)) return log_oom(); @@ -320,7 +327,7 @@ int search_rules_files(char * const *a, const char *root, ConfFile ***ret_files, assert(ret_n_files); if (strv_isempty(a)) { - r = conf_files_list_strv_full(".rules", root, CONF_FILES_REGULAR | CONF_FILES_FILTER_MASKED, + r = conf_files_list_strv_full(".rules", root, CONF_FILES_REGULAR | CONF_FILES_FILTER_MASKED | CONF_FILES_WARN, (const char* const*) CONF_PATHS_STRV("udev/rules.d"), &files, &n_files); if (r < 0) return log_error_errno(r, "Failed to enumerate rules files: %m"); diff --git a/test/units/TEST-17-UDEV.sanity-check.sh b/test/units/TEST-17-UDEV.sanity-check.sh index 98a277a47e..5f1a93e78f 100755 --- a/test/units/TEST-17-UDEV.sanity-check.sh +++ b/test/units/TEST-17-UDEV.sanity-check.sh @@ -38,7 +38,7 @@ udevadm cat 99-systemd udevadm cat 99-systemd.rules udevadm cat /usr/lib/udev/rules.d/99-systemd.rules udevadm cat /usr/lib/udev/rules.d -(! udevadm cat /dev/null) +udevadm cat /dev/null udevadm cat --config udevadm cat -h diff --git a/test/units/TEST-17-UDEV.verify.sh b/test/units/TEST-17-UDEV.verify.sh index 5b6baa4280..66f34a3e36 100755 --- a/test/units/TEST-17-UDEV.verify.sh +++ b/test/units/TEST-17-UDEV.verify.sh @@ -118,8 +118,7 @@ assert_1 --resolve-names=now assert_1 ./nosuchfile # Failed to parse rules file ./nosuchfile: No such file or directory assert_1 ./nosuchfile /dev/null -# '/dev/null' is neither a regular file nor a directory: File descriptor in bad state -assert_1 /dev/null +assert_0 /dev/null rules_dir='etc/udev/rules.d' mkdir -p "${rules_dir}"