의사 터미널에는 한 쌍의 마스터 장치와 슬레이브 장치가 있습니다.
슬레이브 장치 파일에서 마스터 장치 파일(예:)을 어떻게 찾나요 /etc/pts/3
? 나는 찾았 /dev/ptmx
지만 /dev/pts/ptmx
여러 노예가 공유할 수는 없습니다.
마스터와 슬레이브에서 실행되는 프로세스 중 하나가 주어지면 다른 프로세스를 어떻게 찾을 수 있습니까? 예를 들어, 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
두 sshd
프로세스(pid 975 및 978)가 마스터에 대한 핸들을 열었습니다(하나는 9 fd용이고 다른 하나는 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.txt
리눅스 커널 소스 코드에서.
이는 chroot 또는 네임스페이스 컨테이너를 사용하는 모든 시스템에서 실패합니다. 필드를 pty에 일치시키고 fd를 tty
적절한 mount로 여는 안정적인 방법이 없기 때문에 커널을 일부 변경하지 않으면 수정할 수 없습니다 . /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;
}
답변2
Linux에서는 를 사용하세요 devpts
. 마스터 장치 파일이 없습니다. 마스터 측 프로세스는 open 을 통해 얻은 파일 설명자를 사용 ptmx
하지만 해당 장치 노드가 없습니다.
바라보다ptmx
맨페이지더 알아보기.
(Linux의 BSD 버전의 경우 pty
마스터 측과 슬레이브 측 모두 /dev/ptyp1
및 와 같은 일치하는 장치 쌍을 갖습니다 /dev/ttyp1
.)
답변3
lsof +E
ptm/pts를 포함하여 FD의 양쪽 끝에 대한 정보를 제공하는 것 같습니다 .