Search This Blog

Monday, August 31, 2026

How to display a zenity/GUI window to the user from a root cron job

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.0 or :0).
  • XAUTHORITY: Points to the user's .Xauthority cookie 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