1 |
Use subprocess.Popen to correctly configure the signal disposition |
2 |
of the child process, since os.fork leaves the signal disposition |
3 |
in a state which may be inappropriate for various signals including |
4 |
SIGPIPE, SIGQUIT, SIGTERM, and SIGINT. For python implementations |
5 |
other that CPython >= 3, use preexec_fn to manually configure the |
6 |
signal disposition (I have found that this is necessary for CPython |
7 |
2.7 and all PyPy versions tested, including PyPy3). |
8 |
|
9 |
Bug: https://bugs.gentoo.org/675828 |
10 |
Signed-off-by: Zac Medico <zmedico@g.o> |
11 |
--- |
12 |
bin/pid-ns-init | 31 ++++++++++++++++++++++++++++--- |
13 |
1 file changed, 28 insertions(+), 3 deletions(-) |
14 |
|
15 |
diff --git a/bin/pid-ns-init b/bin/pid-ns-init |
16 |
index 182d00a43..86029f983 100644 |
17 |
--- a/bin/pid-ns-init |
18 |
+++ b/bin/pid-ns-init |
19 |
@@ -2,18 +2,37 @@ |
20 |
# Copyright 2018-2019 Gentoo Authors |
21 |
# Distributed under the terms of the GNU General Public License v2 |
22 |
|
23 |
+import errno |
24 |
import functools |
25 |
import os |
26 |
+import platform |
27 |
import signal |
28 |
+import subprocess |
29 |
import sys |
30 |
|
31 |
|
32 |
+if sys.version_info.major < 3 or platform.python_implementation() != 'CPython': |
33 |
+ def signal_disposition_preexec(): |
34 |
+ for signum in ( |
35 |
+ signal.SIGHUP, |
36 |
+ signal.SIGINT, |
37 |
+ signal.SIGPIPE, |
38 |
+ signal.SIGQUIT, |
39 |
+ signal.SIGTERM, |
40 |
+ ): |
41 |
+ signal.signal(signum, signal.SIG_DFL) |
42 |
+else: |
43 |
+ # CPython >= 3 subprocess.Popen handles this internally. |
44 |
+ signal_disposition_preexec = None |
45 |
+ |
46 |
+ |
47 |
KILL_SIGNALS = ( |
48 |
signal.SIGINT, |
49 |
signal.SIGTERM, |
50 |
signal.SIGHUP, |
51 |
) |
52 |
|
53 |
+ |
54 |
def forward_kill_signal(main_child_pid, signum, frame): |
55 |
os.kill(main_child_pid, signum) |
56 |
|
57 |
@@ -28,14 +47,15 @@ def main(argv): |
58 |
# (forwarding signals to init and forwarding exit status to the parent |
59 |
# process). |
60 |
main_child_pid = int(argv[1]) |
61 |
+ proc = None |
62 |
else: |
63 |
# The current process is init (pid 1) in a child pid namespace. |
64 |
binary = argv[1] |
65 |
args = argv[2:] |
66 |
|
67 |
- main_child_pid = os.fork() |
68 |
- if main_child_pid == 0: |
69 |
- os.execv(binary, args) |
70 |
+ proc = subprocess.Popen(args, executable=binary, |
71 |
+ preexec_fn=signal_disposition_preexec) |
72 |
+ main_child_pid = proc.pid |
73 |
|
74 |
sig_handler = functools.partial(forward_kill_signal, main_child_pid) |
75 |
for signum in KILL_SIGNALS: |
76 |
@@ -50,6 +70,11 @@ def main(argv): |
77 |
continue |
78 |
raise |
79 |
if pid == main_child_pid: |
80 |
+ if proc is not None: |
81 |
+ # Suppress warning messages like this: |
82 |
+ # ResourceWarning: subprocess 1234 is still running |
83 |
+ proc.returncode = 0 |
84 |
+ |
85 |
if os.WIFEXITED(status): |
86 |
return os.WEXITSTATUS(status) |
87 |
elif os.WIFSIGNALED(status): |
88 |
-- |
89 |
2.18.1 |