8. Working with Systemd

The basics of creating, configuring, and starting systemd services are explained in the software guide. This section provides a more detailed look in to how systemd can be configured in special cases i.e when applications and services need to be tied to specific devices or other services.

8.1 Creating services with dependencies

Sometimes services can include dependencies to other services and a requirement might be that these services need to be executed in a specific order. Additionally, services may require a specific device to be operational before the service can be started.

8.1.1 Example: service that depends on other services

Assume you have a backend.service that provides connectivity and a userapp.service that provides the user interface. Thus, you want to make sure that the backend is running before the user application is started.

backend.service:

[Unit]
Description="Our backend that provides data"

[Service]
Type=simple
ExecStart=/usr/bin/launch-backend.sh

[Install]
WantedBy=multi-user.target

user.app.serivce:

[Unit]
Description="User interface to view data"
After=backend.service
Requires=backend.service

[Service]
Type=simple
ExecStart=/usr/bin/launch-gui.sh

[Install]
WantedBy=multi-user.target

Finally, enable the service with systemctl enable user.app.service. This will automatically load the backend also.

8.1.2 Example: service that depends on a specific device

Assume that your backed provides data from a can-bus, and thus requires the driver to be loaded before starting the service.

First find out the .device that you want to bind the service to:

root@v700:~# systemctl --type=device --all|grep can0
sys-subsystem-net-devices-can0.device
loaded active plugged /sys/subsystem/net/devices/can0
root@v700:~#

Then, add the binding to the service that requires the specific interface.

[Unit]
Description="Our backed that provides data from CAN0"
BindsTo=sys-subsystem-net-devices-can0.device
After=sys-subsystem-net-devices-can0.device

[Service]
Type=simple
ExecStart=/usr/bin/launch-backend.sh

Now, your service will be bound to wait after the specific device driver has been loaded.

If you cannot find the device, you will need to add a specific udev-rule, creating a .device node with system. See 8.3

8.1.3 Service file locations

For systemd to find service files they must be located in predefined locations. These locations can be checked for each system with the following commands.

For user files:

root@v700:~# systemd-analyze --user unit-paths
…
/home/root/.config/systemd/user.control
/home/root/.config/systemd/user
/etc/systemd/user
…

For system related files:

root@v700:~# systemd-analyze --system unit-paths
…
/etc/systemd/system
/usr/local/lib/systemd/system
/lib/systemd/system
/usr/lib/systemd/system
…

8.2 Viewing dependencies with systemctl list-dependencies

Finding out dependencies might become cumbersome at times and systemd provides tools to help out in this task. It is possible to view dependencies for each service, but also in the reverse.

As an example the System Supervisor runs a specific service on the device on each boot. To see the dependencies for this, run:

root@v700:~# systemctl list-dependencies --all ss.service
ss.service
● ├─system.slice
● └─sysinit.target
●   ├─dev-hugepages.mount
●   ├─dev-mqueue.mount
●   ├─kmod-static-nodes.service
●   ├─ldconfig.service
●   ├─psplash-start.service
●   ├─rngd.service
●   ├─sys-fs-fuse-connections.mount
●   ├─sys-kernel-config.mount
●   ├─sys-kernel-debug.mount
●   ├─systemd-ask-password-console.path
●   ├─systemd-journal-catalog-update.service
●   ├─systemd-journal-flush.service
●   ├─systemd-journald.service
●   ├─systemd-machine-id-commit.service
●   ├─systemd-modules-load.service
●   ├─systemd-sysctl.service
●   ├─systemd-sysusers.service
●   ├─systemd-tmpfiles-setup-dev.service
●   ├─systemd-tmpfiles-setup.service
●   ├─systemd-udev-trigger.service
●   ├─systemd-udevd.service
●   ├─systemd-update-done.service
●   ├─systemd-update-utmp.service
●   ├─local-fs.target
●   │ ├─systemd-remount-fs.service
●   │ ├─tmp.mount
●   │ ├─var-volatile-cache.service
●   │ ├─var-volatile-lib.service
●   │ ├─var-volatile-spool.service
●   │ ├─var-volatile-srv.service
●   │ └─var-volatile.mount
●   └─swap.target

This will provide you with a dependency tree of the service.

To find out what services depend on a specific one, use the -reverse -flag:

root@v700:~# systemctl list-dependencies ss.service --all --reverse
ss.service
● ├─ccauxd.service
● │ └─multi-user.target
● │   └─graphical.target
● └─sys-module-ss.device

The reverse depends will help you to see, where a specific service is started if it is not listed in any of the targets (but is launched as a dependency from another .service).

8.3 Adding systemd .devices

By default, systemd maps most of the devices (all tagged with “systemd”). However if the device is not visible you may create a mapping to use. For this example, let’s use the light sensor that is located on the i2c-bus, but also as a symlink on /dev/lightsensor.

First use udevadm to check the details of the device:

