Pseudoterminals (PTY) Introduction & Architecture

 

Chapter 64: Pseudoterminals (PTY)
Part 1 of 3 โ€” Introduction & Architecture
3
HTML Parts
PTY
Core Concept
TLPI
Chapter 64

๐Ÿ“š Chapter Navigation
โ–ถ Part 1: Introduction & Architecture Part 2: Opening PTY Master Part 3: ptyFork() Deep Dive

What is a Pseudoterminal?

A pseudoterminal (PTY) is a pair of virtual devices โ€” a master and a slave โ€” that together behave like a real terminal (like a serial port or keyboard+screen). However, they are purely software-based and live entirely in the kernel. No physical hardware is involved.

The slave side looks exactly like a real terminal to any process that opens it. The master side is held by a controlling application (like an SSH server or a terminal emulator) that reads from and writes to the slave on behalf of the actual user.

Key Terms in This Part

PTY Master PTY Slave Terminal Emulator UNIX 98 PTY BSD PTY Controlling Terminal /dev/ptmx /dev/pts/N Line Discipline

๐Ÿ—๏ธ PTY Architecture โ€“ Master & Slave

The master and slave are two ends of a bidirectional channel. The slave end has a line discipline just like a real terminal โ€” it handles things like echo, newline processing, and Ctrl+C signal generation. The master end is what the controlling program (e.g., ssh, xterm) talks to.

User Program
(e.g. bash, vim)
opens /dev/pts/N

โ‡„

PTY Slave
/dev/pts/N
Line Discipline

โ‡„

PTY Master
/dev/ptmx
fd from open()

โ‡„

Controlling App
(e.g. sshd, xterm)
read()/write()
Data typed by user โ†’ Controlling App โ†’ PTY Master โ†’ (kernel) โ†’ PTY Slave (Line Discipline) โ†’ User Program reads it

โ“ Why Do We Need Pseudoterminals?

Many programs behave differently depending on whether their standard input/output is a real terminal or a pipe. For example:

  • ls shows colored output on a terminal but plain text through a pipe.
  • Programs like vim, top, and bash require a terminal โ€” they use isatty() to check.
  • SSH, telnet, and terminal emulators (xterm, gnome-terminal) all need to create a virtual terminal for the remote/child shell to run in.

Pseudoterminals solve this: the slave side passes the isatty() check because it truly is a terminal device (just a virtual one).

๐ŸŒ Real-World Use Cases

๐Ÿ–ฅ๏ธ
Terminal Emulators
xterm, gnome-terminal, kitty โ€” slave is the shell’s terminal
๐Ÿ”’
SSH / Telnet
Remote login โ€” PTY gives remote shell a local terminal feel
๐Ÿ“
script(1)
Records terminal sessions โ€” uses PTY to capture all output
๐Ÿค–
Expect
Automates interactive programs by driving their PTY
๐Ÿงช
Testing Tools
pytest-pty, pexpect โ€” drive interactive CLI programs in tests
๐Ÿณ
Docker / Containers
docker run -t allocates a PTY for interactive container shells

๐Ÿ“œ UNIX 98 PTY vs BSD PTY

There are two historical styles of pseudoterminals in Linux:

UNIX 98 (POSIX) PTY โœ…
  • Single multiplexed master device: /dev/ptmx
  • Slaves appear as /dev/pts/0, /dev/pts/1 โ€ฆ
  • Uses posix_openpt(), grantpt(), unlockpt(), ptsname()
  • Modern, preferred approach on Linux
  • Defined by UNIX 98 / POSIX standard
BSD PTY (Legacy) โš ๏ธ
  • Pre-allocated master devices: /dev/ptyXY
  • Slaves: /dev/ttyXY
  • Must search for a free pair manually
  • Limited number of pairs available
  • Still used on older BSDs; legacy on Linux

TLPI Chapter 64 focuses on UNIX 98 style. The ptyMasterOpen() function (Section 64.3) is designed to hide these differences so the same calling code works with both styles.

โš™๏ธ The Line Discipline โ€“ What It Does

Every terminal device (real or virtual) has a line discipline sitting between the hardware (or PTY master) and the user process. It is a kernel module that performs processing on the raw byte stream.

