Subject: Re: bin/10879: su does not reset terminal settings after Ctrl-C
To: jchacon <firstname.lastname@example.org>
From: James Chacon <email@example.com>
Date: 08/24/2000 00:46:04
(This is a long email for a rather dull subject but the implications
intrigued me to a point....:-)
Ok, this is gonna require some thinking to fix the behavior.
The reason the control-C doesn't appear to take effect is because getpass
blocks SIGINT and SIGTSTP while it's processing. However it doesn't stop
processing until it either gets EOF or \n. So what you're seeing is not the
shell misbehaving but it not seeing the process exit until then.
1. You run su
2. You type some stuff and hit ^C.
3. That's currently blocked so nothing happens
4. You eventually hit return.
5. getpass(3) cleans up, turns back on echo and unblocks the signal
6. Now the SIGINT gets delivered and the code exits immediately
7. The shell see the exit and prints a new prompt.
Fixing this isn't as simple though. The reasons for blocking the signals
are good..We're mucking with the terminal (in this case throwing it into
no echo mode), and before returning everything should be cleaned up.
Now, having a library routine catch the signals is quite messy and doing
something other than blocking (like setting them to ignore) is just as bad.
There is no good middle ground here that I can tell, but this behavior is
non obvious to someone trying to abort a su(1). Especially since I can abort
it with other signals like SIGQUIT (^\). That behaves exactly like you'd
expect a SIGINT to work (it exits right away without the return), but depending
on your shell you might get left in no-echo mode (sh/csh do for instance but
bash resets my terminal).
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)
>This is actually not a su bug per se, but a behavior that occurs because
>getpass(3) blocks signals which working with the tty and then unblocks
>afterwards. This causes the interrupt to not actually occur while in non-echo
>mode, but I do agree having to hit the extra return is odd.
>>>Synopsis: su does not reset terminal settings after Ctrl-C
>>>Arrival-Date: Tue Aug 22 08:05:00 PDT 2000
>>>Originator: Ian Fry
>>>Release: Aug 20, 2000
>>System: NetBSD terry 1.5E NetBSD 1.5E (TERRY) #65: Wed Aug 16 13:34:23 BST 2000 ief@terry:/usr/src/sys/arch/i386/compile/TERRY i386
>> If you type Ctrl-C at the password prompt issued by 'su', the terminal
>>settings are not correctly restored.
>> Attempt to 'su' to another user (e.g. root), and press Ctrl-C at the
>>password prompt. Terminal echo setting remains off, and requires resetting
>> This only seems to affect bash (I've also tried sh and csh). However, with
>>sh and csh, you need to press return after the Ctrl-C to get back to a shell
>> Enter an invalid password to abort the su attempt.