summaryrefslogtreecommitdiff
path: root/Kernel/Syscalls/mount.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Kernel/Syscalls/mount.cpp')
-rw-r--r--Kernel/Syscalls/mount.cpp121
1 files changed, 121 insertions, 0 deletions
diff --git a/Kernel/Syscalls/mount.cpp b/Kernel/Syscalls/mount.cpp
new file mode 100644
index 0000000000..87d7e60ce1
--- /dev/null
+++ b/Kernel/Syscalls/mount.cpp
@@ -0,0 +1,121 @@
+#include <Kernel/FileSystem/Custody.h>
+#include <Kernel/FileSystem/DevPtsFS.h>
+#include <Kernel/FileSystem/Ext2FileSystem.h>
+#include <Kernel/FileSystem/Plan9FileSystem.h>
+#include <Kernel/FileSystem/ProcFS.h>
+#include <Kernel/FileSystem/TmpFS.h>
+#include <Kernel/FileSystem/VirtualFileSystem.h>
+#include <Kernel/Process.h>
+
+namespace Kernel {
+
+int Process::sys$mount(const Syscall::SC_mount_params* user_params)
+{
+ if (!is_superuser())
+ return -EPERM;
+
+ REQUIRE_NO_PROMISES;
+
+ Syscall::SC_mount_params params;
+ if (!validate_read_and_copy_typed(&params, user_params))
+ return -EFAULT;
+
+ auto source_fd = params.source_fd;
+ auto target = validate_and_copy_string_from_user(params.target);
+ auto fs_type = validate_and_copy_string_from_user(params.fs_type);
+
+ if (target.is_null())
+ return -EFAULT;
+
+ auto description = file_description(source_fd);
+ if (!description.is_null())
+ dbg() << "mount " << fs_type << ": source fd " << source_fd << " @ " << target;
+ else
+ dbg() << "mount " << fs_type << " @ " << target;
+
+ auto custody_or_error = VFS::the().resolve_path(target, current_directory());
+ if (custody_or_error.is_error())
+ return custody_or_error.error();
+
+ auto& target_custody = custody_or_error.value();
+
+ if (params.flags & MS_REMOUNT) {
+ // We're not creating a new mount, we're updating an existing one!
+ return VFS::the().remount(target_custody, params.flags & ~MS_REMOUNT);
+ }
+
+ if (params.flags & MS_BIND) {
+ // We're doing a bind mount.
+ if (description.is_null())
+ return -EBADF;
+ if (!description->custody()) {
+ // We only support bind-mounting inodes, not arbitrary files.
+ return -ENODEV;
+ }
+ return VFS::the().bind_mount(*description->custody(), target_custody, params.flags);
+ }
+
+ RefPtr<FS> fs;
+
+ if (fs_type == "ext2" || fs_type == "Ext2FS") {
+ if (description.is_null())
+ return -EBADF;
+ if (!description->file().is_seekable()) {
+ dbg() << "mount: this is not a seekable file";
+ return -ENODEV;
+ }
+
+ dbg() << "mount: attempting to mount " << description->absolute_path() << " on " << target;
+
+ fs = Ext2FS::create(*description);
+ } else if (fs_type == "9p" || fs_type == "Plan9FS") {
+ if (description.is_null())
+ return -EBADF;
+
+ fs = Plan9FS::create(*description);
+ } else if (fs_type == "proc" || fs_type == "ProcFS") {
+ fs = ProcFS::create();
+ } else if (fs_type == "devpts" || fs_type == "DevPtsFS") {
+ fs = DevPtsFS::create();
+ } else if (fs_type == "tmp" || fs_type == "TmpFS") {
+ fs = TmpFS::create();
+ } else {
+ return -ENODEV;
+ }
+
+ if (!fs->initialize()) {
+ dbg() << "mount: failed to initialize " << fs_type << " filesystem, fd - " << source_fd;
+ return -ENODEV;
+ }
+
+ auto result = VFS::the().mount(fs.release_nonnull(), target_custody, params.flags);
+ if (!description.is_null())
+ dbg() << "mount: successfully mounted " << description->absolute_path() << " on " << target;
+ else
+ dbg() << "mount: successfully mounted " << target;
+ return result;
+}
+
+int Process::sys$umount(const char* user_mountpoint, size_t mountpoint_length)
+{
+ if (!is_superuser())
+ return -EPERM;
+
+ REQUIRE_NO_PROMISES;
+
+ if (!validate_read(user_mountpoint, mountpoint_length))
+ return -EFAULT;
+
+ auto mountpoint = get_syscall_path_argument(user_mountpoint, mountpoint_length);
+ if (mountpoint.is_error())
+ return mountpoint.error();
+
+ auto custody_or_error = VFS::the().resolve_path(mountpoint.value(), current_directory());
+ if (custody_or_error.is_error())
+ return custody_or_error.error();
+
+ auto& guest_inode = custody_or_error.value()->inode();
+ return VFS::the().unmount(guest_inode);
+}
+
+}