/dev: Explanation & Insights

A Linux directory of special files that stand in for the machine's hardware and kernel services, so programs can reach devices through ordinary file reads and writes.

What It Is

/dev is the directory where your hardware pretends to be files.

Every disk, every terminal, every sound card, the random-number generator, even the black hole you throw unwanted output into — each of them shows up here as something that looks like a file. It has a name, it has an owner, it has permission bits, you can cat it and redirect into it. But open one and there's no document waiting inside. The "file" is a labelled doorway, and behind it stands a piece of the kernel — a device driver — ready to answer. Read from /dev/sda and the kernel fetches bytes off a spinning platter. Write to /dev/null and they vanish. The file is the handle; the driver is the thing on the other end of it.

That is the whole idea of /dev, and it is Unix's oldest and boldest bet made concrete: everything is a file. Not "everything is sort of like a file if you squint" — everything is a file you can open, read, and write with the exact same handful of system calls, whether it's a text document, a hard drive, or the keyboard under your fingers. /dev is where that promise stops being a slogan and becomes a directory you can list.

List it and the first character of every line tells you what kind of thing you're looking at:

$ ls -l /dev | head
crw-------   1 root  root     10,   260 Jul  7 08:54 acpi_thermal_rel
drwxr-xr-x   2 root  root           180 Jul  7 09:03 block
crw-------   1 root  root     10,   234 Jul  7 08:54 btrfs-control
drwxr-xr-x   2 root  root          4800 Jul 12 14:07 char
crw-------   1 root  root      5,     1 Jul  7 08:54 console
lrwxrwxrwx   1 root  root            11 Jul  7 08:54 core -> /proc/kcore
brw-rw----   1 root  disk    254,     0 Jul  7 08:54 dm-0
crw-rw-rw-   1 root  root      1,     7 Jul  7 08:54 full
crw-rw-rw-   1 root  root     10,   229 Jul  7 08:54 fuse
crw-------   1 root  root     89,     0 Jul  7 08:54 i2c-0

That leading letter is the label on the doorway. d is an ordinary directory (/dev has a few, holding related devices). l is a symlinkcore just points off to /proc/kcore. But the two that matter, the two you'll see everywhere here and almost nowhere else on the whole system, are c and b: a character device and a block device. Nearly every line in /dev starts with one of those two letters, and the difference between them is the difference between how the kernel talks to a keyboard and how it talks to a disk.

Why It Matters

Because once hardware is a file, the tools you already have just work on it, and a surprising amount of a server's real work is exactly that.

You back up a whole disk with dd if=/dev/sda of=disk.img — no special "disk-reading program", just a copy from one file to another, where one of the files happens to be a physical drive. You format a partition, and mkfs writes a filesystem onto /dev/sdb1 the same way you'd write text into a document. You mount a drive by naming its device file. When something reads your CPU temperature, it opened a file under here. The reason Unix people can build a hundred tools that each do one thing and pipe them together is that they all speak the same language — bytes in and out of files — and /dev extends that language all the way down to the metal. A disk is not a special case. It is a file that is very large and very careful.

There's a humbler reason too. When a drive starts misbehaving and you need to point smartctl at the actual physical disk, or figure out which of six identical NVMe sticks is the sick one, or confirm the RAID array grabbed the members you meant — /dev is the map. Every real device on the machine has an entry here, and learning to read those entries is learning to see the hardware the way the kernel sees it.

Character Devices and Block Devices

The c/b split runs deep in the kernel, and it's worth understanding because it explains half of what you see in /dev.

A character device (c) is a stream. Bytes flow through it one after another, in order, like water through a hose — you read what comes next, you write and it goes out the end. A keyboard is a character device: keystrokes arrive in the order you type them and there's no such thing as "seek back to the third keystroke." A serial port, a terminal, /dev/null, /dev/random — all streams, all c. There's no notion of position that matters; there's just the next byte.

A block device (b) is addressable. It's a huge array of fixed-size chunks — blocks, historically 512 bytes, now usually 4 KB — and you can jump straight to block number 4,000,000 and read it without touching the four million before it. That random access is exactly what a filesystem needs, because a file's data is scattered across the disk and the kernel has to leap around to gather it. Every disk, every partition, every SSD is a block device. And because they're addressable, block devices get buffered — the kernel keeps recently-touched blocks in a memory cache rather than hitting the platter every time, which is why the second read of a file is so much faster than the first.

