프로세스에서 파일 설명자를 쓸 때 어떻게 파일 설명자를 열고 터미널에 에코합니까?
인수로 지정된 파일 설명자에 로그를 기록하는 백업 프로그램 Duplicity가 있습니다 --log-fd=16
.
물론, 실행하면 lsof -p <duplicity PID>
다음이 표시됩니다.
python2 9224 myuser 0r CHR 1,3 0t0 6 /dev/null
python2 9224 myuser 1w CHR 1,3 0t0 6 /dev/null
python2 9224 myuser 2w CHR 1,3 0t0 6 /dev/null
python2 9224 myuser 3u a_inode 0,11 0 7005 [eventfd]
python2 9224 myuser 4u unix 0x0000000000000000 0t0 158199 type=STREAM
python2 9224 myuser 5u a_inode 0,11 0 7005 [eventfd]
python2 9224 myuser 6u a_inode 0,11 0 7005 [eventfd]
python2 9224 myuser 7r DIR 8,3 4096 22414346 <some random file being accessed during the backup>
python2 9224 myuser 8r CHR 1,9 0t0 11 /dev/urandom
python2 9224 myuser 15r FIFO 0,10 0t0 157054 pipe
python2 9224 myuser 16w FIFO 0,10 0t0 157054 pipe
그러나 Python에서 파일 설명자를 열려고 하면 다음 오류가 발생합니다.
>>> import os
>>> os.fdopen(16)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
OSError: [Errno 9] Bad file descriptor
왜 이런거야? 파일 설명자를 읽는 방법은 무엇입니까?
답변1
사용법 strace
(시스템 호출 및 신호 추적)
용법:
sudo strace -p <PID of writing process> -s 9999 -e write=<corresponding FD>
매뉴얼 페이지에서:
-p pid Attach to the process with the process ID pid and begin tracing. The trace may be terminated
at any time by a keyboard interrupt signal (CTRL-C). strace will respond by detaching itself
from the traced process(es) leaving it (them) to continue running. Multiple -p options can
be used to attach to many processes in addition to command (which is optional if at least one
-p option is given). -p "`pidof PROG`" syntax is supported.
-s strsize Specify the maximum string size to print (the default is 32). Note that filenames are not
considered strings and are always printed in full.
-e read=set
Perform a full hexadecimal and ASCII dump of all the data read from file descriptors listed in the
specified set. For example, to see all input activity on file descriptors 3 and 5 use
-e read=3,5. Note that this is independent from the normal tracing of the read(2) system call
which is controlled by the option -e trace=read.
-e write=set
Perform a full hexadecimal and ASCII dump of all the data written to file descriptors listed in
the specified set. For example, to see all output activity on file descriptors 3 and 5 use
-e write=3,5. Note that this is independent from the normal tracing of the write(2) system call
which is controlled by the option -e trace=write.
답변2
이중성 옵션은 --log=fd
로그에서 분리하려는 복잡한 stderr
파이프라인 에 적합하다고 생각합니다 stdout
.
이 답변이 맞습니다이 문제예를 들어. 간단한 예는 다음과 같습니다.
#!/bin/sh
# Generate output on three different fds
echo hello >&3
echo world >&2
echo today >&1
이렇게 실행하면,
./foo 2> 2.log 3> 3.log 1> 1.log
밝혀지다
$ cat 1.log 2.log 3.log
today
world
hello
답변3
Linux는 최근 이런 종류의 시스템 호출을 얻었습니다.
사용
pidfd_open
PID에서 "PID FD"를 가져옵니다.사용
pidfd_getfd
다른 프로세스의 PID FD를 통해 파일 설명자를 가져옵니다.
Python 3.9부터 pidfd_open
다음과 같이 사용 가능os.pidfd_open
.
pidfd_getfd
아직 Python 표준 라이브러리를 통해 노출되지 않았지만 운 좋게도ctypes
전화하자syscall
, Linux 시스템 호출 번호는 절대 변경되지 않으며 Linux 시스템 호출 API 및 ABI는 이전 버전과 호환되는 방식으로만 변경됩니다.
그래서!
from ctypes import CDLL, c_int, c_long, c_uint, get_errno
from functools import partial
from os import strerror
_syscall = CDLL(None, use_errno=True).syscall
# Non-variadic system call number argument:
_syscall.argtypes = [c_long]
def pidfd_getfd(pidfd, targetfd):
fd = _syscall(
438, # system call number of pidfd_getfd
c_int(pidfd),
c_int(targetfd),
c_uint(0), # unused "flags" argument
)
if fd == -1:
errno = get_errno()
raise OSError(errno, strerror(errno))
return fd
따라서 귀하의 예에서 관심 있는 PID는 9224이고 os.fdopen(16)
호출하지 않고 실행합니다 os.fdopen(pidfd_getfd(os.pidfd_open(9224), 16))
.
sudo
이는 대상 프로세스에 액세스하는 데 필요한 권한이 있는 경우에만 작동하므로 프로세스가 시작된 방법 및 시스템 구성 방법에 따라 상승된 권한(예:)으로 이 코드를 실행 해야 할 수도 있습니다 .