user: rework terminal handling
This commit is contained in:
parent
eccd9d6d23
commit
64d4330810
|
@ -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) {
|
|||
}
|
||||
}
|
||||
|
||||
void termcook(void) {
|
||||
hid_t stdin_pipe[2] = {-1, -1};
|
||||
if (_sys_pipe(stdin_pipe, 0) < 0)
|
||||
return;
|
||||
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 (!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 (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);
|
||||
}
|
||||
}
|
||||
if (!fork()) {
|
||||
close(stdin_pipe[0]);
|
||||
line_editor(0, stdin_pipe[1]);
|
||||
exit(0);
|
||||
}
|
||||
exit(_sys_await());
|
||||
}
|
||||
|
||||
// TODO turn into a separate binary
|
||||
void termcook(void) {
|
||||
if (_sys_pipe(stdin_pipe, 0) < 0)
|
||||
err(1, "pipe");
|
||||
|
||||
thread_create(0, fs, NULL);
|
||||
thread_create(0, line_editor, NULL);
|
||||
_sys_await();
|
||||
exit(1);
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include "driver/driver.h"
|
||||
#include <camellia.h>
|
||||
#include <camellia/compat.h>
|
||||
#include <camellia/flags.h>
|
||||
#include <camellia/fs/misc.h>
|
||||
|
@ -12,9 +13,9 @@
|
|||
|
||||
void redirect(const char *exe, const char *out, const char *in) {
|
||||
if (!fork()) {
|
||||
static char title[128];
|
||||
snprintf(title, sizeof title, "sh >%s", out);
|
||||
setproctitle(title);
|
||||
static char buf[128];
|
||||
snprintf(buf, sizeof buf, "sh >%s", out);
|
||||
setproctitle(buf);
|
||||
|
||||
if (!freopen(out, "a+", stderr)) {
|
||||
fprintf(stdout, "couldn't open %s\n", out);
|
||||
|
@ -25,17 +26,44 @@ void redirect(const char *exe, const char *out, const char *in) {
|
|||
if (!freopen(in, "r", stdin))
|
||||
err(1, "couldn't open %s", in);
|
||||
|
||||
// TODO move to /dev/term/
|
||||
MOUNT_AT("/") {
|
||||
fs_dirinject2((const char*[]){ "/term/", NULL });
|
||||
}
|
||||
MOUNT_AT("/term/") {
|
||||
termcook();
|
||||
}
|
||||
int fd = camellia_open("/term/stdin", OPEN_READ);
|
||||
if (fd < 0) {
|
||||
err(1, "open /term/stdin");
|
||||
}
|
||||
_sys_dup(fd, 0, 0);
|
||||
close(fd);
|
||||
|
||||
for (;;) {
|
||||
if (!fork()) {
|
||||
int pid = fork();
|
||||
if (pid == 0) {
|
||||
// TODO shadow over /term/tokill, as it's an easy thing to miss when sandboxing
|
||||
const char *argv[] = {exe, NULL};
|
||||
termcook();
|
||||
execv(exe, (void*)argv);
|
||||
fprintf(stderr, "init: couldn't start %s\n", exe);
|
||||
exit(1);
|
||||
} else {
|
||||
int len, fd;
|
||||
fd = camellia_open("/term/tokill", OPEN_WRITE);
|
||||
if (fd < 0) {
|
||||
_sys_intr("kill", 4);
|
||||
err(1, "open /term/tokill");
|
||||
}
|
||||
len = snprintf(buf, sizeof buf, "/proc/%d/intrdown", pid);
|
||||
_sys_write(fd, buf, len, 0, 0);
|
||||
len = snprintf(buf, sizeof buf, "/proc/%d/intr", pid);
|
||||
_sys_write(fd, buf, len, 0, 0);
|
||||
close(fd);
|
||||
|
||||
_sys_await();
|
||||
_sys_sleep(1000);
|
||||
}
|
||||
_sys_await();
|
||||
_sys_intr(NULL, 0);
|
||||
_sys_sleep(1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -141,6 +141,7 @@ static void run(char *cmd) {
|
|||
int main(int argc, char **argv) {
|
||||
static char buf[256];
|
||||
FILE *f = stdin;
|
||||
intr_set(NULL);
|
||||
|
||||
if (argc > 1) {
|
||||
f = fopen(argv[1], "r");
|
||||
|
|
Loading…
Reference in New Issue