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 a98a6eb95c.
Follow-up for 10072d8be4.
(cherry picked from commit 4c250e3f1325f91cdee047f7daeaf532abe4af6f)
This commit is contained in:
+10
-10
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user