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

444 views Asked by At

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.

2

There are 2 answers

1
smemsh On BEST ANSWER

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
3
smemsh On

Just a guess, but maybe gsettings needs your display server set, just make your user crontab look like this:

DISPLAY=:0
*/5 * * * * python3 /usr/local/cronwal/cronwal.py

For the bad invocation, you should have seen an error in your email to the user whose crontab it is, which probably would have told you DISPLAY wasn't set, if you had locally-generated mail to unqualified users configured (try echo . | mail -s testing florent to test, but you'll need a package like bsd-mailx installed to try this). Cron mails standard error and output to the user running the crontab.

All X programs need to know the display server to use for actions which operate upon it. You can read the X(7) man page for details. Normally when using a terminal within X, this environment variable is already set, but in your crontab you'll need to provide it. If you're using a different one than :0, you can check it with printenv DISPLAY in a shell within your relevant X environment (and btw :0 is the same as :0.0).