[net.unix-wizards] Undocumented 4.2 tty driver features

stevesu@azure.UUCP (Steve Summit) (08/22/85)

The other day I was wishing that typing control-C wouldn't flush
the output queue.  In desperation, I took a look at the tty
driver code, and lo and behold, I found

	/*
	 * Look for interrupt/quit chars.
	 */
	if (c == tp->t_intrc || c == tp->t_quitc) {
		if ((tp->t_flags&NOFLSH) == 0)
			ttyflush(tp, FREAD|FWRITE);
		ttyecho(c, tp);
		gsignal(tp->t_pgrp, c == tp->t_intrc ? SIGINT : SIGQUIT);
		goto endcase;
	}

(This is from the vicinity of line 720, routine ttyinput(), file
tty.c .)  Yup, the NOFLSH bit says, "don't flush the input and
output queues on the interrupt and quit characters."  There's a
#definition for LNOFLSH in <sys/ioctl.h>, so your programs can
set it, but it turns out that stty knows about it, too!  Try

	stty noflsh
	cat /usr/dict/words
	date
	^C

where you type "date" and hit control-C while /usr/dict/words is
still flying past.  First you'll notice that it keeps flying for
a bit after you hit control-C (because the output wasn't flushed)
and then you'll notice the date get printed (because the input
wasn't flushed, either).  (Disclaimer: this test, for some
reason, doesn't work under the Korn shell, but it works fine
under sh and csh.)

While searching for the ttyflush() routine, I came across a call
to it in the TIOCFLUSH ioctl:

	case TIOCFLUSH: {
		register int flags = *(int *)data;

		if (flags == 0)
			flags = FREAD|FWRITE;
		else
			flags &= FREAD|FWRITE;
		ttyflush(tp, flags);
		break;
	}

(circa line 334, routine ttioctl(), same file.)

And, it turns out that ttyflush() (a bizarre little routine that
I won't reprint here) uses the FREAD and FWRITE bits in its
second argument to decide which queues to flush.  So, the third
argument to a TIOCFLUSH ioctl, which I always thought was garbage,
or a pointer to some garbage, anyway, is actually used for
something, and if you pass the address of something that isn't
zero, you're liable to get less flushed than you wanted.

In fact, though, this is useful, too, since if I want control-C to
flush input but not output, all I have to do is something like

	#include <signal.h>
	#include <sgtty.h>
	#include <sys/file.h>			/* for FREAD */

	int sigint();

	main()
	{
	int noflsh = LNOFLSH;
	ioctl(0, TIOCLBIS, &noflsh);
	signal(SIGINT, sigint);
	pause();
	}

	sigint()
	{
	int fread = FREAD;
	ioctl(0, TIOCFLUSH, &fread);
	}

Now, the $64,000 question is, even though they do _j_u_s_t what I
want, can I use these things?  I really don't like to use
undocumented features.  What I've described exists in several 4.2
ports I've looked at.  But how many?

                                         Steve Summit
                                         tektronix!bronze!stevesu

trt@rti-sel.UUCP (Tom Truscott) (08/23/85)

As you point out, the FREAD/FWRITE parameter to the TIOCFLUSH ioctl
is not merely undocumented, it is required!  That is:
	ioctl(fd, TIOCFLUSH, (char *)0);
is a NOP on 4.2 BSD/VAX.  I suppose this feature is widely known,
but I have noticed some programs that have these NOPs in them.
For example, the 'flushinp()' routine in Pavel Curtis' terminfo.

The correct way to flush input is, of course:
	#include <file.h>
	int flushread = FREAD;
	...
	ioctl(fd, TIOCFLUSH, (char *)&flushread);

It would be nice if a third parameter of '(char *)0' had the effect
of flushing both input and output.  Perhaps in 4.3 BSD?
	Tom Truscott