Skip to main content

Linux concept: SysV init

22 July 2026

Before systemd ran the show, every Linux machine started up the same way it had since the 1980s: the kernel launched a single small program called init, and that program read a plain text file, walked through a list of numbered "runlevels", and ran a pile of shell scripts one after another to bring the system up. That design is SysV init, and for roughly thirty years it was how Unix and Linux booted. It is mostly gone from default installs now, but its fingerprints are everywhere: /etc/init.d, the service command, runlevels, and the K and S symlinks are all still on your machine. Understanding SysV init is understanding where the modern boot came from, and why systemd was built to replace it.

1. The Basics

SysV init (say it "System Five init") is the traditional init system for Unix and Linux: the software that the kernel starts first and that then brings the rest of the machine to life. Like every init system, its core program runs as process ID 1 (PID 1) and stays alive until shutdown. What makes it "SysV" is how it decides what to start: a fixed set of numbered system states called runlevels, and a directory of shell scripts that it runs in order to enter or leave each state.

There are three moving parts, and once you see them the whole system makes sense:

  • The program /sbin/init, running as PID 1, the parent of every other process.
  • A single configuration file, /etc/inittab, that tells init which runlevel to boot into and what to do in each one.
  • A directory of start/stop scripts, /etc/init.d, one script per service, plus a set of rcN.d directories full of symbolic links that decide the order.

That is the entire mental model. init is a simple dispatcher; the real work of starting a service lives in an ordinary shell script that understands the words start and stop. This simplicity was SysV init's great strength (anyone who could write a shell script could add a service) and, as we will see, its great weakness (init itself understood almost nothing about the services it launched).

The right mental model: SysV init is a dispatcher that walks through numbered runlevels and runs hand-written shell scripts to start and stop services. It launches programs, but unlike systemd it does not truly supervise them.

1.1 What Makes PID 1 Special

Being process 1 is not just a small number; it comes with duties the kernel gives to no other process. Every init system, SysV init included, has to carry them, because it is the one process the whole system is built around:

  • It is the ancestor of everything. When any process's parent dies, that process becomes an orphan, and the kernel hands it to PID 1 to look after. So init ends up as the adoptive parent of every stray process on the machine.
  • It must reap zombies. When a process exits, it stays in the process table as a zombie until its parent collects the exit status with wait(). For the orphans it adopts, that parent is init. If init failed to reap them, the process table would slowly fill with dead entries, so reaping is a permanent background job of PID 1.
  • It cannot simply exit. PID 1 has to stay alive for the whole life of the system. If it dies, there is no process left to manage user space, and the kernel panics.
  • It gets special signal treatment. The kernel does not apply default signal actions to PID 1, so a stray signal cannot accidentally kill the one process the system depends on.

This is worth knowing because it is the part of init that has never changed. SysV init, Upstart, and systemd all handle runlevels, units, and services very differently, but every one of them must adopt orphans, reap zombies, and never exit. It is the irreducible core of being PID 1.

1.2 Where SysV init Still Lives Today

On a modern systemd machine, /sbin/init is no longer the old init program. It is a symbolic link to systemd, which keeps the old name and boot loaders working:

$ ls -l /sbin/init
/sbin/init → /lib/systemd/systemd

Yet the SysV layout is still all around you, because systemd deliberately stays compatible with it. The directories and commands below are the SysV world; on a systemd system they are a compatibility layer, but on a true SysV system they are the system:

$ ls -d /etc/rc*.d
/etc/rc0.d  /etc/rc1.d  /etc/rc2.d  /etc/rc3.d
/etc/rc4.d  /etc/rc5.d  /etc/rc6.d  /etc/rcS.d

$ ls /etc/init.d | head -4
anacron
bluetooth
cron
mysql

1.3 The Runlevels at a Glance

A runlevel is a numbered system state that says which group of services should be running. Init can be in exactly one runlevel at a time, and you switch states by telling it to change. The numbers are a long-standing convention:

RunlevelUsual meaning
0 Halt (shut the machine down)
1 (or S) Single-user mode: one root shell, minimal services, for repairs
2 Multi-user (on Debian, full multi-user with networking)
3 Multi-user with networking, text console (Red Hat convention)
4 Unused, free for a custom setup
5 Multi-user with a graphical login (Red Hat convention)
6 Reboot

