Compare commits

..

No commits in common. "6743a1caf4037f03dc51a1277855018e4ab61957" and "ad161cd6bb02053b7b6fd389e85eefae8533a627" have entirely different histories.

9 changed files with 166 additions and 191 deletions

View File

@ -63,7 +63,7 @@
<varlistentry> <varlistentry>
<term><varname>FallbackDNS=</varname></term> <term><varname>FallbackDNS=</varname></term>
<listitem><para>A space-separated list of IPv4 and IPv6 addresses to use as the fallback DNS servers. Please see <listitem><para>A space-separated list of IPv4 and IPv6 addresses to use as the fallback DNS servers. Please see
<varname>DNS=</varname> for acceptable format of addresses. Any per-link DNS servers obtained from <varname>DNS=</varname> for acceptable format of adddresses. Any per-link DNS servers obtained from
<citerefentry><refentrytitle>systemd-networkd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry> <citerefentry><refentrytitle>systemd-networkd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
take precedence over this setting, as do any servers set via <varname>DNS=</varname> above or take precedence over this setting, as do any servers set via <varname>DNS=</varname> above or
<filename>/etc/resolv.conf</filename>. This setting is hence only used if no other DNS server information is <filename>/etc/resolv.conf</filename>. This setting is hence only used if no other DNS server information is

View File

@ -49,16 +49,6 @@ struct statx STATX_DEFINITION;
* defines an older definition */ * defines an older definition */
struct new_statx STATX_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) */ /* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */
#ifndef AT_STATX_DONT_SYNC #ifndef AT_STATX_DONT_SYNC
#define AT_STATX_DONT_SYNC 0x4000 #define AT_STATX_DONT_SYNC 0x4000
@ -74,21 +64,11 @@ struct new_statx STATX_DEFINITION;
#define STATX_MODE 0x00000002U #define STATX_MODE 0x00000002U
#endif #endif
/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */
#ifndef STATX_NLINK
#define STATX_NLINK 0x00000004U
#endif
/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */ /* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */
#ifndef STATX_UID #ifndef STATX_UID
#define STATX_UID 0x00000008U #define STATX_UID 0x00000008U
#endif #endif
/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */
#ifndef STATX_GID
#define STATX_GID 0x00000010U
#endif
/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */ /* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */
#ifndef STATX_ATIME #ifndef STATX_ATIME
#define STATX_ATIME 0x00000020U #define STATX_ATIME 0x00000020U
@ -109,16 +89,6 @@ struct new_statx STATX_DEFINITION;
#define STATX_INO 0x00000100U #define STATX_INO 0x00000100U
#endif #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) */ /* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */
#ifndef STATX_BTIME #ifndef STATX_BTIME
#define STATX_BTIME 0x00000800U #define STATX_BTIME 0x00000800U

View File

