Create a systemd service#
The SimpleCore™ distribution use systemd as init and service manager. There is the official documentation of systemd project here.
systemd units are the way to described a part of the system which is managed by systemd. Hereafter in this article, it will be explained how to add a systemd service, the particular type of systemd unit to manage a process.
Directly on the target#
Out of a package system, a good place to create the systemd service in the
Linux file hierarchy is /etc/systemd/system
. The name of the systemd
service must be composed by:
a prefix, the name of the systemd service using ASCII letters, digits, “:”, “-”, “_”, “.”, and “".
the suffix “.service”.
In that file, there is generally the following two section:
the
Unit
section, which contains information not related to a particular type of systemd unit like a description, the dependencies of the unit…the
Service
section which describes the information about the process.
Here is a small example of a simple service, just printing Hello World. The
content of the service file /etc/systemd/system/hello_world.service
is
[Unit]
Description=Hello World
[Service]
ExecStart=/bin/echo "Hello World"
It is possible to start that service using the command
$ systemctl start hello_world
And to check the status of the process thanks to
$ systemctl status hello_world
It should display
* hello_world.service - Hello World
Loaded: loaded (/etc/systemd/system/hello_world.service; static)
Active: inactive (dead)
Jun 21 13:50:24 sm2s-imx8mini systemd[1]: Started Hello World.
Jun 21 13:50:24 sm2s-imx8mini echo[815]: Hello World
Jun 21 13:50:24 sm2s-imx8mini systemd[1]: hello_world.service: Deactivated successfully.
Moreover, if the systemd service must be executed automatically on boot,
an Install
section is added to describe when the service must be started.
The example becomes
[Unit]
Description=Hello World
[Service]
ExecStart=/bin/echo "Hello World"
[Install]
WantedBy=multi-user.target
Then it is possible to enable the service, to indicate that it should start on boot, thanks to the command
$ systemctl enable hello_world.service
The command should create a symbolic link in the drop-in directory of the indicated target. A target is a type of systemd unit to create synchronization point, grouping systemd units. Here you should see
$ systemctl enable hello_world.service
Created symlink /etc/systemd/system/multi-user.target.wants/hello_world.service -> /etc/systemd/system/hello_world.service.
If you reboot the board and display the status of the service, you should have
* hello_world.service - Hello World
Loaded: loaded (/etc/systemd/system/hello_world.service; enabled; vendor preset: disabled)
Active: inactive (dead) since Wed 2023-06-21 15:11:16 UTC; 16s ago
Process: 496 ExecStart=/bin/echo Hello World (code=exited, status=0/SUCCESS)
Main PID: 496 (code=exited, status=0/SUCCESS)
Jun 21 15:11:16 sm2s-imx8mini systemd[1]: Started Hello World.
Jun 21 15:11:16 sm2s-imx8mini echo[496]: Hello World
Jun 21 15:11:16 sm2s-imx8mini systemd[1]: hello_world.service: Deactivated successfully.
The default target can be known thanks to the command
$ systemctl get-default
Generally it would be:
multi-user.target
graphical.target
And one of this target should be a good target for a user application. If you need to start your application earlier, it is possible to display all the target thanks to
$ systemctl list-units *target
With a Yocto recipe#
If a recipe is already created to make a package of your application you must add in that recipe:
An
inherit systemd
to use the systemd class.Install the service file in the correct directory.
${D}${systemd_system_unitdir}
should be a good place (it will end up in/lib/systemd/system
on the target).Define the variable
SYSTEMD_PACKAGES
. By default it is set to${PN}
so if your systemd unit must go in that package, you haven’t to define that variable.Define the variable
SYSTEMD_SERVICE
. It is the name of the systemd service found in the package (so a package override must be used with this variable).Add the systemd service to the
FILES
that are placed in a package.
So if we want to create a recipe to add the previous hello-world.service
we could write
# SPDX-FileCopyrightText: (C) 2022 Avnet Embedded GmbH
# SPDX-License-Identifier: LicenseRef-Avnet-OSS-1.0
SUMMARY = "Hello World"
LICENSE = "Avnet-OSS-1.0"
LIC_FILES_CHKSUM = "file://${WORKDIR}/LICENSE;md5=4e8c3f6a224c21c1323ae04587ba060c"
SRC_URI = " \
file://LICENSE \
file://hello-world.service \
"
inherit allarch systemd
# No need to define SYSTEMD_PACKAGES as it is set by default to "${PN}"
SYSTEMD_SERVICE:${PN} = "hello-world.service"
do_configure[noexec] = "1"
do_compile[noexec] = "1"
do_install () {
install -d ${D}${systemd_system_unitdir}
install -m 0644 ${WORKDIR}/hello-world.service ${D}${systemd_system_unitdir}/hello-world.service
}
FILES:${PN} = "${systemd_system_unitdir}/hello-world.service"
By default the service will be automatically started on boot. It is possible to
disable it, setting in the recipe the variable SYSTEMD_AUTO_ENABLE
to disable
.