From d8389da7975375b476fe670996b2b280464fd63c Mon Sep 17 00:00:00 2001 From: Zhenchen Wang Date: Sun, 2 Jun 2024 19:41:00 +0800 Subject: [PATCH] Add syscall mknod Signed-off-by: Zhenchen Wang --- docs/src/kernel/linux-compatibility.md | 6 +- kernel/aster-nix/src/device/mod.rs | 17 +++++ kernel/aster-nix/src/syscall/arch/x86.rs | 3 + kernel/aster-nix/src/syscall/mknod.rs | 62 +++++++++++++++++++ kernel/aster-nix/src/syscall/mod.rs | 1 + kernel/aster-nix/src/syscall/stat.rs | 18 ++++-- test/syscall_test/Makefile | 1 + test/syscall_test/blocklists.exfat/mknod_test | 1 + test/syscall_test/blocklists/mknod_test | 6 ++ 9 files changed, 108 insertions(+), 7 deletions(-) create mode 100644 kernel/aster-nix/src/syscall/mknod.rs create mode 100644 test/syscall_test/blocklists.exfat/mknod_test create mode 100644 test/syscall_test/blocklists/mknod_test diff --git a/docs/src/kernel/linux-compatibility.md b/docs/src/kernel/linux-compatibility.md index eb753f14e..f21806863 100644 --- a/docs/src/kernel/linux-compatibility.md +++ b/docs/src/kernel/linux-compatibility.md @@ -153,7 +153,9 @@ provided by Linux on x86-64 architecture. | 130 | rt_sigsuspend | ✅ | | 131 | sigaltstack | ✅ | | 132 | utime | ✅ | -| 133 | mknod | ❌ | +| 133 | mknod | ✅ | +| 132 | utime | ❌ | +| 133 | mknod | ✅ | | 134 | uselib | ❌ | | 135 | personality | ❌ | | 136 | ustat | ❌ | @@ -279,7 +281,7 @@ provided by Linux on x86-64 architecture. | 256 | migrate_pages | ❌ | | 257 | openat | ✅ | | 258 | mkdirat | ✅ | -| 259 | mknodat | ❌ | +| 259 | mknodat | ✅ | | 260 | fchownat | ✅ | | 261 | futimesat | ✅ | | 262 | newfstatat | ✅ | diff --git a/kernel/aster-nix/src/device/mod.rs b/kernel/aster-nix/src/device/mod.rs index f728d9e8f..36c132cfb 100644 --- a/kernel/aster-nix/src/device/mod.rs +++ b/kernel/aster-nix/src/device/mod.rs @@ -47,3 +47,20 @@ pub fn init() -> Result<()> { pty::init()?; Ok(()) } + +pub fn get_device(dev: usize) -> Result> { + if dev == 0 { + return_errno_with_message!(Errno::EPERM, "whiteout device") + } + let major = ((dev >> 32) & 0xffff_f000 | (dev >> 8) & 0x0000_0fff) as u32; + let minor = ((dev >> 12) & 0xffff_ff00 | dev & 0x0000_00ff) as u32; + + match (major, minor) { + (1, 3) => Ok(Arc::new(null::Null)), + (1, 5) => Ok(Arc::new(zero::Zero)), + (5, 0) => Ok(Arc::new(tty::TtyDevice)), + (1, 8) => Ok(Arc::new(random::Random)), + (1, 9) => Ok(Arc::new(urandom::Urandom)), + _ => return_errno_with_message!(Errno::EINVAL, "unsupported device"), + } +} diff --git a/kernel/aster-nix/src/syscall/arch/x86.rs b/kernel/aster-nix/src/syscall/arch/x86.rs index 31dd62cad..ae0976091 100644 --- a/kernel/aster-nix/src/syscall/arch/x86.rs +++ b/kernel/aster-nix/src/syscall/arch/x86.rs @@ -55,6 +55,7 @@ use crate::syscall::{ lseek::sys_lseek, madvise::sys_madvise, mkdir::{sys_mkdir, sys_mkdirat}, + mknod::{sys_mknod, sys_mknodat}, mmap::sys_mmap, mount::sys_mount, mprotect::sys_mprotect, @@ -236,6 +237,7 @@ impl_syscall_nums_and_dispatch_fn! { SYS_RT_SIGSUSPEND = 130 => sys_rt_sigsuspend(args[..2]); SYS_SIGALTSTACK = 131 => sys_sigaltstack(args[..2]); SYS_UTIME = 132 => sys_utime(args[..2]); + SYS_MKNOD = 133 => sys_mknod(args[..3]); SYS_STATFS = 137 => sys_statfs(args[..2]); SYS_FSTATFS = 138 => sys_fstatfs(args[..2]); SYS_GET_PRIORITY = 140 => sys_get_priority(args[..2]); @@ -267,6 +269,7 @@ impl_syscall_nums_and_dispatch_fn! { SYS_WAITID = 247 => sys_waitid(args[..5]); SYS_OPENAT = 257 => sys_openat(args[..4]); SYS_MKDIRAT = 258 => sys_mkdirat(args[..3]); + SYS_MKNODAT = 259 => sys_mknodat(args[..4]); SYS_FCHOWNAT = 260 => sys_fchownat(args[..5]); SYS_FUTIMESAT = 261 => sys_futimesat(args[..3]); SYS_FSTATAT = 262 => sys_fstatat(args[..4]); diff --git a/kernel/aster-nix/src/syscall/mknod.rs b/kernel/aster-nix/src/syscall/mknod.rs new file mode 100644 index 000000000..ef798c55d --- /dev/null +++ b/kernel/aster-nix/src/syscall/mknod.rs @@ -0,0 +1,62 @@ +// SPDX-License-Identifier: MPL-2.0 + +use super::SyscallReturn; +use crate::{ + device::get_device, + fs::{ + file_table::FileDesc, + fs_resolver::{FsPath, AT_FDCWD}, + utils::{InodeMode, InodeType}, + }, + prelude::*, + syscall::{constants::MAX_FILENAME_LEN, stat::FileTypeFlags}, + util::read_cstring_from_user, +}; + +pub fn sys_mknodat( + dirfd: FileDesc, + path_addr: Vaddr, + mode: u16, + dev: usize, +) -> Result { + let path = read_cstring_from_user(path_addr, MAX_FILENAME_LEN)?; + let current = current!(); + let inode_mode = { + let mask_mode = mode & !current.umask().read().get(); + InodeMode::from_bits_truncate(mask_mode) + }; + let file_type = FileTypeFlags::from_bits_truncate(mode); + debug!( + "dirfd = {}, path = {:?}, inode_mode = {:?}, file_type = {:?}, dev = {}", + dirfd, path, inode_mode, file_type, dev + ); + + let (dir_dentry, name) = { + let path = path.to_string_lossy(); + if path.is_empty() { + return_errno_with_message!(Errno::ENOENT, "path is empty"); + } + let fs_path = FsPath::new(dirfd, path.as_ref())?; + current.fs().read().lookup_dir_and_base_name(&fs_path)? + }; + + if file_type.contains(FileTypeFlags::S_IFREG) || file_type.is_empty() { + let _ = dir_dentry.new_fs_child(name.trim_end_matches('/'), InodeType::File, inode_mode)?; + } else if file_type.contains(FileTypeFlags::S_IFCHR) + || file_type.contains(FileTypeFlags::S_IFBLK) + { + let _ = dir_dentry.mknod(name.trim_end_matches('/'), inode_mode, get_device(dev)?)?; + } else if file_type.contains(FileTypeFlags::S_IFIFO) + || file_type.contains(FileTypeFlags::S_IFSOCK) + { + return_errno_with_message!(Errno::EINVAL, "unsupported file type flag"); + } else { + return_errno_with_message!(Errno::EPERM, "unimplemented types"); + } + + Ok(SyscallReturn::Return(0)) +} + +pub fn sys_mknod(path_addr: Vaddr, mode: u16, dev: usize) -> Result { + self::sys_mknodat(AT_FDCWD, path_addr, mode, dev) +} diff --git a/kernel/aster-nix/src/syscall/mod.rs b/kernel/aster-nix/src/syscall/mod.rs index 738fb014d..ade5269f5 100644 --- a/kernel/aster-nix/src/syscall/mod.rs +++ b/kernel/aster-nix/src/syscall/mod.rs @@ -62,6 +62,7 @@ mod listen; mod lseek; mod madvise; mod mkdir; +mod mknod; mod mmap; mod mount; mod mprotect; diff --git a/kernel/aster-nix/src/syscall/stat.rs b/kernel/aster-nix/src/syscall/stat.rs index f27c8bec9..ff33ea2f9 100644 --- a/kernel/aster-nix/src/syscall/stat.rs +++ b/kernel/aster-nix/src/syscall/stat.rs @@ -77,11 +77,19 @@ pub fn sys_fstatat( Ok(SyscallReturn::Return(0)) } -pub const S_IFMT: u32 = 0o170000; -pub const S_IFCHR: u32 = 0o020000; -pub const S_IFDIR: u32 = 0o040000; -pub const S_IFREG: u32 = 0o100000; -pub const S_IFLNK: u32 = 0o120000; +bitflags! { + /// File type. + pub struct FileTypeFlags: u16 { + const S_IFMT = 0o170000; // File type mask. + const S_IFSOCK = 0o140000; // Socket. + const S_IFCHR = 0o020000; // Character device. + const S_IFBLK = 0o060000; // Block device. + const S_IFDIR = 0o040000; // Directory. + const S_IFIFO = 0o010000; // FIFO (named pipe). + const S_IFREG = 0o100000; // Regular file. + const S_IFLNK = 0o120000; // Symbolic link. + } +} /// File Stat #[derive(Debug, Clone, Copy, Pod, Default)] diff --git a/test/syscall_test/Makefile b/test/syscall_test/Makefile index 594689208..328740ba4 100644 --- a/test/syscall_test/Makefile +++ b/test/syscall_test/Makefile @@ -20,6 +20,7 @@ TESTS ?= \ link_test \ lseek_test \ mkdir_test \ + mknod_test \ mmap_test \ mount_test \ open_create_test \ diff --git a/test/syscall_test/blocklists.exfat/mknod_test b/test/syscall_test/blocklists.exfat/mknod_test new file mode 100644 index 000000000..b448e6ae1 --- /dev/null +++ b/test/syscall_test/blocklists.exfat/mknod_test @@ -0,0 +1 @@ +MknodTest.RegularFilePermissions \ No newline at end of file diff --git a/test/syscall_test/blocklists/mknod_test b/test/syscall_test/blocklists/mknod_test new file mode 100644 index 000000000..f1d108a5d --- /dev/null +++ b/test/syscall_test/blocklists/mknod_test @@ -0,0 +1,6 @@ +MknodTest.MknodAtFIFO +MknodTest.MknodOnExistingPathFails +MknodTest.Socket +MknodTest.Fifo +MknodTest.FifoOtrunc +MknodTest.FifoTruncNoOp \ No newline at end of file