擬似端末デバイスのもう一方の端に誰がいるかをどのようにして知ることができますか?


26

私がする場合:

echo foo > /dev/pts/12

いくつかのプロセスはfoo\n、ファイル記述子からマスター側にそれを読み取ります。

そのプロセスとは何かを知る方法はありますか?

または、言い換えると、どのxterm / sshd / script / screen / tmux / expect / socat ...がもう一方の端にあるの/dev/pts/12かをどのようにして見つけることができますか?

lsof /dev/ptmx任意のptyのマスター側にファイル記述子があるプロセスを教えてくれます。プロセス自体はptsname()TIOCGPTNioctl)を使用して、マスター側への独自のfdに基づいてスレーブデバイスを見つけることができるため、以下を使用できます。

gdb --batch --pid "$the_pid" -ex "print ptsname($the_fd)"

によって返されるpid / fdごとに、lsofそのマッピングを構築しますが、その情報を取得するためのより直接的で、信頼性が高く、邪魔にならない方法がありますか?


これは、あなたの望むことですか?sudo find /proc/*/fd/0 -ls | grep '/dev/pts/4'/proc/PID出力としてPIDのリスト()を提供します。
slm

@slm、いや、言い換えれば、どのxterm / sshd / script / screen / tmux / expect / socat ...がのもう一方の端にあるのかを知りたいのです/dev/pts/4。通常、それは/dev/pts/4開いているが必ずしもそうではないプロセスの共通の祖先になります。
ステファンシャゼラス14年

1
ソケットではさらに悪化ます。カーネルデバッガが必要です。
ジル 'SO-悪であるのをやめる'

1
@Falsenames-私は質問を意味すると理解しました-おそらく間違っています-ターミナルで最初に起動されたシェルなどのデータが渡されたプロセスではなく、マスター側から実際に読み取られるプロセスです。私はシェルを起動した場合例えば、screenそれは、screen私が思うに、と- -シェルはそのttyのためのプロセス・リーダー作られ、そうされて、あなたのよう積極的に割り当てて、デバイスの寿命のためにptyスレーブを管理していることが、出力はnot bashから何でも取得psできscreenます。に基づいxtermsxtermpidに戻っていくつかトレースしました/proc/locksが、それは緩いものでした。
mikeserv 14年

回答:


3

最初に、私が見つけた情報に基づいxtermxtermpidに数秒戻ってトレースしようとしました/proc/locksが、それは緩やかでした。つまり、うまくいったと思いますが、せいぜい環境的なものでした-ファイルが提供するすべての情報を完全に理解しておらず、その内容と既知の端末プロセスの間で一致すると思われるものと一致していました。

それから、pty間のlsof/straceアクティブなwrite/talkプロセスを見てみました。どちらのプログラムも実際に使用したことはありませんでしたが、依存しているようですutmp。対象となるpty utmpに何らかの理由でエントリがなかった場合、両者はその存在を認めることを拒否しました。たぶんそれを回避する方法があるかもしれませんが、私はそれを放棄するほど混乱していました。

udevadm宣伝されptsptmいるように/proc/tty/drivers、136と128のメジャー番号のデバイスノードでいくつかの発見を試みましたが、そのツールの非常に有用な経験が不足しており、実質的なものはありませんでした。興味深いことに、:min両方のデバイスタイプの範囲が驚くほどにリストされていることに気付きました0-1048575

しかし、このカーネルドキュメントを再訪してから、mountsの観点から問題について考え始めました。私はそれを数回読んだことがありますが、その行の継続的な研究がこの2012年の/dev/ptsパッチセットに私を導いたとき、私は考えがありました:

sudo fuser -v /dev/ptmx

私は思った私は通常関連付けるプロセスに何を使うのですかmountそして確かに:

                     USER        PID ACCESS COMMAND
/dev/ptmx:           root      410   F.... kmscon
                     mikeserv  710   F.... terminology

そのため、たとえば次のような情報を使用できますterminology

sudo sh -c '${cmd:=grep rchar /proc/410/io} && printf 1 >/dev/pts/0 && $cmd'
###OUTPUT###
rchar: 667991010
rchar: 667991011

ご覧のとおり、少し明示的にテストすることで、このようなプロセスを作成して、任意のptyのマスタープロセスをかなり確実に出力できます。ソケットに関してはsocat、デバッガーではなくその方向からアプローチできることはかなり確かですが、その方法についてはまだ明らかにしていません。それでも、ssあなたが私よりもそれをよく知っているなら、私は助けるかもしれない:

sudo sh -c 'ss -oep | grep "$(printf "pid=%s\n" $(fuser /dev/ptmx))"'

そこで、実際にはもう少し明示的なテストを設定しました。

sudo sh <<\CMD
    chkio() {
        read io io <$1
        dd bs=1 count=$$ </dev/zero >$2 2>/dev/null
        return $((($(read io io <$1; echo $io)-io)!=$$))
    }
    for pts in /dev/pts/[0-9]* ; do
        for ptm in $(fuser /dev/ptmx 2>/dev/null)
            do chkio /proc/$ptm/io $pts && break
        done && set -- "$@" "$ptm owns $pts"
    done
    printf %s\\n "$@"
 CMD

これは、印刷さ$$NUM \0各PTYとチェック前のチェックに対する各マスター・プロセスのIOにNULLバイトを。違いがある場合、$$pidとptyを関連付けます。これは主に機能します。私にとっては、それは戻ります:

410 owns /dev/pts/0
410 owns /dev/pts/1
710 owns /dev/pts/2

それは正しいですが、明らかに、それは少し際どいです。つまり、それらの1人がその時点で大量のデータを読んでいたとしたら、おそらく見逃していたでしょう。私はsttyそれを修正できるように、最初にストップビットまたはそのような何かを送信するために別のptyでモードを変更する方法を見つけようとしています。


2

接続の所有者と接続元を探しているだけであれば、whoコマンドはうまく機能します。

$ who
falsenames   tty8         Jun 13 16:54 (:0)
falsenames   pts/0        Jun 16 11:18 (:0)
falsenames   pts/1        Jun 16 12:59 (:0)
falsenames   pts/2        Jun 16 13:46 (:0)
falsenames   pts/3        Jun 16 14:10 (:0)
falsenames   pts/4        Jun 16 16:41 (:0)

その接続でリッスンしているものも知りたい場合、wは最後にそれを表示します。

$ w
 16:44:09 up 2 days, 23:51,  6 users,  load average: 0.26, 0.98, 1.25
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
falsenames   tty8     :0               Fri16    2days 53:36   0.59s x-session-manager
falsenames   pts/0    :0               11:18    5:25m  1:10   1:10  synergys -a 10.23.8.245 -c .synergy.conf -f -d DEBUG
falsenames   pts/1    :0               12:59    3:44m  0.05s  0.05s bash
falsenames   pts/2    :0               13:46    2:52m  0.11s  0.11s bash
falsenames   pts/3    :0               14:10    2:17   0.07s  0.07s bash
falsenames   pts/4    :0               16:41    1.00s  0.04s  0.00s w

そして、pidを取得するには、psをあなたが見ているttyセッションに制限します。起動するのにまったく邪魔になりません。

$ ps -t pts/0 --forest 
  PID TTY          TIME CMD
23808 pts/0    00:00:00 bash
23902 pts/0    00:03:27  \_ synergys

タイミングによっては、これがニシンにつながる可能性があることに注意してください。しかし、それは始めるのに良い場所です。

$ tty
/dev/pts/4
$ ps -t pts/4 --forest
  PID TTY          TIME CMD
27479 pts/4    00:00:00 bash
 3232 pts/4    00:00:00  \_ ps
27634 pts/4    00:00:00 dbus-launch

感謝しますが、それは私が探しているものではありません。たとえば、上記で/dev/pts/4wコマンドを実行したに対応する端末アプリケーション(Xterm / gnome-terminal ...)のpidを見つけたいです。
ステファンシャゼル14年

申し訳ありませんが、初めてスキャンしたときにpidの部分を完全に見逃してしまいました。エンドプロセス名を知りたいだけだと思いました。
偽名14年

2

私はqemuでも同じ問題を抱えていましたが、最終的に非常に悪い解決策(しかし、解決策)を見つけました。プロセスメモリの解析です。

これは、qemuが特定の形式の文字列にリモートPTSを格納し、ヒープに割り当てていることを知っているため、ここで機能しています。いくつかの変更を加えて、フューザー出力からpidを再利用することで、他の状況でも機能する可能性があります(他の回答を確認してください)。

コードはここから適応されます

#! /usr/bin/env python

import sys
pid = sys.argv[1]

import re
maps_file = open("/proc/" + pid + "/maps", 'r')
mem_file = open("/proc/" + pid + "/mem", 'r', 0)
for line in maps_file.readlines():
    # You may want to remove the 'heap' part to search all RAM
    m = re.match(r'([0-9A-Fa-f]+)-([0-9A-Fa-f]+) ([-r]).*\[heap\]', line)
    if m and m.group(3) == 'r':
        start = int(m.group(1), 16)
        end = int(m.group(2), 16)
        mem_file.seek(start)
        chunk = mem_file.read(end - start)
        # You may want to adapt this one to reduce false matches
        idx = chunk.find("/dev/pts/")
        if idx != -1:
            end = chunk.find("\0", idx)
            print chunk[idx:end]
maps_file.close()
mem_file.close()
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.