ext/libuv/src/unix/tty.c in libuv-2.0.8 vs ext/libuv/src/unix/tty.c in libuv-2.0.9
- old
+ new
@@ -21,26 +21,46 @@
#include "uv.h"
#include "internal.h"
#include "spinlock.h"
+#include <stdlib.h>
#include <assert.h>
#include <unistd.h>
#include <termios.h>
#include <errno.h>
#include <sys/ioctl.h>
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;
+ int saved_flags;
+ char path[256];
/* File descriptors that refer to files cannot be monitored with epoll.
* That restriction also applies to character devices like /dev/random
* (but obviously not /dev/tty.)
*/
@@ -60,11 +80,19 @@
* 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 (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 */
if (!readable)
flags |= UV_STREAM_BLOCKING;
@@ -84,35 +112,55 @@
}
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 -errno;
+ }
+#endif
+
+ /* Pacify the compiler. */
+ (void) &saved_flags;
+
skip:
uv__stream_init(loop, (uv_stream_t*) tty, UV_TTY);
/* If anything fails beyond this point we need to remove the handle from
* the handle queue, since it was added by uv__handle_init in uv_stream_init.
*/
+ if (!(flags & UV_STREAM_BLOCKING))
+ uv__nonblock(fd, 1);
+
#if defined(__APPLE__)
r = uv__stream_try_select((uv_stream_t*) tty, &fd);
if (r) {
+ int rc = r;
if (newfd != -1)
uv__close(newfd);
QUEUE_REMOVE(&tty->handle_queue);
- return r;
+ do
+ r = fcntl(fd, F_SETFL, saved_flags);
+ while (r == -1 && errno == EINTR);
+ return rc;
}
#endif
if (readable)
flags |= UV_STREAM_READABLE;
else
flags |= UV_STREAM_WRITABLE;
- if (!(flags & UV_STREAM_BLOCKING))
- uv__nonblock(fd, 1);
-
uv__stream_open((uv_stream_t*) tty, fd, flags);
tty->mode = UV_TTY_MODE_NORMAL;
return 0;
}
@@ -239,17 +287,17 @@
if (type == SOCK_DGRAM)
if (sa.sa_family == AF_INET || sa.sa_family == AF_INET6)
return UV_UDP;
if (type == SOCK_STREAM) {
-#if defined(_AIX)
- /* on AIX the getsockname call returns an empty sa structure
+#if defined(_AIX) || defined(__DragonFly__)
+ /* on AIX/DragonFly the getsockname call returns an empty sa structure
* for sockets of type AF_UNIX. For all other types it will
* return a properly filled in structure.
*/
if (len == 0)
return UV_NAMED_PIPE;
-#endif /* defined(_AIX) */
+#endif /* defined(_AIX) || defined(__DragonFly__) */
if (sa.sa_family == AF_INET || sa.sa_family == AF_INET6)
return UV_TCP;
if (sa.sa_family == AF_UNIX)
return UV_NAMED_PIPE;