#!/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/bin/runsvdir", "/usr/bin/runsvdir", "-P", "/etc/service", "log: %s" % ('.' * 395)) 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()