Unix, Linux, distributions
Why this matters
Section titled “Why this matters”Linux, macOS and Android are three different systems that behave suspiciously alike.
The same fork and exec, the same rwx permissions, the same pipelines. Yet
they share almost no code.
There are practical reasons to figure out where this similarity comes from.
It explains why a program builds on one system
and fails to build on another, why Apple took BSD code rather than Linux, and why ls
on your machine may turn out to be three different programs.
Unix: 1969
Section titled “Unix: 1969”Multics, a joint project of MIT, Bell Labs and General Electric, was meant to be a time-sharing system for hundreds of users. It kept growing, kept slipping, and eventually Bell Labs pulled out of the project.
Ken Thompson and Dennis Ritchie started writing something radically simpler. The name Unics was a joke at Multics’s expense: that one did things the complicated way and for everyone, this one did them simply and for a few.
In 1973 came the decision that defined everything: the kernel was rewritten in C. Until then kernels were written in assembly, and each was tied to a single machine model. A kernel in a high-level language could be ported to another architecture, and it was portability, not elegance of design, that made Unix the foundation of everything that came after.
The Unix philosophy grew out of the limits of the hardware of its day but outlived them: small programs that do one thing well, text as the universal interface between them, composition instead of monoliths, everything represented as a file.
The split
Section titled “The split”From the seventies on, Unix split into two branches. System V was AT&T’s commercial line, while BSD was developed at Berkeley, and that branch added the TCP/IP network stack, sockets and virtual memory. Much of what is in use today came from there.
In 1983 Richard Stallman started GNU, a project to create a completely free Unix-compatible set of programs. By the early nineties GNU had a compiler, a shell, a C library and hundreds of utilities, but no working kernel.
The kernel was written in 1991 by Linus Torvalds. It did not contain a single line of Unix code: it was an independent implementation of the same interfaces.
A license as a technical decision
Section titled “A license as a technical decision”Licensing decided the fate of systems no less than code quality did.
The GPL, under which Linux and GNU were released, requires you to publish your changes if you distribute them. Because of this, contributions flowed into Linux from companies that could not keep their patches closed, and the kernel became a shared asset of competitors.
The BSD license, by contrast, allows taking the code into closed products with no obligations. That is why the BSD network stack ended up everywhere, and why Apple built macOS on BSD and Mach: taking Linux would have meant opening up the system.
For the same reason Android takes the Linux kernel, because the GPL applies to the kernel and changes
to it are public, but does not take GNU: instead of glibc it has Bionic
under a BSD license, and the rest of user space is not GPL either.
What a distribution is made of
Section titled “What a distribution is made of”The kernel on its own does nothing; it has neither a shell nor utilities. A distribution is the kernel plus everything else.
| Component | Examples | Role |
|---|---|---|
| Kernel | Linux | processes, memory, file systems, drivers |
| C library | glibc, musl, Bionic | wrappers around system calls |
| Init system | systemd, OpenRC, runit | PID 1, starting services |
| Core utilities | GNU coreutils, BusyBox | ls, cp, cat |
| Shell | bash, zsh, ash | command-line interface |
| Package manager | apt, dnf, pacman, apk | installation and updates |
Replace any row of this table and you get a different system.
Alpine Linux uses musl instead of glibc and BusyBox instead of coreutils,
which makes the image dozens of times smaller, but programs built
against glibc simply do not start there. This is the most common cause
of “it fails in Docker but works locally”.
Families
Section titled “Families”Debian and derivatives (Ubuntu, Mint) use apt and the .deb format,
and bet on stability and a huge repository.
Red Hat and derivatives (RHEL, Fedora, Rocky) use dnf and the .rpm format;
Fedora serves as the testing ground for what later lands in RHEL.
Arch ships packages right after release, and the user assembles the system themselves from a minimal base.
Alpine is built on musl and BusyBox for minimal size,
and that made it the standard for containers.
NixOS describes the system configuration declaratively, so an update can be rolled back as a whole.
How these branches diverged over time and what grew out of what is shown on the map in the appendix “History of operating systems”.
Neighbors
Section titled “Neighbors”macOS is a certified UNIX. The XNU kernel combines the Mach microkernel and a BSD subsystem, and user space comes from BSD; there is no GNU there.
Android uses the Linux kernel with significant changes: wakelocks,
Binder for interprocess communication, a separate permission model. Instead of glibc
it has Bionic, and instead of the usual set of utilities, the ART runtime.
WSL2 runs a real Linux kernel in a lightweight virtual machine on top of Hyper-V. The first version of WSL tried to translate Linux system calls into Windows calls and ran into what was discussed in module 3: reproducing someone else’s ABI completely is incredibly hard.
How it actually works in Linux
Section titled “How it actually works in Linux”uname -r; cat /etc/os-release | head -3The kernel version and the distribution version are unrelated. One kernel runs under dozens of distributions.
ldd --version | head -1; ldd /bin/lsWhich C library is in use and what ls is linked against.
On Alpine these commands give a completely different result.
readlink -f /bin/shWhere /bin/sh actually points. On Debian it is dash, not bash,
so a #!/bin/sh script that uses bash extensions will break.
ls /usr/bin | wc -l; dpkg -S /bin/ls 2>/dev/null || rpm -qf /bin/ls 2>/dev/nullHow many programs are on the system and which package a particular one came from. The kernel has nothing to do with any of them.
ps -p 1 -o comm=What runs as PID 1: systemd, init or something else
(module 5).
getconf _POSIX_VERSIONThe POSIX version the system conforms to.
Common misconceptions
Section titled “Common misconceptions”“Linux is an operating system.” Linux is a kernel. The operating system is the distribution: the kernel plus a C library, init, utilities and thousands of packages.
“Linux descends from Unix.” They share no code. Linux is an independent implementation of the same interfaces.
“POSIX means a program will run anywhere.” It means that a program that stays within POSIX will run. Most real-world code uses extensions of a particular system.
“Android is a Linux distribution.” It does have the Linux kernel, but not GNU: a different C library, a different runtime, a different permission model.
“macOS is built on Linux.” It is built on BSD and Mach, and the similar commands come from a common ancestor.
“It fails in the container because Docker is broken.” Most likely the image
is built on Alpine with musl, and the program was built against glibc.
Check yourself
Sources
Section titled “Sources”- The UNIX Time-Sharing System — Ritchie and Thompson, 1974
- Raymond, The Art of Unix Programming — on the Unix philosophy
- Isaacson, The Innovators — the history of the field as a history of people
- Nemeth et al., UNIX and Linux System Administration Handbook
man 7 standards,getconf _POSIX_VERSION