ICANON support (still a bit rough)

This is a massive hack and I admit it.
This commit is contained in:
Kevin Lange 2013-07-27 22:01:08 -07:00
parent 40f0c41932
commit 720a62d6aa
4 changed files with 115 additions and 19 deletions

View File

@ -29,6 +29,7 @@ typedef struct pty {
char * canon_buffer; char * canon_buffer;
size_t canon_bufsize; size_t canon_bufsize;
size_t canon_buflen;
pid_t ct_proc; /* Controlling process (shell) */ pid_t ct_proc; /* Controlling process (shell) */
pid_t fg_proc; /* Foreground process (might also be shell) */ pid_t fg_proc; /* Foreground process (might also be shell) */
@ -37,6 +38,97 @@ typedef struct pty {
list_t * pty_list = NULL; 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) { int pty_ioctl(pty_t * pty, int request, void * argp) {
debug_print(WARNING, "Incoming IOCTL request %d", request); debug_print(WARNING, "Incoming IOCTL request %d", request);
switch (request) { switch (request) {
@ -64,11 +156,25 @@ int pty_ioctl(pty_t * pty, int request, void * argp) {
validate(argp); validate(argp);
memcpy(argp, &pty->tios, sizeof(struct termios)); memcpy(argp, &pty->tios, sizeof(struct termios));
return 0; 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 TCSETS:
case TCSETSW: case TCSETSW:
case TCSETSF: case TCSETSF:
if (!argp) return -1; if (!argp) return -1;
validate(argp); 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)); memcpy(&pty->tios, argp, sizeof(struct termios));
return 0; return 0;
default: default:
@ -77,24 +183,6 @@ int pty_ioctl(pty_t * pty, int request, void * argp) {
return -1; 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)) #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) { 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[VSUSP] = 26; /* ^Z */
pty->tios.c_cc[VTIME] = 0; 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; return pty;
} }

View File

@ -359,6 +359,8 @@ typedef struct {
void handle_signal(process_t *, signal_t *); void handle_signal(process_t *, signal_t *);
int send_signal(pid_t process, uint32_t signal);
#define USER_STACK_BOTTOM 0xAFF00000 #define USER_STACK_BOTTOM 0xAFF00000
#define USER_STACK_TOP 0xB0000000 #define USER_STACK_TOP 0xB0000000
#define SHM_START 0xB0000000 #define SHM_START 0xB0000000

View File

@ -422,7 +422,7 @@ static int uname(struct utsname * name) {
return 0; 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); process_t * receiver = process_from_pid(process);
if (!receiver) { if (!receiver) {

View File

@ -913,12 +913,14 @@ _done:
} }
exit(i); exit(i);
} else { } else {
tcsetpgrp(0, f);
int ret_code = 0; int ret_code = 0;
if (!nowait) { if (!nowait) {
child = f; child = f;
waitpid(f, &ret_code, 0); waitpid(f, &ret_code, 0);
child = 0; child = 0;
} }
tcsetpgrp(0, getpid());
free(cmd); free(cmd);
return ret_code; return ret_code;
} }