From a3d0471b03fcb2c4decf4bb38180354bb84a18e5 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Fri, 28 Feb 2025 16:38:11 +0900 Subject: [PATCH 1/6] basic/linux: update kernel headers from v6.14-rc4 --- src/basic/linux/ethtool.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/basic/linux/ethtool.h b/src/basic/linux/ethtool.h index 34f5dabd33..3bd99694a1 100644 --- a/src/basic/linux/ethtool.h +++ b/src/basic/linux/ethtool.h @@ -680,6 +680,7 @@ enum ethtool_link_ext_substate_module { * @ETH_SS_STATS_ETH_CTRL: names of IEEE 802.3 MAC Control statistics * @ETH_SS_STATS_RMON: names of RMON statistics * @ETH_SS_STATS_PHY: names of PHY(dev) statistics + * @ETH_SS_TS_FLAGS: hardware timestamping flags * * @ETH_SS_COUNT: number of defined string sets */ @@ -706,6 +707,7 @@ enum ethtool_stringset { ETH_SS_STATS_ETH_CTRL, ETH_SS_STATS_RMON, ETH_SS_STATS_PHY, + ETH_SS_TS_FLAGS, /* add new constants above here */ ETH_SS_COUNT From 24845c4ff614607add813322e275cbc8e51ea93c Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Fri, 28 Feb 2025 23:15:16 +0900 Subject: [PATCH 2/6] README: bump supported minimum glibc version to 2.31 The current glibc versions used by major distributions: CentOS 9: 2.34 CentOS 10: 2.39 Fedora 40: 2.39 Fedora 41: 2.40 Fedora 42: 2.41 Ubuntu 20.04 LTS (focal): 2.31 Ubuntu 22.04 LTS (jammy): 2.35 Ubuntu 24.04 LTS (noble): 2.39 Ubuntu 24.10 (oracular): 2.40 Debian 11 (Bullseye, oldstable): 2.31 Debian 12 (Bookworm, stable): 2.36 openSUSE SLE-15-SP6: 2.38 openSUSE Tumbleweed: 2.40 Hence, based on our supporting policy, we can bump the base line to 2.31. This commit does not change anything on our source code. But, will drop many workarounds for supporting older glibc in later commits. --- README | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README b/README index 5194faae5e..9b019396c8 100644 --- a/README +++ b/README @@ -206,7 +206,7 @@ REQUIREMENTS: with audit being enabled. This works correctly only on kernels 3.14 and newer though. TL;DR: turn audit off, still. - glibc >= 2.16 + glibc >= 2.31 libcap libmount >= 2.30 (from util-linux) (util-linux *must* be built without --enable-libmount-support-mtab) From 4424e6c811f46bf2c53c9056a058ba277cfdee40 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Fri, 28 Feb 2025 02:06:32 +0900 Subject: [PATCH 3/6] tree-wide: drop workarounds for statx() struct statx in glibc header was introduced in glibc-2.28 (fd70af45528d59a00eb3190ef6706cb299488fcd), but at that time, sys/stat.h conflicts with linux/stat.h. Since glibc-2.30 (5dad6ffbb2b76215cfcd38c3001778536ada8e8a), sys/stat.h includes linux/stat.h if exists. Since now our baseline of glibc is 2.31. Hence, we can drop workarounds for struct statx by importing linux/stat.h from newer kernel (v6.14-rc4). --- meson.build | 17 --- src/basic/dirent-util.c | 2 +- src/basic/fd-util.c | 23 ++- src/basic/linux/stat.h | 254 ++++++++++++++++++++++++++++++++ src/basic/missing_stat.h | 135 ----------------- src/basic/missing_syscall.h | 23 --- src/basic/missing_syscall_def.h | 68 --------- src/basic/missing_syscalls.py | 1 - src/basic/mountpoint-util.c | 12 +- src/basic/recurse-dir.c | 4 +- src/basic/stat-util.c | 4 +- src/basic/stat-util.h | 25 +--- src/basic/xattr-util.c | 2 +- src/shared/find-esp.c | 21 ++- src/tmpfiles/tmpfiles.c | 24 ++- 15 files changed, 298 insertions(+), 317 deletions(-) create mode 100644 src/basic/linux/stat.h delete mode 100644 src/basic/missing_stat.h diff --git a/meson.build b/meson.build index 0865c861ec..f4fd28410f 100644 --- a/meson.build +++ b/meson.build @@ -569,14 +569,12 @@ decl_headers = ''' #include #include #include -#include #include ''' foreach decl : ['char16_t', 'char32_t', 'struct mount_attr', - 'struct statx', 'struct dirent64', 'struct sched_attr', ] @@ -595,21 +593,9 @@ foreach decl : ['char16_t', endif endif - if decl == 'struct statx' - if have - want_linux_stat_h = false - else - have = cc.sizeof(decl, - prefix : decl_headers + '#include ', - args : '-D_GNU_SOURCE') > 0 - want_linux_stat_h = have - endif - endif - conf.set10('HAVE_' + decl.underscorify().to_upper(), have) endforeach -conf.set10('WANT_LINUX_STAT_H', want_linux_stat_h) conf.set10('WANT_LINUX_FS_H', want_linux_fs_h) foreach ident : ['secure_getenv', '__secure_getenv'] @@ -640,9 +626,6 @@ foreach ident : [ #include '''], ['bpf', '''#include #include '''], - ['statx', '''#include - #include - #include '''], ['explicit_bzero' , '''#include '''], ['reallocarray', '''#include '''], ['set_mempolicy', '''#include diff --git a/src/basic/dirent-util.c b/src/basic/dirent-util.c index 17df6a24c9..51db9820f9 100644 --- a/src/basic/dirent-util.c +++ b/src/basic/dirent-util.c @@ -9,7 +9,7 @@ #include "string-util.h" int dirent_ensure_type(int dir_fd, struct dirent *de) { - STRUCT_STATX_DEFINE(sx); + struct statx sx; int r; assert(dir_fd >= 0); diff --git a/src/basic/fd-util.c b/src/basic/fd-util.c index 539e8ca925..2691210d91 100644 --- a/src/basic/fd-util.c +++ b/src/basic/fd-util.c @@ -1087,30 +1087,29 @@ int path_is_root_at(int dir_fd, const char *path) { } int fds_are_same_mount(int fd1, int fd2) { - STRUCT_NEW_STATX_DEFINE(st1); - STRUCT_NEW_STATX_DEFINE(st2); + struct statx sx1 = {}, sx2 = {}; /* explicitly initialize the struct to make msan silent. */ int r; assert(fd1 >= 0); assert(fd2 >= 0); - r = statx_fallback(fd1, "", AT_EMPTY_PATH, STATX_TYPE|STATX_INO|STATX_MNT_ID, &st1.sx); + r = statx_fallback(fd1, "", AT_EMPTY_PATH, STATX_TYPE|STATX_INO|STATX_MNT_ID, &sx1); if (r < 0) return r; - r = statx_fallback(fd2, "", AT_EMPTY_PATH, STATX_TYPE|STATX_INO|STATX_MNT_ID, &st2.sx); + r = statx_fallback(fd2, "", AT_EMPTY_PATH, STATX_TYPE|STATX_INO|STATX_MNT_ID, &sx2); if (r < 0) return r; /* First, compare inode. If these are different, the fd does not point to the root directory "/". */ - if (!statx_inode_same(&st1.sx, &st2.sx)) + if (!statx_inode_same(&sx1, &sx2)) return false; /* Note, statx() does not provide the mount ID and path_get_mnt_id_at() does not work when an old * kernel is used. In that case, let's assume that we do not have such spurious mount points in an * early boot stage, and silently skip the following check. */ - if (!FLAGS_SET(st1.nsx.stx_mask, STATX_MNT_ID)) { + if (!FLAGS_SET(sx1.stx_mask, STATX_MNT_ID)) { int mntid; r = path_get_mnt_id_at_fallback(fd1, "", &mntid); @@ -1118,11 +1117,11 @@ int fds_are_same_mount(int fd1, int fd2) { return r; assert(mntid >= 0); - st1.nsx.stx_mnt_id = mntid; - st1.nsx.stx_mask |= STATX_MNT_ID; + sx1.stx_mnt_id = mntid; + sx1.stx_mask |= STATX_MNT_ID; } - if (!FLAGS_SET(st2.nsx.stx_mask, STATX_MNT_ID)) { + if (!FLAGS_SET(sx2.stx_mask, STATX_MNT_ID)) { int mntid; r = path_get_mnt_id_at_fallback(fd2, "", &mntid); @@ -1130,11 +1129,11 @@ int fds_are_same_mount(int fd1, int fd2) { return r; assert(mntid >= 0); - st2.nsx.stx_mnt_id = mntid; - st2.nsx.stx_mask |= STATX_MNT_ID; + sx2.stx_mnt_id = mntid; + sx2.stx_mask |= STATX_MNT_ID; } - return statx_mount_same(&st1.nsx, &st2.nsx); + return statx_mount_same(&sx1, &sx2); } const char* accmode_to_string(int flags) { diff --git a/src/basic/linux/stat.h b/src/basic/linux/stat.h new file mode 100644 index 0000000000..2396306c5a --- /dev/null +++ b/src/basic/linux/stat.h @@ -0,0 +1,254 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef _LINUX_STAT_H +#define _LINUX_STAT_H + +#include + +#if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2) + +#define S_IFMT 00170000 +#define S_IFSOCK 0140000 +#define S_IFLNK 0120000 +#define S_IFREG 0100000 +#define S_IFBLK 0060000 +#define S_IFDIR 0040000 +#define S_IFCHR 0020000 +#define S_IFIFO 0010000 +#define S_ISUID 0004000 +#define S_ISGID 0002000 +#define S_ISVTX 0001000 + +#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) +#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) +#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) +#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) +#define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK) +#define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO) +#define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK) + +#define S_IRWXU 00700 +#define S_IRUSR 00400 +#define S_IWUSR 00200 +#define S_IXUSR 00100 + +#define S_IRWXG 00070 +#define S_IRGRP 00040 +#define S_IWGRP 00020 +#define S_IXGRP 00010 + +#define S_IRWXO 00007 +#define S_IROTH 00004 +#define S_IWOTH 00002 +#define S_IXOTH 00001 + +#endif + +/* + * Timestamp structure for the timestamps in struct statx. + * + * tv_sec holds the number of seconds before (negative) or after (positive) + * 00:00:00 1st January 1970 UTC. + * + * tv_nsec holds a number of nanoseconds (0..999,999,999) after the tv_sec time. + * + * __reserved is held in case we need a yet finer resolution. + */ +struct statx_timestamp { + __s64 tv_sec; + __u32 tv_nsec; + __s32 __reserved; +}; + +/* + * Structures for the extended file attribute retrieval system call + * (statx()). + * + * The caller passes a mask of what they're specifically interested in as a + * parameter to statx(). What statx() actually got will be indicated in + * st_mask upon return. + * + * For each bit in the mask argument: + * + * - if the datum is not supported: + * + * - the bit will be cleared, and + * + * - the datum will be set to an appropriate fabricated value if one is + * available (eg. CIFS can take a default uid and gid), otherwise + * + * - the field will be cleared; + * + * - otherwise, if explicitly requested: + * + * - the datum will be synchronised to the server if AT_STATX_FORCE_SYNC is + * set or if the datum is considered out of date, and + * + * - the field will be filled in and the bit will be set; + * + * - otherwise, if not requested, but available in approximate form without any + * effort, it will be filled in anyway, and the bit will be set upon return + * (it might not be up to date, however, and no attempt will be made to + * synchronise the internal state first); + * + * - otherwise the field and the bit will be cleared before returning. + * + * Items in STATX_BASIC_STATS may be marked unavailable on return, but they + * will have values installed for compatibility purposes so that stat() and + * co. can be emulated in userspace. + */ +struct statx { + /* 0x00 */ + /* What results were written [uncond] */ + __u32 stx_mask; + + /* Preferred general I/O size [uncond] */ + __u32 stx_blksize; + + /* Flags conveying information about the file [uncond] */ + __u64 stx_attributes; + + /* 0x10 */ + /* Number of hard links */ + __u32 stx_nlink; + + /* User ID of owner */ + __u32 stx_uid; + + /* Group ID of owner */ + __u32 stx_gid; + + /* File mode */ + __u16 stx_mode; + __u16 __spare0[1]; + + /* 0x20 */ + /* Inode number */ + __u64 stx_ino; + + /* File size */ + __u64 stx_size; + + /* Number of 512-byte blocks allocated */ + __u64 stx_blocks; + + /* Mask to show what's supported in stx_attributes */ + __u64 stx_attributes_mask; + + /* 0x40 */ + /* Last access time */ + struct statx_timestamp stx_atime; + + /* File creation time */ + struct statx_timestamp stx_btime; + + /* Last attribute change time */ + struct statx_timestamp stx_ctime; + + /* Last data modification time */ + struct statx_timestamp stx_mtime; + + /* 0x80 */ + /* Device ID of special file [if bdev/cdev] */ + __u32 stx_rdev_major; + __u32 stx_rdev_minor; + + /* ID of device containing file [uncond] */ + __u32 stx_dev_major; + __u32 stx_dev_minor; + + /* 0x90 */ + __u64 stx_mnt_id; + + /* Memory buffer alignment for direct I/O */ + __u32 stx_dio_mem_align; + + /* File offset alignment for direct I/O */ + __u32 stx_dio_offset_align; + + /* 0xa0 */ + /* Subvolume identifier */ + __u64 stx_subvol; + + /* Min atomic write unit in bytes */ + __u32 stx_atomic_write_unit_min; + + /* Max atomic write unit in bytes */ + __u32 stx_atomic_write_unit_max; + + /* 0xb0 */ + /* Max atomic write segment count */ + __u32 stx_atomic_write_segments_max; + + /* File offset alignment for direct I/O reads */ + __u32 stx_dio_read_offset_align; + + /* 0xb8 */ + __u64 __spare3[9]; /* Spare space for future expansion */ + + /* 0x100 */ +}; + +/* + * Flags to be stx_mask + * + * Query request/result mask for statx() and struct statx::stx_mask. + * + * These bits should be set in the mask argument of statx() to request + * particular items when calling statx(). + */ +#define STATX_TYPE 0x00000001U /* Want/got stx_mode & S_IFMT */ +#define STATX_MODE 0x00000002U /* Want/got stx_mode & ~S_IFMT */ +#define STATX_NLINK 0x00000004U /* Want/got stx_nlink */ +#define STATX_UID 0x00000008U /* Want/got stx_uid */ +#define STATX_GID 0x00000010U /* Want/got stx_gid */ +#define STATX_ATIME 0x00000020U /* Want/got stx_atime */ +#define STATX_MTIME 0x00000040U /* Want/got stx_mtime */ +#define STATX_CTIME 0x00000080U /* Want/got stx_ctime */ +#define STATX_INO 0x00000100U /* Want/got stx_ino */ +#define STATX_SIZE 0x00000200U /* Want/got stx_size */ +#define STATX_BLOCKS 0x00000400U /* Want/got stx_blocks */ +#define STATX_BASIC_STATS 0x000007ffU /* The stuff in the normal stat struct */ +#define STATX_BTIME 0x00000800U /* Want/got stx_btime */ +#define STATX_MNT_ID 0x00001000U /* Got stx_mnt_id */ +#define STATX_DIOALIGN 0x00002000U /* Want/got direct I/O alignment info */ +#define STATX_MNT_ID_UNIQUE 0x00004000U /* Want/got extended stx_mount_id */ +#define STATX_SUBVOL 0x00008000U /* Want/got stx_subvol */ +#define STATX_WRITE_ATOMIC 0x00010000U /* Want/got atomic_write_* fields */ +#define STATX_DIO_READ_ALIGN 0x00020000U /* Want/got dio read alignment info */ + +#define STATX__RESERVED 0x80000000U /* Reserved for future struct statx expansion */ + +/* + * This is deprecated, and shall remain the same value in the future. To avoid + * confusion please use the equivalent (STATX_BASIC_STATS | STATX_BTIME) + * instead. + */ +#define STATX_ALL 0x00000fffU + +/* + * Attributes to be found in stx_attributes and masked in stx_attributes_mask. + * + * These give information about the features or the state of a file that might + * be of use to ordinary userspace programs such as GUIs or ls rather than + * specialised tools. + * + * Note that the flags marked [I] correspond to the FS_IOC_SETFLAGS flags + * semantically. Where possible, the numerical value is picked to correspond + * also. Note that the DAX attribute indicates that the file is in the CPU + * direct access state. It does not correspond to the per-inode flag that + * some filesystems support. + * + */ +#define STATX_ATTR_COMPRESSED 0x00000004 /* [I] File is compressed by the fs */ +#define STATX_ATTR_IMMUTABLE 0x00000010 /* [I] File is marked immutable */ +#define STATX_ATTR_APPEND 0x00000020 /* [I] File is append-only */ +#define STATX_ATTR_NODUMP 0x00000040 /* [I] File is not to be dumped */ +#define STATX_ATTR_ENCRYPTED 0x00000800 /* [I] File requires key to decrypt in fs */ +#define STATX_ATTR_AUTOMOUNT 0x00001000 /* Dir: Automount trigger */ +#define STATX_ATTR_MOUNT_ROOT 0x00002000 /* Root of a mount */ +#define STATX_ATTR_VERITY 0x00100000 /* [I] Verity protected file */ +#define STATX_ATTR_DAX 0x00200000 /* File is currently in DAX state */ +#define STATX_ATTR_WRITE_ATOMIC 0x00400000 /* File supports atomic write operations */ + + +#endif /* _LINUX_STAT_H */ diff --git a/src/basic/missing_stat.h b/src/basic/missing_stat.h deleted file mode 100644 index eba1a3876f..0000000000 --- a/src/basic/missing_stat.h +++ /dev/null @@ -1,135 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -#pragma once - -#include -#include - -#if WANT_LINUX_STAT_H -#include -#endif - -/* The newest definition we are aware of (fa2fcf4f1df1559a0a4ee0f46915b496cc2ebf60; 5.8) */ -#define STATX_DEFINITION { \ - __u32 stx_mask; \ - __u32 stx_blksize; \ - __u64 stx_attributes; \ - __u32 stx_nlink; \ - __u32 stx_uid; \ - __u32 stx_gid; \ - __u16 stx_mode; \ - __u16 __spare0[1]; \ - __u64 stx_ino; \ - __u64 stx_size; \ - __u64 stx_blocks; \ - __u64 stx_attributes_mask; \ - struct statx_timestamp stx_atime; \ - struct statx_timestamp stx_btime; \ - struct statx_timestamp stx_ctime; \ - struct statx_timestamp stx_mtime; \ - __u32 stx_rdev_major; \ - __u32 stx_rdev_minor; \ - __u32 stx_dev_major; \ - __u32 stx_dev_minor; \ - __u64 stx_mnt_id; \ - __u64 __spare2; \ - __u64 __spare3[12]; \ -} - -#if !HAVE_STRUCT_STATX -struct statx_timestamp { - __s64 tv_sec; - __u32 tv_nsec; - __s32 __reserved; -}; - -struct statx STATX_DEFINITION; -#endif - -/* Always define the newest version we are aware of as a distinct type, so that we can use it even if glibc - * 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 -#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_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 -#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_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 -#endif - -/* fa2fcf4f1df1559a0a4ee0f46915b496cc2ebf60 (5.8) */ -#ifndef STATX_MNT_ID -#define STATX_MNT_ID 0x00001000U -#endif - -/* 80340fe3605c0e78cfe496c3b3878be828cfdbfe (5.8) */ -#ifndef STATX_ATTR_MOUNT_ROOT -#define STATX_ATTR_MOUNT_ROOT 0x00002000 /* Root of a mount */ -#endif diff --git a/src/basic/missing_syscall.h b/src/basic/missing_syscall.h index f4eb4dd57b..3eab1a27ef 100644 --- a/src/basic/missing_syscall.h +++ b/src/basic/missing_syscall.h @@ -19,7 +19,6 @@ #include "macro.h" #include "missing_keyctl.h" #include "missing_sched.h" -#include "missing_stat.h" #include "missing_syscall_def.h" /* ======================================================================= */ @@ -223,28 +222,6 @@ static inline int missing_bpf(int cmd, union bpf_attr *attr, size_t size) { /* ======================================================================= */ -#if !HAVE_STATX -struct statx; - -static inline ssize_t missing_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 - -/* This typedef is supposed to be always defined. */ -typedef struct statx struct_statx; - -#if !HAVE_STATX -# define statx(dfd, filename, flags, mask, buffer) missing_statx(dfd, filename, flags, mask, buffer) -#endif - -/* ======================================================================= */ - #if !HAVE_SET_MEMPOLICY enum { MPOL_DEFAULT, diff --git a/src/basic/missing_syscall_def.h b/src/basic/missing_syscall_def.h index 48116fc0f7..e042b6be88 100644 --- a/src/basic/missing_syscall_def.h +++ b/src/basic/missing_syscall_def.h @@ -1333,71 +1333,3 @@ assert_cc(__NR_setxattrat == systemd_NR_setxattrat); # endif # endif #endif - -#ifndef __IGNORE_statx -# if defined(__aarch64__) -# define systemd_NR_statx 291 -# elif defined(__alpha__) -# define systemd_NR_statx 522 -# elif defined(__arc__) || defined(__tilegx__) -# define systemd_NR_statx 291 -# elif defined(__arm__) -# define systemd_NR_statx 397 -# elif defined(__i386__) -# define systemd_NR_statx 383 -# elif defined(__ia64__) -# define systemd_NR_statx 1350 -# elif defined(__loongarch_lp64) -# define systemd_NR_statx 291 -# elif defined(__m68k__) -# define systemd_NR_statx 379 -# elif defined(_MIPS_SIM) -# if _MIPS_SIM == _MIPS_SIM_ABI32 -# define systemd_NR_statx 4366 -# elif _MIPS_SIM == _MIPS_SIM_NABI32 -# define systemd_NR_statx 6330 -# elif _MIPS_SIM == _MIPS_SIM_ABI64 -# define systemd_NR_statx 5326 -# else -# error "Unknown MIPS ABI" -# endif -# elif defined(__hppa__) -# define systemd_NR_statx 349 -# elif defined(__powerpc__) -# define systemd_NR_statx 383 -# elif defined(__riscv) -# if __riscv_xlen == 32 -# define systemd_NR_statx 291 -# elif __riscv_xlen == 64 -# define systemd_NR_statx 291 -# else -# error "Unknown RISC-V ABI" -# endif -# elif defined(__s390__) -# define systemd_NR_statx 379 -# elif defined(__sparc__) -# define systemd_NR_statx 360 -# elif defined(__x86_64__) -# if defined(__ILP32__) -# define systemd_NR_statx (332 | /* __X32_SYSCALL_BIT */ 0x40000000) -# else -# define systemd_NR_statx 332 -# endif -# elif !defined(missing_arch_template) -# warning "statx() syscall number is unknown for your architecture" -# endif - -/* may be an (invalid) negative number due to libseccomp, see PR 13319 */ -# if defined __NR_statx && __NR_statx >= 0 -# if defined systemd_NR_statx -assert_cc(__NR_statx == systemd_NR_statx); -# endif -# else -# if defined __NR_statx -# undef __NR_statx -# endif -# if defined systemd_NR_statx && systemd_NR_statx >= 0 -# define __NR_statx systemd_NR_statx -# endif -# endif -#endif diff --git a/src/basic/missing_syscalls.py b/src/basic/missing_syscalls.py index d0e9d7dec4..e84e0afc20 100644 --- a/src/basic/missing_syscalls.py +++ b/src/basic/missing_syscalls.py @@ -25,7 +25,6 @@ SYSCALLS = [ 'renameat2', 'setns', 'setxattrat', - 'statx', ] def dictify(f): diff --git a/src/basic/mountpoint-util.c b/src/basic/mountpoint-util.c index d366b3aa51..e59a748df0 100644 --- a/src/basic/mountpoint-util.c +++ b/src/basic/mountpoint-util.c @@ -16,7 +16,6 @@ #include "missing_fcntl.h" #include "missing_fs.h" #include "missing_mount.h" -#include "missing_stat.h" #include "missing_syscall.h" #include "mkdir.h" #include "mountpoint-util.h" @@ -261,8 +260,7 @@ int is_mount_point_at(int fd, const char *filename, int flags) { * with a variety of st_dev reported. Also, btrfs subvolumes have different st_dev, even though * they aren't real mounts of their own. */ - STRUCT_STATX_DEFINE(sx); - + struct statx sx = {}; /* explicitly initialize the struct to make msan silent. */ if (statx(fd, filename, at_flags_normalize_nofollow(flags) | AT_NO_AUTOMOUNT | /* don't trigger automounts – mounts are a local concept, hence no need to trigger automounts to determine STATX_ATTR_MOUNT_ROOT */ @@ -401,7 +399,7 @@ int path_get_mnt_id_at_fallback(int dir_fd, const char *path, int *ret) { } int path_get_mnt_id_at(int dir_fd, const char *path, int *ret) { - STRUCT_NEW_STATX_DEFINE(buf); + struct statx sx; assert(dir_fd >= 0 || dir_fd == AT_FDCWD); assert(ret); @@ -412,7 +410,7 @@ int path_get_mnt_id_at(int dir_fd, const char *path, int *ret) { AT_NO_AUTOMOUNT | /* don't trigger automounts, mnt_id is a local concept */ AT_STATX_DONT_SYNC, /* don't go to the network, mnt_id is a local concept */ STATX_MNT_ID, - &buf.sx) < 0) { + &sx) < 0) { if (!ERRNO_IS_NOT_SUPPORTED(errno) && /* statx() is not supported by the kernel. */ !ERRNO_IS_PRIVILEGE(errno) && /* maybe filtered by seccomp. */ errno != EINVAL) /* glibc's fallback method returns EINVAL when AT_STATX_DONT_SYNC is set. */ @@ -421,8 +419,8 @@ int path_get_mnt_id_at(int dir_fd, const char *path, int *ret) { /* Fall back to name_to_handle_at() and then fdinfo if statx is not supported or we lack * privileges */ - } else if (FLAGS_SET(buf.nsx.stx_mask, STATX_MNT_ID)) { - *ret = buf.nsx.stx_mnt_id; + } else if (FLAGS_SET(sx.stx_mask, STATX_MNT_ID)) { + *ret = sx.stx_mnt_id; return 0; } diff --git a/src/basic/recurse-dir.c b/src/basic/recurse-dir.c index 4ff55032cc..18e0655168 100644 --- a/src/basic/recurse-dir.c +++ b/src/basic/recurse-dir.c @@ -151,7 +151,7 @@ int recurse_dir( void *userdata) { _cleanup_free_ DirectoryEntries *de = NULL; - STRUCT_STATX_DEFINE(root_sx); + struct statx root_sx; int r; assert(dir_fd >= 0); @@ -193,7 +193,7 @@ int recurse_dir( for (size_t i = 0; i < de->n_entries; i++) { _cleanup_close_ int inode_fd = -EBADF, subdir_fd = -EBADF; _cleanup_free_ char *joined = NULL; - STRUCT_STATX_DEFINE(sx); + struct statx sx; bool sx_valid = false; const char *p; diff --git a/src/basic/stat-util.c b/src/basic/stat-util.c index 10bd7c0fe1..687b7b2ddc 100644 --- a/src/basic/stat-util.c +++ b/src/basic/stat-util.c @@ -470,8 +470,8 @@ bool statx_inode_same(const struct statx *a, const struct statx *b) { a->stx_ino == b->stx_ino; } -bool statx_mount_same(const struct new_statx *a, const struct new_statx *b) { - if (!new_statx_is_set(a) || !new_statx_is_set(b)) +bool statx_mount_same(const struct statx *a, const struct statx *b) { + if (!statx_is_set(a) || !statx_is_set(b)) return false; /* if we have the mount ID, that's all we need */ diff --git a/src/basic/stat-util.h b/src/basic/stat-util.h index 7556f8f59a..f7c926e9f8 100644 --- a/src/basic/stat-util.h +++ b/src/basic/stat-util.h @@ -11,7 +11,6 @@ #include "fs-util.h" #include "macro.h" -#include "missing_stat.h" #include "siphash24.h" #include "time-util.h" @@ -90,31 +89,12 @@ bool stat_inode_same(const struct stat *a, const struct stat *b); bool stat_inode_unmodified(const struct stat *a, const struct stat *b); bool statx_inode_same(const struct statx *a, const struct statx *b); -bool statx_mount_same(const struct new_statx *a, const struct new_statx *b); +bool statx_mount_same(const struct statx *a, const struct statx *b); int statx_fallback(int dfd, const char *path, int flags, unsigned mask, struct statx *sx); int xstatfsat(int dir_fd, const char *path, struct statfs *ret); -#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 - static inline usec_t statx_timestamp_load(const struct statx_timestamp *ts) { return timespec_load(&(const struct timespec) { .tv_sec = ts->tv_sec, .tv_nsec = ts->tv_nsec }); } @@ -140,6 +120,3 @@ static inline bool stat_is_set(const struct stat *st) { static inline bool statx_is_set(const struct statx *sx) { return sx && sx->stx_mask != 0; } -static inline bool new_statx_is_set(const struct new_statx *sx) { - return sx && sx->stx_mask != 0; -} diff --git a/src/basic/xattr-util.c b/src/basic/xattr-util.c index a43f795f0f..b2ff1bcb32 100644 --- a/src/basic/xattr-util.c +++ b/src/basic/xattr-util.c @@ -379,7 +379,7 @@ int getcrtime_at( usec_t *ret) { _cleanup_free_ le64_t *le = NULL; - STRUCT_STATX_DEFINE(sx); + struct statx sx; usec_t a, b; int r; diff --git a/src/shared/find-esp.c b/src/shared/find-esp.c index f830d6dfe3..9b6517f53d 100644 --- a/src/shared/find-esp.c +++ b/src/shared/find-esp.c @@ -273,8 +273,7 @@ static int verify_fsroot_dir( bool searching = FLAGS_SET(flags, VERIFY_ESP_SEARCHING), unprivileged_mode = FLAGS_SET(flags, VERIFY_ESP_UNPRIVILEGED_MODE); _cleanup_free_ char *f = NULL; - STRUCT_NEW_STATX_DEFINE(sxa); - STRUCT_NEW_STATX_DEFINE(sxb); + struct statx sxa, sxb; int r; /* Checks if the specified directory is at the root of its file system, and returns device @@ -292,21 +291,21 @@ static int verify_fsroot_dir( return log_error_errno(r, "Failed to extract filename of %s: %m", path); r = statx_fallback(dir_fd, strempty(f), AT_SYMLINK_NOFOLLOW|(isempty(f) ? AT_EMPTY_PATH : 0), - STATX_TYPE|STATX_INO|STATX_MNT_ID, &sxa.sx); + STATX_TYPE|STATX_INO|STATX_MNT_ID, &sxa); if (r < 0) return log_full_errno((searching && r == -ENOENT) || (unprivileged_mode && ERRNO_IS_PRIVILEGE(r)) ? LOG_DEBUG : LOG_ERR, r, "Failed to determine block device node of \"%s\": %m", path); - assert(S_ISDIR(sxa.sx.stx_mode)); /* We used O_DIRECTORY above, when opening, so this must hold */ + assert(S_ISDIR(sxa.stx_mode)); /* We used O_DIRECTORY above, when opening, so this must hold */ - if (FLAGS_SET(sxa.sx.stx_attributes_mask, STATX_ATTR_MOUNT_ROOT)) { + if (FLAGS_SET(sxa.stx_attributes_mask, STATX_ATTR_MOUNT_ROOT)) { /* If we have STATX_ATTR_MOUNT_ROOT, we are happy, that's all we need. We operate under the * assumption that a top of a mount point is also the top of the file system. (Which of * course is strictly speaking not always true...) */ - if (!FLAGS_SET(sxa.sx.stx_attributes, STATX_ATTR_MOUNT_ROOT)) + if (!FLAGS_SET(sxa.stx_attributes, STATX_ATTR_MOUNT_ROOT)) return log_full_errno(searching ? LOG_DEBUG : LOG_ERR, SYNTHETIC_ERRNO(searching ? EADDRNOTAVAIL : ENODEV), "Directory \"%s\" is not the root of the file system.", path); @@ -315,15 +314,15 @@ static int verify_fsroot_dir( } /* Now let's look at the parent */ - r = statx_fallback(dir_fd, "", AT_EMPTY_PATH, STATX_TYPE|STATX_INO|STATX_MNT_ID, &sxb.sx); + r = statx_fallback(dir_fd, "", AT_EMPTY_PATH, STATX_TYPE|STATX_INO|STATX_MNT_ID, &sxb); if (r < 0) return log_full_errno(unprivileged_mode && ERRNO_IS_PRIVILEGE(r) ? LOG_DEBUG : LOG_ERR, r, "Failed to determine block device node of parent of \"%s\": %m", path); - if (statx_inode_same(&sxa.sx, &sxb.sx)) /* for the root dir inode nr for both inodes will be the same */ + if (statx_inode_same(&sxa, &sxb)) /* for the root dir inode nr for both inodes will be the same */ goto success; - if (statx_mount_same(&sxa.nsx, &sxb.nsx)) + if (statx_mount_same(&sxa, &sxb)) return log_full_errno(searching ? LOG_DEBUG : LOG_ERR, SYNTHETIC_ERRNO(searching ? EADDRNOTAVAIL : ENODEV), "Directory \"%s\" is not the root of the file system.", path); @@ -332,10 +331,10 @@ success: if (!ret_dev) return 0; - if (sxa.sx.stx_dev_major == 0) /* Hmm, maybe a btrfs device, and the caller asked for the backing device? Then let's try to get it. */ + if (sxa.stx_dev_major == 0) /* Hmm, maybe a btrfs device, and the caller asked for the backing device? Then let's try to get it. */ return btrfs_get_block_device_at(dir_fd, strempty(f), ret_dev); - *ret_dev = makedev(sxa.sx.stx_dev_major, sxa.sx.stx_dev_minor); + *ret_dev = makedev(sxa.stx_dev_major, sxa.stx_dev_minor); return 0; } diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c index 28108b8130..b3b50fc315 100644 --- a/src/tmpfiles/tmpfiles.c +++ b/src/tmpfiles/tmpfiles.c @@ -564,7 +564,7 @@ static int opendir_and_stat( bool *ret_mountpoint) { _cleanup_closedir_ DIR *d = NULL; - STRUCT_NEW_STATX_DEFINE(st1); + struct statx sx1; int r; assert(path); @@ -591,24 +591,23 @@ static int opendir_and_stat( return 0; } - r = statx_fallback(dirfd(d), "", AT_EMPTY_PATH, STATX_MODE|STATX_INO|STATX_ATIME|STATX_MTIME, &st1.sx); + r = statx_fallback(dirfd(d), "", AT_EMPTY_PATH, STATX_MODE|STATX_INO|STATX_ATIME|STATX_MTIME, &sx1); if (r < 0) return log_error_errno(r, "statx(%s) failed: %m", path); - if (FLAGS_SET(st1.sx.stx_attributes_mask, STATX_ATTR_MOUNT_ROOT)) - *ret_mountpoint = FLAGS_SET(st1.sx.stx_attributes, STATX_ATTR_MOUNT_ROOT); + if (FLAGS_SET(sx1.stx_attributes_mask, STATX_ATTR_MOUNT_ROOT)) + *ret_mountpoint = FLAGS_SET(sx1.stx_attributes, STATX_ATTR_MOUNT_ROOT); else { - STRUCT_NEW_STATX_DEFINE(st2); - - r = statx_fallback(dirfd(d), "..", 0, STATX_INO, &st2.sx); + struct statx sx2; + r = statx_fallback(dirfd(d), "..", 0, STATX_INO, &sx2); if (r < 0) return log_error_errno(r, "statx(%s/..) failed: %m", path); - *ret_mountpoint = !statx_mount_same(&st1.nsx, &st2.nsx); + *ret_mountpoint = !statx_mount_same(&sx1, &sx2); } *ret = TAKE_PTR(d); - *ret_sx = st1.sx; + *ret_sx = sx1; return 1; } @@ -707,8 +706,7 @@ static int dir_cleanup( * systems such as overlayfs better where each file is originating from a different * st_dev. */ - STRUCT_STATX_DEFINE(sx); - + struct statx sx; r = statx_fallback( dirfd(d), de->d_name, AT_SYMLINK_NOFOLLOW|AT_NO_AUTOMOUNT, @@ -2994,7 +2992,7 @@ static int remove_recursive( bool remove_instance) { _cleanup_closedir_ DIR *d = NULL; - STRUCT_STATX_DEFINE(sx); + struct statx sx; bool mountpoint; int r; @@ -3144,7 +3142,7 @@ static int clean_item_instance( usec_t cutoff = n - i->age; _cleanup_closedir_ DIR *d = NULL; - STRUCT_STATX_DEFINE(sx); + struct statx sx; bool mountpoint; int r; From 998e6394eaee113b6ee41f7b1ad04c7d9b7db24b Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Fri, 28 Feb 2025 23:28:42 +0900 Subject: [PATCH 4/6] test-stat-util: check if linux/stat.h is actually included from sys/stat.h --- src/test/test-stat-util.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/src/test/test-stat-util.c b/src/test/test-stat-util.c index 3ab177d1ce..e8091e048c 100644 --- a/src/test/test-stat-util.c +++ b/src/test/test-stat-util.c @@ -22,6 +22,40 @@ #include "tests.h" #include "tmpfile-util.h" +TEST(statx_definitions) { + /* Check if linux/stat.h is included from sys/stat.h. */ + ASSERT_EQ(STATX_TYPE, 0x00000001U); + ASSERT_EQ(STATX_MODE, 0x00000002U); + ASSERT_EQ(STATX_NLINK, 0x00000004U); + ASSERT_EQ(STATX_UID, 0x00000008U); + ASSERT_EQ(STATX_GID, 0x00000010U); + ASSERT_EQ(STATX_ATIME, 0x00000020U); + ASSERT_EQ(STATX_MTIME, 0x00000040U); + ASSERT_EQ(STATX_CTIME, 0x00000080U); + ASSERT_EQ(STATX_INO, 0x00000100U); + ASSERT_EQ(STATX_SIZE, 0x00000200U); + ASSERT_EQ(STATX_BLOCKS, 0x00000400U); + ASSERT_EQ(STATX_BASIC_STATS, 0x000007ffU); + ASSERT_EQ(STATX_BTIME, 0x00000800U); + ASSERT_EQ(STATX_MNT_ID, 0x00001000U); + ASSERT_EQ(STATX_DIOALIGN, 0x00002000U); + ASSERT_EQ(STATX_MNT_ID_UNIQUE, 0x00004000U); + ASSERT_EQ(STATX_SUBVOL, 0x00008000U); + ASSERT_EQ(STATX_WRITE_ATOMIC, 0x00010000U); + ASSERT_EQ(STATX_DIO_READ_ALIGN, 0x00020000U); + + ASSERT_EQ(STATX_ATTR_COMPRESSED, 0x00000004); + ASSERT_EQ(STATX_ATTR_IMMUTABLE, 0x00000010); + ASSERT_EQ(STATX_ATTR_APPEND, 0x00000020); + ASSERT_EQ(STATX_ATTR_NODUMP, 0x00000040); + ASSERT_EQ(STATX_ATTR_ENCRYPTED, 0x00000800); + ASSERT_EQ(STATX_ATTR_AUTOMOUNT, 0x00001000); + ASSERT_EQ(STATX_ATTR_MOUNT_ROOT, 0x00002000); + ASSERT_EQ(STATX_ATTR_VERITY, 0x00100000); + ASSERT_EQ(STATX_ATTR_DAX, 0x00200000); + ASSERT_EQ(STATX_ATTR_WRITE_ATOMIC, 0x00400000); +} + TEST(null_or_empty_path) { assert_se(null_or_empty_path("/dev/null") == 1); assert_se(null_or_empty_path("/dev/tty") == 1); /* We assume that any character device is "empty", bleh. */ From d5ddc0e0d3a2f869e6d18ff78390ab16a8f9de98 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Fri, 28 Feb 2025 19:19:23 +0900 Subject: [PATCH 5/6] stat-util: drop statx_fallback() Now both our required baseline of glibc and kernel support statx. --- src/basic/dirent-util.c | 6 ++-- src/basic/fd-util.c | 10 +++--- src/basic/recurse-dir.c | 29 ++++++++--------- src/basic/stat-util.c | 70 ----------------------------------------- src/basic/stat-util.h | 2 -- src/shared/find-esp.c | 15 +++++---- src/tmpfiles/tmpfiles.c | 27 +++++++--------- 7 files changed, 38 insertions(+), 121 deletions(-) diff --git a/src/basic/dirent-util.c b/src/basic/dirent-util.c index 51db9820f9..e25097d8ae 100644 --- a/src/basic/dirent-util.c +++ b/src/basic/dirent-util.c @@ -10,7 +10,6 @@ int dirent_ensure_type(int dir_fd, struct dirent *de) { struct statx sx; - int r; assert(dir_fd >= 0); assert(de); @@ -24,9 +23,8 @@ int dirent_ensure_type(int dir_fd, struct dirent *de) { } /* Let's ask only for the type, nothing else. */ - r = statx_fallback(dir_fd, de->d_name, AT_SYMLINK_NOFOLLOW|AT_NO_AUTOMOUNT, STATX_TYPE, &sx); - if (r < 0) - return r; + if (statx(dir_fd, de->d_name, AT_SYMLINK_NOFOLLOW|AT_NO_AUTOMOUNT, STATX_TYPE, &sx) < 0) + return -errno; assert(FLAGS_SET(sx.stx_mask, STATX_TYPE)); de->d_type = IFTODT(sx.stx_mode); diff --git a/src/basic/fd-util.c b/src/basic/fd-util.c index 2691210d91..8329c44a56 100644 --- a/src/basic/fd-util.c +++ b/src/basic/fd-util.c @@ -1093,13 +1093,11 @@ int fds_are_same_mount(int fd1, int fd2) { assert(fd1 >= 0); assert(fd2 >= 0); - r = statx_fallback(fd1, "", AT_EMPTY_PATH, STATX_TYPE|STATX_INO|STATX_MNT_ID, &sx1); - if (r < 0) - return r; + if (statx(fd1, "", AT_EMPTY_PATH, STATX_TYPE|STATX_INO|STATX_MNT_ID, &sx1) < 0) + return -errno; - r = statx_fallback(fd2, "", AT_EMPTY_PATH, STATX_TYPE|STATX_INO|STATX_MNT_ID, &sx2); - if (r < 0) - return r; + if (statx(fd2, "", AT_EMPTY_PATH, STATX_TYPE|STATX_INO|STATX_MNT_ID, &sx2) < 0) + return -errno; /* First, compare inode. If these are different, the fd does not point to the root directory "/". */ if (!statx_inode_same(&sx1, &sx2)) diff --git a/src/basic/recurse-dir.c b/src/basic/recurse-dir.c index 18e0655168..9612b7c6a5 100644 --- a/src/basic/recurse-dir.c +++ b/src/basic/recurse-dir.c @@ -167,9 +167,8 @@ int recurse_dir( if (FLAGS_SET(flags, RECURSE_DIR_TOPLEVEL)) { if (statx_mask != 0) { - r = statx_fallback(dir_fd, "", AT_EMPTY_PATH, statx_mask, &root_sx); - if (r < 0) - return r; + if (statx(dir_fd, "", AT_EMPTY_PATH, statx_mask, &root_sx) < 0) + return -errno; } r = func(RECURSE_DIR_ENTER, @@ -247,9 +246,8 @@ int recurse_dir( de->entries[i]->d_type = DT_DIR; if (statx_mask != 0 || (flags & RECURSE_DIR_SAME_MOUNT)) { - r = statx_fallback(subdir_fd, "", AT_EMPTY_PATH, statx_mask, &sx); - if (r < 0) - return r; + if (statx(subdir_fd, "", AT_EMPTY_PATH, statx_mask, &sx) < 0) + return -errno; sx_valid = true; } @@ -289,9 +287,8 @@ int recurse_dir( * assume. Let's guarantee that we never pass statx data of a directory where * caller expects a non-directory */ - r = statx_fallback(inode_fd, "", AT_EMPTY_PATH, statx_mask | STATX_TYPE, &sx); - if (r < 0) - return r; + if (statx(inode_fd, "", AT_EMPTY_PATH, statx_mask | STATX_TYPE, &sx) < 0) + return -errno; assert(sx.stx_mask & STATX_TYPE); sx_valid = true; @@ -311,15 +308,15 @@ int recurse_dir( } else if (statx_mask != 0 || (de->entries[i]->d_type == DT_UNKNOWN && (flags & RECURSE_DIR_ENSURE_TYPE))) { - r = statx_fallback(dir_fd, de->entries[i]->d_name, AT_SYMLINK_NOFOLLOW, statx_mask | STATX_TYPE, &sx); - if (r == -ENOENT) /* Vanished by now? Go for next file immediately */ - continue; - if (r < 0) { - log_debug_errno(r, "Failed to stat directory entry '%s': %m", p); + if (statx(dir_fd, de->entries[i]->d_name, AT_SYMLINK_NOFOLLOW, statx_mask | STATX_TYPE, &sx) < 0) { + if (errno == ENOENT) /* Vanished by now? Go for next file immediately */ + continue; - assert(-r <= RECURSE_DIR_SKIP_STAT_INODE_ERROR_MAX - RECURSE_DIR_SKIP_STAT_INODE_ERROR_BASE); + log_debug_errno(errno, "Failed to stat directory entry '%s': %m", p); - r = func(RECURSE_DIR_SKIP_STAT_INODE_ERROR_BASE + -r, + assert(errno <= RECURSE_DIR_SKIP_STAT_INODE_ERROR_MAX - RECURSE_DIR_SKIP_STAT_INODE_ERROR_BASE); + + r = func(RECURSE_DIR_SKIP_STAT_INODE_ERROR_BASE + errno, p, dir_fd, -1, diff --git a/src/basic/stat-util.c b/src/basic/stat-util.c index 687b7b2ddc..8ae588e2e1 100644 --- a/src/basic/stat-util.c +++ b/src/basic/stat-util.c @@ -483,76 +483,6 @@ bool statx_mount_same(const struct statx *a, const struct statx *b) { a->stx_dev_minor == b->stx_dev_minor; } -static bool is_statx_fatal_error(int err, int flags) { - assert(err < 0); - - /* If statx() is not supported or if we see EPERM (which might indicate seccomp filtering or so), - * let's do a fallback. Note that on EACCES we'll not fall back, since that is likely an indication of - * fs access issues, which we should propagate. */ - if (ERRNO_IS_NOT_SUPPORTED(err) || err == -EPERM) - return false; - - /* When unsupported flags are specified, glibc's fallback function returns -EINVAL. - * See statx_generic() in glibc. */ - if (err != -EINVAL) - return true; - - if ((flags & ~(AT_EMPTY_PATH | AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW | AT_STATX_SYNC_AS_STAT)) != 0) - return false; /* Unsupported flags are specified. Let's try to use our implementation. */ - - return true; -} - -int statx_fallback(int dfd, const char *path, int flags, unsigned mask, struct statx *sx) { - static bool avoid_statx = false; - struct stat st; - int r; - - if (!avoid_statx) { - r = RET_NERRNO(statx(dfd, path, flags, mask, sx)); - if (r >= 0 || is_statx_fatal_error(r, flags)) - return r; - - 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; -} - int xstatfsat(int dir_fd, const char *path, struct statfs *ret) { _cleanup_close_ int fd = -EBADF; diff --git a/src/basic/stat-util.h b/src/basic/stat-util.h index f7c926e9f8..e4fd422139 100644 --- a/src/basic/stat-util.h +++ b/src/basic/stat-util.h @@ -91,8 +91,6 @@ bool stat_inode_unmodified(const struct stat *a, const struct stat *b); bool statx_inode_same(const struct statx *a, const struct statx *b); bool statx_mount_same(const struct statx *a, const struct statx *b); -int statx_fallback(int dfd, const char *path, int flags, unsigned mask, struct statx *sx); - int xstatfsat(int dir_fd, const char *path, struct statfs *ret); static inline usec_t statx_timestamp_load(const struct statx_timestamp *ts) { diff --git a/src/shared/find-esp.c b/src/shared/find-esp.c index 9b6517f53d..e0550a7a09 100644 --- a/src/shared/find-esp.c +++ b/src/shared/find-esp.c @@ -290,11 +290,11 @@ static int verify_fsroot_dir( if (r < 0 && r != -EADDRNOTAVAIL) return log_error_errno(r, "Failed to extract filename of %s: %m", path); - r = statx_fallback(dir_fd, strempty(f), AT_SYMLINK_NOFOLLOW|(isempty(f) ? AT_EMPTY_PATH : 0), - STATX_TYPE|STATX_INO|STATX_MNT_ID, &sxa); - if (r < 0) - return log_full_errno((searching && r == -ENOENT) || - (unprivileged_mode && ERRNO_IS_PRIVILEGE(r)) ? LOG_DEBUG : LOG_ERR, r, + if (statx(dir_fd, strempty(f), + AT_SYMLINK_NOFOLLOW|(isempty(f) ? AT_EMPTY_PATH : 0), + STATX_TYPE|STATX_INO|STATX_MNT_ID, &sxa) < 0) + return log_full_errno((searching && errno == ENOENT) || + (unprivileged_mode && ERRNO_IS_PRIVILEGE(errno)) ? LOG_DEBUG : LOG_ERR, errno, "Failed to determine block device node of \"%s\": %m", path); assert(S_ISDIR(sxa.stx_mode)); /* We used O_DIRECTORY above, when opening, so this must hold */ @@ -314,9 +314,8 @@ static int verify_fsroot_dir( } /* Now let's look at the parent */ - r = statx_fallback(dir_fd, "", AT_EMPTY_PATH, STATX_TYPE|STATX_INO|STATX_MNT_ID, &sxb); - if (r < 0) - return log_full_errno(unprivileged_mode && ERRNO_IS_PRIVILEGE(r) ? LOG_DEBUG : LOG_ERR, r, + if (statx(dir_fd, "", AT_EMPTY_PATH, STATX_TYPE|STATX_INO|STATX_MNT_ID, &sxb) < 0) + return log_full_errno(unprivileged_mode && ERRNO_IS_PRIVILEGE(errno) ? LOG_DEBUG : LOG_ERR, errno, "Failed to determine block device node of parent of \"%s\": %m", path); if (statx_inode_same(&sxa, &sxb)) /* for the root dir inode nr for both inodes will be the same */ diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c index b3b50fc315..231247adbf 100644 --- a/src/tmpfiles/tmpfiles.c +++ b/src/tmpfiles/tmpfiles.c @@ -591,17 +591,15 @@ static int opendir_and_stat( return 0; } - r = statx_fallback(dirfd(d), "", AT_EMPTY_PATH, STATX_MODE|STATX_INO|STATX_ATIME|STATX_MTIME, &sx1); - if (r < 0) - return log_error_errno(r, "statx(%s) failed: %m", path); + if (statx(dirfd(d), "", AT_EMPTY_PATH, STATX_MODE|STATX_INO|STATX_ATIME|STATX_MTIME, &sx1) < 0) + return log_error_errno(errno, "statx(%s) failed: %m", path); if (FLAGS_SET(sx1.stx_attributes_mask, STATX_ATTR_MOUNT_ROOT)) *ret_mountpoint = FLAGS_SET(sx1.stx_attributes, STATX_ATTR_MOUNT_ROOT); else { struct statx sx2; - r = statx_fallback(dirfd(d), "..", 0, STATX_INO, &sx2); - if (r < 0) - return log_error_errno(r, "statx(%s/..) failed: %m", path); + if (statx(dirfd(d), "..", 0, STATX_INO, &sx2) < 0) + return log_error_errno(errno, "statx(%s/..) failed: %m", path); *ret_mountpoint = !statx_mount_same(&sx1, &sx2); } @@ -707,16 +705,15 @@ static int dir_cleanup( * st_dev. */ struct statx sx; - r = statx_fallback( - dirfd(d), de->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) { + if (statx(dirfd(d), de->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; + /* FUSE, NFS mounts, SELinux might return EACCES */ - log_full_errno(r == -EACCES ? LOG_DEBUG : LOG_ERR, r, + log_full_errno(errno == EACCES ? LOG_DEBUG : LOG_ERR, errno, "statx(%s/%s) failed: %m", p, de->d_name); continue; } From ee739ea6929a5ca58a0fcf0cb7d3b274e9a5f4c1 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Fri, 28 Feb 2025 19:28:33 +0900 Subject: [PATCH 6/6] mountpoint-util: make statx() failure critical Two error conditions are unreachable, as now both glibc and kernel support statx(). In other many places, failure in statx() are handled as critical, even if it is filtered by seccomp or so. Let's follow the same way here. --- src/basic/mountpoint-util.c | 28 +++++++++------------------- 1 file changed, 9 insertions(+), 19 deletions(-) diff --git a/src/basic/mountpoint-util.c b/src/basic/mountpoint-util.c index e59a748df0..cb79d621a1 100644 --- a/src/basic/mountpoint-util.c +++ b/src/basic/mountpoint-util.c @@ -223,9 +223,9 @@ int is_mount_point_at(int fd, const char *filename, int flags) { filename = "."; else { /* If the file name is empty we'll see if the specified 'fd' is a mount point. - * That's only supported if the kernel supports statx(), or if the inode specified - * via 'fd' refers to a directory. Otherwise, we'll have to fail (ENOTDIR), because - * we have no kernel API to query the information we need. */ + * That's only supported by statx(), or if the inode specified via 'fd' refers to a + * directory. Otherwise, we'll have to fail (ENOTDIR), because we have no kernel API + * to query the information we need. */ flags |= AT_EMPTY_PATH; filename = ""; } @@ -266,14 +266,10 @@ int is_mount_point_at(int fd, const char *filename, int flags) { AT_NO_AUTOMOUNT | /* don't trigger automounts – mounts are a local concept, hence no need to trigger automounts to determine STATX_ATTR_MOUNT_ROOT */ AT_STATX_DONT_SYNC, /* don't go to the network for this – for similar reasons */ STATX_TYPE, - &sx) < 0) { - if (!ERRNO_IS_NOT_SUPPORTED(errno) && /* statx() is not supported by the kernel. */ - !ERRNO_IS_PRIVILEGE(errno) && /* maybe filtered by seccomp. */ - errno != EINVAL) /* glibc's fallback method returns EINVAL when AT_STATX_DONT_SYNC is set. */ - return -errno; + &sx) < 0) + return -errno; - /* If statx() is not available or forbidden, fall back to name_to_handle_at() below */ - } else if (FLAGS_SET(sx.stx_attributes_mask, STATX_ATTR_MOUNT_ROOT)) /* yay! */ + if (FLAGS_SET(sx.stx_attributes_mask, STATX_ATTR_MOUNT_ROOT)) /* yay! */ return FLAGS_SET(sx.stx_attributes, STATX_ATTR_MOUNT_ROOT); _cleanup_free_ struct file_handle *h = NULL, *h_parent = NULL; @@ -410,16 +406,10 @@ int path_get_mnt_id_at(int dir_fd, const char *path, int *ret) { AT_NO_AUTOMOUNT | /* don't trigger automounts, mnt_id is a local concept */ AT_STATX_DONT_SYNC, /* don't go to the network, mnt_id is a local concept */ STATX_MNT_ID, - &sx) < 0) { - if (!ERRNO_IS_NOT_SUPPORTED(errno) && /* statx() is not supported by the kernel. */ - !ERRNO_IS_PRIVILEGE(errno) && /* maybe filtered by seccomp. */ - errno != EINVAL) /* glibc's fallback method returns EINVAL when AT_STATX_DONT_SYNC is set. */ - return -errno; + &sx) < 0) + return -errno; - /* Fall back to name_to_handle_at() and then fdinfo if statx is not supported or we lack - * privileges */ - - } else if (FLAGS_SET(sx.stx_mask, STATX_MNT_ID)) { + if (FLAGS_SET(sx.stx_mask, STATX_MNT_ID)) { *ret = sx.stx_mnt_id; return 0; }