diff options
author | Christian Persch <chpe@src.gnome.org> | 2021-02-01 22:04:12 +0100 |
---|---|---|
committer | Christian Persch <chpe@src.gnome.org> | 2021-02-01 22:04:12 +0100 |
commit | 6ff6542e902a1b7db6eca18cf8bccf24da431679 (patch) | |
tree | 6c572f1122b810240f4889e7c4d0743709c03120 | |
parent | ce347e7022f0e7422c0a4410d51d7caa534b22ce (diff) | |
download | vte-6ff6542e902a1b7db6eca18cf8bccf24da431679.tar.gz |
spawn: Use close_range to set CLOEXEC on all FDs
... when available; otherwise fall back to iterating over /proc/self/fd
as previously.
-rw-r--r-- | src/missing.cc | 36 | ||||
-rw-r--r-- | src/missing.hh | 59 |
2 files changed, 94 insertions, 1 deletions
diff --git a/src/missing.cc b/src/missing.cc index b013f8da..3cf4654f 100644 --- a/src/missing.cc +++ b/src/missing.cc @@ -134,6 +134,26 @@ getrlimit_NOFILE_max(void) return RLIM_INFINITY; } +#ifdef __linux__ + +static inline int +_vte_close_range(int first_fd, + int last_fd, + unsigned flags) +{ +#ifdef SYS_close_range + return syscall(SYS_close_range, + unsigned(first_fd), + last_fd == -1 ? ~0u : unsigned(last_fd), + flags); +#else + errno = ENOSYS; + return -1; +#endif +} + +#endif /* __linux__ */ + /* This function is called between fork and execve/_exit and so must be * async-signal-safe; see man:signal-safety(7). */ @@ -149,7 +169,21 @@ fdwalk(int (*cb)(void *data, int fd), int res = 0; #ifdef __linux__ - /* Avoid use of opendir/closedir since these are not async-signal-safe. */ + + /* First, try close_range(CLOEXEC) which is faster than the methods + * below, and works even if /proc is not available. + */ + res = _vte_close_range(0, -1, CLOSE_RANGE_CLOEXEC); + if (res == 0) + return 0; + if (res == -1 && + errno != ENOSYS /* old kernel */ && + errno != EINVAL /* flags not supported */) + return res; + + /* Fall back to iterating over /proc/self/fd. + * Avoid use of opendir/closedir since these are not async-signal-safe. + */ int dir_fd = open ("/proc/self/fd", O_RDONLY | O_DIRECTORY | O_CLOEXEC); if (dir_fd >= 0) { diff --git a/src/missing.hh b/src/missing.hh index fbeb8a2e..2dd8047d 100644 --- a/src/missing.hh +++ b/src/missing.hh @@ -33,3 +33,62 @@ int fdwalk(int (*cb)(void* data, int fd), char* strchrnul(char const* s, int c); #endif + +#ifdef __linux__ + +/* BEGIN + * The following is copied from systemd/src/basic/missing_syscall_def.h (LGPL2.1+) + */ +#ifndef __NR_close_range +# if defined(__aarch64__) +# define __NR_close_range 436 +# elif defined(__alpha__) +# define __NR_close_range 546 +# elif defined(__arc__) || defined(__tilegx__) +# define __NR_close_range 436 +# elif defined(__arm__) +# define __NR_close_range 436 +# elif defined(__i386__) +# define __NR_close_range 436 +# elif defined(__ia64__) +# define __NR_close_range 1460 +# elif defined(__m68k__) +# define __NR_close_range 436 +# elif defined(_MIPS_SIM) +# if _MIPS_SIM == _MIPS_SIM_ABI32 +# define __NR_close_range 4436 +# elif _MIPS_SIM == _MIPS_SIM_NABI32 +# define __NR_close_range 6436 +# elif _MIPS_SIM == _MIPS_SIM_ABI64 +# define __NR_close_range 5436 +# else +# error "Unknown MIPS ABI" +# endif +# elif defined(__powerpc__) +# define __NR_close_range 436 +# elif defined(__s390__) +# define __NR_close_range 436 +# elif defined(__sparc__) +# define __NR_close_range 436 +# elif defined(__x86_64__) +# if defined(__ILP32__) +# define __NR_close_range (436 | /* __X32_SYSCALL_BIT */ 0x40000000) +# else +# define __NR_close_range 436 +# endif +# else +# warning "close_range() syscall number is unknown for your architecture" +# endif +#endif /* !__NR_close_range */ + +/* END copied from systemd */ + +#if !defined(SYS_close_range) && defined(__NR_close_range) +#define SYS_close_range __NR_close_range +#endif + +#ifndef CLOSE_RANGE_CLOEXEC +#define CLOSE_RANGE_CLOEXEC (1u << 2) +#endif + +#endif /* __linux__ */ |