iredapd / libs /

#!/usr/bin/env python
# $Id: 7274 2008-03-05 01:00:09Z bmc $

# NOTE: Documentation is intended to be processed by epydoc and contains
# epydoc markup.


Convert the calling process to a daemon. To make the current Python process
into a daemon process, you need two lines of code::

    import daemon

If C{daemonize()} fails for any reason, it throws an exception. It also
logs debug messages, using the standard Python 'logging' package, to
channel 'daemon'.

Adapted from:

  - U{}

See Also

Stevens, W. Richard. I{Unix Network Programming} (Addison-Wesley, 1990).

__version__   = "1.0.1"
__author__    = "Brian Clapper,"
__url__       = ""
__copyright__ = "(c) 2008 Brian M. Clapper"
__license__   = "BSD-style license"

__all__ = ['daemonize', 'DaemonError']

# ---------------------------------------------------------------------------
# Imports
# ---------------------------------------------------------------------------

import logging
import os
import sys
import signal

# ---------------------------------------------------------------------------
# Constants
# ---------------------------------------------------------------------------

# Default daemon parameters.
# File mode creation mask of the daemon.
UMASK = 0077

# Default working directory for the daemon.

# Default maximum for the number of available file descriptors.
MAXFD = 1024

# The standard I/O file descriptors are redirected to /dev/null by default.
if (hasattr(os, "devnull")):
    NULL_DEVICE = os.devnull
    NULL_DEVICE = "/dev/null"

# ---------------------------------------------------------------------------
# Logging
# ---------------------------------------------------------------------------

log = logging.getLogger('daemonize')

# ---------------------------------------------------------------------------
# Public classes
# ---------------------------------------------------------------------------

class DaemonError(Exception):
    Thrown by C{daemonize()} when an error occurs while attempting to create
    a daemon. A C{DaemonException} object always contains a single string
    value that contains an error message describing the problem.
    def __init__(self, errorMessage):
        Create a new C{DaemonException}.

        @type errorMessage:  string
        @param errorMessage: the error message
        self.errorMessage = errorMessage

    def __str__(self):
        Get a string version of the exception.

        @return: a string representing the exception
        return self.errorMessage

# ---------------------------------------------------------------------------
# Public functions
# ---------------------------------------------------------------------------

def daemonize(noClose=False):
    Convert the calling process into a daemon.

    @type noClose:  boolean
    @param noClose: If True, don't close the file descriptors. Useful
                    if the calling process has already redirected file
                    descriptors to an output file. WARNING: Only set this
                    parameter to True if you're SURE there are no open file
                    descriptors to the calling terminal. Otherwise, you'll
                    risk having the daemon re-acquire a control terminal,
                    which can cause it to be killed if someone logs off that

    @raise DaemonException: Error during daemonizing
    global log

    if != 'posix':
        log.warn('Daemon is only supported on Posix-compliant systems.')

        # Fork once to go into the background.

        log.debug('Forking first child.')
        pid = _fork()
        if pid != 0:
            # Parent. Exit using os._exit(), which doesn't fire any atexit
            # functions.
        # First child. Create a new session. os.setsid() creates the session
        # and makes this (child) process the process group leader. The process
        # is guaranteed not to have a control terminal.
        log.debug('Creating new session')
        # Ignore SIGHUP
        signal.signal(signal.SIGHUP, signal.SIG_IGN)

        # Fork a second child to ensure that the daemon never reacquires
        # a control terminal.
        log.debug('Forking second child.')
        pid = _fork()
        if pid != 0:
            # Original child. Exit.
        # This is the second child. Set the umask.
        log.debug('Setting umask')
        # Go to a neutral corner (i.e., the primary file system, so
        # the daemon doesn't prevent some other file system from being
        # unmounted).
        log.debug('Changing working directory to "%s"' % WORKDIR)
        # Unless noClose was specified, close all file descriptors.
        if not noClose:
            log.debug('Redirecting file descriptors')

    except DaemonException:

    except OSError, e:
        raise DaemonException('Error during daemonizing: %s [%d]' %\
              (e.strerror, e.errno))

# ---------------------------------------------------------------------------
# Private functions
# ---------------------------------------------------------------------------

def _fork():
        return os.fork()
    except OSError, e:
        raise DaemonException, 'Cannot fork: %s [%d]' % (e.strerror, e.errno)

def _redirectFileDescriptors():
    import resource  # POSIX resource information
    maxfd = resource.getrlimit(resource.RLIMIT_NOFILE)[1]
    if maxfd == resource.RLIM_INFINITY:
        maxfd = MAXFD

    # Close all file descriptors.

    for fd in range(0, maxfd):
        # Only close TTYs.

        except OSError:
            # File descriptor wasn't open. Ignore.

    # Redirect standard input, output and error to something safe.
    # is guaranteed to return the lowest available file
    # descriptor (0, or standard input). Then, we can dup that descriptor
    # for standard output and standard error., os.O_RDWR)
    os.dup2(0, 1)
    os.dup2(0, 2)

# ---------------------------------------------------------------------------
# Main program (for testing)
# ---------------------------------------------------------------------------

if __name__ == '__main__':

    log = logging.getLogger('daemon')
    hdlr = logging.StreamHandler(sys.stdout)
    formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s', '%T')

    log.debug('Before daemonizing, PID=%d' % os.getpid())
    log.debug('After daemonizing, PID=%d' % os.getpid())
    log.debug('Daemon is sleeping for 10 seconds')

    import time

    log.debug('Daemon exiting')
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.