Here's the tell that gives the whole scheme away. Look again at where a device file lists its size:

brw-rw----   1 root  disk    254,     0 Jul  7 08:54 dm-0
crw-rw-rw-   1 root  root      1,     7 Jul  7 08:54 full

Where an ordinary file shows a byte count, a device file shows two numbers254, 0 and 1, 7. That's not the size. A device doesn't have a size; a driver isn't a certain number of bytes long. Those two numbers are the device's address inside the kernel — and they are the actual machinery of the whole directory.

Major and Minor Numbers: The Name Is a Decoy

When you open /dev/null, the kernel does not care that the file is called "null." It doesn't care that it lives in /dev. It reads two small numbers stamped on the file — the major and minor number — and routes your request by those, and those alone. The major number says which driver handles this device; the minor number says which specific instance that driver should use. The name on the door is a courtesy for you. The wiring behind it runs entirely on the numbers.

You can see them plainly:

$ stat -c '%n major=%t minor=%T' /dev/null /dev/zero /dev/urandom
/dev/null major=1 minor=3
/dev/zero major=1 minor=5
/dev/urandom major=1 minor=9

All three share major 1 — that's the kernel's "memory" driver, the one that runs the synthetic devices — and the minor number picks which of its personalities you get: 3 is the bit-bucket, 5 is the zero-fountain, 9 is the random tap. One driver, three doors, told apart by a single number.

And those two numbers aren't your machine's idea. /dev/null is major 1, minor 3 on essentially every Linux machine ever booted — your laptop, a Raspberry Pi, a supercomputer, a phone. It's not 1,3 because someone on your system decided so; it's 1,3 because there is an actual registry. Device numbers are handed out by a body called the Linux Assigned Names and Numbers Authority — LANANA, a name so gloriously bureaucratic it sounds invented — which keeps the master list of who owns which major number, the way a phone company owns area codes. Driver 1 is memory devices; minor 3 within it is, forever, /dev/null. There is a document in the kernel source that is, quite literally, the phone book for hardware.

Which leads to the punchline. Because the name is just a label, you can make your own /dev/null anywhere you like. Point mknod at any path, tell it "character device, major 1, minor 3," and you get a second, fully working bit-bucket — call it /tmp/oblivion if you want — that swallows bytes exactly like the original, because to the kernel it is the original: same two numbers, same door. Rename /dev/null itself and it keeps working. The power was never in the word "null." It was in the numbers the whole time.

Note

This is also why device names like /dev/sda and /dev/sdb can quietly swap between reboots — the kernel assigns them in the order it finds the disks, and that order isn't guaranteed. If you need a name that always points at the same physical drive, use the stable symlinks under /dev/disk/by-id or /dev/disk/by-uuid, which are keyed to the drive's serial or filesystem, not to the luck of the boot-time draw. Pulling the wrong disk during a RAID rebuild because sdb became sdc overnight is a classic, avoidable heartbreak.

The Synthetic Devices

Some of the most-used files in /dev have no hardware behind them at all. They're pure kernel functions wearing a device costume — a driver that computes an answer instead of fetching one. Ask udev where /dev/null actually comes from and it tells on itself:

$ udevadm info -q all -n /dev/null
P: /devices/virtual/mem/null
M: null
U: mem
E: DEVNAME=/dev/null
E: MAJOR=1
E: MINOR=3
E: SUBSYSTEM=mem

