tmpfiles: fix root handling and target resolution (#43031)

This commit is contained in:
Yu Watanabe
2026-07-24 21:15:11 +09:00
committed by GitHub
4 changed files with 139 additions and 20 deletions
+35 -20
View File
@@ -322,16 +322,7 @@ static int specifier_directory(
if (r < 0)
return r;
if (arg_root) {
_cleanup_free_ char *j = NULL;
j = path_join(arg_root, p);
if (!j)
return -ENOMEM;
*ret = TAKE_PTR(j);
} else
*ret = TAKE_PTR(p);
*ret = TAKE_PTR(p);
return 0;
}
@@ -817,9 +808,14 @@ static int dir_cleanup(
log_action("Would remove", "Removing", "%s directory \"%s\"", sub_path);
if (!arg_dry_run &&
unlinkat(dirfd(d), de->d_name, AT_REMOVEDIR) < 0 &&
!IN_SET(errno, ENOENT, ENOTEMPTY))
r = log_warning_errno(errno, "Failed to remove directory \"%s\", ignoring: %m", sub_path);
unlinkat(dirfd(d), de->d_name, AT_REMOVEDIR) < 0) {
if (errno == ENOTEMPTY)
continue;
if (errno != ENOENT)
r = log_warning_errno(errno, "Failed to remove directory \"%s\", ignoring: %m", sub_path);
}
deleted = true;
} else {
_cleanup_close_ int fd = -EBADF; /* This file descriptor is defined here so that the
@@ -2247,11 +2243,14 @@ static int copy_files(Context *c, Item *i) {
return log_error_errno(errno, "Failed to openat(%s): %m", i->path);
}
if (r < 0 && !IN_SET(r, -EEXIST, -EROFS))
return log_error_errno(r, "Failed to copy files to %s: %m", i->path);
if (fstat(fd, &st) < 0)
return log_error_errno(errno, "Failed to fstat(%s): %m", i->path);
if (stat(i->argument, &a) < 0)
return log_error_errno(errno, "Failed to stat(%s): %m", i->argument);
if (lstat(i->argument, &a) < 0)
return log_error_errno(errno, "Failed to lstat(%s): %m", i->argument);
if (((st.st_mode ^ a.st_mode) & S_IFMT) != 0) {
log_debug("Can't copy to %s, file exists already and is of different type", i->path);
@@ -2689,16 +2688,30 @@ static int create_symlink(Context *c, Item *i) {
assert(i);
if (i->ignore_if_target_missing) {
r = chase(i->argument, arg_root, CHASE_SAFE|CHASE_PREFIX_ROOT|CHASE_NOFOLLOW, /* ret_path= */ NULL, /* ret_fd= */ NULL);
_cleanup_free_ char *target = NULL;
ChaseFlags chase_flags = CHASE_SAFE|CHASE_NOFOLLOW;
if (!path_is_absolute(i->argument)) {
_cleanup_free_ char *dn = NULL;
r = path_extract_directory(i->path, &dn);
if (r < 0)
return log_error_errno(r, "Failed to extract directory from path '%s': %m", i->path);
target = path_join(dn, i->argument);
if (!target)
return log_oom();
} else
chase_flags |= CHASE_PREFIX_ROOT;
r = chase(target ?: i->argument, arg_root, chase_flags, /* ret_path= */ NULL, /* ret_fd= */ NULL);
if (r == -ENOENT) {
/* Silently skip over lines where the source file is missing. */
log_debug_errno(r, "Symlink source path '%s/%s' does not exist, skipping line.",
strempty(arg_root), skip_leading_slash(i->argument));
log_debug_errno(r, "Symlink source path '%s' does not exist, skipping line.", i->argument);
return 0;
}
if (r < 0)
return log_error_errno(r, "Failed to check if symlink source path '%s/%s' exists: %m",
strempty(arg_root), skip_leading_slash(i->argument));
return log_error_errno(r, "Failed to check if symlink source path '%s' exists: %m", i->argument);
}
r = path_extract_filename(i->path, &bn);
@@ -4707,6 +4720,8 @@ static int read_config_file(
if (candidate_item && candidate_item->age_set) {
i->age = candidate_item->age;
i->age_set = true;
i->age_by_file = candidate_item->age_by_file;
i->age_by_dir = candidate_item->age_by_dir;
}
}