Two of these are not really "states" you sit in: entering runlevel 0 halts the machine and entering 6 reboots it. That is why you never set your default runlevel to 0 or 6: the system would shut down or reboot forever. The meanings of 2 to 5 are only conventions and differ between distributions, a point we return to in section 7.

Back to top

2. Where the Name Comes From

The name is two pieces: SysV plus init.

SysV init  =  System V (the "V" is Roman numeral five)  +  init (initialization)

System V was a version of Unix released by AT&T in 1983. It was one of the two great branches of Unix (the other being BSD from Berkeley), and it set many conventions that Linux later copied. The init design in System V, with its runlevels and /etc/inittab file, became so influential that the whole style is named after it, to tell it apart from the older, simpler "BSD-style" init that used a few fixed rc scripts instead of numbered runlevels.

init is short for initialization. It is the program that initializes user space: once the kernel has set up the hardware, it hands control to init, which starts everything a person actually uses. Because it is the first program to run, the kernel always gives it PID 1, and by tradition its binary lives at /sbin/init.

So "SysV init" reads as "the System-V-style initialization program". When people say a distribution "uses SysV init", they mean it boots with runlevels, an inittab, and /etc/init.d scripts, rather than with systemd units or the older BSD rc style.

Back to top

3. A Short History

init is one of the oldest ideas in Unix, older than Linux itself. Some form of an "init" process has existed since the earliest Unix in the 1970s, because a system always needs one first process to start the rest.

The specific design we call SysV init came from AT&T UNIX System V in 1983, which formalised the idea of numbered runlevels and a central /etc/inittab file. This was the model Linux adopted. The most widely used Linux implementation, the sysvinit package, was written by Miquel van Smoorenburg in the early 1990s and became the default init on nearly every Linux distribution for the next two decades.

For a long time it simply worked, and no one thought much about it. But as machines gained many cores and many services, its weaknesses began to hurt: it started services strictly one after another, so boot was slow; each service was a fragile hand-written script; and init could not really track a service once it had started. Two replacements set out to fix this:

  • Upstart, shipped by Ubuntu in 2006, reacted to events rather than following a fixed script order, but kept the script-heavy style.
  • systemd, released in 2010, replaced init entirely with declarative unit files, parallel startup, and reliable process tracking through control groups.
EraMilestone
1970s Early Unix has an init as PID 1; boot is a few fixed scripts
1983 AT&T UNIX System V formalises runlevels and /etc/inittab
1992 Miquel van Smoorenburg writes the Linux sysvinit package
2006 Ubuntu ships Upstart, an event-based replacement
2010 systemd is released, using units, parallel boot, and cgroups
2014-2015 Debian, Ubuntu, Fedora, RHEL, Arch, and SUSE switch to systemd
Today SysV init survives as a compatibility layer and on a few systemd-free distributions such as Devuan

SysV init is not quite dead. A handful of distributions keep it on purpose, container base images sometimes use a tiny init, and every mainstream distribution still ships the service command and the /etc/init.d directory so that old scripts keep working. Learning it is less about running it in production and more about reading the many systems and scripts that still assume it.

DistributionHow it avoids systemd
Devuan A fork of Debian made specifically to be free of systemd; uses SysV init by default
antiX A lightweight distribution for older computers; uses SysV init together with runit
MX Linux A popular, stable distribution built on Devuan and antiX; uses SysV init by default
Slackware The oldest surviving Linux distribution; uses BSD-style init scripts that work much like traditional SysV

These are the distributions to reach for if you want to run without systemd on purpose. Note that Slackware is technically BSD-style rather than strictly SysV, but in daily use it feels the same: plain shell scripts starting services in a fixed order.

systemd is also not the only alternative. Beside classic SysV init sit a family of lighter init systems that keep the small-and-simple spirit while adding proper service supervision: OpenRC (the default on Gentoo and Alpine, which still uses /etc/init.d scripts), and the minimalist runit, s6, and dinit. They matter mostly on lightweight or systemd-free systems, but they show that the choice was never simply "SysV or systemd".

