summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYu Watanabe <watanabe.yu+github@gmail.com>2023-07-21 18:07:36 +0200
committerYu Watanabe <watanabe.yu+github@gmail.com>2023-07-21 19:14:54 +0200
commitd35ff4b60e4b5ca166aca48afb5bb7fde3275cac (patch)
treef1e3a7912da90cdcf33b61e90a07397b3540ee73
parentcore: add IgnoreOnSoftReboot= unit option (diff)
downloadsystemd-d35ff4b60e4b5ca166aca48afb5bb7fde3275cac.tar.xz
systemd-d35ff4b60e4b5ca166aca48afb5bb7fde3275cac.zip
stat-util: fix error handling of statx()
When newer glibc is used, but kernel does not support statx(), then glibc try to fallback with fstatat(). That's quite similar to our implementation, but the supported flags are different, and if unsupported flags are specified, it returns EINVAL. Let's handle the case more gracefully.
-rw-r--r--src/basic/stat-util.c34
1 files changed, 24 insertions, 10 deletions
diff --git a/src/basic/stat-util.c b/src/basic/stat-util.c
index b4905220fa..c54374b2c9 100644
--- a/src/basic/stat-util.c
+++ b/src/basic/stat-util.c
@@ -394,21 +394,35 @@ bool statx_mount_same(const struct new_statx *a, const struct new_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) {
- if (statx(dfd, path, flags, mask, sx) < 0) {
- if (!ERRNO_IS_NOT_SUPPORTED(errno) && errno != EPERM)
- return -errno;
-
- /* If statx() is not supported or if we see EPERM (which might indicate seccomp
- * filtering or so), let's do a fallback. Not that on EACCES we'll not fall back,
- * since that is likely an indication of fs access issues, which we should
- * propagate */
- } else
- return 0;
+ r = RET_NERRNO(statx(dfd, path, flags, mask, sx));
+ if (r >= 0 || is_statx_fatal_error(r, flags))
+ return r;
avoid_statx = true;
}