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 |