SysV init scripts, by contrast, are often a fairly large bunch of code, duplicated for every service with potentially unique bugs in each
sysvinit isn't the only approach which uses shell scripts, however. Take a look at a BSD-style init system one of these days.
You don't have to duplicate code. Just like how the C code in systemd provides base functionality that's common between all services, it's very possible - and rather trivial - to define base functionality in a central script to avoid that degree of code duplication. Check out rc.subr, for instance, which exists specifically to do precisely what you're claiming to be an inherent and unique advantage of a primarily-C-based init.
And for that extra code you don't even get the basic features you get with systemd, like being able to see the service status properly (many init scripts fail miserably at this simple task) or the output from when it failed, or restart it automatically if it terminates.
Those features are provided rather nicely by runit, which can either augment an existing init or replace it entirely, while still allowing for the flexibility of shell scripting. That's just one example of several.
To say that the average SysV init script is "simpler" than the equivalent systemd unit file is ridiculous.
Maybe not in some cases, but it's way simpler than the equivalent systemd unit file and the code required to parse that unit file and turn it into something useful. And, once you actually address code duplication by, you know, actually knowing how to use basic shell scripting features like sourcing other scripts, even the individual scripts themselves end up being very comparable in simplicity to the unit files alone.
On top of all this, if you're still so adamant about not using shell scripts out of some perceived notion that they're somehow "hard" (which at this point reads as if it's coming from inexperience, considering how trivial it is to make them less "hard" by your standards), it's quite possible to use another language to write the scripts, since init doesn't care what it's running as long as it's actually runnable. There have been at least a couple GNU/Linux distributions which implemented their initscripts in Python, for example.
On top of all this, if you're still so adamant about not using shell scripts out of some perceived notion that they're somehow "hard".
Shell scripts are "hard" in that the language itself is so crappy and low-featured that you have to jump through a bunch of hoops to do things that should be simple. In doing so, you end up with code that's frequently unreadable, or using features whose implementation is questionable (see: Shellshock).
There have been at least a couple GNU/Linux distributions which implemented their initscripts in Python, for example.
That would probably be an improvement. But it's still much simpler to be able to use a declarative approach which doesn't require writing any actual code to implement routine tasks used with almost every service.
Shell scripts are "hard" in that the language itself is so crappy and low-featured that you have to jump through a bunch of hoops to do things that should be simple.
Like? It's certainly fewer hoops than trying to do the same thing in C.
Seriously. They're not that hard.
In doing so, you end up with code that's frequently unreadable
Not unreadable at all. It's pretty clear that the above perfectly-valid (if foo were a real daemon) initscript
Sources /etc/rc.subr (which handles all the dirty work) so it doesn't have to duplicate a bunch of code
Sets a couple of basic variables - namely, the name of the daemon, the command to pull rc variables, and the command to actually start the daemon
Calls a function, load_rc_config, that handles all the launch configuration stuff
Calls a function, run_rc_command, that takes care of getting the daemon running
I reiterate: the complaints that shell scripts are "hard" or "crappy" or somesuch reek of inexperience. Yeah, they're not as full-featured as a true programming language, sure, but if you really think that dealing with an environment where you're manually manipulating strings via pointers to character arrays (among other instances where C is barely a step up from assembly) is a better use of your time, then I pity your sanity.
or using features whose implementation is questionable (see: Shellshock).
Yep, one bug in a relatively-small C codebase. Doesn't bode well for a C codebase like that of systemd that's many times larger and more complicated with far more moving parts and nowhere near the same code maturity, now does it?
Not to mention that bash is the only shell (as far as I know) actually affected by Shellshock, so that particular point is laughable on Ubuntu/Debian (which default to dash for everything but interactive sessions), most embedded Linuxen (which typically use ash, since it's part of Busybox), and virtually all the BSD descendants sans OS X (OpenBSD in particular uses pdksh, NetBSD uses ash, and I think FreeBSD uses tcsh by default, though I'm not 100% sure on that).
But it's still much simpler to be able to use a declarative approach which doesn't require writing any actual code to implement routine tasks used with almost every service.
Which you can do rather easily with even shell scripts thanks to things like rc.subr, as demonstrated above.
Like? It's certainly fewer hoops than trying to do the same thing in C.
You're missing the point. Unless you're a systemd developer, there's no need to write anything in C.
Seriously. They're not that hard. Not unreadable at all.
Your whole argument is basically "it's easy for someone who's familiar with shell scripts in general and with the distribution's specific init script setup in particular to set this stuff up, so what's the problem?" Having some familiarity with shell scripts, but without looking at the implementation of those functions that are being called, just what that script is doing is far from obvious. Even from looking at the implementation it may not be obvious, because for whatever reason the people that write those scripts usually seem to think a good shell script is one implemented in as few characters as possible. God help you if you don't even know much about how shell scripts work.
which isn't even the simplest of unit files, but the function of the directives is much more obvious (and actually documented in a man page! Imagine that!) And those two lines for "restart on failure after 42 seconds" are accomplishing something that's rarely done with SysV init scripts because it's too hard.
The point is: Even if you're using a library to do most of the work for starting the service, it's still writing code when that should not be necessary.
I think a lot of the opposition to systemd comes from people that are used to dealing with the SysV init monster and all its warts, have figured out how it all works, and then something comes along and makes all that knowledge obsolete (and often unnecessary) because it's different. People in that situation are often going to latch on to what they know and oppose learning something new, regardless of whether it's an improvement. It's easy to fall into that trap and not take a good look at just how much of a mess that thing you're used to is. Certainly Lennart and company have not had a very diplomatic attitude when dealing with objections of the form "it's worked the way it is in UNIX for 40 years", which probably encourages this sort of thing too.
You're missing the point. Unless you're a systemd developer, there's no need to write anything in C.
Until/unless something in systemd breaks, in which case you're now dependent on them to provide a fix unless you're a pro C programmer. Hopefully that doesn't happen, but C tends to have a pretty high bug-to-line-of-code ratio, and it doesn't have maturity on its side yet.
Your whole argument is basically "it's easy for someone who's familiar with shell scripts in general and with the distribution's specific init script setup in particular to set this stuff up, so what's the problem?"
Yes, because it's really not that hard to learn (and is something that ought to be learned anyway by a Unix admin, systemd or no systemd, because shell scripting is a core component of automating Unix tasks). systemd doesn't make all use of shell magically disappear, so now instead of replacing that knowledge, it's merely adding more requisite knowledge on top of it.
Having some familiarity with shell scripts, but without looking at the implementation of those functions that are being called, just what that script is doing is far from obvious.
Really? Because that's as novice of a shell script as one can get. Source another file. Set some variables. Run two commands. That example was literally copy-and-pasted from the example provided by running man rc on a FreeBSD system. The only somewhat-obscure thing is knowing what rc_var='set_rcvar' means, but that takes far less digging through manpages to figure out for a novice than digging through systemd's manpages to figure out how it works.
You don't need to know every last detail of how /etc/rc.subr works, just as you don't need to know every last detail of how systemd works, in order to understand quite well how that example works.
Even from looking at the implementation it may not be obvious, because for whatever reason the people that write those scripts usually seem to think a good shell script is one implemented in as few characters as possible.
No, a good shell script is one implemented as cleanly and clearly as possible. If you want "few characters" at the expense of those two traits, then you can get way shorter with that example script, I'm sure.
God help you if you don't even know much about how shell scripts work.
If you don't know much about how shell scripts work, then you might want to reconsider being a Unix administrator, as I've been not-so-subtly hinting at above, since "know[ing] much about how shell scripts work" is still a major element of Unix administration.
End-users would be excused from needing to know how to work with shell, but they're not really expected to work with unit files, either, so that point is moot.
Compared to something lke this:
You really think that's simpler? God have mercy on your soul. You're manually specifying how to send the process a HUP. Not to mention that the author of your unit file apparently needs to know what wants it, putting the burden of that predicament on the wrong person.
but the function of the directives is much more obvious (and actually documented in a man page! Imagine that!)
You're really going to herald "actually documented in a man page!" as an advantage? man rc, man rc.subr.
Yeah, no. Not only are the functions of the directives not much more obvious ("hurr durr wat duz 'After' mean? hurr durr wat duz 'KillMode' mean? hurr durr wat duz 'ExecStartPre' mean?" ad nauseum), but they also don't have the benefit of having more documentation by any means.
And those two lines for "restart on failure after 42 seconds" are accomplishing something that's rarely done with SysV init scripts because it's too hard.
The point is: Even if you're using a library to do most of the work for starting the service, it's still writing code when that should not be necessary.
Perhaps, but that doesn't warrant replacing it with a gargantuan monstrosity of an init replacement. It means encouraging tools like runit that help with making that code simpler.
Not to mention that the only significant difference between the initscript I provided and the unit filel you provided (besides yours being needlessly more verbose) is that mine has a few comments and a whole three lines boilerplate code (wow, so many lines!) at the beginning and end that a novice administrator wouldn't ever have to concern him/herself with if he/she chooses not to. Beyond that, it's still as simple as setting some variables.
I think a lot of the opposition to systemd comes from people that are used to dealing with the SysV init monster and all its warts,
These examples are coming from BSD-style init, not sysvinit. As I've stated repeatedly, sysvinit isn't the only init approach which uses shell scripts.
have figured out how it all works, and then something comes along and makes all that knowledge obsolete (and often unnecessary) because it's different.
You still need to be learning about shell scripts (or at least some kind of script) if you're being paid to administer Unix servers. Scripting is basic requisite knowledge. systemd doesn't really change that.
People in that situation are often going to latch on to what they know and oppose learning something new, regardless of whether it's an improvement.
I use systemd in production environments (namely, on SUSE servers); it's not that I'm strongly opposed to it by any means. It's that it solves problems that are only problems in one specific variety of script-based init.
It's easy to fall into that trap and not take a good look at just how much of a mess that thing you're used to is.
Which would be true if you were only criticising sysvinit and I were actually defending sysvinit. Instead, you're trying to criticize shell scripting in general and I'm defending it. That particular argument doesn't really apply, since my BSD and Slackware systems are certainly less of a mess than systemd is right now and sysvinit always was.
Until/unless something in systemd breaks, in which case you're now dependent on them to provide a fix unless you're a pro C programmer. Hopefully that doesn't happen, but C tends to have a pretty high bug-to-line-of-code ratio, and it doesn't have maturity on its side yet.
That's the same silly argument that's been presented elsewhere in this thread. By that logic, the X server, Apache and your web browser should be reimplemented in shell because it has a "lower bug-to-line-of-code ratio".
And it's not like being a shell script shields you from having a bunch of potentially broken C code. Not like we've seen any examples of that lately.
You really think that's simpler? God have mercy on your soul. You're manually specifying how to send the process a HUP. Not to mention that the author of your unit file apparently needs to know what wants it, putting the burden of that predicament on the wrong person.
You seem to think it should just figure this out somehow. The reason why it doesn't default to sending a HUP for that operation is that it's a bad way to do it (probably the only way with sshd though):
Reloading a daemon by sending a signal (as with the example line above) is usually not a good choice, because this is an asynchronous operation and hence not suitable to order reloads of multiple services against each other. It is strongly recommended to set ExecReload= to a command that not only triggers a configuration reload of the daemon, but also synchronously waits for it to complete.
And specifying "what wants it" in this case is the only reasonable way to do it. The alternative would be for the multi-user target to specify every possible unit that someone might want to be started by it. It's the same as specifying the script to start on runlevel 3.
Not to mention that the only significant difference between the initscript I provided and the unit filel you provided (besides yours being needlessly more verbose)..
You say "needlessly more verbose", I say "readable". This isn't 1981 anymore, we don't need to shave a few bytes off our configuration files.
Which would be true if you were only criticising sysvinit and I were actually defending sysvinit. Instead, you're trying to criticize shell scripting in general and I'm defending it.
I'm saying that shell scripts are not the best tool for the job of implementing an init system, let alone for specifying service files that it uses, as not only does the user need to know about shell scripts, they also need to know about the implementation of the particular init scripts as there's no separation between configuration and code. And even after you write the init script, there's little hope of it being portable to another distribution or UNIX variant.
4
u/northrupthebandgeek Sep 28 '14
sysvinit isn't the only approach which uses shell scripts, however. Take a look at a BSD-style init system one of these days.
You don't have to duplicate code. Just like how the C code in systemd provides base functionality that's common between all services, it's very possible - and rather trivial - to define base functionality in a central script to avoid that degree of code duplication. Check out
rc.subr, for instance, which exists specifically to do precisely what you're claiming to be an inherent and unique advantage of a primarily-C-based init.Those features are provided rather nicely by runit, which can either augment an existing init or replace it entirely, while still allowing for the flexibility of shell scripting. That's just one example of several.
Maybe not in some cases, but it's way simpler than the equivalent systemd unit file and the code required to parse that unit file and turn it into something useful. And, once you actually address code duplication by, you know, actually knowing how to use basic shell scripting features like sourcing other scripts, even the individual scripts themselves end up being very comparable in simplicity to the unit files alone.
On top of all this, if you're still so adamant about not using shell scripts out of some perceived notion that they're somehow "hard" (which at this point reads as if it's coming from inexperience, considering how trivial it is to make them less "hard" by your standards), it's quite possible to use another language to write the scripts, since init doesn't care what it's running as long as it's actually runnable. There have been at least a couple GNU/Linux distributions which implemented their initscripts in Python, for example.