Basic Commands
# start / stop
systemctl start myservice
systemctl stop service
# reload after making changes to systemd unit files
# note: a reboot also does this
systemctl daemon-reload
# list dependencies of everything
systemctl list-dependencies
# list dependencies for a given unit file
systemctl list-dependencies myservice.service
# list reverse dependencies for a given unit file
systemctl list-dependencies myservice.service --reverse --all
Locations
Location of unit files
/etc/systemd/system/
Location of OS installed unit files (so users don't break the system)
/usr/lib/systemd/system/
Location of runtime systemd unit files
/run/systemd/system
Various types of unit files ".target", ".service", ".path", ".mount", etc
.target = is like a "runlevel" - it lets you tie many unit files under it so you can enable/disable entire groups of things at once
.service = is a running process.
.path = lets you watch for changes to a path using inotify, and then trigger another unit file
.mount = lets you mount filesystems using systemd. /etc/fstab is automatically turned into unit files
Sections of a unit file
[Unit] Metadata and trigger ordering dependencies
Description = description about the unit file
Before = ensures that units specified here are triggered before this unit
After = units listed here are triggered after this unit
Requires = list of units that must be running/completed before this one
Wants = similar to requires but ignores units that are not found or fail
[Install] Metadata and trigger ordering dependencies
WantedBy = reverse dependency for "wants". units listed here must wait for this unit to run/complete before they can run
RequriedBy = reverse dependency for "requires".
Activating the Install section
Items listed in the [Install] section do not take affect until you run "systemctl enable myservice.service". Or conversely "systemctl disable myservice.service". For example, say you have a unit file as such:
[Unit]
Description = myservice.service
[Install]
WantedBy = multi-user.target
RequiredBy = cloud-final.target
When you run "systemctl enable myservice.service", a symlink to this unit file will be created in /etc/systemd/system/multi-user.target.wants/ and in /etc/systemd/system/cloud-final.target/. This will make the dependency take effect.
Note: if the /etc/systemd/system/multi-user.target.wants/ dir does not exist, it will be created
Note: this also works for all types unit files (e.g, you can run 'systemctl enable myservice.path')
[Target | Service | Path | Mount | etc] Type specific unit file configuration
https://www.freedesktop.org/software/systemd/man/latest/systemd.service.html
# simple = "will consider the unit started immediately after the main service process has been forked off"
# oneshot = "is similar to simple; however, the service manager will consider the unit up after the main process exits."
Type = simple
RemainAfterExit = true
# command to run
ExecStart = /bin/bash -c 'echo hi'
ExecStartPost=...
Path
Waits for a path to create or update
https://www.freedesktop.org/software/systemd/man/latest/systemd.path.html
Conditionally starting a service
Two types:
- Conditions fail (quietly) if a unit is run and a condition is not met.
- Asserts fail and return an error
Run if file exists and not empty
[Unit]
ConditionPathExists = /opt/empty.txt
ConditionFileNotEmpty = /opt/empty.txt
Run if file exists and not empty
[Unit]
ConditionPathExists =! /opt/empty.txt
Run if either abc.txt or def.txt exists and user is root
[Unit]
ConditionPathExists=| /tmp/abc.txt
ConditionPathExists=| /tmp/def.txt
ConditionUser = root
List of conditions
https://www.freedesktop.org/software/systemd/man/latest/systemd.unit.html#Conditions%20and%20Asserts
Path unit: Running unit based on path
https://www.freedesktop.org/software/systemd/man/latest/systemd.path.html
Example unit file
[Unit]
Description="Trigger unit based on /tmp/test path"
[Path]
PathModified=/tmp/test
# other options PathExists=, PathExistsGlob=, PathChanged=, PathModified=, DirectoryNotEmpty=
Unit=unit-to-trigger.service
[Install]
WantedBy=multi-user.target