1 | #!/usr/bin/env python
|
---|
2 |
|
---|
3 | import sys, os, time, atexit
|
---|
4 | from signal import SIGTERM
|
---|
5 |
|
---|
6 | class Daemon:
|
---|
7 | """
|
---|
8 | A generic daemon class.
|
---|
9 |
|
---|
10 | Usage: subclass the Daemon class and override the run() method
|
---|
11 | """
|
---|
12 | def __init__(self, pidfile, stdin='/dev/null', stdout='/dev/null', stderr='/dev/null'):
|
---|
13 | self.stdin = stdin
|
---|
14 | self.stdout = stdout
|
---|
15 | self.stderr = stderr
|
---|
16 | self.pidfile = pidfile
|
---|
17 |
|
---|
18 | def daemonize(self):
|
---|
19 | """
|
---|
20 | do the UNIX double-fork magic, see Stevens' "Advanced
|
---|
21 | Programming in the UNIX Environment" for details (ISBN 0201563177)
|
---|
22 | http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC16
|
---|
23 | """
|
---|
24 | try:
|
---|
25 | pid = os.fork()
|
---|
26 | if pid > 0:
|
---|
27 | # exit first parent
|
---|
28 | sys.exit(0)
|
---|
29 | except OSError, e:
|
---|
30 | sys.stderr.write("fork #1 failed: %d (%s)\n" % (e.errno, e.strerror))
|
---|
31 | sys.exit(1)
|
---|
32 |
|
---|
33 | # decouple from parent environment
|
---|
34 | os.chdir("/")
|
---|
35 | os.setsid()
|
---|
36 | os.umask(0)
|
---|
37 |
|
---|
38 | # do second fork
|
---|
39 | try:
|
---|
40 | pid = os.fork()
|
---|
41 | if pid > 0:
|
---|
42 | # exit from second parent
|
---|
43 | sys.exit(0)
|
---|
44 | except OSError, e:
|
---|
45 | sys.stderr.write("fork #2 failed: %d (%s)\n" % (e.errno, e.strerror))
|
---|
46 | sys.exit(1)
|
---|
47 |
|
---|
48 | # redirect standard file descriptors
|
---|
49 | sys.stdout.flush()
|
---|
50 | sys.stderr.flush()
|
---|
51 | si = file(self.stdin, 'r')
|
---|
52 | so = file(self.stdout, 'a+')
|
---|
53 | se = file(self.stderr, 'a+', 0)
|
---|
54 | os.dup2(si.fileno(), sys.stdin.fileno())
|
---|
55 | os.dup2(so.fileno(), sys.stdout.fileno())
|
---|
56 | os.dup2(se.fileno(), sys.stderr.fileno())
|
---|
57 |
|
---|
58 | # write pidfile
|
---|
59 | atexit.register(self.delpid)
|
---|
60 | pid = str(os.getpid())
|
---|
61 | file(self.pidfile,'w+').write("%s\n" % pid)
|
---|
62 |
|
---|
63 | def delpid(self):
|
---|
64 | os.remove(self.pidfile)
|
---|
65 |
|
---|
66 | def start(self):
|
---|
67 | """
|
---|
68 | Start the daemon
|
---|
69 | """
|
---|
70 | # Check for a pidfile to see if the daemon already runs
|
---|
71 | try:
|
---|
72 | pf = file(self.pidfile,'r')
|
---|
73 | pid = int(pf.read().strip())
|
---|
74 | pf.close()
|
---|
75 | except IOError:
|
---|
76 | pid = None
|
---|
77 |
|
---|
78 | if pid:
|
---|
79 | message = "pidfile %s already exist. Daemon already running?\n"
|
---|
80 | sys.stderr.write(message % self.pidfile)
|
---|
81 | sys.exit(1)
|
---|
82 |
|
---|
83 | # Start the daemon
|
---|
84 | self.daemonize()
|
---|
85 | self.run()
|
---|
86 |
|
---|
87 | def stop(self):
|
---|
88 | """
|
---|
89 | Stop the daemon
|
---|
90 | """
|
---|
91 | # Get the pid from the pidfile
|
---|
92 | try:
|
---|
93 | pf = file(self.pidfile,'r')
|
---|
94 | pid = int(pf.read().strip())
|
---|
95 | pf.close()
|
---|
96 | except IOError:
|
---|
97 | pid = None
|
---|
98 |
|
---|
99 | if not pid:
|
---|
100 | message = "pidfile %s does not exist. Daemon not running?\n"
|
---|
101 | sys.stderr.write(message % self.pidfile)
|
---|
102 | return # not an error in a restart
|
---|
103 |
|
---|
104 | # Try killing the daemon process
|
---|
105 | try:
|
---|
106 | while 1:
|
---|
107 | os.kill(pid, SIGTERM)
|
---|
108 | time.sleep(0.1)
|
---|
109 | except OSError, err:
|
---|
110 | err = str(err)
|
---|
111 | if err.find("No such process") > 0:
|
---|
112 | if os.path.exists(self.pidfile):
|
---|
113 | os.remove(self.pidfile)
|
---|
114 | else:
|
---|
115 | print str(err)
|
---|
116 | sys.exit(1)
|
---|
117 |
|
---|
118 | def restart(self):
|
---|
119 | """
|
---|
120 | Restart the daemon
|
---|
121 | """
|
---|
122 | self.stop()
|
---|
123 | self.start()
|
---|
124 |
|
---|
125 | def run(self):
|
---|
126 | """
|
---|
127 | You should override this method when you subclass Daemon. It will be called after the process has been
|
---|
128 | daemonized by start() or restart().
|
---|
129 | """
|
---|