What Is a Pseudoterminal?
A pseudoterminal (PTY) is a pair of virtual devices — a master and a slave. They behave like a real terminal but exist entirely in software. Whatever the master writes, the slave reads, and vice versa. This lets programs that expect a real terminal (like a shell) work over network connections, inside terminal emulators, or inside scripts.
Think of it this way: when you open a terminal window (like xterm or GNOME Terminal), it doesn’t connect to a real physical serial port. Instead it creates a PTY pair. The terminal emulator holds the master side. The shell runs on the slave side.
| Terminal Emulator (xterm, GNOME Terminal) Holds Master fd |
⟵⟶ PTY Pair Kernel IPC |
Shell / Program (bash, ssh session) Holds Slave fd |
| Master (/dev/ptmx) ↔ Slave (/dev/pts/N) — kernel passes data between them with full terminal semantics | ||
Multiple processes can connect to the slave side of a pseudoterminal. A common example is ssh: the session leader on the slave side is a shell, and that shell spawns process groups for each command the remote user runs. All those processes share the pseudoterminal slave as their controlling terminal.
Just like a real terminal, only the foreground process group can read from the slave. If the TOSTOP bit is set in the terminal settings, background processes that try to write to the slave get a SIGTTOU signal.
| SSH Client Remote user types commands |
⟶ | PTY Master sshd holds this fd |
⟶ |
|
Pseudoterminals are not just for network services. They power many everyday Linux tools:
| Tool / Program | How It Uses PTY | Why PTY Is Needed |
|---|---|---|
expect(1) |
Drives interactive programs from a script | Program requires a terminal to run; PTY fakes one |
xterm, gnome-terminal |
Terminal emulator windows | Provides terminal I/O inside a GUI window |
screen(1), tmux |
Terminal multiplexer | Multiplexes one physical terminal across many shells |
script(1) |
Records all shell session I/O to a file | PTY captures both input and output transparently |
| stdio buffering workaround | Force line-buffering instead of block-buffering | stdio uses line-buffering when stdout is a terminal; PTY fakes this |
stdio functions use block buffering — output is held until the buffer fills up. But when writing to a terminal, stdio uses line buffering — output flushes on every newline. By connecting a program’s stdout to a PTY slave instead of a pipe, you can force line-buffered behavior even when you ultimately redirect to a file. This is a useful trick for logging tools.Historically there were two different ways to open and use PTYs, coming from two different UNIX branches:
| Feature | BSD PTY | System V / UNIX 98 PTY |
|---|---|---|
| Origin | BSD UNIX | AT&T System V UNIX |
| Ease of use | More complex | Simpler API |
| Standard | Not standardized | SUSv3 / POSIX standard |
| Linux support | Since early Linux (pre-2.2) | Since kernel 2.2 |
| Recommended for new code | No | Yes — use this |
The UNIX 98 name comes from UNIX 98 (SUSv2), but there is a historical nuance: the original SUSv2 required PTYs to be STREAMS-based, and the Linux implementation is not STREAMS-based. SUSv3 removed the STREAMS requirement, so the Linux implementation is fully conformant with modern standards.
In this chapter, UNIX 98 pseudoterminals are the focus. The key device involved is /dev/ptmx (the PTY master multiplexer).
Key Terms
A pseudoterminal is a software-only pair of virtual devices (master + slave) that behave like a real terminal. A real terminal is a physical or serial device. A PTY has no hardware — it exists entirely in the kernel. Both support terminal semantics (line discipline, job control, TOSTOP, etc.), but PTY data flows between two processes rather than between a process and hardware.
(1) ssh — remote shell sessions over network. (2) xterm / gnome-terminal — GUI terminal emulators. (3) screen / tmux — terminal multiplexers. (4) script(1) — recording shell sessions. (5) expect(1) — automating interactive programs from scripts.
When a program writes to a pipe or file, stdio block-buffers output. When writing to a terminal, it line-buffers. By connecting stdout to a PTY slave, the program thinks it is writing to a terminal and switches to line-buffering automatically, without any code changes in the target program.
BSD PTYs predate System V PTYs and use a more complex API. System V PTYs use a simpler, POSIX-standardized interface based on /dev/ptmx and functions like posix_openpt(), grantpt(), unlockpt(), and ptsname(). Linux supports both since kernel 2.2, but new code should always use the UNIX 98 (System V) interface.
TOSTOP is a terminal line discipline flag. When set, any background process group member that tries to write to the terminal (or PTY slave) receives a SIGTTOU signal and is stopped. Only the foreground process group is allowed to write. This same behavior applies to PTY slaves just like real terminals.
The sshd daemon holds the master side of the PTY. It reads from the master what the remote user types and writes to the master what should be displayed. The shell (and all processes it spawns) runs with the slave side as its controlling terminal. This is the standard master-driver / slave-program model.
Continue Learning
Next: Opening a PTY Master with posix_openpt() and PTY limits
Part 2: posix_openpt() & PTY Limits → Part 3: grantpt / unlockpt / ptsname →
