From 1a865afe5bdd78bfd2023e6b07a5820abf2949ab Mon Sep 17 00:00:00 2001
From: Iustin Pop <iustin@google.com>
Date: Tue, 6 Nov 2012 15:23:34 +0100
Subject: [PATCH] Properly log errors when setting up daemon FDs

While writing the pipe-based reporting and trying various ways to
break the startup, I fought for a while trying to understand why error
reporting was _different_ when running the daemon as a user (with no
rights). It turns out that setupDaemonFDs wants to open the log file
in append mode way before, so we are not protected by the 'prepare'
phase.

This patch explicitly runs the 'setupDaemonFDs' function under the
same handler as the prepare phase, with the only change that here we
instruct handlePrepErr to not log the message via log*, since logging
is not yet set up.

Signed-off-by: Iustin Pop <iustin@google.com>
Reviewed-by: Michael Hanselmann <hansmi@google.com>
---
 htools/Ganeti/Daemon.hs | 14 ++++++++------
 1 file changed, 8 insertions(+), 6 deletions(-)

diff --git a/htools/Ganeti/Daemon.hs b/htools/Ganeti/Daemon.hs
index 8ad738796..73bdb1669 100644
--- a/htools/Ganeti/Daemon.hs
+++ b/htools/Ganeti/Daemon.hs
@@ -309,12 +309,14 @@ daemonize logfile action = do
   _ <- forkProcess $ do
     -- in the child
     closeFd rpipe
+    let wpipe' = Just wpipe
     setupDaemonEnv "/" (unionFileModes groupModes otherModes)
-    setupDaemonFDs $ Just logfile
+    setupDaemonFDs (Just logfile) `Control.Exception.catch`
+      handlePrepErr False wpipe'
     _ <- installHandler lostConnection (Catch (handleSigHup logfile)) Nothing
     -- second fork, launches the actual child code; standard
     -- double-fork technique
-    _ <- forkProcess (action (Just wpipe))
+    _ <- forkProcess (action wpipe')
     exitImmediately ExitSuccess
   closeFd wpipe
   hndl <- fdToHandle rpipe
@@ -397,21 +399,21 @@ innerMain :: GanetiDaemon  -- ^ The daemon we're running
           -> IO ()
 innerMain daemon opts syslog check_result prep_fn exec_fn fd = do
   prep_result <- fullPrep daemon opts syslog check_result prep_fn
-                 `Control.Exception.catch` handlePrepErr fd
+                 `Control.Exception.catch` handlePrepErr True fd
   -- no error reported, we should now close the fd
   maybeCloseFd fd
   exec_fn opts check_result prep_result
 
 -- | Daemon prepare error handling function.
-handlePrepErr :: Maybe Fd -> IOError -> IO a
-handlePrepErr fd err = do
+handlePrepErr :: Bool -> Maybe Fd -> IOError -> IO a
+handlePrepErr logging_setup fd err = do
   let msg = show err
   case fd of
     -- explicitly writing to the fd directly, since when forking it's
     -- better (safer) than trying to convert this into a full handle
     Just fd' -> fdWrite fd' msg >> return ()
     Nothing  -> hPutStrLn stderr (daemonStartupErr msg)
-  logError msg
+  when logging_setup $ logError msg
   exitWith $ ExitFailure 1
 
 -- | Close a file descriptor.
-- 
GitLab