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>
This commit is contained in:
		
				
					committed by
					
						 Denys Vlasenko
						Denys Vlasenko
					
				
			
			
				
	
			
			
			
						parent
						
							e3d4c03852
						
					
				
				
					commit
					ddd1ec1c27
				
			| @@ -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: | /* We manipulate termios this way: | ||||||
|  * - first, we read existing termios settings |  * - first, we read existing termios settings | ||||||
|  * - termios_init modifies some parts and sets it |  * - termios_init modifies some parts and sets it | ||||||
| @@ -233,25 +239,31 @@ static void open_tty(void) | |||||||
|  */ |  */ | ||||||
| static void termios_init(int speed) | static void termios_init(int speed) | ||||||
| { | { | ||||||
| 	/* Flush input and output queues, important for modems! | 	/* Try to drain output buffer, with 5 sec timeout. | ||||||
| 	 * Users report losing previously queued output chars, and I hesitate | 	 * Added on request from users of ~600 baud serial interface | ||||||
| 	 * to use tcdrain here instead of tcflush - I imagine it can block. | 	 * with biggish buffer on a 90MHz CPU. | ||||||
| 	 * Using small sleep instead. | 	 * 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); | 	tcflush(STDIN_FILENO, TCIOFLUSH); | ||||||
|  |  | ||||||
| 	/* Set speed if it wasn't specified as "0" on command line */ | 	/* Set speed if it wasn't specified as "0" on command line */ | ||||||
| 	if (speed != B0) | 	if (speed != B0) | ||||||
| 		cfsetspeed(&G.termios, speed); | 		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 | 	 * 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 | 	 * reads will be done in raw mode anyway. Errors will be dealt with | ||||||
| 	 * later on. | 	 * 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; | 	G.termios.c_cflag = CS8 | HUPCL | CREAD; | ||||||
| 	if (option_mask32 & F_LOCAL) { | 	if (option_mask32 & F_LOCAL) { | ||||||
| 		/* ignore Carrier Detect pin: | 		/* ignore Carrier Detect pin: | ||||||
| @@ -266,9 +278,8 @@ static void termios_init(int speed) | |||||||
| #endif | #endif | ||||||
| 	/* Other bits in c_cflag: | 	/* Other bits in c_cflag: | ||||||
| 	 * CSTOPB 2 stop bits (1 otherwise) | 	 * CSTOPB 2 stop bits (1 otherwise) | ||||||
| 	 * PARENB Enable parity bit | 	 * PARENB Enable parity bit (both on input and output) | ||||||
| 	 * PARODD Use odd parity (else even) | 	 * PARODD Odd parity (else even) | ||||||
| 	 * LOBLK  Block job control output (??) |  | ||||||
| 	 */ | 	 */ | ||||||
| 	G.termios.c_iflag = 0; | 	G.termios.c_iflag = 0; | ||||||
| 	G.termios.c_lflag = 0; | 	G.termios.c_lflag = 0; | ||||||
| @@ -281,7 +292,7 @@ static void termios_init(int speed) | |||||||
| 	G.termios.c_line = 0; | 	G.termios.c_line = 0; | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| 	tcsetattr_stdin_TCSANOW(&G.termios); | 	set_termios(); | ||||||
|  |  | ||||||
| 	debug("term_io 2\n"); | 	debug("term_io 2\n"); | ||||||
| } | } | ||||||
| @@ -309,8 +320,8 @@ static void termios_final(void) | |||||||
| 	 * ICRNL   Map CR to NL | 	 * ICRNL   Map CR to NL | ||||||
| 	 * IUCLC   Map uppercase to lowercase | 	 * IUCLC   Map uppercase to lowercase | ||||||
| 	 * IMAXBEL Echo BEL on input line too long | 	 * IMAXBEL Echo BEL on input line too long | ||||||
| 	 * IUTF8   [Appears to affect tty's idea of char widths, | 	 * IUTF8   Appears to affect tty's idea of char widths, | ||||||
| 	 *         observed to improve backspacing through Unicode chars] | 	 *         observed to improve backspacing through Unicode chars | ||||||
|          */ |          */ | ||||||
|  |  | ||||||
| 	/* line buffered input (NL or EOL or EOF chars end a line); | 	/* 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: | 	/* Other bits in c_lflag: | ||||||
| 	 * XCASE   Map uppercase to \lowercase [tried, doesn't work] | 	 * XCASE   Map uppercase to \lowercase [tried, doesn't work] | ||||||
| 	 * ECHONL  Echo NL even if ECHO is not set | 	 * 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 | 	 * NOFLSH  Don't flush input buffer after interrupt or quit chars | ||||||
| 	 * IEXTEN  Enable extended functions (??) | 	 * IEXTEN  Enable extended functions (??) | ||||||
| 	 *         [glibc says it enables c_cc[LNEXT] "enter literal char" | 	 *         [glibc says it enables c_cc[LNEXT] "enter literal char" | ||||||
| 	 *         and c_cc[VDISCARD] "toggle discard buffered output" chars] | 	 *         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) | 	 * FLUSHO  Output being flushed (c_cc[VDISCARD] is in effect) | ||||||
| 	 * PENDIN  Retype pending input at next read or input char | 	 * 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 | 	 * TOSTOP  Send SIGTTOU for background output | ||||||
| 	 *         (why "stty sane" unsets this bit?) | 	 *         (why "stty sane" unsets this bit?) | ||||||
| 	 */ | 	 */ | ||||||
| @@ -358,8 +369,7 @@ static void termios_final(void) | |||||||
| 	 * VSTART, VSTOP - chars used for IXON/IXOFF | 	 * VSTART, VSTOP - chars used for IXON/IXOFF | ||||||
| 	 */ | 	 */ | ||||||
|  |  | ||||||
| 	if (tcsetattr_stdin_TCSANOW(&G.termios) < 0) | 	set_termios(); | ||||||
| 		bb_perror_msg_and_die("tcsetattr"); |  | ||||||
| } | } | ||||||
|  |  | ||||||
| /* extract baud rate from modem status message */ | /* 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) */ | 	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 | 	 * 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 */ | 	/* Restore terminal settings. Errors will be dealt with later on */ | ||||||
| 	G.termios.c_cc[VMIN] = 1; /* restore to value set by termios_init */ | 	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; | /* 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 */ | 			/* We are here only if G.numspeed > 1 */ | ||||||
| 			baud_index = (baud_index + 1) % G.numspeed; | 			baud_index = (baud_index + 1) % G.numspeed; | ||||||
| 			cfsetspeed(&G.termios, G.speeds[baud_index]); | 			cfsetspeed(&G.termios, G.speeds[baud_index]); | ||||||
| 			tcsetattr_stdin_TCSANOW(&G.termios); | 			set_termios(); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user