1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
|
import subprocess
import os
import time
import sys
import errno
import signal
import traceback
from plumbum.commands.processes import ProcessExecutionError
def posix_daemonize(command, cwd):
MAX_SIZE = 16384
rfd, wfd = os.pipe()
argv = command.formulate()
firstpid = os.fork()
if firstpid == 0:
# first child: become session leader,
os.close(rfd)
rc = 0
try:
os.setsid()
os.umask(0)
stdin = open(os.devnull, "r")
stdout = open(os.devnull, "w")
stderr = open(os.devnull, "w")
signal.signal(signal.SIGHUP, signal.SIG_IGN)
proc = command.popen(cwd = cwd, close_fds = True, stdin = stdin.fileno(),
stdout = stdout.fileno(), stderr = stderr.fileno())
os.write(wfd, str(proc.pid).encode("utf8"))
except:
rc = 1
tbtext = "".join(traceback.format_exception(*sys.exc_info()))[-MAX_SIZE:]
os.write(wfd, tbtext.encode("utf8"))
finally:
os.close(wfd)
os._exit(rc)
else:
# wait for first child to die
os.close(wfd)
_, rc = os.waitpid(firstpid, 0)
output = os.read(rfd, MAX_SIZE)
try:
output = output.decode("utf8")
except UnicodeError:
pass
if rc == 0 and output.isdigit():
secondpid = int(output)
else:
raise ProcessExecutionError(argv, rc, "", output)
proc = subprocess.Popen.__new__(subprocess.Popen)
proc._child_created = True
proc.returncode = None
proc.stdout = None
proc.stdin = None
proc.stderr = None
proc.pid = secondpid
proc.universal_newlines = False
proc._input = None
proc._communication_started = False
proc.args = argv
proc.argv = argv
def poll(self = proc):
if self.returncode is None:
try:
os.kill(self.pid, 0)
except OSError:
ex = sys.exc_info()[1]
if ex.errno == errno.ESRCH:
# process does not exist
self.returncode = 0
else:
raise
return self.returncode
def wait(self = proc):
while self.returncode is None:
if self.poll() is None:
time.sleep(0.5)
return proc.returncode
proc.poll = poll
proc.wait = wait
return proc
def win32_daemonize(command, cwd):
DETACHED_PROCESS = 0x00000008
stdin = open(os.devnull, "r")
stdout = open(os.devnull, "w")
stderr = open(os.devnull, "w")
return command.popen(cwd = cwd, stdin = stdin.fileno(), stdout = stdout.fileno(), stderr = stderr.fileno(),
creationflags = subprocess.CREATE_NEW_PROCESS_GROUP | DETACHED_PROCESS)
|