Compare commits

..

3 Commits

Author SHA1 Message Date
1f4c4928cc
kernel+libc+apps: Add mount and umount syscalls, libc wrappers, and utilities
All checks were successful
continuous-integration/drone/push Build is passing
2023-05-17 20:30:15 +02:00
29174ca228
kernel/VFS: Add a way to unmount file systems 2023-05-17 19:52:26 +02:00
e7d482e78a
kernel+init: Add a VFS mount system and auto-populate the devfs 2023-05-17 19:40:37 +02:00
27 changed files with 483 additions and 33 deletions

View File

@ -24,3 +24,5 @@ luna_app(uname.cpp uname)
luna_app(base64.cpp base64) luna_app(base64.cpp base64)
luna_app(login.cpp login) luna_app(login.cpp login)
luna_app(ipc-test.cpp ipc-test) luna_app(ipc-test.cpp ipc-test)
luna_app(mount.cpp mount)
luna_app(umount.cpp umount)

View File

@ -18,21 +18,6 @@
FILE* g_init_log; FILE* g_init_log;
#define xmknod(path, mode, maj, min) \
if (mknod(path, mode, makedev(maj, min)) < 0) exit(255);
// Too early for console logs (/dev/console is created here!), so we have to resort to exiting with a weird exit code in
// case of failure.
static void populate_devfs()
{
if (mkdir("/dev", 0755) < 0 && errno != EEXIST) exit(255);
xmknod("/dev/console", 0666, 1, 0);
xmknod("/dev/null", 0666, 2, 0);
xmknod("/dev/zero", 0666, 2, 1);
xmknod("/dev/fb0", 0222, 3, 0);
}
struct Service struct Service
{ {
String name; String name;
@ -281,8 +266,6 @@ int main()
return 1; return 1;
} }
populate_devfs();
// Before this point, we don't even have an stdin, stdout and stderr. Set it up now so that child processes (and us) // Before this point, we don't even have an stdin, stdout and stderr. Set it up now so that child processes (and us)
// can print stuff. // can print stuff.
stdin = fopen("/dev/console", "r"); stdin = fopen("/dev/console", "r");

24
apps/mount.cpp Normal file
View File

@ -0,0 +1,24 @@
#include <os/ArgumentParser.h>
#include <stdio.h>
#include <sys/mount.h>
Result<int> luna_main(int argc, char** argv)
{
StringView target;
StringView fstype;
os::ArgumentParser parser;
parser.add_description("Mount a file system.");
parser.add_system_program_info("mount"_sv);
parser.add_positional_argument(target, "mountpoint"_sv, true);
parser.add_value_argument(fstype, 't', "type"_sv, "auto"_sv, "the file system type to use");
parser.parse(argc, argv);
if (mount(target.chars(), fstype.chars()) < 0)
{
perror("mount");
return 1;
}
return 0;
}

22
apps/umount.cpp Normal file
View File

@ -0,0 +1,22 @@
#include <os/ArgumentParser.h>
#include <stdio.h>
#include <sys/mount.h>
Result<int> luna_main(int argc, char** argv)
{
StringView target;
os::ArgumentParser parser;
parser.add_description("Unmount a file system.");
parser.add_system_program_info("umount"_sv);
parser.add_positional_argument(target, "mountpoint"_sv, true);
parser.parse(argc, argv);
if (umount(target.chars()) < 0)
{
perror("umount");
return 1;
}
return 0;
}

View File

