use std::{
ffi::{CStr, CString},
iter::once,
os::unix::prelude::OsStrExt,
path::Path,
};
use crate::loader::{Executable, Interpreter};
fn path_to_c_string(path: &Path) -> CString {
CString::from_vec_with_nul(
path.as_os_str()
.as_bytes()
.iter()
.copied()
.chain(once(0))
.collect(),
)
.unwrap()
}
pub fn exec_with_options(options: ExecOptions) -> ! {
let (bin_addr, bin_header, opt_interp) =
crate::loader::load(options.executable.clone(), options.interpreter);
let path = match options.executable {
Executable::Path(path) => path,
Executable::Bytes { data: _, fake_path } => fake_path,
};
let path = path_to_c_string(&path);
let interp_addr = opt_interp.map(|(addr, _)| addr);
let sp = crate::stack::make_stack(
interp_addr,
bin_addr,
bin_header,
&path,
&options.args,
&options.env,
);
let entry = match opt_interp {
Some((interp_addr, interp_header)) => {
let interp_entry: usize = interp_header.e_entry.try_into().unwrap();
interp_addr + interp_entry
}
None => {
let bin_entry: usize = bin_header.e_entry.try_into().unwrap();
bin_addr + bin_entry
}
};
unsafe { crate::run::run(sp, entry) }
}
pub fn exec(path: &Path, args: &[impl AsRef<CStr>], env: &[impl AsRef<CStr>]) -> ! {
let mut options = ExecOptions::from_path(path);
options.args(args);
options.env_pairs(env);
exec_with_options(options)
}
pub struct ExecOptions {
pub executable: Executable,
pub args: Vec<CString>,
pub env: Vec<CString>,
interpreter: Interpreter,
}
impl ExecOptions {
pub fn from_path(executable_path: impl AsRef<Path>) -> Self {
Self {
executable: Executable::Path(executable_path.as_ref().to_path_buf()),
args: vec![],
env: vec![],
interpreter: Interpreter::FromHeader,
}
}
pub fn from_bytes(executable_bytes: Vec<u8>, fake_path: impl AsRef<Path>) -> Self {
Self {
executable: Executable::Bytes {
data: executable_bytes,
fake_path: fake_path.as_ref().to_path_buf(),
},
args: vec![],
env: vec![],
interpreter: Interpreter::FromHeader,
}
}
pub fn arg(&mut self, value: impl AsRef<CStr>) -> &mut Self {
self.args.push(value.as_ref().to_owned());
self
}
pub fn args(&mut self, values: impl IntoIterator<Item = impl AsRef<CStr>>) -> &mut Self {
self.args
.extend(values.into_iter().map(|v| v.as_ref().to_owned()));
self
}
pub fn env(&mut self, key: impl AsRef<CStr>, value: impl AsRef<CStr>) -> &mut Self {
let mut pair = key.as_ref().to_bytes().to_vec();
pair.push(b'=');
pair.extend(value.as_ref().to_bytes());
self.env.push(CString::new(pair).unwrap());
self
}
pub fn env_pairs(&mut self, pairs: impl IntoIterator<Item = impl AsRef<CStr>>) -> &mut Self {
self.env
.extend(pairs.into_iter().map(|v| v.as_ref().to_owned()));
self
}
pub fn envs(
&mut self,
pairs: impl IntoIterator<Item = (impl AsRef<CStr>, impl AsRef<CStr>)>,
) -> &mut Self {
for (key, value) in pairs {
self.env(key, value);
}
self
}
pub fn override_interpreter(&mut self, interpreter: Option<impl AsRef<Path>>) -> &mut Self {
self.interpreter = match interpreter {
Some(path) => Interpreter::Path(path.as_ref().to_owned()),
None => Interpreter::None,
};
self
}
}