What are System V Init and Runlevels in Linux-Free Linux Device Drivers Training

PREV_LEC NEXT_LEC
Free Linux Kernel Development Course

System V Init and Runlevels

How System V init organizes an embedded Linux system into runlevels, and how the inittab file drives what starts, stops, and respawns at each one.

In this free embedded Linux course lecture we go beyond BusyBox init and look at System V init — the older, more structured init implementation that introduced runlevels and a well-known boot-script layout. You will learn what a runlevel actually is, how inittab entries map to it, and how to move a system between runlevels safely with telinit.

This lecture assumes you have already worked through the BusyBox init and inittab lecture in this free linux kernel development course series — System V init reuses the same inittab idea but extends it with runlevels and a couple of extra action keywords.

System V init runlevels inittab telinit rc scripts free linux device drivers course

What You Will Learn

Lecture Goals

What a runlevel is The 8 System V runlevels inittab field format telinit and runlevel commands Start/kill script ordering System V init in Buildroot and Yocto

Prerequisites

Before You Start

Comfortable with BusyBox init and inittab basics A QEMU or real board with a writable rootfs Basic shell scripting

Why Runlevels Exist

BusyBox init runs one flat list of inittab entries with no concept of “modes.” System V init adds a numbering scheme, the runlevel, that groups which daemons and services should be active at any given moment. A system can be switched from one runlevel to another as a single operation instead of hand-starting and hand-stopping individual services. This matters on embedded boards that need a production mode and a separate maintenance or recovery mode without a full reboot.

System V Runlevel Map
RunlevelMeaning
SSingle-user recovery shell, no services
0Halt the system
1Single-user administrative mode
2Multi-user, no networking
3Multi-user, networking enabled
4Unused / site-defined
5Multi-user, graphical login
6Reboot the system

Levels 1 through 5 are conventions, not kernel rules — a board vendor is free to define runlevel 4 as “factory test mode” or runlevel 3 as “field-update mode.” Only 0 (halt) and 6 (reboot) carry a fixed meaning that every System V init implementation honors.

Checking and Changing the Current Runlevel

Two small utilities talk to PID 1 about runlevels: runlevel reports the current and previous one, and telinit requests a switch.

$ runlevel
N 5
$ telinit 3
$ runlevel
5 3

The first field is the previous runlevel (N means “none — this is the level we booted into”), and the second is the current one. After telinit 3, init runs every kill script for services that should not run in runlevel 3, then every start script for services that should, and runlevel now reports the transition from 5 to 3. You can also force a boot-time runlevel from the kernel command line, for example appending a bare 3 or S after your normal boot arguments.

The inittab Line Format

System V’s inittab extends the same idea BusyBox uses, but every line now carries a runlevel field.

inittab Field Layout
FieldPurpose
idUp to 4 characters, unique per line
runlevelsWhich runlevels this line applies to (blank = all)
actionsysinit, wait, respawn, once, ctrlaltdel, or shutdown
processThe command PID 1 runs

Compared to BusyBox inittab, System V init drops the BusyBox-only askfirst action and puts real meaning into the previously-unused runlevels field. An entry tagged 2345 only fires when the system is entering one of runlevels 2, 3, 4, or 5.

# /etc/inittab — example for a custom embedded target
id:3:initdefault:

# Run once at every boot, before any runlevel scripts
si::sysinit:/etc/init.d/rcS

# Enter single-user recovery shell on demand
~~:S:wait:/sbin/sulogin

# Standard multi-user runlevel scripts
l2:2:wait:/etc/init.d/rc 2
l3:3:wait:/etc/init.d/rc 3
l5:5:wait:/etc/init.d/rc 5
l6:6:wait:/etc/init.d/rc 6

# Serial console login, active in runlevels 2 through 5
ep1:2345:respawn:/sbin/getty 115200 ttyS0

The id:3:initdefault: line tells init that this board should boot straight into runlevel 3 by default — multi-user with networking, no graphical login, which is the common choice for headless embedded targets.

How a Runlevel Switch Actually Runs Scripts

Each of the l2–l6 lines above calls the same script, /etc/init.d/rc, passing the target runlevel as an argument. That script does the real work: it looks inside a per-runlevel directory for two kinds of symlinks pointing back at the real service scripts in /etc/init.d/.

Start and Kill Script Naming
Symlink patternMeaningExample
S<NN>nameStart script, run in ascending numeric orderS20network
K<NN>nameKill script, run in ascending numeric orderK20network

