ladybird/Kernel/Syscalls/mount.cpp
Liav A 97f8927da6 Kernel: Remove the DevTmpFS class
Although this code worked quite well, it is considered to be a code
duplication with the TmpFS code which is more tested and works quite
well for a variety of cases. The only valid reason to keep this
filesystem was that it enforces that no regular files will be created at
all in the filesystem. Later on, we will re-introduce this feature in a
sane manner. Therefore, this can be safely removed after SystemServer no
longer uses this filesystem type anymore.
2022-10-22 19:18:15 +02:00

143 lines
5.5 KiB
C++

/*
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <Kernel/FileSystem/Custody.h>
#include <Kernel/FileSystem/DevPtsFS.h>
#include <Kernel/FileSystem/Ext2FileSystem.h>
#include <Kernel/FileSystem/FATFileSystem.h>
#include <Kernel/FileSystem/ISO9660FileSystem.h>
#include <Kernel/FileSystem/Plan9FileSystem.h>
#include <Kernel/FileSystem/ProcFS.h>
#include <Kernel/FileSystem/SysFS.h>
#include <Kernel/FileSystem/TmpFS.h>
#include <Kernel/FileSystem/VirtualFileSystem.h>
#include <Kernel/Process.h>
namespace Kernel {
struct FileSystemInitializer {
StringView short_name;
StringView name;
bool requires_open_file_description { false };
bool requires_block_device { false };
bool requires_seekable_file { false };
ErrorOr<NonnullLockRefPtr<FileSystem>> (*create_with_fd)(OpenFileDescription&) = nullptr;
ErrorOr<NonnullLockRefPtr<FileSystem>> (*create)(void) = nullptr;
};
static constexpr FileSystemInitializer s_initializers[] = {
{ "proc"sv, "ProcFS"sv, false, false, false, {}, ProcFS::try_create },
{ "devpts"sv, "DevPtsFS"sv, false, false, false, {}, DevPtsFS::try_create },
{ "sys"sv, "SysFS"sv, false, false, false, {}, SysFS::try_create },
{ "tmp"sv, "TmpFS"sv, false, false, false, {}, TmpFS::try_create },
{ "ext2"sv, "Ext2FS"sv, true, true, true, Ext2FS::try_create, {} },
{ "9p"sv, "Plan9FS"sv, true, true, true, Plan9FS::try_create, {} },
{ "iso9660"sv, "ISO9660FS"sv, true, true, true, ISO9660FS::try_create, {} },
{ "fat"sv, "FATFS"sv, true, true, true, FATFS::try_create, {} },
};
static ErrorOr<NonnullLockRefPtr<FileSystem>> create_filesystem_instance(StringView fs_type, OpenFileDescription* possible_description)
{
for (auto& initializer_entry : s_initializers) {
if (fs_type != initializer_entry.short_name && fs_type != initializer_entry.name)
continue;
if (!initializer_entry.requires_open_file_description) {
VERIFY(initializer_entry.create);
NonnullLockRefPtr<FileSystem> fs = TRY(initializer_entry.create());
return fs;
}
VERIFY(initializer_entry.create_with_fd);
if (!possible_description)
return EBADF;
OpenFileDescription& description = *possible_description;
if (initializer_entry.requires_block_device && !description.file().is_block_device())
return ENOTBLK;
if (initializer_entry.requires_seekable_file && !description.file().is_seekable()) {
dbgln("mount: this is not a seekable file");
return ENODEV;
}
NonnullLockRefPtr<FileSystem> fs = TRY(initializer_entry.create_with_fd(description));
return fs;
}
return ENODEV;
}
ErrorOr<FlatPtr> Process::sys$mount(Userspace<Syscall::SC_mount_params const*> user_params)
{
VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this);
TRY(require_no_promises());
auto credentials = this->credentials();
if (!credentials->is_superuser())
return EPERM;
auto params = TRY(copy_typed_from_user(user_params));
auto source_fd = params.source_fd;
auto target = TRY(try_copy_kstring_from_user(params.target));
auto fs_type_string = TRY(try_copy_kstring_from_user(params.fs_type));
auto fs_type = fs_type_string->view();
auto description_or_error = open_file_description(source_fd);
if (!description_or_error.is_error())
dbgln("mount {}: source fd {} @ {}", fs_type, source_fd, target);
else
dbgln("mount {} @ {}", fs_type, target);
auto target_custody = TRY(VirtualFileSystem::the().resolve_path(credentials, target->view(), current_directory()));
if (params.flags & MS_REMOUNT) {
// We're not creating a new mount, we're updating an existing one!
TRY(VirtualFileSystem::the().remount(target_custody, params.flags & ~MS_REMOUNT));
return 0;
}
if (params.flags & MS_BIND) {
// We're doing a bind mount.
if (description_or_error.is_error())
return description_or_error.release_error();
auto description = description_or_error.release_value();
if (!description->custody()) {
// We only support bind-mounting inodes, not arbitrary files.
return ENODEV;
}
TRY(VirtualFileSystem::the().bind_mount(*description->custody(), target_custody, params.flags));
return 0;
}
LockRefPtr<FileSystem> fs;
if (!description_or_error.is_error()) {
auto description = description_or_error.release_value();
fs = TRY(create_filesystem_instance(fs_type, description.ptr()));
auto source_pseudo_path = TRY(description->pseudo_path());
dbgln("mount: attempting to mount {} on {}", source_pseudo_path, target);
} else {
fs = TRY(create_filesystem_instance(fs_type, {}));
}
TRY(fs->initialize());
TRY(VirtualFileSystem::the().mount(*fs, target_custody, params.flags));
return 0;
}
ErrorOr<FlatPtr> Process::sys$umount(Userspace<char const*> user_mountpoint, size_t mountpoint_length)
{
VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this);
auto credentials = this->credentials();
if (!credentials->is_superuser())
return EPERM;
TRY(require_no_promises());
auto mountpoint = TRY(get_syscall_path_argument(user_mountpoint, mountpoint_length));
auto custody = TRY(VirtualFileSystem::the().resolve_path(credentials, mountpoint->view(), current_directory()));
auto& guest_inode = custody->inode();
TRY(VirtualFileSystem::the().unmount(guest_inode));
return 0;
}
}