From c918ac7401a081221761504ec769ab7bb0015267 Mon Sep 17 00:00:00 2001 From: Nick Date: Mon, 12 Oct 2026 17:13:04 +0400 Subject: [PATCH] tmpfiles: do not fail --clean when a file disappears during cleanup dir_cleanup() stores the result of xstatx_full() in r, which is also the function's return value. If a file is removed between readdir() and statx(), it is skipped, but when it was the last entry r stays -ENOENT and --clean fails with EX_CANTCREAT without logging anything. A successful statx() also overwrote errors recorded for earlier entries. Use a separate variable for the statx() result. Reproducer: d=$(mktemp -d) echo "d $d - - - 1d" >$d.conf while :; do touch $d/f{1..200}; rm -f $d/f*; done & for i in $(seq 200); do systemd-tmpfiles --clean $d.conf; echo $?; done | sort | uniq -c kill %1 Before: 177 0 23 73 After: 200 0 Follow-up for a98a6eb95cc980edab4b0f9c59e6573edc7ffe0c. Follow-up for 10072d8be44a3687221adc042cf9b9b45b4c9689. (cherry picked from commit 4c250e3f1325f91cdee047f7daeaf532abe4af6f) --- src/tmpfiles/tmpfiles.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c index b1f81d127c..8924950a4d 100644 --- a/src/tmpfiles/tmpfiles.c +++ b/src/tmpfiles/tmpfiles.c @@ -715,18 +715,18 @@ static int dir_cleanup( continue; struct statx sx; - r = xstatx_full(dirfd(d), de->d_name, - AT_SYMLINK_NOFOLLOW|AT_NO_AUTOMOUNT, - /* xstatx_flags= */ 0, - STATX_TYPE|STATX_MODE|STATX_UID, - STATX_ATIME|STATX_MTIME|STATX_CTIME|STATX_BTIME, - STATX_ATTR_MOUNT_ROOT, - &sx); - if (r == -ENOENT) + int k = xstatx_full(dirfd(d), de->d_name, + AT_SYMLINK_NOFOLLOW|AT_NO_AUTOMOUNT, + /* xstatx_flags= */ 0, + STATX_TYPE|STATX_MODE|STATX_UID, + STATX_ATIME|STATX_MTIME|STATX_CTIME|STATX_BTIME, + STATX_ATTR_MOUNT_ROOT, + &sx); + if (k == -ENOENT) continue; - if (r < 0) { + if (k < 0) { /* FUSE, NFS mounts, SELinux might return EACCES */ - log_full_errno(r == -EACCES ? LOG_DEBUG : LOG_ERR, r, + log_full_errno(k == -EACCES ? LOG_DEBUG : LOG_ERR, k, "statx(%s/%s) failed: %m", p, de->d_name); continue; }