Register dbus service
The promise of dbus is to eliminate the need of an init system by starting
the services on demand. In this guide we will walk through how to register
a simple service on the system bus and manage it via systemd.
Remarks:
- The guide assumes that
git
andgo
programs are already installed
on your machine. - The well-known name of the dbus client will be referred as
bus name
.
Start a dbus service
We will use an example code from godbus as a dbus service.
$ git clone https://github.com/godbus/dbus
We will use the latest release (v5.0.3
) to avoid inconsistency:
$ cd dbus
$ git checkout v5.0.3
go
programs can be executed with the go run
command:
$ go run _examples/server.go
Listening on com.github.guelfey.Demo / /com/github/guelfey/Demo …
Let see what /com/github/guelfey/Demo
object can do:
$ dbus-send --session --dest=com.github.guelfey.Demo \
--type=method_call --print-reply \
/com/github/guelfey/Demo\
org.freedesktop.DBus.Introspectable.Introspectstring "
<node>
<interface name="com.github.guelfey.Demo">
<method name="Foo">
<arg direction="out" type="s"/>
</method>
</interface>
<interface name="org.freedesktop.DBus.Introspectable">
<method name="Introspect">
<arg name="out" direction="out" type="s"/>
</method>
</interface>
</node> "
We have a Foo
method in the com.github.guelfey.Demo
interface. Let see what Foo
method does:
$ dbus-send --session --dest=com.github.guelfey.Demo \
--type=method_call --print-reply \
/com/github/guelfey/Demo com.github.guelfey.Demo.Foostring “Bar!”
Nice, but we used session
bus all along. How about the system
bus?
System bus
Change our example program to connect to the `system` bus:
diff --git a/_examples/server.go b/_examples/server.go
index 0f4ee32..76d5151 100644
--- a/_examples/server.go
+++ b/_examples/server.go
@@ -24,7 +24,7 @@ func (f foo) Foo() (string, *dbus.Error) {
}func main() {
- conn, err := dbus.SessionBus()
+ conn, err := dbus.SystemBus()
if err != nil {
panic(err)
}
Start our service again:
$ dbus-send --system --dest=org.freedesktop.DBus \
--type=method_call --print-reply \
/org/freedektop/DBus \
org.freedesktop.DBus.GetConnectionUnixProcessID \
string:'com.github.guelfey.Demo'Error org.freedesktop.DBus.Error.NameHasNoOwner: Could not get PID of name 'com.github.guelfey.Demo': no such name
System bus policy
Arbitrary dbus client cannot acquire names on system
bus. We have to create a policy file to register the name of our server. Lucky for us the Integrating system services
section of the dbus-daemon documentation defines a minimal policy file:
<!-- /usr/share/dbus-1/system.d/com.github.guelfey.Demo.conf -->
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE busconfig PUBLIC
"-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
<busconfig>
<policy user="${USER}">
<allow own="com.github.guelfey.Demo"/>
</policy><policy context="default">
<allow send_destination="com.github.guelfey.Demo"/>
</policy>
</busconfig>
The policy should be saved as/usr/share/dbus-1/system.d/com.github.guelfey.Demo.conf
so thecom.github.guelfey.Demo
name will be available for ${USER}
. The ${USER}
has to be replaced with a local username which can be yours too. More details about the bus policy can be read in the dbus-daemon and polkit documentations.
Remark: The /usr/share/dbus-1/system.d
directory does not refer to systemd, this directory only contains the policies of the system
bus configuration (/usr/share/dbus-1/system.conf
).
We can start our example server again:
$ go run _examples/server.go
Listening on com.github.guelfey.Demo / /com/github/guelfey/Demo …
The Foo
method is available on the system
bus:
$ dbus-send --system --dest=com.github.guelfey.Demo \
--type=method_call --print-reply \
/com/github/guelfey/Demo com.github.guelfey.Demo.Foostring "Bar!"
Dbus service
Until now we could not refer our example server as dbus service because we started it by hand. However it is quite straightforward to register our server into dbus.
At first we compile our example server so it can be referred more easily:
$ go build -o /tmp/dbus-demo-server _example/server.go
Register service
The dbus-daemon
scan the /usr/share/dbus-1/system-services
for system
services. We should create a simple service file there. The service file has to be named after bus name of the service.
# /usr/share/dbus-1/system-service/com.github.guelfey.Demo.service[D-BUS Service]
Name=com.github.guelfey.Demo
User=${USER}
Exec=/tmp/dbus-demo-server
Remark: ${USER}
should be replaced with username which is used in the policy file.
List activate able services
We can check our service configuration by the ListActivatableNames
method:
$ dbus-send --system --dest=org.freedesktop.DBus \
--type=method_call --print-reply \
/org/freedektop/DBus org.freedesktop.DBus.ListActivatableNamesarray [
string "org.freedesktop.DBus"
string "org.freedesktop.login1"
...
string "com.github.guelfey.Demo"
]
It seems alright, let call our famous Foo
method:
$ dbus-send --system --dest=com.github.guelfey.Demo \
--type=method_call --print-reply \
/com/github/guelfey/Demo com.github.guelfey.Demo.Foostring "Bar!"
Manage dbus services
It is quite easy, but how can I stop or restart our service?
Dbus services are regular processes so we only have to know their PIDs, which can be queried with the GetConnectionUnixProcessID
method:
$ dbus-send --system --dest=org.freedesktop.DBus \
--type=method_call --print-reply \
/org/freedektop/DBus org.freedesktop.DBus.GetConnectionUnixProcessID \
string:'com.github.guelfey.Demo'uint32 7909
We can stop our example service with a SIGINT
signal:
$ kill -SIGINT 7909
We can ensure that our example service is stopped:
$ dbus-send --system --dest=org.freedesktop.DBus \
--type=method_call --print-reply \
/org/freedektop/DBus \
org.freedesktop.DBus.GetConnectionUnixProcessID \
string:'com.github.guelfey.Demo'Error org.freedesktop.DBus.Error.NameHasNoOwner: Could not get PID of name 'com.github.guelfey.Demo': no such name
Systemd service
The GetConnectionUnixProcessID
exposes the process of the dbus service but it is not an administrator friendly way to manage services. Lucky for us dbus services can be managed with systemd so we don’t have to query their PIDs.
Register service
Only a SystemdService
option has to be set in the dbus service file to askdbus-daemon
to start our service with systemd:
# /usr/share/dbus-1/system-service/com.github.guelfey.Demo.service[D-BUS Service]
Name=com.github.guelfey.Demo
Exec=/bin/false
SystemdService=dbus-demo
As you can see from the dbus service file above the User
option is left to
systemd and the `Exec` option is overwritten with /bin/false
so the Exec
would fail if there is no SystemdService
.
The systemd service file of the referred dbus-demo
service should look like this:
# /usr/lib/systemd/system/dbus-demo.service[Unit]
Description=Simple dbus server example
[Service]
Type=dbus
BusName=com.github.guelfey.Demo
ExecStart=/tmp/dbus-demo-server
User=${USER}
This systemd service above will start /tmp/dbus-demo-server
at the first dbus message as ${USER}
(you have to replace it with a real username). Systemd use the BusName
option in the status check of our example server. Systemd consider the service active if the started process acquires thecom.github.guelfey.Demo
BusName
.
Finally a daemon-reload
command has to be called to register our systemd service:
$ sudo systemctl daemon-reload
At this stage our systemd service is inactive:
$ systemctl status dbus-demo
● dbus-demo.service - Simple dbus server example
Loaded: loaded (/usr/lib/systemd/system/dbus-demo.service; disabled; vendor preset: disabled)
Active: inactive (dead)
It will be activated by the first dbus message:
$ dbus-send --system --dest=com.github.guelfey.Demo \
--type=method_call --print-reply \
/com/github/guelfey/Demo com.github.guelfey.Demo.Foostring "Bar!"$ systemctl status dbus-demo
● dbus-demo.service - Simple dbus server example
Loaded: loaded (/usr/lib/systemd/system/dbus-demo.service; disabled; vendor preset: disabled)
Active: active (running) since Sun 2021-01-10 16:44:42 CET; 12s ago
Main PID: 8500 (dbus-demo-serve)
Tasks: 6 (limit: 38345)
Memory: 1.2M
CGroup: /system.slice/dbus-demo.service
└─8500 /usr/bin/dbus-demo-server
We can check that systemd
and dbus-daemon
use the same process (PID=8500):
$ dbus-send --system --dest=org.freedesktop.DBus \
--type=method_call --print-reply \
/org/freedektop/DBus \
org.freedesktop.DBus.GetConnectionUnixProcessID \
string:'com.github.guelfey.Demo'uint32 8500
Epilogue
You have to remember that neither dbus-daemon
or systemd
acquire bus name for your server. The bus name has to be acquired by your server.
We did not use any policy for our example server, but authorization is key
point of dbus services. You should use polkit or a proper bus policy for your
dbus services.
Originally published at https://nyiro.name.