2020-08-27 13:45:01 +00:00
|
|
|
#[cfg(all(test, not(target_os = "emscripten")))]
|
|
|
|
|
mod tests;
|
|
|
|
|
|
2019-02-11 04:23:21 +09:00
|
|
|
use crate::os::unix::prelude::*;
|
|
|
|
|
|
2019-11-27 10:28:39 -08:00
|
|
|
use crate::collections::BTreeMap;
|
|
|
|
|
use crate::ffi::{CStr, CString, OsStr, OsString};
|
2019-02-11 04:23:21 +09:00
|
|
|
use crate::fmt;
|
|
|
|
|
use crate::io;
|
2020-09-21 11:32:06 -07:00
|
|
|
use crate::path::Path;
|
2019-02-11 04:23:21 +09:00
|
|
|
use crate::ptr;
|
|
|
|
|
use crate::sys::fd::FileDesc;
|
2019-08-30 11:51:04 -07:00
|
|
|
use crate::sys::fs::File;
|
2019-02-11 04:23:21 +09:00
|
|
|
use crate::sys::pipe::{self, AnonPipe};
|
2020-09-21 11:32:06 -07:00
|
|
|
use crate::sys_common::process::{CommandEnv, CommandEnvs};
|
2021-06-30 21:44:30 -07:00
|
|
|
use crate::sys_common::IntoInner;
|
2019-02-11 04:23:21 +09:00
|
|
|
|
2019-08-30 11:51:04 -07:00
|
|
|
#[cfg(not(target_os = "fuchsia"))]
|
2019-11-17 22:56:13 -08:00
|
|
|
use crate::sys::fs::OpenOptions;
|
2019-08-30 11:51:04 -07:00
|
|
|
|
2019-11-27 10:28:39 -08:00
|
|
|
use libc::{c_char, c_int, gid_t, uid_t, EXIT_FAILURE, EXIT_SUCCESS};
|
2016-11-23 13:58:13 -08:00
|
|
|
|
2019-08-06 19:32:39 -06:00
|
|
|
cfg_if::cfg_if! {
|
2019-08-30 11:51:04 -07:00
|
|
|
if #[cfg(target_os = "fuchsia")] {
|
|
|
|
|
// fuchsia doesn't have /dev/null
|
|
|
|
|
} else if #[cfg(target_os = "redox")] {
|
2020-03-05 11:33:05 +01:00
|
|
|
const DEV_NULL: &str = "null:\0";
|
2020-10-07 20:38:25 +02:00
|
|
|
} else if #[cfg(target_os = "vxworks")] {
|
|
|
|
|
const DEV_NULL: &str = "/null\0";
|
2019-04-07 08:39:54 -06:00
|
|
|
} else {
|
2020-03-05 11:33:05 +01:00
|
|
|
const DEV_NULL: &str = "/dev/null\0";
|
2019-04-07 08:39:54 -06:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-19 16:14:07 -07:00
|
|
|
// Android with api less than 21 define sig* functions inline, so it is not
|
|
|
|
|
// available for dynamic link. Implementing sigemptyset and sigaddset allow us
|
|
|
|
|
// to support older Android version (independent of libc version).
|
|
|
|
|
// The following implementations are based on https://git.io/vSkNf
|
|
|
|
|
cfg_if::cfg_if! {
|
|
|
|
|
if #[cfg(target_os = "android")] {
|
|
|
|
|
pub unsafe fn sigemptyset(set: *mut libc::sigset_t) -> libc::c_int {
|
|
|
|
|
set.write_bytes(0u8, 1);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
#[allow(dead_code)]
|
|
|
|
|
pub unsafe fn sigaddset(set: *mut libc::sigset_t, signum: libc::c_int) -> libc::c_int {
|
|
|
|
|
use crate::{slice, mem};
|
|
|
|
|
|
|
|
|
|
let raw = slice::from_raw_parts_mut(set as *mut u8, mem::size_of::<libc::sigset_t>());
|
|
|
|
|
let bit = (signum - 1) as usize;
|
|
|
|
|
raw[bit / 8] |= 1 << (bit % 8);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2021-07-20 15:12:36 -07:00
|
|
|
} else {
|
2019-08-19 16:14:07 -07:00
|
|
|
pub use libc::{sigemptyset, sigaddset};
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-23 13:58:13 -08:00
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
// Command
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
pub struct Command {
|
|
|
|
|
program: CString,
|
|
|
|
|
args: Vec<CString>,
|
2021-02-23 20:19:15 -08:00
|
|
|
/// Exactly what will be passed to `execvp`.
|
|
|
|
|
///
|
|
|
|
|
/// First element is a pointer to `program`, followed by pointers to
|
|
|
|
|
/// `args`, followed by a `null`. Be careful when modifying `program` or
|
|
|
|
|
/// `args` to properly update this as well.
|
2018-01-26 07:22:43 -08:00
|
|
|
argv: Argv,
|
2019-09-03 19:32:44 -07:00
|
|
|
env: CommandEnv,
|
2016-11-23 13:58:13 -08:00
|
|
|
|
|
|
|
|
cwd: Option<CString>,
|
|
|
|
|
uid: Option<uid_t>,
|
|
|
|
|
gid: Option<gid_t>,
|
|
|
|
|
saw_nul: bool,
|
2018-07-10 20:52:29 +02:00
|
|
|
closures: Vec<Box<dyn FnMut() -> io::Result<()> + Send + Sync>>,
|
2020-06-15 21:39:34 -07:00
|
|
|
groups: Option<Box<[gid_t]>>,
|
2016-11-23 13:58:13 -08:00
|
|
|
stdin: Option<Stdio>,
|
|
|
|
|
stdout: Option<Stdio>,
|
|
|
|
|
stderr: Option<Stdio>,
|
2021-02-06 14:15:49 +01:00
|
|
|
#[cfg(target_os = "linux")]
|
|
|
|
|
create_pidfd: bool,
|
2016-11-23 13:58:13 -08:00
|
|
|
}
|
|
|
|
|
|
2020-05-22 18:30:26 +02:00
|
|
|
// Create a new type for argv, so that we can make it `Send` and `Sync`
|
2018-01-26 07:22:43 -08:00
|
|
|
struct Argv(Vec<*const c_char>);
|
|
|
|
|
|
2020-05-22 18:30:26 +02:00
|
|
|
// It is safe to make `Argv` `Send` and `Sync`, because it contains
|
|
|
|
|
// pointers to memory owned by `Command.args`
|
2018-01-26 07:22:43 -08:00
|
|
|
unsafe impl Send for Argv {}
|
2020-05-22 18:30:26 +02:00
|
|
|
unsafe impl Sync for Argv {}
|
2018-01-26 07:22:43 -08:00
|
|
|
|
2016-11-23 13:58:13 -08:00
|
|
|
// passed back to std::process with the pipes connected to the child, if any
|
|
|
|
|
// were requested
|
|
|
|
|
pub struct StdioPipes {
|
|
|
|
|
pub stdin: Option<AnonPipe>,
|
|
|
|
|
pub stdout: Option<AnonPipe>,
|
|
|
|
|
pub stderr: Option<AnonPipe>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// passed to do_exec() with configuration of what the child stdio should look
|
|
|
|
|
// like
|
|
|
|
|
pub struct ChildPipes {
|
|
|
|
|
pub stdin: ChildStdio,
|
|
|
|
|
pub stdout: ChildStdio,
|
|
|
|
|
pub stderr: ChildStdio,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub enum ChildStdio {
|
|
|
|
|
Inherit,
|
|
|
|
|
Explicit(c_int),
|
|
|
|
|
Owned(FileDesc),
|
2019-08-30 11:51:04 -07:00
|
|
|
|
|
|
|
|
// On Fuchsia, null stdio is the default, so we simply don't specify
|
|
|
|
|
// any actions at the time of spawning.
|
|
|
|
|
#[cfg(target_os = "fuchsia")]
|
|
|
|
|
Null,
|
2016-11-23 13:58:13 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub enum Stdio {
|
|
|
|
|
Inherit,
|
|
|
|
|
Null,
|
|
|
|
|
MakePipe,
|
|
|
|
|
Fd(FileDesc),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Command {
|
2021-02-06 14:15:49 +01:00
|
|
|
#[cfg(not(target_os = "linux"))]
|
2016-11-23 13:58:13 -08:00
|
|
|
pub fn new(program: &OsStr) -> Command {
|
|
|
|
|
let mut saw_nul = false;
|
|
|
|
|
let program = os2c(program, &mut saw_nul);
|
|
|
|
|
Command {
|
2018-01-26 07:22:43 -08:00
|
|
|
argv: Argv(vec![program.as_ptr(), ptr::null()]),
|
2019-11-17 22:56:13 -08:00
|
|
|
args: vec![program.clone()],
|
2017-08-06 22:54:09 -07:00
|
|
|
program,
|
2017-12-17 15:21:47 +00:00
|
|
|
env: Default::default(),
|
2016-11-23 13:58:13 -08:00
|
|
|
cwd: None,
|
|
|
|
|
uid: None,
|
|
|
|
|
gid: None,
|
2017-08-06 22:54:09 -07:00
|
|
|
saw_nul,
|
2016-11-23 13:58:13 -08:00
|
|
|
closures: Vec::new(),
|
2020-06-15 21:39:34 -07:00
|
|
|
groups: None,
|
2016-11-23 13:58:13 -08:00
|
|
|
stdin: None,
|
|
|
|
|
stdout: None,
|
|
|
|
|
stderr: None,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-02-06 14:15:49 +01:00
|
|
|
#[cfg(target_os = "linux")]
|
|
|
|
|
pub fn new(program: &OsStr) -> Command {
|
|
|
|
|
let mut saw_nul = false;
|
|
|
|
|
let program = os2c(program, &mut saw_nul);
|
|
|
|
|
Command {
|
|
|
|
|
argv: Argv(vec![program.as_ptr(), ptr::null()]),
|
|
|
|
|
args: vec![program.clone()],
|
|
|
|
|
program,
|
|
|
|
|
env: Default::default(),
|
|
|
|
|
cwd: None,
|
|
|
|
|
uid: None,
|
|
|
|
|
gid: None,
|
|
|
|
|
saw_nul,
|
|
|
|
|
closures: Vec::new(),
|
|
|
|
|
groups: None,
|
|
|
|
|
stdin: None,
|
|
|
|
|
stdout: None,
|
|
|
|
|
stderr: None,
|
|
|
|
|
create_pidfd: false,
|
2016-11-23 13:58:13 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-17 22:56:13 -08:00
|
|
|
pub fn set_arg_0(&mut self, arg: &OsStr) {
|
|
|
|
|
// Set a new arg0
|
|
|
|
|
let arg = os2c(arg, &mut self.saw_nul);
|
|
|
|
|
debug_assert!(self.argv.0.len() > 1);
|
|
|
|
|
self.argv.0[0] = arg.as_ptr();
|
|
|
|
|
self.args[0] = arg;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-23 13:58:13 -08:00
|
|
|
pub fn arg(&mut self, arg: &OsStr) {
|
2021-05-02 15:55:22 -06:00
|
|
|
// Overwrite the trailing null pointer in `argv` and then add a new null
|
2016-11-23 13:58:13 -08:00
|
|
|
// pointer.
|
|
|
|
|
let arg = os2c(arg, &mut self.saw_nul);
|
2019-11-17 22:56:13 -08:00
|
|
|
self.argv.0[self.args.len()] = arg.as_ptr();
|
2018-01-26 07:22:43 -08:00
|
|
|
self.argv.0.push(ptr::null());
|
2016-11-23 13:58:13 -08:00
|
|
|
|
|
|
|
|
// Also make sure we keep track of the owned value to schedule a
|
|
|
|
|
// destructor for this memory.
|
|
|
|
|
self.args.push(arg);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn cwd(&mut self, dir: &OsStr) {
|
|
|
|
|
self.cwd = Some(os2c(dir, &mut self.saw_nul));
|
|
|
|
|
}
|
|
|
|
|
pub fn uid(&mut self, id: uid_t) {
|
|
|
|
|
self.uid = Some(id);
|
|
|
|
|
}
|
|
|
|
|
pub fn gid(&mut self, id: gid_t) {
|
|
|
|
|
self.gid = Some(id);
|
|
|
|
|
}
|
2020-06-15 21:39:34 -07:00
|
|
|
pub fn groups(&mut self, groups: &[gid_t]) {
|
|
|
|
|
self.groups = Some(Box::from(groups));
|
|
|
|
|
}
|
2016-11-23 13:58:13 -08:00
|
|
|
|
2021-02-06 14:15:49 +01:00
|
|
|
#[cfg(target_os = "linux")]
|
Add Linux-specific pidfd process extensions
Background:
Over the last year, pidfd support was added to the Linux kernel. This
allows interacting with other processes. In particular, this allows
waiting on a child process with a timeout in a race-free way, bypassing
all of the awful signal-handler tricks that are usually required.
Pidfds can be obtained for a child process (as well as any other
process) via the `pidfd_open` syscall. Unfortunately, this requires
several conditions to hold in order to be race-free (i.e. the pid is not
reused).
Per `man pidfd_open`:
```
· the disposition of SIGCHLD has not been explicitly set to SIG_IGN
(see sigaction(2));
· the SA_NOCLDWAIT flag was not specified while establishing a han‐
dler for SIGCHLD or while setting the disposition of that signal to
SIG_DFL (see sigaction(2)); and
· the zombie process was not reaped elsewhere in the program (e.g.,
either by an asynchronously executed signal handler or by wait(2)
or similar in another thread).
If any of these conditions does not hold, then the child process
(along with a PID file descriptor that refers to it) should instead
be created using clone(2) with the CLONE_PIDFD flag.
```
Sadly, these conditions are impossible to guarantee once any libraries
are used. For example, C code runnng in a different thread could call
`wait()`, which is impossible to detect from Rust code trying to open a
pidfd.
While pid reuse issues should (hopefully) be rare in practice, we can do
better. By passing the `CLONE_PIDFD` flag to `clone()` or `clone3()`, we
can obtain a pidfd for the child process in a guaranteed race-free
manner.
This PR:
This PR adds Linux-specific process extension methods to allow obtaining
pidfds for processes spawned via the standard `Command` API. Other than
being made available to user code, the standard library does not make
use of these pidfds in any way. In particular, the implementation of
`Child::wait` is completely unchanged.
Two Linux-specific helper methods are added: `CommandExt::create_pidfd`
and `ChildExt::pidfd`. These methods are intended to serve as a building
block for libraries to build higher-level abstractions - in particular,
waiting on a process with a timeout.
I've included a basic test, which verifies that pidfds are created iff
the `create_pidfd` method is used. This test is somewhat special - it
should always succeed on systems with the `clone3` system call
available, and always fail on systems without `clone3` available. I'm
not sure how to best ensure this programatically.
This PR relies on the newer `clone3` system call to pass the `CLONE_FD`,
rather than the older `clone` system call. `clone3` was added to Linux
in the same release as pidfds, so this shouldn't unnecessarily limit the
kernel versions that this code supports.
Unresolved questions:
* What should the name of the feature gate be for these newly added
methods?
* Should the `pidfd` method distinguish between an error occurring
and `create_pidfd` not being called?
2020-09-15 23:35:08 -04:00
|
|
|
pub fn create_pidfd(&mut self, val: bool) {
|
2021-02-06 14:15:49 +01:00
|
|
|
self.create_pidfd = val;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(not(target_os = "linux"))]
|
|
|
|
|
#[allow(dead_code)]
|
|
|
|
|
pub fn get_create_pidfd(&self) -> bool {
|
|
|
|
|
false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(target_os = "linux")]
|
|
|
|
|
pub fn get_create_pidfd(&self) -> bool {
|
|
|
|
|
self.create_pidfd
|
Add Linux-specific pidfd process extensions
Background:
Over the last year, pidfd support was added to the Linux kernel. This
allows interacting with other processes. In particular, this allows
waiting on a child process with a timeout in a race-free way, bypassing
all of the awful signal-handler tricks that are usually required.
Pidfds can be obtained for a child process (as well as any other
process) via the `pidfd_open` syscall. Unfortunately, this requires
several conditions to hold in order to be race-free (i.e. the pid is not
reused).
Per `man pidfd_open`:
```
· the disposition of SIGCHLD has not been explicitly set to SIG_IGN
(see sigaction(2));
· the SA_NOCLDWAIT flag was not specified while establishing a han‐
dler for SIGCHLD or while setting the disposition of that signal to
SIG_DFL (see sigaction(2)); and
· the zombie process was not reaped elsewhere in the program (e.g.,
either by an asynchronously executed signal handler or by wait(2)
or similar in another thread).
If any of these conditions does not hold, then the child process
(along with a PID file descriptor that refers to it) should instead
be created using clone(2) with the CLONE_PIDFD flag.
```
Sadly, these conditions are impossible to guarantee once any libraries
are used. For example, C code runnng in a different thread could call
`wait()`, which is impossible to detect from Rust code trying to open a
pidfd.
While pid reuse issues should (hopefully) be rare in practice, we can do
better. By passing the `CLONE_PIDFD` flag to `clone()` or `clone3()`, we
can obtain a pidfd for the child process in a guaranteed race-free
manner.
This PR:
This PR adds Linux-specific process extension methods to allow obtaining
pidfds for processes spawned via the standard `Command` API. Other than
being made available to user code, the standard library does not make
use of these pidfds in any way. In particular, the implementation of
`Child::wait` is completely unchanged.
Two Linux-specific helper methods are added: `CommandExt::create_pidfd`
and `ChildExt::pidfd`. These methods are intended to serve as a building
block for libraries to build higher-level abstractions - in particular,
waiting on a process with a timeout.
I've included a basic test, which verifies that pidfds are created iff
the `create_pidfd` method is used. This test is somewhat special - it
should always succeed on systems with the `clone3` system call
available, and always fail on systems without `clone3` available. I'm
not sure how to best ensure this programatically.
This PR relies on the newer `clone3` system call to pass the `CLONE_FD`,
rather than the older `clone` system call. `clone3` was added to Linux
in the same release as pidfds, so this shouldn't unnecessarily limit the
kernel versions that this code supports.
Unresolved questions:
* What should the name of the feature gate be for these newly added
methods?
* Should the `pidfd` method distinguish between an error occurring
and `create_pidfd` not being called?
2020-09-15 23:35:08 -04:00
|
|
|
}
|
2016-11-23 13:58:13 -08:00
|
|
|
|
|
|
|
|
pub fn saw_nul(&self) -> bool {
|
|
|
|
|
self.saw_nul
|
|
|
|
|
}
|
2020-09-21 11:32:06 -07:00
|
|
|
|
|
|
|
|
pub fn get_program(&self) -> &OsStr {
|
|
|
|
|
OsStr::from_bytes(self.program.as_bytes())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn get_args(&self) -> CommandArgs<'_> {
|
|
|
|
|
let mut iter = self.args.iter();
|
|
|
|
|
iter.next();
|
|
|
|
|
CommandArgs { iter }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn get_envs(&self) -> CommandEnvs<'_> {
|
|
|
|
|
self.env.iter()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn get_current_dir(&self) -> Option<&Path> {
|
|
|
|
|
self.cwd.as_ref().map(|cs| Path::new(OsStr::from_bytes(cs.as_bytes())))
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-23 13:58:13 -08:00
|
|
|
pub fn get_argv(&self) -> &Vec<*const c_char> {
|
2018-01-26 07:22:43 -08:00
|
|
|
&self.argv.0
|
2016-11-23 13:58:13 -08:00
|
|
|
}
|
|
|
|
|
|
2020-09-21 11:32:06 -07:00
|
|
|
pub fn get_program_cstr(&self) -> &CStr {
|
2019-11-17 22:56:13 -08:00
|
|
|
&*self.program
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-01 12:01:07 -08:00
|
|
|
#[allow(dead_code)]
|
2016-11-23 13:58:13 -08:00
|
|
|
pub fn get_cwd(&self) -> &Option<CString> {
|
|
|
|
|
&self.cwd
|
|
|
|
|
}
|
2016-12-01 12:01:07 -08:00
|
|
|
#[allow(dead_code)]
|
2016-11-23 13:58:13 -08:00
|
|
|
pub fn get_uid(&self) -> Option<uid_t> {
|
|
|
|
|
self.uid
|
|
|
|
|
}
|
2016-12-01 12:01:07 -08:00
|
|
|
#[allow(dead_code)]
|
2016-11-23 13:58:13 -08:00
|
|
|
pub fn get_gid(&self) -> Option<gid_t> {
|
|
|
|
|
self.gid
|
|
|
|
|
}
|
2020-06-15 21:39:34 -07:00
|
|
|
#[allow(dead_code)]
|
|
|
|
|
pub fn get_groups(&self) -> Option<&[gid_t]> {
|
|
|
|
|
self.groups.as_deref()
|
|
|
|
|
}
|
2016-11-23 13:58:13 -08:00
|
|
|
|
2018-07-10 20:52:29 +02:00
|
|
|
pub fn get_closures(&mut self) -> &mut Vec<Box<dyn FnMut() -> io::Result<()> + Send + Sync>> {
|
2016-11-23 13:58:13 -08:00
|
|
|
&mut self.closures
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-27 10:28:39 -08:00
|
|
|
pub unsafe fn pre_exec(&mut self, f: Box<dyn FnMut() -> io::Result<()> + Send + Sync>) {
|
2016-11-23 13:58:13 -08:00
|
|
|
self.closures.push(f);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
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
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn capture_env(&mut self) -> Option<CStringArray> {
|
|
|
|
|
let maybe_env = self.env.capture_if_changed();
|
|
|
|
|
maybe_env.map(|env| construct_envp(env, &mut self.saw_nul))
|
|
|
|
|
}
|
2020-10-02 07:44:32 -07:00
|
|
|
|
2018-03-22 09:49:20 -07:00
|
|
|
#[allow(dead_code)]
|
2018-03-19 15:40:09 -07:00
|
|
|
pub fn env_saw_path(&self) -> bool {
|
|
|
|
|
self.env.have_changed_path()
|
|
|
|
|
}
|
2017-12-17 15:21:47 +00:00
|
|
|
|
2020-10-02 07:44:32 -07:00
|
|
|
#[allow(dead_code)]
|
|
|
|
|
pub fn program_is_path(&self) -> bool {
|
|
|
|
|
self.program.to_bytes().contains(&b'/')
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-27 10:28:39 -08:00
|
|
|
pub fn setup_io(
|
|
|
|
|
&self,
|
|
|
|
|
default: Stdio,
|
|
|
|
|
needs_stdin: bool,
|
|
|
|
|
) -> io::Result<(StdioPipes, ChildPipes)> {
|
2016-11-23 13:58:13 -08:00
|
|
|
let null = Stdio::Null;
|
2019-11-27 10:28:39 -08:00
|
|
|
let default_stdin = if needs_stdin { &default } else { &null };
|
2016-11-23 13:58:13 -08:00
|
|
|
let stdin = self.stdin.as_ref().unwrap_or(default_stdin);
|
|
|
|
|
let stdout = self.stdout.as_ref().unwrap_or(&default);
|
|
|
|
|
let stderr = self.stderr.as_ref().unwrap_or(&default);
|
|
|
|
|
let (their_stdin, our_stdin) = stdin.to_child_stdio(true)?;
|
|
|
|
|
let (their_stdout, our_stdout) = stdout.to_child_stdio(false)?;
|
|
|
|
|
let (their_stderr, our_stderr) = stderr.to_child_stdio(false)?;
|
2019-11-27 10:28:39 -08:00
|
|
|
let ours = StdioPipes { stdin: our_stdin, stdout: our_stdout, stderr: our_stderr };
|
|
|
|
|
let theirs = ChildPipes { stdin: their_stdin, stdout: their_stdout, stderr: their_stderr };
|
2016-11-23 13:58:13 -08:00
|
|
|
Ok((ours, theirs))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn os2c(s: &OsStr, saw_nul: &mut bool) -> CString {
|
|
|
|
|
CString::new(s.as_bytes()).unwrap_or_else(|_e| {
|
|
|
|
|
*saw_nul = true;
|
|
|
|
|
CString::new("<string-with-nul>").unwrap()
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
2017-12-17 15:21:47 +00:00
|
|
|
// Helper type to manage ownership of the strings within a C-style array.
|
|
|
|
|
pub struct CStringArray {
|
|
|
|
|
items: Vec<CString>,
|
2019-11-27 10:28:39 -08:00
|
|
|
ptrs: Vec<*const c_char>,
|
2017-12-17 15:21:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl CStringArray {
|
|
|
|
|
pub fn with_capacity(capacity: usize) -> Self {
|
|
|
|
|
let mut result = CStringArray {
|
|
|
|
|
items: Vec::with_capacity(capacity),
|
2019-11-27 10:28:39 -08:00
|
|
|
ptrs: Vec::with_capacity(capacity + 1),
|
2017-12-17 15:21:47 +00:00
|
|
|
};
|
|
|
|
|
result.ptrs.push(ptr::null());
|
|
|
|
|
result
|
|
|
|
|
}
|
|
|
|
|
pub fn push(&mut self, item: CString) {
|
|
|
|
|
let l = self.ptrs.len();
|
2019-11-27 10:28:39 -08:00
|
|
|
self.ptrs[l - 1] = item.as_ptr();
|
2017-12-17 15:21:47 +00:00
|
|
|
self.ptrs.push(ptr::null());
|
|
|
|
|
self.items.push(item);
|
|
|
|
|
}
|
|
|
|
|
pub fn as_ptr(&self) -> *const *const c_char {
|
|
|
|
|
self.ptrs.as_ptr()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-03 19:32:44 -07:00
|
|
|
fn construct_envp(env: BTreeMap<OsString, OsString>, saw_nul: &mut bool) -> CStringArray {
|
2017-12-17 15:21:47 +00:00
|
|
|
let mut result = CStringArray::with_capacity(env.len());
|
2020-02-25 18:10:34 +01:00
|
|
|
for (mut k, v) in env {
|
2017-12-17 15:21:47 +00:00
|
|
|
// Reserve additional space for '=' and null terminator
|
|
|
|
|
k.reserve_exact(v.len() + 2);
|
|
|
|
|
k.push("=");
|
|
|
|
|
k.push(&v);
|
|
|
|
|
|
|
|
|
|
// Add the new entry into the array
|
|
|
|
|
if let Ok(item) = CString::new(k.into_vec()) {
|
|
|
|
|
result.push(item);
|
|
|
|
|
} else {
|
|
|
|
|
*saw_nul = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
result
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-23 13:58:13 -08:00
|
|
|
impl Stdio {
|
2019-11-27 10:28:39 -08:00
|
|
|
pub fn to_child_stdio(&self, readable: bool) -> io::Result<(ChildStdio, Option<AnonPipe>)> {
|
2016-11-23 13:58:13 -08:00
|
|
|
match *self {
|
2019-11-27 10:28:39 -08:00
|
|
|
Stdio::Inherit => Ok((ChildStdio::Inherit, None)),
|
2016-11-23 13:58:13 -08:00
|
|
|
|
|
|
|
|
// Make sure that the source descriptors are not an stdio
|
|
|
|
|
// descriptor, otherwise the order which we set the child's
|
|
|
|
|
// descriptors may blow away a descriptor which we are hoping to
|
|
|
|
|
// save. For example, suppose we want the child's stderr to be the
|
|
|
|
|
// parent's stdout, and the child's stdout to be the parent's
|
|
|
|
|
// stderr. No matter which we dup first, the second will get
|
|
|
|
|
// overwritten prematurely.
|
|
|
|
|
Stdio::Fd(ref fd) => {
|
2021-06-30 21:44:30 -07:00
|
|
|
if fd.as_raw_fd() >= 0 && fd.as_raw_fd() <= libc::STDERR_FILENO {
|
2016-11-23 13:58:13 -08:00
|
|
|
Ok((ChildStdio::Owned(fd.duplicate()?), None))
|
|
|
|
|
} else {
|
2021-06-30 21:44:30 -07:00
|
|
|
Ok((ChildStdio::Explicit(fd.as_raw_fd()), None))
|
2016-11-23 13:58:13 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Stdio::MakePipe => {
|
|
|
|
|
let (reader, writer) = pipe::anon_pipe()?;
|
2019-11-27 10:28:39 -08:00
|
|
|
let (ours, theirs) = if readable { (writer, reader) } else { (reader, writer) };
|
2021-06-30 21:44:30 -07:00
|
|
|
Ok((ChildStdio::Owned(theirs.into_inner()), Some(ours)))
|
2016-11-23 13:58:13 -08:00
|
|
|
}
|
|
|
|
|
|
2019-08-30 11:51:04 -07:00
|
|
|
#[cfg(not(target_os = "fuchsia"))]
|
2016-11-23 13:58:13 -08:00
|
|
|
Stdio::Null => {
|
|
|
|
|
let mut opts = OpenOptions::new();
|
|
|
|
|
opts.read(readable);
|
|
|
|
|
opts.write(!readable);
|
2019-11-27 10:28:39 -08:00
|
|
|
let path = unsafe { CStr::from_ptr(DEV_NULL.as_ptr() as *const _) };
|
2016-11-23 13:58:13 -08:00
|
|
|
let fd = File::open_c(&path, &opts)?;
|
2021-06-30 21:44:30 -07:00
|
|
|
Ok((ChildStdio::Owned(fd.into_inner()), None))
|
2016-11-23 13:58:13 -08:00
|
|
|
}
|
2019-08-30 11:51:04 -07:00
|
|
|
|
|
|
|
|
#[cfg(target_os = "fuchsia")]
|
2019-11-27 10:28:39 -08:00
|
|
|
Stdio::Null => Ok((ChildStdio::Null, None)),
|
2016-11-23 13:58:13 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-06-06 15:42:55 -07:00
|
|
|
impl From<AnonPipe> for Stdio {
|
|
|
|
|
fn from(pipe: AnonPipe) -> Stdio {
|
2021-06-30 21:44:30 -07:00
|
|
|
Stdio::Fd(pipe.into_inner())
|
2017-06-06 15:42:55 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl From<File> for Stdio {
|
|
|
|
|
fn from(file: File) -> Stdio {
|
2021-06-30 21:44:30 -07:00
|
|
|
Stdio::Fd(file.into_inner())
|
2017-06-06 15:42:55 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-23 13:58:13 -08:00
|
|
|
impl ChildStdio {
|
|
|
|
|
pub fn fd(&self) -> Option<c_int> {
|
|
|
|
|
match *self {
|
|
|
|
|
ChildStdio::Inherit => None,
|
|
|
|
|
ChildStdio::Explicit(fd) => Some(fd),
|
2021-06-30 21:44:30 -07:00
|
|
|
ChildStdio::Owned(ref fd) => Some(fd.as_raw_fd()),
|
2019-08-30 11:51:04 -07:00
|
|
|
|
|
|
|
|
#[cfg(target_os = "fuchsia")]
|
|
|
|
|
ChildStdio::Null => None,
|
2016-11-23 13:58:13 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl fmt::Debug for Command {
|
2019-03-01 09:34:11 +01:00
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
2019-12-10 23:32:52 -08:00
|
|
|
if self.program != self.args[0] {
|
|
|
|
|
write!(f, "[{:?}] ", self.program)?;
|
|
|
|
|
}
|
|
|
|
|
write!(f, "{:?}", self.args[0])?;
|
|
|
|
|
|
|
|
|
|
for arg in &self.args[1..] {
|
2016-11-23 13:58:13 -08:00
|
|
|
write!(f, " {:?}", arg)?;
|
|
|
|
|
}
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-03 18:29:30 -08:00
|
|
|
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
|
|
|
|
|
pub struct ExitCode(u8);
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-09-21 11:32:06 -07:00
|
|
|
|
|
|
|
|
pub struct CommandArgs<'a> {
|
|
|
|
|
iter: crate::slice::Iter<'a, CString>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<'a> Iterator for CommandArgs<'a> {
|
|
|
|
|
type Item = &'a OsStr;
|
|
|
|
|
fn next(&mut self) -> Option<&'a OsStr> {
|
|
|
|
|
self.iter.next().map(|cs| OsStr::from_bytes(cs.as_bytes()))
|
|
|
|
|
}
|
|
|
|
|
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()
|
|
|
|
|
}
|
|
|
|
|
}
|