summaryrefslogtreecommitdiffhomepage
path: root/loginutils
diff options
context:
space:
mode:
authorPeter Korsgaard <jacmet@sunsite.dk>2011-01-26 15:15:19 +0100
committerDenys Vlasenko <vda.linux@googlemail.com>2011-01-26 15:15:19 +0100
commitddd1ec1c279da19a79238ce9df820d79415fa33a (patch)
tree7c40426eef48b9986e98f8dc821ac2b0bd207f8c /loginutils
parente3d4c03852f17b20eafaedf957afa1b0bf03c66f (diff)
getty: wait up to 5 seconds for the output buffer to drain
Signed-off-by: Peter Korsgaard <jacmet@sunsite.dk> Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'loginutils')
-rw-r--r--loginutils/getty.c56
1 files changed, 33 insertions, 23 deletions
diff --git a/loginutils/getty.c b/loginutils/getty.c
index 2d2184a76..035534157 100644
--- a/loginutils/getty.c
+++ b/loginutils/getty.c
@@ -224,6 +224,12 @@ static void open_tty(void)
}
}
+static void set_termios(void)
+{
+ if (tcsetattr_stdin_TCSANOW(&G.termios) < 0)
+ bb_perror_msg_and_die("tcsetattr");
+}
+
/* We manipulate termios this way:
* - first, we read existing termios settings
* - termios_init modifies some parts and sets it
@@ -233,25 +239,31 @@ static void open_tty(void)
*/
static void termios_init(int speed)
{
- /* Flush input and output queues, important for modems!
- * Users report losing previously queued output chars, and I hesitate
- * to use tcdrain here instead of tcflush - I imagine it can block.
- * Using small sleep instead.
+ /* Try to drain output buffer, with 5 sec timeout.
+ * Added on request from users of ~600 baud serial interface
+ * with biggish buffer on a 90MHz CPU.
+ * They were losing hundreds of bytes of buffered output
+ * on tcflush.
*/
- usleep(100*1000); /* 0.1 sec */
+ signal_no_SA_RESTART_empty_mask(SIGALRM, record_signo);
+ alarm(5);
+ tcdrain(STDIN_FILENO);
+ alarm(0);
+ signal(SIGALRM, SIG_DFL); /* do not break -t TIMEOUT! */
+
+ /* Flush input and output queues, important for modems! */
tcflush(STDIN_FILENO, TCIOFLUSH);
/* Set speed if it wasn't specified as "0" on command line */
if (speed != B0)
cfsetspeed(&G.termios, speed);
- /*
- * Initial termios settings: 8-bit characters, raw-mode, blocking i/o.
+ /* Initial termios settings: 8-bit characters, raw-mode, blocking i/o.
* Special characters are set after we have read the login name; all
* reads will be done in raw mode anyway. Errors will be dealt with
* later on.
*/
- /* 8 bits; hangup (drop DTR) on last close; enable receive */
+ /* 8 bits; hang up (drop DTR) on last close; enable receive */
G.termios.c_cflag = CS8 | HUPCL | CREAD;
if (option_mask32 & F_LOCAL) {
/* ignore Carrier Detect pin:
@@ -266,9 +278,8 @@ static void termios_init(int speed)
#endif
/* Other bits in c_cflag:
* CSTOPB 2 stop bits (1 otherwise)
- * PARENB Enable parity bit
- * PARODD Use odd parity (else even)
- * LOBLK Block job control output (??)
+ * PARENB Enable parity bit (both on input and output)
+ * PARODD Odd parity (else even)
*/
G.termios.c_iflag = 0;
G.termios.c_lflag = 0;
@@ -281,7 +292,7 @@ static void termios_init(int speed)
G.termios.c_line = 0;
#endif
- tcsetattr_stdin_TCSANOW(&G.termios);
+ set_termios();
debug("term_io 2\n");
}
@@ -309,8 +320,8 @@ static void termios_final(void)
* ICRNL Map CR to NL
* IUCLC Map uppercase to lowercase
* IMAXBEL Echo BEL on input line too long
- * IUTF8 [Appears to affect tty's idea of char widths,
- * observed to improve backspacing through Unicode chars]
+ * IUTF8 Appears to affect tty's idea of char widths,
+ * observed to improve backspacing through Unicode chars
*/
/* line buffered input (NL or EOL or EOF chars end a line);
@@ -324,16 +335,16 @@ static void termios_final(void)
/* Other bits in c_lflag:
* XCASE Map uppercase to \lowercase [tried, doesn't work]
* ECHONL Echo NL even if ECHO is not set
+ * ECHOCTL Echo ctrl chars as ^c (else don't echo) - maybe set this?
+ * ECHOPRT On erase, echo erased chars
+ * [qwe<BS><BS><BS> input looks like "qwe\ewq/" on screen]
* NOFLSH Don't flush input buffer after interrupt or quit chars
* IEXTEN Enable extended functions (??)
* [glibc says it enables c_cc[LNEXT] "enter literal char"
* and c_cc[VDISCARD] "toggle discard buffered output" chars]
- * ECHOCTL Echo ctrl chars as ^c (else don't echo) - maybe set this?
- * ECHOPRT On erase, echo erased chars
- * [qwe<BS><BS><BS> input looks like "qwe\ewq/" on screen]
* FLUSHO Output being flushed (c_cc[VDISCARD] is in effect)
* PENDIN Retype pending input at next read or input char
- * (c_cc[VREPRINT] is being processes)
+ * (c_cc[VREPRINT] is being processed)
* TOSTOP Send SIGTTOU for background output
* (why "stty sane" unsets this bit?)
*/
@@ -358,8 +369,7 @@ static void termios_final(void)
* VSTART, VSTOP - chars used for IXON/IXOFF
*/
- if (tcsetattr_stdin_TCSANOW(&G.termios) < 0)
- bb_perror_msg_and_die("tcsetattr");
+ set_termios();
}
/* extract baud rate from modem status message */
@@ -383,7 +393,7 @@ static void auto_baud(void)
*/
G.termios.c_cc[VMIN] = 0; /* don't block reads (min read is 0 chars) */
- tcsetattr_stdin_TCSANOW(&G.termios);
+ set_termios();
/*
* Wait for a while, then read everything the modem has said so far and
@@ -407,7 +417,7 @@ static void auto_baud(void)
/* Restore terminal settings. Errors will be dealt with later on */
G.termios.c_cc[VMIN] = 1; /* restore to value set by termios_init */
- tcsetattr_stdin_TCSANOW(&G.termios);
+ set_termios();
}
/* get user name, establish parity, speed, erase, kill, eol;
@@ -614,7 +624,7 @@ int getty_main(int argc UNUSED_PARAM, char **argv)
/* We are here only if G.numspeed > 1 */
baud_index = (baud_index + 1) % G.numspeed;
cfsetspeed(&G.termios, G.speeds[baud_index]);
- tcsetattr_stdin_TCSANOW(&G.termios);
+ set_termios();
}
}