]>
Commit | Line | Data |
---|---|---|
85aaf69f SL |
1 | // Copyright 2015 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 | ||
11 | //! Working with processes. | |
12 | ||
c34b1796 | 13 | #![stable(feature = "process", since = "1.0.0")] |
85aaf69f SL |
14 | #![allow(non_upper_case_globals)] |
15 | ||
16 | use prelude::v1::*; | |
17 | use io::prelude::*; | |
18 | ||
c34b1796 | 19 | use ffi::OsStr; |
85aaf69f SL |
20 | use fmt; |
21 | use io::{self, Error, ErrorKind}; | |
c34b1796 | 22 | use path; |
85aaf69f | 23 | use sync::mpsc::{channel, Receiver}; |
d9579d0f | 24 | use sys::pipe::{self, AnonPipe}; |
62682a34 SL |
25 | use sys::process as imp; |
26 | use sys_common::{AsInner, AsInnerMut, FromInner}; | |
85aaf69f SL |
27 | use thread; |
28 | ||
29 | /// Representation of a running or exited child process. | |
30 | /// | |
31 | /// This structure is used to represent and manage child processes. A child | |
32 | /// process is created via the `Command` struct, which configures the spawning | |
33 | /// process and can itself be constructed using a builder-style interface. | |
34 | /// | |
c34b1796 | 35 | /// # Examples |
85aaf69f | 36 | /// |
c34b1796 | 37 | /// ```should_panic |
85aaf69f SL |
38 | /// use std::process::Command; |
39 | /// | |
bd371182 AL |
40 | /// let mut child = Command::new("/bin/cat") |
41 | /// .arg("file.txt") | |
42 | /// .spawn() | |
43 | /// .unwrap_or_else(|e| { panic!("failed to execute child: {}", e) }); | |
44 | /// | |
45 | /// let ecode = child.wait() | |
46 | /// .unwrap_or_else(|e| { panic!("failed to wait on child: {}", e) }); | |
47 | /// | |
48 | /// assert!(ecode.success()); | |
85aaf69f | 49 | /// ``` |
c34b1796 | 50 | #[stable(feature = "process", since = "1.0.0")] |
85aaf69f | 51 | pub struct Child { |
62682a34 | 52 | handle: imp::Process, |
85aaf69f SL |
53 | |
54 | /// None until wait() or wait_with_output() is called. | |
62682a34 | 55 | status: Option<imp::ExitStatus>, |
85aaf69f SL |
56 | |
57 | /// The handle for writing to the child's stdin, if it has been captured | |
c34b1796 | 58 | #[stable(feature = "process", since = "1.0.0")] |
85aaf69f SL |
59 | pub stdin: Option<ChildStdin>, |
60 | ||
61 | /// The handle for reading from the child's stdout, if it has been captured | |
c34b1796 | 62 | #[stable(feature = "process", since = "1.0.0")] |
85aaf69f SL |
63 | pub stdout: Option<ChildStdout>, |
64 | ||
65 | /// The handle for reading from the child's stderr, if it has been captured | |
c34b1796 | 66 | #[stable(feature = "process", since = "1.0.0")] |
85aaf69f SL |
67 | pub stderr: Option<ChildStderr>, |
68 | } | |
69 | ||
62682a34 SL |
70 | impl AsInner<imp::Process> for Child { |
71 | fn as_inner(&self) -> &imp::Process { &self.handle } | |
72 | } | |
73 | ||
85aaf69f | 74 | /// A handle to a child procesess's stdin |
c34b1796 | 75 | #[stable(feature = "process", since = "1.0.0")] |
85aaf69f SL |
76 | pub struct ChildStdin { |
77 | inner: AnonPipe | |
78 | } | |
79 | ||
c34b1796 | 80 | #[stable(feature = "process", since = "1.0.0")] |
85aaf69f SL |
81 | impl Write for ChildStdin { |
82 | fn write(&mut self, buf: &[u8]) -> io::Result<usize> { | |
83 | self.inner.write(buf) | |
84 | } | |
85 | ||
86 | fn flush(&mut self) -> io::Result<()> { | |
87 | Ok(()) | |
88 | } | |
89 | } | |
90 | ||
62682a34 SL |
91 | impl AsInner<AnonPipe> for ChildStdin { |
92 | fn as_inner(&self) -> &AnonPipe { &self.inner } | |
93 | } | |
94 | ||
85aaf69f | 95 | /// A handle to a child procesess's stdout |
c34b1796 | 96 | #[stable(feature = "process", since = "1.0.0")] |
85aaf69f SL |
97 | pub struct ChildStdout { |
98 | inner: AnonPipe | |
99 | } | |
100 | ||
c34b1796 | 101 | #[stable(feature = "process", since = "1.0.0")] |
85aaf69f SL |
102 | impl Read for ChildStdout { |
103 | fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { | |
104 | self.inner.read(buf) | |
105 | } | |
106 | } | |
107 | ||
62682a34 SL |
108 | impl AsInner<AnonPipe> for ChildStdout { |
109 | fn as_inner(&self) -> &AnonPipe { &self.inner } | |
110 | } | |
111 | ||
85aaf69f | 112 | /// A handle to a child procesess's stderr |
c34b1796 | 113 | #[stable(feature = "process", since = "1.0.0")] |
85aaf69f SL |
114 | pub struct ChildStderr { |
115 | inner: AnonPipe | |
116 | } | |
117 | ||
c34b1796 | 118 | #[stable(feature = "process", since = "1.0.0")] |
85aaf69f SL |
119 | impl Read for ChildStderr { |
120 | fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { | |
121 | self.inner.read(buf) | |
122 | } | |
123 | } | |
124 | ||
62682a34 SL |
125 | impl AsInner<AnonPipe> for ChildStderr { |
126 | fn as_inner(&self) -> &AnonPipe { &self.inner } | |
127 | } | |
128 | ||
85aaf69f SL |
129 | /// The `Command` type acts as a process builder, providing fine-grained control |
130 | /// over how a new process should be spawned. A default configuration can be | |
131 | /// generated using `Command::new(program)`, where `program` gives a path to the | |
132 | /// program to be executed. Additional builder methods allow the configuration | |
133 | /// to be changed (for example, by adding arguments) prior to spawning: | |
134 | /// | |
135 | /// ``` | |
85aaf69f SL |
136 | /// use std::process::Command; |
137 | /// | |
bd371182 AL |
138 | /// let output = Command::new("sh") |
139 | /// .arg("-c") | |
140 | /// .arg("echo hello") | |
141 | /// .output() | |
142 | /// .unwrap_or_else(|e| { panic!("failed to execute process: {}", e) }); | |
85aaf69f SL |
143 | /// let hello = output.stdout; |
144 | /// ``` | |
c34b1796 | 145 | #[stable(feature = "process", since = "1.0.0")] |
85aaf69f | 146 | pub struct Command { |
62682a34 | 147 | inner: imp::Command, |
85aaf69f SL |
148 | |
149 | // Details explained in the builder methods | |
62682a34 SL |
150 | stdin: Option<Stdio>, |
151 | stdout: Option<Stdio>, | |
152 | stderr: Option<Stdio>, | |
85aaf69f SL |
153 | } |
154 | ||
155 | impl Command { | |
156 | /// Constructs a new `Command` for launching the program at | |
157 | /// path `program`, with the following default configuration: | |
158 | /// | |
159 | /// * No arguments to the program | |
160 | /// * Inherit the current process's environment | |
161 | /// * Inherit the current process's working directory | |
bd371182 | 162 | /// * Inherit stdin/stdout/stderr for `spawn` or `status`, but create pipes for `output` |
85aaf69f SL |
163 | /// |
164 | /// Builder methods are provided to change these defaults and | |
165 | /// otherwise configure the process. | |
c34b1796 AL |
166 | #[stable(feature = "process", since = "1.0.0")] |
167 | pub fn new<S: AsRef<OsStr>>(program: S) -> Command { | |
85aaf69f | 168 | Command { |
62682a34 | 169 | inner: imp::Command::new(program.as_ref()), |
85aaf69f SL |
170 | stdin: None, |
171 | stdout: None, | |
172 | stderr: None, | |
173 | } | |
174 | } | |
175 | ||
176 | /// Add an argument to pass to the program. | |
c34b1796 AL |
177 | #[stable(feature = "process", since = "1.0.0")] |
178 | pub fn arg<S: AsRef<OsStr>>(&mut self, arg: S) -> &mut Command { | |
179 | self.inner.arg(arg.as_ref()); | |
85aaf69f SL |
180 | self |
181 | } | |
182 | ||
183 | /// Add multiple arguments to pass to the program. | |
c34b1796 AL |
184 | #[stable(feature = "process", since = "1.0.0")] |
185 | pub fn args<S: AsRef<OsStr>>(&mut self, args: &[S]) -> &mut Command { | |
186 | self.inner.args(args.iter().map(AsRef::as_ref)); | |
85aaf69f SL |
187 | self |
188 | } | |
189 | ||
190 | /// Inserts or updates an environment variable mapping. | |
191 | /// | |
192 | /// Note that environment variable names are case-insensitive (but case-preserving) on Windows, | |
193 | /// and case-sensitive on all other platforms. | |
c34b1796 AL |
194 | #[stable(feature = "process", since = "1.0.0")] |
195 | pub fn env<K, V>(&mut self, key: K, val: V) -> &mut Command | |
196 | where K: AsRef<OsStr>, V: AsRef<OsStr> | |
85aaf69f | 197 | { |
c34b1796 | 198 | self.inner.env(key.as_ref(), val.as_ref()); |
85aaf69f SL |
199 | self |
200 | } | |
201 | ||
202 | /// Removes an environment variable mapping. | |
c34b1796 AL |
203 | #[stable(feature = "process", since = "1.0.0")] |
204 | pub fn env_remove<K: AsRef<OsStr>>(&mut self, key: K) -> &mut Command { | |
205 | self.inner.env_remove(key.as_ref()); | |
85aaf69f SL |
206 | self |
207 | } | |
208 | ||
209 | /// Clears the entire environment map for the child process. | |
c34b1796 | 210 | #[stable(feature = "process", since = "1.0.0")] |
85aaf69f SL |
211 | pub fn env_clear(&mut self) -> &mut Command { |
212 | self.inner.env_clear(); | |
213 | self | |
214 | } | |
215 | ||
9346a6ac | 216 | /// Sets the working directory for the child process. |
c34b1796 AL |
217 | #[stable(feature = "process", since = "1.0.0")] |
218 | pub fn current_dir<P: AsRef<path::Path>>(&mut self, dir: P) -> &mut Command { | |
219 | self.inner.cwd(dir.as_ref().as_ref()); | |
85aaf69f SL |
220 | self |
221 | } | |
222 | ||
223 | /// Configuration for the child process's stdin handle (file descriptor 0). | |
c34b1796 | 224 | #[stable(feature = "process", since = "1.0.0")] |
85aaf69f | 225 | pub fn stdin(&mut self, cfg: Stdio) -> &mut Command { |
62682a34 | 226 | self.stdin = Some(cfg); |
85aaf69f SL |
227 | self |
228 | } | |
229 | ||
230 | /// Configuration for the child process's stdout handle (file descriptor 1). | |
c34b1796 | 231 | #[stable(feature = "process", since = "1.0.0")] |
85aaf69f | 232 | pub fn stdout(&mut self, cfg: Stdio) -> &mut Command { |
62682a34 | 233 | self.stdout = Some(cfg); |
85aaf69f SL |
234 | self |
235 | } | |
236 | ||
237 | /// Configuration for the child process's stderr handle (file descriptor 2). | |
c34b1796 | 238 | #[stable(feature = "process", since = "1.0.0")] |
85aaf69f | 239 | pub fn stderr(&mut self, cfg: Stdio) -> &mut Command { |
62682a34 | 240 | self.stderr = Some(cfg); |
85aaf69f SL |
241 | self |
242 | } | |
243 | ||
244 | fn spawn_inner(&self, default_io: StdioImp) -> io::Result<Child> { | |
62682a34 SL |
245 | let default_io = Stdio(default_io); |
246 | ||
247 | // See comment on `setup_io` for what `_drop_later` is. | |
248 | let (their_stdin, our_stdin, _drop_later) = try!( | |
9346a6ac | 249 | setup_io(self.stdin.as_ref().unwrap_or(&default_io), true) |
85aaf69f | 250 | ); |
62682a34 | 251 | let (their_stdout, our_stdout, _drop_later) = try!( |
9346a6ac | 252 | setup_io(self.stdout.as_ref().unwrap_or(&default_io), false) |
85aaf69f | 253 | ); |
62682a34 | 254 | let (their_stderr, our_stderr, _drop_later) = try!( |
9346a6ac | 255 | setup_io(self.stderr.as_ref().unwrap_or(&default_io), false) |
85aaf69f SL |
256 | ); |
257 | ||
62682a34 SL |
258 | match imp::Process::spawn(&self.inner, their_stdin, their_stdout, |
259 | their_stderr) { | |
85aaf69f SL |
260 | Err(e) => Err(e), |
261 | Ok(handle) => Ok(Child { | |
262 | handle: handle, | |
263 | status: None, | |
264 | stdin: our_stdin.map(|fd| ChildStdin { inner: fd }), | |
265 | stdout: our_stdout.map(|fd| ChildStdout { inner: fd }), | |
266 | stderr: our_stderr.map(|fd| ChildStderr { inner: fd }), | |
267 | }) | |
268 | } | |
269 | } | |
270 | ||
271 | /// Executes the command as a child process, returning a handle to it. | |
272 | /// | |
62682a34 | 273 | /// By default, stdin, stdout and stderr are inherited from the parent. |
c34b1796 | 274 | #[stable(feature = "process", since = "1.0.0")] |
85aaf69f SL |
275 | pub fn spawn(&mut self) -> io::Result<Child> { |
276 | self.spawn_inner(StdioImp::Inherit) | |
277 | } | |
278 | ||
279 | /// Executes the command as a child process, waiting for it to finish and | |
280 | /// collecting all of its output. | |
281 | /// | |
282 | /// By default, stdin, stdout and stderr are captured (and used to | |
283 | /// provide the resulting output). | |
284 | /// | |
c34b1796 | 285 | /// # Examples |
85aaf69f SL |
286 | /// |
287 | /// ``` | |
85aaf69f | 288 | /// use std::process::Command; |
9346a6ac | 289 | /// let output = Command::new("cat").arg("foo.txt").output().unwrap_or_else(|e| { |
85aaf69f SL |
290 | /// panic!("failed to execute process: {}", e) |
291 | /// }); | |
292 | /// | |
293 | /// println!("status: {}", output.status); | |
c34b1796 AL |
294 | /// println!("stdout: {}", String::from_utf8_lossy(&output.stdout)); |
295 | /// println!("stderr: {}", String::from_utf8_lossy(&output.stderr)); | |
85aaf69f | 296 | /// ``` |
c34b1796 | 297 | #[stable(feature = "process", since = "1.0.0")] |
85aaf69f | 298 | pub fn output(&mut self) -> io::Result<Output> { |
62682a34 | 299 | self.spawn_inner(StdioImp::MakePipe).and_then(|p| p.wait_with_output()) |
85aaf69f SL |
300 | } |
301 | ||
302 | /// Executes a command as a child process, waiting for it to finish and | |
303 | /// collecting its exit status. | |
304 | /// | |
62682a34 | 305 | /// By default, stdin, stdout and stderr are inherited from the parent. |
85aaf69f | 306 | /// |
c34b1796 | 307 | /// # Examples |
85aaf69f SL |
308 | /// |
309 | /// ``` | |
85aaf69f SL |
310 | /// use std::process::Command; |
311 | /// | |
312 | /// let status = Command::new("ls").status().unwrap_or_else(|e| { | |
313 | /// panic!("failed to execute process: {}", e) | |
314 | /// }); | |
315 | /// | |
316 | /// println!("process exited with: {}", status); | |
317 | /// ``` | |
c34b1796 | 318 | #[stable(feature = "process", since = "1.0.0")] |
85aaf69f SL |
319 | pub fn status(&mut self) -> io::Result<ExitStatus> { |
320 | self.spawn().and_then(|mut p| p.wait()) | |
321 | } | |
322 | } | |
323 | ||
324 | #[stable(feature = "rust1", since = "1.0.0")] | |
325 | impl fmt::Debug for Command { | |
326 | /// Format the program and arguments of a Command for display. Any | |
327 | /// non-utf8 data is lossily converted using the utf8 replacement | |
328 | /// character. | |
329 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
330 | try!(write!(f, "{:?}", self.inner.program)); | |
331 | for arg in &self.inner.args { | |
332 | try!(write!(f, " {:?}", arg)); | |
333 | } | |
334 | Ok(()) | |
335 | } | |
336 | } | |
337 | ||
62682a34 SL |
338 | impl AsInner<imp::Command> for Command { |
339 | fn as_inner(&self) -> &imp::Command { &self.inner } | |
85aaf69f SL |
340 | } |
341 | ||
62682a34 SL |
342 | impl AsInnerMut<imp::Command> for Command { |
343 | fn as_inner_mut(&mut self) -> &mut imp::Command { &mut self.inner } | |
85aaf69f SL |
344 | } |
345 | ||
62682a34 SL |
346 | // Takes a `Stdio` configuration (this module) and whether the to-be-owned |
347 | // handle will be readable. | |
348 | // | |
349 | // Returns a triple of (stdio to spawn with, stdio to store, stdio to drop). The | |
350 | // stdio to spawn with is passed down to the `sys` module and indicates how the | |
351 | // stdio stream should be set up. The "stdio to store" is an object which | |
352 | // should be returned in the `Child` that makes its way out. The "stdio to drop" | |
353 | // represents the raw value of "stdio to spawn with", but is the owned variant | |
354 | // for it. This needs to be dropped after the child spawns | |
355 | fn setup_io(io: &Stdio, readable: bool) | |
356 | -> io::Result<(imp::Stdio, Option<AnonPipe>, Option<AnonPipe>)> | |
85aaf69f | 357 | { |
62682a34 SL |
358 | Ok(match io.0 { |
359 | StdioImp::MakePipe => { | |
d9579d0f | 360 | let (reader, writer) = try!(pipe::anon_pipe()); |
85aaf69f | 361 | if readable { |
62682a34 | 362 | (imp::Stdio::Raw(reader.raw()), Some(writer), Some(reader)) |
85aaf69f | 363 | } else { |
62682a34 | 364 | (imp::Stdio::Raw(writer.raw()), Some(reader), Some(writer)) |
85aaf69f SL |
365 | } |
366 | } | |
62682a34 SL |
367 | StdioImp::Raw(ref owned) => (imp::Stdio::Raw(owned.raw()), None, None), |
368 | StdioImp::Inherit => (imp::Stdio::Inherit, None, None), | |
369 | StdioImp::None => (imp::Stdio::None, None, None), | |
85aaf69f SL |
370 | }) |
371 | } | |
372 | ||
373 | /// The output of a finished process. | |
374 | #[derive(PartialEq, Eq, Clone)] | |
c34b1796 | 375 | #[stable(feature = "process", since = "1.0.0")] |
85aaf69f SL |
376 | pub struct Output { |
377 | /// The status (exit code) of the process. | |
c34b1796 | 378 | #[stable(feature = "process", since = "1.0.0")] |
85aaf69f SL |
379 | pub status: ExitStatus, |
380 | /// The data that the process wrote to stdout. | |
c34b1796 | 381 | #[stable(feature = "process", since = "1.0.0")] |
85aaf69f SL |
382 | pub stdout: Vec<u8>, |
383 | /// The data that the process wrote to stderr. | |
c34b1796 | 384 | #[stable(feature = "process", since = "1.0.0")] |
85aaf69f SL |
385 | pub stderr: Vec<u8>, |
386 | } | |
387 | ||
bd371182 | 388 | /// Describes what to do with a standard I/O stream for a child process. |
c34b1796 | 389 | #[stable(feature = "process", since = "1.0.0")] |
85aaf69f SL |
390 | pub struct Stdio(StdioImp); |
391 | ||
392 | // The internal enum for stdio setup; see below for descriptions. | |
85aaf69f | 393 | enum StdioImp { |
62682a34 SL |
394 | MakePipe, |
395 | Raw(imp::RawStdio), | |
85aaf69f | 396 | Inherit, |
62682a34 | 397 | None, |
85aaf69f SL |
398 | } |
399 | ||
400 | impl Stdio { | |
401 | /// A new pipe should be arranged to connect the parent and child processes. | |
c34b1796 | 402 | #[stable(feature = "process", since = "1.0.0")] |
62682a34 | 403 | pub fn piped() -> Stdio { Stdio(StdioImp::MakePipe) } |
85aaf69f SL |
404 | |
405 | /// The child inherits from the corresponding parent descriptor. | |
c34b1796 AL |
406 | #[stable(feature = "process", since = "1.0.0")] |
407 | pub fn inherit() -> Stdio { Stdio(StdioImp::Inherit) } | |
85aaf69f SL |
408 | |
409 | /// This stream will be ignored. This is the equivalent of attaching the | |
410 | /// stream to `/dev/null` | |
c34b1796 | 411 | #[stable(feature = "process", since = "1.0.0")] |
62682a34 SL |
412 | pub fn null() -> Stdio { Stdio(StdioImp::None) } |
413 | } | |
414 | ||
415 | impl FromInner<imp::RawStdio> for Stdio { | |
416 | fn from_inner(inner: imp::RawStdio) -> Stdio { | |
417 | Stdio(StdioImp::Raw(inner)) | |
418 | } | |
85aaf69f SL |
419 | } |
420 | ||
421 | /// Describes the result of a process after it has terminated. | |
422 | #[derive(PartialEq, Eq, Clone, Copy, Debug)] | |
c34b1796 | 423 | #[stable(feature = "process", since = "1.0.0")] |
62682a34 | 424 | pub struct ExitStatus(imp::ExitStatus); |
85aaf69f SL |
425 | |
426 | impl ExitStatus { | |
427 | /// Was termination successful? Signal termination not considered a success, | |
428 | /// and success is defined as a zero exit status. | |
c34b1796 | 429 | #[stable(feature = "process", since = "1.0.0")] |
85aaf69f SL |
430 | pub fn success(&self) -> bool { |
431 | self.0.success() | |
432 | } | |
433 | ||
9346a6ac | 434 | /// Returns the exit code of the process, if any. |
85aaf69f SL |
435 | /// |
436 | /// On Unix, this will return `None` if the process was terminated | |
437 | /// by a signal; `std::os::unix` provides an extension trait for | |
438 | /// extracting the signal and other details from the `ExitStatus`. | |
c34b1796 | 439 | #[stable(feature = "process", since = "1.0.0")] |
85aaf69f SL |
440 | pub fn code(&self) -> Option<i32> { |
441 | self.0.code() | |
442 | } | |
443 | } | |
444 | ||
62682a34 SL |
445 | impl AsInner<imp::ExitStatus> for ExitStatus { |
446 | fn as_inner(&self) -> &imp::ExitStatus { &self.0 } | |
85aaf69f SL |
447 | } |
448 | ||
c34b1796 | 449 | #[stable(feature = "process", since = "1.0.0")] |
85aaf69f SL |
450 | impl fmt::Display for ExitStatus { |
451 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
452 | self.0.fmt(f) | |
453 | } | |
454 | } | |
455 | ||
456 | impl Child { | |
457 | /// Forces the child to exit. This is equivalent to sending a | |
458 | /// SIGKILL on unix platforms. | |
c34b1796 | 459 | #[stable(feature = "process", since = "1.0.0")] |
85aaf69f SL |
460 | pub fn kill(&mut self) -> io::Result<()> { |
461 | #[cfg(unix)] fn collect_status(p: &mut Child) { | |
462 | // On Linux (and possibly other unices), a process that has exited will | |
463 | // continue to accept signals because it is "defunct". The delivery of | |
464 | // signals will only fail once the child has been reaped. For this | |
465 | // reason, if the process hasn't exited yet, then we attempt to collect | |
466 | // their status with WNOHANG. | |
467 | if p.status.is_none() { | |
468 | match p.handle.try_wait() { | |
469 | Some(status) => { p.status = Some(status); } | |
470 | None => {} | |
471 | } | |
472 | } | |
473 | } | |
474 | #[cfg(windows)] fn collect_status(_p: &mut Child) {} | |
475 | ||
476 | collect_status(self); | |
477 | ||
478 | // if the process has finished, and therefore had waitpid called, | |
479 | // and we kill it, then on unix we might ending up killing a | |
480 | // newer process that happens to have the same (re-used) id | |
481 | if self.status.is_some() { | |
482 | return Err(Error::new( | |
483 | ErrorKind::InvalidInput, | |
484 | "invalid argument: can't kill an exited process", | |
85aaf69f SL |
485 | )) |
486 | } | |
487 | ||
488 | unsafe { self.handle.kill() } | |
489 | } | |
490 | ||
62682a34 SL |
491 | /// Returns the OS-assigned process identifier associated with this child. |
492 | #[unstable(feature = "process_id", reason = "api recently added")] | |
493 | pub fn id(&self) -> u32 { | |
494 | self.handle.id() | |
495 | } | |
496 | ||
9346a6ac | 497 | /// Waits for the child to exit completely, returning the status that it |
85aaf69f SL |
498 | /// exited with. This function will continue to have the same return value |
499 | /// after it has been called at least once. | |
500 | /// | |
501 | /// The stdin handle to the child process, if any, will be closed | |
502 | /// before waiting. This helps avoid deadlock: it ensures that the | |
503 | /// child does not block waiting for input from the parent, while | |
504 | /// the parent waits for the child to exit. | |
c34b1796 | 505 | #[stable(feature = "process", since = "1.0.0")] |
85aaf69f SL |
506 | pub fn wait(&mut self) -> io::Result<ExitStatus> { |
507 | drop(self.stdin.take()); | |
508 | match self.status { | |
509 | Some(code) => Ok(ExitStatus(code)), | |
510 | None => { | |
511 | let status = try!(self.handle.wait()); | |
512 | self.status = Some(status); | |
513 | Ok(ExitStatus(status)) | |
514 | } | |
515 | } | |
516 | } | |
517 | ||
9346a6ac | 518 | /// Simultaneously waits for the child to exit and collect all remaining |
85aaf69f SL |
519 | /// output on the stdout/stderr handles, returning a `Output` |
520 | /// instance. | |
521 | /// | |
522 | /// The stdin handle to the child process, if any, will be closed | |
523 | /// before waiting. This helps avoid deadlock: it ensures that the | |
524 | /// child does not block waiting for input from the parent, while | |
525 | /// the parent waits for the child to exit. | |
c34b1796 | 526 | #[stable(feature = "process", since = "1.0.0")] |
85aaf69f SL |
527 | pub fn wait_with_output(mut self) -> io::Result<Output> { |
528 | drop(self.stdin.take()); | |
529 | fn read<T: Read + Send + 'static>(stream: Option<T>) -> Receiver<io::Result<Vec<u8>>> { | |
530 | let (tx, rx) = channel(); | |
531 | match stream { | |
532 | Some(stream) => { | |
533 | thread::spawn(move || { | |
534 | let mut stream = stream; | |
535 | let mut ret = Vec::new(); | |
536 | let res = stream.read_to_end(&mut ret); | |
537 | tx.send(res.map(|_| ret)).unwrap(); | |
538 | }); | |
539 | } | |
540 | None => tx.send(Ok(Vec::new())).unwrap() | |
541 | } | |
542 | rx | |
543 | } | |
544 | let stdout = read(self.stdout.take()); | |
545 | let stderr = read(self.stderr.take()); | |
546 | let status = try!(self.wait()); | |
547 | ||
548 | Ok(Output { | |
549 | status: status, | |
550 | stdout: stdout.recv().unwrap().unwrap_or(Vec::new()), | |
551 | stderr: stderr.recv().unwrap().unwrap_or(Vec::new()), | |
552 | }) | |
553 | } | |
554 | } | |
555 | ||
c34b1796 AL |
556 | /// Terminates the current process with the specified exit code. |
557 | /// | |
558 | /// This function will never return and will immediately terminate the current | |
559 | /// process. The exit code is passed through to the underlying OS and will be | |
560 | /// available for consumption by another process. | |
561 | /// | |
562 | /// Note that because this function never returns, and that it terminates the | |
563 | /// process, no destructors on the current stack or any other thread's stack | |
564 | /// will be run. If a clean shutdown is needed it is recommended to only call | |
565 | /// this function at a known point where there are no more destructors left | |
566 | /// to run. | |
567 | #[stable(feature = "rust1", since = "1.0.0")] | |
568 | pub fn exit(code: i32) -> ! { | |
569 | ::sys::os::exit(code) | |
570 | } | |
571 | ||
85aaf69f SL |
572 | #[cfg(test)] |
573 | mod tests { | |
c34b1796 | 574 | use prelude::v1::*; |
85aaf69f | 575 | use io::prelude::*; |
c34b1796 AL |
576 | |
577 | use io::ErrorKind; | |
85aaf69f SL |
578 | use rt::running_on_valgrind; |
579 | use str; | |
c34b1796 | 580 | use super::{Command, Output, Stdio}; |
85aaf69f SL |
581 | |
582 | // FIXME(#10380) these tests should not all be ignored on android. | |
583 | ||
584 | #[cfg(not(target_os="android"))] | |
585 | #[test] | |
586 | fn smoke() { | |
587 | let p = Command::new("true").spawn(); | |
588 | assert!(p.is_ok()); | |
589 | let mut p = p.unwrap(); | |
590 | assert!(p.wait().unwrap().success()); | |
591 | } | |
592 | ||
593 | #[cfg(not(target_os="android"))] | |
594 | #[test] | |
595 | fn smoke_failure() { | |
596 | match Command::new("if-this-is-a-binary-then-the-world-has-ended").spawn() { | |
597 | Ok(..) => panic!(), | |
598 | Err(..) => {} | |
599 | } | |
600 | } | |
601 | ||
602 | #[cfg(not(target_os="android"))] | |
603 | #[test] | |
604 | fn exit_reported_right() { | |
605 | let p = Command::new("false").spawn(); | |
606 | assert!(p.is_ok()); | |
607 | let mut p = p.unwrap(); | |
608 | assert!(p.wait().unwrap().code() == Some(1)); | |
c34b1796 | 609 | drop(p.wait()); |
85aaf69f SL |
610 | } |
611 | ||
612 | #[cfg(all(unix, not(target_os="android")))] | |
613 | #[test] | |
614 | fn signal_reported_right() { | |
c34b1796 | 615 | use os::unix::process::ExitStatusExt; |
85aaf69f SL |
616 | |
617 | let p = Command::new("/bin/sh").arg("-c").arg("kill -9 $$").spawn(); | |
618 | assert!(p.is_ok()); | |
619 | let mut p = p.unwrap(); | |
620 | match p.wait().unwrap().signal() { | |
621 | Some(9) => {}, | |
622 | result => panic!("not terminated by signal 9 (instead, {:?})", result), | |
623 | } | |
624 | } | |
625 | ||
626 | pub fn run_output(mut cmd: Command) -> String { | |
627 | let p = cmd.spawn(); | |
628 | assert!(p.is_ok()); | |
629 | let mut p = p.unwrap(); | |
630 | assert!(p.stdout.is_some()); | |
631 | let mut ret = String::new(); | |
632 | p.stdout.as_mut().unwrap().read_to_string(&mut ret).unwrap(); | |
633 | assert!(p.wait().unwrap().success()); | |
634 | return ret; | |
635 | } | |
636 | ||
637 | #[cfg(not(target_os="android"))] | |
638 | #[test] | |
639 | fn stdout_works() { | |
640 | let mut cmd = Command::new("echo"); | |
c34b1796 | 641 | cmd.arg("foobar").stdout(Stdio::piped()); |
85aaf69f SL |
642 | assert_eq!(run_output(cmd), "foobar\n"); |
643 | } | |
644 | ||
645 | #[cfg(all(unix, not(target_os="android")))] | |
646 | #[test] | |
647 | fn set_current_dir_works() { | |
648 | let mut cmd = Command::new("/bin/sh"); | |
649 | cmd.arg("-c").arg("pwd") | |
650 | .current_dir("/") | |
c34b1796 | 651 | .stdout(Stdio::piped()); |
85aaf69f SL |
652 | assert_eq!(run_output(cmd), "/\n"); |
653 | } | |
654 | ||
655 | #[cfg(all(unix, not(target_os="android")))] | |
656 | #[test] | |
657 | fn stdin_works() { | |
658 | let mut p = Command::new("/bin/sh") | |
659 | .arg("-c").arg("read line; echo $line") | |
c34b1796 AL |
660 | .stdin(Stdio::piped()) |
661 | .stdout(Stdio::piped()) | |
85aaf69f SL |
662 | .spawn().unwrap(); |
663 | p.stdin.as_mut().unwrap().write("foobar".as_bytes()).unwrap(); | |
664 | drop(p.stdin.take()); | |
665 | let mut out = String::new(); | |
666 | p.stdout.as_mut().unwrap().read_to_string(&mut out).unwrap(); | |
667 | assert!(p.wait().unwrap().success()); | |
668 | assert_eq!(out, "foobar\n"); | |
669 | } | |
670 | ||
671 | ||
672 | #[cfg(all(unix, not(target_os="android")))] | |
673 | #[test] | |
674 | fn uid_works() { | |
c34b1796 | 675 | use os::unix::prelude::*; |
85aaf69f SL |
676 | use libc; |
677 | let mut p = Command::new("/bin/sh") | |
678 | .arg("-c").arg("true") | |
679 | .uid(unsafe { libc::getuid() }) | |
680 | .gid(unsafe { libc::getgid() }) | |
681 | .spawn().unwrap(); | |
682 | assert!(p.wait().unwrap().success()); | |
683 | } | |
684 | ||
685 | #[cfg(all(unix, not(target_os="android")))] | |
686 | #[test] | |
687 | fn uid_to_root_fails() { | |
c34b1796 | 688 | use os::unix::prelude::*; |
85aaf69f SL |
689 | use libc; |
690 | ||
691 | // if we're already root, this isn't a valid test. Most of the bots run | |
692 | // as non-root though (android is an exception). | |
693 | if unsafe { libc::getuid() == 0 } { return } | |
694 | assert!(Command::new("/bin/ls").uid(0).gid(0).spawn().is_err()); | |
695 | } | |
696 | ||
697 | #[cfg(not(target_os="android"))] | |
698 | #[test] | |
699 | fn test_process_status() { | |
700 | let mut status = Command::new("false").status().unwrap(); | |
701 | assert!(status.code() == Some(1)); | |
702 | ||
703 | status = Command::new("true").status().unwrap(); | |
704 | assert!(status.success()); | |
705 | } | |
706 | ||
707 | #[test] | |
708 | fn test_process_output_fail_to_start() { | |
709 | match Command::new("/no-binary-by-this-name-should-exist").output() { | |
c34b1796 | 710 | Err(e) => assert_eq!(e.kind(), ErrorKind::NotFound), |
85aaf69f SL |
711 | Ok(..) => panic!() |
712 | } | |
713 | } | |
714 | ||
715 | #[cfg(not(target_os="android"))] | |
716 | #[test] | |
717 | fn test_process_output_output() { | |
718 | let Output {status, stdout, stderr} | |
719 | = Command::new("echo").arg("hello").output().unwrap(); | |
c34b1796 | 720 | let output_str = str::from_utf8(&stdout).unwrap(); |
85aaf69f SL |
721 | |
722 | assert!(status.success()); | |
723 | assert_eq!(output_str.trim().to_string(), "hello"); | |
724 | // FIXME #7224 | |
725 | if !running_on_valgrind() { | |
726 | assert_eq!(stderr, Vec::new()); | |
727 | } | |
728 | } | |
729 | ||
730 | #[cfg(not(target_os="android"))] | |
731 | #[test] | |
732 | fn test_process_output_error() { | |
733 | let Output {status, stdout, stderr} | |
734 | = Command::new("mkdir").arg(".").output().unwrap(); | |
735 | ||
736 | assert!(status.code() == Some(1)); | |
737 | assert_eq!(stdout, Vec::new()); | |
738 | assert!(!stderr.is_empty()); | |
739 | } | |
740 | ||
741 | #[cfg(not(target_os="android"))] | |
742 | #[test] | |
743 | fn test_finish_once() { | |
744 | let mut prog = Command::new("false").spawn().unwrap(); | |
745 | assert!(prog.wait().unwrap().code() == Some(1)); | |
746 | } | |
747 | ||
748 | #[cfg(not(target_os="android"))] | |
749 | #[test] | |
750 | fn test_finish_twice() { | |
751 | let mut prog = Command::new("false").spawn().unwrap(); | |
752 | assert!(prog.wait().unwrap().code() == Some(1)); | |
753 | assert!(prog.wait().unwrap().code() == Some(1)); | |
754 | } | |
755 | ||
756 | #[cfg(not(target_os="android"))] | |
757 | #[test] | |
758 | fn test_wait_with_output_once() { | |
c34b1796 | 759 | let prog = Command::new("echo").arg("hello").stdout(Stdio::piped()) |
85aaf69f SL |
760 | .spawn().unwrap(); |
761 | let Output {status, stdout, stderr} = prog.wait_with_output().unwrap(); | |
c34b1796 | 762 | let output_str = str::from_utf8(&stdout).unwrap(); |
85aaf69f SL |
763 | |
764 | assert!(status.success()); | |
765 | assert_eq!(output_str.trim().to_string(), "hello"); | |
766 | // FIXME #7224 | |
767 | if !running_on_valgrind() { | |
768 | assert_eq!(stderr, Vec::new()); | |
769 | } | |
770 | } | |
771 | ||
85aaf69f SL |
772 | #[cfg(all(unix, not(target_os="android")))] |
773 | pub fn env_cmd() -> Command { | |
774 | Command::new("env") | |
775 | } | |
776 | #[cfg(target_os="android")] | |
777 | pub fn env_cmd() -> Command { | |
778 | let mut cmd = Command::new("/system/bin/sh"); | |
779 | cmd.arg("-c").arg("set"); | |
780 | cmd | |
781 | } | |
782 | ||
783 | #[cfg(windows)] | |
784 | pub fn env_cmd() -> Command { | |
785 | let mut cmd = Command::new("cmd"); | |
786 | cmd.arg("/c").arg("set"); | |
787 | cmd | |
788 | } | |
789 | ||
790 | #[cfg(not(target_os="android"))] | |
791 | #[test] | |
792 | fn test_inherit_env() { | |
c34b1796 | 793 | use std::env; |
85aaf69f SL |
794 | if running_on_valgrind() { return; } |
795 | ||
796 | let result = env_cmd().output().unwrap(); | |
797 | let output = String::from_utf8(result.stdout).unwrap(); | |
798 | ||
c34b1796 | 799 | for (ref k, ref v) in env::vars() { |
85aaf69f SL |
800 | // don't check windows magical empty-named variables |
801 | assert!(k.is_empty() || | |
c34b1796 | 802 | output.contains(&format!("{}={}", *k, *v)), |
85aaf69f SL |
803 | "output doesn't contain `{}={}`\n{}", |
804 | k, v, output); | |
805 | } | |
806 | } | |
807 | #[cfg(target_os="android")] | |
808 | #[test] | |
809 | fn test_inherit_env() { | |
c34b1796 | 810 | use std::env; |
85aaf69f SL |
811 | if running_on_valgrind() { return; } |
812 | ||
813 | let mut result = env_cmd().output().unwrap(); | |
814 | let output = String::from_utf8(result.stdout).unwrap(); | |
815 | ||
c34b1796 | 816 | for (ref k, ref v) in env::vars() { |
85aaf69f SL |
817 | // don't check android RANDOM variables |
818 | if *k != "RANDOM".to_string() { | |
c34b1796 AL |
819 | assert!(output.contains(&format!("{}={}", |
820 | *k, | |
821 | *v)) || | |
822 | output.contains(&format!("{}=\'{}\'", | |
823 | *k, | |
824 | *v))); | |
85aaf69f SL |
825 | } |
826 | } | |
827 | } | |
828 | ||
829 | #[test] | |
830 | fn test_override_env() { | |
831 | use env; | |
832 | ||
833 | // In some build environments (such as chrooted Nix builds), `env` can | |
834 | // only be found in the explicitly-provided PATH env variable, not in | |
835 | // default places such as /bin or /usr/bin. So we need to pass through | |
836 | // PATH to our sub-process. | |
837 | let mut cmd = env_cmd(); | |
838 | cmd.env_clear().env("RUN_TEST_NEW_ENV", "123"); | |
839 | if let Some(p) = env::var_os("PATH") { | |
840 | cmd.env("PATH", &p); | |
841 | } | |
842 | let result = cmd.output().unwrap(); | |
c34b1796 | 843 | let output = String::from_utf8_lossy(&result.stdout).to_string(); |
85aaf69f SL |
844 | |
845 | assert!(output.contains("RUN_TEST_NEW_ENV=123"), | |
846 | "didn't find RUN_TEST_NEW_ENV inside of:\n\n{}", output); | |
847 | } | |
848 | ||
849 | #[test] | |
850 | fn test_add_to_env() { | |
851 | let result = env_cmd().env("RUN_TEST_NEW_ENV", "123").output().unwrap(); | |
c34b1796 | 852 | let output = String::from_utf8_lossy(&result.stdout).to_string(); |
85aaf69f SL |
853 | |
854 | assert!(output.contains("RUN_TEST_NEW_ENV=123"), | |
855 | "didn't find RUN_TEST_NEW_ENV inside of:\n\n{}", output); | |
856 | } | |
857 | } |