As most distributions have switched to systemd as default "init", some
people have asked why we actually keep sysvinit around, as it's old and
crusty, and systemd can do so much more.
My answer is: systemd and sysvinit solve entirely different problems, and
neither can ever replace the other fully.
The big argument in favour of systemd is integration: when you keep
everything in one process, it is easy to make sure that components talk to
each other. That is nice, but kind of misses the point: integration could
be done via IPC as well, and systemd uses a lot of it to separate
privileges anyway.
The tighter integration comes from something else: the configuration
format. Where sysvinit uses a lot of shell scripts ("imperative" format),
systemd uses explicit keywords ("descriptive" format), and this is the
important design decision here: descriptive formats cannot do anything
unanticipated, neither good nor bad.
This is important for UI programmers: if there is a button that says "if I
close the lid switch, suspend the laptop", then this needs to be connected
to functionality that behaves this way, and this connection needs to work
in both directions, so the user will find the active setting there when
opening the dialog. So, we need to limit ourselves to a closed set of
choices, so the UI people can prepare translations.
This is the design tradeoff systemd makes: better integration in exchange
for less flexibility.
Of course, it is simple to allow "custom" actions everywhere, but that
starts to break the "well-integrated" behaviour. There is an
old blog
post
from Joey Hess about how to implement a simple alarm clock, using systemd,
and this shows both how powerful and how limited the system is.
On one hand, the single line
WakeSystem=true
takes care of the entire
dependency chain attached to making sure the system is actually on -- when
the system is going to suspend mode, some program needs to determine that
there are scheduled jobs that should wake up the system, determined which
of these is the next one, program the wakeup time into the hardware and
only then allow the suspend to continue.
On the other hand, the descriptive framework already breaks down in this
simple example, because the default behaviour of the system is to go to
sleep if the lid switch is closed, and the easiest way to fix this is to
tell systemd to ignore the lid switch while the program is running. The IPC
permissions disallow scheduled user jobs from setting this, so a "custom"
action is taken that sets up the "ignore the lid switch" policy, changes to
an unprivileged user, and runs the actual job.
So, it is possible to get back flexibility, but this is traded for
integration: while the job is running, any functionality that the "suspend
laptop when the lid is closed" button had, is broken.
For something simple as a switch on a personal laptop that breaks if the
user configures something that is non-standard, that is acceptable.
However, the keywords in the service
unit files, the
timer files, etc.
are also part of a descriptive framework, and the services using them
expect that the things they promise are kept by the framework, so there is
a limit to how many exceptions you can grant.
SystemV init really comes from the other direction here. Nothing is
promised to init scripts but a vague notion that they will be run with
sufficient privileges. There is no dependency tracking that ensures that
certain services will always start before others, just priorities. You can
add a dependency system like
insserv if you like and make sure that all
the requirements for it to work (i.e. services
declaring their
dependencies) are given, and there is a safe fallback of not parallelizing
so we can always play it safe.
Because there is so little promised to scripts, writing them becomes a bit
tedious -- all of them have a large case statement where they parse the
command line, all of them need to reimplement dropping privileges and
finding the PID of a running process. There are lots of helpers for the
more common things, like the LSB standard functions for colorful and
matching console output, and Debian's
start-stop-daemon
for privilege and
PID file handling, but in the end it remains each script's responsibility.
Systemd will never be able to provide the same flexibility to admins while
at the same time keeping the promises made in the descriptive language, and
sysvinit will never reach the same amount of easy integration. I think it
is fairly safe to predict both of these things, and I'd even go a step
further: if any one of them tried, I'd ask the project managers what they
were thinking.
The only way to keep systems as complex as these running is to limit the
scope of the project.
With systemd, the complexity is kept in the internals, and it is important
for manageability that all possible interactions are well-defined. That is
a huge issue when writing
adventure games, where you need to define
interaction rules for each player action in combination with each object,
and each pair of objects that can be combined with the "Use" action. Where
adventure games would default to "This doesn't seem to work." or "I cannot
use this.", this would not be a helpful error message when we're trying to
boot, so we really need to cut down on actions and object types here.
Sysvinit, on the other hand, is both more extreme in limiting the scope to
very few actions (
restart
,
wait
,
once
) and only one object type
(process that can be started and may occasionally terminate) in the main
program, and a lot more open in what scripts outside the main program are
allowed to do. The prime example for this is that the majority of
configuration takes place outside the
inittab even -- a script is
responsible for the interface that services are registered by dropping init
scripts into specific directories, and scripts can also create additional
interfaces, but none of this is intrinsic to the init system itself.
Which system is the right choice for your system is just that: your choice.
You would choose a starting point, and customize what is necessary for your
computer to do what you want it to do.
Here's the thing: most users will be entirely happy with fully uncustomized
systemd. It will suspend your laptop if you close the lid, and even give
your download manager veto power. I fully support Debian's decision to use
systemd as the default init for new installs, because it makes sense to use
the default that is good for the vast majority of users.
However, my opening statement still stands: systemd can never support all
use cases, because it is constrained by its design. Trying to change that
would turn it into an unmaintainable mess, and the authors are right in
rejecting this. There are use cases that define the project, and use cases
that are out of scope.
This is what we need sysvinit for: the bits that the systemd project
managers rightfully reject, but that are someone's use case. Telling these
users to get lost would be extremely bad style for the "universal operating
system."
For example, if someone needs a service that asks a database server for a
list of virtual machines to start, runs each in its private network
namespace that is named after replacing part of the virtual machine name
with the last two octets of the host machine's IP address, then binds a
virtual Ethernet device into the network namespace and sets up a NAT rule
that allows devices to talk to the public Internet and a firewall rule to
stop VMs from talking to each other.
Such a beast would live outside of systemd's world view. You can easily
start it, but systemd would not know how to monitor it (as long as there is
some process still running, is that a good sign), not know how to shut down
one instance, not know how to map processes to instances and so on. SystemV
init has the advantage here that none of these things are defined by the
system, and as long as my init script has some code to handle "status", I
can easily check up on my processes with the same interface I'd use for
everything else.
This requires me to have more knowledge of how the init system works, that
is true, however I'd also venture that the learning curve for sysvinit is
shallower. If you know shell scripting, you can understand what init
scripts do, without memorizing special rules that govern how certain
keywords interact, and keeping track of changes to these rules as the
feature set is expanded.
That said, I'm looking at becoming the new maintainer of the sysvinit
package so we can continue to ship it and give our users a choice, but I'd
definitely need help, as I only have a few systems left that won't run
properly with systemd because of its nasty habit to keep lots of code in
memory where sysvinit would unload it after use (by letting the shell
process end), and these don't make good test systems.
The overall plan is to set up a CI system that
- tests sysvinit -> systemd transition
- tests systemd -> sysvinit transition
- tests debootstrap with systemd
- tests debootstrap with sysvinit
- tests whether service start works for a list of services, so we can
catch regressions
- scans packages that have systemd unit files for init scripts, and vice
versa
Ideally, I'd like to reach a state where we can actually ensure that the
default configuration is somewhat similar regardless of which init system
we use, and that it is possible to install with either (this is a nasty
regression in
jessie: bootstrapping a foreign-architecture system broke).
This will take time, and step one is probably looking at bugs first -- I'm
grateful for any help I can get here, primarily I'd like to hear about
regressions via bug reports.
tl;dr: as a distribution, we need both systemd and sysvinit. If you
suggest that systemd can replace sysvinit, I will probably understand that
you think that the systemd maintainers don't know project management. I'm
reluctantly looking at becoming the official maintainer because I think it
is important to keep around.