What Is sysvinit and How Does It Differ From systemd?

Updated

sysvinit is the traditional Unix System V-style init system: it is the first process the kernel starts (PID 1) and is responsible for bringing the rest of the operating system up. It reads /etc/inittab to decide which runlevel to enter, then runs the scripts in /etc/init.d (linked from runlevel directories such as /etc/rc3.d) in a fixed sequence to start daemons like networking, cron, and syslog. It is a good fit if you want a small, script-driven, predictable boot process, or if you are maintaining older distributions and hardware. It is a poor fit if you need parallel service startup, socket activation, or integrated logging, which is where systemd differs most.

What sysvinit actually does

The init daemon is the first process spawned by the kernel, so it holds PID #1 and is responsible for spawning the other daemons the OS needs to operate — networking, cron, syslog, and so on. sysvinit performs that role in a deliberately simple way:

  • Runlevels. /etc/inittab defines what each runlevel means (single-user, multi-user, graphical, reboot, shutdown) and which scripts run for each.
  • Sequential scripts. Each service is a shell script in /etc/init.d. Symlinks in /etc/rcN.d named S##name (start) and K##name (kill) determine order by their numeric prefix.
  • No built-in supervision. If a daemon crashes, sysvinit does not automatically restart it unless the script or an external tool does so.
  • Plain-text logs. Services typically write to syslog or their own files; there is no unified journal.

Because ordering is encoded in filenames and scripts run one after another, boot time grows with the number of services, but the behavior is easy to trace by reading the scripts.

How systemd differs

systemd replaces the script-and-runlevel model with declarative unit files and a central manager. The practical differences:

Dimension sysvinit systemd
Startup Sequential shell scripts Parallel, dependency-ordered units
Configuration /etc/inittab + /etc/init.d scripts Unit files (*.service, *.target, etc.)
Service dependencies Ordering via S##/K## prefixes Explicit After=, Requires=, Wants=
Process supervision None built in Restarts, cgroups, resource control
Logging syslog or per-service files journald journal
Activation Start at boot/runlevel Also socket, bus, path, timer activation
Targets vs runlevels Runlevels Targets (e.g. multi-user.target)

The trade-off is the same one the source frames as the core dispute: systemd claims to be a good and modern replacement for SysVinit, but it concentrates many responsibilities (init, logging, networking, device management) into one project, which is exactly what critics object to.

Alternatives to both

The init landscape is wider than sysvinit vs systemd. The source lists these init daemons, with several marked inactive (no development activity for several years):

  • Active: systemd, SysVinit, OpenRC, runit, s6, Shepherd, finit, Hummingbird, superd, 31init, Dinit, procd, dmaster, prometheus
  • Inactive: uselessd, Upstart, InitNG, cinit, minit, Epoch

If your goal is simply to avoid systemd, OpenRC, runit, and s6 are the commonly cited replacements; if your goal is minimal change from a classic setup, staying on sysvinit or a compatible script-based init is the smallest step.

Why people move away from systemd

The source's case against systemd is built on a list of notable bugs and security issues rather than on architecture alone. Examples it cites include:

  • A Datadog outage costing 5 million dollars caused by a systemd upgrade.
  • A widespread Azure outage when systemd 237-3ubuntu10.54 was published to the bionic-security pocket, after which instances could no longer resolve DNS queries, breaking networking.
  • CVE-2017-15908 (resolved loop on packets with pseudo DNS types), CVE-2018-15688 (out-of-bounds write in systemd-networkd DHCPv6 option handling), and CVE-2018-16864/16865/16866 (a systemd-journald exploit).
  • Operational issues such as PID 1 getting stuck printing "Time has been changed" continuously, systemctl status taking over 10 seconds when the disk journal is used, and systemctl treating active→failed as a successful operation.

These are the concrete observations behind the general complaint; they are worth reading directly if you are deciding whether the risk profile matters for your systems.

Migrating from systemd to sysvinit: what to watch

There is no in-place switch — you generally choose a distribution or image that ships the init you want, or rebuild the userland around it. When you do, expect these friction points:

  1. Service definitions don't translate. A *.service unit has no direct sysvinit equivalent; you rewrite it as an /etc/init.d script with start, stop, restart, and status cases.
  2. Dependencies become ordering. After=/Requires= must be expressed as S##/K## numbering, which is coarser and easier to get wrong.
  3. No journal. You lose journalctl; plan for syslog or per-service log files and adjust any tooling that parsed the journal.
  4. No socket/timer activation. Services that relied on systemd socket or timer units need another mechanism (inetd-style activation, cron, or an external supervisor).
  5. Supervision is your job. If you depended on Restart=always, add a supervisor or a wrapper loop, or accept that a crashed daemon stays down.

Verify each step by rebooting into the target runlevel and checking that the expected daemons are running and that networking, logging, and cron behave as before.

Choosing between them

Pick sysvinit (or a compatible script-based init) when you want a small, readable, sequential boot process, are working with older or resource-constrained systems, or specifically want to avoid systemd's scope. Pick systemd when you need parallel startup, dependency management, socket/timer activation, cgroup-based resource control, and unified logging out of the box. If neither extreme fits, OpenRC, runit, or s6 sit between them and are the usual destinations for people leaving systemd without returning to classic SysV scripts.