Back to top

4. Simple Use Cases

You do not write files to use SysV init day to day. A few commands cover almost all normal contact with it, and they still work on a systemd machine through the compatibility layer.

4.1 See the Current Runlevel

The runlevel command prints two values: the previous runlevel and the current one. An N in the first slot means there has been no change since boot ("None"):

$ runlevel
N 5

Here the machine booted straight into runlevel 5 (graphical) and has not changed level since. This one command answers "what state is the system in?" without any guesswork.

4.2 Start, Stop, and Check a Service

The classic way to control one service is the service command, which is just a thin wrapper that runs the matching script in /etc/init.d with the action you ask for. Changing a service needs root, so these take sudo:

$ sudo service cron start      # run /etc/init.d/cron start
$ sudo service cron stop       # run /etc/init.d/cron stop
$ sudo service cron restart    # stop then start
$ service cron status          # is it running? (reading state needs no root)

Running the script directly does the exact same thing; the service command only tidies the environment first:

$ sudo /etc/init.d/cron restart
[ ok ] Restarting cron (via systemctl): cron.service.

Notice the words "via systemctl" in the output above. On a systemd system, the old command is quietly forwarded to systemd. On a real SysV system the script would do the work itself.

4.3 Change Runlevel, Halt, or Reboot

To move the whole machine into a different state, you tell init to switch runlevel with telinit (short for "tell init"). The plain init command does the same:

$ sudo telinit 3      # switch to multi-user text mode now
$ sudo telinit 1      # drop to single-user (rescue) mode
$ sudo init 0         # halt: runlevel 0 shuts the machine down
$ sudo init 6         # reboot: runlevel 6 restarts the machine

This is why init 0 and init 6 are old-school shorthands for shutdown and reboot: they simply switch to the runlevel whose whole job is to stop everything and then power off or restart.

Back to top

5. Moderate Use Cases

To go beyond running services, you need to understand the two files that drive SysV init: the /etc/inittab configuration and the rcN.d symlink directories.

5.1 Reading /etc/inittab

On a true SysV system, /etc/inittab is the master switchboard. Every line has four colon-separated fields:

id:runlevels:action:process
FieldMeaning
id A short unique label for the line
runlevels Which runlevels this line applies to, e.g. 2345
action When and how to run it: initdefault, wait, respawn, sysinit, and so on
process The command to run

A typical inittab looks like this:

id:5:initdefault:                      # boot into runlevel 5 by default
si::sysinit:/etc/init.d/rcS            # one-time early setup
l3:3:wait:/etc/init.d/rc 3            # entering runlevel 3: run the rc script for 3
l5:5:wait:/etc/init.d/rc 5            # entering runlevel 5: run the rc script for 5
ca::ctrlaltdel:/sbin/shutdown -r now  # what Ctrl-Alt-Del does
1:2345:respawn:/sbin/getty 38400 tty1 # a login prompt on tty1, restarted if it dies

Two lines carry most of the meaning. The initdefault line sets the runlevel the machine boots into; changing its number changes the default boot state. The respawn lines are the one place init really does supervise something: if a getty (the login prompt) exits, init starts it again, which is why a fresh login prompt appears the moment you log out of a text console.

When init enters a runlevel, it runs one script, /etc/init.d/rc N, which looks in the matching /etc/rcN.d directory. That directory is full of symbolic links back to the real scripts in /etc/init.d, and the link names encode the order and the action:

$ ls -l /etc/rc2.d
K01speech-dispatcher → ../init.d/speech-dispatcher
S01cron              → ../init.d/cron
S01mysql             → ../init.d/mysql
S01docker            → ../init.d/docker

The naming rule is simple and is the heart of SysV init:

  • A link starting with S means Start: run the script with start when entering this runlevel.
  • A link starting with K means Kill: run the script with stop when entering this runlevel.
  • The two digits after the letter set the order. Scripts run in numeric order, so S10 runs before S20. This lets you start a database before the web server that needs it.

Classic systems spread the numbers out (S20apache2, K80apache2) to hand-tune the order. Newer Debian and Ubuntu compute the order from dependencies and give almost everything S01, which is why the example above shows so many S01 links.

