diff options
| author | Alex Crichton <alex@alexcrichton.com> | 2016-02-03 16:55:59 -0800 |
|---|---|---|
| committer | Alex Crichton <alex@alexcrichton.com> | 2016-02-10 09:28:48 -0800 |
| commit | b1898db0f10f9641c7616e93499348d4fe743ddd (patch) | |
| tree | c0f4add8dbc41cf4946ba211b2cff3ce1416a6cf /src/libstd/sys | |
| parent | 6c4198469025bf037f59d617c5b75229546ce68a (diff) | |
| download | rust-b1898db0f10f9641c7616e93499348d4fe743ddd.tar.gz rust-b1898db0f10f9641c7616e93499348d4fe743ddd.zip | |
std: Implement CommandExt::before_exec
This is a Unix-specific function which adds the ability to register a closure to run pre-exec to configure the child process as required (note that these closures are run post-fork). cc #31398
Diffstat (limited to 'src/libstd/sys')
| -rw-r--r-- | src/libstd/sys/unix/ext/process.rs | 38 | ||||
| -rw-r--r-- | src/libstd/sys/unix/process.rs | 15 |
2 files changed, 51 insertions, 2 deletions
diff --git a/src/libstd/sys/unix/ext/process.rs b/src/libstd/sys/unix/ext/process.rs index 97938b07f8b..96727ed6674 100644 --- a/src/libstd/sys/unix/ext/process.rs +++ b/src/libstd/sys/unix/ext/process.rs @@ -12,6 +12,9 @@ #![stable(feature = "rust1", since = "1.0.0")] +use prelude::v1::*; + +use io; use os::unix::io::{FromRawFd, RawFd, AsRawFd, IntoRawFd}; use os::unix::raw::{uid_t, gid_t}; use process; @@ -44,6 +47,34 @@ pub trait CommandExt { #[unstable(feature = "process_session_leader", reason = "recently added", issue = "27811")] fn session_leader(&mut self, on: bool) -> &mut process::Command; + + /// Schedules a closure to be run just before the `exec` function is + /// invoked. + /// + /// The closure is allowed to return an I/O error whose OS error code will + /// be communicated back to the parent and returned as an error from when + /// the spawn was requested. + /// + /// Multiple closures can be registered and they will be called in order of + /// their registration. If a closure returns `Err` then no further closures + /// will be called and the spawn operation will immediately return with a + /// failure. + /// + /// # Notes + /// + /// This closure will be run in the context of the child process after a + /// `fork`. This primarily means that any modificatons made to memory on + /// behalf of this closure will **not** be visible to the parent process. + /// This is often a very constrained environment where normal operations + /// like `malloc` or acquiring a mutex are not guaranteed to work (due to + /// other threads perhaps still running when the `fork` was run). + /// + /// When this closure is run, aspects such as the stdio file descriptors and + /// working directory have successfully been changed, so output to these + /// locations may not appear where intended. + #[unstable(feature = "process_exec", issue = "31398")] + fn before_exec<F>(&mut self, f: F) -> &mut process::Command + where F: FnMut() -> io::Result<()> + Send + Sync + 'static; } #[stable(feature = "rust1", since = "1.0.0")] @@ -62,6 +93,13 @@ impl CommandExt for process::Command { self.as_inner_mut().session_leader(on); self } + + fn before_exec<F>(&mut self, f: F) -> &mut process::Command + where F: FnMut() -> io::Result<()> + Send + Sync + 'static + { + self.as_inner_mut().before_exec(Box::new(f)); + self + } } /// Unix-specific extensions to `std::process::ExitStatus` diff --git a/src/libstd/sys/unix/process.rs b/src/libstd/sys/unix/process.rs index ed512b834f8..7387e9def9f 100644 --- a/src/libstd/sys/unix/process.rs +++ b/src/libstd/sys/unix/process.rs @@ -58,6 +58,7 @@ pub struct Command { gid: Option<gid_t>, session_leader: bool, saw_nul: bool, + closures: Vec<Box<FnMut() -> io::Result<()> + Send + Sync>>, } impl Command { @@ -75,6 +76,7 @@ impl Command { gid: None, session_leader: false, saw_nul: saw_nul, + closures: Vec::new(), } } @@ -164,6 +166,11 @@ impl Command { pub fn session_leader(&mut self, session_leader: bool) { self.session_leader = session_leader; } + + pub fn before_exec(&mut self, + f: Box<FnMut() -> io::Result<()> + Send + Sync>) { + self.closures.push(f); + } } fn os2c(s: &OsStr, saw_nul: &mut bool) -> CString { @@ -283,7 +290,7 @@ impl Process { Ok(()) } - pub fn spawn(cfg: &Command, + pub fn spawn(cfg: &mut Command, in_fd: Stdio, out_fd: Stdio, err_fd: Stdio) -> io::Result<Process> { @@ -387,7 +394,7 @@ impl Process { // allocation). Instead we just close it manually. This will never // have the drop glue anyway because this code never returns (the // child will either exec() or invoke libc::exit) - unsafe fn exec(cfg: &Command, + unsafe fn exec(cfg: &mut Command, in_fd: Stdio, out_fd: Stdio, err_fd: Stdio) -> io::Error { @@ -497,6 +504,10 @@ impl Process { } } + for callback in cfg.closures.iter_mut() { + try!(callback()); + } + libc::execvp(cfg.argv[0], cfg.argv.as_ptr()); io::Error::last_os_error() } |
