pidproxy.py 2.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. #!/usr/bin/env python
  2. ##############################################################################
  3. #
  4. # Copyright (c) 2007 Agendaless Consulting and Contributors.
  5. # All Rights Reserved.
  6. #
  7. # This software is subject to the provisions of the BSD-like license at
  8. # http://www.repoze.org/LICENSE.txt. A copy of the license should accompany
  9. # this distribution. THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL
  10. # EXPRESS OR IMPLIED WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO,
  11. # THE IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND
  12. # FITNESS FOR A PARTICULAR PURPOSE
  13. #
  14. ##############################################################################
  15. """ An executable which proxies for a subprocess; upon a signal, it sends that
  16. signal to the process identified by a pidfile. """
  17. import os
  18. import sys
  19. import signal
  20. import time
  21. class PidProxy:
  22. pid = None
  23. def __init__(self, args):
  24. self.setsignals()
  25. try:
  26. self.pidfile, cmdargs = args[1], args[2:]
  27. self.command = os.path.abspath(cmdargs[0])
  28. self.cmdargs = cmdargs
  29. except (ValueError, IndexError):
  30. self.usage()
  31. sys.exit(1)
  32. def go(self):
  33. self.pid = os.spawnv(os.P_NOWAIT, self.command, self.cmdargs)
  34. while 1:
  35. time.sleep(5)
  36. try:
  37. pid, sts = os.waitpid(-1, os.WNOHANG)
  38. except OSError:
  39. pid, sts = None, None
  40. if pid:
  41. break
  42. def usage(self):
  43. print "pidproxy.py <pidfile name> <command> [<cmdarg1> ...]"
  44. def setsignals(self):
  45. signal.signal(signal.SIGTERM, self.passtochild)
  46. signal.signal(signal.SIGHUP, self.passtochild)
  47. signal.signal(signal.SIGINT, self.passtochild)
  48. signal.signal(signal.SIGUSR1, self.passtochild)
  49. signal.signal(signal.SIGUSR2, self.passtochild)
  50. signal.signal(signal.SIGCHLD, self.reap)
  51. def reap(self, sig, frame):
  52. # do nothing, we reap our child synchronously
  53. pass
  54. def passtochild(self, sig, frame):
  55. try:
  56. pid = int(open(self.pidfile, 'r').read().strip())
  57. except:
  58. pid = None
  59. print "Can't read child pidfile %s!" % self.pidfile
  60. return
  61. os.kill(pid, sig)
  62. if sig in [signal.SIGTERM, signal.SIGINT, signal.SIGQUIT]:
  63. sys.exit(0)
  64. if __name__ == '__main__':
  65. pp = PidProxy(sys.argv)
  66. pp.go()