@ -13,7 +13,6 @@
#include "mountpoint-util.h" #include "mountpoint-util.h"
#include "parse-util.h" #include "parse-util.h"
#include "path-util.h" #include "path-util.h"
#include "stat-util.h"
#include "stdio-util.h" #include "stdio-util.h"
#include "strv.h" #include "strv.h"
@ -136,8 +135,13 @@ int fd_is_mount_point(int fd, const char *filename, int flags) {
_cleanup_free_ struct file_handle *h = NULL, *h_parent = NULL; _cleanup_free_ struct file_handle *h = NULL, *h_parent = NULL;
int mount_id = -1, mount_id_parent = -1; int mount_id = -1, mount_id_parent = -1;
bool nosupp = false, check_st_dev = true; bool nosupp = false, check_st_dev = true;
STRUCT_STATX_DEFINE(sx);
struct stat a, b; 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; int r;
assert(fd >= 0); assert(fd >= 0);
@ -294,7 +298,15 @@ int path_is_mount_point(const char *t, const char *root, int flags) {
} }
int path_get_mnt_id(const char *path, int *ret) { int path_get_mnt_id(const char *path, int *ret) {
STRUCT_NEW_STATX_DEFINE(buf); 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
;
int r; int r;
if (statx(AT_FDCWD, path, AT_SYMLINK_NOFOLLOW|AT_NO_AUTOMOUNT, STATX_MNT_ID, &buf.sx) < 0) { if (statx(AT_FDCWD, path, AT_SYMLINK_NOFOLLOW|AT_NO_AUTOMOUNT, STATX_MNT_ID, &buf.sx) < 0) {

View File

@ -153,9 +153,6 @@ void mac_selinux_maybe_reload(void) {
#if HAVE_SELINUX #if HAVE_SELINUX
int r; int r;
if (!initialized)
return;
r = selinux_status_updated(); r = selinux_status_updated();
if (r < 0) if (r < 0)
log_debug_errno(errno, "Failed to update SELinux from status page: %m"); log_debug_errno(errno, "Failed to update SELinux from status page: %m");

View File

@ -15,7 +15,6 @@
#include "macro.h" #include "macro.h"
#include "missing_fs.h" #include "missing_fs.h"
#include "missing_magic.h" #include "missing_magic.h"
#include "missing_syscall.h"
#include "parse-util.h" #include "parse-util.h"
#include "stat-util.h" #include "stat-util.h"
#include "string-util.h" #include "string-util.h"
@ -414,59 +413,3 @@ bool stat_inode_unmodified(const struct stat *a, const struct stat *b) {
a->st_ino == b->st_ino && 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 */ (!(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;
}

View File

@ -10,7 +10,6 @@
#include <sys/vfs.h> #include <sys/vfs.h>
#include "macro.h" #include "macro.h"
#include "missing_stat.h"
int is_symlink(const char *path); int is_symlink(const char *path);
int is_dir(const char *path, bool follow); int is_dir(const char *path, bool follow);
@ -92,24 +91,3 @@ int device_path_parse_major_minor(const char *path, mode_t *ret_mode, dev_t *ret
int proc_mounted(void); int proc_mounted(void);
bool stat_inode_unmodified(const struct stat *a, const struct stat *b); 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

View File

@ -12,7 +12,6 @@
#include "macro.h" #include "macro.h"
#include "missing_syscall.h" #include "missing_syscall.h"
#include "sparse-endian.h" #include "sparse-endian.h"
#include "stat-util.h"
#include "stdio-util.h" #include "stdio-util.h"
#include "string-util.h" #include "string-util.h"
#include "time-util.h" #include "time-util.h"
@ -155,7 +154,12 @@ static int parse_crtime(le64_t le, usec_t *usec) {
} }
int fd_getcrtime_at(int dirfd, const char *name, usec_t *ret, int flags) { int fd_getcrtime_at(int dirfd, const char *name, usec_t *ret, int flags) {
STRUCT_STATX_DEFINE(sx); 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
;
usec_t a, b; usec_t a, b;
le64_t le; le64_t le;
size_t n; size_t n;

View File

@ -2087,7 +2087,7 @@ static int initialize_runtime(
return log_emergency_errno(r, "Failed to determine $XDG_RUNTIME_DIR path: %m"); return log_emergency_errno(r, "Failed to determine $XDG_RUNTIME_DIR path: %m");
} }
(void) mkdir_p_label(p, 0755); (void) mkdir_p(p, 0755);
(void) make_inaccessible_nodes(p, UID_INVALID, GID_INVALID); (void) make_inaccessible_nodes(p, UID_INVALID, GID_INVALID);
} }

View File

@ -517,6 +517,7 @@ static int dir_cleanup(
int maxdepth, int maxdepth,
bool keep_this_level) { bool keep_this_level) {
static bool use_statx = true;
bool deleted = false; bool deleted = false;
struct dirent *dent; struct dirent *dent;
int r = 0; int r = 0;
@ -524,72 +525,114 @@ static int dir_cleanup(
FOREACH_DIRENT_ALL(dent, d, break) { FOREACH_DIRENT_ALL(dent, d, break) {
_cleanup_free_ char *sub_path = NULL; _cleanup_free_ char *sub_path = NULL;
nsec_t atime_nsec, mtime_nsec, ctime_nsec, btime_nsec; nsec_t atime_nsec, mtime_nsec, ctime_nsec, btime_nsec;
mode_t mode;
uid_t uid;
if (dot_or_dot_dot(dent->d_name)) if (dot_or_dot_dot(dent->d_name))
continue; continue;
/* If statx() is supported, use it. It's preferable over fstatat() since it tells us if (use_statx) {
* explicitly where we are looking at a mount point, for free as side information. Determing /* If statx() is supported, use it. It's preferable over fstatat() since it tells us
* the same information without statx() is hard, see the complexity of path_is_mount_point(), * explicitly where we are looking at a mount point, for free as side
* and also much slower as it requires a number of syscalls instead of just one. Hence, when * information. Determing the same information without statx() is hard, see the
* we have modern statx() we use it instead of fstat() and do proper mount point checks, * complexity of path_is_mount_point(), and also much slower as it requires a numbre
* while on older kernels's well do traditional st_dev based detection of mount points. * 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
* Using statx() for detecting mount points also has the benfit that we handle weird file * do traditional st_dev based detection of mount points.
* systems such as overlayfs better where each file is originating from a different *
* st_dev. */ * 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_DEFINE(sx); 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
;
r = statx_fallback( if (statx(dirfd(d), dent->d_name,
dirfd(d), dent->d_name, AT_SYMLINK_NOFOLLOW|AT_NO_AUTOMOUNT,
AT_SYMLINK_NOFOLLOW|AT_NO_AUTOMOUNT, STATX_TYPE|STATX_MODE|STATX_UID|STATX_ATIME|STATX_MTIME|STATX_CTIME|STATX_BTIME,
STATX_TYPE|STATX_MODE|STATX_UID|STATX_ATIME|STATX_MTIME|STATX_CTIME|STATX_BTIME, &sx) < 0) {
&sx);
if (r == -ENOENT) if (errno == ENOENT)
continue; continue;
if (r < 0) { if (ERRNO_IS_NOT_SUPPORTED(errno) || errno == EPERM)
/* FUSE, NFS mounts, SELinux might return EACCES */ use_statx = false; /* Not supported or blocked by seccomp or so */
r = log_full_errno(errno == EACCES ? LOG_DEBUG : LOG_ERR, errno, else {
"statx(%s/%s) failed: %m", p, dent->d_name); /* FUSE, NFS mounts, SELinux might return EACCES */
continue; 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;
}
} }
if (FLAGS_SET(sx.stx_attributes_mask, STATX_ATTR_MOUNT_ROOT)) { if (!use_statx) {
/* Yay, we have the mount point API, use it */ struct stat s;
if (FLAGS_SET(sx.stx_attributes, STATX_ATTR_MOUNT_ROOT)) {
log_debug("Ignoring \"%s/%s\": different mount points.", p, dent->d_name); 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);
continue; continue;
} }
} else {
/* So we might have statx() but the STATX_ATTR_MOUNT_ROOT flag is not supported, fall /* Stay on the same filesystem */
* back to traditional stx_dev checking. */ if (major(s.st_dev) != rootdev_major || minor(s.st_dev) != rootdev_minor) {
if (sx.stx_dev_major != rootdev_major ||
sx.stx_dev_minor != rootdev_minor) {
log_debug("Ignoring \"%s/%s\": different filesystem.", p, dent->d_name); log_debug("Ignoring \"%s/%s\": different filesystem.", p, dent->d_name);
continue; continue;
} }
/* Try to detect bind mounts of the same filesystem instance; they do not differ in device mode = s.st_mode;
* major/minors. This type of query is not supported on all kernels or filesystem types uid = s.st_uid;
* though. */ atime_nsec = timespec_load_nsec(&s.st_atim);
if (S_ISDIR(sx.stx_mode)) { mtime_nsec = timespec_load_nsec(&s.st_mtim);
int q; ctime_nsec = timespec_load_nsec(&s.st_ctim);
btime_nsec = 0;
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; /* Try to detect bind mounts of the same filesystem instance; they
mtime_nsec = FLAGS_SET(sx.stx_mask, STATX_MTIME) ? load_statx_timestamp_nsec(&sx.stx_mtime) : 0; * do not differ in device major/minors. This type of query is not
ctime_nsec = FLAGS_SET(sx.stx_mask, STATX_CTIME) ? load_statx_timestamp_nsec(&sx.stx_ctime) : 0; * supported on all kernels or filesystem types though. */
btime_nsec = FLAGS_SET(sx.stx_mask, STATX_BTIME) ? load_statx_timestamp_nsec(&sx.stx_btime) : 0; 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;
}
}
sub_path = path_join(p, dent->d_name); sub_path = path_join(p, dent->d_name);
if (!sub_path) { if (!sub_path) {
@ -608,12 +651,12 @@ static int dir_cleanup(
continue; continue;
} }
if (S_ISDIR(sx.stx_mode)) { if (S_ISDIR(mode)) {
_cleanup_closedir_ DIR *sub_dir = NULL; _cleanup_closedir_ DIR *sub_dir = NULL;
if (mountpoint && if (mountpoint &&
streq(dent->d_name, "lost+found") && streq(dent->d_name, "lost+found") &&
sx.stx_uid == 0) { uid == 0) {
log_debug("Ignoring directory \"%s\".", sub_path); log_debug("Ignoring directory \"%s\".", sub_path);
continue; continue;
} }
@ -689,14 +732,14 @@ static int dir_cleanup(
} else { } else {
/* Skip files for which the sticky bit is set. These are semantics we define, and are /* 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. */ * unknown elsewhere. See XDG_RUNTIME_DIR specification for details. */
if (sx.stx_mode & S_ISVTX) { if (mode & S_ISVTX) {
log_debug("Skipping \"%s\": sticky bit set.", sub_path); log_debug("Skipping \"%s\": sticky bit set.", sub_path);
continue; continue;
} }
if (mountpoint && if (mountpoint &&
S_ISREG(sx.stx_mode) && S_ISREG(mode) &&
sx.stx_uid == 0 && uid == 0 &&
STR_IN_SET(dent->d_name, STR_IN_SET(dent->d_name,
".journal", ".journal",
"aquota.user", "aquota.user",
@ -706,13 +749,13 @@ static int dir_cleanup(
} }
/* Ignore sockets that are listed in /proc/net/unix */ /* Ignore sockets that are listed in /proc/net/unix */
if (S_ISSOCK(sx.stx_mode) && unix_socket_alive(sub_path)) { if (S_ISSOCK(mode) && unix_socket_alive(sub_path)) {
log_debug("Skipping \"%s\": live socket.", sub_path); log_debug("Skipping \"%s\": live socket.", sub_path);
continue; continue;
} }
/* Ignore device nodes */ /* Ignore device nodes */
if (S_ISCHR(sx.stx_mode) || S_ISBLK(sx.stx_mode)) { if (S_ISCHR(mode) || S_ISBLK(mode)) {
log_debug("Skipping \"%s\": a device.", sub_path); log_debug("Skipping \"%s\": a device.", sub_path);
continue; continue;
} }
@ -2248,9 +2291,18 @@ static int remove_item(Item *i) {
static int clean_item_instance(Item *i, const char* instance) { static int clean_item_instance(Item *i, const char* instance) {
char timestamp[FORMAT_TIMESTAMP_MAX]; char timestamp[FORMAT_TIMESTAMP_MAX];
_cleanup_closedir_ DIR *d = NULL; _cleanup_closedir_ DIR *d = NULL;
STRUCT_STATX_DEFINE(sx); uint32_t dev_major, dev_minor;
int mountpoint, r; nsec_t atime_nsec, mtime_nsec;
int mountpoint = -1;
usec_t cutoff, n; 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); assert(i);
@ -2273,34 +2325,53 @@ static int clean_item_instance(Item *i, const char* instance) {
return log_error_errno(errno, "Failed to open directory %s: %m", instance); return log_error_errno(errno, "Failed to open directory %s: %m", instance);
} }
r = statx_fallback(dirfd(d), "", AT_EMPTY_PATH, STATX_MODE|STATX_INO|STATX_ATIME|STATX_MTIME, &sx); if (statx(dirfd(d), "", AT_EMPTY_PATH, STATX_MODE|STATX_INO|STATX_ATIME|STATX_MTIME, &sx) < 0) {
if (r < 0) struct stat s;
return log_error_errno(r, "statx(%s) failed: %m", instance);
if (FLAGS_SET(sx.stx_attributes_mask, STATX_ATTR_MOUNT_ROOT)) if (!ERRNO_IS_NOT_SUPPORTED(errno) && !ERRNO_IS_PRIVILEGE(errno))
mountpoint = FLAGS_SET(sx.stx_attributes, STATX_ATTR_MOUNT_ROOT); return log_error_errno(errno, "statx(%s) failed: %m", i->path);
else {
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) {
struct stat ps; struct stat ps;
if (fstatat(dirfd(d), "..", &ps, AT_SYMLINK_NOFOLLOW) != 0) if (fstatat(dirfd(d), "..", &ps, AT_SYMLINK_NOFOLLOW) != 0)
return log_error_errno(errno, "stat(%s/..) failed: %m", i->path); return log_error_errno(errno, "stat(%s/..) failed: %m", i->path);
mountpoint = mountpoint =
sx.stx_dev_major != major(ps.st_dev) || dev_major != major(ps.st_dev) ||
sx.stx_dev_minor != minor(ps.st_dev) || dev_minor != minor(ps.st_dev) ||
sx.stx_ino != ps.st_ino; ino != ps.st_ino;
} }
log_debug("Cleanup threshold for %s \"%s\" is %s", log_debug("Cleanup threshold for %s \"%s\" is %s",
mountpoint ? "mount point" : "directory", mountpoint ? "mount point" : "directory",
instance, instance,
format_timestamp_style(timestamp, sizeof(timestamp), cutoff, TIMESTAMP_US)); format_timestamp_style(timestamp, sizeof(timestamp), cutoff, TIMESTAMP_US));
return dir_cleanup(i, instance, d, return dir_cleanup(i, instance, d,
load_statx_timestamp_nsec(&sx.stx_atime), atime_nsec, mtime_nsec, cutoff * NSEC_PER_USEC,
load_statx_timestamp_nsec(&sx.stx_mtime), dev_major, dev_minor, mountpoint,
cutoff * NSEC_PER_USEC,
sx.stx_dev_major, sx.stx_dev_minor, mountpoint,
MAX_DEPTH, i->keep_first_level); MAX_DEPTH, i->keep_first_level);
} }