From 796345558a3a17408be2812ff0432be4ee6fe3e8 Mon Sep 17 00:00:00 2001 From: Iustin Pop <iustin@google.com> Date: Tue, 5 Oct 2010 13:36:45 +0200 Subject: [PATCH] Abstract daemon file descriptor setup This does some slight changes: - Daemonize() doesn't explicitly close the file-descriptors anymore, but only implicitly via the usage of dup2 - StartDaemonChild uses separate devnull for stdin (rdonly) and stdout/stderr (wronly), or if using a log file, it uses it in append mode Signed-off-by: Iustin Pop <iustin@google.com> Reviewed-by: Michael Hanselmann <hansmi@google.com> --- lib/utils.py | 63 ++++++++++++++++++++++++++++------------------------ 1 file changed, 34 insertions(+), 29 deletions(-) diff --git a/lib/utils.py b/lib/utils.py index 3a6d67a72..85ea39344 100644 --- a/lib/utils.py +++ b/lib/utils.py @@ -252,6 +252,38 @@ def SetupDaemonEnv(cwd="/", umask=077): os.setsid() +def SetupDaemonFDs(output_file, output_fd): + """Setups up a daemon's file descriptors. + + @param output_file: if not None, the file to which to redirect + stdout/stderr + @param output_fd: if not None, the file descriptor for stdout/stderr + + """ + # check that at most one is defined + assert [output_file, output_fd].count(None) >= 1 + + # Open /dev/null (read-only, only for stdin) + devnull_fd = os.open(os.devnull, os.O_RDONLY) + + if output_fd is not None: + pass + elif output_file is not None: + # Open output file + try: + output_fd = os.open(output_file, + os.O_WRONLY | os.O_CREAT | os.O_APPEND, 0600) + except EnvironmentError, err: + raise Exception("Opening output file failed: %s" % err) + else: + output_fd = os.open(os.devnull, os.O_WRONLY) + + # Redirect standard I/O + os.dup2(devnull_fd, 0) + os.dup2(output_fd, 1) + os.dup2(output_fd, 2) + + def StartDaemon(cmd, env=None, cwd="/", output=None, output_fd=None, pidfile=None): """Start a daemon process after forking twice. @@ -398,27 +430,7 @@ def _StartDaemonChild(errpipe_read, errpipe_write, else: fd_pidfile = None - # Open /dev/null - fd_devnull = os.open(os.devnull, os.O_RDWR) - - assert not output or (bool(output) ^ (fd_output is not None)) - - if fd_output is not None: - pass - elif output: - # Open output file - try: - # TODO: Implement flag to set append=yes/no - fd_output = os.open(output, os.O_WRONLY | os.O_CREAT, 0600) - except EnvironmentError, err: - raise Exception("Opening output file failed: %s" % err) - else: - fd_output = fd_devnull - - # Redirect standard I/O - os.dup2(fd_devnull, 0) - os.dup2(fd_output, 1) - os.dup2(fd_output, 2) + SetupDaemonFDs(output, fd_output) # Send daemon PID to parent RetryOnSignal(os.write, pidpipe_write, str(os.getpid())) @@ -2162,14 +2174,7 @@ def Daemonize(logfile): else: os._exit(0) # Exit parent of the first child. - for fd in range(3): - _CloseFDNoErr(fd) - i = os.open("/dev/null", os.O_RDONLY) # stdin - assert i == 0, "Can't close/reopen stdin" - i = os.open(logfile, os.O_WRONLY|os.O_CREAT|os.O_APPEND, 0600) # stdout - assert i == 1, "Can't close/reopen stdout" - # Duplicate standard output to standard error. - os.dup2(1, 2) + SetupDaemonFDs(logfile, None) return 0 -- GitLab