|
@@ -0,0 +1,249 @@
|
|
|
+#include <map>
|
|
|
+
|
|
|
+#include <errno.h>
|
|
|
+#include <stdint.h>
|
|
|
+#include <sys/mount.h>
|
|
|
+#include <unistd.h>
|
|
|
+
|
|
|
+#include <types/status.h>
|
|
|
+
|
|
|
+#include <kernel/module.hpp>
|
|
|
+#include <kernel/vfs.hpp>
|
|
|
+#include <kernel/vfs/vfs.hpp>
|
|
|
+
|
|
|
+struct mount_flags_opt {
|
|
|
+ unsigned long flag;
|
|
|
+ const char* name;
|
|
|
+};
|
|
|
+
|
|
|
+static struct mount_flags_opt mount_opts[] = {
|
|
|
+ {MS_NOSUID, ",nosuid"},
|
|
|
+ {MS_NODEV, ",nodev"},
|
|
|
+ {MS_NOEXEC, ",noexec"},
|
|
|
+ {MS_NOATIME, ",noatime"},
|
|
|
+ {MS_RELATIME, ",relatime"},
|
|
|
+ {MS_LAZYTIME, ",lazytime"},
|
|
|
+};
|
|
|
+
|
|
|
+static std::string get_mount_opts(unsigned long mnt_flags)
|
|
|
+{
|
|
|
+ std::string retval;
|
|
|
+
|
|
|
+ if (mnt_flags & MS_RDONLY)
|
|
|
+ retval += "ro";
|
|
|
+ else
|
|
|
+ retval += "rw";
|
|
|
+
|
|
|
+ for (const auto& opt : mount_opts) {
|
|
|
+ if (mnt_flags & opt.flag)
|
|
|
+ retval += opt.name;
|
|
|
+ }
|
|
|
+
|
|
|
+ return retval;
|
|
|
+}
|
|
|
+
|
|
|
+static ssize_t mounts_read(char* page, size_t n)
|
|
|
+{
|
|
|
+ auto orig_n = n;
|
|
|
+
|
|
|
+ for (const auto& [ _, mdata ] : fs::mounts) {
|
|
|
+ if (n == 0)
|
|
|
+ break;
|
|
|
+
|
|
|
+ // TODO: get vfs options
|
|
|
+ auto mount_flags = get_mount_opts(mdata.flags);
|
|
|
+
|
|
|
+ int nwrote = snprintf(page, n, "%s %s %s %s 0 0\n",
|
|
|
+ mdata.source.c_str(), mdata.mount_point.c_str(),
|
|
|
+ mdata.fstype.c_str(), mount_flags.c_str());
|
|
|
+
|
|
|
+ n -= nwrote;
|
|
|
+ page += nwrote;
|
|
|
+ }
|
|
|
+
|
|
|
+ return orig_n - n;
|
|
|
+}
|
|
|
+
|
|
|
+namespace fs::proc {
|
|
|
+
|
|
|
+struct proc_file {
|
|
|
+ std::string name;
|
|
|
+
|
|
|
+ ssize_t (*read)(char* page_buffer, size_t n);
|
|
|
+ ssize_t (*write)(const char* data, size_t n);
|
|
|
+};
|
|
|
+
|
|
|
+class procfs : public virtual fs::vfs {
|
|
|
+private:
|
|
|
+ std::string source;
|
|
|
+ std::map<ino_t, proc_file> files;
|
|
|
+
|
|
|
+ ino_t free_ino = 1;
|
|
|
+
|
|
|
+public:
|
|
|
+ static procfs* create(const char* source, unsigned long, const void*)
|
|
|
+ {
|
|
|
+ // TODO: flags
|
|
|
+ return new procfs(source);
|
|
|
+ }
|
|
|
+
|
|
|
+ int create_file(std::string name,
|
|
|
+ ssize_t (*read_func)(char*, size_t),
|
|
|
+ ssize_t (*write_func)(const char*, size_t))
|
|
|
+ {
|
|
|
+ auto ino = free_ino++;
|
|
|
+
|
|
|
+ auto [ _, inserted ] =
|
|
|
+ files.insert({ino, proc_file {name, read_func, write_func}});
|
|
|
+
|
|
|
+ cache_inode(0, ino, S_IFREG | 0666, 0, 0);
|
|
|
+
|
|
|
+ return inserted ? 0 : -EEXIST;
|
|
|
+ }
|
|
|
+
|
|
|
+ procfs(const char* _source)
|
|
|
+ : source{_source}
|
|
|
+ {
|
|
|
+ auto* ind = cache_inode(0, 0, S_IFDIR | 0777, 0, 0);
|
|
|
+
|
|
|
+ create_file("mounts", mounts_read, nullptr);
|
|
|
+
|
|
|
+ register_root_node(ind);
|
|
|
+ }
|
|
|
+
|
|
|
+ size_t read(inode* file, char* buf, size_t buf_size, size_t offset, size_t n) override
|
|
|
+ {
|
|
|
+ if (file->ino == 0)
|
|
|
+ return -EISDIR;
|
|
|
+
|
|
|
+ auto iter = files.find(file->ino);
|
|
|
+ if (!iter)
|
|
|
+ return -EIO;
|
|
|
+
|
|
|
+ auto& [ ino, pf ] = *iter;
|
|
|
+
|
|
|
+ if (!pf.read)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ // TODO: fix it
|
|
|
+ if (offset)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ // TODO: allocate page buffer
|
|
|
+ char* page_buffer = new char[4096];
|
|
|
+
|
|
|
+ ssize_t nread = pf.read(page_buffer, 4096);
|
|
|
+ if (nread < 0) {
|
|
|
+ delete[] page_buffer;
|
|
|
+ return nread;
|
|
|
+ }
|
|
|
+
|
|
|
+ n = std::min(n, buf_size);
|
|
|
+ n = std::min(n, (size_t)nread);
|
|
|
+
|
|
|
+ strncpy(buf, page_buffer, n);
|
|
|
+
|
|
|
+ delete[] page_buffer;
|
|
|
+ return n;
|
|
|
+ }
|
|
|
+
|
|
|
+ int readdir(inode *dir, size_t offset, const filldir_func &callback) override
|
|
|
+ {
|
|
|
+ if (dir->ino != 0)
|
|
|
+ return -ENOTDIR;
|
|
|
+
|
|
|
+ // TODO: fix it
|
|
|
+ if (offset)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ int nread = 0;
|
|
|
+ for (const auto& [ ino, pf ] : files) {
|
|
|
+ auto* ind = get_inode(ino);
|
|
|
+ int ret = callback(pf.name.c_str(), 0, ind, ind->mode);
|
|
|
+ if (ret != GB_OK)
|
|
|
+ return -EIO;
|
|
|
+ ++nread;
|
|
|
+ }
|
|
|
+
|
|
|
+ return nread;
|
|
|
+ }
|
|
|
+
|
|
|
+ virtual int inode_statx(dentry* dent, statx* st, unsigned int mask) override
|
|
|
+ {
|
|
|
+ auto* ind = dent->ind;
|
|
|
+
|
|
|
+ st->stx_mask = 0;
|
|
|
+
|
|
|
+ if (mask & STATX_NLINK) {
|
|
|
+ st->stx_nlink = ind->nlink;
|
|
|
+ st->stx_mask |= STATX_NLINK;
|
|
|
+ }
|
|
|
+
|
|
|
+ // TODO: set modification time
|
|
|
+ if (mask & STATX_MTIME) {
|
|
|
+ st->stx_mtime = {};
|
|
|
+ st->stx_mask |= STATX_MTIME;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (mask & STATX_SIZE) {
|
|
|
+ st->stx_size = ind->size;
|
|
|
+ st->stx_mask |= STATX_SIZE;
|
|
|
+ }
|
|
|
+
|
|
|
+ st->stx_mode = 0;
|
|
|
+ if (mask & STATX_MODE) {
|
|
|
+ st->stx_mode |= ind->mode & ~S_IFMT;
|
|
|
+ st->stx_mask |= STATX_MODE;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (mask & STATX_TYPE) {
|
|
|
+ st->stx_mode |= ind->mode & S_IFMT;
|
|
|
+ st->stx_mask |= STATX_TYPE;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (mask & STATX_INO) {
|
|
|
+ st->stx_ino = ind->ino;
|
|
|
+ st->stx_mask |= STATX_INO;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (mask & STATX_BLOCKS) {
|
|
|
+ st->stx_blocks = 0;
|
|
|
+ st->stx_blksize = 4096;
|
|
|
+ st->stx_mask |= STATX_BLOCKS;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (mask & STATX_UID) {
|
|
|
+ st->stx_uid = ind->uid;
|
|
|
+ st->stx_mask |= STATX_UID;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (mask & STATX_GID) {
|
|
|
+ st->stx_gid = ind->gid;
|
|
|
+ st->stx_mask |= STATX_GID;
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+class procfs_module : public virtual kernel::module::module {
|
|
|
+public:
|
|
|
+ procfs_module() : module("procfs") { }
|
|
|
+
|
|
|
+ virtual int init() override
|
|
|
+ {
|
|
|
+ int ret = fs::register_fs("procfs", procfs::create);
|
|
|
+ if (ret != 0)
|
|
|
+ return kernel::module::MODULE_FAILED;
|
|
|
+ return kernel::module::MODULE_SUCCESS;
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+static kernel::module::module* procfs_init()
|
|
|
+{
|
|
|
+ return new procfs_module;
|
|
|
+}
|
|
|
+
|
|
|
+INTERNAL_MODULE(procfs, procfs_init);
|
|
|
+
|
|
|
+} // namespace fs::proc
|