2019-12-21 13:16:18 +02:00
|
|
|
#![unstable(feature = "process_internals", issue = "none")]
|
2017-12-17 15:21:47 +00:00
|
|
|
|
2020-08-27 13:45:01 +00:00
|
|
|
#[cfg(test)]
|
|
|
|
mod tests;
|
|
|
|
|
2019-12-22 17:42:04 -05:00
|
|
|
use crate::borrow::Borrow;
|
2019-02-11 04:23:21 +09:00
|
|
|
use crate::collections::BTreeMap;
|
|
|
|
use crate::env;
|
2019-12-22 17:42:04 -05:00
|
|
|
use crate::env::split_paths;
|
|
|
|
use crate::ffi::{OsStr, OsString};
|
2019-02-11 04:23:21 +09:00
|
|
|
use crate::fmt;
|
|
|
|
use crate::fs;
|
|
|
|
use crate::io::{self, Error, ErrorKind};
|
|
|
|
use crate::mem;
|
|
|
|
use crate::os::windows::ffi::OsStrExt;
|
|
|
|
use crate::path::Path;
|
|
|
|
use crate::ptr;
|
|
|
|
use crate::sys::c;
|
2019-12-22 17:42:04 -05:00
|
|
|
use crate::sys::cvt;
|
|
|
|
use crate::sys::fs::{File, OpenOptions};
|
2019-02-11 04:23:21 +09:00
|
|
|
use crate::sys::handle::Handle;
|
|
|
|
use crate::sys::pipe::{self, AnonPipe};
|
|
|
|
use crate::sys::stdio;
|
2021-04-28 19:11:57 +02:00
|
|
|
use crate::sys_common::mutex::StaticMutex;
|
2020-09-21 11:32:06 -07:00
|
|
|
use crate::sys_common::process::{CommandEnv, CommandEnvs};
|
2020-03-11 16:05:11 -04:00
|
|
|
use crate::sys_common::AsInner;
|
2019-02-11 04:23:21 +09:00
|
|
|
|
2019-12-22 17:42:04 -05:00
|
|
|
use libc::{c_void, EXIT_FAILURE, EXIT_SUCCESS};
|
2015-02-06 09:42:57 -08:00
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Command
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2017-12-17 15:21:47 +00:00
|
|
|
#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
|
|
|
|
#[doc(hidden)]
|
2019-09-03 19:32:44 -07:00
|
|
|
pub struct EnvKey(OsString);
|
2017-12-17 15:21:47 +00:00
|
|
|
|
2019-09-03 19:32:44 -07:00
|
|
|
impl From<OsString> for EnvKey {
|
2020-03-11 16:05:11 -04:00
|
|
|
fn from(mut k: OsString) -> Self {
|
|
|
|
k.make_ascii_uppercase();
|
|
|
|
EnvKey(k)
|
2017-12-17 15:21:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-03 19:32:44 -07:00
|
|
|
impl From<EnvKey> for OsString {
|
2019-12-22 17:42:04 -05:00
|
|
|
fn from(k: EnvKey) -> Self {
|
|
|
|
k.0
|
|
|
|
}
|
2015-02-06 09:42:57 -08:00
|
|
|
}
|
|
|
|
|
2019-09-03 19:32:44 -07:00
|
|
|
impl Borrow<OsStr> for EnvKey {
|
2019-12-22 17:42:04 -05:00
|
|
|
fn borrow(&self) -> &OsStr {
|
|
|
|
&self.0
|
|
|
|
}
|
2017-12-17 15:21:47 +00:00
|
|
|
}
|
|
|
|
|
2019-09-03 19:32:44 -07:00
|
|
|
impl AsRef<OsStr> for EnvKey {
|
2019-12-22 17:42:04 -05:00
|
|
|
fn as_ref(&self) -> &OsStr {
|
|
|
|
&self.0
|
|
|
|
}
|
2017-12-17 15:21:47 +00:00
|
|
|
}
|
|
|
|
|
2016-01-15 15:29:45 -05:00
|
|
|
fn ensure_no_nuls<T: AsRef<OsStr>>(str: T) -> io::Result<T> {
|
|
|
|
if str.as_ref().encode_wide().any(|b| b == 0) {
|
2021-03-21 20:22:38 +01:00
|
|
|
Err(io::Error::new_const(ErrorKind::InvalidInput, &"nul byte found in provided data"))
|
2016-01-15 15:29:45 -05:00
|
|
|
} else {
|
|
|
|
Ok(str)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-06 09:42:57 -08:00
|
|
|
pub struct Command {
|
2016-01-15 15:29:45 -05:00
|
|
|
program: OsString,
|
|
|
|
args: Vec<OsString>,
|
2019-09-03 19:32:44 -07:00
|
|
|
env: CommandEnv,
|
2016-01-15 15:29:45 -05:00
|
|
|
cwd: Option<OsString>,
|
2016-11-30 19:44:07 -05:00
|
|
|
flags: u32,
|
2016-01-15 15:29:45 -05:00
|
|
|
detach: bool, // not currently exposed in std::process
|
2016-02-04 11:10:37 -08:00
|
|
|
stdin: Option<Stdio>,
|
|
|
|
stdout: Option<Stdio>,
|
|
|
|
stderr: Option<Stdio>,
|
2020-10-08 22:26:31 +00:00
|
|
|
force_quotes_enabled: bool,
|
2016-02-04 11:10:37 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
pub enum Stdio {
|
|
|
|
Inherit,
|
|
|
|
Null,
|
|
|
|
MakePipe,
|
|
|
|
Handle(Handle),
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct StdioPipes {
|
|
|
|
pub stdin: Option<AnonPipe>,
|
|
|
|
pub stdout: Option<AnonPipe>,
|
|
|
|
pub stderr: Option<AnonPipe>,
|
2015-02-06 09:42:57 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Command {
|
|
|
|
pub fn new(program: &OsStr) -> Command {
|
|
|
|
Command {
|
|
|
|
program: program.to_os_string(),
|
|
|
|
args: Vec::new(),
|
2017-12-17 15:21:47 +00:00
|
|
|
env: Default::default(),
|
2015-02-06 09:42:57 -08:00
|
|
|
cwd: None,
|
2016-11-30 19:44:07 -05:00
|
|
|
flags: 0,
|
2015-02-06 09:42:57 -08:00
|
|
|
detach: false,
|
2016-02-04 11:10:37 -08:00
|
|
|
stdin: None,
|
|
|
|
stdout: None,
|
|
|
|
stderr: None,
|
2020-10-08 22:26:31 +00:00
|
|
|
force_quotes_enabled: false,
|
2015-02-06 09:42:57 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn arg(&mut self, arg: &OsStr) {
|
|
|
|
self.args.push(arg.to_os_string())
|
|
|
|
}
|
2019-09-03 19:32:44 -07:00
|
|
|
pub fn env_mut(&mut self) -> &mut CommandEnv {
|
2017-12-17 15:21:47 +00:00
|
|
|
&mut self.env
|
2015-02-06 09:42:57 -08:00
|
|
|
}
|
|
|
|
pub fn cwd(&mut self, dir: &OsStr) {
|
|
|
|
self.cwd = Some(dir.to_os_string())
|
|
|
|
}
|
2016-02-04 11:10:37 -08:00
|
|
|
pub fn stdin(&mut self, stdin: Stdio) {
|
|
|
|
self.stdin = Some(stdin);
|
|
|
|
}
|
|
|
|
pub fn stdout(&mut self, stdout: Stdio) {
|
|
|
|
self.stdout = Some(stdout);
|
|
|
|
}
|
|
|
|
pub fn stderr(&mut self, stderr: Stdio) {
|
|
|
|
self.stderr = Some(stderr);
|
2016-01-15 15:29:45 -05:00
|
|
|
}
|
2016-11-30 21:31:47 -05:00
|
|
|
pub fn creation_flags(&mut self, flags: u32) {
|
2016-11-30 19:44:07 -05:00
|
|
|
self.flags = flags;
|
|
|
|
}
|
2015-06-09 16:41:14 -07:00
|
|
|
|
2020-10-08 22:26:31 +00:00
|
|
|
pub fn force_quotes(&mut self, enabled: bool) {
|
|
|
|
self.force_quotes_enabled = enabled;
|
|
|
|
}
|
|
|
|
|
2020-09-21 11:32:06 -07:00
|
|
|
pub fn get_program(&self) -> &OsStr {
|
|
|
|
&self.program
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_args(&self) -> CommandArgs<'_> {
|
|
|
|
let iter = self.args.iter();
|
|
|
|
CommandArgs { iter }
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_envs(&self) -> CommandEnvs<'_> {
|
|
|
|
self.env.iter()
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_current_dir(&self) -> Option<&Path> {
|
|
|
|
self.cwd.as_ref().map(|cwd| Path::new(cwd))
|
|
|
|
}
|
|
|
|
|
2019-12-22 17:42:04 -05:00
|
|
|
pub fn spawn(
|
|
|
|
&mut self,
|
|
|
|
default: Stdio,
|
|
|
|
needs_stdin: bool,
|
|
|
|
) -> io::Result<(Process, StdioPipes)> {
|
2017-12-17 15:21:47 +00:00
|
|
|
let maybe_env = self.env.capture_if_changed();
|
2015-04-27 13:44:20 -07:00
|
|
|
// To have the spawning semantics of unix/windows stay the same, we need
|
|
|
|
// to read the *child's* PATH if one is provided. See #15149 for more
|
|
|
|
// details.
|
2017-12-17 15:21:47 +00:00
|
|
|
let program = maybe_env.as_ref().and_then(|env| {
|
|
|
|
if let Some(v) = env.get(OsStr::new("PATH")) {
|
2015-02-06 09:42:57 -08:00
|
|
|
// Split the value and test each path to see if the
|
|
|
|
// program exists.
|
|
|
|
for path in split_paths(&v) {
|
2019-12-22 17:42:04 -05:00
|
|
|
let path = path
|
|
|
|
.join(self.program.to_str().unwrap())
|
|
|
|
.with_extension(env::consts::EXE_EXTENSION);
|
2015-02-23 10:59:17 -08:00
|
|
|
if fs::metadata(&path).is_ok() {
|
2019-12-22 17:42:04 -05:00
|
|
|
return Some(path.into_os_string());
|
2015-02-06 09:42:57 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
None
|
|
|
|
});
|
|
|
|
|
2015-04-27 13:44:20 -07:00
|
|
|
let mut si = zeroed_startupinfo();
|
2015-11-02 16:23:22 -08:00
|
|
|
si.cb = mem::size_of::<c::STARTUPINFO>() as c::DWORD;
|
|
|
|
si.dwFlags = c::STARTF_USESTDHANDLES;
|
2015-02-06 09:42:57 -08:00
|
|
|
|
2016-02-04 11:10:37 -08:00
|
|
|
let program = program.as_ref().unwrap_or(&self.program);
|
2020-10-08 22:26:31 +00:00
|
|
|
let mut cmd_str = make_command_line(program, &self.args, self.force_quotes_enabled)?;
|
2015-04-27 13:44:20 -07:00
|
|
|
cmd_str.push(0); // add null terminator
|
2015-02-06 09:42:57 -08:00
|
|
|
|
2015-04-27 13:44:20 -07:00
|
|
|
// stolen from the libuv code.
|
2016-11-30 19:44:07 -05:00
|
|
|
let mut flags = self.flags | c::CREATE_UNICODE_ENVIRONMENT;
|
2016-02-04 11:10:37 -08:00
|
|
|
if self.detach {
|
2015-11-02 16:23:22 -08:00
|
|
|
flags |= c::DETACHED_PROCESS | c::CREATE_NEW_PROCESS_GROUP;
|
2015-04-27 13:44:20 -07:00
|
|
|
}
|
2015-02-06 09:42:57 -08:00
|
|
|
|
2017-12-17 15:21:47 +00:00
|
|
|
let (envp, _data) = make_envp(maybe_env)?;
|
2016-03-22 22:01:37 -05:00
|
|
|
let (dirp, _data) = make_dirp(self.cwd.as_ref())?;
|
2015-04-27 13:44:20 -07:00
|
|
|
let mut pi = zeroed_process_information();
|
|
|
|
|
2016-02-04 09:59:47 -08:00
|
|
|
// Prepare all stdio handles to be inherited by the child. This
|
|
|
|
// currently involves duplicating any existing ones with the ability to
|
|
|
|
// be inherited by child processes. Note, however, that once an
|
|
|
|
// inheritable handle is created, *any* spawned child will inherit that
|
|
|
|
// handle. We only want our own child to inherit this handle, so we wrap
|
|
|
|
// the remaining portion of this spawn in a mutex.
|
|
|
|
//
|
|
|
|
// For more information, msdn also has an article about this race:
|
|
|
|
// http://support.microsoft.com/kb/315939
|
2021-04-28 19:11:57 +02:00
|
|
|
static CREATE_PROCESS_LOCK: StaticMutex = StaticMutex::new();
|
|
|
|
|
|
|
|
let _guard = unsafe { CREATE_PROCESS_LOCK.lock() };
|
2016-02-04 09:59:47 -08:00
|
|
|
|
2019-12-22 17:42:04 -05:00
|
|
|
let mut pipes = StdioPipes { stdin: None, stdout: None, stderr: None };
|
2016-02-12 10:28:03 -08:00
|
|
|
let null = Stdio::Null;
|
2019-12-22 17:42:04 -05:00
|
|
|
let default_stdin = if needs_stdin { &default } else { &null };
|
2016-02-12 10:28:03 -08:00
|
|
|
let stdin = self.stdin.as_ref().unwrap_or(default_stdin);
|
2016-02-04 11:10:37 -08:00
|
|
|
let stdout = self.stdout.as_ref().unwrap_or(&default);
|
|
|
|
let stderr = self.stderr.as_ref().unwrap_or(&default);
|
2016-03-22 22:01:37 -05:00
|
|
|
let stdin = stdin.to_handle(c::STD_INPUT_HANDLE, &mut pipes.stdin)?;
|
2019-12-22 17:42:04 -05:00
|
|
|
let stdout = stdout.to_handle(c::STD_OUTPUT_HANDLE, &mut pipes.stdout)?;
|
|
|
|
let stderr = stderr.to_handle(c::STD_ERROR_HANDLE, &mut pipes.stderr)?;
|
2016-02-04 09:59:47 -08:00
|
|
|
si.hStdInput = stdin.raw();
|
|
|
|
si.hStdOutput = stdout.raw();
|
|
|
|
si.hStdError = stderr.raw();
|
|
|
|
|
2016-03-22 22:01:37 -05:00
|
|
|
unsafe {
|
2019-12-22 17:42:04 -05:00
|
|
|
cvt(c::CreateProcessW(
|
|
|
|
ptr::null(),
|
|
|
|
cmd_str.as_mut_ptr(),
|
|
|
|
ptr::null_mut(),
|
|
|
|
ptr::null_mut(),
|
|
|
|
c::TRUE,
|
|
|
|
flags,
|
|
|
|
envp,
|
|
|
|
dirp,
|
|
|
|
&mut si,
|
|
|
|
&mut pi,
|
|
|
|
))
|
2016-03-22 22:01:37 -05:00
|
|
|
}?;
|
2015-02-06 09:42:57 -08:00
|
|
|
|
2015-04-27 13:44:20 -07:00
|
|
|
// We close the thread handle because we don't care about keeping
|
|
|
|
// the thread id valid, and we aren't keeping the thread handle
|
|
|
|
// around to be able to close it later.
|
|
|
|
drop(Handle::new(pi.hThread));
|
2015-02-06 09:42:57 -08:00
|
|
|
|
2016-02-04 11:10:37 -08:00
|
|
|
Ok((Process { handle: Handle::new(pi.hProcess) }, pipes))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Debug for Command {
|
2019-03-01 09:34:11 +01:00
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
2016-03-22 22:01:37 -05:00
|
|
|
write!(f, "{:?}", self.program)?;
|
2016-02-04 11:10:37 -08:00
|
|
|
for arg in &self.args {
|
2016-03-22 22:01:37 -05:00
|
|
|
write!(f, " {:?}", arg)?;
|
2016-02-04 11:10:37 -08:00
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Stdio {
|
2019-12-22 17:42:04 -05:00
|
|
|
fn to_handle(&self, stdio_id: c::DWORD, pipe: &mut Option<AnonPipe>) -> io::Result<Handle> {
|
2016-02-04 11:10:37 -08:00
|
|
|
match *self {
|
|
|
|
// If no stdio handle is available, then inherit means that it
|
|
|
|
// should still be unavailable so propagate the
|
|
|
|
// INVALID_HANDLE_VALUE.
|
2019-12-22 17:42:04 -05:00
|
|
|
Stdio::Inherit => match stdio::get_handle(stdio_id) {
|
|
|
|
Ok(io) => {
|
|
|
|
let io = Handle::new(io);
|
|
|
|
let ret = io.duplicate(0, true, c::DUPLICATE_SAME_ACCESS);
|
|
|
|
io.into_raw();
|
|
|
|
ret
|
2016-02-04 11:10:37 -08:00
|
|
|
}
|
2019-12-22 17:42:04 -05:00
|
|
|
Err(..) => Ok(Handle::new(c::INVALID_HANDLE_VALUE)),
|
|
|
|
},
|
2016-02-04 11:10:37 -08:00
|
|
|
|
|
|
|
Stdio::MakePipe => {
|
std: Don't pass overlapped handles to processes
This commit fixes a mistake introduced in #31618 where overlapped handles were
leaked to child processes on Windows. On Windows once a handle is in overlapped
mode it should always have I/O executed with an instance of `OVERLAPPED`. Most
child processes, however, are not prepared to have their stdio handles in
overlapped mode as they don't use `OVERLAPPED` on reads/writes to the handle.
Now we haven't had any odd behavior in Rust up to this point, and the original
bug was introduced almost a year ago. I believe this is because it turns out
that if you *don't* pass an `OVERLAPPED` then the system will [supply one for
you][link]. In this case everything will go awry if you concurrently operate on
the handle. In Rust, however, the stdio handles are always locked, and there's
no way to not use them unlocked in libstd. Due to that change we've always had
synchronized access to these handles, which means that Rust programs typically
"just work".
Conversely, though, this commit fixes the test case included, which exhibits
behavior that other programs Rust spawns may attempt to execute. Namely, the
stdio handles may be concurrently used and having them in overlapped mode wreaks
havoc.
[link]: https://blogs.msdn.microsoft.com/oldnewthing/20121012-00/?p=6343
Closes #38811
2017-01-04 15:32:39 -08:00
|
|
|
let ours_readable = stdio_id != c::STD_INPUT_HANDLE;
|
2019-05-27 16:51:29 +02:00
|
|
|
let pipes = pipe::anon_pipe(ours_readable, true)?;
|
std: Don't pass overlapped handles to processes
This commit fixes a mistake introduced in #31618 where overlapped handles were
leaked to child processes on Windows. On Windows once a handle is in overlapped
mode it should always have I/O executed with an instance of `OVERLAPPED`. Most
child processes, however, are not prepared to have their stdio handles in
overlapped mode as they don't use `OVERLAPPED` on reads/writes to the handle.
Now we haven't had any odd behavior in Rust up to this point, and the original
bug was introduced almost a year ago. I believe this is because it turns out
that if you *don't* pass an `OVERLAPPED` then the system will [supply one for
you][link]. In this case everything will go awry if you concurrently operate on
the handle. In Rust, however, the stdio handles are always locked, and there's
no way to not use them unlocked in libstd. Due to that change we've always had
synchronized access to these handles, which means that Rust programs typically
"just work".
Conversely, though, this commit fixes the test case included, which exhibits
behavior that other programs Rust spawns may attempt to execute. Namely, the
stdio handles may be concurrently used and having them in overlapped mode wreaks
havoc.
[link]: https://blogs.msdn.microsoft.com/oldnewthing/20121012-00/?p=6343
Closes #38811
2017-01-04 15:32:39 -08:00
|
|
|
*pipe = Some(pipes.ours);
|
|
|
|
Ok(pipes.theirs.into_handle())
|
2016-02-04 11:10:37 -08:00
|
|
|
}
|
|
|
|
|
2019-12-22 17:42:04 -05:00
|
|
|
Stdio::Handle(ref handle) => handle.duplicate(0, true, c::DUPLICATE_SAME_ACCESS),
|
2016-02-04 11:10:37 -08:00
|
|
|
|
|
|
|
// Open up a reference to NUL with appropriate read/write
|
|
|
|
// permissions as well as the ability to be inherited to child
|
|
|
|
// processes (as this is about to be inherited).
|
|
|
|
Stdio::Null => {
|
|
|
|
let size = mem::size_of::<c::SECURITY_ATTRIBUTES>();
|
|
|
|
let mut sa = c::SECURITY_ATTRIBUTES {
|
|
|
|
nLength: size as c::DWORD,
|
|
|
|
lpSecurityDescriptor: ptr::null_mut(),
|
|
|
|
bInheritHandle: 1,
|
|
|
|
};
|
|
|
|
let mut opts = OpenOptions::new();
|
|
|
|
opts.read(stdio_id == c::STD_INPUT_HANDLE);
|
|
|
|
opts.write(stdio_id != c::STD_INPUT_HANDLE);
|
|
|
|
opts.security_attributes(&mut sa);
|
2019-12-22 17:42:04 -05:00
|
|
|
File::open(Path::new("NUL"), &opts).map(|file| file.into_handle())
|
2016-02-04 11:10:37 -08:00
|
|
|
}
|
|
|
|
}
|
2015-02-06 09:42:57 -08:00
|
|
|
}
|
2016-02-04 11:10:37 -08:00
|
|
|
}
|
|
|
|
|
2017-06-06 15:42:55 -07:00
|
|
|
impl From<AnonPipe> for Stdio {
|
|
|
|
fn from(pipe: AnonPipe) -> Stdio {
|
|
|
|
Stdio::Handle(pipe.into_handle())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<File> for Stdio {
|
|
|
|
fn from(file: File) -> Stdio {
|
|
|
|
Stdio::Handle(file.into_handle())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-02-04 11:10:37 -08:00
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Processes
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
/// A value representing a child process.
|
|
|
|
///
|
|
|
|
/// The lifetime of this value is linked to the lifetime of the actual
|
|
|
|
/// process - the Process destructor calls self.finish() which waits
|
|
|
|
/// for the process to terminate.
|
|
|
|
pub struct Process {
|
|
|
|
handle: Handle,
|
|
|
|
}
|
2015-02-06 09:42:57 -08:00
|
|
|
|
2016-02-04 11:10:37 -08:00
|
|
|
impl Process {
|
2016-02-03 18:09:35 -08:00
|
|
|
pub fn kill(&mut self) -> io::Result<()> {
|
2019-12-22 17:42:04 -05:00
|
|
|
cvt(unsafe { c::TerminateProcess(self.handle.raw(), 1) })?;
|
2015-02-06 09:42:57 -08:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2015-04-16 09:44:05 -07:00
|
|
|
pub fn id(&self) -> u32 {
|
2019-12-22 17:42:04 -05:00
|
|
|
unsafe { c::GetProcessId(self.handle.raw()) as u32 }
|
2015-04-16 09:44:05 -07:00
|
|
|
}
|
|
|
|
|
2016-02-03 18:09:35 -08:00
|
|
|
pub fn wait(&mut self) -> io::Result<ExitStatus> {
|
2015-02-06 09:42:57 -08:00
|
|
|
unsafe {
|
2015-11-02 16:23:22 -08:00
|
|
|
let res = c::WaitForSingleObject(self.handle.raw(), c::INFINITE);
|
|
|
|
if res != c::WAIT_OBJECT_0 {
|
2019-12-22 17:42:04 -05:00
|
|
|
return Err(Error::last_os_error());
|
2015-02-06 09:42:57 -08:00
|
|
|
}
|
2015-10-29 13:45:56 -07:00
|
|
|
let mut status = 0;
|
2016-03-22 22:01:37 -05:00
|
|
|
cvt(c::GetExitCodeProcess(self.handle.raw(), &mut status))?;
|
2015-10-29 13:45:56 -07:00
|
|
|
Ok(ExitStatus(status))
|
2015-02-06 09:42:57 -08:00
|
|
|
}
|
|
|
|
}
|
2015-05-12 11:03:49 -07:00
|
|
|
|
2017-02-03 17:39:41 -05:00
|
|
|
pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
|
2017-01-05 22:47:09 -08:00
|
|
|
unsafe {
|
|
|
|
match c::WaitForSingleObject(self.handle.raw(), 0) {
|
|
|
|
c::WAIT_OBJECT_0 => {}
|
|
|
|
c::WAIT_TIMEOUT => {
|
2017-02-03 17:39:41 -05:00
|
|
|
return Ok(None);
|
2017-01-05 22:47:09 -08:00
|
|
|
}
|
|
|
|
_ => return Err(io::Error::last_os_error()),
|
|
|
|
}
|
|
|
|
let mut status = 0;
|
|
|
|
cvt(c::GetExitCodeProcess(self.handle.raw(), &mut status))?;
|
2017-02-03 17:39:41 -05:00
|
|
|
Ok(Some(ExitStatus(status)))
|
2017-01-05 22:47:09 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-22 17:42:04 -05:00
|
|
|
pub fn handle(&self) -> &Handle {
|
|
|
|
&self.handle
|
|
|
|
}
|
2015-07-15 23:31:24 -07:00
|
|
|
|
2019-12-22 17:42:04 -05:00
|
|
|
pub fn into_handle(self) -> Handle {
|
|
|
|
self.handle
|
|
|
|
}
|
2015-02-06 09:42:57 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
|
2015-11-02 16:23:22 -08:00
|
|
|
pub struct ExitStatus(c::DWORD);
|
2015-02-06 09:42:57 -08:00
|
|
|
|
|
|
|
impl ExitStatus {
|
|
|
|
pub fn success(&self) -> bool {
|
|
|
|
self.0 == 0
|
|
|
|
}
|
|
|
|
pub fn code(&self) -> Option<i32> {
|
2015-10-29 13:45:56 -07:00
|
|
|
Some(self.0 as i32)
|
2015-02-06 09:42:57 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-13 13:47:18 +02:00
|
|
|
/// Converts a raw `c::DWORD` to a type-safe `ExitStatus` by wrapping it without copying.
|
2016-04-26 15:23:46 -07:00
|
|
|
impl From<c::DWORD> for ExitStatus {
|
|
|
|
fn from(u: c::DWORD) -> ExitStatus {
|
|
|
|
ExitStatus(u)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-06 09:42:57 -08:00
|
|
|
impl fmt::Display for ExitStatus {
|
2019-03-01 09:34:11 +01:00
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
2019-01-09 09:35:09 -08:00
|
|
|
// Windows exit codes with the high bit set typically mean some form of
|
|
|
|
// unhandled exception or warning. In this scenario printing the exit
|
|
|
|
// code in decimal doesn't always make sense because it's a very large
|
|
|
|
// and somewhat gibberish number. The hex code is a bit more
|
|
|
|
// recognizable and easier to search for, so print that.
|
|
|
|
if self.0 & 0x80000000 != 0 {
|
|
|
|
write!(f, "exit code: {:#x}", self.0)
|
|
|
|
} else {
|
|
|
|
write!(f, "exit code: {}", self.0)
|
|
|
|
}
|
2015-02-06 09:42:57 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-03 18:29:30 -08:00
|
|
|
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
|
|
|
|
pub struct ExitCode(c::DWORD);
|
|
|
|
|
|
|
|
impl ExitCode {
|
|
|
|
pub const SUCCESS: ExitCode = ExitCode(EXIT_SUCCESS as _);
|
|
|
|
pub const FAILURE: ExitCode = ExitCode(EXIT_FAILURE as _);
|
|
|
|
|
2018-04-05 11:07:19 -07:00
|
|
|
#[inline]
|
2018-03-03 18:29:30 -08:00
|
|
|
pub fn as_i32(&self) -> i32 {
|
|
|
|
self.0 as i32
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-02 16:23:22 -08:00
|
|
|
fn zeroed_startupinfo() -> c::STARTUPINFO {
|
|
|
|
c::STARTUPINFO {
|
2015-02-06 09:42:57 -08:00
|
|
|
cb: 0,
|
|
|
|
lpReserved: ptr::null_mut(),
|
|
|
|
lpDesktop: ptr::null_mut(),
|
|
|
|
lpTitle: ptr::null_mut(),
|
|
|
|
dwX: 0,
|
|
|
|
dwY: 0,
|
|
|
|
dwXSize: 0,
|
|
|
|
dwYSize: 0,
|
|
|
|
dwXCountChars: 0,
|
|
|
|
dwYCountCharts: 0,
|
|
|
|
dwFillAttribute: 0,
|
|
|
|
dwFlags: 0,
|
|
|
|
wShowWindow: 0,
|
|
|
|
cbReserved2: 0,
|
|
|
|
lpReserved2: ptr::null_mut(),
|
2015-11-02 16:23:22 -08:00
|
|
|
hStdInput: c::INVALID_HANDLE_VALUE,
|
|
|
|
hStdOutput: c::INVALID_HANDLE_VALUE,
|
|
|
|
hStdError: c::INVALID_HANDLE_VALUE,
|
2015-02-06 09:42:57 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-02 16:23:22 -08:00
|
|
|
fn zeroed_process_information() -> c::PROCESS_INFORMATION {
|
|
|
|
c::PROCESS_INFORMATION {
|
2015-02-06 09:42:57 -08:00
|
|
|
hProcess: ptr::null_mut(),
|
|
|
|
hThread: ptr::null_mut(),
|
|
|
|
dwProcessId: 0,
|
2019-12-22 17:42:04 -05:00
|
|
|
dwThreadId: 0,
|
2015-02-06 09:42:57 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-01-15 15:29:45 -05:00
|
|
|
// Produces a wide string *without terminating null*; returns an error if
|
|
|
|
// `prog` or any of the `args` contain a nul.
|
2020-10-08 22:26:31 +00:00
|
|
|
fn make_command_line(prog: &OsStr, args: &[OsString], force_quotes: bool) -> io::Result<Vec<u16>> {
|
2015-04-25 15:35:22 -04:00
|
|
|
// Encode the command and arguments in a command line string such
|
|
|
|
// that the spawned process may recover them using CommandLineToArgvW.
|
2015-02-06 09:42:57 -08:00
|
|
|
let mut cmd: Vec<u16> = Vec::new();
|
2017-06-04 21:47:24 +01:00
|
|
|
// Always quote the program name so CreateProcess doesn't interpret args as
|
|
|
|
// part of the name if the binary wasn't found first time.
|
|
|
|
append_arg(&mut cmd, prog, true)?;
|
2015-02-06 09:42:57 -08:00
|
|
|
for arg in args {
|
|
|
|
cmd.push(' ' as u16);
|
2020-10-08 22:26:31 +00:00
|
|
|
append_arg(&mut cmd, arg, force_quotes)?;
|
2015-02-06 09:42:57 -08:00
|
|
|
}
|
2016-01-15 15:29:45 -05:00
|
|
|
return Ok(cmd);
|
2015-02-06 09:42:57 -08:00
|
|
|
|
2017-06-04 21:47:24 +01:00
|
|
|
fn append_arg(cmd: &mut Vec<u16>, arg: &OsStr, force_quotes: bool) -> io::Result<()> {
|
2015-02-06 09:42:57 -08:00
|
|
|
// If an argument has 0 characters then we need to quote it to ensure
|
|
|
|
// that it actually gets passed through on the command line or otherwise
|
|
|
|
// it will be dropped entirely when parsed on the other end.
|
2016-03-22 22:01:37 -05:00
|
|
|
ensure_no_nuls(arg)?;
|
2015-02-06 09:42:57 -08:00
|
|
|
let arg_bytes = &arg.as_inner().inner.as_inner();
|
2019-12-22 17:42:04 -05:00
|
|
|
let quote = force_quotes
|
|
|
|
|| arg_bytes.iter().any(|c| *c == b' ' || *c == b'\t')
|
2015-03-24 16:53:34 -07:00
|
|
|
|| arg_bytes.is_empty();
|
2015-02-06 09:42:57 -08:00
|
|
|
if quote {
|
|
|
|
cmd.push('"' as u16);
|
|
|
|
}
|
|
|
|
|
2015-04-25 15:35:22 -04:00
|
|
|
let mut backslashes: usize = 0;
|
2019-09-05 13:47:59 +02:00
|
|
|
for x in arg.encode_wide() {
|
2015-04-25 15:35:22 -04:00
|
|
|
if x == '\\' as u16 {
|
|
|
|
backslashes += 1;
|
2015-02-06 09:42:57 -08:00
|
|
|
} else {
|
2015-04-25 15:35:22 -04:00
|
|
|
if x == '"' as u16 {
|
|
|
|
// Add n+1 backslashes to total 2n+1 before internal '"'.
|
2018-12-04 11:17:58 -08:00
|
|
|
cmd.extend((0..=backslashes).map(|_| '\\' as u16));
|
2015-04-25 15:35:22 -04:00
|
|
|
}
|
|
|
|
backslashes = 0;
|
2015-02-06 09:42:57 -08:00
|
|
|
}
|
2015-04-25 15:35:22 -04:00
|
|
|
cmd.push(x);
|
2015-02-06 09:42:57 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
if quote {
|
2015-04-25 15:35:22 -04:00
|
|
|
// Add n backslashes to total 2n before ending '"'.
|
2018-07-26 17:11:10 +02:00
|
|
|
cmd.extend((0..backslashes).map(|_| '\\' as u16));
|
2015-02-06 09:42:57 -08:00
|
|
|
cmd.push('"' as u16);
|
|
|
|
}
|
2016-01-15 15:29:45 -05:00
|
|
|
Ok(())
|
2015-02-06 09:42:57 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-22 17:42:04 -05:00
|
|
|
fn make_envp(maybe_env: Option<BTreeMap<EnvKey, OsString>>) -> io::Result<(*mut c_void, Vec<u16>)> {
|
2015-02-06 09:42:57 -08:00
|
|
|
// On Windows we pass an "environment block" which is not a char**, but
|
|
|
|
// rather a concatenation of null-terminated k=v\0 sequences, with a final
|
|
|
|
// \0 to terminate.
|
2017-12-17 15:21:47 +00:00
|
|
|
if let Some(env) = maybe_env {
|
|
|
|
let mut blk = Vec::new();
|
|
|
|
|
|
|
|
for (k, v) in env {
|
|
|
|
blk.extend(ensure_no_nuls(k.0)?.encode_wide());
|
|
|
|
blk.push('=' as u16);
|
|
|
|
blk.extend(ensure_no_nuls(v)?.encode_wide());
|
2015-02-06 09:42:57 -08:00
|
|
|
blk.push(0);
|
|
|
|
}
|
2017-12-17 15:21:47 +00:00
|
|
|
blk.push(0);
|
|
|
|
Ok((blk.as_mut_ptr() as *mut c_void, blk))
|
|
|
|
} else {
|
|
|
|
Ok((ptr::null_mut(), Vec::new()))
|
2015-02-06 09:42:57 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-01-15 15:29:45 -05:00
|
|
|
fn make_dirp(d: Option<&OsString>) -> io::Result<(*const u16, Vec<u16>)> {
|
2015-02-06 09:42:57 -08:00
|
|
|
match d {
|
2015-04-27 13:44:20 -07:00
|
|
|
Some(dir) => {
|
2016-03-22 22:01:37 -05:00
|
|
|
let mut dir_str: Vec<u16> = ensure_no_nuls(dir)?.encode_wide().collect();
|
2015-04-27 13:44:20 -07:00
|
|
|
dir_str.push(0);
|
2016-01-15 15:29:45 -05:00
|
|
|
Ok((dir_str.as_ptr(), dir_str))
|
2019-12-22 17:42:04 -05:00
|
|
|
}
|
|
|
|
None => Ok((ptr::null(), Vec::new())),
|
2015-04-27 13:44:20 -07:00
|
|
|
}
|
|
|
|
}
|
2020-09-21 11:32:06 -07:00
|
|
|
|
|
|
|
pub struct CommandArgs<'a> {
|
|
|
|
iter: crate::slice::Iter<'a, OsString>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> Iterator for CommandArgs<'a> {
|
|
|
|
type Item = &'a OsStr;
|
|
|
|
fn next(&mut self) -> Option<&'a OsStr> {
|
|
|
|
self.iter.next().map(|s| s.as_ref())
|
|
|
|
}
|
|
|
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
|
|
|
self.iter.size_hint()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> ExactSizeIterator for CommandArgs<'a> {
|
|
|
|
fn len(&self) -> usize {
|
|
|
|
self.iter.len()
|
|
|
|
}
|
|
|
|
fn is_empty(&self) -> bool {
|
|
|
|
self.iter.is_empty()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> fmt::Debug for CommandArgs<'a> {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
|
|
f.debug_list().entries(self.iter.clone()).finish()
|
|
|
|
}
|
|
|
|
}
|