From 720a62d6aac571128054a50b863ff93ec91104f7 Mon Sep 17 00:00:00 2001 From: Kevin Lange Date: Sat, 27 Jul 2013 22:01:08 -0700 Subject: [PATCH] ICANON support (still a bit rough) This is a massive hack and I admit it. --- kernel/fs/tty.c | 128 ++++++++++++++++++++++++++++++++++------ kernel/include/system.h | 2 + kernel/sys/syscall.c | 2 +- userspace/core/sh.c | 2 + 4 files changed, 115 insertions(+), 19 deletions(-) diff --git a/kernel/fs/tty.c b/kernel/fs/tty.c index 7a5c6973..6d8e360c 100644 --- a/kernel/fs/tty.c +++ b/kernel/fs/tty.c @@ -29,6 +29,7 @@ typedef struct pty { char * canon_buffer; size_t canon_bufsize; + size_t canon_buflen; pid_t ct_proc; /* Controlling process (shell) */ pid_t fg_proc; /* Foreground process (might also be shell) */ @@ -37,6 +38,97 @@ typedef struct pty { list_t * pty_list = NULL; +#define IN(character) ring_buffer_write(pty->in, 1, (uint8_t *)&(character)) +#define OUT(character) ring_buffer_write(pty->out, 1, (uint8_t *)&(character)) + +static void dump_input_buffer(pty_t * pty) { + char * c = pty->canon_buffer; + while (pty->canon_buflen > 0) { + IN(*c); + pty->canon_buflen--; + c++; + } +} + +static void output_process(pty_t * pty, uint8_t c) { + if (c == '\n' && (pty->tios.c_oflag & ONLCR)) { + uint8_t d = '\r'; + OUT(d); + } + OUT(c); +} + +static void input_process(pty_t * pty, uint8_t c) { + if (pty->tios.c_lflag & ICANON) { + debug_print(INFO, "Processing for character %d in canon mode", c); + if (c == pty->tios.c_cc[VKILL]) { + while (pty->canon_buflen > 0) { + pty->canon_buflen--; + pty->canon_buffer[pty->canon_buflen] = '\0'; + if (pty->tios.c_lflag & ECHO) { + output_process(pty, '\010'); + output_process(pty, ' '); + output_process(pty, '\010'); + } + } + return; + } + if (c == pty->tios.c_cc[VERASE]) { + /* Backspace */ + if (pty->canon_buflen > 0) { + pty->canon_buflen--; + pty->canon_buffer[pty->canon_buflen] = '\0'; + if (pty->tios.c_lflag & ECHO) { + output_process(pty, '\010'); + output_process(pty, ' '); + output_process(pty, '\010'); + } + } + return; + } + if (c == pty->tios.c_cc[VINTR]) { + if (pty->tios.c_lflag & ECHO) { + output_process(pty, '^'); + output_process(pty, '@' + c); + output_process(pty, '\n'); + } + if (pty->fg_proc) { + send_signal(pty->fg_proc, SIGINT); + } + return; + } + if (c == pty->tios.c_cc[VQUIT]) { + if (pty->tios.c_lflag & ECHO) { + output_process(pty, '^'); + output_process(pty, '@' + c); + output_process(pty, '\n'); + } + if (pty->fg_proc) { + send_signal(pty->fg_proc, SIGQUIT); + } + return; + } + pty->canon_buffer[pty->canon_buflen] = c; + if (pty->tios.c_lflag & ECHO) { + output_process(pty, c); + } + if (pty->canon_buffer[pty->canon_buflen] == '\n') { + pty->canon_buflen++; + dump_input_buffer(pty); + return; + } + if (pty->canon_buflen == pty->canon_bufsize) { + dump_input_buffer(pty); + return; + } + pty->canon_buflen++; + return; + } else if (pty->tios.c_lflag & ECHO) { + output_process(pty, c); + } + IN(c); +} + int pty_ioctl(pty_t * pty, int request, void * argp) { debug_print(WARNING, "Incoming IOCTL request %d", request); switch (request) { @@ -64,11 +156,25 @@ int pty_ioctl(pty_t * pty, int request, void * argp) { validate(argp); memcpy(argp, &pty->tios, sizeof(struct termios)); return 0; + case TIOCSPGRP: + if (!argp) return -1; + validate(argp); + pty->fg_proc = *(pid_t *)argp; + return 0; + case TIOCGPGRP: + if (!argp) return -1; + validate(argp); + *(pid_t *)argp = pty->fg_proc; + return 0; case TCSETS: case TCSETSW: case TCSETSF: if (!argp) return -1; validate(argp); + if (!(((struct termios *)argp)->c_lflag & ICANON) && (pty->tios.c_lflag & ICANON)) { + /* Switch out of canonical mode, the dump the input buffer */ + + } memcpy(&pty->tios, argp, sizeof(struct termios)); return 0; default: @@ -77,24 +183,6 @@ int pty_ioctl(pty_t * pty, int request, void * argp) { return -1; } -#define IN(character) ring_buffer_write(pty->in, 1, (uint8_t *)&(character)) -#define OUT(character) ring_buffer_write(pty->out, 1, (uint8_t *)&(character)) - -static void output_process(pty_t * pty, uint8_t c) { - if (c == '\n' && (pty->tios.c_oflag & ONLCR)) { - uint8_t d = '\r'; - OUT(d); - } - OUT(c); -} - -static void input_process(pty_t * pty, uint8_t c) { - if (pty->tios.c_lflag & ECHO) { - output_process(pty, c); - } - IN(c); -} - #define MIN(a,b) ((a) < (b) ? (a) : (b)) uint32_t read_pty_master(fs_node_t * node, uint32_t offset, uint32_t size, uint8_t *buffer) { @@ -269,6 +357,10 @@ pty_t * pty_new(struct winsize * size) { pty->tios.c_cc[VSUSP] = 26; /* ^Z */ pty->tios.c_cc[VTIME] = 0; + pty->canon_buffer = malloc(TTY_BUFFER_SIZE); + pty->canon_bufsize = TTY_BUFFER_SIZE; + pty->canon_buflen = 0; + return pty; } diff --git a/kernel/include/system.h b/kernel/include/system.h index eca066d3..9517e3bd 100644 --- a/kernel/include/system.h +++ b/kernel/include/system.h @@ -359,6 +359,8 @@ typedef struct { void handle_signal(process_t *, signal_t *); +int send_signal(pid_t process, uint32_t signal); + #define USER_STACK_BOTTOM 0xAFF00000 #define USER_STACK_TOP 0xB0000000 #define SHM_START 0xB0000000 diff --git a/kernel/sys/syscall.c b/kernel/sys/syscall.c index dfec845d..346790e9 100644 --- a/kernel/sys/syscall.c +++ b/kernel/sys/syscall.c @@ -422,7 +422,7 @@ static int uname(struct utsname * name) { return 0; } -static int send_signal(pid_t process, uint32_t signal) { +int send_signal(pid_t process, uint32_t signal) { process_t * receiver = process_from_pid(process); if (!receiver) { diff --git a/userspace/core/sh.c b/userspace/core/sh.c index a8c29b48..d16478de 100644 --- a/userspace/core/sh.c +++ b/userspace/core/sh.c @@ -913,12 +913,14 @@ _done: } exit(i); } else { + tcsetpgrp(0, f); int ret_code = 0; if (!nowait) { child = f; waitpid(f, &ret_code, 0); child = 0; } + tcsetpgrp(0, getpid()); free(cmd); return ret_code; }