123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287 |
- #!/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 '<b>Hello </b>!'
-
- # 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)
|