@ -38,8 +38,10 @@ set(SOURCES
src/sys/chdir.cpp src/sys/chdir.cpp
src/sys/link.cpp src/sys/link.cpp
src/sys/uname.cpp src/sys/uname.cpp
src/sys/mount.cpp
src/fs/VFS.cpp src/fs/VFS.cpp
src/fs/Pipe.cpp src/fs/Pipe.cpp
src/fs/Mount.cpp
src/fs/tmpfs/FileSystem.cpp src/fs/tmpfs/FileSystem.cpp
src/fs/devices/DeviceRegistry.cpp src/fs/devices/DeviceRegistry.cpp
src/fs/devices/NullDevice.cpp src/fs/devices/NullDevice.cpp

19
kernel/src/fs/Mount.cpp Normal file
View File

@ -0,0 +1,19 @@
#include "fs/Mount.h"
LinkedList<MountInode> g_mounts;
Result<SharedPtr<VFS::Inode>> MountInode::create(SharedPtr<VFS::Inode> source, SharedPtr<VFS::FileSystem> fs)
{
auto inode = TRY(adopt_shared_if_nonnull(new (std::nothrow) MountInode()));
inode->m_source = source;
inode->m_mountee = fs;
inode->m_mount_root_inode = fs->root_inode();
auto parent = TRY(source->find(".."));
TRY(fs->set_mount_dir(parent));
g_mounts.append(inode.ptr());
return (SharedPtr<VFS::Inode>)inode;
}

150
kernel/src/fs/Mount.h Normal file
View File

@ -0,0 +1,150 @@
#pragma once
#include "fs/VFS.h"
#include <luna/LinkedList.h>
class MountInode : public VFS::Inode, public LinkedListNode<MountInode>
{
public:
static Result<SharedPtr<VFS::Inode>> create(SharedPtr<VFS::Inode> source, SharedPtr<VFS::FileSystem> fs);
void set_fs(SharedPtr<VFS::FileSystem> fs)
{
m_mountee = fs;
}
Result<SharedPtr<VFS::Inode>> find(const char* name) const override
{
return m_mount_root_inode->find(name);
}
Option<VFS::DirectoryEntry> get(usize index) const override
{
return m_mount_root_inode->get(index);
}
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 blocking() const override
{
return false;
}
usize size() const override
{
return 0;
}
mode_t mode() const override
{
return m_mount_root_inode->mode();
}
u32 uid() const override
{
return m_mount_root_inode->uid();
}
u32 gid() const override
{
return m_mount_root_inode->gid();
}
Result<void> chmod(mode_t mode) override
{
return m_mount_root_inode->chmod(mode);
}
Result<void> chown(u32 uid, u32 gid) override
{
return m_mount_root_inode->chown(uid, gid);
}
VFS::FileSystem* fs() const override
{
return m_mountee.ptr();
}
usize inode_number() const override
{
return m_mount_root_inode->inode_number();
}
VFS::InodeType type() const override
{
return VFS::InodeType::Directory;
}
void did_link() override
{
m_mount_root_inode->did_link();
}
void did_unlink() override
{
m_mount_root_inode->did_unlink();
}
usize entries() const override
{
return m_mount_root_inode->entries();
}
bool is_mountpoint() const override
{
return true;
}
SharedPtr<VFS::Inode> source() const
{
return m_source;
}
Result<void> remove_entry(const char* name) override
{
return m_mount_root_inode->remove_entry(name);
}
Result<SharedPtr<VFS::Inode>> create_file(const char* name) override
{
return m_mount_root_inode->create_file(name);
}
Result<SharedPtr<VFS::Inode>> create_subdirectory(const char* name) override
{
return m_mount_root_inode->create_subdirectory(name);
}
Result<void> add_entry(SharedPtr<VFS::Inode> inode, const char* name) override
{
return m_mount_root_inode->add_entry(inode, name);
}
Result<void> replace_entry(SharedPtr<VFS::Inode> inode, const char* name) override
{
return m_mount_root_inode->replace_entry(inode, name);
}
virtual ~MountInode() = default;
private:
SharedPtr<VFS::Inode> m_source;
SharedPtr<VFS::FileSystem> m_mountee;
SharedPtr<VFS::Inode> m_mount_root_inode;
MountInode() = default;
};
extern LinkedList<MountInode> g_mounts;

View File

@ -1,5 +1,6 @@
#include "fs/VFS.h" #include "fs/VFS.h"
#include "Log.h" #include "Log.h"
#include "fs/Mount.h"
#include "thread/Thread.h" #include "thread/Thread.h"
#include <bits/modes.h> #include <bits/modes.h>
#include <luna/PathParser.h> #include <luna/PathParser.h>
@ -97,6 +98,8 @@ namespace VFS
bool can_execute(SharedPtr<Inode> inode, Credentials auth) bool can_execute(SharedPtr<Inode> inode, Credentials auth)
{ {
if (auth.euid == 0) return true;
if (inode->uid() == auth.euid) { return inode->mode() & S_IXUSR; } if (inode->uid() == auth.euid) { return inode->mode() & S_IXUSR; }
if (inode->gid() == auth.egid) { return inode->mode() & S_IXGRP; } if (inode->gid() == auth.egid) { return inode->mode() & S_IXGRP; }
@ -105,6 +108,8 @@ namespace VFS
bool can_write(SharedPtr<Inode> inode, Credentials auth) bool can_write(SharedPtr<Inode> inode, Credentials auth)
{ {
if (auth.euid == 0) return true;
if (inode->uid() == auth.euid) { return inode->mode() & S_IWUSR; } if (inode->uid() == auth.euid) { return inode->mode() & S_IWUSR; }
if (inode->gid() == auth.egid) { return inode->mode() & S_IWGRP; } if (inode->gid() == auth.egid) { return inode->mode() & S_IWGRP; }
@ -113,6 +118,8 @@ namespace VFS
bool can_read(SharedPtr<Inode> inode, Credentials auth) bool can_read(SharedPtr<Inode> inode, Credentials auth)
{ {
if (auth.euid == 0) return true;
if (inode->uid() == auth.euid) { return inode->mode() & S_IRUSR; } if (inode->uid() == auth.euid) { return inode->mode() & S_IRUSR; }
if (inode->gid() == auth.egid) { return inode->mode() & S_IRGRP; } if (inode->gid() == auth.egid) { return inode->mode() & S_IRGRP; }
@ -128,4 +135,55 @@ namespace VFS
{ {
return inode->mode() & S_ISGID; return inode->mode() & S_ISGID;
} }
Result<void> mount_root(SharedPtr<VFS::FileSystem> fs)
{
root_fs = fs;
return {};
}
Result<void> mount(const char* path, SharedPtr<VFS::FileSystem> fs, Credentials auth,
SharedPtr<VFS::Inode> working_directory)
{
auto parser = TRY(PathParser::create(path));
auto parent_path = TRY(parser.dirname());
auto child = TRY(parser.basename());
kdbgln("vfs: Mounting filesystem on target %s", path);
auto parent_inode = TRY(resolve_path(parent_path.chars(), auth, working_directory));
auto inode = TRY(parent_inode->find(child.chars()));
if (inode->type() != VFS::InodeType::Directory) return err(ENOTDIR);
if (inode->is_mountpoint()) return err(EBUSY);
auto mount = TRY(MountInode::create(inode, fs));
TRY(parent_inode->replace_entry(mount, child.chars()));
return {};
}
Result<void> umount(const char* path, Credentials auth, SharedPtr<VFS::Inode> working_directory)
{
auto parser = TRY(PathParser::create(path));
auto parent_path = TRY(parser.dirname());
auto child = TRY(parser.basename());
kdbgln("vfs: Unmounting filesystem on target %s", path);
auto parent_inode = TRY(resolve_path(parent_path.chars(), auth, working_directory));
auto inode = TRY(parent_inode->find(child.chars()));
if (!inode->is_mountpoint()) return err(EINVAL);
// There are still open file descriptors referencing files within this file system.
if (inode->fs()->handles() != 0) return err(EBUSY);
auto mount = (MountInode*)inode.ptr();
TRY(parent_inode->replace_entry(mount->source(), child.chars()));
return {};
}
} }

View File

@ -46,6 +46,8 @@ namespace VFS
virtual Result<void> remove_entry(const char* name) = 0; virtual Result<void> remove_entry(const char* name) = 0;
virtual Result<void> replace_entry(SharedPtr<Inode> inode, const char* name) = 0;
virtual usize entries() const = 0; virtual usize entries() const = 0;
// File-specific methods // File-specific methods
@ -72,6 +74,11 @@ namespace VFS
return 0; return 0;
} }
virtual bool is_mountpoint() const
{
return false;
}
virtual void did_link() = 0; virtual void did_link() = 0;
virtual void did_unlink() = 0; virtual void did_unlink() = 0;
@ -118,6 +125,11 @@ namespace VFS
return err(ENOTDIR); return err(ENOTDIR);
} }
Result<void> replace_entry(SharedPtr<Inode>, const char*) override
{
return err(ENOTDIR);
}
Result<void> remove_entry(const char*) override Result<void> remove_entry(const char*) override
{ {
return err(ENOTDIR); return err(ENOTDIR);
@ -169,6 +181,11 @@ namespace VFS
return err(ENOTDIR); return err(ENOTDIR);
} }
Result<void> replace_entry(SharedPtr<Inode>, const char*) override
{
return err(ENOTDIR);
}
Result<void> remove_entry(const char*) override Result<void> remove_entry(const char*) override
{ {
return err(ENOTDIR); return err(ENOTDIR);
@ -198,10 +215,28 @@ namespace VFS
virtual Result<SharedPtr<Inode>> create_device_inode(u32 major, u32 minor) = 0; virtual Result<SharedPtr<Inode>> create_device_inode(u32 major, u32 minor) = 0;
virtual ~FileSystem() = default; virtual Result<void> set_mount_dir(SharedPtr<Inode> parent) = 0;
};
extern SharedPtr<FileSystem> root_fs; virtual u64 handles() const
{
return m_handles;
}
virtual void add_handle()
{
m_handles++;
}
virtual void remove_handle()
{
m_handles--;
}
virtual ~FileSystem() = default;
protected:
u64 m_handles { 0 };
};
Result<SharedPtr<Inode>> resolve_path(const char* path, Credentials auth, Result<SharedPtr<Inode>> resolve_path(const char* path, Credentials auth,
SharedPtr<VFS::Inode> working_directory = {}); SharedPtr<VFS::Inode> working_directory = {});
@ -221,4 +256,10 @@ namespace VFS
bool is_setgid(SharedPtr<Inode> inode); bool is_setgid(SharedPtr<Inode> inode);
Inode& root_inode(); Inode& root_inode();
Result<void> mount_root(SharedPtr<VFS::FileSystem> fs);
Result<void> mount(const char* path, SharedPtr<VFS::FileSystem> fs, Credentials auth,
SharedPtr<Inode> working_directory = {});
Result<void> umount(const char* path, Credentials auth, SharedPtr<Inode> working_directory = {});
} }

