Add the redirection of standard I/O for process
This commit is contained in:
parent
221f5b78e8
commit
e1648fc870
@ -65,7 +65,7 @@ int main(int argc, char* argv[]) {
|
||||
|
||||
// Use Occlum PAL to execute the cmd
|
||||
int exit_status = 0;
|
||||
if (occlum_pal_exec(cmd_path, cmd_args, &exit_status) < 0) {
|
||||
if (occlum_pal_exec(cmd_path, cmd_args, NULL, &exit_status) < 0) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
|
@ -27,7 +27,8 @@ enclave {
|
||||
*/
|
||||
public int occlum_ecall_new_process(
|
||||
[in, string] const char* executable_path,
|
||||
[user_check] const char** argv);
|
||||
[user_check] const char** argv,
|
||||
[in] const struct occlum_stdio_fds* io_fds);
|
||||
|
||||
/*
|
||||
* Execute the LibOS thread specified by the TID.
|
||||
|
@ -10,4 +10,10 @@ struct timeval {
|
||||
suseconds_t tv_usec; /* microseconds */
|
||||
};
|
||||
|
||||
struct occlum_stdio_fds {
|
||||
int stdin_fd;
|
||||
int stdout_fd;
|
||||
int stderr_fd;
|
||||
};
|
||||
|
||||
#endif /* __OCCLUM_EDL_TYPES_H__ */
|
||||
|
@ -1,5 +1,6 @@
|
||||
use super::*;
|
||||
use exception::*;
|
||||
use fs::HostStdioFds;
|
||||
use process::pid_t;
|
||||
use std::ffi::{CStr, CString, OsString};
|
||||
use std::path::{Path, PathBuf};
|
||||
@ -56,13 +57,14 @@ pub extern "C" fn occlum_ecall_init(log_level: *const c_char) -> i32 {
|
||||
pub extern "C" fn occlum_ecall_new_process(
|
||||
path_buf: *const c_char,
|
||||
argv: *const *const c_char,
|
||||
host_stdio_fds: *const HostStdioFds,
|
||||
) -> i32 {
|
||||
if HAS_INIT.load(Ordering::SeqCst) == false {
|
||||
return EXIT_STATUS_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
let (path, args) = match parse_arguments(path_buf, argv) {
|
||||
Ok(path_and_args) => path_and_args,
|
||||
let (path, args, host_stdio_fds) = match parse_arguments(path_buf, argv, host_stdio_fds) {
|
||||
Ok(path_and_args_and_host_stdio_fds) => path_and_args_and_host_stdio_fds,
|
||||
Err(e) => {
|
||||
eprintln!("invalid arguments for LibOS: {}", e.backtrace());
|
||||
return EXIT_STATUS_INTERNAL_ERROR;
|
||||
@ -70,11 +72,13 @@ pub extern "C" fn occlum_ecall_new_process(
|
||||
};
|
||||
let _ = backtrace::enable_backtrace(ENCLAVE_PATH, PrintFormat::Short);
|
||||
panic::catch_unwind(|| {
|
||||
backtrace::__rust_begin_short_backtrace(|| match do_new_process(&path, &args) {
|
||||
Ok(pid_t) => pid_t as i32,
|
||||
Err(e) => {
|
||||
eprintln!("failed to boot up LibOS: {}", e.backtrace());
|
||||
EXIT_STATUS_INTERNAL_ERROR
|
||||
backtrace::__rust_begin_short_backtrace(|| {
|
||||
match do_new_process(&path, &args, &host_stdio_fds) {
|
||||
Ok(pid_t) => pid_t as i32,
|
||||
Err(e) => {
|
||||
eprintln!("failed to boot up LibOS: {}", e.backtrace());
|
||||
EXIT_STATUS_INTERNAL_ERROR
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
@ -135,7 +139,8 @@ fn parse_log_level(level_chars: *const c_char) -> Result<LevelFilter> {
|
||||
fn parse_arguments(
|
||||
path_ptr: *const c_char,
|
||||
argv: *const *const c_char,
|
||||
) -> Result<(PathBuf, Vec<CString>)> {
|
||||
host_stdio_fds: *const HostStdioFds,
|
||||
) -> Result<(PathBuf, Vec<CString>, HostStdioFds)> {
|
||||
let path_buf = {
|
||||
let path_cstring = clone_cstring_safely(path_ptr)?;
|
||||
let path_string = path_cstring
|
||||
@ -155,18 +160,31 @@ fn parse_arguments(
|
||||
|
||||
let mut args = clone_cstrings_safely(argv)?;
|
||||
args.insert(0, program_cstring);
|
||||
Ok((path_buf, args))
|
||||
|
||||
let host_stdio_fds = HostStdioFds::from_user(host_stdio_fds)?;
|
||||
|
||||
Ok((path_buf, args, host_stdio_fds))
|
||||
}
|
||||
|
||||
fn do_new_process(program_path: &PathBuf, argv: &Vec<CString>) -> Result<pid_t> {
|
||||
fn do_new_process(
|
||||
program_path: &PathBuf,
|
||||
argv: &Vec<CString>,
|
||||
host_stdio_fds: &HostStdioFds,
|
||||
) -> Result<pid_t> {
|
||||
validate_program_path(program_path)?;
|
||||
|
||||
let envp = &config::LIBOS_CONFIG.env;
|
||||
let file_actions = Vec::new();
|
||||
let parent = &process::IDLE_PROCESS;
|
||||
let program_path_str = program_path.to_str().unwrap();
|
||||
let new_tid =
|
||||
process::do_spawn_without_exec(&program_path_str, argv, envp, &file_actions, parent)?;
|
||||
let new_tid = process::do_spawn_without_exec(
|
||||
&program_path_str,
|
||||
argv,
|
||||
envp,
|
||||
&file_actions,
|
||||
host_stdio_fds,
|
||||
parent,
|
||||
)?;
|
||||
Ok(new_tid)
|
||||
}
|
||||
|
||||
|
@ -19,7 +19,7 @@ pub use self::file_table::{FileDesc, FileTable};
|
||||
pub use self::inode_file::{AsINodeFile, INodeExt, INodeFile};
|
||||
pub use self::pipe::Pipe;
|
||||
pub use self::rootfs::ROOT_INODE;
|
||||
pub use self::stdio::{StdinFile, StdoutFile};
|
||||
pub use self::stdio::{HostStdioFds, StdinFile, StdoutFile};
|
||||
pub use self::syscalls::*;
|
||||
|
||||
mod dev_fs;
|
||||
|
@ -1,20 +1,114 @@
|
||||
use super::*;
|
||||
use core::cell::RefCell;
|
||||
use core::cmp;
|
||||
use std::io::{BufReader, LineWriter};
|
||||
use std::sync::SgxMutex;
|
||||
|
||||
macro_rules! try_libc_stdio {
|
||||
($ret: expr) => {{
|
||||
let ret = unsafe { $ret };
|
||||
if ret < 0 {
|
||||
let errno_c = unsafe { libc::errno() };
|
||||
Err(errno!(Errno::from(errno_c as u32)))
|
||||
} else {
|
||||
Ok(ret)
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
// Struct for the occlum_stdio_fds
|
||||
#[repr(C)]
|
||||
pub struct HostStdioFds {
|
||||
pub stdin_fd: i32,
|
||||
pub stdout_fd: i32,
|
||||
pub stderr_fd: i32,
|
||||
}
|
||||
|
||||
impl HostStdioFds {
|
||||
pub fn from_user(ptr: *const HostStdioFds) -> Result<Self> {
|
||||
if ptr.is_null() {
|
||||
return Ok(Self {
|
||||
stdin_fd: libc::STDIN_FILENO,
|
||||
stdout_fd: libc::STDOUT_FILENO,
|
||||
stderr_fd: libc::STDERR_FILENO,
|
||||
});
|
||||
}
|
||||
let host_stdio_fds_c = unsafe { &*ptr };
|
||||
if host_stdio_fds_c.stdin_fd < 0
|
||||
|| host_stdio_fds_c.stdout_fd < 0
|
||||
|| host_stdio_fds_c.stderr_fd < 0
|
||||
{
|
||||
return_errno!(EBADF, "invalid file descriptor");
|
||||
}
|
||||
Ok(Self {
|
||||
stdin_fd: host_stdio_fds_c.stdin_fd,
|
||||
stdout_fd: host_stdio_fds_c.stdout_fd,
|
||||
stderr_fd: host_stdio_fds_c.stderr_fd,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
struct StdoutRaw {
|
||||
host_fd: i32,
|
||||
}
|
||||
|
||||
impl StdoutRaw {
|
||||
pub fn new(host_fd: FileDesc) -> Self {
|
||||
Self {
|
||||
host_fd: host_fd as i32,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::io::Write for StdoutRaw {
|
||||
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
|
||||
let writting_len = cmp::min(buf.len(), size_t::max_value() as usize);
|
||||
let ret = try_libc_stdio!(libc::ocall::write(
|
||||
self.host_fd,
|
||||
buf.as_ptr() as *const c_void,
|
||||
writting_len,
|
||||
))
|
||||
.unwrap_or_else(|err| {
|
||||
warn!("tolerate the write error: {:?}", err.errno());
|
||||
writting_len as isize
|
||||
});
|
||||
// sanity check
|
||||
assert!(ret <= writting_len as isize);
|
||||
Ok(ret as usize)
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> std::io::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct StdoutFile {
|
||||
inner: std::io::Stdout,
|
||||
inner: SgxMutex<LineWriter<StdoutRaw>>,
|
||||
host_fd: FileDesc,
|
||||
}
|
||||
|
||||
impl StdoutFile {
|
||||
pub fn new() -> StdoutFile {
|
||||
pub fn new(host_fd: FileDesc) -> Self {
|
||||
StdoutFile {
|
||||
inner: std::io::stdout(),
|
||||
inner: SgxMutex::new(LineWriter::new(StdoutRaw::new(host_fd))),
|
||||
host_fd,
|
||||
}
|
||||
}
|
||||
|
||||
fn get_host_fd(&self) -> FileDesc {
|
||||
self.host_fd
|
||||
}
|
||||
}
|
||||
|
||||
impl File for StdoutFile {
|
||||
fn write(&self, buf: &[u8]) -> Result<usize> {
|
||||
let write_len = { self.inner.lock().write(buf).map_err(|e| errno!(e))? };
|
||||
let write_len = {
|
||||
self.inner
|
||||
.lock()
|
||||
.unwrap()
|
||||
.write(buf)
|
||||
.map_err(|e| errno!(e))?
|
||||
};
|
||||
Ok(write_len)
|
||||
}
|
||||
|
||||
@ -23,7 +117,7 @@ impl File for StdoutFile {
|
||||
}
|
||||
|
||||
fn writev(&self, bufs: &[&[u8]]) -> Result<usize> {
|
||||
let mut guard = self.inner.lock();
|
||||
let mut guard = self.inner.lock().unwrap();
|
||||
let mut total_bytes = 0;
|
||||
for buf in bufs {
|
||||
match guard.write(buf) {
|
||||
@ -70,7 +164,7 @@ impl File for StdoutFile {
|
||||
}
|
||||
|
||||
fn sync_data(&self) -> Result<()> {
|
||||
self.inner.lock().flush()?;
|
||||
self.inner.lock().unwrap().flush()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -86,10 +180,7 @@ impl File for StdoutFile {
|
||||
|
||||
let cmd_bits = cmd.cmd_num() as c_int;
|
||||
let cmd_arg_ptr = cmd.arg_ptr() as *const c_int;
|
||||
let host_stdout_fd = {
|
||||
use std::os::unix::io::AsRawFd;
|
||||
self.inner.as_raw_fd() as i32
|
||||
};
|
||||
let host_stdout_fd = self.get_host_fd() as i32;
|
||||
try_libc!(libc::ocall::ioctl_arg1(
|
||||
host_stdout_fd,
|
||||
cmd_bits,
|
||||
@ -107,33 +198,75 @@ impl File for StdoutFile {
|
||||
|
||||
impl Debug for StdoutFile {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "StdoutFile")
|
||||
write!(f, "StdoutFile with host_fd: {}", self.host_fd)
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Send for StdoutFile {}
|
||||
unsafe impl Sync for StdoutFile {}
|
||||
|
||||
struct StdinRaw {
|
||||
host_fd: i32,
|
||||
}
|
||||
|
||||
impl StdinRaw {
|
||||
pub fn new(host_fd: FileDesc) -> Self {
|
||||
Self {
|
||||
host_fd: host_fd as i32,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::io::Read for StdinRaw {
|
||||
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
|
||||
let reading_len = cmp::min(buf.len(), size_t::max_value() as usize);
|
||||
let ret = try_libc_stdio!(libc::ocall::read(
|
||||
self.host_fd,
|
||||
buf.as_mut_ptr() as *mut c_void,
|
||||
reading_len,
|
||||
))
|
||||
.unwrap_or_else(|err| {
|
||||
warn!("tolerate the read error: {:?}", err.errno());
|
||||
0
|
||||
});
|
||||
// sanity check
|
||||
assert!(ret <= reading_len as isize);
|
||||
Ok(ret as usize)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct StdinFile {
|
||||
inner: std::io::Stdin,
|
||||
inner: SgxMutex<BufReader<StdinRaw>>,
|
||||
host_fd: FileDesc,
|
||||
}
|
||||
|
||||
impl StdinFile {
|
||||
pub fn new() -> StdinFile {
|
||||
pub fn new(host_fd: FileDesc) -> Self {
|
||||
StdinFile {
|
||||
inner: std::io::stdin(),
|
||||
inner: SgxMutex::new(BufReader::new(StdinRaw::new(host_fd))),
|
||||
host_fd,
|
||||
}
|
||||
}
|
||||
|
||||
fn get_host_fd(&self) -> FileDesc {
|
||||
self.host_fd
|
||||
}
|
||||
}
|
||||
|
||||
impl File for StdinFile {
|
||||
fn read(&self, buf: &mut [u8]) -> Result<usize> {
|
||||
let read_len = { self.inner.lock().read(buf).map_err(|e| errno!(e))? };
|
||||
let read_len = {
|
||||
self.inner
|
||||
.lock()
|
||||
.unwrap()
|
||||
.read(buf)
|
||||
.map_err(|e| errno!(e))?
|
||||
};
|
||||
Ok(read_len)
|
||||
}
|
||||
|
||||
fn readv(&self, bufs: &mut [&mut [u8]]) -> Result<usize> {
|
||||
let mut guard = self.inner.lock();
|
||||
let mut guard = self.inner.lock().unwrap();
|
||||
let mut total_bytes = 0;
|
||||
for buf in bufs {
|
||||
match guard.read(buf) {
|
||||
@ -175,6 +308,29 @@ impl File for StdinFile {
|
||||
})
|
||||
}
|
||||
|
||||
fn ioctl(&self, cmd: &mut IoctlCmd) -> Result<()> {
|
||||
let can_delegate_to_host = match cmd {
|
||||
IoctlCmd::TIOCGWINSZ(_) => true,
|
||||
IoctlCmd::TIOCSWINSZ(_) => true,
|
||||
_ => false,
|
||||
};
|
||||
if !can_delegate_to_host {
|
||||
return_errno!(EINVAL, "unknown ioctl cmd for stdin");
|
||||
}
|
||||
|
||||
let cmd_bits = cmd.cmd_num() as c_int;
|
||||
let cmd_arg_ptr = cmd.arg_ptr() as *const c_int;
|
||||
let host_stdin_fd = self.get_host_fd() as i32;
|
||||
try_libc!(libc::ocall::ioctl_arg1(
|
||||
host_stdin_fd,
|
||||
cmd_bits,
|
||||
cmd_arg_ptr
|
||||
));
|
||||
cmd.validate_arg_val()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
@ -182,7 +338,7 @@ impl File for StdinFile {
|
||||
|
||||
impl Debug for StdinFile {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "StdinFile")
|
||||
write!(f, "StdinFile with host_fd: {}", self.host_fd)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5,7 +5,8 @@ use std::path::Path;
|
||||
use std::sgxfs::SgxFile;
|
||||
|
||||
use super::fs::{
|
||||
CreationFlags, File, FileDesc, FileTable, INodeExt, StdinFile, StdoutFile, ROOT_INODE,
|
||||
CreationFlags, File, FileDesc, FileTable, HostStdioFds, INodeExt, StdinFile, StdoutFile,
|
||||
ROOT_INODE,
|
||||
};
|
||||
use super::misc::ResourceLimitsRef;
|
||||
use super::vm::{ProcessVM, ProcessVMBuilder};
|
||||
@ -24,7 +25,8 @@ pub fn do_spawn(
|
||||
file_actions: &[FileAction],
|
||||
parent_ref: &ProcessRef,
|
||||
) -> Result<pid_t> {
|
||||
let (new_tid, new_process_ref) = new_process(elf_path, argv, envp, file_actions, parent_ref)?;
|
||||
let (new_tid, new_process_ref) =
|
||||
new_process(elf_path, argv, envp, file_actions, None, parent_ref)?;
|
||||
task::enqueue_and_exec_task(new_tid, new_process_ref);
|
||||
Ok(new_tid)
|
||||
}
|
||||
@ -34,9 +36,17 @@ pub fn do_spawn_without_exec(
|
||||
argv: &[CString],
|
||||
envp: &[CString],
|
||||
file_actions: &[FileAction],
|
||||
host_stdio_fds: &HostStdioFds,
|
||||
parent_ref: &ProcessRef,
|
||||
) -> Result<pid_t> {
|
||||
let (new_tid, new_process_ref) = new_process(elf_path, argv, envp, file_actions, parent_ref)?;
|
||||
let (new_tid, new_process_ref) = new_process(
|
||||
elf_path,
|
||||
argv,
|
||||
envp,
|
||||
file_actions,
|
||||
Some(host_stdio_fds),
|
||||
parent_ref,
|
||||
)?;
|
||||
task::enqueue_task(new_tid, new_process_ref);
|
||||
Ok(new_tid)
|
||||
}
|
||||
@ -46,6 +56,7 @@ fn new_process(
|
||||
argv: &[CString],
|
||||
envp: &[CString],
|
||||
file_actions: &[FileAction],
|
||||
host_stdio_fds: Option<&HostStdioFds>,
|
||||
parent_ref: &ProcessRef,
|
||||
) -> Result<(pid_t, ProcessRef)> {
|
||||
let elf_buf = load_elf_to_vec(elf_path, parent_ref)
|
||||
@ -107,7 +118,7 @@ fn new_process(
|
||||
};
|
||||
let vm_ref = Arc::new(SgxMutex::new(vm));
|
||||
let files_ref = {
|
||||
let files = init_files(parent_ref, file_actions)?;
|
||||
let files = init_files(parent_ref, file_actions, host_stdio_fds)?;
|
||||
Arc::new(SgxMutex::new(files))
|
||||
};
|
||||
let rlimits_ref = Default::default();
|
||||
@ -145,7 +156,11 @@ fn load_elf_to_vec(elf_path: &str, parent_ref: &ProcessRef) -> Result<Vec<u8>> {
|
||||
.map_err(|e| errno!(e.errno(), "failed to read the executable ELF"))
|
||||
}
|
||||
|
||||
fn init_files(parent_ref: &ProcessRef, file_actions: &[FileAction]) -> Result<FileTable> {
|
||||
fn init_files(
|
||||
parent_ref: &ProcessRef,
|
||||
file_actions: &[FileAction],
|
||||
host_stdio_fds: Option<&HostStdioFds>,
|
||||
) -> Result<FileTable> {
|
||||
// Usually, we just inherit the file table from the parent
|
||||
let parent = parent_ref.lock().unwrap();
|
||||
let should_inherit_file_table = parent.get_pid() > 0;
|
||||
@ -186,10 +201,16 @@ fn init_files(parent_ref: &ProcessRef, file_actions: &[FileAction]) -> Result<Fi
|
||||
|
||||
// But, for init process, we initialize file table for it
|
||||
let mut file_table = FileTable::new();
|
||||
let stdin: Arc<Box<dyn File>> = Arc::new(Box::new(StdinFile::new()));
|
||||
let stdout: Arc<Box<dyn File>> = Arc::new(Box::new(StdoutFile::new()));
|
||||
// TODO: implement and use a real stderr
|
||||
let stderr = stdout.clone();
|
||||
let stdin: Arc<Box<dyn File>> = Arc::new(Box::new(StdinFile::new(
|
||||
host_stdio_fds.unwrap().stdin_fd as FileDesc,
|
||||
)));
|
||||
let stdout: Arc<Box<dyn File>> = Arc::new(Box::new(StdoutFile::new(
|
||||
host_stdio_fds.unwrap().stdout_fd as FileDesc,
|
||||
)));
|
||||
let stderr: Arc<Box<dyn File>> = Arc::new(Box::new(StdoutFile::new(
|
||||
host_stdio_fds.unwrap().stderr_fd as FileDesc,
|
||||
)));
|
||||
|
||||
file_table.put(stdin, false);
|
||||
file_table.put(stdout, false);
|
||||
file_table.put(stderr, false);
|
||||
|
@ -12,7 +12,8 @@ use fs::{
|
||||
do_fcntl, do_fdatasync, do_fstat, do_fstatat, do_fsync, do_ftruncate, do_getdents64, do_ioctl,
|
||||
do_link, do_lseek, do_lstat, do_mkdir, do_open, do_openat, do_pipe, do_pipe2, do_pread,
|
||||
do_pwrite, do_read, do_readlink, do_readv, do_rename, do_rmdir, do_sendfile, do_stat, do_sync,
|
||||
do_truncate, do_unlink, do_write, do_writev, iovec_t, File, FileDesc, FileRef, Stat,
|
||||
do_truncate, do_unlink, do_write, do_writev, iovec_t, File, FileDesc, FileRef, HostStdioFds,
|
||||
Stat,
|
||||
};
|
||||
use misc::{resource_t, rlimit_t, utsname_t};
|
||||
use net::{
|
||||
|
@ -4,5 +4,6 @@
|
||||
#include <time.h> // import struct timespec
|
||||
#include <sys/time.h> // import struct timeval
|
||||
#include <sys/uio.h> // import struct iovec
|
||||
#include <occlum_pal_api.h> // import occlum_stdio_fds
|
||||
|
||||
#endif /* __OCCLUM_EDL_TYPES__ */
|
||||
|
@ -33,6 +33,15 @@ typedef struct {
|
||||
.log_level = NULL \
|
||||
}
|
||||
|
||||
/*
|
||||
* The struct which consists of file descriptors of standard I/O
|
||||
*/
|
||||
struct occlum_stdio_fds {
|
||||
int stdin_fd;
|
||||
int stdout_fd;
|
||||
int stderr_fd;
|
||||
};
|
||||
|
||||
/*
|
||||
* @brief Initialize an Occlum enclave
|
||||
*
|
||||
@ -48,13 +57,19 @@ int occlum_pal_init(occlum_pal_attr_t* attr);
|
||||
* @param cmd_path The path of the command to be executed
|
||||
* @param cmd_args The arguments to the command. The array must be NULL
|
||||
* terminated.
|
||||
* @param io_fds The file descriptors of the redirected standard I/O
|
||||
* (i.e., stdin, stdout, stderr), If set to NULL, will
|
||||
* use the original standard I/O file descriptors.
|
||||
* @param exit_status Output. The exit status of the command. Note that the
|
||||
* exit status is returned if and only if the function
|
||||
* succeeds.
|
||||
*
|
||||
* @retval If 0, then success; otherwise, check errno for the exact error type.
|
||||
*/
|
||||
int occlum_pal_exec(const char* cmd_path, const char** cmd_args, int* exit_status);
|
||||
int occlum_pal_exec(const char* cmd_path,
|
||||
const char** cmd_args,
|
||||
const struct occlum_stdio_fds* io_fds,
|
||||
int* exit_status);
|
||||
|
||||
/*
|
||||
* @brief Destroy teh Occlum enclave
|
||||
|
@ -47,7 +47,10 @@ int occlum_pal_init(occlum_pal_attr_t* attr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int occlum_pal_exec(const char* cmd_path, const char** cmd_args, int* exit_status) {
|
||||
int occlum_pal_exec(const char* cmd_path,
|
||||
const char** cmd_args,
|
||||
const struct occlum_stdio_fds* io_fds,
|
||||
int* exit_status) {
|
||||
errno = 0;
|
||||
|
||||
if (cmd_path == NULL || cmd_args == NULL || exit_status == NULL) {
|
||||
@ -63,7 +66,7 @@ int occlum_pal_exec(const char* cmd_path, const char** cmd_args, int* exit_statu
|
||||
}
|
||||
|
||||
int libos_tid = -1;
|
||||
sgx_status_t ecall_status = occlum_ecall_new_process(eid, &libos_tid, cmd_path, cmd_args);
|
||||
sgx_status_t ecall_status = occlum_ecall_new_process(eid, &libos_tid, cmd_path, cmd_args, io_fds);
|
||||
if (ecall_status != SGX_SUCCESS) {
|
||||
const char* sgx_err = pal_get_sgx_error_msg(ecall_status);
|
||||
PAL_ERROR("Failed to do ECall: %s", sgx_err);
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include <linux/limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <occlum_pal_api.h>
|
||||
|
||||
static const char* get_instance_dir(void) {
|
||||
@ -32,8 +33,13 @@ int main(int argc, char* argv[]) {
|
||||
}
|
||||
|
||||
// Use Occlum PAL to execute the cmd
|
||||
struct occlum_stdio_fds io_fds = {
|
||||
.stdin_fd = STDIN_FILENO,
|
||||
.stdout_fd = STDOUT_FILENO,
|
||||
.stderr_fd = STDERR_FILENO,
|
||||
};
|
||||
int exit_status = 0;
|
||||
if (occlum_pal_exec(cmd_path, cmd_args, &exit_status) < 0) {
|
||||
if (occlum_pal_exec(cmd_path, cmd_args, &io_fds, &exit_status) < 0) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user