You are not logged in.
I've already posted a RFT for a script that's supposed to send notify-send popups from root-owned processes to all the users on a system.
EDIT: New RFT: https://forums.bunsenlabs.org/viewtopic.php?id=2706
I wanted this so that if a script run from a systemd timer (or cron job) returned failure it would have a way of letting users know directly. If everyone had terminals open then 'wall' would work, and email messages are always available, but that feels so... clunky and old-school...
If you Google this you'll see that others have wanted the same thing, but it doesn't seem so easy. To use notify-send (or probably yad/zenity) you need a user's DBUS address, or XAUTHORITY path, or just their username, PLUS the number of the display they're using. It sounds simple till you try. Of course DISPLAY is :0 in most cases, but we want to be able to do this in all cases, where there might be multiple users logged-in simultaneously, using different displays.
In the above script I chose to parse the output of 'w -hs' and to use the value given as the "remote host", which for a local user on an x-terminal-emulator, or a GUI, resolves to the display number. This gave a list of logged-in users and their displays.
However, my hardware system is too simple to check what happens with multiple displays, for example. Does anyone have experience with this problem, or can offer opinions on whether this is likely to work? Is there a better way to get usernames/displays or, for that matter, for root to send messages to users?
(I looked at 'loginctl list-sessions' and 'loginctl show-session' too, and they offer the chance to filter only "active" sessions, but thought 'w' was simpler...)
Last edited by johnraff (2016-09-20 07:06:08)
...elevator in the Brain Hotel, broken down but just as well...
( a boring Japan blog (currently paused), now on Bluesky, there's also some GitStuff )
Offline
^That might be the way to go. loginctl seems to be the cli interface for logind. w works but the systemd commands might turn out to be more reliable.
for i in $(loginctl --no-legend list-sessions | awk '{print $1}');do loginctl show-session -p Name -p Active -p Remote -p Type -p Display "$i";echo '-----';done
This spits out info on all the current sessions. (I don't like having to do an awk pipe - maybe there's a cleaner way of getting a list of session id numbers.)
...elevator in the Brain Hotel, broken down but just as well...
( a boring Japan blog (currently paused), now on Bluesky, there's also some GitStuff )
Offline
Sorry, cancel all that.
'w -hs' yields the display number of users who logged in via a tty then ran startx... only if they then open a terminal emulator window!
'loginctl show-session sessionnumber' shows such users with Type=tty, Active=no and Display= regardless of emulator windows.
Others have googled "list running x sessions" and the like, and this person had a very similar usage case, but got no good answer. In fact it's quite simple to get a list of current DISPLAY numbers (eg look in /tmp/.X11-unix) and very simple to get a list of currently logged-in users. The hard bit is linking them together! Finally found this idea: http://superuser.com/questions/647464/h … wer-975536
Get a list of users, find a process (or all processes!) belonging to that user and get its PID, get its environment from /proc/$PID/environ and extract DISPLAY from that. (You need to be root to look at /proc/*/environ, but this is all about root sending messages to users anyway.)
This results in a very clunky command that checks the environments of all processes belonging to username, but it does in fact work:
john@bunsen1:~$ for i in $(ps --no-headers -u tester -o pid);do sudo cat /proc/$i/environ | tr '\0' '\n' | grep '^DISPLAY=:';done | grep -o ':[0-9]*' | sort -u
[sudo] password for john:
:1
and
john@bunsen1:~$ for i in $(ps --no-headers -u john -o pid);do sudo cat /proc/$i/environ | tr '\0' '\n' | grep '^DISPLAY=:';done | grep -o ':[0-9]*' | sort -u
cat: /proc/23312/environ: No such file or directory
:0
This will give a list of unique users:
echo $(printf '%s\n' $(users) | sort -u)
so it would be possible to do:
for i in $(printf '%s\n' $(users) | sort -u);do ...all that previous stuff
Alternatively, with no pipes:
declare -A arr
for i in $(users);do arr[$i]=x;done
for i in "${!arr[@]}"; do...
It would be nice to just pick one process that is bound to be running in every user's session, and save checking all of them, but Linux is infinitely tweakable and I couldn't find a single one in tester's list:
john@bunsen1:~$ ps --no-headers -u tester -o pid,cmd
1497 /lib/systemd/systemd --user
1498 (sd-pam)
1501 -bash
1555 /bin/sh /usr/bin/startx
1577 xinit /etc/X11/xinit/xinitrc -- /etc/X11/xinit/xserverrc :1 vt2 -auth /tmp/servera
1583 /usr/bin/openbox --startup /usr/lib/x86_64-linux-gnu/openbox-autostart OPENBOX
1633 /usr/bin/ssh-agent /usr/bin/dbus-launch --exit-with-session /usr/bin/im-launch x-s
1636 /usr/bin/dbus-launch --exit-with-session /usr/bin/im-launch x-session-manager
1637 /usr/bin/dbus-daemon --fork --print-pid 5 --print-address 7 --session
1664 /usr/bin/fcitx
1667 gnome-keyring-daemon --start --components=pkcs11,secrets
1677 /usr/bin/dbus-daemon --fork --print-pid 5 --print-address 7 --config-file /usr/sha
1681 /usr/bin/fcitx-dbus-watcher unix:abstract=/tmp/dbus-pGrM9X6cDB,guid=0dcbd5a44c27cf
1687 /usr/lib/mozc/mozc_server
1691 /usr/lib/x86_64-linux-gnu/xfce4/xfconf/xfconfd
1706 /usr/lib/policykit-1-gnome/polkit-gnome-authentication-agent-1
1709 xfdesktop
1710 xfce4-panel
1711 python /usr/bin/adeskbar
1714 volumeicon
1716 clipit
1726 thunar --daemon
1731 xfce4-power-manager
1734 light-locker
1735 /usr/bin/python /usr/share/system-config-printer/applet.py
1737 nm-applet
1738 xfce4-power-manager
1741 /usr/lib/at-spi2-core/at-spi-bus-launcher
1745 /usr/bin/dbus-daemon --config-file=/etc/at-spi2/accessibility.conf --nofork --prin
1748 /usr/lib/at-spi2-core/at-spi2-registryd --use-gnome-session
1754 /usr/lib/gvfs/gvfsd
1759 /usr/lib/gvfs/gvfsd-fuse /run/user/1001/gvfs -f -o big_writes
1772 /usr/bin/pulseaudio --start
1777 /usr/lib/x86_64-linux-gnu/gconf/gconfd-2
1786 /usr/lib/gvfs/gvfs-udisks2-volume-monitor
1791 /usr/lib/gvfs/gvfs-gphoto2-volume-monitor
1795 /usr/lib/gvfs/gvfs-afc-volume-monitor
1800 /usr/lib/gvfs/gvfs-goa-volume-monitor
1804 /usr/lib/gvfs/gvfs-mtp-volume-monitor
1813 /usr/lib/gvfs/gvfsd-trash --spawner :1.14 /org/gtk/gvfs/exec_spaw/0
1821 conky -c /home/taeko/.conkyrc
1827 /usr/lib/x86_64-linux-gnu/xfce4/panel/wrapper /usr/lib/x86_64-linux-gnu/xfce4/pane
1833 /usr/lib/x86_64-linux-gnu/xfce4/panel/wrapper /usr/lib/x86_64-linux-gnu/xfce4/pane
1846 /bin/sh /usr/bin/start-pulseaudio-x11
1847 /usr/bin/xprop -root -spy
Anyway, if the above code could be cleaned up a bit it does seem to be doing the job we want.
Tricks like 'sudo -u username' don't work because they inherit the parent environment, at least for DISPLAY.
Last edited by johnraff (2016-09-07 06:25:23)
...elevator in the Brain Hotel, broken down but just as well...
( a boring Japan blog (currently paused), now on Bluesky, there's also some GitStuff )
Offline
Yes of course that clunky command can be shortened. 'ps e' outputs the command's environment, so
ps e -u username | sed -rn 's/.* DISPLAY=(:[0-9]*).*/\1/p'
outputs the DISPLAY values found in the environments of all the processes being run by username. No need for sudo, and runs much faster than the above. (needs sudo for other peoples' processes)
One user can be logged into multiple X sessions. To test, I've got two running right now, so for example:
john@bunsen1:~$ declare -A disp
john@bunsen1:~$ for i in $(ps e -u john | sed -rn 's/.* DISPLAY=(:[0-9]*).*/\1/p');do disp[$i]=john;done
john@bunsen1:~$ for i in "${!disp[@]}";do echo "${disp[$i]} -- $i";done
john -- :0
john -- :1
So we can send notifications to both X sessions maybe. I'm just about to test that...
EDIT
Yes notify-send can send messages to both the X sessions being run by john, and if you switch ttys before they've timed out (set a long timeout) then you can see them all.
I think a new script is ready for testing.
Last edited by johnraff (2016-09-09 04:01:40)
...elevator in the Brain Hotel, broken down but just as well...
( a boring Japan blog (currently paused), now on Bluesky, there's also some GitStuff )
Offline
This short script just outputs the names of all the users with X sessions (skipping root) and their display numbers:
#!/bin/bash
declare -A disps usrs
usrs=()
disps=()
for i in $(users);do
[[ $i = root ]] && continue
usrs[$i]=1
done # unique names
for u in "${!usrs[@]}"; do
for i in $(sudo ps e -u "$u" | sed -rn 's/.* DISPLAY=(:[0-9]*).*/\1/p');do
disps[$i]=$u
done
done
for d in "${!disps[@]}";do
echo "User: ${disps[$d]}, Display: $d"
done
...elevator in the Brain Hotel, broken down but just as well...
( a boring Japan blog (currently paused), now on Bluesky, there's also some GitStuff )
Offline