diff --git a/src/libos/include/syscall.h b/src/libos/include/syscall.h index f4bc3f50..a9dcbffa 100644 --- a/src/libos/include/syscall.h +++ b/src/libos/include/syscall.h @@ -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); diff --git a/src/libos/src/fs/file_table.rs b/src/libos/src/fs/file_table.rs index e1b22f02..5b8c544d 100644 --- a/src/libos/src/fs/file_table.rs +++ b/src/libos/src/fs/file_table.rs @@ -44,25 +44,45 @@ impl FileTable { min_free_fd as FileDesc } - pub fn get(&self, fd: FileDesc) -> Option { + 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 { 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 { + pub fn del(&mut self, fd: FileDesc) -> Result { 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"), + } } } diff --git a/src/libos/src/fs/mod.rs b/src/libos/src/fs/mod.rs index a6db8503..30582342 100644 --- a/src/libos/src/fs/mod.rs +++ b/src/libos/src/fs/mod.rs @@ -67,40 +67,35 @@ pub fn do_open(path: &str, flags: u32, mode: u32) -> Result { pub fn do_write(fd: FileDesc, buf: &[u8]) -> Result { 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 { 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 { 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 { 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 { 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 { + 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 { + 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 { + 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) +} diff --git a/src/libos/src/syscall/mod.rs b/src/libos/src/syscall/mod.rs index c9ab3a69..ebb0fe27 100644 --- a/src/libos/src/syscall/mod.rs +++ b/src/libos/src/syscall/mod.rs @@ -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 { + 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 { - 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() + } + } +} diff --git a/src/libos/src/syscall/syscall_entry.c b/src/libos/src/syscall/syscall_entry.c index fc54b336..bbb94b3a 100644 --- a/src/libos/src/syscall/syscall_entry.c +++ b/src/libos/src/syscall/syscall_entry.c @@ -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;