diff options
author | Christian Persch <chpe@src.gnome.org> | 2021-01-19 21:05:45 +0100 |
---|---|---|
committer | Christian Persch <chpe@src.gnome.org> | 2021-01-19 21:05:45 +0100 |
commit | 0a8f1c0d97437e1989dee4a07ea1ea8d85a09f94 (patch) | |
tree | f6b9888e057f1fb92b4c0f23a7f0f888b4aedbd8 | |
parent | 59e11fd751806876dc1a28c9c6d9a17d75db57d2 (diff) | |
download | vte-wip/close-range.tar.gz |
spawn: Use close_range to set CLOEXEC on all FDswip/close-range
... when available; otherwise fall back to iterating over /proc/self/fd
as previously.
-rw-r--r-- | src/missing.cc | 37 | ||||
-rw-r--r-- | src/missing.hh | 55 |
2 files changed, 91 insertions, 1 deletions
diff --git a/src/missing.cc b/src/missing.cc index 214419fc..e890ad7e 100644 --- a/src/missing.cc +++ b/src/missing.cc @@ -134,6 +134,27 @@ getrlimit_NOFILE_max(void) return RLIM_INFINITY; } +#ifdef __linux__ + +static inline int +_vte_close_range(int first_fd, + int last_fd, + unsigned flags) +{ +#ifdef __NR_close_range + errno = 0; + return syscall(__NR_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 +170,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 07422708..39cb433a 100644 --- a/src/missing.hh +++ b/src/missing.hh @@ -33,3 +33,58 @@ 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 */ + +#ifndef CLOSE_RANGE_CLOEXEC +#define CLOSE_RANGE_CLOEXEC (1u << 2) +#endif + +#endif /* __linux__ */ |