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: .. code-block:: [Unit] Description="Our backend that provides data" [Service] Type=simple ExecStart=/usr/bin/launch-backend.sh [Install] WantedBy=multi-user.target user.app.serivce: .. code-block:: [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: .. code-block:: 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. .. code-block:: [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: .. code-block:: 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: .. code-block:: 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: .. code-block:: 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: .. code-block:: 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: .. code-block:: 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: .. code-block:: SUBSYSTEM=="i2c", KERNELS=="16-0044", TAG="systemd", ENV{SYSTEMD_ALIAS}="/dev/lightsensor" Save the file, and reload udev: .. code-block:: udevadm control --reload-rules && udevadm trigger Device will now be visible as a systemd.device: .. code-block:: 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: .. code-block:: 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: ------------------------------------------------------------------ 8.3.1 Launching services from udev (not recommended) ------------------------------------------------------------------ In some cases it might make sense to launch services directly from udev rules. In this case, just add the necessary service to the rule. .. code-block:: ENV{SYSTEMD_WANTS}+="lightsensor.service" This will run the specific service when the device is connected. The pitfall is, that if you have the service enabled elsewhere, it will be hard to know where it is launched from. Thus, the preferred way is to run all services from targets. ========================================================= 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.