kernel: Add pseudoterminals and a /dev/pts filesystem
This commit is contained in:
parent
fbfa5328d7
commit
fd46d134aa
@ -57,6 +57,8 @@ set(SOURCES
|
||||
src/net/UnixSocket.cpp
|
||||
src/fs/tmpfs/FileSystem.cpp
|
||||
src/fs/tmpfs/Inode.cpp
|
||||
src/fs/devpts/FileSystem.cpp
|
||||
src/fs/devpts/Inode.cpp
|
||||
src/fs/ext2/FileSystem.cpp
|
||||
src/fs/ext2/Inode.cpp
|
||||
src/fs/devices/DeviceRegistry.cpp
|
||||
@ -69,6 +71,9 @@ set(SOURCES
|
||||
src/fs/devices/UARTDevice.cpp
|
||||
src/fs/devices/MouseDevice.cpp
|
||||
src/fs/devices/KeyboardDevice.cpp
|
||||
src/fs/devices/PTYMultiplexer.cpp
|
||||
src/fs/devices/MasterPTY.cpp
|
||||
src/fs/devices/SlavePTY.cpp
|
||||
src/fs/InitRD.cpp
|
||||
src/binfmt/ELF.cpp
|
||||
src/binfmt/BinaryFormat.cpp
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "fs/devices/KeyboardDevice.h"
|
||||
#include "fs/devices/MouseDevice.h"
|
||||
#include "fs/devices/NullDevice.h"
|
||||
#include "fs/devices/PTYMultiplexer.h"
|
||||
#include "fs/devices/UARTDevice.h"
|
||||
#include "fs/devices/ZeroDevice.h"
|
||||
#include "fs/tmpfs/FileSystem.h"
|
||||
@ -92,6 +93,12 @@ namespace DeviceRegistry
|
||||
|
||||
for (const auto& descriptor : g_available_devices) TRY(create_special_device_inode(fs, descriptor));
|
||||
|
||||
auto multiplexer = TRY(make_shared<PTYMultiplexer>());
|
||||
multiplexer->set_fs(*fs);
|
||||
multiplexer->set_inode_number(TRY(fs->allocate_inode_number()));
|
||||
|
||||
TRY(fs->root_inode()->add_entry(multiplexer, "ptmx"));
|
||||
|
||||
return fs;
|
||||
}
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ namespace DeviceRegistry
|
||||
DiskPartition = 5,
|
||||
Serial = 6,
|
||||
Input = 7,
|
||||
Terminal = 8,
|
||||
};
|
||||
|
||||
Result<SharedPtr<Device>> fetch_special_device(u32 major, u32 minor);
|
||||
|
125
kernel/src/fs/devices/MasterPTY.cpp
Normal file
125
kernel/src/fs/devices/MasterPTY.cpp
Normal file
@ -0,0 +1,125 @@
|
||||
#include "fs/devices/MasterPTY.h"
|
||||
#include "Pledge.h"
|
||||
#include "fs/devices/DeviceRegistry.h"
|
||||
#include "fs/devices/PTYMultiplexer.h"
|
||||
#include "fs/devpts/FileSystem.h"
|
||||
#include "memory/MemoryManager.h"
|
||||
#include "thread/Scheduler.h"
|
||||
|
||||
Result<SharedPtr<VFS::Inode>> MasterPTY::create_pair(int index)
|
||||
{
|
||||
auto master = TRY(make_shared<MasterPTY>());
|
||||
auto slave = TRY(make_shared<SlavePTY>());
|
||||
|
||||
auto name = TRY(String::format("%d"_sv, index));
|
||||
for (auto& fs : g_devpts_instances) { fs->root_inode()->add_entry(slave, name.chars()); }
|
||||
slave->m_name = move(name);
|
||||
|
||||
master->m_metadata.mode = 0666;
|
||||
master->m_index = index;
|
||||
master->m_slave = slave;
|
||||
master->m_metadata.devid = luna_dev_makedev(DeviceRegistry::Terminal, 0);
|
||||
master->m_settings.c_lflag = ECHO | ECHOE | ECHOCTL | ISIG | ICANON;
|
||||
master->m_settings.c_cc[VEOF] = '\4';
|
||||
master->m_settings.c_cc[VERASE] = '\b';
|
||||
master->m_settings.c_cc[VINTR] = '\3';
|
||||
master->m_settings.c_cc[VQUIT] = '\x1c';
|
||||
master->m_window.ws_col = 80;
|
||||
master->m_window.ws_row = 25;
|
||||
|
||||
slave->m_master = master.ptr();
|
||||
slave->m_metadata.devid = luna_dev_makedev(DeviceRegistry::Terminal, index + 1);
|
||||
slave->m_metadata.uid = Scheduler::current()->auth.euid;
|
||||
slave->m_metadata.gid = Scheduler::current()->auth.egid;
|
||||
slave->m_metadata.mode = 0620;
|
||||
|
||||
return (SharedPtr<VFS::Inode>)master;
|
||||
}
|
||||
|
||||
Result<void> MasterPTY::handle_background_process_group(bool can_succeed, int signo) const
|
||||
{
|
||||
if (!m_foreground_process_group.has_value()) return {};
|
||||
|
||||
auto foreground_pgrp = m_foreground_process_group.value();
|
||||
|
||||
auto* current = Scheduler::current();
|
||||
if (current->pgid == foreground_pgrp) return {};
|
||||
|
||||
if ((current->signal_mask.get(signo - 1)) || (current->signal_handlers[signo - 1].sa_handler == SIG_IGN))
|
||||
{
|
||||
if (can_succeed) return {};
|
||||
return err(EIO);
|
||||
}
|
||||
|
||||
current->send_signal(signo);
|
||||
|
||||
if (can_succeed) return err(EINTR);
|
||||
return err(EIO);
|
||||
}
|
||||
|
||||
Result<usize> MasterPTY::read(u8* buf, usize, usize length) const
|
||||
{
|
||||
length = m_buffer.dequeue_data(buf, length);
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
Result<usize> MasterPTY::write(const u8* buf, usize, usize length)
|
||||
{
|
||||
TRY(m_slave->m_buffer.append_data(buf, length));
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
Result<u64> MasterPTY::ioctl(int request, void* arg)
|
||||
{
|
||||
auto* current = Scheduler::current();
|
||||
TRY(check_pledge(current, Promise::p_tty));
|
||||
|
||||
switch (request)
|
||||
{
|
||||
case TCGETS: {
|
||||
return MemoryManager::copy_to_user_typed((struct termios*)arg, &m_settings) ? 0 : err(EFAULT);
|
||||
}
|
||||
case TCSETS: {
|
||||
if (!MemoryManager::copy_from_user_typed((const struct termios*)arg, &m_settings)) return err(EFAULT);
|
||||
|
||||
return 0;
|
||||
}
|
||||
case TIOCSPGRP: {
|
||||
pid_t pgid;
|
||||
if (!MemoryManager::copy_from_user_typed((const pid_t*)arg, &pgid)) return err(EFAULT);
|
||||
|
||||
bool pgid_exists = false;
|
||||
Scheduler::for_each_in_process_group(pgid, [&pgid_exists](Thread*) {
|
||||
pgid_exists = true;
|
||||
return false;
|
||||
});
|
||||
if (!pgid_exists) return err(EPERM);
|
||||
|
||||
m_foreground_process_group = pgid;
|
||||
return 0;
|
||||
}
|
||||
case TIOCGPGRP: {
|
||||
pid_t pgid = m_foreground_process_group.value_or((pid_t)next_thread_id());
|
||||
if (!MemoryManager::copy_to_user_typed((pid_t*)arg, &pgid)) return err(EFAULT);
|
||||
return 0;
|
||||
}
|
||||
case TIOCGWINSZ: {
|
||||
if (!MemoryManager::copy_to_user_typed((struct winsize*)arg, &m_window)) return err(EFAULT);
|
||||
return 0;
|
||||
}
|
||||
case TIOCGPTN: {
|
||||
if (!MemoryManager::copy_to_user_typed((int*)arg, &m_index)) return err(EFAULT);
|
||||
return 0;
|
||||
}
|
||||
default: return err(EINVAL);
|
||||
}
|
||||
}
|
||||
|
||||
MasterPTY::~MasterPTY()
|
||||
{
|
||||
m_slave->m_master = nullptr;
|
||||
for (auto& fs : g_devpts_instances) { fs->root_inode()->remove_entry(m_slave->m_name.chars()); }
|
||||
PTYMultiplexer::did_remove_pty(m_index);
|
||||
}
|
75
kernel/src/fs/devices/MasterPTY.h
Normal file
75
kernel/src/fs/devices/MasterPTY.h
Normal file
@ -0,0 +1,75 @@
|
||||
#pragma once
|
||||
#include "fs/VFS.h"
|
||||
#include "fs/devices/SlavePTY.h"
|
||||
#include <bits/termios.h>
|
||||
#include <luna/Buffer.h>
|
||||
|
||||
class MasterPTY : public VFS::DeviceInode
|
||||
{
|
||||
public:
|
||||
MasterPTY() = default;
|
||||
|
||||
static Result<SharedPtr<VFS::Inode>> create_pair(int index);
|
||||
|
||||
VFS::InodeType type() const override
|
||||
{
|
||||
return VFS::InodeType::CharacterDevice;
|
||||
}
|
||||
|
||||
Result<u64> query_shared_memory(off_t, usize) override
|
||||
{
|
||||
return err(ENOTSUP);
|
||||
}
|
||||
|
||||
VFS::FileSystem* fs() const override
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Result<usize> read(u8* buf, usize offset, usize length) const override;
|
||||
|
||||
Result<usize> write(const u8* buf, usize offset, usize length) override;
|
||||
|
||||
Result<u64> ioctl(int request, void* arg) override;
|
||||
|
||||
Result<u64> isatty() const override
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
Result<void> truncate(usize) override
|
||||
{
|
||||
// POSIX says truncate is for regular files, but doesn't tell us what error to return for non-regular files.
|
||||
return err(EINVAL);
|
||||
}
|
||||
|
||||
bool will_block_if_read() const override
|
||||
{
|
||||
return m_buffer.is_empty();
|
||||
}
|
||||
|
||||
void did_link() override
|
||||
{
|
||||
m_metadata.nlinks++;
|
||||
}
|
||||
|
||||
void did_unlink() override
|
||||
{
|
||||
m_metadata.nlinks--;
|
||||
}
|
||||
|
||||
virtual ~MasterPTY();
|
||||
|
||||
private:
|
||||
struct termios m_settings;
|
||||
mutable Buffer m_buffer;
|
||||
SharedPtr<SlavePTY> m_slave;
|
||||
mutable Option<pid_t> m_foreground_process_group;
|
||||
struct winsize m_window;
|
||||
|
||||
Result<void> handle_background_process_group(bool can_succeed, int signo) const;
|
||||
|
||||
int m_index;
|
||||
|
||||
friend class SlavePTY;
|
||||
};
|
36
kernel/src/fs/devices/PTYMultiplexer.cpp
Normal file
36
kernel/src/fs/devices/PTYMultiplexer.cpp
Normal file
@ -0,0 +1,36 @@
|
||||
#include "fs/devices/PTYMultiplexer.h"
|
||||
|
||||
Bitset<u64> PTYMultiplexer::m_available_indexes = 0;
|
||||
|
||||
PTYMultiplexer::PTYMultiplexer()
|
||||
{
|
||||
m_metadata.devid = luna_dev_makedev(DeviceRegistry::Terminal, 0);
|
||||
m_metadata.mode = 0666;
|
||||
}
|
||||
|
||||
Result<SharedPtr<VFS::Inode>> PTYMultiplexer::open()
|
||||
{
|
||||
int index = -1;
|
||||
for (int i = 0; i < 64; i++)
|
||||
{
|
||||
if (!m_available_indexes.get(i))
|
||||
{
|
||||
index = i;
|
||||
m_available_indexes.set(i, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (index == -1) return err(ENOSPC);
|
||||
|
||||
return MasterPTY::create_pair(index);
|
||||
}
|
||||
|
||||
void PTYMultiplexer::init()
|
||||
{
|
||||
m_available_indexes.clear();
|
||||
}
|
||||
|
||||
void PTYMultiplexer::did_remove_pty(int index)
|
||||
{
|
||||
m_available_indexes.set(index, false);
|
||||
}
|
80
kernel/src/fs/devices/PTYMultiplexer.h
Normal file
80
kernel/src/fs/devices/PTYMultiplexer.h
Normal file
@ -0,0 +1,80 @@
|
||||
#pragma once
|
||||
#include "fs/VFS.h"
|
||||
#include "fs/devices/DeviceRegistry.h"
|
||||
#include "fs/devices/MasterPTY.h"
|
||||
#include <luna/Bitset.h>
|
||||
|
||||
class PTYMultiplexer : public VFS::DeviceInode
|
||||
{
|
||||
public:
|
||||
PTYMultiplexer();
|
||||
|
||||
VFS::InodeType type() const override
|
||||
{
|
||||
return VFS::InodeType::CharacterDevice;
|
||||
}
|
||||
|
||||
void set_fs(VFS::FileSystem& fs)
|
||||
{
|
||||
m_fs = &fs;
|
||||
}
|
||||
|
||||
void set_inode_number(usize inum)
|
||||
{
|
||||
m_metadata.inum = inum;
|
||||
}
|
||||
|
||||
Result<u64> query_shared_memory(off_t, usize) override
|
||||
{
|
||||
unreachable();
|
||||
}
|
||||
|
||||
Result<SharedPtr<VFS::Inode>> open() override;
|
||||
|
||||
VFS::FileSystem* fs() const override
|
||||
{
|
||||
return m_fs;
|
||||
}
|
||||
|
||||
Result<usize> read(u8*, usize, usize) const override
|
||||
{
|
||||
unreachable();
|
||||
}
|
||||
|
||||
Result<usize> write(const u8*, usize, usize) override
|
||||
{
|
||||
unreachable();
|
||||
}
|
||||
|
||||
Result<void> truncate(usize) override
|
||||
{
|
||||
// POSIX says truncate is for regular files, but doesn't tell us what error to return for non-regular files.
|
||||
return err(EINVAL);
|
||||
}
|
||||
|
||||
bool will_block_if_read() const override
|
||||
{
|
||||
unreachable();
|
||||
}
|
||||
|
||||
void did_link() override
|
||||
{
|
||||
m_metadata.nlinks++;
|
||||
}
|
||||
|
||||
void did_unlink() override
|
||||
{
|
||||
m_metadata.nlinks--;
|
||||
}
|
||||
|
||||
static void init();
|
||||
|
||||
static void did_remove_pty(int index);
|
||||
|
||||
virtual ~PTYMultiplexer() = default;
|
||||
|
||||
private:
|
||||
VFS::FileSystem* m_fs;
|
||||
|
||||
static Bitset<u64> m_available_indexes;
|
||||
};
|
71
kernel/src/fs/devices/SlavePTY.cpp
Normal file
71
kernel/src/fs/devices/SlavePTY.cpp
Normal file
@ -0,0 +1,71 @@
|
||||
#include "fs/devices/SlavePTY.h"
|
||||
#include "Pledge.h"
|
||||
#include "fs/devices/MasterPTY.h"
|
||||
#include "memory/MemoryManager.h"
|
||||
#include "thread/Scheduler.h"
|
||||
|
||||
Result<usize> SlavePTY::read(u8* buf, usize, usize length) const
|
||||
{
|
||||
if (!m_master) return err(EIO);
|
||||
|
||||
TRY(m_master->handle_background_process_group(false, SIGTTIN));
|
||||
|
||||
length = m_buffer.dequeue_data(buf, length);
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
Result<usize> SlavePTY::write(const u8* buf, usize, usize length)
|
||||
{
|
||||
if (!m_master) return err(EIO);
|
||||
|
||||
if (m_master->m_settings.c_lflag & TOSTOP) TRY(m_master->handle_background_process_group(true, SIGTTOU));
|
||||
|
||||
TRY(m_master->m_buffer.append_data(buf, length));
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
Result<u64> SlavePTY::ioctl(int request, void* arg)
|
||||
{
|
||||
auto* current = Scheduler::current();
|
||||
TRY(check_pledge(current, Promise::p_tty));
|
||||
|
||||
if (!m_master) return err(EIO);
|
||||
|
||||
switch (request)
|
||||
{
|
||||
case TCGETS: {
|
||||
return MemoryManager::copy_to_user_typed((struct termios*)arg, &m_master->m_settings) ? 0 : err(EFAULT);
|
||||
}
|
||||
case TCSETS: {
|
||||
if (!MemoryManager::copy_from_user_typed((const struct termios*)arg, &m_master->m_settings)) return err(EFAULT);
|
||||
|
||||
return 0;
|
||||
}
|
||||
case TIOCSPGRP: {
|
||||
pid_t pgid;
|
||||
if (!MemoryManager::copy_from_user_typed((const pid_t*)arg, &pgid)) return err(EFAULT);
|
||||
|
||||
bool pgid_exists = false;
|
||||
Scheduler::for_each_in_process_group(pgid, [&pgid_exists](Thread*) {
|
||||
pgid_exists = true;
|
||||
return false;
|
||||
});
|
||||
if (!pgid_exists) return err(EPERM);
|
||||
|
||||
m_master->m_foreground_process_group = pgid;
|
||||
return 0;
|
||||
}
|
||||
case TIOCGPGRP: {
|
||||
pid_t pgid = m_master->m_foreground_process_group.value_or((pid_t)next_thread_id());
|
||||
if (!MemoryManager::copy_to_user_typed((pid_t*)arg, &pgid)) return err(EFAULT);
|
||||
return 0;
|
||||
}
|
||||
case TIOCGWINSZ: {
|
||||
if (!MemoryManager::copy_to_user_typed((struct winsize*)arg, &m_master->m_window)) return err(EFAULT);
|
||||
return 0;
|
||||
}
|
||||
default: return err(EINVAL);
|
||||
}
|
||||
}
|
69
kernel/src/fs/devices/SlavePTY.h
Normal file
69
kernel/src/fs/devices/SlavePTY.h
Normal file
@ -0,0 +1,69 @@
|
||||
#pragma once
|
||||
#include "fs/VFS.h"
|
||||
#include <luna/Buffer.h>
|
||||
#include <luna/String.h>
|
||||
|
||||
class MasterPTY;
|
||||
|
||||
class SlavePTY : public VFS::DeviceInode
|
||||
{
|
||||
public:
|
||||
SlavePTY() = default;
|
||||
|
||||
VFS::InodeType type() const override
|
||||
{
|
||||
return VFS::InodeType::CharacterDevice;
|
||||
}
|
||||
|
||||
Result<u64> query_shared_memory(off_t, usize) override
|
||||
{
|
||||
return err(ENOTSUP);
|
||||
}
|
||||
|
||||
VFS::FileSystem* fs() const override
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Result<usize> read(u8* buf, usize offset, usize length) const override;
|
||||
|
||||
Result<usize> write(const u8* buf, usize offset, usize length) override;
|
||||
|
||||
Result<u64> ioctl(int request, void* arg) override;
|
||||
|
||||
Result<u64> isatty() const override
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
Result<void> truncate(usize) override
|
||||
{
|
||||
// POSIX says truncate is for regular files, but doesn't tell us what error to return for non-regular files.
|
||||
return err(EINVAL);
|
||||
}
|
||||
|
||||
bool will_block_if_read() const override
|
||||
{
|
||||
return m_buffer.is_empty();
|
||||
}
|
||||
|
||||
void did_link() override
|
||||
{
|
||||
m_metadata.nlinks++;
|
||||
}
|
||||
|
||||
void did_unlink() override
|
||||
{
|
||||
m_metadata.nlinks--;
|
||||
}
|
||||
|
||||
virtual ~SlavePTY() = default;
|
||||
|
||||
private:
|
||||
mutable Buffer m_buffer;
|
||||
|
||||
MasterPTY* m_master;
|
||||
String m_name;
|
||||
|
||||
friend class MasterPTY;
|
||||
};
|
62
kernel/src/fs/devpts/FileSystem.cpp
Normal file
62
kernel/src/fs/devpts/FileSystem.cpp
Normal file
@ -0,0 +1,62 @@
|
||||
#include "fs/devpts/FileSystem.h"
|
||||
#include "arch/Timer.h"
|
||||
#include "fs/devices/DeviceRegistry.h"
|
||||
#include "fs/devpts/Inode.h"
|
||||
#include <luna/Alloc.h>
|
||||
#include <luna/CString.h>
|
||||
#include <luna/Ignore.h>
|
||||
|
||||
Vector<VFS::FileSystem*> g_devpts_instances;
|
||||
|
||||
namespace DevPTS
|
||||
{
|
||||
Result<SharedPtr<VFS::FileSystem>> FileSystem::create()
|
||||
{
|
||||
SharedPtr<FileSystem> fs = TRY(adopt_shared_if_nonnull(new (std::nothrow) FileSystem()));
|
||||
SharedPtr<RootInode> root = TRY(make_shared<RootInode>());
|
||||
|
||||
TRY(root->add_entry(root, "."));
|
||||
TRY(root->add_entry(root, ".."));
|
||||
|
||||
root->set_self(root, {});
|
||||
root->set_fs(*fs, {});
|
||||
root->set_inode_number();
|
||||
root->m_metadata.mode = 0755;
|
||||
root->m_metadata.atime = root->m_metadata.ctime = root->m_metadata.mtime = *Timer::realtime_clock();
|
||||
fs->set_root(root);
|
||||
|
||||
TRY(g_devpts_instances.try_append(fs.ptr()));
|
||||
|
||||
return (SharedPtr<VFS::FileSystem>)fs;
|
||||
}
|
||||
|
||||
Result<u64> FileSystem::allocate_inode_number()
|
||||
{
|
||||
return err(ENOTSUP);
|
||||
}
|
||||
|
||||
FileSystem::FileSystem()
|
||||
{
|
||||
m_host_device_id = DeviceRegistry::next_null_device_id();
|
||||
}
|
||||
|
||||
Result<void> FileSystem::set_mount_dir(SharedPtr<VFS::Inode> parent)
|
||||
{
|
||||
return m_root_inode->replace_entry(parent, "..");
|
||||
}
|
||||
|
||||
Result<void> FileSystem::reset_mount_dir()
|
||||
{
|
||||
return m_root_inode->replace_entry(m_root_inode, "..");
|
||||
}
|
||||
|
||||
void FileSystem::set_root(SharedPtr<VFS::Inode> root)
|
||||
{
|
||||
m_root_inode = root;
|
||||
}
|
||||
|
||||
FileSystem::~FileSystem()
|
||||
{
|
||||
g_devpts_instances.remove_first_matching([this](VFS::FileSystem* ptr) { return ptr == this; });
|
||||
}
|
||||
}
|
61
kernel/src/fs/devpts/FileSystem.h
Normal file
61
kernel/src/fs/devpts/FileSystem.h
Normal file
@ -0,0 +1,61 @@
|
||||
#pragma once
|
||||
#include "fs/VFS.h"
|
||||
#include "fs/devices/DeviceRegistry.h"
|
||||
|
||||
namespace DevPTS
|
||||
{
|
||||
class FileSystem : public VFS::FileSystem
|
||||
{
|
||||
public:
|
||||
SharedPtr<VFS::Inode> root_inode() const override
|
||||
{
|
||||
return m_root_inode;
|
||||
}
|
||||
|
||||
Result<SharedPtr<VFS::Inode>> create_file_inode(mode_t) override
|
||||
{
|
||||
return err(ENOTSUP);
|
||||
}
|
||||
|
||||
Result<SharedPtr<VFS::Inode>> create_dir_inode(SharedPtr<VFS::Inode>, mode_t) override
|
||||
{
|
||||
return err(ENOTSUP);
|
||||
}
|
||||
|
||||
Result<SharedPtr<VFS::Inode>> create_device_inode(u32, u32, mode_t) override
|
||||
{
|
||||
return err(ENOTSUP);
|
||||
}
|
||||
|
||||
Result<SharedPtr<VFS::Inode>> create_symlink_inode(StringView) override
|
||||
{
|
||||
return err(ENOTSUP);
|
||||
}
|
||||
|
||||
Result<u64> allocate_inode_number() override;
|
||||
|
||||
Result<void> set_mount_dir(SharedPtr<VFS::Inode> parent) override;
|
||||
|
||||
Result<void> reset_mount_dir() override;
|
||||
|
||||
static Result<SharedPtr<VFS::FileSystem>> create();
|
||||
|
||||
dev_t host_device_id() const override
|
||||
{
|
||||
return m_host_device_id;
|
||||
}
|
||||
|
||||
virtual ~FileSystem();
|
||||
|
||||
private:
|
||||
FileSystem();
|
||||
|
||||
void set_root(SharedPtr<VFS::Inode> root);
|
||||
|
||||
SharedPtr<VFS::Inode> m_root_inode;
|
||||
|
||||
dev_t m_host_device_id;
|
||||
};
|
||||
}
|
||||
|
||||
extern Vector<VFS::FileSystem*> g_devpts_instances;
|
78
kernel/src/fs/devpts/Inode.cpp
Normal file
78
kernel/src/fs/devpts/Inode.cpp
Normal file
@ -0,0 +1,78 @@
|
||||
#include "fs/devpts/Inode.h"
|
||||
|
||||
namespace DevPTS
|
||||
{
|
||||
Result<SharedPtr<VFS::Inode>> RootInode::find(const char* name) const
|
||||
{
|
||||
for (const auto& entry : m_entries)
|
||||
{
|
||||
if (!strcmp(name, entry.name.chars())) return entry.inode;
|
||||
}
|
||||
|
||||
return err(ENOENT);
|
||||
}
|
||||
|
||||
Result<void> RootInode::replace_entry(SharedPtr<VFS::Inode> inode, const char* name)
|
||||
{
|
||||
for (auto& entry : m_entries)
|
||||
{
|
||||
if (!strcmp(name, entry.name.chars()))
|
||||
{
|
||||
entry.inode = inode;
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
return err(ENOENT);
|
||||
}
|
||||
|
||||
Option<VFS::DirectoryEntry> RootInode::get(usize index) const
|
||||
{
|
||||
if (index >= m_entries.size()) return {};
|
||||
|
||||
return m_entries[index];
|
||||
}
|
||||
|
||||
Result<void> RootInode::add_entry(SharedPtr<VFS::Inode> inode, const char* name)
|
||||
{
|
||||
if (find(name).has_value()) return err(EEXIST);
|
||||
|
||||
VFS::DirectoryEntry entry { inode, name };
|
||||
|
||||
TRY(m_entries.try_append(move(entry)));
|
||||
|
||||
inode->did_link();
|
||||
|
||||
m_metadata.mtime = *Timer::realtime_clock();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
Result<void> RootInode::remove_entry(const char* name)
|
||||
{
|
||||
SharedPtr<VFS::Inode> inode = TRY(find(name));
|
||||
|
||||
if (inode->type() == VFS::InodeType::Directory && inode->entries() != 2) return err(ENOTEMPTY);
|
||||
|
||||
if (inode->is_mountpoint()) return err(EBUSY);
|
||||
|
||||
m_entries.remove_first_matching(
|
||||
[&](const VFS::DirectoryEntry& entry) { return !strcmp(entry.name.chars(), name); });
|
||||
|
||||
inode->did_unlink();
|
||||
|
||||
m_metadata.mtime = *Timer::realtime_clock();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
Result<SharedPtr<VFS::Inode>> RootInode::create_file(const char*, mode_t)
|
||||
{
|
||||
return err(ENOTSUP);
|
||||
}
|
||||
|
||||
Result<SharedPtr<VFS::Inode>> RootInode::create_subdirectory(const char*, mode_t)
|
||||
{
|
||||
return err(ENOTSUP);
|
||||
}
|
||||
}
|
93
kernel/src/fs/devpts/Inode.h
Normal file
93
kernel/src/fs/devpts/Inode.h
Normal file
@ -0,0 +1,93 @@
|
||||
#pragma once
|
||||
#include "fs/VFS.h"
|
||||
#include "fs/devices/DeviceRegistry.h"
|
||||
#include "fs/devpts/FileSystem.h"
|
||||
|
||||
namespace DevPTS
|
||||
{
|
||||
class RootInode : public VFS::Inode
|
||||
{
|
||||
public:
|
||||
RootInode() = default;
|
||||
|
||||
void set_fs(FileSystem& fs, Badge<FileSystem>)
|
||||
{
|
||||
m_fs = &fs;
|
||||
}
|
||||
|
||||
void set_inode_number()
|
||||
{
|
||||
m_metadata.inum = 2;
|
||||
}
|
||||
|
||||
void set_self(SharedPtr<VFS::Inode> self, Badge<FileSystem>)
|
||||
{
|
||||
m_self = self;
|
||||
}
|
||||
|
||||
Result<SharedPtr<VFS::Inode>> find(const char* name) const override;
|
||||
Option<VFS::DirectoryEntry> get(usize index) const override;
|
||||
|
||||
Result<usize> read(u8*, usize, usize) const override
|
||||
{
|
||||
return err(EISDIR);
|
||||
}
|
||||
|
||||
Result<usize> write(const u8*, usize, usize) override
|
||||
{
|
||||
return err(EISDIR);
|
||||
}
|
||||
|
||||
Result<void> truncate(usize) override
|
||||
{
|
||||
return err(EISDIR);
|
||||
}
|
||||
|
||||
bool will_block_if_read() const override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
VFS::FileSystem* fs() const override
|
||||
{
|
||||
return m_fs;
|
||||
}
|
||||
|
||||
VFS::InodeType type() const override
|
||||
{
|
||||
return VFS::InodeType::Directory;
|
||||
}
|
||||
|
||||
void did_link() override
|
||||
{
|
||||
}
|
||||
|
||||
void did_unlink() override
|
||||
{
|
||||
m_self = {};
|
||||
m_entries.clear();
|
||||
}
|
||||
|
||||
usize entries() const override
|
||||
{
|
||||
return m_entries.size();
|
||||
}
|
||||
|
||||
Result<void> remove_entry(const char* name) override;
|
||||
|
||||
Result<SharedPtr<VFS::Inode>> create_file(const char* name, mode_t mode) override;
|
||||
Result<SharedPtr<VFS::Inode>> create_subdirectory(const char* name, mode_t mode) override;
|
||||
|
||||
Result<void> add_entry(SharedPtr<VFS::Inode> inode, const char* name);
|
||||
Result<void> replace_entry(SharedPtr<VFS::Inode> inode, const char* name);
|
||||
|
||||
virtual ~RootInode() = default;
|
||||
|
||||
private:
|
||||
VFS::FileSystem* m_fs;
|
||||
SharedPtr<VFS::Inode> m_self;
|
||||
Vector<VFS::DirectoryEntry> m_entries;
|
||||
|
||||
friend class FileSystem;
|
||||
};
|
||||
}
|
@ -6,6 +6,7 @@
|
||||
#include "config.h"
|
||||
#include "fs/InitRD.h"
|
||||
#include "fs/devices/DeviceRegistry.h"
|
||||
#include "fs/devices/PTYMultiplexer.h"
|
||||
#include "fs/tmpfs/FileSystem.h"
|
||||
#include "memory/MemoryManager.h"
|
||||
#include "thread/Scheduler.h"
|
||||
@ -94,6 +95,7 @@ extern "C" [[noreturn]] void _start()
|
||||
|
||||
Thread::init();
|
||||
Scheduler::init();
|
||||
PTYMultiplexer::init();
|
||||
|
||||
Scheduler::new_kernel_thread(init, "[kinit]");
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include "Pledge.h"
|
||||
#include "fs/VFS.h"
|
||||
#include "fs/devpts/FileSystem.h"
|
||||
#include "fs/ext2/FileSystem.h"
|
||||
#include "fs/tmpfs/FileSystem.h"
|
||||
#include "memory/MemoryManager.h"
|
||||
@ -26,6 +27,8 @@ Result<u64> sys_mount(Registers*, SyscallArgs args)
|
||||
SharedPtr<VFS::FileSystem> fs;
|
||||
|
||||
if (fstype.view() == "tmpfs") fs = TRY(TmpFS::FileSystem::create());
|
||||
else if (fstype.view() == "devpts")
|
||||
fs = TRY(DevPTS::FileSystem::create());
|
||||
else if (fstype.view() == "devfs")
|
||||
fs = TRY(DeviceRegistry::create_devfs_instance());
|
||||
else if (fstype.view() == "ext2")
|
||||
|
@ -45,5 +45,6 @@ struct winsize
|
||||
#define TIOCSPGRP 2
|
||||
#define TIOCGPGRP 3
|
||||
#define TIOCGWINSZ 4
|
||||
#define TIOCGPTN 5
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user