mirror of
https://github.com/systemd/systemd.git
synced 2024-11-28 04:33:36 +08:00
Merge pull request #16928 from poettering/statx-fallback
stat-util: provide single statx() fallback on top of fstatat()
This commit is contained in:
commit
6743a1caf4
@ -49,6 +49,16 @@ struct statx STATX_DEFINITION;
|
||||
* defines an older definition */
|
||||
struct new_statx STATX_DEFINITION;
|
||||
|
||||
/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */
|
||||
#ifndef AT_STATX_SYNC_AS_STAT
|
||||
#define AT_STATX_SYNC_AS_STAT 0x0000
|
||||
#endif
|
||||
|
||||
/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */
|
||||
#ifndef AT_STATX_FORCE_SYNC
|
||||
#define AT_STATX_FORCE_SYNC 0x2000
|
||||
#endif
|
||||
|
||||
/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */
|
||||
#ifndef AT_STATX_DONT_SYNC
|
||||
#define AT_STATX_DONT_SYNC 0x4000
|
||||
@ -64,11 +74,21 @@ struct new_statx STATX_DEFINITION;
|
||||
#define STATX_MODE 0x00000002U
|
||||
#endif
|
||||
|
||||
/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */
|
||||
#ifndef STATX_NLINK
|
||||
#define STATX_NLINK 0x00000004U
|
||||
#endif
|
||||
|
||||
/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */
|
||||
#ifndef STATX_UID
|
||||
#define STATX_UID 0x00000008U
|
||||
#endif
|
||||
|
||||
/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */
|
||||
#ifndef STATX_GID
|
||||
#define STATX_GID 0x00000010U
|
||||
#endif
|
||||
|
||||
/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */
|
||||
#ifndef STATX_ATIME
|
||||
#define STATX_ATIME 0x00000020U
|
||||
@ -89,6 +109,16 @@ struct new_statx STATX_DEFINITION;
|
||||
#define STATX_INO 0x00000100U
|
||||
#endif
|
||||
|
||||
/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */
|
||||
#ifndef STATX_SIZE
|
||||
#define STATX_SIZE 0x00000200U
|
||||
#endif
|
||||
|
||||
/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */
|
||||
#ifndef STATX_BLOCKS
|
||||
#define STATX_BLOCKS 0x00000400U
|
||||
#endif
|
||||
|
||||
/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */
|
||||
#ifndef STATX_BTIME
|
||||
#define STATX_BTIME 0x00000800U
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "mountpoint-util.h"
|
||||
#include "parse-util.h"
|
||||
#include "path-util.h"
|
||||
#include "stat-util.h"
|
||||
#include "stdio-util.h"
|
||||
#include "strv.h"
|
||||
|
||||
@ -135,13 +136,8 @@ int fd_is_mount_point(int fd, const char *filename, int flags) {
|
||||
_cleanup_free_ struct file_handle *h = NULL, *h_parent = NULL;
|
||||
int mount_id = -1, mount_id_parent = -1;
|
||||
bool nosupp = false, check_st_dev = true;
|
||||
STRUCT_STATX_DEFINE(sx);
|
||||
struct stat a, b;
|
||||
struct statx sx
|
||||
#if HAS_FEATURE_MEMORY_SANITIZER
|
||||
= {}
|
||||
# warning "Explicitly initializing struct statx, to work around msan limitation. Please remove as soon as msan has been updated to not require this."
|
||||
#endif
|
||||
;
|
||||
int r;
|
||||
|
||||
assert(fd >= 0);
|
||||
@ -298,15 +294,7 @@ int path_is_mount_point(const char *t, const char *root, int flags) {
|
||||
}
|
||||
|
||||
int path_get_mnt_id(const char *path, int *ret) {
|
||||
union {
|
||||
struct statx sx;
|
||||
struct new_statx nsx;
|
||||
} buf
|
||||
#if HAS_FEATURE_MEMORY_SANITIZER
|
||||
= {}
|
||||
# warning "Explicitly initializing struct statx, to work around msan limitation. Please remove as soon as msan has been updated to not require this."
|
||||
#endif
|
||||
;
|
||||
STRUCT_NEW_STATX_DEFINE(buf);
|
||||
int r;
|
||||
|
||||
if (statx(AT_FDCWD, path, AT_SYMLINK_NOFOLLOW|AT_NO_AUTOMOUNT, STATX_MNT_ID, &buf.sx) < 0) {
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "macro.h"
|
||||
#include "missing_fs.h"
|
||||
#include "missing_magic.h"
|
||||
#include "missing_syscall.h"
|
||||
#include "parse-util.h"
|
||||
#include "stat-util.h"
|
||||
#include "string-util.h"
|
||||
@ -413,3 +414,59 @@ bool stat_inode_unmodified(const struct stat *a, const struct stat *b) {
|
||||
a->st_ino == b->st_ino &&
|
||||
(!(S_ISCHR(a->st_mode) || S_ISBLK(a->st_mode)) || a->st_rdev == b->st_rdev); /* if device node, also compare major/minor, because we can */
|
||||
}
|
||||
|
||||
int statx_fallback(int dfd, const char *path, int flags, unsigned mask, struct statx *sx) {
|
||||
static bool avoid_statx = false;
|
||||
struct stat st;
|
||||
|
||||
if (!avoid_statx) {
|
||||
if (statx(dfd, path, flags, mask, sx) < 0) {
|
||||
if (!ERRNO_IS_NOT_SUPPORTED(errno) && errno != EPERM)
|
||||
return -errno;
|
||||
|
||||
/* If statx() is not supported or if we see EPERM (which might indicate seccomp
|
||||
* filtering or so), let's do a fallback. Not that on EACCES we'll not fall back,
|
||||
* since that is likely an indication of fs access issues, which we should
|
||||
* propagate */
|
||||
} else
|
||||
return 0;
|
||||
|
||||
avoid_statx = true;
|
||||
}
|
||||
|
||||
/* Only do fallback if fstatat() supports the flag too, or if it's one of the sync flags, which are
|
||||
* OK to ignore */
|
||||
if ((flags & ~(AT_EMPTY_PATH|AT_NO_AUTOMOUNT|AT_SYMLINK_NOFOLLOW|
|
||||
AT_STATX_SYNC_AS_STAT|AT_STATX_FORCE_SYNC|AT_STATX_DONT_SYNC)) != 0)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (fstatat(dfd, path, &st, flags & (AT_EMPTY_PATH|AT_NO_AUTOMOUNT|AT_SYMLINK_NOFOLLOW)) < 0)
|
||||
return -errno;
|
||||
|
||||
*sx = (struct statx) {
|
||||
.stx_mask = STATX_TYPE|STATX_MODE|
|
||||
STATX_NLINK|STATX_UID|STATX_GID|
|
||||
STATX_ATIME|STATX_MTIME|STATX_CTIME|
|
||||
STATX_INO|STATX_SIZE|STATX_BLOCKS,
|
||||
.stx_blksize = st.st_blksize,
|
||||
.stx_nlink = st.st_nlink,
|
||||
.stx_uid = st.st_uid,
|
||||
.stx_gid = st.st_gid,
|
||||
.stx_mode = st.st_mode,
|
||||
.stx_ino = st.st_ino,
|
||||
.stx_size = st.st_size,
|
||||
.stx_blocks = st.st_blocks,
|
||||
.stx_rdev_major = major(st.st_rdev),
|
||||
.stx_rdev_minor = minor(st.st_rdev),
|
||||
.stx_dev_major = major(st.st_dev),
|
||||
.stx_dev_minor = minor(st.st_dev),
|
||||
.stx_atime.tv_sec = st.st_atim.tv_sec,
|
||||
.stx_atime.tv_nsec = st.st_atim.tv_nsec,
|
||||
.stx_mtime.tv_sec = st.st_mtim.tv_sec,
|
||||
.stx_mtime.tv_nsec = st.st_mtim.tv_nsec,
|
||||
.stx_ctime.tv_sec = st.st_ctim.tv_sec,
|
||||
.stx_ctime.tv_nsec = st.st_ctim.tv_nsec,
|
||||
};
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include <sys/vfs.h>
|
||||
|
||||
#include "macro.h"
|
||||
#include "missing_stat.h"
|
||||
|
||||
int is_symlink(const char *path);
|
||||
int is_dir(const char *path, bool follow);
|
||||
@ -91,3 +92,24 @@ int device_path_parse_major_minor(const char *path, mode_t *ret_mode, dev_t *ret
|
||||
int proc_mounted(void);
|
||||
|
||||
bool stat_inode_unmodified(const struct stat *a, const struct stat *b);
|
||||
|
||||
int statx_fallback(int dfd, const char *path, int flags, unsigned mask, struct statx *sx);
|
||||
|
||||
#if HAS_FEATURE_MEMORY_SANITIZER
|
||||
# warning "Explicitly initializing struct statx, to work around msan limitation. Please remove as soon as msan has been updated to not require this."
|
||||
# define STRUCT_STATX_DEFINE(var) \
|
||||
struct statx var = {}
|
||||
# define STRUCT_NEW_STATX_DEFINE(var) \
|
||||
union { \
|
||||
struct statx sx; \
|
||||
struct new_statx nsx; \
|
||||
} var = {}
|
||||
#else
|
||||
# define STRUCT_STATX_DEFINE(var) \
|
||||
struct statx var
|
||||
# define STRUCT_NEW_STATX_DEFINE(var) \
|
||||
union { \
|
||||
struct statx sx; \
|
||||
struct new_statx nsx; \
|
||||
} var
|
||||
#endif
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "macro.h"
|
||||
#include "missing_syscall.h"
|
||||
#include "sparse-endian.h"
|
||||
#include "stat-util.h"
|
||||
#include "stdio-util.h"
|
||||
#include "string-util.h"
|
||||
#include "time-util.h"
|
||||
@ -154,12 +155,7 @@ static int parse_crtime(le64_t le, usec_t *usec) {
|
||||
}
|
||||
|
||||
int fd_getcrtime_at(int dirfd, const char *name, usec_t *ret, int flags) {
|
||||
struct_statx sx
|
||||
#if HAS_FEATURE_MEMORY_SANITIZER
|
||||
= {}
|
||||
# warning "Explicitly initializing struct statx, to work around msan limitation. Please remove as soon as msan has been updated to not require this."
|
||||
#endif
|
||||
;
|
||||
STRUCT_STATX_DEFINE(sx);
|
||||
usec_t a, b;
|
||||
le64_t le;
|
||||
size_t n;
|
||||
|
@ -517,7 +517,6 @@ static int dir_cleanup(
|
||||
int maxdepth,
|
||||
bool keep_this_level) {
|
||||
|
||||
static bool use_statx = true;
|
||||
bool deleted = false;
|
||||
struct dirent *dent;
|
||||
int r = 0;
|
||||
@ -525,115 +524,73 @@ static int dir_cleanup(
|
||||
FOREACH_DIRENT_ALL(dent, d, break) {
|
||||
_cleanup_free_ char *sub_path = NULL;
|
||||
nsec_t atime_nsec, mtime_nsec, ctime_nsec, btime_nsec;
|
||||
mode_t mode;
|
||||
uid_t uid;
|
||||
|
||||
if (dot_or_dot_dot(dent->d_name))
|
||||
continue;
|
||||
|
||||
if (use_statx) {
|
||||
/* If statx() is supported, use it. It's preferable over fstatat() since it tells us
|
||||
* explicitly where we are looking at a mount point, for free as side
|
||||
* information. Determing the same information without statx() is hard, see the
|
||||
* complexity of path_is_mount_point(), and also much slower as it requires a numbre
|
||||
* of syscalls instead of just one. Hence, when we have modern statx() we use it
|
||||
* instead of fstat() and do proper mount point checks, while on older kernels's well
|
||||
* do traditional st_dev based detection of mount points.
|
||||
*
|
||||
* Using statx() for detecting mount points also has the benfit that we handle weird
|
||||
* file systems such as overlayfs better where each file is originating from a
|
||||
* different st_dev. */
|
||||
/* If statx() is supported, use it. It's preferable over fstatat() since it tells us
|
||||
* explicitly where we are looking at a mount point, for free as side information. Determing
|
||||
* the same information without statx() is hard, see the complexity of path_is_mount_point(),
|
||||
* and also much slower as it requires a number of syscalls instead of just one. Hence, when
|
||||
* we have modern statx() we use it instead of fstat() and do proper mount point checks,
|
||||
* while on older kernels's well do traditional st_dev based detection of mount points.
|
||||
*
|
||||
* Using statx() for detecting mount points also has the benfit that we handle weird file
|
||||
* systems such as overlayfs better where each file is originating from a different
|
||||
* st_dev. */
|
||||
|
||||
struct statx sx
|
||||
#if HAS_FEATURE_MEMORY_SANITIZER
|
||||
= {}
|
||||
# warning "Explicitly initializing struct statx, to work around msan limitation. Please remove as soon as msan has been updated to not require this."
|
||||
#endif
|
||||
;
|
||||
STRUCT_STATX_DEFINE(sx);
|
||||
|
||||
if (statx(dirfd(d), dent->d_name,
|
||||
AT_SYMLINK_NOFOLLOW|AT_NO_AUTOMOUNT,
|
||||
STATX_TYPE|STATX_MODE|STATX_UID|STATX_ATIME|STATX_MTIME|STATX_CTIME|STATX_BTIME,
|
||||
&sx) < 0) {
|
||||
|
||||
if (errno == ENOENT)
|
||||
continue;
|
||||
if (ERRNO_IS_NOT_SUPPORTED(errno) || errno == EPERM)
|
||||
use_statx = false; /* Not supported or blocked by seccomp or so */
|
||||
else {
|
||||
/* FUSE, NFS mounts, SELinux might return EACCES */
|
||||
r = log_full_errno(errno == EACCES ? LOG_DEBUG : LOG_ERR, errno,
|
||||
"statx(%s/%s) failed: %m", p, dent->d_name);
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
if (FLAGS_SET(sx.stx_attributes_mask, STATX_ATTR_MOUNT_ROOT)) {
|
||||
/* Yay, we have the mount point API, use it */
|
||||
if (FLAGS_SET(sx.stx_attributes, STATX_ATTR_MOUNT_ROOT)) {
|
||||
log_debug("Ignoring \"%s/%s\": different mount points.", p, dent->d_name);
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
/* So we have statx() but the STATX_ATTR_MOUNT_ROOT flag is not
|
||||
* supported, fall back to traditional stx_dev checking. */
|
||||
if (sx.stx_dev_major != rootdev_major ||
|
||||
sx.stx_dev_minor != rootdev_minor) {
|
||||
log_debug("Ignoring \"%s/%s\": different filesystem.", p, dent->d_name);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
mode = sx.stx_mode;
|
||||
uid = sx.stx_uid;
|
||||
atime_nsec = FLAGS_SET(sx.stx_mask, STATX_ATIME) ? load_statx_timestamp_nsec(&sx.stx_atime) : 0;
|
||||
mtime_nsec = FLAGS_SET(sx.stx_mask, STATX_MTIME) ? load_statx_timestamp_nsec(&sx.stx_mtime) : 0;
|
||||
ctime_nsec = FLAGS_SET(sx.stx_mask, STATX_CTIME) ? load_statx_timestamp_nsec(&sx.stx_ctime) : 0;
|
||||
btime_nsec = FLAGS_SET(sx.stx_mask, STATX_BTIME) ? load_statx_timestamp_nsec(&sx.stx_btime) : 0;
|
||||
}
|
||||
r = statx_fallback(
|
||||
dirfd(d), dent->d_name,
|
||||
AT_SYMLINK_NOFOLLOW|AT_NO_AUTOMOUNT,
|
||||
STATX_TYPE|STATX_MODE|STATX_UID|STATX_ATIME|STATX_MTIME|STATX_CTIME|STATX_BTIME,
|
||||
&sx);
|
||||
if (r == -ENOENT)
|
||||
continue;
|
||||
if (r < 0) {
|
||||
/* FUSE, NFS mounts, SELinux might return EACCES */
|
||||
r = log_full_errno(errno == EACCES ? LOG_DEBUG : LOG_ERR, errno,
|
||||
"statx(%s/%s) failed: %m", p, dent->d_name);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!use_statx) {
|
||||
struct stat s;
|
||||
|
||||
if (fstatat(dirfd(d), dent->d_name, &s, AT_SYMLINK_NOFOLLOW) < 0) {
|
||||
if (errno == ENOENT)
|
||||
continue;
|
||||
|
||||
/* FUSE, NFS mounts, SELinux might return EACCES */
|
||||
r = log_full_errno(errno == EACCES ? LOG_DEBUG : LOG_ERR, errno,
|
||||
"stat(%s/%s) failed: %m", p, dent->d_name);
|
||||
if (FLAGS_SET(sx.stx_attributes_mask, STATX_ATTR_MOUNT_ROOT)) {
|
||||
/* Yay, we have the mount point API, use it */
|
||||
if (FLAGS_SET(sx.stx_attributes, STATX_ATTR_MOUNT_ROOT)) {
|
||||
log_debug("Ignoring \"%s/%s\": different mount points.", p, dent->d_name);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Stay on the same filesystem */
|
||||
if (major(s.st_dev) != rootdev_major || minor(s.st_dev) != rootdev_minor) {
|
||||
} else {
|
||||
/* So we might have statx() but the STATX_ATTR_MOUNT_ROOT flag is not supported, fall
|
||||
* back to traditional stx_dev checking. */
|
||||
if (sx.stx_dev_major != rootdev_major ||
|
||||
sx.stx_dev_minor != rootdev_minor) {
|
||||
log_debug("Ignoring \"%s/%s\": different filesystem.", p, dent->d_name);
|
||||
continue;
|
||||
}
|
||||
|
||||
mode = s.st_mode;
|
||||
uid = s.st_uid;
|
||||
atime_nsec = timespec_load_nsec(&s.st_atim);
|
||||
mtime_nsec = timespec_load_nsec(&s.st_mtim);
|
||||
ctime_nsec = timespec_load_nsec(&s.st_ctim);
|
||||
btime_nsec = 0;
|
||||
}
|
||||
/* Try to detect bind mounts of the same filesystem instance; they do not differ in device
|
||||
* major/minors. This type of query is not supported on all kernels or filesystem types
|
||||
* though. */
|
||||
if (S_ISDIR(sx.stx_mode)) {
|
||||
int q;
|
||||
|
||||
/* Try to detect bind mounts of the same filesystem instance; they
|
||||
* do not differ in device major/minors. This type of query is not
|
||||
* supported on all kernels or filesystem types though. */
|
||||
if (S_ISDIR(mode)) {
|
||||
int q;
|
||||
|
||||
q = fd_is_mount_point(dirfd(d), dent->d_name, 0);
|
||||
if (q < 0)
|
||||
log_debug_errno(q, "Failed to determine whether \"%s/%s\" is a mount point, ignoring: %m", p, dent->d_name);
|
||||
else if (q > 0) {
|
||||
log_debug("Ignoring \"%s/%s\": different mount of the same filesystem.", p, dent->d_name);
|
||||
continue;
|
||||
q = fd_is_mount_point(dirfd(d), dent->d_name, 0);
|
||||
if (q < 0)
|
||||
log_debug_errno(q, "Failed to determine whether \"%s/%s\" is a mount point, ignoring: %m", p, dent->d_name);
|
||||
else if (q > 0) {
|
||||
log_debug("Ignoring \"%s/%s\": different mount of the same filesystem.", p, dent->d_name);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
atime_nsec = FLAGS_SET(sx.stx_mask, STATX_ATIME) ? load_statx_timestamp_nsec(&sx.stx_atime) : 0;
|
||||
mtime_nsec = FLAGS_SET(sx.stx_mask, STATX_MTIME) ? load_statx_timestamp_nsec(&sx.stx_mtime) : 0;
|
||||
ctime_nsec = FLAGS_SET(sx.stx_mask, STATX_CTIME) ? load_statx_timestamp_nsec(&sx.stx_ctime) : 0;
|
||||
btime_nsec = FLAGS_SET(sx.stx_mask, STATX_BTIME) ? load_statx_timestamp_nsec(&sx.stx_btime) : 0;
|
||||
|
||||
sub_path = path_join(p, dent->d_name);
|
||||
if (!sub_path) {
|
||||
r = log_oom();
|
||||
@ -651,12 +608,12 @@ static int dir_cleanup(
|
||||
continue;
|
||||
}
|
||||
|
||||
if (S_ISDIR(mode)) {
|
||||
if (S_ISDIR(sx.stx_mode)) {
|
||||
_cleanup_closedir_ DIR *sub_dir = NULL;
|
||||
|
||||
if (mountpoint &&
|
||||
streq(dent->d_name, "lost+found") &&
|
||||
uid == 0) {
|
||||
sx.stx_uid == 0) {
|
||||
log_debug("Ignoring directory \"%s\".", sub_path);
|
||||
continue;
|
||||
}
|
||||
@ -732,14 +689,14 @@ static int dir_cleanup(
|
||||
} else {
|
||||
/* Skip files for which the sticky bit is set. These are semantics we define, and are
|
||||
* unknown elsewhere. See XDG_RUNTIME_DIR specification for details. */
|
||||
if (mode & S_ISVTX) {
|
||||
if (sx.stx_mode & S_ISVTX) {
|
||||
log_debug("Skipping \"%s\": sticky bit set.", sub_path);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (mountpoint &&
|
||||
S_ISREG(mode) &&
|
||||
uid == 0 &&
|
||||
S_ISREG(sx.stx_mode) &&
|
||||
sx.stx_uid == 0 &&
|
||||
STR_IN_SET(dent->d_name,
|
||||
".journal",
|
||||
"aquota.user",
|
||||
@ -749,13 +706,13 @@ static int dir_cleanup(
|
||||
}
|
||||
|
||||
/* Ignore sockets that are listed in /proc/net/unix */
|
||||
if (S_ISSOCK(mode) && unix_socket_alive(sub_path)) {
|
||||
if (S_ISSOCK(sx.stx_mode) && unix_socket_alive(sub_path)) {
|
||||
log_debug("Skipping \"%s\": live socket.", sub_path);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Ignore device nodes */
|
||||
if (S_ISCHR(mode) || S_ISBLK(mode)) {
|
||||
if (S_ISCHR(sx.stx_mode) || S_ISBLK(sx.stx_mode)) {
|
||||
log_debug("Skipping \"%s\": a device.", sub_path);
|
||||
continue;
|
||||
}
|
||||
@ -2291,18 +2248,9 @@ static int remove_item(Item *i) {
|
||||
static int clean_item_instance(Item *i, const char* instance) {
|
||||
char timestamp[FORMAT_TIMESTAMP_MAX];
|
||||
_cleanup_closedir_ DIR *d = NULL;
|
||||
uint32_t dev_major, dev_minor;
|
||||
nsec_t atime_nsec, mtime_nsec;
|
||||
int mountpoint = -1;
|
||||
STRUCT_STATX_DEFINE(sx);
|
||||
int mountpoint, r;
|
||||
usec_t cutoff, n;
|
||||
uint64_t ino;
|
||||
|
||||
struct statx sx
|
||||
#if HAS_FEATURE_MEMORY_SANITIZER
|
||||
= {}
|
||||
# warning "Explicitly initializing struct statx, to work around msan limitation. Please remove as soon as msan has been updated to not require this."
|
||||
#endif
|
||||
;
|
||||
|
||||
assert(i);
|
||||
|
||||
@ -2325,53 +2273,34 @@ static int clean_item_instance(Item *i, const char* instance) {
|
||||
return log_error_errno(errno, "Failed to open directory %s: %m", instance);
|
||||
}
|
||||
|
||||
if (statx(dirfd(d), "", AT_EMPTY_PATH, STATX_MODE|STATX_INO|STATX_ATIME|STATX_MTIME, &sx) < 0) {
|
||||
struct stat s;
|
||||
r = statx_fallback(dirfd(d), "", AT_EMPTY_PATH, STATX_MODE|STATX_INO|STATX_ATIME|STATX_MTIME, &sx);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "statx(%s) failed: %m", instance);
|
||||
|
||||
if (!ERRNO_IS_NOT_SUPPORTED(errno) && !ERRNO_IS_PRIVILEGE(errno))
|
||||
return log_error_errno(errno, "statx(%s) failed: %m", i->path);
|
||||
|
||||
if (fstat(dirfd(d), &s) < 0)
|
||||
return log_error_errno(errno, "stat(%s) failed: %m", i->path);
|
||||
|
||||
dev_major = major(s.st_dev);
|
||||
dev_minor = minor(s.st_dev);
|
||||
ino = s.st_ino;
|
||||
atime_nsec = timespec_load_nsec(&s.st_atim);
|
||||
mtime_nsec = timespec_load_nsec(&s.st_mtim);
|
||||
} else {
|
||||
|
||||
if (FLAGS_SET(sx.stx_attributes_mask, STATX_ATTR_MOUNT_ROOT))
|
||||
mountpoint = FLAGS_SET(sx.stx_attributes, STATX_ATTR_MOUNT_ROOT);
|
||||
|
||||
dev_major = sx.stx_dev_major;
|
||||
dev_minor = sx.stx_dev_minor;
|
||||
ino = sx.stx_ino;
|
||||
atime_nsec = load_statx_timestamp_nsec(&sx.stx_atime);
|
||||
mtime_nsec = load_statx_timestamp_nsec(&sx.stx_mtime);
|
||||
}
|
||||
|
||||
if (mountpoint < 0) {
|
||||
if (FLAGS_SET(sx.stx_attributes_mask, STATX_ATTR_MOUNT_ROOT))
|
||||
mountpoint = FLAGS_SET(sx.stx_attributes, STATX_ATTR_MOUNT_ROOT);
|
||||
else {
|
||||
struct stat ps;
|
||||
|
||||
if (fstatat(dirfd(d), "..", &ps, AT_SYMLINK_NOFOLLOW) != 0)
|
||||
return log_error_errno(errno, "stat(%s/..) failed: %m", i->path);
|
||||
|
||||
mountpoint =
|
||||
dev_major != major(ps.st_dev) ||
|
||||
dev_minor != minor(ps.st_dev) ||
|
||||
ino != ps.st_ino;
|
||||
sx.stx_dev_major != major(ps.st_dev) ||
|
||||
sx.stx_dev_minor != minor(ps.st_dev) ||
|
||||
sx.stx_ino != ps.st_ino;
|
||||
}
|
||||
|
||||
|
||||
log_debug("Cleanup threshold for %s \"%s\" is %s",
|
||||
mountpoint ? "mount point" : "directory",
|
||||
instance,
|
||||
format_timestamp_style(timestamp, sizeof(timestamp), cutoff, TIMESTAMP_US));
|
||||
|
||||
return dir_cleanup(i, instance, d,
|
||||
atime_nsec, mtime_nsec, cutoff * NSEC_PER_USEC,
|
||||
dev_major, dev_minor, mountpoint,
|
||||
load_statx_timestamp_nsec(&sx.stx_atime),
|
||||
load_statx_timestamp_nsec(&sx.stx_mtime),
|
||||
cutoff * NSEC_PER_USEC,
|
||||
sx.stx_dev_major, sx.stx_dev_minor, mountpoint,
|
||||
MAX_DEPTH, i->keep_first_level);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user