#!/bin/env python ''' *** Modified generic daemon class *** Author: https://web.archive.org/web/20160305151936/http://www.jejik.com/articles/2007/02/a_simple_unix_linux_daemon_in_python/ Modified by ivars777@gmail.com License: http://creativecommons.org/licenses/by-sa/3.0/ ''' # Core modules from __future__ import print_function import atexit import errno import os import sys import time import signal class Daemon(object): """ A generic daemon class. Usage: subclass the Daemon class and override the run() method """ def __init__(self, app, pidfile, stdin=os.devnull, stdout=os.devnull, stderr=os.devnull, home_dir='.', umask=0o22, verbose=1, use_gevent=False, use_eventlet=False): self.app = app self.stdin = stdin self.stdout = stdout self.stderr = stderr self.pidfile = pidfile self.home_dir = home_dir self.verbose = verbose self.umask = umask self.daemon_alive = True self.use_gevent = use_gevent self.use_eventlet = use_eventlet def log(self, *args): if self.verbose >= 1: print(*args) 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 """ if self.use_eventlet: import eventlet.tpool eventlet.tpool.killall() try: pid = os.fork() if pid > 0: # Exit first parent sys.exit(0) except OSError as e: sys.stderr.write( "fork #1 failed: %d (%s)\n" % (e.errno, e.strerror)) sys.exit(1) # Decouple from parent environment os.chdir(self.home_dir) os.setsid() os.umask(self.umask) # Do second fork try: pid = os.fork() if pid > 0: # Exit from second parent sys.exit(0) except OSError as e: sys.stderr.write( "fork #2 failed: %d (%s)\n" % (e.errno, e.strerror)) sys.exit(1) if sys.platform != 'darwin': # This block breaks on OS X # Redirect standard file descriptors sys.stdout.flush() sys.stderr.flush() si = open(self.stdin, 'r') so = open(self.stdout, 'a+') if self.stderr: try: se = open(self.stderr, 'a+', 0) except ValueError: # Python 3 can't have unbuffered text I/O se = open(self.stderr, 'a+', 1) else: se = so os.dup2(si.fileno(), sys.stdin.fileno()) os.dup2(so.fileno(), sys.stdout.fileno()) os.dup2(se.fileno(), sys.stderr.fileno()) def sigtermhandler(signum, frame): self.daemon_alive = False sys.exit() if self.use_gevent: import gevent gevent.reinit() gevent.signal(signal.SIGTERM, sigtermhandler, signal.SIGTERM, None) gevent.signal(signal.SIGINT, sigtermhandler, signal.SIGINT, None) else: signal.signal(signal.SIGTERM, sigtermhandler) signal.signal(signal.SIGINT, sigtermhandler) self.log("Started") # Write pidfile atexit.register( self.delpid) # Make sure pid file is removed if we quit pid = str(os.getpid()) open(self.pidfile, 'w+').write("%s\n" % pid) def delpid(self): try: # the process may fork itself again pid = int(open(self.pidfile, 'r').read().strip()) if pid == os.getpid(): os.remove(self.pidfile) except OSError as e: if e.errno == errno.ENOENT: pass else: raise def start(self, *args, **kwargs): """ Start the daemon """ self.log("Starting...") # Check for a pidfile to see if the daemon already runs try: pf = open(self.pidfile, 'r') pid = int(pf.read().strip()) pf.close() except IOError: pid = None except SystemExit: pid = None if pid: message = "pidfile %s already exists. Is it already running?\n" sys.stderr.write(message % self.pidfile) sys.exit(1) # Start the daemon self.daemonize() self.run(*args, **kwargs) def stop(self): """ Stop the daemon """ if self.verbose >= 1: self.log("Stopping...") # Get the pid from the pidfile pid = self.get_pid() if not pid: message = "pidfile %s does not exist. Not running?\n" sys.stderr.write(message % self.pidfile) # Just to be sure. A ValueError might occur if the PID file is # empty but does actually exist if os.path.exists(self.pidfile): os.remove(self.pidfile) return # Not an error in a restart # Try killing the daemon process try: i = 0 while 1: os.kill(pid, signal.SIGTERM) time.sleep(0.1) i = i + 1 if i % 10 == 0: os.kill(pid, signal.SIGHUP) except OSError as err: if err.errno == errno.ESRCH: if os.path.exists(self.pidfile): os.remove(self.pidfile) else: print(str(err)) sys.exit(1) self.log("Stopped") def restart(self): """ Restart the daemon """ self.stop() self.start() def get_pid(self): try: pf = open(self.pidfile, 'r') pid = int(pf.read().strip()) pf.close() except IOError: pid = None except SystemExit: pid = None return pid def is_running(self): pid = self.get_pid() if pid is None: self.log('Process is stopped') return False elif os.path.exists('/proc/%d' % pid): self.log('Process (pid %d) is running...' % pid) return True else: self.log('Process (pid %d) is killed' % pid) return False def run(self, *args, **kwargs): """ Running app """ self.app(*args, **kwargs) #self.log("Starting foreground...") def main(cmd): from datetime import datetime from time import sleep import subprocess print("Starting cmd: ") print(str(cmd)) subprocess.call(cmd) #while True: # print(str(datetime.now())) # sleep(5) #def main2(cmd): # from bottle import route, run # @route('/') # def index(): # return 'Hello !' # run(host='localhost', port=8080) if __name__ == "__main__": if len(sys.argv) > 1: cmd=sys.argv[2:] app = cmd[0] if cmd else "daemonize2" pid = "/var/run/%s.pid"%app daemon = Daemon(main,pid) if "start" == sys.argv[1]: daemon.start(cmd) elif "stop" == sys.argv[1]: daemon.stop() elif "restart" == sys.argv[1]: daemon.restart() elif "manualstart" == sys.argv[1]: daemon.run(cmd) elif "status" == sys.argv[1]: daemon.is_running() else: print("Unknown command") sys.exit(2) sys.exit(0) else: print("usage: %s start|stop|restart|manualstart" % sys.argv[0]) sys.exit(2)