6

What is needed to give cron commands access to the session bus (if it is running)?

It used to work for me, on Debian Stretch (testing) since switching systemd until relatively recently (might have been month or two ago). The strange thing is that while I strongly suspect this is controlled by the PAM configuration, the only change that happened to /etc/pam.d recently enough was adding some calls to pam_selinux to pam.d/systemd-user.

So what should I look for?

Jan Hudec
  • 641

1 Answers1

12

This is likely due to the fact that the DBUS_SESSION_BUS_ADDRESS environment variable isn't propagated to the cron environment.

At least under Gnome, the bus isn't made "discoverable" (as documented in the "AUTOMATIC LAUNCHING" section of the dbus-launch(1) man page) via files in $HOME/.dbus/session-bus. This leaves anything run in your crontab without a way to discover $DBUS_SESSION_BUS_ADDRESS and contact the session D-Bus.

I'll take your word for it that it worked in the past, possibly due to use of $HOME/.dbus or the existence of actual /tmp/dbus-$TMPNAM files referenced in $DBUS_SESSION_BUS_ADDRESS (which is normally set to something resembling unix:abstract=/tmp/dbus-GkJdpPD4sk,guid=0001e69e075e5e2). As the dbus-cleanup-sockets(1) man page explains:

On Linux, this program is essentially useless, because D-Bus defaults to using "abstract sockets" that exist only in memory and don't have a corresponding file in /tmp.

However, we can use a variation on the idea presented in an ubuntuforum post, Attach to existing DBUS session over SSH, to discover the session D-Bus of an existing user session on the local machine from within the cron environment and set $DBUS_SESSION_BUS_ADDRESS accordingly.

While the technique used there discovers the environment from commonly-running processes like nautilus, pulseaudio, and trackerd, and requires that one or more of them be running in the active session, I recommend a more basic approach.

All of the common desktop environment session managers (gnome-session, lxsession, and kded4) have $DBUS_SESSION_BUS_ADDRESS set in their environment, even though they're started before dbus-daemon and have lower PIDs. So, it makes the most sense to just use whatever session manager corresponds to your desktop environment.

I wrote the following script, placed in $HOME/bin/test-crontab-dbus.sh, to test access to the existing session bus:

#!/bin/sh
SESSION_MANAGER=lxsession
OUTFILE=/tmp/${USER}-cron-dbus.txt

export $(cat /proc/$(pgrep "$SESSION_MANAGER" -u "$USER")/environ \
  |egrep -z '^DBUS_SESSION_BUS_ADDRESS=')

date >> $OUTFILE
dbus-send --session --dest=org.freedesktop.DBus \
   / org.freedesktop.DBus.GetId 2>> $OUTFILE
if test "$?" -eq 0; then
    echo "Success contacting session bus!" >> $OUTFILE
fi

The SESSION_MANAGER=lxsession above is appropriate for a main desktop session running under LXDE, under Gnome you'd set SESSION_MANAGER=gnome-session, and under KDE you'd use SESSION_MANAGER=kded4.

If the job in the crontab has access to the session bus, you'll see something like the following in the output:

Fri Dec 18 15:27:02 EST 2015
Success contacting session bus!

Otherwise, you'll see the error message output by dbus-send.

Obviously, you can substitute any other method of testing connectivity to the session bus, including whatever operation you actually need to perform via a cron job.

FeRD
  • 921
  • 1
    You can leverage dbus itself to ping to see if the bus is alive, e.g. if $candidate is a value you think is a valid bus address, dbus-send --bus="$candidate" --dest=org.freedesktop.DBus / org.freedesktop.DBus.GetId will exit with success/fail+error-message if that bus is alive – Cheetah Jan 27 '18 at 01:43
  • @Cheetah : Thanks, that makes a lot of sense! I've incorporated your suggested method into my answer, eliminating the dependency on dbus-test. – FeRD Nov 22 '18 at 13:52
  • 1
    Under KDE5, the correct value for SESSION_MANAGER is "startkde", and you may need to add the "-n" argument to pgrep to ensure it only returns the latest instance of startkde (my system had 2 instances running, and only the latest one had any environment variables set). – Jonathan Watts Dec 19 '19 at 21:24
  • 1
    See also https://unix.stackexchange.com/a/28496/73278 for another way of getting DBUS_SESSION_ADDRESS – Greg Bell Dec 20 '19 at 11:49
  • @GregBell Agreed, that does seem easier! Though, interestingly, my $HOME/.dbus/session-bus/ file is named $(cat /var/lib/dbus/machine-id)-1, not -0 as in the example there. – FeRD Dec 20 '19 at 23:15
  • @JonathanWatts Things seem to have reached a similar point with GNOME. Under 3.34 I have no gnome-session processes running at all. Instead, my logged-in user has /usr/libexec/gnome-session-binary running (also two of them, one with the args --systemd-service --session=gnome) as well as a /usr/libexec/gnome-session-ctl. However, in my case all three processes have DBUS_SESSION_BUS_ADDRESS set in their environment. Still, as @GregBell pointed out https://unix.stackexchange.com/a/28496/73278 kind of makes the whole thing moot. – FeRD Dec 25 '19 at 22:23
  • Hmm, or maybe not. I only just noticed it, but not only is the file in my $HOME/.dbus/session-bus/ named differently from the example at that link, it's also from JUNE. Something did create that file at one point, but it's clearly not being updated. The DBUS_SESSION_BUS_PID it lists doesn't match any currently-running process, and the address points to /tmp/dbus-$linenoise. Whereas in my current session, DBUS_SESSION_BUS_ADDRESS is set to unix:path=/run/user/1000/dbus (a socket that currently exists). – FeRD Dec 25 '19 at 22:30
  • (The situation in my previous comment, with DBUS_SESSION_BUS_ADDRESS now pointing at an actual on-disk socket path, is undoubtedly the result of Fedora switching over to dbus-broker as its DBus daemon.) – FeRD Apr 12 '20 at 03:21