mirror of
https://github.com/rembo10/headphones.git
synced 2026-05-22 03:17:45 +01:00
Improved pidfile handling (from sickbeard)
Added signal watch to shutdown properly and remove pidfile (from sickbeard)
This commit is contained in:
+48
-26
@@ -16,6 +16,7 @@
|
||||
|
||||
import os, sys, locale
|
||||
import time
|
||||
import signal
|
||||
|
||||
from lib.configobj import ConfigObj
|
||||
|
||||
@@ -27,7 +28,10 @@ try:
|
||||
import argparse
|
||||
except ImportError:
|
||||
import lib.argparse as argparse
|
||||
|
||||
|
||||
signal.signal(signal.SIGINT, headphones.sig_handler)
|
||||
signal.signal(signal.SIGTERM, headphones.sig_handler)
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
@@ -36,10 +40,10 @@ def main():
|
||||
headphones.FULL_PATH = os.path.abspath(sys.executable)
|
||||
else:
|
||||
headphones.FULL_PATH = os.path.abspath(__file__)
|
||||
|
||||
|
||||
headphones.PROG_DIR = os.path.dirname(headphones.FULL_PATH)
|
||||
headphones.ARGS = sys.argv[1:]
|
||||
|
||||
|
||||
# From sickbeard
|
||||
headphones.SYS_PLATFORM = sys.platform
|
||||
headphones.SYS_ENCODING = None
|
||||
@@ -53,7 +57,7 @@ def main():
|
||||
# for OSes that are poorly configured I'll just force UTF-8
|
||||
if not headphones.SYS_ENCODING or headphones.SYS_ENCODING in ('ANSI_X3.4-1968', 'US-ASCII', 'ASCII'):
|
||||
headphones.SYS_ENCODING = 'UTF-8'
|
||||
|
||||
|
||||
# Set up and gather command line arguments
|
||||
parser = argparse.ArgumentParser(description='Music add-on for SABnzbd+')
|
||||
|
||||
@@ -65,55 +69,73 @@ def main():
|
||||
parser.add_argument('--config', help='Specify a config file to use')
|
||||
parser.add_argument('--nolaunch', action='store_true', help='Prevent browser from launching on startup')
|
||||
parser.add_argument('--pidfile', help='Create a pid file (only relevant when running as a daemon)')
|
||||
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.verbose:
|
||||
headphones.VERBOSE = 2
|
||||
elif args.quiet:
|
||||
headphones.VERBOSE = 0
|
||||
|
||||
|
||||
if args.daemon:
|
||||
headphones.DAEMON=True
|
||||
headphones.VERBOSE = 0
|
||||
if args.pidfile :
|
||||
headphones.PIDFILE = args.pidfile
|
||||
if sys.platform == 'win32':
|
||||
print "Daemonize not supported under Windows, starting normally"
|
||||
else:
|
||||
headphones.DAEMON=True
|
||||
headphones.VERBOSE = False
|
||||
|
||||
if args.pidfile:
|
||||
headphones.PIDFILE = str(args.pidfile)
|
||||
|
||||
# If the pidfile already exists, headphones may still be running, so exit
|
||||
if os.path.exists(headphones.PIDFILE):
|
||||
sys.exit("PID file '" + headphones.PIDFILE + "' already exists. Exiting.")
|
||||
|
||||
# The pidfile is only useful in daemon mode, make sure we can write the file properly
|
||||
if headphones.DAEMON:
|
||||
headphones.CREATEPID = True
|
||||
try:
|
||||
file(headphones.PIDFILE, 'w').write("pid\n")
|
||||
except IOError, e:
|
||||
raise SystemExit("Unable to write PID file: %s [%d]" % (e.strerror, e.errno))
|
||||
else:
|
||||
logger.warn("Not running in daemon mode. PID file creation disabled.")
|
||||
|
||||
if args.datadir:
|
||||
headphones.DATA_DIR = args.datadir
|
||||
else:
|
||||
headphones.DATA_DIR = headphones.PROG_DIR
|
||||
|
||||
|
||||
if args.config:
|
||||
headphones.CONFIG_FILE = args.config
|
||||
else:
|
||||
headphones.CONFIG_FILE = os.path.join(headphones.DATA_DIR, 'config.ini')
|
||||
|
||||
|
||||
# Try to create the DATA_DIR if it doesn't exist
|
||||
if not os.path.exists(headphones.DATA_DIR):
|
||||
try:
|
||||
os.makedirs(headphones.DATA_DIR)
|
||||
except OSError:
|
||||
raise SystemExit('Could not create data directory: ' + headphones.DATA_DIR + '. Exiting....')
|
||||
|
||||
|
||||
# Make sure the DATA_DIR is writeable
|
||||
if not os.access(headphones.DATA_DIR, os.W_OK):
|
||||
raise SystemExit('Cannot write to the data directory: ' + headphones.DATA_DIR + '. Exiting...')
|
||||
|
||||
|
||||
# Put the database in the DATA_DIR
|
||||
headphones.DB_FILE = os.path.join(headphones.DATA_DIR, 'headphones.db')
|
||||
|
||||
|
||||
headphones.CFG = ConfigObj(headphones.CONFIG_FILE, encoding='utf-8')
|
||||
|
||||
|
||||
# Read config & start logging
|
||||
headphones.initialize()
|
||||
|
||||
|
||||
if headphones.DAEMON:
|
||||
if sys.platform == "win32":
|
||||
print "Daemonize not supported under Windows, starting normally"
|
||||
else:
|
||||
headphones.daemonize()
|
||||
|
||||
|
||||
#configure the connection to the musicbrainz database
|
||||
headphones.mb.startmb()
|
||||
|
||||
@@ -123,8 +145,8 @@ def main():
|
||||
logger.info('Starting Headphones on forced port: %i' % http_port)
|
||||
else:
|
||||
http_port = int(headphones.HTTP_PORT)
|
||||
|
||||
# Try to start the server.
|
||||
|
||||
# Try to start the server.
|
||||
webstart.initialize({
|
||||
'http_port': http_port,
|
||||
'http_host': headphones.HTTP_HOST,
|
||||
@@ -133,15 +155,15 @@ def main():
|
||||
'http_username': headphones.HTTP_USERNAME,
|
||||
'http_password': headphones.HTTP_PASSWORD,
|
||||
})
|
||||
|
||||
|
||||
logger.info('Starting Headphones on port: %i' % http_port)
|
||||
|
||||
|
||||
if headphones.LAUNCH_BROWSER and not args.nolaunch:
|
||||
headphones.launch_browser(headphones.HTTP_HOST, http_port, headphones.HTTP_ROOT)
|
||||
|
||||
|
||||
# Start the background threads
|
||||
headphones.start()
|
||||
|
||||
|
||||
while True:
|
||||
if not headphones.SIGNAL:
|
||||
try:
|
||||
@@ -156,9 +178,9 @@ def main():
|
||||
headphones.shutdown(restart=True)
|
||||
else:
|
||||
headphones.shutdown(restart=True, update=True)
|
||||
|
||||
|
||||
headphones.SIGNAL = None
|
||||
|
||||
|
||||
return
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
+27
-28
@@ -41,6 +41,7 @@ SYS_ENCODING = None
|
||||
|
||||
VERBOSE = 1
|
||||
DAEMON = False
|
||||
CREATEPID = False
|
||||
PIDFILE= None
|
||||
|
||||
SCHED = Scheduler()
|
||||
@@ -577,42 +578,34 @@ def daemonize():
|
||||
|
||||
# Do first fork
|
||||
try:
|
||||
pid = os.fork()
|
||||
if pid == 0:
|
||||
pass
|
||||
else:
|
||||
# Exit the parent process
|
||||
logger.debug('Forking once...')
|
||||
os._exit(0)
|
||||
pid = os.fork() # @UndefinedVariable - only available in UNIX
|
||||
if pid != 0:
|
||||
sys.exit(0)
|
||||
except OSError, e:
|
||||
sys.exit("1st fork failed: %s [%d]" % (e.strerror, e.errno))
|
||||
raise RuntimeError("1st fork failed: %s [%d]" % (e.strerror, e.errno))
|
||||
|
||||
os.setsid()
|
||||
|
||||
# Do second fork
|
||||
# Make sure I can read my own files and shut out others
|
||||
prev = os.umask(0) # @UndefinedVariable - only available in UNIX
|
||||
os.umask(prev and int('077', 8))
|
||||
|
||||
# Make the child a session-leader by detaching from the terminal
|
||||
try:
|
||||
pid = os.fork()
|
||||
if pid > 0:
|
||||
logger.debug('Forking twice...')
|
||||
os._exit(0) # Exit second parent process
|
||||
pid = os.fork() # @UndefinedVariable - only available in UNIX
|
||||
if pid != 0:
|
||||
sys.exit(0)
|
||||
except OSError, e:
|
||||
sys.exit("2nd fork failed: %s [%d]" % (e.strerror, e.errno))
|
||||
raise RuntimeError("2nd fork failed: %s [%d]" % (e.strerror, e.errno))
|
||||
|
||||
os.chdir("/")
|
||||
os.umask(0)
|
||||
dev_null = file('/dev/null', 'r')
|
||||
os.dup2(dev_null.fileno(), sys.stdin.fileno())
|
||||
|
||||
si = open('/dev/null', "r")
|
||||
so = open('/dev/null', "a+")
|
||||
se = open('/dev/null', "a+")
|
||||
|
||||
os.dup2(si.fileno(), sys.stdin.fileno())
|
||||
os.dup2(so.fileno(), sys.stdout.fileno())
|
||||
os.dup2(se.fileno(), sys.stderr.fileno())
|
||||
|
||||
pid = os.getpid()
|
||||
pid = str(os.getpid())
|
||||
logger.info('Daemonized to PID: %s' % pid)
|
||||
if PIDFILE:
|
||||
logger.info('Writing PID %s to %s' % (pid, PIDFILE))
|
||||
|
||||
if CREATEPID:
|
||||
logger.info("Writing PID " + pid + " to " + str(PIDFILE))
|
||||
file(PIDFILE, 'w').write("%s\n" % pid)
|
||||
|
||||
def launch_browser(host, port, root):
|
||||
@@ -827,6 +820,11 @@ def start():
|
||||
|
||||
started = True
|
||||
|
||||
def sig_handler(signum=None, frame=None):
|
||||
if type(signum) != type(None):
|
||||
logger.info("Signal %i caught, saving and exiting..." % int(signum))
|
||||
shutdown()
|
||||
|
||||
def dbcheck():
|
||||
|
||||
conn=sqlite3.connect(DB_FILE)
|
||||
@@ -1013,6 +1011,7 @@ def shutdown(restart=False, update=False):
|
||||
|
||||
if not restart and not update:
|
||||
logger.info('Headphones is shutting down...')
|
||||
|
||||
if update:
|
||||
logger.info('Headphones is updating...')
|
||||
try:
|
||||
@@ -1020,7 +1019,7 @@ def shutdown(restart=False, update=False):
|
||||
except Exception, e:
|
||||
logger.warn('Headphones failed to update: %s. Restarting.' % e)
|
||||
|
||||
if PIDFILE :
|
||||
if CREATEPID :
|
||||
logger.info ('Removing pidfile %s' % PIDFILE)
|
||||
os.remove(PIDFILE)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user