Subversion Repositories SmartDukaan

Rev

Rev 19413 | Rev 19766 | 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
19283 amit.gupta 27
		configure_logging(stdout)
3894 chandransh 28
 
29
	def daemonize(self):
30
		"""
31
		do the UNIX double-fork magic, see Stevens' "Advanced 
32
		Programming in the UNIX Environment" for details (ISBN 0201563177)
33
		http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC16
34
		"""
35
		try: 
36
			pid = os.fork() 
37
			if pid > 0:
38
				# exit first parent
39
				sys.exit(0) 
40
		except OSError, e: 
41
			sys.stderr.write("fork #1 failed: %d (%s)\n" % (e.errno, e.strerror))
42
			sys.exit(1)
43
 
44
		# decouple from parent environment
45
		os.chdir("/") 
46
		os.setsid() 
47
		os.umask(0) 
48
 
49
		# do second fork
50
		try: 
51
			pid = os.fork() 
52
			if pid > 0:
53
				# exit from second parent
54
				sys.exit(0) 
55
		except OSError, e: 
56
			sys.stderr.write("fork #2 failed: %d (%s)\n" % (e.errno, e.strerror))
57
			sys.exit(1) 
58
 
59
		# redirect standard file descriptors
60
		sys.stdout.flush()
61
		sys.stderr.flush()
62
		si = file(self.stdin, 'r')
19284 amit.gupta 63
		so = file(self.stdout, 'a+')
64
		se = file(self.stderr, 'a+', 0)
3894 chandransh 65
		os.dup2(si.fileno(), sys.stdin.fileno())
66
		os.dup2(so.fileno(), sys.stdout.fileno())
67
		os.dup2(se.fileno(), sys.stderr.fileno())
68
 
69
		# write pidfile
70
		atexit.register(self.delpid)
71
		pid = str(os.getpid())
72
		file(self.pidfile,'w+').write("%s\n" % pid)
73
 
74
	def delpid(self):
75
		os.remove(self.pidfile)
76
 
77
	def start(self):
78
		"""
79
		Start the daemon
80
		"""
81
		# Check for a pidfile to see if the daemon already runs
82
		try:
83
			pf = file(self.pidfile,'r')
84
			pid = int(pf.read().strip())
85
			pf.close()
86
		except IOError:
87
			pid = None
88
 
89
		if pid:
90
			message = "pidfile %s already exist. Daemon already running?\n"
91
			sys.stderr.write(message % self.pidfile)
92
			sys.exit(1)
93
 
94
		# Start the daemon
95
		self.daemonize()
96
		self.run()
97
 
98
	def stop(self):
99
		"""
100
		Stop the daemon
101
		"""
102
		# Get the pid from the pidfile
103
		try:
104
			pf = file(self.pidfile,'r')
105
			pid = int(pf.read().strip())
106
			pf.close()
107
		except IOError:
108
			pid = None
109
 
110
		if not pid:
111
			message = "pidfile %s does not exist. Daemon not running?\n"
112
			sys.stderr.write(message % self.pidfile)
113
			return # not an error in a restart
114
 
115
		# Try killing the daemon process	
116
		try:
117
			while 1:
118
				os.kill(pid, SIGTERM)
119
				time.sleep(0.1)
120
		except OSError, err:
121
			err = str(err)
122
			if err.find("No such process") > 0:
123
				if os.path.exists(self.pidfile):
124
					os.remove(self.pidfile)
125
			else:
126
				print str(err)
127
				sys.exit(1)
128
 
129
	def restart(self):
130
		"""
131
		Restart the daemon
132
		"""
133
		self.stop()
134
		self.start()
135
 
136
	def run(self):
137
		"""
138
		You should override this method when you subclass Daemon. It will be called after the process has been
139
		daemonized by start() or restart().
140
		"""
141
		pass
19283 amit.gupta 142
def configure_logging(logfile):
19413 amit.gupta 143
	if logfile is None:
144
		return
145
	fh = logging.FileHandler(logfile, 'w')
146
	formatter = logging.Formatter(logging.BASIC_FORMAT)
147
	fh.setFormatter(formatter)
148
	root = logging.getLogger()
19491 manish.sha 149
	root.setLevel(logging.DEBUG)
19413 amit.gupta 150
	root.addHandler(fh)