How to Programmatically Determine the Active Linux Virtual Terminal in a Multi-Head X11 Environment


2 views

In multi-user Linux systems with multiple X servers running on different virtual terminals (e.g., tty7 and tty8), administrators often need to determine which virtual terminal is currently active (i.e., displayed on the physical monitor). This becomes particularly challenging when accessing the system remotely via SSH.

The traditional w command shows logged-in users and their associated TTYs, but doesn't indicate which virtual terminal is currently active:

$ w
 21:51:30 up ? days,  4:22,  ? users,  load average: 1.72, 1.68, 1.67
USER     TTY      FROM              LOGIN@   IDLE   JCPU   PCPU WHAT
u1       pts/0    :0               Sat18    4days  0.00s 11.68s kdeinit4: kded4 [kdeinit]                      
u2       pts/5    :1               Mon17    2days  0.00s  6.65s kdeinit4: kded4 [kdeinit]

The most reliable method involves querying the kernel's virtual console subsystem:

# Check active VT (virtual terminal)
$ sudo fgconsole
7

# Alternative method using sysfs
$ cat /sys/class/tty/tty0/active
tty7

We can cross-reference this with running X servers:

$ ps aux | grep '/usr/bin/[X]'
root      2944  3.1 12.4 670040 1019904 tty7   Ss+  Aug27 187:52 /usr/bin/X :0 vt7 -br -nolisten tcp -auth /var/run/xauth/A:0-??????
root      5507  0.9  3.7 425136 309676 tty8    Ss+  Aug29  29:38 /usr/bin/X :1 vt8 -br -nolisten tcp -auth /var/run/xauth/A:1-??????

Here's a complete bash solution that combines these approaches:

#!/bin/bash

# Get active VT number
ACTIVE_VT=$(fgconsole 2>/dev/null || cat /sys/class/tty/tty0/active | sed 's/tty//')

# Find corresponding X display
X_DISPLAY=$(ps aux | awk -v vt="$ACTIVE_VT" \
  '/\/usr\/bin\/X/ && $7 == "tty"vt { \
    for(i=1;i<=NF;i++) { \
      if($i ~ /^:[0-9]+$/) {print $i; exit} \
    } \
  }')

echo "Active VT: tty${ACTIVE_VT}"
echo "Corresponding X display: ${X_DISPLAY:-Not found}"

On systems with systemd, we can query logind:

$ busctl get-property org.freedesktop.login1 /org/freedesktop/login1/seat/self org.freedesktop.login1.Seat ActiveSession
o "/org/freedesktop/login1/session/c2"

$ busctl get-property org.freedesktop.login1 /org/freedesktop/login1/session/c2 org.freedesktop.login1.Session VTNr
u 7

These methods may have limitations with:
- Wayland sessions
- Nested X servers
- Some GPU drivers that handle VT switching differently
- Systems without proper permissions for the SSH user


When working with a multi-user Linux system (in this case Debian 6.0 with ATI graphics), you might encounter a situation where multiple X sessions are running on different virtual terminals (e.g., tty7 and tty8), but only one is actively displayed on the physical monitor. The challenge arises when you need to remotely determine which X display is currently active through an SSH connection.

For system administrators and developers working remotely, knowing the active VT is crucial for:

  • Debugging graphical sessions
  • Managing user sessions
  • Automating display-related tasks
  • Implementing display-switching scripts

The standard w command shows logged-in users but doesn't indicate the active VT:


$ w
 21:51:30 up ? days,  4:22,  ? users,  load average: 1.72, 1.68, 1.67
USER     TTY      FROM              LOGIN@   IDLE   JCPU   PCPU WHAT
u1       pts/0    :0               Sat18    4days  0.00s 11.68s kdeinit4: kded4 [kdeinit]
u2       pts/5    :1               Mon17    2days  0.00s  6.65s kdeinit4: kded4 [kdeinit]

Similarly, checking X processes doesn't reveal which is active:


$ ps aux|grep /usr/bin/[X]
root      2944  3.1 12.4 670040 1019904 tty7   Ss+  Aug27 187:52 /usr/bin/X :0 vt7 -br -nolisten tcp -auth /var/run/xauth/A:0-??????
root      5507  0.9  3.7 425136 309676 tty8    Ss+  Aug29  29:38 /usr/bin/X :1 vt8 -br -nolisten tcp -auth /var/run/xauth/A:1-??????

The most reliable method is to examine the virtual console (vc) subsystem:


$ cat /sys/class/tty/tty0/active
tty7

This file contains the currently active virtual terminal. For a more robust solution, you can use this bash function:


get_active_vt() {
    local active_vt
    if [[ -e /sys/class/tty/tty0/active ]]; then
        active_vt=$(cat /sys/class/tty/tty0/active)
        echo "Active VT: ${active_vt}"
    else
        echo "Could not determine active VT" >&2
        return 1
    fi
}

To find which X display corresponds to the active VT:


find_active_x_display() {
    local active_vt x_pid x_display
    
    active_vt=$(cat /sys/class/tty/tty0/active)
    x_pid=$(pgrep -f "X.*vt${active_vt#tty}")
    
    if [[ -n "$x_pid" ]]; then
        x_display=$(ps -p "$x_pid" -o cmd= | grep -oP ':[0-9]+')
        echo "Active X display: $x_display"
    else
        echo "No X server running on $active_vt" >&2
        return 1
    fi
}

For systems without the sysfs interface, you can try:


$ fgconsole
7

Or query the kernel directly:


$ sudo cat /dev/vcs | head -1

Note that:

  • Some systems use Wayland instead of X
  • Virtual terminal behavior may vary between distributions
  • Permissions might be required to access certain files

Here's a complete script to monitor active VT changes:


#!/bin/bash

previous_vt=""

while true; do
    current_vt=$(cat /sys/class/tty/tty0/active 2>/dev/null)
    
    if [[ "$current_vt" != "$previous_vt" ]]; then
        echo "[$(date)] VT changed to $current_vt"
        previous_vt="$current_vt"
    fi
    
    sleep 1
done