【发布时间】:2021-05-12 12:00:42
【问题描述】:
我有一个脚本正在做一些事情,例如自动化测试。由于未知原因,它被 SIGTERM 信号(接缝地)随机终止 - 目标是尝试识别谁在发送信号 - 发送者的 PID。
我尝试过使用signal 库,但它似乎没有提供关于发送者的足够信息,如果使用像signal.signal(signal.SIGTERM, some_handler) 这样的处理程序设置 - 处理程序只传递信号号(15在这种情况下)和当前堆栈,这没有帮助。
我还尝试使用ctypes 并创建一个处理程序(基于对this 的回答),经过一些更改后,我设法让处理程序接受siginfo_t - 但siginfo_t.contents.si_pid 和siginfo_t.contents.si_code 的值对我来说没有意义,因为它们不像发件人的 PID,而且代码不是 15。
我使用的代码如下:
#!/usr/bin/env python3
import sys
import os
import time
from ctypes import Structure, Union, POINTER, CFUNCTYPE, CDLL, byref, sizeof, \
c_short, c_int, c_uint, c_long, c_ulong, c_char_p, c_void_p
SIGTERM = 15
SA_SIGINFO = 4
class sigset_t(Structure):
_fields_ = [
("__val", c_ulong * (1024 // (8 * sizeof (c_long)))),
]
class sigval_t(Union):
_fields_ = [
("sival_int", c_int),
("sival_ptr", c_void_p),
]
class siginfo_t(Structure):
_fields_ = [
("si_signo", c_int),
("si_errno", c_int),
("si_code", c_int),
("_pad", c_int * 29),
("si_pid", c_uint)
]
sa_sigaction_functype = CFUNCTYPE(None, c_int, POINTER(siginfo_t), c_void_p)
sa_handler_functype = CFUNCTYPE(None, c_int, use_errno=True)
class SIGACTION(Structure):
_fields_ = [
# ("sa_handler", sa_handler_functype),
("sa_sigaction", sa_sigaction_functype),
# ("sa_mask", sigset_t),
("sa_mask", siginfo_t),
("sa_flags", c_int),
("sa_restorer", c_void_p),
]
libc = CDLL(None)
def sighandler(sig, siginfo_t, something): # Signal handler function
libc.puts.argtypes = [c_char_p]
libc.puts.restype = c_int
libc.puts("Custom signal handler called for signal {0:d}".format(sig).encode())
# print(str(siginfo_t.contents))
print("Sender PID: " + str(siginfo_t.contents.si_pid))
print("Signal Number: " + str(siginfo_t.contents.si_signo))
def main(*argv):
libc.sigaction.argtypes = [c_int, POINTER(SIGACTION), POINTER(SIGACTION)]
libc.sigaction.restype = c_int
signal_number = SIGTERM
act = SIGACTION(
# sa_handler=sa_handler_functype(sighandler),
sa_sigaction=sa_sigaction_functype(sighandler),
sa_flag=SA_SIGINFO)
res = libc.sigaction(signal_number, byref(act), None)
print("sigaction result: {0:d}".format(res))
print("PId {0:d} waiting for SIG {1:d}...".format(os.getpid(), signal_number))
while 1:
time.sleep(0.1)
if __name__ == "__main__":
main(*sys.argv[1:])
print("\nDone.")
以及我在调用处理程序时得到的值(信号由 PID 14783 的进程发送):
siginfo_t.contents
si_code: 11340640
si_errno: 1
si_pid: 2
si_signo: 1
这是我第一次使用 ctypes 和一般的 C(因此,代码可能没有太大意义),所以任何帮助澄清我为什么会得到无效值以及如何修复它,我将不胜感激,谢谢.
Python 3.8,在 Ubuntu 18.04.5 LTS 上测试
【问题讨论】:
-
您的结构不符合,例如man7.org/linux/man-pages/man2/sigaction.2.html。
si_pid在该手册页上的字节偏移量为 16(假设为 32 位 int),但您的偏移量为 128。