Compare commits
No commits in common. "f77d6ec9539fd87eb3ecad3a742ac684cc6dc5d2" and "0419dae71541643c407cb4146fe942ff5d91a526" have entirely different histories.
f77d6ec953
...
0419dae715
|
@ -54,19 +54,24 @@
|
|||
(i.e. <constant>SD_LISTEN_FDS_START</constant>), the remaining
|
||||
descriptors follow at 4, 5, 6, …, if any.</para>
|
||||
|
||||
<para>If a daemon receives more than one file descriptor, they will be passed in the same order as
|
||||
configured in the systemd socket unit file (see
|
||||
<citerefentry><refentrytitle>systemd.socket</refentrytitle><manvolnum>5</manvolnum></citerefentry> for
|
||||
details) — if there's only one such file (see below). Nonetheless, it is recommended to verify the
|
||||
correct socket types before using them. To simplify this checking, the functions
|
||||
<para>If a daemon receives more than one file descriptor, they
|
||||
will be passed in the same order as configured in the systemd
|
||||
socket unit file (see
|
||||
<citerefentry><refentrytitle>systemd.socket</refentrytitle><manvolnum>5</manvolnum></citerefentry>
|
||||
for details). Nonetheless, it is recommended to verify the correct
|
||||
socket types before using them. To simplify this checking, the
|
||||
functions
|
||||
<citerefentry><refentrytitle>sd_is_fifo</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>sd_is_socket</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>sd_is_socket_inet</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>sd_is_socket_unix</refentrytitle><manvolnum>3</manvolnum></citerefentry> are
|
||||
provided. In order to maximize flexibility, it is recommended to make these checks as loose as possible
|
||||
without allowing incorrect setups. i.e. often, the actual port number a socket is bound to matters little
|
||||
for the service to work, hence it should not be verified. On the other hand, whether a socket is a
|
||||
datagram or stream socket matters a lot for the most common program logics and should be checked.</para>
|
||||
<citerefentry><refentrytitle>sd_is_socket_unix</refentrytitle><manvolnum>3</manvolnum></citerefentry>
|
||||
are provided. In order to maximize flexibility, it is recommended
|
||||
to make these checks as loose as possible without allowing
|
||||
incorrect setups. i.e. often, the actual port number a socket is
|
||||
bound to matters little for the service to work, hence it should
|
||||
not be verified. On the other hand, whether a socket is a datagram
|
||||
or stream socket matters a lot for the most common program logics
|
||||
and should be checked.</para>
|
||||
|
||||
<para>This function call will set the FD_CLOEXEC flag for all
|
||||
passed file descriptors to avoid further inheritance to children
|
||||
|
|
|
@ -1028,24 +1028,20 @@
|
|||
|
||||
<varlistentry>
|
||||
<term><varname>FileDescriptorStoreMax=</varname></term>
|
||||
<listitem><para>Configure how many file descriptors may be stored in the service manager for the
|
||||
service using
|
||||
<listitem><para>Configure how many file descriptors may be stored in the service manager for the service using
|
||||
<citerefentry><refentrytitle>sd_pid_notify_with_fds</refentrytitle><manvolnum>3</manvolnum></citerefentry>'s
|
||||
<literal>FDSTORE=1</literal> messages. This is useful for implementing services that can restart
|
||||
after an explicit request or a crash without losing state. Any open sockets and other file
|
||||
descriptors which should not be closed during the restart may be stored this way. Application state
|
||||
can either be serialized to a file in <filename>/run</filename>, or better, stored in a
|
||||
<citerefentry><refentrytitle>memfd_create</refentrytitle><manvolnum>2</manvolnum></citerefentry>
|
||||
memory file descriptor. Defaults to 0, i.e. no file descriptors may be stored in the service
|
||||
manager. All file descriptors passed to the service manager from a specific service are passed back
|
||||
to the service's main process on the next service restart (see
|
||||
<citerefentry><refentrytitle>sd_listen_fds</refentrytitle><manvolnum>3</manvolnum></citerefentry> for
|
||||
details about the precise protocol used and the order in which the file descriptors are passed). Any
|
||||
file descriptors passed to the service manager are automatically closed when
|
||||
<constant>POLLHUP</constant> or <constant>POLLERR</constant> is seen on them, or when the service is
|
||||
fully stopped and no job is queued or being executed for it. If this option is used,
|
||||
<varname>NotifyAccess=</varname> (see above) should be set to open access to the notification socket
|
||||
provided by systemd. If <varname>NotifyAccess=</varname> is not set, it will be implicitly set to
|
||||
<literal>FDSTORE=1</literal> messages. This is useful for implementing services that can restart after an
|
||||
explicit request or a crash without losing state. Any open sockets and other file descriptors which should not
|
||||
be closed during the restart may be stored this way. Application state can either be serialized to a file in
|
||||
<filename>/run</filename>, or better, stored in a
|
||||
<citerefentry><refentrytitle>memfd_create</refentrytitle><manvolnum>2</manvolnum></citerefentry> memory file
|
||||
descriptor. Defaults to 0, i.e. no file descriptors may be stored in the service manager. All file descriptors
|
||||
passed to the service manager from a specific service are passed back to the service's main process on the next
|
||||
service restart. Any file descriptors passed to the service manager are automatically closed when
|
||||
<constant>POLLHUP</constant> or <constant>POLLERR</constant> is seen on them, or when the service is fully
|
||||
stopped and no job is queued or being executed for it. If this option is used, <varname>NotifyAccess=</varname>
|
||||
(see above) should be set to open access to the notification socket provided by systemd. If
|
||||
<varname>NotifyAccess=</varname> is not set, it will be implicitly set to
|
||||
<option>main</option>.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
|
|
|
@ -81,14 +81,16 @@
|
|||
services, as well as parallelized starting of services. See the
|
||||
blog stories linked at the end for an introduction.</para>
|
||||
|
||||
<para>Note that the daemon software configured for socket activation with socket units needs to be able
|
||||
to accept sockets from systemd, either via systemd's native socket passing interface (see
|
||||
<citerefentry><refentrytitle>sd_listen_fds</refentrytitle><manvolnum>3</manvolnum></citerefentry> for
|
||||
details about the precise protocol used and the order in which the file descriptors are passed) or via
|
||||
traditional <citerefentry
|
||||
project='freebsd'><refentrytitle>inetd</refentrytitle><manvolnum>8</manvolnum></citerefentry>-style
|
||||
socket passing (i.e. sockets passed in via standard input and output, using
|
||||
<varname>StandardInput=socket</varname> in the service file).</para>
|
||||
<para>Note that the daemon software configured for socket
|
||||
activation with socket units needs to be able to accept sockets
|
||||
from systemd, either via systemd's native socket passing interface
|
||||
(see
|
||||
<citerefentry><refentrytitle>sd_listen_fds</refentrytitle><manvolnum>3</manvolnum></citerefentry>
|
||||
for details) or via the traditional
|
||||
<citerefentry project='freebsd'><refentrytitle>inetd</refentrytitle><manvolnum>8</manvolnum></citerefentry>-style
|
||||
socket passing (i.e. sockets passed in via standard input and
|
||||
output, using <varname>StandardInput=socket</varname> in the
|
||||
service file).</para>
|
||||
|
||||
<para>All network sockets allocated through <filename>.socket</filename> units are allocated in the host's network
|
||||
namespace (see <citerefentry
|
||||
|
|
|
@ -49,51 +49,16 @@ struct statx STATX_DEFINITION;
|
|||
* defines an older definition */
|
||||
struct new_statx STATX_DEFINITION;
|
||||
|
||||
/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */
|
||||
#ifndef AT_STATX_DONT_SYNC
|
||||
#define AT_STATX_DONT_SYNC 0x4000
|
||||
#endif
|
||||
|
||||
/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */
|
||||
#ifndef STATX_TYPE
|
||||
#define STATX_TYPE 0x00000001U
|
||||
#endif
|
||||
|
||||
/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */
|
||||
#ifndef STATX_MODE
|
||||
#define STATX_MODE 0x00000002U
|
||||
#endif
|
||||
|
||||
/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */
|
||||
#ifndef STATX_UID
|
||||
#define STATX_UID 0x00000008U
|
||||
#endif
|
||||
|
||||
/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */
|
||||
#ifndef STATX_ATIME
|
||||
#define STATX_ATIME 0x00000020U
|
||||
#endif
|
||||
|
||||
/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */
|
||||
#ifndef STATX_MTIME
|
||||
#define STATX_MTIME 0x00000040U
|
||||
#endif
|
||||
|
||||
/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */
|
||||
#ifndef STATX_CTIME
|
||||
#define STATX_CTIME 0x00000080U
|
||||
#endif
|
||||
|
||||
/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */
|
||||
#ifndef STATX_INO
|
||||
#define STATX_INO 0x00000100U
|
||||
#endif
|
||||
|
||||
/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */
|
||||
#ifndef STATX_BTIME
|
||||
#define STATX_BTIME 0x00000800U
|
||||
#endif
|
||||
|
||||
/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */
|
||||
#ifndef AT_STATX_DONT_SYNC
|
||||
#define AT_STATX_DONT_SYNC 0x4000
|
||||
#endif
|
||||
|
||||
/* fa2fcf4f1df1559a0a4ee0f46915b496cc2ebf60 (5.8) */
|
||||
#ifndef STATX_MNT_ID
|
||||
#define STATX_MNT_ID 0x00001000U
|
||||
|
|
|
@ -244,28 +244,12 @@ struct timespec *timespec_store(struct timespec *ts, usec_t u) {
|
|||
if (u == USEC_INFINITY ||
|
||||
u / USEC_PER_SEC >= TIME_T_MAX) {
|
||||
ts->tv_sec = (time_t) -1;
|
||||
ts->tv_nsec = -1L;
|
||||
ts->tv_nsec = (long) -1;
|
||||
return ts;
|
||||
}
|
||||
|
||||
ts->tv_sec = (time_t) (u / USEC_PER_SEC);
|
||||
ts->tv_nsec = (long) ((u % USEC_PER_SEC) * NSEC_PER_USEC);
|
||||
|
||||
return ts;
|
||||
}
|
||||
|
||||
struct timespec *timespec_store_nsec(struct timespec *ts, nsec_t n) {
|
||||
assert(ts);
|
||||
|
||||
if (n == NSEC_INFINITY ||
|
||||
n / NSEC_PER_SEC >= TIME_T_MAX) {
|
||||
ts->tv_sec = (time_t) -1;
|
||||
ts->tv_nsec = -1L;
|
||||
return ts;
|
||||
}
|
||||
|
||||
ts->tv_sec = (time_t) (n / NSEC_PER_SEC);
|
||||
ts->tv_nsec = (long) (n % NSEC_PER_SEC);
|
||||
ts->tv_nsec = (long int) ((u % USEC_PER_SEC) * NSEC_PER_USEC);
|
||||
|
||||
return ts;
|
||||
}
|
||||
|
|
|
@ -112,7 +112,6 @@ usec_t triple_timestamp_by_clock(triple_timestamp *ts, clockid_t clock);
|
|||
usec_t timespec_load(const struct timespec *ts) _pure_;
|
||||
nsec_t timespec_load_nsec(const struct timespec *ts) _pure_;
|
||||
struct timespec *timespec_store(struct timespec *ts, usec_t u);
|
||||
struct timespec *timespec_store_nsec(struct timespec *ts, nsec_t n);
|
||||
|
||||
usec_t timeval_load(const struct timeval *tv) _pure_;
|
||||
struct timeval *timeval_store(struct timeval *tv, usec_t u);
|
||||
|
|
|
@ -38,8 +38,6 @@
|
|||
#include "log.h"
|
||||
#include "macro.h"
|
||||
#include "main-func.h"
|
||||
#include "missing_stat.h"
|
||||
#include "missing_syscall.h"
|
||||
#include "mkdir.h"
|
||||
#include "mount-util.h"
|
||||
#include "mountpoint-util.h"
|
||||
|
@ -492,137 +490,49 @@ static DIR* opendir_nomod(const char *path) {
|
|||
return xopendirat_nomod(AT_FDCWD, path);
|
||||
}
|
||||
|
||||
static inline nsec_t load_statx_timestamp_nsec(const struct statx_timestamp *ts) {
|
||||
assert(ts);
|
||||
|
||||
if (ts->tv_sec < 0)
|
||||
return NSEC_INFINITY;
|
||||
|
||||
if ((nsec_t) ts->tv_sec >= (UINT64_MAX - ts->tv_nsec) / NSEC_PER_SEC)
|
||||
return NSEC_INFINITY;
|
||||
|
||||
return ts->tv_sec * NSEC_PER_SEC + ts->tv_nsec;
|
||||
}
|
||||
|
||||
static int dir_cleanup(
|
||||
Item *i,
|
||||
const char *p,
|
||||
DIR *d,
|
||||
nsec_t self_atime_nsec,
|
||||
nsec_t self_mtime_nsec,
|
||||
nsec_t cutoff_nsec,
|
||||
dev_t rootdev_major,
|
||||
dev_t rootdev_minor,
|
||||
const struct stat *ds,
|
||||
usec_t cutoff,
|
||||
dev_t rootdev,
|
||||
bool mountpoint,
|
||||
int maxdepth,
|
||||
bool keep_this_level) {
|
||||
|
||||
static bool use_statx = true;
|
||||
bool deleted = false;
|
||||
struct dirent *dent;
|
||||
bool deleted = false;
|
||||
int r = 0;
|
||||
|
||||
FOREACH_DIRENT_ALL(dent, d, break) {
|
||||
struct stat s;
|
||||
usec_t age;
|
||||
_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 (fstatat(dirfd(d), dent->d_name, &s, AT_SYMLINK_NOFOLLOW) < 0) {
|
||||
if (errno == ENOENT)
|
||||
continue;
|
||||
|
||||
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
|
||||
;
|
||||
|
||||
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;
|
||||
}
|
||||
/* 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;
|
||||
}
|
||||
|
||||
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);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Stay on the same filesystem */
|
||||
if (major(s.st_dev) != rootdev_major || minor(s.st_dev) != 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;
|
||||
/* Stay on the same filesystem */
|
||||
if (s.st_dev != rootdev) {
|
||||
log_debug("Ignoring \"%s/%s\": different filesystem.", p, dent->d_name);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* 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)) {
|
||||
if (S_ISDIR(s.st_mode)) {
|
||||
int q;
|
||||
|
||||
q = fd_is_mount_point(dirfd(d), dent->d_name, 0);
|
||||
|
@ -651,12 +561,12 @@ static int dir_cleanup(
|
|||
continue;
|
||||
}
|
||||
|
||||
if (S_ISDIR(mode)) {
|
||||
if (S_ISDIR(s.st_mode)) {
|
||||
_cleanup_closedir_ DIR *sub_dir = NULL;
|
||||
|
||||
if (mountpoint &&
|
||||
streq(dent->d_name, "lost+found") &&
|
||||
uid == 0) {
|
||||
s.st_uid == 0) {
|
||||
log_debug("Ignoring directory \"%s\".", sub_path);
|
||||
continue;
|
||||
}
|
||||
|
@ -679,11 +589,7 @@ static int dir_cleanup(
|
|||
continue;
|
||||
}
|
||||
|
||||
q = dir_cleanup(i,
|
||||
sub_path, sub_dir,
|
||||
atime_nsec, mtime_nsec, cutoff_nsec,
|
||||
rootdev_major, rootdev_minor,
|
||||
false, maxdepth-1, false);
|
||||
q = dir_cleanup(i, sub_path, sub_dir, &s, cutoff, rootdev, false, maxdepth-1, false);
|
||||
if (q < 0)
|
||||
r = q;
|
||||
}
|
||||
|
@ -699,28 +605,22 @@ static int dir_cleanup(
|
|||
}
|
||||
|
||||
/* Ignore ctime, we change it when deleting */
|
||||
if (mtime_nsec != NSEC_INFINITY && mtime_nsec >= cutoff_nsec) {
|
||||
age = timespec_load(&s.st_mtim);
|
||||
if (age >= cutoff) {
|
||||
char a[FORMAT_TIMESTAMP_MAX];
|
||||
/* Follows spelling in stat(1). */
|
||||
log_debug("Directory \"%s\": modify time %s is too new.",
|
||||
sub_path,
|
||||
format_timestamp_style(a, sizeof(a), mtime_nsec / NSEC_PER_USEC, TIMESTAMP_US));
|
||||
format_timestamp_style(a, sizeof(a), age, TIMESTAMP_US));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (atime_nsec != NSEC_INFINITY && atime_nsec >= cutoff_nsec) {
|
||||
age = timespec_load(&s.st_atim);
|
||||
if (age >= cutoff) {
|
||||
char a[FORMAT_TIMESTAMP_MAX];
|
||||
log_debug("Directory \"%s\": access time %s is too new.",
|
||||
sub_path,
|
||||
format_timestamp_style(a, sizeof(a), atime_nsec / NSEC_PER_USEC, TIMESTAMP_US));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (btime_nsec != NSEC_INFINITY && btime_nsec >= cutoff_nsec) {
|
||||
char a[FORMAT_TIMESTAMP_MAX];
|
||||
log_debug("Directory \"%s\": birth time %s is too new.",
|
||||
sub_path,
|
||||
format_timestamp_style(a, sizeof(a), btime_nsec / NSEC_PER_USEC, TIMESTAMP_US));
|
||||
format_timestamp_style(a, sizeof(a), age, TIMESTAMP_US));
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -732,14 +632,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 (s.st_mode & S_ISVTX) {
|
||||
log_debug("Skipping \"%s\": sticky bit set.", sub_path);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (mountpoint &&
|
||||
S_ISREG(mode) &&
|
||||
uid == 0 &&
|
||||
S_ISREG(s.st_mode) &&
|
||||
s.st_uid == 0 &&
|
||||
STR_IN_SET(dent->d_name,
|
||||
".journal",
|
||||
"aquota.user",
|
||||
|
@ -749,13 +649,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(s.st_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(s.st_mode) || S_ISBLK(s.st_mode)) {
|
||||
log_debug("Skipping \"%s\": a device.", sub_path);
|
||||
continue;
|
||||
}
|
||||
|
@ -766,36 +666,31 @@ static int dir_cleanup(
|
|||
continue;
|
||||
}
|
||||
|
||||
if (mtime_nsec != NSEC_INFINITY && mtime_nsec >= cutoff_nsec) {
|
||||
age = timespec_load(&s.st_mtim);
|
||||
if (age >= cutoff) {
|
||||
char a[FORMAT_TIMESTAMP_MAX];
|
||||
/* Follows spelling in stat(1). */
|
||||
log_debug("File \"%s\": modify time %s is too new.",
|
||||
sub_path,
|
||||
format_timestamp_style(a, sizeof(a), mtime_nsec / NSEC_PER_USEC, TIMESTAMP_US));
|
||||
format_timestamp_style(a, sizeof(a), age, TIMESTAMP_US));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (atime_nsec != NSEC_INFINITY && atime_nsec >= cutoff_nsec) {
|
||||
age = timespec_load(&s.st_atim);
|
||||
if (age >= cutoff) {
|
||||
char a[FORMAT_TIMESTAMP_MAX];
|
||||
log_debug("File \"%s\": access time %s is too new.",
|
||||
sub_path,
|
||||
format_timestamp_style(a, sizeof(a), atime_nsec / NSEC_PER_USEC, TIMESTAMP_US));
|
||||
format_timestamp_style(a, sizeof(a), age, TIMESTAMP_US));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ctime_nsec != NSEC_INFINITY && ctime_nsec >= cutoff_nsec) {
|
||||
age = timespec_load(&s.st_ctim);
|
||||
if (age >= cutoff) {
|
||||
char a[FORMAT_TIMESTAMP_MAX];
|
||||
log_debug("File \"%s\": change time %s is too new.",
|
||||
sub_path,
|
||||
format_timestamp_style(a, sizeof(a), ctime_nsec / NSEC_PER_USEC, TIMESTAMP_US));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (btime_nsec != NSEC_INFINITY && btime_nsec >= cutoff_nsec) {
|
||||
char a[FORMAT_TIMESTAMP_MAX];
|
||||
log_debug("File \"%s\": birth time %s is too new.",
|
||||
sub_path,
|
||||
format_timestamp_style(a, sizeof(a), btime_nsec / NSEC_PER_USEC, TIMESTAMP_US));
|
||||
format_timestamp_style(a, sizeof(a), age, TIMESTAMP_US));
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -810,19 +705,21 @@ static int dir_cleanup(
|
|||
|
||||
finish:
|
||||
if (deleted) {
|
||||
char a[FORMAT_TIMESTAMP_MAX], m[FORMAT_TIMESTAMP_MAX];
|
||||
struct timespec ts[2];
|
||||
char a[FORMAT_TIMESTAMP_MAX], b[FORMAT_TIMESTAMP_MAX];
|
||||
usec_t age1, age2;
|
||||
|
||||
age1 = timespec_load(&ds->st_atim);
|
||||
age2 = timespec_load(&ds->st_mtim);
|
||||
|
||||
log_debug("Restoring access and modification time on \"%s\": %s, %s",
|
||||
p,
|
||||
format_timestamp_style(a, sizeof(a), self_atime_nsec / NSEC_PER_USEC, TIMESTAMP_US),
|
||||
format_timestamp_style(m, sizeof(m), self_mtime_nsec / NSEC_PER_USEC, TIMESTAMP_US));
|
||||
|
||||
timespec_store_nsec(ts + 0, self_atime_nsec);
|
||||
timespec_store_nsec(ts + 1, self_mtime_nsec);
|
||||
format_timestamp_style(a, sizeof(a), age1, TIMESTAMP_US),
|
||||
format_timestamp_style(b, sizeof(b), age2, TIMESTAMP_US));
|
||||
|
||||
/* Restore original directory timestamps */
|
||||
if (futimens(dirfd(d), ts) < 0)
|
||||
if (futimens(dirfd(d), (struct timespec[]) {
|
||||
ds->st_atim,
|
||||
ds->st_mtim }) < 0)
|
||||
log_warning_errno(errno, "Failed to revert timestamps of '%s', ignoring: %m", p);
|
||||
}
|
||||
|
||||
|
@ -2289,20 +2186,11 @@ 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 stat s, ps;
|
||||
bool mountpoint;
|
||||
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
|
||||
;
|
||||
char timestamp[FORMAT_TIMESTAMP_MAX];
|
||||
|
||||
assert(i);
|
||||
|
||||
|
@ -2325,53 +2213,24 @@ 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;
|
||||
if (fstat(dirfd(d), &s) < 0)
|
||||
return log_error_errno(errno, "stat(%s) failed: %m", i->path);
|
||||
|
||||
if (!ERRNO_IS_NOT_SUPPORTED(errno) && !ERRNO_IS_PRIVILEGE(errno))
|
||||
return log_error_errno(errno, "statx(%s) failed: %m", i->path);
|
||||
if (!S_ISDIR(s.st_mode))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(ENOTDIR),
|
||||
"%s is not a directory.", 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) {
|
||||
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;
|
||||
}
|
||||
if (fstatat(dirfd(d), "..", &ps, AT_SYMLINK_NOFOLLOW) != 0)
|
||||
return log_error_errno(errno, "stat(%s/..) failed: %m", i->path);
|
||||
|
||||
mountpoint = s.st_dev != ps.st_dev || s.st_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,
|
||||
return dir_cleanup(i, instance, d, &s, cutoff, s.st_dev, mountpoint,
|
||||
MAX_DEPTH, i->keep_first_level);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue