Skip to content

101.3 Change runlevels / boot targets and shutdown or reboot system

runlevels

Runlevels define what tasks can be accomplished in the current state of a Linux system - predefined system states, each with its own set of active services.

systemd

On systemd, runlevels are replaced by targets - groups of units managed together.

systemctl list-units --type=target

There are targets that correspond directly to each SysV runlevel, from runlevel0.target up to runlevel6.target. Two of the most common named targets are multi-user.target (console only) and graphical.target (console plus graphical login).

systemctl get-default               # shows the default target
systemctl status multi-user.target  # shows the status of a specific target

You can switch to a different target immediately with isolate:

systemctl isolate multi-user.target

Besides the regular targets, there are special maintenance/power targets:

  • rescue - local filesystems mounted, no networking, root only (maintenance mode)
  • emergency - only the root filesystem, read-only, no networking, root only (maintenance mode)
  • reboot, halt, poweroff - restart/shutdown variants
systemctl isolate emergency
systemctl is-system-running         # e.g. running, degraded, maintenance

SysV runlevels

On a Red Hat-based system we usually had 7:

  • 0 - Shutdown
  • 1 - Single-user mode (recovery); also called S or s
  • 2 - Multi-user without networking
  • 3 - Multi-user with networking
  • 4 - To be customized by the admin
  • 5 - Multi-user with networking and graphics
  • 6 - Reboot

And in Debian-based systems:

  • 0 - Shutdown
  • 1 - Single-user mode
  • 2 - Multi-user mode with graphics
  • 6 - Reboot

Checking status and setting defaults

The runlevel command shows the current runlevel as two values, the previous one and the current one:

$ runlevel
N 3

N means the runlevel hasn't changed since the last boot.

The default runlevel is set in /etc/inittab, using the special initdefault action:

id:3:initdefault:

This value should never be 0 or 6, since either would shut down or restart the system immediately after boot finishes. The default can also be overridden with a kernel parameter at boot.

To switch runlevels on a running system without rebooting, use telinit:

# runlevel
N 3
# telinit 5
# runlevel
3 5
# init 0        # shuts down the system

All SysVinit scripts live in /etc/init.d/, and each runlevel has its own directory (/etc/rc0.d/, /etc/rc1.d/, etc.) full of symlinks back to those scripts. The first letter of each symlink's name tells init what to do: K kills the service on entering that runlevel, S starts it.

ls -ltrh /etc/init.d/
ls /etc/rc2.d/

On systemd systems, the equivalent configuration lives in /etc/systemd/ and /usr/lib/systemd/, as covered in 101.2.

/etc/inittab

Still part of the exam, even though it's being phased out by Upstart and systemd. The format is:

id:runlevels:action:process
  • id - up to 4 characters, identifies the entry
  • runlevels - which runlevel(s) this line applies to (empty means all)
  • action - how init should treat the process
  • process - the command to run

The available actions: boot and bootwait (run during initialization, the runlevels field is ignored), sysinit (runs after initialization regardless of runlevel), wait (runs for the given runlevels, init waits for it to finish), respawn (restarted if it terminates), and ctrlaltdel (runs when Ctrl+Alt+Del is pressed).

A typical /etc/inittab:

# Default runlevel
id:3:initdefault:
# Configuration script executed during boot
si::sysinit:/etc/init.d/rcS
# Action taken on runlevel S (single user)
~:S:wait:/sbin/sulogin
# Configuration for each execution level
l0:0:wait:/etc/init.d/rc 0
l1:1:wait:/etc/init.d/rc 1
l2:2:wait:/etc/init.d/rc 2
l3:3:wait:/etc/init.d/rc 3
l4:4:wait:/etc/init.d/rc 4
l5:5:wait:/etc/init.d/rc 5
l6:6:wait:/etc/init.d/rc 6
# Action taken upon ctrl+alt+del keystroke
ca::ctrlaltdel:/sbin/shutdown -r now
# Enable consoles for runlevels 2 and 3
1:23:respawn:/sbin/getty tty1 VC linux
2:23:respawn:/sbin/getty tty2 VC linux

