Education

What really happens inside a terminal

A terminal is just a channel for text — keystrokes in, output back. This interactive guide opens one up: read the w command line by line, tell a real TTY from a pseudo-terminal (pts), follow a keystroke through the master/slave pair, and see how one terminal's device can be read — and the permissions that stop it.

  • The w command
  • TTY vs PTS
  • Pseudo-terminals
  • Reading /dev/pts
  • Permissions

Everything below is interactive — decode a w listing, cat a device file, and watch two readers fight over one terminal.

Start here

So… what is a terminal, anyway?

A terminal is just a channel for text: the keys you press go in, and a program's output comes back out. That's it. The word is older than screens — it comes from the teletype, a typewriter wired to a far-away computer. Today almost every terminal you use is faked in software: your SSH session, the terminal app on your laptop, a tmux window. They all pretend to be that old machine.

On a shared Linux server, several people can be connected at once. A single command — w — shows them all and what each is doing. Reading its output raises every question this guide answers: what is pts/0? Why does one session show -bash and another a running program? And could one user read what another is typing?

1 · You type

Your keystrokes become bytes and travel toward the machine — over SSH, through your terminal app, whatever the path is.

2 · A terminal device

The kernel gives the session a terminal device — a file like /dev/pts/3 — that sits in the middle, buffering and relaying the text both ways.

3 · A program reads it

Your shell (bash) reads from that device, echoes what you typed, runs your command, and writes the result back out the same way.

We'll walk it in order: read the w output, learn TTY vs PTS, open up the pseudo-terminal pair, see why cat-ing a device hangs instead of showing nothing, then the part everyone remembers — reading another user's terminal — and why permissions (and good manners) make it stop. Each stop has something to click.

Who's connected

The w command, column by column

w shows who is logged in and what they're doing right now. Here's an example snapshot from a shared server. Tap any column heading (or a row) to see exactly what it means — the headings are the tricky part.

The key point about WHAT

The WHAT column is the session's current foreground process — a live snapshot of what holds the terminal this instant, not a history of past commands. w reads it from the process table; it's best-effort (it shows the process-group leader), so for pipelines it can be approximate, but for a normal session it's accurate.

Names in /dev

tty, pts — what are those?

TTY stands for teletypewriter — those original wired typewriters. Today it just means “a terminal device,” and every terminal is a file under /dev. There are two broad kinds, and the names in w's TTY column tell you which is which.

Real terminals — tty1tty6

The actual text consoles on a machine with a screen attached. You reach them with Ctrl + Alt + F1…F6. They're /dev/tty1, /dev/tty2… — hardware-backed, no network involved.

Pseudo-terminals — pts/0, pts/1

Software-emulated terminals (/dev/pts/N). Anything virtual uses one: an SSH login, your terminal app, each tmux/screen window. The number is just allocation order — nothing meaningful.

bash
tty           # which terminal is THIS shell on?  →  /dev/pts/3
ls /dev/pts   # list every active pseudo-terminal  →  0  1  2  3  4  ptmx
who           # like w, but just users + their tty + login time

That weird FROM value: :pts/1:S.0

In the snapshot, one session's FROM was :pts/1:S.0 instead of an IP. That means it wasn't a fresh network login — it was spawned from inside pts/1, specifically screen window S.0. So that rsync is running in a screen window living under the pts/1 session.

A matched pair

A pseudo-terminal is two ends of one pipe

A pty always comes as a pair. One side — the master — is held by the program that manages the terminal (sshd, your terminal app, screen). The other side — the slave, /dev/pts/N — is what your shell and programs talk to as if it were real hardware. The “s” in pts is that slave end.

Press a key below and follow one byte: input flows master → slave → shell; the shell's output flows back shell → slave → master → your screen. Same wire, both directions.

This is why a “terminal” can exist with no screen, keyboard or network card anywhere near it: it's just a kernel object with two file descriptors. SSH, tmux and screen are all masters wrapping a slave the shell never knows is fake.

Not files — devices

