On Mon, Apr 03, 2017 at 09:36:16AM -0500, Tom Browder wrote: > But I kind of understand why systemd, but I wish I could find a good > cookbook description of how to add or modify a new process.
The first hurdle is learning the terminology that systemd uses. It's not exactly intuitive. Systemd has "run levels" which are used to control which groups of services are started at boot time. But it calls these things "targets" instead of "run levels". The default target is called "graphical.target", which means that if a Display Manager is installed and enabled, it will be started. This is analogous to run level 5 on Red Hat systems. You can see your system's default target by running this command: $ systemctl get-default The other target (run level) that most people will care about is called "multi-user.target". This is analogous to run level 3 on Red Hat systems. It's the same as "graphical.target" but without the Display Manager. If you want to change your system's "run level" from graphical.target to multi-user.target, run this command as root: # systemctl set-default multi-user.target To see a list of your available targets (assuming no major local changes), use this command: $ find /lib/systemd/ -name '*.target' Now, the trickier part: adding a new managed service. Systemd calls these things "units". It also calls them "services", which are a specific type of unit. In the typical case, where you just want to run a daemon, nothing fancy, what you do is create a file in the directory /etc/systemd/system. This file's name should end with ".service" to indicate that this is a service. The first part of the file's name should be whatever you want your service to be called. The .service file is a text file in the "Windows INI" format, meaning there are sections with [Headers] in square brackets, and configuration lines within each section. (See "man systemd.unit" and "man systemd.service" for full details.) Suppose you want to start DJB's daemontools from a locally created systemd unit/service. Here's a file that will do that: ====================================================================== [Unit] Description=daemontools supervisor After=getty.target [Service] Type=simple User=root Group=root Restart=always ExecStart=/command/svscanboot /dev/ttyS0 TimeoutSec=0 [Install] WantedBy=multi-user.target ====================================================================== Mostly it's quite simple once you have an example like this. The ExecStart= line gives the command to be executed. The Type= line tells us that this command runs in the foreground, which every sane daemon should do. If your daemon is self-backgrounding, look for an option to tell it to STOP THAT, BAD DAEMON. Anything that has been seriously maintained at some time in this millennium should either run in the foreground by default, or should at least have an option to run in the foreground. I cannot stress this enough. Your daemons should run in the foreground. Self-backgrounding is BAD. Unconditional self-backgrounding is grounds for being deleted and replaced by something that does not suck. However, because systemd has to live in a world where evil runs free, it goes out of its way to be accomodating to those who must live under such a horrible regime. Therefore, it can be told to manage even a self-backgrounding daemon. (The Linux kernel introduced an entirely new thing called a "cgroup" to make this possible. That's how ridiculous self-backgrounding is.) If your daemon was written in 1985 and self-backgrounds and can't be changed, and you don't have the time to rewrite it yourself, then read "man systemd.service" and look for the word "forking". Be sure to read all of the recommendations. Once you've written your .service file, given it a cool name, and saved it in /etc/systemd/system, there are three more steps. First, you run this command to tell systemd to look for new unit files (as root): # systemctl daemon-reload Second, you tell systemd that your service should be enabled, which means it gets started automatically at boot time. Again, as root: # systemctl enable your.service Finally, tell systemd to start the service right now: # systemctl start your.service When you run systemctl start (or any other systemctl subcommand), note that all it does is send a message to systemd, asking systemd to do stuff. It doesn't hang around to see what happened. It doesn't report status. It just sends the message. Some people dislike this. They want to see a reassuring message to tell them that yes, their daemon is actually running now. Usually because sysvinit used to do that for them. Since there's no feedback from systemctl, therefore, there's one more command you should learn. You can run it without root: $ systemctl status your.service This shows you whether things are running or not. In fact, it tells you a whole bunch of stuff: the state of the service, how long it has been in this state, where it loaded the definitions from, which processes are part of the service's cgroup (in case there's more than one), and so on. In most cases, you can shorten "your.service" to simply "your". For example, using a common, standard Debian service: $ systemctl status cron * cron.service - Regular background program processing daemon Loaded: loaded (/lib/systemd/system/cron.service; enabled) Active: active (running) since Mon 2017-03-13 08:38:05 EDT; 3 weeks 0 days ago Docs: man:cron(8) Main PID: 492 (cron) CGroup: /system.slice/cron.service `-492 /usr/sbin/cron -f Or using the locally installed daemontools service shown previously: $ systemctl status daemontools.service * daemontools.service - daemontools supervisor Loaded: loaded (/etc/systemd/system/daemontools.service; enabled) Active: active (running) since Wed 2017-01-11 03:28:47 EST; 2 months 21 days ago Main PID: 529 (svscanboot) CGroup: /system.slice/daemontools.service |- 529 /bin/sh /command/svscanboot /dev/ttyS0 |- 531 svscan /service |- 532 readproctitle service errors: ............................... |- 533 supervise qmail-send |- 534 supervise log |- 535 supervise qmail-deliverabled |- 536 supervise log |- 537 supervise qpsmtpd |- 538 supervise log |- 539 /usr/local/bin/tcpserver -c 10 -v -R -p -u 112 -g 118 0 25... |- 540 /usr/local/bin/multilog t /var/log/qmail-deliverabled |- 541 /usr/local/bin/multilog t s5000000 /var/log/qpsmtpd |- 542 /usr/local/bin/qmail-deliverabled yes=4799(81.5%), no=1089... |- 543 qmail-send |- 544 /usr/local/bin/multilog t /var/log/qmail |- 550 qmail-lspawn ./Maildir/ |- 551 qmail-rspawn |- 552 qmail-clean `-26226 /usr/local/bin/qpsmtpd [91.200.12.166 : [91.200.12.166] : ... That's how you add a new service. Now, let's suppose you want to MODIFY an existing service, one that is provided by Debian. The Debian service definitions will be in /lib/systemd/system/ (probably), but you should NOT edit those files directly. Your edits would be lost when a new version of the package is installed. What you do instead is, again, create a file in /etc/systemd/system. But don't just copy the entire file over from /lib. Rather, put a few lines in it, indicating the specific things you want to override. You're creating a little miniature "Windows INI" format file, with a section header, and configuration line(s) underneath that. Or, the fancy way to do it is to create a new DIRECTORY in /etc/systemd/system with one or more files inside it, each of which is one of these little miniature INI files to override one specific thing. For example, if you want to change the behavior of the Debian default getty@ service to make it stop clearing the screen all the damned time, you can do this: # mkdir /etc/systemd/system/getty@.service.d # vi /etc/systemd/system/getty@.service.d/noclear.conf And in that file, you put these two lines: [Service] TTYVTDisallocate=no This overrides the "TTYVTDisallocate=yes" that Debian placed in its /lib/systemd/system/getty@.service file, which is what causes the console to be cleared every time getty restarts.