wiki/notebook/linux.systemd.org
Gabriel Arazas b088086b06 Merge evergreen notes into the notebook
Now, it's all under the notebook umbrella. Seems to be appropriate as it
is just my notes after all.

I also updated some notes from there. I didn't keep track of what it is
this time. Something about more learning notes extracted from my
"Learning how to learn" course notes and then some. Lack of time and
hurriness just makes it difficult to track but it should be under
version control already.
2021-07-21 16:28:07 +08:00

13 KiB

Exploring systemd features

systemd is a big tool for a big system. Let's explore some of them from a perspective of a wannabe power user.

systemd at user-level

systemd has the ability to run at user-level empowering the user to manage their own system with their own settings. It immensely helps separating user-specific settings from the system-wide settings.

systemd looks for the units from certain paths. You can look for them from the systemd.unit.5 manual page.

To run systemd as a user instance, simply add a --user flag beforehand for systemctl and other systemd binaries, if applicable.

# See how different the output when run at user- and system-level.
systemctl --user show-units
systemctl show-units

systemctl --user show-environment
systemctl show-environment

systemctl --user start $SERVICE

Timers as cron replacement

You can schedule tasks with timers. If systemd is compiled with the feature, it makes cron unnecessary.

systemd has different ways to denote time.

  • Timespans denote the duration — e.g., 100 seconds, 5M 3w.
  • Timestamps refer to a specific point in time — e.g., 2021-04-02, today, now.
  • Calendar events can refer to more than one point of time — e.g., *-*-4/2, Sun,Wed,Fri *-1/2-1/8.

Here's an example of setting a timer for an example backup service. The following timer unit sets it to execute every day at 18:00.

[Unit]
Description=A deduplicated backup from my computer
Documentation=man:borg(1) https://borgbackup.readthedocs.io/

[Timer]
Unit=borg-backup.service
OnCalendar=*-*-* 18:00:00
Persistent=true

[Install]
WantedBy=graphical.target

This will trigger borg-backup.service from the load path. But you can omit it if you named the timer unit file similarly (e.g., borg-backup.timer with borg-backup.service).

You can find more information about it from the systemd.time.5 manual page. Furthermore, systemd has a testing tool for time with systemd-analyze {timespan,timestamp,calendar}.

printf "Timespan example:\n"
printf "..............\n"
systemd-analyze timespan 4000min
printf "..............\n\n"

printf "Timestamp example:\n"
printf "..............\n"
systemd-analyze timestamp 2021-07-01
printf "..............\n\n"

printf "Calendar example:\n"
printf "..............\n"
systemd-analyze calendar "*-1/4-5 0/2:00:00"
printf "..............\n\n"
Timespan example:
..............
Original: 4000min
      μs: 240000000000
   Human: 2d 18h 40min
..............

Timestamp example:
..............
  Original form: 2021-07-01
Normalized form: Thu 2021-07-01 00:00:00 PST
       (in UTC): Wed 2021-06-30 16:00:00 UTC
   UNIX seconds: @1625068800
       From now: 2 weeks 4 days ago
..............

Calendar example:
..............
  Original form: *-1/4-5 0/2:00:00
Normalized form: *-01/4-05 00/2:00:00
    Next elapse: Sun 2021-09-05 00:00:00 PST
       (in UTC): Sat 2021-09-04 16:00:00 UTC
       From now: 1 month 16 days left
..............

Unit templates

You can create unit templates which is useful for simple services that only requires an argument. Rather than creating individual simple service files, let systemd handle it.

For example, you may want to spawn a service for Borgmatic with multiple repos. If you don't know templates, the dumb way to serve multiple repos is to create individual unit files for each. If you want to schedule them, you also have to create a timer unit for each.

The more efficient solution is to use templates. To make a unit template, there are only a handful of requirements:

  • Addition of %i to represent the template value.
  • The unit file name has to end with @ (e.g., unit-name@.service, unit-name@.timer).

This could be compressed into a template for a service unit. The following code shows how to create one.

[Unit]
Description=Periodic safety backup for %i
Documentation=man:borg(1) https://www.borgbackup.org/

[Service]
Type=simple
ExecStart=borgmatic --config %i --verbose

[Install]
WantedBy=default.target

To use the service, you have to give it a value — e.g., systemctl --user start borg-backup@test.yaml.service.

That's all good but what about scheduling them? What if you want to create an archive every hour starting at 08:00? You can just create a templated timer unit.

[Unit]
Description=Periodic safety backup for %i
Documentation=man:borg(1) https://www.borgbackup.org/

[Timer]
Unit=borg-backup@%i.service
Calendar=08/1:00:00
Persistent=true

[Install]
WantedBy=default.target

Transient units

You can create units on-the-go with systemd-run. It generates transient unit files. Though, this is oriented around service units, making it useful for one-time configurations and task scheduling.

Like most systemd-related binaries, this can configure in system- and user-level.

# This will create a user-level service file with the given command as the task.
systemd-run --user borgmatic --config emergency-config.yaml --verbose

# Create a transient timer for the service.
systemd-run --user borg-backup@external-drive.service --on-calendar=12:00

Service management

One of the functions of the system suite is service management. Like most of the components, it can be used at user-level with their set locations, managing the service daemon, and all.

Just plop down a service unit file at one of the search paths and you can start managing right away. For more information, see the manual page (i.e., systemd.service.5). A summarized version can be found at /foodogsquared/wiki/src/commit/b088086b0695da8b50287b30e0665eff38435008/notebook/Service%20configuration.

Here's an example of a user service resided as $HOME/.config/systemd/user/drive-backup.service.

[Unit]
Description=Periodic safety backup for my external drive
Documentation=man:borg(1) https://www.borgbackup.org/ https://torsion.org/borgmatic/

[Service]
Type=oneshot
ExecStart=%h/.nix-profile/bin/borgmatic --config %h/dotfiles/borgmatic/personal-drive.yaml --verbosity 2 create
ExecStart=%h/.nix-profile/bin/borgmatic --config %h/dotfiles/borgmatic/personal-drive.yaml --verbosity 2 prune
ExecStart=%h/.nix-profile/bin/borgmatic --config %h/dotfiles/borgmatic/personal-drive.yaml --verbosity 2 check

[Install]
WantedBy=default.target

You can then start the service with:

systemctl --user start drive-backup.service

You can also stop it with the stop subcommand (e.g., systemctl --user stop drive-backup.service) and restart it with restart (e.g., systemctl --user restart drive-backup.service).

If you want to enable it at startup, you can go with enable subcommand. (To disable it, use the disable subcommand.)

systemctl --user enable drive-backup.service

systemd will use the configuration file as-is by the time it is started/enabled. Which means if the config file has been modified after activation, it will not take effect until you restarted it. For this, you can reload the daemon with daemon-reload subcommand. But for simpler cases, you can use the reload subcommand without fully restarting the daemon.

systemctl --user reload drive-backup.service

# You could also use...
#   systemctl --user daemon-reload
# ...if you need a stronger option.

Service configuration

There are different types of services.

  • The most common type of service is simple which considers the unit active after the main process is forked (e.g., Service.ExecStart). This is the recommended type for long-running processes.
  • oneshot marks the service resolved after the main process exits. Due to the behavior, it will directly go from activating to deactivating instead of active.
  • exec considers the service active after the binary has been executed.

Aside from types, each service may have one or more commands although the behavior is set depending on the type.

  • ExecStart which is usually the main command and most services will throw an error if it's missing. All services, unless specified as a oneshot service, only have one of these values.
  • ExecStop only executes after the main command successfully starts.
  • ExecStartPre and ExecStartPost gives you additional commands that will be executed before and after the main command, respectively.
  • ExecStopPre and ExecStopPost is similar to the pre- and post-start commands except for the stop command.
  • Reload sets whether the service restarts on fail. Values accepted are no, on-failure, and on-success.

Bootloader configuration

systemd also comes with a bootloader aptly named systemd-boot though it only supports UEFI-based firmware. Just like GRUB, they can be configured through plain-text files.

For detailed information about the bootloader, see the manual page systemd-boot.7.

With a complete installation, the bootloader config folder may look like the following list.

/boot/
`-- loader
    |-- entries             # (ref:loader-entries)
    |   `-- arch.conf
    |-- loader.conf         # (ref:loader-conf)
    `-- random-seed
  • loader/entries/ is a directory containing all of the entries available to be booted.
  • loader.conf contains the loader configuration.

Most Linux distros with systemd installed should have a sample config file somewhere. 1 As an example, we'll show what those look like.

loader.conf is the configuration for the boot loader including the timeout seconds among others. Here is a sample of a bootloader configuration.

default arch
timeout 4

In this config, this simply makes the arch loader entry to be default when no actions has occurred. It will start loading it automatically after a timeout of 4 seconds.

The arch loader entry can be found at ${ESP}/loader/entries/arch.conf. The following code block shows what a loader entry looks like.

title   Arch Linux
linux   /vmlinuz-linux
initrd  /initramfs-linux.img
options root="PARTUUID=${PARTUUID}"

You can customize and create extra entries for the same installation. This is what roam:NixOS does with its package generations, letting the user to boot to a specific point in time from the boot loader. Very useful for emergency boots in case the current generation breaks for whatever reason.

For complete details of the configuration file, you can see loader.conf.5 manual page.

Network manager configuration

With a systemd-ful environment, you can run the network daemon (i.e., systemd-networkd). Once enabled, you can run networkctl to list all of the network devices. 2

networkctl
IDX LINK   TYPE     OPERATIONAL SETUP
  1 lo     loopback carrier     unmanaged
  2 enp1s0 ether    routable    configured
  3 wlan0  wlan     routable    configured

3 links listed.

To configure network manager, you can create a network file in one of systemd unit file paths in the system. Each of the device will be assigned an IP address. You can either assign an IP address or dynamically assign them in some way. One of the common ways to do dynamic IP addresses is installing a DHCP server (which is another thing to be configured). Here's an example of configuring any wireless devices and assigning a dynamic IP addresses with DHCP.

[Match]
Type=wlan

[Network]
DHCP=yes
IPv6PrivacyExtensions=yes

[DHCPv4]
RouteMetric=1024

[DHCPv6]
RouteMetric=1024

DNS server configuration

While the network manager is enabled, you can access the internet. But only with raw IP addresses (e.g., 1.1.1.1 from Cloudflare, 93.174.95.27 for Library Genesis). 3[dog]] or the DNS library from NodeJS.]

Accessing the domain names as you would browse the web normally is an additional layer of the web. To access a domain name, you need a DNS client that can resolve them. While there are plenty of DNS resolvers, systemd has a component systemd-resolved which you can control with resolvectl binary.

systemd-resolved takes a configuration from /etc/resolve.conf which most third-party programs also relies on.


1

In case of Arch Linux, it has an example file at /usr/share/systemd/bootctl/.

2

You can also run ip address for it.

3

You can find the IP addresses with DNS clients such as [[https://github.com/ogham/dog