Enhancement request: use syslog
kseistrup opened this issue · 3 comments
kseistrup commented
The quantumrandom-dev script works good. However, it'd be nice if it could use syslog as its output is invisible when run as a dæmon.
Cheers.
lmacken commented
Yeah, I'd like to see this as well.
First off, we need to get proper daemonization working with qrandom-dev. Then, adding syslog hooks to our current log() method should be fairly trivial.
kseistrup commented
Here's a suggestion for a daemonize() function (no error checking):
# -*- coding: utf-8 -*-
import os
from sys import stdin, stdout, stderr
# How do I get my program to act like a dæmon?
# http://www.unixguide.net/unix/programming/1.7.shtml
def daemonize():
# fork() so the parent can exit, this returns control to the
# command line or shell invoking your program. This step is
# required so that the new process is guaranteed not to be a
# process group leader. The next step, setsid(), fails if
# you're a process group leader.
pid = os.fork()
if pid > 0:
# First parent exits.
# We use _exit() to bypass normal exit processing.
os._exit(0)
# NB: From now on sys.exit() doesn't set a return code!
os.setsid()
# fork() again so the parent, the session group leader, can
# exit. This means that we, as a non-session group leader, can
# never regain a controlling terminal.
pid = os.fork()
if pid > 0:
# Second parent exits
# We use _exit() to bypass normal exit processing.
os._exit(0)
# Now let's decouple from parent environment
# chdir("/") to ensure that our process doesn't keep any directory
# in use. Failure to do this could make it so that an administrator
# couldn't unmount a filesystem, because it was our current directory.
os.chdir('/')
# so that we have complete control over the permissions of anything
# we write. We don't know what umask we may have inherited.
os.umask(0)
# close() fds 0, 1, and 2. This releases the standard in, out, and
# error we inherited from our parent process. We have no way of
# knowing where these fds might have been redirected to. Note that
# many daemons use sysconf() to determine the limit _SC_OPEN_MAX.
# _SC_OPEN_MAX tells you the maximum open files/process. Then in a
# loop, the daemon can close all possible file descriptors. You have
# to decide if you need to do this or not. If you think that there
# might be file-descriptors open you should close them, since there's
# a limit on number of concurrent file descriptors.
(fd0, fd1, fd2) = (stdin.fileno(), stdout.fileno(), stderr.fileno())
for i in range(os.sysconf('SC_OPEN_MAX') - 1, -1, -1):
# dup2() will close fd0, fd1 and fd2 in a while
if i not in (fd0, fd1, fd2):
try:
os.close(i)
except:
pass # Ignore EBADF
# Unbuffered resp. line buffered
# (names taken from, but values unrelated to, stdio.h)
(IONBUF, IOLBUF) = (0, 1)
fpi = file('/dev/null', 'r', IOLBUF)
fpo = file('/dev/null', 'w', IOLBUF)
fpe = file('/dev/null', 'wb', IONBUF)
os.dup2(fpi.fileno(), fd0)
os.dup2(fpo.fileno(), fd1)
os.dup2(fpe.fileno(), fd2)
# eof
Cheers.
kseistrup commented
PS: When run via upstart, or under dæmontools/runit, there's no need for daemonizing the script, so I suggest it be made optional via a command line switch…