Serenity Operating System
at master 144 lines 5.9 kB view raw
1/* 2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7#include <Kernel/FileSystem/Custody.h> 8#include <Kernel/FileSystem/DevPtsFS/FileSystem.h> 9#include <Kernel/FileSystem/Ext2FS/FileSystem.h> 10#include <Kernel/FileSystem/FATFS/FileSystem.h> 11#include <Kernel/FileSystem/ISO9660FS/FileSystem.h> 12#include <Kernel/FileSystem/Plan9FS/FileSystem.h> 13#include <Kernel/FileSystem/ProcFS/FileSystem.h> 14#include <Kernel/FileSystem/RAMFS/FileSystem.h> 15#include <Kernel/FileSystem/SysFS/FileSystem.h> 16#include <Kernel/FileSystem/VirtualFileSystem.h> 17#include <Kernel/Process.h> 18 19namespace Kernel { 20 21struct FileSystemInitializer { 22 StringView short_name; 23 StringView name; 24 bool requires_open_file_description { false }; 25 bool requires_block_device { false }; 26 bool requires_seekable_file { false }; 27 ErrorOr<NonnullLockRefPtr<FileSystem>> (*create_with_fd)(OpenFileDescription&) = nullptr; 28 ErrorOr<NonnullLockRefPtr<FileSystem>> (*create)(void) = nullptr; 29}; 30 31static constexpr FileSystemInitializer s_initializers[] = { 32 { "proc"sv, "ProcFS"sv, false, false, false, {}, ProcFS::try_create }, 33 { "devpts"sv, "DevPtsFS"sv, false, false, false, {}, DevPtsFS::try_create }, 34 { "sys"sv, "SysFS"sv, false, false, false, {}, SysFS::try_create }, 35 { "ram"sv, "RAMFS"sv, false, false, false, {}, RAMFS::try_create }, 36 { "ext2"sv, "Ext2FS"sv, true, true, true, Ext2FS::try_create, {} }, 37 { "9p"sv, "Plan9FS"sv, true, true, true, Plan9FS::try_create, {} }, 38 { "iso9660"sv, "ISO9660FS"sv, true, true, true, ISO9660FS::try_create, {} }, 39 { "fat"sv, "FATFS"sv, true, true, true, FATFS::try_create, {} }, 40}; 41 42static ErrorOr<NonnullLockRefPtr<FileSystem>> find_or_create_filesystem_instance(StringView fs_type, OpenFileDescription* possible_description) 43{ 44 for (auto& initializer_entry : s_initializers) { 45 if (fs_type != initializer_entry.short_name && fs_type != initializer_entry.name) 46 continue; 47 if (!initializer_entry.requires_open_file_description) { 48 VERIFY(initializer_entry.create); 49 NonnullLockRefPtr<FileSystem> fs = TRY(initializer_entry.create()); 50 return fs; 51 } 52 // Note: If there's an associated file description with the filesystem, we could 53 // try to first find it from the VirtualFileSystem filesystem list and if it was not found, 54 // then create it and add it. 55 VERIFY(initializer_entry.create_with_fd); 56 if (!possible_description) 57 return EBADF; 58 OpenFileDescription& description = *possible_description; 59 60 if (initializer_entry.requires_block_device && !description.file().is_block_device()) 61 return ENOTBLK; 62 if (initializer_entry.requires_seekable_file && !description.file().is_seekable()) { 63 dbgln("mount: this is not a seekable file"); 64 return ENODEV; 65 } 66 return TRY(VirtualFileSystem::the().find_already_existing_or_create_file_backed_file_system(description, initializer_entry.create_with_fd)); 67 } 68 return ENODEV; 69} 70 71ErrorOr<FlatPtr> Process::sys$mount(Userspace<Syscall::SC_mount_params const*> user_params) 72{ 73 VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this); 74 TRY(require_no_promises()); 75 auto credentials = this->credentials(); 76 if (!credentials->is_superuser()) 77 return EPERM; 78 79 auto params = TRY(copy_typed_from_user(user_params)); 80 81 auto source_fd = params.source_fd; 82 auto target = TRY(try_copy_kstring_from_user(params.target)); 83 auto fs_type_string = TRY(try_copy_kstring_from_user(params.fs_type)); 84 auto fs_type = fs_type_string->view(); 85 86 auto description_or_error = open_file_description(source_fd); 87 if (!description_or_error.is_error()) 88 dbgln("mount {}: source fd {} @ {}", fs_type, source_fd, target); 89 else 90 dbgln("mount {} @ {}", fs_type, target); 91 92 auto target_custody = TRY(VirtualFileSystem::the().resolve_path(credentials, target->view(), current_directory())); 93 94 if (params.flags & MS_REMOUNT) { 95 // We're not creating a new mount, we're updating an existing one! 96 TRY(VirtualFileSystem::the().remount(target_custody, params.flags & ~MS_REMOUNT)); 97 return 0; 98 } 99 100 if (params.flags & MS_BIND) { 101 // We're doing a bind mount. 102 if (description_or_error.is_error()) 103 return description_or_error.release_error(); 104 auto description = description_or_error.release_value(); 105 if (!description->custody()) { 106 // We only support bind-mounting inodes, not arbitrary files. 107 return ENODEV; 108 } 109 TRY(VirtualFileSystem::the().bind_mount(*description->custody(), target_custody, params.flags)); 110 return 0; 111 } 112 113 LockRefPtr<FileSystem> fs; 114 115 if (!description_or_error.is_error()) { 116 auto description = description_or_error.release_value(); 117 fs = TRY(find_or_create_filesystem_instance(fs_type, description.ptr())); 118 auto source_pseudo_path = TRY(description->pseudo_path()); 119 dbgln("mount: attempting to mount {} on {}", source_pseudo_path, target); 120 } else { 121 fs = TRY(find_or_create_filesystem_instance(fs_type, {})); 122 } 123 124 TRY(fs->initialize()); 125 TRY(VirtualFileSystem::the().mount(*fs, target_custody, params.flags)); 126 return 0; 127} 128 129ErrorOr<FlatPtr> Process::sys$umount(Userspace<char const*> user_mountpoint, size_t mountpoint_length) 130{ 131 VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this); 132 auto credentials = this->credentials(); 133 if (!credentials->is_superuser()) 134 return EPERM; 135 136 TRY(require_no_promises()); 137 138 auto mountpoint = TRY(get_syscall_path_argument(user_mountpoint, mountpoint_length)); 139 auto custody = TRY(VirtualFileSystem::the().resolve_path(credentials, mountpoint->view(), current_directory())); 140 TRY(VirtualFileSystem::the().unmount(*custody)); 141 return 0; 142} 143 144}