use std::{
collections::VecDeque,
os::unix::process::CommandExt,
process::{Command, ExitCode, Stdio},
};
use nix::{
errno::Errno,
fcntl::{open, OFlag},
libc::pid_t,
sys::stat::Mode,
unistd::Pid,
};
use syd::{
eprintfln, path::XPathBuf, printf, printfln, proc::util::proc_environ_read, syslog::LogLevel,
};
#[cfg(all(
not(target_os = "android"),
not(target_arch = "loongarch64"),
not(target_arch = "riscv64"),
target_page_size_4k,
target_pointer_width = "64"
))]
#[global_allocator]
static GLOBAL: hardened_malloc::HardenedMalloc = hardened_malloc::HardenedMalloc;
syd::main! {
syd::set_sigpipe_dfl()?;
syd::log::log_init_simple(LogLevel::Warn)?;
let mut args: VecDeque<_> = std::env::args().skip(1).collect();
let pid = match args.pop_front().as_deref() {
None | Some("-h") => {
help()?;
return Ok(ExitCode::SUCCESS);
}
Some("-e") => {
let _var = if let Some(var) = args.pop_front() {
var
} else {
eprintfln!("Error: -e requires an argument!")?;
return Ok(ExitCode::FAILURE);
};
#[cfg(target_os = "android")]
{
eprintfln!("Error: -e is not supported on Android!")?;
return Ok(ExitCode::FAILURE);
}
#[cfg(not(target_os = "android"))]
match syd::wordexp::WordExp::expand(&_var, true, dur::Duration::from_secs(3)) {
Ok(val) => {
printf!("{val}")?;
return Ok(ExitCode::SUCCESS);
}
Err(err) => {
eprintfln!("Error: {err}")?;
std::process::exit(err.into());
}
};
}
Some(pid) => match pid.parse::<pid_t>().map(Pid::from_raw) {
Ok(pid) => pid,
Err(error) => {
eprintfln!("Invalid PID: {error}")?;
return Ok(ExitCode::FAILURE);
}
},
};
let mut pfd = XPathBuf::try_from("/proc")?;
pfd.try_push_pid(pid)?;
pfd.try_push(b"environ")?;
#[expect(clippy::disallowed_methods)]
let pfd = open(&pfd, OFlag::O_RDONLY, Mode::empty())?.into();
let environ = match proc_environ_read(pfd) {
Ok(environ) => environ,
Err(error) => {
eprintfln!("syd-env: {error}")?;
return Ok(ExitCode::FAILURE);
}
};
let error = Command::new("env")
.args(args)
.env_clear()
.envs(&environ)
.stdin(Stdio::inherit())
.stdout(Stdio::inherit())
.stderr(Stdio::inherit())
.exec();
eprintfln!("syd-env: {error}")?;
Ok(ExitCode::FAILURE)
}
fn help() -> Result<(), Errno> {
printfln!("Usage: syd-env pid [-i] [name=value]... {{command [arg...]}}")?;
printfln!("Run a command with the environment of the process with the given PID.")?;
Ok(())
}