daemonlib.py 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. # -*- coding: utf-8 -*-
  2. import sys, os, time, atexit
  3. from signal import SIGTERM
  4. class Daemon:
  5. """
  6. A generic daemon class.
  7. Usage: subclass the Daemon class and override the _run() method
  8. """
  9. def __init__(self, pidfile, stdin='/dev/null', stdout='/dev/null', stderr='/dev/null'):
  10. self.stdin = stdin
  11. self.stdout = stdout
  12. self.stderr = stderr
  13. self.pidfile = pidfile
  14. def _daemonize(self):
  15. """
  16. do the UNIX double-fork magic, see Stevens' "Advanced
  17. Programming in the UNIX Environment" for details (ISBN 0201563177)
  18. http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC16
  19. """
  20. #脱离父进程
  21. try:
  22. pid = os.fork()
  23. if pid > 0:
  24. sys.exit(0)
  25. except OSError, e:
  26. sys.stderr.write("fork #1 failed: %d (%s)\n" % (e.errno, e.strerror))
  27. sys.exit(1)
  28. #脱离终端
  29. os.setsid()
  30. #修改当前工作目录
  31. os.chdir("/")
  32. #重设文件创建权限
  33. os.umask(0)
  34. #第二次fork,禁止进程重新打开控制终端
  35. try:
  36. pid = os.fork()
  37. if pid > 0:
  38. sys.exit(0)
  39. except OSError, e:
  40. sys.stderr.write("fork #2 failed: %d (%s)\n" % (e.errno, e.strerror))
  41. sys.exit(1)
  42. sys.stdout.flush()
  43. sys.stderr.flush()
  44. si = file(self.stdin, 'r')
  45. so = file(self.stdout, 'a+')
  46. se = file(self.stderr, 'a+', 0)
  47. #重定向标准输入/输出/错误
  48. os.dup2(si.fileno(), sys.stdin.fileno())
  49. os.dup2(so.fileno(), sys.stdout.fileno())
  50. os.dup2(se.fileno(), sys.stderr.fileno())
  51. #注册程序退出时的函数,即删掉pid文件
  52. atexit.register(self.delpid)
  53. pid = str(os.getpid())
  54. file(self.pidfile,'w+').write("%s\n" % pid)
  55. def delpid(self):
  56. os.remove(self.pidfile)
  57. def start(self):
  58. """
  59. Start the daemon
  60. """
  61. # Check for a pidfile to see if the daemon already runs
  62. try:
  63. pf = file(self.pidfile,'r')
  64. pid = int(pf.read().strip())
  65. pf.close()
  66. except IOError:
  67. pid = None
  68. if pid:
  69. message = "pidfile %s already exist. Daemon already running?\n"
  70. sys.stderr.write(message % self.pidfile)
  71. sys.exit(1)
  72. # Start the daemon
  73. self._daemonize()
  74. self._run()
  75. def stop(self):
  76. """
  77. Stop the daemon
  78. """
  79. # Get the pid from the pidfile
  80. try:
  81. pf = file(self.pidfile,'r')
  82. pid = int(pf.read().strip())
  83. pf.close()
  84. except IOError:
  85. pid = None
  86. if not pid:
  87. message = "pidfile %s does not exist. Daemon not running?\n"
  88. sys.stderr.write(message % self.pidfile)
  89. return # not an error in a restart
  90. # Try killing the daemon process
  91. try:
  92. while 1:
  93. os.kill(pid, SIGTERM)
  94. time.sleep(0.1)
  95. except OSError, err:
  96. err = str(err)
  97. if err.find("No such process") > 0:
  98. if os.path.exists(self.pidfile):
  99. os.remove(self.pidfile)
  100. else:
  101. print str(err)
  102. sys.exit(1)
  103. def restart(self):
  104. """
  105. Restart the daemon
  106. """
  107. self.stop()
  108. self.start()
  109. def _run(self):
  110. """
  111. You should override this method when you subclass Daemon. It will be called after the process has been
  112. daemonized by start() or restart().
  113. """