View File

@ -18,7 +18,7 @@ static bool g_echo { true };
Result<void> ConsoleDevice::create() Result<void> ConsoleDevice::create()
{ {
auto device = (SharedPtr<Device>)TRY(make_shared<ConsoleDevice>()); auto device = (SharedPtr<Device>)TRY(make_shared<ConsoleDevice>());
return DeviceRegistry::register_special_device(DeviceRegistry::Console, 0, device); return DeviceRegistry::register_special_device(DeviceRegistry::Console, 0, device, "console");
} }
Result<usize> ConsoleDevice::read(u8* buf, usize, usize length) const Result<usize> ConsoleDevice::read(u8* buf, usize, usize length) const

View File

@ -1,9 +1,12 @@
#include "fs/devices/DeviceRegistry.h" #include "fs/devices/DeviceRegistry.h"
#include "Log.h" #include "Log.h"
#include "fs/VFS.h"
#include "fs/devices/ConsoleDevice.h" #include "fs/devices/ConsoleDevice.h"
#include "fs/devices/FramebufferDevice.h" #include "fs/devices/FramebufferDevice.h"
#include "fs/devices/NullDevice.h" #include "fs/devices/NullDevice.h"
#include "fs/devices/ZeroDevice.h" #include "fs/devices/ZeroDevice.h"
#include "fs/tmpfs/FileSystem.h"
#include "thread/Thread.h"
#include <luna/Vector.h> #include <luna/Vector.h>
struct DeviceDescriptor struct DeviceDescriptor
@ -11,10 +14,14 @@ struct DeviceDescriptor
SharedPtr<Device> device; SharedPtr<Device> device;
u32 major; u32 major;
u32 minor; u32 minor;
const char* name;
mode_t mode;
}; };
Vector<DeviceDescriptor> g_available_devices = {}; Vector<DeviceDescriptor> g_available_devices = {};
SharedPtr<VFS::FileSystem> g_device_fs;
namespace DeviceRegistry namespace DeviceRegistry
{ {
Result<SharedPtr<Device>> fetch_special_device(u32 major, u32 minor) Result<SharedPtr<Device>> fetch_special_device(u32 major, u32 minor)
@ -27,20 +34,39 @@ namespace DeviceRegistry
return err(ENODEV); return err(ENODEV);
} }
Result<void> register_special_device(u32 major, u32 minor, SharedPtr<Device> device) Result<void> create_special_device_inode(DeviceDescriptor& descriptor)
{
auto inode = TRY(g_device_fs->create_device_inode(descriptor.major, descriptor.minor));
inode->chmod(descriptor.mode);
TRY(g_device_fs->root_inode()->add_entry(inode, descriptor.name));
return {};
}
Result<void> register_special_device(u32 major, u32 minor, SharedPtr<Device> device, const char* name, mode_t mode)
{ {
for (const auto& descriptor : g_available_devices) for (const auto& descriptor : g_available_devices)
{ {
if (descriptor.major == major && descriptor.minor == minor) return err(EEXIST); if (descriptor.major == major && descriptor.minor == minor) return err(EEXIST);
} }
kdbgln("DeviceRegistry: registered new device type %u:%u", major, minor); kdbgln("DeviceRegistry: registered new device type %u:%u at path /dev/%s", major, minor, name);
return g_available_devices.try_append(DeviceDescriptor { .device = device, .major = major, .minor = minor }); auto desc = DeviceDescriptor { .device = device, .major = major, .minor = minor, .name = name, .mode = mode };
TRY(g_available_devices.try_append(desc));
TRY(create_special_device_inode(desc));
return {};
} }
Result<void> init() Result<void> init()
{ {
auto device_fs = TRY(TmpFS::FileSystem::create());
TRY(VFS::mount("/dev", device_fs, Credentials {}));
g_device_fs = device_fs;
NullDevice::create(); NullDevice::create();
ZeroDevice::create(); ZeroDevice::create();
ConsoleDevice::create(); ConsoleDevice::create();

View File

@ -2,6 +2,7 @@
#include "fs/devices/Device.h" #include "fs/devices/Device.h"
#include <luna/SharedPtr.h> #include <luna/SharedPtr.h>
#include <sys/types.h>
namespace DeviceRegistry namespace DeviceRegistry
{ {
@ -15,7 +16,8 @@ namespace DeviceRegistry
Result<SharedPtr<Device>> fetch_special_device(u32 major, u32 minor); Result<SharedPtr<Device>> fetch_special_device(u32 major, u32 minor);
Result<void> register_special_device(u32 major, u32 minor, SharedPtr<Device> device); Result<void> register_special_device(u32 major, u32 minor, SharedPtr<Device> device, const char* name,
mode_t mode = 0666);
Result<void> init(); Result<void> init();
} }

View File

@ -6,7 +6,7 @@
Result<void> FramebufferDevice::create() Result<void> FramebufferDevice::create()
{ {
auto device = (SharedPtr<Device>)TRY(make_shared<FramebufferDevice>()); auto device = (SharedPtr<Device>)TRY(make_shared<FramebufferDevice>());
return DeviceRegistry::register_special_device(DeviceRegistry::Framebuffer, 0, device); return DeviceRegistry::register_special_device(DeviceRegistry::Framebuffer, 0, device, "fb0", 0600);
} }
Result<usize> FramebufferDevice::read(u8*, usize, usize) const Result<usize> FramebufferDevice::read(u8*, usize, usize) const

View File

@ -3,5 +3,5 @@
Result<void> NullDevice::create() Result<void> NullDevice::create()
{ {
auto device = (SharedPtr<Device>)TRY(make_shared<NullDevice>()); auto device = (SharedPtr<Device>)TRY(make_shared<NullDevice>());
return DeviceRegistry::register_special_device(DeviceRegistry::Memory, 0, device); return DeviceRegistry::register_special_device(DeviceRegistry::Memory, 0, device, "null");
} }

View File

@ -3,5 +3,5 @@
Result<void> ZeroDevice::create() Result<void> ZeroDevice::create()
{ {
auto device = (SharedPtr<Device>)TRY(make_shared<ZeroDevice>()); auto device = (SharedPtr<Device>)TRY(make_shared<ZeroDevice>());
return DeviceRegistry::register_special_device(DeviceRegistry::Memory, 1, device); return DeviceRegistry::register_special_device(DeviceRegistry::Memory, 1, device, "zero");
} }

View File

@ -1,4 +1,5 @@
#include "fs/tmpfs/FileSystem.h" #include "fs/tmpfs/FileSystem.h"
#include "fs/Mount.h"
#include "fs/devices/DeviceRegistry.h" #include "fs/devices/DeviceRegistry.h"
#include <luna/Alloc.h> #include <luna/Alloc.h>
#include <luna/CString.h> #include <luna/CString.h>
@ -49,6 +50,11 @@ namespace TmpFS
return (SharedPtr<VFS::Inode>)inode; return (SharedPtr<VFS::Inode>)inode;
} }
Result<void> FileSystem::set_mount_dir(SharedPtr<VFS::Inode> parent)
{
return m_root_inode->replace_entry(parent, "..");
}
void FileSystem::set_root(SharedPtr<VFS::Inode> root) void FileSystem::set_root(SharedPtr<VFS::Inode> root)
{ {
m_root_inode = root; m_root_inode = root;
@ -64,6 +70,20 @@ namespace TmpFS
return err(ENOENT); return err(ENOENT);
} }
Result<void> DirInode::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> DirInode::get(usize index) const Option<VFS::DirectoryEntry> DirInode::get(usize index) const
{ {
if (index >= m_entries.size()) return {}; if (index >= m_entries.size()) return {};
@ -90,6 +110,8 @@ namespace TmpFS
if (inode->type() == VFS::InodeType::Directory && inode->entries() != 2) return err(ENOTEMPTY); if (inode->type() == VFS::InodeType::Directory && inode->entries() != 2) return err(ENOTEMPTY);
if (inode->is_mountpoint()) return err(EBUSY);
m_entries.remove_first_matching( m_entries.remove_first_matching(
[&](const VFS::DirectoryEntry& entry) { return !strcmp(entry.name.chars(), name); }); [&](const VFS::DirectoryEntry& entry) { return !strcmp(entry.name.chars(), name); });

View File

@ -21,6 +21,8 @@ namespace TmpFS
Result<SharedPtr<VFS::Inode>> create_dir_inode(SharedPtr<VFS::Inode> parent) override; Result<SharedPtr<VFS::Inode>> create_dir_inode(SharedPtr<VFS::Inode> parent) override;
Result<SharedPtr<VFS::Inode>> create_device_inode(u32 major, u32 minor) override; Result<SharedPtr<VFS::Inode>> create_device_inode(u32 major, u32 minor) override;
Result<void> set_mount_dir(SharedPtr<VFS::Inode> parent) override;
static Result<SharedPtr<VFS::FileSystem>> create(); static Result<SharedPtr<VFS::FileSystem>> create();
virtual ~FileSystem() = default; virtual ~FileSystem() = default;
@ -341,6 +343,7 @@ namespace TmpFS
Result<SharedPtr<VFS::Inode>> create_subdirectory(const char* name) override; Result<SharedPtr<VFS::Inode>> create_subdirectory(const char* name) override;
Result<void> add_entry(SharedPtr<VFS::Inode> inode, const char* name); Result<void> add_entry(SharedPtr<VFS::Inode> inode, const char* name);
Result<void> replace_entry(SharedPtr<VFS::Inode> inode, const char* name);
virtual ~DirInode() = default; virtual ~DirInode() = default;

View File

@ -42,9 +42,10 @@ Result<void> init()
kinfoln("Used memory: %s", to_dynamic_unit(MemoryManager::used()).release_value().chars()); kinfoln("Used memory: %s", to_dynamic_unit(MemoryManager::used()).release_value().chars());
kinfoln("Reserved memory: %s", to_dynamic_unit(MemoryManager::reserved()).release_value().chars()); kinfoln("Reserved memory: %s", to_dynamic_unit(MemoryManager::reserved()).release_value().chars());
VFS::root_fs = TRY(TmpFS::FileSystem::create()); auto root = TRY(TmpFS::FileSystem::create());
TRY(VFS::mount_root(root));
TRY(InitRD::populate_vfs());
TRY(DeviceRegistry::init()); TRY(DeviceRegistry::init());
InitRD::populate_vfs();
auto init = TRY(VFS::resolve_path("/bin/init", Credentials {})); auto init = TRY(VFS::resolve_path("/bin/init", Credentials {}));
auto init_thread = TRY(Scheduler::new_userspace_thread(init, "/bin/init")); auto init_thread = TRY(Scheduler::new_userspace_thread(init, "/bin/init"));

View File

@ -88,7 +88,11 @@ Result<u64> sys_execve(Registers* regs, SyscallArgs args)
{ {
auto& descriptor = current->fd_table[i]; auto& descriptor = current->fd_table[i];
if (!descriptor.has_value()) continue; if (!descriptor.has_value()) continue;
if (descriptor->flags & O_CLOEXEC) descriptor = {}; if (descriptor->flags & O_CLOEXEC)
{
descriptor->inode->fs()->remove_handle();
descriptor = {};
}
} }
MMU::delete_userspace_page_directory(current->directory); MMU::delete_userspace_page_directory(current->directory);
@ -132,7 +136,11 @@ Result<u64> sys_fork(Registers* regs, SyscallArgs)
thread->current_directory_path = move(current_directory_path); thread->current_directory_path = move(current_directory_path);
thread->parent = current; thread->parent = current;
for (int i = 0; i < FD_MAX; i++) { thread->fd_table[i] = current->fd_table[i]; } for (int i = 0; i < FD_MAX; i++)
{
thread->fd_table[i] = current->fd_table[i];
if (current->fd_table[i].has_value()) current->fd_table[i]->inode->fs()->add_handle();
}
image->apply(thread); image->apply(thread);

34
kernel/src/sys/mount.cpp Normal file
View File

@ -0,0 +1,34 @@
#include "fs/VFS.h"
#include "fs/tmpfs/FileSystem.h"
#include "memory/MemoryManager.h"
#include "sys/Syscall.h"
#include "thread/Scheduler.h"
Result<u64> sys_mount(Registers*, SyscallArgs args)
{
auto target = TRY(MemoryManager::strdup_from_user(args[0]));
auto fstype = TRY(MemoryManager::strdup_from_user(args[1]));
auto* current = Scheduler::current();
if (current->auth.euid != 0) return err(EPERM);
// Right now we only support one file system.
if (fstype.view() != "tmpfs") return err(ENODEV);
auto fs = TRY(TmpFS::FileSystem::create());
TRY(VFS::mount(target.chars(), fs, current->auth, current->current_directory));
return 0;
}
Result<u64> sys_umount(Registers*, SyscallArgs args)
{
auto target = TRY(MemoryManager::strdup_from_user(args[0]));
auto* current = Scheduler::current();
if (current->auth.euid != 0) return err(EPERM);
TRY(VFS::umount(target.chars(), current->auth, current->current_directory));
return 0;
}

View File

@ -72,6 +72,8 @@ Result<u64> sys_openat(Registers*, SyscallArgs args)
kinfoln("openat: opening file %s from dirfd %d, flags %d, mode %#o = fd %d", path.chars(), dirfd, flags, mode, fd); kinfoln("openat: opening file %s from dirfd %d, flags %d, mode %#o = fd %d", path.chars(), dirfd, flags, mode, fd);
inode->fs()->add_handle();
current->fd_table[fd] = FileDescriptor { inode, 0, flags & FLAGS_TO_KEEP }; current->fd_table[fd] = FileDescriptor { inode, 0, flags & FLAGS_TO_KEEP };
return (u64)fd; return (u64)fd;
@ -88,6 +90,8 @@ Result<u64> sys_close(Registers*, SyscallArgs args)
if (!descriptor.has_value()) return err(EBADF); if (!descriptor.has_value()) return err(EBADF);
descriptor->inode->fs()->remove_handle();
descriptor = {}; descriptor = {};
return 0; return 0;

View File

@ -182,6 +182,11 @@ namespace Scheduler
{ {
auto stack = thread->kernel_stack; auto stack = thread->kernel_stack;
MemoryManager::unmap_owned_and_free_vm(stack.bottom(), stack.bytes() / ARCH_PAGE_SIZE).release_value(); MemoryManager::unmap_owned_and_free_vm(stack.bottom(), stack.bytes() / ARCH_PAGE_SIZE).release_value();
for (int i = 0; i < FD_MAX; i++)
{
if (thread->fd_table[i].has_value()) thread->fd_table[i]->inode->fs()->remove_handle();
}
} }
if (!thread->is_kernel) MMU::delete_userspace_page_directory(thread->directory); if (!thread->is_kernel) MMU::delete_userspace_page_directory(thread->directory);

View File

@ -24,6 +24,7 @@ set(SOURCES
src/sys/wait.cpp src/sys/wait.cpp
src/sys/ioctl.cpp src/sys/ioctl.cpp
src/sys/utsname.cpp src/sys/utsname.cpp
src/sys/mount.cpp
) )
if(${LUNA_ARCH} STREQUAL "x86_64") if(${LUNA_ARCH} STREQUAL "x86_64")

21
libc/include/sys/mount.h Normal file
View File

@ -0,0 +1,21 @@
/* sys/mount.h: Virtual file system mounting operations. */
#ifndef _SYS_MOUNT_H
#define _SYS_MOUNT_H
#ifdef __cplusplus
extern "C"
{
#endif
/* Mount a file system on target. */
int mount(const char* target, const char* fstype);
/* Unmount the file system mounted on target. */
int umount(const char* target);
#ifdef __cplusplus
}
#endif
#endif

19
libc/src/sys/mount.cpp Normal file
View File

@ -0,0 +1,19 @@
#include <bits/errno-return.h>
#include <sys/mount.h>
#include <sys/syscall.h>
#include <unistd.h>
extern "C"
{
int mount(const char* target, const char* fstype)
{
long rc = syscall(SYS_mount, target, fstype);
__errno_return(rc, int);
}
int umount(const char* target)
{
long rc = syscall(SYS_umount, target);
__errno_return(rc, int);
}
}

View File

@ -4,7 +4,8 @@
_e(exit) _e(clock_gettime) _e(mmap) _e(munmap) _e(usleep) _e(openat) _e(close) _e(read) _e(getpid) _e(write) \ _e(exit) _e(clock_gettime) _e(mmap) _e(munmap) _e(usleep) _e(openat) _e(close) _e(read) _e(getpid) _e(write) \
_e(lseek) _e(mkdir) _e(execve) _e(mknod) _e(fork) _e(waitpid) _e(getppid) _e(fcntl) _e(getdents) _e(getuid) \ _e(lseek) _e(mkdir) _e(execve) _e(mknod) _e(fork) _e(waitpid) _e(getppid) _e(fcntl) _e(getdents) _e(getuid) \
_e(geteuid) _e(getgid) _e(getegid) _e(setuid) _e(setgid) _e(seteuid) _e(setegid) _e(fchmodat) _e(fchownat) \ _e(geteuid) _e(getgid) _e(getegid) _e(setuid) _e(setgid) _e(seteuid) _e(setegid) _e(fchmodat) _e(fchownat) \
_e(ioctl) _e(fstatat) _e(chdir) _e(getcwd) _e(unlinkat) _e(uname) _e(sethostname) _e(dup2) _e(pipe) _e(ioctl) _e(fstatat) _e(chdir) _e(getcwd) _e(unlinkat) _e(uname) _e(sethostname) _e(dup2) _e(pipe) \
_e(mount) _e(umount)
enum Syscalls enum Syscalls
{ {

View File

@ -26,3 +26,5 @@ chmod a+s initrd/bin/su
mkdir -p initrd/home/selene mkdir -p initrd/home/selene
chown 1000:1000 initrd/home/selene chown 1000:1000 initrd/home/selene
mkdir -p initrd/dev