]> git.lizzy.rs Git - rust.git/blob - src/libstd/sys/redox/process.rs
Auto merge of #42480 - eddyb:issue-42463, r=nikomatsakis
[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 macOS 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             t!(cvt(syscall::dup2(fd, 2, &[])));
274             let mut flags = t!(cvt(syscall::fcntl(2, syscall::F_GETFL, 0)));
275             flags &= ! syscall::O_CLOEXEC;
276             t!(cvt(syscall::fcntl(2, syscall::F_SETFL, flags)));
277         }
278         if let Some(fd) = stdio.stdout.fd() {
279             t!(cvt(syscall::dup2(fd, 1, &[])));
280             let mut flags = t!(cvt(syscall::fcntl(1, syscall::F_GETFL, 0)));
281             flags &= ! syscall::O_CLOEXEC;
282             t!(cvt(syscall::fcntl(1, syscall::F_SETFL, flags)));
283         }
284         if let Some(fd) = stdio.stdin.fd() {
285             t!(cvt(syscall::dup2(fd, 0, &[])));
286             let mut flags = t!(cvt(syscall::fcntl(0, syscall::F_GETFL, 0)));
287             flags &= ! syscall::O_CLOEXEC;
288             t!(cvt(syscall::fcntl(0, syscall::F_SETFL, flags)));
289         }
290
291         if let Some(g) = self.gid {
292             t!(cvt(syscall::setregid(g as usize, g as usize)));
293         }
294         if let Some(u) = self.uid {
295             t!(cvt(syscall::setreuid(u as usize, u as usize)));
296         }
297         if let Some(ref cwd) = self.cwd {
298             t!(cvt(syscall::chdir(cwd)));
299         }
300
301         for callback in self.closures.iter_mut() {
302             t!(callback());
303         }
304
305         let mut args: Vec<[usize; 2]> = Vec::new();
306         args.push([self.program.as_ptr() as usize, self.program.len()]);
307         for arg in self.args.iter() {
308             args.push([arg.as_ptr() as usize, arg.len()]);
309         }
310
311         for (key, val) in self.env.iter() {
312             env::set_var(key, val);
313         }
314
315         let program = if self.program.contains(':') || self.program.contains('/') {
316             self.program.to_owned()
317         } else {
318             let mut path_env = ::env::var("PATH").unwrap_or(".".to_string());
319
320             if ! path_env.ends_with('/') {
321                 path_env.push('/');
322             }
323
324             path_env.push_str(&self.program);
325
326             path_env
327         };
328
329         if let Err(err) = syscall::execve(&program, &args) {
330             io::Error::from_raw_os_error(err.errno as i32)
331         } else {
332             panic!("return from exec without err");
333         }
334     }
335
336
337     fn setup_io(&self, default: Stdio, needs_stdin: bool)
338                 -> io::Result<(StdioPipes, ChildPipes)> {
339         let null = Stdio::Null;
340         let default_stdin = if needs_stdin {&default} else {&null};
341         let stdin = self.stdin.as_ref().unwrap_or(default_stdin);
342         let stdout = self.stdout.as_ref().unwrap_or(&default);
343         let stderr = self.stderr.as_ref().unwrap_or(&default);
344         let (their_stdin, our_stdin) = stdin.to_child_stdio(true)?;
345         let (their_stdout, our_stdout) = stdout.to_child_stdio(false)?;
346         let (their_stderr, our_stderr) = stderr.to_child_stdio(false)?;
347         let ours = StdioPipes {
348             stdin: our_stdin,
349             stdout: our_stdout,
350             stderr: our_stderr,
351         };
352         let theirs = ChildPipes {
353             stdin: their_stdin,
354             stdout: their_stdout,
355             stderr: their_stderr,
356         };
357         Ok((ours, theirs))
358     }
359 }
360
361 impl Stdio {
362     fn to_child_stdio(&self, readable: bool)
363                       -> io::Result<(ChildStdio, Option<AnonPipe>)> {
364         match *self {
365             Stdio::Inherit => Ok((ChildStdio::Inherit, None)),
366
367             // Make sure that the source descriptors are not an stdio
368             // descriptor, otherwise the order which we set the child's
369             // descriptors may blow away a descriptor which we are hoping to
370             // save. For example, suppose we want the child's stderr to be the
371             // parent's stdout, and the child's stdout to be the parent's
372             // stderr. No matter which we dup first, the second will get
373             // overwritten prematurely.
374             Stdio::Fd(ref fd) => {
375                 if fd.raw() <= 2 {
376                     Ok((ChildStdio::Owned(fd.duplicate()?), None))
377                 } else {
378                     Ok((ChildStdio::Explicit(fd.raw()), None))
379                 }
380             }
381
382             Stdio::MakePipe => {
383                 let (reader, writer) = pipe::anon_pipe()?;
384                 let (ours, theirs) = if readable {
385                     (writer, reader)
386                 } else {
387                     (reader, writer)
388                 };
389                 Ok((ChildStdio::Owned(theirs.into_fd()), Some(ours)))
390             }
391
392             Stdio::Null => {
393                 let mut opts = OpenOptions::new();
394                 opts.read(readable);
395                 opts.write(!readable);
396                 let fd = File::open(&Path::new("null:"), &opts)?;
397                 Ok((ChildStdio::Owned(fd.into_fd()), None))
398             }
399         }
400     }
401 }
402
403 impl From<AnonPipe> for Stdio {
404     fn from(pipe: AnonPipe) -> Stdio {
405         Stdio::Fd(pipe.into_fd())
406     }
407 }
408
409 impl From<File> for Stdio {
410     fn from(file: File) -> Stdio {
411         Stdio::Fd(file.into_fd())
412     }
413 }
414
415 impl ChildStdio {
416     fn fd(&self) -> Option<usize> {
417         match *self {
418             ChildStdio::Inherit => None,
419             ChildStdio::Explicit(fd) => Some(fd),
420             ChildStdio::Owned(ref fd) => Some(fd.raw()),
421         }
422     }
423 }
424
425 impl fmt::Debug for Command {
426     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
427         write!(f, "{:?}", self.program)?;
428         for arg in &self.args {
429             write!(f, " {:?}", arg)?;
430         }
431         Ok(())
432     }
433 }
434
435 ////////////////////////////////////////////////////////////////////////////////
436 // Processes
437 ////////////////////////////////////////////////////////////////////////////////
438
439 /// Unix exit statuses
440 #[derive(PartialEq, Eq, Clone, Copy, Debug)]
441 pub struct ExitStatus(i32);
442
443 impl ExitStatus {
444     fn exited(&self) -> bool {
445         self.0 & 0x7F == 0
446     }
447
448     pub fn success(&self) -> bool {
449         self.code() == Some(0)
450     }
451
452     pub fn code(&self) -> Option<i32> {
453         if self.exited() {
454             Some((self.0 >> 8) & 0xFF)
455         } else {
456             None
457         }
458     }
459
460     pub fn signal(&self) -> Option<i32> {
461         if !self.exited() {
462             Some(self.0 & 0x7F)
463         } else {
464             None
465         }
466     }
467 }
468
469 impl From<i32> for ExitStatus {
470     fn from(a: i32) -> ExitStatus {
471         ExitStatus(a)
472     }
473 }
474
475 impl fmt::Display for ExitStatus {
476     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
477         if let Some(code) = self.code() {
478             write!(f, "exit code: {}", code)
479         } else {
480             let signal = self.signal().unwrap();
481             write!(f, "signal: {}", signal)
482         }
483     }
484 }
485
486 /// The unique id of the process (this should never be negative).
487 pub struct Process {
488     pid: usize,
489     status: Option<ExitStatus>,
490 }
491
492 impl Process {
493     pub fn id(&self) -> u32 {
494         self.pid as u32
495     }
496
497     pub fn kill(&mut self) -> io::Result<()> {
498         // If we've already waited on this process then the pid can be recycled
499         // and used for another process, and we probably shouldn't be killing
500         // random processes, so just return an error.
501         if self.status.is_some() {
502             Err(Error::new(ErrorKind::InvalidInput,
503                            "invalid argument: can't kill an exited process"))
504         } else {
505             cvt(syscall::kill(self.pid, syscall::SIGKILL))?;
506             Ok(())
507         }
508     }
509
510     pub fn wait(&mut self) -> io::Result<ExitStatus> {
511         if let Some(status) = self.status {
512             return Ok(status)
513         }
514         let mut status = 0;
515         cvt(syscall::waitpid(self.pid, &mut status, 0))?;
516         self.status = Some(ExitStatus(status as i32));
517         Ok(ExitStatus(status as i32))
518     }
519
520     pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
521         if let Some(status) = self.status {
522             return Ok(Some(status))
523         }
524         let mut status = 0;
525         let pid = cvt(syscall::waitpid(self.pid, &mut status, syscall::WNOHANG))?;
526         if pid == 0 {
527             Ok(None)
528         } else {
529             self.status = Some(ExitStatus(status as i32));
530             Ok(Some(ExitStatus(status as i32)))
531         }
532     }
533 }