Running a background maintenance task via root's crontab is straightforward, but notifying a logged-in desktop user upon completion can be tricky. Because cron runs in an isolated, non-interactive environment without access to the user's graphical session, GUI tools like zenity, kdialog, or notify-send fail by default. To display a dialog box on the active user's desktop, you must explicitly provide the correct display and authorization parameters.
The Problem: Cron's Isolated Environment
When root runs a cron job, two critical environment variables are absent:
DISPLAY: Tells the graphical application which X server display to render on (usually:0.0or:0).XAUTHORITY: Points to the user's.Xauthoritycookie file, which authorizes applications to connect to that X server session.
Solution 1: Run Zenity via su with Environment Variables
The standard way to show a Zenity dialog is to execute the command as the target desktop user while exporting the display and authority variables:
su username -c 'DISPLAY=:0.0 XAUTHORITY=/home/username/.Xauthority zenity --info --title="Task Completed" --text="Root cron task has finished successfully."'
(Replace username and /home/username with the actual active user and their home directory path.)
Solution 2: Dynamic User Detection Script
If you manage multi-user workstations or don't want hardcoded usernames, use a wrapper script that automatically detects the currently logged-in desktop user, finds their .Xauthority, and triggers the popup.
Save the following script to /usr/local/bin/notify_user.sh:
#!/usr/bin/env bash
set -euo pipefail
# 1. Identify the user owning the current X session
ACTIVE_USER=$(who | awk '$0 ~ /(:0|\(:0\))/ {print $1; exit}')
if [ -z "${ACTIVE_USER}" ]; then
# Fallback: grab the first active graphical session
ACTIVE_USER=$(who | awk '{print $1; exit}')
fi
USER_HOME=$(eval echo "~${ACTIVE_USER}")
export DISPLAY=":0.0"
export XAUTHORITY="${USER_HOME}/.Xauthority"
# 2. Execute Zenity under the active user's environment
if [ -f "${XAUTHORITY}" ]; then
su "${ACTIVE_USER}" -c "DISPLAY=${DISPLAY} XAUTHORITY=${XAUTHORITY} zenity --info --title=\"${1:-Notification}\" --text=\"${2:-Background task completed.}\""
else
# Modern Wayland/Desktop DBus fallback (notify-send)
USER_ID=$(id -u "${ACTIVE_USER}")
su "${ACTIVE_USER}" -c "DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/${USER_ID}/bus notify-send \"${1:-Notification}\" \"${2:-Background task completed.}\""
fi
Make the script executable:
chmod +x /usr/local/bin/notify_user.sh
Example Cron Implementation
Call the notification script at the end of your root backup or maintenance job in /etc/crontab or sudo crontab -e:
0 2 * * * root /opt/scripts/backup.sh && /usr/local/bin/notify_user.sh "Backup Status" "Nightly system backup finished successfully."
No comments:
Post a Comment