diff --git a/rust/program/infrastructure/src/command/mod.rs b/rust/program/infrastructure/src/command/mod.rs index 8d991bf..eb283f3 100644 --- a/rust/program/infrastructure/src/command/mod.rs +++ b/rust/program/infrastructure/src/command/mod.rs @@ -1,10 +1,7 @@ -#[cfg(target_os = "linux")] -use nix::unistd::execvpe; use std::{ collections::{BTreeMap, BTreeSet}, ffi::{CString, OsString}, }; -#[cfg(target_os = "macos")] use std::{ convert::Infallible, ffi::{CStr, OsStr}, @@ -93,6 +90,34 @@ fn wrap_program(wrap_program: WrapProgram) -> anyhow::Result<()> { 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, SEK: AsRef, SEV: AsRef>( + filename: &CStr, + args: &[SA], + environ: &[(SEK, SEV)], +) -> anyhow::Result { + let environ = environ + .iter() + .map(|(k, v)| { + CString::new(format!( + "{k}={v}", + k = k.as_ref().display(), + v = v.as_ref().display() + )) + .with_context(|| { + format!( + "Environment variable {k} contains null bytes", + k = k.as_ref().display() + ) + }) + }) + .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.