TTYs and X Window: Unix Now and Thenby Hubert Feyrer
In NetBSD, the
wscons console driver can emulate either a VT100 or a Sun display. I was recently asked by a novice user why there was no VT220 offered, and what the difference was between the terminal type emulated by
wscons and the terminal type set in
/etc/tty. I realized that a discussion of the history of terminal emulation would likely be useful to other BSD developers.
First, I'll describe the type of hardware the Unix operating system was designed for. Then I'll discuss its support for applications that talk to other types of hardware, and how information on this hardware is determined and set. Then I'll jump to the modern world to explain how the X Window System works in comparison to the terminal-based I/O of traditional Unix systems. After that, we'll look at today's common terminal emulation applications to show that the ancient Unix terminal system is still in use today.
Examples in this text use the NetBSD multiplatform operating system, but the concepts are common to all Unix systems -- from older versions such as PDS/Cadmus, to modern Unix versions such as BSD, Solaris, and Linux.
Ancient Unix systems
Back in the Stone Age of Unix, computer systems were usually mainframes -- big boxes of blinking lights with memory, mass storage, and computing units that ran processes started by users or operators. As the hardware was very expensive, the systems were true multiuser systems, with many people interacting with the system at the same time. What it usually didn't have -- unlike today's Unix workstations -- was a fixed monitor and keyboard. Instead, issuing commands to the machine and retrieving output was done over serial lines, using teletypewriters first, and CRT (cathode ray tube) terminals later.
Teletypewriters -- the "ttys" in Unix -- are old electronic typewriters that send keys pressed over a serial line to a host. Replies are sent back to the teletypewriter character by character over the serial line, with a built-in printer putting the reply on paper. For a picture of a teletypewriter, see the lower left corner of the image at the Unix User Group homepage.
Early support of input devices
Some typewriters only used capital letters, while others were able to input and print both cases. Rarely found in today's Unix flavors is the traditional way to tell the system to use, or not use, mixed case: If you entered your login name in all lowercase characters, the system assumed your terminal was capable of doing both uppercase and lowercase. But if you entered your login name in all uppercase characters (or your teletypewriter sent everything you typed in uppercase), the system assumed your terminal could only do uppercase, and printed (real) uppercase characters preceded with a backslash in its reply.
AIX Version 4 (C) Copyrights by IBM and by others 1982, 1996. login: ESP 3004-033 YOU LOGGED IN USING ALL UPPERCASE CHARACTERS. IF YOUR WORKSTATION ALSO SUPPORTS LOWERCASE CHARACTERS, LOG OFF, THEN LOG IN AGAIN USING LOWERCASE CHARACTERS. \E\S\P'S \PASSWORD:
This behavior is still described in chapter 11 of 4.4BSD's Unix User's Supplementary Documents -- the "edit" tutorial (see
How a terminal works
More advanced typewriters offered the ability to change from black to red ribbon, and boldface was available everywhere by overstriking -- printing a character, moving the printer head back (by printing a "backspace" character), and then printing the same letter again on the same spot, resulting in a bold look. Not too long after that, the "printer" part of the teletypewriter was replaced with a CRT. The CRT displayed characters by moving an electron beam on a fluorescent screen of glass with a phosphorous coating, giving them a greenish look. The combination of a CRT and keyboard is now widely known as a "terminal."
The functionality is the same as for the teletypewriter -- keystrokes get sent to a processing host over a serial line, and replies are sent back character by character, and the terminal displays them. The terminal itself has no processing capabilities, and is therefore often described as a "dumb" terminal. When the host sends an "f", an "o" and another "o", the screen will say "foo", with the cursor blinking after the second "o", waiting for further output from the host. The character set was 7-bit ASCII, which is still in widespread use in the Unix world today, and which is only slowly being superceded by various competing standards like ISO 8859-1 and Unicode.
Staying at the blinking cursor after our "foo" a bit longer, the host has to send a command character that says "move to the next line," often even followed by another command character asking it to "move to the start of line," depending on the terminal's setting. These control characters are usually known as "carriage return" (CR) and "line feed" (LF). Command characters were originally encoded as ASCII values below 32 (see
man 7 ascii for your nearest ASCII table).
As other control characters for flow control were used, it quickly became obvious that 32 characters were not enough. Command sets that consisted of several characters were used next. These often had a control sequence introducer (CSI), followed by one or more command bytes (for example, "move cursor") and data bytes (row and column). What made this worse was that manufacturers of terminals started to invent their own command sets that were not compatible with other vendors. Representatives of the more prominent command sets are the DEC (now Compaq) VT100/VT220 escape sequences (named so because they had an "escape" character, ASCII 27, as the first character), ANSI codes, and many others.
Handling many different terminals in applications
As Unix machines were used as real multiuser machines, terminals from different vendors were hooked up using the standard serial protocol. However, applications that wanted to use the different terminals' special capabilities had to handle these differences in some way. Compiling hard-coded support for a certain terminal type was not an option as it meant adding a number of programs for each new terminal type -- a maintenance nightmare.
A different approach was made by putting a "translation table" that defined common operations in between, and a mapping to the vendor-specific command sets. The translation table is part of the host's operating system. When an application running on the Unix host wanted to clear a terminal's screen or move the cursor, it looked up the terminal-specific command via a system or library call, and then sent that string to the terminal. There's no need in the application to keep terminal-specific code, and if a new terminal gets added, only the translation table needs to be adjusted. A big win!
In today's world there are two libraries available for mapping terminal attributes. One is the
terminfo library found on many System V and Linux systems, the other is the BSD-originated
termcap library which stores all the translation information all in a single file, usually
/usr/share/misc/termcap. Be sure to have a look!
$TERM and ttys
There's one question left: If a user logs in from one terminal, and starts an application, how does the system know what terminal type to emulate and what command sequences are needed? The answer is that each terminal is hooked up to a certain serial port (
/dev/ttySomething), and the
/etc/ttys file tells the terminal type. (Note: This is for the BSD world; the System V world uses
/etc/inittab for a similar purpose.)
This is from a NetBSD 1.5/SPARC64 system, with
ttyb being the machine's two built-in serial ports, and the "console" line being used for all system input and output. The first column specifies the terminal line, and third column, "type", tells the type of the terminal -- "VT220" for everything but the system console here. Have a look at your
ttys(5) man page for all the details.
The terminal type from column 3 is passed through the login process to the user's login shell, and by that to any applications the user starts. The application then uses
termcap to look up the specific command sequences they may need. When someone logs in from a terminal hooked up to
ttya, it is assumed a VT220 (or compatible) terminal is used.
The information on the terminal type is kept in the
TERM environment variable, which can be set to a different value, if necessary. In addition, the login terminal line can be determined with the
In the above example, I'm logged in on the
ttya serial port. I do not have a (hardware) terminal, but use another computer that's connected to
ttya via a serial line, and that has a terminal emulation program running. The terminal program talks to the Sun over the serial interface, displays the characters it sends, and interprets any special command sequences. As I know from my terminal program's handbook, it does not emulate a VT220 properly but works fine for VT100 commands. The
TERM variable is set here to reflect this in order to make applications behave properly.
Pages: 1, 2