summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Base/etc/fstab4
-rw-r--r--Kernel/CMakeLists.txt1
-rw-r--r--Kernel/FileSystem/DevFS.cpp493
-rw-r--r--Kernel/FileSystem/DevFS.h194
-rw-r--r--Kernel/Syscalls/mount.cpp3
-rwxr-xr-xMeta/build-root-filesystem.sh53
-rw-r--r--Services/SystemServer/main.cpp81
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;