aboutsummaryrefslogtreecommitdiff
path: root/tests/integration/pdeathsig.py
blob: d4a25ac70512f4312d1ef82088430cbc12664f03 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#!/usr/bin/env python3
"""Exec a command with PR_SET_PDEATHSIG — receive a signal when parent dies.

Usage: pdeathsig.py SIGNAL COMMAND [ARGS...]

Fallback for systems without `setpriv --pdeathsig`.
"""
import ctypes
import ctypes.util
import os
import signal
import sys

PR_SET_PDEATHSIG = 1

SIGNALS = {
    "TERM": signal.SIGTERM, "SIGTERM": signal.SIGTERM,
    "INT": signal.SIGINT, "SIGINT": signal.SIGINT,
    "HUP": signal.SIGHUP, "SIGHUP": signal.SIGHUP,
    "KILL": signal.SIGKILL, "SIGKILL": signal.SIGKILL,
}

def main() -> int:
    if len(sys.argv) < 3:
        print(f"usage: {sys.argv[0]} SIGNAL COMMAND [ARGS...]", file=sys.stderr)
        return 2
    sig_name = sys.argv[1]
    argv = sys.argv[2:]
    if sig_name not in SIGNALS:
        print(f"unknown signal: {sig_name}", file=sys.stderr)
        return 2
    sig = SIGNALS[sig_name]
    libc = ctypes.CDLL(ctypes.util.find_library("c") or "libc.so.6", use_errno=True)
    if libc.prctl(PR_SET_PDEATHSIG, sig, 0, 0, 0) != 0:
        err = ctypes.get_errno()
        raise OSError(err, os.strerror(err))
    # Race fix: parent may have died before prctl took effect
    if os.getppid() == 1:
        os.kill(os.getpid(), sig)
    os.execvp(argv[0], argv)
    return 127

if __name__ == "__main__":
    raise SystemExit(main())