Home | History | Annotate | Download | only in server
      1 #!/usr/bin/env python
      2 
      3 # This code has been written by Sander Marechal and published at:
      4 # http://www.jejik.com/articles/2007/02/a_simple_unix_linux_daemon_in_python/
      5 # where the author has placed it in the public domain (see comment #6 at
      6 # http://www.jejik.com/articles/2007/02/a_simple_unix_linux_daemon_in_python/#c6
      7 # ).
      8 # Some minor modifications have been made by the V8 authors. The work remains
      9 # in the public domain.
     10 
     11 import atexit
     12 import os
     13 from signal import SIGTERM
     14 from signal import SIGINT
     15 import sys
     16 import time
     17 
     18 
     19 class Daemon(object):
     20   """
     21   A generic daemon class.
     22 
     23   Usage: subclass the Daemon class and override the run() method
     24   """
     25   def __init__(self, pidfile, stdin='/dev/null',
     26                stdout='/dev/null', stderr='/dev/null'):
     27     self.stdin = stdin
     28     self.stdout = stdout
     29     self.stderr = stderr
     30     self.pidfile = pidfile
     31 
     32   def daemonize(self):
     33     """
     34     do the UNIX double-fork magic, see Stevens' "Advanced
     35     Programming in the UNIX Environment" for details (ISBN 0201563177)
     36     http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC16
     37     """
     38     try:
     39       pid = os.fork()
     40       if pid > 0:
     41         # exit first parent
     42         sys.exit(0)
     43     except OSError, e:
     44       sys.stderr.write("fork #1 failed: %d (%s)\n" % (e.errno, e.strerror))
     45       sys.exit(1)
     46 
     47     # decouple from parent environment
     48     os.chdir("/")
     49     os.setsid()
     50     os.umask(0)
     51 
     52     # do second fork
     53     try:
     54       pid = os.fork()
     55       if pid > 0:
     56         # exit from second parent
     57         sys.exit(0)
     58     except OSError, e:
     59       sys.stderr.write("fork #2 failed: %d (%s)\n" % (e.errno, e.strerror))
     60       sys.exit(1)
     61 
     62     # redirect standard file descriptors
     63     sys.stdout.flush()
     64     sys.stderr.flush()
     65     si = file(self.stdin, 'r')
     66     so = file(self.stdout, 'a+')
     67     se = file(self.stderr, 'a+', 0)
     68     # TODO: (debug) re-enable this!
     69     #os.dup2(si.fileno(), sys.stdin.fileno())
     70     #os.dup2(so.fileno(), sys.stdout.fileno())
     71     #os.dup2(se.fileno(), sys.stderr.fileno())
     72 
     73     # write pidfile
     74     atexit.register(self.delpid)
     75     pid = str(os.getpid())
     76     file(self.pidfile, 'w+').write("%s\n" % pid)
     77 
     78   def delpid(self):
     79     os.remove(self.pidfile)
     80 
     81   def start(self):
     82     """
     83     Start the daemon
     84     """
     85     # Check for a pidfile to see if the daemon already runs
     86     try:
     87       pf = file(self.pidfile, 'r')
     88       pid = int(pf.read().strip())
     89       pf.close()
     90     except IOError:
     91       pid = None
     92 
     93     if pid:
     94       message = "pidfile %s already exist. Daemon already running?\n"
     95       sys.stderr.write(message % self.pidfile)
     96       sys.exit(1)
     97 
     98     # Start the daemon
     99     self.daemonize()
    100     self.run()
    101 
    102   def stop(self):
    103     """
    104     Stop the daemon
    105     """
    106     # Get the pid from the pidfile
    107     try:
    108       pf = file(self.pidfile, 'r')
    109       pid = int(pf.read().strip())
    110       pf.close()
    111     except IOError:
    112       pid = None
    113 
    114     if not pid:
    115       message = "pidfile %s does not exist. Daemon not running?\n"
    116       sys.stderr.write(message % self.pidfile)
    117       return # not an error in a restart
    118 
    119     # Try killing the daemon process
    120     try:
    121       # Give the process a one-second chance to exit gracefully.
    122       os.kill(pid, SIGINT)
    123       time.sleep(1)
    124       while 1:
    125         os.kill(pid, SIGTERM)
    126         time.sleep(0.1)
    127     except OSError, err:
    128       err = str(err)
    129       if err.find("No such process") > 0:
    130         if os.path.exists(self.pidfile):
    131           os.remove(self.pidfile)
    132       else:
    133         print str(err)
    134         sys.exit(1)
    135 
    136   def restart(self):
    137     """
    138     Restart the daemon
    139     """
    140     self.stop()
    141     self.start()
    142 
    143   def run(self):
    144     """
    145     You should override this method when you subclass Daemon. It will be
    146     called after the process has been daemonized by start() or restart().
    147     """
    148