web-dev-qa-db-ja.com

すべてのアクティブなXセッションとその所有者のリストを取得する方法

USBプラグ/アンプラグ通知(ここでは 関連する質問 )を実装しています。notify-send "device plugged" "My Device Title"のようなものを実行する必要があります。問題は、このコマンドを機能させるために、最初にDISPLAYを次のように設定する必要があることです。

export DISPLAY=":0.0"

次に、このコマンドは適切なユーザーが呼び出す必要があります。たとえば、ユーザーdimonの場合:

su dimon -c "notify-send 'device plugged' 'My Device Title'"

したがって、すべてのアクティブなXセッションと適切なユーザーのリストを取得し、DISPLAYの各ユーザーに対してnotify-sendを呼び出す必要があります。

そのためにwを使用しようとしましたが、Linux Mint 13 MATEでの出力例:

USER     TTY      FROM              LOGIN@   IDLE   JCPU   PCPU WHAT
dimon    tty8     :0               Sun15    3days  1:38m  1.95s x-session-manager
dimon    pts/0    :0               Sun15    0.00s  0.20s  0.00s tmux

したがって、ユーザー名とディスプレイの両方があります。私はそれをそのように解析することにしました:

declare -a logged_users=(`w |grep -vP "^(USER| )" |awk '{if (NF==8){print $1" "$3} else {print $1" :0"}}' |sort |uniq`)

現在、配列logged_usersがあります。[0]にはdimonが含まれ、[1]には:0が含まれます。これはすばらしいことですが、残念ながらどこでも機能するわけではありません。たとえば、Ubuntu 12.04でlightdmを使用すると、次のw出力が得られます。

USER     TTY      FROM              LOGIN@   IDLE   JCPU   PCPU WHAT
nui      tty7                      18:22   35:56   1.66s  0.11s gnome-session -
nui      pts/0    :0.0             18:55    5.00s  0.20s  0.00s w

gnome-sessionにFROM値がない理由はわかりません。さらに悪いことに、xubuntuで:

USER     TTY      FROM              LOGIN@   IDLE   JCPU   PCPU WHAT
nui      tty7                      15:50   31:07  52.55s  0.13s /bin/sh /etc/xd

何も表示されません!他のユーザーがログインしている場合、そのユーザーのディスプレイも指定されていません(実際には:1.0です)

だから、私は別のアプローチを探しています。また、ここにはすべてのアクティブなXセッションのリストがあることも知っています:/tmp/.X11-unix、これらのリストは次のように取得できます。

cd /tmp/.X11-unix && for x in X*; do echo ":${x#X}"; done

しかし、その後、ユーザーを取得する方法がわかりません。

では、すべてのアクティブなXセッションと適切なユーザーのリストを取得するにはどうすればよいでしょうか。

5
Dmitry Frank

これはlocal Xサーバーのユーザー向けのソリューションです(リモートまたは仮想Xサーバーを持つローカルXクライアントは無視されます)。

ディスプレイマネージャーのPID(Xorgの親PID)を決定し、その子のPIDを決定し、それらの1つを親として持つすべてのプロセスのユーザーを決定します。

#! /bin/bash
xorg_pid=$(pidof -s /usr/bin/Xorg)
test -n "$xorg_pid" || exit 1
dm_pid=$(ps -eo pid,ppid,args | \
    awk -v xorg_pid=$xorg_pid '$1 == xorg_pid {print $2}')
pid_list="$(ps -eo pid,ppid,cmd | \
    awk -v dm_pid=$dm_pid '$2 == dm_pid {if (matchnr == 0) '\
'{ printf "%s%d ","$2 == ",$1; matchnr++;} '\
'else printf "%s%d ","|| $2 == ",$1;}')"
ps -eo pid,ppid,user,cmd | awk "$pid_list"'{print $3}'
4
Hauke Laging

同じ通知送信問題がありました。

このメソッド(また掲載 ここ )は、_ps e_が提供する環境情報を使用します。 ps e -u username | sed -rn 's/.* DISPLAY=(:[0-9]*).*/\1/p'は、すべてのユーザーusernameのプロセスの環境におけるすべてのDISPLAY番号のリストを出力します。

デスクトップにルート所有のウィンドウがある場合、ルートにも同じDISPLAY番号を持ついくつかのプロセスがありますが、それ以外の場合、1つのDISPLAYは1人のユーザーにのみ関連付けられます。 (逆ではありません-現在、2つのttyで2つのXセッションでログインしているため、:0と:1の両方を使用しています。)

このコードは、現在ログインしているすべてのユーザーの現在使用されているすべてのDISPLAY(つまり、すべてのXセッション)を出力します。 (ルートはスキップされます)

Sudoコマンドのpsに注意してください。他のユーザーのプロセスの環境を表示するには、root権限が必要です。もちろん、スクリプトがrootで実行される場合は不要です。

ユーザー名と表示番号は、一意の値のみを保持するために、連想配列のインデックスとして使用されます。

_#!/bin/bash

declare -A disps usrs
usrs=()
disps=()

for i in $(users);do
    [[ $i = root ]] && continue # skip root
    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"
    #Sudo -u "${disps[$d]}" DISPLAY="$d" notify-send "Title" "Message"
done
_

最後のコメント化された行は、notify-sendを呼び出す方法を示しています。

2
johnraff