From 441e0fdb900b49888fb6d7901a2b5aa92c0a2017 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 13 Oct 2020 17:53:25 +0200 Subject: [PATCH] missing: add close_range() wrapper The syscall was added in 5.9 and is not yet exposed in glibc, hence define our own wrapper. --- meson.build | 1 + src/basic/missing_syscall.h | 46 +++++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/meson.build b/meson.build index c62e0d892b..04cb63d921 100644 --- a/meson.build +++ b/meson.build @@ -533,6 +533,7 @@ foreach ident : [ #include #include '''], ['mallinfo', '''#include '''], + ['close_range', '''#include '''], ] have = cc.has_function(ident[0], prefix : ident[1], args : '-D_GNU_SOURCE') diff --git a/src/basic/missing_syscall.h b/src/basic/missing_syscall.h index c11382b564..01fec6f2f5 100644 --- a/src/basic/missing_syscall.h +++ b/src/basic/missing_syscall.h @@ -734,3 +734,49 @@ static inline int missing_rt_sigqueueinfo(pid_t tgid, int sig, siginfo_t *info) # define rt_sigqueueinfo missing_rt_sigqueueinfo #endif + +/* ======================================================================= */ + +#define systemd_NR_close_range systemd_SC_arch_bias(436) + +/* may be (invalid) negative number due to libseccomp, see PR 13319 */ +#if defined __NR_close_range && __NR_close_range >= 0 +# if defined systemd_NR_close_range +assert_cc(__NR_close_range == systemd_NR_close_range); +# endif +#else +# if defined __NR_close_range +# undef __NR_close_range +# endif +# if defined systemd_NR_close_range +# define __NR_close_range systemd_NR_close_range +# endif +#endif + +#if !HAVE_CLOSE_RANGE +static inline int missing_close_range(int first_fd, int end_fd, unsigned flags) { +# ifdef __NR_close_range + /* Kernel-side the syscall expects fds as unsigned integers (just like close() actually), while + * userspace exclusively uses signed integers for fds. We don't know just yet how glibc is going to + * wrap this syscall, but let's assume it's going to be similar to what they do for close(), + * i.e. make the same unsigned → signed type change from the raw kernel syscall compared to the + * userspace wrapper. There's only one caveat for this: unlike for close() there's the special + * UINT_MAX fd value for the 'end_fd' argument. Let's safely map that to -1 here. And let's refuse + * any other negative values. */ + if ((first_fd < 0) || (end_fd < 0 && end_fd != -1)) { + errno = -EBADF; + return -1; + } + + return syscall(__NR_close_range, + (unsigned) first_fd, + end_fd == -1 ? UINT_MAX : (unsigned) end_fd, /* Of course, the compiler should figure out that this is the identity mapping IRL */ + flags); +# else + errno = ENOSYS; + return -1; +# endif +} + +# define close_range missing_close_range +#endif