From 9b78a12d97a7d9efafc0b082aade90478935cf63 Mon Sep 17 00:00:00 2001 From: Christoph Date: Sun, 20 Sep 2026 14:51:29 +0200 Subject: [PATCH] Initial commit: wer - replacement for w/who on Debian 13 Lists logged-in sessions (local and ssh), one entry per terminal, including multiplexed ssh connections (ControlMaster). Needed because Debian 13 no longer populates utmp, so w/who show nothing. - Sessions and origin via systemd-logind (loginctl) - Terminals detected via session leaders and cgroup mapping - sudo shells (own pty) shown indented below their terminal - BEFEHL column shows the current foreground process - Sessions without a terminal (scp, sftp, ssh -N) are listed too --- wer | 103 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100755 wer diff --git a/wer b/wer new file mode 100755 index 0000000..9ff51a6 --- /dev/null +++ b/wer @@ -0,0 +1,103 @@ +#!/bin/bash +# wer - ein Eintrag pro Terminal (lokal, ssh, auch bei ControlMaster/Multiplexing) +# Ersatz für 'w'/'who' unter Debian 13 +# - sudo-Shells (eigenes Pseudo-Terminal) erscheinen eingerückt unter ihrem Terminal +# - Spalte BEFEHL: aktuell im Vordergrund laufender Befehl (leer = Shell wartet am Prompt) + +declare -A from seen elev +rows=() + +get_from() { # Herkunft einer logind-Sitzung (mit Cache) + local sid=$1 k v remote=no host= + [[ -n ${from[$sid]} ]] && return + while IFS== read -r k v; do + case $k in Remote) remote=$v ;; RemoteHost) host=$v ;; esac + done < <(loginctl show-session "$sid" -p Remote -p RemoteHost 2>/dev/null /dev/null | head -1 +} + +# alle Prozesse mit Terminal: pid ppid sid tty etimes pgid tpgid comm +procs=$(ps -eo pid=,ppid=,sid=,tty=,etimes=,pgid=,tpgid=,comm= -ww /dev/null /dev/null oldest )) && oldest=$et + if [[ $pid == "$sess" ]]; then leader=$pid; lcomm=$comm; lppid=$ppid; fi + done < <(awk -v t="$tty" '$4==t' <<<"$procs") + + [[ -n $lsid ]] || continue # kein Benutzer-Login + seit=$(date -d "@$(( now - oldest ))" '+%F %H:%M') + + if [[ -n $lppid ]]; then + pcomm=$(ps -o comm= -p "$lppid" 2>/dev/null unter dem äußeren Terminal anzeigen + outer=$(ps -o tty= -p "$lppid" 2>/dev/null /dev/null /dev/null /dev/null) + get_from "$lsid" + seen[$lsid]=1 + cmd=$(fgcmd "$tty" "$leader") + rows+=("$lsid|${user:-?}|$tty|${from[$lsid]}|$seit|${lcomm:-$first}|$cmd") +done + +# Spaltenbreite für VON (IPv6-Adressen sind lang) +vw=6 +for r in "${rows[@]}"; do + IFS='|' read -r _ _ _ v _ <<<"$r" + (( ${#v} > vw )) && vw=${#v} +done +fmt="%-8s %-12s %-9s %-${vw}s %-16s %-9s %s\n" + +# ---- Durchgang 2: Ausgabe ---- +printf "$fmt" SESSION BENUTZER TTY VON SEIT PROZESS BEFEHL + +for r in "${rows[@]}"; do + IFS='|' read -r lsid user tty von seit proc cmd <<<"$r" + printf "$fmt" "$lsid" "$user" "$tty" "$von" "$seit" "$proc" "$cmd" + while IFS='|' read -r su st ss sc sb; do + [[ -n $su ]] && printf "$fmt" "" '\_ '"$su" "$st" "sudo" "$ss" "$sc" "$sb" + done <<<"${elev[$tty]}" +done + +# Sitzungen ohne Terminal (scp, sftp, ssh -N ...) ebenfalls anzeigen +while read -r id _ user _; do + [[ -n ${seen[$id]} ]] && continue + [[ $(loginctl show-session "$id" -p Class --value 2>/dev/null /dev/null)" "-" "(kein Terminal)" +done < <(loginctl list-sessions --no-legend --no-pager