pidproxy.py 1.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
  1. #!/usr/bin/env python
  2. """ An executable which proxies for a subprocess; upon a signal, it sends that
  3. signal to the process identified by a pidfile. """
  4. import os
  5. import sys
  6. import signal
  7. import time
  8. class PidProxy:
  9. pid = None
  10. def __init__(self, args):
  11. self.setsignals()
  12. try:
  13. self.pidfile, cmdargs = args[1], args[2:]
  14. self.command = os.path.abspath(cmdargs[0])
  15. self.cmdargs = cmdargs
  16. except (ValueError, IndexError):
  17. self.usage()
  18. sys.exit(1)
  19. def go(self):
  20. self.pid = os.spawnv(os.P_NOWAIT, self.command, self.cmdargs)
  21. while 1:
  22. time.sleep(5)
  23. try:
  24. pid, sts = os.waitpid(-1, os.WNOHANG)
  25. except OSError:
  26. pid, sts = None, None
  27. if pid:
  28. break
  29. def usage(self):
  30. print "pidproxy.py <pidfile name> <command> [<cmdarg1> ...]"
  31. def setsignals(self):
  32. signal.signal(signal.SIGTERM, self.passtochild)
  33. signal.signal(signal.SIGHUP, self.passtochild)
  34. signal.signal(signal.SIGINT, self.passtochild)
  35. signal.signal(signal.SIGUSR1, self.passtochild)
  36. signal.signal(signal.SIGUSR2, self.passtochild)
  37. signal.signal(signal.SIGQUIT, self.passtochild)
  38. signal.signal(signal.SIGCHLD, self.reap)
  39. def reap(self, sig, frame):
  40. # do nothing, we reap our child synchronously
  41. pass
  42. def passtochild(self, sig, frame):
  43. try:
  44. pid = int(open(self.pidfile, 'r').read().strip())
  45. except:
  46. pid = None
  47. print "Can't read child pidfile %s!" % self.pidfile
  48. return
  49. os.kill(pid, sig)
  50. if sig in [signal.SIGTERM, signal.SIGINT, signal.SIGQUIT]:
  51. sys.exit(0)
  52. def main():
  53. pp = PidProxy(sys.argv)
  54. pp.go()
  55. if __name__ == '__main__':
  56. main()