1 #![unstable(feature = "process_internals", issue = "none")]
3 use crate::borrow
::Borrow
;
4 use crate::collections
::BTreeMap
;
6 use crate::env
::split_paths
;
7 use crate::ffi
::{OsStr, OsString}
;
10 use crate::io
::{self, Error, ErrorKind}
;
12 use crate::os
::windows
::ffi
::OsStrExt
;
13 use crate::path
::Path
;
17 use crate::sys
::fs
::{File, OpenOptions}
;
18 use crate::sys
::handle
::Handle
;
19 use crate::sys
::mutex
::Mutex
;
20 use crate::sys
::pipe
::{self, AnonPipe}
;
21 use crate::sys
::stdio
;
22 use crate::sys_common
::process
::CommandEnv
;
23 use crate::sys_common
::AsInner
;
25 use libc
::{c_void, EXIT_FAILURE, EXIT_SUCCESS}
;
27 ////////////////////////////////////////////////////////////////////////////////
29 ////////////////////////////////////////////////////////////////////////////////
31 #[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
33 pub struct EnvKey(OsString
);
35 impl From
<OsString
> for EnvKey
{
36 fn from(mut k
: OsString
) -> Self {
37 k
.make_ascii_uppercase();
42 impl From
<EnvKey
> for OsString
{
43 fn from(k
: EnvKey
) -> Self {
48 impl Borrow
<OsStr
> for EnvKey
{
49 fn borrow(&self) -> &OsStr
{
54 impl AsRef
<OsStr
> for EnvKey
{
55 fn as_ref(&self) -> &OsStr
{
60 fn ensure_no_nuls
<T
: AsRef
<OsStr
>>(str: T
) -> io
::Result
<T
> {
61 if str.as_ref().encode_wide().any(|b
| b
== 0) {
62 Err(io
::Error
::new(ErrorKind
::InvalidInput
, "nul byte found in provided data"))
72 cwd
: Option
<OsString
>,
74 detach
: bool
, // not currently exposed in std::process
76 stdout
: Option
<Stdio
>,
77 stderr
: Option
<Stdio
>,
87 pub struct StdioPipes
{
88 pub stdin
: Option
<AnonPipe
>,
89 pub stdout
: Option
<AnonPipe
>,
90 pub stderr
: Option
<AnonPipe
>,
93 struct DropGuard
<'a
> {
98 pub fn new(program
: &OsStr
) -> Command
{
100 program
: program
.to_os_string(),
102 env
: Default
::default(),
112 pub fn arg(&mut self, arg
: &OsStr
) {
113 self.args
.push(arg
.to_os_string())
115 pub fn env_mut(&mut self) -> &mut CommandEnv
{
118 pub fn cwd(&mut self, dir
: &OsStr
) {
119 self.cwd
= Some(dir
.to_os_string())
121 pub fn stdin(&mut self, stdin
: Stdio
) {
122 self.stdin
= Some(stdin
);
124 pub fn stdout(&mut self, stdout
: Stdio
) {
125 self.stdout
= Some(stdout
);
127 pub fn stderr(&mut self, stderr
: Stdio
) {
128 self.stderr
= Some(stderr
);
130 pub fn creation_flags(&mut self, flags
: u32) {
138 ) -> io
::Result
<(Process
, StdioPipes
)> {
139 let maybe_env
= self.env
.capture_if_changed();
140 // To have the spawning semantics of unix/windows stay the same, we need
141 // to read the *child's* PATH if one is provided. See #15149 for more
143 let program
= maybe_env
.as_ref().and_then(|env
| {
144 if let Some(v
) = env
.get(OsStr
::new("PATH")) {
145 // Split the value and test each path to see if the
147 for path
in split_paths(&v
) {
149 .join(self.program
.to_str().unwrap())
150 .with_extension(env
::consts
::EXE_EXTENSION
);
151 if fs
::metadata(&path
).is_ok() {
152 return Some(path
.into_os_string());
159 let mut si
= zeroed_startupinfo();
160 si
.cb
= mem
::size_of
::<c
::STARTUPINFO
>() as c
::DWORD
;
161 si
.dwFlags
= c
::STARTF_USESTDHANDLES
;
163 let program
= program
.as_ref().unwrap_or(&self.program
);
164 let mut cmd_str
= make_command_line(program
, &self.args
)?
;
165 cmd_str
.push(0); // add null terminator
167 // stolen from the libuv code.
168 let mut flags
= self.flags
| c
::CREATE_UNICODE_ENVIRONMENT
;
170 flags
|= c
::DETACHED_PROCESS
| c
::CREATE_NEW_PROCESS_GROUP
;
173 let (envp
, _data
) = make_envp(maybe_env
)?
;
174 let (dirp
, _data
) = make_dirp(self.cwd
.as_ref())?
;
175 let mut pi
= zeroed_process_information();
177 // Prepare all stdio handles to be inherited by the child. This
178 // currently involves duplicating any existing ones with the ability to
179 // be inherited by child processes. Note, however, that once an
180 // inheritable handle is created, *any* spawned child will inherit that
181 // handle. We only want our own child to inherit this handle, so we wrap
182 // the remaining portion of this spawn in a mutex.
184 // For more information, msdn also has an article about this race:
185 // http://support.microsoft.com/kb/315939
186 static CREATE_PROCESS_LOCK
: Mutex
= Mutex
::new();
187 let _guard
= DropGuard
::new(&CREATE_PROCESS_LOCK
);
189 let mut pipes
= StdioPipes { stdin: None, stdout: None, stderr: None }
;
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 stdin
= stdin
.to_handle(c
::STD_INPUT_HANDLE
, &mut pipes
.stdin
)?
;
196 let stdout
= stdout
.to_handle(c
::STD_OUTPUT_HANDLE
, &mut pipes
.stdout
)?
;
197 let stderr
= stderr
.to_handle(c
::STD_ERROR_HANDLE
, &mut pipes
.stderr
)?
;
198 si
.hStdInput
= stdin
.raw();
199 si
.hStdOutput
= stdout
.raw();
200 si
.hStdError
= stderr
.raw();
203 cvt(c
::CreateProcessW(
205 cmd_str
.as_mut_ptr(),
217 // We close the thread handle because we don't care about keeping
218 // the thread id valid, and we aren't keeping the thread handle
219 // around to be able to close it later.
220 drop(Handle
::new(pi
.hThread
));
222 Ok((Process { handle: Handle::new(pi.hProcess) }
, pipes
))
226 impl fmt
::Debug
for Command
{
227 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
228 write
!(f
, "{:?}", self.program
)?
;
229 for arg
in &self.args
{
230 write
!(f
, " {:?}", arg
)?
;
236 impl<'a
> DropGuard
<'a
> {
237 fn new(lock
: &'a Mutex
) -> DropGuard
<'a
> {
245 impl<'a
> Drop
for DropGuard
<'a
> {
254 fn to_handle(&self, stdio_id
: c
::DWORD
, pipe
: &mut Option
<AnonPipe
>) -> io
::Result
<Handle
> {
256 // If no stdio handle is available, then inherit means that it
257 // should still be unavailable so propagate the
258 // INVALID_HANDLE_VALUE.
259 Stdio
::Inherit
=> match stdio
::get_handle(stdio_id
) {
261 let io
= Handle
::new(io
);
262 let ret
= io
.duplicate(0, true, c
::DUPLICATE_SAME_ACCESS
);
266 Err(..) => Ok(Handle
::new(c
::INVALID_HANDLE_VALUE
)),
270 let ours_readable
= stdio_id
!= c
::STD_INPUT_HANDLE
;
271 let pipes
= pipe
::anon_pipe(ours_readable
, true)?
;
272 *pipe
= Some(pipes
.ours
);
273 Ok(pipes
.theirs
.into_handle())
276 Stdio
::Handle(ref handle
) => handle
.duplicate(0, true, c
::DUPLICATE_SAME_ACCESS
),
278 // Open up a reference to NUL with appropriate read/write
279 // permissions as well as the ability to be inherited to child
280 // processes (as this is about to be inherited).
282 let size
= mem
::size_of
::<c
::SECURITY_ATTRIBUTES
>();
283 let mut sa
= c
::SECURITY_ATTRIBUTES
{
284 nLength
: size
as c
::DWORD
,
285 lpSecurityDescriptor
: ptr
::null_mut(),
288 let mut opts
= OpenOptions
::new();
289 opts
.read(stdio_id
== c
::STD_INPUT_HANDLE
);
290 opts
.write(stdio_id
!= c
::STD_INPUT_HANDLE
);
291 opts
.security_attributes(&mut sa
);
292 File
::open(Path
::new("NUL"), &opts
).map(|file
| file
.into_handle())
298 impl From
<AnonPipe
> for Stdio
{
299 fn from(pipe
: AnonPipe
) -> Stdio
{
300 Stdio
::Handle(pipe
.into_handle())
304 impl From
<File
> for Stdio
{
305 fn from(file
: File
) -> Stdio
{
306 Stdio
::Handle(file
.into_handle())
310 ////////////////////////////////////////////////////////////////////////////////
312 ////////////////////////////////////////////////////////////////////////////////
314 /// A value representing a child process.
316 /// The lifetime of this value is linked to the lifetime of the actual
317 /// process - the Process destructor calls self.finish() which waits
318 /// for the process to terminate.
324 pub fn kill(&mut self) -> io
::Result
<()> {
325 cvt(unsafe { c::TerminateProcess(self.handle.raw(), 1) }
)?
;
329 pub fn id(&self) -> u32 {
330 unsafe { c::GetProcessId(self.handle.raw()) as u32 }
333 pub fn wait(&mut self) -> io
::Result
<ExitStatus
> {
335 let res
= c
::WaitForSingleObject(self.handle
.raw(), c
::INFINITE
);
336 if res
!= c
::WAIT_OBJECT_0
{
337 return Err(Error
::last_os_error());
340 cvt(c
::GetExitCodeProcess(self.handle
.raw(), &mut status
))?
;
341 Ok(ExitStatus(status
))
345 pub fn try_wait(&mut self) -> io
::Result
<Option
<ExitStatus
>> {
347 match c
::WaitForSingleObject(self.handle
.raw(), 0) {
348 c
::WAIT_OBJECT_0
=> {}
352 _
=> return Err(io
::Error
::last_os_error()),
355 cvt(c
::GetExitCodeProcess(self.handle
.raw(), &mut status
))?
;
356 Ok(Some(ExitStatus(status
)))
360 pub fn handle(&self) -> &Handle
{
364 pub fn into_handle(self) -> Handle
{
369 #[derive(PartialEq, Eq, Clone, Copy, Debug)]
370 pub struct ExitStatus(c
::DWORD
);
373 pub fn success(&self) -> bool
{
376 pub fn code(&self) -> Option
<i32> {
381 /// Converts a raw `c::DWORD` to a type-safe `ExitStatus` by wrapping it without copying.
382 impl From
<c
::DWORD
> for ExitStatus
{
383 fn from(u
: c
::DWORD
) -> ExitStatus
{
388 impl fmt
::Display
for ExitStatus
{
389 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
390 // Windows exit codes with the high bit set typically mean some form of
391 // unhandled exception or warning. In this scenario printing the exit
392 // code in decimal doesn't always make sense because it's a very large
393 // and somewhat gibberish number. The hex code is a bit more
394 // recognizable and easier to search for, so print that.
395 if self.0 & 0x80000000 != 0 {
396 write
!(f
, "exit code: {:#x}", self.0)
398 write
!(f
, "exit code: {}", self.0)
403 #[derive(PartialEq, Eq, Clone, Copy, Debug)]
404 pub struct ExitCode(c
::DWORD
);
407 pub const SUCCESS
: ExitCode
= ExitCode(EXIT_SUCCESS
as _
);
408 pub const FAILURE
: ExitCode
= ExitCode(EXIT_FAILURE
as _
);
411 pub fn as_i32(&self) -> i32 {
416 fn zeroed_startupinfo() -> c
::STARTUPINFO
{
419 lpReserved
: ptr
::null_mut(),
420 lpDesktop
: ptr
::null_mut(),
421 lpTitle
: ptr
::null_mut(),
432 lpReserved2
: ptr
::null_mut(),
433 hStdInput
: c
::INVALID_HANDLE_VALUE
,
434 hStdOutput
: c
::INVALID_HANDLE_VALUE
,
435 hStdError
: c
::INVALID_HANDLE_VALUE
,
439 fn zeroed_process_information() -> c
::PROCESS_INFORMATION
{
440 c
::PROCESS_INFORMATION
{
441 hProcess
: ptr
::null_mut(),
442 hThread
: ptr
::null_mut(),
448 // Produces a wide string *without terminating null*; returns an error if
449 // `prog` or any of the `args` contain a nul.
450 fn make_command_line(prog
: &OsStr
, args
: &[OsString
]) -> io
::Result
<Vec
<u16>> {
451 // Encode the command and arguments in a command line string such
452 // that the spawned process may recover them using CommandLineToArgvW.
453 let mut cmd
: Vec
<u16> = Vec
::new();
454 // Always quote the program name so CreateProcess doesn't interpret args as
455 // part of the name if the binary wasn't found first time.
456 append_arg(&mut cmd
, prog
, true)?
;
458 cmd
.push(' '
as u16);
459 append_arg(&mut cmd
, arg
, false)?
;
463 fn append_arg(cmd
: &mut Vec
<u16>, arg
: &OsStr
, force_quotes
: bool
) -> io
::Result
<()> {
464 // If an argument has 0 characters then we need to quote it to ensure
465 // that it actually gets passed through on the command line or otherwise
466 // it will be dropped entirely when parsed on the other end.
467 ensure_no_nuls(arg
)?
;
468 let arg_bytes
= &arg
.as_inner().inner
.as_inner();
469 let quote
= force_quotes
470 || arg_bytes
.iter().any(|c
| *c
== b' '
|| *c
== b'
\t'
)
471 || arg_bytes
.is_empty();
473 cmd
.push('
"' as u16);
476 let mut backslashes: usize = 0;
477 for x in arg.encode_wide() {
478 if x == '\\' as u16 {
482 // Add n+1 backslashes to total 2n+1 before internal '"'.
483 cmd
.extend((0..=backslashes
).map(|_
| '
\\'
as u16));
491 // Add n backslashes to total 2n before ending '"'.
492 cmd
.extend((0..backslashes
).map(|_
| '
\\'
as u16));
493 cmd
.push('
"' as u16);
499 fn make_envp(maybe_env: Option<BTreeMap<EnvKey, OsString>>) -> io::Result<(*mut c_void, Vec<u16>)> {
500 // On Windows we pass an "environment block
" which is not a char**, but
501 // rather a concatenation of null-terminated k=v\0 sequences, with a final
503 if let Some(env) = maybe_env {
504 let mut blk = Vec::new();
507 blk.extend(ensure_no_nuls(k.0)?.encode_wide());
508 blk.push('=' as u16);
509 blk.extend(ensure_no_nuls(v)?.encode_wide());
513 Ok((blk.as_mut_ptr() as *mut c_void, blk))
515 Ok((ptr::null_mut(), Vec::new()))
519 fn make_dirp(d: Option<&OsString>) -> io::Result<(*const u16, Vec<u16>)> {
522 let mut dir_str: Vec<u16> = ensure_no_nuls(dir)?.encode_wide().collect();
524 Ok((dir_str.as_ptr(), dir_str))
526 None => Ok((ptr::null(), Vec::new())),
532 use super::make_command_line;
533 use crate::ffi::{OsStr, OsString};
536 fn test_make_command_line() {
537 fn test_wrapper(prog: &str, args: &[&str]) -> String {
538 let command_line = &make_command_line(
540 &args.iter().map(|a| OsString::from(a)).collect::<Vec<OsString>>(),
543 String::from_utf16(command_line).unwrap()
546 assert_eq!(test_wrapper("prog
", &["aaa
", "bbb
", "ccc
"]), "\"prog
\" aaa bbb ccc
");
549 test_wrapper("C
:\\Program Files
\\blah
\\blah
.exe
", &["aaa
"]),
550 "\"C
:\\Program Files
\\blah
\\blah
.exe
\" aaa
"
553 test_wrapper("C
:\\Program Files
\\test
", &["aa
\"bb
"]),
554 "\"C
:\\Program Files
\\test
\" aa
\\\"bb
"
556 assert_eq!(test_wrapper("echo
", &["a b c
"]), "\"echo
\" \"a b c
\"");
558 test_wrapper("echo
", &["\" \\\" \\", "\\"]),
559 "\"echo
\" \"\\\" \\\\\\\" \\\\\" \\"
562 test_wrapper("\u{03c0}\u{042f}\u{97f3}\u{00e6}\u{221e}", &[]),
563 "\"\u{03c0}\u{042f}\u{97f3}\u{00e6}\u{221e}\""