Thursday, 17 April 2008

simple qdbus tutorial (part two)

Following on from part one of my qdbus tutorial, we move on to look into what happens when we try to manipulate a D-Bus capable application that is already running in remote session. This is not as easy as one might imagine. It's certainly not difficult, but it did take me a little while and some help off the mailing lists to work out what I wanted to do.

For demonstration purposes, I shall be logged in remotely on my home machine via ssh. If I run qdbus as per the last tutorial it fails immediately.
cm@pablo:~> qdbus
Could not connect to D-Bus server: org.freedesktop.DBus.Error.Spawn.ExecFailed: dbus-launch failed to autolaunch D-Bus session: Autolaunch error: X11 initialization failed.
X11? WTF? This may initially seem that qdbus is dependent on an accessible X session. Indeed, if I were to log out, and login again using ssh -X this problem would go away. The big issue being that I would then be connecting to the bus on the local machine and not the remote one which I am trying to manipulate.

What's really happening here is that qdbus is looking for the all important shell variable DBUS_SESSION_BUS_ADDRESS which contains a unique address for each bus. Not finding this, it's running dbus-launch --autostart to try and determine the address by querying another X window. Of course it then fails if it is unable to connect to any X session.

The obvious way to get around this is to set this variable. But how do we determine the bus address that we need to connect to our running instance of a program? This is not difficult, but it's not the most obvious method. As far as I am aware, there is no other easy way to do this - perhaps in future versions this will become more trivial.

The first thing to do is determine the PID of the app that we are after (ktorrent as in the last example).
cm@pablo:~> ps -ef|grep -i ktorrent
cm 4685 1 1 08:50 ? 00:06:17 ktorrent
So, we can see that ktorrent has a PID of 4685. Now to determine the relevant bus address being used by this program (obviously replacing the example PID with the actual one).
cm@pablo:~> cat /proc/4685/environ
This will spew out a stack of environment variables, amongst them, with any luck, the one we are after: DBUS_SESSION_BUS_ADDRESS. What we want to do is export this shell variable, so it is available to our shell session and we in turn will be able to manipulate our app:
export DBUS_SESSION_BUS_ADDRESS="unix:abstract=/tmp/dbus-tIGLky9nbN,guid=49eaa775154aa8aa83ba330048070013"
The above will all be on one line of course (or properly escaped). Having done this, set your faces to stunned as now when you run qdbus, you are now seeing the apps on the correct bus:
cm@pablo:~> qdbus
:1.0
org.ktorrent.ktorrent
:1.2
org.kde.klauncher
:1.3
org.kde.kded
org.kde.kwalletd
:1.69
:1.70
org.freedesktop.DBus
And that's the end of my introduction to qdbus!

3 comments:

Nate said...

Thanks to a combination of your tips and some tips I read somewhere else, I can now do this quickly and easily. Just put the following command in a file that gets sourced on login, such as ~/.bashrc for example.

alias getdbus="export DBUS_SESSION_BUS_ADDRESS=`cat /proc/$(pidof kded4)/environ | tr '\0' '\n' | grep DBUS | cut -d '=' -f2-`"

Since I use kde, kded4 is a process that will always be running, but this may need to be changed. Then once you ssh into your remote computer, just type "getdbus" and voila!

cm said...

Excellent, Nate - thank you. I still wonder why it can't be a little more intuitive.

me said...

Nice work!

I ran into a problem ... 'pidof kded4' spits out to pids which breaks the script. i guess 1 id is plenty so a quick regex should do the trick but I wanted to know if there is some underlying importance which pid is used. do you have some information on that?