Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Updated LICENSE details and description, created setup script, update…

…d output formatting and created daemon status method, created example Daemon class implementation'
  • Loading branch information...
commit 2123c4801dea05ae0bb2a3777974964a92a75512 1 parent 402e053
@wayoutmind wayoutmind authored
View
2  .gitignore
@@ -0,0 +1,2 @@
+.DS_Store
+build/
View
2  LICENSE
@@ -1,4 +1,6 @@
+Daemon-Python, lightweight and no-nonsense POSIX daemon library.
Copyright (c) 2010 Fredrick Galoso http://stackd.com/
+
Based on source code (public domain) by Sander Marechal
http://www.jejik.com/articles/2007/02/a_simple_unix_linux_daemon_in_python/
View
36 setup.py
@@ -0,0 +1,36 @@
+#!/usr/bin/env python
+# encoding: utf-8
+import sys
+from distutils.core import setup
+from distutils.util import get_platform
+
+"""
+Verify Python platform is Linux
+"""
+platform = get_platform()
+if platform.startswith('linux') == False:
+ sys.stderr.write("Daemon-Python is not compatible with %s\n" % platform)
+ sys.exit(1)
+
+"""
+Determine appropriate Python version for installation
+"""
+if sys.version_info[0] >= 3:
+ package_dir = {'': 'src/3.x.x'}
+else:
+ package_dir = {'': 'src/2.x.x'}
+
+setup(
+ name = 'daemon',
+ version = '0.1',
+ description = 'Lightweight and no-nonsense POSIX daemon library for Python (2.x.x/3.x.x)',
+ author = 'Fredrick Galoso - Stackd, LLC',
+ license = 'MIT/X11',
+ platforms='Linux',
+ url = 'https://github.com/stackd/daemon-py',
+ download_url = 'https://github.com/stackd/daemon-py.git',
+ package_dir = package_dir,
+ py_modules = [
+ 'daemon',
+ ],
+)
View
278 src/2.x.x/daemon.py
@@ -1,4 +1,22 @@
#!/usr/bin/env python
+"""
+Daemon-Python (0.1)
+Lightweight and no-nonsense POSIX daemon library
+https://github.com/stackd/daemon-py
+
+DOCUMENTATION
+----------------------------------------
+see README.md
+
+LICENSE
+----------------------------------------
+MIT/X11, see LICENSE
+
+DEPENDENCIES
+----------------------------------------
+Python 2.x.x
+
+"""
import sys
import os
import time
@@ -6,129 +24,147 @@
from signal import SIGTERM
class Daemon(object):
- """
- A generic daemon class for Python 2.x.x
-
- 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):
- """
- UNIX double fork mechanism, 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)
+ """
+ A generic daemon class for Python 2.x.x
+
+ 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):
+ """
+ UNIX double fork mechanism, see Stevens' "Advanced
+ Programming in the UNIX Environment" for details (ISBN 0201563177)
+ """
+ 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
- """
- # Check for a pidfile to see if the daemon already runs
- try:
- pf = file(self.pidfile,'r')
- pid = int(pf.read().strip())
- pf.close()
- except IOError:
- pid = None
-
- if pid:
- message = "pidfile %s already exist. Daemon already running?\n"
- sys.stderr.write(message % self.pidfile)
- sys.exit(1)
-
- # Start the daemon
- self.daemonize()
- self.run()
+ def start(self):
+ """
+ Start the daemon
+ """
+ # Check for a pidfile to see if the daemon is already running
+ try:
+ pf = file(self.pidfile,'r')
+ pid = int(pf.read().strip())
+ pf.close()
+ except IOError:
+ pid = None
+
+ if pid:
+ message = "pidfile %s already exists. %s running?\n"
+ sys.stderr.write(message % (self.pidfile, self.__class__.__name__))
+ sys.exit(1)
+
+ # Start the daemon
+ self.daemonize()
+ self.run()
- def stop(self):
- """
- Stop the daemon
- """
- # 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:
- message = "pidfile %s does not exist. Daemon not running?\n"
- sys.stderr.write(message % self.pidfile)
- return # not an error in a restart
+ def stop(self):
+ """
+ Stop the daemon
+ """
+ # 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:
+ message = "pidfile %s does not exist. %s not running?\n"
+ sys.stderr.write(message % (self.pidfile, self.__class__.__name__))
+ return # not an error in a restart
- # 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:
- if os.path.exists(self.pidfile):
- os.remove(self.pidfile)
- else:
- print str(err)
- 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:
+ 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 restart(self):
+ """
+ Restart the daemon
+ """
+ self.stop()
+ self.start()
+
+ def status(self):
+ """
+ Return the daemon state.
+ """
+ # Check for a pidfile to see if the daemon is already running
+ try:
+ pf = file(self.pidfile,'r')
+ pid = int(pf.read().strip())
+ pf.close()
+ except IOError:
+ pid = None
+
+ if pid:
+ message = "%s (%s) is running.\n"
+ sys.stdout.write(message % (self.__class__.__name__, self.pidfile))
+ elif not pid:
+ message = "pidfile %s does not exist. %s not running.\n"
+ sys.stdout.write(message % (self.pidfile, self.__class__.__name__))
- 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().
- """
-
+ 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().
+ """
+
View
275 src/3.x.x/daemon.py
@@ -1,4 +1,22 @@
#!/usr/bin/env python
+"""
+Daemon-Python (0.1)
+Lightweight and no-nonsense POSIX daemon library
+https://github.com/stackd/daemon-py
+
+DOCUMENTATION
+----------------------------------------
+see README.md
+
+LICENSE
+----------------------------------------
+MIT/X11, see LICENSE
+
+DEPENDENCIES
+----------------------------------------
+Python 3.x.x
+
+"""
import sys
import os
import time
@@ -6,123 +24,142 @@
import signal
class Daemon:
- """
- A generic daemon class for Python 3.x.x
-
- Usage: subclass the daemon class and override the run() method.
- """
- def __init__(self, pidfile): self.pidfile = pidfile
-
- def daemonize(self):
- """Deamonize class. UNIX double fork mechanism."""
+ """
+ A generic daemon class for Python 3.x.x
+
+ Usage: subclass the daemon class and override the run() method.
+ """
+ def __init__(self, pidfile): self.pidfile = pidfile
+
+ def daemonize(self):
+ """Deamonize class. UNIX double fork mechanism."""
+
+ try:
+ pid = os.fork()
+ if pid > 0:
+ # exit first parent
+ sys.exit(0)
+ except OSError as err:
+ sys.stderr.write('fork #1 failed: {0}\n'.format(err))
+ 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 as err:
+ sys.stderr.write('fork #2 failed: {0}\n'.format(err))
+ sys.exit(1)
+
+ # redirect standard file descriptors
+ sys.stdout.flush()
+ sys.stderr.flush()
+ si = open(os.devnull, 'r')
+ so = open(os.devnull, 'a+')
+ se = open(os.devnull, 'a+')
+
+ 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())
+ with open(self.pidfile,'w+') as f:
+ f.write(pid + '\n')
+
+ def delpid(self):
+ os.remove(self.pidfile)
+
+ def start(self):
+ """Start the daemon."""
+
+ # Check for a pidfile to see if the daemon is already running
+ try:
+ with open(self.pidfile,'r') as pf:
+
+ pid = int(pf.read().strip())
+ except IOError:
+ pid = None
+
+ if pid:
+ message = "pidfile {0} already exists. " + \
+ "{1} already running?\n"
+ sys.stderr.write(message.format(self.pidfile, self.__class__.__name__))
+ sys.exit(1)
+
+ # Start the daemon
+ self.daemonize()
+ self.run()
+
+ def stop(self):
+ """Stop the daemon."""
+
+ # Get the pid from the pidfile
+ try:
+ with open(self.pidfile,'r') as pf:
+ pid = int(pf.read().strip())
+ except IOError:
+ pid = None
+
+ if not pid:
+ message = "pidfile {0} does not exist. " + \
+ "{1} not running?\n"
+ sys.stderr.write(message.format(self.pidfile, self.__class__.__name__))
+ return # not an error in a restart
+
+ # Try killing the daemon process
+ try:
+ while 1:
+ os.kill(pid, signal.SIGTERM)
+ time.sleep(0.1)
+ except OSError as err:
+ e = str(err.args)
+ if e.find("No such process") > 0:
+ if os.path.exists(self.pidfile):
+ os.remove(self.pidfile)
+ else:
+ print (str(err.args))
+ sys.exit(1)
+
+ def restart(self):
+ """Restart the daemon."""
+ self.stop()
+ self.start()
+
+ def status(self):
+ """
+ Return the daemon state.
+ """
+ # Check for a pidfile to see if the daemon is already running
+ try:
+ with open(self.pidfile,'r') as pf:
+ pid = int(pf.read().strip())
+ except IOError:
+ pid = None
+
+ if pid:
+ message = "{0} ({1}) is running.\n"
+ sys.stdout.write(message.format(self.__class__.__name__, self.pidfile))
+ elif not pid:
+ message = "pidfile {0} does not exist. " + \
+ "{1} not running.\n"
+ sys.stdout.write(message.format(self.pidfile, self.__class__.__name__))
+
+ def run(self):
+ """
+ You should override this method when you subclass Daemon.
- try:
- pid = os.fork()
- if pid > 0:
- # exit first parent
- sys.exit(0)
- except OSError as err:
- sys.stderr.write('fork #1 failed: {0}\n'.format(err))
- 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 as err:
- sys.stderr.write('fork #2 failed: {0}\n'.format(err))
- sys.exit(1)
-
- # redirect standard file descriptors
- sys.stdout.flush()
- sys.stderr.flush()
- si = open(os.devnull, 'r')
- so = open(os.devnull, 'a+')
- se = open(os.devnull, 'a+')
-
- 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())
- with open(self.pidfile,'w+') as f:
- f.write(pid + '\n')
-
- def delpid(self):
- os.remove(self.pidfile)
-
- def start(self):
- """Start the daemon."""
-
- # Check for a pidfile to see if the daemon already runs
- try:
- with open(self.pidfile,'r') as pf:
-
- pid = int(pf.read().strip())
- except IOError:
- pid = None
-
- if pid:
- message = "pidfile {0} already exist. " + \
- "Daemon already running?\n"
- sys.stderr.write(message.format(self.pidfile))
- sys.exit(1)
-
- # Start the daemon
- self.daemonize()
- self.run()
-
- def stop(self):
- """Stop the daemon."""
-
- # Get the pid from the pidfile
- try:
- with open(self.pidfile,'r') as pf:
- pid = int(pf.read().strip())
- except IOError:
- pid = None
-
- if not pid:
- message = "pidfile {0} does not exist. " + \
- "Daemon not running?\n"
- sys.stderr.write(message.format(self.pidfile))
- return # not an error in a restart
-
- # Try killing the daemon process
- try:
- while 1:
- os.kill(pid, signal.SIGTERM)
- time.sleep(0.1)
- except OSError as err:
- e = str(err.args)
- if e.find("No such process") > 0:
- if os.path.exists(self.pidfile):
- os.remove(self.pidfile)
- else:
- print (str(err.args))
- 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 been daemonized by
- start() or restart().
- """
-
+ It will be called after the process has been daemonized by
+ start() or restart().
+ """
+
View
31 src/test.py
@@ -0,0 +1,31 @@
+#!/usr/bin/env python
+"""
+Unit test/basic Daemon-Python implementation
+"""
+import sys
+import time
+from daemon import Daemon
+
+class TestDaemon(Daemon):
+ def run(self): #Define what tasks/processes to daemonize
+ while True:
+ time.sleep(1)
+
+if __name__ == "__main__":
+ daemon = TestDaemon('/tmp/daemon-py-test.pid') #Define pidfile location (typically /tmp or /var/run)
+ if len(sys.argv) == 2:
+ if 'start' == sys.argv[1]:
+ daemon.start()
+ elif 'stop' == sys.argv[1]:
+ daemon.stop()
+ elif 'restart' == sys.argv[1]:
+ daemon.restart()
+ elif 'status' == sys.argv[1]:
+ daemon.status()
+ else:
+ print "Unknown command"
+ sys.exit(2)
+ sys.exit(0)
+ else:
+ print "Usage: %s start|stop|restart|status" % sys.argv[0]
+ sys.exit(2)
Please sign in to comment.
Something went wrong with that request. Please try again.