43 lines
1.2 KiB
Python
43 lines
1.2 KiB
Python
###############################################################################
|
|
# Launch a subprocess using forkexec and make sure only the needed fd are
|
|
# shared in the two process.
|
|
#
|
|
# author: Thomas Moreau and Olivier Grisel
|
|
#
|
|
import os
|
|
import sys
|
|
|
|
|
|
def close_fds(keep_fds): # pragma: no cover
|
|
"""Close all the file descriptors except those in keep_fds."""
|
|
|
|
# Make sure to keep stdout and stderr open for logging purpose
|
|
keep_fds = {*keep_fds, 1, 2}
|
|
|
|
# We try to retrieve all the open fds
|
|
try:
|
|
open_fds = {int(fd) for fd in os.listdir('/proc/self/fd')}
|
|
except FileNotFoundError:
|
|
import resource
|
|
max_nfds = resource.getrlimit(resource.RLIMIT_NOFILE)[0]
|
|
open_fds = {*range(max_nfds)}
|
|
|
|
for i in open_fds - keep_fds:
|
|
try:
|
|
os.close(i)
|
|
except OSError:
|
|
pass
|
|
|
|
|
|
def fork_exec(cmd, keep_fds, env=None):
|
|
# copy the environment variables to set in the child process
|
|
env = env or {}
|
|
child_env = {**os.environ, **env}
|
|
|
|
pid = os.fork()
|
|
if pid == 0: # pragma: no cover
|
|
close_fds(keep_fds)
|
|
os.execve(sys.executable, cmd, child_env)
|
|
else:
|
|
return pid
|