Inside a Linux System
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
- Firmware — BIOS or UEFI — POSTs, finds a boot device, loads the bootloader. UEFI reads the ESP's
EFI/tree. - Bootloader — GRUB (usually) — presents the menu, loads
vmlinuz+initramfsinto memory, hands over with a kernel command line (root=/dev/sda3 ro quiet). - Kernel — decompresses, initializes drivers, mounts the rootfs, runs
/sbin/initas PID 1. (The initramfs — a temporary rootfs in RAM — carries drivers the kernel needs to reach the real rootfs.) - PID 1 — init — the ancestor of every process; brings the system to a usable state.
- Services — gettys, daemons, network, logging — all spawned by init.
- Login — a getty prompts;
loginchecks/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
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
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; .targets are the runlevel analogues (multi-user.target ≈ runlevel 3).
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 getty@tty1.service — 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
# /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
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 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 treesysctl//proc/sys— live kernel knobs:sysctl -w net.ipv4.ip_forward=1modprobe/lsmod/modinfo— loadable modules — the driver's hotplug layer
Runlevels / targets — the modes
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
dmesg | less— read your kernel's boot transcript.cat /etc/inittab(SysV) orsystemctl list-dependencies(systemd) — the boot plan.pstree -p | head -20— the fork family from PID 1.journalctl -borless /var/log/messages— this boot's log.- Switch a virtual console (Ctrl-Alt-F2); identify the getty that owns it.
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 |