Why cat /dev/tty1 looks “empty” (it isn't)

Try to cat a terminal and nothing appears — it just sits there. It looks like an empty file. It isn't. These aren't files with contents at all; they're character devices (the c at the start of crw--w----). cat doesn't read stored bytes — it opens the device and asks the kernel for live input. A terminal has no end-of-file, so cat blocks forever waiting for input that never comes. Not empty — a live stream with nothing flowing.

Run cat on a few different device files and watch what each one does. Hit Ctrl + C to stop the ones that hang or stream.

file /dev/tty1character special (4/1)

A regular file shows a byte size. A device shows two numbers instead — the major/minor (here 4/1): major 4 is the tty driver, minor 1 is tty1. They have no size because they aren't storage — they're an address into a kernel driver. /dev/null is the one that truly is always empty: it returns end-of-file instantly.

Reading the device

Reading someone else's terminal

Here's the part that feels like magic. As root, cat /dev/pts/0 opens another user's terminal. But remember: a terminal's input is consumed, not broadcast — the kernel hands each typed character to exactly one reader. So when you attach your cat to a live session, every keystroke that user types is split between their shell and your cat, semi-randomly.

That means it's not a quiet wiretap. It steals input from the real user and garbles their session — characters vanish on them while fragments land in your cat. A clean command can arrive as gibberish, its characters scattered between the two readers. Run the demo and watch one command get torn in two.

This is a real snooping vector — treat it that way

Reading another person's terminal is classic eavesdropping, and on a machine you don't administer it's unauthorized access — don't do it. It belongs in your toolkit only for your own systems and authorized debugging. Next we'll see exactly why a normal user usually can't do this — and how to legitimately watch a session without hijacking it.

Why it's usually blocked

Permissions: who is allowed to read a terminal

When the kernel creates a pty it sets the owner to the session's user and a mode of roughly crw--w----. Decode it: owner gets rw-, group (tty) gets -w- (write only — that's for wall/write messaging, not reading), and everyone else gets --- (nothing). So a normal “other” user simply can't open it to read. Flip the bits below and see who can snoop.

The catch: root ignores file permissions entirely. The mode is irrelevant to root — that's why root could read pts/0 reliably. And if a non-root user ever can read someone's tty, the perms aren't stock — check ls -l /dev/pts/N and id: you may be in the tty group, or the device is looser than the default.

Ending a session

Can you rm /dev/pts/1 to kick someone? No.

Tempting idea: delete the device file and the user drops. It doesn't work — for two reasons. First, /dev/pts is a kernel-managed virtual filesystem (devpts); its entries appear and vanish automatically as ptys open and close — rm can't really remove them. Second, even deleting a device node never kills the process using it: processes hold the terminal by an open file descriptor, not by its path. The name is just a label (the same reason deleting an open file doesn't free its disk space until the program closes it).

bash · as root
ps -t pts/1        # what's running on that terminal?
pkill -t pts/1     # SIGTERM every process on pts/1  (the normal way)
pkill -9 -t pts/1  # force it, if they won't go
# or end the login shell / sshd session by PID:
ps -ft pts/1
kill -HUP <pid>     # a clean "hang up", like the line dropped

Want to watch a session — without stealing input?

Don't cat the device. Use a tool built for it: script records a session to a file, a shared tmux (tmux new -s demotmux attach -t demo) or screen -x lets two people see the same terminal and its output is mirrored, not consumed. That's the legitimate way to pair, teach or supervise — no garbled keystrokes, nobody snooped.

In one breath

The whole journey, recapped

  1. A terminal is a two-way text channel; w lists every live session on a machine.
  2. In w, WHAT is the session's current foreground process — a live snapshot, not command history.
  3. TTY = teletype = terminal device. tty1…tty6 are real consoles; pts/N are pseudo-terminals (SSH, terminal apps, tmux/screen).
  4. A pseudo-terminal is a master/slave pair: input goes master→slave→shell, output goes back the same wire.
  5. Terminal device files are character devices with no EOFcat blocks waiting for live input; it isn't “empty”.
  6. Reading /dev/pts/N steals and splits the victim's keystrokes — it eavesdrops and garbles their session.
  7. Permissions (crw--w----: owner rw, group tty write-only, others nothing) stop normal users — but root bypasses them all.
  8. You can't rm a session away (fd keeps it alive); end it with pkill -t, and watch one with script/tmux, never by snooping.