1""" 2 *** 3 Modified generic daemon class 4 *** 5 6 Author: http://www.jejik.com/articles/2007/02/a_simple_unix_linux_daemon_in_python/ 7 www.serverdensity.com 8 9 License: http://creativecommons.org/licenses/by-sa/3.0/ 10 11 Changes: 23rd Jan 2009 (David Mytton <david@serverdensity.com>) 12 - Replaced hard coded '/dev/null in __init__ with os.devnull 13 - Added OS check to conditionally remove code that doesn't 14 work on OS X 15 - Added output to console on completion 16 - Tidied up formatting 17 11th Mar 2009 (David Mytton <david@serverdensity.com>) 18 - Fixed problem with daemon exiting on Python 2.4 (before 19 SystemExit was part of the Exception base) 20 13th Aug 2010 (David Mytton <david@serverdensity.com> 21 - Fixed unhandled exception if PID file is empty 22""" 23 24# Core modules 25import atexit 26import os 27import sys 28import time 29 30from signal import SIGTERM 31 32 33class Daemon: 34 """ 35 A generic daemon class. 36 37 Usage: subclass the Daemon class and override the run() method 38 """ 39 def __init__(self, pidfile, stdin=os.devnull, stdout=os.devnull, 40 stderr=os.devnull): 41 self.stdin = stdin 42 self.stdout = stdout 43 self.stderr = stderr 44 self.pidfile = pidfile 45 46 def daemonize(self): 47 """ 48 Do the UNIX double-fork magic, see Stevens' "Advanced 49 Programming in the UNIX Environment" for details (ISBN 0201563177) 50 http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC16 51 """ 52 try: 53 pid = os.fork() 54 if pid > 0: 55 # Exit first parent 56 sys.exit(0) 57 except OSError, e: 58 sys.stderr.write( 59 "fork #1 failed: %d (%s)\n" % (e.errno, e.strerror)) 60 sys.exit(1) 61 62 # Decouple from parent environment 63 os.chdir("/") 64 os.setsid() 65 os.umask(0) 66 67 # Do second fork 68 try: 69 pid = os.fork() 70 if pid > 0: 71 # Exit from second parent 72 sys.exit(0) 73 except OSError, e: 74 sys.stderr.write( 75 "fork #2 failed: %d (%s)\n" % (e.errno, e.strerror)) 76 sys.exit(1) 77 78 if sys.platform != 'darwin': # This block breaks on OS X 79 # Redirect standard file descriptors 80 sys.stdout.flush() 81 sys.stderr.flush() 82 si = open(self.stdin, 'r') 83 so = open(self.stdout, 'a+') 84 se = open(self.stderr, 'a+', 0) 85 os.dup2(si.fileno(), sys.stdin.fileno()) 86 os.dup2(so.fileno(), sys.stdout.fileno()) 87 os.dup2(se.fileno(), sys.stderr.fileno()) 88 89 print "Started" 90 91 # Write pidfile 92 # Make sure pid file is removed if we quit 93 atexit.register(self.delpid) 94 pid = str(os.getpid()) 95 pid_handler = open(self.pidfile, 'w+') 96 pid_handler.write("%s\n" % pid) 97 pid_handler.close() 98 99 def delpid(self): 100 os.remove(self.pidfile) 101 102 def start(self): 103 """ 104 Start the daemon 105 """ 106 107 print "Starting..." 108 109 # Check for a pidfile to see if the daemon already runs 110 pid = None 111 try: 112 pf = open(self.pidfile, 'r') 113 pid = int(pf.read().strip()) 114 pf.close() 115 except (IOError, SystemExit): 116 pass 117 118 if pid: 119 message = "pidfile %s already exists. Is it already running?\n" 120 sys.stderr.write(message % self.pidfile) 121 sys.exit(1) 122 123 # Start the daemon 124 self.daemonize() 125 self.run() 126 127 def stop(self): 128 """ 129 Stop the daemon 130 """ 131 132 print "Stopping..." 133 134 # Get the pid from the pidfile 135 pid = None 136 try: 137 pf = open(self.pidfile, 'r') 138 pid = int(pf.read().strip()) 139 pf.close() 140 except (IOError, ValueError): 141 pass 142 143 if not pid: 144 message = "pidfile %s does not exist. Not running?\n" 145 sys.stderr.write(message % self.pidfile) 146 147 # Just to be sure. A ValueError might occur if the PID file is 148 # empty but does actually exist 149 if os.path.exists(self.pidfile): 150 os.remove(self.pidfile) 151 152 return # Not an error in a restart 153 154 # Try killing the daemon process 155 try: 156 while 1: 157 os.kill(pid, SIGTERM) 158 time.sleep(0.1) 159 except OSError, err: 160 err = str(err) 161 if err.find("No such process") > 0: 162 if os.path.exists(self.pidfile): 163 os.remove(self.pidfile) 164 else: 165 print str(err) 166 sys.exit(1) 167 168 print "Stopped" 169 170 def restart(self): 171 """ 172 Restart the daemon 173 """ 174 self.stop() 175 self.start() 176 177 def run(self): 178 """ 179 You should override this method when you subclass Daemon. It will be 180 called after the process has been daemonized by start() or restart(). 181 """ 182 pass 183