1
1
mirror of https://github.com/systemd/systemd-stable.git synced 2024-12-24 21:34:08 +03:00

Merge pull request #8222 from poettering/journal-by-inode

make sure we detect journal rotation even on inotify q overrun
This commit is contained in:
Zbigniew Jędrzejewski-Szmek 2018-02-20 21:36:25 +01:00 committed by GitHub
commit 2e10cc5649
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 420 additions and 178 deletions

View File

@ -449,6 +449,8 @@ decl_headers = '''
#include <uchar.h>
#include <linux/ethtool.h>
#include <linux/fib_rules.h>
#include <linux/stat.h>
#include <sys/stat.h>
'''
# FIXME: key_serial_t is only defined in keyutils.h, this is bound to fail
@ -457,6 +459,7 @@ foreach decl : ['char16_t',
'key_serial_t',
'struct ethtool_link_settings',
'struct fib_rule_uid_range',
'struct statx',
]
# We get -1 if the size cannot be determined
@ -519,6 +522,9 @@ foreach ident : [
['bpf', '''#include <sys/syscall.h>
#include <unistd.h>'''],
['explicit_bzero' , '''#include <string.h>'''],
['statx', '''#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>'''],
]
have = cc.has_function(ident[0], prefix : ident[1], args : '-D_GNU_SOURCE')

View File

