]>
Commit | Line | Data |
---|---|---|
416331ca XL |
1 | use crate::os::unix::prelude::*; |
2 | ||
60c5eb7d XL |
3 | use crate::collections::BTreeMap; |
4 | use crate::ffi::{CStr, CString, OsStr, OsString}; | |
416331ca XL |
5 | use crate::fmt; |
6 | use crate::io; | |
7 | use crate::ptr; | |
8 | use crate::sys::fd::FileDesc; | |
9 | use crate::sys::fs::{File, OpenOptions}; | |
10 | use crate::sys::pipe::{self, AnonPipe}; | |
e1599b0c | 11 | use crate::sys_common::process::CommandEnv; |
416331ca | 12 | |
60c5eb7d | 13 | use libc::{c_char, c_int, gid_t, uid_t, EXIT_FAILURE, EXIT_SUCCESS}; |
416331ca XL |
14 | |
15 | //////////////////////////////////////////////////////////////////////////////// | |
16 | // Command | |
17 | //////////////////////////////////////////////////////////////////////////////// | |
18 | ||
19 | pub struct Command { | |
20 | // Currently we try hard to ensure that the call to `.exec()` doesn't | |
21 | // actually allocate any memory. While many platforms try to ensure that | |
22 | // memory allocation works after a fork in a multithreaded process, it's | |
23 | // been observed to be buggy and somewhat unreliable, so we do our best to | |
24 | // just not do it at all! | |
25 | // | |
26 | // Along those lines, the `argv` and `envp` raw pointers here are exactly | |
27 | // what's gonna get passed to `execvp`. The `argv` array starts with the | |
28 | // `program` and ends with a NULL, and the `envp` pointer, if present, is | |
29 | // also null-terminated. | |
30 | // | |
31 | // Right now we don't support removing arguments, so there's no much fancy | |
32 | // support there, but we support adding and removing environment variables, | |
33 | // so a side table is used to track where in the `envp` array each key is | |
34 | // located. Whenever we add a key we update it in place if it's already | |
35 | // present, and whenever we remove a key we update the locations of all | |
36 | // other keys. | |
37 | program: CString, | |
38 | args: Vec<CString>, | |
39 | argv: Argv, | |
e1599b0c | 40 | env: CommandEnv, |
416331ca XL |
41 | |
42 | cwd: Option<CString>, | |
43 | uid: Option<uid_t>, | |
44 | gid: Option<gid_t>, | |
45 | saw_nul: bool, | |
46 | closures: Vec<Box<dyn FnMut() -> io::Result<()> + Send + Sync>>, | |
47 | stdin: Option<Stdio>, | |
48 | stdout: Option<Stdio>, | |
49 | stderr: Option<Stdio>, | |
50 | } | |
51 | ||
f9f354fc | 52 | // Create a new type for `Argv`, so that we can make it `Send` and `Sync` |
416331ca XL |
53 | struct Argv(Vec<*const c_char>); |
54 | ||
f9f354fc XL |
55 | // It is safe to make `Argv` `Send` and `Sync`, because it contains |
56 | // pointers to memory owned by `Command.args` | |
416331ca | 57 | unsafe impl Send for Argv {} |
f9f354fc | 58 | unsafe impl Sync for Argv {} |
416331ca XL |
59 | |
60 | // passed back to std::process with the pipes connected to the child, if any | |
61 | // were requested | |
62 | pub struct StdioPipes { | |
63 | pub stdin: Option<AnonPipe>, | |
64 | pub stdout: Option<AnonPipe>, | |
65 | pub stderr: Option<AnonPipe>, | |
66 | } | |
67 | ||
68 | // passed to do_exec() with configuration of what the child stdio should look | |
69 | // like | |
70 | pub struct ChildPipes { | |
71 | pub stdin: ChildStdio, | |
72 | pub stdout: ChildStdio, | |
73 | pub stderr: ChildStdio, | |
74 | } | |
75 | ||
76 | pub enum ChildStdio { | |
77 | Inherit, | |
78 | Explicit(c_int), | |
79 | Owned(FileDesc), | |
80 | } | |
81 | ||
82 | pub enum Stdio { | |
83 | Inherit, | |
84 | Null, | |
85 | MakePipe, | |
86 | Fd(FileDesc), | |
87 | } | |
88 | ||
89 | impl Command { | |
90 | pub fn new(program: &OsStr) -> Command { | |
91 | let mut saw_nul = false; | |
92 | let program = os2c(program, &mut saw_nul); | |
93 | Command { | |
94 | argv: Argv(vec![program.as_ptr(), ptr::null()]), | |
dfeec247 | 95 | args: vec![program.clone()], |
416331ca | 96 | program, |
416331ca XL |
97 | env: Default::default(), |
98 | cwd: None, | |
99 | uid: None, | |
100 | gid: None, | |
101 | saw_nul, | |
102 | closures: Vec::new(), | |
103 | stdin: None, | |
104 | stdout: None, | |
105 | stderr: None, | |
106 | } | |
107 | } | |
108 | ||
dfeec247 XL |
109 | pub fn set_arg_0(&mut self, arg: &OsStr) { |
110 | // Set a new arg0 | |
111 | let arg = os2c(arg, &mut self.saw_nul); | |
112 | debug_assert!(self.argv.0.len() > 1); | |
113 | self.argv.0[0] = arg.as_ptr(); | |
114 | self.args[0] = arg; | |
115 | } | |
116 | ||
416331ca XL |
117 | pub fn arg(&mut self, arg: &OsStr) { |
118 | // Overwrite the trailing NULL pointer in `argv` and then add a new null | |
119 | // pointer. | |
120 | let arg = os2c(arg, &mut self.saw_nul); | |
dfeec247 | 121 | self.argv.0[self.args.len()] = arg.as_ptr(); |
416331ca XL |
122 | self.argv.0.push(ptr::null()); |
123 | ||
124 | // Also make sure we keep track of the owned value to schedule a | |
125 | // destructor for this memory. | |
126 | self.args.push(arg); | |
127 | } | |
128 | ||
129 | pub fn cwd(&mut self, dir: &OsStr) { | |
130 | self.cwd = Some(os2c(dir, &mut self.saw_nul)); | |
131 | } | |
132 | pub fn uid(&mut self, id: uid_t) { | |
133 | self.uid = Some(id); | |
134 | } | |
135 | pub fn gid(&mut self, id: gid_t) { | |
136 | self.gid = Some(id); | |
137 | } | |
138 | ||
139 | pub fn saw_nul(&self) -> bool { | |
140 | self.saw_nul | |
141 | } | |
142 | pub fn get_argv(&self) -> &Vec<*const c_char> { | |
143 | &self.argv.0 | |
144 | } | |
145 | ||
dfeec247 XL |
146 | pub fn get_program(&self) -> &CStr { |
147 | &*self.program | |
148 | } | |
149 | ||
416331ca XL |
150 | #[allow(dead_code)] |
151 | pub fn get_cwd(&self) -> &Option<CString> { | |
152 | &self.cwd | |
153 | } | |
154 | #[allow(dead_code)] | |
155 | pub fn get_uid(&self) -> Option<uid_t> { | |
156 | self.uid | |
157 | } | |
158 | #[allow(dead_code)] | |
159 | pub fn get_gid(&self) -> Option<gid_t> { | |
160 | self.gid | |
161 | } | |
162 | ||
163 | pub fn get_closures(&mut self) -> &mut Vec<Box<dyn FnMut() -> io::Result<()> + Send + Sync>> { | |
164 | &mut self.closures | |
165 | } | |
166 | ||
60c5eb7d | 167 | pub unsafe fn pre_exec(&mut self, _f: Box<dyn FnMut() -> io::Result<()> + Send + Sync>) { |
416331ca | 168 | // Fork() is not supported in vxWorks so no way to run the closure in the new procecss. |
e1599b0c | 169 | unimplemented!(); |
416331ca XL |
170 | } |
171 | ||
172 | pub fn stdin(&mut self, stdin: Stdio) { | |
173 | self.stdin = Some(stdin); | |
174 | } | |
175 | ||
176 | pub fn stdout(&mut self, stdout: Stdio) { | |
177 | self.stdout = Some(stdout); | |
178 | } | |
179 | ||
180 | pub fn stderr(&mut self, stderr: Stdio) { | |
181 | self.stderr = Some(stderr); | |
182 | } | |
183 | ||
e1599b0c | 184 | pub fn env_mut(&mut self) -> &mut CommandEnv { |
416331ca XL |
185 | &mut self.env |
186 | } | |
187 | ||
188 | pub fn capture_env(&mut self) -> Option<CStringArray> { | |
189 | let maybe_env = self.env.capture_if_changed(); | |
190 | maybe_env.map(|env| construct_envp(env, &mut self.saw_nul)) | |
191 | } | |
192 | #[allow(dead_code)] | |
193 | pub fn env_saw_path(&self) -> bool { | |
194 | self.env.have_changed_path() | |
195 | } | |
196 | ||
60c5eb7d XL |
197 | pub fn setup_io( |
198 | &self, | |
199 | default: Stdio, | |
200 | needs_stdin: bool, | |
201 | ) -> io::Result<(StdioPipes, ChildPipes)> { | |
416331ca | 202 | let null = Stdio::Null; |
60c5eb7d | 203 | let default_stdin = if needs_stdin { &default } else { &null }; |
416331ca XL |
204 | let stdin = self.stdin.as_ref().unwrap_or(default_stdin); |
205 | let stdout = self.stdout.as_ref().unwrap_or(&default); | |
206 | let stderr = self.stderr.as_ref().unwrap_or(&default); | |
207 | let (their_stdin, our_stdin) = stdin.to_child_stdio(true)?; | |
208 | let (their_stdout, our_stdout) = stdout.to_child_stdio(false)?; | |
209 | let (their_stderr, our_stderr) = stderr.to_child_stdio(false)?; | |
60c5eb7d XL |
210 | let ours = StdioPipes { stdin: our_stdin, stdout: our_stdout, stderr: our_stderr }; |
211 | let theirs = ChildPipes { stdin: their_stdin, stdout: their_stdout, stderr: their_stderr }; | |
416331ca XL |
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>, | |
60c5eb7d | 226 | ptrs: Vec<*const c_char>, |
416331ca XL |
227 | } |
228 | ||
229 | impl CStringArray { | |
230 | pub fn with_capacity(capacity: usize) -> Self { | |
231 | let mut result = CStringArray { | |
232 | items: Vec::with_capacity(capacity), | |
60c5eb7d | 233 | ptrs: Vec::with_capacity(capacity + 1), |
416331ca XL |
234 | }; |
235 | result.ptrs.push(ptr::null()); | |
236 | result | |
237 | } | |
238 | pub fn push(&mut self, item: CString) { | |
239 | let l = self.ptrs.len(); | |
60c5eb7d | 240 | self.ptrs[l - 1] = item.as_ptr(); |
416331ca XL |
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 | ||
e1599b0c | 249 | fn construct_envp(env: BTreeMap<OsString, OsString>, saw_nul: &mut bool) -> CStringArray { |
416331ca XL |
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 { | |
60c5eb7d | 271 | pub fn to_child_stdio(&self, readable: bool) -> io::Result<(ChildStdio, Option<AnonPipe>)> { |
416331ca | 272 | match *self { |
60c5eb7d | 273 | Stdio::Inherit => Ok((ChildStdio::Inherit, None)), |
416331ca XL |
274 | |
275 | // Make sure that the source descriptors are not an stdio | |
276 | // descriptor, otherwise the order which we set the child's | |
277 | // descriptors may blow away a descriptor which we are hoping to | |
278 | // save. For example, suppose we want the child's stderr to be the | |
279 | // parent's stdout, and the child's stdout to be the parent's | |
280 | // stderr. No matter which we dup first, the second will get | |
281 | // overwritten prematurely. | |
282 | Stdio::Fd(ref fd) => { | |
283 | if fd.raw() >= 0 && fd.raw() <= libc::STDERR_FILENO { | |
284 | Ok((ChildStdio::Owned(fd.duplicate()?), None)) | |
285 | } else { | |
286 | Ok((ChildStdio::Explicit(fd.raw()), None)) | |
287 | } | |
288 | } | |
289 | ||
290 | Stdio::MakePipe => { | |
291 | let (reader, writer) = pipe::anon_pipe()?; | |
60c5eb7d | 292 | let (ours, theirs) = if readable { (writer, reader) } else { (reader, writer) }; |
416331ca XL |
293 | Ok((ChildStdio::Owned(theirs.into_fd()), Some(ours))) |
294 | } | |
295 | ||
296 | Stdio::Null => { | |
297 | let mut opts = OpenOptions::new(); | |
298 | opts.read(readable); | |
299 | opts.write(!readable); | |
60c5eb7d | 300 | let path = unsafe { CStr::from_ptr("/null\0".as_ptr() as *const _) }; |
416331ca XL |
301 | let fd = File::open_c(&path, &opts)?; |
302 | Ok((ChildStdio::Owned(fd.into_fd()), None)) | |
303 | } | |
304 | } | |
305 | } | |
306 | } | |
307 | ||
308 | impl From<AnonPipe> for Stdio { | |
309 | fn from(pipe: AnonPipe) -> Stdio { | |
310 | Stdio::Fd(pipe.into_fd()) | |
311 | } | |
312 | } | |
313 | ||
314 | impl From<File> for Stdio { | |
315 | fn from(file: File) -> Stdio { | |
316 | Stdio::Fd(file.into_fd()) | |
317 | } | |
318 | } | |
319 | ||
320 | impl ChildStdio { | |
321 | pub fn fd(&self) -> Option<c_int> { | |
322 | match *self { | |
323 | ChildStdio::Inherit => None, | |
324 | ChildStdio::Explicit(fd) => Some(fd), | |
325 | ChildStdio::Owned(ref fd) => Some(fd.raw()), | |
326 | } | |
327 | } | |
328 | } | |
329 | ||
330 | impl fmt::Debug for Command { | |
331 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | |
dfeec247 XL |
332 | if self.program != self.args[0] { |
333 | write!(f, "[{:?}] ", self.program)?; | |
334 | } | |
335 | write!(f, "{:?}", self.args[0])?; | |
336 | ||
337 | for arg in &self.args[1..] { | |
416331ca XL |
338 | write!(f, " {:?}", arg)?; |
339 | } | |
340 | Ok(()) | |
341 | } | |
342 | } | |
343 | ||
344 | /// Unix exit statuses | |
345 | #[derive(PartialEq, Eq, Clone, Copy, Debug)] | |
346 | pub struct ExitStatus(c_int); | |
347 | ||
348 | impl ExitStatus { | |
349 | pub fn new(status: c_int) -> ExitStatus { | |
350 | ExitStatus(status) | |
351 | } | |
352 | ||
353 | fn exited(&self) -> bool { | |
1b1a35ee | 354 | libc::WIFEXITED(self.0) |
416331ca XL |
355 | } |
356 | ||
357 | pub fn success(&self) -> bool { | |
358 | self.code() == Some(0) | |
359 | } | |
360 | ||
361 | pub fn code(&self) -> Option<i32> { | |
1b1a35ee | 362 | if self.exited() { Some(libc::WEXITSTATUS(self.0)) } else { None } |
416331ca XL |
363 | } |
364 | ||
365 | pub fn signal(&self) -> Option<i32> { | |
1b1a35ee | 366 | if !self.exited() { Some(libc::WTERMSIG(self.0)) } else { None } |
416331ca XL |
367 | } |
368 | } | |
369 | ||
3dfed10e | 370 | /// Converts a raw `c_int` to a type-safe `ExitStatus` by wrapping it without copying. |
416331ca XL |
371 | impl From<c_int> for ExitStatus { |
372 | fn from(a: c_int) -> ExitStatus { | |
373 | ExitStatus(a) | |
374 | } | |
375 | } | |
376 | ||
377 | impl fmt::Display for ExitStatus { | |
378 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | |
379 | if let Some(code) = self.code() { | |
380 | write!(f, "exit code: {}", code) | |
381 | } else { | |
382 | let signal = self.signal().unwrap(); | |
383 | write!(f, "signal: {}", signal) | |
384 | } | |
385 | } | |
386 | } | |
387 | ||
388 | #[derive(PartialEq, Eq, Clone, Copy, Debug)] | |
389 | pub struct ExitCode(u8); | |
390 | ||
391 | impl ExitCode { | |
392 | pub const SUCCESS: ExitCode = ExitCode(EXIT_SUCCESS as _); | |
393 | pub const FAILURE: ExitCode = ExitCode(EXIT_FAILURE as _); | |
394 | ||
395 | #[inline] | |
396 | pub fn as_i32(&self) -> i32 { | |
397 | self.0 as i32 | |
398 | } | |
399 | } |