mirror of
/repos/baseimage-docker.git
synced 2025-12-30 08:01:31 +01:00
117 lines
2.9 KiB
Python
Executable File
117 lines
2.9 KiB
Python
Executable File
#!/usr/bin/python2
|
|
import os, sys, stat, signal, errno
|
|
|
|
pid = None
|
|
status = None
|
|
|
|
def listdir(path):
|
|
try:
|
|
result = os.stat(path)
|
|
except OSError:
|
|
return []
|
|
if stat.S_ISDIR(result.st_mode):
|
|
return sorted(os.listdir(path))
|
|
else:
|
|
return []
|
|
|
|
def is_exe(path):
|
|
try:
|
|
return os.path.isfile(path) and os.access(path, os.X_OK)
|
|
except OSError:
|
|
return False
|
|
|
|
def reap_child(signum, frame):
|
|
global pid, status, waiting_for_runit
|
|
try:
|
|
result = os.wait3(os.WNOHANG)
|
|
if result is not None and pid == result[0]:
|
|
status = result[1]
|
|
except OSError:
|
|
pass
|
|
|
|
def stop_child_process(name):
|
|
global pid
|
|
print("*** Shutting down %s (PID %d)..." % (name, pid))
|
|
try:
|
|
os.kill(pid, signal.SIGHUP)
|
|
except OSError:
|
|
pass
|
|
|
|
def run_command_killable(*argv):
|
|
global pid
|
|
filename = argv[0]
|
|
pid = os.spawnvp(os.P_NOWAIT, filename, argv)
|
|
signal.signal(signal.SIGINT, lambda signum, frame: stop_child_process(filename))
|
|
signal.signal(signal.SIGTERM, lambda signum, frame: stop_child_process(filename))
|
|
try:
|
|
this_pid, status = os.waitpid(pid, 0)
|
|
except OSError as e:
|
|
if e.errno == errno.EINTR:
|
|
sys.exit(2)
|
|
else:
|
|
raise
|
|
finally:
|
|
signal.signal(signal.SIGINT, signal.SIG_DFL)
|
|
signal.signal(signal.SIGTERM, signal.SIG_DFL)
|
|
if status != 0:
|
|
sys.stderr.write("*** %s failed with exit code %d\n" % (filename, status))
|
|
sys.exit(1)
|
|
|
|
# Run /etc/my_init.d/*
|
|
for name in listdir("/etc/my_init.d"):
|
|
filename = "/etc/my_init.d/" + name
|
|
if is_exe(filename):
|
|
print("*** Running %s..." % filename)
|
|
run_command_killable(filename)
|
|
|
|
# Run /etc/rc.local.
|
|
if is_exe("/etc/rc.local"):
|
|
print("*** Running /etc/rc.local...")
|
|
run_command_killable("/etc/rc.local")
|
|
|
|
# Start runit.
|
|
signal.signal(signal.SIGCHLD, reap_child)
|
|
print("*** Booting runit...")
|
|
pid = os.spawnl(os.P_NOWAIT, "/usr/sbin/runsvdir-start", "/usr/sbin/runsvdir-start")
|
|
print("*** Runit started as PID %d" % pid)
|
|
signal.signal(signal.SIGTERM, lambda signum, frame: stop_child_process("runit"))
|
|
|
|
# Wait for runit, and while waiting, reap any adopted orphans.
|
|
done = False
|
|
while not done:
|
|
try:
|
|
this_pid, status = os.waitpid(pid, 0)
|
|
done = True
|
|
except OSError as e:
|
|
if e.errno == errno.EINTR:
|
|
# Try again
|
|
pass
|
|
else:
|
|
# The SIGCHLD handler probably caught it.
|
|
done = True
|
|
|
|
# Runit has exited. Reset signal handlers.
|
|
print("*** Runit exited with code %s. Waiting for all services to shut down..." % status)
|
|
signal.signal(signal.SIGCHLD, signal.SIG_DFL)
|
|
signal.signal(signal.SIGTERM, signal.SIG_DFL)
|
|
signal.siginterrupt(signal.SIGCHLD, False)
|
|
signal.siginterrupt(signal.SIGTERM, False)
|
|
|
|
# Wait at most 5 seconds for services to shut down.
|
|
import time
|
|
|
|
def shutdown(signum = None, frame = None):
|
|
global status
|
|
if status is not None:
|
|
sys.exit(status)
|
|
|
|
signal.signal(signal.SIGALRM, shutdown)
|
|
signal.alarm(5)
|
|
done = False
|
|
while not done:
|
|
done = os.system("/usr/bin/sv status /etc/service/* | grep -q '^run:'") != 0
|
|
if not done:
|
|
time.sleep(0.5)
|
|
shutdown()
|
|
|