From ed3920e3cfd0ce54f549beed90e3951f380907e4 Mon Sep 17 00:00:00 2001
From: Iustin Pop <iustin@google.com>
Date: Wed, 6 Oct 2010 11:15:09 +0200
Subject: [PATCH] Fix a rare bug in StartDaemonChild and GenericMain

I've seen cases where the result from str(sys.exc_info()[1]) is ""; this
breaks the error reporting as the parent relies on non-empty error
messages to properly detect child status (otherwise it will try to read
the pid and fail, so on).

While this was always in case of asserts, we need to ensure this doesn't
happen. Therefore we abstract this functionality (writing the error
message) and ensure we write a non-empty string in the new function.

Signed-off-by: Iustin Pop <iustin@google.com>
Reviewed-by: Michael Hanselmann <hansmi@google.com>
---
 lib/daemon.py |  3 +--
 lib/utils.py  | 21 ++++++++++++++++++---
 2 files changed, 19 insertions(+), 5 deletions(-)

diff --git a/lib/daemon.py b/lib/daemon.py
index 302097a19..c3c476178 100644
--- a/lib/daemon.py
+++ b/lib/daemon.py
@@ -671,8 +671,7 @@ def GenericMain(daemon_name, optionparser,
         prep_results = None
       logging.info("%s daemon startup", daemon_name)
     except Exception, err:
-      if wpipe is not None:
-        os.write(wpipe, _BeautifyError(err))
+      utils.WriteErrorToFD(wpipe, _BeautifyError(err))
       raise
 
     if wpipe is not None:
diff --git a/lib/utils.py b/lib/utils.py
index 54588cf89..095e38b65 100644
--- a/lib/utils.py
+++ b/lib/utils.py
@@ -435,9 +435,7 @@ def _StartDaemonChild(errpipe_read, errpipe_write,
   except: # pylint: disable-msg=W0702
     try:
       # Report errors to original process
-      buf = str(sys.exc_info()[1])
-
-      RetryOnSignal(os.write, errpipe_write, buf)
+      WriteErrorToFD(errpipe_write, str(sys.exc_info()[1]))
     except: # pylint: disable-msg=W0702
       # Ignore errors in error handling
       pass
@@ -445,6 +443,23 @@ def _StartDaemonChild(errpipe_read, errpipe_write,
   os._exit(1) # pylint: disable-msg=W0212
 
 
+def WriteErrorToFD(fd, err):
+  """Possibly write an error message to a fd.
+
+  @type fd: None or int (file descriptor)
+  @param fd: if not None, the error will be written to this fd
+  @param err: string, the error message
+
+  """
+  if fd is None:
+    return
+
+  if not err:
+    err = "<unknown error>"
+
+  RetryOnSignal(os.write, fd, err)
+
+
 def _RunCmdPipe(cmd, env, via_shell, cwd, interactive):
   """Run a command and return its output.
 
-- 
GitLab