diff options
author | Yu Watanabe <watanabe.yu+github@gmail.com> | 2023-07-21 18:07:36 +0200 |
---|---|---|
committer | Yu Watanabe <watanabe.yu+github@gmail.com> | 2023-07-21 19:14:54 +0200 |
commit | d35ff4b60e4b5ca166aca48afb5bb7fde3275cac (patch) | |
tree | f1e3a7912da90cdcf33b61e90a07397b3540ee73 /src/basic/stat-util.c | |
parent | core: add IgnoreOnSoftReboot= unit option (diff) | |
download | systemd-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.
Diffstat (limited to 'src/basic/stat-util.c')
-rw-r--r-- | src/basic/stat-util.c | 34 |
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; } |