1 // Copyright 2012-2014 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.
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.
12 use collections
::HashMap
;
16 use ffi
::{OsString, OsStr}
;
19 use io
::{self, Error, ErrorKind}
;
22 use os
::windows
::ffi
::OsStrExt
;
25 use sys
::mutex
::Mutex
;
27 use sys
::fs
::{OpenOptions, File}
;
28 use sys
::handle
::Handle
;
29 use sys
::pipe
::{self, AnonPipe}
;
32 use sys_common
::{AsInner, FromInner}
;
34 ////////////////////////////////////////////////////////////////////////////////
36 ////////////////////////////////////////////////////////////////////////////////
38 fn mk_key(s
: &OsStr
) -> OsString
{
39 FromInner
::from_inner(sys
::os_str
::Buf
{
40 inner
: s
.as_inner().inner
.to_ascii_uppercase()
44 fn ensure_no_nuls
<T
: AsRef
<OsStr
>>(str: T
) -> io
::Result
<T
> {
45 if str.as_ref().encode_wide().any(|b
| b
== 0) {
46 Err(io
::Error
::new(ErrorKind
::InvalidInput
, "nul byte found in provided data"))
55 env
: Option
<HashMap
<OsString
, OsString
>>,
56 cwd
: Option
<OsString
>,
58 detach
: bool
, // not currently exposed in std::process
60 stdout
: Option
<Stdio
>,
61 stderr
: Option
<Stdio
>,
71 pub struct StdioPipes
{
72 pub stdin
: Option
<AnonPipe
>,
73 pub stdout
: Option
<AnonPipe
>,
74 pub stderr
: Option
<AnonPipe
>,
77 struct DropGuard
<'a
> {
82 pub fn new(program
: &OsStr
) -> Command
{
84 program
: program
.to_os_string(),
96 pub fn arg(&mut self, arg
: &OsStr
) {
97 self.args
.push(arg
.to_os_string())
99 fn init_env_map(&mut self){
100 if self.env
.is_none() {
101 self.env
= Some(env
::vars_os().map(|(key
, val
)| {
106 pub fn env(&mut self, key
: &OsStr
, val
: &OsStr
) {
108 self.env
.as_mut().unwrap().insert(mk_key(key
), val
.to_os_string());
110 pub fn env_remove(&mut self, key
: &OsStr
) {
112 self.env
.as_mut().unwrap().remove(&mk_key(key
));
114 pub fn env_clear(&mut self) {
115 self.env
= Some(HashMap
::new())
117 pub fn cwd(&mut self, dir
: &OsStr
) {
118 self.cwd
= Some(dir
.to_os_string())
120 pub fn stdin(&mut self, stdin
: Stdio
) {
121 self.stdin
= Some(stdin
);
123 pub fn stdout(&mut self, stdout
: Stdio
) {
124 self.stdout
= Some(stdout
);
126 pub fn stderr(&mut self, stderr
: Stdio
) {
127 self.stderr
= Some(stderr
);
129 pub fn creation_flags(&mut self, flags
: u32) {
133 pub fn spawn(&mut self, default: Stdio
, needs_stdin
: bool
)
134 -> io
::Result
<(Process
, StdioPipes
)> {
135 // To have the spawning semantics of unix/windows stay the same, we need
136 // to read the *child's* PATH if one is provided. See #15149 for more
138 let program
= self.env
.as_ref().and_then(|env
| {
139 for (key
, v
) in env
{
140 if OsStr
::new("PATH") != &**key { continue }
142 // Split the value and test each path to see if the
144 for path
in split_paths(&v
) {
145 let path
= path
.join(self.program
.to_str().unwrap())
146 .with_extension(env
::consts
::EXE_EXTENSION
);
147 if fs
::metadata(&path
).is_ok() {
148 return Some(path
.into_os_string())
156 let mut si
= zeroed_startupinfo();
157 si
.cb
= mem
::size_of
::<c
::STARTUPINFO
>() as c
::DWORD
;
158 si
.dwFlags
= c
::STARTF_USESTDHANDLES
;
160 let program
= program
.as_ref().unwrap_or(&self.program
);
161 let mut cmd_str
= make_command_line(program
, &self.args
)?
;
162 cmd_str
.push(0); // add null terminator
164 // stolen from the libuv code.
165 let mut flags
= self.flags
| c
::CREATE_UNICODE_ENVIRONMENT
;
167 flags
|= c
::DETACHED_PROCESS
| c
::CREATE_NEW_PROCESS_GROUP
;
170 let (envp
, _data
) = make_envp(self.env
.as_ref())?
;
171 let (dirp
, _data
) = make_dirp(self.cwd
.as_ref())?
;
172 let mut pi
= zeroed_process_information();
174 // Prepare all stdio handles to be inherited by the child. This
175 // currently involves duplicating any existing ones with the ability to
176 // be inherited by child processes. Note, however, that once an
177 // inheritable handle is created, *any* spawned child will inherit that
178 // handle. We only want our own child to inherit this handle, so we wrap
179 // the remaining portion of this spawn in a mutex.
181 // For more information, msdn also has an article about this race:
182 // http://support.microsoft.com/kb/315939
183 static CREATE_PROCESS_LOCK
: Mutex
= Mutex
::new();
184 let _guard
= DropGuard
::new(&CREATE_PROCESS_LOCK
);
186 let mut pipes
= StdioPipes
{
191 let null
= Stdio
::Null
;
192 let default_stdin
= if needs_stdin {&default}
else {&null}
;
193 let stdin
= self.stdin
.as_ref().unwrap_or(default_stdin
);
194 let stdout
= self.stdout
.as_ref().unwrap_or(&default);
195 let stderr
= self.stderr
.as_ref().unwrap_or(&default);
196 let stdin
= stdin
.to_handle(c
::STD_INPUT_HANDLE
, &mut pipes
.stdin
)?
;
197 let stdout
= stdout
.to_handle(c
::STD_OUTPUT_HANDLE
,
199 let stderr
= stderr
.to_handle(c
::STD_ERROR_HANDLE
,
201 si
.hStdInput
= stdin
.raw();
202 si
.hStdOutput
= stdout
.raw();
203 si
.hStdError
= stderr
.raw();
206 cvt(c
::CreateProcessW(ptr
::null(),
207 cmd_str
.as_mut_ptr(),
210 c
::TRUE
, flags
, envp
, dirp
,
214 // We close the thread handle because we don't care about keeping
215 // the thread id valid, and we aren't keeping the thread handle
216 // around to be able to close it later.
217 drop(Handle
::new(pi
.hThread
));
219 Ok((Process { handle: Handle::new(pi.hProcess) }
, pipes
))
224 impl fmt
::Debug
for Command
{
225 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
226 write
!(f
, "{:?}", self.program
)?
;
227 for arg
in &self.args
{
228 write
!(f
, " {:?}", arg
)?
;
234 impl<'a
> DropGuard
<'a
> {
235 fn new(lock
: &'a Mutex
) -> DropGuard
<'a
> {
238 DropGuard { lock: lock }
243 impl<'a
> Drop
for DropGuard
<'a
> {
252 fn to_handle(&self, stdio_id
: c
::DWORD
, pipe
: &mut Option
<AnonPipe
>)
253 -> io
::Result
<Handle
> {
255 // If no stdio handle is available, then inherit means that it
256 // should still be unavailable so propagate the
257 // INVALID_HANDLE_VALUE.
259 match stdio
::get(stdio_id
) {
261 let io
= Handle
::new(io
.handle());
262 let ret
= io
.duplicate(0, true,
263 c
::DUPLICATE_SAME_ACCESS
);
267 Err(..) => Ok(Handle
::new(c
::INVALID_HANDLE_VALUE
)),
272 let ours_readable
= stdio_id
!= c
::STD_INPUT_HANDLE
;
273 let pipes
= pipe
::anon_pipe(ours_readable
)?
;
274 *pipe
= Some(pipes
.ours
);
276 c
::SetHandleInformation(pipes
.theirs
.handle().raw(),
277 c
::HANDLE_FLAG_INHERIT
,
278 c
::HANDLE_FLAG_INHERIT
)
280 Ok(pipes
.theirs
.into_handle())
283 Stdio
::Handle(ref handle
) => {
284 handle
.duplicate(0, true, c
::DUPLICATE_SAME_ACCESS
)
287 // Open up a reference to NUL with appropriate read/write
288 // permissions as well as the ability to be inherited to child
289 // processes (as this is about to be inherited).
291 let size
= mem
::size_of
::<c
::SECURITY_ATTRIBUTES
>();
292 let mut sa
= c
::SECURITY_ATTRIBUTES
{
293 nLength
: size
as c
::DWORD
,
294 lpSecurityDescriptor
: ptr
::null_mut(),
297 let mut opts
= OpenOptions
::new();
298 opts
.read(stdio_id
== c
::STD_INPUT_HANDLE
);
299 opts
.write(stdio_id
!= c
::STD_INPUT_HANDLE
);
300 opts
.security_attributes(&mut sa
);
301 File
::open(Path
::new("NUL"), &opts
).map(|file
| {
309 impl From
<AnonPipe
> for Stdio
{
310 fn from(pipe
: AnonPipe
) -> Stdio
{
311 Stdio
::Handle(pipe
.into_handle())
315 impl From
<File
> for Stdio
{
316 fn from(file
: File
) -> Stdio
{
317 Stdio
::Handle(file
.into_handle())
321 ////////////////////////////////////////////////////////////////////////////////
323 ////////////////////////////////////////////////////////////////////////////////
325 /// A value representing a child process.
327 /// The lifetime of this value is linked to the lifetime of the actual
328 /// process - the Process destructor calls self.finish() which waits
329 /// for the process to terminate.
335 pub fn kill(&mut self) -> io
::Result
<()> {
337 c
::TerminateProcess(self.handle
.raw(), 1)
342 pub fn id(&self) -> u32 {
344 c
::GetProcessId(self.handle
.raw()) as u32
348 pub fn wait(&mut self) -> io
::Result
<ExitStatus
> {
350 let res
= c
::WaitForSingleObject(self.handle
.raw(), c
::INFINITE
);
351 if res
!= c
::WAIT_OBJECT_0
{
352 return Err(Error
::last_os_error())
355 cvt(c
::GetExitCodeProcess(self.handle
.raw(), &mut status
))?
;
356 Ok(ExitStatus(status
))
360 pub fn try_wait(&mut self) -> io
::Result
<Option
<ExitStatus
>> {
362 match c
::WaitForSingleObject(self.handle
.raw(), 0) {
363 c
::WAIT_OBJECT_0
=> {}
367 _
=> return Err(io
::Error
::last_os_error()),
370 cvt(c
::GetExitCodeProcess(self.handle
.raw(), &mut status
))?
;
371 Ok(Some(ExitStatus(status
)))
375 pub fn handle(&self) -> &Handle { &self.handle }
377 pub fn into_handle(self) -> Handle { self.handle }
380 #[derive(PartialEq, Eq, Clone, Copy, Debug)]
381 pub struct ExitStatus(c
::DWORD
);
384 pub fn success(&self) -> bool
{
387 pub fn code(&self) -> Option
<i32> {
392 impl From
<c
::DWORD
> for ExitStatus
{
393 fn from(u
: c
::DWORD
) -> ExitStatus
{
398 impl fmt
::Display
for ExitStatus
{
399 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
400 write
!(f
, "exit code: {}", self.0)
404 fn zeroed_startupinfo() -> c
::STARTUPINFO
{
407 lpReserved
: ptr
::null_mut(),
408 lpDesktop
: ptr
::null_mut(),
409 lpTitle
: ptr
::null_mut(),
420 lpReserved2
: ptr
::null_mut(),
421 hStdInput
: c
::INVALID_HANDLE_VALUE
,
422 hStdOutput
: c
::INVALID_HANDLE_VALUE
,
423 hStdError
: c
::INVALID_HANDLE_VALUE
,
427 fn zeroed_process_information() -> c
::PROCESS_INFORMATION
{
428 c
::PROCESS_INFORMATION
{
429 hProcess
: ptr
::null_mut(),
430 hThread
: ptr
::null_mut(),
436 // Produces a wide string *without terminating null*; returns an error if
437 // `prog` or any of the `args` contain a nul.
438 fn make_command_line(prog
: &OsStr
, args
: &[OsString
]) -> io
::Result
<Vec
<u16>> {
439 // Encode the command and arguments in a command line string such
440 // that the spawned process may recover them using CommandLineToArgvW.
441 let mut cmd
: Vec
<u16> = Vec
::new();
442 // Always quote the program name so CreateProcess doesn't interpret args as
443 // part of the name if the binary wasn't found first time.
444 append_arg(&mut cmd
, prog
, true)?
;
446 cmd
.push(' '
as u16);
447 append_arg(&mut cmd
, arg
, false)?
;
451 fn append_arg(cmd
: &mut Vec
<u16>, arg
: &OsStr
, force_quotes
: bool
) -> io
::Result
<()> {
452 // If an argument has 0 characters then we need to quote it to ensure
453 // that it actually gets passed through on the command line or otherwise
454 // it will be dropped entirely when parsed on the other end.
455 ensure_no_nuls(arg
)?
;
456 let arg_bytes
= &arg
.as_inner().inner
.as_inner();
457 let quote
= force_quotes
|| arg_bytes
.iter().any(|c
| *c
== b' '
|| *c
== b'
\t'
)
458 || arg_bytes
.is_empty();
460 cmd
.push('
"' as u16);
463 let mut iter = arg.encode_wide();
464 let mut backslashes: usize = 0;
465 while let Some(x) = iter.next() {
466 if x == '\\' as u16 {
470 // Add n+1 backslashes to total 2n+1 before internal '"'.
471 for _
in 0..(backslashes
+1) {
472 cmd
.push('
\\'
as u16);
481 // Add n backslashes to total 2n before ending '"'.
482 for _
in 0..backslashes
{
483 cmd
.push('
\\'
as u16);
485 cmd
.push('
"' as u16);
491 fn make_envp(env: Option<&collections::HashMap<OsString, OsString>>)
492 -> io::Result<(*mut c_void, Vec<u16>)> {
493 // On Windows we pass an "environment block
" which is not a char**, but
494 // rather a concatenation of null-terminated k=v\0 sequences, with a final
498 let mut blk = Vec::new();
501 blk.extend(ensure_no_nuls(pair.0)?.encode_wide());
502 blk.push('=' as u16);
503 blk.extend(ensure_no_nuls(pair.1)?.encode_wide());
507 Ok((blk.as_mut_ptr() as *mut c_void, blk))
509 _ => Ok((ptr::null_mut(), Vec::new()))
513 fn make_dirp(d: Option<&OsString>) -> io::Result<(*const u16, Vec<u16>)> {
517 let mut dir_str: Vec<u16> = ensure_no_nuls(dir)?.encode_wide().collect();
519 Ok((dir_str.as_ptr(), dir_str))
521 None => Ok((ptr::null(), Vec::new()))
527 use ffi::{OsStr, OsString};
528 use super::make_command_line;
531 fn test_make_command_line() {
532 fn test_wrapper(prog: &str, args: &[&str]) -> String {
533 let command_line = &make_command_line(OsStr::new(prog),
535 .map(|a| OsString::from(a))
536 .collect::<Vec<OsString>>())
538 String::from_utf16(command_line).unwrap()
542 test_wrapper("prog
", &["aaa
", "bbb
", "ccc
"]),
543 "\"prog
\" aaa bbb ccc
"
547 test_wrapper("C
:\\Program Files
\\blah
\\blah
.exe
", &["aaa
"]),
548 "\"C
:\\Program Files
\\blah
\\blah
.exe
\" aaa
"
551 test_wrapper("C
:\\Program Files
\\test
", &["aa
\"bb
"]),
552 "\"C
:\\Program Files
\\test
\" aa
\\\"bb
"
555 test_wrapper("echo
", &["a b c
"]),
559 test_wrapper("echo
", &["\" \\\" \\", "\\"]),
560 "\"echo
\" \"\\\" \\\\\\\" \\\\\" \\"
563 test_wrapper("\u{03c0}\u{042f}\u{97f3}\u{00e6}\u{221e}", &[]),
564 "\"\u{03c0}\u{042f}\u{97f3}\u{00e6}\u{221e}\""