Rollup merge of #66512 - jsgf:process-argv0, r=Dylan-DPC
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? I'm assuming so. Addresses: #66510
This commit is contained in:
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#![stable(feature = "rust1", since = "1.0.0")]
|
#![stable(feature = "rust1", since = "1.0.0")]
|
||||||
|
|
||||||
|
use crate::ffi::OsStr;
|
||||||
use crate::io;
|
use crate::io;
|
||||||
use crate::os::unix::io::{FromRawFd, RawFd, AsRawFd, IntoRawFd};
|
use crate::os::unix::io::{FromRawFd, RawFd, AsRawFd, IntoRawFd};
|
||||||
use crate::process;
|
use crate::process;
|
||||||
@@ -103,6 +104,14 @@ pub trait CommandExt {
|
|||||||
/// cross-platform `spawn` instead.
|
/// cross-platform `spawn` instead.
|
||||||
#[stable(feature = "process_exec2", since = "1.9.0")]
|
#[stable(feature = "process_exec2", since = "1.9.0")]
|
||||||
fn exec(&mut self) -> io::Error;
|
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")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
@@ -127,6 +136,13 @@ impl CommandExt for process::Command {
|
|||||||
fn exec(&mut self) -> io::Error {
|
fn exec(&mut self) -> io::Error {
|
||||||
self.as_inner_mut().exec(sys::process::Stdio::Inherit)
|
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`].
|
/// Unix-specific extensions to [`process::ExitStatus`].
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use crate::os::unix::prelude::*;
|
use crate::os::unix::prelude::*;
|
||||||
|
|
||||||
use crate::ffi::{OsString, OsStr, CString};
|
use crate::ffi::{OsString, OsStr, CString, CStr};
|
||||||
use crate::fmt;
|
use crate::fmt;
|
||||||
use crate::io;
|
use crate::io;
|
||||||
use crate::ptr;
|
use crate::ptr;
|
||||||
@@ -11,10 +11,7 @@ use crate::sys_common::process::CommandEnv;
|
|||||||
use crate::collections::BTreeMap;
|
use crate::collections::BTreeMap;
|
||||||
|
|
||||||
#[cfg(not(target_os = "fuchsia"))]
|
#[cfg(not(target_os = "fuchsia"))]
|
||||||
use {
|
use crate::sys::fs::OpenOptions;
|
||||||
crate::ffi::CStr,
|
|
||||||
crate::sys::fs::OpenOptions,
|
|
||||||
};
|
|
||||||
|
|
||||||
use libc::{c_int, gid_t, uid_t, c_char, EXIT_SUCCESS, EXIT_FAILURE};
|
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);
|
let program = os2c(program, &mut saw_nul);
|
||||||
Command {
|
Command {
|
||||||
argv: Argv(vec![program.as_ptr(), ptr::null()]),
|
argv: Argv(vec![program.as_ptr(), ptr::null()]),
|
||||||
|
args: vec![program.clone()],
|
||||||
program,
|
program,
|
||||||
args: Vec::new(),
|
|
||||||
env: Default::default(),
|
env: Default::default(),
|
||||||
cwd: None,
|
cwd: None,
|
||||||
uid: 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) {
|
pub fn arg(&mut self, arg: &OsStr) {
|
||||||
// Overwrite the trailing NULL pointer in `argv` and then add a new null
|
// Overwrite the trailing NULL pointer in `argv` and then add a new null
|
||||||
// pointer.
|
// pointer.
|
||||||
let arg = os2c(arg, &mut self.saw_nul);
|
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());
|
self.argv.0.push(ptr::null());
|
||||||
|
|
||||||
// Also make sure we keep track of the owned value to schedule a
|
// Also make sure we keep track of the owned value to schedule a
|
||||||
@@ -178,6 +183,10 @@ impl Command {
|
|||||||
&self.argv.0
|
&self.argv.0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_program(&self) -> &CStr {
|
||||||
|
&*self.program
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn get_cwd(&self) -> &Option<CString> {
|
pub fn get_cwd(&self) -> &Option<CString> {
|
||||||
&self.cwd
|
&self.cwd
|
||||||
|
|||||||
@@ -110,7 +110,7 @@ impl Command {
|
|||||||
ZX_HANDLE_INVALID,
|
ZX_HANDLE_INVALID,
|
||||||
FDIO_SPAWN_CLONE_JOB | FDIO_SPAWN_CLONE_LDSVC | FDIO_SPAWN_CLONE_NAMESPACE
|
FDIO_SPAWN_CLONE_JOB | FDIO_SPAWN_CLONE_LDSVC | FDIO_SPAWN_CLONE_NAMESPACE
|
||||||
| FDIO_SPAWN_CLONE_ENVIRON, // this is ignored when envp is non-null
|
| 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(),
|
actions.len() as size_t, actions.as_ptr(),
|
||||||
&mut process_handle,
|
&mut process_handle,
|
||||||
ptr::null_mut(),
|
ptr::null_mut(),
|
||||||
|
|||||||
@@ -248,7 +248,7 @@ impl Command {
|
|||||||
*sys::os::environ() = envp.as_ptr();
|
*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())
|
Err(io::Error::last_os_error())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -373,7 +373,7 @@ impl Command {
|
|||||||
.unwrap_or_else(|| *sys::os::environ() as *const _);
|
.unwrap_or_else(|| *sys::os::environ() as *const _);
|
||||||
let ret = libc::posix_spawnp(
|
let ret = libc::posix_spawnp(
|
||||||
&mut p.pid,
|
&mut p.pid,
|
||||||
self.get_argv()[0],
|
self.get_program().as_ptr(),
|
||||||
file_actions.0.as_ptr(),
|
file_actions.0.as_ptr(),
|
||||||
attrs.0.as_ptr(),
|
attrs.0.as_ptr(),
|
||||||
self.get_argv().as_ptr() as *const _,
|
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");
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user