The good and bad of the System V init system

February 14, 2014

The good of System V init is that it gave us several big improvements over what came before in V7 and BSD Unix. First and largest, it modularized the boot process; instead of a monolithic shell script (or two, if you counted /etc/rc.local) you had a collection of little ones, one for each separate service. This alone is a massive win and enabled all sorts of things that we take for granted today (for example, casually stopping or starting a service).

The other big change is that System V init turned the entire work of init from a collection of hacks into a systematic and generalized thing. It formally defined runlevels and runlevel transitions and created in /etc/inittab a general mechanism for specifying all of the work init did, from booting to running gettys on serial lines (or running anything) to how to reboot the system. System V init removed the magic and hardcoding in favour of transparency. Things like reboot stopped killing processes and making special system calls and turned into 'tell init to go into runlevel ...', and then /etc/inittab and runlevel transitions said what to do so that this actually rebooted the machine. In the process it added a way to specify how services shut down.

(Simply defining runlevels formally meant that other systems could now tell what state the system was in and behave differently between eg single user mode and multiuser mode.)

The very general and high level view of the bad of the System V init system is that fundamentally all it does is blindly run shell scripts (and that only when the runlevel changes). This creates all sorts of lower-level consequences:

  • SysV init doesn't know what services are even theoretically running right now, much less which ones of them might have failed since they were started.

  • It doesn't know what processes are associated with what services. Even individual init scripts don't know this reliably, especially for modern multi-process services.

  • Even init scripts themselves can't be certain what the state of their service is. They must resort to ad hoc approaches like PID files, flag files for 'did someone run <script> start at some time this boot', checking process listings, and so on. These can misfire.

  • Services are restarted in a different environment than how they are started on boot. Often contamination leaks in to a restarted service (in the form of stray environment variables and other things).

  • Output from services being started is not logged or captured in any systematic way. Many init scripts simply throw it away and there's certainly no official proper place to put it.

  • The ordering of service starts is entirely linear, by explicit specification and guarantee. System V init explicitly says 'I start things in the following order'. There is no parallelism.

  • Services are only started and stopped when the runlevel changes. There is no support for starting services on demand, on events, or when their prerequisites become ready (or stopping them when a prerequisite is being shut down).

  • System V init has no idea of dependencies and thus no way for services to declare 'if X is restarted I need to be restarted too' or 'don't start me until X declares itself ready'.

  • There is no provision for restarting services on failure. Technically you can give your service a direct /etc/inittab entry (if it doesn't background itself) but then you move it outside of what people consider 'the init system' and lose everything associated with a regular init script.

  • Since init scripts are shell scripts, they're essentially impossible for programs to analyse to determine various things about them.

  • It's both hard and system-dependent to write a completely correct init script (and many init scripts are mostly boilerplate). As a result it's common for init scripts to not be completely correct.

  • Init scripts are not lightweight things in general, either in reading them to understand them or in executing them to do things.

In theory you can try to fix many of these issues by adding workarounds in your standard init script functionality. Your 'standard' init script utilities would capture all daemon output in a documented place and way, start everything in cgroups (on Linux) or containers to track processes reliably, have support for restarting services on failure, carefully scrub every last bit of the environment on restarts, monitor things even after start, et cetera et cetera, and then you would insist that absolutely every init script use your utilities and only your utilities. In practice nothing like this has ever worked in practice (people always show up with init scripts that have bugs, take shortcuts, or do not even try to use your complex 'standard' init utilities) and the result would not particularly be a 'System V init system' except in a fairly loose sense.

(It would also make each init script do even more work and run even more slowly than they do now.)

Written on 14 February 2014.
« Init's (historical) roles
'Broken by design: systemd' is itself kind of broken »

Page tools: View Source, Add Comment.
Login: Password:
Atom Syndication: Recent Comments.

Last modified: Fri Feb 14 02:41:30 2014
This dinky wiki is brought to you by the Insane Hackers Guild, Python sub-branch.