userland_execve/
exec.rs

1use std::{
2    ffi::{CStr, CString},
3    iter::once,
4    os::unix::prelude::OsStrExt,
5    path::{Path, PathBuf},
6};
7
8fn path_to_c_string(path: &Path) -> CString {
9    CString::from_vec_with_nul(
10        path.as_os_str()
11            .as_bytes()
12            .iter()
13            .copied()
14            .chain(once(0))
15            .collect(),
16    )
17    .unwrap()
18}
19
20pub fn exec_with_options(options: ExecOptions) -> ! {
21    let (bin_addr, bin_header, opt_interp) =
22        crate::loader::load(&options.executable, options.interpreter);
23    let path = path_to_c_string(&options.executable);
24    let interp_addr = opt_interp.map(|(addr, _)| addr);
25    let sp = crate::stack::make_stack(
26        interp_addr,
27        bin_addr,
28        bin_header,
29        &path,
30        &options.args,
31        &options.env,
32    );
33    let entry = match opt_interp {
34        Some((interp_addr, interp_header)) => {
35            let interp_entry: usize = interp_header.e_entry.try_into().unwrap();
36            interp_addr + interp_entry
37        }
38        None => {
39            let bin_entry: usize = bin_header.e_entry.try_into().unwrap();
40            bin_addr + bin_entry
41        }
42    };
43    unsafe { crate::run::run(sp, entry) }
44}
45
46pub fn exec(path: &Path, args: &[impl AsRef<CStr>], env: &[impl AsRef<CStr>]) -> ! {
47    let mut options = ExecOptions::new(path);
48    options.args(args);
49    options.env_pairs(env);
50
51    exec_with_options(options)
52}
53
54pub struct ExecOptions {
55    pub executable: PathBuf,
56    pub args: Vec<CString>,
57    pub env: Vec<CString>,
58    interpreter: crate::loader::Interpreter,
59}
60
61impl ExecOptions {
62    pub fn new(executable: impl AsRef<Path>) -> Self {
63        Self {
64            executable: executable.as_ref().to_owned(),
65            args: vec![],
66            env: vec![],
67            interpreter: crate::loader::Interpreter::FromHeader,
68        }
69    }
70
71    pub fn arg(&mut self, value: impl AsRef<CStr>) -> &mut Self {
72        self.args.push(value.as_ref().to_owned());
73        self
74    }
75
76    pub fn args(&mut self, values: impl IntoIterator<Item = impl AsRef<CStr>>) -> &mut Self {
77        self.args
78            .extend(values.into_iter().map(|v| v.as_ref().to_owned()));
79        self
80    }
81
82    pub fn env(&mut self, key: impl AsRef<CStr>, value: impl AsRef<CStr>) -> &mut Self {
83        let mut pair = key.as_ref().to_bytes().to_vec();
84        pair.push(b'=');
85        pair.extend(value.as_ref().to_bytes());
86        self.env.push(CString::new(pair).unwrap());
87        self
88    }
89
90    pub fn env_pairs(&mut self, pairs: impl IntoIterator<Item = impl AsRef<CStr>>) -> &mut Self {
91        self.env
92            .extend(pairs.into_iter().map(|v| v.as_ref().to_owned()));
93        self
94    }
95
96    pub fn envs(
97        &mut self,
98        pairs: impl IntoIterator<Item = (impl AsRef<CStr>, impl AsRef<CStr>)>,
99    ) -> &mut Self {
100        for (key, value) in pairs {
101            self.env(key, value);
102        }
103        self
104    }
105
106    pub fn override_interpreter(&mut self, interpreter: Option<impl AsRef<Path>>) -> &mut Self {
107        self.interpreter = match interpreter {
108            Some(path) => crate::loader::Interpreter::Path(path.as_ref().to_owned()),
109            None => crate::loader::Interpreter::None,
110        };
111        self
112    }
113}