diff options
Diffstat (limited to 'src/user/app')
53 files changed, 0 insertions, 4857 deletions
diff --git a/src/user/app/drawmouse/drawmouse.c b/src/user/app/drawmouse/drawmouse.c deleted file mode 100644 index 31a1255..0000000 --- a/src/user/app/drawmouse/drawmouse.c +++ /dev/null @@ -1,87 +0,0 @@ -#include <camellia.h> -#include <camellia/syscalls.h> -#include <shared/ring.h> -#include <stdbool.h> -#include <stdio.h> -#include <string.h> -#include <unistd.h> -#include <draw.h> - -#define MOUSE_SIZE 10 - -#define eprintf(fmt, ...) fprintf(stderr, "drawmouse: "fmt"\n" __VA_OPT__(,) __VA_ARGS__) - -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("/kdev/ps2/mouse", OPEN_READ); - if (fd < 0) { - eprintf("couldn't open mouse"); - return 1; - } - - if (fb_setup(&fb, "/kdev/video/") < 0) { - eprintf("fb_setup error"); - 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/user/app/dvd/dvd.c b/src/user/app/dvd/dvd.c deleted file mode 100644 index a15b440..0000000 --- a/src/user/app/dvd/dvd.c +++ /dev/null @@ -1,43 +0,0 @@ -#include <camellia/execbuf.h> -#include <camellia/syscalls.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <draw.h> - -#define eprintf(fmt, ...) fprintf(stderr, "vterm: "fmt"\n" __VA_OPT__(,) __VA_ARGS__) - -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, "/kdev/video/") < 0) { - eprintf("fb_setup error"); - 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/user/app/ext2fs/ext2 b/src/user/app/ext2fs/ext2 deleted file mode 160000 -Subproject 8db7b4fbb2429b504d7c711dae89d917de16bed diff --git a/src/user/app/ext2fs/main.c b/src/user/app/ext2fs/main.c deleted file mode 100644 index 12ef3bc..0000000 --- a/src/user/app/ext2fs/main.c +++ /dev/null @@ -1,243 +0,0 @@ -#include "ext2/ex_cache.h" -#include "ext2/ext2.h" -#include <assert.h> -#include <camellia/flags.h> -#include <camellia/fs/dir.h> -#include <camellia/fs/misc.h> -#include <camellia/fsutil.h> -#include <camellia/syscalls.h> -#include <err.h> -#include <errno.h> -#include <stdbool.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -struct handle { - uint32_t n; - bool dir; -}; - -static int my_read(void *fp, void *buf, size_t len, size_t off); -static int my_write(void *fp, const void *buf, size_t len, size_t off); -static void do_open(struct ext2 *fs, hid_t reqh, struct ufs_request *req, char *buf); -static void do_read(struct ext2 *fs, hid_t reqh, struct ufs_request *req, char *buf, size_t buflen); -static void do_write(struct ext2 *fs, hid_t reqh, struct ufs_request *req, char *buf); -static void do_getsize(struct ext2 *fs, hid_t reqh, struct ufs_request *req); - -static int -my_read(void *fp, void *buf, size_t len, size_t off) -{ - if (fseek(fp, off, SEEK_SET) < 0) { - return -1; - } else if (fread(buf, len, 1, fp) == 1) { - return 0; - } else { - return -1; - } -} - -static int -my_write(void *fp, const void *buf, size_t len, size_t off) -{ - if (fseek(fp, off, SEEK_SET) < 0) { - return -1; - } else if (fwrite(buf, len, 1, fp) == 1) { - return 0; - } else { - return -1; - } -} - -static void -do_open(struct ext2 *fs, hid_t reqh, struct ufs_request *req, char *buf) -{ - bool is_dir = req->len == 0 || buf[req->len-1] == '/'; - uint32_t n = ext2c_walk(fs, buf, req->len); - if (n == 0) { - if (is_dir) { - _sys_fs_respond(reqh, NULL, -ENOSYS, 0); - return; - } - /* buf[0] == '/', strrchr != NULL */ - char *name = strrchr(buf, '/') + 1; - uint32_t dir_n = ext2c_walk(fs, buf, name - buf); - if (dir_n == 0) { - _sys_fs_respond(reqh, NULL, -ENOENT, 0); - return; - } - n = ext2_alloc_inode(fs, 0100700); - if (n == 0) { - _sys_fs_respond(reqh, NULL, -1, 0); - return; - } - if (ext2_link(fs, dir_n, name, n, 1) < 0) { - _sys_fs_respond(reqh, NULL, -1, 0); - return; - } - } else { - struct ext2d_inode *inode = ext2_req_inode(fs, n); - if (!inode) { - _sys_fs_respond(reqh, NULL, -ENOENT, 0); - return; - } - int type = (inode->perms >> 12) & 0xF; - ext2_dropreq(fs, inode, false); - - if ((type == 0x8 && is_dir) || (type == 0x4 && !is_dir)) { - _sys_fs_respond(reqh, NULL, -ENOENT, 0); - return; - } else if (type != 0x8 && type != 0x4) { - _sys_fs_respond(reqh, NULL, -ENOSYS, 0); - return; - } - } - - struct handle *h = malloc(sizeof *h); - if (!h) { - _sys_fs_respond(reqh, NULL, -1, 0); - return; - } - h->n = n; - h->dir = is_dir; - _sys_fs_respond(reqh, h, 0, 0); -} - -static void -do_read(struct ext2 *fs, hid_t reqh, struct ufs_request *req, char *buf, size_t buflen) -{ - struct handle *h = req->id; - if (!h->dir) { - struct ext2d_inode *inode = ext2_req_inode(fs, h->n); - if (!inode) goto err; - fs_normslice(&req->offset, &req->capacity, inode->size_lower, false); - ext2_dropreq(fs, inode, false); - - void *b = ext2_req_file(fs, h->n, &req->capacity, req->offset); - if (b) { - _sys_fs_respond(reqh, b, req->capacity, 0); - ext2_dropreq(fs, b, false); - } else if (req->capacity == 0) { - /* set by ext2_req_file on EOF */ - _sys_fs_respond(reqh, b, 0, 0); - } else goto err; - } else { - struct dirbuild db; - char namebuf[257]; - if (req->capacity > buflen) - req->capacity = buflen; - dir_start(&db, req->offset, buf, buflen); - for (struct ext2_diriter iter = {0}; ext2_diriter(&iter, fs, h->n); ) { - if (iter.ent->namelen_lower == 1 && iter.ent->name[0] == '.') { - continue; - } - if (iter.ent->namelen_lower == 2 - && iter.ent->name[0] == '.' - && iter.ent->name[1] == '.') - { - continue; - } - if (iter.ent->type == 2) { /* dir */ - memcpy(namebuf, iter.ent->name, iter.ent->namelen_lower); - namebuf[iter.ent->namelen_lower] = '/'; - dir_appendl(&db, namebuf, iter.ent->namelen_lower + 1); - } else { - dir_appendl(&db, iter.ent->name, iter.ent->namelen_lower); - } - } - _sys_fs_respond(reqh, buf, dir_finish(&db), 0); - } - return; -err: - _sys_fs_respond(reqh, NULL, -1, 0); -} - -static void -do_write(struct ext2 *fs, hid_t reqh, struct ufs_request *req, char *buf) -{ - struct handle *h = req->id; - if (h->dir) goto err; - - struct ext2d_inode *inode = ext2_req_inode(fs, h->n); - if (!inode) goto err; - fs_normslice(&req->offset, &req->len, inode->size_lower, true); - if ((req->flags & WRITE_TRUNCATE) || inode->size_lower < req->offset + req->len) { - inode->size_lower = req->offset + req->len; - if (ext2_dropreq(fs, inode, true) < 0) { - goto err; - } - } else { - ext2_dropreq(fs, inode, false); - } - inode = NULL; - - int ret = ext2_write(fs, h->n, buf, req->len, req->offset); - _sys_fs_respond(reqh, NULL, ret, 0); - return; -err: - _sys_fs_respond(reqh, NULL, -1, 0); -} - -static void -do_getsize(struct ext2 *fs, hid_t reqh, struct ufs_request *req) { - struct handle *h = req->id; - if (h->dir) goto err; - - struct ext2d_inode *inode = ext2_req_inode(fs, h->n); - if (!inode) goto err; - _sys_fs_respond(reqh, NULL, inode->size_lower, 0); - ext2_dropreq(fs, inode, false); - return; -err: - _sys_fs_respond(reqh, NULL, -1, 0); -} - -int -main(int argc, char **argv) -{ - intr_set(NULL); - - if (argc < 2) errx(1, "bad usage"); - // TODO pread/pwrite for normal handles - FILE *disk = fopen(argv[1], "r+"); - if (!disk) err(1, "couldn't open '%s'", argv[1]); - - struct e2device *dev = exc_init(my_read, my_write, (void*)disk); - if (!dev) errx(1, "exc_init failed"); - struct ext2 *fs = ext2_opendev(dev, exc_req, exc_drop); - if (!fs) errx(1, "ext2_opendev failed"); - - const size_t buflen = 4096; - char *buf = malloc(buflen); - struct ufs_request req; - for (;;) { - hid_t reqh = ufs_wait(buf, buflen, &req); - struct handle *h = req.id; - if (reqh < 0) break; - switch (req.op) { - case VFSOP_OPEN: - do_open(fs, reqh, &req, buf); - break; - case VFSOP_READ: - do_read(fs, reqh, &req, buf, buflen); - break; - case VFSOP_WRITE: - do_write(fs, reqh, &req, buf); - break; - case VFSOP_GETSIZE: - do_getsize(fs, reqh, &req); - break; - case VFSOP_CLOSE: - free(h); - _sys_fs_respond(reqh, NULL, -1, 0); - break; - default: - _sys_fs_respond(reqh, NULL, -1, 0); - break; - } - } - warnx("cleaning up"); - - return 1; -} diff --git a/src/user/app/find/find.c b/src/user/app/find/find.c deleted file mode 100644 index d473b82..0000000 --- a/src/user/app/find/find.c +++ /dev/null @@ -1,55 +0,0 @@ -#include <camellia/path.h> -#include <dirent.h> -#include <err.h> -#include <errno.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -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/user/app/httpd/httpd.c b/src/user/app/httpd/httpd.c deleted file mode 100644 index 668e534..0000000 --- a/src/user/app/httpd/httpd.c +++ /dev/null @@ -1,77 +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 <camellia/flags.h> -#include <camellia/syscalls.h> -#include <err.h> -#include <stdio.h> -#include <string.h> -#include <unistd.h> - -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; - } - FILE *f = fdopen(h, "r"); - if (!f) { - fprintf(c, "HTTP/1.1 500 Internal Server Error\r\n\r\n"); - return; - } - - if (path[strlen(path) - 1] != '/') { - /* regular file */ - fprintf(c, "HTTP/1.1 200 OK\r\n"); - fprintf(c, "\r\n"); - for (;;) { - int len = fread(buf, 1, sizeof buf, f); - if (len <= 0) break; - fwrite(buf, 1, len, c); - } - } else { - /* directory listing */ - fprintf(c, "HTTP/1.1 200 OK\r\n"); - fprintf(c, "Content-Type: text/html; charset=UTF-8\r\n"); - fprintf(c, "\r\n"); - fprintf(c, "<h1>directory listing for %s</h1><hr><ul><li><a href=..>..</a></li>", path); - for (;;) { - int len = fread(buf, 1, sizeof buf, f); - if (len <= 0) break; - // TODO directory library - // based on find.c - for (int pos = 0; pos < len; ) { - if (buf[pos] == '\0') break; - const char *end = memchr(buf + pos, 0, len - pos); - if (!end) break; - fprintf(c, "<li><a href=\"%s\">%s</a></li>", buf + pos, buf + pos); - pos += end - (buf + pos) + 1; - } - } - } - fclose(f); -} - -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/user/app/init/driver/driver.h b/src/user/app/init/driver/driver.h deleted file mode 100644 index 98c18f1..0000000 --- a/src/user/app/init/driver/driver.h +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once -#include <camellia/types.h> - -void initctl_drv(hid_t killswitch); -void ps2_drv(void); -void tmpfs_drv(void); - -void termcook(void); diff --git a/src/user/app/init/driver/initctl.c b/src/user/app/init/driver/initctl.c deleted file mode 100644 index fed71b7..0000000 --- a/src/user/app/init/driver/initctl.c +++ /dev/null @@ -1,44 +0,0 @@ -#include "driver.h" -#include <camellia/syscalls.h> -#include <ctype.h> -#include <errno.h> -#include <stdlib.h> -#include <string.h> -#include <camellia/compat.h> - -void initctl_drv(hid_t killswitch) { - struct ufs_request res; - char buf[64]; - const size_t buflen = sizeof buf; - while (!c0_fs_wait(buf, buflen, &res)) { - switch (res.op) { - case VFSOP_OPEN: - c0_fs_respond(NULL, res.len == 0 ? 0 : -1, 0); - break; - case VFSOP_WRITE: - /* null terminate */ - if (res.len > buflen - 1) - res.len = buflen - 1; - buf[res.len] = '\0'; - /* cut at first whitespace */ - for (size_t i = 0; buf[i]; i++) { - if (isspace(buf[i])) { - buf[i] = '\0'; - break; - } - } - if (!strcmp(buf, "halt")) { - _sys_write(killswitch, "halt", 4, 0, 0); - } - if (!strcmp(buf, "intr")) { - _sys_write(killswitch, "intr", 4, 0, 0); - } - c0_fs_respond(NULL, res.len, 0); - break; - default: - c0_fs_respond(NULL, -ENOSYS, 0); - break; - } - } - exit(1); -} diff --git a/src/user/app/init/driver/ps2.c b/src/user/app/init/driver/ps2.c deleted file mode 100644 index 5470249..0000000 --- a/src/user/app/init/driver/ps2.c +++ /dev/null @@ -1,129 +0,0 @@ -#include "driver.h" -#include <assert.h> -#include <camellia/compat.h> -#include <camellia/syscalls.h> -#include <errno.h> -#include <shared/ring.h> -#include <stdbool.h> -#include <stdlib.h> -#include <thread.h> - - -static const char keymap_lower[] = { - '\0', '\0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '\b', '\t', - 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\r', '\0', 'a', 's', - 'd', 'f', 'g', 'h', 'j', 'k', 'l', '\0', '\'', '`', '\0', '\\', 'z', 'x', 'c', 'v', - 'b', 'n', 'm', ',', '.', '/', '\0', '*', '\0', ' ', '\0', '\0', '\0', '\0', '\0', '\0', - '\0', '\0', '\0', '\0', '\0', '\0', '\0', '7', '8', '9', '-', '4', '5', '6', '+', '1', - '2', '3', '0', '.', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', - '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', - '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', -}; - -static const char keymap_upper[] = { - '\0', '\0', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', '\b', '\t', - 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', '\r', '\0', 'A', 'S', - 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', '"', '~', '\0', '|', 'Z', 'X', 'C', 'V', - 'B', 'N', 'M', '<', '>', '?', '\0', '*', '\0', ' ', '\0', '\0', '\0', '\0', '\0', '\0', - '\0', '\0', '\0', '\0', '\0', '\0', '\0', '7', '8', '9', '-', '4', '5', '6', '+', '1', - '2', '3', '0', '.', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', - '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', - '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', -}; - - -static volatile uint8_t backlog_buf[16]; -static volatile ring_t backlog = {(void*)backlog_buf, sizeof backlog_buf, 0, 0}; - -static hid_t fd; - -static bool keys[0x80] = {0}; - -static void parse_scancode(uint8_t s) { - bool ctrl = keys[0x1D]; - bool shift = keys[0x2A] || keys[0x36]; - bool down = !(s & 0x80); - char c; - s &= 0x7f; - keys[s] = down; - - c = shift ? keymap_upper[s] : keymap_lower[s]; - if (ctrl && keymap_upper[s] >= 'A' && keymap_upper[s] <= 'Z') - c = keymap_upper[s] - 'A' + 1; - if (down && c) ring_put1b((void*)&backlog, c); -} - - -/** Is a thread waiting for /kdev/ps2/kb? */ -static volatile bool blocked = false; -/* for use in read_thread */ -static hid_t rt_reqh; -static size_t rt_cap; - -static void read_thread(void *unused) { - char buf[512]; - (void)unused; - - assert(blocked); - while (ring_used((void*)&backlog) == 0) { - /* read raw input until we have something to output */ - int len = _sys_read(fd, buf, sizeof buf, 0); - if (len == 0) break; - for (int i = 0; i < len; i++) - parse_scancode(buf[i]); - } - if (ring_used((void*)&backlog) > 0) { - int ret = ring_get((void*)&backlog, buf, rt_cap); - _sys_fs_respond(rt_reqh, buf, ret, 0); - } else { - _sys_fs_respond(rt_reqh, 0, -EGENERIC, 0); - } - blocked = false; -} - -static void fs_loop(void) { - static char buf[512]; - int ret; - for (;;) { - struct ufs_request res; - hid_t reqh = _sys_fs_wait(buf, sizeof buf, &res); - if (reqh < 0) return; - - switch (res.op) { - case VFSOP_OPEN: - if (res.len == 0) { - _sys_fs_respond(reqh, NULL, 1, 0); - } else { - _sys_fs_respond(reqh, NULL, -ENOENT, 0); - } - break; - - case VFSOP_READ: - if (blocked) { - _sys_fs_respond(reqh, NULL, -EAGAIN, 0); - break; - } else if (ring_used((void*)&backlog) > 0) { - ret = ring_get((void*)&backlog, buf, res.capacity); - _sys_fs_respond(reqh, buf, ret, 0); - } else { - blocked = true; - rt_reqh = reqh; - rt_cap = res.capacity; - thread_create(0, read_thread, 0); - } - break; - - default: - _sys_fs_respond(reqh, NULL, -1, 0); - break; - } - } -} - -void ps2_drv(void) { - fd = _sys_open("/kdev/ps2/kb", 12, 0); - if (fd < 0) exit(1); - - fs_loop(); - exit(0); -} diff --git a/src/user/app/init/driver/termcook.c b/src/user/app/init/driver/termcook.c deleted file mode 100644 index a76f3a8..0000000 --- a/src/user/app/init/driver/termcook.c +++ /dev/null @@ -1,103 +0,0 @@ -#include "driver.h" -#include <camellia/syscalls.h> -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> - -enum tstate { - Normal, - Esc, - CSI, -}; - -static void w_output(hid_t output, const char *buf, size_t len) { - size_t pos = 0; - while (pos < len) { - int ret = _sys_write(output, buf + pos, len - pos, pos, 0); - if (ret < 0) break; - pos += ret; - } -} - -static void line_editor(hid_t input, hid_t output) { - char readbuf[16], linebuf[256]; - size_t linepos = 0; - enum tstate state = Normal; - for (;;) { - int readlen = _sys_read(input, readbuf, sizeof readbuf, -1); - if (readlen < 0) return; - for (int i = 0; i < readlen; i++) { - char c = readbuf[i]; - switch (state) { - case Normal: - switch (c) { - case '\b': - case 0x7f: - if (linepos != 0) { - printf("\b \b"); - linepos--; - } - break; - case 3: /* C-c */ - _sys_exit(1); - case 4: /* EOT, C-d */ - if (linepos > 0) { - w_output(output, linebuf, linepos); - linepos = 0; - } else { - _sys_write(output, NULL, 0, 0, 0); /* EOF */ - } - break; - case '\n': - case '\r': - printf("\n"); - if (linepos < sizeof linebuf) - linebuf[linepos++] = '\n'; - w_output(output, linebuf, linepos); - linepos = 0; - break; - case '\e': - state = Esc; - break; - case '\t': - break; - default: - if (linepos < sizeof linebuf) { - linebuf[linepos++] = c; - printf("%c", c); - } - break; - } - break; - case Esc: - if (c == '[') state = CSI; - else state = Normal; - break; - case CSI: - if (0x40 <= c && c <= 0x7E) state = Normal; - break; - } - } - } -} - -void termcook(void) { - hid_t stdin_pipe[2] = {-1, -1}; - if (_sys_pipe(stdin_pipe, 0) < 0) - return; - - if (!fork()) { - /* the caller continues in a child process, - * so it can be killed when the line editor quits */ - _sys_dup(stdin_pipe[0], 0, 0); - close(stdin_pipe[0]); - close(stdin_pipe[1]); - return; - } - if (!fork()) { - close(stdin_pipe[0]); - line_editor(0, stdin_pipe[1]); - exit(0); - } - exit(_sys_await()); -} diff --git a/src/user/app/init/init.c b/src/user/app/init/init.c deleted file mode 100644 index fcebfc7..0000000 --- a/src/user/app/init/init.c +++ /dev/null @@ -1,151 +0,0 @@ -#include "driver/driver.h" -#include <camellia/flags.h> -#include <camellia/syscalls.h> -#include <stdint.h> -#include <stdio.h> -#include <string.h> -#include <unistd.h> -#include <camellia/fs/misc.h> - -#define die(fmt, ...) do { fprintf(stderr, "init: " fmt, __VA_ARGS__); exit(1); } while (0) - -static char title[128]; - -void redirect(const char *exe, const char *out, const char *in) { - if (!fork()) { - snprintf(title, sizeof title, "sh >%s", out); - setproctitle(title); - - if (!freopen(out, "a+", stderr)) { - fprintf(stdout, "couldn't open %s\n", out); - exit(1); - } - if (!freopen(out, "a+", stdout)) - die("couldn't open %s\n", out); - if (!freopen(in, "r", stdin)) - die(" couldn't open %s\n", in); - - for (;;) { - if (!fork()) { - const char *argv[] = {exe, NULL}; - termcook(); - execv(exe, (void*)argv); - fprintf(stderr, "init: couldn't start %s\n", exe); - _sys_sleep(5000); - exit(1); - } - _sys_await(); - _sys_intr(); - } - } -} - -int main(void) { - const char *teststr = "I am teststr.\n"; - hid_t killswitch_pipe[2]; - - freopen("/kdev/com1", "a+", stdout); - freopen("/kdev/com1", "a+", stderr); - printf("[init] stage 2, main at %p, teststr at %p\n", &main, teststr); - - MOUNT_AT("/") { - fs_dirinject2((const char*[]){ - "/keyboard/", - "/usr/", - "/bin/", - "/Users/", - "/tmp/", - "/vtty", - "/net/", - "/initctl", - NULL - }); - } - - MOUNT_AT("/keyboard") { - MOUNT_AT("/") { fs_whitelist((const char*[]){"/kdev/ps2/kb", NULL}); } - ps2_drv(); - } - MOUNT_AT("/usr/") { - fs_union((const char*[]){ - "/init/usr/", - NULL - }); - } - MOUNT_AT("/bin/") { - fs_union((const char*[]){ - "/init/bin/amd64/", - "/init/bin/sh/", - "/init/usr/bin/", - "/init/usr/local/bin/", - NULL - }); - } - MOUNT_AT("/Users/") { - MOUNT_AT("/tmp/") { - const char *argv[] = {"/bin/tmpfs", NULL}; - execv(argv[0], (void*)argv); - } - // TODO a simple union isn't enough here - fs_union((const char*[]){ - "/tmp/", - "/init/Users/", - NULL - }); - } - MOUNT_AT("/tmp/") { - const char *allow[] = {"/bin/tmpfs", NULL}; - const char *argv[] = {"/bin/tmpfs", NULL}; - MOUNT_AT("/") { fs_whitelist(allow); } - execv(argv[0], (void*)argv); - } - MOUNT_AT("/vtty") { - const char *allow[] = {"/bin/vterm", "/kdev/video/", "/keyboard", "/init/usr/share/fonts/", NULL}; - const char *argv[] = {"/bin/vterm", NULL}; - MOUNT_AT("/") { fs_whitelist(allow); } - execv(argv[0], (void*)argv); - } - MOUNT_AT("/net/") { - const char *allow[] = {"/bin/netstack", "/kdev/eth", NULL}; - const char *argv[] = {"/bin/netstack", "/kdev/eth", "192.168.0.11", "192.168.0.2", NULL}; - MOUNT_AT("/") { fs_whitelist(allow); } - execv(argv[0], (void*)argv); - } - - if (_sys_pipe(killswitch_pipe, 0) < 0) { - printf("couldn't create the killswitch pipe, quitting...\n"); - return 1; - } - MOUNT_AT("/initctl") { - close(killswitch_pipe[0]); - initctl_drv(killswitch_pipe[1]); - } - close(killswitch_pipe[1]); - - if (!fork()) { - // TODO close on exec - close(killswitch_pipe[0]); - redirect("/bin/shell", "/kdev/com1", "/kdev/com1"); - redirect("/bin/shell", "/vtty", "/keyboard"); - exit(1); - } - - char buf[128]; - for (;;) { - if (_sys_read(killswitch_pipe[0], buf, 128, 0) != 4) { - break; - } - if (memcmp(buf, "intr", 4) == 0) { - _sys_intr(); - } else if (memcmp(buf, "halt", 4) == 0) { - break; - } - } - printf("[init] intr\n"); - _sys_intr(); - _sys_sleep(1000); - printf("[init] filicide\n"); - _sys_filicide(); - printf("[init] goodbye\n"); - return 0; -} diff --git a/src/user/app/iochk/iochk.c b/src/user/app/iochk/iochk.c deleted file mode 100644 index 0850821..0000000 --- a/src/user/app/iochk/iochk.c +++ /dev/null @@ -1,97 +0,0 @@ -#include <assert.h> -#include <camellia.h> -#include <camellia/syscalls.h> -#include <stdbool.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -static bool verbose = false; - -#define verbosef(...) do { if (verbose) printf(__VA_ARGS__); } while (0) -#define eprintf(fmt, ...) fprintf(stderr, "iochk: "fmt"\n" __VA_OPT__(,) __VA_ARGS__) - - -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) { - eprintf("out of memory"); - goto end; - } - - long offlast = 0; - long retlast = _sys_read(h, buflast, buflen, offlast); - if (retlast < 0) { - eprintf("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) { - eprintf("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)) { - eprintf("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) { - eprintf("no files given"); - 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) { - eprintf("couldn't open %s", path); - continue; - } - check(h); - close(h); - } - return 0; -} diff --git a/src/user/app/iostress/iostress.c b/src/user/app/iostress/iostress.c deleted file mode 100644 index ac555de..0000000 --- a/src/user/app/iostress/iostress.c +++ /dev/null @@ -1,43 +0,0 @@ -#include <camellia/syscalls.h> -#include <errno.h> -#include <stdio.h> -#include <string.h> -#include <x86intrin.h> - -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/user/app/logfs/logfs.c b/src/user/app/logfs/logfs.c deleted file mode 100644 index a50d530..0000000 --- a/src/user/app/logfs/logfs.c +++ /dev/null @@ -1,34 +0,0 @@ -#include <camellia.h> -#include <camellia/syscalls.h> -#include <err.h> -#include <stdio.h> -#include <stdlib.h> -#include <camellia/fs/misc.h> - -_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/user/app/login/login.c b/src/user/app/login/login.c deleted file mode 100644 index 0f9e8b7..0000000 --- a/src/user/app/login/login.c +++ /dev/null @@ -1,89 +0,0 @@ -#include <camellia/flags.h> -#include <camellia/syscalls.h> -#include <ctype.h> -#include <errno.h> -#include <limits.h> -#include <stdbool.h> -#include <stdio.h> -#include <string.h> -#include <unistd.h> -#include <camellia/fs/misc.h> - -static const char *shell = "/bin/shell"; - -static void cutspace(char *s) { - for (; *s; s++) { - if (isspace(*s)) { - *s = '\0'; - break; - } - } -} - -static bool segcmp(const char *path, int idx, const char *s2) { - if (idx < 0) return false; - while (idx > 0) { - if (*path == '\0') return false; - if (*path == '/') idx--; - path++; - } - /* path is at the start of the selected segment */ - while (*s2 && *path++ == *s2++); - return (*path == '\0' || *path == '/') && *s2 == '\0'; -} - -static void drv(const char *user) { - char *buf = malloc(PATH_MAX); - for (;;) { - struct ufs_request req; - hid_t reqh = ufs_wait(buf, PATH_MAX, &req); - if (reqh < 0) break; - switch (req.op) { - case VFSOP_OPEN: - if (segcmp(buf, 1, "Users") && segcmp(buf, 2, user)) { // /Users/$user/** - forward_open(reqh, buf, req.len, req.flags); - } else if (segcmp(buf, 1, "Users") && segcmp(buf, 3, "private")) { // /Users/*/private/** - _sys_fs_respond(reqh, NULL, -EACCES, 0); - } else if (!OPEN_WRITEABLE(req.flags)) { - forward_open(reqh, buf, req.len, req.flags); - } else { - _sys_fs_respond(reqh, NULL, -EACCES, 0); - } - break; - - default: - _sys_fs_respond(reqh, NULL, -1, 0); - break; - } - } - free(buf); -} - -static void trylogin(const char *user) { - if (strcmp(user, "root") != 0) { - char buf[128]; - snprintf(buf, sizeof buf, "/Users/%s/", user); - if (chdir(buf) < 0) { - printf("no such user: %s\n", user); - return; - } - MOUNT_AT("/") { drv(user); } - } - - execv(shell, NULL); - fprintf(stderr, "login: couldn't launch %s\n", shell); - exit(1); -} - -int main(void) { - char user[64]; - printf("\nCamellia\n"); - for (;;) { - printf("login: "); - fgets(user, sizeof user, stdin); - if (ferror(stdin)) return -1; - - cutspace(user); - if (user[0]) trylogin(user); - } -} diff --git a/src/user/app/netdog/nd.c b/src/user/app/netdog/nd.c deleted file mode 100644 index af5c264..0000000 --- a/src/user/app/netdog/nd.c +++ /dev/null @@ -1,48 +0,0 @@ -#include <camellia.h> -#include <camellia/syscalls.h> -#include <stdio.h> -#include <string.h> -#include <thread.h> - -#define eprintf(fmt, ...) fprintf(stderr, "netdog: "fmt"\n" __VA_OPT__(,) __VA_ARGS__) - -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) { - eprintf("no argument"); - return 1; - } - - conn = camellia_open(argv[1], OPEN_RW); - if (conn < 0) { - eprintf("couldn't open '%s', err %u", argv[1], -conn); - return -conn; - } - - thread_create(0, send_stdin, NULL); - thread_create(0, recv_stdout, NULL); - _sys_await(); - return 0; -} diff --git a/src/user/app/netstack/arp.c b/src/user/app/netstack/arp.c deleted file mode 100644 index 3a1c8da..0000000 --- a/src/user/app/netstack/arp.c +++ /dev/null @@ -1,151 +0,0 @@ -#include "proto.h" -#include "util.h" -#include <assert.h> -#include <camellia/syscalls.h> -#include <string.h> - -enum { - HdrType = 0, - HdrTypeEther = 1, - ProtoType = 2, - HdrALen = 4, - ProtoALen = 5, - Operation = 6, - OpReq = 1, - OpReply = 2, -}; - -struct arpc { - struct arpc *next; - uint32_t ip; - mac_t mac; -}; -static struct arpc *arpcache; -static void arpcache_put(uint32_t ip, mac_t mac); - -void arp_parse(const uint8_t *buf, size_t len) { - if (len < Operation + 2) return; - uint16_t htype = nget16(buf + HdrType); - uint16_t ptype = nget16(buf + ProtoType); - uint16_t op = nget16(buf + Operation); - - if (!(htype == HdrTypeEther && ptype == ET_IPv4)) return; - enum { /* only valid for this combination of header + proto */ - SrcMAC = 8, - SrcIP = 14, - DstMAC = 18, - DstIP = 24, - }; - if (len < DstIP + 4) return; - arpcache_put(nget32(buf + SrcIP), *(mac_t*)buf + SrcMAC); - - if (op == OpReq) { - uint32_t daddr = nget32(buf + DstIP); - if (daddr == state.ip) { - uint8_t *pkt = ether_start(30, (struct ethernet){ - .dst = (void*)(buf + SrcMAC), - .type = ET_ARP, - }); - nput16(pkt + HdrType, HdrTypeEther); - nput16(pkt + ProtoType, ET_IPv4); - pkt[HdrALen] = 6; - pkt[ProtoALen] = 4; - nput16(pkt + Operation, OpReply); - memcpy(pkt + SrcMAC, state.mac, 6); - nput32(pkt + SrcIP, state.ip); - memcpy(pkt + DstMAC, buf + SrcMAC, 10); /* sender's MAC and IP */ - ether_finish(pkt); - } - } -} - -void arp_request(uint32_t ip) { - enum { - SrcMAC = 8, - SrcIP = 14, - DstMAC = 18, - DstIP = 24, - }; - uint8_t *pkt = ether_start(28, (struct ethernet){ - .src = &state.mac, - .dst = &MAC_BROADCAST, - .type = ET_ARP, - }); - nput16(pkt + HdrType, HdrTypeEther); - nput16(pkt + ProtoType, ET_IPv4); - pkt[HdrALen] = 6; - pkt[ProtoALen] = 4; - nput16(pkt + Operation, OpReq); - memcpy(pkt + SrcMAC, state.mac, 6); - nput32(pkt + SrcIP, state.ip); - memcpy(pkt + DstMAC, &MAC_BROADCAST, 6); - nput32(pkt + DstIP, ip); - ether_finish(pkt); -} - -static void arpcache_put(uint32_t ip, mac_t mac) { - for (struct arpc *iter = arpcache; iter; iter = iter->next) { - if (memcmp(iter->mac, mac, 6) == 0) { - if (iter->ip == ip) return; /* cache entry correct */ - else break; /* cache entry needs updating */ - } - } - struct arpc *e = malloc(sizeof *e); - e->next = arpcache; - e->ip = ip; - memcpy(e->mac, mac, 6); - arpcache = e; -} - -int arpcache_get(uint32_t ip, mac_t *mac) { - for (struct arpc *iter = arpcache; iter; iter = iter->next) { - if (iter->ip == ip) { - if (mac) memcpy(mac, iter->mac, 6); - return 0; - } - } - return -1; -} - -void arp_fsread(hid_t h, long offset) { - const char *fmt = "%08x\t%02x:%02x:%02x:%02x:%02x:%02x\n"; - long linelen = snprintf(NULL, 0, fmt, 0, 1, 2, 3, 4, 5, 6) + 1; - char buf[28]; - assert(linelen <= (long)sizeof(buf)); - if (offset < 0) goto err; - - struct arpc *cur = arpcache; - if (!cur) goto err; - for (; linelen <= offset; offset -= linelen) { - cur = cur->next; - if (!cur) goto err; - } - assert(0 <= offset && offset < linelen); - - snprintf(buf, sizeof buf, fmt, cur->ip, - cur->mac[0], - cur->mac[1], - cur->mac[2], - cur->mac[3], - cur->mac[4], - cur->mac[5]); - _sys_fs_respond(h, buf + offset, linelen - offset, 0); - return; -err: - _sys_fs_respond(h, NULL, -1, 0); -} - -long arp_fswrite(const char *buf, long len, long offset) { - if (offset != -1) return -1; - uint32_t ip; - char tmp[16]; - size_t iplen = len < 15 ? len : 15; - memcpy(tmp, buf, iplen); - tmp[iplen] = '\0'; - if (ip_parse(tmp, &ip) < 0) { - return -1; - } else { - arp_request(ip); - return len; - } -} diff --git a/src/user/app/netstack/ether.c b/src/user/app/netstack/ether.c deleted file mode 100644 index 52abac2..0000000 --- a/src/user/app/netstack/ether.c +++ /dev/null @@ -1,59 +0,0 @@ -#include <camellia/syscalls.h> -#include "proto.h" -#include "util.h" - -enum { - DstMAC = 0, - SrcMAC = 6, - EtherType = 12, - Payload = 14, -}; -struct ethq *ether_queue; - -void ether_parse(const uint8_t *buf, size_t len) { - struct ethernet ether = (struct ethernet){ - .src = (void*)(buf + SrcMAC), - .dst = (void*)(buf + DstMAC), - .type = nget16(buf + EtherType), - }; - - for (struct ethq **iter = ðer_queue; iter && *iter; ) { - struct ethq *qe = *iter; - _sys_fs_respond(qe->h, buf, len, 0); - /* remove entry */ - /* yes, doing it this way here doesn't make sense. i'm preparing for filtering */ - *iter = qe->next; - free(qe); - } - - switch (ether.type) { - case ET_IPv4: - ipv4_parse(buf + Payload, len - Payload, ether); - break; - case ET_ARP: - arp_parse(buf + Payload, len - Payload); - break; - } -} - -static const size_t fhoff = sizeof(size_t); -uint8_t *ether_start(size_t len, struct ethernet ether) { - if (len < 60 - Payload) len = 60 - Payload; - - if (!ether.dst) eprintf("NULL ether.dst!"); // TODO arp? i guess? - if (!ether.src) ether.src = &state.mac; - - uint8_t *buf = malloc(fhoff + Payload + len); - memset(buf, 0, fhoff + Payload + len); - *(size_t*)buf = len + Payload; - memcpy(buf + fhoff + DstMAC, ether.dst, 6); - memcpy(buf + fhoff + SrcMAC, ether.src, 6); - nput16(buf + fhoff + EtherType, ether.type); - return buf + fhoff + Payload; -} -void ether_finish(uint8_t *pkt) { - uint8_t *buf = pkt - Payload - fhoff; - size_t len = *(size_t*)buf; - _sys_write(state.raw_h, buf + fhoff, len, 0, 0); - free(buf); -} diff --git a/src/user/app/netstack/fs.c b/src/user/app/netstack/fs.c deleted file mode 100644 index 6d51c35..0000000 --- a/src/user/app/netstack/fs.c +++ /dev/null @@ -1,320 +0,0 @@ -/* - * path format: - * /net/raw - * raw ethernet frames (read-write) - * /net/arp - * ARP cache (currently read-only) - * /net/connect/0.0.0.0/1.2.3.4/udp/53 - * connect from 0.0.0.0 (any ip) to 1.2.3.4 on udp port 53 - * /net/listen/0.0.0.0/{tcp,udp}/53 - * waits for a connection to any ip on udp port 53 - * open() returns once a connection to ip 0.0.0.0 on udp port 53 is received - */ -#include "proto.h" -#include "util.h" -#include <camellia/flags.h> -#include <camellia/syscalls.h> -#include <errno.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -enum handle_type { - H_ETHER, - H_TCP, - H_UDP, - H_ARP, -}; - -struct strqueue { - struct strqueue *next; - size_t len; - char buf[]; -}; - -struct handle { - enum handle_type type; - struct { - struct udp_conn *c; - struct strqueue *rx, *rxlast; - } udp; - struct { - struct tcp_conn *c; - size_t readcap; - } tcp; - bool dead; - hid_t reqh; -}; - - -static void tcp_listen_callback(struct tcp_conn *c, void *arg) { - struct handle *h = arg; - h->tcp.c = c; - _sys_fs_respond(h->reqh, h, 0, 0); - h->reqh = -1; -} - -/* also called from recv_enqueue. yes, it's a mess */ -static void tcp_recv_callback(void *arg) { - struct handle *h = arg; - char buf[1024]; - if (h->reqh >= 0) { - if (h->tcp.readcap > sizeof buf) - h->tcp.readcap = sizeof buf; - size_t len = tcpc_tryread(h->tcp.c, buf, h->tcp.readcap); - if (len > 0) { - _sys_fs_respond(h->reqh, buf, len, 0); - h->reqh = -1; - } - } -} - -static void tcp_close_callback(void *arg) { - struct handle *h = arg; - h->dead = true; - if (h->reqh >= 0) { - _sys_fs_respond(h->reqh, NULL, -ECONNRESET, 0); - h->reqh = -1; - return; - } -} - -static void udp_listen_callback(struct udp_conn *c, void *arg) { - struct handle *h = arg; - h->udp.c = c; - _sys_fs_respond(h->reqh, h, 0, 0); - h->reqh = -1; -} - -static void udp_recv_callback(const void *buf, size_t len, void *arg) { - struct handle *h = arg; - if (h->reqh >= 0) { - _sys_fs_respond(h->reqh, buf, len, 0); - h->reqh = -1; - return; - } - struct strqueue *sq = malloc(sizeof(*sq) + len); - sq->next = NULL; - sq->len = len; - memcpy(sq->buf, buf, len); - if (h->udp.rx) { - h->udp.rxlast->next = sq; - h->udp.rxlast = sq; - } else { - h->udp.rx = sq; - h->udp.rxlast = sq; - } -} - -static void recv_enqueue(struct handle *h, hid_t reqh, size_t readcap) { - if (h->reqh > 0) { - // TODO queue - _sys_fs_respond(reqh, NULL, -1, 0); - return; - } - if (h->type == H_UDP && h->udp.rx) { - _sys_fs_respond(reqh, h->udp.rx->buf, h->udp.rx->len, 0); - h->udp.rx = h->udp.rx->next; - free(h->udp.rx); - return; - } - h->reqh = reqh; - if (h->type == H_TCP) { - h->tcp.readcap = readcap; - tcp_recv_callback(h); - } -} - -static void fs_open(hid_t reqh, char *path, int flags) { -#define respond(buf, val) do{ _sys_fs_respond(reqh, buf, val, 0); return; }while(0) - struct handle *h; - if (*path != '/') respond(NULL, -1); - path++; - - if (strcmp(path, "raw") == 0) { - h = malloc(sizeof *h); - memset(h, 0, sizeof *h); - h->type = H_ETHER; - respond(h, 0); - } else if (strcmp(path, "arp") == 0) { - h = malloc(sizeof *h); - memset(h, 0, sizeof *h); - h->type = H_ARP; - respond(h, 0); - } - - /* everything below ends up sending packets */ - if (!OPEN_WRITEABLE(flags)) - respond(NULL, -EACCES); - - char *save; - const char *verb, *proto, *port_s; - uint32_t srcip, dstip; - - verb = strtok_r(path, "/", &save); - if (!verb) respond(NULL, -1); - - if (ip_parse(strtok_r(NULL, "/", &save), &srcip) < 0) - respond(NULL, -1); - if (srcip != 0) { - eprintf("unimplemented"); - respond(NULL, -1); - } - - if (strcmp(verb, "listen") == 0) { - proto = strtok_r(NULL, "/", &save); - if (!proto) respond(NULL, -1); - if (strcmp(proto, "udp") == 0) { - port_s = strtok_r(NULL, "/", &save); - if (port_s) { - uint16_t port = strtol(port_s, NULL, 0); - h = malloc(sizeof *h); - memset(h, 0, sizeof *h); - h->type = H_UDP; - h->reqh = reqh; - udp_listen(port, udp_listen_callback, udp_recv_callback, h); - return; - } - } - if (strcmp(proto, "tcp") == 0) { - port_s = strtok_r(NULL, "/", &save); - if (port_s) { - uint16_t port = strtol(port_s, NULL, 0); - h = malloc(sizeof *h); - memset(h, 0, sizeof *h); - h->type = H_TCP; - h->reqh = reqh; - tcp_listen(port, tcp_listen_callback, tcp_recv_callback, tcp_close_callback, h); - return; - } - } - } else if (strcmp(verb, "connect") == 0) { - if (ip_parse(strtok_r(NULL, "/", &save), &dstip) < 0) - respond(NULL, -1); - proto = strtok_r(NULL, "/", &save); - if (!proto) respond(NULL, -1); - if (strcmp(proto, "tcp") == 0) { - port_s = strtok_r(NULL, "/", &save); - if (port_s) { - uint16_t port = strtol(port_s, NULL, 0); - h = malloc(sizeof *h); - memset(h, 0, sizeof *h); - h->type = H_TCP; - h->tcp.c = tcpc_new((struct tcp){ - .dst = port, - .ip.dst = dstip, - }, tcp_recv_callback, tcp_close_callback, h); - if (h->tcp.c) { - respond(h, 0); - } else { - free(h); - respond(NULL, -1); - } - } - } - if (strcmp(proto, "udp") == 0) { - port_s = strtok_r(NULL, "/", &save); - if (port_s) { - uint16_t port = strtol(port_s, NULL, 0); - h = malloc(sizeof *h); - memset(h, 0, sizeof *h); - h->type = H_UDP; - h->udp.c = udpc_new((struct udp){ - .dst = port, - .ip.dst = dstip, - }, udp_recv_callback, h); - if (h->udp.c) { - respond(h, 0); - } else { - free(h); - respond(NULL, -1); - } - } - } - } - respond(NULL, -1); -#undef respond -} - -void fs_thread(void *arg) { (void)arg; - const size_t buflen = 4096; - char *buf = malloc(buflen); - for (;;) { - struct ufs_request res; - hid_t reqh = _sys_fs_wait(buf, buflen, &res); - if (reqh < 0) break; - struct handle *h = res.id; - long ret; - switch (res.op) { - case VFSOP_OPEN: - if (res.len < buflen) { - buf[res.len] = '\0'; - fs_open(reqh, buf, res.flags); - } else { - _sys_fs_respond(reqh, NULL, -1, 0); - } - break; - case VFSOP_READ: - if (h->dead) { - _sys_fs_respond(reqh, NULL, -ECONNRESET, 0); - break; - } - switch (h->type) { - case H_ETHER: { - struct ethq *qe; - qe = malloc(sizeof *qe); - qe->h = reqh; - qe->next = ether_queue; - ether_queue = qe; - break;} - case H_TCP: - case H_UDP: - recv_enqueue(h, reqh, res.capacity); - break; - case H_ARP: - arp_fsread(reqh, res.offset); - break; - default: - _sys_fs_respond(reqh, NULL, -1, 0); - } - break; - case VFSOP_WRITE: - if (h->dead) { - _sys_fs_respond(reqh, NULL, -ECONNRESET, 0); - break; - } - switch (h->type) { - case H_ETHER: - ret = _sys_write(state.raw_h, buf, res.len, 0, 0); - _sys_fs_respond(reqh, NULL, ret, 0); - break; - case H_TCP: - tcpc_send(h->tcp.c, buf, res.len); - _sys_fs_respond(reqh, NULL, res.len, 0); - break; - case H_UDP: - udpc_send(h->udp.c, buf, res.len); - _sys_fs_respond(reqh, NULL, res.len, 0); - break; - case H_ARP: - _sys_fs_respond(reqh, NULL, arp_fswrite(buf, res.len, res.offset), 0); - break; - default: - _sys_fs_respond(reqh, NULL, -1, 0); - } - break; - case VFSOP_CLOSE: - // TODO remove entries in queue - // TODO why does close even have _sys_fs_respond? - if (h->type == H_TCP) tcpc_close(h->tcp.c); - if (h->type == H_UDP) udpc_close(h->udp.c); - free(h); - _sys_fs_respond(reqh, NULL, -1, 0); - break; - default: - _sys_fs_respond(reqh, NULL, -1, 0); - break; - } - } - free(buf); -} diff --git a/src/user/app/netstack/icmp.c b/src/user/app/netstack/icmp.c deleted file mode 100644 index 0c6a502..0000000 --- a/src/user/app/netstack/icmp.c +++ /dev/null @@ -1,34 +0,0 @@ -#include "proto.h" -#include "util.h" - -enum { - Type = 0, - Code = 1, - Checksum = 2, - Payload = 4, -}; - -void icmp_parse(const uint8_t *buf, size_t len, struct ipv4 ip) { - if (len < Payload) return; - uint8_t type = buf[Type]; - if (type == 8 && ip.dst == state.ip) { - /* echo reply */ - icmp_send(buf + Payload, len - Payload, (struct icmp){ - .type = 0, - .ip.dst = ip.src, - .ip.e.dst = ip.e.src, - }); - } -} - -void icmp_send(const void *payload, size_t len, struct icmp i) { - i.ip.proto = 1; - uint8_t *pkt = malloc(Payload + len); - pkt[Type] = i.type; - pkt[Code] = i.code; - memcpy(pkt + Payload, payload, len); - nput16(pkt + Checksum, 0); - nput16(pkt + Checksum, ip_checksum(pkt, Payload + len)); - ipv4_send(pkt, Payload + len, i.ip); - free(pkt); -} diff --git a/src/user/app/netstack/ipv4.c b/src/user/app/netstack/ipv4.c deleted file mode 100644 index 1336dc1..0000000 --- a/src/user/app/netstack/ipv4.c +++ /dev/null @@ -1,216 +0,0 @@ -#include "proto.h" -#include "util.h" -#include <assert.h> -#include <stdlib.h> - -enum { - Version = 0, - HdrLen = 0, - TotalLen = 2, - Id = 4, - FragInfo = 6, - EvilBit = 0x8000, - DontFrag = 0x4000, - MoreFrags = 0x2000, - FragOff = 0x1FFF, - TTL = 8, - Proto = 9, - Checksum = 10, - SrcIP = 12, - DstIP = 16, -}; -static void ipv4_dispatch(const uint8_t *buf, size_t len, struct ipv4 ip); - -struct fragment { - struct fragment *next; /* sorted */ - size_t len, offset; - bool last; - uint8_t buf[]; -}; -struct fragmented { - /* src, dst, proto, id come from the first arrived packet - * and are used to tell fragmenteds apart. - * the rest comes from the sequentially first packet. - * ip.h.header points to a malloc'd buffer*/ - struct ipv4 h; - - struct fragment *first; - struct fragmented *next, **prev; /* *(inc->prev) == inc */ - // TODO timer -}; -struct fragmented *fragmenteds; -static struct fragmented *fragmented_find(struct ipv4 fraghdr); -static void fragmented_tryinsert(const uint8_t *payload, size_t plen, struct ipv4 ip); -static void fragmented_tryfinish(struct fragmented *inc); -static void fragmented_free(struct fragmented *inc); - -static struct fragmented *fragmented_find(struct ipv4 fraghdr) { - struct fragmented *inc; - for (inc = fragmenteds; inc; inc = inc->next) { - if (inc->h.src == fraghdr.src && - inc->h.dst == fraghdr.dst && - inc->h.proto == fraghdr.proto && - inc->h.id == fraghdr.id) - { - return inc; - } - } - inc = malloc(sizeof *inc); - memset(inc, 0, sizeof *inc); - inc->h.src = fraghdr.src; - inc->h.dst = fraghdr.dst; - inc->h.proto = fraghdr.proto; - inc->h.id = fraghdr.id; - - inc->next = fragmenteds; - if (inc->next) inc->next->prev = &inc->next; - inc->prev = &fragmenteds; - *inc->prev = inc; - return inc; -} - -static void fragmented_tryinsert(const uint8_t *payload, size_t plen, struct ipv4 ip) { - struct fragmented *inc = fragmented_find(ip); - size_t off = (ip.fraginfo & FragOff) * 8; - bool last = !(ip.fraginfo & MoreFrags); - // eprintf("fragmented packet, %u + %u, part of 0x%x", off, plen, inc); - - /* find the first fragment at a bigger offset, and insert before it */ - struct fragment **insert = &inc->first; - for (; *insert; insert = &(*insert)->next) { - if ((*insert)->offset > off) break; - if ((*insert)->offset == off) return; /* duplicate packet */ - } - /* later on: frag->next = *insert; - * if we're the last fragment, frag->next must == NULL */ - if (last && *insert != NULL) return; - - struct fragment *frag = malloc(sizeof(struct fragment) + plen); - frag->next = *insert; - *insert = frag; - frag->len = plen; - frag->offset = off; - frag->last = last; - memcpy(frag->buf, payload, plen); - - if (off == 0) { /* save header */ - assert(!inc->h.header); - void *headercpy = malloc(ip.hlen); - memcpy(headercpy, ip.header, ip.hlen); - inc->h = ip; - inc->h.header = headercpy; - } - - fragmented_tryfinish(inc); -} - -static void fragmented_tryfinish(struct fragmented *inc) { - if (inc->first->offset != 0) return; - for (struct fragment *iter = inc->first; iter; iter = iter->next) { - size_t iterend = iter->offset + iter->len; - struct fragment *next = iter->next; - if (next) { - if (iterend < next->offset) return; /* incomplete */ - if (iterend > next->offset) { - fragmented_free(inc); - return; - } - } else if (iter->last) { - void *buf = malloc(iterend); - for (struct fragment *iter = inc->first; iter; iter = iter->next) { - assert(iter->offset + iter->len <= iterend); - memcpy(buf + iter->offset, iter->buf, iter->len); - } - ipv4_dispatch(buf, iterend, inc->h); - free(buf); - fragmented_free(inc); - } - } -} - -static void fragmented_free(struct fragmented *inc) { - if (inc->next) { - inc->next->prev = inc->prev; - *inc->next->prev = inc->next; - } else { - *inc->prev = NULL; - } - - for (struct fragment *next, *iter = inc->first; iter; iter = next) { - next = iter->next; - free(iter); - } - free((void*)inc->h.header); - free(inc); -} - - -static void ipv4_dispatch(const uint8_t *buf, size_t len, struct ipv4 ip) { - switch (ip.proto) { - case 0x01: icmp_parse(buf, len, ip); break; - case 0x06: tcp_parse(buf, len, ip); break; - case 0x11: udp_parse(buf, len, ip); break; - } -} - -void ipv4_parse(const uint8_t *buf, size_t len, struct ethernet ether) { - uint8_t version, headerlen; - uint16_t totallen; - - version = buf[Version] >> 4; - if (version != 4) return; - headerlen = (buf[HdrLen] & 0xf) * 4; - totallen = nget16(buf + TotalLen); - if (totallen < headerlen) return; - - /* ignores checksum. TODO? */ - - struct ipv4 ip = (struct ipv4){ - .e = ether, - .src = nget32(buf + SrcIP), - .dst = nget32(buf + DstIP), - .id = nget16(buf + Id), - .fraginfo = nget16(buf + FragInfo), - .proto = buf[Proto], - .header = buf, - .hlen = headerlen, - }; - - if (ip.fraginfo & ~(EvilBit | DontFrag)) { - fragmented_tryinsert(buf + headerlen, totallen - headerlen, ip); - } else { - if (totallen > len) return; - ipv4_dispatch(buf + headerlen, totallen - headerlen, ip); - } -} - -static uint16_t next_id = 0; -void ipv4_send(const void *payload, size_t len, struct ipv4 ip) { - const size_t mtu = 1500; - const size_t hdrlen = 20; - - ip.e.type = ET_IPv4; - if (!ip.src) ip.src = state.ip; - if (!ip.e.dst && ip.dst == 0xFFFFFFFF) - ip.e.dst = &MAC_BROADCAST; - - uint16_t id = next_id++; - for (size_t off = 0, fraglen = mtu - hdrlen; off < len; off += fraglen) { - if (fraglen > len - off) - fraglen = len - off; - bool last = off + fraglen >= len; - uint8_t *pkt = ether_start(hdrlen + fraglen, ip.e); - pkt[Version] = 0x40; - pkt[HdrLen] |= hdrlen / 4; - nput16(pkt + TotalLen, hdrlen + fraglen); - nput16(pkt + Id, id); - nput16(pkt + FragInfo, (off >> 3) | (last ? 0 : MoreFrags)); - pkt[TTL] = 0xFF; - pkt[Proto] = ip.proto; - nput32(pkt + SrcIP, ip.src); - nput32(pkt + DstIP, ip.dst); - nput16(pkt + Checksum, ip_checksum(pkt, hdrlen)); - memcpy(pkt + hdrlen, payload + off, fraglen); - ether_finish(pkt); - } -} diff --git a/src/user/app/netstack/netstack.c b/src/user/app/netstack/netstack.c deleted file mode 100644 index 2636429..0000000 --- a/src/user/app/netstack/netstack.c +++ /dev/null @@ -1,53 +0,0 @@ -#include "proto.h" -#include "util.h" -#include <camellia.h> -#include <camellia/syscalls.h> -#include <stdbool.h> -#include <stddef.h> -#include <stdlib.h> -#include <string.h> -#include <thread.h> - -struct net_state state = { - // TODO dynamically get mac - .mac = {0x52, 0x54, 0x00, 0xCA, 0x77, 0x1A}, -}; - -void network_thread(void *arg) { (void)arg; - const size_t buflen = 4096; - char *buf = malloc(buflen); - for (;;) { - long ret = _sys_read(state.raw_h, buf, buflen, -1); - if (ret < 0) break; - ether_parse((void*)buf, ret); - } - free(buf); -} - -void fs_thread(void *arg); - -int main(int argc, char **argv) { - if (argc < 4) { - eprintf("usage: netstack iface ip gateway"); - return 1; - } - state.raw_h = camellia_open(argv[1], OPEN_RW); - if (state.raw_h < 0) { - eprintf("couldn't open %s", argv[1]); - return 1; - } - if (ip_parse(argv[2], &state.ip) < 0) { - eprintf("invalid ip"); - return -1; - } - if (ip_parse(argv[3], &state.gateway) < 0) { - eprintf("invalid gateway"); - return -1; - } - setproctitle(argv[2]); - arp_request(state.gateway); - thread_create(0, network_thread, NULL); - thread_create(0, fs_thread, NULL); - _sys_await(); - return 0; -} diff --git a/src/user/app/netstack/proto.h b/src/user/app/netstack/proto.h deleted file mode 100644 index 8ea11ac..0000000 --- a/src/user/app/netstack/proto.h +++ /dev/null @@ -1,107 +0,0 @@ -#pragma once -#include <camellia/types.h> -#include <stdbool.h> -#include <stdint.h> - -typedef uint8_t mac_t[6]; -static const mac_t MAC_BROADCAST = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; - -extern struct net_state { - mac_t mac; - uint32_t ip, gateway; - - hid_t raw_h; -} state; - -enum { /* ethertype */ - ET_IPv4 = 0x800, - ET_ARP = 0x806, -}; - -struct ethernet { - const mac_t *src, *dst; - uint16_t type; -}; - -struct ipv4 { - struct ethernet e; - uint32_t src, dst; - uint16_t id, fraginfo; - uint8_t proto; - const uint8_t *header; size_t hlen; -}; - -struct tcp { - struct ipv4 ip; - uint16_t src, dst; -}; - -struct udp { - struct ipv4 ip; - uint16_t src, dst; -}; - -struct icmp { - struct ipv4 ip; - uint8_t type, code; -}; - - -/* NOT THREADSAFE, YET USED FROM CONCURRENT THREADS - * will break if i implement a scheduler*/ -struct ethq { - struct ethq *next; - hid_t h; -}; -extern struct ethq *ether_queue; - -void arp_parse(const uint8_t *buf, size_t len); -void arp_request(uint32_t ip); -/* 0 on success, -1 on failure */ -int arpcache_get(uint32_t ip, mac_t *mac); -void arp_fsread(hid_t h, long offset); -long arp_fswrite(const char *buf, long len, long offset); - -void icmp_parse(const uint8_t *buf, size_t len, struct ipv4 ip); -void icmp_send(const void *payload, size_t len, struct icmp i); - -void ipv4_parse(const uint8_t *buf, size_t len, struct ethernet ether); -void ipv4_send(const void *payload, size_t len, struct ipv4 ip); - -void ether_parse(const uint8_t *buf, size_t len); -uint8_t *ether_start(size_t len, struct ethernet ether); -void ether_finish(uint8_t *pkt); - -struct udp_conn; -void udp_parse(const uint8_t *buf, size_t len, struct ipv4 ip); -/* calls callback once, after a client connects. */ -void udp_listen( - uint16_t port, - void (*on_conn)(struct udp_conn *, void *carg), - void (*on_recv)(const void *, size_t, void *carg), - void *carg); -struct udp_conn *udpc_new( - struct udp u, - void (*on_recv)(const void *, size_t, void *carg), - void *carg); -// TODO udp_onclosed -void udpc_send(struct udp_conn *, const void *buf, size_t len); -/* frees */ -void udpc_close(struct udp_conn *); - -struct tcp_conn; -void tcp_parse(const uint8_t *buf, size_t len, struct ipv4 ip); -void tcp_listen( - uint16_t port, - void (*on_conn)(struct tcp_conn *, void *carg), - void (*on_recv)(void *carg), - void (*on_close)(void *carg), - void *carg); -struct tcp_conn *tcpc_new( - struct tcp t, - void (*on_recv)(void *carg), - void (*on_close)(void *carg), - void *carg); -size_t tcpc_tryread(struct tcp_conn *, void *buf, size_t len); -void tcpc_send(struct tcp_conn *, const void *buf, size_t len); -void tcpc_close(struct tcp_conn *); diff --git a/src/user/app/netstack/tcp.c b/src/user/app/netstack/tcp.c deleted file mode 100644 index d1adeab..0000000 --- a/src/user/app/netstack/tcp.c +++ /dev/null @@ -1,268 +0,0 @@ -/* Welcome to spaghetti land. - * This is anything but production quality. It's throwaway code, meant - * only to see how networking could fit into the architecture of the - * system. */ -#include "proto.h" -#include "util.h" -#include <assert.h> -#include <shared/ring.h> - -enum { - SrcPort = 0, - DstPort = 2, - Seq = 4, - AckNum = 8, /* last processed seq + 1 */ - Flags = 12, - FlagSize = 0xF000, /* size of header / 4 bytes */ - /* 3 bits: 0, still unused - * 3 bits: modern stuff not in the original RFC */ - FlagURG = 0x0020, /* urgent */ - FlagACK = 0x0010, - FlagPSH = 0x0008, /* force buffer flush */ - FlagRST = 0x0004, /* reset connection */ - FlagSYN = 0x0002, /* first packet; sync sequence numbers */ - FlagFIN = 0x0001, /* last packet */ - FlagAll = 0x003F, - WinSize = 14, /* amount of data we're willing to receive */ - Checksum = 16, - Urgent = 18, - MinHdr = 20, -}; - -enum tcp_state { - LISTEN, - SYN_SENT, - SYN_RCVD, - ESTABILISHED, - LAST_ACK, - CLOSED, -}; - -struct tcp_conn { - uint32_t lip, rip; - mac_t rmac; - uint16_t lport, rport; - struct tcp_conn *next, **link; - - enum tcp_state state; - uint32_t lack, rack; - uint32_t lseq; - bool uclosed; /* did the user close? */ - - void (*on_conn)(struct tcp_conn *, void *carg); - void (*on_recv)(void *carg); - void (*on_close)(void *carg); - void *carg; - - ring_t rx; -}; -static struct tcp_conn *conns; -static void conns_append(struct tcp_conn *c) { - c->next = conns; - if (c->next) - c->next->link = &c->next; - c->link = &conns; - *c->link = c; -} -static void tcpc_sendraw(struct tcp_conn *c, uint16_t flags, const void *buf, size_t len) { - uint8_t *pkt = malloc(MinHdr + len); - memset(pkt, 0, MinHdr); - - nput16(pkt + SrcPort, c->lport); - nput16(pkt + DstPort, c->rport); - nput32(pkt + Seq, c->lseq); - c->lseq += len; - nput32(pkt + AckNum, c->lack); - flags |= (MinHdr / 4) << 12; - nput16(pkt + Flags, flags); - nput16(pkt + WinSize, ring_avail(&c->rx)); - memcpy(pkt + MinHdr, buf, len); - nput16(pkt + Checksum, ip_checksumphdr(pkt, MinHdr + len, c->lip, c->rip, 6)); - - ipv4_send(pkt, MinHdr + len, (struct ipv4){ - .proto = 6, - .src = c->lip, - .dst = c->rip, - .e.dst = &c->rmac, - }); - free(pkt); -} -void tcp_listen( - uint16_t port, - void (*on_conn)(struct tcp_conn *, void *carg), - void (*on_recv)(void *carg), - void (*on_close)(void *carg), - void *carg) -{ - struct tcp_conn *c = malloc(sizeof *c); - memset(c, 0, sizeof *c); - c->lport = port; - c->lip = state.ip; - c->state = LISTEN; - c->on_conn = on_conn; - c->on_recv = on_recv; - c->on_close = on_close; - c->carg = carg; - // TODO setting the ring size super low loses every nth byte. probably a bug with ring_t itself! - c->rx = (ring_t){malloc(4096), 4096, 0, 0}; - conns_append(c); -} -struct tcp_conn *tcpc_new( - struct tcp t, - void (*on_recv)(void *carg), - void (*on_close)(void *carg), - void *carg) -{ - struct tcp_conn *c = malloc(sizeof *c); - memset(c, 0, sizeof *c); - c->lip = t.ip.src ? t.ip.src : state.ip; - c->rip = t.ip.dst; - c->lport = t.src ? t.src : 50002; // TODO randomize source ports - c->rport = t.dst; - if (arpcache_get(c->rip, &c->rmac) < 0) { - // TODO wait for ARP reply - arp_request(c->rip); - if (arpcache_get(state.gateway, &c->rmac) < 0) { - eprintf("neither target nor gateway not in ARP cache, dropping"); - free(c); - return NULL; - } - } - - c->state = SYN_SENT; - c->on_recv = on_recv; - c->on_close = on_close; - c->carg = carg; - c->rx = (ring_t){malloc(4096), 4096, 0, 0}; - conns_append(c); - - tcpc_sendraw(c, FlagSYN, NULL, 0); - c->lseq++; - return c; -} -size_t tcpc_tryread(struct tcp_conn *c, void *buf, size_t len) { - if (!buf) return ring_used(&c->rx); - return ring_get(&c->rx, buf, len); -} -void tcpc_send(struct tcp_conn *c, const void *buf, size_t len) { - tcpc_sendraw(c, FlagACK | FlagPSH, buf, len); -} -static void tcpc_tryfree(struct tcp_conn *c) { - if (c->state == CLOSED && c->uclosed) { - if (c->next) c->next->link = c->link; - *c->link = c->next; - free(c->rx.buf); - free(c); - } -} -void tcpc_close(struct tcp_conn *c) { - /* ONLY FOR USE BY THE USER, drops their reference */ - assert(!c->uclosed); - c->uclosed = true; - if (c->state != CLOSED && c->state != LAST_ACK && c->state != LISTEN) { - tcpc_sendraw(c, FlagFIN | FlagACK, NULL, 0); - c->state = LAST_ACK; - c->on_conn = NULL; - c->on_close = NULL; - } - tcpc_tryfree(c); -} - -void tcp_parse(const uint8_t *buf, size_t len, struct ipv4 ip) { - if (len < 20) return; - uint16_t srcport = nget16(buf + SrcPort); - uint16_t dstport = nget16(buf + DstPort); - uint32_t seq = nget32(buf + Seq); - uint32_t acknum = nget32(buf + AckNum); - uint16_t flags = nget16(buf + Flags); - // uint16_t winsize = nget16(buf + WinSize); - // uint16_t chksum = nget16(buf + Checksum); - uint16_t hdrlen = ((flags & FlagSize) >> 12) * 4; - if (hdrlen > len) return; - uint16_t payloadlen = len - hdrlen; - - for (struct tcp_conn *iter = conns; iter; iter = iter->next) { - if (iter->state == CLOSED) continue; - if (iter->lport != dstport) continue; - - if (iter->state == LISTEN && (flags & FlagAll) == FlagSYN) { - iter->state = SYN_RCVD; - iter->rip = ip.src; - iter->rport = srcport; - iter->lack = seq + 1; - memcpy(&iter->rmac, ip.e.src, sizeof(mac_t)); - tcpc_sendraw(iter, FlagSYN | FlagACK, NULL, 0); - iter->lseq++; - if (iter->on_conn) iter->on_conn(iter, iter->carg); - return; - } - - if (iter->rip == ip.src && iter->rport == srcport) { - // TODO doesn't handle seq/ack overflows - if (iter->state == SYN_SENT) { - if (flags & FlagSYN) { - iter->state = ESTABILISHED; - iter->lack = seq + 1; - tcpc_sendraw(iter, FlagACK, NULL, 0); - return; - } else { - // TODO resend syn? - return; - } - } - if (flags & FlagACK) { - if (iter->rack < acknum) - iter->rack = acknum; - if (iter->state == LAST_ACK) { - // TODO check if ack has correct number - iter->state = CLOSED; - tcpc_tryfree(iter); - // TODO free (also after a timeout) - return; - } - } - if (iter->lack != seq && iter->lack - 1 != seq) { - eprintf("remote seq jumped by %d", seq - iter->lack); - tcpc_sendraw(iter, FlagACK, NULL, 0); - return; - } - // TODO check if overflows window size - if (payloadlen) { - iter->lack = seq + payloadlen; - ring_put(&iter->rx, buf + hdrlen, payloadlen); - if (iter->on_recv) iter->on_recv(iter->carg); - tcpc_sendraw(iter, FlagACK, NULL, 0); - } - if (flags & FlagFIN) { - // TODO should resend the packet until an ACK is received - // TODO duplicated in tcpc_close - tcpc_sendraw(iter, FlagFIN | FlagACK, NULL, 0); - iter->state = LAST_ACK; - if (iter->on_close) iter->on_close(iter->carg); - return; - } - return; - } - } - - if ((flags & FlagRST) == 0) { - uint8_t *pkt = malloc(MinHdr); - memset(pkt, 0, MinHdr); - nput16(pkt + SrcPort, dstport); - nput16(pkt + DstPort, srcport); - nput32(pkt + Seq, acknum); - nput32(pkt + AckNum, seq + 1); - uint16_t pktflags = FlagRST | FlagACK; - pktflags |= (MinHdr / 4) << 12; - nput16(pkt + Flags, pktflags); - nput16(pkt + Checksum, ip_checksumphdr(pkt, MinHdr, ip.src, ip.dst, 6)); - - ipv4_send(pkt, MinHdr, (struct ipv4){ - .proto = 6, - .src = ip.dst, - .dst = ip.src, - .e.dst = ip.e.src, - }); - free(pkt); - } -} diff --git a/src/user/app/netstack/udp.c b/src/user/app/netstack/udp.c deleted file mode 100644 index 3d560ae..0000000 --- a/src/user/app/netstack/udp.c +++ /dev/null @@ -1,124 +0,0 @@ -#include "proto.h" -#include "util.h" - -enum { - SrcPort = 0, - DstPort = 2, - Length = 4, - Checksum = 6, - Payload = 8, -}; - - -struct udp_conn { - uint32_t lip, rip; - uint16_t lport, rport; - mac_t rmac; - void (*on_conn)(struct udp_conn *, void *); /* if non-NULL - listening, if NULL - estabilished */ - void (*on_recv)(const void *, size_t, void *); - void *carg; - struct udp_conn *next, **link; -}; -static struct udp_conn *conns; -static void conns_append(struct udp_conn *c) { - c->next = conns; - if (c->next) - c->next->link = &c->next; - c->link = &conns; - *c->link = c; -} -void udp_listen( - uint16_t port, - void (*on_conn)(struct udp_conn *, void *carg), - void (*on_recv)(const void *, size_t, void *carg), - void *carg) -{ - if (!on_conn) return; - struct udp_conn *c = malloc(sizeof *c); - c->lport = port; - c->lip = state.ip; - c->on_conn = on_conn; - c->on_recv = on_recv; - c->carg = carg; - conns_append(c); -} -struct udp_conn *udpc_new( - struct udp u, - void (*on_recv)(const void *, size_t, void *carg), - void *carg) -{ - struct udp_conn *c = malloc(sizeof *c); - memset(c, 0, sizeof *c); - c->lip = u.ip.src; - c->rip = u.ip.dst; - c->lport = u.src ? u.src : 50000; // TODO randomize source ports - c->rport = u.dst; - if (arpcache_get(c->rip, &c->rmac) < 0) { - // TODO make arp request, wait for reply - eprintf("not in ARP cache, unimplemented"); - free(c); - return NULL; - } - c->on_recv = on_recv; - c->carg = carg; - conns_append(c); - return c; -} -void udpc_send(struct udp_conn *c, const void *buf, size_t len) { - uint8_t *pkt = malloc(Payload + len); - nput16(pkt + SrcPort, c->lport); - nput16(pkt + DstPort, c->rport); - nput16(pkt + Length, Payload + len); - nput16(pkt + Checksum, 0); - memcpy(pkt + Payload, buf, len); - ipv4_send(pkt, Payload + len, (struct ipv4){ - .proto = 0x11, - .src = c->lip, - .dst = c->rip, - .e.dst = &c->rmac, - }); - free(pkt); -} -void udpc_close(struct udp_conn *c) { - if (c->next) c->next->link = c->link; - *(c->link) = c->next; - free(c); -} - - -void udp_parse(const uint8_t *buf, size_t len, struct ipv4 ip) { - uint16_t srcport = nget16(buf + SrcPort); - uint16_t dstport = nget16(buf + DstPort); - bool active = false; - - for (struct udp_conn *iter = conns; iter; iter = iter->next) { - if (iter->on_conn && dstport == iter->lport) { - iter->on_conn(iter, iter->carg); - iter->on_conn = NULL; - iter->rport = srcport; - memcpy(&iter->rmac, ip.e.src, sizeof(mac_t)); - iter->rip = ip.src; - } - if (iter->rip == ip.src && - iter->rport == srcport && - iter->lport == dstport && - iter->on_recv) - { - active = true; - iter->on_recv(buf + Payload, len - Payload, iter->carg); - } - } - - if (!active) { - uint8_t *pkt = malloc(4 + ip.hlen + 8); - nput32(pkt, 0); - memcpy(pkt + 4, ip.header, ip.hlen + 8); - icmp_send(pkt, 4 + ip.hlen + 8, (struct icmp){ - .type = 3, /* destination unreachable */ - .code = 3, /* port unreachable */ - .ip.dst = ip.src, - .ip.e.dst = ip.e.src, - }); - free(pkt); - } -} diff --git a/src/user/app/netstack/util.c b/src/user/app/netstack/util.c deleted file mode 100644 index 68092aa..0000000 --- a/src/user/app/netstack/util.c +++ /dev/null @@ -1,60 +0,0 @@ -#include "util.h" - -/* https://www.w3.org/TR/PNG/#D-CRCAppendix */ -static uint32_t crc_table[256]; -uint32_t crc32(const uint8_t *buf, size_t len) { - if (!crc_table[1]) { - for (int i = 0; i < 256; i++) { - uint32_t c = i; - for (int j = 0; j < 8; j++) - c = ((c&1) ? 0xedb88320 : 0) ^ (c >> 1); - crc_table[i] = c; - } - } - - uint32_t c = 0xFFFFFFFF; - for (size_t i = 0; i < len; i++) - c = crc_table[(c ^ buf[i]) & 0xff] ^ (c >> 8); - return ~c; -} - -uint16_t ip_checksum(const uint8_t *buf, size_t len) { - uint32_t c = 0; - while (len >= 2) { - c += nget16(buf); - buf += 2; len -= 2; - } - if (len) c += (*buf) << 8; - while (c > 0xFFFF) c = (c & 0xFFFF) + (c >> 16); - return ~c; -} - -uint16_t ip_checksumphdr( - const uint8_t *buf, size_t len, - uint32_t ip1, uint32_t ip2, - uint16_t proto) -{ - uint32_t c = (uint16_t)~ip_checksum(buf, len); - c += (ip1 & 0xFFFF) + (ip1 >> 16); - c += (ip2 & 0xFFFF) + (ip2 >> 16); - c += proto + len; - while (c > 0xFFFF) c = (c & 0xFFFF) + (c >> 16); - return ~c; -} - -int ip_parse(const char *s, uint32_t *dest) { - if (!s) return -1; - - uint32_t ip = strtol(s, (char**)&s, 0); - int parts = 1; - for (; parts < 4; parts++) { - if (!*s) break; - if (*s++ != '.') return -1; - ip <<= 8; - ip += strtol(s, (char**)&s, 0); - } - if (parts > 1) - ip = ((ip & 0xFFFFFF00) << 8 * (4 - parts)) | (ip & 0xFF); - *dest = ip; - return 0; -} diff --git a/src/user/app/netstack/util.h b/src/user/app/netstack/util.h deleted file mode 100644 index 0b29560..0000000 --- a/src/user/app/netstack/util.h +++ /dev/null @@ -1,44 +0,0 @@ -#pragma once -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#define eprintf(fmt, ...) fprintf(stderr, "netstack: "fmt"\n" __VA_OPT__(,) __VA_ARGS__) - -uint32_t crc32(const uint8_t *buf, size_t len); -uint16_t ip_checksum(const uint8_t *buf, size_t len); -uint16_t ip_checksumphdr( - const uint8_t *buf, size_t len, - uint32_t ip1, uint32_t ip2, - uint16_t proto); -/* 0 on success, negative failure */ -int ip_parse(const char *s, uint32_t *ip); - -static inline void nput16(void *vbuf, uint16_t n) { - uint8_t *b = vbuf; - b[0] = n >> 8; - b[1] = n >> 0; -} - -static inline void nput32(void *vbuf, uint32_t n) { - uint8_t *b = vbuf; - b[0] = n >> 24; - b[1] = n >> 16; - b[2] = n >> 8; - b[3] = n >> 0; -} - -static inline uint16_t nget16(const void *vbuf) { - const uint8_t *b = vbuf; - return (b[0] << 8) - | (b[1] << 0); -} - -static inline uint32_t nget32(const void *vbuf) { - const uint8_t *b = vbuf; - return (b[0] << 24) - | (b[1] << 16) - | (b[2] << 8) - | (b[3] << 0); -} diff --git a/src/user/app/ps/ps.c b/src/user/app/ps/ps.c deleted file mode 100644 index 76a5841..0000000 --- a/src/user/app/ps/ps.c +++ /dev/null @@ -1,54 +0,0 @@ -#include <_proc.h> -#include <ctype.h> -#include <err.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -int -main(void) -{ - char *readbuf = malloc(4096); - char *procbuf = malloc(4096); - FILE *f = fopen("/proc/", "r"); - if (!f) { - err(1, "couldn't open /proc/"); - } - - // TODO library for iterating over directories - for (;;) { - int len = fread(readbuf, 1, 4096, f); - if (len <= 0) break; - for (int pos = 0; pos < len; ) { - char *end = memchr(readbuf + pos, 0, len - pos); - if (!end) { - errx(1, "unimplemented: buffer overflow"); - } - size_t entryl = end - (readbuf+pos) + 1; - if (isdigit(readbuf[pos])) { - FILE *g; - sprintf(procbuf, "/proc/%smem", readbuf+pos); - 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); - } - end[-1] = '\0'; /* remove trailing slash */ - printf("%s\t%s\n", readbuf+pos, procbuf); - } - pos += entryl; - } - } - - free(readbuf); - free(procbuf); - fclose(f); - return 0; -} diff --git a/src/user/app/shell/builtins.c b/src/user/app/shell/builtins.c deleted file mode 100644 index 9c294b2..0000000 --- a/src/user/app/shell/builtins.c +++ /dev/null @@ -1,254 +0,0 @@ -#include "builtins.h" -#include "shell.h" -#include <camellia.h> -#include <camellia/fs/misc.h> -#include <camellia/path.h> -#include <err.h> -#include <stdbool.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/stat.h> -#include <unistd.h> - -#define DEFAULT_ARGV(...) \ - char *_argv_default[] = {argv[0], __VA_ARGS__}; \ - if (argc <= 1) { \ - argc = sizeof(_argv_default) / sizeof(*_argv_default); \ - argv = _argv_default; \ - } - -static void cmd_cat(int argc, char **argv) { - const size_t buflen = 4096; - char *buf = malloc(buflen); - - DEFAULT_ARGV("!stdin"); - for (int i = 1; i < argc; i++) { - FILE *file = fopen(argv[i], "r"); - if (!file) { - perror(argv[i]); - return; - } - if (!strcmp(argv[i], "!stdin")) fextflags(file, FEXT_NOFILL); - for (;;) { - int len = fread(buf, 1, buflen, file); - if (len <= 0) break; - fwrite(buf, 1, len, stdout); - } - if (ferror(file)) { - perror(argv[i]); - return; - } - fclose(file); - } -} - -static void cmd_echo(int argc, char **argv) { - bool newline = true; - int i = 1; - - if (!strcmp("-n", argv[i])) { - i++; - newline = false; - } - - printf("%s", argv[i++]); - for (; i < argc; i++) - printf(" %s", argv[i]); - if (newline) - printf("\n"); -} - -void cmd_getsize(int argc, char **argv) { - if (argc < 2) errx(1, "no arguments"); - for (int i = 1; i < argc; i++) { - hid_t h = camellia_open(argv[i], OPEN_READ); - if (h < 0) { - warn("error opening %s", argv[i]); - continue; - } - printf("%s: %d\n", argv[i], (int)_sys_getsize(h)); - _sys_close(h); - } -} - -void cmd_hexdump(int argc, char **argv) { - DEFAULT_ARGV("!stdin"); - const size_t buflen = 4096; - uint8_t *buf = malloc(buflen); - FILE *file; - bool canonical = strcmp(argv[0], "hd") == 0; - size_t readlen = ~0; - size_t pos = 0; - bool raw = false; - - int c; - optind = 0; - while ((c = getopt(argc, argv, "Cn:s:r")) != -1) { - switch (c) { - case 'C': - canonical = true; - break; - case 'n': - readlen = strtol(optarg, NULL, 0); - break; - case 's': - pos = strtol(optarg, NULL, 0); - break; - case 'r': /* "raw" mode, print data as soon as it's read without buffering */ - raw = true; - break; - default: - return; - } - } - if (readlen != (size_t)~0) - readlen += pos; - - for (; optind < argc; optind++) { - file = fopen(argv[optind], "r"); - if (!file) { - warn("couldn't open %s", argv[optind]); - continue; - } - if (raw) fextflags(file, FEXT_NOFILL); - fseek(file, pos, SEEK_SET); - bool skipped = false; - while (pos < readlen) { - size_t len = buflen; - if (len > readlen - pos) - len = readlen - pos; - len = fread(buf, 1, len, file); - if (len == 0) break; - - for (size_t i = 0; i < len; i += 16) { - if (i >= 16 && !memcmp(buf + i, buf + i - 16, 16)) { - if (!skipped) { - printf("*\n"); - skipped = true; - } - continue; - } else skipped = false; - printf("%08zx ", pos + i); - - for (size_t j = i; j < i + 8 && j < len; j++) - printf("%02x ", buf[j]); - printf(" "); - for (size_t j = i + 8; j < i + 16 && j < len; j++) - printf("%02x ", buf[j]); - - if (canonical) { - printf(" |"); - - for (size_t j = i; j < i + 16 && j < len; j++) { - char c = '.'; - if (0x20 <= buf[j] && buf[j] < 0x7f) c = buf[j]; - printf("%c", c); - } - printf("|\n"); - } else { - printf("\n"); - } - } - pos += len; - } - printf("%08zx\n", pos); - fclose(file); - } -} - -static void cmd_ls(int argc, char **argv) { - FILE *file; - const size_t buflen = 4096; - char *buf = malloc(buflen); - - DEFAULT_ARGV("."); - for (int i = 1; i < argc; i++) { - char *path = (void*)argv[i]; - int pathlen = strlen(path); - - if (!pathlen || path[pathlen - 1] != '/') { - memcpy(buf, path, pathlen); - buf[pathlen] = '/'; - buf[pathlen+1] = '\0'; - path = buf; - } - - file = fopen(path, "r"); - if (!file) { - warn("couldn't open %s", argv[i]); - continue; - } - for (;;) { - int len = fread(buf, 1, buflen, file); - if (len <= 0) break; - for (int i = 0; i < len; i++) - if (buf[i] == '\0') buf[i] = '\n'; - fwrite(buf, 1, len, stdout); - } - fclose(file); - } -} - -static void cmd_mkdir(int argc, char **argv) { - // TODO mkdir -p - if (argc < 2) errx(1, "no arguments"); - for (int i = 1; i < argc; i++) { - if (mkdir(argv[i], 0777) < 0) - perror(argv[i]); - } -} - -static void cmd_rm(int argc, char **argv) { - if (argc < 2) errx(1, "no arguments"); - for (int i = 1; i < argc; i++) { - if (unlink(argv[i]) < 0) - perror(argv[i]); - } -} - -static void cmd_sleep(int argc, char **argv) { - if (argc < 2) errx(1, "no arguments"); - _sys_sleep(strtol(argv[1], NULL, 0) * 1000); -} - -static void cmd_touch(int argc, char **argv) { - if (argc < 2) errx(1, "no arguments"); - for (int i = 1; i < argc; i++) { - FILE *f = fopen(argv[i], "a"); - if (!f) perror(argv[i]); - fclose(f); - } -} - -static void cmd_whitelist(int argc, char **argv) { - int split = 1; - for (; split < argc;) { - if (!strcmp("--", argv[split])) break; - split++; - } - argv[split] = NULL; - MOUNT_AT("/") { fs_whitelist((void*)&argv[1]); } - - if (split < argc) { - run_args(argc - split - 1, &argv[split + 1], NULL); - } else { - const char **argv = (const char*[]){"shell", NULL}; - run_args(1, (void*)argv, NULL); - } -} - -struct builtin builtins[] = { - {"cat", cmd_cat}, - {"echo", cmd_echo}, - {"getsize", cmd_getsize}, - {"hd", cmd_hexdump}, - {"hexdump", cmd_hexdump}, - {"ls", cmd_ls}, - {"mkdir", cmd_mkdir}, - {"rm", cmd_rm}, - {"sleep", cmd_sleep}, - {"touch", cmd_touch}, - {"whitelist", cmd_whitelist}, - {NULL, NULL}, -}; diff --git a/src/user/app/shell/builtins.h b/src/user/app/shell/builtins.h deleted file mode 100644 index 1e422bb..0000000 --- a/src/user/app/shell/builtins.h +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once -#include <camellia/syscalls.h> -#include <stdbool.h> - -struct builtin { - const char *name; - void (*fn)(int argc, char **argv); -}; - -extern struct builtin builtins[]; diff --git a/src/user/app/shell/parser.c b/src/user/app/shell/parser.c deleted file mode 100644 index ad09348..0000000 --- a/src/user/app/shell/parser.c +++ /dev/null @@ -1,76 +0,0 @@ -#include "shell.h" -#include <ctype.h> -#include <stdbool.h> -#include <string.h> - -static char skipspace(char **sp) { - char *s = *sp; - while (*s && isspace(*s)) s++; - *sp = s; - return *s; -} - -static bool isspecial(char c) { - return c == '>' || c == '#'; -} - -static char *parg(char **sp) { - char *s = *sp; - char *res = NULL; - - if (skipspace(&s)) { - // TODO incorrectly handles strings like a"b" - switch (*s) { - case '"': - s++; - res = s; - while (*s && *s != '"') - s++; - break; - default: - res = s; - while (*s && !isspace(*s) && !isspecial(*s)) - s++; - if (*s == '#') { - *s = '\0'; /* end parsing early */ - if (res == s) /* don't output an empty arg */ - res = NULL; - } - break; - } - if (*s) *s++ = '\0'; - } - - *sp = s; - return res; -} - -int parse(char *s, char **argv, size_t argvlen, struct redir *redir) { - if (argvlen == 0) return -1; - size_t argc = 0; - char *arg; - - *argv = NULL; - redir->stdout = NULL; - redir->append = false; - - while (skipspace(&s)) { - switch (*s) { - case '>': - s++; - if (*s == '>') { - s++; - redir->append = true; - } - redir->stdout = parg(&s); - break; - default: - arg = parg(&s); - argv[argc++] = arg; - if (argc >= argvlen) - return -1; - } - } - argv[argc] = NULL; - return argc; -} diff --git a/src/user/app/shell/shell.c b/src/user/app/shell/shell.c deleted file mode 100644 index 185aa7e..0000000 --- a/src/user/app/shell/shell.c +++ /dev/null @@ -1,178 +0,0 @@ -#include "builtins.h" -#include "shell.h" -#include <camellia/flags.h> -#include <camellia/syscalls.h> -#include <err.h> -#include <errno.h> -#include <stdbool.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <camellia/fs/misc.h> -#include <x86intrin.h> - -int main(); - -static void execp(char **argv) { - if (!argv || !*argv) return; - if (strncmp(argv[0], "/", 1) == 0 || - strncmp(argv[0], "./", 2) == 0 || - strncmp(argv[0], "../", 3) == 0) - { - execv(argv[0], argv); - } else { - size_t cmdlen = strlen(argv[0]); - char *s = malloc(cmdlen + 6); - if (!s) err(1, "malloc"); - memcpy(s, "/bin/", 5); - memcpy(s + 5, argv[0], cmdlen + 1); - execv(s, argv); - free(s); - } -} - -void run_args(int argc, char **argv, struct redir *redir) { - if (!*argv) return; - - /* "special" commands that can't be handled in a subprocess */ - if (!strcmp(argv[0], "mount")) { - if (argc < 3) { - fprintf(stderr, "mount: not enough arguments\n"); - return; - } - MOUNT_AT("/") { - fs_dirinject(argv[1]); - } - MOUNT_AT(argv[1]) { - run_args(argc - 2, argv + 2, redir); - exit(1); - } - return; - } else if (!strcmp(argv[0], "shadow")) { - if (argc < 2) { - fprintf(stderr, "shadow: missing path\n"); - } else { - _sys_mount(HANDLE_NULLFS, argv[1], strlen(argv[1])); - } - } else if (!strcmp(argv[0], "procmnt")) { - if (argc < 2) { - fprintf(stderr, "procmnt: missing mountpoint\n"); - return; - } - _sys_mount(HANDLE_PROCFS, argv[1], strlen(argv[1])); - /* - if (!(3 <= argc && !strcmp(argv[2], "raw"))) { - if (!mount_at("/")) { - fs_dirinject(argv[1]); - exit(1); - } - } - */ - return; - } else if (!strcmp(argv[0], "cd")) { - if (chdir(argc > 1 ? argv[1] : "/") < 0) - perror("cd"); - return; - } else if (!strcmp(argv[0], "time")) { - uint64_t time = __rdtsc(); - uint64_t div = 3000; - run_args(argc - 1, argv + 1, redir); - time = __rdtsc() - time; - printf("%lu ns (assuming 3GHz)\n", time / div); - return; - } else if (!strcmp(argv[0], "exit")) { - exit(0); - } else if (!strcmp(argv[0], "getpid")) { - printf("my\t%d\nparent\t%d\n", getpid(), getppid()); - return; - } - - if (fork()) { - _sys_await(); - return; - } - - if (redir && redir->stdout) { - FILE *f = fopen(redir->stdout, redir->append ? "a" : "w"); - if (!f) { - err(1, "couldn't open %s for redirection", redir->stdout); - } - - /* a workaround for file offsets not being preserved across exec()s. - * TODO document that weird behaviour of exec() */ - hid_t p[2]; - if (_sys_pipe(p, 0) < 0) { - errx(1, "couldn't create redirection pipe"); - } - if (!_sys_fork(FORK_NOREAP, NULL)) { - /* the child forwards data from the pipe to the file */ - const size_t buflen = 512; - char *buf = malloc(buflen); - if (!buf) err(1, "when redirecting"); - close(p[1]); - for (;;) { - long len = _sys_read(p[0], buf, buflen, 0); - if (len < 0) exit(0); - fwrite(buf, 1, len, f); - if (ferror(f)) exit(0); - } - } - - fclose(f); - close(p[0]); - if (_sys_dup(p[1], 1, 0) < 0) { - errx(1, "dup() failed when redirecting"); - } - } - - for (struct builtin *iter = builtins; iter->name; iter++) { - if (!strcmp(argv[0], iter->name)) { - setprogname(argv[0]); - iter->fn(argc, argv); - exit(0); - } - } - - execp(argv); - if (errno == EINVAL) { - errx(1, "%s isn't a valid executable", argv[0]); - } else { - errx(1, "unknown command: %s", argv[0]); - } -} - -static void run(char *cmd) { -#define ARGV_MAX 16 - char *argv[ARGV_MAX]; - struct redir redir; - int argc = parse(cmd, argv, ARGV_MAX, &redir); - if (argc < 0) { - warn("parsing error"); - } else { - run_args(argc, argv, &redir); - } -} - -int main(int argc, char **argv) { - static char buf[256]; - FILE *f = stdin; - - if (argc > 1) { - f = fopen(argv[1], "r"); - if (!f) { - err(1, "couldn't open %s", argv[1]); - return 1; - } - } - - for (;;) { - if (f == stdin) { - printf("%s $ ", getcwd(buf, sizeof buf)); - } - if (!fgets(buf, 256, f)) { - return 0; - } - run(buf); - } -} diff --git a/src/user/app/shell/shell.h b/src/user/app/shell/shell.h deleted file mode 100644 index 050e704..0000000 --- a/src/user/app/shell/shell.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once -#include <stdbool.h> -#include <stddef.h> - -struct redir { - const char *stdout; - bool append; -}; - -int parse(char *s, char **argv, size_t argvlen, struct redir *redir); -void run_args(int argc, char **argv, struct redir *redir); diff --git a/src/user/app/testelf/main.c b/src/user/app/testelf/main.c deleted file mode 100644 index 0cbe56c..0000000 --- a/src/user/app/testelf/main.c +++ /dev/null @@ -1,26 +0,0 @@ -#include <err.h> -#include <stdio.h> -#include <string.h> -#include <unistd.h> - -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/user/app/tests/kernel/fdlimit.c b/src/user/app/tests/kernel/fdlimit.c deleted file mode 100644 index f332357..0000000 --- a/src/user/app/tests/kernel/fdlimit.c +++ /dev/null @@ -1,49 +0,0 @@ -#include "../tests.h" -#include <camellia/flags.h> -#include <errno.h> -#include <unistd.h> - -static void test_fdlimit_pipe(void) { - hid_t ends[2]; - hid_t h[2] = {-1, -1}; - for (;;) { - hid_t cur = _sys_open("/", 1, OPEN_READ); - if (cur == -EMFILE) break; - test(cur >= 0); - h[0] = h[1]; - h[1] = cur; - } - test(h[0] >= 0); /* we need at least two handles */ - - test(_sys_pipe(ends, 0) == -EMFILE); - test(_sys_open("/", 1, OPEN_READ) == -EMFILE); - - close(h[1]); - test(_sys_pipe(ends, 0) == -EMFILE); - test(_sys_open("/", 1, OPEN_READ) == h[1]); - test(_sys_open("/", 1, OPEN_READ) == -EMFILE); - - close(h[0]); - close(h[1]); - test(_sys_pipe(ends, 0) == 0); -} - -static void test_fdlimit_fork(void) { - for (;;) { - hid_t cur = _sys_open("/", 1, OPEN_READ); - if (cur == -EMFILE) break; - test(cur >= 0); - } - - if (!_sys_fork(0, NULL)) _sys_exit(123); - - test(_sys_fork(FORK_NEWFS, NULL) == -EMFILE); - test(_sys_await() == 123); - test(_sys_await() == ~0); -} - -void r_k_fdlimit(void) { - /* all these tests implicitly test if the vfs returns -EMFILE */ - run_test(test_fdlimit_pipe); - run_test(test_fdlimit_fork); -} diff --git a/src/user/app/tests/kernel/fs.c b/src/user/app/tests/kernel/fs.c deleted file mode 100644 index b5684d7..0000000 --- a/src/user/app/tests/kernel/fs.c +++ /dev/null @@ -1,79 +0,0 @@ -#include "../tests.h" -#include <camellia/flags.h> -#include <camellia/syscalls.h> -#include <stdbool.h> -#include <string.h> - -static void test_unfinished_req(void) { - hid_t h = -1; - int ret = _sys_fork(FORK_NEWFS, &h); - test(0 <= ret); - if (ret == 0) { - // TODO make a similar test with all 0s passed to fs_wait - struct ufs_request res; - _sys_fs_wait(NULL, 0, &res); - // TODO second fs_wait - exit(0); - } else { - test(0 <= h); - test(_sys_mount(h, "/", 1) == 0); - int ret = _sys_open("/", 1, 0); - test(ret < 0); - // the handler quits while handling that call - but this syscall should return anyways - } -} - -static void test_orphaned_fs(void) { - hid_t h = -1; - int ret = _sys_fork(FORK_NEWFS, &h); - test(0 <= ret); - if (ret == 0) { - exit(0); - } else { - test(0 <= h); - test(_sys_mount(h, "/", 1) == 0); - int ret = _sys_open("/", 1, 0); - test(ret < 0); - } -} - -static void test_fs_cleanup(void) { - const char *msg = "success"; - int msglen = 8; - char buf[16]; - hid_t ends[2]; - test(_sys_pipe(ends, 0) >= 0); - if (!_sys_fork(0, NULL)) { - hid_t h = -1; - if (_sys_fork(FORK_NEWFS, &h) == 0) { - for (;;) { - struct ufs_request req; - hid_t reqh = _sys_fs_wait(buf, sizeof buf, &req); - if (reqh < 0) break; - _sys_fs_respond(reqh, NULL, 0, 0); /* success */ - } - /* this is the test: does it break out of the loop - * when it should cleanup */ - _sys_write(ends[1], msg, msglen, -1, 0); - exit(0); - } else { - test(_sys_mount(h, "/", 1) == 0); - h = _sys_open("/", 1, 0); - test(h >= 0); - _sys_close(h); - // TODO another test without the delay - _sys_sleep(0); - exit(0); - } - } else { - test(_sys_read(ends[0], buf, sizeof buf, 0) == msglen); - test(memcmp(buf, msg, msglen) == 0); - } -} - -void r_k_fs(void) { - run_test(test_unfinished_req); - run_test(test_orphaned_fs); - run_test(test_fs_cleanup); - run_test(test_fs_cleanup); -} diff --git a/src/user/app/tests/kernel/misc.c b/src/user/app/tests/kernel/misc.c deleted file mode 100644 index 5d6b531..0000000 --- a/src/user/app/tests/kernel/misc.c +++ /dev/null @@ -1,66 +0,0 @@ -#include "../tests.h" -#include <camellia/errno.h> -#include <camellia/flags.h> -#include <camellia/syscalls.h> -#include <string.h> -#include <unistd.h> - -static void test_fault_kill(void) { - if (!fork()) { /* invalid memory access */ - asm volatile("movb $69, 0" ::: "memory"); - test_fail(); - } - if (!fork()) { /* #GP */ - asm volatile("hlt" ::: "memory"); - test_fail(); - } - - int await_cnt = 0; - while (_sys_await() != ~0) await_cnt++; - test(await_cnt == 2); -} - -static void test_efault(void) { -#if 0 - const char *str = "o, 16 characters"; - char str2[16]; - char *invalid = (void*)0x1000; - hid_t h; - - memcpy(str2, str, 16); - - test((h = _sys_open(TMPFILEPATH, strlen(TMPFILEPATH), OPEN_CREATE | OPEN_WRITE)) >= 0); - test(_sys_write(h, str, 16, 0, 0) == 16); - test(_sys_write(h, str2, 16, 0, 0) == 16); - - test(_sys_write(h, invalid, 16, 0, 0) == -EFAULT); - - /* x64 non-canonical pointers */ - test(_sys_write(h, (void*)((uintptr_t)str ^ 0x8000000000000000), 16, 0, 0) == -EFAULT); - test(_sys_write(h, (void*)((uintptr_t)str ^ 0x1000000000000000), 16, 0, 0) == -EFAULT); - test(_sys_write(h, (void*)((uintptr_t)str ^ 0x0100000000000000), 16, 0, 0) == -EFAULT); - test(_sys_write(h, (void*)((uintptr_t)str ^ 0x0010000000000000), 16, 0, 0) == -EFAULT); - test(_sys_write(h, (void*)((uintptr_t)str ^ 0x0001000000000000), 16, 0, 0) == -EFAULT); - test(_sys_write(h, (void*)((uintptr_t)str ^ 0x0000800000000000), 16, 0, 0) == -EFAULT); - - test(_sys_write(h, (void*)((uintptr_t)str2 ^ 0x8000000000000000), 16, 0, 0) == -EFAULT); - test(_sys_write(h, (void*)((uintptr_t)str2 ^ 0x1000000000000000), 16, 0, 0) == -EFAULT); - test(_sys_write(h, (void*)((uintptr_t)str2 ^ 0x0100000000000000), 16, 0, 0) == -EFAULT); - test(_sys_write(h, (void*)((uintptr_t)str2 ^ 0x0010000000000000), 16, 0, 0) == -EFAULT); - test(_sys_write(h, (void*)((uintptr_t)str2 ^ 0x0001000000000000), 16, 0, 0) == -EFAULT); - test(_sys_write(h, (void*)((uintptr_t)str2 ^ 0x0000800000000000), 16, 0, 0) == -EFAULT); - - test(_sys_write(h, str, 16, 0, 0) == 16); - close(h); -#endif -} - -static void test_invalid_syscall(void) { - test(_syscall(~0, 0, 0, 0, 0, 0) < 0); -} - -void r_k_misc(void) { - run_test(test_fault_kill); - run_test(test_efault); - run_test(test_invalid_syscall); -} diff --git a/src/user/app/tests/kernel/miscsyscall.c b/src/user/app/tests/kernel/miscsyscall.c deleted file mode 100644 index 459da2a..0000000 --- a/src/user/app/tests/kernel/miscsyscall.c +++ /dev/null @@ -1,315 +0,0 @@ -#include "../tests.h" -#include <camellia/errno.h> -#include <camellia/execbuf.h> -#include <camellia/flags.h> -#include <camellia/syscalls.h> -#include <string.h> -#include <unistd.h> - - -static void test_await(void) { - /* creates 16 child processes, each returning a different value. then checks - * if await() returns every value exactly once */ - int ret; - int counts[16] = {0}; - - for (int i = 0; i < 16; i++) - if (!fork()) - exit(i); - - while ((ret = _sys_await()) != ~0) { - test(0 <= ret && ret < 16); - counts[ret]++; - } - - for (int i = 0; i < 16; i++) - test(counts[i] == 1); -} - -static void test_await2(void) { - /* hangs on failure */ - if (!fork()) { - if (!fork()) { - for (;;) _sys_sleep(1000000000); - } else { - exit(123); - } - } - test(_sys_await() == 123); - test(_sys_await() == ~0); /* don't wait for tombstone */ - _sys_filicide(); -} - -static void test_wait2_basic(void) { - struct sys_wait2 data = {0}; - int pid; - pid = fork(); - if (pid == 0) { - exit(420); - } - test(_sys_wait2(-1, 0, &data) == pid); - test(data.status == 420); - test(_sys_wait2(-1, 0, NULL) == -ECHILD); -} - -static void test_pipe(void) { - const char *pipe_msgs[2] = {"hello", "world"}; - hid_t ends[2]; - char buf[16]; - - /* test regular reads / writes */ - test(_sys_pipe(ends, 0) >= 0); - if (!fork()) { - /* those repeated asserts ensure that you can't read/write to the wrong ends */ - test(_sys_read(ends[1], buf, 16, 0) < 0); - test(_sys_write(ends[0], buf, 16, 0, 0) < 0); - - test(5 == _sys_write(ends[1], pipe_msgs[0], 5, -1, 0)); - - test(_sys_read(ends[1], buf, 16, 0) < 0); - test(_sys_write(ends[0], buf, 16, 0, 0) < 0); - - test(5 == _sys_write(ends[1], pipe_msgs[1], 5, -1, 0)); - - exit(0); - } else { - test(_sys_read(ends[1], buf, 16, 0) < 0); - test(_sys_write(ends[0], buf, 16, 0, 0) < 0); - - test(5 == _sys_read(ends[0], buf, 16, 0)); - test(!memcmp(buf, pipe_msgs[0], 5)); - - test(_sys_read(ends[1], buf, 16, 0) < 0); - test(_sys_write(ends[0], buf, 16, 0, 0) < 0); - - test(5 == _sys_read(ends[0], buf, 16, 0)); - test(!memcmp(buf, pipe_msgs[1], 5)); - - _sys_await(); - } - close(ends[0]); - close(ends[1]); - - - /* writing to pipes with one end closed */ - test(_sys_pipe(ends, 0) >= 0); - for (int i = 0; i < 16; i++) { - if (!fork()) { - close(ends[1]); - test(_sys_read(ends[0], buf, 16, 0) < 0); - exit(0); - } - } - close(ends[1]); - for (int i = 0; i < 16; i++) - _sys_await(); - close(ends[0]); - - test(_sys_pipe(ends, 0) >= 0); - for (int i = 0; i < 16; i++) { - if (!fork()) { - close(ends[0]); - test(_sys_write(ends[1], buf, 16, 0, 0) < 0); - exit(0); - } - } - close(ends[0]); - for (int i = 0; i < 16; i++) - _sys_await(); - close(ends[1]); - - - /* queueing */ - test(_sys_pipe(ends, 0) >= 0); - for (int i = 0; i < 16; i++) { - if (!fork()) { - test(_sys_write(ends[1], pipe_msgs[0], 5, -1, 0) == 5); - exit(0); - } - } - close(ends[1]); - for (int i = 0; i < 16; i++) { - test(_sys_read(ends[0], buf, sizeof buf, 0) == 5); - _sys_await(); - } - test(_sys_read(ends[0], buf, sizeof buf, 0) < 0); - close(ends[0]); - - test(_sys_pipe(ends, 0) >= 0); - for (int i = 0; i < 16; i++) { - if (!fork()) { - memset(buf, 0, sizeof buf); - test(_sys_read(ends[0], buf, 5, -1) == 5); - test(!memcmp(buf, pipe_msgs[1], 5)); - exit(0); - } - } - close(ends[0]); - for (int i = 0; i < 16; i++) { - test(_sys_write(ends[1], pipe_msgs[1], 5, -1, 0) == 5); - _sys_await(); - } - test(_sys_write(ends[1], pipe_msgs[1], 5, -1, 0) < 0); - close(ends[1]); - - - // not a to.do detect when all processes that can read are stuck on writing to the pipe and vice versa - // it seems like linux just lets the process hang endlessly. -} - -static void test_memflag(void) { - void *page = (void*)0x77777000; - _sys_memflag(page, 4096, MEMFLAG_PRESENT); // allocate page - memset(page, 77, 4096); // write to it - _sys_memflag(page, 4096, 0); // free it - - if (!fork()) { - memset(page, 11, 4096); // should segfault - exit(0); - } else { - test(_sys_await() != 0); // test if the process crashed - } - - char *pages[4]; - for (size_t i = 0; i < 4; i++) { - pages[i] = _sys_memflag(NULL, 4096, MEMFLAG_FINDFREE); - test(pages[i] == _sys_memflag(NULL, 4096, MEMFLAG_FINDFREE | MEMFLAG_PRESENT)); - if (i > 0) test(pages[i] != pages[i-1]); - *pages[i] = 0x77; - } - - for (size_t i = 0; i < 4; i++) - _sys_memflag(pages, 4096, MEMFLAG_PRESENT); -} - -static void test_dup(void) { - hid_t pipe[2]; - hid_t h1, h2; - test(_sys_pipe(pipe, 0) >= 0); - - if (!fork()) { - close(pipe[0]); - - h1 = _sys_dup(pipe[1], -1, 0); - test(h1 >= 0); - test(h1 != pipe[1]); - h2 = _sys_dup(h1, -1, 0); - test(h2 >= 0); - test(h2 != pipe[1] && h2 != h1); - - _sys_write(pipe[1], "og", 2, 0, 0); - _sys_write(h1, "h1", 2, 0, 0); - _sys_write(h2, "h2", 2, 0, 0); - - close(pipe[1]); - _sys_write(h1, "h1", 2, 0, 0); - _sys_write(h2, "h2", 2, 0, 0); - - test(_sys_dup(h1, pipe[1], 0) == pipe[1]); - test(_sys_dup(h2, pipe[1], 0) == pipe[1]); - test(_sys_dup(h1, pipe[1], 0) == pipe[1]); - test(_sys_dup(h2, pipe[1], 0) == pipe[1]); - close(h1); - close(h2); - - test(_sys_dup(pipe[1], h2, 0) == h2); - _sys_write(h2, "h2", 2, 0, 0); - close(h2); - - test(_sys_dup(pipe[1], h1, 0) == h1); - _sys_write(h1, "h1", 2, 0, 0); - close(h1); - - exit(0); - } else { - char buf[16]; - size_t count = 0; - close(pipe[1]); - while (_sys_read(pipe[0], buf, sizeof buf, 0) >= 0) - count++; - test(count == 7); - _sys_await(); - } - - - close(pipe[0]); -} - -static void test_execbuf(void) { - if (!fork()) { - uint64_t buf[] = { - EXECBUF_SYSCALL, _SYS_EXIT, 123, 0, 0, 0, 0, - }; - _sys_execbuf(buf, sizeof buf); - test_fail(); - } else { - test(_sys_await() == 123); - } -} - -static void test_sleep(void) { - hid_t reader; - FILE *writer; - if (!forkpipe(&writer, &reader)) { - if (!fork()) { - if (!fork()) { - _sys_sleep(100); - fprintf(writer, "1"); - _sys_sleep(200); - fprintf(writer, "3"); - _sys_sleep(200); - fprintf(writer, "5"); - _sys_exit(0); - } - if (!fork()) { - fprintf(writer, "0"); - _sys_sleep(200); - fprintf(writer, "2"); - _sys_sleep(200); - fprintf(writer, "4"); - /* get killed while asleep - * a peaceful death, i suppose. */ - for (;;) _sys_sleep(1000000000); - } - _sys_await(); - _sys_filicide(); - _sys_exit(0); - } - - /* this part checks if, after killing an asleep process, - * other processes can still wake up */ - _sys_sleep(600); - fprintf(writer, "6"); - exit(0); - } else { - const char *expected = "0123456"; - size_t target = strlen(expected); - size_t pos = 0; - for (;;) { - char buf[128]; - long ret = _sys_read(reader, buf, sizeof buf, 0); - if (ret < 0) break; - test(pos + ret <= target); - test(memcmp(buf, expected + pos, ret) == 0); - pos += ret; - } - test(pos == target); - } -} - -static void test_badopen(void) { - test(_sys_open(TMPFILEPATH, strlen(TMPFILEPATH), OPEN_CREATE | OPEN_WRITE) >= 0); - test(_sys_open(TMPFILEPATH, strlen(TMPFILEPATH), OPEN_CREATE) == -EINVAL); -} - -void r_k_miscsyscall(void) { - run_test(test_await); - run_test(test_await2); - run_test(test_wait2_basic); - run_test(test_pipe); - run_test(test_memflag); - run_test(test_dup); - run_test(test_execbuf); - run_test(test_sleep); - run_test(test_badopen); -} diff --git a/src/user/app/tests/kernel/path.c b/src/user/app/tests/kernel/path.c deleted file mode 100644 index 5a22c36..0000000 --- a/src/user/app/tests/kernel/path.c +++ /dev/null @@ -1,108 +0,0 @@ -#include "../tests.h" -#include <camellia/path.h> -#include <string.h> -#include <camellia/compat.h> -#include <camellia/fs/misc.h> - -static void test_path_simplify(void) { - const char *testcases[][2] = { - {"/", "/"}, - {"/.", "/"}, - {"//", "/"}, - {"/asdf", "/asdf"}, - {"/asdf/", "/asdf/"}, - {"/asdf//", "/asdf/"}, - {"/asdf/./", "/asdf/"}, - {"/a/./b", "/a/b"}, - {"/a/./b/", "/a/b/"}, - - // some slightly less easy cases - {"/asdf/..", "/"}, - {"/asdf/../", "/"}, - {"/asdf/.", "/asdf/"}, - {"/asdf//.", "/asdf/"}, - - {"/foo/bar/..", "/foo/"}, - {"/foo/bar/../baz", "/foo/baz"}, - {"/foo/bar/../baz/", "/foo/baz/"}, - {"/foo/bar/xyz/..", "/foo/bar/"}, - {"/foo/bar/xyz/../", "/foo/bar/"}, - - // going under the root or close to it - {"/..", NULL}, - {"/../asdf", NULL}, - {"/../asdf/", NULL}, - {"/./a/../..", NULL}, - {"/a/a/../..", "/"}, - {"/a/../a/..", "/"}, - {"/a/../../a", NULL}, - {"/../a/../a", NULL}, - {"/../../a/a", NULL}, - {"/////../..", NULL}, - {"//a//../..", NULL}, - - // relative paths aren't allowed - {"relative", NULL}, - {"some/stuff", NULL}, - {"./stuff", NULL}, - {"../stuff", NULL}, - {"", NULL}, - }; - - char buf[256]; - for (size_t i = 0; i < sizeof(testcases) / sizeof(testcases[0]); i++) { - const char *input = testcases[i][0]; - const char *expected = testcases[i][1]; - int len = path_simplify(input, buf, strlen(input)); - if (expected == NULL) { - test(len == 0); - } else { - // TODO an argument for printing info on test failure - test(len == (int)strlen(expected) && !memcmp(expected, buf, len)); - } - } -} - -static void mount_resolve_drv(const char *path) { - if (mount_at(path) != 0) return; - - struct ufs_request res; - while (!c0_fs_wait(NULL, 0, &res)) { - // TODO does the first argument of c0_fs_respond need to be non-const? - c0_fs_respond((void*)path, strlen(path), 0); - } - exit(1); -} - -static void test_mount_resolve(void) { - const char *testcases[][2] = { - {"/", "/"}, - {"/test", "/"}, - {"/dir", "/dir"}, - {"/dir/..", "/"}, - {"/dir/../dir", "/dir"}, - {"/dirry", "/"}, - {"/dir/", "/dir"}, - {"/dir/shadowed", "/dir"}, - {"/dir/shadowed/", "/dir"}, - }; - mount_resolve_drv("/"); - mount_resolve_drv("/dir/shadowed"); - mount_resolve_drv("/dir"); - - char buf[16]; - for (size_t i = 0; i < sizeof(testcases) / sizeof(testcases[0]); i++) { - const char *input = testcases[i][0]; - const char *expected = testcases[i][1]; - hid_t h = _sys_open(input, strlen(input), 0); - test(h >= 0); - int len = _sys_read(h, buf, sizeof buf, 0); - test(len == (int)strlen(expected) && !memcmp(expected, buf, len)); - _sys_close(h); - } -} - -void r_k_path(void) { - run_test(test_path_simplify); - run_test(test_mount_resolve); -} diff --git a/src/user/app/tests/kernel/threads.c b/src/user/app/tests/kernel/threads.c deleted file mode 100644 index b3c1c06..0000000 --- a/src/user/app/tests/kernel/threads.c +++ /dev/null @@ -1,55 +0,0 @@ -#include "../tests.h" -#include <camellia/flags.h> -#include <camellia/syscalls.h> -#include <string.h> -#include <esemaphore.h> -#include <thread.h> - -int global_n; -static void basic_thread(void *sem) { - global_n = 10; - esem_signal(sem); -} -static void test_basic_thread(void) { - struct evil_sem *sem = esem_new(0); - global_n = 0; - thread_create(FORK_NOREAP, basic_thread, sem); - esem_wait(sem); - test(global_n == 10); -} - -hid_t global_h; -static void shared_handle(void *sem) { - hid_t ends[2]; - test(_sys_pipe(ends, 0) >= 0); - global_h = ends[0]; - esem_signal(sem); - _sys_write(ends[1], "Hello!", 7, -1, 0); -} -static void test_shared_handle(void) { - struct evil_sem *sem = esem_new(0); - char buf[16]; - global_h = -1; - thread_create(FORK_NOREAP, shared_handle, sem); - esem_wait(sem); - - test(global_h >= 0); - test(_sys_read(global_h, buf, sizeof buf, 0) == 7); - test(!strcmp("Hello!", buf)); -} - -static void many_thread(void *arg) { - *(uint64_t*)arg += 10; -} -static void test_many_threads(void) { - uint64_t n = 0; - for (int i = 0; i < 10; i++) thread_create(0, many_thread, &n); - for (int i = 0; i < 10; i++) _sys_await(); - test(n == 100); -} - -void r_k_threads(void) { - run_test(test_basic_thread); - run_test(test_shared_handle); - run_test(test_many_threads); -} diff --git a/src/user/app/tests/libc/esemaphore.c b/src/user/app/tests/libc/esemaphore.c deleted file mode 100644 index f089f4f..0000000 --- a/src/user/app/tests/libc/esemaphore.c +++ /dev/null @@ -1,95 +0,0 @@ -#include "../tests.h" -#include <camellia/flags.h> -#include <camellia/syscalls.h> -#include <stdio.h> -#include <string.h> -#include <unistd.h> -#include <esemaphore.h> - -static void odd(hid_t out, struct evil_sem *sem1, struct evil_sem *sem2) { - _sys_write(out, "1", 1, -1, 0); - esem_signal(sem1); - - esem_wait(sem2); - _sys_write(out, "3", 1, -1, 0); - esem_signal(sem1); - - esem_wait(sem2); - _sys_write(out, "5", 1, -1, 0); - esem_signal(sem1); -} - -static void even(hid_t out, struct evil_sem *sem1, struct evil_sem *sem2) { - esem_wait(sem1); - _sys_write(out, "2", 1, -1, 0); - esem_signal(sem2); - - esem_wait(sem1); - _sys_write(out, "4", 1, -1, 0); - esem_signal(sem2); - - esem_wait(sem1); - _sys_write(out, "6", 1, -1, 0); - esem_signal(sem2); -} - -static void test_semaphore(void) { - struct evil_sem *sem1, *sem2; - hid_t pipe[2]; - test(_sys_pipe(pipe, 0) >= 0); - - if (!fork()) { - sem1 = esem_new(0); - sem2 = esem_new(0); - test(sem1 && sem2); - if (!fork()) { - odd(pipe[1], sem1, sem2); - exit(69); - } else { - even(pipe[1], sem1, sem2); - test(_sys_await() == 69); - } - esem_free(sem1); - esem_free(sem2); - - _sys_write(pipe[1], "|", 1, -1, 0); - - sem1 = esem_new(0); - sem2 = esem_new(0); - test(sem1 && sem2); - if (!fork()) { - even(pipe[1], sem1, sem2); - exit(69); - } else { - odd(pipe[1], sem1, sem2); - test(_sys_await() == 69); - _sys_await(); - } - esem_free(sem1); - esem_free(sem2); - - _sys_filicide(); - exit(0); - } else { - close(pipe[1]); - - char buf[16]; - size_t pos = 0; - for (;;) { - int ret = _sys_read(pipe[0], buf + pos, sizeof(buf) - pos, 0); - if (ret < 0) break; - pos += ret; - } - buf[pos] = '\0'; // idc about the "potential" overflow - if (strcmp(buf, "123456|123456")) { - printf("%s\n", buf); - test_fail(); - } - - _sys_await(); - } -} - -void r_libc_esemaphore(void) { - run_test(test_semaphore); -} diff --git a/src/user/app/tests/libc/setjmp.c b/src/user/app/tests/libc/setjmp.c deleted file mode 100644 index 0dded9d..0000000 --- a/src/user/app/tests/libc/setjmp.c +++ /dev/null @@ -1,31 +0,0 @@ -#include "../tests.h" -#include <stdbool.h> -#include <setjmp.h> - -static void test_setjmp(void) { - jmp_buf env; - volatile bool inner; - int val; - inner = false; - if (!(val = setjmp(env))) { - inner = true; - longjmp(env, 1234); - test(0); - } else { - test(val == 1234); - test(inner); - } - inner = false; - if (!(val = setjmp(env))) { - inner = true; - longjmp(env, 0); - test(0); - } else { - test(val == 1); - test(inner); - } -} - -void r_libc_setjmp(void) { - run_test(test_setjmp); -} diff --git a/src/user/app/tests/libc/string.c b/src/user/app/tests/libc/string.c deleted file mode 100644 index 6afe350..0000000 --- a/src/user/app/tests/libc/string.c +++ /dev/null @@ -1,124 +0,0 @@ -#include "../tests.h" -#include <stdbool.h> -#include <stdlib.h> -#include <string.h> - -static void test_memcmp(void) { - test(0 == memcmp("some", "thing", 0)); - test(0 != memcmp("some", "thing", 1)); - test(0 != memcmp("some", "thing", 4)); - - test(0 == memcmp("test", "tennis", 0)); - test(0 == memcmp("test", "tennis", 1)); - test(0 == memcmp("test", "tennis", 2)); - test(0 != memcmp("test", "tennis", 3)); - test(0 != memcmp("test", "tennis", 4)); - test(0 != memcmp("test", "tennis", 5)); - - test(0 > memcmp("foo", "moo", 4)); - test(0 < memcmp("moo", "foo", 4)); - test(0 > memcmp("555", "654", 3)); - test(0 < memcmp("654", "555", 3)); -} - -static bool memall(const unsigned char *s, unsigned char c, size_t n) { - for (size_t i = 0; i < n; i++) - if (s[i] != c) return false; - return true; -} - -static void test_memset(void) { - const size_t buflen = 4096; - void *buf = malloc(buflen); - test(buf); - for (int i = 0; i < 257; i++) { - memset(buf, i, buflen); - test(memall(buf, i & 0xff, buflen)); - } - free(buf); -} - -static void test_memmove(void) { - const int partsize = 64; - char buf[partsize * 3]; - for (int i = 0; i < partsize * 2; i++) { - memset(buf, 0, sizeof buf); - for (int j = 0; j < partsize; j++) buf[i + j] = j; - memmove(buf + partsize, buf + i, partsize); - for (int j = 0; j < partsize; j++) test(buf[partsize + j] == j); - } -} - -static void test_strcmp(void) { - test(0 == strcmp("string", "string")); - test(0 > strcmp("str", "string")); - test(0 < strcmp("string", "str")); - - test(0 != strcmp("stress", "string")); - - test(0 != strncmp("abc", "ab", 3)); - test(0 == strncmp("abc", "ab", 2)); -} - -static void test_strtol(void) { - char *end; - test(1234 == strtol("1234", NULL, 10)); - test(1234 == strtol("+1234", NULL, 10)); - test(-1234 == strtol("-1234", NULL, 10)); - - test(1234 == strtol("1234", &end, 10)); - test(!strcmp("", end)); - test(1234 == strtol(" 1234hello", &end, 10)); - test(!strcmp("hello", end)); - - test(1234 == strtol(" 1234hello", &end, 0)); - test(!strcmp("hello", end)); - test(0xCAF3 == strtol(" 0xCaF3hello", &end, 0)); - test(!strcmp("hello", end)); - test(01234 == strtol(" 01234hello", &end, 0)); - test(!strcmp("hello", end)); -} - -static void test_strspn(void) { - test(0 == strspn("", "1234")); - test(0 == strspn("asdf", "1234")); - test(0 == strspn("a2df", "1234")); - test(2 == strspn("42df", "1234")); - test(4 == strspn("4211", "1234")); - - test(0 == strcspn("", "1234")); - test(4 == strcspn("asdf", "1234")); - test(1 == strcspn("a2df", "1234")); -} - -static void test_strtok(void) { - const char *sep = " \t"; - { - char line[] = "LINE TO BE SEPARATED"; - test(!strcmp(strtok(line, sep), "LINE")); - test(!strcmp(strtok(NULL, sep), "TO")); - test(!strcmp(strtok(NULL, sep), "BE")); - test(!strcmp(strtok(NULL, sep), "SEPARATED")); - for (int i = 0; i < 4; i++) - test(strtok(NULL, sep) == NULL); - } - { - char line[] = " LINE TO\tBE \t SEPARATED "; - test(!strcmp(strtok(line, sep), "LINE")); - test(!strcmp(strtok(NULL, sep), "TO")); - test(!strcmp(strtok(NULL, sep), "BE")); - test(!strcmp(strtok(NULL, sep), "SEPARATED")); - for (int i = 0; i < 4; i++) - test(strtok(NULL, sep) == NULL); - } -} - -void r_libc_string(void) { - run_test(test_memcmp); - run_test(test_memset); - run_test(test_memmove); - run_test(test_strcmp); - run_test(test_strtol); - run_test(test_strspn); - run_test(test_strtok); -} diff --git a/src/user/app/tests/shared/printf.c b/src/user/app/tests/shared/printf.c deleted file mode 100644 index d8df48a..0000000 --- a/src/user/app/tests/shared/printf.c +++ /dev/null @@ -1,55 +0,0 @@ -#include "../tests.h" -#include <stdio.h> -#include <string.h> - -#pragma GCC diagnostic ignored "-Wformat-truncation" - -static void test_printf(void) { - char buf[64]; - memset(buf, '?', 64); - - /* test proper overflow handling in snprintf */ - test(13 == snprintf(buf, 15, "That's 0x%x", 0x1337)); - test(!memcmp(buf, "That's 0x1337\0??", 16)); - test(17 == snprintf(buf, 15, "%05x %05x %05x", 0, 0, 0)); - test(!memcmp(buf, "00000 00000 00\0?", 16)); - - /* all the other stuff */ - snprintf(buf, sizeof buf, "%010x", 0x1BABE); - test(!strcmp(buf, "000001babe")); - snprintf(buf, sizeof buf, "%10x", 0x1BABE); - test(!strcmp(buf, " 1babe")); - snprintf(buf, sizeof buf, "%10s", "hello"); - test(!strcmp(buf, " hello")); - - snprintf(buf, sizeof buf, "%s%%%s", "ab", "cd"); - test(!strcmp(buf, "ab%cd")); - - snprintf(buf, sizeof buf, "%05u,%05u", 1234, 56789); - test(!strcmp(buf, "01234,56789")); - - snprintf(buf, sizeof buf, "%5d,%5d", 123, 4567); - test(!strcmp(buf, " 123, 4567")); - snprintf(buf, sizeof buf, "%5d,%5d", -123, -4567); - test(!strcmp(buf, " -123,-4567")); - - snprintf(buf, sizeof buf, "%u,%d,%x", 0, 0, 0); - test(!strcmp(buf, "0,0,0")); - - /* precision */ - snprintf(buf, sizeof buf, "%5.2u,%5.2d,%5.2x", 0, 0, 0); - test(!strcmp(buf, " 00, 00, 00")); - snprintf(buf, sizeof buf, "%5.2u,%5.2d,%5.2x", 10, -10, 0x10); - test(!strcmp(buf, " 10, -10, 10")); - snprintf(buf, sizeof buf, "%5.3d", -1); - test(!strcmp(buf, " -001")); - snprintf(buf, sizeof buf, "%.5d", 123); - test(!strcmp(buf, "00123")); - - snprintf(buf, sizeof buf, "%.1s,%.10s,%.*s", "hello", "hello", 3, "hello"); - test(!strcmp(buf, "h,hello,hel")); -} - -void r_s_printf(void) { - run_test(test_printf); -} diff --git a/src/user/app/tests/shared/ringbuf.c b/src/user/app/tests/shared/ringbuf.c deleted file mode 100644 index d2a35a1..0000000 --- a/src/user/app/tests/shared/ringbuf.c +++ /dev/null @@ -1,49 +0,0 @@ -#include "../tests.h" -#include <shared/ring.h> -#include <string.h> - -static void test_ringbuf(void) { - char backbuf[16], cmpbuf[16]; - size_t num_read = 0, num_written = 0; - uint8_t c; - - ring_t r = {backbuf, 16, 0, 0}; - - /* aliasing */ - for (size_t i = 0; i < 16; i++) { - test(ring_used(&r) == 0); - test(ring_avail(&r) == 16); - ring_put(&r, "11 bytes...", 11); - test(ring_used(&r) == 11); - test(ring_avail(&r) == 5); - - memset(cmpbuf, 0, sizeof cmpbuf); - test(ring_get(&r, cmpbuf, 16) == 11); - test(memcmp(cmpbuf, "11 bytes...", 11) == 0); - } - - test(ring_used(&r) == 0); - for (size_t i = 0; i < 7; i++) - ring_put1b(&r, num_written++); - test(ring_used(&r) == 7); - for (size_t i = 0; i < 3; i++) { - ring_get(&r, &c, 1); - test(num_read++ == c); - } - test(ring_used(&r) == 4); - - for (size_t j = 0; j < 40; j++) { - for (size_t i = 0; i < 7; i++) - ring_put1b(&r, num_written++ & 0xff); - test(ring_used(&r) == 11); - for (size_t i = 0; i < 7; i++) { - ring_get(&r, &c, 1); - test((num_read++ & 0xff) == c); - } - test(ring_used(&r) == 4); - } -} - -void r_s_ringbuf(void) { - run_test(test_ringbuf); -} diff --git a/src/user/app/tests/stress.c b/src/user/app/tests/stress.c deleted file mode 100644 index 1ef018c..0000000 --- a/src/user/app/tests/stress.c +++ /dev/null @@ -1,28 +0,0 @@ -#include "tests.h" -#include <camellia/flags.h> -#include <camellia/syscalls.h> -#include <stdlib.h> -#include <unistd.h> - -static void run_forked(void (*fn)()) { - if (!fork()) { - fn(); - exit(0); - } else { - /* successful tests must return 0 - * TODO add a better fail msg */ - if (_sys_await() != 0) test_fail(); - } -} - - -static void stress_fork(void) { - for (size_t i = 0; i < 2048; i++) { - if (!fork()) exit(0); - _sys_await(); - } -} - -void stress_all(void) { - run_forked(stress_fork); -} diff --git a/src/user/app/tests/tests.c b/src/user/app/tests/tests.c deleted file mode 100644 index 5cba682..0000000 --- a/src/user/app/tests/tests.c +++ /dev/null @@ -1,68 +0,0 @@ -#include "tests.h" -#include <camellia/syscalls.h> -#include <unistd.h> - -__attribute__((visibility("hidden"))) -extern char __executable_start[]; - -FILE *fail_trig; - -void run_test(void (*fn)()) { - if (!fork()) { - fn(); - _sys_filicide(); - exit(0); - } else { - /* successful tests must return 0 */ - if (_sys_await() != 0) { - test_failf("%p, base %p", (void*)((void*)fn - (void*)__executable_start), __executable_start); - } - } -} - -int forkpipe(FILE **f, hid_t *h) { - hid_t ends[2]; - if (_sys_pipe(ends, 0) < 0) { - fprintf(stderr, "couldn't create pipe\n"); - exit(1); - } - int ret = fork(); - if (!ret) { - close(ends[0]); - *f = fdopen(ends[1], "w"); - *h = -1; - } else { - close(ends[1]); - *f = NULL; - *h = ends[0]; - } - return ret; -} - -int main(void) { - hid_t reader; - if (!forkpipe(&fail_trig, &reader)) { - r_k_miscsyscall(); - r_k_fs(); - r_k_fdlimit(); - r_k_misc(); - r_k_path(); - r_k_threads(); - r_libc_esemaphore(); - r_libc_setjmp(); - r_libc_string(); - r_s_printf(); - r_s_ringbuf(); - exit(0); - } else { - for (;;) { - char buf[128]; - long ret = _sys_read(reader, buf, sizeof buf, 0); - if (ret < 0) break; - printf("\033[31mFAIL\033[0m "); - fwrite(buf, ret, 1, stdout); - printf("\n"); - } - } - return 0; -} diff --git a/src/user/app/tests/tests.h b/src/user/app/tests/tests.h deleted file mode 100644 index 5037e1a..0000000 --- a/src/user/app/tests/tests.h +++ /dev/null @@ -1,37 +0,0 @@ -#pragma once -#include <camellia/syscalls.h> -#include <stdio.h> -#include <stdlib.h> - -#define TMPFILEPATH "/tmp/.test_internal" - -void run_test(void (*fn)()); - -void r_k_fdlimit(void); -void r_k_fs(void); -void r_k_misc(void); -void r_k_miscsyscall(void); -void r_k_path(void); -void r_k_threads(void); -void r_libc_esemaphore(void); -void r_libc_setjmp(void); -void r_libc_string(void); -void r_s_printf(void); -void r_s_ringbuf(void); - -extern FILE *fail_trig; - -int forkpipe(FILE **f, hid_t *h); - -#define argify(str) str, sizeof(str) - 1 -#define test_fail() do { \ - fprintf(fail_trig, "%s():%u", __func__, __LINE__); \ - fflush(fail_trig); \ - exit(0); \ -} while (0) -#define test_failf(fmt, ...) do { \ - fprintf(fail_trig, "%s():%u " fmt, __func__, __LINE__, __VA_ARGS__); \ - fflush(fail_trig); \ - exit(0); \ -} while (0) -#define test(cond) if (!(cond)) test_fail(); diff --git a/src/user/app/tmpfs/tmpfs.c b/src/user/app/tmpfs/tmpfs.c deleted file mode 100644 index 6d58790..0000000 --- a/src/user/app/tmpfs/tmpfs.c +++ /dev/null @@ -1,198 +0,0 @@ -#include <camellia/flags.h> -#include <camellia/fs/dir.h> -#include <camellia/fs/misc.h> -#include <camellia/fsutil.h> -#include <camellia/syscalls.h> -#include <errno.h> -#include <stdbool.h> -#include <stddef.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -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/user/app/vterm/draw.c b/src/user/app/vterm/draw.c deleted file mode 100644 index ee36a0f..0000000 --- a/src/user/app/vterm/draw.c +++ /dev/null @@ -1,17 +0,0 @@ -#include "vterm.h" -#include <camellia/execbuf.h> -#include <camellia/syscalls.h> -#include <string.h> - -struct framebuf fb; -struct rect dirty; - -void scroll(void) { - size_t row_len = fb.pitch * font.h; - memmove(fb.b, fb.b + row_len, fb.len - row_len); - memset(fb.b + fb.len - row_len, 0, row_len); - cursor.y--; - - dirty.x1 = 0; dirty.y1 = 0; - dirty.x2 = ~0; dirty.y2 = ~0; -} diff --git a/src/user/app/vterm/font.c b/src/user/app/vterm/font.c deleted file mode 100644 index 777b094..0000000 --- a/src/user/app/vterm/font.c +++ /dev/null @@ -1,76 +0,0 @@ -#include "vterm.h" -#include <err.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -struct psf2 font; -void *font_data; - -void font_load(const char *path) { - FILE *f = fopen(path, "r"); - if (!f) { - err(1, "couldn't open font \"%s\"", path); - } - - void *buf; - long buflen; - - fseek(f, 0, SEEK_END); - buflen = ftell(f); - if (buflen < 0) { - errx(1, "can't get the size of \"%s\"", path); - } - - buf = malloc(buflen); - if (!buf) { - err(1, "out of memory"); - } - - fseek(f, 0, SEEK_SET); - fread(buf, 1, buflen, f); - if (ferror(f)) { - err(1, "error reading font"); - } - fclose(f); - - if (!memcmp(buf, "\x72\xb5\x4a\x86", 4)) { - memcpy(&font, buf, sizeof font); - font_data = buf + font.glyph_offset; - } else if (!memcmp(buf, "\x36\x04", 2)) { - struct psf1 *hdr = buf; - font = (struct psf2){ - .glyph_amt = 256, - .glyph_size = hdr->h, - .h = hdr->h, - .w = 8, - }; - font_data = buf + 4; - } else { - errx(1, "invalid psf header"); - } -} - -void font_blit(uint32_t glyph, int x, int y) { - if (glyph >= font.glyph_amt) glyph = 0; - if (x < 0 || (x+1) * font.w >= fb.width || - y < 0 || (y+1) * font.h >= fb.height) - { - return; - } - - dirty_mark(&dirty, x * font.w, y * font.h); - dirty_mark(&dirty, (x+1) * font.w - 1, (y+1) * font.h - 1); - - char *bitmap = font_data + font.glyph_size * glyph; - for (size_t i = 0; i < font.w; i++) { - for (size_t j = 0; j < font.h; j++) { - size_t idx = j * font.w + i; - char byte = bitmap[idx / 8]; - byte >>= (7-(idx&7)); - byte &= 1; - *((uint32_t*)&fb.b[fb.pitch * (y * font.h + j) + 4 * (x * font.w + i)]) = byte * 0xB0B0B0; - } - } - return; -} diff --git a/src/user/app/vterm/vterm.c b/src/user/app/vterm/vterm.c deleted file mode 100644 index f365f6b..0000000 --- a/src/user/app/vterm/vterm.c +++ /dev/null @@ -1,72 +0,0 @@ -#include "vterm.h" -#include <camellia/syscalls.h> -#include <stdbool.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <camellia/compat.h> - -struct point cursor = {0}; - -void in_char(char c) { - switch (c) { - case '\n': - cursor.x = 0; - cursor.y++; - break; - case '\b': - if (cursor.x > 0) cursor.x--; - break; - case '\t': - /* rounds down to nearest multiple of 8 and adds 8 - = adding 1 and rounding up to the nearest multiple of 8 */ - cursor.x = (cursor.x & ~7) + 8; - break; - default: - font_blit(c, cursor.x, cursor.y); - cursor.x++; - } - - if (cursor.x * font.w >= fb.width) { - cursor.x = 0; - cursor.y++; - } - while ((cursor.y + 1) * font.h >= fb.height) scroll(); -} - -int main(void) { - if (fb_setup(&fb, "/kdev/video/") < 0) { - eprintf("fb_setup error"); - return 1; - } - font_load("/init/usr/share/fonts/spleen/spleen-8x16.psfu"); - - static char buf[512]; - struct ufs_request res; - while (!c0_fs_wait(buf, sizeof buf, &res)) { - switch (res.op) { - case VFSOP_OPEN: - // TODO check path - c0_fs_respond(NULL, 0, 0); - break; - - case VFSOP_WRITE: - if (res.flags) { - c0_fs_respond(NULL, -1, 0); - } else { - for (size_t i = 0; i < res.len; i++) - in_char(buf[i]); - dirty_flush(&dirty, &fb); - c0_fs_respond(NULL, res.len, 0); - } - break; - - default: - c0_fs_respond(NULL, -1, 0); - break; - } - } - - return 1; -} diff --git a/src/user/app/vterm/vterm.h b/src/user/app/vterm/vterm.h deleted file mode 100644 index 026e71a..0000000 --- a/src/user/app/vterm/vterm.h +++ /dev/null @@ -1,39 +0,0 @@ -#pragma once -#include <camellia/types.h> -#include <stdint.h> -#include <stdio.h> -#include <draw.h> - -#define eprintf(fmt, ...) fprintf(stderr, "vterm: "fmt"\n" __VA_OPT__(,) __VA_ARGS__) - - -struct psf1 { - uint16_t magic; - uint8_t mode; - uint8_t h; -} __attribute__((packed)); -struct psf2 { - uint32_t magic; - uint32_t version; - uint32_t glyph_offset; - uint32_t flags; - uint32_t glyph_amt; - uint32_t glyph_size; - uint32_t h; - uint32_t w; -} __attribute__((packed)); -extern struct psf2 font; -extern void *font_data; -void font_load(const char *path); -void font_blit(uint32_t glyph, int x, int y); - -extern struct framebuf fb; - -extern struct rect dirty; -void vdirty_mark(uint32_t x, uint32_t y); -void flush(void); -void scroll(void); - -struct point {uint32_t x, y;}; -extern struct point cursor; -void in_char(char c); |