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