Skip to content

Commit 9a7b1f2

Browse files
committed
Only set_blocking only on OwnedFd
Do not `set_blocking` on `StdioImpl::inherit` as we do not own them and also do not `set_blocking` on `Stdio` constructed using `FromRawFd::from_raw_fd` Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com>
1 parent c689253 commit 9a7b1f2

File tree

3 files changed

+50
-43
lines changed

3 files changed

+50
-43
lines changed

src/native_mux_impl/command.rs

Lines changed: 1 addition & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use super::Error;
22
use super::RemoteChild;
3-
use super::{stdio::set_blocking, ChildStderr, ChildStdin, ChildStdout, Stdio};
3+
use super::{ChildStderr, ChildStdin, ChildStdout, Stdio};
44

55
use std::borrow::Cow;
66
use std::ffi::OsStr;
@@ -71,27 +71,6 @@ impl Command {
7171
stderr.as_raw_fd_or_null_fd()?,
7272
];
7373

74-
let is_inherited = [
75-
self.stdin_v.is_inherited(),
76-
self.stdout_v.is_inherited(),
77-
self.stderr_v.is_inherited(),
78-
];
79-
80-
stdios
81-
.into_iter()
82-
.zip(is_inherited)
83-
.filter_map(|(stdio, is_inherited)| if !is_inherited { Some(stdio) } else { None })
84-
// Note that once we do this, these file descriptors
85-
// (and the Fds we got them from above) should no longer be used in
86-
// any async context, as they'd start blocking.
87-
//
88-
// We give away the descriptors in stdios when we pass them to
89-
// open_new_session (which doesn't use them in an async context),
90-
// and the Fds are dropped when this function returns, meaning no
91-
// owned file descriptors we set to be blocking here can be used in
92-
// an async context in the future.
93-
.try_for_each(|stdio| set_blocking(stdio).map_err(Error::ChildIo))?;
94-
9574
let cmd = NonZeroByteSlice::new(&self.cmd).ok_or(Error::InvalidCommand)?;
9675

9776
let session = Session::builder()

src/native_mux_impl/stdio.rs

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ fn cvt(ret: c_int) -> io::Result<c_int> {
4242
}
4343
}
4444

45-
pub(super) fn set_blocking(fd: RawFd) -> io::Result<()> {
45+
fn set_blocking(fd: RawFd) -> io::Result<()> {
4646
let flags = cvt(unsafe { fcntl(fd, F_GETFL) })?;
4747
cvt(unsafe { fcntl(fd, F_SETFL, flags & (!O_NONBLOCK)) })?;
4848

@@ -64,14 +64,21 @@ impl Fd {
6464
///
6565
/// `T::into_raw_fd` must return a valid fd and transfers
6666
/// the ownershipt of it.
67-
unsafe fn new_owned<T: IntoRawFd>(fd: T) -> Self {
67+
unsafe fn new_owned<T: IntoRawFd>(fd: T) -> Result<Self, Error> {
6868
let raw_fd = fd.into_raw_fd();
69-
Fd::Owned(OwnedFd::from_raw_fd(raw_fd))
69+
// Create owned_fd so that the fd will be closed on error
70+
let owned_fd = OwnedFd::from_raw_fd(raw_fd);
71+
72+
set_blocking(raw_fd).map_err(Error::ChildIo)?;
73+
74+
Ok(Fd::Owned(owned_fd))
7075
}
7176
}
7277

73-
impl From<PipeRead> for Fd {
74-
fn from(pipe_read: PipeRead) -> Self {
78+
impl TryFrom<PipeRead> for Fd {
79+
type Error = Error;
80+
81+
fn try_from(pipe_read: PipeRead) -> Result<Self, Error> {
7582
// Safety:
7683
//
7784
// PipeRead::into_raw_fd returns a valid fd and transfers the
@@ -80,8 +87,10 @@ impl From<PipeRead> for Fd {
8087
}
8188
}
8289

83-
impl From<PipeWrite> for Fd {
84-
fn from(pipe_write: PipeWrite) -> Self {
90+
impl TryFrom<PipeWrite> for Fd {
91+
type Error = Error;
92+
93+
fn try_from(pipe_write: PipeWrite) -> Result<Self, Error> {
8594
// Safety:
8695
//
8796
// PipeWrite::into_raw_fd returns a valid fd and transfers the
@@ -97,9 +106,15 @@ impl Stdio {
97106
StdioImpl::Null => Ok((Fd::Null, None)),
98107
StdioImpl::Pipe => {
99108
let (read, write) = create_pipe()?;
100-
Ok((read.into(), Some(write)))
109+
Ok((read.try_into()?, Some(write)))
110+
}
111+
StdioImpl::Fd(fd, owned) => {
112+
let raw_fd = fd.as_raw_fd();
113+
if *owned {
114+
set_blocking(raw_fd).map_err(Error::ChildIo)?;
115+
}
116+
Ok((Fd::Borrowed(raw_fd), None))
101117
}
102-
StdioImpl::Fd(fd) => Ok((Fd::Borrowed(fd.as_raw_fd()), None)),
103118
}
104119
}
105120

@@ -109,9 +124,15 @@ impl Stdio {
109124
StdioImpl::Null => Ok((Fd::Null, None)),
110125
StdioImpl::Pipe => {
111126
let (read, write) = create_pipe()?;
112-
Ok((write.into(), Some(read)))
127+
Ok((write.try_into()?, Some(read)))
128+
}
129+
StdioImpl::Fd(fd, owned) => {
130+
let raw_fd = fd.as_raw_fd();
131+
if *owned {
132+
set_blocking(raw_fd).map_err(Error::ChildIo)?;
133+
}
134+
Ok((Fd::Borrowed(raw_fd), None))
113135
}
114-
StdioImpl::Fd(fd) => Ok((Fd::Borrowed(fd.as_raw_fd()), None)),
115136
}
116137
}
117138

src/stdio.rs

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ pub(crate) enum StdioImpl {
1818
/// Read/Write to a newly created pipe
1919
Pipe,
2020
/// Read/Write to custom fd
21-
Fd(OwnedFd),
21+
Fd(OwnedFd, bool),
2222
/// Inherit stdin/stdout/stderr
2323
Inherit,
2424
}
@@ -40,18 +40,23 @@ impl Stdio {
4040
}
4141

4242
/// The child inherits from the corresponding parent descriptor.
43+
///
44+
/// NOTE that the stdio fd must be in blocking mode, otherwise
45+
/// ssh might not flush all output since it considers
46+
/// (`EAGAIN`/`EWOULDBLOCK`) as an error
4347
pub const fn inherit() -> Self {
4448
Self(StdioImpl::Inherit)
4549
}
46-
47-
#[cfg(feature = "native-mux")]
48-
pub(super) fn is_inherited(&self) -> bool {
49-
matches!(self.0, StdioImpl::Inherit)
50-
}
5150
}
51+
/// FromRawFd takes ownership of the fd passed in
52+
/// and closes the fd on drop.
53+
///
54+
/// NOTE that the fd must be in blocking mode, otherwise
55+
/// ssh might not flush all output since it considers
56+
/// (`EAGAIN`/`EWOULDBLOCK`) as an error
5257
impl FromRawFd for Stdio {
5358
unsafe fn from_raw_fd(fd: RawFd) -> Self {
54-
Self(StdioImpl::Fd(OwnedFd::from_raw_fd(fd)))
59+
Self(StdioImpl::Fd(OwnedFd::from_raw_fd(fd), false))
5560
}
5661
}
5762
impl From<Stdio> for process::Stdio {
@@ -64,14 +69,16 @@ impl From<Stdio> for process::Stdio {
6469
// safety: StdioImpl(fd) is only constructed from known-valid and
6570
// owned file descriptors by virtue of the safety requirement
6671
// for invoking from_raw_fd.
67-
StdioImpl::Fd(fd) => unsafe { process::Stdio::from_raw_fd(IntoRawFd::into_raw_fd(fd)) },
72+
StdioImpl::Fd(fd, _) => unsafe {
73+
process::Stdio::from_raw_fd(IntoRawFd::into_raw_fd(fd))
74+
},
6875
}
6976
}
7077
}
7178

7279
impl From<OwnedFd> for Stdio {
7380
fn from(fd: OwnedFd) -> Self {
74-
Self(StdioImpl::Fd(fd))
81+
Self(StdioImpl::Fd(fd, true))
7582
}
7683
}
7784

@@ -82,7 +89,7 @@ macro_rules! impl_from_for_stdio {
8289
let fd = arg.into_raw_fd();
8390
// safety: $type must have a valid into_raw_fd implementation
8491
// and must not be RawFd.
85-
unsafe { Self::from_raw_fd(fd) }
92+
Self(StdioImpl::Fd(unsafe { OwnedFd::from_raw_fd(fd) }, true))
8693
}
8794
}
8895
};

0 commit comments

Comments
 (0)