From 6a4d4a41a664e6a4c406a449ea847abd4a224bcf Mon Sep 17 00:00:00 2001 From: dzwdz Date: Fri, 22 Sep 2023 23:42:30 +0200 Subject: build: support single file commands --- configure | 19 ++-- src/cmd/drawmouse.c | 86 ++++++++++++++++++ src/cmd/drawmouse/drawmouse.c | 86 ------------------ src/cmd/dvd.c | 42 +++++++++ src/cmd/dvd/dvd.c | 42 --------- src/cmd/find.c | 55 ++++++++++++ src/cmd/find/find.c | 55 ------------ src/cmd/httpd.c | 82 +++++++++++++++++ src/cmd/httpd/httpd.c | 82 ----------------- src/cmd/iochk.c | 96 ++++++++++++++++++++ src/cmd/iochk/iochk.c | 96 -------------------- src/cmd/iostress.c | 43 +++++++++ src/cmd/iostress/iostress.c | 43 --------- src/cmd/logfs.c | 34 ++++++++ src/cmd/logfs/logfs.c | 34 -------- src/cmd/netdog.c | 48 ++++++++++ src/cmd/netdog/nd.c | 48 ---------- src/cmd/ps.c | 54 ++++++++++++ src/cmd/ps/ps.c | 54 ------------ src/cmd/socksfs.c | 164 ++++++++++++++++++++++++++++++++++ src/cmd/socksfs/socksfs.c | 164 ---------------------------------- src/cmd/testelf/main.c | 26 ------ src/cmd/tmpfs.c | 198 ++++++++++++++++++++++++++++++++++++++++++ src/cmd/tmpfs/tmpfs.c | 198 ------------------------------------------ src/cmd/true.c | 3 + src/cmd/true/true.c | 3 - 26 files changed, 918 insertions(+), 937 deletions(-) create mode 100644 src/cmd/drawmouse.c delete mode 100644 src/cmd/drawmouse/drawmouse.c create mode 100644 src/cmd/dvd.c delete mode 100644 src/cmd/dvd/dvd.c create mode 100644 src/cmd/find.c delete mode 100644 src/cmd/find/find.c create mode 100644 src/cmd/httpd.c delete mode 100644 src/cmd/httpd/httpd.c create mode 100644 src/cmd/iochk.c delete mode 100644 src/cmd/iochk/iochk.c create mode 100644 src/cmd/iostress.c delete mode 100644 src/cmd/iostress/iostress.c create mode 100644 src/cmd/logfs.c delete mode 100644 src/cmd/logfs/logfs.c create mode 100644 src/cmd/netdog.c delete mode 100644 src/cmd/netdog/nd.c create mode 100644 src/cmd/ps.c delete mode 100644 src/cmd/ps/ps.c create mode 100644 src/cmd/socksfs.c delete mode 100644 src/cmd/socksfs/socksfs.c delete mode 100644 src/cmd/testelf/main.c create mode 100644 src/cmd/tmpfs.c delete mode 100644 src/cmd/tmpfs/tmpfs.c create mode 100644 src/cmd/true.c delete mode 100644 src/cmd/true/true.c diff --git a/configure b/configure index 9583fdd..68486a3 100755 --- a/configure +++ b/configure @@ -1,12 +1,17 @@ #!/usr/bin/env python3 from glob import glob +import os file = open('Makefile', 'w', encoding='utf-8') def raw(s): print(s, file=file) def srcobj(path): - srcs = glob(path + '/**/*.[csS]', recursive=True) + srcs = None + if os.path.isfile(path): + srcs = [path] + else: + srcs = glob(path + '/**/*.[csS]', recursive=True) objs = ['out/obj/' + src.removeprefix('src/') + '.o' for src in srcs] return ' ' + ' '.join(objs) + ' ' @@ -95,13 +100,15 @@ t('out/fs/boot/grub/grub.cfg', 'src/kernel/arch/amd64/grub.cfg', ['cp $< $@']) t('out/fs.e2', '', ['mkfs.ext2 $@ 1024 >/dev/null']) -userbins = glob('*', root_dir='src/cmd/') -raw("USERBINS = " + " ".join(userbins)) - -for cmd in userbins: - t(f'out/initrd/bin/amd64/{cmd}', '$(LIB) ' + srcobj(f'src/cmd/{cmd}'), [ +userbins = [] +for src in glob('*', root_dir='src/cmd/'): + cmd = src.removesuffix('.c') + t(f'out/initrd/bin/amd64/{cmd}', '$(LIB) ' + srcobj(f'src/cmd/{src}'), [ '$(CC) $^ -o $@' ]) + userbins.append(cmd) + +raw("USERBINS = " + " ".join(userbins)) # don't build the example implementation from libext2 t('out/obj/cmd/ext2fs/ext2/example.c.o', '', ['touch $@']) diff --git a/src/cmd/drawmouse.c b/src/cmd/drawmouse.c new file mode 100644 index 0000000..f20d9bd --- /dev/null +++ b/src/cmd/drawmouse.c @@ -0,0 +1,86 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MOUSE_SIZE 10 + +struct framebuf fb, lastbehind; +struct rect dirty; + +static uint8_t r_buf[64]; +static ring_t r = {(void*)r_buf, sizeof r_buf, 0, 0}; +static struct {uint32_t x, y;} cursor, lastcur; + + +static void draw_mouse(void) { + static bool drawn = false; + if (drawn) + fb_cpy(&fb, &lastbehind, lastcur.x, lastcur.y, 0, 0, MOUSE_SIZE, MOUSE_SIZE); + drawn = true; + dirty_mark(&dirty, lastcur.x, lastcur.y); + dirty_mark(&dirty, lastcur.x + MOUSE_SIZE, lastcur.y + MOUSE_SIZE); + fb_cpy(&lastbehind, &fb, 0, 0, cursor.x, cursor.y, MOUSE_SIZE, MOUSE_SIZE); + for (int i = 0; i < MOUSE_SIZE; i++) { + for (int j = 0; j < MOUSE_SIZE - i; j++) { + uint32_t *px = fb_pixel(&fb, cursor.x + i, cursor.y + j); + if (px) { + *px ^= 0x808080; + dirty_mark(&dirty, cursor.x + i, cursor.y + j); + } + } + } + lastcur = cursor; +} + + +struct packet { + uint8_t left : 1; + uint8_t right : 1; + uint8_t middle : 1; + uint8_t _useless : 5; + int8_t dx, dy; +} __attribute__((packed)); + +int main(void) { + char buf[64]; + hid_t fd = camellia_open("/dev/ps2/mouse", OPEN_READ); + if (fd < 0) { + err(1, "open"); + return 1; + } + + if (fb_setup(&fb, "/dev/video/") < 0) { + err(1, "fb_setup"); + return 1; + } + fb_anon(&lastbehind, MOUSE_SIZE, MOUSE_SIZE); + + + for (;;) { + int len = _sys_read(fd, buf, sizeof buf, 0); + if (len == 0) break; + ring_put(&r, buf, len); + while (ring_used(&r) >= 3) { + struct packet p; + ring_get(&r, &p, sizeof p); + p.dy *= -1; + // TODO check mouse click + if (-p.dx > (int)cursor.x) p.dx = -cursor.x; + if (-p.dy > (int)cursor.y) p.dy = -cursor.y; + cursor.x += p.dx; + cursor.y += p.dy; + if (cursor.x >= fb.width) cursor.x = fb.width - 1; + if (cursor.y >= fb.height) cursor.y = fb.height - 1; + draw_mouse(); + if (p.left && p.right) return 0; + } + dirty_flush(&dirty, &fb); + } + return 0; +} diff --git a/src/cmd/drawmouse/drawmouse.c b/src/cmd/drawmouse/drawmouse.c deleted file mode 100644 index f20d9bd..0000000 --- a/src/cmd/drawmouse/drawmouse.c +++ /dev/null @@ -1,86 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define MOUSE_SIZE 10 - -struct framebuf fb, lastbehind; -struct rect dirty; - -static uint8_t r_buf[64]; -static ring_t r = {(void*)r_buf, sizeof r_buf, 0, 0}; -static struct {uint32_t x, y;} cursor, lastcur; - - -static void draw_mouse(void) { - static bool drawn = false; - if (drawn) - fb_cpy(&fb, &lastbehind, lastcur.x, lastcur.y, 0, 0, MOUSE_SIZE, MOUSE_SIZE); - drawn = true; - dirty_mark(&dirty, lastcur.x, lastcur.y); - dirty_mark(&dirty, lastcur.x + MOUSE_SIZE, lastcur.y + MOUSE_SIZE); - fb_cpy(&lastbehind, &fb, 0, 0, cursor.x, cursor.y, MOUSE_SIZE, MOUSE_SIZE); - for (int i = 0; i < MOUSE_SIZE; i++) { - for (int j = 0; j < MOUSE_SIZE - i; j++) { - uint32_t *px = fb_pixel(&fb, cursor.x + i, cursor.y + j); - if (px) { - *px ^= 0x808080; - dirty_mark(&dirty, cursor.x + i, cursor.y + j); - } - } - } - lastcur = cursor; -} - - -struct packet { - uint8_t left : 1; - uint8_t right : 1; - uint8_t middle : 1; - uint8_t _useless : 5; - int8_t dx, dy; -} __attribute__((packed)); - -int main(void) { - char buf[64]; - hid_t fd = camellia_open("/dev/ps2/mouse", OPEN_READ); - if (fd < 0) { - err(1, "open"); - return 1; - } - - if (fb_setup(&fb, "/dev/video/") < 0) { - err(1, "fb_setup"); - return 1; - } - fb_anon(&lastbehind, MOUSE_SIZE, MOUSE_SIZE); - - - for (;;) { - int len = _sys_read(fd, buf, sizeof buf, 0); - if (len == 0) break; - ring_put(&r, buf, len); - while (ring_used(&r) >= 3) { - struct packet p; - ring_get(&r, &p, sizeof p); - p.dy *= -1; - // TODO check mouse click - if (-p.dx > (int)cursor.x) p.dx = -cursor.x; - if (-p.dy > (int)cursor.y) p.dy = -cursor.y; - cursor.x += p.dx; - cursor.y += p.dy; - if (cursor.x >= fb.width) cursor.x = fb.width - 1; - if (cursor.y >= fb.height) cursor.y = fb.height - 1; - draw_mouse(); - if (p.left && p.right) return 0; - } - dirty_flush(&dirty, &fb); - } - return 0; -} diff --git a/src/cmd/dvd.c b/src/cmd/dvd.c new file mode 100644 index 0000000..0b5caaf --- /dev/null +++ b/src/cmd/dvd.c @@ -0,0 +1,42 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +struct framebuf fb; +struct rect dirty; + +void draw_rect(uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint32_t col) { + for (uint32_t i = 0; i < w; i++) { + for (uint32_t j = 0; j < h; j++) { + *((uint32_t*)(fb.b + fb.pitch * (y+j) + 4 * (x+i))) = col; + } + } + dirty_mark(&dirty, x, y); + dirty_mark(&dirty, x + w, y + h); +} + +int main(void) { + if (fb_setup(&fb, "/dev/video/") < 0) { + err(1, "fb_setup"); + return 1; + } + int dx = 2, dy = 2, x = 100, y = 100, w = 150, h = 70; + uint32_t col = 0x800000; + + for (;;) { + if (x + dx < 0 || (size_t)(x + dx + w) >= fb.width) dx *= -1; + if (y + dy < 0 || (size_t)(y + dy + h) >= fb.height) dy *= -1; + x += dx; + y += dy; + draw_rect(x, y, w, h, col++); + dirty_flush(&dirty, &fb); + _sys_sleep(1000 / 60); + } + + return 1; +} diff --git a/src/cmd/dvd/dvd.c b/src/cmd/dvd/dvd.c deleted file mode 100644 index 0b5caaf..0000000 --- a/src/cmd/dvd/dvd.c +++ /dev/null @@ -1,42 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include - -struct framebuf fb; -struct rect dirty; - -void draw_rect(uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint32_t col) { - for (uint32_t i = 0; i < w; i++) { - for (uint32_t j = 0; j < h; j++) { - *((uint32_t*)(fb.b + fb.pitch * (y+j) + 4 * (x+i))) = col; - } - } - dirty_mark(&dirty, x, y); - dirty_mark(&dirty, x + w, y + h); -} - -int main(void) { - if (fb_setup(&fb, "/dev/video/") < 0) { - err(1, "fb_setup"); - return 1; - } - int dx = 2, dy = 2, x = 100, y = 100, w = 150, h = 70; - uint32_t col = 0x800000; - - for (;;) { - if (x + dx < 0 || (size_t)(x + dx + w) >= fb.width) dx *= -1; - if (y + dy < 0 || (size_t)(y + dy + h) >= fb.height) dy *= -1; - x += dx; - y += dy; - draw_rect(x, y, w, h, col++); - dirty_flush(&dirty, &fb); - _sys_sleep(1000 / 60); - } - - return 1; -} diff --git a/src/cmd/find.c b/src/cmd/find.c new file mode 100644 index 0000000..d473b82 --- /dev/null +++ b/src/cmd/find.c @@ -0,0 +1,55 @@ +#include +#include +#include +#include +#include +#include +#include + +void recurse(char *path) { + DIR *d = opendir(path); + if (!d) { + warn("couldn't open %s", path); + return; + } + for (;;) { + struct dirent *dent; + errno = 0; + dent = readdir(d); + if (!dent) { + if (errno) { + warn("when reading %s", path); + } + break; + } + printf("%s%s\n", path, dent->d_name); + /* if the string ends with '/' */ + if (strchr(dent->d_name, '\0')[-1] == '/') { + // TODO no overflow check + char *pend = strchr(path, '\0'); + strcpy(pend, dent->d_name); + recurse(path); + *pend = '\0'; + } + } + closedir(d); +} + +void find(const char *path) { + // TODO bound checking + // TODO or just implement asprintf() + char *buf = malloc(PATH_MAX); + memcpy(buf, path, strlen(path)+1); + recurse(buf); + free(buf); +} + +int main(int argc, char **argv) { + if (argc < 2) { + find("/"); + } else { + for (int i = 1; i < argc; i++) + find(argv[i]); + } + return 0; +} diff --git a/src/cmd/find/find.c b/src/cmd/find/find.c deleted file mode 100644 index d473b82..0000000 --- a/src/cmd/find/find.c +++ /dev/null @@ -1,55 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -void recurse(char *path) { - DIR *d = opendir(path); - if (!d) { - warn("couldn't open %s", path); - return; - } - for (;;) { - struct dirent *dent; - errno = 0; - dent = readdir(d); - if (!dent) { - if (errno) { - warn("when reading %s", path); - } - break; - } - printf("%s%s\n", path, dent->d_name); - /* if the string ends with '/' */ - if (strchr(dent->d_name, '\0')[-1] == '/') { - // TODO no overflow check - char *pend = strchr(path, '\0'); - strcpy(pend, dent->d_name); - recurse(path); - *pend = '\0'; - } - } - closedir(d); -} - -void find(const char *path) { - // TODO bound checking - // TODO or just implement asprintf() - char *buf = malloc(PATH_MAX); - memcpy(buf, path, strlen(path)+1); - recurse(buf); - free(buf); -} - -int main(int argc, char **argv) { - if (argc < 2) { - find("/"); - } else { - for (int i = 1; i < argc; i++) - find(argv[i]); - } - return 0; -} diff --git a/src/cmd/httpd.c b/src/cmd/httpd.c new file mode 100644 index 0000000..8826dcb --- /dev/null +++ b/src/cmd/httpd.c @@ -0,0 +1,82 @@ +/* garbage httpd, just to see if it works + * easily DoSable (like the rest of the network stack), vulnerable to path traversal, etc */ +#include +#include +#include +#include +#include +#include +#include + +static void handle(FILE *c) { + char buf[2048]; + fgets(buf, sizeof buf, c); + printf("%s", buf); + + if (memcmp(buf, "GET /", 5) != 0) { + fprintf(c, "HTTP/1.1 400 Bad Request\r\n\r\n"); + return; + } + char *path = buf + 4; + char *end = strchr(path, ' '); + if (end) *end = '\0'; + + hid_t h = _sys_open(path, strlen(path), OPEN_READ); + if (h < 0) { + fprintf(c, "HTTP/1.1 404 Not Found\r\n\r\n"); + return; + } + + if (path[strlen(path) - 1] != '/') { + FILE *f = fdopen(h, "r"); + if (!f) { + fprintf(c, "HTTP/1.1 500 Internal Server Error\r\n\r\n"); + return; + } + + /* regular file */ + fprintf(c, "HTTP/1.1 200 OK\r\n\r\n"); + for (;;) { + int len = fread(buf, 1, sizeof buf, f); + if (len <= 0) break; + fwrite(buf, 1, len, c); + } + + fclose(f); + } else { + /* directory listing */ + DIR *dir = opendir_f(fdopen(h, "r")); + if (!dir) { + fprintf(c, "HTTP/1.1 500 Internal Server Error\r\n\r\n"); + return; + } + + fprintf(c, + "HTTP/1.1 200 OK\r\n" + "Content-Type: text/html; charset=UTF-8\r\n" + "\r\n" + "

