1#![allow(non_upper_case_globals)]
4#![allow(non_camel_case_types)]
5#![allow(non_snake_case)]
6#![allow(deref_nullptr)]
7#![allow(dead_code)]
8
9mod sys;
10use sys::*;
11
12use std::ffi::CString;
13use std::fmt;
14use std::os::raw::{c_char, c_int};
15use std::os::unix::io::AsRawFd;
16use std::pin::Pin;
17use std::ptr;
18use std::sync::{Arc, Mutex};
19
20#[derive(Debug, Clone, Copy, Eq, PartialEq)]
22pub enum Error {
23 VersionError,
24 InitError,
25 CreateError,
26 ExecError,
27 ArgumentsError,
28 CStringError,
29}
30
31impl fmt::Display for Error {
32 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
33 match self {
34 Error::VersionError => write!(f, "PAL API version mismatch"),
35 Error::InitError => write!(f, "Initialization error"),
36 Error::CreateError => write!(f, "Process creation error"),
37 Error::ExecError => write!(f, "Process execution error"),
38 Error::ArgumentsError => write!(f, "Arguments list error"),
39 Error::CStringError => write!(f, "String contains a bare \\0 character"),
40 }
41 }
42}
43
44impl std::error::Error for Error {}
45
46#[derive(Debug, Copy, Clone, PartialEq, Eq)]
48pub enum LogLevel {
49 Off,
50 Error,
51 Warn,
52 Info,
53 Trace,
54}
55
56impl LogLevel {
57 fn as_bytes(&self) -> &'static [u8] {
58 match *self {
59 LogLevel::Off => b"off",
60 LogLevel::Error => b"error",
61 LogLevel::Warn => b"warn",
62 LogLevel::Info => b"info",
63 LogLevel::Trace => b"trace",
64 }
65 }
66}
67
68#[derive(Debug, Clone, PartialEq, Eq)]
70pub struct Config {
71 instance_dir: CString,
72 log_level: LogLevel,
73}
74
75impl Config {
76 pub fn new(instance_dir: impl ToString) -> Result<Self, Error> {
81 Ok(Self {
82 instance_dir: CString::new(instance_dir.to_string().as_bytes())
83 .map_err(|_| Error::CStringError)?,
84 log_level: LogLevel::Off,
85 })
86 }
87}
88
89impl Default for Config {
90 fn default() -> Self {
91 Config {
92 instance_dir: CString::new(b".".to_vec()).unwrap(),
93 log_level: LogLevel::Off,
94 }
95 }
96}
97
98#[derive(Debug, Clone, PartialEq, Eq)]
99pub struct Stdio {
100 stdin: c_int,
101 stdout: c_int,
102 stderr: c_int,
103}
104
105impl Default for Stdio {
106 fn default() -> Self {
107 Self {
108 stdin: 0,
109 stdout: 1,
110 stderr: 2,
111 }
112 }
113}
114
115impl Stdio {
116 pub fn new(stdin: impl AsRawFd, stdout: impl AsRawFd, stderr: impl AsRawFd) -> Self {
118 Self {
119 stdin: stdin.as_raw_fd() as _,
120 stdout: stdout.as_raw_fd() as _,
121 stderr: stderr.as_raw_fd() as _,
122 }
123 }
124
125 fn to_api(&self) -> Pin<Box<occlum_stdio_fds>> {
126 Box::pin(occlum_stdio_fds {
127 stdin_fd: self.stdin,
128 stdout_fd: self.stdout,
129 stderr_fd: self.stderr,
130 })
131 }
132}
133
134#[derive(Debug, PartialEq, Eq)]
136pub struct ProcessBuilder {
137 path: CString,
138 argv: Vec<CString>,
139 env: Vec<CString>,
140 pid: c_int,
141 stdio: Option<Stdio>,
142}
143
144#[derive(Debug)]
145pub struct CStringsVec {
146 cstrings: Vec<CString>,
147 ptrs: Vec<*const c_char>,
148}
149
150impl CStringsVec {
151 fn new(cstrings: Vec<CString>) -> Result<Self, Error> {
152 let mut ptrs = Vec::with_capacity(cstrings.len() + 1);
153 for cstring in &cstrings {
154 ptrs.push(cstring.as_ptr());
155 }
156 ptrs.push(ptr::null());
157 Ok(Self { cstrings, ptrs })
158 }
159
160 fn as_mut_ptr(&mut self) -> *mut *const c_char {
161 self.ptrs.as_mut_ptr()
162 }
163}
164
165#[derive(Debug)]
166struct ProcessApiConcrete {
167 path: CString,
168 argv_cstrings_vec: CStringsVec,
169 env_cstrings_vec: CStringsVec,
170 stdio_api: Pin<Box<occlum_stdio_fds>>,
171 pid: Pin<Box<c_int>>,
172}
173
174#[derive(Debug)]
175struct ProcessApi {
176 concrete: ProcessApiConcrete,
177 ptrs: Pin<Box<occlum_pal_create_process_args>>,
178}
179
180#[derive(Debug)]
182pub struct Process {
183 enclave: Arc<Mutex<Enclave>>,
184 process_api: ProcessApi,
185}
186
187impl Process {
188 pub fn process_id(&self) -> ProcessId {
190 ProcessId {
191 pid: unsafe { *self.process_api.ptrs.pid },
192 }
193 }
194
195 pub fn exec(&self) -> Result<ExitCode, Error> {
197 let mut exit_code: c_int = -1;
198 let mut exec_args = Box::pin(occlum_pal_exec_args {
199 pid: self.process_id().pid,
200 exit_value: &mut exit_code,
201 });
202 let exec_result = unsafe { occlum_pal_exec(&mut *exec_args) };
203 if exec_result == 0 {
204 Ok(exit_code)
205 } else {
206 Err(Error::CreateError)
207 }
208 }
209}
210
211#[derive(Debug, Clone, PartialEq, Eq, Hash)]
213pub struct ProcessId {
214 pid: c_int,
215}
216
217impl ProcessId {
218 pub fn kill(self) -> Result<(), Error> {
220 let result = unsafe { occlum_pal_kill(self.pid, 9) };
221 if result == 0 {
222 Ok(())
223 } else {
224 Err(Error::ExecError)
225 }
226 }
227
228 pub fn terminate(self) -> Result<(), Error> {
230 let result = unsafe { occlum_pal_kill(self.pid, 16) };
231 if result == 0 {
232 Ok(())
233 } else {
234 Err(Error::ExecError)
235 }
236 }
237}
238
239pub type ExitCode = c_int;
240
241impl ProcessBuilder {
242 pub fn new(
248 path: impl ToString,
249 argv: Option<&[String]>,
250 env: Option<&[String]>,
251 stdio: Option<Stdio>,
252 ) -> Result<Self, Error> where {
253 let path = CString::new(path.to_string().as_bytes()).map_err(|_| Error::CStringError)?;
254 let argv = match argv {
255 None => vec![path.clone()],
256 Some(argv) => {
257 let mut y = vec![];
258 for x in argv {
259 y.push(CString::new(x.to_string().as_bytes()).map_err(|_| Error::CStringError)?)
260 }
261 y
262 }
263 };
264 if argv.is_empty() {
265 return Err(Error::ArgumentsError);
266 }
267
268 let env = env.unwrap_or(&[]);
269 let env = {
270 let mut y = vec![];
271 for x in env {
272 y.push(CString::new(x.to_string().as_bytes()).map_err(|_| Error::CStringError)?)
273 }
274 y
275 };
276
277 Ok(Self {
278 path,
279 argv,
280 env,
281 pid: -1,
282 stdio,
283 })
284 }
285
286 pub fn build(self, enclave: &Arc<Mutex<Enclave>>) -> Result<Process, Error> {
288 let stdio_api = match self.stdio {
289 None => Stdio::default().to_api(),
290 Some(stdio) => stdio.to_api(),
291 };
292 let mut process_api_concrete = ProcessApiConcrete {
293 path: self.path,
294 argv_cstrings_vec: CStringsVec::new(self.argv)?,
295 env_cstrings_vec: CStringsVec::new(self.env)?,
296 stdio_api,
297 pid: Box::pin(-1),
298 };
299 let mut process_api_ptrs = Box::pin(occlum_pal_create_process_args {
300 path: process_api_concrete.path.as_ptr(),
301 argv: process_api_concrete.argv_cstrings_vec.as_mut_ptr(),
302 env: process_api_concrete.env_cstrings_vec.as_mut_ptr(),
303 stdio: &*process_api_concrete.stdio_api,
304 pid: &mut *process_api_concrete.pid,
305 });
306 if unsafe { occlum_pal_create_process(&mut *process_api_ptrs) } != 0 {
307 return Err(Error::CreateError);
308 }
309 Ok(Process {
310 enclave: enclave.clone(),
311 process_api: ProcessApi {
312 concrete: process_api_concrete,
313 ptrs: process_api_ptrs,
314 },
315 })
316 }
317}
318
319#[derive(Debug)]
320struct ConfigApiConcrete {
321 instance_dir: CString,
322 log_level: CString,
323}
324
325#[derive(Debug)]
326struct ConfigApi {
327 concrete: ConfigApiConcrete,
328 ptrs: Pin<Box<occlum_pal_attr>>,
329}
330
331#[derive(Debug)]
333pub struct Enclave {
334 config: Config,
335 config_api: ConfigApi,
336}
337
338impl Enclave {
339 pub fn new(config: Config) -> Result<Arc<Mutex<Self>>, Error> {
341 if (unsafe { occlum_pal_get_version() } <= 0) {
342 return Err(Error::VersionError);
343 }
344
345 let config_api_concrete = ConfigApiConcrete {
346 instance_dir: CString::new(config.instance_dir.as_bytes())
347 .map_err(|_| Error::CStringError)?,
348 log_level: CString::new(config.log_level.as_bytes())
349 .map_err(|_| Error::CStringError)?,
350 };
351 let config_api_ptrs = Box::pin(occlum_pal_attr {
352 instance_dir: config_api_concrete.instance_dir.as_ptr() as *const c_char,
353 log_level: config_api_concrete.log_level.as_bytes().as_ptr() as *const c_char,
354 });
355 if unsafe { occlum_pal_init(&*config_api_ptrs) } != 0 {
356 return Err(Error::InitError);
357 }
358 Ok(Arc::new(Mutex::new(Enclave {
359 config,
360 config_api: ConfigApi {
361 concrete: config_api_concrete,
362 ptrs: config_api_ptrs,
363 },
364 })))
365 }
366
367 fn destroy(&mut self) {
368 unsafe {
369 occlum_pal_destroy();
370 }
371 }
372}
373
374impl Drop for Enclave {
375 fn drop(&mut self) {
376 self.destroy();
377 }
378}