5.3 Enabling a Service the SysV Way

You rarely make those symlinks by hand. Each distribution family has a tool that creates and removes them for you, reading the dependency headers inside the init script:

# Debian and Ubuntu
$ sudo update-rc.d cron defaults   # create S/K links in the default runlevels
$ sudo update-rc.d cron remove     # remove all its links

# Red Hat and SUSE
$ sudo chkconfig cron on           # enable at boot
$ sudo chkconfig --list cron       # show its runlevels

This is the SysV equivalent of systemctl enable. In both worlds, "enabling" a service means recording, in a fixed place, that it should start at boot. Here that record is a symlink; under systemd it is also a symlink, in a .wants directory.

Back to top

6. Advanced Use Cases

The real craft of SysV init is writing a good init script, because init itself gives you almost nothing: no restart-on-crash, no logging, no process tracking. Everything a service needs, the script must provide by hand.

6.1 Anatomy of an init Script

An init script is an ordinary shell script that accepts an action as its first argument. At minimum it must handle start, stop, restart, and status. A simplified script looks like this:

#!/bin/sh
### BEGIN INIT INFO
# Provides:          myapp
# Required-Start:    $remote_fs $network
# Required-Stop:     $remote_fs $network
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: My application
### END INIT INFO

DAEMON=/opt/myapp/app
PIDFILE=/var/run/myapp.pid

case "$1" in
  start)
    start-stop-daemon --start --background \
      --make-pidfile --pidfile "$PIDFILE" --exec "$DAEMON"
    ;;
  stop)
    start-stop-daemon --stop --pidfile "$PIDFILE"
    ;;
  restart)
    "$0" stop
    "$0" start
    ;;
  status)
    [ -f "$PIDFILE" ] && echo "running" || echo "stopped"
    ;;
  *)
    echo "Usage: $0 {start|stop|restart|status}"
    exit 1
    ;;
esac

6.2 The LSB Header

The comment block at the top, between BEGIN INIT INFO and END INIT INFO, is not decoration. It is the LSB header (Linux Standard Base), and the enabling tools read it to work out the boot order:

FieldMeaning
Provides The name other scripts can depend on
Required-Start What must already be running before this starts
Required-Stop What must still be running when this stops
Default-Start Runlevels to create S links in
Default-Stop Runlevels to create K links in

Names beginning with $, such as $network or $remote_fs, are "virtual facilities": standard milestones the system defines so scripts do not have to name each other directly. From these headers, a tool like insserv works out a safe order and assigns the two-digit numbers on the S and K links.

6.3 start-stop-daemon and the PID File Problem

The helper start-stop-daemon (on Debian) exists because starting and reliably stopping a background program in shell is harder than it looks. Its job is to launch the daemon, record its process ID in a PID file, and later read that file back to find and kill the right process.

This PID file is SysV init's Achilles heel. The script guesses which process to manage from a number written in a file. If the program forks a child, crashes without cleaning up, or the PID is reused by an unrelated process, the script can stop the wrong thing or lose track entirely. Systemd fixed exactly this by tracking every service in a control group instead of trusting a PID file, so a service and all its children can always be found and stopped.

6.4 /etc/rc.local: The Escape Hatch

For a quick command to run once at the end of boot, without writing a full init script, SysV systems offer /etc/rc.local. Any commands in this file run late in the boot, after the normal services:

#!/bin/sh -e
# commands here run once at the end of boot
/opt/scripts/warm-cache.sh
exit 0

It is convenient but crude: no logging, no dependency checks, no restart. systemd keeps a compatibility rc-local.service so an existing /etc/rc.local still runs, but for anything real a proper unit (or init script) is the better home.

Back to top

7. Something Most Users Do Not Know

SysV init has no registry, no database, and no config format for "which services start at boot". The entire answer is encoded in the names of symbolic links in the rcN.d directories. The letter (S or K) says start or stop, the two digits say the order, and the rest is the script name. That is all. You can read the complete boot plan for a runlevel with a plain ls, and change it by renaming or deleting links. It is beautifully transparent and, at scale, painfully manual, which is why every distribution wrapped it in tools like update-rc.d and chkconfig.

