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
|
// Use Occlum PAL to execute the cmd
|
||||||
int exit_status = 0;
|
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;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,7 +27,8 @@ enclave {
|
|||||||
*/
|
*/
|
||||||
public int occlum_ecall_new_process(
|
public int occlum_ecall_new_process(
|
||||||
[in, string] const char* executable_path,
|
[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.
|
* Execute the LibOS thread specified by the TID.
|
||||||
|
@ -10,4 +10,10 @@ struct timeval {
|
|||||||
suseconds_t tv_usec; /* microseconds */
|
suseconds_t tv_usec; /* microseconds */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct occlum_stdio_fds {
|
||||||
|
int stdin_fd;
|
||||||
|
int stdout_fd;
|
||||||
|
int stderr_fd;
|
||||||
|
};
|
||||||
|
|
||||||
#endif /* __OCCLUM_EDL_TYPES_H__ */
|
#endif /* __OCCLUM_EDL_TYPES_H__ */
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
use exception::*;
|
use exception::*;
|
||||||
|
use fs::HostStdioFds;
|
||||||
use process::pid_t;
|
use process::pid_t;
|
||||||
use std::ffi::{CStr, CString, OsString};
|
use std::ffi::{CStr, CString, OsString};
|
||||||
use std::path::{Path, PathBuf};
|
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(
|
pub extern "C" fn occlum_ecall_new_process(
|
||||||
path_buf: *const c_char,
|
path_buf: *const c_char,
|
||||||
argv: *const *const c_char,
|
argv: *const *const c_char,
|
||||||
|
host_stdio_fds: *const HostStdioFds,
|
||||||
) -> i32 {
|
) -> i32 {
|
||||||
if HAS_INIT.load(Ordering::SeqCst) == false {
|
if HAS_INIT.load(Ordering::SeqCst) == false {
|
||||||
return EXIT_STATUS_INTERNAL_ERROR;
|
return EXIT_STATUS_INTERNAL_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
let (path, args) = match parse_arguments(path_buf, argv) {
|
let (path, args, host_stdio_fds) = match parse_arguments(path_buf, argv, host_stdio_fds) {
|
||||||
Ok(path_and_args) => path_and_args,
|
Ok(path_and_args_and_host_stdio_fds) => path_and_args_and_host_stdio_fds,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
eprintln!("invalid arguments for LibOS: {}", e.backtrace());
|
eprintln!("invalid arguments for LibOS: {}", e.backtrace());
|
||||||
return EXIT_STATUS_INTERNAL_ERROR;
|
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);
|
let _ = backtrace::enable_backtrace(ENCLAVE_PATH, PrintFormat::Short);
|
||||||
panic::catch_unwind(|| {
|
panic::catch_unwind(|| {
|
||||||
backtrace::__rust_begin_short_backtrace(|| match do_new_process(&path, &args) {
|
backtrace::__rust_begin_short_backtrace(|| {
|
||||||
Ok(pid_t) => pid_t as i32,
|
match do_new_process(&path, &args, &host_stdio_fds) {
|
||||||
Err(e) => {
|
Ok(pid_t) => pid_t as i32,
|
||||||
eprintln!("failed to boot up LibOS: {}", e.backtrace());
|
Err(e) => {
|
||||||
EXIT_STATUS_INTERNAL_ERROR
|
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(
|
fn parse_arguments(
|
||||||
path_ptr: *const c_char,
|
path_ptr: *const c_char,
|
||||||
argv: *const *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_buf = {
|
||||||
let path_cstring = clone_cstring_safely(path_ptr)?;
|
let path_cstring = clone_cstring_safely(path_ptr)?;
|
||||||
let path_string = path_cstring
|
let path_string = path_cstring
|
||||||
@ -155,18 +160,31 @@ fn parse_arguments(
|
|||||||
|
|
||||||
let mut args = clone_cstrings_safely(argv)?;
|
let mut args = clone_cstrings_safely(argv)?;
|
||||||
args.insert(0, program_cstring);
|
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)?;
|
validate_program_path(program_path)?;
|
||||||
|
|
||||||
let envp = &config::LIBOS_CONFIG.env;
|
let envp = &config::LIBOS_CONFIG.env;
|
||||||
let file_actions = Vec::new();
|
let file_actions = Vec::new();
|
||||||
let parent = &process::IDLE_PROCESS;
|
let parent = &process::IDLE_PROCESS;
|
||||||
let program_path_str = program_path.to_str().unwrap();
|
let program_path_str = program_path.to_str().unwrap();
|
||||||
let new_tid =
|
let new_tid = process::do_spawn_without_exec(
|
||||||
process::do_spawn_without_exec(&program_path_str, argv, envp, &file_actions, parent)?;
|
&program_path_str,
|
||||||
|
argv,
|
||||||
|
envp,
|
||||||
|
&file_actions,
|
||||||
|
host_stdio_fds,
|
||||||
|
parent,
|
||||||
|
)?;
|
||||||
Ok(new_tid)
|
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::inode_file::{AsINodeFile, INodeExt, INodeFile};
|
||||||
pub use self::pipe::Pipe;
|
pub use self::pipe::Pipe;
|
||||||
pub use self::rootfs::ROOT_INODE;
|
pub use self::rootfs::ROOT_INODE;
|
||||||
pub use self::stdio::{StdinFile, StdoutFile};
|
pub use self::stdio::{HostStdioFds, StdinFile, StdoutFile};
|
||||||
pub use self::syscalls::*;
|
pub use self::syscalls::*;
|
||||||
|
|
||||||
mod dev_fs;
|
mod dev_fs;
|
||||||
|
@ -1,20 +1,114 @@
|
|||||||
use super::*;
|
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 {
|
pub struct StdoutFile {
|
||||||
inner: std::io::Stdout,
|
inner: SgxMutex<LineWriter<StdoutRaw>>,
|
||||||
|
host_fd: FileDesc,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StdoutFile {
|
impl StdoutFile {
|
||||||
pub fn new() -> StdoutFile {
|
pub fn new(host_fd: FileDesc) -> Self {
|
||||||
StdoutFile {
|
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 {
|
impl File for StdoutFile {
|
||||||
fn write(&self, buf: &[u8]) -> Result<usize> {
|
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)
|
Ok(write_len)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -23,7 +117,7 @@ impl File for StdoutFile {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn writev(&self, bufs: &[&[u8]]) -> Result<usize> {
|
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;
|
let mut total_bytes = 0;
|
||||||
for buf in bufs {
|
for buf in bufs {
|
||||||
match guard.write(buf) {
|
match guard.write(buf) {
|
||||||
@ -70,7 +164,7 @@ impl File for StdoutFile {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn sync_data(&self) -> Result<()> {
|
fn sync_data(&self) -> Result<()> {
|
||||||
self.inner.lock().flush()?;
|
self.inner.lock().unwrap().flush()?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,10 +180,7 @@ impl File for StdoutFile {
|
|||||||
|
|
||||||
let cmd_bits = cmd.cmd_num() as c_int;
|
let cmd_bits = cmd.cmd_num() as c_int;
|
||||||
let cmd_arg_ptr = cmd.arg_ptr() as *const c_int;
|
let cmd_arg_ptr = cmd.arg_ptr() as *const c_int;
|
||||||
let host_stdout_fd = {
|
let host_stdout_fd = self.get_host_fd() as i32;
|
||||||
use std::os::unix::io::AsRawFd;
|
|
||||||
self.inner.as_raw_fd() as i32
|
|
||||||
};
|
|
||||||
try_libc!(libc::ocall::ioctl_arg1(
|
try_libc!(libc::ocall::ioctl_arg1(
|
||||||
host_stdout_fd,
|
host_stdout_fd,
|
||||||
cmd_bits,
|
cmd_bits,
|
||||||
@ -107,33 +198,75 @@ impl File for StdoutFile {
|
|||||||
|
|
||||||
impl Debug for StdoutFile {
|
impl Debug for StdoutFile {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
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 Send for StdoutFile {}
|
||||||
unsafe impl Sync 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 {
|
pub struct StdinFile {
|
||||||
inner: std::io::Stdin,
|
inner: SgxMutex<BufReader<StdinRaw>>,
|
||||||
|
host_fd: FileDesc,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StdinFile {
|
impl StdinFile {
|
||||||
pub fn new() -> StdinFile {
|
pub fn new(host_fd: FileDesc) -> Self {
|
||||||
StdinFile {
|
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 {
|
impl File for StdinFile {
|
||||||
fn read(&self, buf: &mut [u8]) -> Result<usize> {
|
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)
|
Ok(read_len)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn readv(&self, bufs: &mut [&mut [u8]]) -> Result<usize> {
|
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;
|
let mut total_bytes = 0;
|
||||||
for buf in bufs {
|
for buf in bufs {
|
||||||
match guard.read(buf) {
|
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 {
|
fn as_any(&self) -> &dyn Any {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
@ -182,7 +338,7 @@ impl File for StdinFile {
|
|||||||
|
|
||||||
impl Debug for StdinFile {
|
impl Debug for StdinFile {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
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 std::sgxfs::SgxFile;
|
||||||
|
|
||||||
use super::fs::{
|
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::misc::ResourceLimitsRef;
|
||||||
use super::vm::{ProcessVM, ProcessVMBuilder};
|
use super::vm::{ProcessVM, ProcessVMBuilder};
|
||||||
@ -24,7 +25,8 @@ pub fn do_spawn(
|
|||||||
file_actions: &[FileAction],
|
file_actions: &[FileAction],
|
||||||
parent_ref: &ProcessRef,
|
parent_ref: &ProcessRef,
|
||||||
) -> Result<pid_t> {
|
) -> 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);
|
task::enqueue_and_exec_task(new_tid, new_process_ref);
|
||||||
Ok(new_tid)
|
Ok(new_tid)
|
||||||
}
|
}
|
||||||
@ -34,9 +36,17 @@ pub fn do_spawn_without_exec(
|
|||||||
argv: &[CString],
|
argv: &[CString],
|
||||||
envp: &[CString],
|
envp: &[CString],
|
||||||
file_actions: &[FileAction],
|
file_actions: &[FileAction],
|
||||||
|
host_stdio_fds: &HostStdioFds,
|
||||||
parent_ref: &ProcessRef,
|
parent_ref: &ProcessRef,
|
||||||
) -> Result<pid_t> {
|
) -> 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);
|
task::enqueue_task(new_tid, new_process_ref);
|
||||||
Ok(new_tid)
|
Ok(new_tid)
|
||||||
}
|
}
|
||||||
@ -46,6 +56,7 @@ fn new_process(
|
|||||||
argv: &[CString],
|
argv: &[CString],
|
||||||
envp: &[CString],
|
envp: &[CString],
|
||||||
file_actions: &[FileAction],
|
file_actions: &[FileAction],
|
||||||
|
host_stdio_fds: Option<&HostStdioFds>,
|
||||||
parent_ref: &ProcessRef,
|
parent_ref: &ProcessRef,
|
||||||
) -> Result<(pid_t, ProcessRef)> {
|
) -> Result<(pid_t, ProcessRef)> {
|
||||||
let elf_buf = load_elf_to_vec(elf_path, parent_ref)
|
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 vm_ref = Arc::new(SgxMutex::new(vm));
|
||||||
let files_ref = {
|
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))
|
Arc::new(SgxMutex::new(files))
|
||||||
};
|
};
|
||||||
let rlimits_ref = Default::default();
|
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"))
|
.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
|
// Usually, we just inherit the file table from the parent
|
||||||
let parent = parent_ref.lock().unwrap();
|
let parent = parent_ref.lock().unwrap();
|
||||||
let should_inherit_file_table = parent.get_pid() > 0;
|
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
|
// But, for init process, we initialize file table for it
|
||||||
let mut file_table = FileTable::new();
|
let mut file_table = FileTable::new();
|
||||||
let stdin: Arc<Box<dyn File>> = Arc::new(Box::new(StdinFile::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()));
|
host_stdio_fds.unwrap().stdin_fd as FileDesc,
|
||||||
// TODO: implement and use a real stderr
|
)));
|
||||||
let stderr = stdout.clone();
|
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(stdin, false);
|
||||||
file_table.put(stdout, false);
|
file_table.put(stdout, false);
|
||||||
file_table.put(stderr, 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_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_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_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 misc::{resource_t, rlimit_t, utsname_t};
|
||||||
use net::{
|
use net::{
|
||||||
|
@ -4,5 +4,6 @@
|
|||||||
#include <time.h> // import struct timespec
|
#include <time.h> // import struct timespec
|
||||||
#include <sys/time.h> // import struct timeval
|
#include <sys/time.h> // import struct timeval
|
||||||
#include <sys/uio.h> // import struct iovec
|
#include <sys/uio.h> // import struct iovec
|
||||||
|
#include <occlum_pal_api.h> // import occlum_stdio_fds
|
||||||
|
|
||||||
#endif /* __OCCLUM_EDL_TYPES__ */
|
#endif /* __OCCLUM_EDL_TYPES__ */
|
||||||
|
@ -33,6 +33,15 @@ typedef struct {
|
|||||||
.log_level = NULL \
|
.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
|
* @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_path The path of the command to be executed
|
||||||
* @param cmd_args The arguments to the command. The array must be NULL
|
* @param cmd_args The arguments to the command. The array must be NULL
|
||||||
* terminated.
|
* 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
|
* @param exit_status Output. The exit status of the command. Note that the
|
||||||
* exit status is returned if and only if the function
|
* exit status is returned if and only if the function
|
||||||
* succeeds.
|
* succeeds.
|
||||||
*
|
*
|
||||||
* @retval If 0, then success; otherwise, check errno for the exact error type.
|
* @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
|
* @brief Destroy teh Occlum enclave
|
||||||
|
@ -47,7 +47,10 @@ int occlum_pal_init(occlum_pal_attr_t* attr) {
|
|||||||
return 0;
|
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;
|
errno = 0;
|
||||||
|
|
||||||
if (cmd_path == NULL || cmd_args == NULL || exit_status == NULL) {
|
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;
|
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) {
|
if (ecall_status != SGX_SUCCESS) {
|
||||||
const char* sgx_err = pal_get_sgx_error_msg(ecall_status);
|
const char* sgx_err = pal_get_sgx_error_msg(ecall_status);
|
||||||
PAL_ERROR("Failed to do ECall: %s", sgx_err);
|
PAL_ERROR("Failed to do ECall: %s", sgx_err);
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include <linux/limits.h>
|
#include <linux/limits.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
#include <occlum_pal_api.h>
|
#include <occlum_pal_api.h>
|
||||||
|
|
||||||
static const char* get_instance_dir(void) {
|
static const char* get_instance_dir(void) {
|
||||||
@ -32,8 +33,13 @@ int main(int argc, char* argv[]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Use Occlum PAL to execute the cmd
|
// 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;
|
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;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user