Skip to main content

px_userland_execve/
exec.rs

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