In this article we will explore what systemd is, what problems it solves in the embedded systems field and how we can write a configuration file for our application.
We should start by saying that systemd is a service manager for Linux. By service, we mean any program running on the system. Systemd is compatible with SysV init scripts but offers advanced features such as:
the
starting of services in parallel
the
activation of services via socket or Dbus
the
managing of dependencies between different services
the
process isolation via cgroups
These features make it possible to simplify the configuration of services when booting an embedded system as well as allowing precise control over each individual service.
Consider for example a GUI application that during its operation needs to spawn other processes, such as a music player. In a normal system these processes have their own lifetime with respect to the program that spawned them. So, in order to ensure that the GUI application is fully stopped, it is necessary to kill all the processes that the GUI can spawn.
With systemd of this is necessary, since the processes spawned by the GUI are part of the same systemd service. Therefore, all that is required is to stop the GUI service, after which systemd will know which processes must be stopped.
Service configuration
Each service is described by a configuration file, which has a format very similar to INI files.
The simplest file consists of 3 sections: Unit, Service and Install.
[Unit]
It contains the basic information about the service. The most important fields of this section are:
Description:
a line describing the service.
Wants:
a list of services required for this service. If your program uses
socket or dbus activation, systemd automatically manages
dependencies and this field is not required.
After:
systemd
will wait for the services contained in this field to start before
starting this process. This field can also be omitted if activation
via socket or dbus is being used.
[Service]
This section specifies which file should be executed and how it will be executed. The most important fields are:
ExecStart:
the absolute
path
of the executable file.
Environment:
it is used to set the environment variables for the process. For
example:
Environment=EGLFS_HIDE_CURSOR=1
“POINTERCAL_FILE=/path/with spaces/pointercal”
Note that if
the variable contains spaces, the
name of the variable must also be placed in quotation mark.
Type:
it is used by systemd to understand which process is the “main
process”. It is useful when there are daemons that fork a few
times before starting; conversely, it is not particularly useful in
the case of a single application to be launched. Just set it to
simple.
Restart:
it configures how and when the service must be started. For embedded
systems that must always be on, the recommended value is always.
SuccessExitStatus:
a list of signals or numbers (other than 0) that indicate correct
termination of the program.
Multiple forks are widely used to create daemons from the shell. The documentation in this regard is very detailed.
[Install]
This section is useful for deciding when a service should be enabled or disabled. In systemd jargon, a service is enabled if it is started automatically at boot; this is usually the intended behaviour for embedded systems. In short:
[Install]
WantedBy=multi-user.target
Complete example
Here is a complete example of a configuration file for a GUI application to be started at boot.
[Unit]
Description=Description for myprogram
Wants=rpcbind.service
After=rpcbind.service
[Service]
Environment=“MY_ENV_VAR=/some/path/to/file with space.ini”
ExecStart=/usr/local/myprogram
Type=simple
[Install]
WantedBy=multi-user.target
This brings the article to a close. For further information I suggest you read the systemd documentation and the variables guide of the configuration files.