How to configure D-Bus and SSH X-Forwarding to prevent SSH from hanging on exit?

Solution 1:

Per dbus-launch(1):

If DBUS_SESSION_BUS_ADDRESS is not set for a process that tries to use D-Bus, by default the process will attempt to invoke dbus-launch with the --autolaunch option to start up a new session bus or find the existing bus address on the X display or in a file in ~/.dbus/session-bus/

Whenever an autolaunch occurs, the application that had to start a new bus will be in its own little world; it can effectively end up starting a whole new session if it tries to use a lot of bus services. This can be suboptimal or even totally broken, depending on the app and what it tries to do.

There are two common reasons for autolaunch. One is ssh to a remote machine.

So it seems the trick is to start dbus-daemon preemptively, in such a way that programs can find it. I use:

[[email protected] ~]$ dbus-launch --exit-with-session gnome-terminal

which, aside from gnome-terminal, starts dbus-daemon and sets $DBUS_SESSION_BUS_ADDRESS within gnome-terminal.

Any X programs run from gnome-terminal then behave nicely, and dbus-launch cleans up after itself when gnome-terminal exits.

Solution 2:

I wonder if the problem doesn't come because of an unknown or inexiting dbus session.

Indeed when an SSH session is open, it doesn't launch a dbus session. Some programs may launch it, but then the session doesn't know about it (hence can't close it).

Not knowing about the dbus session also means that programs thzat use dbus but don't launch it themselves will have problems.

dbus sections are per machine and per X11 display. Their info is stored in $HOME/.dbus/session-bus/- however, the process referenced there may be closed, so an extra check is needed to determine if launching dbus is needed or not. Then, the variables there are to ber exported to the session.

Then it works like a charm :)

I put the following in my .bash_profile file:

# set dbus for remote SSH connections
if [ -n "$SSH_CLIENT" -a -n "$DISPLAY" ]; then
    machine_id=$(LANGUAGE=C hostnamectl|grep 'Machine ID:'| sed 's/^.*: //')
    x_display=$(echo $DISPLAY|sed 's/^.*:\([0-9]\+\)\(\.[0-9]\+\)*$/\1/')
    if [ -r "$dbus_session_file" ]; then
            export $(grep '^DBUS.*=' "$dbus_session_file")
            # check if PID still running, if not launch dbus
            ps $DBUS_SESSION_BUS_PID | tail -1 | grep dbus-daemon >& /dev/null
            [ "$?" != "0" ] && export $(dbus-launch) >& /dev/null
            export $(dbus-launch) >& /dev/null

notes: hostnamectl is part of systemd and allows to retrieve the machine-id the dbus-launch displays the variables we want; by using export $(dbus-launch) we retrieve the output of dbus-launch and export the variables

if you want it to be done on non-interactive sessio (eg when running a command from ssh) try putting it in .bashrc instead (but beware that bashrc is executed at EVEERY opened shell)

Solution 3:

I had the same problem when trying to run a remote X command, and make the session exit after the X tool had exited.

So I wanted to run

ssh -X [email protected] "firefox -no-remote"

But had to use:

ssh -X [email protected] 'export \`dbus-launch\`; dbus-launch firefox -no-remote; kill -TERM $DBUS_SESSION_BUS_PID'

After closing firefox this would also close the ssh session.


This seems to leave a load of dbus-daemon processes running on the server, so this is not optimal, adding --exit-with-session on both accounts doesn't help, because this reverts the original behaviour

update 2: this does work when I use single quotes, (as suggested by @lobo) and adding kill -TERM $DBUS_SESSION_BUS_PID to kill the leftover dbus-daemon processes, as proposed by Holgr Joukl from