diff --git a/src/lib/shell/pipe_exec/streams.rs b/src/lib/shell/pipe_exec/streams.rs index 4e6813874cfa026906c873e44311cfde97de645e..626c017de32a9dd419813c1d32b2d79f3147b33d 100644 --- a/src/lib/shell/pipe_exec/streams.rs +++ b/src/lib/shell/pipe_exec/streams.rs @@ -13,14 +13,13 @@ pub(crate) fn redir(old: RawFd, new: RawFd) { /// Duplicates STDIN, STDOUT, and STDERR; in that order; and returns them as `File`s. /// Why, you ask? A simple safety mechanism to ensure that the duplicated FDs are closed /// when dropped. -pub(crate) fn duplicate_streams() -> io::Result<(File, File, File)> { - // Duplicates STDIN and converts it into a `File`. - sys::dup(sys::STDIN_FILENO).map(|fd| unsafe { File::from_raw_fd(fd) }) - // Do the same for stdout, and then meld the result with stdin - .and_then(|stdin| sys::dup(sys::STDOUT_FILENO) - .map(|fd| unsafe { File::from_raw_fd(fd) }) - .map(|stdout| (stdin, stdout)) - ) +pub(crate) fn duplicate_streams() -> io::Result<(Option<File>, File, File)> { + // STDIN may have been closed for a background shell, so it is ok if it cannot be duplicated. + let stdin = sys::dup(sys::STDIN_FILENO).ok().map(|fd| unsafe { File::from_raw_fd(fd) }); + + sys::dup(sys::STDOUT_FILENO) + .map(|fd| unsafe { File::from_raw_fd(fd) }) + .map(|stdout| (stdin, stdout)) // And then meld stderr alongside stdin and stdout .and_then(|(stdin, stdout)| sys::dup(sys::STDERR_FILENO) .map(|fd| unsafe { File::from_raw_fd(fd) }) @@ -28,8 +27,10 @@ pub(crate) fn duplicate_streams() -> io::Result<(File, File, File)> { ) } -pub(crate) fn redirect_streams(inp: File, out: File, err: File) { - redir(inp.as_raw_fd(), sys::STDIN_FILENO); +pub(crate) fn redirect_streams(inp: Option<File>, out: File, err: File) { + if let Some(inp) = inp { + redir(inp.as_raw_fd(), sys::STDIN_FILENO); + } redir(out.as_raw_fd(), sys::STDOUT_FILENO); redir(err.as_raw_fd(), sys::STDERR_FILENO); }