Skip to content

Commit

Permalink
stream: autodetect direction
Browse files Browse the repository at this point in the history
Previously, we required the user to specify the expected read/write flags
for a pipe or tty. But we've already been asking the OS to tell us
what they actually are (fcntl F_GETFL), so we can hopefully just use that
information directly.

Fix libuv#1936
  • Loading branch information
vtjnash committed Aug 28, 2018
1 parent 90891b4 commit 7d08ef8
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 31 deletions.
20 changes: 17 additions & 3 deletions src/unix/pipe.c
Original file line number Diff line number Diff line change
Expand Up @@ -132,11 +132,21 @@ void uv__pipe_close(uv_pipe_t* handle) {


int uv_pipe_open(uv_pipe_t* handle, uv_file fd) {
int flags;
int mode;
int err;
flags = 0;

if (uv__fd_exists(handle->loop, fd))
return UV_EEXIST;

do
mode = fcntl(fd, F_GETFL);
while (mode == -1 && errno == EINTR);

if (mode == -1)
return UV__ERR(errno); /* according to docs, must be EBADF */

err = uv__nonblock(fd, 1);
if (err)
return err;
Expand All @@ -147,9 +157,13 @@ int uv_pipe_open(uv_pipe_t* handle, uv_file fd) {
return err;
#endif /* defined(__APPLE__) */

return uv__stream_open((uv_stream_t*)handle,
fd,
UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
mode &= O_ACCMODE;
if (mode != O_WRONLY)
flags |= UV_HANDLE_READABLE;
if (mode != O_RDONLY)
flags |= UV_HANDLE_WRITABLE;

return uv__stream_open((uv_stream_t*)handle, fd, flags);
}


Expand Down
37 changes: 16 additions & 21 deletions src/unix/tty.c
Original file line number Diff line number Diff line change
Expand Up @@ -92,13 +92,15 @@ static int uv__tty_is_slave(const int fd) {
return result;
}

int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) {
int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int unused) {
uv_handle_type type;
int flags;
int newfd;
int r;
int saved_flags;
int mode;
char path[256];
(void)unused; /* deprecated parameter is no longer needed */

/* File descriptors that refer to files cannot be monitored with epoll.
* That restriction also applies to character devices like /dev/random
Expand All @@ -111,6 +113,15 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) {
flags = 0;
newfd = -1;

/* Save the fd flags in case we need to restore them due to an error. */
do
saved_flags = fcntl(fd, F_GETFL);
while (saved_flags == -1 && errno == EINTR);

if (saved_flags == -1)
return UV__ERR(errno);
mode = saved_flags & O_ACCMODE;

/* 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.
Expand All @@ -128,13 +139,13 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) {
* slave device.
*/
if (uv__tty_is_slave(fd) && ttyname_r(fd, path, sizeof(path)) == 0)
r = uv__open_cloexec(path, O_RDWR);
r = uv__open_cloexec(path, saved_flags & O_ACCMODE);
else
r = -1;

if (r < 0) {
/* fallback to using blocking writes */
if (!readable)
if (mode != O_RDONLY)
flags |= UV_HANDLE_BLOCKING_WRITES;
goto skip;
}
Expand All @@ -154,22 +165,6 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) {
fd = newfd;
}

#if defined(__APPLE__)
/* Save the fd flags in case we need to restore them due to an error. */
do
saved_flags = fcntl(fd, F_GETFL);
while (saved_flags == -1 && errno == EINTR);

if (saved_flags == -1) {
if (newfd != -1)
uv__close(newfd);
return UV__ERR(errno);
}
#endif

/* Pacify the compiler. */
(void) &saved_flags;

skip:
uv__stream_init(loop, (uv_stream_t*) tty, UV_TTY);

Expand All @@ -194,9 +189,9 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) {
}
#endif

if (readable)
if (mode != O_WRONLY)
flags |= UV_HANDLE_READABLE;
else
if (mode != O_RDONLY)
flags |= UV_HANDLE_WRITABLE;

uv__stream_open((uv_stream_t*) tty, fd, flags);
Expand Down
12 changes: 5 additions & 7 deletions src/win/tty.c
Original file line number Diff line number Diff line change
Expand Up @@ -172,9 +172,12 @@ void uv_console_init(void) {
}


int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int readable) {
int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int unused) {
BOOL readable;
DWORD NumberOfEvents;
HANDLE handle;
CONSOLE_SCREEN_BUFFER_INFO screen_buffer_info;
(void)unused;

uv__once_init();
handle = (HANDLE) uv__get_osfhandle(fd);
Expand All @@ -199,6 +202,7 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int readable) {
fd = -1;
}

readable = GetNumberOfConsoleInputEvents(handle, &NumberOfEvents);
if (!readable) {
/* Obtain the screen buffer info with the output handle. */
if (!GetConsoleScreenBufferInfo(handle, &screen_buffer_info)) {
Expand Down Expand Up @@ -382,12 +386,6 @@ int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) {
}


int uv_is_tty(uv_file file) {
DWORD result;
return GetConsoleMode((HANDLE) _get_osfhandle(file), &result) != 0;
}


int uv_tty_get_winsize(uv_tty_t* tty, int* width, int* height) {
CONSOLE_SCREEN_BUFFER_INFO info;

Expand Down

0 comments on commit 7d08ef8

Please sign in to comment.