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