web-dev-qa-db-ja.com

疑似端末のマスターとスレーブを相互に見つけるにはどうすればよいですか?

疑似端末には、マスターとスレーブのペアがあります。

スレーブデバイスファイル(例:/etc/pts/3)からマスターデバイスファイルを見つけるにはどうすればよいですか? /dev/ptmx/dev/pts/ptmxしか見つかりませんが、複数のスレーブで共有することはできません。

マスターとスレーブで動作しているプロセスの1つを考えると、他のプロセスをどのように見つけることができますか?たとえば、psは、各プロセスの制御ttyに関する情報を提供します。それは役に立ちますか?

ありがとう。

1
Tim

それは、あるべきよりも難しいことの1つです。

新しいLinuxカーネルでは、マスターとペアになっているスレーブptyのインデックスは、_tty-index_の_/proc/PID/fdinfo/FD_エントリから収集できます。これを参照してください commit

古いカーネルでは、それを取得する唯一の方法は、マスターptyを保持するプロセスにデバッガーでアタッチし、ファイル記述子でptsname(3)(または直接ioctl(TIOCGPTN))を呼び出すことです。

[ただし、両方の方法で、複数のdevptsマウントを使用するシステムで問題が発生します。以下を参照してください]

その情報を使用して、マスターとスレーブのペアのリストを作成できます。これにより、スレーブから起動するマスターを検索することもできます。

これはそれを行うべきばかげたスクリプトです。最初に_tty-index_の方法を試し、それが機能しない場合はgdbにフォールバックします。後者の場合、workinggdb(_gdb-minimal_または他の半分壊れたgdbほとんどのディストリビューションには付属していません)が必要です。 gdbを使用すると、非常に遅くなります

Ptyペアごとに、次のように出力されます。

_/dev/pts/1
    1227  3     t/ct_test
        1228  +*      t/ct_test
        1230  +      t/ct_test
/dev/pts/3
    975   9     'sshd: root [priv]' '' '' '' '' '' '' '' ''
    978   14,18,19   'sshd: root@pts/3' '' '' '' '' '' '' ''
        979   -*0,1,2,255   -bash
        1222  1     tiocsti
        1393  -0,1,2   sleep 3600
        1231  +0,2   Perl ptys.pl
        1232  +1,2   cut -b1-60
_

2つのsshdプロセス(pid 975および978)には、マスター側へのオープンハンドルがあります(1つは9 fdとして、もう1つは14、18、および19 fdsとして)。 sleepおよび_-bash_には、標準(0、1、および2)fdsとしてスレーブ側へのオープンハンドルがあります。セッションリーダー(bash)には_*_、フォアグラウンドのプロセス(Perlおよびcut)には_+_、バックグラウンドのプロセス(lessおよび_-bash_)にはマークが付けられます。 _-_。

_t/ct_test_プロセスは、fdを開かずに、制御端末としてptyを使用しています。 tiocstiは、制御端末ではなく、ハンドルが開いています。

Debian9およびFedora28でテスト済み。使用している魔法数に関する情報は、Linuxカーネルの procfs(5) および _Documentation/admin-guide/devices.txt_ にあります。ソース。


これは、chrootまたは名前空間コンテナを使用するシステムでは失敗します。 _/proc/PID/stat_からptyへのttyフィールドを一致させる信頼できる方法がなく、fdが_/dev/ptmx_を介して対応する_/dev/pts_マウントに開かれるため、カーネルにいくつかの変更を加えることなく修正することはできません。それについての暴言については ここ を参照してください。

これは、_/dev/tty_を介して開かれたfdにもリンクされません。 realttyは、プロセスにアタッチしてioctl(fd, TIOCGDEV, &dev)を呼び出すことで解決できますが、これはgdbの別の汚い大量使用を意味し、次のようになります。上記と同じ問題ですが、疑似ttyスレーブのメジャーとマイナーの数があいまいです。

ptys.pl:

_my (%pty, %ctty);
for(</proc/*[0-9]*/{fd/*,stat}>){
    if(my ($pid, $fd) = m{/proc/(\d+)/fd/(\d+)}){
        next unless -c $_;
        my $rdev = (stat)[6]; my $maj = $rdev >> 8 & 0xfff;
        if($rdev == 0x502){ # /dev/ptmx or /dev/pts/ptmx
            $pty{ptsname($pid, $fd, readlink $_)}{m}{$pid}{$fd} = 1;
        }elsif($maj >= 136 && $maj <= 143){ # /dev/pts/N
            $pty{readlink $_}{s}{$pid}{$fd} = 1;
        }
    }else{
        my @s = readfile($_) =~ /(?<=\().*(?=\))|[^\s()]+/gs;
        $ctty{$s[6]}{$s[0]} =       # ctty{tty}{pid} =
            ($s[4] == $s[7] ? '+' : '-').   # pgrp == tpgid
            ($s[0] == $s[5] ? '*' : '');    # pid == sid
    }
}
for(sort {length($a)<=>length($b) or $a cmp $b} keys %pty){
    print "$_\n";
    pproc(4, $pty{$_}{m}); pproc(8, $pty{$_}{s}, $ctty{(stat)[6]});
}

sub readfile { local $/; my $h; open $h, '<', shift and <$h> }
sub cmdline {
    join ' ', map { s/'/'\\''/g, $_ = "'$_'" if m{^$|[^\w./+=-]}; $_ }
        readfile("/proc/$_[0]/cmdline") =~ /([^\0]*)\0/g;
}
sub pproc {
    my ($px, $h, $sinfo) = @_;
    exists $$h{$_} or $$h{$_} = {''} for keys %$sinfo;
    return printf "%*s???\n", $px, "" unless $h;
    for my $pid (sort {$a<=>$b} keys %$h){
        printf "%*s%-5d %s%-3s   %s\n", $px, "", $pid, $$sinfo{$pid},
            join(',', sort {$a<=>$b} keys %{$$h{$pid}}),
            cmdline $pid;
    }
}
sub ptsname {
    my ($pid, $fd, $ptmx) = @_;
    return '???' unless defined(my $ptn = getptn($pid, $fd));
    $ptmx =~ m{(.*)(?:/pts)?/ptmx$} ? "$1/pts/$ptn" : "$ptmx ..?? pts/$ptn"
}
sub getptn {
    my ($pid, $fd) = @_;
    return $1 if
        readfile("/proc/$pid/fdinfo/$fd") =~ /^tty-index:\s*(\d+)$/m;
    return gdb_ioctl($pid, $fd, 0x80045430);    # TIOCGPTN
}
sub gdb_ioctl {
    my ($pid, $fd, $ioctl) = @_;
    my $cmd = qq{p (int)ioctl($fd, $ioctl, &errno) ? -1 : errno};
    qx{exec 3>&1; gdb -batch -p $pid -ex '$cmd' 2>&1 >&3 |
            grep -v '/sysdeps/.*No such file or directory' >&2}
        =~ /^\$1 *= *(\d+)$/m ? $1 : undef;
}
_
7
mosvy

Linuxでは、devptsを使用すると、マスターデバイスファイルはありません。マスター側のプロセスは、ptmxを開くことで取得するファイル記述子を使用しますが、対応するデバイスノードはありません。

詳細については、 ptmxマンページ を参照してください。

(Linux上のBSDスタイルのptysでは、マスター側とスレーブ側にそれぞれ/dev/ptyp1/dev/ttyp1などの一致するデバイスペアがあります。)

4
Stephen Kitt