相手の擬似端末マスターとスレーブをどのように知ることができますか?

相手の擬似端末マスターとスレーブをどのように知ることができますか?

擬似端末には、一対のマスター装置とスレーブ装置があります。

スレーブデバイスファイルでマスターデバイスファイル(例)をどのように検索しますか/etc/pts/3?私は見つけ/dev/ptmxましたが、/dev/pts/ptmxいくつかの奴隷が共有することはできません。

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

ありがとうございます。

ベストアンサー1

これは、やるべきことよりもやりにくいことです。

tty-index最新のLinuxカーネルでは、マスターとペアになっているスレーブptyのインデックスは次の項目から収集できます/proc/PID/fdinfo/FD。これを見て犯罪

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

[しかし、複数のdevptマウントを使用するシステムでは、両方の方法で問題が発生します。下記をご覧ください。]

この情報を使用してマスター - スレーブペアリングリストを構築し、スレーブデバイスでマスター検索を開始することもできます。

以下は、そのtty-index方法を最初に試してから動作しない場合gdb。後者の場合、布材 gdb(ほとんどのディストリビューションはそうではないか、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 fd用)。標準(0、1、2)fdでスレーブ側に開いたハンドルがありますsleep-bashセッションリーダー(bash)も*、前景プロセス(および)も表示され、バックグラウンドプロセス(およびperl)も表示されます。cut+less-bash-

これらのt/ct_testプロセスは、 fd が開かれていない状態で pty を制御端末として使用します。tiocsti開いたハンドルがありますが、制御端末ではありません。

Debian 9とFedora 28でテストされました。使用されるマジックナンバーに関する情報は以下にあります。procfs(5)そしてDocumentation/admin-guide/devices.txtLinuxカーネルのソースコードから。


これは、chrootまたは名前空間コンテナを使用するすべてのシステムで失敗します。フィールドをptyに一致させ、fdをtty適切なマウントで開く安定した方法がないため、カーネルを一部変更しないと変更できません。/proc/PID/statバラより/dev/ptmx/dev/ptsこここれについて豪言大胆です。

/dev/ttyまた、以下を介して開かれたfdには関連付けられません。本物ttyはプロセスに接続して呼び出すことで解決できますが、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;
}

おすすめ記事