Rev 20125 | Blame | Compare with Previous | Last modification | View Log | RSS feed
#!/usr/bin/env python'''This daemon has been taken from the blog post of<a href="http://www.jejik.com/authors/sander_marechal/">Sander Marechal</a>at http://www.jejik.com/articles/2007/02/a_simple_unix_linux_daemon_in_python/Some of the references within the code comments are no longer available.'''import sys, os, time, atexitfrom signal import SIGTERMimport loggingclass Daemon:"""A generic daemon class.Usage: subclass the Daemon class and override the run() method"""def __init__(self, pidfile, stdin='/dev/null', stdout='/dev/null', stderr='/dev/null'):self.stdin = stdinself.stdout = stdoutself.stderr = stderrself.pidfile = pidfileif stdout!='/dev/null':configure_logging()def daemonize(self):"""do the UNIX double-fork magic, see Stevens' "AdvancedProgramming in the UNIX Environment" for details (ISBN 0201563177)http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC16"""try:pid = os.fork()if pid > 0:# exit first parentsys.exit(0)except OSError, e:sys.stderr.write("fork #1 failed: %d (%s)\n" % (e.errno, e.strerror))sys.exit(1)# decouple from parent environmentos.chdir("/")os.setsid()os.umask(0)# do second forktry:pid = os.fork()if pid > 0:# exit from second parentsys.exit(0)except OSError, e:sys.stderr.write("fork #2 failed: %d (%s)\n" % (e.errno, e.strerror))sys.exit(1)# redirect standard file descriptorssys.stdout.flush()sys.stderr.flush()si = file(self.stdin, 'r')so = file(self.stdout, 'a+')se = file(self.stderr, 'a+', 0)os.dup2(si.fileno(), sys.stdin.fileno())os.dup2(so.fileno(), sys.stdout.fileno())os.dup2(se.fileno(), sys.stderr.fileno())# write pidfileatexit.register(self.delpid)pid = str(os.getpid())file(self.pidfile,'w+').write("%s\n" % pid)def delpid(self):os.remove(self.pidfile)def start(self):"""Start the daemon"""# Check for a pidfile to see if the daemon already runstry:pf = file(self.pidfile,'r')pid = int(pf.read().strip())pf.close()except IOError:pid = Noneif pid:message = "pidfile %s already exist. Daemon already running?\n"sys.stderr.write(message % self.pidfile)sys.exit(1)# Start the daemonself.daemonize()self.run()def stop(self):"""Stop the daemon"""# Get the pid from the pidfiletry:pf = file(self.pidfile,'r')pid = int(pf.read().strip())pf.close()except IOError:pid = Noneif not pid:message = "pidfile %s does not exist. Daemon not running?\n"sys.stderr.write(message % self.pidfile)return # not an error in a restart# Try killing the daemon processtry:while 1:os.kill(pid, SIGTERM)time.sleep(0.1)except OSError, err:err = str(err)if err.find("No such process") > 0:if os.path.exists(self.pidfile):os.remove(self.pidfile)else:print str(err)sys.exit(1)def restart(self):"""Restart the daemon"""self.stop()self.start()def run(self):"""You should override this method when you subclass Daemon. It will be called after the process has beendaemonized by start() or restart()."""passdef configure_logging():thriftLogger = logging.getLogger("thrift")ch = logging.StreamHandler(sys.stdout)thriftLogger.setLevel(logging.ERROR)thriftLogger.addHandler(ch)