mirror of
https://github.com/AdaCore/git-hooks.git
synced 2026-02-12 12:43:11 -08:00
Now that Python 3.x is required, this import is no longer useful. Note that this commit deliberately excludes the imports done in the testsuite, so as to allow these changes to be reviewed independently of the changes to be made in the testsuite. Change-Id: I28e1857df2cf0b2f9e7ddeab00b456d6ef513755 TN: U530-006
97 lines
2.7 KiB
Python
97 lines
2.7 KiB
Python
"""A module to handle daemonization...
|
|
"""
|
|
|
|
import os
|
|
import sys
|
|
from syslog import syslog
|
|
|
|
|
|
def daemonize(output_fd=None):
|
|
"""Create a daemon process.
|
|
|
|
PARAMETERS
|
|
output_fd: If not none, a file descriptor where stdout and
|
|
stderr should be redirected.
|
|
|
|
RETURN VALUE
|
|
This function returns True for the child (daemon) process,
|
|
while it returns False for the parent process.
|
|
"""
|
|
# Flush the output a first time to make sure the child processes
|
|
# do not inherit some buffered output from the parent, causing
|
|
# some output generated by the parent to be printed multiple times
|
|
# due to both parent and child printing it at flush time.
|
|
for f in sys.stdout, sys.stderr:
|
|
f.flush()
|
|
|
|
# Perform the first fork.
|
|
try:
|
|
pid = os.fork()
|
|
if pid > 0:
|
|
# In the parent. We can now return.
|
|
return False
|
|
except OSError as e:
|
|
sys.stderr.write("fork #1 failed: (%d) %s\n" % (e.errno, e.strerror))
|
|
return False
|
|
|
|
# Decouple ourselves from the parent environment.
|
|
os.chdir("/")
|
|
os.umask(0)
|
|
os.setsid()
|
|
|
|
# Perform the second fork, to daemonize ourselves.
|
|
try:
|
|
pid = os.fork()
|
|
if pid > 0:
|
|
# In the second parent. Exit.
|
|
sys.exit(0)
|
|
except OSError as e: # pragma: no cover (really hard to cover -- see U627-007)
|
|
syslog("git-hooks: fork #2 failed: (%d) %s" % (e.errno, e.strerror))
|
|
sys.exit(1)
|
|
|
|
# Flush the output...
|
|
for f in sys.stdout, sys.stderr:
|
|
f.flush()
|
|
|
|
# Perform the input/output redirection.
|
|
|
|
os.close(0)
|
|
os.dup2(os.open("/dev/null", os.O_RDONLY), 0)
|
|
|
|
if output_fd is None: # pragma: no cover (never true in testsuite mode)
|
|
output_fd = os.open("/dev/null", os.O_WRONLY)
|
|
os.close(1)
|
|
os.dup2(output_fd, 1)
|
|
os.close(2)
|
|
os.dup2(output_fd, 2)
|
|
|
|
return True
|
|
|
|
|
|
def run_in_daemon(fun):
|
|
"""Run the given callbable in a daemon process.
|
|
|
|
In GIT_HOOKS_TESTSUITE_MODE, the function's stdout and stderr
|
|
is redirected to a pipe and then re-printed on our stdout.
|
|
But this is only for testing purposes. In normal mode,
|
|
the function's stdout/stderr, as well as stdin are redirected
|
|
to /dev/null.
|
|
|
|
PARAMETERS
|
|
fun: A callable.
|
|
"""
|
|
daemon_pipe = (None, None)
|
|
if "GIT_HOOKS_TESTSUITE_MODE" in os.environ:
|
|
daemon_pipe = os.pipe()
|
|
|
|
in_daemon = daemonize(daemon_pipe[1])
|
|
if in_daemon:
|
|
fun()
|
|
sys.exit(0)
|
|
else:
|
|
if daemon_pipe[0] is not None:
|
|
os.close(daemon_pipe[1])
|
|
daemon_stdout = os.fdopen(daemon_pipe[0])
|
|
print(daemon_stdout.read(), file=sys.stderr, end="")
|
|
daemon_stdout.close()
|