diff options
Diffstat (limited to 'src/user')
-rw-r--r-- | src/user/app/init/init.c | 9 | ||||
-rw-r--r-- | src/user/app/shell/shell.c | 2 | ||||
-rw-r--r-- | src/user/bootstrap/main.c | 2 | ||||
-rw-r--r-- | src/user/lib/fs/dirinject.c | 129 | ||||
-rw-r--r-- | src/user/lib/fs/misc.c | 78 | ||||
-rw-r--r-- | src/user/lib/include/camellia/fs/misc.h | 3 |
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); |