7.2 Runlevel Numbers Mean Different Things on Different Distributions

A common and dangerous surprise: the numbers 2 through 5 are only conventions, and the two big Unix families never agreed on them. On Red Hat-style systems, runlevel 3 is multi-user text mode and 5 adds a graphical desktop. On Debian-style systems, runlevels 2 through 5 are all the same full multi-user state by default. So a script or instruction that says "boot to runlevel 3 for no graphics" is correct on Red Hat and does nothing useful on Debian. Only 0 (halt), 1 (single-user), and 6 (reboot) mean the same thing everywhere.

RunlevelRed Hat familyDebian family
2 Multi-user, no NFS Full multi-user (default)
3 Multi-user, text Full multi-user
5 Multi-user, graphical Full multi-user

7.3 init Really Does Supervise One Thing: getty

People say old init "did not watch its services", and that is mostly true, with one clear exception: the respawn action in inittab. Any line marked respawn is restarted by init the instant it exits. Its main use is the getty login prompts on the virtual consoles: log out, and init immediately starts a fresh prompt. This tiny piece of supervision has always been in init; systemd simply generalised it to every service with directives like Restart=on-failure.

7.4 Why the Old Boot Was So Slow

SysV init ran the S scripts in a runlevel strictly one at a time, in number order, each finishing before the next began. If a network mount was slow, everything behind it simply waited. Modern hardware can start dozens of independent services at once, but SysV init had no idea which services were independent, so it could not overlap them safely. This single fact (serial startup) is the clearest reason a big SysV server could take minutes to boot while an equivalent systemd machine takes seconds: systemd reads the dependencies and starts everything it safely can in parallel.

7.5 On Your systemd Machine, It Is All a Polite Illusion

Run service cron restart on a current Ubuntu or Debian box and it works, printing "via systemctl". There is no SysV init running at all. systemd ships a generator that reads any leftover /etc/init.d scripts at boot and turns each one into a temporary unit on the fly, and it provides drop-in replacements for service, telinit, runlevel, and even a mapping from runlevels to targets (runlevel 3 becomes multi-user.target). The whole SysV surface is kept alive as a courtesy so decades of scripts and habits keep working.

7.6 How the Kernel Finds init in the First Place

Before any of this can happen, the kernel has to locate an init program to run as PID 1, and it does so by trying a short list of fixed paths in order. The first one that exists and runs, wins:

1. /sbin/init      the normal place (a symlink to systemd today)
2. /etc/init        an older location, tried next
3. /bin/init        another fallback
4. /bin/sh          last resort: just give a shell

If none of them can be run, the kernel gives up with a panic, because a system with no PID 1 cannot go on. This list is also why a broken init is recoverable. You can tell the kernel to skip it entirely by adding an init= option to the boot command line in GRUB:

init=/bin/bash     boot straight into a shell as PID 1, no init at all

This classic rescue trick hands you a root shell before any service or even the real init starts, which is exactly what you want when a bad configuration stops the machine from booting normally. It works on any Linux system, SysV or systemd, because the choice happens in the kernel, one step before init runs.

Back to top

8. Best Practices

  • On a modern system, prefer systemd units. If you are writing something new, a short unit file gives you restart-on-crash, logging, and reliable process tracking that an init script cannot match. Reach for SysV init only when you must support a system that has nothing else.
  • Use the enabling tools, not raw symlinks. Let update-rc.d (Debian) or chkconfig (Red Hat) create and remove the rcN.d links so the dependency order stays correct.
  • Always write a correct LSB header. The Required-Start and Default-Start lines are how the boot order is computed. A missing header means your service may start at the wrong time.
  • Make your init script idempotent and honest. start on an already-running service should not start a second copy, and status should report the truth. Use start-stop-daemon rather than rolling your own PID handling.
  • Never set the default runlevel to 0 or 6. The machine would halt or reboot on every boot. Use 3 or 5 (Red Hat) or 2 (Debian).
  • Read the manual. The SysV tools are well documented, and the manual pages are the authority.
$ man init          # the init program and PID 1
$ man inittab        # the /etc/inittab format and actions
$ man telinit        # changing runlevel
$ man 8 service      # running an init script
$ man update-rc.d    # managing the S/K links on Debian
Back to top

