]> git.lizzy.rs Git - rust.git/blob - src/libstd/sys/unix/process/process_common.rs
Command::env_saw_path() may be unused on platforms not using posix_spawn()
[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     #[allow(dead_code)]
188     pub fn env_saw_path(&self) -> bool {
189         self.env.have_changed_path()
190     }
191
192     pub fn setup_io(&self, default: Stdio, needs_stdin: bool)
193                 -> io::Result<(StdioPipes, ChildPipes)> {
194         let null = Stdio::Null;
195         let default_stdin = if needs_stdin {&default} else {&null};
196         let stdin = self.stdin.as_ref().unwrap_or(default_stdin);
197         let stdout = self.stdout.as_ref().unwrap_or(&default);
198         let stderr = self.stderr.as_ref().unwrap_or(&default);
199         let (their_stdin, our_stdin) = stdin.to_child_stdio(true)?;
200         let (their_stdout, our_stdout) = stdout.to_child_stdio(false)?;
201         let (their_stderr, our_stderr) = stderr.to_child_stdio(false)?;
202         let ours = StdioPipes {
203             stdin: our_stdin,
204             stdout: our_stdout,
205             stderr: our_stderr,
206         };
207         let theirs = ChildPipes {
208             stdin: their_stdin,
209             stdout: their_stdout,
210             stderr: their_stderr,
211         };
212         Ok((ours, theirs))
213     }
214 }
215
216 fn os2c(s: &OsStr, saw_nul: &mut bool) -> CString {
217     CString::new(s.as_bytes()).unwrap_or_else(|_e| {
218         *saw_nul = true;
219         CString::new("<string-with-nul>").unwrap()
220     })
221 }
222
223 // Helper type to manage ownership of the strings within a C-style array.
224 pub struct CStringArray {
225     items: Vec<CString>,
226     ptrs: Vec<*const c_char>
227 }
228
229 impl CStringArray {
230     pub fn with_capacity(capacity: usize) -> Self {
231         let mut result = CStringArray {
232             items: Vec::with_capacity(capacity),
233             ptrs: Vec::with_capacity(capacity+1)
234         };
235         result.ptrs.push(ptr::null());
236         result
237     }
238     pub fn push(&mut self, item: CString) {
239         let l = self.ptrs.len();
240         self.ptrs[l-1] = item.as_ptr();
241         self.ptrs.push(ptr::null());
242         self.items.push(item);
243     }
244     pub fn as_ptr(&self) -> *const *const c_char {
245         self.ptrs.as_ptr()
246     }
247 }
248
249 fn construct_envp(env: BTreeMap<DefaultEnvKey, OsString>, saw_nul: &mut bool) -> CStringArray {
250     let mut result = CStringArray::with_capacity(env.len());
251     for (k, v) in env {
252         let mut k: OsString = k.into();
253
254         // Reserve additional space for '=' and null terminator
255         k.reserve_exact(v.len() + 2);
256         k.push("=");
257         k.push(&v);
258
259         // Add the new entry into the array
260         if let Ok(item) = CString::new(k.into_vec()) {
261             result.push(item);
262         } else {
263             *saw_nul = true;
264         }
265     }
266
267     result
268 }
269
270 impl Stdio {
271     pub fn to_child_stdio(&self, readable: bool)
272                       -> io::Result<(ChildStdio, Option<AnonPipe>)> {
273         match *self {
274             Stdio::Inherit => {
275                 Ok((ChildStdio::Inherit, None))
276             },
277
278             // Make sure that the source descriptors are not an stdio
279             // descriptor, otherwise the order which we set the child's
280             // descriptors may blow away a descriptor which we are hoping to
281             // save. For example, suppose we want the child's stderr to be the
282             // parent's stdout, and the child's stdout to be the parent's
283             // stderr. No matter which we dup first, the second will get
284             // overwritten prematurely.
285             Stdio::Fd(ref fd) => {
286                 if fd.raw() >= 0 && fd.raw() <= libc::STDERR_FILENO {
287                     Ok((ChildStdio::Owned(fd.duplicate()?), None))
288                 } else {
289                     Ok((ChildStdio::Explicit(fd.raw()), None))
290                 }
291             }
292
293             Stdio::MakePipe => {
294                 let (reader, writer) = pipe::anon_pipe()?;
295                 let (ours, theirs) = if readable {
296                     (writer, reader)
297                 } else {
298                     (reader, writer)
299                 };
300                 Ok((ChildStdio::Owned(theirs.into_fd()), Some(ours)))
301             }
302
303             Stdio::Null => {
304                 let mut opts = OpenOptions::new();
305                 opts.read(readable);
306                 opts.write(!readable);
307                 let path = unsafe {
308                     CStr::from_ptr("/dev/null\0".as_ptr() as *const _)
309                 };
310                 let fd = File::open_c(&path, &opts)?;
311                 Ok((ChildStdio::Owned(fd.into_fd()), None))
312             }
313         }
314     }
315 }
316
317 impl From<AnonPipe> for Stdio {
318     fn from(pipe: AnonPipe) -> Stdio {
319         Stdio::Fd(pipe.into_fd())
320     }
321 }
322
323 impl From<File> for Stdio {
324     fn from(file: File) -> Stdio {
325         Stdio::Fd(file.into_fd())
326     }
327 }
328
329 impl ChildStdio {
330     pub fn fd(&self) -> Option<c_int> {
331         match *self {
332             ChildStdio::Inherit => None,
333             ChildStdio::Explicit(fd) => Some(fd),
334             ChildStdio::Owned(ref fd) => Some(fd.raw()),
335         }
336     }
337 }
338
339 impl fmt::Debug for Command {
340     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
341         write!(f, "{:?}", self.program)?;
342         for arg in &self.args {
343             write!(f, " {:?}", arg)?;
344         }
345         Ok(())
346     }
347 }
348
349 /// Unix exit statuses
350 #[derive(PartialEq, Eq, Clone, Copy, Debug)]
351 pub struct ExitStatus(c_int);
352
353 impl ExitStatus {
354     pub fn new(status: c_int) -> ExitStatus {
355         ExitStatus(status)
356     }
357
358     fn exited(&self) -> bool {
359         unsafe { libc::WIFEXITED(self.0) }
360     }
361
362     pub fn success(&self) -> bool {
363         self.code() == Some(0)
364     }
365
366     pub fn code(&self) -> Option<i32> {
367         if self.exited() {
368             Some(unsafe { libc::WEXITSTATUS(self.0) })
369         } else {
370             None
371         }
372     }
373
374     pub fn signal(&self) -> Option<i32> {
375         if !self.exited() {
376             Some(unsafe { libc::WTERMSIG(self.0) })
377         } else {
378             None
379         }
380     }
381 }
382
383 impl From<c_int> for ExitStatus {
384     fn from(a: c_int) -> ExitStatus {
385         ExitStatus(a)
386     }
387 }
388
389 impl fmt::Display for ExitStatus {
390     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
391         if let Some(code) = self.code() {
392             write!(f, "exit code: {}", code)
393         } else {
394             let signal = self.signal().unwrap();
395             write!(f, "signal: {}", signal)
396         }
397     }
398 }
399
400 #[derive(PartialEq, Eq, Clone, Copy, Debug)]
401 pub struct ExitCode(u8);
402
403 impl ExitCode {
404     pub const SUCCESS: ExitCode = ExitCode(EXIT_SUCCESS as _);
405     pub const FAILURE: ExitCode = ExitCode(EXIT_FAILURE as _);
406
407     pub fn as_i32(&self) -> i32 {
408         self.0 as i32
409     }
410 }
411
412 #[cfg(all(test, not(target_os = "emscripten")))]
413 mod tests {
414     use super::*;
415
416     use ffi::OsStr;
417     use mem;
418     use ptr;
419     use libc;
420     use sys::cvt;
421
422     macro_rules! t {
423         ($e:expr) => {
424             match $e {
425                 Ok(t) => t,
426                 Err(e) => panic!("received error for `{}`: {}", stringify!($e), e),
427             }
428         }
429     }
430
431     // Android with api less than 21 define sig* functions inline, so it is not
432     // available for dynamic link. Implementing sigemptyset and sigaddset allow us
433     // to support older Android version (independent of libc version).
434     // The following implementations are based on https://git.io/vSkNf
435
436     #[cfg(not(target_os = "android"))]
437     extern {
438         #[cfg_attr(target_os = "netbsd", link_name = "__sigemptyset14")]
439         fn sigemptyset(set: *mut libc::sigset_t) -> libc::c_int;
440
441         #[cfg_attr(target_os = "netbsd", link_name = "__sigaddset14")]
442         fn sigaddset(set: *mut libc::sigset_t, signum: libc::c_int) -> libc::c_int;
443     }
444
445     #[cfg(target_os = "android")]
446     unsafe fn sigemptyset(set: *mut libc::sigset_t) -> libc::c_int {
447         libc::memset(set as *mut _, 0, mem::size_of::<libc::sigset_t>());
448         return 0;
449     }
450
451     #[cfg(target_os = "android")]
452     unsafe fn sigaddset(set: *mut libc::sigset_t, signum: libc::c_int) -> libc::c_int {
453         use slice;
454
455         let raw = slice::from_raw_parts_mut(set as *mut u8, mem::size_of::<libc::sigset_t>());
456         let bit = (signum - 1) as usize;
457         raw[bit / 8] |= 1 << (bit % 8);
458         return 0;
459     }
460
461     // See #14232 for more information, but it appears that signal delivery to a
462     // newly spawned process may just be raced in the macOS, so to prevent this
463     // test from being flaky we ignore it on macOS.
464     #[test]
465     #[cfg_attr(target_os = "macos", ignore)]
466     // When run under our current QEMU emulation test suite this test fails,
467     // although the reason isn't very clear as to why. For now this test is
468     // ignored there.
469     #[cfg_attr(target_arch = "arm", ignore)]
470     #[cfg_attr(target_arch = "aarch64", ignore)]
471     fn test_process_mask() {
472         unsafe {
473             // Test to make sure that a signal mask does not get inherited.
474             let mut cmd = Command::new(OsStr::new("cat"));
475
476             let mut set: libc::sigset_t = mem::uninitialized();
477             let mut old_set: libc::sigset_t = mem::uninitialized();
478             t!(cvt(sigemptyset(&mut set)));
479             t!(cvt(sigaddset(&mut set, libc::SIGINT)));
480             t!(cvt(libc::pthread_sigmask(libc::SIG_SETMASK, &set, &mut old_set)));
481
482             cmd.stdin(Stdio::MakePipe);
483             cmd.stdout(Stdio::MakePipe);
484
485             let (mut cat, mut pipes) = t!(cmd.spawn(Stdio::Null, true));
486             let stdin_write = pipes.stdin.take().unwrap();
487             let stdout_read = pipes.stdout.take().unwrap();
488
489             t!(cvt(libc::pthread_sigmask(libc::SIG_SETMASK, &old_set,
490                                          ptr::null_mut())));
491
492             t!(cvt(libc::kill(cat.id() as libc::pid_t, libc::SIGINT)));
493             // We need to wait until SIGINT is definitely delivered. The
494             // easiest way is to write something to cat, and try to read it
495             // back: if SIGINT is unmasked, it'll get delivered when cat is
496             // next scheduled.
497             let _ = stdin_write.write(b"Hello");
498             drop(stdin_write);
499
500             // Either EOF or failure (EPIPE) is okay.
501             let mut buf = [0; 5];
502             if let Ok(ret) = stdout_read.read(&mut buf) {
503                 assert_eq!(ret, 0);
504             }
505
506             t!(cat.wait());
507         }
508     }
509 }