]> git.lizzy.rs Git - rust.git/blob - library/std/src/sys/windows/process.rs
Rollup merge of #82483 - tmiasko:option-from-str, r=matthewjasper
[rust.git] / library / std / src / sys / windows / process.rs
1 #![unstable(feature = "process_internals", issue = "none")]
2
3 #[cfg(test)]
4 mod tests;
5
6 use crate::borrow::Borrow;
7 use crate::collections::BTreeMap;
8 use crate::env;
9 use crate::env::split_paths;
10 use crate::ffi::{OsStr, OsString};
11 use crate::fmt;
12 use crate::fs;
13 use crate::io::{self, Error, ErrorKind};
14 use crate::mem;
15 use crate::os::windows::ffi::OsStrExt;
16 use crate::path::Path;
17 use crate::ptr;
18 use crate::sys::c;
19 use crate::sys::cvt;
20 use crate::sys::fs::{File, OpenOptions};
21 use crate::sys::handle::Handle;
22 use crate::sys::mutex::Mutex;
23 use crate::sys::pipe::{self, AnonPipe};
24 use crate::sys::stdio;
25 use crate::sys_common::process::{CommandEnv, CommandEnvs};
26 use crate::sys_common::AsInner;
27
28 use libc::{c_void, EXIT_FAILURE, EXIT_SUCCESS};
29
30 ////////////////////////////////////////////////////////////////////////////////
31 // Command
32 ////////////////////////////////////////////////////////////////////////////////
33
34 #[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
35 #[doc(hidden)]
36 pub struct EnvKey(OsString);
37
38 impl From<OsString> for EnvKey {
39     fn from(mut k: OsString) -> Self {
40         k.make_ascii_uppercase();
41         EnvKey(k)
42     }
43 }
44
45 impl From<EnvKey> for OsString {
46     fn from(k: EnvKey) -> Self {
47         k.0
48     }
49 }
50
51 impl Borrow<OsStr> for EnvKey {
52     fn borrow(&self) -> &OsStr {
53         &self.0
54     }
55 }
56
57 impl AsRef<OsStr> for EnvKey {
58     fn as_ref(&self) -> &OsStr {
59         &self.0
60     }
61 }
62
63 fn ensure_no_nuls<T: AsRef<OsStr>>(str: T) -> io::Result<T> {
64     if str.as_ref().encode_wide().any(|b| b == 0) {
65         Err(io::Error::new_const(ErrorKind::InvalidInput, &"nul byte found in provided data"))
66     } else {
67         Ok(str)
68     }
69 }
70
71 pub struct Command {
72     program: OsString,
73     args: Vec<OsString>,
74     env: CommandEnv,
75     cwd: Option<OsString>,
76     flags: u32,
77     detach: bool, // not currently exposed in std::process
78     stdin: Option<Stdio>,
79     stdout: Option<Stdio>,
80     stderr: Option<Stdio>,
81     force_quotes_enabled: bool,
82 }
83
84 pub enum Stdio {
85     Inherit,
86     Null,
87     MakePipe,
88     Handle(Handle),
89 }
90
91 pub struct StdioPipes {
92     pub stdin: Option<AnonPipe>,
93     pub stdout: Option<AnonPipe>,
94     pub stderr: Option<AnonPipe>,
95 }
96
97 struct DropGuard<'a> {
98     lock: &'a Mutex,
99 }
100
101 impl Command {
102     pub fn new(program: &OsStr) -> Command {
103         Command {
104             program: program.to_os_string(),
105             args: Vec::new(),
106             env: Default::default(),
107             cwd: None,
108             flags: 0,
109             detach: false,
110             stdin: None,
111             stdout: None,
112             stderr: None,
113             force_quotes_enabled: false,
114         }
115     }
116
117     pub fn arg(&mut self, arg: &OsStr) {
118         self.args.push(arg.to_os_string())
119     }
120     pub fn env_mut(&mut self) -> &mut CommandEnv {
121         &mut self.env
122     }
123     pub fn cwd(&mut self, dir: &OsStr) {
124         self.cwd = Some(dir.to_os_string())
125     }
126     pub fn stdin(&mut self, stdin: Stdio) {
127         self.stdin = Some(stdin);
128     }
129     pub fn stdout(&mut self, stdout: Stdio) {
130         self.stdout = Some(stdout);
131     }
132     pub fn stderr(&mut self, stderr: Stdio) {
133         self.stderr = Some(stderr);
134     }
135     pub fn creation_flags(&mut self, flags: u32) {
136         self.flags = flags;
137     }
138
139     pub fn force_quotes(&mut self, enabled: bool) {
140         self.force_quotes_enabled = enabled;
141     }
142
143     pub fn get_program(&self) -> &OsStr {
144         &self.program
145     }
146
147     pub fn get_args(&self) -> CommandArgs<'_> {
148         let iter = self.args.iter();
149         CommandArgs { iter }
150     }
151
152     pub fn get_envs(&self) -> CommandEnvs<'_> {
153         self.env.iter()
154     }
155
156     pub fn get_current_dir(&self) -> Option<&Path> {
157         self.cwd.as_ref().map(|cwd| Path::new(cwd))
158     }
159
160     pub fn spawn(
161         &mut self,
162         default: Stdio,
163         needs_stdin: bool,
164     ) -> io::Result<(Process, StdioPipes)> {
165         let maybe_env = self.env.capture_if_changed();
166         // To have the spawning semantics of unix/windows stay the same, we need
167         // to read the *child's* PATH if one is provided. See #15149 for more
168         // details.
169         let program = maybe_env.as_ref().and_then(|env| {
170             if let Some(v) = env.get(OsStr::new("PATH")) {
171                 // Split the value and test each path to see if the
172                 // program exists.
173                 for path in split_paths(&v) {
174                     let path = path
175                         .join(self.program.to_str().unwrap())
176                         .with_extension(env::consts::EXE_EXTENSION);
177                     if fs::metadata(&path).is_ok() {
178                         return Some(path.into_os_string());
179                     }
180                 }
181             }
182             None
183         });
184
185         let mut si = zeroed_startupinfo();
186         si.cb = mem::size_of::<c::STARTUPINFO>() as c::DWORD;
187         si.dwFlags = c::STARTF_USESTDHANDLES;
188
189         let program = program.as_ref().unwrap_or(&self.program);
190         let mut cmd_str = make_command_line(program, &self.args, self.force_quotes_enabled)?;
191         cmd_str.push(0); // add null terminator
192
193         // stolen from the libuv code.
194         let mut flags = self.flags | c::CREATE_UNICODE_ENVIRONMENT;
195         if self.detach {
196             flags |= c::DETACHED_PROCESS | c::CREATE_NEW_PROCESS_GROUP;
197         }
198
199         let (envp, _data) = make_envp(maybe_env)?;
200         let (dirp, _data) = make_dirp(self.cwd.as_ref())?;
201         let mut pi = zeroed_process_information();
202
203         // Prepare all stdio handles to be inherited by the child. This
204         // currently involves duplicating any existing ones with the ability to
205         // be inherited by child processes. Note, however, that once an
206         // inheritable handle is created, *any* spawned child will inherit that
207         // handle. We only want our own child to inherit this handle, so we wrap
208         // the remaining portion of this spawn in a mutex.
209         //
210         // For more information, msdn also has an article about this race:
211         // http://support.microsoft.com/kb/315939
212         static CREATE_PROCESS_LOCK: Mutex = Mutex::new();
213         let _guard = DropGuard::new(&CREATE_PROCESS_LOCK);
214
215         let mut pipes = StdioPipes { stdin: None, stdout: None, stderr: None };
216         let null = Stdio::Null;
217         let default_stdin = if needs_stdin { &default } else { &null };
218         let stdin = self.stdin.as_ref().unwrap_or(default_stdin);
219         let stdout = self.stdout.as_ref().unwrap_or(&default);
220         let stderr = self.stderr.as_ref().unwrap_or(&default);
221         let stdin = stdin.to_handle(c::STD_INPUT_HANDLE, &mut pipes.stdin)?;
222         let stdout = stdout.to_handle(c::STD_OUTPUT_HANDLE, &mut pipes.stdout)?;
223         let stderr = stderr.to_handle(c::STD_ERROR_HANDLE, &mut pipes.stderr)?;
224         si.hStdInput = stdin.raw();
225         si.hStdOutput = stdout.raw();
226         si.hStdError = stderr.raw();
227
228         unsafe {
229             cvt(c::CreateProcessW(
230                 ptr::null(),
231                 cmd_str.as_mut_ptr(),
232                 ptr::null_mut(),
233                 ptr::null_mut(),
234                 c::TRUE,
235                 flags,
236                 envp,
237                 dirp,
238                 &mut si,
239                 &mut pi,
240             ))
241         }?;
242
243         // We close the thread handle because we don't care about keeping
244         // the thread id valid, and we aren't keeping the thread handle
245         // around to be able to close it later.
246         drop(Handle::new(pi.hThread));
247
248         Ok((Process { handle: Handle::new(pi.hProcess) }, pipes))
249     }
250 }
251
252 impl fmt::Debug for Command {
253     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
254         write!(f, "{:?}", self.program)?;
255         for arg in &self.args {
256             write!(f, " {:?}", arg)?;
257         }
258         Ok(())
259     }
260 }
261
262 impl<'a> DropGuard<'a> {
263     fn new(lock: &'a Mutex) -> DropGuard<'a> {
264         unsafe {
265             lock.lock();
266             DropGuard { lock }
267         }
268     }
269 }
270
271 impl<'a> Drop for DropGuard<'a> {
272     fn drop(&mut self) {
273         unsafe {
274             self.lock.unlock();
275         }
276     }
277 }
278
279 impl Stdio {
280     fn to_handle(&self, stdio_id: c::DWORD, pipe: &mut Option<AnonPipe>) -> io::Result<Handle> {
281         match *self {
282             // If no stdio handle is available, then inherit means that it
283             // should still be unavailable so propagate the
284             // INVALID_HANDLE_VALUE.
285             Stdio::Inherit => match stdio::get_handle(stdio_id) {
286                 Ok(io) => {
287                     let io = Handle::new(io);
288                     let ret = io.duplicate(0, true, c::DUPLICATE_SAME_ACCESS);
289                     io.into_raw();
290                     ret
291                 }
292                 Err(..) => Ok(Handle::new(c::INVALID_HANDLE_VALUE)),
293             },
294
295             Stdio::MakePipe => {
296                 let ours_readable = stdio_id != c::STD_INPUT_HANDLE;
297                 let pipes = pipe::anon_pipe(ours_readable, true)?;
298                 *pipe = Some(pipes.ours);
299                 Ok(pipes.theirs.into_handle())
300             }
301
302             Stdio::Handle(ref handle) => handle.duplicate(0, true, c::DUPLICATE_SAME_ACCESS),
303
304             // Open up a reference to NUL with appropriate read/write
305             // permissions as well as the ability to be inherited to child
306             // processes (as this is about to be inherited).
307             Stdio::Null => {
308                 let size = mem::size_of::<c::SECURITY_ATTRIBUTES>();
309                 let mut sa = c::SECURITY_ATTRIBUTES {
310                     nLength: size as c::DWORD,
311                     lpSecurityDescriptor: ptr::null_mut(),
312                     bInheritHandle: 1,
313                 };
314                 let mut opts = OpenOptions::new();
315                 opts.read(stdio_id == c::STD_INPUT_HANDLE);
316                 opts.write(stdio_id != c::STD_INPUT_HANDLE);
317                 opts.security_attributes(&mut sa);
318                 File::open(Path::new("NUL"), &opts).map(|file| file.into_handle())
319             }
320         }
321     }
322 }
323
324 impl From<AnonPipe> for Stdio {
325     fn from(pipe: AnonPipe) -> Stdio {
326         Stdio::Handle(pipe.into_handle())
327     }
328 }
329
330 impl From<File> for Stdio {
331     fn from(file: File) -> Stdio {
332         Stdio::Handle(file.into_handle())
333     }
334 }
335
336 ////////////////////////////////////////////////////////////////////////////////
337 // Processes
338 ////////////////////////////////////////////////////////////////////////////////
339
340 /// A value representing a child process.
341 ///
342 /// The lifetime of this value is linked to the lifetime of the actual
343 /// process - the Process destructor calls self.finish() which waits
344 /// for the process to terminate.
345 pub struct Process {
346     handle: Handle,
347 }
348
349 impl Process {
350     pub fn kill(&mut self) -> io::Result<()> {
351         cvt(unsafe { c::TerminateProcess(self.handle.raw(), 1) })?;
352         Ok(())
353     }
354
355     pub fn id(&self) -> u32 {
356         unsafe { c::GetProcessId(self.handle.raw()) as u32 }
357     }
358
359     pub fn wait(&mut self) -> io::Result<ExitStatus> {
360         unsafe {
361             let res = c::WaitForSingleObject(self.handle.raw(), c::INFINITE);
362             if res != c::WAIT_OBJECT_0 {
363                 return Err(Error::last_os_error());
364             }
365             let mut status = 0;
366             cvt(c::GetExitCodeProcess(self.handle.raw(), &mut status))?;
367             Ok(ExitStatus(status))
368         }
369     }
370
371     pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
372         unsafe {
373             match c::WaitForSingleObject(self.handle.raw(), 0) {
374                 c::WAIT_OBJECT_0 => {}
375                 c::WAIT_TIMEOUT => {
376                     return Ok(None);
377                 }
378                 _ => return Err(io::Error::last_os_error()),
379             }
380             let mut status = 0;
381             cvt(c::GetExitCodeProcess(self.handle.raw(), &mut status))?;
382             Ok(Some(ExitStatus(status)))
383         }
384     }
385
386     pub fn handle(&self) -> &Handle {
387         &self.handle
388     }
389
390     pub fn into_handle(self) -> Handle {
391         self.handle
392     }
393 }
394
395 #[derive(PartialEq, Eq, Clone, Copy, Debug)]
396 pub struct ExitStatus(c::DWORD);
397
398 impl ExitStatus {
399     pub fn success(&self) -> bool {
400         self.0 == 0
401     }
402     pub fn code(&self) -> Option<i32> {
403         Some(self.0 as i32)
404     }
405 }
406
407 /// Converts a raw `c::DWORD` to a type-safe `ExitStatus` by wrapping it without copying.
408 impl From<c::DWORD> for ExitStatus {
409     fn from(u: c::DWORD) -> ExitStatus {
410         ExitStatus(u)
411     }
412 }
413
414 impl fmt::Display for ExitStatus {
415     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
416         // Windows exit codes with the high bit set typically mean some form of
417         // unhandled exception or warning. In this scenario printing the exit
418         // code in decimal doesn't always make sense because it's a very large
419         // and somewhat gibberish number. The hex code is a bit more
420         // recognizable and easier to search for, so print that.
421         if self.0 & 0x80000000 != 0 {
422             write!(f, "exit code: {:#x}", self.0)
423         } else {
424             write!(f, "exit code: {}", self.0)
425         }
426     }
427 }
428
429 #[derive(PartialEq, Eq, Clone, Copy, Debug)]
430 pub struct ExitCode(c::DWORD);
431
432 impl ExitCode {
433     pub const SUCCESS: ExitCode = ExitCode(EXIT_SUCCESS as _);
434     pub const FAILURE: ExitCode = ExitCode(EXIT_FAILURE as _);
435
436     #[inline]
437     pub fn as_i32(&self) -> i32 {
438         self.0 as i32
439     }
440 }
441
442 fn zeroed_startupinfo() -> c::STARTUPINFO {
443     c::STARTUPINFO {
444         cb: 0,
445         lpReserved: ptr::null_mut(),
446         lpDesktop: ptr::null_mut(),
447         lpTitle: ptr::null_mut(),
448         dwX: 0,
449         dwY: 0,
450         dwXSize: 0,
451         dwYSize: 0,
452         dwXCountChars: 0,
453         dwYCountCharts: 0,
454         dwFillAttribute: 0,
455         dwFlags: 0,
456         wShowWindow: 0,
457         cbReserved2: 0,
458         lpReserved2: ptr::null_mut(),
459         hStdInput: c::INVALID_HANDLE_VALUE,
460         hStdOutput: c::INVALID_HANDLE_VALUE,
461         hStdError: c::INVALID_HANDLE_VALUE,
462     }
463 }
464
465 fn zeroed_process_information() -> c::PROCESS_INFORMATION {
466     c::PROCESS_INFORMATION {
467         hProcess: ptr::null_mut(),
468         hThread: ptr::null_mut(),
469         dwProcessId: 0,
470         dwThreadId: 0,
471     }
472 }
473
474 // Produces a wide string *without terminating null*; returns an error if
475 // `prog` or any of the `args` contain a nul.
476 fn make_command_line(prog: &OsStr, args: &[OsString], force_quotes: bool) -> io::Result<Vec<u16>> {
477     // Encode the command and arguments in a command line string such
478     // that the spawned process may recover them using CommandLineToArgvW.
479     let mut cmd: Vec<u16> = Vec::new();
480     // Always quote the program name so CreateProcess doesn't interpret args as
481     // part of the name if the binary wasn't found first time.
482     append_arg(&mut cmd, prog, true)?;
483     for arg in args {
484         cmd.push(' ' as u16);
485         append_arg(&mut cmd, arg, force_quotes)?;
486     }
487     return Ok(cmd);
488
489     fn append_arg(cmd: &mut Vec<u16>, arg: &OsStr, force_quotes: bool) -> io::Result<()> {
490         // If an argument has 0 characters then we need to quote it to ensure
491         // that it actually gets passed through on the command line or otherwise
492         // it will be dropped entirely when parsed on the other end.
493         ensure_no_nuls(arg)?;
494         let arg_bytes = &arg.as_inner().inner.as_inner();
495         let quote = force_quotes
496             || arg_bytes.iter().any(|c| *c == b' ' || *c == b'\t')
497             || arg_bytes.is_empty();
498         if quote {
499             cmd.push('"' as u16);
500         }
501
502         let mut backslashes: usize = 0;
503         for x in arg.encode_wide() {
504             if x == '\\' as u16 {
505                 backslashes += 1;
506             } else {
507                 if x == '"' as u16 {
508                     // Add n+1 backslashes to total 2n+1 before internal '"'.
509                     cmd.extend((0..=backslashes).map(|_| '\\' as u16));
510                 }
511                 backslashes = 0;
512             }
513             cmd.push(x);
514         }
515
516         if quote {
517             // Add n backslashes to total 2n before ending '"'.
518             cmd.extend((0..backslashes).map(|_| '\\' as u16));
519             cmd.push('"' as u16);
520         }
521         Ok(())
522     }
523 }
524
525 fn make_envp(maybe_env: Option<BTreeMap<EnvKey, OsString>>) -> io::Result<(*mut c_void, Vec<u16>)> {
526     // On Windows we pass an "environment block" which is not a char**, but
527     // rather a concatenation of null-terminated k=v\0 sequences, with a final
528     // \0 to terminate.
529     if let Some(env) = maybe_env {
530         let mut blk = Vec::new();
531
532         for (k, v) in env {
533             blk.extend(ensure_no_nuls(k.0)?.encode_wide());
534             blk.push('=' as u16);
535             blk.extend(ensure_no_nuls(v)?.encode_wide());
536             blk.push(0);
537         }
538         blk.push(0);
539         Ok((blk.as_mut_ptr() as *mut c_void, blk))
540     } else {
541         Ok((ptr::null_mut(), Vec::new()))
542     }
543 }
544
545 fn make_dirp(d: Option<&OsString>) -> io::Result<(*const u16, Vec<u16>)> {
546     match d {
547         Some(dir) => {
548             let mut dir_str: Vec<u16> = ensure_no_nuls(dir)?.encode_wide().collect();
549             dir_str.push(0);
550             Ok((dir_str.as_ptr(), dir_str))
551         }
552         None => Ok((ptr::null(), Vec::new())),
553     }
554 }
555
556 pub struct CommandArgs<'a> {
557     iter: crate::slice::Iter<'a, OsString>,
558 }
559
560 impl<'a> Iterator for CommandArgs<'a> {
561     type Item = &'a OsStr;
562     fn next(&mut self) -> Option<&'a OsStr> {
563         self.iter.next().map(|s| s.as_ref())
564     }
565     fn size_hint(&self) -> (usize, Option<usize>) {
566         self.iter.size_hint()
567     }
568 }
569
570 impl<'a> ExactSizeIterator for CommandArgs<'a> {
571     fn len(&self) -> usize {
572         self.iter.len()
573     }
574     fn is_empty(&self) -> bool {
575         self.iter.is_empty()
576     }
577 }
578
579 impl<'a> fmt::Debug for CommandArgs<'a> {
580     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
581         f.debug_list().entries(self.iter.clone()).finish()
582     }
583 }