Subversion Repositories SmartDukaan

Rev

Rev 3894 | Rev 19284 | 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')
19283 amit.gupta 63
 
64
		so = os.open(self.stdout, os.O_RDWR)
65
		#so = file(self.stdout, 'a+')
66
		se = os.open(self.stderr, os.O_RDWR)
3894 chandransh 67
		os.dup2(si.fileno(), sys.stdin.fileno())
68
		os.dup2(so.fileno(), sys.stdout.fileno())
69
		os.dup2(se.fileno(), sys.stderr.fileno())
70
 
71
		# write pidfile
72
		atexit.register(self.delpid)
73
		pid = str(os.getpid())
74
		file(self.pidfile,'w+').write("%s\n" % pid)
75
 
76
	def delpid(self):
77
		os.remove(self.pidfile)
78
 
79
	def start(self):
80
		"""
81
		Start the daemon
82
		"""
83
		# Check for a pidfile to see if the daemon already runs
84
		try:
85
			pf = file(self.pidfile,'r')
86
			pid = int(pf.read().strip())
87
			pf.close()
88
		except IOError:
89
			pid = None
90
 
91
		if pid:
92
			message = "pidfile %s already exist. Daemon already running?\n"
93
			sys.stderr.write(message % self.pidfile)
94
			sys.exit(1)
95
 
96
		# Start the daemon
97
		self.daemonize()
98
		self.run()
99
 
100
	def stop(self):
101
		"""
102
		Stop the daemon
103
		"""
104
		# Get the pid from the pidfile
105
		try:
106
			pf = file(self.pidfile,'r')
107
			pid = int(pf.read().strip())
108
			pf.close()
109
		except IOError:
110
			pid = None
111
 
112
		if not pid:
113
			message = "pidfile %s does not exist. Daemon not running?\n"
114
			sys.stderr.write(message % self.pidfile)
115
			return # not an error in a restart
116
 
117
		# Try killing the daemon process	
118
		try:
119
			while 1:
120
				os.kill(pid, SIGTERM)
121
				time.sleep(0.1)
122
		except OSError, err:
123
			err = str(err)
124
			if err.find("No such process") > 0:
125
				if os.path.exists(self.pidfile):
126
					os.remove(self.pidfile)
127
			else:
128
				print str(err)
129
				sys.exit(1)
130
 
131
	def restart(self):
132
		"""
133
		Restart the daemon
134
		"""
135
		self.stop()
136
		self.start()
137
 
138
	def run(self):
139
		"""
140
		You should override this method when you subclass Daemon. It will be called after the process has been
141
		daemonized by start() or restart().
142
		"""
143
		pass
19283 amit.gupta 144
def configure_logging(logfile):
145
    fh = logging.FileHandler(logfile, 'w')
146
    formatter = logging.Formatter(logging.BASIC_FORMAT)
147
    fh.setFormatter(formatter)
148
    root = logging.getLogger()
149
    root.setLevel(logging.ERROR)
150
    root.addHandler(fh)