directory listing for %s


" + "
  • ..
  • ", + path + ); + + struct dirent *d; + while ((d = readdir(dir))) { + fprintf(c, "
  • %s
  • ", d->d_name, d->d_name); + } + closedir(dir); + } +} + +int main(int argc, char **argv) { + const char *path = (argc > 1) ? argv[1] : "/net/listen/0.0.0.0/tcp/80"; + hid_t conn; + for (;;) { + conn = _sys_open(path, strlen(path), OPEN_RW); + if (conn < 0) + errx(1, "open('%s') failed, errno %d", path, -conn); + FILE *f = fdopen(conn, "a+"); + handle(f); + fclose(f); + } +} diff --git a/src/cmd/httpd/httpd.c b/src/cmd/httpd/httpd.c deleted file mode 100644 index 8826dcb..0000000 --- a/src/cmd/httpd/httpd.c +++ /dev/null @@ -1,82 +0,0 @@ -/* garbage httpd, just to see if it works - * easily DoSable (like the rest of the network stack), vulnerable to path traversal, etc */ -#include -#include -#include -#include -#include -#include -#include - -static void handle(FILE *c) { - char buf[2048]; - fgets(buf, sizeof buf, c); - printf("%s", buf); - - if (memcmp(buf, "GET /", 5) != 0) { - fprintf(c, "HTTP/1.1 400 Bad Request\r\n\r\n"); - return; - } - char *path = buf + 4; - char *end = strchr(path, ' '); - if (end) *end = '\0'; - - hid_t h = _sys_open(path, strlen(path), OPEN_READ); - if (h < 0) { - fprintf(c, "HTTP/1.1 404 Not Found\r\n\r\n"); - return; - } - - if (path[strlen(path) - 1] != '/') { - FILE *f = fdopen(h, "r"); - if (!f) { - fprintf(c, "HTTP/1.1 500 Internal Server Error\r\n\r\n"); - return; - } - - /* regular file */ - fprintf(c, "HTTP/1.1 200 OK\r\n\r\n"); - for (;;) { - int len = fread(buf, 1, sizeof buf, f); - if (len <= 0) break; - fwrite(buf, 1, len, c); - } - - fclose(f); - } else { - /* directory listing */ - DIR *dir = opendir_f(fdopen(h, "r")); - if (!dir) { - fprintf(c, "HTTP/1.1 500 Internal Server Error\r\n\r\n"); - return; - } - - fprintf(c, - "HTTP/1.1 200 OK\r\n" - "Content-Type: text/html; charset=UTF-8\r\n" - "\r\n" - "

    directory listing for %s


    " - "
    • ..
    • ", - path - ); - - struct dirent *d; - while ((d = readdir(dir))) { - fprintf(c, "
    • %s
    • ", d->d_name, d->d_name); - } - closedir(dir); - } -} - -int main(int argc, char **argv) { - const char *path = (argc > 1) ? argv[1] : "/net/listen/0.0.0.0/tcp/80"; - hid_t conn; - for (;;) { - conn = _sys_open(path, strlen(path), OPEN_RW); - if (conn < 0) - errx(1, "open('%s') failed, errno %d", path, -conn); - FILE *f = fdopen(conn, "a+"); - handle(f); - fclose(f); - } -} diff --git a/src/cmd/iochk.c b/src/cmd/iochk.c new file mode 100644 index 0000000..4483610 --- /dev/null +++ b/src/cmd/iochk.c @@ -0,0 +1,96 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static bool verbose = false; + +#define verbosef(...) do { if (verbose) printf(__VA_ARGS__); } while (0) + +void check(hid_t h) { + const size_t buflen = 4096; + const size_t offsets[] = { + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 16, 32, 64, 128, 256, + 512, 1024, 2048, + }; + char *buflast = malloc(buflen); + char *bufcur = malloc(buflen); + if (!buflast || !bufcur) { + err(1, "malloc"); + goto end; + } + + long offlast = 0; + long retlast = _sys_read(h, buflast, buflen, offlast); + if (retlast < 0) { + fprintf(stderr, "error %ld when reading at offset %ld", retlast, offlast); + goto end; + } + + for (size_t i = 0; i < sizeof(offsets) / sizeof(offsets[0]); i++) { + char *tmp; + long offcur = offsets[i]; + long diff = offcur - offlast; + assert(diff >= 0); + if (retlast < diff) break; + + long retcur = _sys_read(h, bufcur, buflen, offcur); + if (retcur < 0) { + fprintf(stderr, "error %ld when reading at offset %ld", retlast, offcur); + break; + } + if (retcur < retlast + offlast - offcur) { + verbosef("warn: unexpected ret %ld < %ld + %ld - %ld\n", retcur, retlast, offlast, offcur); + } + if (memcmp(buflast + diff, bufcur, retlast - diff)) { + fprintf(stderr, "inconsistent read from offsets %ld and %ld", offlast, offcur); + } + + offlast = offcur; + retlast = retcur; + tmp = bufcur; + bufcur = buflast; + buflast = tmp; + } + + // TODO check negative offsets + +end: + free(buflast); + free(bufcur); +} + +int main(int argc, char **argv) { + int c; + while ((c = getopt(argc, argv, "v")) != -1) { + switch (c) { + case 'v': + verbose = true; + break; + default: + return 1; + } + } + if (optind >= argc) { + fprintf(stderr, "usage: iochk [-v] file [files...]\n"); + return 1; + } + for (; optind < argc; optind++) { + const char *path = argv[optind]; + verbosef("checking %s...\n", path); + hid_t h = camellia_open(path, OPEN_READ); + if (h < 0) { + err(1, "open %s", path); + continue; + } + check(h); + close(h); + } + return 0; +} diff --git a/src/cmd/iochk/iochk.c b/src/cmd/iochk/iochk.c deleted file mode 100644 index 4483610..0000000 --- a/src/cmd/iochk/iochk.c +++ /dev/null @@ -1,96 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static bool verbose = false; - -#define verbosef(...) do { if (verbose) printf(__VA_ARGS__); } while (0) - -void check(hid_t h) { - const size_t buflen = 4096; - const size_t offsets[] = { - 0, 1, 2, 3, 4, 5, 6, 7, - 8, 16, 32, 64, 128, 256, - 512, 1024, 2048, - }; - char *buflast = malloc(buflen); - char *bufcur = malloc(buflen); - if (!buflast || !bufcur) { - err(1, "malloc"); - goto end; - } - - long offlast = 0; - long retlast = _sys_read(h, buflast, buflen, offlast); - if (retlast < 0) { - fprintf(stderr, "error %ld when reading at offset %ld", retlast, offlast); - goto end; - } - - for (size_t i = 0; i < sizeof(offsets) / sizeof(offsets[0]); i++) { - char *tmp; - long offcur = offsets[i]; - long diff = offcur - offlast; - assert(diff >= 0); - if (retlast < diff) break; - - long retcur = _sys_read(h, bufcur, buflen, offcur); - if (retcur < 0) { - fprintf(stderr, "error %ld when reading at offset %ld", retlast, offcur); - break; - } - if (retcur < retlast + offlast - offcur) { - verbosef("warn: unexpected ret %ld < %ld + %ld - %ld\n", retcur, retlast, offlast, offcur); - } - if (memcmp(buflast + diff, bufcur, retlast - diff)) { - fprintf(stderr, "inconsistent read from offsets %ld and %ld", offlast, offcur); - } - - offlast = offcur; - retlast = retcur; - tmp = bufcur; - bufcur = buflast; - buflast = tmp; - } - - // TODO check negative offsets - -end: - free(buflast); - free(bufcur); -} - -int main(int argc, char **argv) { - int c; - while ((c = getopt(argc, argv, "v")) != -1) { - switch (c) { - case 'v': - verbose = true; - break; - default: - return 1; - } - } - if (optind >= argc) { - fprintf(stderr, "usage: iochk [-v] file [files...]\n"); - return 1; - } - for (; optind < argc; optind++) { - const char *path = argv[optind]; - verbosef("checking %s...\n", path); - hid_t h = camellia_open(path, OPEN_READ); - if (h < 0) { - err(1, "open %s", path); - continue; - } - check(h); - close(h); - } - return 0; -} diff --git a/src/cmd/iostress.c b/src/cmd/iostress.c new file mode 100644 index 0000000..ac555de --- /dev/null +++ b/src/cmd/iostress.c @@ -0,0 +1,43 @@ +#include +#include +#include +#include +#include + +int main(int argc, char **argv) { + long num_runs = 4; + long num_calls = 512; + long num_bytes = 1; + uint64_t *results; + char *inbuf; + + if (argc > 1) num_runs = strtol(argv[1], NULL, 0); + if (argc > 2) num_calls = strtol(argv[2], NULL, 0); + if (argc > 3) num_bytes = strtol(argv[3], NULL, 0); + if (argc > 4 || num_runs == 0 || num_calls == 0) { + fprintf(stderr, "usage: %s [num_runs] [num_calls] [num_bytes]\n", argv[0]); + return 1; + } + + results = malloc(sizeof(*results) * num_runs); + inbuf = malloc(num_bytes); + memset(inbuf, '.', num_bytes); + + for (long i = 0; i < num_runs; i++) { + uint64_t time = __rdtsc(); + for (long j = 0; j < num_calls; j++) + _sys_write(1, inbuf, num_bytes, -1, 0); + results[i] = __rdtsc() - time; + _sys_write(1, "\n", 1, -1, 0); + } + + uint64_t total = 0; + for (long i = 0; i < num_runs; i++) { + uint64_t scaled = results[i] / 3000; + total += scaled; + fprintf(stderr, "run %ld: %lu\n", i, scaled); + } + fprintf(stderr, "%lu calls, %lu bytes. avg %lu\n", num_calls, num_bytes, total / num_runs); + + return 0; +} diff --git a/src/cmd/iostress/iostress.c b/src/cmd/iostress/iostress.c deleted file mode 100644 index ac555de..0000000 --- a/src/cmd/iostress/iostress.c +++ /dev/null @@ -1,43 +0,0 @@ -#include -#include -#include -#include -#include - -int main(int argc, char **argv) { - long num_runs = 4; - long num_calls = 512; - long num_bytes = 1; - uint64_t *results; - char *inbuf; - - if (argc > 1) num_runs = strtol(argv[1], NULL, 0); - if (argc > 2) num_calls = strtol(argv[2], NULL, 0); - if (argc > 3) num_bytes = strtol(argv[3], NULL, 0); - if (argc > 4 || num_runs == 0 || num_calls == 0) { - fprintf(stderr, "usage: %s [num_runs] [num_calls] [num_bytes]\n", argv[0]); - return 1; - } - - results = malloc(sizeof(*results) * num_runs); - inbuf = malloc(num_bytes); - memset(inbuf, '.', num_bytes); - - for (long i = 0; i < num_runs; i++) { - uint64_t time = __rdtsc(); - for (long j = 0; j < num_calls; j++) - _sys_write(1, inbuf, num_bytes, -1, 0); - results[i] = __rdtsc() - time; - _sys_write(1, "\n", 1, -1, 0); - } - - uint64_t total = 0; - for (long i = 0; i < num_runs; i++) { - uint64_t scaled = results[i] / 3000; - total += scaled; - fprintf(stderr, "run %ld: %lu\n", i, scaled); - } - fprintf(stderr, "%lu calls, %lu bytes. avg %lu\n", num_calls, num_bytes, total / num_runs); - - return 0; -} diff --git a/src/cmd/logfs.c b/src/cmd/logfs.c new file mode 100644 index 0000000..a50d530 --- /dev/null +++ b/src/cmd/logfs.c @@ -0,0 +1,34 @@ +#include +#include +#include +#include +#include +#include + +_Noreturn void fs(void) { + const size_t buflen = 1024; + char *buf = malloc(buflen); + if (!buf) err(1, "malloc"); + for (;;) { + struct ufs_request req; + hid_t reqh = ufs_wait(buf, buflen, &req); + if (reqh < 0) errx(1, "ufs_wait error"); + + switch (req.op) { + case VFSOP_OPEN: + printf("[logfs] open(\"%s\", 0x%x)\n", buf, req.flags); + forward_open(reqh, buf, req.len, req.flags); + break; + default: + /* Unsupported vfs operation. + * Currently if you never create your own file descriptors you won't receive + * anything but VFSOP_OPEN, but it's idiomatic to handle this anyways. */ + _sys_fs_respond(reqh, NULL, -1, 0); + break; + } + } +} + +int main(void) { + fs(); +} diff --git a/src/cmd/logfs/logfs.c b/src/cmd/logfs/logfs.c deleted file mode 100644 index a50d530..0000000 --- a/src/cmd/logfs/logfs.c +++ /dev/null @@ -1,34 +0,0 @@ -#include -#include -#include -#include -#include -#include - -_Noreturn void fs(void) { - const size_t buflen = 1024; - char *buf = malloc(buflen); - if (!buf) err(1, "malloc"); - for (;;) { - struct ufs_request req; - hid_t reqh = ufs_wait(buf, buflen, &req); - if (reqh < 0) errx(1, "ufs_wait error"); - - switch (req.op) { - case VFSOP_OPEN: - printf("[logfs] open(\"%s\", 0x%x)\n", buf, req.flags); - forward_open(reqh, buf, req.len, req.flags); - break; - default: - /* Unsupported vfs operation. - * Currently if you never create your own file descriptors you won't receive - * anything but VFSOP_OPEN, but it's idiomatic to handle this anyways. */ - _sys_fs_respond(reqh, NULL, -1, 0); - break; - } - } -} - -int main(void) { - fs(); -} diff --git a/src/cmd/netdog.c b/src/cmd/netdog.c new file mode 100644 index 0000000..221dc9c --- /dev/null +++ b/src/cmd/netdog.c @@ -0,0 +1,48 @@ +#include +#include +#include +#include +#include +#include +#include + +hid_t conn; + +void send_stdin(void *arg) { (void)arg; + static char buf[4096]; + for (;;) { + // TODO define STDIN_FILENO + long ret = _sys_read(0, buf, sizeof buf, -1); + if (ret <= 0) return; /* instead of sending an empty packet, quit. */ + ret = _sys_write(conn, buf, ret, -1, 0); + if (ret < 0) return; + } +} + +void recv_stdout(void *arg) { (void)arg; + static char buf[4096]; + for (;;) { + long ret = _sys_read(conn, buf, sizeof buf, -1); + if (ret < 0) return; + ret = _sys_write(1, buf, ret, -1, 0); + if (ret < 0) return; + } +} + +int main(int argc, char **argv) { + if (argc < 2) { + fprintf(stderr, "usage: netdog /net/connect/source/target/proto/port\n"); + return 1; + } + + conn = camellia_open(argv[1], OPEN_RW); + if (conn < 0) { + err(1, "open %s", argv[1]); + return -conn; + } + + thread_create(0, send_stdin, NULL); + thread_create(0, recv_stdout, NULL); + _sys_await(); + return 0; +} diff --git a/src/cmd/netdog/nd.c b/src/cmd/netdog/nd.c deleted file mode 100644 index 221dc9c..0000000 --- a/src/cmd/netdog/nd.c +++ /dev/null @@ -1,48 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -hid_t conn; - -void send_stdin(void *arg) { (void)arg; - static char buf[4096]; - for (;;) { - // TODO define STDIN_FILENO - long ret = _sys_read(0, buf, sizeof buf, -1); - if (ret <= 0) return; /* instead of sending an empty packet, quit. */ - ret = _sys_write(conn, buf, ret, -1, 0); - if (ret < 0) return; - } -} - -void recv_stdout(void *arg) { (void)arg; - static char buf[4096]; - for (;;) { - long ret = _sys_read(conn, buf, sizeof buf, -1); - if (ret < 0) return; - ret = _sys_write(1, buf, ret, -1, 0); - if (ret < 0) return; - } -} - -int main(int argc, char **argv) { - if (argc < 2) { - fprintf(stderr, "usage: netdog /net/connect/source/target/proto/port\n"); - return 1; - } - - conn = camellia_open(argv[1], OPEN_RW); - if (conn < 0) { - err(1, "open %s", argv[1]); - return -conn; - } - - thread_create(0, send_stdin, NULL); - thread_create(0, recv_stdout, NULL); - _sys_await(); - return 0; -} diff --git a/src/cmd/ps.c b/src/cmd/ps.c new file mode 100644 index 0000000..c855251 --- /dev/null +++ b/src/cmd/ps.c @@ -0,0 +1,54 @@ +#include <_proc.h> +#include +#include +#include +#include +#include +#include + +void +usage(void) +{ + fprintf(stderr, "usage: ps [path]\n"); + exit(1); +} + +int +main(int argc, const char *argv[]) +{ + const char *path = argc >= 2 ? argv[1] : "/proc/"; + if (argc > 2) usage(); + + char *procbuf = malloc(4096); + DIR *dir = opendir(path); + if (!dir) { + err(1, "couldn't open %s", path); + } + + struct dirent *de; + while ((de = readdir(dir))) { + const char *name = de->d_name; + if (isdigit(name[0])) { + FILE *g; + sprintf(procbuf, "%s%smem", path, name); + g = fopen(procbuf, "r"); + if (!g) { + warn("couldn't open \"%s\"", procbuf); + strcpy(procbuf, "(can't peek)"); + } else { + fseek(g, (long)&_psdata_loc->desc, SEEK_SET); + if (fread(procbuf, 1, 128, g) <= 0) { + strcpy(procbuf, "(no psdata)"); + } + procbuf[128] = '\0'; + fclose(g); + } + *strchr(name, '/') = '\0'; + printf("%s\t%s\n", name, procbuf); + } + } + + free(procbuf); + closedir(dir); + return 0; +} diff --git a/src/cmd/ps/ps.c b/src/cmd/ps/ps.c deleted file mode 100644 index c855251..0000000 --- a/src/cmd/ps/ps.c +++ /dev/null @@ -1,54 +0,0 @@ -#include <_proc.h> -#include -#include -#include -#include -#include -#include - -void -usage(void) -{ - fprintf(stderr, "usage: ps [path]\n"); - exit(1); -} - -int -main(int argc, const char *argv[]) -{ - const char *path = argc >= 2 ? argv[1] : "/proc/"; - if (argc > 2) usage(); - - char *procbuf = malloc(4096); - DIR *dir = opendir(path); - if (!dir) { - err(1, "couldn't open %s", path); - } - - struct dirent *de; - while ((de = readdir(dir))) { - const char *name = de->d_name; - if (isdigit(name[0])) { - FILE *g; - sprintf(procbuf, "%s%smem", path, name); - g = fopen(procbuf, "r"); - if (!g) { - warn("couldn't open \"%s\"", procbuf); - strcpy(procbuf, "(can't peek)"); - } else { - fseek(g, (long)&_psdata_loc->desc, SEEK_SET); - if (fread(procbuf, 1, 128, g) <= 0) { - strcpy(procbuf, "(no psdata)"); - } - procbuf[128] = '\0'; - fclose(g); - } - *strchr(name, '/') = '\0'; - printf("%s\t%s\n", name, procbuf); - } - } - - free(procbuf); - closedir(dir); - return 0; -} diff --git a/src/cmd/socksfs.c b/src/cmd/socksfs.c new file mode 100644 index 0000000..9469d0c --- /dev/null +++ b/src/cmd/socksfs.c @@ -0,0 +1,164 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct { + hid_t sock; +} Handle; + +static char *socks_addr; + +static void* +fs_open(char *path, int flags) { + char *tokp; + + if (*path++ != '/') { + return errno = ENOENT, NULL; + } + if (!OPEN_WRITEABLE(flags)) { + return errno = EACCES, NULL; + } + + const char *verb = strtok_r(path, "/", &tokp); + if (!verb) { + return errno = ENOENT, NULL; + } + if (strcmp(verb, "connect") != 0) { + return errno = ENOSYS, NULL; // unimpl. + } + + // TODO ip parsing in stdlib + // uint32_t srcip; + //if (ip_parse(strtok_r(NULL, "/", &tokp), &srcip) < 0 || srcip != 0) { + // return errno = ENOENT, NULL; + //} + strtok_r(NULL, "/", &tokp); + + char *dest = strtok_r(NULL, "/", &tokp); + if (!dest) return errno = ENOENT, NULL; + size_t destlen = strlen(dest); + if (destlen >= 256) return errno = ENAMETOOLONG, NULL; + // let's assume it's a domain + + char *proto = strtok_r(NULL, "/", &tokp); + if (!proto) return errno = ENOENT, NULL; + if (strcmp(proto, "tcp") != 0) { + return errno = ENOSYS, NULL; // unimpl. + } + + char *port_s = strtok_r(NULL, "/", &tokp); + if (!port_s) return errno = ENOENT, NULL; + uint16_t port = strtol(port_s, NULL, 0); + + Handle *h; + h = calloc(1, sizeof(*h)); + if (!h) return errno = ENOMEM, NULL; + + h->sock = camellia_open(socks_addr, OPEN_READ | OPEN_WRITE); + if (h->sock < 0) { + goto err; + } + + /* 0x05 version 5 + * 0x01 one authentication method: + * 0x00 no auth */ + char buf[512]; + write(h->sock, "\x05\x01\x00", 3); + + errno = EGENERIC; + ssize_t ret = read(h->sock, buf, 2); + if (ret != 2) goto err; // yeah yeah i know + if (memcmp(buf, "\x05\x00", 2) != 0) goto err; + + int p = 0; + buf[p++] = 5; /* v5 */ + buf[p++] = 1; /* tcp connection */ + buf[p++] = 0; /* reserved */ + buf[p++] = 3; /* addr type, 3 = domain */ + buf[p++] = destlen; /* length, max 255 */ + memcpy(buf + p, dest, destlen); + p += destlen; + buf[p++] = port >> 8; + buf[p++] = port; + + write(h->sock, buf, p); + + ret = read(h->sock, buf, 10); + // just comparing to what tor replies, i have bigger issues than making this general + if (ret != 10 || memcmp(buf, "\x05\x00\x00\x01\x00\x00\x00\x00\x00\x00", 10) != 0) { + goto err; + } + + return h; + +err: + close(h->sock); + free(h); + return NULL; +} + +int main(int argc, char *argv[]) { + const size_t buflen = 4096; + char *buf = malloc(buflen); + + if (argc != 2) { + fprintf(stderr, "usage: socksfs /net/connect/.../\n"); + return 1; + } + socks_addr = argv[1]; + + struct ufs_request req; + hid_t reqh; + // TODO an fs_wait flag to only wait for OPENs, and then to only wait for a given handle + // then i can use proper threads + while ((reqh = ufs_wait(buf, buflen, &req))) { + Handle *h = req.id; + switch (req.op) { + case VFSOP_OPEN: { + void *ret = fs_open(buf, req.flags); + if (ret) { + _sys_fs_respond(reqh, ret, 0, 0); + } else { + _sys_fs_respond(reqh, NULL, -errno, 0); + } + break; + } + case VFSOP_READ: { + if (_sys_fork(FORK_NOREAP, NULL) == 0) { + int len = MIN(buflen, req.capacity); + len = _sys_read(h->sock, buf, len, -1); + _sys_fs_respond(reqh, buf, len, 0); + exit(0); + } else { + close(reqh); + } + break; + } + case VFSOP_WRITE: { + if (_sys_fork(FORK_NOREAP, NULL) == 0) { + int len = _sys_write(h->sock, buf, req.len, -1, 0); + _sys_fs_respond(reqh, NULL, len, 0); + exit(0); + } else { + close(reqh); + } + break; + } + case VFSOP_CLOSE: + close(h->sock); + free(h); + _sys_fs_respond(reqh, NULL, -1, 0); + break; + default: + _sys_fs_respond(reqh, NULL, -1, 0); + break; + } + } +} diff --git a/src/cmd/socksfs/socksfs.c b/src/cmd/socksfs/socksfs.c deleted file mode 100644 index 9469d0c..0000000 --- a/src/cmd/socksfs/socksfs.c +++ /dev/null @@ -1,164 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -typedef struct { - hid_t sock; -} Handle; - -static char *socks_addr; - -static void* -fs_open(char *path, int flags) { - char *tokp; - - if (*path++ != '/') { - return errno = ENOENT, NULL; - } - if (!OPEN_WRITEABLE(flags)) { - return errno = EACCES, NULL; - } - - const char *verb = strtok_r(path, "/", &tokp); - if (!verb) { - return errno = ENOENT, NULL; - } - if (strcmp(verb, "connect") != 0) { - return errno = ENOSYS, NULL; // unimpl. - } - - // TODO ip parsing in stdlib - // uint32_t srcip; - //if (ip_parse(strtok_r(NULL, "/", &tokp), &srcip) < 0 || srcip != 0) { - // return errno = ENOENT, NULL; - //} - strtok_r(NULL, "/", &tokp); - - char *dest = strtok_r(NULL, "/", &tokp); - if (!dest) return errno = ENOENT, NULL; - size_t destlen = strlen(dest); - if (destlen >= 256) return errno = ENAMETOOLONG, NULL; - // let's assume it's a domain - - char *proto = strtok_r(NULL, "/", &tokp); - if (!proto) return errno = ENOENT, NULL; - if (strcmp(proto, "tcp") != 0) { - return errno = ENOSYS, NULL; // unimpl. - } - - char *port_s = strtok_r(NULL, "/", &tokp); - if (!port_s) return errno = ENOENT, NULL; - uint16_t port = strtol(port_s, NULL, 0); - - Handle *h; - h = calloc(1, sizeof(*h)); - if (!h) return errno = ENOMEM, NULL; - - h->sock = camellia_open(socks_addr, OPEN_READ | OPEN_WRITE); - if (h->sock < 0) { - goto err; - } - - /* 0x05 version 5 - * 0x01 one authentication method: - * 0x00 no auth */ - char buf[512]; - write(h->sock, "\x05\x01\x00", 3); - - errno = EGENERIC; - ssize_t ret = read(h->sock, buf, 2); - if (ret != 2) goto err; // yeah yeah i know - if (memcmp(buf, "\x05\x00", 2) != 0) goto err; - - int p = 0; - buf[p++] = 5; /* v5 */ - buf[p++] = 1; /* tcp connection */ - buf[p++] = 0; /* reserved */ - buf[p++] = 3; /* addr type, 3 = domain */ - buf[p++] = destlen; /* length, max 255 */ - memcpy(buf + p, dest, destlen); - p += destlen; - buf[p++] = port >> 8; - buf[p++] = port; - - write(h->sock, buf, p); - - ret = read(h->sock, buf, 10); - // just comparing to what tor replies, i have bigger issues than making this general - if (ret != 10 || memcmp(buf, "\x05\x00\x00\x01\x00\x00\x00\x00\x00\x00", 10) != 0) { - goto err; - } - - return h; - -err: - close(h->sock); - free(h); - return NULL; -} - -int main(int argc, char *argv[]) { - const size_t buflen = 4096; - char *buf = malloc(buflen); - - if (argc != 2) { - fprintf(stderr, "usage: socksfs /net/connect/.../\n"); - return 1; - } - socks_addr = argv[1]; - - struct ufs_request req; - hid_t reqh; - // TODO an fs_wait flag to only wait for OPENs, and then to only wait for a given handle - // then i can use proper threads - while ((reqh = ufs_wait(buf, buflen, &req))) { - Handle *h = req.id; - switch (req.op) { - case VFSOP_OPEN: { - void *ret = fs_open(buf, req.flags); - if (ret) { - _sys_fs_respond(reqh, ret, 0, 0); - } else { - _sys_fs_respond(reqh, NULL, -errno, 0); - } - break; - } - case VFSOP_READ: { - if (_sys_fork(FORK_NOREAP, NULL) == 0) { - int len = MIN(buflen, req.capacity); - len = _sys_read(h->sock, buf, len, -1); - _sys_fs_respond(reqh, buf, len, 0); - exit(0); - } else { - close(reqh); - } - break; - } - case VFSOP_WRITE: { - if (_sys_fork(FORK_NOREAP, NULL) == 0) { - int len = _sys_write(h->sock, buf, req.len, -1, 0); - _sys_fs_respond(reqh, NULL, len, 0); - exit(0); - } else { - close(reqh); - } - break; - } - case VFSOP_CLOSE: - close(h->sock); - free(h); - _sys_fs_respond(reqh, NULL, -1, 0); - break; - default: - _sys_fs_respond(reqh, NULL, -1, 0); - break; - } - } -} diff --git a/src/cmd/testelf/main.c b/src/cmd/testelf/main.c deleted file mode 100644 index 0cbe56c..0000000 --- a/src/cmd/testelf/main.c +++ /dev/null @@ -1,26 +0,0 @@ -#include -#include -#include -#include - -const char *str = "Hello!", *str2 = "World."; - -int main(int argc, char **argv) { - printf("elftest's &main == %p\n", &main); - printf("%s %s\n", str, str2); - printf("argc == %u\n", argc); - for (int i = 0; i < argc; i++) - printf("argv[%u] == %p == \"%s\"\n", i, argv[i], argv[i]); - if (argv[1] && strcmp(argv[1], "stackexec") == 0) { - /* exec something with arguments on the stack */ - const char s_d[] = "I am a pretty long string on the stack. Oh my. " \ - "I hope I won't get corrupted.\0"; - char s[sizeof(s_d)]; - memcpy(s, s_d, sizeof(s_d)); - const char *argv2[] = {"/bin/testelf", s, s, "hello", s, s, s, "lol", NULL}; - printf("argv2 == %p, s == %p\n== exec ==\n", argv2, s); - execv((void*)argv2[0], (void*)argv2); - err(1, "execv"); - } - return 0; -} diff --git a/src/cmd/tmpfs.c b/src/cmd/tmpfs.c new file mode 100644 index 0000000..6d58790 --- /dev/null +++ b/src/cmd/tmpfs.c @@ -0,0 +1,198 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct node { + char *name; + size_t namelen; + bool directory; + char *buf; + size_t size, capacity; + + size_t open; /* amount of open handles */ + + struct node *sibling, *child; + /* Pointer to the sibling/child field referencing the node. NULL for removed + * files. */ + struct node **ref; + + /* allocated by tmpfs_open + * freed by node_close when (open == 0 && ref == NULL && self != node_root). */ +}; + +static struct node node_root = { + .directory = true, +}; + +/** Responds to open(), finding an existing node, or creating one when applicable. */ +static struct node *tmpfs_open(const char *path, struct ufs_request *req); +/** Finds a direct child with the given name. */ +static struct node *node_getchild(struct node *parent, const char *name, size_t len); +/** Corresponds to close(); drops a reference. */ +static void node_close(struct node *node); +/** Removes a file. It's kept in memory until all the open handles are closed. */ +static long node_remove(struct node *node); + + +static struct node *node_getchild(struct node *parent, const char *name, size_t len) { + for (struct node *iter = parent->child; iter; iter = iter->sibling) { + if (iter->namelen == len && !memcmp(name, iter->name, len)) { + return iter; + } + } + return NULL; +} + +static struct node *tmpfs_open(const char *path, struct ufs_request *req) { + /* *path is not null terminated! */ + struct node *node = &node_root; + if (req->len == 0) return NULL; + if (req->len == 1) return node; /* "/" */ + path++; + req->len--; + + bool more = true; + size_t segpos = 0, seglen; /* segments end with a slash, inclusive */ + while (more) { + struct node *parent = node; + char *slash = memchr(path + segpos, '/', req->len - segpos); + seglen = (slash ? (size_t)(slash - path + 1) : req->len) - segpos; + more = segpos + seglen < req->len; + + node = node_getchild(parent, path + segpos, seglen); + if (!node) { + if (!more && (req->flags & OPEN_CREATE)) { + node = calloc(1, sizeof *node); + + node->name = malloc(seglen + 1); + if (node->name == NULL) { + free(node); + return NULL; + } + memcpy(node->name, path + segpos, seglen); + node->name[seglen] = '\0'; + + node->directory = slash; + node->namelen = seglen; + if (parent->child) { + parent->child->ref = &node->sibling; + *parent->child->ref = parent->child; + } + node->ref = &parent->child; + *node->ref = node; + } else { + return NULL; + } + } + segpos += seglen; + } + node->open++; + return node; +} + +static void node_close(struct node *node) { + node->open--; + if (!node->ref && node != &node_root && node->open == 0) { + free(node->buf); + free(node); + } +} + +static long node_remove(struct node *node) { + if (node == &node_root) return -1; + if (!node->ref) return -1; + if (node->child) return -ENOTEMPTY; + *node->ref = node->sibling; + node->ref = NULL; + node_close(node); + return 0; +} + +int main(void) { + const size_t buflen = 4096; + char *buf = malloc(buflen); + if (!buf) return -1; + + for (;;) { + struct ufs_request req; + hid_t reqh = ufs_wait(buf, buflen, &req); + struct node *ptr = req.id; + if (reqh < 0) break; + + switch (req.op) { + case VFSOP_OPEN: + ptr = tmpfs_open(buf, &req); + _sys_fs_respond(reqh, ptr, ptr ? 0 : -ENOENT, 0); + break; + + case VFSOP_READ: + if (ptr->directory) { + struct dirbuild db; + dir_start(&db, req.offset, buf, buflen); + for (struct node *iter = ptr->child; iter; iter = iter->sibling) { + dir_appendl(&db, iter->name, iter->namelen); + } + _sys_fs_respond(reqh, buf, dir_finish(&db), 0); + } else { + fs_normslice(&req.offset, &req.len, ptr->size, false); + _sys_fs_respond(reqh, ptr->buf + req.offset, req.len, 0); + } + break; + + case VFSOP_WRITE: + if (ptr->directory) { + _sys_fs_respond(reqh, NULL, -ENOSYS, 0); + break; + } + + fs_normslice(&req.offset, &req.len, ptr->size, true); + if (ptr->capacity <= req.offset + req.len) { + ptr->capacity = (req.offset + req.len + 511) & ~511; + ptr->buf = realloc(ptr->buf, ptr->capacity); + } + + memcpy(ptr->buf + req.offset, buf, req.len); + if ((req.flags & WRITE_TRUNCATE) || ptr->size < req.offset + req.len) { + ptr->size = req.offset + req.len; + } + _sys_fs_respond(reqh, NULL, req.len, 0); + break; + + case VFSOP_GETSIZE: + if (ptr->directory) { + // TODO could be cached in ptr->size + struct dirbuild db; + dir_start(&db, req.offset, NULL, buflen); + for (struct node *iter = ptr->child; iter; iter = iter->sibling) { + dir_append(&db, iter->name); + } + _sys_fs_respond(reqh, NULL, dir_finish(&db), 0); + } else { + _sys_fs_respond(reqh, NULL, ptr->size, 0); + } + break; + + case VFSOP_REMOVE: + _sys_fs_respond(reqh, NULL, node_remove(ptr), 0); + break; + + case VFSOP_CLOSE: + node_close(ptr); + _sys_fs_respond(reqh, NULL, -1, 0); + break; + + default: + _sys_fs_respond(reqh, NULL, -1, 0); + break; + } + } + return 1; +} diff --git a/src/cmd/tmpfs/tmpfs.c b/src/cmd/tmpfs/tmpfs.c deleted file mode 100644 index 6d58790..0000000 --- a/src/cmd/tmpfs/tmpfs.c +++ /dev/null @@ -1,198 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -struct node { - char *name; - size_t namelen; - bool directory; - char *buf; - size_t size, capacity; - - size_t open; /* amount of open handles */ - - struct node *sibling, *child; - /* Pointer to the sibling/child field referencing the node. NULL for removed - * files. */ - struct node **ref; - - /* allocated by tmpfs_open - * freed by node_close when (open == 0 && ref == NULL && self != node_root). */ -}; - -static struct node node_root = { - .directory = true, -}; - -/** Responds to open(), finding an existing node, or creating one when applicable. */ -static struct node *tmpfs_open(const char *path, struct ufs_request *req); -/** Finds a direct child with the given name. */ -static struct node *node_getchild(struct node *parent, const char *name, size_t len); -/** Corresponds to close(); drops a reference. */ -static void node_close(struct node *node); -/** Removes a file. It's kept in memory until all the open handles are closed. */ -static long node_remove(struct node *node); - - -static struct node *node_getchild(struct node *parent, const char *name, size_t len) { - for (struct node *iter = parent->child; iter; iter = iter->sibling) { - if (iter->namelen == len && !memcmp(name, iter->name, len)) { - return iter; - } - } - return NULL; -} - -static struct node *tmpfs_open(const char *path, struct ufs_request *req) { - /* *path is not null terminated! */ - struct node *node = &node_root; - if (req->len == 0) return NULL; - if (req->len == 1) return node; /* "/" */ - path++; - req->len--; - - bool more = true; - size_t segpos = 0, seglen; /* segments end with a slash, inclusive */ - while (more) { - struct node *parent = node; - char *slash = memchr(path + segpos, '/', req->len - segpos); - seglen = (slash ? (size_t)(slash - path + 1) : req->len) - segpos; - more = segpos + seglen < req->len; - - node = node_getchild(parent, path + segpos, seglen); - if (!node) { - if (!more && (req->flags & OPEN_CREATE)) { - node = calloc(1, sizeof *node); - - node->name = malloc(seglen + 1); - if (node->name == NULL) { - free(node); - return NULL; - } - memcpy(node->name, path + segpos, seglen); - node->name[seglen] = '\0'; - - node->directory = slash; - node->namelen = seglen; - if (parent->child) { - parent->child->ref = &node->sibling; - *parent->child->ref = parent->child; - } - node->ref = &parent->child; - *node->ref = node; - } else { - return NULL; - } - } - segpos += seglen; - } - node->open++; - return node; -} - -static void node_close(struct node *node) { - node->open--; - if (!node->ref && node != &node_root && node->open == 0) { - free(node->buf); - free(node); - } -} - -static long node_remove(struct node *node) { - if (node == &node_root) return -1; - if (!node->ref) return -1; - if (node->child) return -ENOTEMPTY; - *node->ref = node->sibling; - node->ref = NULL; - node_close(node); - return 0; -} - -int main(void) { - const size_t buflen = 4096; - char *buf = malloc(buflen); - if (!buf) return -1; - - for (;;) { - struct ufs_request req; - hid_t reqh = ufs_wait(buf, buflen, &req); - struct node *ptr = req.id; - if (reqh < 0) break; - - switch (req.op) { - case VFSOP_OPEN: - ptr = tmpfs_open(buf, &req); - _sys_fs_respond(reqh, ptr, ptr ? 0 : -ENOENT, 0); - break; - - case VFSOP_READ: - if (ptr->directory) { - struct dirbuild db; - dir_start(&db, req.offset, buf, buflen); - for (struct node *iter = ptr->child; iter; iter = iter->sibling) { - dir_appendl(&db, iter->name, iter->namelen); - } - _sys_fs_respond(reqh, buf, dir_finish(&db), 0); - } else { - fs_normslice(&req.offset, &req.len, ptr->size, false); - _sys_fs_respond(reqh, ptr->buf + req.offset, req.len, 0); - } - break; - - case VFSOP_WRITE: - if (ptr->directory) { - _sys_fs_respond(reqh, NULL, -ENOSYS, 0); - break; - } - - fs_normslice(&req.offset, &req.len, ptr->size, true); - if (ptr->capacity <= req.offset + req.len) { - ptr->capacity = (req.offset + req.len + 511) & ~511; - ptr->buf = realloc(ptr->buf, ptr->capacity); - } - - memcpy(ptr->buf + req.offset, buf, req.len); - if ((req.flags & WRITE_TRUNCATE) || ptr->size < req.offset + req.len) { - ptr->size = req.offset + req.len; - } - _sys_fs_respond(reqh, NULL, req.len, 0); - break; - - case VFSOP_GETSIZE: - if (ptr->directory) { - // TODO could be cached in ptr->size - struct dirbuild db; - dir_start(&db, req.offset, NULL, buflen); - for (struct node *iter = ptr->child; iter; iter = iter->sibling) { - dir_append(&db, iter->name); - } - _sys_fs_respond(reqh, NULL, dir_finish(&db), 0); - } else { - _sys_fs_respond(reqh, NULL, ptr->size, 0); - } - break; - - case VFSOP_REMOVE: - _sys_fs_respond(reqh, NULL, node_remove(ptr), 0); - break; - - case VFSOP_CLOSE: - node_close(ptr); - _sys_fs_respond(reqh, NULL, -1, 0); - break; - - default: - _sys_fs_respond(reqh, NULL, -1, 0); - break; - } - } - return 1; -} diff --git a/src/cmd/true.c b/src/cmd/true.c new file mode 100644 index 0000000..061ed7e --- /dev/null +++ b/src/cmd/true.c @@ -0,0 +1,3 @@ +int main(void) { + return 0; +} diff --git a/src/cmd/true/true.c b/src/cmd/true/true.c deleted file mode 100644 index 061ed7e..0000000 --- a/src/cmd/true/true.c +++ /dev/null @@ -1,3 +0,0 @@ -int main(void) { - return 0; -} -- cgit v1.2.3