From 484aa0ba971eeefc71e5bb9025db335b101f2acf Mon Sep 17 00:00:00 2001 From: Joachim Nilsson Date: Sun, 26 Apr 2020 22:06:59 +0200 Subject: [PATCH] Fix issue with VINTR, VEOF et al not being restored after boot On Alpine Linux 3.6 the tcsetattr() calls failed. This turned out to be a deeply rooted issue not limited to just musl libc. The workaround is to call tcsetattr() in several rounds. In particular the modem signals, c_cflag bits, always fail, so we take a bet on Linux having set up the terminals (hope as a strategy) and ignore that problem, for now. Also, use TCSAFLUSH with tcsetattr(), that seems to work better and is what BusyBox stty use. The local CTL() macro is replaced with CTL() from ttydefaults.h, which exists also in musl libc. Signed-off-by: Joachim Nilsson --- src/exec.c | 6 +++--- src/getty.c | 9 ++++----- src/stty.c | 24 ++++++++++++------------ 3 files changed, 19 insertions(+), 20 deletions(-) diff --git a/src/exec.c b/src/exec.c index fe6c52b6..dc33ba0f 100644 --- a/src/exec.c +++ b/src/exec.c @@ -256,7 +256,7 @@ static void prepare_tty(char *tty, speed_t speed, char *procname, struct rlimit term.c_lflag &= ~ISIG; term.c_cc[VEOF] = _POSIX_VDISABLE; term.c_cc[VINTR] = _POSIX_VDISABLE; - tcsetattr(STDIN_FILENO, TCSANOW, &term); + tcsetattr(STDIN_FILENO, TCSAFLUSH, &term); } /* Reset signal handlers that were set by the parent process */ @@ -309,7 +309,7 @@ static int activate_console(int noclear, int nowait) c.c_oflag &= ~(OPOST); c.c_cflag |= (CS8); c.c_lflag &= ~(ECHO|ICANON|IEXTEN|ISIG); - tcsetattr(STDIN_FILENO, TCSANOW, &c); + tcsetattr(STDIN_FILENO, TCSAFLUSH, &c); } while (!fexist(SYNC_SHUTDOWN)) { @@ -338,7 +338,7 @@ static int activate_console(int noclear, int nowait) } /* Restore TTY */ - if (tcsetattr(STDIN_FILENO, TCSANOW, &orig) == -1) + if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &orig) == -1) ret = 0; return ret; diff --git a/src/getty.c b/src/getty.c index de59abbe..426cae26 100644 --- a/src/getty.c +++ b/src/getty.c @@ -41,7 +41,6 @@ #define _PATH_LOGIN "/bin/login" #endif -#define CTL(x) ((x) ^ 0100) #define print(s) (void)write(STDOUT_FILENO, s, strlen(s)) @@ -164,7 +163,7 @@ static void do_getty(char *tty, char *name, size_t len) np = name; while ((ch = readch(tty)) != '\n') { - if (ch == CTL('U')) { + if (ch == CTRL('U')) { while (np > name) { (void)write(1, "\b \b", 3); np--; @@ -290,9 +289,9 @@ int sh(char *tty) /* Reenable Ctrl-D and Ctrl-C, and ... */ if (!tcgetattr(STDIN_FILENO, &term)) { term.c_lflag |= ISIG; - term.c_cc[VEOF] = CTL('D'); - term.c_cc[VINTR] = CTL('C'); - tcsetattr(STDIN_FILENO, TCSANOW, &term); + term.c_cc[VEOF] = CEOF; + term.c_cc[VINTR] = CINTR; + tcsetattr(STDIN_FILENO, TCSAFLUSH, &term); } /* ... unblock signals in general */ diff --git a/src/stty.c b/src/stty.c index b625e3b3..f8dfd102 100644 --- a/src/stty.c +++ b/src/stty.c @@ -96,29 +96,29 @@ void stty(int fd, speed_t speed) cfsetospeed(&term, speed); tcsetattr(fd, TCSAFLUSH, &term); } - tcflush(fd, TCIOFLUSH); - /* Disable modem specific flags */ - term.c_cflag &= ~(0|CSTOPB|PARENB|PARODD|CBAUDEX); - term.c_cflag &= ~CRTSCTS; - term.c_cflag |= CLOCAL; + /* Modem specific control flags */ + term.c_cflag &= ~(PARENB|PARODD|CSTOPB|CRTSCTS); + term.c_cflag |= CS8|HUPCL|CREAD|CLOCAL; + term.c_line = 0; + tcsetattr(fd, TCSAFLUSH, &term); /* Timeouts, minimum chars and default flags */ term.c_cc[VTIME] = 0; term.c_cc[VMIN] = 1; term.c_iflag = ICRNL|IXON|IXOFF; term.c_oflag = OPOST|ONLCR; - term.c_cflag |= CS8|CREAD|HUPCL; term.c_lflag |= ICANON|ISIG|ECHO|ECHOE|ECHOK|ECHOKE; + tcsetattr(fd, TCSAFLUSH, &term); /* Reset special characters to defaults */ - term.c_cc[VINTR] = CTRL('C'); - term.c_cc[VQUIT] = CTRL('\\'); - term.c_cc[VEOF] = CTRL('D'); - term.c_cc[VEOL] = '\n'; - term.c_cc[VKILL] = CTRL('U'); + term.c_cc[VINTR] = CINTR; + term.c_cc[VQUIT] = CQUIT; + term.c_cc[VEOF] = CEOF; + term.c_cc[VEOL] = CEOL; + term.c_cc[VKILL] = CKILL; term.c_cc[VERASE] = CERASE; - tcsetattr(fd, TCSANOW, &term); + tcsetattr(fd, TCSAFLUSH, &term); /* Show cursor again, if it was hidden previously */ write(fd, "\033[?25h", 6);