web-dev-qa-db-ja.com

疑似端末デバイスの反対側に誰がいるのか、どうすればわかりますか?

私が行う場合:

_echo foo > /dev/pts/12
_

一部のプロセスは、その_foo\n_をファイル記述子からマスター側に読み取ります。

そのプロセスが何であるかを見つける方法はありますか?

または、言い換えると、どのxterm/sshd/script/screen/tmux/expect/socat ...が_/dev/pts/12_の反対側にあるかをどのように確認できますか?

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

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

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

26

最初に、/proc/locksで見つけた情報に基づいて、いくつかのxtermsをxterm pidにトレースしてみましたが、緩いものでした。つまり、うまくいったとは思いますが、せいぜい状況依存でした。ファイルが提供するすべての情報を完全に理解しているわけではなく、ファイルの内容と既知の端末プロセスの間で対応しているように見えるものにのみ一致していました。

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

/proc/tty/driversudevadmptsにそれぞれアドバタイズされるように、136と128のメジャー番号のデバイスノードでptmの検出を試みましたが、非常に便利な経験もありませんそのツールを使用して、再び実質的なものは何も見つかりませんでした。興味深いことに、私は両方のデバイスタイプの:min範囲が驚異的な0-1048575でリストされていることに気付きました。

しかし、これを再訪するまでは このカーネルドキュメント でしたが、mountsの観点から問題について考え始めました。以前に何度か読んだことがありましたが、その行での継続的な調査が私にこれを導いたとき this 2012 /dev/pts patchset アイデアがありました:

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 nullバイトを各ptyに出力し、以前のチェックに対して各マスタープロセスのioをチェックします。違いが$$の場合、pidをptyに関連付けます。これはほとんど機能します。つまり、私にとっては、次を返します:

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

これは正しいですが、明らかに、少々際どいです。つまり、それらの1つがその時点で大量のデータを読み取っていた場合、おそらく見落とすことになります。最初にストップビットを送信するために別のptyのsttyモードを変更する方法を理解しようとしています。

3
mikeserv

Qemuでも同じ問題が発生し、最終的に非常に悪い解決策が見つかりました(ただし、解決策はまだあります)。プロセスメモリの解析です。

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

コードは here から変更されています。

#! /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()
2
calandoa

接続の所有者と接続元を探しているだけの場合は、 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
2
Falsenames