9. Common Mistakes

9.1 Myth versus Reality

MythReality
"SysV init supervises services and restarts them if they crash." It does not, except for respawn lines like getty. A crashed daemon just stays down.
"Runlevel 3 means text mode and 5 means graphical, everywhere." That is only the Red Hat convention. On Debian, runlevels 2 to 5 are identical by default.
"init reads which services to start from a config file." The boot plan is encoded in the names of symlinks in the rcN.d directories, nothing more.
"init and systemd are completely different worlds." systemd is /sbin/init today and keeps service, runlevel, and /etc/init.d working through a compatibility layer.
"The S and K numbers are arbitrary." They set the exact start and stop order. Getting them wrong starts a service before the thing it depends on.

9.2 Other Traps to Avoid

  • Editing rcN.d links by hand. It is easy to break the order or forget the matching K link. Use update-rc.d or chkconfig instead.
  • Trusting a stale PID file. If a daemon dies without cleaning up, the old PID may now belong to another program, and a stop can kill the wrong process.
  • Forgetting the LSB header on a new script. Without it the enabling tool cannot place the service correctly in the boot order.
  • Assuming init 0 is a safe test. It halts the machine. On a remote server that means you have just shut it off with no easy way back.
  • Expecting logs in the journal. A pure SysV service writes wherever its script sends output, often a file in /var/log or nowhere at all; there is no unified journal to search.
  • Editing an init script that systemd has replaced with a native unit. If a real .service exists, systemd uses it and ignores the old /etc/init.d script, so your edits appear to do nothing.
Back to top

10. Summary

SysV init is the classic way Unix and Linux booted for thirty years: a small init program at PID 1, a set of numbered runlevels, and a directory of shell scripts run in order. It was simple enough that anyone could add a service and transparent enough that the whole boot plan was just a list of symlinks. It was also slow, script-heavy, and nearly blind to the services it launched, which is exactly why systemd replaced it. Knowing SysV init tells you where today's boot came from and lets you read the many scripts and systems that still assume it.

  • SysV init is the System-V-style init system: init as PID 1, driven by /etc/inittab, runlevels, and /etc/init.d scripts.
  • A runlevel is a numbered system state; 0 halts, 1 is single-user, 6 reboots, and 2 to 5 are multi-user conventions that differ by distribution.
  • You control it with runlevel, telinit, init, and service, and enable services with update-rc.d or chkconfig.
  • The boot order lives entirely in the S and K symlink names in the rcN.d directories: S starts, K stops, the digits set the order.
  • Each service is a hand-written init script with an LSB header; init gives no supervision beyond respawn, and stopping relies on fragile PID files.
  • Its serial, one-at-a-time startup is why old boots were slow; systemd's parallel, dependency-driven boot is the direct answer.
  • On a modern machine /sbin/init is systemd, which keeps the whole SysV toolset working as a compatibility layer.

This is the quick reference worth keeping:

runlevel                    show previous and current runlevel
telinit 3                   switch to runlevel 3
init 0                      halt the machine (runlevel 0)
init 6                      reboot the machine (runlevel 6)
service NAME start|stop     run an init.d script's start/stop
service NAME status         report a service's state
/etc/inittab                the master config: default runlevel, getty, etc.
/etc/init.d/                the service scripts themselves
/etc/rcN.d/                 S and K symlinks that set order for runlevel N
update-rc.d NAME defaults   enable a service at boot (Debian)
chkconfig NAME on           enable a service at boot (Red Hat)
/etc/rc.local               commands to run once at the end of boot
man inittab                 the reference for the inittab format

Most servers today run systemd, but plenty of older machines, appliances, and containers still boot the SysV way, and its scripts linger in places you would not expect. If your systems mix old init scripts with modern units, boot in an order no one on the team can quite explain, or depend on a service that quietly fails to come back, it pays to have someone map out how the machine really starts, so its behaviour is something you understand rather than something you hope for.

Back to top
Linux concept: SysV init
Peter Martin
Peter Martin
Joomla Specialist

Peter is a Joomla specialist and a Linux admin for fast, secure and scalable websites.