mrrl-containers

MRRL version of container scripts
git clone https://ccx.te2000.cz/git/mrrl-containers
Log | Files | Refs

pidns_run.py (2149B)


      1 #!/usr/bin/env python3
      2 import sys
      3 import os
      4 import os.path
      5 import ctypes
      6 import fcntl
      7 import select
      8 import errno
      9 
     10 libc = ctypes.CDLL(None, use_errno=True)
     11 CLONE_NEWPID = 0x20000000
     12 
     13 
     14 def nonblock_cloexec(fd):
     15     fcntl.fcntl(
     16         fd,
     17         fcntl.F_SETFD,
     18         fcntl.fcntl(fd, fcntl.F_GETFD) | os.O_NONBLOCK | fcntl.FD_CLOEXEC,
     19     )
     20 
     21 
     22 def exit_status(status):
     23     sig = status & 0xff
     24     ret = status >> 8
     25     if sig:
     26         raise SystemExit(128 + sig)
     27     if ret >= 128:
     28         raise SystemExit(128)
     29     raise SystemExit(ret)
     30 
     31 
     32 def main(argv):
     33     (parent_rfd, parent_wfd) = os.pipe()
     34     nonblock_cloexec(parent_rfd)
     35     nonblock_cloexec(parent_wfd)
     36     if libc.unshare(CLONE_NEWPID) != 0:
     37         raise OSError(ctypes.get_errno())
     38     fork_pid = os.fork()
     39     if fork_pid == 0:
     40         # child
     41         assert os.getpid() == 1
     42         os.close(parent_wfd)
     43         fork2_pid = os.fork()
     44         if fork2_pid == 0:
     45             # child
     46             if argv[1][0] == '/':
     47                 os.execv(argv[1], argv[1:])
     48             for d in os.environ['PATH'].split(':'):
     49                 try:
     50                     os.execv(os.path.join(d, argv[1]), argv[1:])
     51                 except FileNotFoundError:
     52                     continue
     53             raise SystemExit(127)
     54         else:
     55             # parent
     56             rlist, wlist, elist = (parent_rfd,), (), ()
     57             while True:
     58                 (pid, status) = os.waitpid(0, os.WNOHANG)
     59                 if pid == fork2_pid:
     60                     exit_status(status)
     61                 try:
     62                     r, w, x = select.select(rlist, wlist, elist, 1.0)
     63                 except select.error as e:
     64                     code, msg = e.args
     65                     # We might get interrupted by SIGCHLD here
     66                     if code != errno.EINTR:
     67                         raise
     68                 if r:
     69                     sys.stderr.write('pidns_run: parent died, terminating\n')
     70                     raise SystemExit(111)
     71 
     72     else:
     73         # parent
     74         os.close(parent_rfd)
     75         (pid, status) = os.waitpid(fork_pid, 0)
     76         exit_status(status)
     77 
     78 
     79 if __name__ == '__main__':
     80     main(sys.argv)