pythonbashcrongsettings

Weird behavior of gsettings set a new desktop.background with cron


I want to change my desktop background every 5 minutes. I'm on ubuntu, this work and effectively change my background by another one :

gsettings set org.gnome.desktop.background picture-uri "file:/img.jpg"

I can launch it from a python script, that'll choose a random image from a specific directory. I put the script here, even if I'm not sure if it's relevant here

import os
import subprocess as sub
import random
files = [f for f in os.listdir('/usr/share/rwallpaper')]
rando = random.randint(0, (len(files) - 1))
cmd = ["gsettings", "set", "org.gnome.desktop.background", "picture-uri"]
wallpaper = "\"file:/usr/share/rwallpaper/" + files[rando] + "\""
cmd.append(wallpaper)
print(" ".join(cmd)) #to remove after
sub.run(cmd)

and this works too. So now i wanted to use cron to periodically execute my python code

$ sudo crontab -e
*/5 * * * * python3 /usr/local/cronwal/cronwal.py

and it doesn't work. I seen somewhere that it could be an user environnement issue so I tried to change the execution above with things like

*/5 * * * * sudo -u "me" python3 /usr/local/cronwal/cronwal.py
*/5 * * * * su me  -c "python3 /usr/local/cronwal/cronwal.py"

doesn't work. To be clear, in a root shell, the original command (first gsetting command at the top of my post) or these two doesn't work either, it's not a cron issue.

So, i decided to use crontab as my user. Perhaps it was a user related issue that can't be resolved by su/sudo

I tried this

$crontab -u me -e #in a shell run by "me"
*/5 * * * * python3 /usr/local/cronwal/cronwal.py 

and it doesn't work. More exactly, i can see in the cron service status

févr. 14 18:05:01 florent-NB50TZ CRON[56843]: pam_unix(cron:session): session opened for user root by (uid=0)
févr. 14 18:05:01 florent-NB50TZ CRON[56844]: pam_unix(cron:session): session opened for user florent by (uid=0)
févr. 14 18:05:01 florent-NB50TZ CRON[56843]: pam_unix(cron:session): session closed for user root
févr. 14 18:05:01 florent-NB50TZ CRON[56849]: (florent) CMD (python3 /usr/local/cronwal/cronwal.py )
févr. 14 18:05:01 florent-NB50TZ CRON[56844]: pam_unix(cron:session): session closed for user florent

(i lied, "me" is florent) so, as the line

(florent) CMD (python3 /usr/local/cronwal/cronwal.py )

imply, I run the script as florent, so it should work the same right ? But no. Even if the script run with my florent shell work, the cron wont work.

python3 /usr/local/cronwal/cronwal.py
#change of background

**Edit :**I did change the line in the crontab so I can have feedback. I indeed removed the mail with an option MAILTO="", so I need to have my feedback in another way.

*/5 * * * * python3 /usr/local/cronwal/cronwal.py >> /home/florent/cronwal.log 2>>/home/florent/cronwal.log

and as i thought, no error output. I only have the print(" ".join(cmd)) in the log.


Solution

  • In addition to $DISPLAY you may need to set $DBUS_SESSION_BUS_ADDRESS environment, because gsettings is using dbus (discovered when not setting DISPLAY, the error message talks about being unable to auto-launch D-Bus); you might try:

    DISPLAY=:0
    */5 * * * * eval $(ps -ww -p $(pgrep gnome-session) -o cmd= e | fmt -1 | grep DBUS_SESSION_BUS_ADDRESS) python3 /usr/local/cronwal/cronwal.py
    

    This gets the session address from the environment of the gnome-session process owned by the crontab invoker, and sets it in the environment of your python3 process, allowing the forked gsettings command to communicate over the session bus.

    You can check if DBUS_SESSION_BUS_ADDRESS is set in your terminal with printenv and copy that if there's some syntax error above (no way for me to test), but it will not work on the next gnome session of course if you hardcode it like that, you'd have to change it every time:

    DISPLAY=:0
    */5 * * * * DBUS_SESSION_BUS_ADDRESS="whatever printenv says" python3 /usr/local/cronwal/cronwal.py