parent
bb93578b88
commit
6d1c9ff2dc
3 changed files with 60 additions and 12 deletions
|
@ -21,7 +21,7 @@ clap = { version = "4.5.39", default-features = false, features = [
|
|||
"derive",
|
||||
] }
|
||||
log = { version = "0.4.27", default-features = false, features = ["std"] }
|
||||
nix = { version = "0.30.1", default-features = false, features = ["process"] }
|
||||
nix = { version = "0.30.1", default-features = false }
|
||||
serde = { version = "1.0.219", default-features = false, features = [
|
||||
"derive",
|
||||
"std",
|
||||
|
|
|
@ -9,6 +9,6 @@ anyhow = { workspace = true }
|
|||
clap = { workspace = true }
|
||||
common = { path = "../../lib/common" }
|
||||
log = { workspace = true }
|
||||
nix = { workspace = true }
|
||||
nix = { workspace = true, features = ["env", "process"] }
|
||||
serde = { workspace = true }
|
||||
hakari = { version = "0.1", path = "../../lib/hakari" }
|
||||
|
|
|
@ -1,4 +1,8 @@
|
|||
use std::{collections::BTreeSet, ffi::CString};
|
||||
use std::{
|
||||
collections::BTreeSet,
|
||||
convert::Infallible,
|
||||
ffi::{CStr, CString, OsStr, OsString},
|
||||
};
|
||||
|
||||
use anyhow::Context as _;
|
||||
use clap::{Parser, Subcommand};
|
||||
|
@ -195,18 +199,13 @@ fn wrap_program(wrap_program: WrapProgram) -> anyhow::Result<()> {
|
|||
return Err(anyhow::format_err!("No command to execute was specified"));
|
||||
}
|
||||
let unique: BTreeSet<_> = BTreeSet::from_iter(endpoint);
|
||||
let mut env = Vec::<CString>::new();
|
||||
let mut env = Vec::<(OsString, OsString)>::new();
|
||||
for (key, value) in std::env::vars() {
|
||||
env.push(
|
||||
CString::new(format!("{key}={value}"))
|
||||
.with_context(|| format!("Environment variable {key} contained a null byte"))?,
|
||||
);
|
||||
env.push((OsString::from(key), OsString::from(value)));
|
||||
}
|
||||
for env_set in unique {
|
||||
for (key, value) in env_set.try_into_env_data()? {
|
||||
env.push(CString::new(format!("{key}={value}")).with_context(|| {
|
||||
format!("Environment variable {key} contained a null byte")
|
||||
})?);
|
||||
env.push((OsString::from(key), OsString::from(value)));
|
||||
}
|
||||
}
|
||||
let mut args = Vec::new();
|
||||
|
@ -217,7 +216,56 @@ fn wrap_program(wrap_program: WrapProgram) -> anyhow::Result<()> {
|
|||
}
|
||||
(args, env)
|
||||
};
|
||||
nix::unistd::execvpe(&args[0], args.as_slice(), env.as_slice())?;
|
||||
unsafe {
|
||||
execvpe(&args[0], args.as_slice(), env.as_slice())?;
|
||||
}
|
||||
// This will never get executed
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
/// Safety: No other threads may read or write environment variables when this function is called.
|
||||
/// The easiest way to ensure this is using a single threaded program.
|
||||
/// Note: On Linux specifically this safety requirement is not needed
|
||||
unsafe fn execvpe<SA: AsRef<CStr>, SEK: AsRef<OsStr>, SEV: AsRef<OsStr>>(
|
||||
filename: &CStr,
|
||||
args: &[SA],
|
||||
environ: &[(SEK, SEV)],
|
||||
) -> anyhow::Result<Infallible> {
|
||||
let environ: Vec<_> = environ
|
||||
.iter()
|
||||
.map(|(k, v)| {
|
||||
CString::new(Format!("{k}={v}"))
|
||||
.with_context(|| format!("Environment variable {k} contains null bytes"))?
|
||||
})
|
||||
.collect();
|
||||
Ok(nix::unistd::execvpe(filename, args, &environ)?)
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
/// Safety: No other threads may read or write environment variables when this function is called.
|
||||
/// The easiest way to ensure this is using a single threaded program.
|
||||
// Simple "bad" version of execvpe that also works on OSX
|
||||
unsafe fn execvpe<SA: AsRef<CStr>, SEK: AsRef<OsStr>, SEV: AsRef<OsStr>>(
|
||||
filename: &CStr,
|
||||
args: &[SA],
|
||||
environ: &[(SEK, SEV)],
|
||||
) -> anyhow::Result<Infallible> {
|
||||
let current_env = std::env::vars_os();
|
||||
// Safety: Same as this function
|
||||
unsafe { nix::env::clearenv()? };
|
||||
for (key, val) in environ {
|
||||
// Safety: Same as this function
|
||||
unsafe { std::env::set_var(key.as_ref(), val.as_ref()) };
|
||||
}
|
||||
match nix::unistd::execvp(filename, args) {
|
||||
Err(err) => {
|
||||
unsafe { nix::env::clearenv()? };
|
||||
for (key, val) in current_env {
|
||||
unsafe { std::env::set_var(key.as_os_str(), val.as_os_str()) };
|
||||
}
|
||||
Err(err.into())
|
||||
}
|
||||
_ => unreachable!("execvp doesn't return on success"),
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue