+ // On error, close all pipes_ (ignoring errors, but that seems fine here).
+ auto pipesGuard = makeGuard([this] { pipes_.clear(); });
+
+ // Create a pipe to use to receive error information from the child,
+ // in case it fails before calling exec()
+ int errFds[2];
+#if FOLLY_HAVE_PIPE2
+ checkUnixError(::pipe2(errFds, O_CLOEXEC), "pipe2");
+#else
+ checkUnixError(::pipe(errFds), "pipe");
+#endif
+ SCOPE_EXIT {
+ CHECK_ERR(::close(errFds[0]));
+ if (errFds[1] >= 0) {
+ CHECK_ERR(::close(errFds[1]));
+ }
+ };
+
+#if !FOLLY_HAVE_PIPE2
+ // Ask the child to close the read end of the error pipe.
+ checkUnixError(fcntl(errFds[0], F_SETFD, FD_CLOEXEC), "set FD_CLOEXEC");
+ // Set the close-on-exec flag on the write side of the pipe.
+ // This way the pipe will be closed automatically in the child if execve()
+ // succeeds. If the exec fails the child can write error information to the
+ // pipe.
+ checkUnixError(fcntl(errFds[1], F_SETFD, FD_CLOEXEC), "set FD_CLOEXEC");
+#endif
+
+ // Perform the actual work of setting up pipes then forking and
+ // executing the child.
+ spawnInternal(std::move(argv), executable, options, env, errFds[1]);
+
+ // After spawnInternal() returns the child is alive. We have to be very
+ // careful about throwing after this point. We are inside the constructor,
+ // so if we throw the Subprocess object will have never existed, and the
+ // destructor will never be called.
+ //
+ // We should only throw if we got an error via the errFd, and we know the
+ // child has exited and can be immediately waited for. In all other cases,
+ // we have no way of cleaning up the child.
+
+ // Close writable side of the errFd pipe in the parent process
+ CHECK_ERR(::close(errFds[1]));
+ errFds[1] = -1;
+
+ // Read from the errFd pipe, to tell if the child ran into any errors before
+ // calling exec()
+ readChildErrorPipe(errFds[0], executable);
+
+ // We have fully succeeded now, so release the guard on pipes_
+ pipesGuard.dismiss();
+}
+
+void Subprocess::spawnInternal(
+ std::unique_ptr<const char*[]> argv,
+ const char* executable,
+ Options& options,
+ const std::vector<std::string>* env,
+ int errFd) {