1 # -*- coding: utf-8 -*-
5 # Copyright 2007, 2009 Sander Marechal <s.marechal@jejik.com>
6 # Copyright 2010, 2011, 2012 Jack Kaliko <kaliko@azylum.org>
8 # http://www.jejik.com/articles/2007/02/a_simple_unix_linux_daemon_in_python/
14 from signal import signal, SIGTERM
19 A generic daemon class.
21 Usage: subclass the Daemon class and override the run() method
23 Daemon([pidfile[, stdin[, stdout[, stderr]]]])
25 pidfile : file to write pid to (default no pid file writen)
26 stdin : standard input file descriptor (default to /dev/null)
27 stdout : standard output file descriptor (default to /dev/null)
28 stderr : standard error file descriptorr (default to /dev/null)
32 def __init__(self, pidfile,
39 self.pidfile = pidfile
44 Do the UNIX double-fork magic.
45 see W. Richard Stevens, "Advanced Programming in the Unix Environment"
46 for details (ISBN 0201563177)
49 Unix processes belong to "process group" which in turn lies within a "session".
50 A session can have a controlling tty.
51 Forking twice allows to detach the session from a possible tty.
52 The process lives then within the init process.
60 sys.stderr.write('fork #1 failed: {0.errno:d} ({0.strerror})\n'.format(e))
63 # Decouple from parent environment
66 self.umask = os.umask(0)
72 # exit from second parent
75 sys.stderr.write('fork #2 failed: {0.errno:d} ({0.strerror})\n'.format(e))
79 # redirect standard file descriptors
82 # TODO: binary or txt mode?
83 si = open(self.stdin, mode='rb')
84 so = open(self.stdout, mode='ab+')
85 se = open(self.stderr, mode='ab+', buffering=0)
86 os.dup2(si.fileno(), sys.stdin.fileno())
87 os.dup2(so.fileno(), sys.stdout.fileno())
88 os.dup2(se.fileno(), sys.stderr.fileno())
90 atexit.register(self.shutdown)
91 self.signal_management()
97 pid = str(os.getpid())
100 open(self.pidfile, 'w').write('%s\n' % pid)
101 except Exception as wpid_err:
102 sys.stderr.write('Error trying to write pid file: {}\n'.format(wpid_err))
105 atexit.register(self.delpid)
107 def signal_management(self):
108 """Declare signal handlers
110 signal(SIGTERM, self.exit_handler)
112 def exit_handler(self, signum, frame):
116 """Remove PID file"""
118 os.unlink(self.pidfile)
119 except OSError as err:
120 message = 'Error trying to remove PID file: {}\n'
121 sys.stderr.write(message.format(err))
127 # Check for a pidfile to see if the daemon already runs
129 pf = open(self.pidfile, 'r')
130 pid = int(pf.read().strip())
136 message = 'pidfile {0.pidfile} already exist. Daemon already running?\n'
137 sys.stderr.write(message.format(self))
144 def foreground(self):
146 Foreground/debug mode
149 atexit.register(self.shutdown)
156 # Get the pid from the pidfile
158 pf = open(self.pidfile, 'r')
159 pid = int(pf.read().strip())
165 message = 'pidfile {0.pidfile} does not exist. Is the Daemon running?\n'
166 sys.stderr.write(message.format(self))
167 return # not an error in a restart
169 # Try killing the daemon process
171 os.kill(pid, SIGTERM)
173 except OSError as err:
175 if os.path.exists(self.pidfile):
176 message = "Daemon's not running? removing pid file {0.pidfile}.\n"
177 sys.stderr.write(message.format(self))
178 os.remove(self.pidfile)
180 sys.stderr.write(err.strerror)
192 You should override this method when you subclass Daemon. It will be
193 called when the process is being stopped.
195 Daemon() uses atexit to call Daemon().shutdown(), as a consequence
196 shutdown and any other functions registered via this module are not
197 called when the program is killed by an un-handled/unknown signal.
198 This is the reason of Daemon().signal_management() existence.
203 You should override this method when you subclass Daemon. It will be
204 called after the process has been daemonized by start() or restart().
208 # vim: ai ts=4 sw=4 sts=4 expandtab