You are not logged in.

#1 2016-09-05 03:56:09

johnraff
nullglob
From: Nagoya, Japan
Registered: 2015-09-09
Posts: 12,558
Website

[SOLVED] Best way to identify logged-in users and their DISPLAY?

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 )

Introduction to the Bunsenlabs Boron Desktop

Offline

#2 2016-09-06 06:46:50

johnraff
nullglob
From: Nagoya, Japan
Registered: 2015-09-09
Posts: 12,558
Website

Re: [SOLVED] Best way to identify logged-in users and their DISPLAY?

^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 )

Introduction to the Bunsenlabs Boron Desktop

Offline

#3 2016-09-07 06:16:47

johnraff
nullglob
From: Nagoya, Japan
Registered: 2015-09-09
Posts: 12,558
Website

Re: [SOLVED] Best way to identify logged-in users and their DISPLAY?

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 )

Introduction to the Bunsenlabs Boron Desktop

Offline

#4 2016-09-08 03:23:44

johnraff
nullglob
From: Nagoya, Japan
Registered: 2015-09-09
Posts: 12,558
Website

Re: [SOLVED] Best way to identify logged-in users and their DISPLAY?

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.  cool

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 )

Introduction to the Bunsenlabs Boron Desktop

Offline

#5 2016-09-09 04:03:22

johnraff
nullglob
From: Nagoya, Japan
Registered: 2015-09-09
Posts: 12,558
Website

Re: [SOLVED] Best way to identify logged-in users and their DISPLAY?

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 )

Introduction to the Bunsenlabs Boron Desktop

Offline

Board footer

Powered by FluxBB