Classic sysvinit or BSD-style init doesn't rely upon this sort of functionality at all. Just some simple scripts. No need to complicate it any further. A few signals are all that are needed.
If you look into these, you'll find tons of near-duplicate code between scripts, and frequently every script reinvents the wheel in one way or another.
/etc/init.d $ for I in * ; do printf "%s %s \n" $(cat $I | grep -v -e '#' | wc -l) $I; done | sort -n | grep -v net.e | tail
142 mysql
142 sysfs
157 kexec
172 udev
172 xdm
182 apache2
195 bootmisc
232 named
297 dmcrypt
736 net.lo
This is on an OpenRC Gentoo system. There's very little duplicated code in the init scripts.
You might well complain that many these init scripts are substantially longer than the equivalent systemd unit files. Your complaint would be valid. Thing is, many of these init scripts do so much more than the equivalent systemd unit files. Ferinstance, the postgres and mysql unit files that I've seen permit no user configuration (like, such as, altering daemon listen port, config file location, and the like). [0] They also don't do any sort of housekeeping such as verification of the validity of the service's configuration file, checking and repairing mode and ownership of the same, and verifying the existence of the service's data directory.
I understand that OpenRC wasn't being considered for Debian Jessie, but it does a lot of things right, and is (IMO) head-and-shoulders above SysV init. (But then, isn't even bringing up SysV init kind of beating on a dead horse? We all agree that it really needs improvement.)
For a look at a simpler init script, check out the script for dnsmasq: http://pastebin.ca/2845520 . Looks pretty simple, no? At least as simple as the systemd service files we've been seeing, yes? The config file for dnsmasq is a single line: DNSMASQ_OPTS="--user=dnsmasq --group=dnsmasq" .
OpenRC provides complexity when you need it, and gets out of your way when you don't.
[0] I don't have systemd installed, so I might be missing the user configuration facilities. If they exist, and the configuration files have any appreciable complexity, then their line count must be counted against the unit file's line length.
If duplicate code bothers you this much, then what stops you from abstracting the common routines into something like BSD's /etc/rc.subr, and then sourcing them in the service-specific init script?
Yes, modern linux and sysvinit are pigs compared to some alternatives (though systemd is worse). The choice isn't a binary choice between sysvinit and systemd. How about this? init + rc + all the scripts combined are smaller than your handful of daemon-specific scripts. And I understand exactly how all of this works (the kernel parts included). I can easily change any part of it, I can easily debug any part of it, I can easily extend any of it if I need special features. With systems that comprise hundreds of thousands of lines of code, just beginning to understand how all of it works together takes much more time...
You cannot assume that /bin/sh always refers to Bash. There's a lot more to Unix than just Linux and Mac OS X. On FreeBSD /bin/sh is a 1989 rewrite of the SVR4 Bourne shell. As of 10.0-RELEASE it comes to 21167 lines, including its Makefile, ancillary shell scripts, and documentation.
That's not really fair since the shell is an independent part of the system and could be swapped out for another implementation. Plus, it's not there just for the init system; it'd be there regardless of the init system. It's an already existing independent component, which is used for leverage.
Otherwise should we also count the C compiler, libc, all the CLI utilities and the kernel?
But here you go. Still smaller than systemd. Sysvinit needs a shell too...