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