Tutorial busctl command, become a D-Bus guru

CaffeineAddict

Well-Known Member
Joined
Jan 21, 2024
Messages
3,968
Reaction score
4,156
Credits
32,446
Before we dive in, some terminology needs to precede...

What is D-Bus?
D-Bus is an Inter Process Communication (IPC) mechanism.
D-Bus (short for "Desktop Bus") allows communication between multiple processes running concurrently on the same machine.

In short it allows one process to communicate with another process.

What is busctl?
busctl is terminal command used to introspect and monitor the D-Bus bus.
You can use it to 'communicate' with a process within the limits of interface members that a process exposes on the D-Bus.

Process opening a connection and exposing interfaces on D-Bus is called D-Bus service and is the one "owning" the connection,
Process using interfaces of a service is called D-Bus client.

To list all processes providing services use the following command:
Bash:
busctl list

Here's sample (truncated) output:

busctl_list.png


In this tutorial we'll deal with org.bluez service, marked with red in the screenshot.

The output consists of 9 columns, column names are at the top of the tabular output, their meanings are as follows:
NAME
This is either well known service name or unique name.
A D-Bus service may export its well known name (e.g. org.bluez) which allows you use members of its interfaces without special permissions.
In case of unique name (e.g. :1.91) you'll need to configure permissions to be able to introspect and interact with the program exposing D-Bus interfaces (D-Bus service)

Unique name (e.g. :1.91) consists of the bus instance ID (1) and per‑connection sequence number (91)

PID
process ID of the process owning the D-Bus connection

PROCESS
process name of the process owning the D-Bus connection

USER
User owning the process, the process is running with this users' privileges

CONNECTION
This is the same as NAME column, except in case of well known service name it shows unique connection name which would be otherwise shown if there's no well known name.

UNIT
systemd unit the service runs under

SESSION
Session ID

DESCRIPTION
Session description

To list only D-Bus services with well known name and omit unique names use this instead:
Bash:
busctl --acquired

To show service status and details run busctl with status command and specify service name:
Bash:
busctl status org.bluez

Sample output:

status.png


We know service name which is org.bluez but we want to list "objects" that this service handles, to do so use tree command:
Bash:
busctl tree org.bluez

Sample output:

tree.png


Tree command lists objects recursively, the most nested nodes are objects of interest, in this example that's my bluetooth adapter, there are no other objects here.
Pay attention that service well-known name is dot separated, while object name is separated by / path separator.

Next thing we do is list interfaces and interface members (e.g. methods, properties, signals etc.)
To do this use introspect command and specify service name followed by object path:
Bash:
busctl introspect org.bluez /org/bluez/hci0/dev_40_45_DA_1C_59_58

Sample output:

interface.png


Let's first explain this output:
Under NAME column there are blue lines and white lines (preceded with a dot because methods are called on interface)
The blue lines are "interface" names, in this example the red marked is interface for device object (dev_40_45_DA_1C_59_58)
Each interface exposes "members" (methods, properties, signals etc.) (green marked is Connect method)

In programing terminology a "member" comes from being a member of a class.
Methods, signals, variables are kinds of members.
"Interface" is a class but one that doesn't implement anything, it only provides members that are implemented by classes in the object.

Methods are just like C functions, they have signature and can be called with or without parameters depending on method signature.
A method signature in programing terminology is function name, parameter names and their types as well as function return value and its type (and possibly calling convention but not applicable here).

Properties are in fact variables, you can set them or get them.
Properties likewise have signature, this is value type, e.g. string, int, bool etc.

Signals are messages that we (or a client process) can send to service.
In programing terminology a signal notifies listeners about events or state changes.

The TYPE column tells whether symbol under NAME is a method, property or signal or something else.

SIGNATURE column tells method or property signature.
These letters are data types and have the following meaning:

y: byte (uint8)
b: boolean
n: int16
q: uint16
i: int32
u: uint32
x: int64
t: uint64
d: double
s: string
o: object path
g: signature (type signature string)
h: file descriptor (unix fd)
v: variant
aT: array of type T
(T1T2...): struct/tuple (e.g. si = string + int32)
{KT}: dictionary entry used inside arrays for maps - maps are represented as a{KT}, e.g., a{sv} = dict string -> variant

The last 4 data types are container types (e.g. classes, user defined types).
- means a method does not take any arguments.

The RESULT/VALUE column in case of a method lists return value data type, - means the method doesn't return anything.
In case of properties it displays current value or - if no value is set.

FLAGS column describe member attributes or behaviors.
For instance a method may be const which means it doesn't change any internals, a property may as well be const meaning we can't change it.

Armed with this knowledge we can now call some methods and set values, for the purpose of this demonstration we'll connect to my phone.
Since it's already paired all I need is to call Connect method, for this we use the call command.
As a 3rd parameter for call and other interaction commands you need to specify interface in addition to interface member.

Bash:
busctl call org.bluez /org/bluez/hci0/dev_40_45_DA_1C_59_58 org.bluez.Device1 Connect

Since this function doesn't return anything there's no output however it did made my PC connected to phone:

connected.png


Note that Connect method according to SIGNATURE column does not take any parameters, if it did such as ConnectProfile for instance which takes s data type, a string, you'd call it with a string, that is, profile name which to connect, e.g.:
Bash:
busctl call org.bluez /org/bluez/hci0/dev_40_45_DA_1C_59_58 org.bluez.Device1 ConnectProfile s <profile_name>
Note that you need to precede each argument with data type as shown in SIGNATURE column.

To get property value we use get-property command:
Bash:
busctl get-property org.bluez /org/bluez/hci0/dev_40_45_DA_1C_59_58 org.bluez.Device1 Blocked

Sample output corresponds to signature and value columns:

getprop.png


To set property you'd use set-property command, however be careful what you set, I don't know what to set so I'll set Blocked to same value as it is for demo purposes.
When setting you need to specify both the signature and value.

Bash:
busctl set-property org.bluez /org/bluez/hci0/dev_40_45_DA_1C_59_58 org.bluez.Device1 Blocked b false

There's no output when setting properties.

To send a signal use emit command, however since no signals are listed under Device1 there's nothing to send.
For more info and other commands and command description run man busctl

If you want to hack services with unique name this SO thread will help you set permissions:

When to use busctl?
Normally you shouldn't need to use it because a program or service normally provides either GUI or CLI interface, but in some cases UI or CLI may not expose some functionalities in which case if for instance you're troubleshooting something you may find some secret functionality with busctl and use it to resolve a problem.

Ofc. you can use it only because you can, armed with this knowledge you surely can. :p
 
Last edited:


Follow Linux.org

Members online


Top