bash % daemon.py stop
This recipe defines a function daemonize() that should be called at program startup to
make the program run as a daemon. The signature to daemonize() is using keyword-
only arguments to make the purpose of the optional arguments more clear when used.
This forces the user to use a call such as this:
As opposed to a more cryptic call such as:
# Illegal. Must use keyword arguments
The steps involved in creating a daemon are fairly cryptic, but the general idea is as
follows. First, a daemon has to detach itself from its parent process. This is the purpose
of the first os.fork() operation and immediate termination by the parent.
After the child has been orphaned, the call to os.setsid() creates an entirely new
process session and sets the child as the leader. This also sets the child as the leader of
a new process group and makes sure there is no controlling terminal. If this all sounds
a bit too magical, it has to do with getting the daemon to detach properly from the
terminal and making sure that things like signals don’t interfere with its operation.
The calls to os.chdir() and os.umask(0) change the current working directory and
reset the file mode mask. Changing the directory is usually a good idea so that the
daemon is no longer working in the directory from which it was launched.
The second call to os.fork() is by far the more mysterious operation here. This step
makes the daemon process give up the ability to acquire a new controlling terminal and
provides even more isolation (essentially, the daemon gives up its session leadership
and thus no longer has the permission to open controlling terminals). Although you
could probably omit this step, it’s typically recommended.
Once the daemon process has been properly detached, it performs steps to reinitialize
the standard I/O streams to point at files specified by the user. This part is actually
somewhat tricky. References to file objects associated with the standard I/O streams are
found in multiple places in the interpreter (sys.stdout, sys.__stdout__, etc.). Simply
closing sys.stdout and reassigning it is not likely to work correctly, because there’s no
way to know if it will fix all uses of sys.stdout. Instead, a separate file object is opened,
and the os.dup2() call is used to have it replace the file descriptor currently being used
12.14. Launching a Daemon Process on Unix | 537