After editing /etc/inittab, run telinit q to make init reload it, without needing a reboot.


Stopping the system

The shutdown command is the safe way to shut down or restart a system, rather than just cutting the power. It happens in order: first it warns everyone currently logged in, then it blocks anyone new from logging in, then it tells init to switch to the shutdown or reboot runlevel. As part of that, every process is asked to stop on its own first, using signal SIGTERM (signal number 15). Any process still running a moment later is forced to stop with SIGKILL (signal number 9), which cannot be ignored.

shutdown [option] time [message]
  • time - hh:mm, +m (minutes from now), or now
  • message - text broadcast to logged-in users, sent via wall
  • -h - halt the system
  • -r - reboot the system
  • -c - cancel a pending shutdown
shutdown -r +60 "Reloading updated kernel"
shutdown -c

If neither -h nor -r is given, the system goes to runlevel 1 (single-user mode) by default.

Root can restrict who's allowed to reboot via Ctrl+Alt+Del by adding the -a option to the ctrlaltdel line in /etc/inittab. Once set, only users listed in /etc/shutdown.allow are permitted to use that key combination.

Halt, reboot, and poweroff

  • halt - halts the system
  • reboot - halts the system, then reboots it
  • poweroff - halts the system, then powers it off (sends an ACPI shutdown signal)

On most distros these are symbolic links to systemctl itself:

$ which poweroff
/usr/sbin/poweroff
$ ls -l /usr/sbin/poweroff
lrwxrwxrwx 1 root root 14 ... /usr/sbin/poweroff -> /bin/systemctl

The systemd-native equivalents are systemctl reboot and systemctl poweroff, both requiring root privileges.

Advanced Configuration and Power Interface (ACPI)

ACPI is an open standard that lets the OS discover and configure hardware, perform power management (like putting unused components to sleep), handle auto-configuration such as Plug and Play and hot-swapping, and perform status monitoring. It's the subsystem that lets a command like shutdown actually signal the hardware to power itself down.

On a systemd system, events like suspend and hibernate are normally handled by systemctl suspend and systemctl hibernate, configured through /etc/systemd/logind.conf. If a separate power manager such as the acpid daemon is running instead, it takes over that role, handling finer-grained events like the laptop lid closing or the battery reaching a certain charge level.


Notifying users

The wall command sends a message to every logged-in user's terminal:

wall "System going down for maintenance in 10 minutes"

Other places users see notifications, before and after logging in:

  • /etc/issue - shown on the local console, before login
  • /etc/issue.net - shown over the network, before login
  • /etc/motd - message of the day, shown after login
  • mesg - controls whether a user receives wall messages (shutdown's own warning messages ignore this setting regardless)

systemctl itself sends wall messages automatically for emergency, halt, power-off, reboot, and rescue events.


Summary

I have a Linux system that needs predefined states for different situations, like normal operation versus maintenance. On older SysV based systems, these states are called runlevels, numbered 0 through 6, with the default one set in /etc/inittab using an initdefault line. On systemd systems, the same idea exists as targets, like multi-user.target for a normal console system or graphical.target for a desktop.

I can check my current runlevel with runlevel, switch between them live with telinit, or use systemctl isolate and systemctl get-default for the systemd equivalent. Every runlevel has an /etc/rc[0-6].d/ directory full of S-prefixed (start) and K-prefixed (kill) symlinks pointing back to the real scripts in /etc/init.d/.

When I actually need to shut the system down, shutdown is the safe way to do it. It warns everyone logged in, blocks new logins, and gives running processes a chance to close cleanly with SIGTERM before force-killing anything left with SIGKILL. halt, reboot, and poweroff are the more direct commands, and on most modern systems they're just symlinks to systemctl under the hood.

Finally, I have wall for warning everyone on the system before I do any of this, which is exactly what shutdown uses internally to send its own warnings.