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 11import atexit 12import os 13from signal import SIGTERM 14from signal import SIGINT 15import sys 16import time 17 18 19class 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