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

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

私が次のことをしたら:

echo foo > /dev/pts/12

一部のプロセスはfoo\nファイル記述子からマスターにそれを読み込みます。

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

言い換えれば、どのxterm/sshd/script/screen/tmux/expect/socat...が反対側にあるのか、どうすればわかりますか/dev/pts/12

lsof /dev/ptmxptyのマスター側にファイル記述子があるプロセスを知らせます。プロセス自体はptsname()TIOCGPTNioctl)を使用して独自のfdに基づいてマスターデバイスを見つけることができるので、次のことができます。

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

このマップは返された各pid / fdに対して作成されていますが、lsofこの情報を取得するより直接的で信頼性が高く、侵害の少ない方法はありますか?

答え1

最初は見つけた情報に基づいてpidを追跡してみましたが、緩んでxtermいました。私の言葉は、うまくいくと思いますが、せいぜい状況に応じたものです。そのファイルが提供するすべての情報を完全に理解しておらず、その内容と既知の端末プロセスの間で一致しているように見えるものだけが一致します。xterm/proc/locks

それから、pty間のアクティブlsof/straceプロセスを観察しようとしています。write/talk私は以前に2つのプログラムを実際に使用したことがありませんが、それに依存しているようです。何らかの理由でutmp私のターゲットptyにエントリがない場合、どちらもその存在を認めません。utmpたぶんこの問題を解決する方法があるかもしれませんが、混乱して諦めました。

私はudevadmそれぞれと広告された136と128のマスターデバイスノードを使用していくつかの発見を試みptsましptmたが、/proc/tty/driversそのツールの非常に有用な経験が不足しており、もう一度実用的なコンテンツを見つけることができませんでした。しかし、興味深いことに、両方:minのデバイスタイプが驚くべき価格でリストされていることがわかりました0-1048575

これをもう一度見るまでこのカーネル文書しかし、私はこの問題をsの観点から考え始めましたmount。私は以前この内容を何度も読んでいましたが、その分野の継続的な研究を通してこれを発見しました。この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

各ptyに$$num nullバイトを印刷し\0、前の確認と比較して各基本プロセスのioを確認します。それ以外の場合は、$$pidをptyに関連付けます。これ最大働く私の言葉は、私には次のように返されます。

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

正しい言葉ですが、明らかに少し不自然です。私の言うことは、それらの1つがその時点で大量のデータを読んでいる場合、それを見逃す可能性があるということです。stty問題を解決するために、ストップビットが最初に送信されるように他のptyでモードを変更する方法を見つけようとしています。

答え2

2017年、Linuxにはこのプロセスを少し簡単にする新機能が追加されました(コミットd01c3289e7d、Linux 4.14以降の場合)

オープンプロセスのリストを取得した後/dev/ptmx

$ fuser dev/ptmx
/dev/ptmx:           1330334 1507443

pts次の番号を受け取ることができます。

for pid in $(fuser /dev/ptmx 2>/dev/null); do grep -r tty-index /proc/$pid/fdinfo; done
/proc/1330334/fdinfo/13:tty-index:  0
/proc/1330334/fdinfo/14:tty-index:  1
/proc/1330334/fdinfo/27:tty-index:  2
/proc/1330334/fdinfo/28:tty-index:  4
/proc/1507443/fdinfo/3:tty-index:   3

結果は<pid>:<ptmx fd>aからその項目へのマッピングです。/dev/pts/<index>

バージョン 4.90 以降lsofこのAPIを使用して相手に報告し、/dev/ptmxファイルを使用//dev/pts/x開くことができます。-E+E

$ lsof -E -ad 0 -p $$
COMMAND   PID     USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
zsh     14335     user    0u   CHR  136,8      0t0   11 /dev/pts/8 14333,xterm,5u
$ lsof +E -ad 0 -p $$
COMMAND   PID     USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
xterm   14333     user    5u   CHR    5,2      0t0   87 /dev/ptmx ->/dev/pts/8 14335,zsh,0u 14335,zsh,1u 14335,zsh,2u 14335,zsh,10u 14391,lsof,0u 14391,lsof,1u 14391,lsof,2u
zsh     14335     user    0u   CHR  136,8      0t0   11 /dev/pts/8 14333,xterm,5u

答え3

誰が接続したのか、どこで接続したのかを調べると、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
 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を取得するには、現在表示されているttyセッションにpsを制限します。起動がまったく目立たない。

$ 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

答え4

私はqemuと同じ問題を抱えて、ついに非常に悪い解決策(しかしまだ解決策)を見つけました:プロセスメモリを解析します。

これは、qemuがリモートptを特定の形式の文字列として保存し、ヒープに割り当てることを知っているので、ここで機能します。おそらく他の場合でも動作します。いくつか変更し、フュージョン出力の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()

関連情報