Difference between revisions of "Daemonize Python"

From Noah.org
Jump to: navigation, search
Line 5: Line 5:
  
 
This short module shows the correct way to create a UNIX daemon process in Python. Creating a proper UNIX daemon is not as trivial as it sounds; although, some UNIX variants have system calls specifically for creating a daemon process.
 
This short module shows the correct way to create a UNIX daemon process in Python. Creating a proper UNIX daemon is not as trivial as it sounds; although, some UNIX variants have system calls specifically for creating a daemon process.
<pre class="code">
 
#!/usr/bin/env python
 
import sys, os, signal
 
  
'''This module is used to fork the current process into a daemon.
+
<include svncat src="file:///home/svn/src/python/daemonize.py" highlight="python" />
 
+
Almost none of this is necessary (or advisable) if your daemon
+
is being started by inetd. In that case, stdin, stdout and stderr are
+
all set up for you to refer to the network connection, and the fork()s
+
and session manipulation should not be done (to avoid confusing inetd).
+
Only the chdir() and umask() steps remain as useful.
+
 
+
References:
+
    UNIX Programming FAQ
+
        1.7 How do I get my program to act like a daemon?
+
        http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC16
+
 
+
    Advanced Programming in the Unix Environment
+
        W. Richard Stevens, 1992, Addison-Wesley, ISBN 0-201-56317-7.
+
 
+
Noah Spurrier
+
'''
+
 
+
def daemonize (stdin='/dev/null', stdout='/dev/null', stderr='/dev/null'):
+
    '''This forks the current process into a daemon.
+
    The stdin, stdout, and stderr arguments are file names that
+
    will be opened and be used to replace the standard file descriptors
+
    in sys.stdin, sys.stdout, and sys.stderr.
+
    These arguments are optional and default to /dev/null.
+
    Note that stderr is opened unbuffered, so
+
    if it shares a file with stdout then interleaved output
+
    may not appear in the order that you expect.
+
    '''
+
 
+
    # Do first fork.
+
    try:
+
        pid = os.fork()
+
        if pid > 0:
+
            return pid
+
    except OSError, e:
+
return (e.errno, e.strerror) # Fork failed.
+
 
+
    # Decouple from parent environment.
+
    os.setsid()
+
 
+
    # When the first child terminates, all processes in the second child
+
    # are sent a SIGHUP. This causes it to be ignored.
+
    signal.signal(signal.SIGHUP, signal.SIG_IGN)
+
 
+
    # Do second fork.
+
    try:
+
        pid = os.fork()
+
        if pid > 0:
+
            os._exit(0)  # Exit second parent.
+
    except OSError, e:
+
        sys.stderr.write ("fork #2 failed: (%d) %s\n" % (e.errno, e.strerror) )
+
        os._exit(1)
+
 
+
    # Now I am a daemon!
+
   
+
    os.chdir("/") # don't hold open any directories
+
    os.umask(0)
+
 
+
    # Close open files. Try the system configuration variable, SC_OPEN_MAX,
+
    # for the maximum number of open files to close. If it doesn't exist, use 1024.
+
    try:
+
        maxfd = os.sysconf("SC_OPEN_MAX")
+
    except (AttributeError, ValueError):
+
        maxfd = 1024
+
    for fd in range(3, maxfd):
+
        try:
+
            os.close(fd)
+
        except OSError:  # ERROR (ignore)
+
            pass
+
 
+
    # Redirect standard file descriptors.
+
    si = open(stdin, 'r')
+
    so = open(stdout, 'a+')
+
    se = open(stderr, 'a+', 0)
+
    os.dup2(si.fileno(), sys.stdin.fileno())
+
    os.dup2(so.fileno(), sys.stdout.fileno())
+
    os.dup2(se.fileno(), sys.stderr.fileno())
+
    return 0
+
 
+
def main ():
+
    '''This is an example main function run by the daemon.
+
    This prints a count and timestamp once per second.
+
    '''
+
    import time
+
    sys.stdout.write ('Daemon started with pid %d\n' % os.getpid() )
+
    sys.stdout.write ('Daemon stdout output\n')
+
    sys.stderr.write ('Daemon stderr output\n')
+
    c = 0
+
    while 1:
+
        sys.stdout.write ('%d: %s\n' % (c, time.ctime(time.time())) )
+
        sys.stdout.flush()
+
        c = c + 1
+
        time.sleep(1)
+
 
+
if __name__ == "__main__":
+
    print str(daemonize('/dev/null','/tmp/daemon.log','/tmp/daemon.log'))
+
    main()
+
</pre>
+

Revision as of 07:40, 7 December 2007

Python Daemonize source

This short module shows the correct way to create a UNIX daemon process in Python. Creating a proper UNIX daemon is not as trivial as it sounds; although, some UNIX variants have system calls specifically for creating a daemon process.

<include svncat src="file:///home/svn/src/python/daemonize.py" highlight="python" />