summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordzwdz2023-08-04 01:20:38 +0200
committerdzwdz2023-08-06 00:36:07 +0200
commita71120adf590f699c4b8d6249a340976575ea530 (patch)
treefa099b8552c1536e29f1a1a9ec2bb04663b8370b
parent2d7da42acbf2782636e481ebd79f30700fb7dc9e (diff)
libc: fs_dirinject2 for injecting multiple paths
-rw-r--r--src/user/app/init/init.c9
-rw-r--r--src/user/app/shell/shell.c2
-rw-r--r--src/user/bootstrap/main.c2
-rw-r--r--src/user/lib/fs/dirinject.c129
-rw-r--r--src/user/lib/fs/misc.c78
-rw-r--r--src/user/lib/include/camellia/fs/misc.h3
6 files changed, 144 insertions, 79 deletions
diff --git a/src/user/app/init/init.c b/src/user/app/init/init.c
index 9528a28..61fb27b 100644
--- a/src/user/app/init/init.c
+++ b/src/user/app/init/init.c
@@ -43,6 +43,15 @@ int main(void) {
freopen("/kdev/com1", "a+", stderr);
printf("[init] stage 2, main at %p, teststr at %p\n", &main, teststr);
+ MOUNT_AT("/") {
+ fs_dirinject2((const char*[]){
+ "/fake/b/c",
+ "/fake/c",
+ "/faker",
+ NULL
+ });
+ }
+
MOUNT_AT("/keyboard") {
MOUNT_AT("/") { fs_whitelist((const char*[]){"/kdev/ps2/kb", NULL}); }
ps2_drv();
diff --git a/src/user/app/shell/shell.c b/src/user/app/shell/shell.c
index 8e13029..e9293bc 100644
--- a/src/user/app/shell/shell.c
+++ b/src/user/app/shell/shell.c
@@ -61,7 +61,7 @@ void run_args(int argc, char **argv, struct redir *redir) {
/*
if (!(3 <= argc && !strcmp(argv[2], "raw"))) {
if (!fork2_n_mount("/")) {
- fs_dir_inject(argv[1]);
+ fs_dirinject(argv[1]);
exit(1);
}
}
diff --git a/src/user/bootstrap/main.c b/src/user/bootstrap/main.c
index 638585c..4e900f5 100644
--- a/src/user/bootstrap/main.c
+++ b/src/user/bootstrap/main.c
@@ -25,7 +25,7 @@ int main(void) {
}
_sys_mount(HANDLE_PROCFS, "/proc/", strlen("/proc/"));
- MOUNT_AT("/") { fs_dir_inject("/proc/"); }
+ MOUNT_AT("/") { fs_dirinject("/proc/"); }
MOUNT_AT("/init/") { tar_driver(&_initrd); }
diff --git a/src/user/lib/fs/dirinject.c b/src/user/lib/fs/dirinject.c
new file mode 100644
index 0000000..9b08756
--- /dev/null
+++ b/src/user/lib/fs/dirinject.c
@@ -0,0 +1,129 @@
+#include <assert.h>
+#include <camellia/fs/dir.h>
+#include <camellia/fs/misc.h>
+#include <camellia/syscalls.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/param.h>
+#include <unistd.h>
+
+typedef struct Handle {
+ int delegate;
+ int plen;
+ char path[];
+} Handle;
+
+static int
+dir_seglen(const char *path)
+{
+ /* if path contains /, return its position + 1
+ * otherwise, return strlen */
+ int len = 0;
+ while (path[len]) {
+ if (path[len] == '/') {
+ len++;
+ break;
+ }
+ len++;
+ }
+ return len;
+}
+
+static int
+find_injects(const char *injects[], const char *path, int plen, struct dirbuild *db)
+{
+ // TODO deduplicate
+ const char *inj;
+ int matches = 0;
+ assert(plen >= 1);
+ assert(path[plen-1] == '/');
+
+ while ((inj = *injects++)) {
+ int ilen = strlen(inj);
+ if (plen < ilen && memcmp(path, inj, plen) == 0) {
+ if (db) {
+ /* inj[plen-1] == '/' */
+ const char *ent = inj + plen;
+ dir_appendl(db, ent, dir_seglen(ent));
+ }
+ matches++;
+ }
+ }
+ return matches;
+}
+
+void
+fs_dirinject2(const char *injects[])
+{
+ const size_t buflen = 4096;
+ char *buf = malloc(buflen);
+ if (!buf) exit(1);
+
+ for (;;) {
+ struct ufs_request req;
+ hid_t reqh = _sys_fs_wait(buf, buflen, &req);
+ if (reqh < 0) break;
+ Handle *hndl = req.id;
+ switch (req.op) {
+ case VFSOP_OPEN: {
+ if (buf[req.len - 1] == '/') {
+ if (find_injects(injects, buf, req.len, NULL) > 0) {
+ /* opening a directory that we're injecting into */
+ hndl = malloc(sizeof(Handle) + req.len);
+ if (hndl == NULL) {
+ _sys_fs_respond(reqh, NULL, -EGENERIC, 0);
+ break;
+ }
+ /* ignore errors from _sys_open */
+ hndl->delegate = _sys_open(buf, req.len, req.flags);
+ hndl->plen = req.len;
+ memcpy(hndl->path, buf, hndl->plen);
+ _sys_fs_respond(reqh, hndl, 0, 0);
+ break;
+ }
+ }
+ /* default behaviour */
+ forward_open(reqh, buf, req.len, req.flags);
+ break;
+ }
+
+ case VFSOP_CLOSE: {
+ if (hndl->delegate >= 0) {
+ close(hndl->delegate);
+ }
+ free(hndl);
+ _sys_fs_respond(reqh, NULL, 0, 0);
+ break;
+ }
+
+ case VFSOP_READ:
+ case VFSOP_GETSIZE: {
+ struct dirbuild db;
+ char *target = NULL;
+ if (req.op == VFSOP_READ) {
+ target = buf;
+ }
+ req.capacity = MIN(req.capacity, buflen);
+
+ dir_start(&db, req.offset, target, req.capacity);
+ find_injects(injects, hndl->path, hndl->plen, &db);
+ if (hndl->delegate >= 0) {
+ dir_append_from(&db, hndl->delegate);
+ }
+ _sys_fs_respond(reqh, target, dir_finish(&db), 0);
+ break;
+ }
+
+ default: {
+ _sys_fs_respond(reqh, NULL, -1, 0);
+ break;
+ }
+ }
+ }
+ exit(0);
+}
+
+void
+fs_dirinject(const char *path) {
+ fs_dirinject2((const char*[]){ path, NULL });
+}
diff --git a/src/user/lib/fs/misc.c b/src/user/lib/fs/misc.c
index c68d2be..2a39e9a 100644
--- a/src/user/lib/fs/misc.c
+++ b/src/user/lib/fs/misc.c
@@ -20,20 +20,6 @@ bool fork2_n_mount(const char *path) {
return false;
}
-static int dir_seglen(const char *path) {
- /* if path contains /, return its position + 1
- * otherwise, return strlen */
- int len = 0;
- while (path[len]) {
- if (path[len] == '/') {
- len++;
- break;
- }
- len++;
- }
- return len;
-}
-
void forward_open(hid_t reqh, const char *path, long len, int flags) {
// TODO use threads
// TODO solve for more complex cases, e.g. fs_union
@@ -41,7 +27,7 @@ void forward_open(hid_t reqh, const char *path, long len, int flags) {
* but that should only hold the caller back, and not the fs driver.
*
* for example, running `httpd` in one term would prevent you from doing
- * basically anything on the second term, because fs_dir_inject would be
+ * basically anything on the second term, because fs_dirinject would be
* stuck on open()ing the socket */
if (!_sys_fork(FORK_NOREAP, NULL)) {
_sys_fs_respond(reqh, NULL, _sys_open(path, len, flags), FSR_DELEGATE);
@@ -150,66 +136,6 @@ void fs_union(const char **list) {
exit(0);
}
-
-void fs_dir_inject(const char *path) {
- struct fs_dir_handle {
- const char *inject;
- int delegate, inject_len;
- };
- const size_t path_len = strlen(path);
- const size_t buflen = 1024;
- char *buf = malloc(buflen);
- if (!buf) exit(1);
-
- for (;;) {
- struct ufs_request res;
- hid_t reqh = _sys_fs_wait(buf, buflen, &res);
- if (reqh < 0) break;
- struct fs_dir_handle *data = res.id;
- switch (res.op) {
- struct dirbuild db;
- case VFSOP_OPEN:
- if (buf[res.len - 1] == '/' &&
- res.len < path_len && !memcmp(path, buf, res.len))
- {
- /* opening a directory that we're injecting into */
- data = malloc(sizeof *data);
- data->delegate = _sys_open(buf, res.len, res.flags);
- data->inject = path + res.len;
- data->inject_len = dir_seglen(data->inject);
- _sys_fs_respond(reqh, data, 0, 0);
- } else {
- forward_open(reqh, buf, res.len, res.flags);
- }
- break;
-
- case VFSOP_CLOSE:
- if (data->delegate >= 0)
- close(data->delegate);
- free(data);
- _sys_fs_respond(reqh, NULL, 0, 0);
- break;
-
- case VFSOP_READ:
- case VFSOP_GETSIZE:
- if (res.capacity > buflen)
- res.capacity = buflen;
- char *target = res.op == VFSOP_READ ? buf : NULL;
- dir_start(&db, res.offset, target, res.capacity);
- dir_appendl(&db, data->inject, data->inject_len);
- if (data->delegate >= 0)
- dir_append_from(&db, data->delegate);
- _sys_fs_respond(reqh, target, dir_finish(&db), 0);
- break;
-
- default:
- _sys_fs_respond(reqh, NULL, -1, 0);
- break;
- }
- }
- exit(0);
-}
-
hid_t ufs_wait(char *buf, size_t len, struct ufs_request *req) {
hid_t reqh;
for (;;) {
@@ -240,7 +166,7 @@ bool mount_at_pred(const char *path) {
if (strcmp("/", path) && !fork2_n_mount("/")) {
_klogf("%s: dir", path);
setproctitle("d'%s'", path);
- fs_dir_inject(path);
+ fs_dirinject(path);
exit(1);
}
return false; /* continue after the for loop */
diff --git a/src/user/lib/include/camellia/fs/misc.h b/src/user/lib/include/camellia/fs/misc.h
index c84c5b6..92679e9 100644
--- a/src/user/lib/include/camellia/fs/misc.h
+++ b/src/user/lib/include/camellia/fs/misc.h
@@ -10,7 +10,8 @@ void fs_passthru(const char *prefix);
void fs_whitelist(const char **list);
void fs_union(const char **list);
-void fs_dir_inject(const char *path);
+void fs_dirinject(const char *path);
+void fs_dirinject2(const char *injects[]);
bool mount_at_pred(const char *path);