Add dup, dup2, and dup3

This commit is contained in:
Tate, Hongliang Tian 2019-01-06 23:38:04 +08:00
parent d40af94aaf
commit 77a18bbc4d
5 changed files with 177 additions and 61 deletions

@ -13,13 +13,18 @@ extern "C" {
extern int occlum_open(const char* path, int flags, int mode);
extern int occlum_close(int fd);
extern ssize_t occlum_read(int fd, void* buf, size_t size);
extern ssize_t occlum_write(int fd, const void* buf, size_t size);
extern ssize_t occlum_readv(int fd, struct iovec* iov, int count);
extern ssize_t occlum_write(int fd, const void* buf, size_t size);
extern ssize_t occlum_writev(int fd, const struct iovec* iov, int count);
extern off_t occlum_lseek(int fd, off_t offset, int whence);
extern int occlum_pipe(int fds[2]);
extern int occlum_pipe2(int fds[2], int flags);
extern int occlum_dup(int old_fd);
extern int occlum_dup2(int old_fd, int new_fd);
extern int occlum_dup3(int old_fd, int new_fd, int flags);
extern int occlum_spawn(int* child_pid, const char* path,
const char** argv,
const char** envp);

@ -44,25 +44,45 @@ impl FileTable {
min_free_fd as FileDesc
}
pub fn get(&self, fd: FileDesc) -> Option<FileRef> {
pub fn put_at(&mut self, fd: FileDesc, file: FileRef, close_on_spawn: bool) {
let mut table = &mut self.table;
let mut table_entry = Some(FileTableEntry::new(file, close_on_spawn));
if fd as usize >= table.len() {
table.resize(fd as usize + 1, None);
}
std::mem::swap(&mut table_entry, &mut table[fd as usize]);
if table_entry.is_none() {
self.num_fds += 1;
}
}
pub fn get(&self, fd: FileDesc) -> Result<FileRef, Error> {
if fd as usize >= self.table.len() {
return None;
return errno!(EBADF, "Invalid file descriptor");
}
let table = &self.table;
table[fd as usize].as_ref().map(|entry| entry.file.clone())
match table[fd as usize].as_ref() {
Some(table_entry) => Ok(table_entry.file.clone()),
None => errno!(EBADF, "Invalid file descriptor"),
}
}
pub fn del(&mut self, fd: FileDesc) -> Option<FileRef> {
pub fn del(&mut self, fd: FileDesc) -> Result<FileRef, Error> {
if fd as usize >= self.table.len() {
return None;
return errno!(EBADF, "Invalid file descriptor");
}
let mut del_entry = None;
let mut del_table_entry = None;
let table = &mut self.table;
std::mem::swap(&mut del_entry, &mut table[fd as usize]);
self.num_fds -= 1;
del_entry.map(|entry| entry.file)
std::mem::swap(&mut del_table_entry, &mut table[fd as usize]);
match del_table_entry {
Some(del_table_entry) => {
self.num_fds -= 1;
Ok(del_table_entry.file)
},
None => errno!(EBADF, "Invalid file descriptor"),
}
}
}

@ -67,40 +67,35 @@ pub fn do_open(path: &str, flags: u32, mode: u32) -> Result<FileDesc, Error> {
pub fn do_write(fd: FileDesc, buf: &[u8]) -> Result<usize, Error> {
let current_ref = process::get_current();
let current_process = current_ref.lock().unwrap();
let file_ref = current_process.get_files().get(fd)
.ok_or_else(|| Error::new(Errno::EBADF, "Invalid file descriptor [do_write]"))?;
let file_ref = current_process.get_files().get(fd)?;
file_ref.write(buf)
}
pub fn do_read(fd: FileDesc, buf: &mut [u8]) -> Result<usize, Error> {
let current_ref = process::get_current();
let current_process = current_ref.lock().unwrap();
let file_ref = current_process.get_files().get(fd)
.ok_or_else(|| Error::new(Errno::EBADF, "Invalid file descriptor [do_read]"))?;
let file_ref = current_process.get_files().get(fd)?;
file_ref.read(buf)
}
pub fn do_writev<'a, 'b>(fd: FileDesc, bufs: &'a [&'b [u8]]) -> Result<usize, Error> {
let current_ref = process::get_current();
let current_process = current_ref.lock().unwrap();
let file_ref = current_process.get_files().get(fd)
.ok_or_else(|| Error::new(Errno::EBADF, "Invalid file descriptor [do_write]"))?;
let file_ref = current_process.get_files().get(fd)?;
file_ref.writev(bufs)
}
pub fn do_readv<'a, 'b>(fd: FileDesc, bufs: &'a mut [&'b mut [u8]]) -> Result<usize, Error> {
let current_ref = process::get_current();
let current_process = current_ref.lock().unwrap();
let file_ref = current_process.get_files().get(fd)
.ok_or_else(|| Error::new(Errno::EBADF, "Invalid file descriptor [do_read]"))?;
let file_ref = current_process.get_files().get(fd)?;
file_ref.readv(bufs)
}
pub fn do_lseek<'a, 'b>(fd: FileDesc, offset: SeekFrom) -> Result<off_t, Error> {
let current_ref = process::get_current();
let current_process = current_ref.lock().unwrap();
let file_ref = current_process.get_files().get(fd)
.ok_or_else(|| Error::new(Errno::EBADF, "Invalid file descriptor [do_lseek]"))?;
let file_ref = current_process.get_files().get(fd)?;
file_ref.seek(offset)
}
@ -108,10 +103,8 @@ pub fn do_close(fd: FileDesc) -> Result<(), Error> {
let current_ref = process::get_current();
let mut current_process = current_ref.lock().unwrap();
let file_table = current_process.get_files_mut();
match file_table.del(fd) {
Some(_) => Ok(()),
None => Err(Error::new(Errno::EBADF, "Invalid file descriptor [do_close]")),
}
file_table.del(fd)?;
Ok(())
}
pub fn do_pipe2(flags: u32) -> Result<[FileDesc; 2], Error> {
@ -127,3 +120,36 @@ pub fn do_pipe2(flags: u32) -> Result<[FileDesc; 2], Error> {
close_on_spawn);
Ok([reader_fd, writer_fd])
}
pub fn do_dup(old_fd: FileDesc) -> Result<FileDesc, Error> {
let current_ref = process::get_current();
let mut current = current_ref.lock().unwrap();
let file_table = current.get_files_mut();
let file = file_table.get(old_fd)?;
let new_fd = file_table.put(file, false);
Ok(new_fd)
}
pub fn do_dup2(old_fd: FileDesc, new_fd: FileDesc) -> Result<FileDesc, Error> {
let current_ref = process::get_current();
let mut current = current_ref.lock().unwrap();
let file_table = current.get_files_mut();
let file = file_table.get(old_fd)?;
if old_fd != new_fd {
file_table.put_at(new_fd, file, false);
}
Ok(new_fd)
}
pub fn do_dup3(old_fd: FileDesc, new_fd: FileDesc, flags: u32) -> Result<FileDesc, Error> {
let current_ref = process::get_current();
let mut current = current_ref.lock().unwrap();
let file_table = current.get_files_mut();
let file = file_table.get(old_fd)?;
if old_fd == new_fd {
return errno!(EINVAL, "old_fd must not be equal to new_fd");
}
let close_on_spawn = flags & O_CLOEXEC != 0;
file_table.put_at(new_fd, file, close_on_spawn);
Ok(new_fd)
}

@ -195,6 +195,43 @@ fn do_brk(new_brk_addr: *const c_void) -> Result<*const c_void, Error> {
vm::do_brk(new_brk_addr).map(|ret_brk_addr| ret_brk_addr as *const c_void)
}
fn do_wait4(pid: c_int, _exit_status: *mut c_int) -> Result<pid_t, Error> {
if _exit_status != 0 as *mut c_int {
check_mut_ptr_from_user(_exit_status)?;
}
let child_process_filter = match pid {
pid if pid < -1 => {
process::ChildProcessFilter::WithPGID((-pid) as pid_t)
},
-1 => {
process::ChildProcessFilter::WithAnyPID
},
0 => {
let gpid = process::do_getgpid();
process::ChildProcessFilter::WithPGID(gpid)
},
pid if pid > 0 => {
process::ChildProcessFilter::WithPID(pid as pid_t)
},
_ => {
panic!("THIS SHOULD NEVER HAPPEN!");
}
};
let mut exit_status = 0;
match process::do_wait4(&child_process_filter, &mut exit_status) {
Ok(pid) => {
if _exit_status != 0 as *mut c_int {
unsafe { *_exit_status = exit_status; }
}
Ok(pid)
}
Err(e) => {
Err(e)
}
}
}
fn do_pipe2(fds_u: *mut c_int, flags: c_int) -> Result<(), Error> {
check_mut_array_from_user(fds_u, 2)?;
// TODO: how to deal with open flags???
@ -405,43 +442,6 @@ pub extern "C" fn occlum_spawn(
}
}
fn do_wait4(pid: c_int, _exit_status: *mut c_int) -> Result<pid_t, Error> {
if _exit_status != 0 as *mut c_int {
check_mut_ptr_from_user(_exit_status)?;
}
let child_process_filter = match pid {
pid if pid < -1 => {
process::ChildProcessFilter::WithPGID((-pid) as pid_t)
},
-1 => {
process::ChildProcessFilter::WithAnyPID
},
0 => {
let gpid = process::do_getgpid();
process::ChildProcessFilter::WithPGID(gpid)
},
pid if pid > 0 => {
process::ChildProcessFilter::WithPID(pid as pid_t)
},
_ => {
panic!("THIS SHOULD NEVER HAPPEN!");
}
};
let mut exit_status = 0;
match process::do_wait4(&child_process_filter, &mut exit_status) {
Ok(pid) => {
if _exit_status != 0 as *mut c_int {
unsafe { *_exit_status = exit_status; }
}
Ok(pid)
}
Err(e) => {
Err(e)
}
}
}
#[no_mangle]
pub extern "C" fn occlum_wait4(child_pid: c_int, exit_status: *mut c_int,
options: c_int/*, rusage: *mut Rusage*/) -> c_int
@ -455,3 +455,50 @@ pub extern "C" fn occlum_wait4(child_pid: c_int, exit_status: *mut c_int,
}
}
}
#[no_mangle]
pub extern "C" fn occlum_dup(old_fd: c_int) -> c_int
{
let old_fd = old_fd as FileDesc;
match fs::do_dup(old_fd) {
Ok(new_fd) => {
new_fd as c_int
}
Err(e) => {
e.errno.as_retval()
}
}
}
#[no_mangle]
pub extern "C" fn occlum_dup2(old_fd: c_int, new_fd: c_int)
-> c_int
{
let old_fd = old_fd as FileDesc;
let new_fd = new_fd as FileDesc;
match fs::do_dup2(old_fd, new_fd) {
Ok(new_fd) => {
new_fd as c_int
}
Err(e) => {
e.errno.as_retval()
}
}
}
#[no_mangle]
pub extern "C" fn occlum_dup3(old_fd: c_int, new_fd: c_int, flags: c_int)
-> c_int
{
let old_fd = old_fd as FileDesc;
let new_fd = new_fd as FileDesc;
let flags = flags as u32;
match fs::do_dup3(old_fd, new_fd, flags) {
Ok(new_fd) => {
new_fd as c_int
}
Err(e) => {
e.errno.as_retval()
}
}
}

@ -125,6 +125,24 @@ long dispatch_syscall(int num, long arg0, long arg1, long arg2, long arg3, long
ret = (long) occlum_pipe2(fds, flags);
break;
}
case SYS_dup: {
DECL_SYSCALL_ARG(int, old_fd, arg0);
ret = (long) occlum_dup(old_fd);
break;
}
case SYS_dup2: {
DECL_SYSCALL_ARG(int, old_fd, arg0);
DECL_SYSCALL_ARG(int, new_fd, arg1);
ret = (long) occlum_dup2(old_fd, new_fd);
break;
}
case SYS_dup3: {
DECL_SYSCALL_ARG(int, old_fd, arg0);
DECL_SYSCALL_ARG(int, new_fd, arg1);
DECL_SYSCALL_ARG(int, flags, arg2);
ret = (long) occlum_dup3(old_fd, new_fd, flags);
break;
}
default:
ret = occlum_unknown(num);
break;