mirror of
https://github.com/rust-lang/rust.git
synced 2024-12-04 12:44:40 +00:00
Add unix::process::CommandExt::arg0
This allows argv[0] to be overridden on the executable's command-line. This also makes the program executed independent of argv[0]. Does Fuchsia have the same semantics? Addresses: #66510
This commit is contained in:
parent
361791bb5f
commit
6dee1a5a9f
@ -2,6 +2,7 @@
|
||||
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
|
||||
use crate::ffi::OsStr;
|
||||
use crate::io;
|
||||
use crate::os::unix::io::{FromRawFd, RawFd, AsRawFd, IntoRawFd};
|
||||
use crate::process;
|
||||
@ -103,6 +104,14 @@ pub trait CommandExt {
|
||||
/// cross-platform `spawn` instead.
|
||||
#[stable(feature = "process_exec2", since = "1.9.0")]
|
||||
fn exec(&mut self) -> io::Error;
|
||||
|
||||
/// Set executable argument
|
||||
///
|
||||
/// Set the first process argument, `argv[0]`, to something other than the
|
||||
/// default executable path.
|
||||
#[unstable(feature = "process_set_argv0", issue = "66510")]
|
||||
fn arg0<S>(&mut self, arg: S) -> &mut process::Command
|
||||
where S: AsRef<OsStr>;
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
@ -127,6 +136,13 @@ impl CommandExt for process::Command {
|
||||
fn exec(&mut self) -> io::Error {
|
||||
self.as_inner_mut().exec(sys::process::Stdio::Inherit)
|
||||
}
|
||||
|
||||
fn arg0<S>(&mut self, arg: S) -> &mut process::Command
|
||||
where S: AsRef<OsStr>
|
||||
{
|
||||
self.as_inner_mut().set_arg_0(arg.as_ref());
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// Unix-specific extensions to [`process::ExitStatus`].
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::os::unix::prelude::*;
|
||||
|
||||
use crate::ffi::{OsString, OsStr, CString};
|
||||
use crate::ffi::{OsString, OsStr, CString, CStr};
|
||||
use crate::fmt;
|
||||
use crate::io;
|
||||
use crate::ptr;
|
||||
@ -11,10 +11,7 @@ use crate::sys_common::process::CommandEnv;
|
||||
use crate::collections::BTreeMap;
|
||||
|
||||
#[cfg(not(target_os = "fuchsia"))]
|
||||
use {
|
||||
crate::ffi::CStr,
|
||||
crate::sys::fs::OpenOptions,
|
||||
};
|
||||
use crate::sys::fs::OpenOptions;
|
||||
|
||||
use libc::{c_int, gid_t, uid_t, c_char, EXIT_SUCCESS, EXIT_FAILURE};
|
||||
|
||||
@ -135,8 +132,8 @@ impl Command {
|
||||
let program = os2c(program, &mut saw_nul);
|
||||
Command {
|
||||
argv: Argv(vec![program.as_ptr(), ptr::null()]),
|
||||
args: vec![program.clone()],
|
||||
program,
|
||||
args: Vec::new(),
|
||||
env: Default::default(),
|
||||
cwd: None,
|
||||
uid: None,
|
||||
@ -149,11 +146,19 @@ impl Command {
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
pub fn arg(&mut self, arg: &OsStr) {
|
||||
// Overwrite the trailing NULL pointer in `argv` and then add a new null
|
||||
// pointer.
|
||||
let arg = os2c(arg, &mut self.saw_nul);
|
||||
self.argv.0[self.args.len() + 1] = arg.as_ptr();
|
||||
self.argv.0[self.args.len()] = arg.as_ptr();
|
||||
self.argv.0.push(ptr::null());
|
||||
|
||||
// Also make sure we keep track of the owned value to schedule a
|
||||
@ -178,6 +183,10 @@ impl Command {
|
||||
&self.argv.0
|
||||
}
|
||||
|
||||
pub fn get_program(&self) -> &CStr {
|
||||
&*self.program
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn get_cwd(&self) -> &Option<CString> {
|
||||
&self.cwd
|
||||
|
@ -110,7 +110,7 @@ impl Command {
|
||||
ZX_HANDLE_INVALID,
|
||||
FDIO_SPAWN_CLONE_JOB | FDIO_SPAWN_CLONE_LDSVC | FDIO_SPAWN_CLONE_NAMESPACE
|
||||
| FDIO_SPAWN_CLONE_ENVIRON, // this is ignored when envp is non-null
|
||||
self.get_argv()[0], self.get_argv().as_ptr(), envp,
|
||||
self.get_program().as_ptr(), self.get_argv().as_ptr(), envp,
|
||||
actions.len() as size_t, actions.as_ptr(),
|
||||
&mut process_handle,
|
||||
ptr::null_mut(),
|
||||
|
@ -248,7 +248,7 @@ impl Command {
|
||||
*sys::os::environ() = envp.as_ptr();
|
||||
}
|
||||
|
||||
libc::execvp(self.get_argv()[0], self.get_argv().as_ptr());
|
||||
libc::execvp(self.get_program().as_ptr(), self.get_argv().as_ptr());
|
||||
Err(io::Error::last_os_error())
|
||||
}
|
||||
|
||||
@ -373,7 +373,7 @@ impl Command {
|
||||
.unwrap_or_else(|| *sys::os::environ() as *const _);
|
||||
let ret = libc::posix_spawnp(
|
||||
&mut p.pid,
|
||||
self.get_argv()[0],
|
||||
self.get_program().as_ptr(),
|
||||
file_actions.0.as_ptr(),
|
||||
attrs.0.as_ptr(),
|
||||
self.get_argv().as_ptr() as *const _,
|
||||
|
33
src/test/ui/command-argv0.rs
Normal file
33
src/test/ui/command-argv0.rs
Normal file
@ -0,0 +1,33 @@
|
||||
// run-pass
|
||||
|
||||
// ignore-windows - this is a unix-specific test
|
||||
// ignore-cloudabi no processes
|
||||
// ignore-emscripten no processes
|
||||
// ignore-sgx no processes
|
||||
#![feature(process_set_argv0)]
|
||||
|
||||
use std::env;
|
||||
use std::os::unix::process::CommandExt;
|
||||
use std::process::Command;
|
||||
|
||||
fn main() {
|
||||
let args: Vec<_> = env::args().collect();
|
||||
|
||||
if args.len() > 1 {
|
||||
assert_eq!(args[1], "doing-test");
|
||||
assert_eq!(args[0], "i have a silly name");
|
||||
|
||||
println!("passed");
|
||||
return;
|
||||
}
|
||||
|
||||
let output =
|
||||
Command::new(&args[0]).arg("doing-test").arg0("i have a silly name").output().unwrap();
|
||||
assert!(
|
||||
output.stderr.is_empty(),
|
||||
"Non-empty stderr: {}",
|
||||
String::from_utf8_lossy(&output.stderr)
|
||||
);
|
||||
assert!(output.status.success());
|
||||
assert_eq!(output.stdout, b"passed\n");
|
||||
}
|
Loading…
Reference in New Issue
Block a user