It’s an important piece, here. The author stays calm and elucidates some points I take seriously. Up to now, everything I’ve seen against systemd has been extremely angry in tone, which has made it very difficult to understand. I do believe that the level of acrimony is essentially a personality conflict, as several have claimed, but unfortunately pid 1 is a really important piece of the system and does deserve very careful attention to detail in its design, so I haven’t felt I had the luxury of just not reading the mess.
I personally find systemd nicer in the short term than init scripts. I’ve written a few init scripts over the years, and I must say that I never had any desire to understand the history of the different styles and how to do them portably - I was running Debian, so I wrote them the Debian way. I have been made aware that this means they won’t work anywhere else. In fact, they barely worked on Debian, and I never did figure out most of the issues. Readers should feel free to dismiss this as me being inept, if they prefer. :) I do understand how forking works and why daemons have traditionally had to fork twice but why that’s not always needed anymore, and actually a lot of what’s happening behind the scenes, and I found that next to impossible to relate to what was happening in the shell script.
Systemd promises a declarative configuration language. This is the point where I disagree with this article’s author: he sees the use of the shell in initialization as not a problem. I’m sorry - but using a general-purpose shell makes it impossible to avoid impurities in the functional sense. Shell-based init is always going to be intensely dependent on what parts of the system are already working, what environment variables are in scope, whether it’s being invoked manually or automatically… carefully sanitizing the environment in each script is not much of a solution, since Unix uses far too much state for true sanitizing to be possible. The only solution to that is to solve it generally, by using a DSL that excludes knowledge of that state from its specifications.
It’s absolutely right, though, that systemd has necessarily had to reinvent the substitution mechanisms of the shell. Mind, those mechanisms are the ugliest part of the shell, but they fill a real need and systemd has done a bad job with them. In writing unit files, I’ve run into plenty of cases where I couldn’t do things the way systemd intended because it doesn’t deign to provide the appropriate substitution features.
The author also mentions predictability, the inability to know what units will start on the next boot. This is fair, although I have no idea how “sysvinit outperforms systemd immeasurably” in this regard. I understand the run-levels thing, but not how it interacts with dependencies well enough to make any such prediction. Yes, I’m not a system administrator; I am far more often in the position of writing software than running it, though I tend to believe we could all use some of both.
The points about systemd behaving condescendingly towards its user are well taken, and I agree completely.
The author also asserts that the vocabulary of directives is far smaller than it needs to be. I definitely have, myself, run into cases where the existing systemd directives are inadequate. My personal peeve is not allowing mount points that can be invoked as a non-admin; also, the existing mechanisms for making units parametric are very special-case, and not useful in really any of the situations I’d want them. I do, in fact, expect that systemd is going to add directives - and I agree with the author that this is a bad thing. They need to be adding general mechanisms for extensibility, not special cases.
Having read this piece, I’m pretty sure systemd is not going to be satisfying to me in the long run. I do wish we had more options here, but I’m afraid the amount of acrimony over systemd is going to terrify programmers away from writing better pid 1 implementations for a long, long time.
Systemd promises a declarative configuration language. This is the point where I disagree with this article’s author: he sees the use of the shell in initialization as not a problem. I’m sorry - but using a general-purpose shell makes it impossible to avoid impurities in the functional sense.
It’s already impossible to avoid impure initialization units, because you can call out to external programs (especially, shell init scripts) with them; and furthermore, this capability is inescapable, because without it, your init system will be insufficiently flexible to launch everything it needs to launch and thus useless. (Or its internal configuration language will be as computationally powerful as shell, but this is much much worse, since at least we’ve had thirty years to figure out how to write decent shell.) Minimizing the degree to which init configuration has side effects is of course desirable, but preventing it altogether is impossible.
This point, or at least specifically systemctl edit (which I didn’t know about beforehand) I actually don’t have much issue with; in the same vein as sudoedit visudo or crontab -e, putting a thin wrapper around editing files that can brick your system to do at least a minimal syntax check is eminently reasonable. (After a quick check of the documentation, which contrary to many claims is not especially helpful, it’s not clear if systemctl edit actually does any checks; if not, it’s a stupid waste of time and I rescind this counterpoint. And regardless, systemctl is a stupid, ludicrously overlarge crime against commandline interface design.)
I think my personal issues with systemd essentially boil down to the following two:
If it were merely mediocre but optional, I wouldn’t care at all. It’s far from the most mediocre piece of software out there; in fact, it’s probably better than the most mediocre software I voluntarily use already. But having it forced on me, and in particular having it forced into a place where I need my software to be as simple, robust, and understandable as possible, is hugely galling. It’s especially disappointing to me, because I really like Linux’s software bazaar, so I would much prefer not to be pushed to a BSD. =/
Or its internal configuration language will be as computationally powerful as shell, but this is much much worse, since at least we’ve had thirty years to figure out how to write decent shell.
I’m not sure I agree on this part. Sysvinit scripts, at least as they exist in the wild, are really really bad, and 30 years has barely helped the situation. Debian attempts to apply some coding discipline and standards to its versions, but they’re still a mess of verbose, error-prone boilerplate to handle all kinds of edge cases, which still often ends up with bugs. Imo, it might be time to just admit that shell init scripts are a dead end: a badly designed tool that hasn’t been fixed and never will be. Maybe somewhere on par with configuration driven by m4 macros, in the realm of bug-prone, unreadable ‘70s-isms which should be abandoned.
edit: I should admit that sysvinit in particular is a big part of the brokenness though; a non-sysvinit shell-based init system could certainly be less bad.
On the other hand, BSD rc scripts and OpenRC init scripts are both nominally shell and entirely declarative in most simple cases (and are trivially extended where needed, because again, they are shell scripts).
My point was really this: language design is really hard and very difficult to get right, and if a language evolves out of something not really intended to be a language (the way systemd’s directives seem to be going), it’s effectively guaranteed to be an unusable, incomprehensible abomination. Shell is not a great language, but it’s very well and widely understood, and it’s conducive to the creation of (easily extensible) DSLs like BSD rc.
I don’t disagree that it’s a hard problem. I don’t think there IS a feasible acceptable answer here. :(
Imo, it might be time to just admit that shell init scripts are a dead end: a badly designed tool that hasn’t been fixed and never will be.
I could not agree more. On an hours-per-line basis I have downright wasted more time reading shell scripts than any other sort of code whatsoever. Buggy, unreadable, entirely lacking in standards or discipline… I find them the epitome of “hacky” in the most derogatory sense.
I would be the first to say “good riddance” if we were to move away from shell scripts as a community.
Oh, 100%. Let’s figure out a replacement, right now.
OK, first of all, it’s got to be a rich environment – something that lets us be versatile, because environments change all the time. It’ll need to be something that we can use to automate the execution of many other programs. And since we need to be able to iterate on the development pretty frequently and come up with ad hoc arrangements of programs, it’ll need to have a read-eval-print loop. And since we need to be able to take output from one program and use that in the next program in a ‘pipeline’, we’ll need to have some sort of facility for piping information from one program to the next. Oh, and since we might need to execute programs or not, depending on certain conditions like their exit codes, we’ll need to have variables, and conditional data structures, and looping. We’re also going to need it to be able to use job control – to be able to execute programs in the background, perhaps using a priority system to inform the kernel which jobs to give more timeslices to. And we’re also going to need the ability to do string substitutions for our variables, so that we can pass arguments to these programs. And we’re going to need wildcard substitution while we’re at it, for processing large lists of files from the filesystem. And it’ll be useful to have a set of variables and values that are persistent for our session, and also initialized at the beginning of our session; we can call that an ‘environment’ maybe. Since we need to be able to iterate quickly, we’ll also need a history of the commands that we’ve used in the REPL when we invoke this interactively; perhaps even a list of directories we’ve visited that we can scroll through. It would also be pretty useful to be able to get help about the built-in command list because we’re starting to make this fairly rich and complicated; and, if we’re feeling particularly excited, it would be kind of nice to have automatic command completion, history editing, spell checking, and syntax highlighting.
There! We’ve got the basic outline of an amazing replacement for shell scripts! Let’s call it the ‘Born Again Shell’, to signify our disruption of the computing space. I’m pretty sure we can take this to sand hill road and get 100m. Who’s in?
I’m pretty sure this thread was where I recently said, yes, absolutely it’s not obvious what to replace current shells with that aren’t just the same thing again. That doesn’t mean the design is actually as constrained as you’re making it out to be. I agree that the majority of the features you’re talking about should be in any shell-replacement (though job control needs a total rethink).
It particularly doesn’t mean we’re constrained to implement only, and exactly those.
And there are a million really simple language-design praxis issues that bash has, such as the fifty types of [foo] and [[foo]] and [ with a space before the contents ] and also [[ with a space before the contents ]]. But picking on those almost feels cheap, frankly, because one could improve those substantially and still not invent anything particularly novel, and I wouldn’t necessarily even be interested in the result unless I felt it was likely to stay around.
I would love to draw an art history analogy here, but I don’t know enough. :) But just because we’ve been stuck in a loop for twenty years (which isn’t even that long), and can’t see a way to proceed that isn’t the same thing we’ve been doing… well, it seems absurdly fatalistic to say there’s no way out of it, ever.
I agree with you that it’s a local maxima, and that there’s 60-year old cruft and temporary hacks in there which show their age. Certainly there’s room for significant improvement in many directions; and one does get the impression, given the flowering in PL theory, that an improvement is there for the taking.
That said, having heard all these complaints about the Unix shell, I then rushed to try out the thing that a lot of people are heralding as the New Example of Greatness, the shining beacon on the hill: powershell. I even needed it to do a simple thing: to run, on a list of remote machines, a process which kills an existing process, deploys a new executable from a shared directory, and then restarts the (graphical) process. Imagine distributing software to kiosks. I was gladdened and heartened to find that this was not just powershell, but powershell 3.0: a masterwork crafted through several revisions to finally arrive at true greatness.
I invite anyone to try that from a fresh install of two or more windows 8 boxes networked together. It’s incredibly educational, especially if you remember that Microsoft is one of the largest tech companies, filled with well-paid smart people, with a mandate for technical improvement, and half a century of operating systems knowledge. The task is simple; it is the sort of thing one does in a Unix shell in 5 minutes, and the sort of thing you create at an operational level in development probably up to several times a week.
(ASIDE: Nevertheless it turns out that not only is such a thing impossible, but it fails in horrible, ugly, and impossible to debug ways all the way throughout your journey to that discovery. You will discover that two commands have the same named parameter, but the parameter means very different things. You will learn that remoting is not allowed by default. You will learn that scripting itself is not allowed by default. You will learn that you cannot easily open up ports. You will learn that when you mount a share in explorer, it does not show up in powershell; powershell has its own, incompatible and different system for setting up shares. You will learn that you must explicitly give permission on the command line for scripts to remote, using an arcane syntax different from all of the other powershell syntax. You will learn that in 2015, windows shares still do not always show up on all machines consistently. And finally, finally you will learn that when you open a program using powershell remoting, it appears on an invisible desktop and cannot access the logged in user windows desktop, even if you are logged in as that user.)
All of this is to say: the Unix shell is one of the most successful and effective tools ever to exist; Unix now dominates every phone, every tablet, every television, and the internet. That is largely because Unix is open and manageable, in the large and in the small; and no small part of that is due to the shell. More respect is, I think, due.
Haha, well, I’m certainly ready to believe bad things about powershell. It was always hard for me to take seriously the idea that Microsoft was going to invent a significant improvement to how we work. :) It’s definitely a good example of different not always being better.
Within the scope of the problem as currently defined, yes, it’s impossible to actually force daemons to be pure. It would be very interesting, I think, to see something that handles isolation for services in the way nix handles it for compilation - everything gets an anonymous identifier instead of cluttering a global namespace, so the only way you can use a dependency you didn’t declare is by poking into internals, which is certainly a matter of trust but we shouldn’t be assuming bad will on the part of authors of services we rely on.
Nothing like that exists today, and it would have significant challenges; for example, if a mail service needs to listen on an external tcp port, but an otherwise-unrelated service wants to connect to that port as a client, there’s no obvious way to avoid the port being a global identifier.
I do think using an imperative language with fully general capabilities as part of the initialization can be avoided and should. Yes, systemd has issues with its declarative options being inadequate; that doesn’t mean everything will always be inadequate. Even systemd could fix the gaps if it were going in that direction, though, as discussed, it’s fairly clear that it’s not.
I agree that a thing like I want is a very large jump. I would never ask anyone to use such a thing before it’s proven.
Also, I agree with your points 1 and 2. I’m not happy at having it forced on me, either. I’d be adopting it if it were optional, but it’s still really upsetting that it isn’t. I realize the engineering isn’t feasible to maintain two versions of a distro in parallel… But, yes, the ecosystem is hurting as a result of this.
I may be missing something, but it seems that there are alternatives to traditional (e.g. awful) init, and systemd? launchd, from my former employer, for instance.
I’m shortly going to have to be living on Linux for work, and the combination of desktop environments, systemd, and the utter tire fire that is the (non nix?) world of package and dependency management makes me very, very, very queasy. I don’t like Unix much at all, but I like it even less when it’s hiding in the uncanny valley between “classic” SunOS or BSD asceticism and Windows. I could start an LFS project or something to produce a distribution that satisfies my very particular needs, but that seems like a lot of wasted effort just to be able to run nvcc.
Yeah, launchd is actually fairly nice. It’s deeply wedded to Apple’s stack (in particular, xnu, and also the plist format), but I’m sure enough effort could produce a Linux distribution based on it. I just… don’t think of that as remotely likely to happen. I guess I was framing the problem as how we can get a good alternative for open-source OSes, and I think the answer to that is that we can’t right now.
You mentioned nix in passing - I’m no expert, but I do believe its approach of isolating everything so that there cannot be hidden dependencies has worked well. I’m hopeful that when the package repository is larger, and some of the weaknesses have better solutions, people will start to see the appeal of that. Dependency management is truly the hard problem in an OS distribution.
I’ve converted almost entirely to FreeBSD, but for I think NixOS is the best Linux distro out there. I’m interested, some day, in trying to make a NixBSD for great good.
But I think @jfb’s point is really good. Many people’s only defence of systemd appears to be that “it’s better than init scripts”. But, like I said in my other response, things like daemontools are fantastic. So simple yet so functional.
Wasn’t FreeBSD working on a port of LaunchD (https://github.com/freebsd/openlaunchd)? I remember this being a major initiative at one point, did it die on the vine? I have been poking around BSD because I don’t love systemd, and I am a huge fan of ZFS.
I’m not actually sure, I’m a relative recent FreeBSD (re)convert.
I do not know if these arguments against systemd are any good but I have recently switched to deamontools for most thingsand really enjoy the simplicity. For a server, it does everything needed with minimal complexity.
daemontools (and the similar runit) are absolutely wonderful tools for system administration. I used them at my former job and they simplified things immensely.
I recently setup a new system using Arch Linux after trying FreeBSD (which I prefer, but doesn’t work on the hardware I have) and I’ve been giving systemd the college try. I commend its goals, but I feel it’s doomed to the complexity hell of dependency management.
I have tried various init schemes over the years and even implemented one of my own for an embedded system. In all init attempts I have seen that try to start things in the right order, it has never worked. There are always bizarre cases that arise and the proper dependency logic is suprisingly hard to get right, even though it’s “just a directed graph”.
Honestly, the best policy I’ve found for this is to just start the service and have it look for what it needs. If it can’t find it, it quits in some easily detectable way (non-zero exit code, for example) and the system just tries again. It’s marginally wasteful but considerably simpler and generally easier to debug.
That’s the kind of thing daemontools/runit excel at, and why I much prefer them.
Honestly, the best policy I’ve found for this is to just start the service and have it look for what it needs. If it can’t find it, it quits in some easily detectable way (non-zero exit code, for example) and the system just tries again. It’s marginally wasteful but considerably simpler and generally easier to debug
I think this is something I would have fought you on 5 or 6 years ago, but I’ve come to realise that, even though it sounds so cheap, the complexity of trying to do an upstart or a systemd is massive relative to the actual wins you get. It’s a good lesson that I don’t think our industry has really come to appreciate.
I find systemd to be almost objectively superior to initd, but I totally understand and respect that others might feel the opposite.
I tried to find what the author recommended in place of systemd but could only find that they had chosen to switch to OpenBSD, and I am not familiar with what system OpenBSD uses. If it uses initd, well, I am glad the author found an operating system he can enjoy. For myself, I refuse to use any system that uses initd.
If there is a significantly better system in *nix land than systemd, however, I’d be interested in reading a comparison on that.
When was the last time daemontools was updated? I could be wrong, but most of DJB’s old projects seem abandoned and unmaintained, as great as they are. They don’t even seem to be hosted in any sort of modern VCS.
It doesn’t need to be updated. It’s done. I wish more software would be finished.
On a tangent: I really hate that the software industry wants software to be constantly updated and uses “last commit” as a quality metric. Good quality software doesn’t need to be updated often.
I agree 90%. Even software that was done may become undone due to external changes. As one example, old software uses select. Now you’d use kqueue or epoll. Time passes, things change, and not always for the worse.
I agree, I think scalabilty is a valid external pressure to update something. Luckily in this case the number of processes one can run on a machine has not changed much in a few decades.
Better than systemd at what? It’s hard to even define the terms because systemd is so sprawling and intrusive.
If you just care about declaratively configuring your services I find OpenRC much nicer.