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 |