Subversion Repositories SmartDukaan

Rev

Rev 19993 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
3894 chandransh 1
#!/usr/bin/env python
2
 
3
'''
4
This daemon has been taken from the blog post of 
5
<a href="http://www.jejik.com/authors/sander_marechal/">Sander Marechal</a>
6
at http://www.jejik.com/articles/2007/02/a_simple_unix_linux_daemon_in_python/
7
 
8
Some of the references within the code comments are no longer available.
9
 
10
'''
11
 
12
import sys, os, time, atexit
19283 amit.gupta 13
from signal import SIGTERM
14
import logging 
3894 chandransh 15
 
16
class Daemon:
17
	"""
18
	A generic daemon class.
19
 
20
	Usage: subclass the Daemon class and override the run() method
21
	"""
22
	def __init__(self, pidfile, stdin='/dev/null', stdout='/dev/null', stderr='/dev/null'):
23
		self.stdin = stdin
24
		self.stdout = stdout
25
		self.stderr = stderr
26
		self.pidfile = pidfile
20125 amit.gupta 27
		if stdout!='/dev/null':
28
			thriftLogger = logging.getLogger("thrift")
29
			ch = logging.StreamHandler(sys.stdout)
30
			thriftLogger.setLevel(logging.ERROR)
31
			thriftLogger.addHandler(ch)
32
 
3894 chandransh 33
 
34
	def daemonize(self):
35
		"""
36
		do the UNIX double-fork magic, see Stevens' "Advanced 
37
		Programming in the UNIX Environment" for details (ISBN 0201563177)
38
		http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC16
39
		"""
40
		try: 
41
			pid = os.fork() 
42
			if pid > 0:
43
				# exit first parent
44
				sys.exit(0) 
45
		except OSError, e: 
46
			sys.stderr.write("fork #1 failed: %d (%s)\n" % (e.errno, e.strerror))
47
			sys.exit(1)
48
 
49
		# decouple from parent environment
50
		os.chdir("/") 
51
		os.setsid() 
52
		os.umask(0) 
53
 
54
		# do second fork
55
		try: 
56
			pid = os.fork() 
57
			if pid > 0:
58
				# exit from second parent
59
				sys.exit(0) 
60
		except OSError, e: 
61
			sys.stderr.write("fork #2 failed: %d (%s)\n" % (e.errno, e.strerror))
62
			sys.exit(1) 
63
 
64
		# redirect standard file descriptors
65
		sys.stdout.flush()
66
		sys.stderr.flush()
67
		si = file(self.stdin, 'r')
19284 amit.gupta 68
		so = file(self.stdout, 'a+')
69
		se = file(self.stderr, 'a+', 0)
3894 chandransh 70
		os.dup2(si.fileno(), sys.stdin.fileno())
71
		os.dup2(so.fileno(), sys.stdout.fileno())
72
		os.dup2(se.fileno(), sys.stderr.fileno())
73
 
74
		# write pidfile
75
		atexit.register(self.delpid)
76
		pid = str(os.getpid())
77
		file(self.pidfile,'w+').write("%s\n" % pid)
78
 
79
	def delpid(self):
80
		os.remove(self.pidfile)
81
 
82
	def start(self):
83
		"""
84
		Start the daemon
85
		"""
86
		# Check for a pidfile to see if the daemon already runs
87
		try:
88
			pf = file(self.pidfile,'r')
89
			pid = int(pf.read().strip())
90
			pf.close()
91
		except IOError:
92
			pid = None
93
 
94
		if pid:
95
			message = "pidfile %s already exist. Daemon already running?\n"
96
			sys.stderr.write(message % self.pidfile)
97
			sys.exit(1)
98
 
99
		# Start the daemon
100
		self.daemonize()
101
		self.run()
102
 
103
	def stop(self):
104
		"""
105
		Stop the daemon
106
		"""
107
		# Get the pid from the pidfile
108
		try:
109
			pf = file(self.pidfile,'r')
110
			pid = int(pf.read().strip())
111
			pf.close()
112
		except IOError:
113
			pid = None
114
 
115
		if not pid:
116
			message = "pidfile %s does not exist. Daemon not running?\n"
117
			sys.stderr.write(message % self.pidfile)
118
			return # not an error in a restart
119
 
120
		# Try killing the daemon process	
121
		try:
122
			while 1:
123
				os.kill(pid, SIGTERM)
124
				time.sleep(0.1)
125
		except OSError, err:
126
			err = str(err)
127
			if err.find("No such process") > 0:
128
				if os.path.exists(self.pidfile):
129
					os.remove(self.pidfile)
130
			else:
131
				print str(err)
132
				sys.exit(1)
133
 
134
	def restart(self):
135
		"""
136
		Restart the daemon
137
		"""
138
		self.stop()
139
		self.start()
140
 
141
	def run(self):
142
		"""
143
		You should override this method when you subclass Daemon. It will be called after the process has been
144
		daemonized by start() or restart().
145
		"""
146
		pass
19766 amit.gupta 147
 
19283 amit.gupta 148
def configure_logging(logfile):
19867 amit.gupta 149
	fh = logging.FileHandler(logfile)
19413 amit.gupta 150
	formatter = logging.Formatter(logging.BASIC_FORMAT)
151
	fh.setFormatter(formatter)
152
	root = logging.getLogger()
19766 amit.gupta 153
	root.setLevel(logging.ERROR)
19413 amit.gupta 154
	root.addHandler(fh)