From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from gate001.proxmox.com (gate001.proxmox.com [IPv6:2a0f:8001:1:32::40]) by lore.proxmox.com (Postfix) with ESMTPS id 138061FF0B7 for ; Tue, 25 Aug 2026 13:09:26 +0200 (CEST) Received: from gate001.proxmox.com (localhost.localdomain [127.0.0.1]) by gate001.proxmox.com (Proxmox) with ESMTP id B8D0621625; Tue, 25 Aug 2026 13:09:14 +0200 (CEST) From: Alexandre Derumier To: pve-devel@lists.proxmox.com subject: SPAM: [RFC qemu-server 02/13] add D-Bus display support Date: Tue, 25 Aug 2026 13:08:34 +0200 Message-ID: <20260825110849.2967694-3-alexandre.derumier@groupe-cyllene.com> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20260825110849.2967694-1-alexandre.derumier@groupe-cyllene.com> References: <20260825110849.2967694-1-alexandre.derumier@groupe-cyllene.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-SPAM-LEVEL: Spam detection results: 6 AWL 0.200 Adjusted score from AWL reputation of From: address DMARC_QUAR 0.1 DMARC quarantine policy HEADER_FROM_DIFFERENT_DOMAINS 0.25 From and EnvelopeFrom 2nd level mail domains are different KAM_DMARC_QUARANTINE 4 DKIM has Failed or SPF has failed on the message and the domain has a DMARC quarantine policy KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment (newer systems) KAM_LAZY_DOMAIN_SECURITY 1 Sending domain does not have any anti-forgery methods RDNS_NONE 1.274 Delivered to internal network by a host with no rDNS SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_NONE 0.001 SPF: sender does not publish an SPF Record Message-ID-Hash: WU3U2FK3C4RJVZ4VTUISCGCSF7YZQUBM X-Message-ID-Hash: WU3U2FK3C4RJVZ4VTUISCGCSF7YZQUBM X-MailFrom: root@formationkvm1.odiso.net X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header CC: Alexandre Derumier X-Mailman-Version: 3.3.10 Precedence: list List-Id: Proxmox VE development discussion List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: From: Alexandre Derumier Add a private D-Bus daemon per VM for QEMU's -display dbus. Signed-off-by: Alexandre Derumier --- 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"; + + + org.qemu + unix:path=$socket + $pidfile + EXTERNAL + + + + + + +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