root@v700:~# udevadm info /sys/devices/platform/bus@5a000000/5a810000.i2c/i2c-16/16-0044
P: /devices/platform/bus@5a000000/5a810000.i2c/i2c-16/16-0044
L: 0
E: DEVPATH=/devices/platform/bus@5a000000/5a810000.i2c/i2c-16/16-0044
E: DRIVER=isl29018
E: OF_NAME=isl29035
E: OF_FULLNAME=/bus@5a000000/i2c@5a810000/isl29035@44
E: OF_COMPATIBLE_0=isil,isl29035
E: OF_COMPATIBLE_N=1
E: MODALIAS=of:Nisl29035T(null)Cisil,isl29035
E: SUBSYSTEM=i2c
E: USEC_INITIALIZED=4914427

Then, create a rule in udev, to add the tag “systemd” to the device, and also map the /dev/lightsenor link to make it more useable.

Under /etc/udev/rules.d/lightsensor.rules, add:

SUBSYSTEM=="i2c", KERNELS=="16-0044", TAG="systemd",
ENV{SYSTEMD_ALIAS}="/dev/lightsensor"

Save the file, and reload udev:

udevadm control --reload-rules && udevadm trigger

Device will now be visible as a systemd.device:

root@v700:~# systemctl --type=device --all |grep -e 044 -e lightsensor
dev-lightsensor.device
loaded active plugged /dev/lightsensor
sys-devices-platform-bus\x405a000000-5a810000.i2c-i2c\x2d16-16\x2d0044.device
loaded active plugged /sys/devices/platform/bus@5a000000/5a810000.i2c/i2c-16/16-0044

Additionally, you will be able to see the added tags with udevadm:

root@v700:~# udevadm info /sys/devices/platform/bus@5a000000/5a810000.i2c/i2c-16/16-0044
P: /devices/platform/bus@5a000000/5a810000.i2c/i2c-16/16-0044
L: 0
E: DEVPATH=/devices/platform/bus@5a000000/5a810000.i2c/i2c-16/16-0044
E: DRIVER=isl29018
E: OF_NAME=isl29035
E: OF_FULLNAME=/bus@5a000000/i2c@5a810000/isl29035@44
E: OF_COMPATIBLE_0=isil,isl29035
E: OF_COMPATIBLE_N=1
E: MODALIAS=of:Nisl29035T(null)Cisil,isl29035
E: SUBSYSTEM=i2c
E: USEC_INITIALIZED=4914427
E: SYSTEMD_ALIAS=/dev/lightsensor
E: TAGS=:systemd:

Technical support

Additional sources of information are available on the CrossControl support site: https://crosscontrol.com/support/

You will need to register to the site in order to be able to access all information available.

Contact your reseller or supplier for help with possible problems with your device. To get the best help, you should have access to your device and be prepared with the following information before you contact support.
  • The part number and serial number of the device, which you can find on the brand label.

  • Date of purchase, which can be found on the invoice.

  • The conditions and circumstances under which the problem arises.

  • Status indicator patterns (i.e., LED blink pattern).

  • Prepare a system report on the device, using CCSettingsConsole (if possible).

  • Detailed description of all external equipment connected to the unit (when relevant to the problem).

Trademarks and terms of use

© 2022 CrossControl

All trademarks sighted in this document are the property of their respective owners.

CCpilot is a trademark which is the property of CrossControl.

The registered trademark Linux® is used pursuant to a sublicense from the Linux Foundation, the exclusive licensee of Linus Torvalds, owner of the mark on a world­wide basis.

CC Linux is an official Linux distribution pursuant to the terms of the Linux Sublicense Agreement

Microsoft® and Windows® are registered trademarks which belong to Microsoft Corporation in the USA and/or other countries.

Arm® is a registered trademark of Arm Limited (or its subsidiaries) in the US and/or elsewhere.

Qt is a registered trademark of The Qt Company Ltd. and its subsidiaries.

CrossControl is not responsible for editing errors, technical errors or for material which has been omitted in this document. CrossControl is not responsible for unintentional damage or for damage which occurs as a result of supplying, handling or using of this material including the devices and software referred to herein. The information in this handbook is supplied without any guarantees and can change without prior notification.

For CrossControl licensed software, CrossControl grants you a license, to under CrossControl’s intellectual property rights, to use, reproduce, distribute, market, and sell the software, only as a part of or integrated within, the devices for which this documentation concerns. Any other usage, such as, but not limited to, reproduction, distribution, marketing, sales and reverse engineering of this documentation, licensed software source code or any other affiliated material may not be performed without the written consent of CrossControl.

CrossControl respects the intellectual property of others, and we ask our users to do the same. Where software based on CrossControl software or products is distributed, the software may only be distributed in accordance with the terms and conditions provided by the reproduced licensors.

For end-user license agreements (EULAs), copyright notices, conditions, and disclaimers, regarding certain third-party components used in the device, refer to the copyright notices documentation.