commit 438d895c543e458b6f77288667a80de0f66e050a
parent caacc82941a0619c312e681fc9e99413090c1f43
Author: ccx <ccx@te2000.cz>
Date: Fri, 1 Mar 2024 06:08:57 +0000
Rename pidns_run, exit properly on parent disappearing.
Diffstat:
D | sbin/pidns_run | | | 76 | ---------------------------------------------------------------------------- |
A | sbin/pidns_run.py | | | 80 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
2 files changed, 80 insertions(+), 76 deletions(-)
diff --git a/sbin/pidns_run b/sbin/pidns_run
@@ -1,76 +0,0 @@
-#!/usr/bin/env python3
-import sys
-import os
-import os.path
-import ctypes
-import fcntl
-import select
-import errno
-
-libc = ctypes.CDLL(None, use_errno=True)
-CLONE_NEWPID = 0x20000000
-
-
-def nonblock_cloexec(fd):
- fcntl.fcntl(
- fd,
- fcntl.F_SETFD,
- fcntl.fcntl(fd, fcntl.F_GETFD) | os.O_NONBLOCK | fcntl.FD_CLOEXEC,
- )
-
-
-def exit_status(status):
- sig = status & 0xff
- ret = status >> 8
- if sig:
- raise SystemExit(128 + sig)
- if ret >= 128:
- raise SystemExit(128)
- raise SystemExit(ret)
-
-
-def main(argv):
- (parent_rfd, parent_wfd) = os.pipe()
- nonblock_cloexec(parent_rfd)
- nonblock_cloexec(parent_wfd)
- if libc.unshare(CLONE_NEWPID) != 0:
- raise OSError(ctypes.get_errno())
- fork_pid = os.fork()
- if fork_pid == 0:
- # child
- assert os.getpid() == 1
- os.close(parent_wfd)
- fork2_pid = os.fork()
- if fork2_pid == 0:
- # child
- if argv[1][0] == '/':
- os.execv(argv[1], argv[1:])
- for d in os.environ['PATH'].split(':'):
- try:
- os.execv(os.path.join(d, argv[1]), argv[1:])
- except FileNotFoundError:
- continue
- raise SystemExit(127)
- else:
- # parent
- rlist, wlist, elist = (parent_rfd,), (), ()
- while True:
- (pid, status) = os.waitpid(0, os.WNOHANG)
- if pid == fork2_pid:
- exit_status(status)
- try:
- r, w, x = select.select(rlist, wlist, elist, 1.0)
- except select.error as e:
- code, msg = e.args
- # We might get interrupted by SIGCHLD here
- if code != errno.EINTR:
- raise
- else:
- # parent
- os.close(parent_rfd)
- (pid, status) = os.waitpid(fork_pid, 0)
- exit_status(status)
-
-
-if __name__ == '__main__':
- main(sys.argv)
diff --git a/sbin/pidns_run.py b/sbin/pidns_run.py
@@ -0,0 +1,80 @@
+#!/usr/bin/env python3
+import sys
+import os
+import os.path
+import ctypes
+import fcntl
+import select
+import errno
+
+libc = ctypes.CDLL(None, use_errno=True)
+CLONE_NEWPID = 0x20000000
+
+
+def nonblock_cloexec(fd):
+ fcntl.fcntl(
+ fd,
+ fcntl.F_SETFD,
+ fcntl.fcntl(fd, fcntl.F_GETFD) | os.O_NONBLOCK | fcntl.FD_CLOEXEC,
+ )
+
+
+def exit_status(status):
+ sig = status & 0xff
+ ret = status >> 8
+ if sig:
+ raise SystemExit(128 + sig)
+ if ret >= 128:
+ raise SystemExit(128)
+ raise SystemExit(ret)
+
+
+def main(argv):
+ (parent_rfd, parent_wfd) = os.pipe()
+ nonblock_cloexec(parent_rfd)
+ nonblock_cloexec(parent_wfd)
+ if libc.unshare(CLONE_NEWPID) != 0:
+ raise OSError(ctypes.get_errno())
+ fork_pid = os.fork()
+ if fork_pid == 0:
+ # child
+ assert os.getpid() == 1
+ os.close(parent_wfd)
+ fork2_pid = os.fork()
+ if fork2_pid == 0:
+ # child
+ if argv[1][0] == '/':
+ os.execv(argv[1], argv[1:])
+ for d in os.environ['PATH'].split(':'):
+ try:
+ os.execv(os.path.join(d, argv[1]), argv[1:])
+ except FileNotFoundError:
+ continue
+ raise SystemExit(127)
+ else:
+ # parent
+ rlist, wlist, elist = (parent_rfd,), (), ()
+ while True:
+ (pid, status) = os.waitpid(0, os.WNOHANG)
+ if pid == fork2_pid:
+ exit_status(status)
+ try:
+ r, w, x = select.select(rlist, wlist, elist, 1.0)
+ except select.error as e:
+ code, msg = e.args
+ # We might get interrupted by SIGCHLD here
+ if code != errno.EINTR:
+ raise
+ if r:
+ sys.stderr.write('pidns_run: parent died, terminating\n')
+ raise SystemExit(111)
+
+ else:
+ # parent
+ os.close(parent_rfd)
+ (pid, status) = os.waitpid(fork_pid, 0)
+ exit_status(status)
+
+
+if __name__ == '__main__':
+ main(sys.argv)