Compare commits
3 Commits
4d106b6b8c
...
1f4c4928cc
Author | SHA1 | Date | |
---|---|---|---|
1f4c4928cc | |||
29174ca228 | |||
e7d482e78a |
@ -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)
|
||||||
|
@ -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
24
apps/mount.cpp
Normal 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
22
apps/umount.cpp
Normal 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;
|
||||||
|
}
|
@ -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
19
kernel/src/fs/Mount.cpp
Normal 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
150
kernel/src/fs/Mount.h
Normal 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;
|
@ -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 {};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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 = {});
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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();
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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");
|
||||||
}
|
}
|
||||||
|
@ -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");
|
||||||
}
|
}
|
||||||
|
@ -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); });
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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"));
|
||||||
|
@ -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
34
kernel/src/sys/mount.cpp
Normal 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;
|
||||||
|
}
|
@ -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;
|
||||||
|
@ -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);
|
||||||
|
@ -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
21
libc/include/sys/mount.h
Normal 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
19
libc/src/sys/mount.cpp
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
@ -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
|
||||||
{
|
{
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user