misc/163871: 'script' save endline as ^M

Bruce Evans brde at optusnet.com.au
Sat Jan 7 08:24:18 UTC 2012


On Sat, 7 Jan 2012, Bruce Evans wrote:

> ...
> watch(8) probably works better for input too.  Someone recently tried to
> fix EOF handling in script(1) and had problems using VEOF since this gives
> input processing unless the default echo mode is turned off.  Perhaps
> watch(8) can handle this better too.  But watch doesn't understand EOF at
> all, and is hard to terminate (the old version that I'm testing with
> is terminated by ^G which generates a SIGINT, but it dumps core instead
> of catching this signal as intended, and all versions have an unsafe
> SIGINT handler which asks for core dumps).

The core dump is because watch(8) tries to shoot its foot off, but only
I notice because only my tty driver has been fixed to do the shooting.
watch(8) sets both VINTR and VQUIT to ^G.  This should (*) result in ^G
generating both a SIGINT and a SIGQUIT, and the SIGQUIT must terminate
watch(8) since watch(8) only catches SIGINT.  But the unfixed tty
driver only generates SIGINT.  The same bug affects VSUSP matching either
VINTR or VSUSP, bu I didn't fix that.

(*) POSIX doesn't seem to say what happens when control characters are
equal, but it is hard to read its general specification of them as
allowing the bugs.  From POSIX.1-2001-draft7 (the 2007 draft is similar):

% 6722              INTR       Special character on input, which is recognized if the ISIG flag is set. Generates a
% 6723                         SIGINT signal which is sent to all processes in the foreground process group for which
% 6724                         the terminal is the controlling terminal. If ISIG is set, the INTR character shall be
% 6725                         discarded when processed.
% 6726              QUIT       Special character on input, which is recognized if the ISIG flag is set. Generates a
% 6727                         SIGQUIT signal which is sent to all processes in the foreground process group for
% 6728                         which the terminal is the controlling terminal. If ISIG is set, the QUIT character shall be
% 6729                         discarded when processed.
% 6747              SUSP       If the ISIG flag is set, receipt of the SUSP character shall cause a SIGTSTP signal to be
% 6748                         sent to all processes in the foreground process group for which the terminal is the
% 6749                         controlling terminal, and the SUSP character shall be discarded when processed.

This says that these special characters are "recognized" and the
corresponding signal is sent whenever ISIG is set.  The characters are
discarded after processing them.  It takes a weaselish reading to allow
the bug: we have to discard the characters after processing them just
enough to generate a signal for them after processing them as another
type of control character.  But I believe the discarding wasn't meant
to do that.  It is just to keep these characters out of the final
input.

FreeBSD's termios(4) has essentially the same wording for this.

% ...
% 7019           If ISIG is set, each input character shall be checked against the special control characters INTR,
% 7020           QUIT, and SUSP. If an input character matches one of these control characters, the function
% 7021           associated with that character shall be performed. If ISIG is not set, no checking shall be done.

This specifies what must be done if an input character matches "one" of
the control characters.  If it matches more than one, then it certainly
matches just one, so this can be read as requiring the action to be performed
for all matches.  "one" can be read as "only one", but I think this is
reading too much uniqueness into "one".  And if "only one" is meant, the
precedence becomes important, but nothing is said about precedence.

Anyway, the behaviour when some V characters are identical is very
unportable, so they should never be be identical, and applications
should not make some identical by changing only some and accidentally
matching others.  watch(8) is setting VQUIT because it doesn't want
to get SIGQUIT.  It is only accidental that setting it to the same as
VINTR normally avoids the SIGQUIT (because VINTR has precedence, and
the bug prevents getting both signals).  It should be setting VQUIT
to _POSIX_VDISABLE to avoid SIGQUIT (it must do something, since the
user might already have set it to ^G, in which case setting only VINTR
to ^G would create the ambiguiuty).  Before _POSIX_VDISABLE existed,
the only way to kill a control characted was to set it to a harmless
value.  The null character may have been most harmless, and VQUIT =
VINTR was apparently harmless too since most tty drivers had the bug.
Maybe POSIX requires the bug somewhere, for historical incompatibility,
although with _POSIX_VDISABLE it doesn't need this hack.  VQUIT is
set by remarkably few applications in /usr/src (especially to a
hard-coded value), so watch(8) is the main example of this.  Newer
code tends to use _POSIX_VDISABLE.

"stty sane" doesn't change control characters, so after watch(8)
didn't restore the state, I saw much further weirdness from VINTR =
VQUIT.  Most applications catch neither signal, and so they get
killed normally by SIGINT for ^G instead of ^C.  Others tend to
catch both SIGINT and ignore SIGQUIT, so they don't get killed like
watch(8).

Bruce


More information about the freebsd-bugs mailing list