summaryrefslogtreecommitdiff
path: root/src/cmd/init/driver/termcook.c
diff options
context:
space:
mode:
authordzwdz2023-09-30 00:43:02 +0200
committerdzwdz2023-09-30 00:43:02 +0200
commit64d4330810a37dd9c41a82ae6cc420850ca1e7da (patch)
treef44cfcbb9ad364ceb144dc927ae9350e4cab5cd8 /src/cmd/init/driver/termcook.c
parenteccd9d6d23f15a37ad118897d167dd18973242a1 (diff)
user: rework terminal handling
Diffstat (limited to 'src/cmd/init/driver/termcook.c')
-rw-r--r--src/cmd/init/driver/termcook.c105
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);
}