Subject: Re: bin/10879: su does not reset terminal settings after Ctrl-C
To: James Chacon <jchacon@genuity.net>
From: Greg A. Woods <woods@weird.com>
List: tech-userlevel
Date: 08/24/2000 11:51:27
[ On Thursday, August 24, 2000 at 00:46:04 (-0400), James Chacon wrote: ]
> Subject: Re: bin/10879: su does not reset terminal settings after Ctrl-C
>
> I think one of the follwing need to occur:
>
> 1. Block all signals in getpass so everything is consistant across the board
> and document that code using getpass(3) needs to expect the non-obvious
> SIGINT + return == exit behaviour.
>
> 2. Put signal handlers in getpass(3) which catch everything, reset the
> terminal settings and then pass off to either the default or a previously
> installed handler. (YUCK)
>
> 3. Don't block anything and let the terminal/shell do their thing on exit.
> Expect the application code to catch relevant signals and possibly have
> to deal with resetting echo mode on the terminal. (i.e. updating the
> man page to getpass(3) to include "If aborted by a signal the terminal will
> be left in non-echo mode."
>
> 4. Ignore all the issues related around this and just fix su to use it's own
> getpass implementation and catch the signals itself. (Still update
> the getpass(3) man page at a minimum to explain what's occuring here).
>
> I actually think #3 is the most reasonable but it will require any userland
> code relying on getpass to accomodate change. (24 files today)
You missed another posible solution....
5. have getpass(3) put the terminal in raw mode and emulate all of the
character processing within itself.
BTW #4 is completely the wrong approach and probably shouldn't even be
listed as a potential solution.
#2 is possible, but a little yucky as you say. It's also probably about
as hard to get right as my #5 too.
#1 is more or less wrong too, and is what taught me to use ^D (i.e. the
EOF character) to abort 'su' etc.
In reality though #3 is the only correct solution, and is the one that's
been chosen by Unix for a long time now (I'm not sure since exactly
when, though I do note from the sources I have that up to System III
that SIGINT is simply ignored until after a '\n' or EOF is returned and
that only echo processing is modifed, however all of the AT&T Unix
manuals I have, including the System V Release 2.2 manual page from
about 1986, state explicitly that "An interrupt will terminate input and
send an interrupt signal to the calling program before returning." with
the implication being that echoing is not re-enabled in that case).
Of course users of getpass() must be fixed up to catch SIGINT and to
properly reset the terminal modes when it is triggered.... We can't be
relying on interactive shells to restore the terminal modes!
The code in 4.3BSD-Reno has the comment:
/*
* note - blocking signals isn't necessarily the
* right thing, but we leave it for now.
*/
I can assure you that I was very happy with the behaviour of System V
'su' w.r.t. interrupts during the getpass() call, and I've been rather
disappointed by the return of the broken behaviour in even modern BSDs.
My remaining problem with *BSD tty behaviour, which is demonstrated by
getpass(), is the mis-handling of EOF. Traditionally I recall ^D
working at any point on a line. In BSD it only has the effect of
generating EOF when entered at the beginning of a line. This frustrates
me almost every time I want to abort 'su' as I have to remember that: a)
BSD's version still blocks SIGINT; and b) that EOF only works at the
beginning of the line so now I have to use ^U^D instead.
--
Greg A. Woods
+1 416 218-0098 VE3TCP <gwoods@acm.org> <robohack!woods>
Planix, Inc. <woods@planix.com>; Secrets of the Weird <woods@weird.com>