daemon.py 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. #!/usr/bin/env python3
  2. # This script is licensed under CC BY-SA
  3. # Source: http://www.jejik.com/articles/2007/02/a_simple_unix_linux_daemon_in_python/
  4. import sys, os, time, atexit, signal
  5. class Daemon:
  6. """A generic daemon class.
  7. Usage: subclass the daemon class and override the run() method."""
  8. def __init__(self, pidfile): self.pidfile = pidfile
  9. def daemonize(self):
  10. """Deamonize class. UNIX double fork mechanism."""
  11. try:
  12. pid = os.fork()
  13. if pid > 0:
  14. # exit first parent
  15. sys.exit(0)
  16. except OSError as err:
  17. sys.stderr.write('fork #1 failed: {0}\n'.format(err))
  18. sys.exit(1)
  19. # decouple from parent environment
  20. os.chdir('/')
  21. os.setsid()
  22. os.umask(0)
  23. # do second fork
  24. try:
  25. pid = os.fork()
  26. if pid > 0:
  27. # exit from second parent
  28. sys.exit(0)
  29. except OSError as err:
  30. sys.stderr.write('fork #2 failed: {0}\n'.format(err))
  31. sys.exit(1)
  32. # redirect standard file descriptors
  33. sys.stdout.flush()
  34. sys.stderr.flush()
  35. si = open(os.devnull, 'r')
  36. so = open(os.devnull, 'a+')
  37. se = open(os.devnull, 'a+')
  38. os.dup2(si.fileno(), sys.stdin.fileno())
  39. os.dup2(so.fileno(), sys.stdout.fileno())
  40. os.dup2(se.fileno(), sys.stderr.fileno())
  41. # write pidfile
  42. atexit.register(self.delpid)
  43. pid = str(os.getpid())
  44. with open(self.pidfile,'w+') as f:
  45. f.write(pid + '\n')
  46. def delpid(self):
  47. os.remove(self.pidfile)
  48. def start(self):
  49. """Start the daemon."""
  50. # Check for a pidfile to see if the daemon already runs
  51. try:
  52. with open(self.pidfile,'r') as pf:
  53. pid = int(pf.read().strip())
  54. except IOError:
  55. pid = None
  56. if pid:
  57. message = "pidfile {0} already exist. " + \
  58. "Daemon already running?\n"
  59. sys.stderr.write(message.format(self.pidfile))
  60. sys.exit(1)
  61. # Start the daemon
  62. self.daemonize()
  63. self.run()
  64. def stop(self):
  65. """Stop the daemon."""
  66. # Get the pid from the pidfile
  67. try:
  68. with open(self.pidfile,'r') as pf:
  69. pid = int(pf.read().strip())
  70. except IOError:
  71. pid = None
  72. if not pid:
  73. message = "pidfile {0} does not exist. " + \
  74. "Daemon not running?\n"
  75. sys.stderr.write(message.format(self.pidfile))
  76. return # not an error in a restart
  77. # Try killing the daemon process
  78. try:
  79. while 1:
  80. os.kill(pid, signal.SIGTERM)
  81. time.sleep(0.1)
  82. except OSError as err:
  83. e = str(err.args)
  84. if e.find("No such process") > 0:
  85. if os.path.exists(self.pidfile):
  86. os.remove(self.pidfile)
  87. else:
  88. print (str(err.args))
  89. sys.exit(1)
  90. def restart(self):
  91. """Restart the daemon."""
  92. self.stop()
  93. self.start()
  94. def run(self):
  95. """hello"""