Skip to content

Instantly share code, notes, and snippets.

@digitaltrails
Last active March 22, 2024 09:19
Show Gist options
  • Save digitaltrails/26aad3282d8739db1de8bc2e59c812eb to your computer and use it in GitHub Desktop.
Save digitaltrails/26aad3282d8739db1de8bc2e59c812eb to your computer and use it in GitHub Desktop.
notify-desktop - linux find and notify desktop session
#!/bin/bash
# Provides a way for a root process to perform a notify send for each
# of the local desktop users on this machine.
#
# Intended for use by cron and timer jobs. Arguments are passed straight
# to notify send. Falls back to using wall. Care must be taken to
# avoid using this script in any potential fast loops.
#
# X11 users should already have a dbus address socket at /run/user/<userid>/bus
# and this script should work without requiring any initialisation. Should
# this not be the case, X11 users could initilise a proxy as per the wayland
# instructions below.
#
# Due to stricter security requirements Wayland lacks an dbus socket
# accessible to root. Wayland users will need to run a proxy to
# provide root with the necessary socket. Each wayland user must add
# the following to a Wayland session startup script:
#
# notify-desktop --create-dbus-proxy
#
# That will start xdg-dbus-proxy process and make a socket available under:
# /run/user/<userid>/proxy_dbus_<desktop_sessionid>
#
# Once there is a listening socket, any root script or job can pass
# messages using the syntax of notify-send (man notify-send).
#
# Example messages
# notify-desktop -a Daily-backup -t 0 -i dialog-information.png "Backup completed without error"
# notify-desktop -a Remote-rsync -t 6000 -i dialog-warning.png "Remote host not currently on the network"
# notify-desktop -a Daily-backup -t 0 -i dialog-error.png "Error running backup, please consult journalctl"
# notify-desktop -a OS-Upgrade -t 0 -i dialog-warning.png "Update in progress, do not shutdown until further completion notice."
#
# Warnings:
# 1) There has only been limited testing on wayland
# 2) There has only been no testing for multiple GUI sessions on one desktop
#
if [ $1 == "--create-dbus-proxy" ]
then
if [ -n "$DBUS_SESSION_BUS_ADDRESS" ]
then
sessionid=$(cat /proc/self/sessionid)
xdg-dbus-proxy $DBUS_SESSION_BUS_ADDRESS /run/user/$(id -u)/proxy_dbus_$sessionid &
exit 0
else
echo "ERROR: no value for DBUS_SESSION_BUS_ADDRESS environment variable - not a wayland/X11 session?"
exit 1
fi
fi
function find_desktop_session {
for sessionid in $(loginctl list-sessions --no-legend | awk '{ print $1 }')
do
loginctl show-session -p Id -p Name -p User -p State -p Type -p Remote -p Display $sessionid |
awk -F= '
/[A-Za-z]+/ { val[$1] = $2; }
END {
if (val["Remote"] == "no" &&
val["State"] == "active" &&
(val["Type"] == "x11" || val["Type"] == "wayland")) {
print val["Name"], val["User"], val["Id"];
}
}'
done
}
count=0
while read -r -a desktop_info
do
if [ ${#desktop_info[@]} -eq 3 ]
then
desktop_user=${desktop_info[0]}
desktop_id=${desktop_info[1]}
desktop_sessionid=${desktop_info[2]}
proxy_bus_socket="/run/user/$desktop_id/proxy_dbus_$desktop_sessionid"
if [ -S $proxy_bus_socket ]
then
bus_address="$proxy_bus_socket"
else
bus_address="/run/user/$desktop_id/bus"
fi
sudo -u $desktop_user DBUS_SESSION_BUS_ADDRESS="unix:path=$bus_address" notify-send "$@"
count=$[count + 1]
fi
done <<<$(find_desktop_session)
# If no one has been notified fall back to wall
if [ $count -eq 0 ]
then
echo "$@" | wall
fi
# Don't want this to cause a job to stop
exit 0
@digitaltrails
Copy link
Author

Generalised for Wayland. Because Wayland is locked up tighter than X11. Each Wayland user needs to start an xdg-dbus-proxy to provide a socket for access to user's dbus session bus (if you examine the normal value of a user's DBUS_SESSION_BUS_ADDRESS you will see that it is a abstract socket). I've added an option for the script start the required proxy, the initialisation would have to be run in each users session at login. Proxy initialisation could also be done manually/separately providing you amend the code to use the socket you've independently created. X11 seems to always create an accessible socket under /run/user//bus, so no user level initialisation is required.

In theory this version should notify all local desktop sessions, but so far I've failed to get a working Xephyr or XNest KDE session, so notifying more than one desktop user remains untested.

I removed the unnecessary reference to the DISPLAY variable, only access to the bus is required.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment