diff options
Diffstat (limited to 'Kernel')
-rw-r--r-- | Kernel/API/Syscall.h | 10 | ||||
-rw-r--r-- | Kernel/CMakeLists.txt | 1 | ||||
-rw-r--r-- | Kernel/Process.h | 4 | ||||
-rw-r--r-- | Kernel/Syscalls/statvfs.cpp | 97 | ||||
-rw-r--r-- | Kernel/UnixTypes.h | 22 |
5 files changed, 133 insertions, 1 deletions
diff --git a/Kernel/API/Syscall.h b/Kernel/API/Syscall.h index 80f6ce9747..6d9edf4247 100644 --- a/Kernel/API/Syscall.h +++ b/Kernel/API/Syscall.h @@ -22,6 +22,7 @@ struct timespec; struct sockaddr; struct siginfo; struct stat; +struct statvfs; typedef u32 socklen_t; } @@ -177,7 +178,9 @@ namespace Kernel { S(anon_create) \ S(msyscall) \ S(readv) \ - S(emuctl) + S(emuctl) \ + S(statvfs) \ + S(fstatvfs) namespace Syscall { @@ -458,6 +461,11 @@ struct SC_inode_watcher_add_watch_params { u32 event_mask; }; +struct SC_statvfs_params { + StringArgument path; + struct statvfs* buf; +}; + void initialize(); int sync(); diff --git a/Kernel/CMakeLists.txt b/Kernel/CMakeLists.txt index 9a3c350ed0..4bd5a17fb2 100644 --- a/Kernel/CMakeLists.txt +++ b/Kernel/CMakeLists.txt @@ -196,6 +196,7 @@ set(KERNEL_SOURCES Syscalls/sigaction.cpp Syscalls/socket.cpp Syscalls/stat.cpp + Syscalls/statvfs.cpp Syscalls/sync.cpp Syscalls/sysconf.cpp Syscalls/thread.cpp diff --git a/Kernel/Process.h b/Kernel/Process.h index ed53a536a6..819a7a7f21 100644 --- a/Kernel/Process.h +++ b/Kernel/Process.h @@ -410,6 +410,8 @@ public: KResultOr<int> sys$prctl(int option, FlatPtr arg1, FlatPtr arg2); KResultOr<int> sys$set_coredump_metadata(Userspace<const Syscall::SC_set_coredump_metadata_params*>); KResultOr<int> sys$anon_create(size_t, int options); + KResultOr<int> sys$statvfs(Userspace<const Syscall::SC_statvfs_params*> user_params); + KResultOr<int> sys$fstatvfs(int fd, statvfs* buf); template<bool sockname, typename Params> int get_sock_or_peer_name(const Params&); @@ -529,6 +531,8 @@ private: KResult do_exec(NonnullRefPtr<FileDescription> main_program_description, Vector<String> arguments, Vector<String> environment, RefPtr<FileDescription> interpreter_description, Thread*& new_main_thread, u32& prev_flags, const Elf32_Ehdr& main_program_header); KResultOr<ssize_t> do_write(FileDescription&, const UserOrKernelBuffer&, size_t); + KResultOr<int> do_statvfs(String path, statvfs* buf); + KResultOr<RefPtr<FileDescription>> find_elf_interpreter_for_executable(const String& path, const Elf32_Ehdr& elf_header, int nread, size_t file_size); int alloc_fd(int first_candidate_fd = 0); diff --git a/Kernel/Syscalls/statvfs.cpp b/Kernel/Syscalls/statvfs.cpp new file mode 100644 index 0000000000..2f6d4d3553 --- /dev/null +++ b/Kernel/Syscalls/statvfs.cpp @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2021, Justin Mietzner <sw1tchbl4d3@sw1tchbl4d3.com> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <Kernel/FileSystem/Custody.h> +#include <Kernel/FileSystem/FileDescription.h> +#include <Kernel/FileSystem/VirtualFileSystem.h> +#include <Kernel/Process.h> + +namespace Kernel { + +KResultOr<int> Process::do_statvfs(String path, statvfs* buf) +{ + auto custody_or_error = VFS::the().resolve_path(path, current_directory(), nullptr, 0); + if (custody_or_error.is_error()) + return custody_or_error.error(); + + auto& custody = custody_or_error.value(); + auto& inode = custody->inode(); + auto& fs = inode.fs(); + + statvfs kernelbuf = {}; + + kernelbuf.f_bsize = static_cast<u64>(fs.block_size()); + kernelbuf.f_frsize = fs.fragment_size(); + kernelbuf.f_blocks = fs.total_block_count(); + kernelbuf.f_bfree = fs.free_block_count(); + + // FIXME: Implement "available blocks" into Filesystem + kernelbuf.f_bavail = fs.free_block_count(); + + kernelbuf.f_files = fs.total_inode_count(); + kernelbuf.f_ffree = fs.free_inode_count(); + kernelbuf.f_favail = fs.free_inode_count(); // FIXME: same as f_bavail + + kernelbuf.f_fsid = 0; // FIXME: Implement "Filesystem ID" into Filesystem + + kernelbuf.f_namemax = 255; + + Custody* current_custody = custody; + + while (current_custody) { + VFS::the().for_each_mount([&kernelbuf, ¤t_custody](auto& mount) { + if (current_custody) { + if (¤t_custody->inode() == &mount.guest()) { + int mountflags = mount.flags(); + int flags = 0; + if (mountflags & MS_RDONLY) + flags = flags | ST_RDONLY; + if (mountflags & MS_NOSUID) + flags = flags | ST_NOSUID; + + kernelbuf.f_flag = flags; + current_custody = nullptr; + } + } + }); + + if (current_custody) { + current_custody = current_custody->parent(); + } + } + + if (!copy_to_user(buf, &kernelbuf)) + return EFAULT; + + return 0; +} + +KResultOr<int> Process::sys$statvfs(Userspace<const Syscall::SC_statvfs_params*> user_params) +{ + REQUIRE_PROMISE(rpath); + + Syscall::SC_statvfs_params params; + if (!copy_from_user(¶ms, user_params)) + return EFAULT; + auto path = get_syscall_path_argument(params.path); + if (path.is_error()) + return path.error(); + + return do_statvfs(path.value(), params.buf); +} + +KResultOr<int> Process::sys$fstatvfs(int fd, statvfs* buf) +{ + REQUIRE_PROMISE(stdio); + + auto description = file_description(fd); + if (!description) + return EBADF; + + return do_statvfs(description->absolute_path(), buf); +} + +} diff --git a/Kernel/UnixTypes.h b/Kernel/UnixTypes.h index dce27f9070..c981d7727a 100644 --- a/Kernel/UnixTypes.h +++ b/Kernel/UnixTypes.h @@ -718,3 +718,25 @@ enum { DT_WHT = 14 #define DT_WHT DT_WHT }; + +typedef uint64_t fsblkcnt_t; +typedef uint64_t fsfilcnt_t; + +#define ST_RDONLY 0x1 +#define ST_NOSUID 0x2 + +struct statvfs { + unsigned long f_bsize; + unsigned long f_frsize; + fsblkcnt_t f_blocks; + fsblkcnt_t f_bfree; + fsblkcnt_t f_bavail; + + fsfilcnt_t f_files; + fsfilcnt_t f_ffree; + fsfilcnt_t f_favail; + + unsigned long f_fsid; + unsigned long f_flag; + unsigned long f_namemax; +}; |