PageRenderTime 52ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/src/libstd/io/process.rs

https://gitlab.com/anispy211/rust
Rust | 857 lines | 518 code | 103 blank | 236 comment | 18 complexity | 3fe5bb8669b448c626c57cf880037d86 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. use prelude::*;
  12. use fmt;
  13. use io::IoResult;
  14. use io;
  15. use libc;
  16. use rt::rtio::{RtioProcess, IoFactory, LocalIo};
  17. /// Signal a process to exit, without forcibly killing it. Corresponds to
  18. /// SIGTERM on unix platforms.
  19. #[cfg(windows)] pub static PleaseExitSignal: int = 15;
  20. /// Signal a process to exit immediately, forcibly killing it. Corresponds to
  21. /// SIGKILL on unix platforms.
  22. #[cfg(windows)] pub static MustDieSignal: int = 9;
  23. /// Signal a process to exit, without forcibly killing it. Corresponds to
  24. /// SIGTERM on unix platforms.
  25. #[cfg(not(windows))] pub static PleaseExitSignal: int = libc::SIGTERM as int;
  26. /// Signal a process to exit immediately, forcibly killing it. Corresponds to
  27. /// SIGKILL on unix platforms.
  28. #[cfg(not(windows))] pub static MustDieSignal: int = libc::SIGKILL as int;
  29. /// Representation of a running or exited child process.
  30. ///
  31. /// This structure is used to create, run, and manage child processes. A process
  32. /// is configured with the `ProcessConfig` struct which contains specific
  33. /// options for dictating how the child is spawned.
  34. ///
  35. /// # Example
  36. ///
  37. /// ```should_fail
  38. /// use std::io::Process;
  39. ///
  40. /// let mut child = match Process::new("/bin/cat", [~"file.txt"]) {
  41. /// Ok(child) => child,
  42. /// Err(e) => fail!("failed to execute child: {}", e),
  43. /// };
  44. ///
  45. /// let contents = child.stdout.get_mut_ref().read_to_end();
  46. /// assert!(child.wait().success());
  47. /// ```
  48. pub struct Process {
  49. handle: ~RtioProcess:Send,
  50. /// Handle to the child's stdin, if the `stdin` field of this process's
  51. /// `ProcessConfig` was `CreatePipe`. By default, this handle is `Some`.
  52. pub stdin: Option<io::PipeStream>,
  53. /// Handle to the child's stdout, if the `stdout` field of this process's
  54. /// `ProcessConfig` was `CreatePipe`. By default, this handle is `Some`.
  55. pub stdout: Option<io::PipeStream>,
  56. /// Handle to the child's stderr, if the `stderr` field of this process's
  57. /// `ProcessConfig` was `CreatePipe`. By default, this handle is `Some`.
  58. pub stderr: Option<io::PipeStream>,
  59. /// Extra I/O handles as configured by the original `ProcessConfig` when
  60. /// this process was created. This is by default empty.
  61. pub extra_io: ~[Option<io::PipeStream>],
  62. }
  63. /// This configuration describes how a new process should be spawned. A blank
  64. /// configuration can be created with `ProcessConfig::new()`. It is also
  65. /// recommented to use a functional struct update pattern when creating process
  66. /// configuration:
  67. ///
  68. /// ```
  69. /// use std::io::ProcessConfig;
  70. ///
  71. /// let config = ProcessConfig {
  72. /// program: "/bin/sh",
  73. /// args: &[~"-c", ~"true"],
  74. /// .. ProcessConfig::new()
  75. /// };
  76. /// ```
  77. pub struct ProcessConfig<'a> {
  78. /// Path to the program to run
  79. pub program: &'a str,
  80. /// Arguments to pass to the program (doesn't include the program itself)
  81. pub args: &'a [~str],
  82. /// Optional environment to specify for the program. If this is None, then
  83. /// it will inherit the current process's environment.
  84. pub env: Option<&'a [(~str, ~str)]>,
  85. /// Optional working directory for the new process. If this is None, then
  86. /// the current directory of the running process is inherited.
  87. pub cwd: Option<&'a Path>,
  88. /// Configuration for the child process's stdin handle (file descriptor 0).
  89. /// This field defaults to `CreatePipe(true, false)` so the input can be
  90. /// written to.
  91. pub stdin: StdioContainer,
  92. /// Configuration for the child process's stdout handle (file descriptor 1).
  93. /// This field defaults to `CreatePipe(false, true)` so the output can be
  94. /// collected.
  95. pub stdout: StdioContainer,
  96. /// Configuration for the child process's stdout handle (file descriptor 2).
  97. /// This field defaults to `CreatePipe(false, true)` so the output can be
  98. /// collected.
  99. pub stderr: StdioContainer,
  100. /// Any number of streams/file descriptors/pipes may be attached to this
  101. /// process. This list enumerates the file descriptors and such for the
  102. /// process to be spawned, and the file descriptors inherited will start at
  103. /// 3 and go to the length of this array. The first three file descriptors
  104. /// (stdin/stdout/stderr) are configured with the `stdin`, `stdout`, and
  105. /// `stderr` fields.
  106. pub extra_io: &'a [StdioContainer],
  107. /// Sets the child process's user id. This translates to a `setuid` call in
  108. /// the child process. Setting this value on windows will cause the spawn to
  109. /// fail. Failure in the `setuid` call on unix will also cause the spawn to
  110. /// fail.
  111. pub uid: Option<uint>,
  112. /// Similar to `uid`, but sets the group id of the child process. This has
  113. /// the same semantics as the `uid` field.
  114. pub gid: Option<uint>,
  115. /// If true, the child process is spawned in a detached state. On unix, this
  116. /// means that the child is the leader of a new process group.
  117. pub detach: bool,
  118. }
  119. /// The output of a finished process.
  120. pub struct ProcessOutput {
  121. /// The status (exit code) of the process.
  122. pub status: ProcessExit,
  123. /// The data that the process wrote to stdout.
  124. pub output: ~[u8],
  125. /// The data that the process wrote to stderr.
  126. pub error: ~[u8],
  127. }
  128. /// Describes what to do with a standard io stream for a child process.
  129. pub enum StdioContainer {
  130. /// This stream will be ignored. This is the equivalent of attaching the
  131. /// stream to `/dev/null`
  132. Ignored,
  133. /// The specified file descriptor is inherited for the stream which it is
  134. /// specified for.
  135. InheritFd(libc::c_int),
  136. /// Creates a pipe for the specified file descriptor which will be created
  137. /// when the process is spawned.
  138. ///
  139. /// The first boolean argument is whether the pipe is readable, and the
  140. /// second is whether it is writable. These properties are from the view of
  141. /// the *child* process, not the parent process.
  142. CreatePipe(bool /* readable */, bool /* writable */),
  143. }
  144. /// Describes the result of a process after it has terminated.
  145. /// Note that Windows have no signals, so the result is usually ExitStatus.
  146. #[deriving(Eq, TotalEq, Clone)]
  147. pub enum ProcessExit {
  148. /// Normal termination with an exit status.
  149. ExitStatus(int),
  150. /// Termination by signal, with the signal number.
  151. ExitSignal(int),
  152. }
  153. impl fmt::Show for ProcessExit {
  154. /// Format a ProcessExit enum, to nicely present the information.
  155. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  156. match *self {
  157. ExitStatus(code) => write!(f.buf, "exit code: {}", code),
  158. ExitSignal(code) => write!(f.buf, "signal: {}", code),
  159. }
  160. }
  161. }
  162. impl ProcessExit {
  163. /// Was termination successful? Signal termination not considered a success,
  164. /// and success is defined as a zero exit status.
  165. pub fn success(&self) -> bool {
  166. return self.matches_exit_status(0);
  167. }
  168. /// Checks whether this ProcessExit matches the given exit status.
  169. /// Termination by signal will never match an exit code.
  170. pub fn matches_exit_status(&self, wanted: int) -> bool {
  171. *self == ExitStatus(wanted)
  172. }
  173. }
  174. impl<'a> ProcessConfig<'a> {
  175. /// Creates a new configuration with blanks as all of the defaults. This is
  176. /// useful when using functional struct updates:
  177. ///
  178. /// ```rust
  179. /// use std::io::process::{ProcessConfig, Process};
  180. ///
  181. /// let config = ProcessConfig {
  182. /// program: "/bin/sh",
  183. /// args: &[~"-c", ~"echo hello"],
  184. /// .. ProcessConfig::new()
  185. /// };
  186. ///
  187. /// let p = Process::configure(config);
  188. /// ```
  189. ///
  190. pub fn new<'a>() -> ProcessConfig<'a> {
  191. ProcessConfig {
  192. program: "",
  193. args: &[],
  194. env: None,
  195. cwd: None,
  196. stdin: CreatePipe(true, false),
  197. stdout: CreatePipe(false, true),
  198. stderr: CreatePipe(false, true),
  199. extra_io: &[],
  200. uid: None,
  201. gid: None,
  202. detach: false,
  203. }
  204. }
  205. }
  206. impl Process {
  207. /// Creates a new process for the specified program/arguments, using
  208. /// otherwise default configuration.
  209. ///
  210. /// By default, new processes have their stdin/stdout/stderr handles created
  211. /// as pipes the can be manipulated through the respective fields of the
  212. /// returned `Process`.
  213. ///
  214. /// # Example
  215. ///
  216. /// ```
  217. /// use std::io::Process;
  218. ///
  219. /// let mut process = match Process::new("sh", &[~"c", ~"echo hello"]) {
  220. /// Ok(p) => p,
  221. /// Err(e) => fail!("failed to execute process: {}", e),
  222. /// };
  223. ///
  224. /// let output = process.stdout.get_mut_ref().read_to_end();
  225. /// ```
  226. pub fn new(prog: &str, args: &[~str]) -> IoResult<Process> {
  227. Process::configure(ProcessConfig {
  228. program: prog,
  229. args: args,
  230. .. ProcessConfig::new()
  231. })
  232. }
  233. /// Executes the specified program with arguments, waiting for it to finish
  234. /// and collecting all of its output.
  235. ///
  236. /// # Example
  237. ///
  238. /// ```
  239. /// use std::io::Process;
  240. /// use std::str;
  241. ///
  242. /// let output = match Process::output("cat", [~"foo.txt"]) {
  243. /// Ok(output) => output,
  244. /// Err(e) => fail!("failed to execute process: {}", e),
  245. /// };
  246. ///
  247. /// println!("status: {}", output.status);
  248. /// println!("stdout: {}", str::from_utf8_lossy(output.output));
  249. /// println!("stderr: {}", str::from_utf8_lossy(output.error));
  250. /// ```
  251. pub fn output(prog: &str, args: &[~str]) -> IoResult<ProcessOutput> {
  252. Process::new(prog, args).map(|mut p| p.wait_with_output())
  253. }
  254. /// Executes a child process and collects its exit status. This will block
  255. /// waiting for the child to exit.
  256. ///
  257. /// # Example
  258. ///
  259. /// ```
  260. /// use std::io::Process;
  261. ///
  262. /// let status = match Process::status("ls", []) {
  263. /// Ok(status) => status,
  264. /// Err(e) => fail!("failed to execute process: {}", e),
  265. /// };
  266. ///
  267. /// println!("process exited with: {}", status);
  268. /// ```
  269. pub fn status(prog: &str, args: &[~str]) -> IoResult<ProcessExit> {
  270. Process::new(prog, args).map(|mut p| p.wait())
  271. }
  272. /// Creates a new process with the specified configuration.
  273. pub fn configure(config: ProcessConfig) -> IoResult<Process> {
  274. let mut config = Some(config);
  275. LocalIo::maybe_raise(|io| {
  276. io.spawn(config.take_unwrap()).map(|(p, io)| {
  277. let mut io = io.move_iter().map(|p| {
  278. p.map(|p| io::PipeStream::new(p))
  279. });
  280. Process {
  281. handle: p,
  282. stdin: io.next().unwrap(),
  283. stdout: io.next().unwrap(),
  284. stderr: io.next().unwrap(),
  285. extra_io: io.collect(),
  286. }
  287. })
  288. })
  289. }
  290. /// Sends `signal` to another process in the system identified by `id`.
  291. ///
  292. /// Note that windows doesn't quite have the same model as unix, so some
  293. /// unix signals are mapped to windows signals. Notably, unix termination
  294. /// signals (SIGTERM/SIGKILL/SIGINT) are translated to `TerminateProcess`.
  295. ///
  296. /// Additionally, a signal number of 0 can check for existence of the target
  297. /// process. Note, though, that on some platforms signals will continue to
  298. /// be successfully delivered if the child has exited, but not yet been
  299. /// reaped.
  300. pub fn kill(id: libc::pid_t, signal: int) -> IoResult<()> {
  301. LocalIo::maybe_raise(|io| io.kill(id, signal))
  302. }
  303. /// Returns the process id of this child process
  304. pub fn id(&self) -> libc::pid_t { self.handle.id() }
  305. /// Sends the specified signal to the child process, returning whether the
  306. /// signal could be delivered or not.
  307. ///
  308. /// Note that signal 0 is interpreted as a poll to check whether the child
  309. /// process is still alive or not. If an error is returned, then the child
  310. /// process has exited.
  311. ///
  312. /// On some unix platforms signals will continue to be received after a
  313. /// child has exited but not yet been reaped. In order to report the status
  314. /// of signal delivery correctly, unix implementations may invoke
  315. /// `waitpid()` with `WNOHANG` in order to reap the child as necessary.
  316. ///
  317. /// # Errors
  318. ///
  319. /// If the signal delivery fails, the corresponding error is returned.
  320. pub fn signal(&mut self, signal: int) -> IoResult<()> {
  321. self.handle.kill(signal)
  322. }
  323. /// Sends a signal to this child requesting that it exits. This is
  324. /// equivalent to sending a SIGTERM on unix platforms.
  325. pub fn signal_exit(&mut self) -> IoResult<()> {
  326. self.signal(PleaseExitSignal)
  327. }
  328. /// Sends a signal to this child forcing it to exit. This is equivalent to
  329. /// sending a SIGKILL on unix platforms.
  330. pub fn signal_kill(&mut self) -> IoResult<()> {
  331. self.signal(MustDieSignal)
  332. }
  333. /// Wait for the child to exit completely, returning the status that it
  334. /// exited with. This function will continue to have the same return value
  335. /// after it has been called at least once.
  336. ///
  337. /// The stdin handle to the child process will be closed before waiting.
  338. pub fn wait(&mut self) -> ProcessExit {
  339. drop(self.stdin.take());
  340. self.handle.wait()
  341. }
  342. /// Simultaneously wait for the child to exit and collect all remaining
  343. /// output on the stdout/stderr handles, returning a `ProcessOutput`
  344. /// instance.
  345. ///
  346. /// The stdin handle to the child is closed before waiting.
  347. pub fn wait_with_output(&mut self) -> ProcessOutput {
  348. drop(self.stdin.take());
  349. fn read(stream: Option<io::PipeStream>) -> Receiver<IoResult<~[u8]>> {
  350. let (tx, rx) = channel();
  351. match stream {
  352. Some(stream) => spawn(proc() {
  353. let mut stream = stream;
  354. tx.send(stream.read_to_end())
  355. }),
  356. None => tx.send(Ok(~[]))
  357. }
  358. rx
  359. }
  360. let stdout = read(self.stdout.take());
  361. let stderr = read(self.stderr.take());
  362. let status = self.wait();
  363. ProcessOutput { status: status,
  364. output: stdout.recv().ok().unwrap_or(~[]),
  365. error: stderr.recv().ok().unwrap_or(~[]) }
  366. }
  367. }
  368. impl Drop for Process {
  369. fn drop(&mut self) {
  370. // Close all I/O before exiting to ensure that the child doesn't wait
  371. // forever to print some text or something similar.
  372. drop(self.stdin.take());
  373. drop(self.stdout.take());
  374. drop(self.stderr.take());
  375. loop {
  376. match self.extra_io.pop() {
  377. Some(_) => (),
  378. None => break,
  379. }
  380. }
  381. self.wait();
  382. }
  383. }
  384. #[cfg(test)]
  385. mod tests {
  386. use io::process::{ProcessConfig, Process};
  387. use prelude::*;
  388. // FIXME(#10380) these tests should not all be ignored on android.
  389. #[cfg(not(target_os="android"))]
  390. iotest!(fn smoke() {
  391. let args = ProcessConfig {
  392. program: "true",
  393. .. ProcessConfig::new()
  394. };
  395. let p = Process::configure(args);
  396. assert!(p.is_ok());
  397. let mut p = p.unwrap();
  398. assert!(p.wait().success());
  399. })
  400. #[cfg(not(target_os="android"))]
  401. iotest!(fn smoke_failure() {
  402. let args = ProcessConfig {
  403. program: "if-this-is-a-binary-then-the-world-has-ended",
  404. .. ProcessConfig::new()
  405. };
  406. match Process::configure(args) {
  407. Ok(..) => fail!(),
  408. Err(..) => {}
  409. }
  410. })
  411. #[cfg(not(target_os="android"))]
  412. iotest!(fn exit_reported_right() {
  413. let args = ProcessConfig {
  414. program: "false",
  415. .. ProcessConfig::new()
  416. };
  417. let p = Process::configure(args);
  418. assert!(p.is_ok());
  419. let mut p = p.unwrap();
  420. assert!(p.wait().matches_exit_status(1));
  421. drop(p.wait().clone());
  422. })
  423. #[cfg(unix, not(target_os="android"))]
  424. iotest!(fn signal_reported_right() {
  425. let args = ProcessConfig {
  426. program: "/bin/sh",
  427. args: &[~"-c", ~"kill -1 $$"],
  428. .. ProcessConfig::new()
  429. };
  430. let p = Process::configure(args);
  431. assert!(p.is_ok());
  432. let mut p = p.unwrap();
  433. match p.wait() {
  434. process::ExitSignal(1) => {},
  435. result => fail!("not terminated by signal 1 (instead, {})", result),
  436. }
  437. })
  438. pub fn read_all(input: &mut Reader) -> ~str {
  439. input.read_to_str().unwrap()
  440. }
  441. pub fn run_output(args: ProcessConfig) -> ~str {
  442. let p = Process::configure(args);
  443. assert!(p.is_ok());
  444. let mut p = p.unwrap();
  445. assert!(p.stdout.is_some());
  446. let ret = read_all(p.stdout.get_mut_ref() as &mut Reader);
  447. assert!(p.wait().success());
  448. return ret;
  449. }
  450. #[cfg(not(target_os="android"))]
  451. iotest!(fn stdout_works() {
  452. let args = ProcessConfig {
  453. program: "echo",
  454. args: &[~"foobar"],
  455. stdout: CreatePipe(false, true),
  456. .. ProcessConfig::new()
  457. };
  458. assert_eq!(run_output(args), ~"foobar\n");
  459. })
  460. #[cfg(unix, not(target_os="android"))]
  461. iotest!(fn set_cwd_works() {
  462. let cwd = Path::new("/");
  463. let args = ProcessConfig {
  464. program: "/bin/sh",
  465. args: &[~"-c", ~"pwd"],
  466. cwd: Some(&cwd),
  467. stdout: CreatePipe(false, true),
  468. .. ProcessConfig::new()
  469. };
  470. assert_eq!(run_output(args), ~"/\n");
  471. })
  472. #[cfg(unix, not(target_os="android"))]
  473. iotest!(fn stdin_works() {
  474. let args = ProcessConfig {
  475. program: "/bin/sh",
  476. args: &[~"-c", ~"read line; echo $line"],
  477. stdin: CreatePipe(true, false),
  478. stdout: CreatePipe(false, true),
  479. .. ProcessConfig::new()
  480. };
  481. let mut p = Process::configure(args).unwrap();
  482. p.stdin.get_mut_ref().write("foobar".as_bytes()).unwrap();
  483. drop(p.stdin.take());
  484. let out = read_all(p.stdout.get_mut_ref() as &mut Reader);
  485. assert!(p.wait().success());
  486. assert_eq!(out, ~"foobar\n");
  487. })
  488. #[cfg(not(target_os="android"))]
  489. iotest!(fn detach_works() {
  490. let args = ProcessConfig {
  491. program: "true",
  492. detach: true,
  493. .. ProcessConfig::new()
  494. };
  495. let mut p = Process::configure(args).unwrap();
  496. assert!(p.wait().success());
  497. })
  498. #[cfg(windows)]
  499. iotest!(fn uid_fails_on_windows() {
  500. let args = ProcessConfig {
  501. program: "test",
  502. uid: Some(10),
  503. .. ProcessConfig::new()
  504. };
  505. assert!(Process::configure(args).is_err());
  506. })
  507. #[cfg(unix, not(target_os="android"))]
  508. iotest!(fn uid_works() {
  509. use libc;
  510. let args = ProcessConfig {
  511. program: "/bin/sh",
  512. args: &[~"-c", ~"true"],
  513. uid: Some(unsafe { libc::getuid() as uint }),
  514. gid: Some(unsafe { libc::getgid() as uint }),
  515. .. ProcessConfig::new()
  516. };
  517. let mut p = Process::configure(args).unwrap();
  518. assert!(p.wait().success());
  519. })
  520. #[cfg(unix, not(target_os="android"))]
  521. iotest!(fn uid_to_root_fails() {
  522. use libc;
  523. // if we're already root, this isn't a valid test. Most of the bots run
  524. // as non-root though (android is an exception).
  525. if unsafe { libc::getuid() == 0 } { return }
  526. let args = ProcessConfig {
  527. program: "/bin/ls",
  528. uid: Some(0),
  529. gid: Some(0),
  530. .. ProcessConfig::new()
  531. };
  532. assert!(Process::configure(args).is_err());
  533. })
  534. #[cfg(not(target_os="android"))]
  535. iotest!(fn test_process_status() {
  536. let mut status = Process::status("false", []).unwrap();
  537. assert!(status.matches_exit_status(1));
  538. status = Process::status("true", []).unwrap();
  539. assert!(status.success());
  540. })
  541. iotest!(fn test_process_output_fail_to_start() {
  542. match Process::output("/no-binary-by-this-name-should-exist", []) {
  543. Err(e) => assert_eq!(e.kind, FileNotFound),
  544. Ok(..) => fail!()
  545. }
  546. })
  547. #[cfg(not(target_os="android"))]
  548. iotest!(fn test_process_output_output() {
  549. let ProcessOutput {status, output, error}
  550. = Process::output("echo", [~"hello"]).unwrap();
  551. let output_str = str::from_utf8_owned(output).unwrap();
  552. assert!(status.success());
  553. assert_eq!(output_str.trim().to_owned(), ~"hello");
  554. // FIXME #7224
  555. if !running_on_valgrind() {
  556. assert_eq!(error, ~[]);
  557. }
  558. })
  559. #[cfg(not(target_os="android"))]
  560. iotest!(fn test_process_output_error() {
  561. let ProcessOutput {status, output, error}
  562. = Process::output("mkdir", [~"."]).unwrap();
  563. assert!(status.matches_exit_status(1));
  564. assert_eq!(output, ~[]);
  565. assert!(!error.is_empty());
  566. })
  567. #[cfg(not(target_os="android"))]
  568. iotest!(fn test_finish_once() {
  569. let mut prog = Process::new("false", []).unwrap();
  570. assert!(prog.wait().matches_exit_status(1));
  571. })
  572. #[cfg(not(target_os="android"))]
  573. iotest!(fn test_finish_twice() {
  574. let mut prog = Process::new("false", []).unwrap();
  575. assert!(prog.wait().matches_exit_status(1));
  576. assert!(prog.wait().matches_exit_status(1));
  577. })
  578. #[cfg(not(target_os="android"))]
  579. iotest!(fn test_wait_with_output_once() {
  580. let mut prog = Process::new("echo", [~"hello"]).unwrap();
  581. let ProcessOutput {status, output, error} = prog.wait_with_output();
  582. let output_str = str::from_utf8_owned(output).unwrap();
  583. assert!(status.success());
  584. assert_eq!(output_str.trim().to_owned(), ~"hello");
  585. // FIXME #7224
  586. if !running_on_valgrind() {
  587. assert_eq!(error, ~[]);
  588. }
  589. })
  590. #[cfg(not(target_os="android"))]
  591. iotest!(fn test_wait_with_output_twice() {
  592. let mut prog = Process::new("echo", [~"hello"]).unwrap();
  593. let ProcessOutput {status, output, error} = prog.wait_with_output();
  594. let output_str = str::from_utf8_owned(output).unwrap();
  595. assert!(status.success());
  596. assert_eq!(output_str.trim().to_owned(), ~"hello");
  597. // FIXME #7224
  598. if !running_on_valgrind() {
  599. assert_eq!(error, ~[]);
  600. }
  601. let ProcessOutput {status, output, error} = prog.wait_with_output();
  602. assert!(status.success());
  603. assert_eq!(output, ~[]);
  604. // FIXME #7224
  605. if !running_on_valgrind() {
  606. assert_eq!(error, ~[]);
  607. }
  608. })
  609. #[cfg(unix,not(target_os="android"))]
  610. pub fn run_pwd(dir: Option<&Path>) -> Process {
  611. Process::configure(ProcessConfig {
  612. program: "pwd",
  613. cwd: dir,
  614. .. ProcessConfig::new()
  615. }).unwrap()
  616. }
  617. #[cfg(target_os="android")]
  618. pub fn run_pwd(dir: Option<&Path>) -> Process {
  619. Process::configure(ProcessConfig {
  620. program: "/system/bin/sh",
  621. args: &[~"-c",~"pwd"],
  622. cwd: dir.map(|a| &*a),
  623. .. ProcessConfig::new()
  624. }).unwrap()
  625. }
  626. #[cfg(windows)]
  627. pub fn run_pwd(dir: Option<&Path>) -> Process {
  628. Process::configure(ProcessConfig {
  629. program: "cmd",
  630. args: &[~"/c", ~"cd"],
  631. cwd: dir.map(|a| &*a),
  632. .. ProcessConfig::new()
  633. }).unwrap()
  634. }
  635. iotest!(fn test_keep_current_working_dir() {
  636. use os;
  637. let mut prog = run_pwd(None);
  638. let output = str::from_utf8_owned(prog.wait_with_output().output).unwrap();
  639. let parent_dir = os::getcwd();
  640. let child_dir = Path::new(output.trim());
  641. let parent_stat = parent_dir.stat().unwrap();
  642. let child_stat = child_dir.stat().unwrap();
  643. assert_eq!(parent_stat.unstable.device, child_stat.unstable.device);
  644. assert_eq!(parent_stat.unstable.inode, child_stat.unstable.inode);
  645. })
  646. iotest!(fn test_change_working_directory() {
  647. use os;
  648. // test changing to the parent of os::getcwd() because we know
  649. // the path exists (and os::getcwd() is not expected to be root)
  650. let parent_dir = os::getcwd().dir_path();
  651. let mut prog = run_pwd(Some(&parent_dir));
  652. let output = str::from_utf8_owned(prog.wait_with_output().output).unwrap();
  653. let child_dir = Path::new(output.trim());
  654. let parent_stat = parent_dir.stat().unwrap();
  655. let child_stat = child_dir.stat().unwrap();
  656. assert_eq!(parent_stat.unstable.device, child_stat.unstable.device);
  657. assert_eq!(parent_stat.unstable.inode, child_stat.unstable.inode);
  658. })
  659. #[cfg(unix,not(target_os="android"))]
  660. pub fn run_env(env: Option<~[(~str, ~str)]>) -> Process {
  661. Process::configure(ProcessConfig {
  662. program: "env",
  663. env: env.as_ref().map(|e| e.as_slice()),
  664. .. ProcessConfig::new()
  665. }).unwrap()
  666. }
  667. #[cfg(target_os="android")]
  668. pub fn run_env(env: Option<~[(~str, ~str)]>) -> Process {
  669. Process::configure(ProcessConfig {
  670. program: "/system/bin/sh",
  671. args: &[~"-c",~"set"],
  672. env: env.as_ref().map(|e| e.as_slice()),
  673. .. ProcessConfig::new()
  674. }).unwrap()
  675. }
  676. #[cfg(windows)]
  677. pub fn run_env(env: Option<~[(~str, ~str)]>) -> Process {
  678. Process::configure(ProcessConfig {
  679. program: "cmd",
  680. args: &[~"/c", ~"set"],
  681. env: env.as_ref().map(|e| e.as_slice()),
  682. .. ProcessConfig::new()
  683. }).unwrap()
  684. }
  685. #[cfg(not(target_os="android"))]
  686. iotest!(fn test_inherit_env() {
  687. use os;
  688. if running_on_valgrind() { return; }
  689. let mut prog = run_env(None);
  690. let output = str::from_utf8_owned(prog.wait_with_output().output).unwrap();
  691. let r = os::env();
  692. for &(ref k, ref v) in r.iter() {
  693. // don't check windows magical empty-named variables
  694. assert!(k.is_empty() || output.contains(format!("{}={}", *k, *v)));
  695. }
  696. })
  697. #[cfg(target_os="android")]
  698. iotest!(fn test_inherit_env() {
  699. use os;
  700. if running_on_valgrind() { return; }
  701. let mut prog = run_env(None);
  702. let output = str::from_utf8_owned(prog.wait_with_output().output).unwrap();
  703. let r = os::env();
  704. for &(ref k, ref v) in r.iter() {
  705. // don't check android RANDOM variables
  706. if *k != ~"RANDOM" {
  707. assert!(output.contains(format!("{}={}", *k, *v)) ||
  708. output.contains(format!("{}=\'{}\'", *k, *v)));
  709. }
  710. }
  711. })
  712. iotest!(fn test_add_to_env() {
  713. let new_env = ~[(~"RUN_TEST_NEW_ENV", ~"123")];
  714. let mut prog = run_env(Some(new_env));
  715. let result = prog.wait_with_output();
  716. let output = str::from_utf8_lossy(result.output).into_owned();
  717. assert!(output.contains("RUN_TEST_NEW_ENV=123"),
  718. "didn't find RUN_TEST_NEW_ENV inside of:\n\n{}", output);
  719. })
  720. #[cfg(unix)]
  721. pub fn sleeper() -> Process {
  722. Process::new("sleep", [~"1000"]).unwrap()
  723. }
  724. #[cfg(windows)]
  725. pub fn sleeper() -> Process {
  726. // There's a `timeout` command on windows, but it doesn't like having
  727. // its output piped, so instead just ping ourselves a few times with
  728. // gaps inbetweeen so we're sure this process is alive for awhile
  729. Process::new("ping", [~"127.0.0.1", ~"-n", ~"1000"]).unwrap()
  730. }
  731. iotest!(fn test_kill() {
  732. let mut p = sleeper();
  733. Process::kill(p.id(), PleaseExitSignal).unwrap();
  734. assert!(!p.wait().success());
  735. })
  736. iotest!(fn test_exists() {
  737. let mut p = sleeper();
  738. assert!(Process::kill(p.id(), 0).is_ok());
  739. p.signal_kill().unwrap();
  740. assert!(!p.wait().success());
  741. })
  742. iotest!(fn test_zero() {
  743. let mut p = sleeper();
  744. p.signal_kill().unwrap();
  745. for _ in range(0, 20) {
  746. if p.signal(0).is_err() {
  747. assert!(!p.wait().success());
  748. return
  749. }
  750. timer::sleep(100);
  751. }
  752. fail!("never saw the child go away");
  753. })
  754. }