Terminals are one of the oldest and most fundamental parts of UNIX and Linux. Even today, every shell window you open is technically a terminal emulator. Understanding how terminals work at the kernel level is essential for embedded Linux engineers who write daemons, handle serial ports, work with pseudoterminals, or write interactive command-line tools.
This series covers Chapter 62 of The Linux Programming Interface. In Part 1 we look at what terminals are, where the name TTY comes from, and how modern systems still rely on the same concepts invented decades ago.
1. What Is a Terminal?
In the early days of UNIX, a terminal was a physical device โ a keyboard and a display (usually a CRT screen) connected to the computer through a serial line (RS-232). The user typed on the keyboard; characters appeared on the screen; the computer processed them.
Even earlier than CRTs, terminals were teletype (TTY) machines โ electromechanical typewriters that printed output on paper rolls. That is where the abbreviation tty comes from, and it is still used throughout Linux today.
Serial lines were also used to connect printers, modems, and even to link two computers together. On early UNIX, each terminal line was represented as a character device at /dev/tty1, /dev/tty2, etc. On modern Linux, /dev/ttyn refers to virtual consoles โ the text-mode screens you switch between with Ctrl+Alt+F1, Ctrl+Alt+F2, and so on.
2. The Standardization Problem
In the early UNIX era, each terminal manufacturer used different control sequences for things like:
- Moving the cursor to the top-left of the screen
- Clearing the screen
- Moving to a specific row/column
Writing a program like a text editor (vi) that needed to control the cursor was a nightmare โ you had to know which terminal the user had, and write different code for each.
The solution came in two layers:
- termcap / terminfo databases โ a big lookup table that maps capability names (like “move cursor to position X,Y”) to the actual byte sequences for hundreds of terminal types.
- curses library โ a programming library that sits on top of terminfo and lets you write screen-oriented programs portably. The
ncurseslibrary you use in Linux today is a direct descendant.
Eventually Digital Equipment Corporation’s VT-100 terminal became so popular that its escape sequences became a de facto standard, and later an official ANSI standard. Most terminal emulators today (xterm, GNOME Terminal, etc.) emulate a VT-100/VT-220.
3. Modern Terminals โ The Terminal Emulator
Today, nobody uses a physical CRT terminal connected via RS-232. Instead:
- The computer has a graphical display managed by the X Window System (or Wayland).
- You run a terminal emulator application โ like
xterm, GNOME Terminal, Konsole, or Alacritty. - The terminal emulator draws a window, handles keyboard input, and talks to the kernel through a pseudoterminal (PTY) device.
From the kernel’s perspective, a terminal emulator window is almost identical to an old physical terminal. The same TTY driver code handles both. The only real difference is the underlying device: a real RS-232 line vs. a pseudoterminal.
Chapter 64 of TLPI covers pseudoterminals in detail. For now, just understand that the terminal driver (TTY driver) is always in the middle โ between the user-facing side (physical terminal or emulator window) and the application.
4. Why Do Embedded Engineers Need to Know This?
Embedded Linux engineers encounter TTY/terminal concepts in several real scenarios:
/dev/ttyS0, /dev/ttyUSB0, etc. You need termios to configure baud rate, parity, stop bits, and flow control.termios to put the serial port in raw mode.5. Checking Your Terminal Device
You can check what terminal device is associated with a file descriptor using the ttyname() function or the tty command.
/* Check if a file descriptor refers to a terminal and get its name */
#include <stdio.h>
#include <unistd.h>
int main(void)
{
/* isatty() returns 1 if fd refers to a terminal, 0 otherwise */
if (isatty(STDIN_FILENO)) {
printf("stdin is a terminal: %s\n", ttyname(STDIN_FILENO));
} else {
printf("stdin is NOT a terminal (maybe a pipe or file)\n");
}
if (isatty(STDOUT_FILENO)) {
printf("stdout is a terminal: %s\n", ttyname(STDOUT_FILENO));
} else {
printf("stdout is NOT a terminal\n");
}
return 0;
}
Sample output when run in a terminal emulator:
stdin is a terminal: /dev/pts/3
stdout is a terminal: /dev/pts/3
Sample output when stdout is redirected to a file (./a.out > out.txt):
stdin is a terminal: /dev/pts/3
stdout is NOT a terminal
Notice that stdin is /dev/pts/3 โ a pseudoterminal slave created by the terminal emulator (xterm, GNOME Terminal, etc.). Real serial ports would show up as /dev/ttyS0, USB-to-serial adapters as /dev/ttyUSB0, and virtual consoles as /dev/tty1.
The isatty() check is important in real programs. Many programs (like ls) behave differently depending on whether stdout is a terminal โ for example, ls shows colored output when talking to a terminal, but plain text when output is piped.
6. The Special Device /dev/tty
Linux provides a special device file /dev/tty which always refers to the controlling terminal of the calling process. This is useful when you want to read from or write to the terminal even if stdin/stdout are redirected.
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
int main(void)
{
char password[128];
/* Open controlling terminal directly, bypassing stdin redirection */
int tty_fd = open("/dev/tty", O_RDWR);
if (tty_fd == -1) {
perror("open /dev/tty");
return 1;
}
write(tty_fd, "Enter password: ", 16);
int n = read(tty_fd, password, sizeof(password) - 1);
if (n > 0) {
password[n] = '\0';
/* Remove trailing newline */
if (password[n-1] == '\n') password[n-1] = '\0';
}
write(tty_fd, "\nPassword received.\n", 20);
close(tty_fd);
return 0;
}
This is exactly how programs like sudo prompt for a password even when stdin is a pipe.
Interview Questions โ Part 1
TTY stands for TeleTYpe. Early computer terminals were teletype machines โ electromechanical typewriters that printed output on paper. Even though modern terminals are software (xterm, GNOME Terminal), the kernel still uses the TTY abstraction internally and all terminal devices are still referred to as TTYs. The name stuck because the same kernel driver code handles both old and new terminals.
/dev/tty1 is a virtual console โ a full-screen text-mode terminal that the kernel provides directly (accessed via Ctrl+Alt+F1). /dev/pts/3 is a pseudoterminal slave created by a terminal emulator (xterm, GNOME Terminal). Both are TTY devices from the kernel’s perspective, but the PTY is backed by a user-space emulator while the virtual console is backed directly by the kernel’s console driver.
/dev/tty always refers to the controlling terminal of the current process, regardless of what stdin or stdout are pointing to. This allows a program to access the terminal even when stdin/stdout/stderr are redirected to files or pipes. Classic use cases: password prompts in scripts, and interactive prompts in tools like sudo and ssh-add.
The terminal driver (TTY driver) is a kernel subsystem that sits between the terminal device (physical or emulated) and the user process. It lives inside the Linux kernel. Its responsibilities include:
- Buffering input and output characters
- Handling line editing (Backspace, Ctrl+U to erase line, etc.) in canonical mode
- Generating signals (SIGINT for Ctrl+C, SIGQUIT for Ctrl+\)
- Echo โ automatically sending typed characters back to the output
- Translating newlines, handling CR/LF
isatty(fd) returns 1 if the file descriptor refers to a terminal, 0 otherwise. In practice it is used to:
- Enable/disable ANSI color codes (many programs color output only when talking to a terminal)
- Enable/disable interactive prompts (don’t show “Press Enter to continue” if output is a file)
- Decide whether to buffer output or flush it line by line
The ls, grep --color=auto, and git commands all use isatty() internally.
terminfo (and its predecessor termcap) is a database of terminal capabilities. It maps human-readable capability names (like cup for “cursor position”) to the actual byte sequences a specific terminal understands. It was created because different terminal manufacturers used completely different escape sequences for the same operations, making portable terminal programs nearly impossible to write. The ncurses library uses terminfo under the hood.
Part 2 โ Terminal Modes and I/O Queues Part 3 โ termios Attributes
