diff --git a/src/libstd/process.rs b/src/libstd/process.rs index ae9316ddd62..42d9ad81b59 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -22,11 +22,8 @@ use io::{self, Error, ErrorKind}; use path; use sync::mpsc::{channel, Receiver}; use sys::pipe::{self, AnonPipe}; -use sys::process::Command as CommandImp; -use sys::process::Process as ProcessImp; -use sys::process::ExitStatus as ExitStatusImp; -use sys::process::Stdio as StdioImp2; -use sys_common::{AsInner, AsInnerMut}; +use sys::process as imp; +use sys_common::{AsInner, AsInnerMut, FromInner}; use thread; /// Representation of a running or exited child process. @@ -52,10 +49,10 @@ use thread; /// ``` #[stable(feature = "process", since = "1.0.0")] pub struct Child { - handle: ProcessImp, + handle: imp::Process, /// None until wait() or wait_with_output() is called. - status: Option, + status: Option, /// The handle for writing to the child's stdin, if it has been captured #[stable(feature = "process", since = "1.0.0")] @@ -70,6 +67,10 @@ pub struct Child { pub stderr: Option, } +impl AsInner for Child { + fn as_inner(&self) -> &imp::Process { &self.handle } +} + /// A handle to a child procesess's stdin #[stable(feature = "process", since = "1.0.0")] pub struct ChildStdin { @@ -87,6 +88,10 @@ impl Write for ChildStdin { } } +impl AsInner for ChildStdin { + fn as_inner(&self) -> &AnonPipe { &self.inner } +} + /// A handle to a child procesess's stdout #[stable(feature = "process", since = "1.0.0")] pub struct ChildStdout { @@ -100,6 +105,10 @@ impl Read for ChildStdout { } } +impl AsInner for ChildStdout { + fn as_inner(&self) -> &AnonPipe { &self.inner } +} + /// A handle to a child procesess's stderr #[stable(feature = "process", since = "1.0.0")] pub struct ChildStderr { @@ -113,6 +122,10 @@ impl Read for ChildStderr { } } +impl AsInner for ChildStderr { + fn as_inner(&self) -> &AnonPipe { &self.inner } +} + /// The `Command` type acts as a process builder, providing fine-grained control /// over how a new process should be spawned. A default configuration can be /// generated using `Command::new(program)`, where `program` gives a path to the @@ -131,12 +144,12 @@ impl Read for ChildStderr { /// ``` #[stable(feature = "process", since = "1.0.0")] pub struct Command { - inner: CommandImp, + inner: imp::Command, // Details explained in the builder methods - stdin: Option, - stdout: Option, - stderr: Option, + stdin: Option, + stdout: Option, + stderr: Option, } impl Command { @@ -153,7 +166,7 @@ impl Command { #[stable(feature = "process", since = "1.0.0")] pub fn new>(program: S) -> Command { Command { - inner: CommandImp::new(program.as_ref()), + inner: imp::Command::new(program.as_ref()), stdin: None, stdout: None, stderr: None, @@ -210,25 +223,26 @@ impl Command { /// Configuration for the child process's stdin handle (file descriptor 0). #[stable(feature = "process", since = "1.0.0")] pub fn stdin(&mut self, cfg: Stdio) -> &mut Command { - self.stdin = Some(cfg.0); + self.stdin = Some(cfg); self } /// Configuration for the child process's stdout handle (file descriptor 1). #[stable(feature = "process", since = "1.0.0")] pub fn stdout(&mut self, cfg: Stdio) -> &mut Command { - self.stdout = Some(cfg.0); + self.stdout = Some(cfg); self } /// Configuration for the child process's stderr handle (file descriptor 2). #[stable(feature = "process", since = "1.0.0")] pub fn stderr(&mut self, cfg: Stdio) -> &mut Command { - self.stderr = Some(cfg.0); + self.stderr = Some(cfg); self } fn spawn_inner(&self, default_io: StdioImp) -> io::Result { + let default_io = Stdio(default_io); let (their_stdin, our_stdin) = try!( setup_io(self.stdin.as_ref().unwrap_or(&default_io), true) ); @@ -239,7 +253,8 @@ impl Command { setup_io(self.stderr.as_ref().unwrap_or(&default_io), false) ); - match ProcessImp::spawn(&self.inner, their_stdin, their_stdout, their_stderr) { + match imp::Process::spawn(&self.inner, their_stdin, their_stdout, + their_stderr) { Err(e) => Err(e), Ok(handle) => Ok(Child { handle: handle, @@ -256,7 +271,7 @@ impl Command { /// By default, stdin, stdout and stderr are inherited by the parent. #[stable(feature = "process", since = "1.0.0")] pub fn spawn(&mut self) -> io::Result { - self.spawn_inner(StdioImp::Inherit) + self.spawn_inner(StdioImp::Raw(imp::Stdio::Inherit)) } /// Executes the command as a child process, waiting for it to finish and @@ -279,7 +294,7 @@ impl Command { /// ``` #[stable(feature = "process", since = "1.0.0")] pub fn output(&mut self) -> io::Result { - self.spawn_inner(StdioImp::Piped).and_then(|p| p.wait_with_output()) + self.spawn_inner(StdioImp::MakePipe).and_then(|p| p.wait_with_output()) } /// Executes a command as a child process, waiting for it to finish and @@ -318,29 +333,27 @@ impl fmt::Debug for Command { } } -impl AsInner for Command { - fn as_inner(&self) -> &CommandImp { &self.inner } +impl AsInner for Command { + fn as_inner(&self) -> &imp::Command { &self.inner } } -impl AsInnerMut for Command { - fn as_inner_mut(&mut self) -> &mut CommandImp { &mut self.inner } +impl AsInnerMut for Command { + fn as_inner_mut(&mut self) -> &mut imp::Command { &mut self.inner } } -fn setup_io(io: &StdioImp, readable: bool) - -> io::Result<(StdioImp2, Option)> +fn setup_io(io: &Stdio, readable: bool) + -> io::Result<(imp::Stdio, Option)> { - use self::StdioImp::*; - Ok(match *io { - Null => (StdioImp2::None, None), - Inherit => (StdioImp2::Inherit, None), - Piped => { + Ok(match io.0 { + StdioImp::MakePipe => { let (reader, writer) = try!(pipe::anon_pipe()); if readable { - (StdioImp2::Piped(reader), Some(writer)) + (imp::Stdio::Piped(reader), Some(writer)) } else { - (StdioImp2::Piped(writer), Some(reader)) + (imp::Stdio::Piped(writer), Some(reader)) } } + StdioImp::Raw(ref raw) => (raw.clone_if_copy(), None), }) } @@ -364,32 +377,36 @@ pub struct Output { pub struct Stdio(StdioImp); // The internal enum for stdio setup; see below for descriptions. -#[derive(Clone)] enum StdioImp { - Piped, - Inherit, - Null, + MakePipe, + Raw(imp::Stdio), } impl Stdio { /// A new pipe should be arranged to connect the parent and child processes. #[stable(feature = "process", since = "1.0.0")] - pub fn piped() -> Stdio { Stdio(StdioImp::Piped) } + pub fn piped() -> Stdio { Stdio(StdioImp::MakePipe) } /// The child inherits from the corresponding parent descriptor. #[stable(feature = "process", since = "1.0.0")] - pub fn inherit() -> Stdio { Stdio(StdioImp::Inherit) } + pub fn inherit() -> Stdio { Stdio(StdioImp::Raw(imp::Stdio::Inherit)) } /// This stream will be ignored. This is the equivalent of attaching the /// stream to `/dev/null` #[stable(feature = "process", since = "1.0.0")] - pub fn null() -> Stdio { Stdio(StdioImp::Null) } + pub fn null() -> Stdio { Stdio(StdioImp::Raw(imp::Stdio::None)) } +} + +impl FromInner for Stdio { + fn from_inner(inner: imp::Stdio) -> Stdio { + Stdio(StdioImp::Raw(inner)) + } } /// Describes the result of a process after it has terminated. #[derive(PartialEq, Eq, Clone, Copy, Debug)] #[stable(feature = "process", since = "1.0.0")] -pub struct ExitStatus(ExitStatusImp); +pub struct ExitStatus(imp::ExitStatus); impl ExitStatus { /// Was termination successful? Signal termination not considered a success, @@ -410,8 +427,8 @@ impl ExitStatus { } } -impl AsInner for ExitStatus { - fn as_inner(&self) -> &ExitStatusImp { &self.0 } +impl AsInner for ExitStatus { + fn as_inner(&self) -> &imp::ExitStatus { &self.0 } } #[stable(feature = "process", since = "1.0.0")] diff --git a/src/libstd/sys/unix/ext/process.rs b/src/libstd/sys/unix/ext/process.rs index 45d0d62a015..2d30b016a2d 100644 --- a/src/libstd/sys/unix/ext/process.rs +++ b/src/libstd/sys/unix/ext/process.rs @@ -13,10 +13,11 @@ #![stable(feature = "rust1", since = "1.0.0")] use os::unix::raw::{uid_t, gid_t}; +use os::unix::io::{FromRawFd, RawFd, AsRawFd}; use prelude::v1::*; use process; use sys; -use sys_common::{AsInnerMut, AsInner}; +use sys_common::{AsInnerMut, AsInner, FromInner}; /// Unix-specific extensions to the `std::process::Command` builder #[stable(feature = "rust1", since = "1.0.0")] @@ -63,3 +64,49 @@ impl ExitStatusExt for process::ExitStatus { } } } + +#[stable(feature = "from_raw_os", since = "1.1.0")] +impl FromRawFd for process::Stdio { + /// Creates a new instance of `Stdio` from the raw underlying file + /// descriptor. + /// + /// When this `Stdio` is used as an I/O handle for a child process the given + /// file descriptor will be `dup`d into the destination file descriptor in + /// the child process. + /// + /// Note that this function **does not** take ownership of the file + /// descriptor provided and it will **not** be closed when `Stdio` goes out + /// of scope. As a result this method is unsafe because due to the lack of + /// knowledge about the lifetime of the provided file descriptor, this could + /// cause another I/O primitive's ownership property of its file descriptor + /// to be violated. + /// + /// Also note that this file descriptor may be used multiple times to spawn + /// processes. For example the `Command::spawn` function could be called + /// more than once to spawn more than one process sharing this file + /// descriptor. + unsafe fn from_raw_fd(fd: RawFd) -> process::Stdio { + process::Stdio::from_inner(sys::process::Stdio::Fd(fd)) + } +} + +#[stable(feature = "from_raw_os", since = "1.1.0")] +impl AsRawFd for process::ChildStdin { + fn as_raw_fd(&self) -> RawFd { + self.as_inner().fd().raw() + } +} + +#[stable(feature = "from_raw_os", since = "1.1.0")] +impl AsRawFd for process::ChildStdout { + fn as_raw_fd(&self) -> RawFd { + self.as_inner().fd().raw() + } +} + +#[stable(feature = "from_raw_os", since = "1.1.0")] +impl AsRawFd for process::ChildStderr { + fn as_raw_fd(&self) -> RawFd { + self.as_inner().fd().raw() + } +} diff --git a/src/libstd/sys/unix/pipe.rs b/src/libstd/sys/unix/pipe.rs index e9d8c69fefb..6283a29ae46 100644 --- a/src/libstd/sys/unix/pipe.rs +++ b/src/libstd/sys/unix/pipe.rs @@ -44,7 +44,6 @@ impl AnonPipe { self.0.write(buf) } - pub fn into_fd(self) -> FileDesc { - self.0 - } + pub fn fd(&self) -> &FileDesc { &self.0 } + pub fn into_fd(self) -> FileDesc { self.0 } } diff --git a/src/libstd/sys/unix/process.rs b/src/libstd/sys/unix/process.rs index f4bc5973040..76af42d9348 100644 --- a/src/libstd/sys/unix/process.rs +++ b/src/libstd/sys/unix/process.rs @@ -123,6 +123,7 @@ pub enum Stdio { Inherit, Piped(AnonPipe), None, + Fd(c_int), } const CLOEXEC_MSG_FOOTER: &'static [u8] = b"NOEX"; @@ -253,6 +254,7 @@ impl Process { let setup = |src: Stdio, dst: c_int| { let fd = match src { Stdio::Inherit => return true, + Stdio::Fd(fd) => return cvt_r(|| libc::dup2(fd, dst)).is_ok(), Stdio::Piped(pipe) => pipe.into_fd(), // If a stdio file descriptor is set to be ignored, we open up @@ -416,3 +418,14 @@ fn translate_status(status: c_int) -> ExitStatus { ExitStatus::Signal(imp::WTERMSIG(status)) } } + +impl Stdio { + pub fn clone_if_copy(&self) -> Stdio { + match *self { + Stdio::Inherit => Stdio::Inherit, + Stdio::None => Stdio::None, + Stdio::Fd(fd) => Stdio::Fd(fd), + Stdio::Piped(_) => unreachable!(), + } + } +} diff --git a/src/libstd/sys/windows/ext/mod.rs b/src/libstd/sys/windows/ext/mod.rs index 08dfa4cc877..ead533e7759 100644 --- a/src/libstd/sys/windows/ext/mod.rs +++ b/src/libstd/sys/windows/ext/mod.rs @@ -20,6 +20,7 @@ pub mod ffi; pub mod fs; pub mod io; pub mod raw; +pub mod process; /// A prelude for conveniently writing platform-specific code. /// diff --git a/src/libstd/sys/windows/ext/process.rs b/src/libstd/sys/windows/ext/process.rs new file mode 100644 index 00000000000..0fd43a450f3 --- /dev/null +++ b/src/libstd/sys/windows/ext/process.rs @@ -0,0 +1,69 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Extensions to `std::process` for Windows. + +#![stable(feature = "from_raw_os", since = "1.1.0")] + +use os::windows::io::{FromRawHandle, RawHandle, AsRawHandle}; +use process; +use sys; +use sys_common::{AsInner, FromInner}; + +#[stable(feature = "from_raw_os", since = "1.1.0")] +impl FromRawHandle for process::Stdio { + /// Creates a new instance of `Stdio` from the raw underlying handle. + /// + /// When this `Stdio` is used as an I/O handle for a child process the given + /// handle will be duplicated via `DuplicateHandle` to ensure that the + /// handle has the correct permissions to cross the process boundary. + /// + /// Note that this function **does not** take ownership of the handle + /// provided and it will **not** be closed when `Stdio` goes out of scope. + /// As a result this method is unsafe because due to the lack of knowledge + /// about the lifetime of the provided handle, this could cause another I/O + /// primitive's ownership property of its handle to be violated. + /// + /// Also note that this handle may be used multiple times to spawn + /// processes. For example the `Command::spawn` function could be called + /// more than once to spawn more than one process sharing this handle. + unsafe fn from_raw_handle(handle: RawHandle) -> process::Stdio { + let handle = sys::handle::RawHandle::new(handle as *mut _); + process::Stdio::from_inner(sys::process::Stdio::Handle(handle)) + } +} + +#[stable(feature = "from_raw_os", since = "1.1.0")] +impl AsRawHandle for process::Child { + fn as_raw_handle(&self) -> RawHandle { + self.as_inner().handle().raw() as *mut _ + } +} + +#[stable(feature = "from_raw_os", since = "1.1.0")] +impl AsRawHandle for process::ChildStdin { + fn as_raw_handle(&self) -> RawHandle { + self.as_inner().handle().raw() as *mut _ + } +} + +#[stable(feature = "from_raw_os", since = "1.1.0")] +impl AsRawHandle for process::ChildStdout { + fn as_raw_handle(&self) -> RawHandle { + self.as_inner().handle().raw() as *mut _ + } +} + +#[stable(feature = "from_raw_os", since = "1.1.0")] +impl AsRawHandle for process::ChildStderr { + fn as_raw_handle(&self) -> RawHandle { + self.as_inner().handle().raw() as *mut _ + } +} diff --git a/src/libstd/sys/windows/handle.rs b/src/libstd/sys/windows/handle.rs index c835d503388..a566c5eff32 100644 --- a/src/libstd/sys/windows/handle.rs +++ b/src/libstd/sys/windows/handle.rs @@ -15,26 +15,55 @@ use io; use libc::funcs::extra::kernel32::{GetCurrentProcess, DuplicateHandle}; use libc::{self, HANDLE}; use mem; +use ops::Deref; use ptr; use sys::cvt; -pub struct Handle(HANDLE); +/// An owned container for `HANDLE` object, closing them on Drop. +/// +/// All methods are inherited through a `Deref` impl to `RawHandle` +pub struct Handle(RawHandle); -unsafe impl Send for Handle {} -unsafe impl Sync for Handle {} +/// A wrapper type for `HANDLE` objects to give them proper Send/Sync inference +/// as well as Rust-y methods. +/// +/// This does **not** drop the handle when it goes out of scope, use `Handle` +/// instead for that. +#[derive(Copy, Clone)] +pub struct RawHandle(HANDLE); + +unsafe impl Send for RawHandle {} +unsafe impl Sync for RawHandle {} impl Handle { pub fn new(handle: HANDLE) -> Handle { - Handle(handle) + Handle(RawHandle::new(handle)) } - pub fn raw(&self) -> HANDLE { self.0 } - pub fn into_raw(self) -> HANDLE { - let ret = self.0; + let ret = self.raw(); mem::forget(self); return ret; } +} + +impl Deref for Handle { + type Target = RawHandle; + fn deref(&self) -> &RawHandle { &self.0 } +} + +impl Drop for Handle { + fn drop(&mut self) { + unsafe { let _ = libc::CloseHandle(self.raw()); } + } +} + +impl RawHandle { + pub fn new(handle: HANDLE) -> RawHandle { + RawHandle(handle) + } + + pub fn raw(&self) -> HANDLE { self.0 } pub fn read(&self, buf: &mut [u8]) -> io::Result { let mut read = 0; @@ -79,9 +108,3 @@ impl Handle { Ok(Handle::new(ret)) } } - -impl Drop for Handle { - fn drop(&mut self) { - unsafe { let _ = libc::CloseHandle(self.0); } - } -} diff --git a/src/libstd/sys/windows/process.rs b/src/libstd/sys/windows/process.rs index 178b6ea42d2..05073e60f5d 100644 --- a/src/libstd/sys/windows/process.rs +++ b/src/libstd/sys/windows/process.rs @@ -27,7 +27,7 @@ use ptr; use sync::StaticMutex; use sys::c; use sys::fs::{OpenOptions, File}; -use sys::handle::Handle; +use sys::handle::{Handle, RawHandle}; use sys::pipe::AnonPipe; use sys::stdio; use sys::{self, cvt}; @@ -109,6 +109,7 @@ pub enum Stdio { Inherit, Piped(AnonPipe), None, + Handle(RawHandle), } impl Process { @@ -217,6 +218,8 @@ impl Process { } } } + + pub fn handle(&self) -> &Handle { &self.handle } } #[derive(PartialEq, Eq, Clone, Copy, Debug)] @@ -353,6 +356,15 @@ fn make_dirp(d: Option<&OsString>) -> (*const u16, Vec) { } impl Stdio { + pub fn clone_if_copy(&self) -> Stdio { + match *self { + Stdio::Inherit => Stdio::Inherit, + Stdio::None => Stdio::None, + Stdio::Handle(handle) => Stdio::Handle(handle), + Stdio::Piped(_) => unreachable!(), + } + } + fn to_handle(&self, stdio_id: libc::DWORD) -> io::Result { use libc::DUPLICATE_SAME_ACCESS; @@ -362,6 +374,9 @@ impl Stdio { io.handle().duplicate(0, true, DUPLICATE_SAME_ACCESS) }) } + Stdio::Handle(ref handle) => { + handle.duplicate(0, true, DUPLICATE_SAME_ACCESS) + } Stdio::Piped(ref pipe) => { pipe.handle().duplicate(0, true, DUPLICATE_SAME_ACCESS) }