]> git.lizzy.rs Git - rust.git/blob - src/libstd/sys/unix/process/process_common.rs
Auto merge of #42480 - eddyb:issue-42463, r=nikomatsakis
[rust.git] / src / libstd / sys / unix / process / process_common.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 os::unix::prelude::*;
12
13 use collections::hash_map::{HashMap, Entry};
14 use env;
15 use ffi::{OsString, OsStr, CString, CStr};
16 use fmt;
17 use io;
18 use libc::{self, c_int, gid_t, uid_t, c_char};
19 use ptr;
20 use sys::fd::FileDesc;
21 use sys::fs::{File, OpenOptions};
22 use sys::pipe::{self, AnonPipe};
23
24 ////////////////////////////////////////////////////////////////////////////////
25 // Command
26 ////////////////////////////////////////////////////////////////////////////////
27
28 pub struct Command {
29     // Currently we try hard to ensure that the call to `.exec()` doesn't
30     // actually allocate any memory. While many platforms try to ensure that
31     // memory allocation works after a fork in a multithreaded process, it's
32     // been observed to be buggy and somewhat unreliable, so we do our best to
33     // just not do it at all!
34     //
35     // Along those lines, the `argv` and `envp` raw pointers here are exactly
36     // what's gonna get passed to `execvp`. The `argv` array starts with the
37     // `program` and ends with a NULL, and the `envp` pointer, if present, is
38     // also null-terminated.
39     //
40     // Right now we don't support removing arguments, so there's no much fancy
41     // support there, but we support adding and removing environment variables,
42     // so a side table is used to track where in the `envp` array each key is
43     // located. Whenever we add a key we update it in place if it's already
44     // present, and whenever we remove a key we update the locations of all
45     // other keys.
46     program: CString,
47     args: Vec<CString>,
48     env: Option<HashMap<OsString, (usize, CString)>>,
49     argv: Vec<*const c_char>,
50     envp: Option<Vec<*const c_char>>,
51
52     cwd: Option<CString>,
53     uid: Option<uid_t>,
54     gid: Option<gid_t>,
55     saw_nul: bool,
56     closures: Vec<Box<FnMut() -> io::Result<()> + Send + Sync>>,
57     stdin: Option<Stdio>,
58     stdout: Option<Stdio>,
59     stderr: Option<Stdio>,
60 }
61
62 // passed back to std::process with the pipes connected to the child, if any
63 // were requested
64 pub struct StdioPipes {
65     pub stdin: Option<AnonPipe>,
66     pub stdout: Option<AnonPipe>,
67     pub stderr: Option<AnonPipe>,
68 }
69
70 // passed to do_exec() with configuration of what the child stdio should look
71 // like
72 pub struct ChildPipes {
73     pub stdin: ChildStdio,
74     pub stdout: ChildStdio,
75     pub stderr: ChildStdio,
76 }
77
78 pub enum ChildStdio {
79     Inherit,
80     Explicit(c_int),
81     Owned(FileDesc),
82 }
83
84 pub enum Stdio {
85     Inherit,
86     Null,
87     MakePipe,
88     Fd(FileDesc),
89 }
90
91 impl Command {
92     pub fn new(program: &OsStr) -> Command {
93         let mut saw_nul = false;
94         let program = os2c(program, &mut saw_nul);
95         Command {
96             argv: vec![program.as_ptr(), ptr::null()],
97             program: program,
98             args: Vec::new(),
99             env: None,
100             envp: None,
101             cwd: None,
102             uid: None,
103             gid: None,
104             saw_nul: saw_nul,
105             closures: Vec::new(),
106             stdin: None,
107             stdout: None,
108             stderr: None,
109         }
110     }
111
112     pub fn arg(&mut self, arg: &OsStr) {
113         // Overwrite the trailing NULL pointer in `argv` and then add a new null
114         // pointer.
115         let arg = os2c(arg, &mut self.saw_nul);
116         self.argv[self.args.len() + 1] = arg.as_ptr();
117         self.argv.push(ptr::null());
118
119         // Also make sure we keep track of the owned value to schedule a
120         // destructor for this memory.
121         self.args.push(arg);
122     }
123
124     fn init_env_map(&mut self) -> (&mut HashMap<OsString, (usize, CString)>,
125                                    &mut Vec<*const c_char>) {
126         if self.env.is_none() {
127             let mut map = HashMap::new();
128             let mut envp = Vec::new();
129             for (k, v) in env::vars_os() {
130                 let s = pair_to_key(&k, &v, &mut self.saw_nul);
131                 envp.push(s.as_ptr());
132                 map.insert(k, (envp.len() - 1, s));
133             }
134             envp.push(ptr::null());
135             self.env = Some(map);
136             self.envp = Some(envp);
137         }
138         (self.env.as_mut().unwrap(), self.envp.as_mut().unwrap())
139     }
140
141     pub fn env(&mut self, key: &OsStr, val: &OsStr) {
142         let new_key = pair_to_key(key, val, &mut self.saw_nul);
143         let (map, envp) = self.init_env_map();
144
145         // If `key` is already present then we just update `envp` in place
146         // (and store the owned value), but if it's not there we override the
147         // trailing NULL pointer, add a new NULL pointer, and store where we
148         // were located.
149         match map.entry(key.to_owned()) {
150             Entry::Occupied(mut e) => {
151                 let (i, ref mut s) = *e.get_mut();
152                 envp[i] = new_key.as_ptr();
153                 *s = new_key;
154             }
155             Entry::Vacant(e) => {
156                 let len = envp.len();
157                 envp[len - 1] = new_key.as_ptr();
158                 envp.push(ptr::null());
159                 e.insert((len - 1, new_key));
160             }
161         }
162     }
163
164     pub fn env_remove(&mut self, key: &OsStr) {
165         let (map, envp) = self.init_env_map();
166
167         // If we actually ended up removing a key, then we need to update the
168         // position of all keys that come after us in `envp` because they're all
169         // one element sooner now.
170         if let Some((i, _)) = map.remove(key) {
171             envp.remove(i);
172
173             for (_, &mut (ref mut j, _)) in map.iter_mut() {
174                 if *j >= i {
175                     *j -= 1;
176                 }
177             }
178         }
179     }
180
181     pub fn env_clear(&mut self) {
182         self.env = Some(HashMap::new());
183         self.envp = Some(vec![ptr::null()]);
184     }
185
186     pub fn cwd(&mut self, dir: &OsStr) {
187         self.cwd = Some(os2c(dir, &mut self.saw_nul));
188     }
189     pub fn uid(&mut self, id: uid_t) {
190         self.uid = Some(id);
191     }
192     pub fn gid(&mut self, id: gid_t) {
193         self.gid = Some(id);
194     }
195
196     pub fn saw_nul(&self) -> bool {
197         self.saw_nul
198     }
199     pub fn get_envp(&self) -> &Option<Vec<*const c_char>> {
200         &self.envp
201     }
202     pub fn get_argv(&self) -> &Vec<*const c_char> {
203         &self.argv
204     }
205
206     #[allow(dead_code)]
207     pub fn get_cwd(&self) -> &Option<CString> {
208         &self.cwd
209     }
210     #[allow(dead_code)]
211     pub fn get_uid(&self) -> Option<uid_t> {
212         self.uid
213     }
214     #[allow(dead_code)]
215     pub fn get_gid(&self) -> Option<gid_t> {
216         self.gid
217     }
218
219     pub fn get_closures(&mut self) -> &mut Vec<Box<FnMut() -> io::Result<()> + Send + Sync>> {
220         &mut self.closures
221     }
222
223     pub fn before_exec(&mut self,
224                        f: Box<FnMut() -> io::Result<()> + Send + Sync>) {
225         self.closures.push(f);
226     }
227
228     pub fn stdin(&mut self, stdin: Stdio) {
229         self.stdin = Some(stdin);
230     }
231
232     pub fn stdout(&mut self, stdout: Stdio) {
233         self.stdout = Some(stdout);
234     }
235
236     pub fn stderr(&mut self, stderr: Stdio) {
237         self.stderr = Some(stderr);
238     }
239
240     pub fn setup_io(&self, default: Stdio, needs_stdin: bool)
241                 -> io::Result<(StdioPipes, ChildPipes)> {
242         let null = Stdio::Null;
243         let default_stdin = if needs_stdin {&default} else {&null};
244         let stdin = self.stdin.as_ref().unwrap_or(default_stdin);
245         let stdout = self.stdout.as_ref().unwrap_or(&default);
246         let stderr = self.stderr.as_ref().unwrap_or(&default);
247         let (their_stdin, our_stdin) = stdin.to_child_stdio(true)?;
248         let (their_stdout, our_stdout) = stdout.to_child_stdio(false)?;
249         let (their_stderr, our_stderr) = stderr.to_child_stdio(false)?;
250         let ours = StdioPipes {
251             stdin: our_stdin,
252             stdout: our_stdout,
253             stderr: our_stderr,
254         };
255         let theirs = ChildPipes {
256             stdin: their_stdin,
257             stdout: their_stdout,
258             stderr: their_stderr,
259         };
260         Ok((ours, theirs))
261     }
262 }
263
264 fn os2c(s: &OsStr, saw_nul: &mut bool) -> CString {
265     CString::new(s.as_bytes()).unwrap_or_else(|_e| {
266         *saw_nul = true;
267         CString::new("<string-with-nul>").unwrap()
268     })
269 }
270
271 impl Stdio {
272     pub fn to_child_stdio(&self, readable: bool)
273                       -> io::Result<(ChildStdio, Option<AnonPipe>)> {
274         match *self {
275             Stdio::Inherit => {
276                 Ok((ChildStdio::Inherit, None))
277             },
278
279             // Make sure that the source descriptors are not an stdio
280             // descriptor, otherwise the order which we set the child's
281             // descriptors may blow away a descriptor which we are hoping to
282             // save. For example, suppose we want the child's stderr to be the
283             // parent's stdout, and the child's stdout to be the parent's
284             // stderr. No matter which we dup first, the second will get
285             // overwritten prematurely.
286             Stdio::Fd(ref fd) => {
287                 if fd.raw() >= 0 && fd.raw() <= libc::STDERR_FILENO {
288                     Ok((ChildStdio::Owned(fd.duplicate()?), None))
289                 } else {
290                     Ok((ChildStdio::Explicit(fd.raw()), None))
291                 }
292             }
293
294             Stdio::MakePipe => {
295                 let (reader, writer) = pipe::anon_pipe()?;
296                 let (ours, theirs) = if readable {
297                     (writer, reader)
298                 } else {
299                     (reader, writer)
300                 };
301                 Ok((ChildStdio::Owned(theirs.into_fd()), Some(ours)))
302             }
303
304             Stdio::Null => {
305                 let mut opts = OpenOptions::new();
306                 opts.read(readable);
307                 opts.write(!readable);
308                 let path = unsafe {
309                     CStr::from_ptr("/dev/null\0".as_ptr() as *const _)
310                 };
311                 let fd = File::open_c(&path, &opts)?;
312                 Ok((ChildStdio::Owned(fd.into_fd()), None))
313             }
314         }
315     }
316 }
317
318 impl From<AnonPipe> for Stdio {
319     fn from(pipe: AnonPipe) -> Stdio {
320         Stdio::Fd(pipe.into_fd())
321     }
322 }
323
324 impl From<File> for Stdio {
325     fn from(file: File) -> Stdio {
326         Stdio::Fd(file.into_fd())
327     }
328 }
329
330 impl ChildStdio {
331     pub fn fd(&self) -> Option<c_int> {
332         match *self {
333             ChildStdio::Inherit => None,
334             ChildStdio::Explicit(fd) => Some(fd),
335             ChildStdio::Owned(ref fd) => Some(fd.raw()),
336         }
337     }
338 }
339
340 fn pair_to_key(key: &OsStr, value: &OsStr, saw_nul: &mut bool) -> CString {
341     let (key, value) = (key.as_bytes(), value.as_bytes());
342     let mut v = Vec::with_capacity(key.len() + value.len() + 1);
343     v.extend(key);
344     v.push(b'=');
345     v.extend(value);
346     CString::new(v).unwrap_or_else(|_e| {
347         *saw_nul = true;
348         CString::new("foo=bar").unwrap()
349     })
350 }
351
352 impl fmt::Debug for Command {
353     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
354         write!(f, "{:?}", self.program)?;
355         for arg in &self.args {
356             write!(f, " {:?}", arg)?;
357         }
358         Ok(())
359     }
360 }
361
362 /// Unix exit statuses
363 #[derive(PartialEq, Eq, Clone, Copy, Debug)]
364 pub struct ExitStatus(c_int);
365
366 impl ExitStatus {
367     pub fn new(status: c_int) -> ExitStatus {
368         ExitStatus(status)
369     }
370
371     fn exited(&self) -> bool {
372         unsafe { libc::WIFEXITED(self.0) }
373     }
374
375     pub fn success(&self) -> bool {
376         self.code() == Some(0)
377     }
378
379     pub fn code(&self) -> Option<i32> {
380         if self.exited() {
381             Some(unsafe { libc::WEXITSTATUS(self.0) })
382         } else {
383             None
384         }
385     }
386
387     pub fn signal(&self) -> Option<i32> {
388         if !self.exited() {
389             Some(unsafe { libc::WTERMSIG(self.0) })
390         } else {
391             None
392         }
393     }
394 }
395
396 impl From<c_int> for ExitStatus {
397     fn from(a: c_int) -> ExitStatus {
398         ExitStatus(a)
399     }
400 }
401
402 impl fmt::Display for ExitStatus {
403     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
404         if let Some(code) = self.code() {
405             write!(f, "exit code: {}", code)
406         } else {
407             let signal = self.signal().unwrap();
408             write!(f, "signal: {}", signal)
409         }
410     }
411 }
412
413 #[cfg(all(test, not(target_os = "emscripten")))]
414 mod tests {
415     use super::*;
416
417     use ffi::OsStr;
418     use mem;
419     use ptr;
420     use libc;
421     use sys::cvt;
422
423     macro_rules! t {
424         ($e:expr) => {
425             match $e {
426                 Ok(t) => t,
427                 Err(e) => panic!("received error for `{}`: {}", stringify!($e), e),
428             }
429         }
430     }
431
432     // Android with api less than 21 define sig* functions inline, so it is not
433     // available for dynamic link. Implementing sigemptyset and sigaddset allow us
434     // to support older Android version (independent of libc version).
435     // The following implementations are based on https://git.io/vSkNf
436
437     #[cfg(not(target_os = "android"))]
438     extern {
439         #[cfg_attr(target_os = "netbsd", link_name = "__sigemptyset14")]
440         fn sigemptyset(set: *mut libc::sigset_t) -> libc::c_int;
441
442         #[cfg_attr(target_os = "netbsd", link_name = "__sigaddset14")]
443         fn sigaddset(set: *mut libc::sigset_t, signum: libc::c_int) -> libc::c_int;
444     }
445
446     #[cfg(target_os = "android")]
447     unsafe fn sigemptyset(set: *mut libc::sigset_t) -> libc::c_int {
448         libc::memset(set as *mut _, 0, mem::size_of::<libc::sigset_t>());
449         return 0;
450     }
451
452     #[cfg(target_os = "android")]
453     unsafe fn sigaddset(set: *mut libc::sigset_t, signum: libc::c_int) -> libc::c_int {
454         use slice;
455
456         let raw = slice::from_raw_parts_mut(set as *mut u8, mem::size_of::<libc::sigset_t>());
457         let bit = (signum - 1) as usize;
458         raw[bit / 8] |= 1 << (bit % 8);
459         return 0;
460     }
461
462     // See #14232 for more information, but it appears that signal delivery to a
463     // newly spawned process may just be raced in the macOS, so to prevent this
464     // test from being flaky we ignore it on macOS.
465     #[test]
466     #[cfg_attr(target_os = "macos", ignore)]
467     #[cfg_attr(target_os = "nacl", ignore)] // no signals on NaCl.
468     // When run under our current QEMU emulation test suite this test fails,
469     // although the reason isn't very clear as to why. For now this test is
470     // ignored there.
471     #[cfg_attr(target_arch = "arm", ignore)]
472     fn test_process_mask() {
473         unsafe {
474             // Test to make sure that a signal mask does not get inherited.
475             let mut cmd = Command::new(OsStr::new("cat"));
476
477             let mut set: libc::sigset_t = mem::uninitialized();
478             let mut old_set: libc::sigset_t = mem::uninitialized();
479             t!(cvt(sigemptyset(&mut set)));
480             t!(cvt(sigaddset(&mut set, libc::SIGINT)));
481             t!(cvt(libc::pthread_sigmask(libc::SIG_SETMASK, &set, &mut old_set)));
482
483             cmd.stdin(Stdio::MakePipe);
484             cmd.stdout(Stdio::MakePipe);
485
486             let (mut cat, mut pipes) = t!(cmd.spawn(Stdio::Null, true));
487             let stdin_write = pipes.stdin.take().unwrap();
488             let stdout_read = pipes.stdout.take().unwrap();
489
490             t!(cvt(libc::pthread_sigmask(libc::SIG_SETMASK, &old_set,
491                                          ptr::null_mut())));
492
493             t!(cvt(libc::kill(cat.id() as libc::pid_t, libc::SIGINT)));
494             // We need to wait until SIGINT is definitely delivered. The
495             // easiest way is to write something to cat, and try to read it
496             // back: if SIGINT is unmasked, it'll get delivered when cat is
497             // next scheduled.
498             let _ = stdin_write.write(b"Hello");
499             drop(stdin_write);
500
501             // Either EOF or failure (EPIPE) is okay.
502             let mut buf = [0; 5];
503             if let Ok(ret) = stdout_read.read(&mut buf) {
504                 assert_eq!(ret, 0);
505             }
506
507             t!(cat.wait());
508         }
509     }
510 }