# -*- coding: utf-8 -*- # # Copyright (C) 2006 Edgewall Software # All rights reserved. # # This software is licensed as described in the file COPYING, which # you should have received as part of this distribution. The terms # are also available at http://trac.edgewall.org/wiki/TracLicense. # # This software consists of voluntary contributions made by many # individuals. For the exact contribution history, see the revision # history and logs, available at http://trac.edgewall.org/log/. import atexit import errno import os import sys def daemonize(pidfile=None, progname=None, stdin='/dev/null', stdout='/dev/null', stderr='/dev/null', umask=022): """Fork a daemon process.""" if pidfile: # Check whether the pid file already exists and refers to a still # process running pidfile = os.path.abspath(pidfile) if os.path.exists(pidfile): fileobj = open(pidfile) try: try: pid = int(fileobj.read()) except ValueError: sys.exit('Invalid PID in file %s' % pidfile) finally: fileobj.close() try: # signal the process to see if it is still running os.kill(pid, 0) if not progname: progname = os.path.basename(sys.argv[0]) sys.exit('%s is already running with pid %s' % (progname, pid)) except OSError, e: if e.errno != errno.ESRCH: raise # Perform first fork pid = os.fork() if pid > 0: sys.exit(0) # exit first parent # Decouple from parent environment os.chdir('/') os.umask(umask) os.setsid() # Perform second fork pid = os.fork() if pid > 0: sys.exit(0) # exit second parent # The process is now daemonized, redirect standard file descriptors for stream in sys.stdout, sys.stderr: stream.flush() stdin = open(stdin, 'r') stdout = open(stdout, 'a+') stderr = open(stderr, 'a+', 0) os.dup2(stdin.fileno(), sys.stdin.fileno()) os.dup2(stdout.fileno(), sys.stdout.fileno()) os.dup2(stderr.fileno(), sys.stderr.fileno()) if pidfile: # Create/update the pid file, and register a hook to remove it when the # process exits fileobj = open(pidfile, 'w') try: fileobj.write(str(os.getpid())) finally: fileobj.close() def remove_pidfile(): if os.path.exists(pidfile): os.remove(pidfile) atexit.register(remove_pidfile)