PTY Master (Controlling App writes bytes here)
โ†“
Line Discipline (N_TTY)

  • Echo: echoes typed characters back
  • Canonical mode: buffers input until newline
  • Signal generation: Ctrl+C โ†’ SIGINT, Ctrl+Z โ†’ SIGTSTP
  • Erase/kill: Backspace erases previous char
  • Flow control: Ctrl+S / Ctrl+Q (XON/XOFF)
โ†“
PTY Slave (User Program reads processed bytes)

The line discipline can be switched to raw mode (no processing) using tcsetattr() โ€” this is what programs like vim and ssh do when they want full control of every keystroke.

๐Ÿ’ป Verifying PTY Devices on Your System

Run these commands to see pseudoterminals in action on a Linux system:

/* List all current PTY slave devices */
$ ls -la /dev/pts/
total 0
crw--w---- 1 ravi tty  136, 0 Jun 18 10:00 0
crw--w---- 1 ravi tty  136, 1 Jun 18 10:05 1
c--------- 1 root root   5, 2 Jun 18 10:00 ptmx

/* Each open terminal window = one /dev/pts/N entry */
/* /dev/pts/ptmx is equivalent to /dev/ptmx */

/* Check what PTY your current shell is using */
$ tty
/dev/pts/0

/* Check if stdin is a terminal */
$ ls -la /proc/self/fd/0
lrwx------ 1 ravi ravi 64 Jun 18 10:00 /proc/self/fd/0 -> /dev/pts/0
/* Minimal C program: check if fd 0 is a terminal */
#include <stdio.h>
#include <unistd.h>

int main(void)
{
    if (isatty(STDIN_FILENO))
        printf("stdin is a terminal (PTY or real)\n");
    else
        printf("stdin is NOT a terminal (pipe or file)\n");
    return 0;
}

/* 
 * Compile: gcc -o check_tty check_tty.c
 * Run directly:  ./check_tty        -> "stdin is a terminal"
 * Run via pipe:  echo "" | ./check_tty -> "stdin is NOT a terminal"
 */

๐ŸŽฏ Interview Questions โ€“ PTY Introduction
Q1. What is a pseudoterminal and how is it different from a real terminal?

A real terminal is a physical device (serial port, keyboard+screen). A pseudoterminal is a kernel-emulated pair of devices (master + slave) that behaves exactly like a terminal but requires no hardware. The slave passes isatty() checks; the master is a file descriptor held by a controlling application.

Q2. What is the role of the line discipline in a PTY?

The line discipline (typically N_TTY) sits between the PTY master and slave in the kernel. It performs input processing โ€” character echo, canonical buffering, signal generation (Ctrl+C โ†’ SIGINT), erase/kill handling, and flow control. It can be disabled by setting the terminal to raw mode via tcsetattr().

Q3. Why do terminal emulators like xterm or gnome-terminal use PTYs?

The shell (bash, zsh) running inside the emulator must have a real terminal as its controlling terminal. A PTY slave serves this role. The terminal emulator holds the master side and renders characters received from the slave, while forwarding user keystrokes to the slave.

Q4. What is the difference between UNIX 98 PTY and BSD PTY?

UNIX 98 PTY uses a single multiplexed master /dev/ptmx and dynamically creates slaves under /dev/pts/. BSD PTY uses pre-allocated static device pairs (/dev/ptyXY + /dev/ttyXY) and requires searching for a free pair. UNIX 98 is the modern standard on Linux.

Q5. Name three programs that use pseudoterminals and explain why.

(1) sshd โ€” allocates a PTY so the remote shell has a controlling terminal for interactive use. (2) script(1) โ€” uses a PTY to capture all terminal I/O (including control sequences) to a file. (3) expect โ€” drives interactive programs automatically by writing to and reading from the PTY master.

Q6. What does isatty(fd) check, and how does a PTY slave pass this check?

isatty() calls tcgetattr() internally. If the call succeeds (returns 0), the fd is a terminal; if it fails with ENOTTY, it is not. A PTY slave passes this check because it is a genuine character device with a line discipline, registered as a terminal in the kernel โ€” tcgetattr() succeeds on it.

Next: Opening a PTY Master
Learn posix_openpt(), grantpt(), unlockpt(), ptsname() and the ptyMasterOpen() helper

Part 2: Opening PTY Master โ†’ Part 3: ptyFork()

Leave a Reply

Your email address will not be published. Required fields are marked *