Add dup, dup2, and dup3
This commit is contained in:
parent
d40af94aaf
commit
77a18bbc4d
@ -13,13 +13,18 @@ extern "C" {
|
|||||||
extern int occlum_open(const char* path, int flags, int mode);
|
extern int occlum_open(const char* path, int flags, int mode);
|
||||||
extern int occlum_close(int fd);
|
extern int occlum_close(int fd);
|
||||||
extern ssize_t occlum_read(int fd, void* buf, size_t size);
|
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_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 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 off_t occlum_lseek(int fd, off_t offset, int whence);
|
||||||
|
|
||||||
extern int occlum_pipe(int fds[2]);
|
extern int occlum_pipe(int fds[2]);
|
||||||
extern int occlum_pipe2(int fds[2], int flags);
|
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,
|
extern int occlum_spawn(int* child_pid, const char* path,
|
||||||
const char** argv,
|
const char** argv,
|
||||||
const char** envp);
|
const char** envp);
|
||||||
|
@ -44,25 +44,45 @@ impl FileTable {
|
|||||||
min_free_fd as FileDesc
|
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() {
|
if fd as usize >= self.table.len() {
|
||||||
return None;
|
return errno!(EBADF, "Invalid file descriptor");
|
||||||
}
|
}
|
||||||
|
|
||||||
let table = &self.table;
|
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() {
|
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;
|
let table = &mut self.table;
|
||||||
std::mem::swap(&mut del_entry, &mut table[fd as usize]);
|
std::mem::swap(&mut del_table_entry, &mut table[fd as usize]);
|
||||||
self.num_fds -= 1;
|
match del_table_entry {
|
||||||
del_entry.map(|entry| entry.file)
|
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> {
|
pub fn do_write(fd: FileDesc, buf: &[u8]) -> Result<usize, Error> {
|
||||||
let current_ref = process::get_current();
|
let current_ref = process::get_current();
|
||||||
let current_process = current_ref.lock().unwrap();
|
let current_process = current_ref.lock().unwrap();
|
||||||
let file_ref = current_process.get_files().get(fd)
|
let file_ref = current_process.get_files().get(fd)?;
|
||||||
.ok_or_else(|| Error::new(Errno::EBADF, "Invalid file descriptor [do_write]"))?;
|
|
||||||
file_ref.write(buf)
|
file_ref.write(buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn do_read(fd: FileDesc, buf: &mut [u8]) -> Result<usize, Error> {
|
pub fn do_read(fd: FileDesc, buf: &mut [u8]) -> Result<usize, Error> {
|
||||||
let current_ref = process::get_current();
|
let current_ref = process::get_current();
|
||||||
let current_process = current_ref.lock().unwrap();
|
let current_process = current_ref.lock().unwrap();
|
||||||
let file_ref = current_process.get_files().get(fd)
|
let file_ref = current_process.get_files().get(fd)?;
|
||||||
.ok_or_else(|| Error::new(Errno::EBADF, "Invalid file descriptor [do_read]"))?;
|
|
||||||
file_ref.read(buf)
|
file_ref.read(buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn do_writev<'a, 'b>(fd: FileDesc, bufs: &'a [&'b [u8]]) -> Result<usize, Error> {
|
pub fn do_writev<'a, 'b>(fd: FileDesc, bufs: &'a [&'b [u8]]) -> Result<usize, Error> {
|
||||||
let current_ref = process::get_current();
|
let current_ref = process::get_current();
|
||||||
let current_process = current_ref.lock().unwrap();
|
let current_process = current_ref.lock().unwrap();
|
||||||
let file_ref = current_process.get_files().get(fd)
|
let file_ref = current_process.get_files().get(fd)?;
|
||||||
.ok_or_else(|| Error::new(Errno::EBADF, "Invalid file descriptor [do_write]"))?;
|
|
||||||
file_ref.writev(bufs)
|
file_ref.writev(bufs)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn do_readv<'a, 'b>(fd: FileDesc, bufs: &'a mut [&'b mut [u8]]) -> Result<usize, Error> {
|
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_ref = process::get_current();
|
||||||
let current_process = current_ref.lock().unwrap();
|
let current_process = current_ref.lock().unwrap();
|
||||||
let file_ref = current_process.get_files().get(fd)
|
let file_ref = current_process.get_files().get(fd)?;
|
||||||
.ok_or_else(|| Error::new(Errno::EBADF, "Invalid file descriptor [do_read]"))?;
|
|
||||||
file_ref.readv(bufs)
|
file_ref.readv(bufs)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn do_lseek<'a, 'b>(fd: FileDesc, offset: SeekFrom) -> Result<off_t, Error> {
|
pub fn do_lseek<'a, 'b>(fd: FileDesc, offset: SeekFrom) -> Result<off_t, Error> {
|
||||||
let current_ref = process::get_current();
|
let current_ref = process::get_current();
|
||||||
let current_process = current_ref.lock().unwrap();
|
let current_process = current_ref.lock().unwrap();
|
||||||
let file_ref = current_process.get_files().get(fd)
|
let file_ref = current_process.get_files().get(fd)?;
|
||||||
.ok_or_else(|| Error::new(Errno::EBADF, "Invalid file descriptor [do_lseek]"))?;
|
|
||||||
file_ref.seek(offset)
|
file_ref.seek(offset)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -108,10 +103,8 @@ pub fn do_close(fd: FileDesc) -> Result<(), Error> {
|
|||||||
let current_ref = process::get_current();
|
let current_ref = process::get_current();
|
||||||
let mut current_process = current_ref.lock().unwrap();
|
let mut current_process = current_ref.lock().unwrap();
|
||||||
let file_table = current_process.get_files_mut();
|
let file_table = current_process.get_files_mut();
|
||||||
match file_table.del(fd) {
|
file_table.del(fd)?;
|
||||||
Some(_) => Ok(()),
|
Ok(())
|
||||||
None => Err(Error::new(Errno::EBADF, "Invalid file descriptor [do_close]")),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn do_pipe2(flags: u32) -> Result<[FileDesc; 2], Error> {
|
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);
|
close_on_spawn);
|
||||||
Ok([reader_fd, writer_fd])
|
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)
|
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> {
|
fn do_pipe2(fds_u: *mut c_int, flags: c_int) -> Result<(), Error> {
|
||||||
check_mut_array_from_user(fds_u, 2)?;
|
check_mut_array_from_user(fds_u, 2)?;
|
||||||
// TODO: how to deal with open flags???
|
// 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]
|
#[no_mangle]
|
||||||
pub extern "C" fn occlum_wait4(child_pid: c_int, exit_status: *mut c_int,
|
pub extern "C" fn occlum_wait4(child_pid: c_int, exit_status: *mut c_int,
|
||||||
options: c_int/*, rusage: *mut Rusage*/) -> 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);
|
ret = (long) occlum_pipe2(fds, flags);
|
||||||
break;
|
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:
|
default:
|
||||||
ret = occlum_unknown(num);
|
ret = occlum_unknown(num);
|
||||||
break;
|
break;
|
||||||
|
Loading…
Reference in New Issue
Block a user