My Weblog
18 10 2004Mon, 18 Oct 2004
Red Hat Gets Terminal Settings Wrong
Okay, I don't really mind if Red Hat decides to do things differently
than Debian, but I do mind if they way they do things breaks the
standard, accepted way. In this case, I'm referring to the way that Red
Hat configures the terminal backspace character.
Now, Red Hat configures the Backspace key to send Control-H, which is the
classic, historical setting for it. However, this interferes with
Emacs, which uses Control-H to start the help system. The modern (and
IMHO correct) setting is to use ASCII DEL (^?, value 127) for Backspace.
Debian follows this method as detailed in the Keyboard
Configuration
section of the Debian
Policy Manual. This allows Backspace, Delete, and Control-H to be interpreted
independently of one another.
The fact that Red Hat chooses to use the old configuration bothers me,
but I can deal with that. What I can't deal with is that Red Hat puts
the following code into /etc/bashrc:
if [ -x /usr/bin/tput ]; then
if [ "x`tput kbs`" != "x" ]; then # We can't do this with "dumb" terminal
stty erase `tput kbs`
elif [ -x /usr/bin/wc ]; then
if [ "`tput kbs|wc -c `" -gt 0 ]; then # We can't do this with "dumb" terminal
stty erase `tput kbs`
fi
fi
fi
This sets the tty erase character to whatever is specified as the
backspace code in the terminfo database. Whoever wrote this is trying to work around terminals that send one character with the backspace key, yet whose tty device is set to use the other character. This may work with terminals on the local machine, or with remote logins to machines that use the same erase character, but it breaks backspace on other systems. The erase character is correctly
set by telnetd and sshd to match the erase character used on the client, and this code forces it to be whatever character the server uses. The program being run must generate output that is correctly displayed
on the user's terminal, which means that the server must use the terminal settings the client wants, not the other way around.
It is also unreasonable to consider this a fix for local terminals whose erase character and Backspace binding don't match up. If this is the case, then there is a configuration problem and it should be corrected by changing the configuration for that specific terminal or emulator (i.e. by changing the backarrowKey, ptyInitialErase, or backarrowKeyIsErase resources for xterm). Writing a shell script to work around the problem doesn't fix it, it just hides the problem.
A possible solution would be to run stty erase ^?
explicitly in my shell startup script. This is unacceptable however,
since it 1) doesn't change the fact that Red Hat's default setup is
broken and 2) some of my accounts are used by several other people who
use different distros, and setting the erase character explicitly might
break their terminal settings.
To take one step toward solving this problem, remove above code from /etc/bashrc. It's a nasty kludge written solely to cover up the fact that Red Hat can't figure out how to change X resources and terminal emulator settings to match their termcap and terminfo databases.
Update: I have noticed that the delete key is also broken. This isn't that big of a deal, it's just annoying. On some machines the delete key (in bash at least) has the same effect as the backspace key (delete previous character) and on others it prints a tilde (and probably some control characters). As long as it doesn't break things for anyone else, I'm fine with it. I use backspace a lot more than delete anyway :-)
Actually, this appears to only be a problem when running a remote screen session on some redhat boxes. Remote ssh sessions work fine. For some reason, screen on these machines doesn't set the kD termcap capability correctly. It would be awesome if the TERMCAP variable was preserved for remote logins. :-/
Update (2004-10-18): I've discovered another stupid RedHat BS/DEL 'fix'. RedHat provides a global configuration file for GNU screen, which is an application that I depend on everyday. In this /etc/screenrc file, there is the following code:
# This makes screen treat backspaces '^?' as
# deletes. There should be a fix in the code
# for the way termcap inheritance works,
# but I dont know where to put it, and this works.
bindkey -d -k kb stuff "\010"
This forces the backspace key to send ^H, which is WRONG!!! Even if you think that ^H is the correct character for backspace (which it isn't), it is not correct to force screen to send ^H for backspace. If my kb/kbs entry is defined as ^?, this code makes it absolutely impossible to send ^?, since screen will always translate it to ^H. I don't know what the heck this is supposed to fix. If my kb/kbs is defined as ^H to begin with, this does nothing and is therefore useless. If the kb/kbs entry is ^?, now it becomes impossible to send DEL to the application. This will break all apps that use the stty erase character to determine what backspace should be if the erase character isn't ^H. Now another fix is required, like the brain-dead 'stty erase `tput kbs`' hack described above. The only way to solve the problem is as follows:
- Remove all hacks from both system-wide and personal config files that change stty erase, the kb/kbs definitions, or the mapping for the backspace key
- Choose a system-wide backspace character (either ^H or ^?)
- Change terminfo/termcap entries so that kb/kbs is set to that character
- Make sure all terminal emulators send this character when the backspace key is pressed. This should be set system-wide
- Make sure all terminal emulators set the erase character to this value. This should be set system-wide
- Configure applications system-wide to use the stty erase character to determine what the backspace key sends
- If that is not possible, configure the application to accept both ^H and ^? for backspace
- If that is not possible, make sure the apps use termcap/terminfo to determine the backspace character
- If that is not possible, then the app is broken and must be fixed.
If you do these steps, backspace will only be broken under the following conditions:
- If the app assumes a particular value for backspace, and cannot be configured otherwise
- If you log into this machine remotely, and the remote client sends the other character for backspace, BUT only if the application (running on this machine) can only use terminfo/termcap to determine what backspace should be. This is why the app should use the stty erase setting, not the term{cap,info} entry
- If the client's erase character does not match the value it sends for the backspace key. These must be the same. This can only be fixed on the client end.
- If the client does not tell the server what it thinks the erase character should be. Modern versions of telnet and ssh do this already, so nothing should need to be done here. If this is a problem, then using 'stty erase' to set the erase character is acceptable
- If you log in from this machine to a machine that uses the other erase character. This is not a problem unless the remote machine uses one of the above hacks on the stty erase character, or the app doesn't use stty erase. Just set the app to accept both characters, or tweak the termcap/terminfo entry to use your character. Most apps honor stty erase over the termcap/terminfo entry.
In short, the stty erase character should be treated as correct at all times, and termcap/terminfo should match it. The backspace key should also match it. Any other configuration will have more problems than this one. If someone tells you otherwise, they're stupid. Ignore them.
posted at: 11:46 | path: /computers/linux/redhat | permanent link to this entry
