diff options
author | dzwdz | 2023-01-06 21:11:44 +0100 |
---|---|---|
committer | dzwdz | 2023-01-06 21:11:44 +0100 |
commit | a1a4ab33cd75f0bc1d5e71989b01ba3446c998ae (patch) | |
tree | 4796f9ffc780dcb0336ed7c66c0cb42584320d61 /src/kernel/vfs/procfs.c | |
parent | e0c7bad47a54d865ef6194643e2cd20f6094e507 (diff) |
kernel: basic procfs
Diffstat (limited to 'src/kernel/vfs/procfs.c')
-rw-r--r-- | src/kernel/vfs/procfs.c | 122 |
1 files changed, 122 insertions, 0 deletions
diff --git a/src/kernel/vfs/procfs.c b/src/kernel/vfs/procfs.c new file mode 100644 index 0000000..e434c45 --- /dev/null +++ b/src/kernel/vfs/procfs.c @@ -0,0 +1,122 @@ +#include <camellia/errno.h> +#include <kernel/mem/virt.h> +#include <kernel/panic.h> +#include <kernel/proc.h> +#include <kernel/vfs/procfs.h> +#include <kernel/vfs/request.h> +#include <shared/mem.h> + +static uint32_t openpath(const char *path, size_t len, struct process *root); +static struct process *findgid(uint32_t gid, struct process *root); +static void procfs_accept(struct vfs_request *req); +static void procfs_cleanup(struct vfs_backend *be); + +static uint32_t +openpath(const char *path, size_t len, struct process *p) +{ + if (len == 0) return 0; + path++, len--; + + while (len) { + uint32_t cid = 0; + for (; 0 < len && *path != '/'; path++, len--) { + char c = *path; + if (!('0' <= c && c <= '9')) { + return 0; + } + cid = cid * 10 + *path - '0'; + } + if (len == 0) { + return 0; + } + assert(*path == '/'); + path++, len--; + + p = p->child; + if (!p) return 0; + while (p->cid != cid) { + p = p->sibling; + if (!p) return 0; + } + } + return p->globalid; +} + +static struct process * +findgid(uint32_t gid, struct process *root) +{ + for (struct process *p = root; p; p = process_next(p)) { + if (p->globalid == gid) return p; + } + return NULL; +} + +static void +procfs_accept(struct vfs_request *req) +{ + struct process *root = req->backend->kern.data; + struct process *p; + char buf[512]; + assert(root); + if (req->type == VFSOP_OPEN) { + int gid; + assert(req->input.kern); + gid = openpath(req->input.buf_kern, req->input.len, root); + vfsreq_finish_short(req, gid == 0 ? -ENOENT : gid); + return; + } + p = findgid((uintptr_t)req->id, root); + if (!p) { + vfsreq_finish_short(req, -EGENERIC); + return; + } + + if (req->type == VFSOP_READ) { + // TODO port dirbuild to kernel + int pos = 0; + if (req->offset != 0) { + vfsreq_finish_short(req, -ENOSYS); + return; + } + for (struct process *iter = p->child; iter; iter = iter->sibling) { + assert(pos < 512); + // processes could possibly be identified by unique identifiers instead + // e.g. an encrypted gid, or just a randomly generated one + // con: would require bringing in a crypto library + pos += snprintf(buf + pos, 512 - pos, "%d/", iter->cid) + 1; + if (512 <= pos) { + vfsreq_finish_short(req, -1); + } + } + assert(0 <= pos && (size_t)pos <= sizeof buf); + virt_cpy_to(req->caller->pages, req->output.buf, buf, pos); + vfsreq_finish_short(req, pos); + } else { + vfsreq_finish_short(req, -ENOSYS); + } +} + +static void +procfs_cleanup(struct vfs_backend *be) +{ + struct process *p = be->kern.data; + assert(p); + p->refcount--; +} + +struct vfs_backend * +procfs_backend(struct process *proc) +{ + struct vfs_backend *be = kzalloc(sizeof(struct vfs_backend)); + *be = (struct vfs_backend) { + .is_user = false, + .potential_handlers = 1, + .refcount = 1, + .kern.accept = procfs_accept, + .kern.data = proc, + .kern.cleanup = procfs_cleanup, + }; + proc->refcount++; + assert(proc->refcount); /* overflow */ + return be; +} |