]> git.lizzy.rs Git - rust.git/blob - src/libstd/sys/redox/process.rs
Rollup merge of #39604 - est31:i128_tests, r=alexcrichton
[rust.git] / src / libstd / sys / redox / process.rs
1 // Copyright 2016 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 use collections::hash_map::HashMap;
12 use env;
13 use ffi::OsStr;
14 use fmt;
15 use io::{self, Error, ErrorKind};
16 use path::Path;
17 use sys::fd::FileDesc;
18 use sys::fs::{File, OpenOptions};
19 use sys::pipe::{self, AnonPipe};
20 use sys::{cvt, syscall};
21
22 ////////////////////////////////////////////////////////////////////////////////
23 // Command
24 ////////////////////////////////////////////////////////////////////////////////
25
26 pub struct Command {
27     // Currently we try hard to ensure that the call to `.exec()` doesn't
28     // actually allocate any memory. While many platforms try to ensure that
29     // memory allocation works after a fork in a multithreaded process, it's
30     // been observed to be buggy and somewhat unreliable, so we do our best to
31     // just not do it at all!
32     //
33     // Along those lines, the `argv` and `envp` raw pointers here are exactly
34     // what's gonna get passed to `execvp`. The `argv` array starts with the
35     // `program` and ends with a NULL, and the `envp` pointer, if present, is
36     // also null-terminated.
37     //
38     // Right now we don't support removing arguments, so there's no much fancy
39     // support there, but we support adding and removing environment variables,
40     // so a side table is used to track where in the `envp` array each key is
41     // located. Whenever we add a key we update it in place if it's already
42     // present, and whenever we remove a key we update the locations of all
43     // other keys.
44     program: String,
45     args: Vec<String>,
46     env: HashMap<String, String>,
47
48     cwd: Option<String>,
49     uid: Option<u32>,
50     gid: Option<u32>,
51     saw_nul: bool,
52     closures: Vec<Box<FnMut() -> io::Result<()> + Send + Sync>>,
53     stdin: Option<Stdio>,
54     stdout: Option<Stdio>,
55     stderr: Option<Stdio>,
56 }
57
58 // passed back to std::process with the pipes connected to the child, if any
59 // were requested
60 pub struct StdioPipes {
61     pub stdin: Option<AnonPipe>,
62     pub stdout: Option<AnonPipe>,
63     pub stderr: Option<AnonPipe>,
64 }
65
66 // passed to do_exec() with configuration of what the child stdio should look
67 // like
68 struct ChildPipes {
69     stdin: ChildStdio,
70     stdout: ChildStdio,
71     stderr: ChildStdio,
72 }
73
74 enum ChildStdio {
75     Inherit,
76     Explicit(usize),
77     Owned(FileDesc),
78 }
79
80 pub enum Stdio {
81     Inherit,
82     Null,
83     MakePipe,
84     Fd(FileDesc),
85 }
86
87 impl Command {
88     pub fn new(program: &OsStr) -> Command {
89         Command {
90             program: program.to_str().unwrap().to_owned(),
91             args: Vec::new(),
92             env: HashMap::new(),
93             cwd: None,
94             uid: None,
95             gid: None,
96             saw_nul: false,
97             closures: Vec::new(),
98             stdin: None,
99             stdout: None,
100             stderr: None,
101         }
102     }
103
104     pub fn arg(&mut self, arg: &OsStr) {
105         self.args.push(arg.to_str().unwrap().to_owned());
106     }
107
108     pub fn env(&mut self, key: &OsStr, val: &OsStr) {
109         self.env.insert(key.to_str().unwrap().to_owned(), val.to_str().unwrap().to_owned());
110     }
111
112     pub fn env_remove(&mut self, key: &OsStr) {
113         self.env.remove(key.to_str().unwrap());
114     }
115
116     pub fn env_clear(&mut self) {
117         self.env.clear();
118     }
119
120     pub fn cwd(&mut self, dir: &OsStr) {
121         self.cwd = Some(dir.to_str().unwrap().to_owned());
122     }
123     pub fn uid(&mut self, id: u32) {
124         self.uid = Some(id);
125     }
126     pub fn gid(&mut self, id: u32) {
127         self.gid = Some(id);
128     }
129
130     pub fn before_exec(&mut self,
131                        f: Box<FnMut() -> io::Result<()> + Send + Sync>) {
132         self.closures.push(f);
133     }
134
135     pub fn stdin(&mut self, stdin: Stdio) {
136         self.stdin = Some(stdin);
137     }
138     pub fn stdout(&mut self, stdout: Stdio) {
139         self.stdout = Some(stdout);
140     }
141     pub fn stderr(&mut self, stderr: Stdio) {
142         self.stderr = Some(stderr);
143     }
144
145     pub fn spawn(&mut self, default: Stdio, needs_stdin: bool)
146                  -> io::Result<(Process, StdioPipes)> {
147          const CLOEXEC_MSG_FOOTER: &'static [u8] = b"NOEX";
148
149          if self.saw_nul {
150              return Err(io::Error::new(ErrorKind::InvalidInput,
151                                        "nul byte found in provided data"));
152          }
153
154          let (ours, theirs) = self.setup_io(default, needs_stdin)?;
155          let (input, output) = pipe::anon_pipe()?;
156
157          let pid = unsafe {
158              match cvt(syscall::clone(0))? {
159                  0 => {
160                      drop(input);
161                      let err = self.do_exec(theirs);
162                      let errno = err.raw_os_error().unwrap_or(syscall::EINVAL) as u32;
163                      let bytes = [
164                          (errno >> 24) as u8,
165                          (errno >> 16) as u8,
166                          (errno >>  8) as u8,
167                          (errno >>  0) as u8,
168                          CLOEXEC_MSG_FOOTER[0], CLOEXEC_MSG_FOOTER[1],
169                          CLOEXEC_MSG_FOOTER[2], CLOEXEC_MSG_FOOTER[3]
170                      ];
171                      // pipe I/O up to PIPE_BUF bytes should be atomic, and then
172                      // we want to be sure we *don't* run at_exit destructors as
173                      // we're being torn down regardless
174                      assert!(output.write(&bytes).is_ok());
175                      let _ = syscall::exit(1);
176                      panic!("failed to exit");
177                  }
178                  n => n,
179              }
180          };
181
182          let mut p = Process { pid: pid, status: None };
183          drop(output);
184          let mut bytes = [0; 8];
185
186          // loop to handle EINTR
187          loop {
188              match input.read(&mut bytes) {
189                  Ok(0) => return Ok((p, ours)),
190                  Ok(8) => {
191                      assert!(combine(CLOEXEC_MSG_FOOTER) == combine(&bytes[4.. 8]),
192                              "Validation on the CLOEXEC pipe failed: {:?}", bytes);
193                      let errno = combine(&bytes[0.. 4]);
194                      assert!(p.wait().is_ok(),
195                              "wait() should either return Ok or panic");
196                      return Err(Error::from_raw_os_error(errno))
197                  }
198                  Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
199                  Err(e) => {
200                      assert!(p.wait().is_ok(),
201                              "wait() should either return Ok or panic");
202                      panic!("the CLOEXEC pipe failed: {:?}", e)
203                  },
204                  Ok(..) => { // pipe I/O up to PIPE_BUF bytes should be atomic
205                      assert!(p.wait().is_ok(),
206                              "wait() should either return Ok or panic");
207                      panic!("short read on the CLOEXEC pipe")
208                  }
209              }
210          }
211
212          fn combine(arr: &[u8]) -> i32 {
213              let a = arr[0] as u32;
214              let b = arr[1] as u32;
215              let c = arr[2] as u32;
216              let d = arr[3] as u32;
217
218              ((a << 24) | (b << 16) | (c << 8) | (d << 0)) as i32
219          }
220     }
221
222     pub fn exec(&mut self, default: Stdio) -> io::Error {
223         if self.saw_nul {
224             return io::Error::new(ErrorKind::InvalidInput,
225                                   "nul byte found in provided data")
226         }
227
228         match self.setup_io(default, true) {
229             Ok((_, theirs)) => unsafe { self.do_exec(theirs) },
230             Err(e) => e,
231         }
232     }
233
234     // And at this point we've reached a special time in the life of the
235     // child. The child must now be considered hamstrung and unable to
236     // do anything other than syscalls really. Consider the following
237     // scenario:
238     //
239     //      1. Thread A of process 1 grabs the malloc() mutex
240     //      2. Thread B of process 1 forks(), creating thread C
241     //      3. Thread C of process 2 then attempts to malloc()
242     //      4. The memory of process 2 is the same as the memory of
243     //         process 1, so the mutex is locked.
244     //
245     // This situation looks a lot like deadlock, right? It turns out
246     // that this is what pthread_atfork() takes care of, which is
247     // presumably implemented across platforms. The first thing that
248     // threads to *before* forking is to do things like grab the malloc
249     // mutex, and then after the fork they unlock it.
250     //
251     // Despite this information, libnative's spawn has been witnessed to
252     // deadlock on both OSX and FreeBSD. I'm not entirely sure why, but
253     // all collected backtraces point at malloc/free traffic in the
254     // child spawned process.
255     //
256     // For this reason, the block of code below should contain 0
257     // invocations of either malloc of free (or their related friends).
258     //
259     // As an example of not having malloc/free traffic, we don't close
260     // this file descriptor by dropping the FileDesc (which contains an
261     // allocation). Instead we just close it manually. This will never
262     // have the drop glue anyway because this code never returns (the
263     // child will either exec() or invoke syscall::exit)
264     unsafe fn do_exec(&mut self, stdio: ChildPipes) -> io::Error {
265         macro_rules! t {
266             ($e:expr) => (match $e {
267                 Ok(e) => e,
268                 Err(e) => return e,
269             })
270         }
271
272         if let Some(fd) = stdio.stderr.fd() {
273             let _ = syscall::close(2);
274             t!(cvt(syscall::dup(fd, &[])));
275             let _ = syscall::close(fd);
276         }
277         if let Some(fd) = stdio.stdout.fd() {
278             let _ = syscall::close(1);
279             t!(cvt(syscall::dup(fd, &[])));
280             let _ = syscall::close(fd);
281         }
282         if let Some(fd) = stdio.stdin.fd() {
283             let _ = syscall::close(0);
284             t!(cvt(syscall::dup(fd, &[])));
285             let _ = syscall::close(fd);
286         }
287
288         if let Some(g) = self.gid {
289             t!(cvt(syscall::setregid(g as usize, g as usize)));
290         }
291         if let Some(u) = self.uid {
292             t!(cvt(syscall::setreuid(u as usize, u as usize)));
293         }
294         if let Some(ref cwd) = self.cwd {
295             t!(cvt(syscall::chdir(cwd)));
296         }
297
298         for callback in self.closures.iter_mut() {
299             t!(callback());
300         }
301
302         let mut args: Vec<[usize; 2]> = Vec::new();
303         args.push([self.program.as_ptr() as usize, self.program.len()]);
304         for arg in self.args.iter() {
305             args.push([arg.as_ptr() as usize, arg.len()]);
306         }
307
308         for (key, val) in self.env.iter() {
309             env::set_var(key, val);
310         }
311
312         let program = if self.program.contains(':') || self.program.contains('/') {
313             self.program.to_owned()
314         } else {
315             let mut path_env = ::env::var("PATH").unwrap_or(".".to_string());
316
317             if ! path_env.ends_with('/') {
318                 path_env.push('/');
319             }
320
321             path_env.push_str(&self.program);
322
323             path_env
324         };
325
326         if let Err(err) = syscall::execve(&program, &args) {
327             io::Error::from_raw_os_error(err.errno as i32)
328         } else {
329             panic!("return from exec without err");
330         }
331     }
332
333
334     fn setup_io(&self, default: Stdio, needs_stdin: bool)
335                 -> io::Result<(StdioPipes, ChildPipes)> {
336         let null = Stdio::Null;
337         let default_stdin = if needs_stdin {&default} else {&null};
338         let stdin = self.stdin.as_ref().unwrap_or(default_stdin);
339         let stdout = self.stdout.as_ref().unwrap_or(&default);
340         let stderr = self.stderr.as_ref().unwrap_or(&default);
341         let (their_stdin, our_stdin) = stdin.to_child_stdio(true)?;
342         let (their_stdout, our_stdout) = stdout.to_child_stdio(false)?;
343         let (their_stderr, our_stderr) = stderr.to_child_stdio(false)?;
344         let ours = StdioPipes {
345             stdin: our_stdin,
346             stdout: our_stdout,
347             stderr: our_stderr,
348         };
349         let theirs = ChildPipes {
350             stdin: their_stdin,
351             stdout: their_stdout,
352             stderr: their_stderr,
353         };
354         Ok((ours, theirs))
355     }
356 }
357
358 impl Stdio {
359     fn to_child_stdio(&self, readable: bool)
360                       -> io::Result<(ChildStdio, Option<AnonPipe>)> {
361         match *self {
362             Stdio::Inherit => Ok((ChildStdio::Inherit, None)),
363
364             // Make sure that the source descriptors are not an stdio
365             // descriptor, otherwise the order which we set the child's
366             // descriptors may blow away a descriptor which we are hoping to
367             // save. For example, suppose we want the child's stderr to be the
368             // parent's stdout, and the child's stdout to be the parent's
369             // stderr. No matter which we dup first, the second will get
370             // overwritten prematurely.
371             Stdio::Fd(ref fd) => {
372                 if fd.raw() <= 2 {
373                     Ok((ChildStdio::Owned(fd.duplicate()?), None))
374                 } else {
375                     Ok((ChildStdio::Explicit(fd.raw()), None))
376                 }
377             }
378
379             Stdio::MakePipe => {
380                 let (reader, writer) = pipe::anon_pipe()?;
381                 let (ours, theirs) = if readable {
382                     (writer, reader)
383                 } else {
384                     (reader, writer)
385                 };
386                 Ok((ChildStdio::Owned(theirs.into_fd()), Some(ours)))
387             }
388
389             Stdio::Null => {
390                 let mut opts = OpenOptions::new();
391                 opts.read(readable);
392                 opts.write(!readable);
393                 let fd = File::open(&Path::new("null:"), &opts)?;
394                 Ok((ChildStdio::Owned(fd.into_fd()), None))
395             }
396         }
397     }
398 }
399
400 impl ChildStdio {
401     fn fd(&self) -> Option<usize> {
402         match *self {
403             ChildStdio::Inherit => None,
404             ChildStdio::Explicit(fd) => Some(fd),
405             ChildStdio::Owned(ref fd) => Some(fd.raw()),
406         }
407     }
408 }
409
410 impl fmt::Debug for Command {
411     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
412         write!(f, "{:?}", self.program)?;
413         for arg in &self.args {
414             write!(f, " {:?}", arg)?;
415         }
416         Ok(())
417     }
418 }
419
420 ////////////////////////////////////////////////////////////////////////////////
421 // Processes
422 ////////////////////////////////////////////////////////////////////////////////
423
424 /// Unix exit statuses
425 #[derive(PartialEq, Eq, Clone, Copy, Debug)]
426 pub struct ExitStatus(i32);
427
428 impl ExitStatus {
429     fn exited(&self) -> bool {
430         self.0 & 0x7F == 0
431     }
432
433     pub fn success(&self) -> bool {
434         self.code() == Some(0)
435     }
436
437     pub fn code(&self) -> Option<i32> {
438         if self.exited() {
439             Some((self.0 >> 8) & 0xFF)
440         } else {
441             None
442         }
443     }
444
445     pub fn signal(&self) -> Option<i32> {
446         if !self.exited() {
447             Some(self.0 & 0x7F)
448         } else {
449             None
450         }
451     }
452 }
453
454 impl From<i32> for ExitStatus {
455     fn from(a: i32) -> ExitStatus {
456         ExitStatus(a)
457     }
458 }
459
460 impl fmt::Display for ExitStatus {
461     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
462         if let Some(code) = self.code() {
463             write!(f, "exit code: {}", code)
464         } else {
465             let signal = self.signal().unwrap();
466             write!(f, "signal: {}", signal)
467         }
468     }
469 }
470
471 /// The unique id of the process (this should never be negative).
472 pub struct Process {
473     pid: usize,
474     status: Option<ExitStatus>,
475 }
476
477 impl Process {
478     pub fn id(&self) -> u32 {
479         self.pid as u32
480     }
481
482     pub fn kill(&mut self) -> io::Result<()> {
483         // If we've already waited on this process then the pid can be recycled
484         // and used for another process, and we probably shouldn't be killing
485         // random processes, so just return an error.
486         if self.status.is_some() {
487             Err(Error::new(ErrorKind::InvalidInput,
488                            "invalid argument: can't kill an exited process"))
489         } else {
490             cvt(syscall::kill(self.pid, syscall::SIGKILL))?;
491             Ok(())
492         }
493     }
494
495     pub fn wait(&mut self) -> io::Result<ExitStatus> {
496         if let Some(status) = self.status {
497             return Ok(status)
498         }
499         let mut status = 0;
500         cvt(syscall::waitpid(self.pid, &mut status, 0))?;
501         self.status = Some(ExitStatus(status as i32));
502         Ok(ExitStatus(status as i32))
503     }
504
505     pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
506         if let Some(status) = self.status {
507             return Ok(Some(status))
508         }
509         let mut status = 0;
510         let pid = cvt(syscall::waitpid(self.pid, &mut status, syscall::WNOHANG))?;
511         if pid == 0 {
512             Ok(None)
513         } else {
514             self.status = Some(ExitStatus(status as i32));
515             Ok(Some(ExitStatus(status as i32)))
516         }
517     }
518 }