[Mint 18, 19] Using notify-send from a user crontab

Write tutorials here
There are more tutorials here http://community.linuxmint.com/tutorial/welcome
Forum rules
Please don't add support questions to tutorials,start your own thread in the appropriate sub-forum instead. Before you post please read this
Post Reply
rene
Level 8
Level 8
Posts: 2226
Joined: Sun Mar 27, 2016 6:58 pm

[Mint 18, 19] Using notify-send from a user crontab

Post by rene » Sat Oct 06, 2018 7:26 pm

Since I've wanted to do so a few times I expect the following may be useful to some. Current as of Mint 18 and 19.

Employing the desktop notification mechanism from the command line is a matter of installing libnotify-bin if it isn't yet installed and invoking e.g. notify-send -u critical -i dialog-warning "summary" "optional text". The "-u critical" keeps the notification on screen until manually closed, the "-i dialog-warning" selects a notification icon as could be chosen from among for example the "Standard Status Icons" section of https://standards.freedesktop.org/icon- ... atest.html

Doing so from a user crontab does not however work: notify-send communicates over the dbus session bus but cron jobs are not part of any graphical user session; are not provided the session bus address of whichever graphical session runs the desktop notifier to be contacted. For Mint 19 and supposedly Ubuntu 18.04 this is easily remedied by manually providing the cron job with the DBUS_SESSION_BUS_ADDRESS="unix:path=/run/user/$(id -u)/bus" environment variable but that socket does not in fact exist on Mint 18 and supposedly Ubuntu 16.04.

On Mint 18 the first idea might be to source ~/.dbus/session-bus/$(dbus-uuidgen --get)-0, in which "0" is the X display number as in principle available via loginctl similarly to the below, but when a new session bus launches --- as can happen for any number of reasons --- that file will describe the new bus, not the "main" user session bus that notify-send needs to communicate with the desktop notifier.

In absence of the socket as available from under /run/user for Mint 19 the somewhat unfortunate thing to do is look at the environment of some user graphical session process so as to retrieve DBUS_SESSION_BUS_ADDRESS. Hardcoding e.g. "gnome-session" as said process is the usual thing to do but with logind there's a slightly more elegant method available: get the session identifier for the "Display" session from loginctl show-user <name>, its "Leader" from loginctl show-session <session> and its oldest child with pgrep -o -P <leader>; that oldest child will in normal setups be the desktop session manager and have the correct DBUS_SESSION_BUS_ADDRESS.

As code: you would replace a call of notify-send in a user crontab with a call of, e.g., the executable shell script ~/bin/cron-notify,

Code: Select all

#!/bin/sh
if [ -z "$DBUS_SESSION_BUS_ADDRESS" ]; then 
    if [ -z "$LOGNAME" ]; then
        EUID=$(id -u)
    else
        EUID=$(id -u "$LOGNAME")
    fi
    [ -z $EUID ] && exit

    if [ -S /run/user/$EUID/bus ]; then
        export DBUS_SESSION_BUS_ADDRESS="unix:path=/run/user/$EUID/bus"
    else
        SESSION=$(loginctl -p Display show-user "$LOGNAME" | cut -d= -f2)
        [ -z "$SESSION" ] && exit
        LEADER=$(loginctl -p Leader show-session "$SESSION" | cut -d= -f2)
        [ -z $LEADER ] && exit
        OLDEST=$(pgrep -o -P $LEADER)
        [ -z $OLDEST ] && exit
        export $(grep -z DBUS_SESSION_BUS_ADDRESS /proc/$OLDEST/environ)
        [ -z "$DBUS_SESSION_BUS_ADDRESS" ] && exit
    fi
fi
notify-send "$@"
Note that the described method, the "else" branch in the above, works on Mint 19 as well as Mint 18 but that we clearly needn't bother if we have the socket available from under /run/user. Also, that the --value parameter to loginctl as available on Mint 19 and allowing to forego cut is not available on Mint 18.

If the user is not in fact logged in this exits gracefully without notifying anything, and it is hoped that this method may survive a few versions.

Post Reply

Return to “Tutorials”