about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2013-11-07 15:24:30 -0800
committerAlex Crichton <alex@alexcrichton.com>2013-11-10 01:37:11 -0800
commitb652bbc6700e36c9ad80105c89d7fc2e3afec111 (patch)
treed204a6217cfb8dbc41fdc44346a779ee60665924
parentdf4c0b8e4349d50f317553de5a47d0cd56cdc227 (diff)
downloadrust-b652bbc6700e36c9ad80105c89d7fc2e3afec111.tar.gz
rust-b652bbc6700e36c9ad80105c89d7fc2e3afec111.zip
Fall back from uv tty instances more aggressively
It appears that uv's support for interacting with a stdio stream as a tty when
it's actually a pipe is pretty problematic. To get around this, promote a check
to see if the stream is a tty to the top of the tty constructor, and bail out
quickly if it's not identified as a tty.

Closes #10237
-rw-r--r--src/librustuv/tty.rs20
-rw-r--r--src/librustuv/uvll.rs2
-rw-r--r--src/libstd/rt/io/stdio.rs6
-rw-r--r--src/libstd/rt/rtio.rs1
4 files changed, 19 insertions, 10 deletions
diff --git a/src/librustuv/tty.rs b/src/librustuv/tty.rs
index 04e406ce987..4853973f1a3 100644
--- a/src/librustuv/tty.rs
+++ b/src/librustuv/tty.rs
@@ -30,8 +30,22 @@ impl TtyWatcher {
     pub fn new(loop_: &Loop, fd: libc::c_int, readable: bool)
         -> Result<TtyWatcher, UvError>
     {
-        let handle = UvHandle::alloc(None::<TtyWatcher>, uvll::UV_TTY);
+        // libuv may succeed in giving us a handle (via uv_tty_init), but if the
+        // handle isn't actually connected to a terminal there are frequently
+        // many problems in using it with libuv. To get around this, always
+        // return a failure if the specified file descriptor isn't actually a
+        // TTY.
+        //
+        // Related:
+        // - https://github.com/joyent/libuv/issues/982
+        // - https://github.com/joyent/libuv/issues/988
+        if unsafe { uvll::guess_handle(fd) != uvll::UV_TTY as libc::c_int } {
+            return Err(UvError(uvll::EBADF));
+        }
 
+        // If this file descriptor is indeed guessed to be a tty, then go ahead
+        // with attempting to open it as a tty.
+        let handle = UvHandle::alloc(None::<TtyWatcher>, uvll::UV_TTY);
         match unsafe {
             uvll::uv_tty_init(loop_.handle, handle, fd as libc::c_int,
                               readable as libc::c_int)
@@ -86,10 +100,6 @@ impl RtioTTY for TtyWatcher {
             n => Err(uv_error_to_io_error(UvError(n)))
         }
     }
-
-    fn isatty(&self) -> bool {
-        unsafe { uvll::guess_handle(self.fd) == uvll::UV_TTY as libc::c_int }
-    }
 }
 
 impl UvHandle<uvll::uv_tty_t> for TtyWatcher {
diff --git a/src/librustuv/uvll.rs b/src/librustuv/uvll.rs
index d009201e840..58d182a22c3 100644
--- a/src/librustuv/uvll.rs
+++ b/src/librustuv/uvll.rs
@@ -54,6 +54,7 @@ pub mod errors {
     pub static EPIPE: c_int = -4048;
     pub static ECONNABORTED: c_int = -4080;
     pub static ECANCELED: c_int = -4082;
+    pub static EBADF: c_int = -4084;
 }
 #[cfg(not(windows))]
 pub mod errors {
@@ -67,6 +68,7 @@ pub mod errors {
     pub static EPIPE: c_int = -libc::EPIPE;
     pub static ECONNABORTED: c_int = -libc::ECONNABORTED;
     pub static ECANCELED : c_int = -libc::ECANCELED;
+    pub static EBADF : c_int = -libc::EBADF;
 }
 
 pub static PROCESS_SETUID: c_int = 1 << 0;
diff --git a/src/libstd/rt/io/stdio.rs b/src/libstd/rt/io/stdio.rs
index d33821a34b1..674b34639bc 100644
--- a/src/libstd/rt/io/stdio.rs
+++ b/src/libstd/rt/io/stdio.rs
@@ -277,12 +277,10 @@ impl StdWriter {
         }
     }
 
-    /// Returns whether this tream is attached to a TTY instance or not.
-    ///
-    /// This is similar to libc's isatty() function
+    /// Returns whether this stream is attached to a TTY instance or not.
     pub fn isatty(&self) -> bool {
         match self.inner {
-            TTY(ref tty) => tty.isatty(),
+            TTY(*) => true,
             File(*) => false,
         }
     }
diff --git a/src/libstd/rt/rtio.rs b/src/libstd/rt/rtio.rs
index 1e12da8645c..d623914cdad 100644
--- a/src/libstd/rt/rtio.rs
+++ b/src/libstd/rt/rtio.rs
@@ -222,7 +222,6 @@ pub trait RtioTTY {
     fn write(&mut self, buf: &[u8]) -> Result<(), IoError>;
     fn set_raw(&mut self, raw: bool) -> Result<(), IoError>;
     fn get_winsize(&mut self) -> Result<(int, int), IoError>;
-    fn isatty(&self) -> bool;
 }
 
 pub trait PausibleIdleCallback {