From 2b771e32f5795e0fdda458e3bb2651ef6b9673ac Mon Sep 17 00:00:00 2001 From: Gou Ngai Date: Sun, 2 Apr 2023 15:43:53 +0800 Subject: [PATCH] Add dup,dup2 (#224) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * dup,dup2 * fix: sys_dup2语义与posix不一致的问题 --------- Co-authored-by: longjin --- kernel/src/filesystem/vfs/core.rs | 7 +- kernel/src/filesystem/vfs/file.rs | 11 +-- kernel/src/filesystem/vfs/syscall.rs | 95 +++++++++++++++++++++- kernel/src/lib.rs | 3 +- kernel/src/process/process.rs | 51 ++++++++---- kernel/src/syscall/syscall.c | 7 +- kernel/src/syscall/syscall_num.h | 2 + user/apps/about/about.c | 6 +- user/libs/libc/src/include/export/unistd.h | 4 + user/libs/libc/src/unistd.c | 17 +++- user/libs/libsystem/syscall.h | 2 + 11 files changed, 166 insertions(+), 39 deletions(-) diff --git a/kernel/src/filesystem/vfs/core.rs b/kernel/src/filesystem/vfs/core.rs index ba1131d2..94294f70 100644 --- a/kernel/src/filesystem/vfs/core.rs +++ b/kernel/src/filesystem/vfs/core.rs @@ -16,9 +16,10 @@ use crate::{ ramfs::RamFS, vfs::{file::File, mount::MountFS, FileSystem, FileType}, }, - include::bindings::bindings::{PAGE_4K_SIZE}, + include::bindings::bindings::PAGE_4K_SIZE, io::SeekFrom, - kerror, kinfo, syscall::SystemError, + kerror, kinfo, + syscall::SystemError, }; use super::{file::FileMode, utils::rsplit_path, IndexNode, InodeId}; @@ -237,7 +238,7 @@ pub fn do_open(path: &str, mode: FileMode) -> Result { } // 把文件对象存入pcb - return current_pcb().alloc_fd(file); + return current_pcb().alloc_fd(file, None); } /// @brief 根据文件描述符,读取文件数据。尝试读取的数据长度与buf的长度相同。 diff --git a/kernel/src/filesystem/vfs/file.rs b/kernel/src/filesystem/vfs/file.rs index c18a4df4..e8b93bd5 100644 --- a/kernel/src/filesystem/vfs/file.rs +++ b/kernel/src/filesystem/vfs/file.rs @@ -3,14 +3,9 @@ use core::mem::MaybeUninit; use alloc::{boxed::Box, string::String, sync::Arc, vec::Vec}; use crate::{ - arch::asm::current::current_pcb, - driver::tty::TtyFilePrivateData, - filesystem::procfs::ProcfsFilePrivateData, - include::bindings::bindings::{ - process_control_block, - }, - io::SeekFrom, - kerror, syscall::SystemError, + arch::asm::current::current_pcb, driver::tty::TtyFilePrivateData, + filesystem::procfs::ProcfsFilePrivateData, include::bindings::bindings::process_control_block, + io::SeekFrom, kerror, syscall::SystemError, }; use super::{Dirent, FileType, IndexNode, Metadata}; diff --git a/kernel/src/filesystem/vfs/syscall.rs b/kernel/src/filesystem/vfs/syscall.rs index 71819a7a..a9ef927e 100644 --- a/kernel/src/filesystem/vfs/syscall.rs +++ b/kernel/src/filesystem/vfs/syscall.rs @@ -4,11 +4,14 @@ use alloc::{boxed::Box, string::ToString}; use crate::{ arch::asm::{current::current_pcb, ptrace::user_mode}, + filesystem::vfs::file::FileDescriptorVec, include::bindings::bindings::{ - pt_regs, verify_area, AT_REMOVEDIR, PAGE_2M_SIZE, PAGE_4K_SIZE, PROC_MAX_FD_NUM, SEEK_CUR, SEEK_END, SEEK_MAX, SEEK_SET, + pt_regs, verify_area, AT_REMOVEDIR, PAGE_2M_SIZE, PAGE_4K_SIZE, PROC_MAX_FD_NUM, SEEK_CUR, + SEEK_END, SEEK_MAX, SEEK_SET, }, io::SeekFrom, - kerror, syscall::SystemError, + kerror, + syscall::SystemError, }; use super::{ @@ -344,3 +347,91 @@ pub extern "C" fn sys_unlink_at(regs: &pt_regs) -> u64 { } } } + +fn do_dup(oldfd: i32) -> Result { + if let Some(fds) = FileDescriptorVec::from_pcb(current_pcb()) { + // 获得当前文件描述符数组 + // 确认oldfd是否有效 + if FileDescriptorVec::validate_fd(oldfd) { + if let Some(file) = &fds.fds[oldfd as usize] { + // 尝试获取对应的文件结构体 + let file_cp = (file).try_clone(); + if file_cp.is_none() { + return Err(SystemError::EBADF); + } + let res = current_pcb().alloc_fd(*file_cp.unwrap(), None); + // 申请文件描述符,并把文件对象存入其中 + return res; + } + // oldfd对应的文件不存在 + return Err(SystemError::EBADF); + } + return Err(SystemError::EBADF); + } else { + return Err(SystemError::EMFILE); + } +} + +#[no_mangle] +/// @brief 根据提供的文件描述符的fd,复制对应的文件结构体,并返回新复制的文件结构体对应的fd +pub extern "C" fn sys_dup(regs: &pt_regs) -> u64 { + let fd: i32 = regs.r8 as i32; + let r = do_dup(fd); + if r.is_ok() { + return r.unwrap() as u64; + } else { + return r.unwrap_err().to_posix_errno() as u64; + } +} + +fn do_dup2(oldfd: i32, newfd: i32) -> Result { + if let Some(fds) = FileDescriptorVec::from_pcb(current_pcb()) { + // 获得当前文件描述符数组 + if FileDescriptorVec::validate_fd(oldfd) && FileDescriptorVec::validate_fd(newfd) { + //确认oldfd, newid是否有效 + if oldfd == newfd { + // 若oldfd与newfd相等 + return Ok(newfd); + } + + if let Some(file) = &fds.fds[oldfd as usize] { + if fds.fds[newfd as usize].is_some() { + // close newfd + if let Err(_) = current_pcb().drop_fd(newfd) { + // An I/O error occurred while attempting to close fildes2. + return Err(SystemError::EIO); + } + } + + // 尝试获取对应的文件结构体 + let file_cp = file.try_clone(); + if file_cp.is_none() { + return Err(SystemError::EBADF); + } + // 申请文件描述符,并把文件对象存入其中 + let res = current_pcb().alloc_fd(*file_cp.unwrap(), Some(newfd)); + + return res; + } + return Err(SystemError::EBADF); + } else { + return Err(SystemError::EBADF); + } + } + // 从pcb获取文件描述符数组失败 + return Err(SystemError::EMFILE); +} + +#[no_mangle] +/// @brief 根据提供的文件描述符的fd,和指定新fd,复制对应的文件结构体, +/// 并返回新复制的文件结构体对应的fd +pub extern "C" fn sys_dup2(regs: &pt_regs) -> u64 { + let ofd = regs.r8 as i32; + let nfd = regs.r9 as i32; + let r = do_dup2(ofd, nfd); + if r.is_ok() { + return r.unwrap() as u64; + } else { + return r.unwrap_err().to_posix_errno() as u64; + } +} diff --git a/kernel/src/lib.rs b/kernel/src/lib.rs index 2a8923db..03e93efb 100644 --- a/kernel/src/lib.rs +++ b/kernel/src/lib.rs @@ -50,7 +50,7 @@ use mm::allocator::KernelAllocator; // <3> use crate::{ arch::asm::current::current_pcb, - include::bindings::bindings::{process_do_exit, BLACK, GREEN}, filesystem::vfs::ROOT_INODE, + include::bindings::bindings::{process_do_exit, BLACK, GREEN}, }; // 声明全局的slab分配器 @@ -97,6 +97,5 @@ pub fn panic(info: &PanicInfo) -> ! { #[no_mangle] pub extern "C" fn __rust_demo_func() -> i32 { printk_color!(GREEN, BLACK, "__rust_demo_func()\n"); - return 0; } diff --git a/kernel/src/process/process.rs b/kernel/src/process/process.rs index 7691b31e..3a264510 100644 --- a/kernel/src/process/process.rs +++ b/kernel/src/process/process.rs @@ -7,13 +7,17 @@ use alloc::boxed::Box; use crate::{ arch::{asm::current::current_pcb, fpu::FpState}, - filesystem::vfs::{file::{File, FileDescriptorVec, FileMode}, ROOT_INODE}, + filesystem::vfs::{ + file::{File, FileDescriptorVec, FileMode}, + ROOT_INODE, + }, include::bindings::bindings::{ - process_control_block, CLONE_FS, PROC_INTERRUPTIBLE, - PROC_RUNNING, PROC_STOPPED, PROC_UNINTERRUPTIBLE, + process_control_block, CLONE_FS, PROC_INTERRUPTIBLE, PROC_RUNNING, PROC_STOPPED, + PROC_UNINTERRUPTIBLE, }, sched::core::{cpu_executing, sched_enqueue}, - smp::core::{smp_get_processor_id, smp_send_reschedule}, syscall::SystemError, + smp::core::{smp_get_processor_id, smp_send_reschedule}, + syscall::SystemError, }; use super::preempt::{preempt_disable, preempt_enable}; @@ -173,9 +177,12 @@ impl process_control_block { /// @brief 申请文件描述符,并把文件对象存入其中。 /// + /// @param file 要存放的文件对象 + /// @param fd 如果为Some(i32),表示指定要申请这个文件描述符,如果这个文件描述符已经被使用,那么返回EBADF + /// /// @return Ok(i32) 申请到的文件描述符编号 /// @return Err(SystemError) 申请失败,返回错误码,并且,file对象将被drop掉 - pub fn alloc_fd(&mut self, file: File) -> Result { + pub fn alloc_fd(&mut self, file: File, fd: Option) -> Result { // 获取pcb的文件描述符数组的引用 let fds: &mut FileDescriptorVec = if let Some(f) = FileDescriptorVec::from_pcb(current_pcb()) { @@ -192,16 +199,28 @@ impl process_control_block { r.unwrap() }; - // 寻找空闲的文件描述符 - let mut cnt = 0; - for x in fds.fds.iter_mut() { + if fd.is_some() { + // 指定了要申请的文件描述符编号 + let new_fd = fd.unwrap(); + let x = &mut fds.fds[new_fd as usize]; if x.is_none() { *x = Some(Box::new(file)); - return Ok(cnt); + return Ok(new_fd); + } else { + return Err(SystemError::EBADF); } - cnt += 1; + } else { + // 寻找空闲的文件描述符 + let mut cnt = 0; + for x in fds.fds.iter_mut() { + if x.is_none() { + *x = Some(Box::new(file)); + return Ok(cnt); + } + cnt += 1; + } + return Err(SystemError::ENFILE); } - return Err(SystemError::ENFILE); } /// @brief 根据文件描述符序号,获取文件结构体的可变引用 @@ -377,10 +396,10 @@ pub fn init_stdio() -> Result<(), SystemError> { .expect("Init stdio: can't create stderr"); /* - 按照规定,进程的文件描述符数组的前三个位置,分别是stdin, stdout, stderr - */ - assert_eq!(current_pcb().alloc_fd(stdin).unwrap(), 0); - assert_eq!(current_pcb().alloc_fd(stdout).unwrap(), 1); - assert_eq!(current_pcb().alloc_fd(stderr).unwrap(), 2); + 按照规定,进程的文件描述符数组的前三个位置,分别是stdin, stdout, stderr + */ + assert_eq!(current_pcb().alloc_fd(stdin, None).unwrap(), 0); + assert_eq!(current_pcb().alloc_fd(stdout, None).unwrap(), 1); + assert_eq!(current_pcb().alloc_fd(stderr, None).unwrap(), 2); return Ok(()); } diff --git a/kernel/src/syscall/syscall.c b/kernel/src/syscall/syscall.c index 31be416a..2534de9f 100644 --- a/kernel/src/syscall/syscall.c +++ b/kernel/src/syscall/syscall.c @@ -400,6 +400,9 @@ uint64_t sys_pipe(struct pt_regs *regs) extern uint64_t sys_mkdir(struct pt_regs *regs); +extern int sys_dup(int oldfd); +extern int sys_dup2(int oldfd, int newfd); + system_call_t system_call_table[MAX_SYSTEM_CALL_NUM] = { [0] = system_call_not_exists, [1] = sys_put_string, @@ -429,5 +432,7 @@ system_call_t system_call_table[MAX_SYSTEM_CALL_NUM] = { [25] = sys_rt_sigreturn, [26] = sys_getpid, [27] = sys_sched, - [28 ... 255] = system_call_not_exists, + [28] = sys_dup, + [29] = sys_dup2, + [30 ... 255] = system_call_not_exists, }; diff --git a/kernel/src/syscall/syscall_num.h b/kernel/src/syscall/syscall_num.h index d6cea975..9fe42d37 100644 --- a/kernel/src/syscall/syscall_num.h +++ b/kernel/src/syscall/syscall_num.h @@ -39,5 +39,7 @@ #define SYS_RT_SIGRETURN 25 // 从信号处理函数返回 #define SYS_GETPID 26 // 获取当前进程的pid(进程标识符) #define SYS_SCHED 27 // 让系统立即运行调度器(该系统调用不能由运行在Ring3的程序发起) +#define SYS_DUP 28 +#define SYS_DUP2 29 #define SYS_AHCI_END_REQ 255 // AHCI DMA请求结束end_request的系统调用 \ No newline at end of file diff --git a/user/apps/about/about.c b/user/apps/about/about.c index a61145be..c774e3db 100644 --- a/user/apps/about/about.c +++ b/user/apps/about/about.c @@ -1,10 +1,10 @@ -#include "sys_version.h" // 这是系统的版本头文件,在编译过程中自动生成 +#include "sys_version.h" // 这是系统的版本头文件,在编译过程中自动生成 +#include #include #include #include #include #include - void print_ascii_logo() { printf(" ____ ___ ____ \n"); @@ -36,7 +36,7 @@ void print_copyright() } int main() -{ +{ print_ascii_logo(); print_copyright(); diff --git a/user/libs/libc/src/include/export/unistd.h b/user/libs/libc/src/include/export/unistd.h index fb7101d7..e3f599a6 100644 --- a/user/libs/libc/src/include/export/unistd.h +++ b/user/libs/libc/src/include/export/unistd.h @@ -122,6 +122,10 @@ void swab(void *restrict src, void *restrict dest, ssize_t nbytes); pid_t getpid(void); +int dup(int fd); + +int dup2(int ofd, int nfd); + #if defined(__cplusplus) } /* extern "C" */ #endif diff --git a/user/libs/libc/src/unistd.c b/user/libs/libc/src/unistd.c index f385365d..7517ab34 100644 --- a/user/libs/libc/src/unistd.c +++ b/user/libs/libc/src/unistd.c @@ -1,10 +1,10 @@ #include #include +#include #include #include #include #include -#include /** * @brief 关闭文件接口 @@ -88,7 +88,6 @@ pid_t vfork(void) uint64_t brk(uint64_t end_brk) { uint64_t x = (uint64_t)syscall_invoke(SYS_BRK, (uint64_t)end_brk, 0, 0, 0, 0, 0, 0, 0); - // printf("brk(): end_brk=%#018lx x=%#018lx", (uint64_t)end_brk, x); return x; } @@ -197,10 +196,20 @@ void swab(void *restrict src, void *restrict dest, ssize_t nbytes) /** * @brief 获取当前进程的pid(进程标识符) - * + * * @return pid_t 当前进程的pid */ pid_t getpid(void) { - syscall_invoke(SYS_GETPID, 0, 0, 0, 0, 0, 0, 0, 0); + return syscall_invoke(SYS_GETPID, 0, 0, 0, 0, 0, 0, 0, 0); +} + +int dup(int fd) +{ + return syscall_invoke(SYS_DUP, fd, 0, 0, 0, 0, 0, 0, 0); +} + +int dup2(int ofd, int nfd) +{ + return syscall_invoke(SYS_DUP2, ofd, nfd, 0, 0, 0, 0, 0, 0); } \ No newline at end of file diff --git a/user/libs/libsystem/syscall.h b/user/libs/libsystem/syscall.h index e553d23f..8a12d45e 100644 --- a/user/libs/libsystem/syscall.h +++ b/user/libs/libsystem/syscall.h @@ -32,6 +32,8 @@ #define SYS_SIGACTION 24 // 设置进程的信号处理动作 #define SYS_RT_SIGRETURN 25 // 从信号处理函数返回 #define SYS_GETPID 26 // 获取当前进程的pid(进程标识符) +#define SYS_DUP 28 +#define SYS_DUP2 29 /** * @brief 用户态系统调用函数