1

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.

Zartant
  • 109
  • 9
  • What is the output from `cat /var/spool/cron/crontabs/florent`? –  Feb 14 '21 at 20:11
  • @Roadowl `MAILTO=""`, `DISPLAY=:0`, and the very last line I puted in my post. looks like the file i edit with crontab -e – Zartant Feb 14 '21 at 20:23
  • Just to be sure, place the full path to python3 in the crontab; do `type python3` and put the rightmost part of the result in the crontab instead of just `python3`. –  Feb 14 '21 at 20:36
  • Here's something else to try: put this as a separate entry in your crontab: `*/3 * * * * cat /usr/local/cronwal/cronwal.py > /home/florent/crontab-test.log 2>&1`. –  Feb 14 '21 at 20:41
  • @Roadowl I added the line and I put the full path, no change for now (and the crontab-test.log is the content of cronwal.py) – Zartant Feb 14 '21 at 20:51
  • Why are you editing root's crontab (the `sudo`) and not your own? And why don't you put `cronwal.py` somewhere in your home directory (and use its full path in the crontab)? –  Feb 14 '21 at 23:11
  • Are you a member of the `crontab` group? What does `groups` say, is `crontab` in that list? –  Feb 14 '21 at 23:14

2 Answers2

1

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).

smemsh
  • 94
  • 3
  • Thanks for the guess, it unfortunately didn't worked. Display=:0 doesn't change a thing, and `printenv DISPLAY` return `:0` – Zartant Feb 14 '21 at 18:22
  • 1
    if you can't get local mail working, to debug you can do `python3 /usr/local/cronwal/cronwal.py >/tmp/cronwall.out 2>&1` as the cron command, and then look at the output file after it runs. this puts stdout and stderr into the file rather than letting cron capture it (and try to mail you) – smemsh Feb 14 '21 at 18:32
  • i tried, the main post is edited. It's a good idea that I should have tried earlier but nothing useful came out, unfortunately. – Zartant Feb 14 '21 at 19:17
1

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
smemsh
  • 94
  • 3
  • Your last proposition works for now, I'll check later if I need to do something to make it persistant, thanks – Zartant Feb 16 '21 at 06:36