[Python-checkins] r70467 - peps/trunk/pep-3143.txt
brett.cannon
python-checkins at python.org
Thu Mar 19 03:14:42 CET 2009
Author: brett.cannon
Date: Thu Mar 19 03:14:42 2009
New Revision: 70467
Log:
Add PEP 3143: Standard daemon process library by Ben Finney.
Added:
peps/trunk/pep-3143.txt
Added: peps/trunk/pep-3143.txt
==============================================================================
--- (empty file)
+++ peps/trunk/pep-3143.txt Thu Mar 19 03:14:42 2009
@@ -0,0 +1,585 @@
+PEP: 3143
+Title: Standard daemon process library
+Version: $Revision: 1.1 $
+Last-Modified: $Date: 2009-03-19 12:51 $
+Author: Ben Finney <ben+python at benfinney.id.au>
+Status: Draft
+Type: Standards Track
+Content-Type: text/x-rst
+Created: 2009-01-26
+Python-Version: 3.2
+Post-History:
+
+
+========
+Abstract
+========
+
+Writing a program to become a well-behaved Unix daemon is somewhat
+complex and tricky to get right, yet the steps are largely similar for
+any daemon regardless of what else the program may need to do.
+
+This PEP introduces a package to the Python standard library that
+provides a simple interface to the task of becoming a daemon process.
+
+
+.. contents::
+..
+ Table of Contents:
+ Abstract
+ Specification
+ Example usage
+ Interface
+ ``DaemonContext`` objects
+ Motivation
+ Rationale
+ Correct daemon behaviour
+ A daemon is not a service
+ Reference Implementation
+ Other daemon implementations
+ References
+ Copyright
+
+
+=============
+Specification
+=============
+
+Example usage
+=============
+
+Simple example of direct `DaemonContext` usage::
+
+ import daemon
+
+ from spam import do_main_program
+
+ with daemon.DaemonContext() as daemon_context:
+ do_main_program()
+
+More complex example usage::
+
+ import os
+ import grp
+ import signal
+ import daemon
+ import lockfile
+
+ from spam import (
+ initial_program_setup,
+ do_main_program,
+ program_cleanup,
+ reload_program_config,
+ )
+
+ context = daemon.DaemonContext(
+ working_directory='/var/lib/foo',
+ umask=0o002,
+ pidfile=lockfile.FileLock('/var/run/spam.pid'),
+ )
+
+ context.signal_map = {
+ signal.SIGTERM: program_cleanup,
+ signal.SIGHUP: 'terminate',
+ signal.SIGUSR1: reload_program_config,
+ }
+
+ mail_gid = grp.getgrnam('mail').gr_gid
+ context.gid = mail_gid
+
+ important_file = open('spam.data', 'w')
+ interesting_file = open('eggs.data', 'w')
+ context.files_preserve = [important_file, interesting_file]
+
+ initial_program_setup()
+
+ with context:
+ do_main_program()
+
+
+Interface
+=========
+
+A new package, `daemon`, is added to the standard library.
+
+A class, `DaemonContext`, is defined to represent the settings and
+process context for the program running as a daemon process.
+
+
+``DaemonContext`` objects
+=========================
+
+A `DaemonContext` instance represents the behaviour settings and
+process context for the program when it becomes a daemon. The
+behaviour and environment is customised by setting options on the
+instance, before calling the `open` method.
+
+Each option can be passed as a keyword argument to the `DaemonContext`
+constructor, or subsequently altered by assigning to an attribute on
+the instance at any time prior to calling `open`. That is, for
+options named `wibble` and `wubble`, the following invocation::
+
+ foo = daemon.DaemonContext(wibble=bar, wubble=baz)
+ foo.open()
+
+is equivalent to::
+
+ foo = daemon.DaemonContext()
+ foo.wibble = bar
+ foo.wubble = baz
+ foo.open()
+
+The following options are defined.
+
+`files_preserve`
+ :Default: ``None``
+
+ List of files that should *not* be closed when starting the
+ daemon. If ``None``, all open file descriptors will be closed.
+
+ Elements of the list are file descriptors (as returned by a file
+ object's `fileno()` method) or Python `file` objects. Each
+ specifies a file that is not to be closed during daemon start.
+
+`chroot_directory`
+ :Default: ``None``
+
+ Full path to a directory to set as the effective root directory of
+ the process. If ``None``, specifies that the root directory is not
+ to be changed.
+
+`working_directory`
+ :Default: ``'/'``
+
+ Full path of the working directory to which the process should
+ change on daemon start.
+
+ Since a filesystem cannot be unmounted if a process has its
+ current working directory on that filesystem, this should either
+ be left at default or set to a directory that is a sensible “home
+ directory” for the daemon while it is running.
+
+`umask`
+ :Default: ``0``
+
+ File access creation mask (“umask”) to set for the process on
+ daemon start.
+
+ Since a process inherits its umask from its parent process,
+ starting the daemon will reset the umask to this value so that
+ files are created by the daemon with access modes as it expects.
+
+`pidfile`
+ :Default: ``None``
+
+ Context manager for a PID lock file. When the daemon context opens
+ and closes, it enters and exits the `pidfile` context manager.
+
+`detach_process`
+ :Default: ``None``
+
+ If ``True``, detach the process context when opening the daemon
+ context; if ``False``, do not detach.
+
+ If unspecified (``None``) during initialisation of the instance,
+ this will be set to ``True`` by default, and ``False`` only if
+ detaching the process is determined to be redundant; for example,
+ in the case when the process was started by `init`, by `initd`, or
+ by `inetd`.
+
+`signal_map`
+ :Default: system-dependent
+
+ Mapping from operating system signals to callback actions.
+
+ The mapping is used when the daemon context opens, and determines
+ the action for each signal's signal handler:
+
+ * A value of ``None`` will ignore the signal (by setting the
+ signal action to ``signal.SIG_IGN``).
+
+ * A string value will be used as the name of an attribute on the
+ ``DaemonContext`` instance. The attribute's value will be used
+ as the action for the signal handler.
+
+ * Any other value will be used as the action for the signal
+ handler.
+
+ The default value depends on which signals are defined on the
+ running system. Each item from the list below whose signal is
+ actually defined in the ``signal`` module will appear in the
+ default map:
+
+ * ``signal.SIGCLD``: ``None``
+
+ * ``signal.SIGTTIN``: ``None``
+
+ * ``signal.SIGTTOU``: ``None``
+
+ * ``signal.SIGTSTP``: ``None``
+
+ * ``signal.SIGTERM``: ``'terminate'``
+
+`uid`
+ :Default: ``os.getuid()``
+
+`gid`
+ :Default: ``os.getgid()``
+
+ The user ID (“UID”) value and group ID (“GID”) value to switch
+ the process to on daemon start.
+
+ The default values, the real UID and GID of the process, will
+ relinquish any effective privilege elevation inherited by the
+ process.
+
+`prevent_core`
+ :Default: ``True``
+
+ If true, prevents the generation of core files, in order to avoid
+ leaking sensitive information from daemons run as `root`.
+
+`stdin`
+ :Default: ``None``
+
+`stdout`
+ :Default: ``None``
+
+`stderr`
+ :Default: ``None``
+
+ Each of `stdin`, `stdout`, and `stderr` is a file-like object
+ which will be used as the new file for the standard I/O stream
+ `sys.stdin`, `sys.stdout`, and `sys.stderr` respectively. The file
+ should therefore be open, with a minimum of mode 'r' in the case
+ of `stdin`, and mode 'w+' in the case of `stdout` and `stderr`.
+
+ If the object has a `fileno()` method that returns a file
+ descriptor, the corresponding file will be excluded from being
+ closed during daemon start (that is, it will be treated as though
+ it were listed in `files_preserve`).
+
+ If ``None``, the corresponding system stream is re-bound to the
+ file named by `os.devnull`.
+
+
+The following methods are defined.
+
+`open()`
+ :Return: ``None``
+
+ Open the daemon context, turning the current program into a daemon
+ process. This performs the following steps:
+
+ * If the `prevent_core` attribute is true, set the resource limits
+ for the process to prevent any core dump from the process.
+
+ * If the `chroot_directory` attribute is not ``None``, set the
+ effective root directory of the process to that directory (via
+ `os.chroot`).
+
+ This allows running the daemon process inside a “chroot gaol”
+ as a means of limiting the system's exposure to rogue behaviour
+ by the process. Note that the specified directory needs to
+ already be set up for this purpose.
+
+ * Set the process UID and GID to the `uid` and `gid` attribute
+ values.
+
+ * Close all open file descriptors. This excludes those listed in
+ the `files_preserve` attribute, and those that correspond to the
+ `stdin`, `stdout`, or `stderr` attributes.
+
+ * Change current working directory to the path specified by the
+ `working_directory` attribute.
+
+ * Reset the file access creation mask to the value specified by
+ the `umask` attribute.
+
+ * If the `detach_process` option is true, detach the current
+ process into its own process group, and disassociate from any
+ controlling terminal.
+
+ * Set signal handlers as specified by the `signal_map` attribute.
+
+ * If any of the attributes `stdin`, `stdout`, `stderr` are not
+ ``None``, bind the system streams `sys.stdin`, `sys.stdout`,
+ and/or `sys.stderr` to the files represented by the
+ corresponding attributes. Where the attribute has a file
+ descriptor, the descriptor is duplicated (instead of re-binding
+ the name).
+
+ * If the `pidfile` attribute is not ``None``, enter its context
+ manager.
+
+ When the function returns, the running program is a daemon
+ process.
+
+`close()`
+ :Return: ``None``
+
+ Close the daemon context. This does nothing by default, but may be
+ overridden by a derived class.
+
+`terminate(signal_number, stack_frame)`
+ :Return: ``None``
+
+ Signal handler for the ``signal.SIGTERM`` signal. Performs the
+ following steps:
+
+ * If the `pidfile` attribute is not ``None``, exit its context
+ manager.
+
+ * Call the `close()` method.
+
+ * Raise a ``SystemExit`` exception.
+
+The class also implements the context manager protocol via
+``__enter__`` and ``__exit__`` methods.
+
+`__enter__()`
+ :Return: The ``DaemonContext`` instance
+
+ Call the instance's `open()` method, then return the instance.
+
+`__exit__(exc_type, exc_value, exc_traceback)`
+ :Return: ``True`` or ``False`` as defined by the context manager
+ protocol
+
+ Call the instance's `close()` method, then return ``True`` if the
+ exception was handled or ``False`` if it was not.
+
+
+==========
+Motivation
+==========
+
+The majority of programs written to be Unix daemons either implement
+behaviour very similar to that in the `specification`_, or are
+poorly-behaved daemons by the `correct daemon behaviour`_.
+
+Since these steps should be much the same in most implementations but
+are very particular and easy to omit or implement incorrectly, they
+are a prime target for a standard well-tested implementation in the
+standard library.
+
+
+=========
+Rationale
+=========
+
+Correct daemon behaviour
+========================
+
+According to Stevens in [stevens]_ §2.6, a program should perform the
+following steps to become a Unix daemon process.
+
+* Close all open file descriptors.
+
+* Change current working directory.
+
+* Reset the file access creation mask.
+
+* Run in the background.
+
+* Disassociate from process group.
+
+* Ignore terminal I/O signals.
+
+* Disassociate from control terminal.
+
+* Don't reacquire a control terminal.
+
+* Correctly handle the following circumstances:
+
+ * Started by System V `init` process.
+
+ * Daemon termination by ``SIGTERM`` signal.
+
+ * Children generate ``SIGCLD`` signal.
+
+The `daemon` tool [slack-daemon]_ lists (in its summary of features)
+behaviour that should be performed when turning a program into a
+well-behaved Unix daemon process. It differs from this PEP's intent in
+that it invokes a *separate* program as a daemon process. The
+following features are appropriate for a daemon that starts itself
+once the program is already running:
+
+* Sets up the correct process context for a daemon.
+
+* Behaves sensibly when started by `initd(8)` or `inetd(8)`.
+
+* Revokes any suid or sgid privileges to reduce security risks in case
+ daemon is incorrectly installed with special privileges.
+
+* Prevents the generation of core files to prevent leaking sensitive
+ information from daemons run as root (optional).
+
+* Names the daemon by creating and locking a PID file to guarantee
+ that only one daemon with the given name can execute at any given
+ time (optional).
+
+* Sets the user and group under which to run the daemon (optional,
+ root only).
+
+* Creates a chroot gaol (optional, root only).
+
+* Captures the daemon's stdout and stderr and directs them to syslog
+ (optional).
+
+A daemon is not a service
+=========================
+
+This PEP addresses only Unix-style daemons, for which the above
+correct behaviour is relevant, as opposed to comparable behaviours on
+other operating systems.
+
+There is a related concept in many systems, called a “service”. A
+service differs from the model in this PEP, in that rather than having
+the *current* program continue to run as a daemon process, a service
+starts an *additional* process to run in the background, and the
+current process communicates with that additional process via some
+defined channels.
+
+The Unix-style daemon model in this PEP can be used, among other
+things, to implement the background-process part of a service; but
+this PEP does not address the other aspects of setting up and managing
+a service.
+
+
+========================
+Reference Implementation
+========================
+
+The `python-daemon` package [python-daemon]_.
+
+Other daemon implementations
+============================
+
+Prior to this PEP, several existing third-party Python libraries or
+tools implemented some of this PEP's `correct daemon behaviour`_.
+
+The `reference implementation`_ is a fairly direct successor from the
+following implementations:
+
+* Many good ideas were contributed by the community to Python cookbook
+ recipes #66012 [cookbook-66012]_ and #278731 [cookbook-278731]_.
+
+* The `bda.daemon` library [bda.daemon]_ is an implementation of
+ [cookbook-66012]_. It is the predecessor of [python-daemon]_.
+
+Other Python daemon implementations that differ from this PEP:
+
+* The `zdaemon` tool [zdaemon]_ was written for the Zope project. Like
+ [slack-daemon]_, it differs from this specification because it is
+ used to run another program as a daemon process.
+
+* The Python library `daemon` [clapper-daemon]_ is (according to its
+ homepage) no longer maintained. As of version 1.0.1, it implements
+ the basic steps from [stevens]_.
+
+* The `daemonize` library [seutter-daemonize]_ also implements the
+ basic steps from [stevens]_.
+
+* Ray Burr's `daemon.py` module [burr-daemon]_ provides the [stevens]_
+ procedure as well as PID file handling and redirection of output to
+ syslog.
+
+* Twisted [twisted]_ includes, perhaps unsurprisingly, an
+ implementation of a process daemonisation API that is integrated
+ with the rest of the Twisted framework; it differs significantly
+ from the API in this PEP.
+
+* The Python `initd` library [dagitses-initd]_, which uses
+ [clapper-daemon]_, implements an equivalent of Unix `initd(8)` for
+ controlling a daemon process.
+
+
+==========
+References
+==========
+
+.. [stevens]
+
+ `Unix Network Programming`, W. Richard Stevens, 1994 Prentice
+ Hall.
+
+.. [slack-daemon]
+
+ The (non-Python) “libslack” implementation of a `daemon` tool
+ `<http://www.libslack.org/daemon/>`_ by “raf” <raf at raf.org>.
+
+.. [python-daemon]
+
+ The `python-daemon` library
+ `<http://pypi.python.org/pypi/python-daemon/>`_ by Ben Finney et
+ al.
+
+.. [cookbook-66012]
+
+ Python Cookbook recipe 66012, “Fork a daemon process on Unix”
+ `<http://code.activestate.com/recipes/66012/>`_.
+
+.. [cookbook-278731]
+
+ Python Cookbook recipe 278731, “Creating a daemon the Python way”
+ `<http://code.activestate.com/recipes/278731/>`_.
+
+.. [bda.daemon]
+
+ The `bda.daemon` library
+ `<http://pypi.python.org/pypi/bda.daemon/>`_ by Robert
+ Niederreiter et al.
+
+.. [zdaemon]
+
+ The `zdaemon` tool `<http://pypi.python.org/pypi/zdaemon/>`_ by
+ Guido van Rossum et al.
+
+.. [clapper-daemon]
+
+ The `daemon` library `<http://pypi.python.org/pypi/daemon/>`_ by
+ Brian Clapper.
+
+.. [seutter-daemonize]
+
+ The `daemonize` library `<http://daemonize.sourceforge.net/>`_ by
+ Jerry Seutter.
+
+.. [burr-daemon]
+
+ The `daemon.py` module
+ `<http://www.nightmare.com/~ryb/code/daemon.py>`_ by Ray Burr.
+
+.. [twisted]
+
+ The `Twisted` application framework
+ `<http://pypi.python.org/pypi/Twisted/>`_ by Glyph Lefkowitz et
+ al.
+
+.. [dagitses-initd]
+
+ The Python `initd` library `<http://pypi.python.org/pypi/initd/>`_
+ by Michael Andreas Dagitses.
+
+
+=========
+Copyright
+=========
+
+This work is hereby placed in the public domain. To the extent that
+placing a work in the public domain is not legally possible, the
+copyright holder hereby grants to all recipients of this work all
+rights and freedoms that would otherwise be restricted by copyright.
+
+
+..
+ Local variables:
+ mode: rst
+ coding: utf-8
+ time-stamp-start: "^:Last-Modified:[ ]+"
+ time-stamp-end: "$"
+ time-stamp-line-limit: 20
+ time-stamp-format: "%:y-%02m-%02d %02H:%02M"
+ End:
+ vim: filetype=rst fileencoding=utf-8 :
More information about the Python-checkins
mailing list