@ -232,23 +232,18 @@ int btrfs_subvol_get_read_only_fd(int fd) {
}
int btrfs_reflink(int infd, int outfd) {
struct stat st;
int r;
assert(infd >= 0);
assert(outfd >= 0);
/* Make sure we invoke the ioctl on a regular file, so that no
* device driver accidentally gets it. */
/* Make sure we invoke the ioctl on a regular file, so that no device driver accidentally gets it. */
if (fstat(outfd, &st) < 0)
return -errno;
if (!S_ISREG(st.st_mode))
return -EINVAL;
r = ioctl(outfd, BTRFS_IOC_CLONE, infd);
r = fd_verify_regular(outfd);
if (r < 0)
return r;
if (ioctl(outfd, BTRFS_IOC_CLONE, infd) < 0)
return -errno;
return 0;
@ -261,21 +256,17 @@ int btrfs_clone_range(int infd, uint64_t in_offset, int outfd, uint64_t out_offs
.src_length = sz,
.dest_offset = out_offset,
};
struct stat st;
int r;
assert(infd >= 0);
assert(outfd >= 0);
assert(sz > 0);
if (fstat(outfd, &st) < 0)
return -errno;
if (!S_ISREG(st.st_mode))
return -EINVAL;
r = ioctl(outfd, BTRFS_IOC_CLONE_RANGE, &args);
r = fd_verify_regular(outfd);
if (r < 0)
return r;
if (ioctl(outfd, BTRFS_IOC_CLONE_RANGE, &args) < 0)
return -errno;
return 0;
@ -760,15 +751,13 @@ int btrfs_subvol_get_subtree_quota(const char *path, uint64_t subvol_id, BtrfsQu
}
int btrfs_defrag_fd(int fd) {
struct stat st;
int r;
assert(fd >= 0);
if (fstat(fd, &st) < 0)
return -errno;
if (!S_ISREG(st.st_mode))
return -EINVAL;
r = fd_verify_regular(fd);
if (r < 0)
return r;
if (ioctl(fd, BTRFS_IOC_DEFRAG, NULL) < 0)
return -errno;

View File

@ -1187,6 +1187,10 @@ int fflush_sync_and_check(FILE *f) {
if (fsync(fileno(f)) < 0)
return -errno;
r = fsync_directory_of_file(fileno(f));
if (r < 0)
return r;
return 0;
}

View File

@ -967,3 +967,33 @@ int unlinkat_deallocate(int fd, const char *name, int flags) {
return 0;
}
int fsync_directory_of_file(int fd) {
_cleanup_free_ char *path = NULL, *dn = NULL;
_cleanup_close_ int dfd = -1;
int r;
r = fd_verify_regular(fd);
if (r < 0)
return r;
r = fd_get_path(fd, &path);
if (r < 0)
return r;
if (!path_is_absolute(path))
return -EINVAL;
dn = dirname_malloc(path);
if (!dn)
return -ENOMEM;
dfd = open(dn, O_RDONLY|O_CLOEXEC|O_DIRECTORY);
if (dfd < 0)
return -errno;
if (fsync(dfd) < 0)
return -errno;
return 0;
}

View File

@ -107,3 +107,5 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(char*, unlink_and_free);
int access_fd(int fd, int mode);
int unlinkat_deallocate(int fd, const char *name, int flags);
int fsync_directory_of_file(int fd);

View File

@ -137,7 +137,7 @@ int loop_write(int fd, const void *buf, size_t nbytes, bool do_poll) {
assert(fd >= 0);
assert(buf);
if (nbytes > (size_t) SSIZE_MAX)
if (_unlikely_(nbytes > (size_t) SSIZE_MAX))
return -EINVAL;
do {

View File

@ -34,10 +34,12 @@
#include <linux/neighbour.h>
#include <linux/oom.h>
#include <linux/rtnetlink.h>
#include <linux/stat.h>
#include <net/ethernet.h>
#include <stdlib.h>
#include <sys/resource.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <uchar.h>
#include <unistd.h>
@ -1372,4 +1374,43 @@ struct fib_rule_uid_range {
#define PF_KTHREAD 0x00200000
#endif
#if ! HAVE_STRUCT_STATX
struct statx_timestamp {
int64_t tv_sec;
uint32_t tv_nsec;
uint32_t __reserved;
};
struct statx {
uint32_t stx_mask;
uint32_t stx_blksize;
uint64_t stx_attributes;
uint32_t stx_nlink;
uint32_t stx_uid;
uint32_t stx_gid;
uint16_t stx_mode;
uint16_t __spare0[1];
uint64_t stx_ino;
uint64_t stx_size;
uint64_t stx_blocks;
uint64_t stx_attributes_mask;
struct statx_timestamp stx_atime;
struct statx_timestamp stx_btime;
struct statx_timestamp stx_ctime;
struct statx_timestamp stx_mtime;
uint32_t stx_rdev_major;
uint32_t stx_rdev_minor;
uint32_t stx_dev_major;
uint32_t stx_dev_minor;
uint64_t __spare2[14];
};
#endif
#ifndef STATX_BTIME
#define STATX_BTIME 0x00000800U
#endif
#ifndef AT_STATX_DONT_SYNC
#define AT_STATX_DONT_SYNC 0x4000
#endif
#include "missing_syscall.h"

View File

@ -383,3 +383,26 @@ static inline int bpf(int cmd, union bpf_attr *attr, size_t size) {
# endif
# endif
#endif
#if !HAVE_STATX
# ifndef __NR_statx
# if defined __i386__
# define __NR_bpf 383
# elif defined __x86_64__
# define __NR_bpf 332
# else
# warning "__NR_statx not defined for your architecture"
# endif
# endif
struct statx;
static inline ssize_t statx(int dfd, const char *filename, unsigned flags, unsigned int mask, struct statx *buffer) {
# ifdef __NR_statx
return syscall(__NR_statx, dfd, filename, flags, mask, buffer);
# else
errno = ENOSYS;
return -1;
# endif
}
#endif

View File

@ -269,3 +269,32 @@ int path_is_temporary_fs(const char *path) {
return fd_is_temporary_fs(fd);
}
int stat_verify_regular(const struct stat *st) {
assert(st);
/* Checks whether the specified stat() structure refers to a regular file. If not returns an appropriate error
* code. */
if (S_ISDIR(st->st_mode))
return -EISDIR;
if (S_ISLNK(st->st_mode))
return -ELOOP;
if (!S_ISREG(st->st_mode))
return -EBADFD;
return 0;
}
int fd_verify_regular(int fd) {
struct stat st;
assert(fd >= 0);
if (fstat(fd, &st) < 0)
return -errno;
return stat_verify_regular(&st);
}

View File

@ -75,3 +75,6 @@ int path_is_temporary_fs(const char *path);
* signed/unsigned comparison, because the magic can be 32 bit unsigned.
*/
#define F_TYPE_EQUAL(a, b) (a == (typeof(a)) b)
int stat_verify_regular(const struct stat *st);
int fd_verify_regular(int fd);

View File

@ -20,6 +20,7 @@
#include <errno.h>
#include <fcntl.h>
#include <linux/stat.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
@ -29,8 +30,10 @@
#include "alloc-util.h"
#include "fd-util.h"
#include "macro.h"
#include "missing.h"
#include "sparse-endian.h"
#include "stdio-util.h"
#include "string-util.h"
#include "time-util.h"
#include "xattr-util.h"
@ -111,11 +114,21 @@ ssize_t fgetxattrat_fake(int dirfd, const char *filename, const char *attribute,
/* The kernel doesn't have a fgetxattrat() command, hence let's emulate one */
fd = openat(dirfd, filename, O_CLOEXEC|O_PATH|(flags & AT_SYMLINK_NOFOLLOW ? O_NOFOLLOW : 0));
if (fd < 0)
return -errno;
if (flags & ~(AT_SYMLINK_NOFOLLOW|AT_EMPTY_PATH))
return -EINVAL;
xsprintf(fn, "/proc/self/fd/%i", fd);
if (isempty(filename)) {
if (!(flags & AT_EMPTY_PATH))
return -EINVAL;
xsprintf(fn, "/proc/self/fd/%i", dirfd);
} else {
fd = openat(dirfd, filename, O_CLOEXEC|O_PATH|(flags & AT_SYMLINK_NOFOLLOW ? O_NOFOLLOW : 0));
if (fd < 0)
return -errno;
xsprintf(fn, "/proc/self/fd/%i", fd);
}
l = getxattr(fn, attribute, value, size);
if (l < 0)
@ -137,52 +150,66 @@ static int parse_crtime(le64_t le, usec_t *usec) {
return 0;
}
int fd_getcrtime(int fd, usec_t *usec) {
int fd_getcrtime_at(int dirfd, const char *name, usec_t *ret, int flags) {
struct statx sx;
usec_t a, b;
le64_t le;
ssize_t n;
int r;
assert(fd >= 0);
assert(usec);
assert(ret);
/* Until Linux gets a real concept of birthtime/creation time,
* let's fake one with xattrs */
if (flags & ~(AT_EMPTY_PATH|AT_SYMLINK_NOFOLLOW))
return -EINVAL;
n = fgetxattr(fd, "user.crtime_usec", &le, sizeof(le));
if (n < 0)
return -errno;
if (n != sizeof(le))
return -EIO;
/* So here's the deal: the creation/birth time (crtime/btime) of a file is a relatively newly supported concept
* on Linux (or more strictly speaking: a concept that only recently got supported in the API, it was
* implemented on various file systems on the lower level since a while, but never was accessible). However, we
* needed a concept like that for vaccuuming algorithms and such, hence we emulated it via a user xattr for a
* long time. Starting with Linux 4.11 there's statx() which exposes the timestamp to userspace for the first
* time, where it is available. Thius function will read it, but it tries to keep some compatibility with older
* systems: we try to read both the crtime/btime and the xattr, and then use whatever is older. After all the
* concept is useful for determining how "old" a file really is, and hence using the older of the two makes
* most sense. */
return parse_crtime(le, usec);
}
int fd_getcrtime_at(int dirfd, const char *name, usec_t *usec, int flags) {
le64_t le;
ssize_t n;
if (statx(dirfd, strempty(name), flags|AT_STATX_DONT_SYNC, STATX_BTIME, &sx) >= 0 &&
(sx.stx_mask & STATX_BTIME) &&
sx.stx_btime.tv_sec != 0)
a = (usec_t) sx.stx_btime.tv_sec * USEC_PER_SEC +
(usec_t) sx.stx_btime.tv_nsec / NSEC_PER_USEC;
else
a = USEC_INFINITY;
n = fgetxattrat_fake(dirfd, name, "user.crtime_usec", &le, sizeof(le), flags);
if (n < 0)
return -errno;
if (n != sizeof(le))
return -EIO;
r = -errno;
else if (n != sizeof(le))
r = -EIO;
else
r = parse_crtime(le, &b);
if (r < 0) {
if (a != USEC_INFINITY) {
*ret = a;
return 0;
}
return parse_crtime(le, usec);
return r;
}
if (a != USEC_INFINITY)
*ret = MIN(a, b);
else
*ret = b;
return 0;
}
int path_getcrtime(const char *p, usec_t *usec) {
le64_t le;
ssize_t n;
int fd_getcrtime(int fd, usec_t *ret) {
return fd_getcrtime_at(fd, NULL, ret, AT_EMPTY_PATH);
}
assert(p);
assert(usec);
n = getxattr(p, "user.crtime_usec", &le, sizeof(le));
if (n < 0)
return -errno;
if (n != sizeof(le))
return -EIO;
return parse_crtime(le, usec);
int path_getcrtime(const char *p, usec_t *ret) {
return fd_getcrtime_at(AT_FDCWD, p, ret, 0);
}
int fd_setcrtime(int fd, usec_t usec) {
@ -190,7 +217,7 @@ int fd_setcrtime(int fd, usec_t usec) {
assert(fd >= 0);
if (usec <= 0)
if (IN_SET(usec, 0, USEC_INFINITY))
usec = now(CLOCK_REALTIME);
le = htole64((uint64_t) usec);

View File

@ -434,12 +434,13 @@ static int copy_file_with_version_check(const char *from, const char *to, bool f
(void) copy_times(fd_from, fd_to);
r = fsync(fd_to);
if (r < 0) {
if (fsync(fd_to) < 0) {
(void) unlink_noerrno(t);
return log_error_errno(errno, "Failed to copy data from \"%s\" to \"%s\": %m", from, t);
}
(void) fsync_directory_of_file(fd_to);
r = renameat(AT_FDCWD, t, AT_FDCWD, to);
if (r < 0) {
(void) unlink_noerrno(t);

View File

@ -260,6 +260,8 @@ static int fix_permissions(
if (fsync(fd) < 0)
return log_error_errno(errno, "Failed to sync coredump %s: %m", coredump_tmpfile_name(filename));
(void) fsync_directory_of_file(fd);
r = link_tmpfile(fd, filename, target);
if (r < 0)
return log_error_errno(r, "Failed to move coredump %s into place: %m", target);

View File

@ -37,6 +37,7 @@
#include "import-common.h"
#include "missing.h"
#include "ratelimit.h"
#include "stat-util.h"
#include "string-util.h"
#include "util.h"
@ -319,8 +320,9 @@ int raw_export_start(RawExport *e, const char *path, int fd, ImportCompressType
if (fstat(sfd, &e->st) < 0)
return -errno;
if (!S_ISREG(e->st.st_mode))
return -ENOTTY;
r = stat_verify_regular(&e->st);
if (r < 0)
return r;
/* Try to take a reflink snapshot of the file, if we can t make the export atomic */
tfd = reflink_snapshot(sfd, path);

View File

@ -33,6 +33,7 @@
#include "chattr-util.h"
#include "compress.h"
#include "fd-util.h"
#include "fs-util.h"
#include "journal-authenticate.h"
#include "journal-def.h"
#include "journal-file.h"
@ -42,6 +43,7 @@
#include "random-util.h"
#include "sd-event.h"
#include "set.h"
#include "stat-util.h"
#include "string-util.h"
#include "strv.h"
#include "xattr-util.h"
@ -453,39 +455,6 @@ static int journal_file_init_header(JournalFile *f, JournalFile *template) {
return 0;
}
static int fsync_directory_of_file(int fd) {
_cleanup_free_ char *path = NULL, *dn = NULL;
_cleanup_close_ int dfd = -1;
struct stat st;
int r;
if (fstat(fd, &st) < 0)
return -errno;
if (!S_ISREG(st.st_mode))
return -EBADFD;
r = fd_get_path(fd, &path);
if (r < 0)
return r;
if (!path_is_absolute(path))
return -EINVAL;
dn = dirname_malloc(path);
if (!dn)
return -ENOMEM;
dfd = open(dn, O_RDONLY|O_CLOEXEC|O_DIRECTORY);
if (dfd < 0)
return -errno;
if (fsync(dfd) < 0)
return -errno;
return 0;
}
static int journal_file_refresh_header(JournalFile *f) {
sd_id128_t boot_id;
int r;
@ -643,6 +612,8 @@ static int journal_file_verify_header(JournalFile *f) {
}
static int journal_file_fstat(JournalFile *f) {
int r;
assert(f);
assert(f->fd >= 0);
@ -651,6 +622,11 @@ static int journal_file_fstat(JournalFile *f) {
f->last_stat_usec = now(CLOCK_MONOTONIC);
/* Refuse dealing with with files that aren't regular */
r = stat_verify_regular(&f->last_stat);
if (r < 0)
return r;
/* Refuse appending to files that are already deleted */
if (f->last_stat.st_nlink <= 0)
return -EIDRM;
@ -3292,6 +3268,8 @@ int journal_file_open(
goto fail;
}
} else {
assert(fd >= 0);
/* If we don't know the path, fill in something explanatory and vaguely useful */
if (asprintf(&f->path, "/proc/self/%i", fd) < 0) {
r = -ENOMEM;
@ -3306,7 +3284,11 @@ int journal_file_open(
}
if (f->fd < 0) {
f->fd = open(f->path, f->flags|O_CLOEXEC, f->mode);
/* We pass O_NONBLOCK here, so that in case somebody pointed us to some character device node or FIFO
* or so, we likely fail quickly than block for long. For regular files O_NONBLOCK has no effect, hence
* it doesn't hurt in that case. */
f->fd = open(f->path, f->flags|O_CLOEXEC|O_NONBLOCK, f->mode);
if (f->fd < 0) {
r = -errno;
goto fail;
@ -3314,6 +3296,10 @@ int journal_file_open(
/* fds we opened here by us should also be closed by us. */
f->close_fd = true;
r = fd_nonblock(f->fd, false);
if (r < 0)
goto fail;
}
f->cache_fd = mmap_cache_add_fd(f->mmap, f->fd);
@ -3330,17 +3316,12 @@ int journal_file_open(
(void) journal_file_warn_btrfs(f);
/* Let's attach the creation time to the journal file,
* so that the vacuuming code knows the age of this
* file even if the file might end up corrupted one
* day... Ideally we'd just use the creation time many
* file systems maintain for each file, but there is
* currently no usable API to query this, hence let's
* emulate this via extended attributes. If extended
* attributes are not supported we'll just skip this,
* and rely solely on mtime/atime/ctime of the file. */
fd_setcrtime(f->fd, 0);
/* Let's attach the creation time to the journal file, so that the vacuuming code knows the age of this
* file even if the file might end up corrupted one day... Ideally we'd just use the creation time many
* file systems maintain for each file, but the API to query this is very new, hence let's emulate this
* via extended attributes. If extended attributes are not supported we'll just skip this, and rely
* solely on mtime/atime/ctime of the file. */
(void) fd_setcrtime(f->fd, 0);
#if HAVE_GCRYPT
/* Try to load the FSPRG state, and if we can't, then
@ -3691,7 +3672,7 @@ void journal_default_metrics(JournalMetrics *m, int fd) {
if (fstatvfs(fd, &ss) >= 0)
fs_size = ss.f_frsize * ss.f_blocks;
else {
log_debug_errno(errno, "Failed to detremine disk size: %m");
log_debug_errno(errno, "Failed to determine disk size: %m");
fs_size = 0;
}

View File

@ -1243,6 +1243,16 @@ static bool path_has_prefix(sd_journal *j, const char *path, const char *prefix)
return path_startswith(path, prefix);
}
static void track_file_disposition(sd_journal *j, JournalFile *f) {
assert(j);
assert(f);
if (!j->has_runtime_files && path_has_prefix(j, f->path, "/run"))
j->has_runtime_files = true;
else if (!j->has_persistent_files && path_has_prefix(j, f->path, "/var"))
j->has_persistent_files = true;
}
static const char *skip_slash(const char *p) {
if (!p)
@ -1254,86 +1264,125 @@ static const char *skip_slash(const char *p) {
return p;
}
static int add_any_file(sd_journal *j, int fd, const char *path) {
JournalFile *f = NULL;
static int add_any_file(
sd_journal *j,
int fd,
const char *path) {
bool close_fd = false;
JournalFile *f;
struct stat st;
int r, k;
assert(j);
assert(fd >= 0 || path);
if (path) {
f = ordered_hashmap_get(j->files, path);
if (f) {
/* Mark this file as seen in this generation. This is used to GC old files in
* process_q_overflow() to detect journal files that are still and discern them from those who
* are gone. */
f->last_seen_generation = j->generation;
return 0;
if (fd < 0) {
if (j->toplevel_fd >= 0)
/* If there's a top-level fd defined make the path relative, explicitly, since otherwise
* openat() ignores the first argument. */
fd = openat(j->toplevel_fd, skip_slash(path), O_RDONLY|O_CLOEXEC|O_NONBLOCK);
else
fd = open(path, O_RDONLY|O_CLOEXEC|O_NONBLOCK);
if (fd < 0) {
r = log_debug_errno(errno, "Failed to open journal file %s: %m", path);
goto finish;
}
close_fd = true;
r = fd_nonblock(fd, false);
if (r < 0) {
r = log_debug_errno(errno, "Failed to turn off O_NONBLOCK for %s: %m", path);
goto finish;
}
}
if (fstat(fd, &st) < 0) {
r = log_debug_errno(errno, "Failed to fstat file '%s': %m", path);
goto finish;
}
r = stat_verify_regular(&st);
if (r < 0) {
log_debug_errno(r, "Refusing to open '%s', as it is not a regular file.", path);
goto finish;
}
f = ordered_hashmap_get(j->files, path);
if (f) {
if (f->last_stat.st_dev == st.st_dev &&
f->last_stat.st_ino == st.st_ino) {
/* We already track this file, under the same path and with the same device/inode numbers, it's
* hence really the same. Mark this file as seen in this generation. This is used to GC old
* files in process_q_overflow() to detect journal files that are still there and discern them
* from those which are gone. */
f->last_seen_generation = j->generation;
r = 0;
goto finish;
}
/* So we tracked a file under this name, but it has a different inode/device. In that case, it got
* replaced (probably due to rotation?), let's drop it hence from our list. */
remove_file_real(j, f);
f = NULL;
}
if (ordered_hashmap_size(j->files) >= JOURNAL_FILES_MAX) {
log_debug("Too many open journal files, not adding %s.", path);
r = -ETOOMANYREFS;
goto fail;
}
if (fd < 0 && j->toplevel_fd >= 0) {
/* If there's a top-level fd defined, open the file relative to this now. (Make the path relative,
* explicitly, since otherwise openat() ignores the first argument.) */
fd = openat(j->toplevel_fd, skip_slash(path), O_RDONLY|O_CLOEXEC);
if (fd < 0) {
r = log_debug_errno(errno, "Failed to open journal file %s: %m", path);
goto fail;
}
close_fd = true;
goto finish;
}
r = journal_file_open(fd, path, O_RDONLY, 0, false, false, NULL, j->mmap, NULL, NULL, &f);
if (r < 0) {
if (close_fd)
safe_close(fd);
log_debug_errno(r, "Failed to open journal file %s: %m", path);
goto fail;
goto finish;
}
/* journal_file_dump(f); */
r = ordered_hashmap_put(j->files, f->path, f);
if (r < 0) {
f->close_fd = close_fd;
f->close_fd = false; /* make sure journal_file_close() doesn't close the caller's fd (or our own). We'll let the caller do that, or ourselves */
(void) journal_file_close(f);
goto fail;
goto finish;
}
close_fd = false; /* the fd is now owned by the JournalFile object */
f->last_seen_generation = j->generation;
if (!j->has_runtime_files && path_has_prefix(j, f->path, "/run"))
j->has_runtime_files = true;
else if (!j->has_persistent_files && path_has_prefix(j, f->path, "/var"))
j->has_persistent_files = true;
log_debug("File %s added.", f->path);
track_file_disposition(j, f);
check_network(j, f->fd);
j->current_invalidate_counter++;
return 0;
log_debug("File %s added.", f->path);
fail:
k = journal_put_error(j, r, path);
if (k < 0)
return k;
r = 0;
finish:
if (close_fd)
safe_close(fd);
if (r < 0) {
k = journal_put_error(j, r, path);
if (k < 0)
return k;
}
return r;
}
static int add_file(sd_journal *j, const char *prefix, const char *filename) {
static int add_file_by_name(
sd_journal *j,
const char *prefix,
const char *filename) {
const char *path;
assert(j);
@ -1350,7 +1399,11 @@ static int add_file(sd_journal *j, const char *prefix, const char *filename) {
return add_any_file(j, -1, path);
}
static void remove_file(sd_journal *j, const char *prefix, const char *filename) {
static void remove_file_by_name(
sd_journal *j,
const char *prefix,
const char *filename) {
const char *path;
JournalFile *f;
@ -1370,7 +1423,7 @@ static void remove_file_real(sd_journal *j, JournalFile *f) {
assert(j);
assert(f);
ordered_hashmap_remove(j->files, f->path);
(void) ordered_hashmap_remove(j->files, f->path);
log_debug("File %s removed.", f->path);
@ -1463,8 +1516,9 @@ static void directory_enumerate(sd_journal *j, Directory *m, DIR *d) {
assert(d);
FOREACH_DIRENT_ALL(de, d, goto fail) {
if (dirent_is_journal_file(de))
(void) add_file(j, m->path, de->d_name);
(void) add_file_by_name(j, m->path, de->d_name);
if (m->is_root && dirent_is_id128_subdir(de))
(void) add_directory(j, m->path, de->d_name);
@ -2016,10 +2070,9 @@ _public_ int sd_journal_open_files_fd(sd_journal **ret, int fds[], unsigned n_fd
goto fail;
}
if (!S_ISREG(st.st_mode)) {
r = -EBADFD;
r = stat_verify_regular(&st);
if (r < 0)
goto fail;
}
r = add_any_file(j, fds[i], NULL);
if (r < 0)
@ -2495,9 +2548,9 @@ static void process_inotify_event(sd_journal *j, struct inotify_event *e) {
/* Event for a journal file */
if (e->mask & (IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB))
(void) add_file(j, d->path, e->name);
(void) add_file_by_name(j, d->path, e->name);
else if (e->mask & (IN_DELETE|IN_MOVED_FROM|IN_UNMOUNT))
remove_file(j, d->path, e->name);
remove_file_by_name(j, d->path, e->name);
} else if (!d->is_root && e->len == 0) {

View File

@ -23,6 +23,7 @@
#include <unistd.h>
#include "fd-util.h"
#include "fs-util.h"
#include "hexdecoct.h"
#include "id128-util.h"
#include "io-util.h"
@ -180,9 +181,13 @@ int id128_write_fd(int fd, Id128Format f, sd_id128_t id, bool do_sync) {
if (do_sync) {
if (fsync(fd) < 0)
return -errno;
r = fsync_directory_of_file(fd);
if (r < 0)
return r;
}
return r;
return 0;
}
int id128_write(const char *p, Id128Format f, sd_id128_t id, bool do_sync) {

View File

@ -1284,10 +1284,10 @@ static int unit_file_load(
info->type = UNIT_FILE_TYPE_MASKED;
return 0;
}
if (S_ISDIR(st.st_mode))
return -EISDIR;
if (!S_ISREG(st.st_mode))
return -ENOTTY;
r = stat_verify_regular(&st);
if (r < 0)
return r;
f = fdopen(fd, "re");
if (!f)
@ -2163,12 +2163,9 @@ int unit_file_link(
if (lstat(full, &st) < 0)
return -errno;
if (S_ISLNK(st.st_mode))
return -ELOOP;
if (S_ISDIR(st.st_mode))
return -EISDIR;
if (!S_ISREG(st.st_mode))
return -ENOTTY;
r = stat_verify_regular(&st);
if (r < 0)
return r;
q = in_search_path(&paths, *i);
if (q < 0)

View File

@ -27,6 +27,7 @@
#include "alloc-util.h"
#include "fd-util.h"
#include "loop-util.h"
#include "stat-util.h"
int loop_device_make(int fd, int open_flags, LoopDevice **ret) {
const struct loop_info64 info = {
@ -37,7 +38,7 @@ int loop_device_make(int fd, int open_flags, LoopDevice **ret) {
_cleanup_free_ char *loopdev = NULL;
struct stat st;
LoopDevice *d;
int nr;
int nr, r;
assert(fd >= 0);
assert(ret);
@ -69,8 +70,9 @@ int loop_device_make(int fd, int open_flags, LoopDevice **ret) {
return 0;
}
if (!S_ISREG(st.st_mode))
return -EINVAL;
r = stat_verify_regular(&st);
if (r < 0)
return r;
control = open("/dev/loop-control", O_RDWR|O_CLOEXEC|O_NOCTTY|O_NONBLOCK);
if (control < 0)

View File

@ -552,6 +552,15 @@ static void test_unlinkat_deallocate(void) {
assert_se(st.st_nlink == 0);
}
static void test_fsync_directory_of_file(void) {
_cleanup_close_ int fd = -1;
fd = open_tmpfile_unlinkable(NULL, O_RDWR);
assert_se(fd >= 0);
assert_se(fsync_directory_of_file(fd) >= 0);
}
int main(int argc, char *argv[]) {
test_unlink_noerrno();
test_get_files_in_directory();
@ -562,6 +571,7 @@ int main(int argc, char *argv[]) {
test_access_fd();
test_touch_file();
test_unlinkat_deallocate();
test_fsync_directory_of_file();
return 0;
}

View File

@ -26,6 +26,7 @@
#include "alloc-util.h"
#include "fd-util.h"
#include "fileio.h"
#include "fs-util.h"
#include "macro.h"
#include "string-util.h"
@ -63,8 +64,42 @@ cleanup:
assert_se(rmdir(t) >= 0);
}
static void test_getcrtime(void) {
_cleanup_close_ int fd = -1;
char ts[FORMAT_TIMESTAMP_MAX];
const char *vt;
usec_t usec, k;
int r;
assert_se(tmp_dir(&vt) >= 0);
fd = open_tmpfile_unlinkable(vt, O_RDWR);
assert_se(fd >= 0);
r = fd_getcrtime(fd, &usec);
if (r < 0)
log_debug_errno(r, "btime: %m");
else
log_debug("btime: %s", format_timestamp(ts, sizeof(ts), usec));
k = now(CLOCK_REALTIME);
r = fd_setcrtime(fd, 1519126446UL * USEC_PER_SEC);
if (!IN_SET(r, -EOPNOTSUPP, -ENOTTY)) {
assert_se(fd_getcrtime(fd, &usec) >= 0);
assert_se(k < 1519126446UL * USEC_PER_SEC ||
usec == 1519126446UL * USEC_PER_SEC);
}
}
int main(void) {
log_set_max_level(LOG_DEBUG);
log_parse_environment();
log_open();
test_fgetxattrat_fake();
test_getcrtime();
return 0;
}