virtual/mem — a virtual device, no bus, no cable, no chip. There are a handful of these and every admin leans on them daily:

  • /dev/null — the bit-bucket. Everything written to it is discarded; reading it gives instant end-of-file. This is where 2>/dev/null sends the error messages you don't want to see. It is the most obedient thing in computing: hand it anything, and it faithfully does nothing with it.
  • /dev/zero — an infinite fountain of zero bytes. Read a gigabyte, get a gigabyte of \0. Used to wipe a disk, to pre-fill a file to a fixed size, to feed a benchmark something to chew on.
  • /dev/random and /dev/urandom — the random taps, where a machine built to be perfectly predictable reaches for genuine unpredictability (it gathers entropy — real physical noise, the timing jitter of interrupts and disk seeks — because a deterministic box can't manufacture surprise on its own). Reach for /dev/urandom when you need a key, a password, or a token.
  • /dev/full — remarkable, because its entire job is to be broken. /dev/full is a device that is permanently, deliberately out of space: every write to it fails instantly with "No space left on device," on purpose, forever. The kernel ships you a pre-broken disk so you can rehearse disaster — pipe your program's output at /dev/full and watch how it behaves the day a real drive fills up, without having to fill a real drive to find out. A fire drill you can echo into.

Pro Tip

/dev/null is safely world-writable — crw-rw-rw-, anyone can throw bytes at it — precisely because it does nothing with them; there's no harm a stranger can do to a black hole. That permission model is the whole point of /dev: the danger isn't the file, it's the driver behind it, and the bits are set accordingly. /dev/null is open to all. /dev/sda most certainly is not.

Permissions and the disk Group

Which brings us to the quietest security boundary on the machine. Look at a real disk:

$ ls -l /dev/nvme0n1
brw-rw---- 1 root disk 259, 0 Jul  7 08:54 /dev/nvme0n1

Owner root, group disk, and rw-rw----: root can read and write it, members of the disk group can read and write it, and nobody else can touch it. That group line is not decoration — it is one of the most powerful grants on a Linux system, and it's easy to hand out by accident.

A block device is the raw disk, the bytes underneath everything. File permissions — the chmod 600 secrets.txt you set so only you can read your secrets — live inside the filesystem. But the raw device sits below the filesystem, and reading it directly means reading every block on the platter, including the ones holding other people's carefully-locked files. Anyone who can read /dev/nvme0n1 can, with enough patience, read everything on it — passwords, keys, the lot — walking straight past every permission bit set on every file above. That's why adding a user to the disk group is very nearly the same as making them root. The group looks innocent. It is not.

How I Inspect It

/dev was built for the tools you already own, so none of this needs anything special. The everyday moves:

# What's actually here, and what kind (c/b/d/l in the first column)
ls -l /dev

# The full identity of one device: type, major, minor
stat /dev/null

# Where does this device really come from? (driver, subsystem, virtual or real)
udevadm info -q all -n /dev/nvme0n1

# The disks and partitions as a readable tree, with sizes and mount points
lsblk

# Stable names that survive a reboot's disk-reordering
ls -l /dev/disk/by-id

stat is the one I reach for most when a device confuses me:

$ stat /dev/null
  File: /dev/null
  Size: 0         Blocks: 0          IO Block: 4096   character special file
Device: 0,6 Inode: 4            Links: 1     Device type: 1,3
Access: (0666/crw-rw-rw-)  Uid: (    0/    root)   Gid: (    0/    root)

There it is in plain English — "character special file," device type 1,3, mode crw-rw-rw-. Everything the terse ls -l line was telling you, spelled out.

/dev/pts: Where Your Terminal Isn't

One corner of /dev deserves its own moment, because you are almost certainly sitting inside it right now. List it:

$ ls -l /dev/pts
crw------- 1 arndt tty  136, 0 Jul  7 08:55 0
crw------- 1 arndt tty  136, 1 Jul 12 17:57 1
crw------- 1 arndt tty  136, 2 Jul 12 18:16 2
c--------- 1 root  root   5, 2 Jul  7 08:54 ptmx

Each numbered file is a pseudoterminal — a fake terminal — and there's one for every shell session you have open. SSH into a server and you get one. Open a second tmux pane and you get another. Above there are three: three live sessions, each talking to its own /dev/pts/N believing it's a real terminal.

And the "believing" is not just a figure of speech. Those files are called tty — group tty, right there in the listing — and tty is short for teletype: the clattering electromechanical typewriters, all levers and ribbon and paper, that people used to talk to computers with in the 1960s, before screens. A program printed a line and a physical machine hammered it onto a roll of paper across the room. The kernel learned to speak to those machines, and it never forgot how. So today, when your sleek encrypted SSH session connects, the kernel greets it as if it were a Teletype Model 33 chattering away on a paper roll — and your terminal, keeping up the act, politely pretends to be one. ptmx is the puppeteer's handle (the "master"); /dev/pts/0 is the puppet your shell sees. Half a century after the last teletype was unplugged, every terminal window on Earth is still doing an impression of one.

Where Did All the Devices Go? A Short History

Here's a question worth asking, because the answer is a small story. If /dev needs a file for every device, and there are thousands of possible devices, who makes all those files?

For most of Unix's life, the answer was: you did, by hand, in advance. /dev was an ordinary directory on the disk, and it shipped stuffed with device nodes — hundreds, sometimes thousands of them — created ahead of time with mknod for every device the system might conceivably have, whether or not it was plugged in. There was a script called MAKEDEV whose whole job was to churn out this pile of files: a node for the fourth SCSI disk you didn't own, for the eighth serial port that wasn't there, for tape drives nobody had seen in years. /dev was a warehouse of doorways, most of them opening onto nothing, kept just in case.

It worked, but it was absurd, and as hardware got hot-pluggable — USB sticks, drives appearing and vanishing while the machine ran — it stopped working at all. A static list can't keep up with a world where you plug in a webcam and expect it to appear. So Linux fixed it, in stages. First devfs (an early-2000s attempt, later abandoned for being racy and awkward). Then the approach that won: udev, arriving in 2003, backed a little later by devtmpfs — a /dev that lives entirely in RAM and is rebuilt from scratch at every boot. Now the kernel notices real hardware as it appears, creates a node for it on the spot, and udev — using the hardware's own descriptions from /sys — gives it a sensible name and the right permissions. Plug in a USB drive and watch /dev/sdc wink into existence in real time. Unplug it and it's gone.

So the warehouse of empty doorways is gone, replaced by a directory that mirrors, moment to moment, exactly the hardware you actually have. /dev used to be a guess made in advance; now it's a live photograph of the machine.

That whole "everything is a file" idea, by the way, is where the phrase was born — Unix's designers at Bell Labs in the early 1970s decided the cleanest way to handle a bewildering zoo of hardware was to make it all look like the one thing every program already knew how to use: a file. /dev was the first place they aimed that idea, and half a century on it's still the clearest expression of it. Its sibling /proc later pointed the same trick at the kernel's own running state, and /sys at the hardware's wiring — but /dev was here first, turning the disk itself into something you could cat.

Cheat Sheet

Command What it tells you
ls -l /dev Everything here; first column is the type (c, b, d, l)
stat /dev/sda One device's type, major/minor, and permissions, spelled out
lsblk Block devices as a readable tree, with sizes and mount points
udevadm info -q all -n /dev/sda Where a device really comes from — driver, subsystem, real or virtual
ls -l /dev/disk/by-id Stable names keyed to serials, immune to boot-time reordering
ls /dev/pts Every open pseudoterminal — one per shell session
cat /proc/devices The major-number registry as your kernel currently sees it

Reading the first column of ls -l /dev at a glance:

First char Meaning
c Character device — a byte stream (terminals, /dev/null, /dev/random)
b Block device — addressable storage (disks, partitions, /dev/dm-0)
d An ordinary subdirectory (/dev/pts, /dev/disk, /dev/block)
l A symlink to another device or path (/dev/core/proc/kcore)

See Also

  • /proc — the sibling virtual filesystem, aiming "everything is a file" at the kernel's live state
  • /sys — the hardware-and-driver tree that udev reads to name the devices in /dev
  • The root directory — where /dev hangs, and the tree it descends from
  • udev — the daemon that populates /dev and gives devices their names and permissions
  • /dev/null — the bit-bucket, in full
  • /dev/random — the entropy tap, and why real randomness is hard to make
  • file descriptor — the small integers a process uses to hold any of these files open
  • mount — how a block device under /dev becomes a directory you can use
  • lsblk and stat — the tools that turn a /dev entry into something readable
  • RAID — arrays built out of the block devices you find here

When a disk under /dev starts to fail, would you rather find out from a dashboard or from a dead server?

CleverUptime watches the real devices on your machine — disk space, temperature, the drives your data actually lives on — and tells you in plain language the moment one starts to slip, so you meet the problem while it's still just a warning.

Want to see your own server's health right now? One command, no signup, no install.

Check your server →