From 0dfe1b3caa344514226132be1373904b9959dcab Mon Sep 17 00:00:00 2001 From: baiqiaosen Date: Thu, 30 May 2024 01:33:20 -0700 Subject: [PATCH] add sys_dup2 and sys_dup3 --- api/arceos_posix_api/src/imp/fd_ops.rs | 33 ++++++++++++++++++ api/arceos_posix_api/src/lib.rs | 2 +- ulib/axlibc/src/fd_ops.rs | 2 +- ulib/axstarry/src/ctypes.rs | 2 ++ ulib/axstarry/src/syscall_fs/imp/io.rs | 47 ++++++++++++++++++++++---- 5 files changed, 77 insertions(+), 9 deletions(-) diff --git a/api/arceos_posix_api/src/imp/fd_ops.rs b/api/arceos_posix_api/src/imp/fd_ops.rs index 75ee61061f..26a85d075a 100644 --- a/api/arceos_posix_api/src/imp/fd_ops.rs +++ b/api/arceos_posix_api/src/imp/fd_ops.rs @@ -100,6 +100,39 @@ pub fn sys_dup2(old_fd: c_int, new_fd: c_int) -> c_int { }) } +/// Duplicate a file descriptor. +pub fn sys_dup3(old_fd: c_int, new_fd: c_int, flags: c_int) -> c_int { + debug!( + "sys_dup3 <= old_fd: {}, new_fd: {}, flags: {}", + old_fd, new_fd, flags + ); + syscall_body!(sys_dup3, { + if old_fd == new_fd { + let r = sys_fcntl(old_fd, ctypes::F_GETFD as _, 0); + if r >= 0 { + return Ok(old_fd); + } else { + return Ok(r); + } + } + if new_fd as usize >= AX_FILE_LIMIT { + return Err(LinuxError::EBADF); + } + + let f = get_file_like(old_fd)?; + FD_TABLE + .write() + .add_at(new_fd as usize, f) + .ok_or(LinuxError::EMFILE)?; + + if (flags & (ctypes::O_CLOEXEC as c_int)) != 0 { + let res = sys_fcntl(new_fd, ctypes::F_SETFD as _, ctypes::FD_CLOEXEC as _); + } + + Ok(new_fd) + }) +} + /// Manipulate file descriptor. /// /// TODO: `SET/GET` command is ignored, hard-code stdin/stdout diff --git a/api/arceos_posix_api/src/lib.rs b/api/arceos_posix_api/src/lib.rs index 75eb9bd7ce..6604436e40 100644 --- a/api/arceos_posix_api/src/lib.rs +++ b/api/arceos_posix_api/src/lib.rs @@ -38,7 +38,7 @@ pub use imp::task::{sys_exit, sys_getpid, sys_sched_yield}; pub use imp::time::{sys_clock_gettime, sys_nanosleep}; #[cfg(feature = "fd")] -pub use imp::fd_ops::{sys_close, sys_dup, sys_dup2, sys_fcntl}; +pub use imp::fd_ops::{sys_close, sys_dup, sys_dup2, sys_dup3, sys_fcntl}; #[cfg(feature = "fs")] pub use imp::fs::{sys_fstat, sys_getcwd, sys_lseek, sys_lstat, sys_open, sys_rename, sys_stat}; #[cfg(feature = "select")] diff --git a/ulib/axlibc/src/fd_ops.rs b/ulib/axlibc/src/fd_ops.rs index 1b1a9d0001..53838a56f7 100644 --- a/ulib/axlibc/src/fd_ops.rs +++ b/ulib/axlibc/src/fd_ops.rs @@ -1,5 +1,5 @@ use crate::{ctypes, utils::e}; -use arceos_posix_api::{sys_close, sys_dup, sys_dup2, sys_fcntl}; +use arceos_posix_api::{sys_close, sys_dup, sys_dup2, sys_dup3, sys_fcntl}; use axerrno::LinuxError; use core::ffi::c_int; diff --git a/ulib/axstarry/src/ctypes.rs b/ulib/axstarry/src/ctypes.rs index c06286a71b..cbf37b4b77 100644 --- a/ulib/axstarry/src/ctypes.rs +++ b/ulib/axstarry/src/ctypes.rs @@ -4,6 +4,8 @@ use axhal::{ }; use bitflags::*; use core::panic; +/// a flag used in sys_dup3 +pub const O_CLOEXEC: u32 = 524288; /// The nano seconds number per second pub const NSEC_PER_SEC: usize = 1_000_000_000; bitflags! { diff --git a/ulib/axstarry/src/syscall_fs/imp/io.rs b/ulib/axstarry/src/syscall_fs/imp/io.rs index 829b389a29..27d60d58b1 100644 --- a/ulib/axstarry/src/syscall_fs/imp/io.rs +++ b/ulib/axstarry/src/syscall_fs/imp/io.rs @@ -1,5 +1,6 @@ //! 负责与 IO 相关的系统调用 extern crate alloc; +use crate::ctypes; use crate::syscall_net::Socket; use crate::{IoVec, SyscallError, SyscallResult}; use alloc::string::ToString; @@ -299,17 +300,47 @@ pub fn syscall_dup(args: [usize; 6]) -> SyscallResult { /// 返回值:成功执行,返回新的文件描述符。失败,返回-1。 #[cfg(target_arch = "x86_64")] pub fn syscall_dup2(args: [usize; 6]) -> SyscallResult { - syscall_dup3(args) + let fd = args[0]; + let new_fd = args[1]; + let process = current_process(); + let mut fd_table = process.fd_manager.fd_table.lock(); + if fd >= fd_table.len() { + debug!("fd {} is out of range", fd); + return Err(SyscallError::EPERM); + } + if fd_table[fd].is_none() { + debug!("fd {} is not opened", fd); + return Err(SyscallError::EPERM); + } + if new_fd >= fd_table.len() { + if new_fd >= (process.fd_manager.get_limit() as usize) { + // 超出了资源限制 + return Err(SyscallError::EBADF); + } + for _i in fd_table.len()..new_fd + 1 { + fd_table.push(None); + } + } + // if process_inner.fd_manager.fd_table[new_fd].is_some() { + // debug!("new_fd {} is already opened", new_fd); + // return ErrorNo::EINVAL as isize; + // } + info!("dup2 fd {} to new fd {}", fd, new_fd); + // 就算new_fd已经被打开了,也可以被重新替代掉 + fd_table[new_fd] = fd_table[fd].clone(); + Ok(new_fd as isize) } /// 功能:复制文件描述符,并指定了新的文件描述符; /// # Arguments /// * fd: usize, 原文件所在的文件描述符 /// * new_fd: usize, 新的文件描述符 +/// * flags: usize, 文件描述符标志 /// 返回值:成功执行,返回新的文件描述符。失败,返回-1。 pub fn syscall_dup3(args: [usize; 6]) -> SyscallResult { let fd = args[0]; let new_fd = args[1]; + let flags = args[2]; let process = current_process(); let mut fd_table = process.fd_manager.fd_table.lock(); if fd >= fd_table.len() { @@ -320,6 +351,10 @@ pub fn syscall_dup3(args: [usize; 6]) -> SyscallResult { debug!("fd {} is not opened", fd); return Err(SyscallError::EPERM); } + if fd == new_fd { + debug!("oldfd is equal to newfd"); + return Err(SyscallError::EINVAL); + } if new_fd >= fd_table.len() { if new_fd >= (process.fd_manager.get_limit() as usize) { // 超出了资源限制 @@ -329,13 +364,11 @@ pub fn syscall_dup3(args: [usize; 6]) -> SyscallResult { fd_table.push(None); } } - // if process_inner.fd_manager.fd_table[new_fd].is_some() { - // debug!("new_fd {} is already opened", new_fd); - // return ErrorNo::EINVAL as isize; - // } - info!("dup3 fd {} to new fd {}", fd, new_fd); - // 就算new_fd已经被打开了,也可以被重新替代掉 + info!("dup3 fd {} to new fd {} with flags {}", fd, new_fd, flags); fd_table[new_fd] = fd_table[fd].clone(); + if flags as u32 & ctypes::O_CLOEXEC != 0 { + fd_table[new_fd].as_mut().unwrap().set_close_on_exec(true); + } Ok(new_fd as isize) }