diff --git a/docs/src/kernel/linux-compatibility.md b/docs/src/kernel/linux-compatibility.md index 0b6b77a58..521468dd0 100644 --- a/docs/src/kernel/linux-compatibility.md +++ b/docs/src/kernel/linux-compatibility.md @@ -312,7 +312,7 @@ provided by Linux on x86-64 architecture. | 289 | signalfd4 | ❌ | | 290 | eventfd2 | ✅ | | 291 | epoll_create1 | ✅ | -| 292 | dup3 | ❌ | +| 292 | dup3 | ✅ | | 293 | pipe2 | ✅ | | 294 | inotify_init1 | ❌ | | 295 | preadv | ❌ | diff --git a/kernel/aster-nix/src/fs/file_table.rs b/kernel/aster-nix/src/fs/file_table.rs index 4c6229c3a..e11c0ef4d 100644 --- a/kernel/aster-nix/src/fs/file_table.rs +++ b/kernel/aster-nix/src/fs/file_table.rs @@ -99,7 +99,7 @@ impl FileTable { item: Arc, flags: FdFlags, ) -> Option> { - let entry = FileTableEntry::new(item, FdFlags::empty()); + let entry = FileTableEntry::new(item, flags); let entry = self.table.put_at(fd as usize, entry); if entry.is_some() { let events = FdEvents::Close(fd); diff --git a/kernel/aster-nix/src/syscall/arch/x86.rs b/kernel/aster-nix/src/syscall/arch/x86.rs index 828fc6893..f5ee5e8e5 100644 --- a/kernel/aster-nix/src/syscall/arch/x86.rs +++ b/kernel/aster-nix/src/syscall/arch/x86.rs @@ -15,7 +15,7 @@ use crate::syscall::{ clone::{sys_clone, sys_clone3}, close::sys_close, connect::sys_connect, - dup::{sys_dup, sys_dup2}, + dup::{sys_dup, sys_dup2, sys_dup3}, epoll::{sys_epoll_create, sys_epoll_create1, sys_epoll_ctl, sys_epoll_pwait, sys_epoll_wait}, eventfd::{sys_eventfd, sys_eventfd2}, execve::{sys_execve, sys_execveat}, @@ -264,6 +264,7 @@ impl_syscall_nums_and_dispatch_fn! { SYS_ACCEPT4 = 288 => sys_accept4(args[..4]); SYS_EVENTFD2 = 290 => sys_eventfd2(args[..2]); SYS_EPOLL_CREATE1 = 291 => sys_epoll_create1(args[..1]); + SYS_DUP3 = 292 => sys_dup3(args[..3]); SYS_PIPE2 = 293 => sys_pipe2(args[..2]); SYS_PRLIMIT64 = 302 => sys_prlimit64(args[..4]); SYS_GETRANDOM = 318 => sys_getrandom(args[..3]); diff --git a/kernel/aster-nix/src/syscall/dup.rs b/kernel/aster-nix/src/syscall/dup.rs index dcd8bc913..243fe849c 100644 --- a/kernel/aster-nix/src/syscall/dup.rs +++ b/kernel/aster-nix/src/syscall/dup.rs @@ -4,6 +4,7 @@ use super::SyscallReturn; use crate::{ fs::file_table::{FdFlags, FileDesc}, prelude::*, + process::ResourceType, }; pub fn sys_dup(old_fd: FileDesc) -> Result { @@ -11,24 +12,55 @@ pub fn sys_dup(old_fd: FileDesc) -> Result { let current = current!(); let mut file_table = current.file_table().lock(); - let file = file_table.get_file(old_fd)?.clone(); - // The two file descriptors do not share the close-on-exec flag. - let new_fd = file_table.insert(file, FdFlags::empty()); + let new_fd = file_table.dup(old_fd, 0, FdFlags::empty())?; + Ok(SyscallReturn::Return(new_fd as _)) } pub fn sys_dup2(old_fd: FileDesc, new_fd: FileDesc) -> Result { debug!("old_fd = {}, new_fd = {}", old_fd, new_fd); - let current = current!(); - let mut file_table = current.file_table().lock(); - let file = file_table.get_file(old_fd)?.clone(); - if old_fd != new_fd { - // The two file descriptors do not share the close-on-exec flag. - if let Some(old_file) = file_table.insert_at(new_fd, file, FdFlags::empty()) { - // If the file descriptor `new_fd` was previously open, close it silently. - let _ = old_file.clean_for_close(); - } + if old_fd == new_fd { + let current = current!(); + let file_table = current.file_table().lock(); + let _ = file_table.get_file(old_fd)?; + return Ok(SyscallReturn::Return(new_fd as _)); } + + do_dup3(old_fd, new_fd, FdFlags::empty()) +} + +pub fn sys_dup3(old_fd: FileDesc, new_fd: FileDesc, flags: u32) -> Result { + debug!("old_fd = {}, new_fd = {}", old_fd, new_fd); + + let fdflag = match flags { + 0x0 => FdFlags::empty(), + 0x80000 => FdFlags::CLOEXEC, + _ => return_errno_with_message!(Errno::EINVAL, "flags must be O_CLOEXEC or 0"), + }; + + do_dup3(old_fd, new_fd, fdflag) +} + +fn do_dup3(old_fd: FileDesc, new_fd: FileDesc, flags: FdFlags) -> Result { + if old_fd == new_fd { + return_errno!(Errno::EINVAL); + } + + let current = current!(); + if new_fd + >= current + .resource_limits() + .lock() + .get_rlimit(ResourceType::RLIMIT_NOFILE) + .get_cur() as FileDesc + { + return_errno!(Errno::EBADF); + } + + let mut file_table = current.file_table().lock(); + let _ = file_table.close_file(new_fd); + let new_fd = file_table.dup(old_fd, new_fd, flags)?; + Ok(SyscallReturn::Return(new_fd as _)) } diff --git a/kernel/aster-nix/src/syscall/eventfd.rs b/kernel/aster-nix/src/syscall/eventfd.rs index 01cf427d6..f4225f0e1 100644 --- a/kernel/aster-nix/src/syscall/eventfd.rs +++ b/kernel/aster-nix/src/syscall/eventfd.rs @@ -20,10 +20,14 @@ use crate::{ fs::{ file_handle::FileLike, file_table::{FdFlags, FileDesc}, - utils::{CreationFlags, StatusFlags}, + utils::{CreationFlags, InodeMode, InodeType, Metadata, StatusFlags}, }, prelude::*, - process::signal::{Pauser, Pollee, Poller}, + process::{ + signal::{Pauser, Pollee, Poller}, + Gid, Uid, + }, + time::clocks::RealTimeClock, }; pub fn sys_eventfd(init_val: u64) -> Result { @@ -253,4 +257,24 @@ impl FileLike for EventFile { ) -> Option>> { self.pollee.unregister_observer(observer) } + + fn metadata(&self) -> Metadata { + let now = RealTimeClock::get().read_time(); + Metadata { + dev: 0, + ino: 0, + size: 0, + blk_size: 0, + blocks: 0, + atime: now, + mtime: now, + ctime: now, + type_: InodeType::NamedPipe, + mode: InodeMode::from_bits_truncate(0o200), + nlinks: 1, + uid: Uid::new_root(), + gid: Gid::new_root(), + rdev: 0, + } + } } diff --git a/regression/syscall_test/Makefile b/regression/syscall_test/Makefile index 596332b8f..e4044251a 100644 --- a/regression/syscall_test/Makefile +++ b/regression/syscall_test/Makefile @@ -11,6 +11,7 @@ TESTS ?= \ chown_test \ chroot_test \ creat_test \ + dup_test \ epoll_test \ eventfd_test \ fsync_test \