Factor out various ways to execute subprocesses into separate functions.

This is so that they can be implemented properly for Windows. For now, though, they are left in blaze_util.cc since the Windows implementations aren't there yet.

--
MOS_MIGRATED_REVID=120709884
diff --git a/src/main/cpp/blaze.cc b/src/main/cpp/blaze.cc
index 65f7b65..3b7a044 100644
--- a/src/main/cpp/blaze.cc
+++ b/src/main/cpp/blaze.cc
@@ -492,38 +492,6 @@
   return result;
 }
 
-// Causes the current process to become a daemon (i.e. a child of
-// init, detached from the terminal, in its own session.)  We don't
-// change cwd, though.
-static void Daemonize() {
-  // Don't call die() or exit() in this function; we're already in a
-  // child process so it won't work as expected.  Just don't do
-  // anything that can possibly fail. :)
-
-  signal(SIGHUP, SIG_IGN);
-  if (fork() > 0) {
-    // This second fork is required iff there's any chance cmd will
-    // open an specific tty explicitly, e.g., open("/dev/tty23"). If
-    // not, this fork can be removed.
-    _exit(blaze_exit_code::SUCCESS);
-  }
-
-  setsid();
-
-  close(STDIN_FILENO);
-  close(STDOUT_FILENO);
-  close(STDERR_FILENO);
-
-  open("/dev/null", O_RDONLY);  // stdin
-  // stdout:
-  if (open(globals->jvm_log_file.c_str(),
-           O_WRONLY | O_CREAT | O_TRUNC, 0666) == -1) {
-    // In a daemon, no-one can hear you scream.
-    open("/dev/null", O_WRONLY);
-  }
-  dup(STDOUT_FILENO);  // stderr (2>&1)
-}
-
 // Do a chdir into the workspace, and die if it fails.
 static void GoToWorkspace() {
   if (BlazeStartupOptions::InWorkspace(globals->workspace) &&
@@ -589,33 +557,8 @@
   // we can still print errors to the terminal.
   GoToWorkspace();
 
-  int fds[2];
-  if (pipe(fds)) {
-    pdie(blaze_exit_code::INTERNAL_ERROR, "pipe creation failed");
-  }
-  int child = fork();
-  if (child == -1) {
-    pdie(blaze_exit_code::INTERNAL_ERROR, "fork() failed");
-  } else if (child > 0) {  // we're the parent
-    close(fds[1]);  // parent keeps only the reading side
-    return fds[0];
-  } else {
-    close(fds[0]);  // child keeps only the writing side
-  }
-
-  Daemonize();
-
-  // TODO(lberki): This writes the wrong PID on Windows because ExecuteProgram()
-  // invokes CreateProcess() there.
-  if (!WriteFile(ToString(getpid()), server_dir + "/server.pid")) {
-    // The exit code does not matter because we are already in the daemonized
-    // server. The output of this operation will end up in jvm.out .
-    pdie(0, "Cannot write PID file");
-  }
-
-  ExecuteProgram(exe, jvm_args_vector);
-  pdie(blaze_exit_code::INTERNAL_ERROR, "execv of '%s' failed", exe.c_str());
-  return -1;
+  return ExecuteDaemon(exe, jvm_args_vector, globals->jvm_log_file.c_str(),
+                server_dir + "/server.pid");
 }
 
 static bool KillRunningServerIfAny(BlazeServer *server);
diff --git a/src/main/cpp/blaze_util.cc b/src/main/cpp/blaze_util.cc
index 5740cb4..5421fb7 100644
--- a/src/main/cpp/blaze_util.cc
+++ b/src/main/cpp/blaze_util.cc
@@ -18,6 +18,7 @@
 #include <fcntl.h>
 #include <limits.h>
 #include <pwd.h>
+#include <signal.h>
 #include <stdarg.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -283,22 +284,20 @@
 
 // Read the Jvm version from a file descriptor. The read fd
 // should contains a similar output as the java -version output.
-string ReadJvmVersion(int fd) {
-  string version_string;
-  if (ReadFileDescriptor(fd, &version_string)) {
-    // try to look out for 'version "'
-    static const string version_pattern = "version \"";
-    size_t found = version_string.find(version_pattern);
-    if (found != string::npos) {
-      found += version_pattern.size();
-      // If we found "version \"", process until next '"'
-      size_t end = version_string.find("\"", found);
-      if (end == string::npos) {  // consider end of string as a '"'
-        end = version_string.size();
-      }
-      return version_string.substr(found, end - found);
+string ReadJvmVersion(const string& version_string) {
+  // try to look out for 'version "'
+  static const string version_pattern = "version \"";
+  size_t found = version_string.find(version_pattern);
+  if (found != string::npos) {
+    found += version_pattern.size();
+    // If we found "version \"", process until next '"'
+    size_t end = version_string.find("\"", found);
+    if (end == string::npos) {  // consider end of string as a '"'
+      end = version_string.size();
     }
+    return version_string.substr(found, end - found);
   }
+
   return "";
 }
 
@@ -307,28 +306,8 @@
   args.push_back("java");
   args.push_back("-version");
 
-  int fds[2];
-  if (pipe(fds)) {
-    pdie(blaze_exit_code::INTERNAL_ERROR, "pipe creation failed");
-  }
-
-  int child = fork();
-  if (child == -1) {
-    pdie(blaze_exit_code::INTERNAL_ERROR, "fork() failed");
-  } else if (child > 0) {  // we're the parent
-    close(fds[1]);         // parent keeps only the reading side
-    return ReadJvmVersion(fds[0]);
-  } else {
-    close(fds[0]);  // child keeps only the writing side
-    // Redirect output to the writing side of the dup.
-    dup2(fds[1], STDOUT_FILENO);
-    dup2(fds[1], STDERR_FILENO);
-    // Execute java -version
-    ExecuteProgram(java_exe, args);
-    pdie(blaze_exit_code::INTERNAL_ERROR, "Failed to run java -version");
-  }
-  // The if never falls through here.
-  return NULL;
+  string version_string = RunProgram(java_exe, args);
+  return ReadJvmVersion(version_string);
 }
 
 bool CheckJavaVersionIsAtLeast(const string &jvm_version,
@@ -357,4 +336,90 @@
   return true;
 }
 
+// Causes the current process to become a daemon (i.e. a child of
+// init, detached from the terminal, in its own session.)  We don't
+// change cwd, though.
+static void Daemonize(const string& daemon_output) {
+  // Don't call die() or exit() in this function; we're already in a
+  // child process so it won't work as expected.  Just don't do
+  // anything that can possibly fail. :)
+
+  signal(SIGHUP, SIG_IGN);
+  if (fork() > 0) {
+    // This second fork is required iff there's any chance cmd will
+    // open an specific tty explicitly, e.g., open("/dev/tty23"). If
+    // not, this fork can be removed.
+    _exit(blaze_exit_code::SUCCESS);
+  }
+
+  setsid();
+
+  close(0);
+  close(1);
+  close(2);
+
+  open("/dev/null", O_RDONLY);  // stdin
+  // stdout:
+  if (open(daemon_output.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0666) == -1) {
+    // In a daemon, no-one can hear you scream.
+    open("/dev/null", O_WRONLY);
+  }
+  dup(STDOUT_FILENO);  // stderr (2>&1)
+}
+
+int ExecuteDaemon(const string& exe, const std::vector<string>& args_vector,
+                  const string& daemon_output, const string& pid_file) {
+  int fds[2];
+  if (pipe(fds)) {
+    pdie(blaze_exit_code::INTERNAL_ERROR, "pipe creation failed");
+  }
+  int child = fork();
+  if (child == -1) {
+    pdie(blaze_exit_code::INTERNAL_ERROR, "fork() failed");
+  } else if (child > 0) {  // we're the parent
+    close(fds[1]);  // parent keeps only the reading side
+    return fds[0];
+  } else {
+    close(fds[0]);  // child keeps only the writing side
+  }
+
+  Daemonize(daemon_output);
+  if (!WriteFile(ToString(getpid()), pid_file)) {
+    // The exit code does not matter because we are already in the daemonized
+    // server. The output of this operation will end up in jvm.out .
+    pdie(0, "Cannot write PID file");
+  }
+
+  ExecuteProgram(exe, args_vector);
+  pdie(0, "Cannot execute %s", exe.c_str());
+}
+
+string RunProgram(const string& exe, const std::vector<string>& args_vector) {
+  int fds[2];
+  if (pipe(fds)) {
+    pdie(blaze_exit_code::INTERNAL_ERROR, "pipe creation failed");
+  }
+
+  int child = fork();
+  if (child == -1) {
+    pdie(blaze_exit_code::INTERNAL_ERROR, "fork() failed");
+  } else if (child > 0) {  // we're the parent
+    close(fds[1]);         // parent keeps only the reading side
+    string result;
+    if (!ReadFileDescriptor(fds[0], &result)) {
+      pdie(blaze_exit_code::INTERNAL_ERROR, "Cannot read subprocess output");
+    }
+
+    return result;
+  } else {  // We're the child
+    close(fds[0]);  // child keeps only the writing side
+    // Redirect output to the writing side of the dup.
+    dup2(fds[1], STDOUT_FILENO);
+    dup2(fds[1], STDERR_FILENO);
+    // Execute the binary
+    ExecuteProgram(exe, args_vector);
+    pdie(blaze_exit_code::INTERNAL_ERROR, "Failed to run %s", exe.c_str());
+  }
+}
+
 }  // namespace blaze
diff --git a/src/main/cpp/blaze_util.h b/src/main/cpp/blaze_util.h
index e0d1b2b..86a8256 100644
--- a/src/main/cpp/blaze_util.h
+++ b/src/main/cpp/blaze_util.h
@@ -82,12 +82,11 @@
 // Enable messages mostly of interest to developers.
 bool VerboseLogging();
 
-// Read the JVM version from a file descriptor. The fd should point
-// to the output of a "java -version" execution and is supposed to contains
-// a string of the form 'version "version-number"' in the first 255 bytes.
-// If the string is found, version-number is returned, else the empty string
-// is returned.
-string ReadJvmVersion(int fd);
+// Read the JVM version from a string. The string should contain the output of a
+// "java -version" execution and is supposed to contain a string of the form
+// 'version "version-number"' in the first 255 bytes. If the string is found,
+// version-number is returned, else the empty string is returned.
+string ReadJvmVersion(const string& version_string);
 
 // Get the version string from the given java executable. The java executable
 // is supposed to output a string in the form '.*version ".*".*'. This method
diff --git a/src/main/cpp/blaze_util_platform.h b/src/main/cpp/blaze_util_platform.h
index 4aa462e..42a2f5d 100644
--- a/src/main/cpp/blaze_util_platform.h
+++ b/src/main/cpp/blaze_util_platform.h
@@ -59,6 +59,17 @@
 // This function does not return on success.
 void ExecuteProgram(const string& exe, const std::vector<string>& args_vector);
 
+// Starts a daemon process with its standard output and standard error
+// redirected to the file "daemon_output". Returns a file descriptor of a named
+// pipe whose other end is held by the daemon and which is closed if the daemon
+// exits.
+int ExecuteDaemon(const string& exe, const std::vector<string>& args_vector,
+                   const string& daemon_output, const string& pid_file);
+
+// Executes a subprocess and returns its standard output and standard error.
+// If this fails, exits with the appropriate error code.
+string RunProgram(const string& exe, const std::vector<string>& args_vector);
+
 // Convert a path from Bazel internal form to underlying OS form.
 // On Unixes this is an identity operation.
 // On Windows, Bazel internal from is cygwin path, and underlying OS form