From: Boria F. <bo...@bl...> - 2001-04-08 22:17:53
|
Hi here's a patch to restore tty state when uml exits. it's still meant more for viewing than for using, although it should be closer to the final version. known problems: several including using malloc/free. i also changed the number of arguments to open_chan{_pair}/close_chan{_pair} to accomodate flags. the story with stdio_console.c: because console_write is called early in boot, something has to be done to save state in console_setup, but because irqs don't work at that stage, what i did is only open the out channel (thus the addition of the NO_IN flag to open_chan_pair). the in channel is later opened via con_open when the system is fully up. the code assumes that there is no such io_chan in which in.fd refers to one tty and out.fd to another. the assumption avoids some problems with save_tty_state/restore_tty_state as tty state is saved on a per terminal basis and not per fd. also, i haven't tested the changes to ssl.c yet. anyway, here's the code. comments/suggestions very welcome tia, boria diff -ru uml_orig/arch/um/drivers/chan_kern.c uml/arch/um/drivers/chan_kern.c --- uml_orig/arch/um/drivers/chan_kern.c Sun Apr 8 20:21:10 2001 +++ uml/arch/um/drivers/chan_kern.c Sun Apr 8 22:25:42 2001 @@ -57,8 +57,8 @@ SA_INTERRUPT | SA_SHIRQ, "socket", data)); } -static int open_chan(struct chan *chan, int (*irq_setup)(int fd, void *data), - int input, void *data) +static int open_chan(struct chan *chan, int flags, + int (*irq_setup)(int fd, void *data), int input, void *data) { struct io_chan subchan; int err; @@ -72,18 +72,18 @@ err = open_pty(chan); break; case TTY: - err = open_tty(chan); + err = open_tty(chan, flags & SAVE_STATE); break; case PTS: err = open_pts(chan); break; case FD: - err = open_fd(chan); + err = open_fd(chan, flags & SAVE_STATE); break; case SOCKET: subchan = ((struct io_chan) PTS_IO_CHAN_INIT(NULL, -1, 1, INIT_STATIC)); - err = open_chan_pair(&subchan, irq_setup, data); + err = open_chan_pair(&subchan, 0, 0, irq_setup, data); if(err) return(err); chan->data.sock.pty = subchan.in.fd; err = open_socket(chan); @@ -102,35 +102,41 @@ return(0); } -int open_chan_pair(struct io_chan *chan, int (*irq_setup)(int fd, void *data), - void *data) +int open_chan_pair(struct io_chan *chan, int in_flags, int out_flags, + int (*irq_setup)(int fd, void *data), void *data) { int err; - err = open_chan(&chan->in, irq_setup, 1, data); - if(err) return(err); - if(chan->out.type != COPY) - err = open_chan(&chan->out, irq_setup, 0, data); + if(!(in_flags & NO_IN)){ + err = open_chan(&chan->in, in_flags, irq_setup, 1, data); + if(err) return(err); + } + if(chan->out.type != COPY && !(out_flags & NO_OUT)) + err = open_chan(&chan->out, out_flags, irq_setup, 0, data); return(err); } -static void close_chan(struct chan *chan) +static void close_chan(struct chan *chan, int flags) { switch(chan->type){ case XTERM: if(chan->data.xterm.pid != -1) kill(chan->data.xterm.pid, SIGKILL); break; + case FD: + case TTY: + if(flags & RESTORE_STATE) restore_tty_state(chan); + break; default: break; } } -void close_chan_pair(struct io_chan *chan) +void close_chan_pair(struct io_chan *chan, int in_flags, int out_flags) { - close_chan(&chan->in); - if(chan->out.type != COPY) - close_chan(&chan->out); + if(!(in_flags & NO_IN)) close_chan(&chan->in, in_flags); + if(chan->out.type != COPY && !(out_flags & NO_OUT)) + close_chan(&chan->out, out_flags); } int write_chan(struct io_chan *chan, const char *buf, int len) diff -ru uml_orig/arch/um/drivers/chan_user.c uml/arch/um/drivers/chan_user.c --- uml_orig/arch/um/drivers/chan_user.c Sun Apr 8 20:21:10 2001 +++ uml/arch/um/drivers/chan_user.c Sun Apr 8 22:35:44 2001 @@ -10,6 +10,7 @@ #include <errno.h> #include <fcntl.h> #include <termios.h> +#include <malloc.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/stat.h> @@ -42,8 +43,39 @@ return(1); } -int open_fd(struct chan *chan) +void save_tty_state(struct chan *chan) { + if((chan->type != TTY && !(chan->type == FD && isatty(chan->fd))) + || chan->data.tty.tty_state) + return; + + chan->data.tty.tty_state = malloc(sizeof(struct termios)); + if(!chan->data.tty.tty_state) + printk("malloc termios failed fd=%d\n", chan->fd); + else if(tcgetattr(chan->fd, chan->data.tty.tty_state) < 0){ + printk("tcgetattr failed fd=%d errno=%d\n", + chan->fd, errno); + free(chan->data.tty.tty_state); + chan->data.tty.tty_state = NULL; + } +} + + +void restore_tty_state(struct chan *chan) +{ + if(!chan->data.tty.tty_state) + return; + + if(tcsetattr(chan->fd, TCSADRAIN, chan->data.tty.tty_state) < 0){ + printk("tcsetattr failed fd=%d errno=%d\n", chan->fd, errno); + free(chan->data.tty.tty_state); + chan->data.tty.tty_state = NULL; + } +} + +int open_fd(struct chan *chan, int save_state) +{ + if(save_state) save_tty_state(chan); raw(chan->fd, 0); return(0); } @@ -148,13 +180,14 @@ return(0); } -int open_tty(struct chan *chan) +int open_tty(struct chan *chan, int save_state) { int fd; fd = open(chan->data.tty.dev, O_RDWR); if(fd < 0) return(-errno); chan->fd = fd; + if(save_state) save_tty_state(chan); if(chan->data.tty.raw) raw(fd, 1); return(0); } diff -ru uml_orig/arch/um/drivers/ssl.c uml/arch/um/drivers/ssl.c --- uml_orig/arch/um/drivers/ssl.c Sun Apr 8 20:21:10 2001 +++ uml/arch/um/drivers/ssl.c Sun Apr 8 22:37:03 2001 @@ -68,8 +68,8 @@ if(tty == NULL) panic("NULL tty in ssl_open"); private[line].tty = tty; tty->driver_data = &private[line]; - err = open_chan_pair(&private[line].chan, setup_ssl_irq, - &private[line]); + err = open_chan_pair(&private[line].chan, 0, SAVE_STATE, + setup_ssl_irq, &private[line]); up(&ssl_sem); if(err){ printk("Couldn't open serial line %d - errno = %d\n", line, @@ -289,7 +289,7 @@ int i; for(i=0;i<sizeof(private)/sizeof(private[0]);i++){ - close_chan_pair(&private[i].chan); + close_chan_pair(&private[i].chan, 0, RESTORE_STATE); } } diff -ru uml_orig/arch/um/drivers/stdio_console.c uml/arch/um/drivers/stdio_console.c --- uml_orig/arch/um/drivers/stdio_console.c Sun Apr 8 20:21:10 2001 +++ uml/arch/um/drivers/stdio_console.c Sun Apr 8 21:14:01 2001 @@ -59,7 +59,8 @@ int err; down(&stdio_sem); - err = open_chan_pair(&vts[line].chan, setup_console_irq, &vts[line]); + err = open_chan_pair(&vts[line].chan, 0, 0, setup_console_irq, + &vts[line]); if(err < 0){ printk("Failed to open virtual console %d, errno = %d\n", line, err); @@ -193,8 +194,19 @@ static int console_setup(struct console *co, char *options) { + open_chan_pair(&vts[co->index].chan, NO_IN, SAVE_STATE, NULL, NULL); return(0); } + +static void console_exit(void) +{ + int i; + + for(i = 0; i < MAX_TTYS; i++) + close_chan_pair(&vts[i].chan, 0, RESTORE_STATE); +} + +__exitcall(console_exit); static struct console stdiocons = { "tty", diff -ru uml_orig/arch/um/include/chan.h uml/arch/um/include/chan.h --- uml_orig/arch/um/include/chan.h Sun Apr 8 20:21:10 2001 +++ uml/arch/um/include/chan.h Sun Apr 8 22:24:01 2001 @@ -46,6 +46,16 @@ #define INIT_ALL (1) #define INIT_ONE (2) +/* Applies to both chan_open_pair() and chan_close_pair() */ +#define NO_IN 0x00000001 +#define NO_OUT 0x00000010 + +/* Applies only to chan_open{_pair}() */ +#define SAVE_STATE 0x00000100 + +/* Applies only to chan_close{_pair}() */ +#define RESTORE_STATE 0x00001000 + #define PTY_CHAN_INIT(announce, dev, raw, pri) \ { PTY, -1, 1, 0, pri, { pty: { announce, dev, raw } } } @@ -101,19 +111,23 @@ extern void tty_eof(void *tty_ptr, int *hung_up); extern void tty_interrupt(struct io_chan *chan, void *tty_ptr, int count); extern void tty_receive_char(void *tty_ptr, char ch); -extern int open_chan_pair(struct io_chan *chan, +extern int open_chan_pair(struct io_chan *chan, int in_flags, int out_flags, int (*irq_setup)(int fd, void *data), void *data); -extern int open_fd(struct chan *chan); +extern int open_fd(struct chan *chan, int save_state); extern int open_xterm(struct chan *chan); extern int open_pty(struct chan *chan); -extern int open_tty(struct chan *chan); +extern int open_tty(struct chan *chan, int save_state); extern int open_pts(struct chan *chan); extern int open_socket(struct chan *chan); extern int write_chan(struct io_chan *chan, const char *buf, int len); extern int parse_chan_pair(char *str, int device, struct io_chan *chan, int pri, struct chan_opts *opts); extern void accept_connection(struct chan *chan); -extern void close_chan_pair(struct io_chan *chan); +extern void close_chan_pair(struct io_chan *chan, int in_flags, + int out_flags); + +extern void save_tty_state(struct chan *chan); +extern void restore_tty_state(struct chan *chan); #endif diff -ru uml_orig/arch/um/kernel/trap_kern.c uml/arch/um/kernel/trap_kern.c --- uml_orig/arch/um/kernel/trap_kern.c Sun Apr 8 20:21:10 2001 +++ uml/arch/um/kernel/trap_kern.c Sun Apr 8 21:10:41 2001 @@ -185,7 +185,7 @@ void exit_debugger(void) { - close_chan_pair(&gdb_chan); + close_chan_pair(&gdb_chan, 0, 0); } __exitcall(exit_debugger); diff -ru uml_orig/arch/um/main.c uml/arch/um/main.c --- uml_orig/arch/um/main.c Sun Apr 8 20:21:10 2001 +++ uml/arch/um/main.c Sun Apr 8 22:18:45 2001 @@ -25,7 +25,6 @@ int main(int argc, char **argv, char **envp) { - struct termios tt; struct rlimit lim; int ret, i; char **new_argv; @@ -65,9 +64,6 @@ } stacksizelim = (lim.rlim_cur + PGD_BOUND - 1) & ~(PGD_BOUND - 1); get_profile_timer(); - if(isatty(0)) tcgetattr(0, &tt); - else if(isatty(1)) tcgetattr(1, &tt); - else tcgetattr(2, &tt); if((new_argv = malloc((argc + 1) * sizeof(char *))) == NULL){ perror("Mallocing argv"); @@ -86,14 +82,10 @@ /* Reboot */ if(ret){ printf("\n"); - tcsetattr(0, TCSADRAIN, &tt); execve(new_argv[0], new_argv, envp); perror("Failed to exec kernel"); ret = 1; } - if(isatty(0)) tcsetattr(0, TCSADRAIN, &tt); - else if(isatty(1)) tcsetattr(1, TCSADRAIN, &tt); - else tcsetattr(2, TCSADRAIN, &tt); printf("\n"); return(ret); } diff -ru uml_orig/arch/um/ptproxy/proxy.c uml/arch/um/ptproxy/proxy.c --- uml_orig/arch/um/ptproxy/proxy.c Sun Apr 8 20:21:10 2001 +++ uml/arch/um/ptproxy/proxy.c Sun Apr 8 21:11:00 2001 @@ -207,7 +207,7 @@ { int err, slave, child; - err = open_chan_pair(&gdb_chan, NULL, NULL); + err = open_chan_pair(&gdb_chan, 0, 0, NULL, NULL); if(err) return(err); slave = CHAN_OUT_FD(gdb_chan); if((child = fork()) == 0){ |
From: Jeff D. <jd...@ka...> - 2001-04-09 15:16:02
|
bo...@bl... said: > the story with stdio_console.c: because console_write is called early > in boot, something has to be done to save state in console_setup, but > because irqs don't work at that stage, what i did is only open the out > channel (thus the addition of the NO_IN flag to open_chan_pair). the > in channel is later opened via con_open when the system is fully up. This is ugly. How about introducing a new channel type which would be an output-only, no state-saving console? The main console would be initialized to it, and switched over to the current input/output, state-saving channel when the kernel opens the console so that init can talk to it. Jeff |
From: Boria F. <bo...@bl...> - 2001-04-09 16:36:38
|
On Mon, Apr 09, 2001 at 11:28:20AM -0500, Jeff Dike wrote: > This is ugly. How about introducing a new channel type which would be an > output-only, no state-saving console? The main console would be initialized Hi Perhaps i understood you wrong, but having a new channel type would IMHO introduce several problems. Maybe the flags thing can be avoided in some other way. What's the difference between only opening an out channel and having a separate output-only channel type? Also, the channel type the console uses can be changed from the command line with the con0= switch - my patch will still work for that case. Initialising the console to an output-only channel would introduce problems with parse_chan_pair. The new channel type would have to "embed" the true physical channel, be it a TTY or an FD or an xterm. The saving of state has to go _before_ any call to write_console is made (and that means in console_setup) , so it can't be a no state-saving channel. very open to suggestions. TIA, boria |