aboutsummaryrefslogtreecommitdiff
path: root/tests/integration/pdeathsig.py
diff options
context:
space:
mode:
Diffstat (limited to 'tests/integration/pdeathsig.py')
-rwxr-xr-xtests/integration/pdeathsig.py44
1 files changed, 44 insertions, 0 deletions
diff --git a/tests/integration/pdeathsig.py b/tests/integration/pdeathsig.py
new file mode 100755
index 00000000..d4a25ac7
--- /dev/null
+++ b/tests/integration/pdeathsig.py
@@ -0,0 +1,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())