Created
April 13, 2011 05:09
-
-
Save jmhobbs/916994 to your computer and use it in GitHub Desktop.
Cooked version of Python daemon base script.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
# Origin: http://www.jejik.com/articles/2007/02/a_simple_unix_linux_daemon_in_python/ | |
# Cooked up a bit by @jmhobbs | |
import sys, os, time, errno, atexit | |
from signal import SIGTERM | |
class 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 = stdin | |
self.stdout = stdout | |
self.stderr = stderr | |
self.pidfile = pidfile | |
def daemonize(self): | |
""" | |
do the UNIX double-fork magic, see Stevens' "Advanced | |
Programming 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 parent | |
sys.exit(0) | |
except OSError, e: | |
sys.stderr.write("fork #1 failed: %d (%s)\n" % (e.errno, e.strerror)) | |
sys.exit(1) | |
# decouple from parent environment | |
os.chdir("/") | |
os.setsid() | |
os.umask(0) | |
# do second fork | |
try: | |
pid = os.fork() | |
if pid > 0: | |
# exit from second parent | |
sys.exit(0) | |
except OSError, e: | |
sys.stderr.write("fork #2 failed: %d (%s)\n" % (e.errno, e.strerror)) | |
sys.exit(1) | |
# redirect standard file descriptors | |
sys.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 pidfile | |
atexit.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 | |
""" | |
if self._status(): | |
sys.stderr.write("Daemon already running?\n") | |
sys.exit(1) | |
print "Daemon starting." | |
# Start the daemon | |
self.daemonize() | |
self.run() | |
def stop(self): | |
""" | |
Stop the daemon | |
""" | |
pid = None | |
try: | |
pid = self._status() | |
if not pid: | |
sys.stderr.write("Daemon not running?\n") | |
return # not an error in a restart | |
except Exception, e: | |
print "Error:", e | |
sys.exit(1) | |
# Try killing the daemon process | |
try: | |
while 1: | |
os.kill(pid, SIGTERM) | |
time.sleep(0.1) | |
except OSError, err: | |
err = str(err) | |
if err.find("No such process") > 0: | |
print "Daemon stopped." | |
if os.path.exists(self.pidfile): | |
os.remove(self.pidfile) | |
else: | |
print str(err) | |
sys.exit(1) | |
def status(self): | |
if not self._status(): | |
status = "not running" | |
else: | |
status = "running" | |
print "The daemon is %s." % status | |
def _status(self): | |
""" | |
Check if the daemon is running | |
""" | |
# Get the pid from the pidfile | |
try: | |
pf = file(self.pidfile,'r') | |
pid = int(pf.read().strip()) | |
pf.close() | |
except IOError: | |
pid = None | |
if not pid: | |
return None | |
# See if it is alive | |
try: | |
os.kill(pid, 0) | |
except OSError, err: | |
if err.errno == errno.ESRCH: | |
return None | |
elif err.errno == errno.EPERM: | |
raise Exception( "Could not signal process with pid %d" % pid ) | |
else: | |
raise Exception( "Unknown error" ) | |
else: | |
return pid | |
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 been | |
daemonized by start() or restart(). | |
""" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment