unix: open ttyname instead of /dev/tty
Find the real name of the tty using ttyname_r(3) instead of opening "/dev/tty" which causes trouble if the fd doesn't point to the controlling terminal. PR-URL: https://github.com/libuv/libuv/pull/779 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Saúl Ibarra Corretgé <saghul@gmail.com>
This commit is contained in:
parent
643c9e9c32
commit
387102b247
@ -129,6 +129,7 @@ EXTRA_DIST = test/fixtures/empty_file \
|
||||
TESTS = test/run-tests
|
||||
check_PROGRAMS = test/run-tests
|
||||
test_run_tests_CFLAGS =
|
||||
test_run_tests_LDFLAGS =
|
||||
test_run_tests_SOURCES = test/blackhole-server.c \
|
||||
test/dns-server.c \
|
||||
test/echo-server.c \
|
||||
@ -303,15 +304,18 @@ libuv_la_SOURCES += src/unix/darwin.c \
|
||||
src/unix/fsevents.c \
|
||||
src/unix/kqueue.c \
|
||||
src/unix/proctitle.c
|
||||
test_run_tests_LDFLAGS += -lutil
|
||||
endif
|
||||
|
||||
if DRAGONFLY
|
||||
include_HEADERS += include/uv-bsd.h
|
||||
test_run_tests_LDFLAGS += -lutil
|
||||
endif
|
||||
|
||||
if FREEBSD
|
||||
include_HEADERS += include/uv-bsd.h
|
||||
libuv_la_SOURCES += src/unix/freebsd.c src/unix/kqueue.c
|
||||
test_run_tests_LDFLAGS += -lutil
|
||||
endif
|
||||
|
||||
if LINUX
|
||||
@ -322,16 +326,19 @@ libuv_la_SOURCES += src/unix/linux-core.c \
|
||||
src/unix/linux-syscalls.c \
|
||||
src/unix/linux-syscalls.h \
|
||||
src/unix/proctitle.c
|
||||
test_run_tests_LDFLAGS += -lutil
|
||||
endif
|
||||
|
||||
if NETBSD
|
||||
include_HEADERS += include/uv-bsd.h
|
||||
libuv_la_SOURCES += src/unix/kqueue.c src/unix/netbsd.c
|
||||
test_run_tests_LDFLAGS += -lutil
|
||||
endif
|
||||
|
||||
if OPENBSD
|
||||
include_HEADERS += include/uv-bsd.h
|
||||
libuv_la_SOURCES += src/unix/kqueue.c src/unix/openbsd.c
|
||||
test_run_tests_LDFLAGS += -lutil
|
||||
endif
|
||||
|
||||
if SUNOS
|
||||
|
||||
@ -58,14 +58,22 @@ API
|
||||
`readable`, specifies if you plan on calling :c:func:`uv_read_start` with
|
||||
this stream. stdin is readable, stdout is not.
|
||||
|
||||
On Unix this function will try to open ``/dev/tty`` and use it if the passed
|
||||
file descriptor refers to a TTY. This lets libuv put the tty in non-blocking
|
||||
mode without affecting other processes that share the tty.
|
||||
On Unix this function will determine the path of the fd of the terminal
|
||||
using :man:`ttyname_r(3)`, open it, and use it if the passed file descriptor
|
||||
refers to a TTY. This lets libuv put the tty in non-blocking mode without
|
||||
affecting other processes that share the tty.
|
||||
|
||||
This function is not thread safe on systems that don't support
|
||||
ioctl TIOCGPTN or TIOCPTYGNAME, for instance OpenBSD and Solaris.
|
||||
|
||||
.. note::
|
||||
If opening ``/dev/tty`` fails, libuv falls back to blocking writes for
|
||||
If reopening the TTY fails, libuv falls back to blocking writes for
|
||||
non-readable TTY streams.
|
||||
|
||||
.. versionchanged:: 1.9.0: the path of the TTY is determined by
|
||||
:man:`ttyname_r(3)`. In earlier versions libuv opened
|
||||
`/dev/tty` instead.
|
||||
|
||||
.. versionchanged:: 1.5.0: trying to initialize a TTY stream with a file
|
||||
descriptor that refers to a file returns `UV_EINVAL`
|
||||
on UNIX.
|
||||
|
||||
@ -23,6 +23,7 @@
|
||||
#include "internal.h"
|
||||
#include "spinlock.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <unistd.h>
|
||||
#include <termios.h>
|
||||
@ -33,12 +34,30 @@ static int orig_termios_fd = -1;
|
||||
static struct termios orig_termios;
|
||||
static uv_spinlock_t termios_spinlock = UV_SPINLOCK_INITIALIZER;
|
||||
|
||||
static int uv__tty_is_slave(const int fd) {
|
||||
int result;
|
||||
#if defined(__linux__) || defined(__FreeBSD__)
|
||||
int dummy;
|
||||
|
||||
result = ioctl(fd, TIOCGPTN, &dummy) != 0;
|
||||
#elif defined(__APPLE__)
|
||||
char dummy[256];
|
||||
|
||||
result = ioctl(fd, TIOCPTYGNAME, &dummy) != 0;
|
||||
#else
|
||||
/* Fallback to ptsname
|
||||
*/
|
||||
result = ptsname(fd) == NULL;
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) {
|
||||
uv_handle_type type;
|
||||
int flags;
|
||||
int newfd;
|
||||
int r;
|
||||
char path[256];
|
||||
|
||||
/* File descriptors that refer to files cannot be monitored with epoll.
|
||||
* That restriction also applies to character devices like /dev/random
|
||||
@ -62,7 +81,15 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) {
|
||||
* other processes.
|
||||
*/
|
||||
if (type == UV_TTY) {
|
||||
r = uv__open_cloexec("/dev/tty", O_RDWR);
|
||||
/* Reopening a pty in master mode won't work either because the reopened
|
||||
* pty will be in slave mode (*BSD) or reopening will allocate a new
|
||||
* master/slave pair (Linux). Therefore check if the fd points to a
|
||||
* slave device.
|
||||
*/
|
||||
if (uv__tty_is_slave(fd) && ttyname_r(fd, path, sizeof(path)) == 0)
|
||||
r = uv__open_cloexec(path, O_RDWR);
|
||||
else
|
||||
r = -1;
|
||||
|
||||
if (r < 0) {
|
||||
/* fallback to using blocking writes */
|
||||
|
||||
@ -44,6 +44,7 @@ TEST_DECLARE (semaphore_2)
|
||||
TEST_DECLARE (semaphore_3)
|
||||
TEST_DECLARE (tty)
|
||||
TEST_DECLARE (tty_file)
|
||||
TEST_DECLARE (tty_pty)
|
||||
TEST_DECLARE (stdio_over_pipes)
|
||||
TEST_DECLARE (ip6_pton)
|
||||
TEST_DECLARE (ipc_listen_before_write)
|
||||
@ -387,6 +388,7 @@ TASK_LIST_START
|
||||
TEST_ENTRY (pipe_set_non_blocking)
|
||||
TEST_ENTRY (tty)
|
||||
TEST_ENTRY (tty_file)
|
||||
TEST_ENTRY (tty_pty)
|
||||
TEST_ENTRY (stdio_over_pipes)
|
||||
TEST_ENTRY (ip6_pton)
|
||||
TEST_ENTRY (ipc_listen_before_write)
|
||||
|
||||
@ -28,6 +28,13 @@
|
||||
#else /* Unix */
|
||||
# include <fcntl.h>
|
||||
# include <unistd.h>
|
||||
# if defined(__linux__)
|
||||
# include <pty.h>
|
||||
# elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__)
|
||||
# include <util.h>
|
||||
# elif defined(__FreeBSD__) || defined(__DragonFly__)
|
||||
# include <libutil.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
@ -182,3 +189,35 @@ TEST_IMPL(tty_file) {
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
TEST_IMPL(tty_pty) {
|
||||
# if defined(__linux__) || defined(__OpenBSD__) || defined(__NetBSD__) || \
|
||||
defined(__APPLE__) || defined(__FreeBSD__) || defined(__DragonFly__)
|
||||
int master_fd, slave_fd;
|
||||
struct winsize w;
|
||||
uv_loop_t loop;
|
||||
uv_tty_t master_tty, slave_tty;
|
||||
|
||||
ASSERT(0 == uv_loop_init(&loop));
|
||||
|
||||
ASSERT(0 == openpty(&master_fd, &slave_fd, NULL, NULL, &w));
|
||||
ASSERT(0 == uv_tty_init(&loop, &slave_tty, slave_fd, 0));
|
||||
ASSERT(0 == uv_tty_init(&loop, &master_tty, master_fd, 0));
|
||||
/* Check if the file descriptor was reopened. If it is,
|
||||
* UV_STREAM_BLOCKING (value 0x80) isn't set on flags.
|
||||
*/
|
||||
ASSERT(0 == (slave_tty.flags & 0x80));
|
||||
/* The master_fd of a pty should never be reopened.
|
||||
*/
|
||||
ASSERT(master_tty.flags & 0x80);
|
||||
ASSERT(0 == close(slave_fd));
|
||||
uv_close((uv_handle_t*) &slave_tty, NULL);
|
||||
ASSERT(0 == close(master_fd));
|
||||
uv_close((uv_handle_t*) &master_tty, NULL);
|
||||
|
||||
ASSERT(0 == uv_run(&loop, UV_RUN_DEFAULT));
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user