Something on your system talks over D-Bus and you have no idea what it is saying. busctl lets you look without touching. You will list services, walk their object trees, read properties, and learn which commands change system state. The examples use busctl from systemd 255, installed here as package version 255.4-1ubuntu8.17.
Allow about fifteen minutes. You need a shell on a Linux system with a reachable D-Bus system bus. The discovery and read examples are ordinary commands and normally need no elevated privileges.
Tip: some services restrict what an unprivileged caller can see or do. A permission error is meaningful evidence, not a reason to reach for sudo straight away.
Confirm the binary and version first. This is read-only:
$ command -v busctl
/usr/bin/busctl
$ busctl --version
systemd 255 (255.4-1ubuntu8.17)
The manpage describes busctl as a tool for introspecting and monitoring D-Bus. Its default connection is the system bus. Add --user when you specifically need the calling user's bus.
Tip: do not switch buses just because a name is absent. First establish which bus owns the service you are investigating.
Checkpoint: the version output should identify systemd 255 or another version you have recorded. Option details can differ between systemd releases, so keep this check with your troubleshooting notes.
Use list to see peers by service name. --no-pager makes output predictable in a terminal transcript, while --no-legend removes headings and the footer:
$ busctl --no-pager --no-legend list | head -5
:1.0 867 systemd-network systemd-network :1.0 systemd-networkd.service - -
:1.1 920 systemd-timesyn systemd-timesync :1.1 systemd-timesyncd.service - -
:1.13 936 networkd-dispat root :1.13 networkd-dispatcher.service - -
:1.15 942 snapd root :1.15 snapd.service - -
:1.18 1176 unattended-upgr root :1.18 unattended-upgrades.service - -
Two kinds of name show up:
org.freedesktop.systemd1.Use --unique or --acquired to narrow the list. --activatable instead shows names that are not running but can be started automatically when accessed.
Output is host-specific. A missing service may be stopped, unavailable on this bus, or under a different well-known name. Check the list before copying a name into later commands.
Ask for process and credential information with status:
$ busctl --no-pager status org.freedesktop.systemd1 | head -12
PID=1
PPID=n/a
TTY=n/a
UID=0
EUID=0
SUID=0
FSUID=0
GID=0
EGID=0
SGID=0
FSGID=0
SupplementaryGIDs=
Without a service argument, status describes the bus owner. A numeric argument is treated as a process ID. Treat this as a snapshot: credentials augmented from /proc can be newer than the rest of the reply.
Next, map the service's object paths:
$ busctl --no-pager tree org.freedesktop.systemd1 | head -12
└─ /org
└─ /org/freedesktop
├─ /org/freedesktop/LogControl1
└─ /org/freedesktop/systemd1
├─ /org/freedesktop/systemd1/job
└─ /org/freedesktop/systemd1/unit
├─ /org/freedesktop/systemd1/unit/ModemManager_2eservice
├─ /org/freedesktop/systemd1/unit/NetworkManager_2dwait_2donline_2eservice
├─ /org/freedesktop/systemd1/unit/NetworkManager_2eservice
├─ /org/freedesktop/systemd1/unit/_2d_2emount
├─ /org/freedesktop/systemd1/unit/_2d_2eslice
Use --list with tree for a flat list when the hierarchy is too large. Object paths are case-sensitive and are not file-system paths, even though they look like them.
Introspection shows the methods, properties and signals an object exposes. Limit it to one interface when you already know which matters:
$ busctl --no-pager introspect org.freedesktop.systemd1 \
/org/freedesktop/systemd1 org.freedesktop.systemd1.Manager | head -8
NAME TYPE SIGNATURE RESULT/VALUE
.AbandonScope method s -
.AddDependencyUnitFiles method asssbb a(sss)
.AttachProcessesToUnit method ssau -
.BindMountUnit method sssbb -
.CancelJob method u -
.CleanUnit method sas -
.ClearJobs method - s
For a property, give the service, object path, interface and property name. The terse form includes the D-Bus signature:
$ busctl --no-pager get-property \
org.freedesktop.systemd1 /org/freedesktop/systemd1 \
org.freedesktop.systemd1.Manager LogLevel
s "info"
Use --verbose when nested values need readable structure. Use --json=pretty when another tool or a human benefits from explicit JSON type information:
$ busctl --no-pager --json=pretty get-property \
org.freedesktop.systemd1 /org/freedesktop/systemd1 \
org.freedesktop.systemd1.Manager LogLevel
{
"type" : "s",
"data" : "info"
}
Tip: do not parse the terse output as plain text without accounting for its type marker. as means an array of strings, while s means one string.
call invokes a method. Its shape is service object interface method signature arguments. The signature describes the arguments, and each argument follows as a separately formatted string. For example, the systemd manager's StartUnit method takes two strings:
$ busctl call org.freedesktop.systemd1 /org/freedesktop/systemd1 \
org.freedesktop.systemd1.Manager StartUnit ss \
"example.service" "replace"
o "/org/freedesktop/systemd1/job/42684"
The job number is variable.
Warning: this example is not a harmless inspection: it asks systemd to start a unit. Before running an unfamiliar call, inspect the method signature and service documentation, confirm the exact arguments, and decide whether starting, stopping, reloading or changing a unit is acceptable. A method can trigger service activity even when the bus command looks like a query.
Recovery: for a real change, use a maintenance window and record a way back. Undoing a systemd start may need a separate systemctl stop decision, and a service may have dependencies or automatic restart behaviour.
Three details on call worth knowing:
--expect-reply=no for a change you need to verify. It sends the call without waiting for success or failure.--timeout= when the documented operation needs a different limit.--quiet hides a successful reply payload. It still prints errors and preserves the method's success or failure in the exit status, which suits scripts once the method and arguments have been tested interactively.monitor prints messages exchanged on the bus. With a service name it filters to messages to or from that peer; without one it can be very noisy. Stop it with Ctrl+C:
$ busctl --no-pager monitor org.freedesktop.systemd1
^C
Security warning: bus traffic can contain credentials, paths, arguments and application data. Treat terminal logs and shared captures as sensitive.
capture writes pcapng to standard output, so redirect it deliberately and set an appropriate --size= snap length. Do not leave a broad monitor or capture running in a busy production environment.
list.status, tree, introspect and get-property for investigation.call, set-property, emit, monitoring and capture as actions needing deliberate scope.