libbb: consolidate the code to set termios unbuffered mode
No binary (build failed)
—
(log yok)
| @@ -354,7 +354,7 @@ struct globals { | |
| #if ENABLE_FEATURE_VI_USE_SIGNALS | |
| sigjmp_buf restart; // catch_sig() | |
| #endif | |
| - | struct termios term_orig, term_vi; // remember what the cooked mode was |
| + | struct termios term_orig; // remember what the cooked mode was |
| #if ENABLE_FEATURE_VI_COLON | |
| char *initial_cmds[3]; // currently 2 entries, NULL terminated | |
| #endif | |
| @@ -462,7 +462,6 @@ struct globals { | |
| #define context_end (G.context_end ) | |
| #define restart (G.restart ) | |
| #define term_orig (G.term_orig ) | |
| - | #define term_vi (G.term_vi ) |
| #define initial_cmds (G.initial_cmds ) | |
| #define readbuffer (G.readbuffer ) | |
| #define scr_out_buf (G.scr_out_buf ) | |
| @@ -2731,15 +2730,9 @@ static char *swap_context(char *p) // goto new context for '' command make this | |
| //----- Set terminal attributes -------------------------------- | |
| static void rawmode(void) | |
| { | |
| - | tcgetattr(0, &term_orig); |
| - | term_vi = term_orig; |
| - | term_vi.c_lflag &= (~ICANON & ~ECHO); // leave ISIG on - allow intr's |
| - | term_vi.c_iflag &= (~IXON & ~ICRNL); |
| - | term_vi.c_oflag &= (~ONLCR); |
| - | term_vi.c_cc[VMIN] = 1; |
| - | term_vi.c_cc[VTIME] = 0; |
| - | erase_char = term_vi.c_cc[VERASE]; |
| - | tcsetattr_stdin_TCSANOW(&term_vi); |
| + | // no TERMIOS_CLEAR_ISIG: leave ISIG on - allow signals |
| + | set_termios_to_raw(STDIN_FILENO, &term_orig, TERMIOS_RAW_CRNL); |
| + | erase_char = term_orig.c_cc[VERASE]; |
| } | |
| static void cookmode(void) | |
| @@ -1438,6 +1438,10 @@ int get_terminal_width_height(int fd, unsigned *width, unsigned *height) FAST_FU | |
| int get_terminal_width(int fd) FAST_FUNC; | |
| int tcsetattr_stdin_TCSANOW(const struct termios *tp) FAST_FUNC; | |
| + | #define TERMIOS_CLEAR_ISIG (1 << 0) |
| + | #define TERMIOS_RAW_CRNL (1 << 1) |
| + | #define TERMIOS_RAW_INPUT (1 << 2) |
| + | int set_termios_to_raw(int fd, struct termios *oldterm, int flags) FAST_FUNC; |
| /* NB: "unsigned request" is crucial! "int request" will break some arches! */ | |
| int ioctl_or_perror(int fd, unsigned request, void *argp, const char *fmt,...) __attribute__ ((format (printf, 4, 5))) FAST_FUNC; | |
| @@ -2325,7 +2325,7 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman | |
| /* ~ECHO, ~ECHONL: turn off echoing, including newline echoing */ | |
| /* ~ISIG: turn off INTR (ctrl-C), QUIT, SUSP */ | |
| new_settings.c_lflag &= ~(ICANON | ECHO | ECHONL | ISIG); | |
| - | /* reads would block only if < 1 char is available */ |
| + | /* reads will block only if < 1 char is available */ |
| new_settings.c_cc[VMIN] = 1; | |
| /* no timeout (reads block forever) */ | |
| new_settings.c_cc[VTIME] = 0; | |
| @@ -311,6 +311,43 @@ int FAST_FUNC tcsetattr_stdin_TCSANOW(const struct termios *tp) | |
| return tcsetattr(STDIN_FILENO, TCSANOW, tp); | |
| } | |
| + | int FAST_FUNC set_termios_to_raw(int fd, struct termios *oldterm, int flags) |
| + | { |
| + | //TODO: lineedit, microcom and less might be adapted to use this too: |
| + | // grep for "tcsetattr" |
| + | |
| + | struct termios newterm; |
| + | |
| + | tcgetattr(fd, oldterm); |
| + | newterm = *oldterm; |
| + | |
| + | /* Turn off buffered input (ICANON) |
| + | * Turn off echoing (ECHO) |
| + | * and separate echoing of newline (ECHONL, normally off anyway) |
| + | */ |
| + | newterm.c_lflag &= ~(ICANON | ECHO | ECHONL); |
| + | if (flags & TERMIOS_CLEAR_ISIG) { |
| + | /* dont recognize INT/QUIT/SUSP chars */ |
| + | newterm.c_lflag &= ~ISIG; |
| + | } |
| + | /* reads will block only if < 1 char is available */ |
| + | newterm.c_cc[VMIN] = 1; |
| + | /* no timeout (reads block forever) */ |
| + | newterm.c_cc[VTIME] = 0; |
| + | if (flags & TERMIOS_RAW_CRNL) { |
| + | /* dont convert CR to NL on input */ |
| + | newterm.c_iflag &= ~(IXON | ICRNL); |
| + | /* dont convert NL to CR on output */ |
| + | newterm.c_oflag &= ~(ONLCR); |
| + | } |
| + | if (flags & TERMIOS_RAW_INPUT) { |
| + | /* dont convert anything on input */ |
| + | newterm.c_iflag &= ~(BRKINT|INLCR|ICRNL|IXON|IXOFF|IUCLC|IXANY|IMAXBEL); |
| + | } |
| + | |
| + | return tcsetattr(fd, TCSANOW, &newterm); |
| + | } |
| + | |
| pid_t FAST_FUNC safe_waitpid(pid_t pid, int *wstat, int options) | |
| { | |
| pid_t r; | |
| @@ -316,7 +316,7 @@ static void init_tty_attrs(int speed) | |
| /* non-raw output; add CR to each NL */ | |
| G.tty_attrs.c_oflag = OPOST | ONLCR; | |
| - | /* reads would block only if < 1 char is available */ |
| + | /* reads will block only if < 1 char is available */ |
| G.tty_attrs.c_cc[VMIN] = 1; | |
| /* no timeout (reads block forever) */ | |
| G.tty_attrs.c_cc[VTIME] = 0; | |
| @@ -105,12 +105,12 @@ int vlock_main(int argc UNUSED_PARAM, char **argv) | |
| ioctl(STDIN_FILENO, VT_SETMODE, &vtm); | |
| #endif | |
| + | //TODO: use set_termios_to_raw() |
| tcgetattr(STDIN_FILENO, &oterm); | |
| term = oterm; | |
| - | term.c_iflag &= ~BRKINT; |
| - | term.c_iflag |= IGNBRK; |
| - | term.c_lflag &= ~ISIG; |
| - | term.c_lflag &= ~(ECHO | ECHOCTL); |
| + | term.c_iflag |= IGNBRK; /* ignore serial break (why? VTs don't have breaks, right?) */ |
| + | term.c_iflag &= ~BRKINT; /* redundant? "dont translate break to SIGINT" */ |
| + | term.c_lflag &= ~(ISIG | ECHO | ECHOCTL); /* ignore ^C ^Z, echo off */ |
| tcsetattr_stdin_TCSANOW(&term); | |
| while (1) { | |
| @@ -213,6 +213,7 @@ int chat_main(int argc UNUSED_PARAM, char **argv) | |
| , signal_handler); | |
| #if ENABLE_FEATURE_CHAT_TTY_HIFI | |
| + | //TODO: use set_termios_to_raw() |
| tcgetattr(STDIN_FILENO, &tio); | |
| tio0 = tio; | |
| cfmakeraw(&tio); | |
| @@ -363,7 +363,6 @@ int conspy_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | |
| int conspy_main(int argc UNUSED_PARAM, char **argv) | |
| { | |
| char tty_name[sizeof(DEV_TTY "NN")]; | |
| - | struct termios termbuf; |
| unsigned opts; | |
| unsigned ttynum; | |
| int poll_timeout_ms; | |
| @@ -414,16 +413,14 @@ int conspy_main(int argc UNUSED_PARAM, char **argv) | |
| bb_signals(BB_FATAL_SIGS, cleanup); | |
| - | // All characters must be passed through to us unaltered |
| G.kbd_fd = xopen(CURRENT_TTY, O_RDONLY); | |
| - | tcgetattr(G.kbd_fd, &G.term_orig); |
| - | termbuf = G.term_orig; |
| - | termbuf.c_iflag &= ~(BRKINT|INLCR|ICRNL|IXON|IXOFF|IUCLC|IXANY|IMAXBEL); |
| - | //termbuf.c_oflag &= ~(OPOST); - no, we still want \n -> \r\n |
| - | termbuf.c_lflag &= ~(ISIG|ICANON|ECHO); |
| - | termbuf.c_cc[VMIN] = 1; |
| - | termbuf.c_cc[VTIME] = 0; |
| - | tcsetattr(G.kbd_fd, TCSANOW, &termbuf); |
| + | |
| + | // All characters must be passed through to us unaltered |
| + | set_termios_to_raw(G.kbd_fd, &G.term_orig, 0 |
| + | | TERMIOS_CLEAR_ISIG // no signals on ^C ^Z etc |
| + | | TERMIOS_RAW_INPUT // turn off all input conversions |
| + | ); |
| + | //Note: termios.c_oflag &= ~(OPOST); - no, we still want \n -> \r\n |
| poll_timeout_ms = 250; | |
| while (1) { | |
| @@ -33,6 +33,7 @@ | |
| // set raw tty mode | |
| static void xget1(int fd, struct termios *t, struct termios *oldt) | |
| { | |
| + | //TODO: use set_termios_to_raw() |
| tcgetattr(fd, oldt); | |
| *t = *oldt; | |
| cfmakeraw(t); | |
| @@ -263,6 +263,7 @@ int rx_main(int argc UNUSED_PARAM, char **argv) | |
| termios_err = tcgetattr(read_fd, &tty); | |
| if (termios_err == 0) { | |
| + | //TODO: use set_termios_to_raw() |
| orig_tty = tty; | |
| cfmakeraw(&tty); | |
| tcsetattr(read_fd, TCSAFLUSH, &tty); | |
| @@ -683,7 +683,6 @@ int powertop_main(int UNUSED_PARAM argc, char UNUSED_PARAM **argv) | |
| ullong cur_duration[MAX_CSTATE_COUNT]; | |
| char cstate_lines[MAX_CSTATE_COUNT + 2][64]; | |
| #if ENABLE_FEATURE_USE_TERMIOS | |
| - | struct termios new_settings; |
| struct pollfd pfd[1]; | |
| pfd[0].fd = 0; | |
| @@ -707,14 +706,11 @@ int powertop_main(int UNUSED_PARAM argc, char UNUSED_PARAM **argv) | |
| puts("Collecting data for "DEFAULT_SLEEP_STR" seconds"); | |
| #if ENABLE_FEATURE_USE_TERMIOS | |
| - | tcgetattr(0, (void *)&G.init_settings); |
| - | memcpy(&new_settings, &G.init_settings, sizeof(new_settings)); |
| - | /* Turn on unbuffered input, turn off echoing */ |
| - | new_settings.c_lflag &= ~(ISIG | ICANON | ECHO | ECHONL); |
| + | /* Turn on unbuffered input; turn off echoing, ^C ^Z etc */ |
| + | set_termios_to_raw(STDIN_FILENO, &G.init_settings, TERMIOS_CLEAR_ISIG); |
| + | bb_signals(BB_FATAL_SIGS, sig_handler); |
| /* So we don't forget to reset term settings */ | |
| atexit(reset_term); | |
| - | bb_signals(BB_FATAL_SIGS, sig_handler); |
| - | tcsetattr_stdin_TCSANOW(&new_settings); |
| #endif | |
| /* Collect initial data */ | |
| @@ -1089,9 +1089,6 @@ int top_main(int argc UNUSED_PARAM, char **argv) | |
| unsigned interval; | |
| char *str_interval, *str_iterations; | |
| unsigned scan_mask = TOP_MASK; | |
| - | #if ENABLE_FEATURE_USE_TERMIOS |
| - | struct termios new_settings; |
| - | #endif |
| INIT_G(); | |
| @@ -1141,11 +1138,8 @@ int top_main(int argc UNUSED_PARAM, char **argv) | |
| } | |
| #if ENABLE_FEATURE_USE_TERMIOS | |
| else { | |
| - | tcgetattr(0, (void *) &initial_settings); |
| - | memcpy(&new_settings, &initial_settings, sizeof(new_settings)); |
| - | /* unbuffered input, turn off echo */ |
| - | new_settings.c_lflag &= ~(ISIG | ICANON | ECHO | ECHONL); |
| - | tcsetattr_stdin_TCSANOW(&new_settings); |
| + | /* Turn on unbuffered input; turn off echoing, ^C ^Z etc */ |
| + | set_termios_to_raw(STDIN_FILENO, &initial_settings, TERMIOS_CLEAR_ISIG); |
| } | |
| bb_signals(BB_FATAL_SIGS, sig_catcher); | |
| @@ -143,7 +143,7 @@ shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val), | |
| // Setting it to more than 1 breaks poll(): | |
| // it blocks even if there's data. !?? | |
| //tty.c_cc[VMIN] = nchars < 256 ? nchars : 255; | |
| - | /* reads would block only if < 1 char is available */ |
| + | /* reads will block only if < 1 char is available */ |
| tty.c_cc[VMIN] = 1; | |
| /* no timeout (reads block forever) */ | |
| tty.c_cc[VTIME] = 0; | |
| @@ -1226,7 +1226,6 @@ void check2(void); | |
| int fsck_minix_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | |
| int fsck_minix_main(int argc UNUSED_PARAM, char **argv) | |
| { | |
| - | struct termios tmp; |
| int retcode = 0; | |
| xfunc_error_retval = 8; | |
| @@ -1271,10 +1270,7 @@ int fsck_minix_main(int argc UNUSED_PARAM, char **argv) | |
| read_tables(); | |
| if (OPT_manual) { | |
| - | tcgetattr(0, &sv_termios); |
| - | tmp = sv_termios; |
| - | tmp.c_lflag &= ~(ICANON | ECHO); |
| - | tcsetattr_stdin_TCSANOW(&tmp); |
| + | set_termios_to_raw(STDIN_FILENO, &sv_termios, 0); |
| termios_set = 1; | |
| } | |
| @@ -43,7 +43,6 @@ struct globals { | |
| unsigned terminal_width; | |
| unsigned terminal_height; | |
| struct termios initial_settings; | |
| - | struct termios new_settings; |
| } FIX_ALIASING; | |
| #define G (*(struct globals*)bb_common_bufsiz1) | |
| #define INIT_G() do { setup_common_bufsiz(); } while (0) | |
| @@ -101,12 +100,9 @@ int more_main(int argc UNUSED_PARAM, char **argv) | |
| return bb_cat(argv); | |
| G.tty_fileno = fileno(tty); | |
| - | tcgetattr(G.tty_fileno, &G.initial_settings); |
| - | G.new_settings = G.initial_settings; |
| - | G.new_settings.c_lflag &= ~(ICANON | ECHO); |
| - | G.new_settings.c_cc[VMIN] = 1; |
| - | G.new_settings.c_cc[VTIME] = 0; |
| - | tcsetattr_tty_TCSANOW(&G.new_settings); |
| + | |
| + | /* Turn on unbuffered input; turn off echoing */ |
| + | set_termios_to_raw(G.tty_fileno, &G.initial_settings, 0); |
| bb_signals(BB_FATAL_SIGS, gotsig); | |
| do { | |