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.
14 use collections
::HashMap
;
18 use ffi
::{OsString, OsStr}
;
21 use io
::{self, Error, ErrorKind}
;
24 use os
::windows
::ffi
::OsStrExt
;
27 use sync
::StaticMutex
;
29 use sys
::fs
::{OpenOptions, File}
;
30 use sys
::handle
::Handle
;
31 use sys
::pipe
::{self, AnonPipe}
;
34 use sys_common
::{AsInner, FromInner}
;
36 ////////////////////////////////////////////////////////////////////////////////
38 ////////////////////////////////////////////////////////////////////////////////
40 fn mk_key(s
: &OsStr
) -> OsString
{
41 FromInner
::from_inner(sys
::os_str
::Buf
{
42 inner
: s
.as_inner().inner
.to_ascii_uppercase()
46 fn ensure_no_nuls
<T
: AsRef
<OsStr
>>(str: T
) -> io
::Result
<T
> {
47 if str.as_ref().encode_wide().any(|b
| b
== 0) {
48 Err(io
::Error
::new(ErrorKind
::InvalidInput
, "nul byte found in provided data"))
57 env
: Option
<HashMap
<OsString
, OsString
>>,
58 cwd
: Option
<OsString
>,
59 detach
: bool
, // not currently exposed in std::process
61 stdout
: Option
<Stdio
>,
62 stderr
: Option
<Stdio
>,
72 pub struct StdioPipes
{
73 pub stdin
: Option
<AnonPipe
>,
74 pub stdout
: Option
<AnonPipe
>,
75 pub stderr
: Option
<AnonPipe
>,
79 pub fn new(program
: &OsStr
) -> Command
{
81 program
: program
.to_os_string(),
92 pub fn arg(&mut self, arg
: &OsStr
) {
93 self.args
.push(arg
.to_os_string())
95 fn init_env_map(&mut self){
96 if self.env
.is_none() {
97 self.env
= Some(env
::vars_os().map(|(key
, val
)| {
102 pub fn env(&mut self, key
: &OsStr
, val
: &OsStr
) {
104 self.env
.as_mut().unwrap().insert(mk_key(key
), val
.to_os_string());
106 pub fn env_remove(&mut self, key
: &OsStr
) {
108 self.env
.as_mut().unwrap().remove(&mk_key(key
));
110 pub fn env_clear(&mut self) {
111 self.env
= Some(HashMap
::new())
113 pub fn cwd(&mut self, dir
: &OsStr
) {
114 self.cwd
= Some(dir
.to_os_string())
116 pub fn stdin(&mut self, stdin
: Stdio
) {
117 self.stdin
= Some(stdin
);
119 pub fn stdout(&mut self, stdout
: Stdio
) {
120 self.stdout
= Some(stdout
);
122 pub fn stderr(&mut self, stderr
: Stdio
) {
123 self.stderr
= Some(stderr
);
126 pub fn spawn(&mut self, default: Stdio
, needs_stdin
: bool
)
127 -> io
::Result
<(Process
, StdioPipes
)> {
128 // To have the spawning semantics of unix/windows stay the same, we need
129 // to read the *child's* PATH if one is provided. See #15149 for more
131 let program
= self.env
.as_ref().and_then(|env
| {
132 for (key
, v
) in env
{
133 if OsStr
::new("PATH") != &**key { continue }
135 // Split the value and test each path to see if the
137 for path
in split_paths(&v
) {
138 let path
= path
.join(self.program
.to_str().unwrap())
139 .with_extension(env
::consts
::EXE_EXTENSION
);
140 if fs
::metadata(&path
).is_ok() {
141 return Some(path
.into_os_string())
149 let mut si
= zeroed_startupinfo();
150 si
.cb
= mem
::size_of
::<c
::STARTUPINFO
>() as c
::DWORD
;
151 si
.dwFlags
= c
::STARTF_USESTDHANDLES
;
153 let program
= program
.as_ref().unwrap_or(&self.program
);
154 let mut cmd_str
= make_command_line(program
, &self.args
)?
;
155 cmd_str
.push(0); // add null terminator
157 // stolen from the libuv code.
158 let mut flags
= c
::CREATE_UNICODE_ENVIRONMENT
;
160 flags
|= c
::DETACHED_PROCESS
| c
::CREATE_NEW_PROCESS_GROUP
;
163 let (envp
, _data
) = make_envp(self.env
.as_ref())?
;
164 let (dirp
, _data
) = make_dirp(self.cwd
.as_ref())?
;
165 let mut pi
= zeroed_process_information();
167 // Prepare all stdio handles to be inherited by the child. This
168 // currently involves duplicating any existing ones with the ability to
169 // be inherited by child processes. Note, however, that once an
170 // inheritable handle is created, *any* spawned child will inherit that
171 // handle. We only want our own child to inherit this handle, so we wrap
172 // the remaining portion of this spawn in a mutex.
174 // For more information, msdn also has an article about this race:
175 // http://support.microsoft.com/kb/315939
176 static CREATE_PROCESS_LOCK
: StaticMutex
= StaticMutex
::new();
177 let _lock
= CREATE_PROCESS_LOCK
.lock();
179 let mut pipes
= StdioPipes
{
184 let null
= Stdio
::Null
;
185 let default_stdin
= if needs_stdin {&default}
else {&null}
;
186 let stdin
= self.stdin
.as_ref().unwrap_or(default_stdin
);
187 let stdout
= self.stdout
.as_ref().unwrap_or(&default);
188 let stderr
= self.stderr
.as_ref().unwrap_or(&default);
189 let stdin
= stdin
.to_handle(c
::STD_INPUT_HANDLE
, &mut pipes
.stdin
)?
;
190 let stdout
= stdout
.to_handle(c
::STD_OUTPUT_HANDLE
,
192 let stderr
= stderr
.to_handle(c
::STD_ERROR_HANDLE
,
194 si
.hStdInput
= stdin
.raw();
195 si
.hStdOutput
= stdout
.raw();
196 si
.hStdError
= stderr
.raw();
199 cvt(c
::CreateProcessW(ptr
::null(),
200 cmd_str
.as_mut_ptr(),
203 c
::TRUE
, flags
, envp
, dirp
,
207 // We close the thread handle because we don't care about keeping
208 // the thread id valid, and we aren't keeping the thread handle
209 // around to be able to close it later.
210 drop(Handle
::new(pi
.hThread
));
212 Ok((Process { handle: Handle::new(pi.hProcess) }
, pipes
))
217 impl fmt
::Debug
for Command
{
218 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
219 write
!(f
, "{:?}", self.program
)?
;
220 for arg
in &self.args
{
221 write
!(f
, " {:?}", arg
)?
;
228 fn to_handle(&self, stdio_id
: c
::DWORD
, pipe
: &mut Option
<AnonPipe
>)
229 -> io
::Result
<Handle
> {
231 // If no stdio handle is available, then inherit means that it
232 // should still be unavailable so propagate the
233 // INVALID_HANDLE_VALUE.
235 match stdio
::get(stdio_id
) {
236 Ok(io
) => io
.handle().duplicate(0, true,
237 c
::DUPLICATE_SAME_ACCESS
),
238 Err(..) => Ok(Handle
::new(c
::INVALID_HANDLE_VALUE
)),
243 let (reader
, writer
) = pipe
::anon_pipe()?
;
244 let (ours
, theirs
) = if stdio_id
== c
::STD_INPUT_HANDLE
{
251 c
::SetHandleInformation(theirs
.handle().raw(),
252 c
::HANDLE_FLAG_INHERIT
,
253 c
::HANDLE_FLAG_INHERIT
)
255 Ok(theirs
.into_handle())
258 Stdio
::Handle(ref handle
) => {
259 handle
.duplicate(0, true, c
::DUPLICATE_SAME_ACCESS
)
262 // Open up a reference to NUL with appropriate read/write
263 // permissions as well as the ability to be inherited to child
264 // processes (as this is about to be inherited).
266 let size
= mem
::size_of
::<c
::SECURITY_ATTRIBUTES
>();
267 let mut sa
= c
::SECURITY_ATTRIBUTES
{
268 nLength
: size
as c
::DWORD
,
269 lpSecurityDescriptor
: ptr
::null_mut(),
272 let mut opts
= OpenOptions
::new();
273 opts
.read(stdio_id
== c
::STD_INPUT_HANDLE
);
274 opts
.write(stdio_id
!= c
::STD_INPUT_HANDLE
);
275 opts
.security_attributes(&mut sa
);
276 File
::open(Path
::new("NUL"), &opts
).map(|file
| {
284 ////////////////////////////////////////////////////////////////////////////////
286 ////////////////////////////////////////////////////////////////////////////////
288 /// A value representing a child process.
290 /// The lifetime of this value is linked to the lifetime of the actual
291 /// process - the Process destructor calls self.finish() which waits
292 /// for the process to terminate.
298 pub fn kill(&mut self) -> io
::Result
<()> {
300 c
::TerminateProcess(self.handle
.raw(), 1)
305 pub fn id(&self) -> u32 {
307 c
::GetProcessId(self.handle
.raw()) as u32
311 pub fn wait(&mut self) -> io
::Result
<ExitStatus
> {
313 let res
= c
::WaitForSingleObject(self.handle
.raw(), c
::INFINITE
);
314 if res
!= c
::WAIT_OBJECT_0
{
315 return Err(Error
::last_os_error())
318 cvt(c
::GetExitCodeProcess(self.handle
.raw(), &mut status
))?
;
319 Ok(ExitStatus(status
))
323 pub fn handle(&self) -> &Handle { &self.handle }
325 pub fn into_handle(self) -> Handle { self.handle }
328 #[derive(PartialEq, Eq, Clone, Copy, Debug)]
329 pub struct ExitStatus(c
::DWORD
);
332 pub fn success(&self) -> bool
{
335 pub fn code(&self) -> Option
<i32> {
340 impl fmt
::Display
for ExitStatus
{
341 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
342 write
!(f
, "exit code: {}", self.0)
346 fn zeroed_startupinfo() -> c
::STARTUPINFO
{
349 lpReserved
: ptr
::null_mut(),
350 lpDesktop
: ptr
::null_mut(),
351 lpTitle
: ptr
::null_mut(),
362 lpReserved2
: ptr
::null_mut(),
363 hStdInput
: c
::INVALID_HANDLE_VALUE
,
364 hStdOutput
: c
::INVALID_HANDLE_VALUE
,
365 hStdError
: c
::INVALID_HANDLE_VALUE
,
369 fn zeroed_process_information() -> c
::PROCESS_INFORMATION
{
370 c
::PROCESS_INFORMATION
{
371 hProcess
: ptr
::null_mut(),
372 hThread
: ptr
::null_mut(),
378 // Produces a wide string *without terminating null*; returns an error if
379 // `prog` or any of the `args` contain a nul.
380 fn make_command_line(prog
: &OsStr
, args
: &[OsString
]) -> io
::Result
<Vec
<u16>> {
381 // Encode the command and arguments in a command line string such
382 // that the spawned process may recover them using CommandLineToArgvW.
383 let mut cmd
: Vec
<u16> = Vec
::new();
384 append_arg(&mut cmd
, prog
)?
;
386 cmd
.push(' '
as u16);
387 append_arg(&mut cmd
, arg
)?
;
391 fn append_arg(cmd
: &mut Vec
<u16>, arg
: &OsStr
) -> io
::Result
<()> {
392 // If an argument has 0 characters then we need to quote it to ensure
393 // that it actually gets passed through on the command line or otherwise
394 // it will be dropped entirely when parsed on the other end.
395 ensure_no_nuls(arg
)?
;
396 let arg_bytes
= &arg
.as_inner().inner
.as_inner();
397 let quote
= arg_bytes
.iter().any(|c
| *c
== b' '
|| *c
== b'
\t'
)
398 || arg_bytes
.is_empty();
400 cmd
.push('
"' as u16);
403 let mut iter = arg.encode_wide();
404 let mut backslashes: usize = 0;
405 while let Some(x) = iter.next() {
406 if x == '\\' as u16 {
410 // Add n+1 backslashes to total 2n+1 before internal '"'.
411 for _
in 0..(backslashes
+1) {
412 cmd
.push('
\\'
as u16);
421 // Add n backslashes to total 2n before ending '"'.
422 for _
in 0..backslashes
{
423 cmd
.push('
\\'
as u16);
425 cmd
.push('
"' as u16);
431 fn make_envp(env: Option<&collections::HashMap<OsString, OsString>>)
432 -> io::Result<(*mut c_void, Vec<u16>)> {
433 // On Windows we pass an "environment block
" which is not a char**, but
434 // rather a concatenation of null-terminated k=v\0 sequences, with a final
438 let mut blk = Vec::new();
441 blk.extend(ensure_no_nuls(pair.0)?.encode_wide());
442 blk.push('=' as u16);
443 blk.extend(ensure_no_nuls(pair.1)?.encode_wide());
447 Ok((blk.as_mut_ptr() as *mut c_void, blk))
449 _ => Ok((ptr::null_mut(), Vec::new()))
453 fn make_dirp(d: Option<&OsString>) -> io::Result<(*const u16, Vec<u16>)> {
457 let mut dir_str: Vec<u16> = ensure_no_nuls(dir)?.encode_wide().collect();
459 Ok((dir_str.as_ptr(), dir_str))
461 None => Ok((ptr::null(), Vec::new()))
468 use ffi::{OsStr, OsString};
469 use super::make_command_line;
472 fn test_make_command_line() {
473 fn test_wrapper(prog: &str, args: &[&str]) -> String {
474 let command_line = &make_command_line(OsStr::new(prog),
476 .map(|a| OsString::from(a))
477 .collect::<Vec<OsString>>())
479 String::from_utf16(command_line).unwrap()
483 test_wrapper("prog
", &["aaa
", "bbb
", "ccc
"]),
488 test_wrapper("C
:\\Program Files
\\blah
\\blah
.exe
", &["aaa
"]),
489 "\"C
:\\Program Files
\\blah
\\blah
.exe
\" aaa
"
492 test_wrapper("C
:\\Program Files
\\test
", &["aa
\"bb
"]),
493 "\"C
:\\Program Files
\\test
\" aa
\\\"bb
"
496 test_wrapper("echo
", &["a b c
"]),
500 test_wrapper("echo
", &["\" \\\" \\", "\\"]),
501 "echo
\"\\\" \\\\\\\" \\\\\" \\"
504 test_wrapper("\u{03c0}\u{042f}\u{97f3}\u{00e6}\u{221e}", &[]),
505 "\u{03c0}\u{042f}\u{97f3}\u{00e6}\u{221e}"