| OLD | NEW |
| (Empty) |
| 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 """ | |
| OLD | NEW |