diff options
author | dzwdz | 2023-09-30 00:43:02 +0200 |
---|---|---|
committer | dzwdz | 2023-09-30 00:43:02 +0200 |
commit | 64d4330810a37dd9c41a82ae6cc420850ca1e7da (patch) | |
tree | f44cfcbb9ad364ceb144dc927ae9350e4cab5cd8 /src/cmd/init/driver/termcook.c | |
parent | eccd9d6d23f15a37ad118897d167dd18973242a1 (diff) |
user: rework terminal handling
Diffstat (limited to 'src/cmd/init/driver/termcook.c')
-rw-r--r-- | src/cmd/init/driver/termcook.c | 105 |
1 files changed, 87 insertions, 18 deletions
diff --git a/src/cmd/init/driver/termcook.c b/src/cmd/init/driver/termcook.c index a0da8c3..e0edcf5 100644 --- a/src/cmd/init/driver/termcook.c +++ b/src/cmd/init/driver/termcook.c @@ -1,10 +1,16 @@ #include "driver.h" +#include <camellia.h> #include <camellia/compat.h> +#include <camellia/flags.h> +#include <camellia/fs/dir.h> +#include <camellia/fs/misc.h> #include <camellia/syscalls.h> #include <err.h> #include <errno.h> #include <stdio.h> #include <stdlib.h> +#include <string.h> +#include <thread.h> #include <unistd.h> enum tstate { @@ -13,6 +19,19 @@ enum tstate { CSI, }; +enum handles { + Hroot, + Htokill, +}; + +typedef struct Tokill Tokill; +struct Tokill { + Tokill *next; + char path[]; /* NUL-terminated */ +}; +static Tokill *tokill = NULL; +static hid_t stdin_pipe[2]; + static void w_output(hid_t output, const char *buf, size_t len) { size_t pos = 0; while (pos < len) { @@ -22,10 +41,22 @@ static void w_output(hid_t output, const char *buf, size_t len) { } } -static void line_editor(hid_t input, hid_t output) { +static void send_intr(char *intr) { + for (Tokill *it = tokill; it; it = it->next) { + int fd = camellia_open(it->path, OPEN_WRITE); + // TODO remove dead from list + if (fd < 0) continue; + _sys_write(fd, intr, strlen(intr), -1, 0); + close(fd); + } +} + +static void line_editor(void *) { char readbuf[16], linebuf[256]; size_t linepos = 0; enum tstate state = Normal; + hid_t input = 0; + hid_t output = stdin_pipe[1]; for (;;) { int readlen = _sys_read(input, readbuf, sizeof readbuf, -1); if (readlen < 0) { @@ -46,7 +77,11 @@ static void line_editor(hid_t input, hid_t output) { } break; case 3: /* C-c */ - _sys_exit(1); + send_intr(""); + break; + case 0x1c: /* C-\ */ + send_intr("kill"); + break; case 4: /* EOT, C-d */ if (linepos > 0) { w_output(output, linebuf, linepos); @@ -88,23 +123,57 @@ static void line_editor(hid_t input, hid_t output) { } } +static void fs(void *) { + const size_t buflen = 1024; + char *buf = malloc(buflen); + int pipefd = stdin_pipe[0]; + if (!buf) err(1, "malloc"); + for (;;) { + struct ufs_request req; + hid_t reqh = ufs_wait(buf, buflen, &req); + int id = (int)req.id; + if (reqh < 0) errx(1, "ufs_wait error"); + + if (req.op == VFSOP_OPEN) { + if (strcmp(buf, "/") == 0) { + _sys_fs_respond(reqh, (void*)Hroot, 0, 0); + } else if (strcmp(buf, "/tokill") == 0) { + _sys_fs_respond(reqh, (void*)Htokill, 0, 0); + } else if (strcmp(buf, "/stdin") == 0) { + _sys_fs_respond(reqh, NULL, pipefd, FSR_DELEGATE); + } else { + _sys_fs_respond(reqh, NULL, -ENOENT, 0); + } + } else if (id == Hroot && (req.op == VFSOP_READ || req.op == VFSOP_GETSIZE)) { + struct dirbuild db; + char *target = req.op == VFSOP_READ ? buf : NULL; + dir_start(&db, req.offset, target, buflen); + dir_append(&db, "stdin"); + _sys_fs_respond(reqh, target, dir_finish(&db), 0); + } else if (id == Htokill && req.op == VFSOP_WRITE) { + // alternatively, pass fd? + Tokill *head = calloc(sizeof(Tokill) + req.len + 1, 1); + if (!head) { + _sys_fs_respond(reqh, NULL, -ENOMEM, 0); + continue; + } + memcpy(head->path, buf, req.len); + head->next = tokill; + tokill = head; + _sys_fs_respond(reqh, NULL, req.len, 0); + } else { + _sys_fs_respond(reqh, NULL, -ENOSYS, 0); + } + } +} + +// TODO turn into a separate binary void termcook(void) { - hid_t stdin_pipe[2] = {-1, -1}; if (_sys_pipe(stdin_pipe, 0) < 0) - return; + err(1, "pipe"); - 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()); + thread_create(0, fs, NULL); + thread_create(0, line_editor, NULL); + _sys_await(); + exit(1); } |