From: Alexandre Derumier <alexandre.derumier@groupe-cyllene.com>
To: pve-devel@lists.proxmox.com
Subject: [RFC qemu-server 02/13] add D-Bus display support
Date: Tue, 25 Aug 2026 13:34:27 +0200 [thread overview]
Message-ID: <20260825113442.947620-3-alexandre.derumier@groupe-cyllene.com> (raw)
In-Reply-To: <20260825113442.947620-1-alexandre.derumier@groupe-cyllene.com>
Add a private D-Bus daemon per VM for QEMU's -display dbus.
Signed-off-by: Alexandre Derumier <alexandre.derumier@groupe-cyllene.com>
---
src/PVE/QemuServer/DBusDisplay.pm | 100 ++++++++++++++++++++++++++++++
src/PVE/QemuServer/Helpers.pm | 6 ++
2 files changed, 106 insertions(+)
create mode 100644 src/PVE/QemuServer/DBusDisplay.pm
diff --git a/src/PVE/QemuServer/DBusDisplay.pm b/src/PVE/QemuServer/DBusDisplay.pm
new file mode 100644
index 0000000..b8684be
--- /dev/null
+++ b/src/PVE/QemuServer/DBusDisplay.pm
@@ -0,0 +1,100 @@
+package PVE::QemuServer::DBusDisplay;
+
+# A private D-Bus bus per VM for QEMU's -display dbus. QEMU connects to the
+# address rather than creating it, and every QEMU wants to own org.qemu, so the
+# session bus would cap a node at one VM. libvirt does the same.
+
+use strict;
+use warnings;
+
+use Time::HiRes qw(usleep);
+
+use PVE::ProcFSTools;
+use PVE::Tools qw(file_set_contents);
+use PVE::QemuServer::Helpers;
+
+sub config_file {
+ my ($vmid) = @_;
+ return "$PVE::QemuServer::Helpers::var_run_tmpdir/$vmid.dbusdisplay.conf";
+}
+
+sub pidfile {
+ my ($vmid) = @_;
+ return "$PVE::QemuServer::Helpers::var_run_tmpdir/$vmid.dbusdisplay.pid";
+}
+
+sub write_config {
+ my ($vmid) = @_;
+
+ my $socket = PVE::QemuServer::Helpers::dbus_socket($vmid);
+ my $pidfile = pidfile($vmid);
+
+ my $conf = <<"EOF";
+<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-Bus Bus Configuration 1.0//EN"
+ "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
+<busconfig>
+ <type>org.qemu</type>
+ <listen>unix:path=$socket</listen>
+ <pidfile>$pidfile</pidfile>
+ <auth>EXTERNAL</auth>
+ <policy context="default">
+ <allow send_destination="*" eavesdrop="true"/>
+ <allow eavesdrop="true"/>
+ <allow own="*"/>
+ </policy>
+</busconfig>
+EOF
+
+ my $path = config_file($vmid);
+ file_set_contents($path, $conf, 0600);
+
+ return $path;
+}
+
+# Called inside the VM's systemd scope, so it dies with the VM, as swtpm does.
+sub start {
+ my ($vmid) = @_;
+
+ stop($vmid); # a survivor from an unclean stop still holds the socket
+
+ my $config = write_config($vmid);
+ unlink PVE::QemuServer::Helpers::dbus_socket($vmid);
+
+ PVE::Tools::run_command(
+ ['dbus-daemon', "--config-file=$config", '--fork'],
+ errmsg => "failed to start D-Bus daemon for VM $vmid",
+ );
+
+ return;
+}
+
+sub stop {
+ my ($vmid) = @_;
+
+ my $pidfile = pidfile($vmid);
+ if (my $pid = eval { PVE::Tools::file_read_firstline($pidfile) }) {
+ if ($pid =~ m/^(\d+)$/) {
+ $pid = $1;
+ kill('TERM', $pid);
+
+ # Waited for: a dying daemon unlinks the new socket and holds the VM's scope
+ # cgroup open, which blocks the next start.
+ for (my $waited = 0; $waited < 5; $waited += 0.05) {
+ last if !PVE::ProcFSTools::check_process_running($pid);
+ usleep(50_000);
+ }
+ if (PVE::ProcFSTools::check_process_running($pid)) {
+ warn "D-Bus daemon for VM $vmid did not exit, killing it\n";
+ kill('KILL', $pid);
+ }
+ }
+ }
+
+ unlink $pidfile;
+ unlink config_file($vmid);
+ unlink PVE::QemuServer::Helpers::dbus_socket($vmid);
+
+ return;
+}
+
+1;
diff --git a/src/PVE/QemuServer/Helpers.pm b/src/PVE/QemuServer/Helpers.pm
index dd17eef..816f7aa 100644
--- a/src/PVE/QemuServer/Helpers.pm
+++ b/src/PVE/QemuServer/Helpers.pm
@@ -140,6 +140,12 @@ sub vnc_socket {
return "${var_run_tmpdir}/$vmid.vnc";
}
+sub dbus_socket {
+ my ($vmid) = @_;
+ # dbusdisplay, not dbus: keep it apart from the dbus-vmstate helper's files.
+ return "${var_run_tmpdir}/$vmid.dbusdisplay";
+}
+
# Parse the cmdline of a running kvm/qemu-* process and return arguments as hash
sub parse_cmdline {
my ($pid) = @_;
--
2.55.0
next prev parent reply other threads:[~2026-08-25 11:35 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-25 11:34 [RFC pve-http-server/qemu-server/pve-manager/pve-{qemu-kyber,kyberproxy, kyber-web,qemu-rdp,rdpproxy,rdp-web} 00/13] add rdp && kyber consoles for qemu over D-Bus display Alexandre Derumier
2026-08-25 11:34 ` [RFC pve-http-server 01/13] anyevent : proxy a path prefix to a local http proxy Alexandre Derumier
2026-08-25 11:34 ` Alexandre Derumier [this message]
2026-08-25 11:34 ` [RFC qemu-server 03/13] add kyber display Alexandre Derumier
2026-08-25 11:34 ` [RFC qemu-server 04/13] add rdp display Alexandre Derumier
2026-08-25 11:34 ` [RFC qemu-server 05/13] add experimental kyber-gl display Alexandre Derumier
2026-08-25 11:34 ` [RFC pve-manager 06/13] ui: add kyber console Alexandre Derumier
2026-08-25 11:34 ` [RFC pve-manager 07/13] ui: add rdp console Alexandre Derumier
2026-08-25 11:34 ` [RFC pve-kyber-web 10/13] add pve-kyber-web: console's webassembly client Alexandre Derumier
2026-08-25 11:34 ` [RFC pve-qemu-rdp 11/13] Add pve-qemu-rdp: an RDP server for the console Alexandre Derumier
2026-08-25 11:34 ` [RFC pve-rdpproxy 12/13] Add pve-rdpproxy Alexandre Derumier
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260825113442.947620-3-alexandre.derumier@groupe-cyllene.com \
--to=alexandre.derumier@groupe-cyllene.com \
--cc=pve-devel@lists.proxmox.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox