월별 글 목록: 2021년 7월월

의사 터미널 장치의 다른 쪽 끝에 누가 있는지 어떻게 알 수 있습니까? : echo foo > /dev/pts/12 일부 프로세스는 foo\n파일 디스크립터에서

내가하면 :

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)"

lsof해당 매핑을 빌드하기 위해 반환 된 각 pid / fd에 대해 해당 정보를 얻는 더 직접적이고 신뢰할 수 있으며 덜 침입적인 방법이 있습니까?



답변

처음에는 내가 찾은 정보를 기반으로 몇 가지 xtermxtermpid 로 추적하려고 시도했지만 /proc/locks느슨했습니다. 나는 그것이 효과가 있다고 생각하지만 그것은 최선의 상황이었다. 나는 파일이 제공하는 모든 정보를 완전히 이해하지 못하고 그 내용과 알려진 터미널 프로세스 사이에 일치하는 것처럼 일치하는 것만 일치했다.

그런 다음 ptys 사이 lsof/strace의 활성 write/talk프로세스를 보았습니다 . 나는 실제로 이전에 어느 프로그램도 사용하지 않았지만 그들은 의지하는 것 같습니다 utmp. 내 대상 pty utmp에 어떤 이유로 든 항목 이 없으면 둘 다 존재한다고 인정하기를 거부했습니다. 어쩌면 그 주위에 방법이있을 수 있지만 그것을 버릴만큼 혼란 스러웠습니다.

나는 약간의 노력 udevadm에 대한 광고로 136 개 128 주 번호 장치 노드 발견을 pts하고 ptm각각에 /proc/tty/drivers, 그러나 나는 또한 도구로 어떤 매우 유용한 경험이 부족하고 다시 상당한 아무것도를 설정합니다. 그러나 흥미롭게도 :min두 장치 유형 의 범위가 엄청나게 높았습니다 0-1048575.

이 커널 문서 를 다시 방문하기 전까지 는 문제에 대해 생각하기 시작했습니다 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 \0null 바이트를 인쇄 하고 이전 검사와 비교하여 각 마스터 프로세스의 io를 검사합니다. 차이가 있으면 $$pid를 pty와 연관시킵니다. 이것은 대부분 작동합니다. 내 말은, 그것은 다음을 반환합니다.

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

어느 것이 맞지만, 분명히 약간의 정확성입니다. 그 당시 다른 사람들 중 한 명이 많은 데이터를 읽었다면 아마도 그리워했을 것입니다. stty스톱 비트를 먼저 보내거나 그와 비슷한 것을 보내기 위해 다른 pty에서 모드 를 변경하는 방법을 알아 내려고 노력 중 입니다.


답변

연결을 소유 한 사람과 연결 위치를 찾는 경우 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


답변

나는 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()


답변