When entering a new runlevel, rc first runs every K script in the outgoing runlevel’s directory (stopping services no longer wanted), then every S script in the incoming runlevel’s directory (starting services that should now be running). Any daemon with neither a start nor a kill entry for the new runlevel is simply sent SIGTERM — the default assumption is that a service not explicitly kept alive should be terminated on transition.

System V Init on Buildroot and Yocto

Both major embedded build systems can produce a System V init rootfs, but neither implements the full desktop-style runlevel machinery by default.

Buildroot

Buildroot’s sysvinit package ships a minimal inittab and treats runlevels as effectively cosmetic — switching to 0 or 6 halts or reboots the board, but there is no per-runlevel start/kill script tree unless you build one yourself.

Yocto Project

Yocto’s sysvinit recipes are closer to a traditional desktop layout, with real rcN.d directories per runlevel, which makes it a better fit if your product genuinely needs distinct operating modes rather than a single always-on state.

Hands-On: Adding a Custom Runlevel Service

This walkthrough adds an original demo service, ep-heartbeat, that only runs in runlevel 3 and is cleanly stopped when leaving it.

# 1. Write the service script
cat > /etc/init.d/ep-heartbeat << 'SCRIPT'
#!/bin/sh
case "$1" in
  start) echo "ep-heartbeat: starting" ; ( while true; do sleep 5; done ) & ;;
  stop)  echo "ep-heartbeat: stopping" ; killall -q sleep ;;
esac
SCRIPT
chmod +x /etc/init.d/ep-heartbeat

# 2. Link it into runlevel 3's start/kill directories
ln -s ../init.d/ep-heartbeat /etc/rc3.d/S90ep-heartbeat
ln -s ../init.d/ep-heartbeat /etc/rc3.d/K10ep-heartbeat

# 3. Trigger the transition and watch it fire
telinit 3
ep-heartbeat: starting

Switching away from runlevel 3 runs the matching K10ep-heartbeat symlink, printing ep-heartbeat: stopping before the next runlevel’s start scripts execute.

Common Mistakes and Troubleshooting

Forgetting the trailing colon. Every inittab field is colon-separated, and a missing trailing colon on an action line is a frequent typo that silently breaks parsing on some init builds.

Reusing an id. The id field must be unique across the file — a duplicate silently shadows the earlier entry instead of raising an error.

Expecting runlevel numbers to be portable. Runlevel 4 means nothing standard — don’t assume a third-party board support package uses the same convention you do.

Best Practices

Recommendations

Keep production boards on a single default runlevel unless you truly need modes Number start/kill scripts with gaps (10, 20, 30) to leave room for later insertions Document any non-standard runlevel meaning directly in inittab comments

Summary and Key Takeaways

System V init layers a runlevel concept on top of the same inittab mechanism BusyBox uses. Runlevels group which daemons should be running, telinit triggers a transition, and the rc script drives ordered kill-then-start symlink directories to get there. Most embedded products only ever use one runlevel in practice, but the mechanism is there when a device genuinely needs distinct operating modes.

Conclusion

Understanding System V init’s runlevel model rounds out your picture of how PID 1 can be built: BusyBox init for the simplest boards, System V init when you need modes and a modular script layout, and systemd when you need dependency-based parallel startup on more capable hardware. The next lecture in this free linux device drivers course series looks at how systemd unit files replace this entire model.

FAQ

What is a runlevel in System V init?

A runlevel is a named set of services that should be active at once — switching runlevels starts and stops that whole set as a single operation instead of managing services individually.

How many runlevels does System V init have?

Eight: numbered 0 through 6, plus S for single-user mode. Only 0 (halt) and 6 (reboot) have a fixed, universal meaning.

What is the difference between telinit and runlevel?

telinit requests a runlevel change from PID 1, while runlevel only reports the current and previous runlevel without changing anything.

Does Buildroot fully implement System V runlevels?

No. Buildroot’s sysvinit package only implements halt and reboot behavior for runlevels 0 and 6; it does not build a full rcN.d start/kill script tree by default.

What happens to a daemon with no script in the new runlevel?

It receives SIGTERM. System V init assumes a service should stop unless a start script explicitly keeps it running in the new runlevel.

Is System V init still relevant for embedded Linux in the latest kernels?

Yes for simpler boards and legacy product lines, though systemd has become common on more capable embedded hardware that can afford its resource footprint.

Can I set the boot runlevel from the kernel command line?

Yes — appending a single digit (0-6) or S to the kernel command line overrides the initdefault entry in inittab for that boot only.

Keep Learning Embedded Linux

This lecture is part of EmbeddedPathashala’s free embedded Linux course covering the full boot path from toolchain to init systems.

2 Comments

Leave a Reply

Your email address will not be published. Required fields are marked *