PageRenderTime 55ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/src/libstd/old_io/process.rs

https://gitlab.com/pranith/rust
Rust | 1239 lines | 799 code | 132 blank | 308 comment | 40 complexity | 76f5cec3cc267fd79c7628b7316c72be MD5 | raw file
  1. // Copyright 2013 The Rust Project Developers. See the COPYRIGHT
  2. // file at the top-level directory of this distribution and at
  3. // http://rust-lang.org/COPYRIGHT.
  4. //
  5. // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
  6. // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
  7. // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
  8. // option. This file may not be copied, modified, or distributed
  9. // except according to those terms.
  10. //! Bindings for executing child processes
  11. #![allow(non_upper_case_globals)]
  12. #![unstable(feature = "old_io")]
  13. #![deprecated(since = "1.0.0",
  14. reason = "replaced with the std::process module")]
  15. pub use self::StdioContainer::*;
  16. pub use self::ProcessExit::*;
  17. use prelude::v1::*;
  18. use collections::HashMap;
  19. use ffi::CString;
  20. use fmt;
  21. use old_io::pipe::{PipeStream, PipePair};
  22. use old_io::{IoResult, IoError, Reader, Writer};
  23. use old_io;
  24. use old_path::{Path, GenericPath};
  25. use libc;
  26. use os;
  27. use old_path::BytesContainer;
  28. use sync::mpsc::{channel, Receiver};
  29. use sys::fs::FileDesc;
  30. use sys::process::Process as ProcessImp;
  31. use sys;
  32. use thread;
  33. #[cfg(windows)] use hash;
  34. #[cfg(windows)] use str;
  35. /// Signal a process to exit, without forcibly killing it. Corresponds to
  36. /// SIGTERM on unix platforms.
  37. #[cfg(windows)] pub const PleaseExitSignal: isize = 15;
  38. /// Signal a process to exit immediately, forcibly killing it. Corresponds to
  39. /// SIGKILL on unix platforms.
  40. #[cfg(windows)] pub const MustDieSignal: isize = 9;
  41. /// Signal a process to exit, without forcibly killing it. Corresponds to
  42. /// SIGTERM on unix platforms.
  43. #[cfg(not(windows))] pub const PleaseExitSignal: isize = libc::SIGTERM as isize;
  44. /// Signal a process to exit immediately, forcibly killing it. Corresponds to
  45. /// SIGKILL on unix platforms.
  46. #[cfg(not(windows))] pub const MustDieSignal: isize = libc::SIGKILL as isize;
  47. /// Representation of a running or exited child process.
  48. ///
  49. /// This structure is used to represent and manage child processes. A child
  50. /// process is created via the `Command` struct, which configures the spawning
  51. /// process and can itself be constructed using a builder-style interface.
  52. ///
  53. /// # Examples
  54. ///
  55. /// ```should_panic
  56. /// # #![feature(old_io)]
  57. /// use std::old_io::*;
  58. ///
  59. /// let mut child = match Command::new("/bin/cat").arg("file.txt").spawn() {
  60. /// Ok(child) => child,
  61. /// Err(e) => panic!("failed to execute child: {}", e),
  62. /// };
  63. ///
  64. /// let contents = child.stdout.as_mut().unwrap().read_to_end();
  65. /// assert!(child.wait().unwrap().success());
  66. /// ```
  67. pub struct Process {
  68. handle: ProcessImp,
  69. forget: bool,
  70. /// None until wait() is called.
  71. exit_code: Option<ProcessExit>,
  72. /// Manually delivered signal
  73. exit_signal: Option<isize>,
  74. /// Deadline after which wait() will return
  75. deadline: u64,
  76. /// Handle to the child's stdin, if the `stdin` field of this process's
  77. /// `ProcessConfig` was `CreatePipe`. By default, this handle is `Some`.
  78. pub stdin: Option<PipeStream>,
  79. /// Handle to the child's stdout, if the `stdout` field of this process's
  80. /// `ProcessConfig` was `CreatePipe`. By default, this handle is `Some`.
  81. pub stdout: Option<PipeStream>,
  82. /// Handle to the child's stderr, if the `stderr` field of this process's
  83. /// `ProcessConfig` was `CreatePipe`. By default, this handle is `Some`.
  84. pub stderr: Option<PipeStream>,
  85. }
  86. /// A representation of environment variable name
  87. /// It compares case-insensitive on Windows and case-sensitive everywhere else.
  88. #[cfg(not(windows))]
  89. #[derive(Hash, PartialEq, Eq, Clone, Debug)]
  90. struct EnvKey(CString);
  91. #[doc(hidden)]
  92. #[cfg(windows)]
  93. #[derive(Eq, Clone, Debug)]
  94. struct EnvKey(CString);
  95. #[cfg(windows)]
  96. impl hash::Hash for EnvKey {
  97. fn hash<H: hash::Hasher>(&self, state: &mut H) {
  98. use ascii::AsciiExt;
  99. let &EnvKey(ref x) = self;
  100. match str::from_utf8(x.as_bytes()) {
  101. Ok(s) => for ch in s.chars() {
  102. ch.to_ascii_lowercase().hash(state);
  103. },
  104. Err(..) => x.hash(state)
  105. }
  106. }
  107. }
  108. #[cfg(windows)]
  109. impl PartialEq for EnvKey {
  110. fn eq(&self, other: &EnvKey) -> bool {
  111. use ascii::AsciiExt;
  112. let &EnvKey(ref x) = self;
  113. let &EnvKey(ref y) = other;
  114. match (str::from_utf8(x.as_bytes()), str::from_utf8(y.as_bytes())) {
  115. (Ok(xs), Ok(ys)) => {
  116. if xs.len() != ys.len() {
  117. return false
  118. } else {
  119. for (xch, ych) in xs.chars().zip(ys.chars()) {
  120. if xch.to_ascii_lowercase() != ych.to_ascii_lowercase() {
  121. return false;
  122. }
  123. }
  124. return true;
  125. }
  126. },
  127. // If either is not a valid utf8 string, just compare them byte-wise
  128. _ => return x.eq(y)
  129. }
  130. }
  131. }
  132. impl BytesContainer for EnvKey {
  133. fn container_as_bytes<'a>(&'a self) -> &'a [u8] {
  134. let &EnvKey(ref k) = self;
  135. k.container_as_bytes()
  136. }
  137. }
  138. /// A HashMap representation of environment variables.
  139. pub type EnvMap = HashMap<EnvKey, CString>;
  140. /// The `Command` type acts as a process builder, providing fine-grained control
  141. /// over how a new process should be spawned. A default configuration can be
  142. /// generated using `Command::new(program)`, where `program` gives a path to the
  143. /// program to be executed. Additional builder methods allow the configuration
  144. /// to be changed (for example, by adding arguments) prior to spawning:
  145. ///
  146. /// ```
  147. /// # #![feature(old_io)]
  148. /// use std::old_io::*;
  149. ///
  150. /// let mut process = match Command::new("sh").arg("-c").arg("echo hello").spawn() {
  151. /// Ok(p) => p,
  152. /// Err(e) => panic!("failed to execute process: {}", e),
  153. /// };
  154. ///
  155. /// let output = process.stdout.as_mut().unwrap().read_to_end();
  156. /// ```
  157. #[derive(Clone)]
  158. pub struct Command {
  159. // The internal data for the builder. Documented by the builder
  160. // methods below, and serialized into rt::rtio::ProcessConfig.
  161. program: CString,
  162. args: Vec<CString>,
  163. env: Option<EnvMap>,
  164. cwd: Option<CString>,
  165. stdin: StdioContainer,
  166. stdout: StdioContainer,
  167. stderr: StdioContainer,
  168. uid: Option<usize>,
  169. gid: Option<usize>,
  170. detach: bool,
  171. }
  172. // FIXME (#12938): Until DST lands, we cannot decompose &str into & and str, so
  173. // we cannot usefully take BytesContainer arguments by reference (without forcing an
  174. // additional & around &str). So we are instead temporarily adding an instance
  175. // for &Path, so that we can take BytesContainer as owned. When DST lands, the &Path
  176. // instance should be removed, and arguments bound by BytesContainer should be passed by
  177. // reference. (Here: {new, arg, args, env}.)
  178. impl Command {
  179. /// Constructs a new `Command` for launching the program at
  180. /// path `program`, with the following default configuration:
  181. ///
  182. /// * No arguments to the program
  183. /// * Inherit the current process's environment
  184. /// * Inherit the current process's working directory
  185. /// * A readable pipe for stdin (file descriptor 0)
  186. /// * A writeable pipe for stdout and stderr (file descriptors 1 and 2)
  187. ///
  188. /// Builder methods are provided to change these defaults and
  189. /// otherwise configure the process.
  190. pub fn new<T: BytesContainer>(program: T) -> Command {
  191. Command {
  192. program: CString::new(program.container_as_bytes()).unwrap(),
  193. args: Vec::new(),
  194. env: None,
  195. cwd: None,
  196. stdin: CreatePipe(true, false),
  197. stdout: CreatePipe(false, true),
  198. stderr: CreatePipe(false, true),
  199. uid: None,
  200. gid: None,
  201. detach: false,
  202. }
  203. }
  204. /// Add an argument to pass to the program.
  205. pub fn arg<'a, T: BytesContainer>(&'a mut self, arg: T) -> &'a mut Command {
  206. self.args.push(CString::new(arg.container_as_bytes()).unwrap());
  207. self
  208. }
  209. /// Add multiple arguments to pass to the program.
  210. pub fn args<'a, T: BytesContainer>(&'a mut self, args: &[T]) -> &'a mut Command {
  211. self.args.extend(args.iter().map(|arg| {
  212. CString::new(arg.container_as_bytes()).unwrap()
  213. }));
  214. self
  215. }
  216. // Get a mutable borrow of the environment variable map for this `Command`.
  217. #[allow(deprecated)]
  218. fn get_env_map<'a>(&'a mut self) -> &'a mut EnvMap {
  219. match self.env {
  220. Some(ref mut map) => map,
  221. None => {
  222. // if the env is currently just inheriting from the parent's,
  223. // materialize the parent's env into a hashtable.
  224. self.env = Some(::env::vars().map(|(k, v)| {
  225. (EnvKey(CString::new(k).unwrap()),
  226. CString::new(v).unwrap())
  227. }).collect());
  228. self.env.as_mut().unwrap()
  229. }
  230. }
  231. }
  232. /// Inserts or updates an environment variable mapping.
  233. ///
  234. /// Note that environment variable names are case-insensitive (but case-preserving) on Windows,
  235. /// and case-sensitive on all other platforms.
  236. pub fn env<'a, T, U>(&'a mut self, key: T, val: U)
  237. -> &'a mut Command
  238. where T: BytesContainer, U: BytesContainer {
  239. let key = EnvKey(CString::new(key.container_as_bytes()).unwrap());
  240. let val = CString::new(val.container_as_bytes()).unwrap();
  241. self.get_env_map().insert(key, val);
  242. self
  243. }
  244. /// Removes an environment variable mapping.
  245. pub fn env_remove<'a, T>(&'a mut self, key: T) -> &'a mut Command
  246. where T: BytesContainer {
  247. let key = EnvKey(CString::new(key.container_as_bytes()).unwrap());
  248. self.get_env_map().remove(&key);
  249. self
  250. }
  251. /// Sets the entire environment map for the child process.
  252. ///
  253. /// If the given slice contains multiple instances of an environment
  254. /// variable, the *rightmost* instance will determine the value.
  255. pub fn env_set_all<'a, T, U>(&'a mut self, env: &[(T,U)])
  256. -> &'a mut Command
  257. where T: BytesContainer, U: BytesContainer {
  258. self.env = Some(env.iter().map(|&(ref k, ref v)| {
  259. (EnvKey(CString::new(k.container_as_bytes()).unwrap()),
  260. CString::new(v.container_as_bytes()).unwrap())
  261. }).collect());
  262. self
  263. }
  264. /// Set the working directory for the child process.
  265. pub fn cwd<'a>(&'a mut self, dir: &Path) -> &'a mut Command {
  266. self.cwd = Some(CString::new(dir.as_vec()).unwrap());
  267. self
  268. }
  269. /// Configuration for the child process's stdin handle (file descriptor 0).
  270. /// Defaults to `CreatePipe(true, false)` so the input can be written to.
  271. pub fn stdin<'a>(&'a mut self, cfg: StdioContainer) -> &'a mut Command {
  272. self.stdin = cfg;
  273. self
  274. }
  275. /// Configuration for the child process's stdout handle (file descriptor 1).
  276. /// Defaults to `CreatePipe(false, true)` so the output can be collected.
  277. pub fn stdout<'a>(&'a mut self, cfg: StdioContainer) -> &'a mut Command {
  278. self.stdout = cfg;
  279. self
  280. }
  281. /// Configuration for the child process's stderr handle (file descriptor 2).
  282. /// Defaults to `CreatePipe(false, true)` so the output can be collected.
  283. pub fn stderr<'a>(&'a mut self, cfg: StdioContainer) -> &'a mut Command {
  284. self.stderr = cfg;
  285. self
  286. }
  287. /// Sets the child process's user id. This translates to a `setuid` call in
  288. /// the child process. Setting this value on windows will cause the spawn to
  289. /// fail. Failure in the `setuid` call on unix will also cause the spawn to
  290. /// fail.
  291. pub fn uid<'a>(&'a mut self, id: usize) -> &'a mut Command {
  292. self.uid = Some(id);
  293. self
  294. }
  295. /// Similar to `uid`, but sets the group id of the child process. This has
  296. /// the same semantics as the `uid` field.
  297. pub fn gid<'a>(&'a mut self, id: usize) -> &'a mut Command {
  298. self.gid = Some(id);
  299. self
  300. }
  301. /// Sets the child process to be spawned in a detached state. On unix, this
  302. /// means that the child is the leader of a new process group.
  303. pub fn detached<'a>(&'a mut self) -> &'a mut Command {
  304. self.detach = true;
  305. self
  306. }
  307. /// Executes the command as a child process, which is returned.
  308. pub fn spawn(&self) -> IoResult<Process> {
  309. let (their_stdin, our_stdin) = try!(setup_io(self.stdin));
  310. let (their_stdout, our_stdout) = try!(setup_io(self.stdout));
  311. let (their_stderr, our_stderr) = try!(setup_io(self.stderr));
  312. match ProcessImp::spawn(self, their_stdin, their_stdout, their_stderr) {
  313. Err(e) => Err(e),
  314. Ok(handle) => Ok(Process {
  315. handle: handle,
  316. forget: false,
  317. exit_code: None,
  318. exit_signal: None,
  319. deadline: 0,
  320. stdin: our_stdin,
  321. stdout: our_stdout,
  322. stderr: our_stderr,
  323. })
  324. }
  325. }
  326. /// Executes the command as a child process, waiting for it to finish and
  327. /// collecting all of its output.
  328. ///
  329. /// # Examples
  330. ///
  331. /// ```
  332. /// # #![feature(old_io, core, convert)]
  333. /// use std::old_io::Command;
  334. ///
  335. /// let output = match Command::new("cat").arg("foot.txt").output() {
  336. /// Ok(output) => output,
  337. /// Err(e) => panic!("failed to execute process: {}", e),
  338. /// };
  339. ///
  340. /// println!("status: {}", output.status);
  341. /// println!("stdout: {}", String::from_utf8_lossy(output.output.as_ref()));
  342. /// println!("stderr: {}", String::from_utf8_lossy(output.error.as_ref()));
  343. /// ```
  344. pub fn output(&self) -> IoResult<ProcessOutput> {
  345. self.spawn().and_then(|p| p.wait_with_output())
  346. }
  347. /// Executes a command as a child process, waiting for it to finish and
  348. /// collecting its exit status.
  349. ///
  350. /// # Examples
  351. ///
  352. /// ```
  353. /// # #![feature(old_io)]
  354. /// use std::old_io::Command;
  355. ///
  356. /// let status = match Command::new("ls").status() {
  357. /// Ok(status) => status,
  358. /// Err(e) => panic!("failed to execute process: {}", e),
  359. /// };
  360. ///
  361. /// println!("process exited with: {}", status);
  362. /// ```
  363. pub fn status(&self) -> IoResult<ProcessExit> {
  364. self.spawn().and_then(|mut p| p.wait())
  365. }
  366. }
  367. #[stable(feature = "rust1", since = "1.0.0")]
  368. impl fmt::Debug for Command {
  369. /// Format the program and arguments of a Command for display. Any
  370. /// non-utf8 data is lossily converted using the utf8 replacement
  371. /// character.
  372. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  373. try!(write!(f, "{:?}", self.program));
  374. for arg in &self.args {
  375. try!(write!(f, " '{:?}'", arg));
  376. }
  377. Ok(())
  378. }
  379. }
  380. fn setup_io(io: StdioContainer) -> IoResult<(Option<PipeStream>, Option<PipeStream>)> {
  381. let ours;
  382. let theirs;
  383. match io {
  384. Ignored => {
  385. theirs = None;
  386. ours = None;
  387. }
  388. InheritFd(fd) => {
  389. theirs = Some(PipeStream::from_filedesc(FileDesc::new(fd, false)));
  390. ours = None;
  391. }
  392. CreatePipe(readable, _writable) => {
  393. let PipePair { reader, writer } = try!(PipeStream::pair());
  394. if readable {
  395. theirs = Some(reader);
  396. ours = Some(writer);
  397. } else {
  398. theirs = Some(writer);
  399. ours = Some(reader);
  400. }
  401. }
  402. }
  403. Ok((theirs, ours))
  404. }
  405. // Allow the sys module to get access to the Command state
  406. impl sys::process::ProcessConfig<EnvKey, CString> for Command {
  407. fn program(&self) -> &CString {
  408. &self.program
  409. }
  410. fn args(&self) -> &[CString] {
  411. &self.args
  412. }
  413. fn env(&self) -> Option<&EnvMap> {
  414. self.env.as_ref()
  415. }
  416. fn cwd(&self) -> Option<&CString> {
  417. self.cwd.as_ref()
  418. }
  419. fn uid(&self) -> Option<usize> {
  420. self.uid.clone()
  421. }
  422. fn gid(&self) -> Option<usize> {
  423. self.gid.clone()
  424. }
  425. fn detach(&self) -> bool {
  426. self.detach
  427. }
  428. }
  429. /// The output of a finished process.
  430. #[derive(PartialEq, Eq, Clone)]
  431. pub struct ProcessOutput {
  432. /// The status (exit code) of the process.
  433. pub status: ProcessExit,
  434. /// The data that the process wrote to stdout.
  435. pub output: Vec<u8>,
  436. /// The data that the process wrote to stderr.
  437. pub error: Vec<u8>,
  438. }
  439. /// Describes what to do with a standard io stream for a child process.
  440. #[derive(Clone, Copy)]
  441. pub enum StdioContainer {
  442. /// This stream will be ignored. This is the equivalent of attaching the
  443. /// stream to `/dev/null`
  444. Ignored,
  445. /// The specified file descriptor is inherited for the stream which it is
  446. /// specified for. Ownership of the file descriptor is *not* taken, so the
  447. /// caller must clean it up.
  448. InheritFd(libc::c_int),
  449. /// Creates a pipe for the specified file descriptor which will be created
  450. /// when the process is spawned.
  451. ///
  452. /// The first boolean argument is whether the pipe is readable, and the
  453. /// second is whether it is writable. These properties are from the view of
  454. /// the *child* process, not the parent process.
  455. CreatePipe(bool /* readable */, bool /* writable */),
  456. }
  457. /// Describes the result of a process after it has terminated.
  458. /// Note that Windows have no signals, so the result is usually ExitStatus.
  459. #[derive(PartialEq, Eq, Clone, Copy, Debug)]
  460. pub enum ProcessExit {
  461. /// Normal termination with an exit status.
  462. ExitStatus(isize),
  463. /// Termination by signal, with the signal number.
  464. ExitSignal(isize),
  465. }
  466. #[stable(feature = "rust1", since = "1.0.0")]
  467. impl fmt::Display for ProcessExit {
  468. /// Format a ProcessExit enum, to nicely present the information.
  469. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  470. match *self {
  471. ExitStatus(code) => write!(f, "exit code: {}", code),
  472. ExitSignal(code) => write!(f, "signal: {}", code),
  473. }
  474. }
  475. }
  476. impl ProcessExit {
  477. /// Was termination successful? Signal termination not considered a success,
  478. /// and success is defined as a zero exit status.
  479. pub fn success(&self) -> bool {
  480. return self.matches_exit_status(0);
  481. }
  482. /// Checks whether this ProcessExit matches the given exit status.
  483. /// Termination by signal will never match an exit code.
  484. pub fn matches_exit_status(&self, wanted: isize) -> bool {
  485. *self == ExitStatus(wanted)
  486. }
  487. }
  488. impl Process {
  489. /// Sends `signal` to another process in the system identified by `id`.
  490. ///
  491. /// Note that windows doesn't quite have the same model as unix, so some
  492. /// unix signals are mapped to windows signals. Notably, unix termination
  493. /// signals (SIGTERM/SIGKILL/SIGINT) are translated to `TerminateProcess`.
  494. ///
  495. /// Additionally, a signal number of 0 can check for existence of the target
  496. /// process. Note, though, that on some platforms signals will continue to
  497. /// be successfully delivered if the child has exited, but not yet been
  498. /// reaped.
  499. pub fn kill(id: libc::pid_t, signal: isize) -> IoResult<()> {
  500. unsafe { ProcessImp::killpid(id, signal) }
  501. }
  502. /// Returns the process id of this child process
  503. pub fn id(&self) -> libc::pid_t { self.handle.id() }
  504. /// Sends the specified signal to the child process, returning whether the
  505. /// signal could be delivered or not.
  506. ///
  507. /// Note that signal 0 is interpreted as a poll to check whether the child
  508. /// process is still alive or not. If an error is returned, then the child
  509. /// process has exited.
  510. ///
  511. /// On some unix platforms signals will continue to be received after a
  512. /// child has exited but not yet been reaped. In order to report the status
  513. /// of signal delivery correctly, unix implementations may invoke
  514. /// `waitpid()` with `WNOHANG` in order to reap the child as necessary.
  515. ///
  516. /// # Errors
  517. ///
  518. /// If the signal delivery fails, the corresponding error is returned.
  519. pub fn signal(&mut self, signal: isize) -> IoResult<()> {
  520. #[cfg(unix)] fn collect_status(p: &mut Process) {
  521. // On Linux (and possibly other unices), a process that has exited will
  522. // continue to accept signals because it is "defunct". The delivery of
  523. // signals will only fail once the child has been reaped. For this
  524. // reason, if the process hasn't exited yet, then we attempt to collect
  525. // their status with WNOHANG.
  526. if p.exit_code.is_none() {
  527. match p.handle.try_wait() {
  528. Some(code) => { p.exit_code = Some(code); }
  529. None => {}
  530. }
  531. }
  532. }
  533. #[cfg(windows)] fn collect_status(_p: &mut Process) {}
  534. collect_status(self);
  535. // if the process has finished, and therefore had waitpid called,
  536. // and we kill it, then on unix we might ending up killing a
  537. // newer process that happens to have the same (re-used) id
  538. if self.exit_code.is_some() {
  539. return Err(IoError {
  540. kind: old_io::InvalidInput,
  541. desc: "invalid argument: can't kill an exited process",
  542. detail: None,
  543. })
  544. }
  545. // A successfully delivered signal that isn't 0 (just a poll for being
  546. // alive) is recorded for windows (see wait())
  547. match unsafe { self.handle.kill(signal) } {
  548. Ok(()) if signal == 0 => Ok(()),
  549. Ok(()) => { self.exit_signal = Some(signal); Ok(()) }
  550. Err(e) => Err(e),
  551. }
  552. }
  553. /// Sends a signal to this child requesting that it exits. This is
  554. /// equivalent to sending a SIGTERM on unix platforms.
  555. pub fn signal_exit(&mut self) -> IoResult<()> {
  556. self.signal(PleaseExitSignal)
  557. }
  558. /// Sends a signal to this child forcing it to exit. This is equivalent to
  559. /// sending a SIGKILL on unix platforms.
  560. pub fn signal_kill(&mut self) -> IoResult<()> {
  561. self.signal(MustDieSignal)
  562. }
  563. /// Wait for the child to exit completely, returning the status that it
  564. /// exited with. This function will continue to have the same return value
  565. /// after it has been called at least once.
  566. ///
  567. /// The stdin handle to the child process will be closed before waiting.
  568. ///
  569. /// # Errors
  570. ///
  571. /// This function can fail if a timeout was previously specified via
  572. /// `set_timeout` and the timeout expires before the child exits.
  573. pub fn wait(&mut self) -> IoResult<ProcessExit> {
  574. drop(self.stdin.take());
  575. match self.exit_code {
  576. Some(code) => Ok(code),
  577. None => {
  578. let code = try!(self.handle.wait(self.deadline));
  579. // On windows, waitpid will never return a signal. If a signal
  580. // was successfully delivered to the process, however, we can
  581. // consider it as having died via a signal.
  582. let code = match self.exit_signal {
  583. None => code,
  584. Some(signal) if cfg!(windows) => ExitSignal(signal),
  585. Some(..) => code,
  586. };
  587. self.exit_code = Some(code);
  588. Ok(code)
  589. }
  590. }
  591. }
  592. /// Sets a timeout, in milliseconds, for future calls to wait().
  593. ///
  594. /// The argument specified is a relative distance into the future, in
  595. /// milliseconds, after which any call to wait() will return immediately
  596. /// with a timeout error, and all future calls to wait() will not block.
  597. ///
  598. /// A value of `None` will clear any previous timeout, and a value of `Some`
  599. /// will override any previously set timeout.
  600. ///
  601. /// # Examples
  602. ///
  603. /// ```no_run
  604. /// # #![feature(old_io, io)]
  605. /// use std::old_io::{Command, IoResult};
  606. /// use std::old_io::process::ProcessExit;
  607. ///
  608. /// fn run_gracefully(prog: &str) -> IoResult<ProcessExit> {
  609. /// let mut p = try!(Command::new("long-running-process").spawn());
  610. ///
  611. /// // give the process 10 seconds to finish completely
  612. /// p.set_timeout(Some(10_000));
  613. /// match p.wait() {
  614. /// Ok(status) => return Ok(status),
  615. /// Err(..) => {}
  616. /// }
  617. ///
  618. /// // Attempt to exit gracefully, but don't wait for it too long
  619. /// try!(p.signal_exit());
  620. /// p.set_timeout(Some(1_000));
  621. /// match p.wait() {
  622. /// Ok(status) => return Ok(status),
  623. /// Err(..) => {}
  624. /// }
  625. ///
  626. /// // Well, we did our best, forcefully kill the process
  627. /// try!(p.signal_kill());
  628. /// p.set_timeout(None);
  629. /// p.wait()
  630. /// }
  631. /// ```
  632. #[unstable(feature = "io",
  633. reason = "the type of the timeout is likely to change")]
  634. pub fn set_timeout(&mut self, timeout_ms: Option<u64>) {
  635. self.deadline = timeout_ms.map(|i| i + sys::timer::now()).unwrap_or(0);
  636. }
  637. /// Simultaneously wait for the child to exit and collect all remaining
  638. /// output on the stdout/stderr handles, returning a `ProcessOutput`
  639. /// instance.
  640. ///
  641. /// The stdin handle to the child is closed before waiting.
  642. ///
  643. /// # Errors
  644. ///
  645. /// This function can fail for any of the same reasons that `wait()` can
  646. /// fail.
  647. pub fn wait_with_output(mut self) -> IoResult<ProcessOutput> {
  648. drop(self.stdin.take());
  649. fn read(stream: Option<old_io::PipeStream>) -> Receiver<IoResult<Vec<u8>>> {
  650. let (tx, rx) = channel();
  651. match stream {
  652. Some(stream) => {
  653. thread::spawn(move || {
  654. let mut stream = stream;
  655. tx.send(stream.read_to_end()).unwrap();
  656. });
  657. }
  658. None => tx.send(Ok(Vec::new())).unwrap()
  659. }
  660. rx
  661. }
  662. let stdout = read(self.stdout.take());
  663. let stderr = read(self.stderr.take());
  664. let status = try!(self.wait());
  665. Ok(ProcessOutput {
  666. status: status,
  667. output: stdout.recv().unwrap().unwrap_or(Vec::new()),
  668. error: stderr.recv().unwrap().unwrap_or(Vec::new()),
  669. })
  670. }
  671. /// Forgets this process, allowing it to outlive the parent
  672. ///
  673. /// This function will forcefully prevent calling `wait()` on the child
  674. /// process in the destructor, allowing the child to outlive the
  675. /// parent. Note that this operation can easily lead to leaking the
  676. /// resources of the child process, so care must be taken when
  677. /// invoking this method.
  678. pub fn forget(mut self) {
  679. self.forget = true;
  680. }
  681. }
  682. impl Drop for Process {
  683. fn drop(&mut self) {
  684. if self.forget { return }
  685. // Close all I/O before exiting to ensure that the child doesn't wait
  686. // forever to print some text or something similar.
  687. drop(self.stdin.take());
  688. drop(self.stdout.take());
  689. drop(self.stderr.take());
  690. self.set_timeout(None);
  691. let _ = self.wait().unwrap();
  692. }
  693. }
  694. #[cfg(test)]
  695. mod tests {
  696. use prelude::v1::*;
  697. use old_io::{Truncate, Write, TimedOut, timer, process, FileNotFound};
  698. use old_io::{Reader, Writer};
  699. use old_path::{GenericPath, Path};
  700. use old_io::fs::PathExtensions;
  701. use old_io::timer::*;
  702. use rt::running_on_valgrind;
  703. use str;
  704. use super::{CreatePipe};
  705. use super::{InheritFd, Process, PleaseExitSignal, Command, ProcessOutput};
  706. use sync::mpsc::channel;
  707. use thread;
  708. use time::Duration;
  709. // FIXME(#10380) these tests should not all be ignored on android.
  710. #[cfg(not(target_os="android"))]
  711. #[test]
  712. fn smoke() {
  713. let p = Command::new("true").spawn();
  714. assert!(p.is_ok());
  715. let mut p = p.unwrap();
  716. assert!(p.wait().unwrap().success());
  717. }
  718. #[cfg(not(target_os="android"))]
  719. #[test]
  720. fn smoke_failure() {
  721. match Command::new("if-this-is-a-binary-then-the-world-has-ended").spawn() {
  722. Ok(..) => panic!(),
  723. Err(..) => {}
  724. }
  725. }
  726. #[cfg(not(target_os="android"))]
  727. #[test]
  728. fn exit_reported_right() {
  729. let p = Command::new("false").spawn();
  730. assert!(p.is_ok());
  731. let mut p = p.unwrap();
  732. assert!(p.wait().unwrap().matches_exit_status(1));
  733. drop(p.wait().clone());
  734. }
  735. #[cfg(all(unix, not(target_os="android")))]
  736. #[test]
  737. fn signal_reported_right() {
  738. let p = Command::new("/bin/sh").arg("-c").arg("kill -9 $$").spawn();
  739. assert!(p.is_ok());
  740. let mut p = p.unwrap();
  741. match p.wait().unwrap() {
  742. process::ExitSignal(9) => {},
  743. result => panic!("not terminated by signal 9 (instead, {})", result),
  744. }
  745. }
  746. pub fn read_all(input: &mut Reader) -> String {
  747. input.read_to_string().unwrap()
  748. }
  749. pub fn run_output(cmd: Command) -> String {
  750. let p = cmd.spawn();
  751. assert!(p.is_ok());
  752. let mut p = p.unwrap();
  753. assert!(p.stdout.is_some());
  754. let ret = read_all(p.stdout.as_mut().unwrap() as &mut Reader);
  755. assert!(p.wait().unwrap().success());
  756. return ret;
  757. }
  758. #[cfg(not(target_os="android"))]
  759. #[test]
  760. fn stdout_works() {
  761. let mut cmd = Command::new("echo");
  762. cmd.arg("foobar").stdout(CreatePipe(false, true));
  763. assert_eq!(run_output(cmd), "foobar\n");
  764. }
  765. #[cfg(all(unix, not(target_os="android")))]
  766. #[test]
  767. fn set_cwd_works() {
  768. let mut cmd = Command::new("/bin/sh");
  769. cmd.arg("-c").arg("pwd")
  770. .cwd(&Path::new("/"))
  771. .stdout(CreatePipe(false, true));
  772. assert_eq!(run_output(cmd), "/\n");
  773. }
  774. #[cfg(all(unix, not(target_os="android")))]
  775. #[test]
  776. fn stdin_works() {
  777. let mut p = Command::new("/bin/sh")
  778. .arg("-c").arg("read line; echo $line")
  779. .stdin(CreatePipe(true, false))
  780. .stdout(CreatePipe(false, true))
  781. .spawn().unwrap();
  782. p.stdin.as_mut().unwrap().write("foobar".as_bytes()).unwrap();
  783. drop(p.stdin.take());
  784. let out = read_all(p.stdout.as_mut().unwrap() as &mut Reader);
  785. assert!(p.wait().unwrap().success());
  786. assert_eq!(out, "foobar\n");
  787. }
  788. #[cfg(not(target_os="android"))]
  789. #[test]
  790. fn detach_works() {
  791. let mut p = Command::new("true").detached().spawn().unwrap();
  792. assert!(p.wait().unwrap().success());
  793. }
  794. #[cfg(windows)]
  795. #[test]
  796. fn uid_fails_on_windows() {
  797. assert!(Command::new("test").uid(10).spawn().is_err());
  798. }
  799. #[cfg(all(unix, not(target_os="android")))]
  800. #[test]
  801. fn uid_works() {
  802. use libc;
  803. let mut p = Command::new("/bin/sh")
  804. .arg("-c").arg("true")
  805. .uid(unsafe { libc::getuid() as usize })
  806. .gid(unsafe { libc::getgid() as usize })
  807. .spawn().unwrap();
  808. assert!(p.wait().unwrap().success());
  809. }
  810. #[cfg(all(unix, not(target_os="android")))]
  811. #[test]
  812. fn uid_to_root_fails() {
  813. use libc;
  814. // if we're already root, this isn't a valid test. Most of the bots run
  815. // as non-root though (android is an exception).
  816. if unsafe { libc::getuid() == 0 } { return }
  817. assert!(Command::new("/bin/ls").uid(0).gid(0).spawn().is_err());
  818. }
  819. #[cfg(not(target_os="android"))]
  820. #[test]
  821. fn test_process_status() {
  822. let mut status = Command::new("false").status().unwrap();
  823. assert!(status.matches_exit_status(1));
  824. status = Command::new("true").status().unwrap();
  825. assert!(status.success());
  826. }
  827. #[test]
  828. fn test_process_output_fail_to_start() {
  829. match Command::new("/no-binary-by-this-name-should-exist").output() {
  830. Err(e) => assert_eq!(e.kind, FileNotFound),
  831. Ok(..) => panic!()
  832. }
  833. }
  834. #[cfg(not(target_os="android"))]
  835. #[test]
  836. fn test_process_output_output() {
  837. let ProcessOutput {status, output, error}
  838. = Command::new("echo").arg("hello").output().unwrap();
  839. let output_str = str::from_utf8(&output).unwrap();
  840. assert!(status.success());
  841. assert_eq!(output_str.trim().to_string(), "hello");
  842. // FIXME #7224
  843. if !running_on_valgrind() {
  844. assert_eq!(error, Vec::new());
  845. }
  846. }
  847. #[cfg(not(target_os="android"))]
  848. #[test]
  849. fn test_process_output_error() {
  850. let ProcessOutput {status, output, error}
  851. = Command::new("mkdir").arg(".").output().unwrap();
  852. assert!(status.matches_exit_status(1));
  853. assert_eq!(output, Vec::new());
  854. assert!(!error.is_empty());
  855. }
  856. #[cfg(not(target_os="android"))]
  857. #[test]
  858. fn test_finish_once() {
  859. let mut prog = Command::new("false").spawn().unwrap();
  860. assert!(prog.wait().unwrap().matches_exit_status(1));
  861. }
  862. #[cfg(not(target_os="android"))]
  863. #[test]
  864. fn test_finish_twice() {
  865. let mut prog = Command::new("false").spawn().unwrap();
  866. assert!(prog.wait().unwrap().matches_exit_status(1));
  867. assert!(prog.wait().unwrap().matches_exit_status(1));
  868. }
  869. #[cfg(not(target_os="android"))]
  870. #[test]
  871. fn test_wait_with_output_once() {
  872. let prog = Command::new("echo").arg("hello").spawn().unwrap();
  873. let ProcessOutput {status, output, error} = prog.wait_with_output().unwrap();
  874. let output_str = str::from_utf8(&output).unwrap();
  875. assert!(status.success());
  876. assert_eq!(output_str.trim().to_string(), "hello");
  877. // FIXME #7224
  878. if !running_on_valgrind() {
  879. assert_eq!(error, Vec::new());
  880. }
  881. }
  882. #[cfg(all(unix, not(target_os="android")))]
  883. pub fn pwd_cmd() -> Command {
  884. Command::new("pwd")
  885. }
  886. #[cfg(target_os="android")]
  887. pub fn pwd_cmd() -> Command {
  888. let mut cmd = Command::new("/system/bin/sh");
  889. cmd.arg("-c").arg("pwd");
  890. cmd
  891. }
  892. #[cfg(windows)]
  893. pub fn pwd_cmd() -> Command {
  894. let mut cmd = Command::new("cmd");
  895. cmd.arg("/c").arg("cd");
  896. cmd
  897. }
  898. #[test]
  899. fn test_keep_current_working_dir() {
  900. use os;
  901. let prog = pwd_cmd().spawn().unwrap();
  902. let output = String::from_utf8(prog.wait_with_output().unwrap().output).unwrap();
  903. let parent_dir = Path::new(::env::current_dir().unwrap().to_str().unwrap());
  904. let child_dir = Path::new(output.trim());
  905. let parent_stat = parent_dir.stat().unwrap();
  906. let child_stat = child_dir.stat().unwrap();
  907. assert_eq!(parent_stat.unstable.device, child_stat.unstable.device);
  908. assert_eq!(parent_stat.unstable.inode, child_stat.unstable.inode);
  909. }
  910. #[test]
  911. fn test_change_working_directory() {
  912. use os;
  913. // test changing to the parent of os::getcwd() because we know
  914. // the path exists (and os::getcwd() is not expected to be root)
  915. let parent_dir = Path::new(::env::current_dir().unwrap().to_str().unwrap());
  916. let prog = pwd_cmd().cwd(&parent_dir).spawn().unwrap();
  917. let output = String::from_utf8(prog.wait_with_output().unwrap().output).unwrap();
  918. let child_dir = Path::new(output.trim());
  919. let parent_stat = parent_dir.stat().unwrap();
  920. let child_stat = child_dir.stat().unwrap();
  921. assert_eq!(parent_stat.unstable.device, child_stat.unstable.device);
  922. assert_eq!(parent_stat.unstable.inode, child_stat.unstable.inode);
  923. }
  924. #[cfg(all(unix, not(target_os="android")))]
  925. pub fn env_cmd() -> Command {
  926. Command::new("env")
  927. }
  928. #[cfg(target_os="android")]
  929. pub fn env_cmd() -> Command {
  930. let mut cmd = Command::new("/system/bin/sh");
  931. cmd.arg("-c").arg("set");
  932. cmd
  933. }
  934. #[cfg(windows)]
  935. pub fn env_cmd() -> Command {
  936. let mut cmd = Command::new("cmd");
  937. cmd.arg("/c").arg("set");
  938. cmd
  939. }
  940. #[cfg(not(target_os="android"))]
  941. #[test]
  942. fn test_inherit_env() {
  943. use os;
  944. if running_on_valgrind() { return; }
  945. let prog = env_cmd().spawn().unwrap();
  946. let output = String::from_utf8(prog.wait_with_output().unwrap().output).unwrap();
  947. let r = ::env::vars();
  948. for (k, v) in r {
  949. // don't check windows magical empty-named variables
  950. assert!(k.is_empty() ||
  951. output.contains(&format!("{}={}", k, v)),
  952. "output doesn't contain `{}={}`\n{}",
  953. k, v, output);
  954. }
  955. }
  956. #[cfg(target_os="android")]
  957. #[test]
  958. fn test_inherit_env() {
  959. use os;
  960. if running_on_valgrind() { return; }
  961. let mut prog = env_cmd().spawn().unwrap();
  962. let output = String::from_utf8(prog.wait_with_output().unwrap().output).unwrap();
  963. let r = ::env::vars();
  964. for (k, v) in r {
  965. // don't check android RANDOM variables
  966. if k != "RANDOM".to_string() {
  967. assert!(output.contains(&format!("{}={}", k, v)) ||
  968. output.contains(&format!("{}=\'{}\'", k, v)));
  969. }
  970. }
  971. }
  972. #[test]
  973. fn test_override_env() {
  974. use os;
  975. // In some build environments (such as chrooted Nix builds), `env` can
  976. // only be found in the explicitly-provided PATH env variable, not in
  977. // default places such as /bin or /usr/bin. So we need to pass through
  978. // PATH to our sub-process.
  979. let path_val: String;
  980. let mut new_env = vec![("RUN_TEST_NEW_ENV", "123")];
  981. match ::env::var("PATH") {
  982. Err(..) => {}
  983. Ok(val) => {
  984. path_val = val;
  985. new_env.push(("PATH", &path_val))
  986. }
  987. }
  988. let prog = env_cmd().env_set_all(&new_env).spawn().unwrap();
  989. let result = prog.wait_with_output().unwrap();
  990. let output = String::from_utf8_lossy(&result.output).to_string();
  991. assert!(output.contains("RUN_TEST_NEW_ENV=123"),
  992. "didn't find RUN_TEST_NEW_ENV inside of:\n\n{}", output);
  993. }
  994. #[test]
  995. fn test_add_to_env() {
  996. let prog = env_cmd().env("RUN_TEST_NEW_ENV", "123").spawn().unwrap();
  997. let result = prog.wait_with_output().unwrap();
  998. let output = String::from_utf8_lossy(&result.output).to_string();
  999. assert!(output.contains("RUN_TEST_NEW_ENV=123"),
  1000. "didn't find RUN_TEST_NEW_ENV inside of:\n\n{}", output);
  1001. }
  1002. #[cfg(unix)]
  1003. pub fn sleeper() -> Process {
  1004. Command::new("sleep").arg("1000").spawn().unwrap()
  1005. }
  1006. #[cfg(windows)]
  1007. pub fn sleeper() -> Process {
  1008. // There's a `timeout` command on windows, but it doesn't like having
  1009. // its output piped, so instead just ping ourselves a few times with
  1010. // gaps in between so we're sure this process is alive for awhile
  1011. Command::new("ping").arg("127.0.0.1").arg("-n").arg("1000").spawn().unwrap()
  1012. }
  1013. #[test]
  1014. fn test_kill() {
  1015. let mut p = sleeper();
  1016. Process::kill(p.id(), PleaseExitSignal).unwrap();
  1017. assert!(!p.wait().unwrap().success());
  1018. }
  1019. #[test]
  1020. fn test_exists() {
  1021. let mut p = sleeper();
  1022. assert!(Process::kill(p.id(), 0).is_ok());
  1023. p.signal_kill().unwrap();
  1024. assert!(!p.wait().unwrap().success());
  1025. }
  1026. #[test]
  1027. fn test_zero() {
  1028. let mut p = sleeper();
  1029. p.signal_kill().unwrap();
  1030. for _ in 0..20 {
  1031. if p.signal(0).is_err() {
  1032. assert!(!p.wait().unwrap().success());
  1033. return
  1034. }
  1035. timer::sleep(Duration::milliseconds(100));
  1036. }
  1037. panic!("never saw the child go away");
  1038. }
  1039. #[test]
  1040. fn wait_timeout() {
  1041. let mut p = sleeper();
  1042. p.set_timeout(Some(10));
  1043. assert_eq!(p.wait().err().unwrap().kind, TimedOut);
  1044. assert_eq!(p.wait().err().unwrap().kind, TimedOut);
  1045. p.signal_kill().unwrap();
  1046. p.set_timeout(None);
  1047. assert!(p.wait().is_ok());
  1048. }
  1049. #[test]
  1050. fn wait_timeout2() {
  1051. let (tx, rx) = channel();
  1052. let tx2 = tx.clone();
  1053. let _t = thread::spawn(move|| {
  1054. let mut p = sleeper();
  1055. p.set_timeout(Some(10));
  1056. assert_eq!(p.wait().err().unwrap().kind, TimedOut);
  1057. p.signal_kill().unwrap();
  1058. tx.send(()).unwrap();
  1059. });
  1060. let _t = thread::spawn(move|| {
  1061. let mut p = sleeper();
  1062. p.set_timeout(Some(10));
  1063. assert_eq!(p.wait().err().unwrap().kind, TimedOut);
  1064. p.signal_kill().unwrap();
  1065. tx2.send(()).unwrap();
  1066. });
  1067. rx.recv().unwrap();
  1068. rx.recv().unwrap();
  1069. }
  1070. #[test]
  1071. fn forget() {
  1072. let p = sleeper();
  1073. let id = p.id();
  1074. p.forget();
  1075. assert!(Process::kill(id, 0).is_ok());
  1076. assert!(Process::kill(id, PleaseExitSignal).is_ok());
  1077. }
  1078. #[test]
  1079. fn dont_close_fd_on_command_spawn() {
  1080. use sys::fs;
  1081. let path = if cfg!(windows) {
  1082. Path::new("NUL")
  1083. } else {
  1084. Path::new("/dev/null")
  1085. };
  1086. let fdes = match fs::open(&path, Truncate, Write) {
  1087. Ok(f) => f,
  1088. Err(_) => panic!("failed to open file descriptor"),
  1089. };
  1090. let mut cmd = pwd_cmd();
  1091. let _ = cmd.stdout(InheritFd(fdes.fd()));
  1092. assert!(cmd.status().unwrap().success());
  1093. assert!(fdes.write("extra write\n".as_bytes()).is_ok());
  1094. }
  1095. #[test]
  1096. #[cfg(windows)]
  1097. fn env_map_keys_ci() {
  1098. use ffi::CString;
  1099. use super::EnvKey;
  1100. let mut cmd = Command::new("");
  1101. cmd.env("path", "foo");
  1102. cmd.env("Path", "bar");
  1103. let env = &cmd.env.unwrap();
  1104. let val = env.get(&EnvKey(CString::new("PATH").unwrap()));
  1105. assert!(val.unwrap() == &CString::new("bar").unwrap());
  1106. }
  1107. }