unix: reopen tty as /dev/tty
Reopen the file descriptor when it refers to a tty. This lets us put the tty in non-blocking mode without affecting other processes that share it with us. This brings back commit31f9fbc, which was reverted in20bb1bf. The OSX select trick is working now. Original patch by @bnoordhuis
This commit is contained in:
parent
daa457b1c0
commit
b197515367
105
src/unix/core.c
105
src/unix/core.c
@ -59,12 +59,15 @@
|
||||
# include <sys/filio.h>
|
||||
# include <sys/ioctl.h>
|
||||
# include <sys/wait.h>
|
||||
#endif
|
||||
|
||||
#if __FreeBSD__ >= 10
|
||||
# define uv__accept4 accept4
|
||||
# define UV__SOCK_NONBLOCK SOCK_NONBLOCK
|
||||
# define UV__SOCK_CLOEXEC SOCK_CLOEXEC
|
||||
# define UV__O_CLOEXEC O_CLOEXEC
|
||||
# if __FreeBSD__ >= 10
|
||||
# define uv__accept4 accept4
|
||||
# define UV__SOCK_NONBLOCK SOCK_NONBLOCK
|
||||
# define UV__SOCK_CLOEXEC SOCK_CLOEXEC
|
||||
# endif
|
||||
# if !defined(F_DUP2FD_CLOEXEC) && defined(_F_DUP2FD_CLOEXEC)
|
||||
# define F_DUP2FD_CLOEXEC _F_DUP2FD_CLOEXEC
|
||||
# endif
|
||||
#endif
|
||||
|
||||
static void uv__run_pending(uv_loop_t* loop);
|
||||
@ -821,3 +824,93 @@ int uv_getrusage(uv_rusage_t* rusage) {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv__open_cloexec(const char* path, int flags) {
|
||||
int err;
|
||||
int fd;
|
||||
|
||||
#if defined(__linux__) || (defined(__FreeBSD__) && __FreeBSD__ >= 9)
|
||||
static int no_cloexec;
|
||||
|
||||
if (!no_cloexec) {
|
||||
fd = open(path, flags | UV__O_CLOEXEC);
|
||||
if (fd != -1)
|
||||
return fd;
|
||||
|
||||
if (errno != EINVAL)
|
||||
return -errno;
|
||||
|
||||
/* O_CLOEXEC not supported. */
|
||||
no_cloexec = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
fd = open(path, flags);
|
||||
if (fd == -1)
|
||||
return -errno;
|
||||
|
||||
err = uv__cloexec(fd, 1);
|
||||
if (err) {
|
||||
uv__close(fd);
|
||||
return err;
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
|
||||
int uv__dup2_cloexec(int oldfd, int newfd) {
|
||||
int r;
|
||||
#if defined(__FreeBSD__) && __FreeBSD__ >= 10
|
||||
do
|
||||
r = dup3(oldfd, newfd, O_CLOEXEC);
|
||||
while (r == -1 && errno == EINTR);
|
||||
if (r == -1)
|
||||
return -errno;
|
||||
return r;
|
||||
#elif defined(__FreeBSD__) && defined(F_DUP2FD_CLOEXEC)
|
||||
do
|
||||
r = fcntl(oldfd, F_DUP2FD_CLOEXEC, newfd);
|
||||
while (r == -1 && errno == EINTR);
|
||||
if (r != -1)
|
||||
return r;
|
||||
if (errno != EINVAL)
|
||||
return -errno;
|
||||
/* Fall through. */
|
||||
#elif defined(__linux__)
|
||||
static int no_dup3;
|
||||
if (!no_dup3) {
|
||||
do
|
||||
r = uv__dup3(oldfd, newfd, UV__O_CLOEXEC);
|
||||
while (r == -1 && (errno == EINTR || errno == EBUSY));
|
||||
if (r != -1)
|
||||
return r;
|
||||
if (errno != ENOSYS)
|
||||
return -errno;
|
||||
/* Fall through. */
|
||||
no_dup3 = 1;
|
||||
}
|
||||
#endif
|
||||
{
|
||||
int err;
|
||||
do
|
||||
r = dup2(oldfd, newfd);
|
||||
#if defined(__linux__)
|
||||
while (r == -1 && (errno == EINTR || errno == EBUSY));
|
||||
#else
|
||||
while (r == -1 && errno == EINTR);
|
||||
#endif
|
||||
|
||||
if (r == -1)
|
||||
return -errno;
|
||||
|
||||
err = uv__cloexec(newfd, 1);
|
||||
if (err) {
|
||||
uv__close(newfd);
|
||||
return err;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
@ -189,6 +189,8 @@ int uv__stream_try_select(uv_stream_t* stream, int* fd);
|
||||
#endif /* defined(__APPLE__) */
|
||||
void uv__server_io(uv_loop_t* loop, uv__io_t* w, unsigned int events);
|
||||
int uv__accept(int sockfd);
|
||||
int uv__dup2_cloexec(int oldfd, int newfd);
|
||||
int uv__open_cloexec(const char* path, int flags);
|
||||
|
||||
/* tcp */
|
||||
int uv_tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb);
|
||||
|
||||
@ -219,6 +219,16 @@
|
||||
# endif
|
||||
#endif /* __NR_pwritev */
|
||||
|
||||
#ifndef __NR_dup3
|
||||
# if defined(__x86_64__)
|
||||
# define __NR_dup3 292
|
||||
# elif defined(__i386__)
|
||||
# define __NR_dup3 330
|
||||
# elif defined(__arm__)
|
||||
# define __NR_dup3 (UV_SYSCALL_BASE + 358)
|
||||
# endif
|
||||
#endif /* __NR_pwritev */
|
||||
|
||||
|
||||
int uv__accept4(int fd, struct sockaddr* addr, socklen_t* addrlen, int flags) {
|
||||
#if defined(__i386__)
|
||||
@ -407,6 +417,7 @@ int uv__utimesat(int dirfd,
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
ssize_t uv__preadv(int fd, const struct iovec *iov, int iovcnt, off_t offset) {
|
||||
#if defined(__NR_preadv)
|
||||
return syscall(__NR_preadv, fd, iov, iovcnt, offset);
|
||||
@ -415,6 +426,7 @@ ssize_t uv__preadv(int fd, const struct iovec *iov, int iovcnt, off_t offset) {
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
ssize_t uv__pwritev(int fd, const struct iovec *iov, int iovcnt, off_t offset) {
|
||||
#if defined(__NR_pwritev)
|
||||
return syscall(__NR_pwritev, fd, iov, iovcnt, offset);
|
||||
@ -422,3 +434,12 @@ ssize_t uv__pwritev(int fd, const struct iovec *iov, int iovcnt, off_t offset) {
|
||||
return errno = ENOSYS, -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int uv__dup3(int oldfd, int newfd, int flags) {
|
||||
#if defined(__NR_dup3)
|
||||
return syscall(__NR_dup3, oldfd, newfd, flags);
|
||||
#else
|
||||
return errno = ENOSYS, -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -149,5 +149,6 @@ int uv__utimesat(int dirfd,
|
||||
int flags);
|
||||
ssize_t uv__preadv(int fd, const struct iovec *iov, int iovcnt, off_t offset);
|
||||
ssize_t uv__pwritev(int fd, const struct iovec *iov, int iovcnt, off_t offset);
|
||||
int uv__dup3(int oldfd, int newfd, int flags);
|
||||
|
||||
#endif /* UV_LINUX_SYSCALL_H_ */
|
||||
|
||||
@ -63,36 +63,6 @@ static void uv__stream_io(uv_loop_t* loop, uv__io_t* w, unsigned int events);
|
||||
static size_t uv__write_req_size(uv_write_t* req);
|
||||
|
||||
|
||||
/* Used by the accept() EMFILE party trick. */
|
||||
static int uv__open_cloexec(const char* path, int flags) {
|
||||
int err;
|
||||
int fd;
|
||||
|
||||
#if defined(__linux__)
|
||||
fd = open(path, flags | UV__O_CLOEXEC);
|
||||
if (fd != -1)
|
||||
return fd;
|
||||
|
||||
if (errno != EINVAL)
|
||||
return -errno;
|
||||
|
||||
/* O_CLOEXEC not supported. */
|
||||
#endif
|
||||
|
||||
fd = open(path, flags);
|
||||
if (fd == -1)
|
||||
return -errno;
|
||||
|
||||
err = uv__cloexec(fd, 1);
|
||||
if (err) {
|
||||
uv__close(fd);
|
||||
return err;
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
|
||||
static size_t uv_count_bufs(const uv_buf_t bufs[], unsigned int nbufs) {
|
||||
unsigned int i;
|
||||
size_t bytes;
|
||||
|
||||
@ -35,26 +35,61 @@ static uv_spinlock_t termios_spinlock = UV_SPINLOCK_INITIALIZER;
|
||||
|
||||
|
||||
int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) {
|
||||
uv__stream_init(loop, (uv_stream_t*)tty, UV_TTY);
|
||||
int flags;
|
||||
int newfd;
|
||||
int r;
|
||||
|
||||
newfd = -1;
|
||||
|
||||
uv__stream_init(loop, (uv_stream_t*) tty, UV_TTY);
|
||||
|
||||
/* Reopen the file descriptor when it refers to a tty. This lets us put the
|
||||
* tty in non-blocking mode without affecting other processes that share it
|
||||
* with us.
|
||||
*
|
||||
* Example: `node | cat` - if we put our fd 0 in non-blocking mode, it also
|
||||
* affects fd 1 of `cat` because both file descriptors refer to the same
|
||||
* struct file in the kernel. When we reopen our fd 0, it points to a
|
||||
* different struct file, hence changing its properties doesn't affect
|
||||
* other processes.
|
||||
*/
|
||||
if (isatty(fd)) {
|
||||
newfd = uv__open_cloexec("/dev/tty", O_RDWR);
|
||||
|
||||
if (newfd == -1)
|
||||
return -errno;
|
||||
|
||||
r = uv__dup2_cloexec(newfd, fd);
|
||||
if (r < 0 && r != -EINVAL) {
|
||||
/* EINVAL means newfd == fd which could conceivably happen if another
|
||||
* thread called close(fd) between our calls to isatty() and open().
|
||||
* That's a rather unlikely event but let's handle it anyway.
|
||||
*/
|
||||
uv__close(newfd);
|
||||
return r;
|
||||
}
|
||||
|
||||
fd = newfd;
|
||||
}
|
||||
|
||||
#if defined(__APPLE__)
|
||||
{
|
||||
int err = uv__stream_try_select((uv_stream_t*) tty, &fd);
|
||||
if (err)
|
||||
return err;
|
||||
r = uv__stream_try_select((uv_stream_t*) tty, &fd);
|
||||
if (r) {
|
||||
if (newfd != -1)
|
||||
uv__close(newfd);
|
||||
return r;
|
||||
}
|
||||
#endif /* defined(__APPLE__) */
|
||||
#endif
|
||||
|
||||
if (readable) {
|
||||
uv__nonblock(fd, 1);
|
||||
uv__stream_open((uv_stream_t*)tty, fd, UV_STREAM_READABLE);
|
||||
} else {
|
||||
/* Note: writable tty we set to blocking mode. */
|
||||
uv__stream_open((uv_stream_t*)tty, fd, UV_STREAM_WRITABLE);
|
||||
tty->flags |= UV_STREAM_BLOCKING;
|
||||
}
|
||||
if (readable)
|
||||
flags = UV_STREAM_READABLE;
|
||||
else
|
||||
flags = UV_STREAM_WRITABLE;
|
||||
|
||||
uv__nonblock(fd, 1);
|
||||
uv__stream_open((uv_stream_t*) tty, fd, flags);
|
||||
tty->mode = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user