diff options
-rw-r--r-- | Base/etc/fstab | 4 | ||||
-rw-r--r-- | Kernel/CMakeLists.txt | 1 | ||||
-rw-r--r-- | Kernel/FileSystem/DevFS.cpp | 493 | ||||
-rw-r--r-- | Kernel/FileSystem/DevFS.h | 194 | ||||
-rw-r--r-- | Kernel/Syscalls/mount.cpp | 3 | ||||
-rwxr-xr-x | Meta/build-root-filesystem.sh | 53 | ||||
-rw-r--r-- | Services/SystemServer/main.cpp | 81 |
7 files changed, 774 insertions, 55 deletions
diff --git a/Base/etc/fstab b/Base/etc/fstab index 4cff6ee8a6..4ca46238da 100644 --- a/Base/etc/fstab +++ b/Base/etc/fstab @@ -1,8 +1,7 @@ # Root file system. This is a fake entry which gets ignored by `mount -a`; # the actual logic for mounting root is in the kernel. /dev/hda / ext2 nodev,nosuid,ro -# Remount /bin, /dev, /root, and /home while adding the appropriate permissions. -/dev /dev bind bind,nosuid,ro +# Remount /bin, /root, and /home while adding the appropriate permissions. /bin /bin bind bind,nodev,ro /etc /etc bind bind,nodev,nosuid /home /home bind bind,nodev,nosuid @@ -10,5 +9,4 @@ /var /var bind bind,nodev,nosuid none /proc proc nosuid -none /dev/pts devpts noexec,nosuid,ro none /tmp tmp nodev,nosuid diff --git a/Kernel/CMakeLists.txt b/Kernel/CMakeLists.txt index 6e52b21545..8467eaa7b3 100644 --- a/Kernel/CMakeLists.txt +++ b/Kernel/CMakeLists.txt @@ -47,6 +47,7 @@ set(KERNEL_SOURCES DoubleBuffer.cpp FileSystem/BlockBasedFileSystem.cpp FileSystem/Custody.cpp + FileSystem/DevFS.cpp FileSystem/DevPtsFS.cpp FileSystem/Ext2FileSystem.cpp FileSystem/FIFO.cpp diff --git a/Kernel/FileSystem/DevFS.cpp b/Kernel/FileSystem/DevFS.cpp new file mode 100644 index 0000000000..f86fda89e9 --- /dev/null +++ b/Kernel/FileSystem/DevFS.cpp @@ -0,0 +1,493 @@ +/* + * Copyright (c) 2020, Liav A. <liavalb@hotmail.co.il> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <AK/Singleton.h> +#include <AK/StringBuilder.h> +#include <AK/StringView.h> +#include <Kernel/FileSystem/DevFS.h> +#include <Kernel/FileSystem/VirtualFileSystem.h> + +namespace Kernel { + +NonnullRefPtr<DevFS> DevFS::create() +{ + return adopt(*new DevFS); +} + +DevFS::DevFS() + : m_root_inode(adopt(*new DevFSRootDirectoryInode(*this))) +{ + LOCKER(m_lock); + Device::for_each([&](Device& device) { + // FIXME: Find a better way to not add MasterPTYs or SlavePTYs! + if (device.is_master_pty() || (device.is_character_device() && device.major() == 201)) + return; + notify_new_device(device); + }); +} + +void DevFS::notify_new_device(Device& device) +{ + LOCKER(m_lock); + auto new_device_inode = adopt(*new DevFSDeviceInode(*this, device)); + m_nodes.append(new_device_inode); + m_root_inode->m_devices.append(new_device_inode); +} + +size_t DevFS::get_new_inode_index() +{ + LOCKER(m_lock); + return 1 + (++m_inode_index); +} + +void DevFS::notify_device_removal(Device&) +{ + TODO(); +} + +DevFS::~DevFS() +{ +} + +bool DevFS::initialize() +{ + return true; +} + +NonnullRefPtr<Inode> DevFS::root_inode() const +{ + return *m_root_inode; +} + +RefPtr<Inode> DevFS::get_inode(InodeIdentifier inode_id) const +{ + LOCKER(m_lock); + if (inode_id.index() == 1) + return m_root_inode; + for (auto& node : m_nodes) { + if (inode_id.index() == node.index()) + return node; + } + return nullptr; +} + +DevFSInode::DevFSInode(DevFS& fs) + : Inode(fs, fs.get_new_inode_index()) +{ +} +ssize_t DevFSInode::read_bytes(off_t, ssize_t, UserOrKernelBuffer&, FileDescription*) const +{ + ASSERT_NOT_REACHED(); +} + +KResult DevFSInode::traverse_as_directory(Function<bool(const FS::DirectoryEntryView&)>) const +{ + ASSERT_NOT_REACHED(); +} + +RefPtr<Inode> DevFSInode::lookup(StringView) +{ + ASSERT_NOT_REACHED(); +} + +void DevFSInode::flush_metadata() +{ +} + +ssize_t DevFSInode::write_bytes(off_t, ssize_t, const UserOrKernelBuffer&, FileDescription*) +{ + ASSERT_NOT_REACHED(); +} + +KResultOr<NonnullRefPtr<Inode>> DevFSInode::create_child(const String&, mode_t, dev_t, uid_t, gid_t) +{ + return KResult(-EROFS); +} + +KResult DevFSInode::add_child(Inode&, const StringView&, mode_t) +{ + return KResult(-EROFS); +} + +KResult DevFSInode::remove_child(const StringView&) +{ + return KResult(-EROFS); +} + +KResultOr<size_t> DevFSInode::directory_entry_count() const +{ + ASSERT_NOT_REACHED(); +} + +KResult DevFSInode::chmod(mode_t) +{ + return KResult(-EPERM); +} + +KResult DevFSInode::chown(uid_t, gid_t) +{ + return KResult(-EPERM); +} + +KResult DevFSInode::truncate(u64) +{ + return KResult(-EPERM); +} + +String DevFSLinkInode::name() const +{ + return m_name; +} +DevFSLinkInode::~DevFSLinkInode() +{ +} +DevFSLinkInode::DevFSLinkInode(DevFS& fs, String name) + : DevFSInode(fs) + , m_name(name) +{ +} +ssize_t DevFSLinkInode::read_bytes(off_t offset, ssize_t, UserOrKernelBuffer& buffer, FileDescription*) const +{ + LOCKER(m_lock); + ASSERT(offset == 0); + ASSERT(!m_link.is_null()); + if (!buffer.write(((const u8*)m_link.substring_view(0).characters_without_null_termination()) + offset, m_link.length())) + return -EFAULT; + return m_link.length(); +} +InodeMetadata DevFSLinkInode::metadata() const +{ + LOCKER(m_lock); + InodeMetadata metadata; + metadata.inode = { fsid(), index() }; + metadata.mode = S_IFLNK | 0555; + metadata.uid = 0; + metadata.gid = 0; + metadata.size = 0; + metadata.mtime = mepoch; + return metadata; +} +ssize_t DevFSLinkInode::write_bytes(off_t offset, ssize_t count, const UserOrKernelBuffer& buffer, FileDescription*) +{ + LOCKER(m_lock); + ASSERT(offset == 0); + ASSERT(buffer.is_kernel_buffer()); + m_link = buffer.copy_into_string(count); + return count; +} + +DevFSDirectoryInode::DevFSDirectoryInode(DevFS& fs) + : DevFSInode(fs) +{ +} +DevFSDirectoryInode::~DevFSDirectoryInode() +{ +} +InodeMetadata DevFSDirectoryInode::metadata() const +{ + LOCKER(m_lock); + InodeMetadata metadata; + metadata.inode = { fsid(), 1 }; + metadata.mode = 0040555; + metadata.uid = 0; + metadata.gid = 0; + metadata.size = 0; + metadata.mtime = mepoch; + return metadata; +} +KResult DevFSDirectoryInode::traverse_as_directory(Function<bool(const FS::DirectoryEntryView&)>) const +{ + LOCKER(m_lock); + return KResult(-EINVAL); +} +RefPtr<Inode> DevFSDirectoryInode::lookup(StringView) +{ + LOCKER(m_lock); + return nullptr; +} +KResultOr<size_t> DevFSDirectoryInode::directory_entry_count() const +{ + LOCKER(m_lock); + return m_devices.size(); +} + +DevFSRootDirectoryInode::DevFSRootDirectoryInode(DevFS& fs) + : DevFSDirectoryInode(fs) + , m_parent_fs(fs) +{ +} +KResult DevFSRootDirectoryInode::traverse_as_directory(Function<bool(const FS::DirectoryEntryView&)> callback) const +{ + LOCKER(m_parent_fs.m_lock); + callback({ ".", identifier(), 0 }); + callback({ "..", identifier(), 0 }); + + for (auto& folder : m_subfolders) { + InodeIdentifier identifier = { fsid(), folder.index() }; + callback({ folder.name(), identifier, 0 }); + } + for (auto& link : m_links) { + InodeIdentifier identifier = { fsid(), link.index() }; + callback({ link.name(), identifier, 0 }); + } + + for (auto& device_node : m_devices) { + InodeIdentifier identifier = { fsid(), device_node.index() }; + callback({ device_node.name(), identifier, 0 }); + } + return KSuccess; +} +RefPtr<Inode> DevFSRootDirectoryInode::lookup(StringView name) +{ + LOCKER(m_parent_fs.m_lock); + for (auto& subfolder : m_subfolders) { + if (subfolder.name() == name) + return subfolder; + } + for (auto& link : m_links) { + if (link.name() == name) + return link; + } + + for (auto& device_node : m_devices) { + if (device_node.name() == name) { + return device_node; + } + } + return nullptr; +} +KResultOr<NonnullRefPtr<Inode>> DevFSRootDirectoryInode::create_child(const String& name, mode_t mode, dev_t, uid_t, gid_t) +{ + LOCKER(m_parent_fs.m_lock); + + InodeMetadata metadata; + metadata.mode = mode; + if (metadata.is_directory()) { + for (auto& folder : m_subfolders) { + if (folder.name() == name) + return KResult(-EEXIST); + } + if (name != "pts") + return KResult(-EROFS); + auto new_directory_inode = adopt(*new DevFSPtsDirectoryInode(m_parent_fs)); + m_subfolders.append(new_directory_inode); + m_parent_fs.m_nodes.append(new_directory_inode); + return KResult(KSuccess); + } + if (metadata.is_symlink()) { + for (auto& link : m_links) { + if (link.name() == name) + return KResult(-EEXIST); + } + dbg() << "DevFS: Success on create new symlink"; + auto new_link_inode = adopt(*new DevFSLinkInode(m_parent_fs, name)); + m_links.append(new_link_inode); + m_parent_fs.m_nodes.append(new_link_inode); + return new_link_inode; + } + return KResult(-EROFS); +} + +DevFSRootDirectoryInode::~DevFSRootDirectoryInode() +{ +} +InodeMetadata DevFSRootDirectoryInode::metadata() const +{ + LOCKER(m_parent_fs.m_lock); + InodeMetadata metadata; + metadata.inode = { fsid(), 1 }; + metadata.mode = 0040555; + metadata.uid = 0; + metadata.gid = 0; + metadata.size = 0; + metadata.mtime = mepoch; + return metadata; +} +KResultOr<size_t> DevFSRootDirectoryInode::directory_entry_count() const +{ + LOCKER(m_parent_fs.m_lock); + return m_devices.size() + DevFSDirectoryInode::directory_entry_count().value(); +} + +DevFSDeviceInode::DevFSDeviceInode(DevFS& fs, const Device& device) + : DevFSInode(fs) + , m_attached_device(device) +{ +} +DevFSDeviceInode::~DevFSDeviceInode() +{ +} +KResult DevFSDeviceInode::chown(uid_t uid, gid_t gid) +{ + LOCKER(m_lock); + m_uid = uid; + m_gid = gid; + return KSuccess; +} + +String DevFSDeviceInode::name() const +{ + if (m_cached_name.is_null() || m_cached_name.is_empty()) + const_cast<DevFSDeviceInode&>(*this).m_cached_name = determine_name(); + return m_cached_name; +} + +String DevFSDeviceInode::determine_name() const +{ + LOCKER(m_lock); + if (m_attached_device->is_character_device()) { + switch (m_attached_device->major()) { + case 85: + if (m_attached_device->minor() == 1) + return "keyboard"; + ASSERT_NOT_REACHED(); + case 10: + if (m_attached_device->minor() == 1) + return "mouse"; + ASSERT_NOT_REACHED(); + case 42: + if (m_attached_device->minor() == 42) + return "audio"; + ASSERT_NOT_REACHED(); + case 1: + switch (m_attached_device->minor()) { + case 8: + return "random"; + case 3: + return "null"; + case 5: + return "zero"; + case 7: + return "full"; + default: + ASSERT_NOT_REACHED(); + } + case 5: + if (m_attached_device->minor() == 1) + return "console"; + if (m_attached_device->minor() == 2) + return "ptmx"; + ASSERT_NOT_REACHED(); + + case 4: + if (m_attached_device->minor() >= 64) + return String::format("ttyS%d", m_attached_device->minor() - 64); + return String::format("tty%d", m_attached_device->minor()); + + default: + ASSERT_NOT_REACHED(); + } + } else { + switch (m_attached_device->major()) { + case 29: + return String::format("fb%d", m_attached_device->minor()); + case 3: { + size_t drive_index = (u8)'a' + m_attached_device->minor(); + char drive_letter = (u8)drive_index; + return String::format("hd%c", drive_letter); + } + + case 100: + return "hda1"; + } + } + + ASSERT_NOT_REACHED(); +} +ssize_t DevFSDeviceInode::read_bytes(off_t offset, ssize_t count, UserOrKernelBuffer& buffer, FileDescription* description) const +{ + LOCKER(m_lock); + ASSERT(!!description); + if (!m_attached_device->can_read(*description, offset)) + return -EIO; + auto nread = const_cast<Device&>(*m_attached_device).read(*description, offset, buffer, count); + if (nread.is_error()) + return -EIO; + return nread.value(); +} + +InodeMetadata DevFSDeviceInode::metadata() const +{ + LOCKER(m_lock); + InodeMetadata metadata; + metadata.inode = { fsid(), index() }; + metadata.mode = (m_attached_device->is_block_device() ? S_IFBLK : S_IFCHR) | m_attached_device->required_mode(); + metadata.uid = m_uid; + metadata.gid = m_gid; + metadata.size = 0; + metadata.mtime = mepoch; + metadata.major_device = m_attached_device->major(); + metadata.minor_device = m_attached_device->minor(); + return metadata; +} +ssize_t DevFSDeviceInode::write_bytes(off_t offset, ssize_t count, const UserOrKernelBuffer& buffer, FileDescription* description) +{ + LOCKER(m_lock); + ASSERT(!!description); + if (!m_attached_device->can_read(*description, offset)) + return -EIO; + auto nread = const_cast<Device&>(*m_attached_device).write(*description, offset, buffer, count); + if (nread.is_error()) + return -EIO; + return nread.value(); +} + +DevFSPtsDirectoryInode::DevFSPtsDirectoryInode(DevFS& fs) + : DevFSDirectoryInode(fs) +{ +} +KResult DevFSPtsDirectoryInode::traverse_as_directory(Function<bool(const FS::DirectoryEntryView&)> callback) const +{ + LOCKER(m_lock); + callback({ ".", identifier(), 0 }); + callback({ "..", identifier(), 0 }); + return KSuccess; +} +RefPtr<Inode> DevFSPtsDirectoryInode::lookup(StringView) +{ + return nullptr; +} +DevFSPtsDirectoryInode::~DevFSPtsDirectoryInode() +{ +} +InodeMetadata DevFSPtsDirectoryInode::metadata() const +{ + LOCKER(m_lock); + InodeMetadata metadata; + metadata.inode = { fsid(), index() }; + metadata.mode = 0040555; + metadata.uid = 0; + metadata.gid = 0; + metadata.size = 0; + metadata.mtime = mepoch; + return metadata; +} +KResultOr<size_t> DevFSPtsDirectoryInode::directory_entry_count() const +{ + return 0; +} + +} diff --git a/Kernel/FileSystem/DevFS.h b/Kernel/FileSystem/DevFS.h new file mode 100644 index 0000000000..ab12a605db --- /dev/null +++ b/Kernel/FileSystem/DevFS.h @@ -0,0 +1,194 @@ +/* + * Copyright (c) 2020, Liav A. <liavalb@hotmail.co.il> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include <AK/Types.h> +#include <Kernel/FileSystem/FileSystem.h> +#include <Kernel/FileSystem/Inode.h> +#include <Kernel/FileSystem/InodeMetadata.h> +#include <Kernel/TTY/SlavePTY.h> + +namespace Kernel { + +class DevFSInode; +class DevFSDeviceInode; +class DevFSDirectoryInode; +class DevFSRootDirectoryInode; +class DevFSDevicesDirectoryInode; +class DevFSPtsDirectoryInode; +class Device; +class DevFS final : public FS { + friend class DevFSInode; + friend class DevFSRootDirectoryInode; + +public: + virtual ~DevFS() override; + static NonnullRefPtr<DevFS> create(); + + virtual bool initialize() override; + virtual const char* class_name() const override { return "DevFS"; } + + void notify_new_device(Device&); + void notify_device_removal(Device&); + + virtual NonnullRefPtr<Inode> root_inode() const override; + +private: + DevFS(); + RefPtr<Inode> get_inode(InodeIdentifier) const; + size_t get_new_inode_index(); + + NonnullRefPtr<DevFSRootDirectoryInode> m_root_inode; + NonnullRefPtrVector<DevFSInode> m_nodes; + + size_t m_inode_index { 0 }; +}; + +class DevFSInode : public Inode { + friend class DevFS; + friend class DevFSRootDirectoryInode; + +public: + virtual String name() const = 0; + +protected: + DevFSInode(DevFS&); + virtual ssize_t read_bytes(off_t, ssize_t, UserOrKernelBuffer& buffer, FileDescription*) const override; + virtual KResult traverse_as_directory(Function<bool(const FS::DirectoryEntryView&)>) const override; + virtual RefPtr<Inode> lookup(StringView name) override; + virtual void flush_metadata() override; + virtual ssize_t write_bytes(off_t, ssize_t, const UserOrKernelBuffer& buffer, FileDescription*) override; + virtual KResultOr<NonnullRefPtr<Inode>> create_child(const String& name, mode_t, dev_t, uid_t, gid_t) override; + virtual KResult add_child(Inode&, const StringView& name, mode_t) override; + virtual KResult remove_child(const StringView& name) override; + virtual KResultOr<size_t> directory_entry_count() const override; + virtual KResult chmod(mode_t) override; + virtual KResult chown(uid_t, gid_t) override; + virtual KResult truncate(u64) override; + +private: + size_t m_index; +}; + +class DevFSDeviceInode : public DevFSInode { + friend class DevFS; + friend class DevFSRootDirectoryInode; + +public: + virtual String name() const override; + virtual ~DevFSDeviceInode() override; + +private: + String determine_name() const; + DevFSDeviceInode(DevFS&, const Device&); + // ^Inode + virtual ssize_t read_bytes(off_t, ssize_t, UserOrKernelBuffer& buffer, FileDescription*) const override; + virtual InodeMetadata metadata() const override; + virtual ssize_t write_bytes(off_t, ssize_t, const UserOrKernelBuffer& buffer, FileDescription*) override; + virtual KResult chown(uid_t, gid_t) override; + + NonnullRefPtr<Device> m_attached_device; + String m_cached_name; + + uid_t m_uid { 0 }; + gid_t m_gid { 0 }; +}; + +class DevFSLinkInode : public DevFSInode { + friend class DevFS; + friend class DevFSRootDirectoryInode; + +public: + virtual String name() const override; + virtual ~DevFSLinkInode() override; + +protected: + DevFSLinkInode(DevFS&, String); + // ^Inode + virtual ssize_t read_bytes(off_t, ssize_t, UserOrKernelBuffer& buffer, FileDescription*) const override; + virtual InodeMetadata metadata() const override; + virtual ssize_t write_bytes(off_t, ssize_t, const UserOrKernelBuffer& buffer, FileDescription*) override; + + const String m_name; + String m_link; +}; + +class DevFSDirectoryInode : public DevFSInode { + friend class DevFS; + friend class DevFSRootDirectoryInode; + +public: + virtual ~DevFSDirectoryInode() override; + +protected: + DevFSDirectoryInode(DevFS&); + // ^Inode + virtual InodeMetadata metadata() const override; + virtual KResult traverse_as_directory(Function<bool(const FS::DirectoryEntryView&)>) const override; + virtual RefPtr<Inode> lookup(StringView name) override; + virtual KResultOr<size_t> directory_entry_count() const override; + + NonnullRefPtrVector<DevFSDeviceInode> m_devices; +}; + +class DevFSPtsDirectoryInode final : public DevFSDirectoryInode { + friend class DevFS; + friend class DevFSRootDirectoryInode; + +public: + virtual ~DevFSPtsDirectoryInode() override; + virtual String name() const override { return "pts"; }; + +private: + explicit DevFSPtsDirectoryInode(DevFS&); + virtual KResult traverse_as_directory(Function<bool(const FS::DirectoryEntryView&)>) const override; + virtual RefPtr<Inode> lookup(StringView name) override; + virtual InodeMetadata metadata() const override; + virtual KResultOr<size_t> directory_entry_count() const override; +}; + +class DevFSRootDirectoryInode final : public DevFSDirectoryInode { + friend class DevFS; + +public: + virtual ~DevFSRootDirectoryInode() override; + virtual String name() const override { return "."; } + +private: + explicit DevFSRootDirectoryInode(DevFS&); + virtual KResultOr<NonnullRefPtr<Inode>> create_child(const String& name, mode_t, dev_t, uid_t, gid_t) override; + virtual KResult traverse_as_directory(Function<bool(const FS::DirectoryEntryView&)>) const override; + virtual RefPtr<Inode> lookup(StringView name) override; + virtual InodeMetadata metadata() const override; + virtual KResultOr<size_t> directory_entry_count() const override; + + NonnullRefPtrVector<DevFSDirectoryInode> m_subfolders; + NonnullRefPtrVector<DevFSLinkInode> m_links; + DevFS& m_parent_fs; +}; + +} diff --git a/Kernel/Syscalls/mount.cpp b/Kernel/Syscalls/mount.cpp index ca95f84636..e2d12c8141 100644 --- a/Kernel/Syscalls/mount.cpp +++ b/Kernel/Syscalls/mount.cpp @@ -25,6 +25,7 @@ */ #include <Kernel/FileSystem/Custody.h> +#include <Kernel/FileSystem/DevFS.h> #include <Kernel/FileSystem/DevPtsFS.h> #include <Kernel/FileSystem/Ext2FileSystem.h> #include <Kernel/FileSystem/Plan9FileSystem.h> @@ -104,6 +105,8 @@ int Process::sys$mount(Userspace<const Syscall::SC_mount_params*> user_params) fs = ProcFS::create(); } else if (fs_type == "devpts" || fs_type == "DevPtsFS") { fs = DevPtsFS::create(); + } else if (fs_type == "dev" || fs_type == "DevFS") { + fs = DevFS::create(); } else if (fs_type == "tmp" || fs_type == "TmpFS") { fs = TmpFS::create(); } else { diff --git a/Meta/build-root-filesystem.sh b/Meta/build-root-filesystem.sh index 4c8e650f33..d2894e00d1 100755 --- a/Meta/build-root-filesystem.sh +++ b/Meta/build-root-filesystem.sh @@ -3,9 +3,7 @@ set -e wheel_gid=1 -tty_gid=2 phys_gid=3 -audio_gid=4 utmp_gid=5 window_uid=13 window_gid=13 @@ -82,57 +80,8 @@ chown 0:$utmp_gid mnt/var/run/utmp chmod 664 mnt/var/run/utmp echo "done" -printf "setting up device nodes... " +printf "setting up device nodes folder... " mkdir -p mnt/dev -mkdir -p mnt/dev/pts -mknod mnt/dev/fb0 b 29 0 -chmod 660 mnt/dev/fb0 -chown 0:$phys_gid mnt/dev/fb0 -mknod mnt/dev/tty0 c 4 0 -mknod mnt/dev/tty1 c 4 1 -mknod mnt/dev/tty2 c 4 2 -mknod mnt/dev/tty3 c 4 3 -mknod mnt/dev/ttyS0 c 4 64 -mknod mnt/dev/ttyS1 c 4 65 -mknod mnt/dev/ttyS2 c 4 66 -mknod mnt/dev/ttyS3 c 4 67 -for tty in 0 1 2 3 S0 S1 S2 S3; do - chmod 620 mnt/dev/tty$tty - chown 0:$tty_gid mnt/dev/tty$tty -done -mknod mnt/dev/random c 1 8 -mknod mnt/dev/null c 1 3 -mknod mnt/dev/zero c 1 5 -mknod mnt/dev/full c 1 7 -# random, is failing (randomly) on fuse-ext2 on macos :) -chmod 666 mnt/dev/random || true -ln -s random mnt/dev/urandom -chmod 666 mnt/dev/null -chmod 666 mnt/dev/zero -chmod 666 mnt/dev/full -mknod mnt/dev/keyboard c 85 1 -chmod 440 mnt/dev/keyboard -chown 0:$phys_gid mnt/dev/keyboard -mknod mnt/dev/mouse c 10 1 -chmod 440 mnt/dev/mouse -chown 0:$phys_gid mnt/dev/mouse -mknod mnt/dev/audio c 42 42 -chmod 220 mnt/dev/audio -chown 0:$audio_gid mnt/dev/audio -mknod mnt/dev/ptmx c 5 2 -chmod 666 mnt/dev/ptmx -mknod mnt/dev/hda b 3 0 -mknod mnt/dev/hdb b 3 1 -mknod mnt/dev/hdc b 3 2 -mknod mnt/dev/hdd b 3 3 -for hd in a b c d; do - chmod 600 mnt/dev/hd$hd -done - -ln -s /proc/self/fd/0 mnt/dev/stdin -ln -s /proc/self/fd/1 mnt/dev/stdout -ln -s /proc/self/fd/2 mnt/dev/stderr -echo "done" printf "writing version file... " GIT_HASH=$( (git log --pretty=format:'%h' -n 1 | head -c 7) || true ) diff --git a/Services/SystemServer/main.cpp b/Services/SystemServer/main.cpp index 4e57a74a74..26b7abef96 100644 --- a/Services/SystemServer/main.cpp +++ b/Services/SystemServer/main.cpp @@ -34,6 +34,7 @@ #include <errno.h> #include <signal.h> #include <stdio.h> +#include <sys/stat.h> #include <sys/types.h> #include <sys/wait.h> #include <unistd.h> @@ -84,6 +85,84 @@ static void parse_boot_mode() dbg() << "Booting in " << g_boot_mode << " mode"; } +static void prepare_devfs() +{ + // FIXME: Find a better way to all of this stuff, without hardcoding all of this! + + int rc = mount(-1, "/dev", "dev", 0); + if (rc != 0) { + ASSERT_NOT_REACHED(); + } + + rc = mkdir("/dev/pts", 0755); + if (rc != 0) { + ASSERT_NOT_REACHED(); + } + + rc = mount(-1, "/dev/pts", "devpts", 0); + if (rc != 0) { + ASSERT_NOT_REACHED(); + } + + rc = symlink("/dev/random", "/dev/urandom"); + if (rc < 0) { + ASSERT_NOT_REACHED(); + } + + // FIXME: Find a better way to chown without hardcoding the gid! + rc = chown("/dev/fb0", 0, 3); + if (rc < 0) { + ASSERT_NOT_REACHED(); + } + + // FIXME: Find a better way to chown without hardcoding the gid! + rc = chown("/dev/keyboard", 0, 3); + if (rc < 0) { + ASSERT_NOT_REACHED(); + } + + // FIXME: Find a better way to chown without hardcoding the gid! + rc = chown("/dev/mouse", 0, 3); + if (rc < 0) { + ASSERT_NOT_REACHED(); + } + + for (size_t index = 0; index < 4; index++) { + // FIXME: Find a better way to chown without hardcoding the gid! + rc = chown(String::format("/dev/tty%d", index).characters(), 0, 2); + if (rc < 0) { + ASSERT_NOT_REACHED(); + } + } + + for (size_t index = 0; index < 4; index++) { + // FIXME: Find a better way to chown without hardcoding the gid! + rc = chown(String::format("/dev/ttyS%d", index).characters(), 0, 2); + if (rc < 0) { + ASSERT_NOT_REACHED(); + } + } + + // FIXME: Find a better way to chown without hardcoding the gid! + rc = chown("/dev/audio", 0, 4); + if (rc < 0) { + ASSERT_NOT_REACHED(); + } + + rc = symlink("/proc/self/fd/0", "/dev/stdin"); + if (rc < 0) { + ASSERT_NOT_REACHED(); + } + rc = symlink("/proc/self/fd/1", "/dev/stdout"); + if (rc < 0) { + ASSERT_NOT_REACHED(); + } + rc = symlink("/proc/self/fd/2", "/dev/stderr"); + if (rc < 0) { + ASSERT_NOT_REACHED(); + } +} + static void mount_all_filesystems() { dbg() << "Spawning mount -a to mount all filesystems."; @@ -103,6 +182,8 @@ static void mount_all_filesystems() int main(int, char**) { + prepare_devfs(); + if (pledge("stdio proc exec tty accept unix rpath wpath cpath chown fattr id sigaction", nullptr) < 0) { perror("pledge"); return 1; |