bug in tty driver?

Ross Cartlidge rossc at metro.oz
Mon Dec 16 10:30:17 AEST 1985


In article <130 at codas.UUCP> mikel at codas.UUCP (Mikel Manitius) writes:
>> Description:
>> 
>> The following combination of events seems to cause reads of a tty to return
>> EOF (VAX System V, Rel 2.0, Version 2; but may apply to your system as well):
>> 
>> Place the following text in a file called "foo".
>> 	sleep 10
>> 	: remember previous settings
>> 	x=`stty -g`
>> 	stty raw
>> 	stty $x
>> 
>> Now type:
>> sh foo<CR>
>> x^H<no CR>
>> After 10 seconds, your shell will exit.  This applies to both the tty driver
>> and the sxt driver.
>> 					Ron Williams
>> 					utzoo!hcrvax!hcrvx1!ronald

[This explanation assumes good knowledge of System V tty driver]

This behaviour is caused by a failure in a heuristic employed
by the LDCHG ioctl call in tt0 when the ICANON flag is toggled. 
When ICANON is toggled all characters are put back
on the raw queue for reprocessing. The delimiter count(t_delct),
however, is set to the number of characters on the raw queue
as there could be a delimiter in the (unprocessed) raw queue.
Thus in the foo example, above, we have two characters on the
raw queue (x^H) when ICANON toggles off then on. Which
results in x^H remaining on the raw queue (canonical processing is
not done until a read(2) is called) but now the t_delct value
is 2. Which means that read(2) will return after canonical
processing.
Thus when the shell executes a read(2) after executing foo
it will return 0 characters as x^H results in no characters
placed on canon queue. Sh(1) interprets this as on EOF.

FIX:
	The problem of what to do with characters that have been input,
but not read when mode changes occur, cannot be handled elegantly
in SysV as t_delct cannot be set accurately after
a mode change. The best solution is for "canon" in
tty.c to check if t_delct speaks the truth and, if
it can find no delimiters, then it should wait
for more characters before decrementing t_delct and returning
to ttread. The diff(1) listing for io/tty.c
implements this strategy. (I have not indented the for loop
so as to keep the diff listing small)

371a372
> 	int	 gotdelim	= 0;
372a374,375
> 	for (;;)
> {
412a416
> 				gotdelim = 1;
431c435,436
< 		if (c == '\n' || c == tp->t_cc[VEOL] || c == tp->t_cc[VEOL2])
---
> 		if (c == '\n' || c == tp->t_cc[VEOL] || c == tp->t_cc[VEOL2]) {
> 			gotdelim = 1;
432a438
> 		}
435a442,446
> 	if (gotdelim)
> 		break;
> 	else
> 		tp->t_delct = 0;
> }



More information about the Net.bugs.usg mailing list