Skip to content
ALB Wiki

Diff — Inside a Linux System

Comparing rev 4 → rev 5

{{infobox
| title = Inside a Linux System
| chapter = Linux Handbook, chapter 17 — the boot sequence, init, services, the anatomy
| core | kernel + initramfs + PID 1 + services + login — the whole arc
| paths = SysVinit (the readable path) · systemd (the standard path)
| skills | boot chain · runlevels/units · service management · logs
| next | Networking — the system's window outward
}}
**A Linux system is an arc**: firmware hands to a bootloader, the bootloader hands to a kernel, the kernel mounts a rootfs and execs PID 1, PID 1 brings up services, services reach a login. This chapter walks the whole arc — both init paths (SysVinit's readable rc scripts and systemd's unit graph) — and teaches you to read and control the machine's own machinery.
## The boot chain — six handoffs
```
firmware → bootloader → kernel (+initramfs) → rootfs → PID 1 → services → login
```
1. **Firmware** — BIOS or UEFI — POSTs, finds a boot device, loads the bootloader. UEFI reads the ESP's `EFI/` tree.
2. **Bootloader** — GRUB (usually) — presents the menu, loads `vmlinuz` + `initramfs` into memory, hands over with a kernel command line (`root=/dev/sda3 ro quiet`).
3. **Kernel** — decompresses, initializes drivers, mounts the rootfs, runs `/sbin/init` as **PID 1**. (The initramfs — a temporary rootfs in RAM — carries drivers the kernel needs to *reach* the real rootfs.)
4. **PID 1** — init — the ancestor of every process; brings the system to a usable state.
5. **Services** — gettys, daemons, network, logging — all spawned by init.
6. **Login** — a getty prompts; `login` checks `/etc/passwd`+shadow; a shell starts.
Each handoff is inspectable: `dmesg` is the kernel's own log of stage 3; `journalctl` or `/var/log/messages` covers stages 4–6.
## PID 1 — the two paths
### SysVinit — the readable path
```sh
cat /etc/inittab          # the runlevel map — id:3:initdefault:
ls /etc/rc.d/             # rc.S (sysinit) rc.M (multiuser) rc.6 (reboot) rc.inet1 rc.sshd
/etc/rc.d/rc.sshd restart # the interface — scripts you can READ
```
Inittab defines **runlevels** — 0 halt, 1 single-user, 3 multiuser (Slackware default), 4 X11, 6 reboot. `telinit 3` changes them. Services are `rc.*` shell scripts, started in order. The beauty: **it's all shell** — `cat /etc/rc.d/rc.M` shows you *exactly* what boot does. Slackware's entire init system fits in a few readable scripts.
### systemd — the standard path
```sh
systemctl status sshd        # state of a unit
systemctl start sshd         # bring up
systemctl enable sshd        # start at boot
systemctl list-units --type=service
systemctl list-dependencies  # the dependency graph
systemctl isolate multi-user.target   # the "runlevel" equivalent
journalctl -u sshd           # the unit's log
journalctl -b                # this boot's whole log
journalctl -f                # follow live
```
Systemd replaces scripts with **units** — declarative files in `/etc/systemd/system/` + `/usr/lib/systemd/system/` — started by dependency order, not sequence. Faster, parallel, self-logging — and opaque in ways SysVinit never is. `.service`, `.mount`, `.socket`, `.timer`, `.target` — the unit types; `.target`s are the runlevel analogues (`multi-user.target` ≈ runlevel 3).
+
## The runlevels — the complete map
+
+
```sh
+
# SysV: 0 halt · 1 single-user · 2 unused · 3 multiuser · 4 X11 · 5 unused · 6 reboot
+
runlevel                      # where you are — "N 3"
+
telinit 1                     # single-user — the maintenance mode
+
telinit 3                     # multiuser text
+
telinit 4                     # X11 — the graphical level
+
telinit 6                     # reboot
+
init 0                        # halt — the older spelling
+
+
# systemd's target equivalents:
+
systemctl isolate rescue.target          # single-user
+
systemctl isolate multi-user.target      # = runlevel 3
+
systemctl isolate graphical.target       # = runlevel 4/5
+
systemctl get-default                    # the default target
+
systemctl set-default multi-user.target  # change it
+
systemctl reboot / poweroff / suspend
+
shutdown -h now / shutdown -r +5 "message" / shutdown -c
+
```
+
+
Runlevel 1/rescue = single-user: minimal services, no network, root shell — where fsck, password resets, and surgery happen.
+
+
## The init scripts — SysV's readable machinery
+
+
```sh
+
ls /etc/rc.d/                 # Slackware's scripts
+
# rc.S  — system init (early)
+
# rc.M  — multiuser — the main one
+
# rc.0/6 — halt/reboot
+
# rc.inet1 — network
+
# rc.sshd rc.mysqld ... — services
+
/etc/rc.d/rc.sshd restart    # the interface
+
/etc/rc.d/rc.local           # the local-hacks script — last in boot
+
/etc/rc.d/rc.local_shutdown  # and on shutdown
+
```
+
+
Each is a plain shell script — `cat /etc/rc.d/rc.M` shows the *entire* multiuser boot sequence in a page of readable commands. The `K`/`S` symlink convention (`rc3.d/S10sysklogd` = start at priority 10) orders them.
+
## The services' plumbing
**gettys** — the login prompts: one per virtual console (`Ctrl-Alt-F2` switches). Inittab's `c1:12345:respawn:/sbin/agetty tty1` or systemd's `[email protected]` — `respawn` is the self-healing restart.
**Daemons** — long-running services — daemonize by detaching from the terminal (setsid, no tty); systemd manages them as units. Logs to syslog (`/var/log/messages`) or journald.
**Cron** — the scheduler: `crontab -e` — `0 3 * * * /usr/local/bin/backup` — minute hour day month weekday. `/etc/cron.daily/` et al. for the system. systemd **timers** are the modern unit-based equivalent.
## systemd units — the anatomy
```ini
# /etc/systemd/system/myservice.service — a complete unit
[Unit]
Description=My service
After=network.target
Wants=network-online.target
[Service]
Type=simple                    # simple|forking|oneshot|notify|dbus|idle|exec
ExecStart=/usr/bin/myservice --flag
ExecReload=/bin/kill -HUP $MAINPID
Restart=on-failure             # always|on-success|on-failure|no
RestartSec=5
User=mysvc
Group=mysvc
WorkingDirectory=/var/lib/mysvc
Environment=VAR=val
ExecStartPre=/usr/bin/precheck
ExecStartPost=/usr/bin/post
LimitNOFILE=65536
ProtectSystem=strict           # read-only /
PrivateTmp=true                # own /tmp
NoNewPrivileges=true
[Install]
WantedBy=multi-user.target     # enable → symlink into the target's .wants/
```
The sections: `[Unit]` dependencies, `[Service]` the process config, `[Install]` how `enable` wires it into boot. `Type=` is the contract — `simple` (foreground), `forking` (daemonizes), `oneshot` (runs once), `notify` (sd_notify protocol). `systemctl daemon-reload` after editing; `systemctl cat` shows the composed unit.
## The unit types
`.service` processes · `.socket` socket-activation · `.timer` cron-replacement · `.mount` mounts · `.automount` lazy-mounts · `.target` runlevel-groups · `.path` inotify triggers · `.slice` cgroup buckets · `.device` udev-derived. `systemctl list-units --type=service` enumerates.
## The journal — structured logging
```sh
journalctl --list-boots             # every boot, ever — pick one to read
journalctl _PID=1234                # by process
journalctl -g 'pattern'             # grep the journal
journalctl -o json-pretty           # structured output
journalctl --priority=emerg..err    # level band
journalctl _SYSTEMD_UNIT=sshd.service _COMM=sshd
```
Fields are queryable (`_PID`, `_COMM`, `_SYSTEMD_UNIT`) — journald is a queryable database, not text files.
+
+
## The boot stages' detail — what actually fires when
+
+
```text
+
0. Firmware    — UEFI/BIOS POST → reads GPT → loads bootloader
+
1. Bootloader  — GRUB loads kernel + initramfs → jumps to start_kernel
+
2. Kernel      — init/main.c → start_kernel() → scheduler + mm + drivers
+
                 → rest_init() → kernel_init → run_init_process("/sbin/init")
+
3. Initramfs   — early root: unpack → its init loads modules → mounts real root
+
                 → switch_root → the real root takes over
+
4. PID 1       — /sbin/init (SysV) or /usr/lib/systemd/systemd
+
5. Services    — SysV: rc.S → rc.M → gettys
+
                 systemd: targets → units → [email protected]
+
6. Login       — getty/agetty → login → PAM → /etc/profile → shell
+
```
+
+
`dmesg` shows stage 2-3 verbatim — the `BIOS-e820` map, the mount, the `Run /sbin/init as init process` line. `journalctl -b` shows stage 4-5. The kernel cmdline (`cat /proc/cmdline`) is stage 1's record.
+
+
## The PID-1 contract — what init must do
+
+
- Reap orphans — every reparented child ends at PID 1
+
- Never exit — the kernel panics if PID 1 dies
+
- Handle SIGCHLD — collect zombies
+
- Be the root of the cgroup tree — every process descends
+
- Start the world — mount the filesystems, bring up services, spawn login
+
+
SysVinit does it via `/etc/inittab` + rc scripts — readable shell. systemd does it via unit-graph + journald — structured. Both satisfy the contract; the argument is about *how*.
## The kernel's own interfaces
- **`dmesg`** — the kernel ring buffer: hardware detection, driver loads, oopses — boot's transcript
- **`/proc`** — processes + kernel state as files
- **`/sys`** — devices/drivers as a browsable object tree
- **`sysctl`/`/proc/sys`** — live kernel knobs: `sysctl -w net.ipv4.ip_forward=1`
- **`modprobe`**/`lsmod`/`modinfo` — loadable modules — the driver's hotplug layer
## Runlevels / targets — the modes
```sh
runlevel              # SysV — where you are
telinit 1             # single-user — maintenance mode (the rescue level)
telinit 3             # multiuser text
telinit 6             # reboot
systemctl isolate rescue.target     # systemd's single-user
systemctl reboot / poweroff         # the controlled shutdowns
shutdown -h now                     # traditional halt
```
Runlevel 1 / `rescue.target` — single-user mode — is the maintenance door: minimal services, root shell, the place filesystem checks and password resets happen. The kernel command line's `single` or `init=/bin/bash` boots straight there — the rescue technique of last resort.
## The LFS system's boot — what you built
The LFS SysVinit path installs `sysvinit` + `sysklogd` + the boot scripts — `/etc/rc.d/init.d/` scripts for cleanfs, modules, network, sysklogd — a minimal but *legible* init. Chapter 6's `/etc/inittab` + fstab + rc scripts are the whole machine's waking machinery — you wrote them from nothing.
## Where the system goes wrong
| Symptom | Cause |
| --- | --- |
| Boots to `grub>` or rescue | Bootloader/config — chapter 6 territory |
| Kernel panic — can't mount root | rootfs driver/filesystem not built-in |
| Boots, no login prompt | getty not spawning — inittab/agetty |
| Service won't start | `systemctl status`/`journalctl -u` — or the rc script's exit code |
| Slow boot | `systemd-analyze blame` — or a blocking rc script |
| `dmesg` flooded with errors | Driver/hardware — `dmesg -l err` filters |
| Can't change runlevel | systemd targets ≠ SysV runlevels — wrong tool for the init |
## Exercises
1. `dmesg | less` — read your kernel's boot transcript.
2. `cat /etc/inittab` (SysV) or `systemctl list-dependencies` (systemd) — the boot plan.
3. `pstree -p | head -20` — the fork family from PID 1.
4. `journalctl -b` or `less /var/log/messages` — this boot's log.
5. Switch a virtual console (Ctrl-Alt-F2); identify the getty that owns it.
6. `sysctl -a | less` — the kernel's tunable mind.
## Timeline
| Handoff | The mechanism |
| --- | --- |
| firmware | BIOS/UEFI → ESP/boot sector |
| bootloader | GRUB → vmlinuz + initramfs + cmdline |
| kernel | init → mount rootfs → /sbin/init |
| PID 1 | rc scripts or unit graph |
| services | gettys, daemons, network, logging |
| login | getty → login → shell |
## See also
- [[Linux]] · [[LFS Kernel and Boot]] · [[Processes]] · [[Filesystem]]
[[Category:Linux]]
[[Category:Handbook]]
[[Category:Boot]]