diff options
author | Tobias Bosch <tbosch@google.com> | 2019-08-16 11:47:00 -0700 |
---|---|---|
committer | Tobias Bosch <tbosch@google.com> | 2019-08-20 17:48:54 +0000 |
commit | a50a9c16b6a3b2522bea3b6562d023a7b87dbd49 (patch) | |
tree | 4d17d8e02962ba4e62c66e49f520cb1b310adc7d /compiler_wrapper/env.go | |
parent | 36c19215f13c983c2ae0096ed9170fd064744622 (diff) | |
download | toolchain-utils-a50a9c16b6a3b2522bea3b6562d023a7b87dbd49.tar.gz |
Forward os.Stdin to child processes.
BUG=chromium:773875
TEST=unit tests, build glibc with compiler wrapper
Change-Id: I0b5c1f5adaee18499b72747cd6042b00a9d52c1d
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/third_party/toolchain-utils/+/1760973
Reviewed-by: George Burgess <gbiv@chromium.org>
Tested-by: Tobias Bosch <tbosch@google.com>
Diffstat (limited to 'compiler_wrapper/env.go')
-rw-r--r-- | compiler_wrapper/env.go | 45 |
1 files changed, 37 insertions, 8 deletions
diff --git a/compiler_wrapper/env.go b/compiler_wrapper/env.go index 40bc2e41..bbf3ec45 100644 --- a/compiler_wrapper/env.go +++ b/compiler_wrapper/env.go @@ -17,9 +17,10 @@ type env interface { getenv(key string) string environ() []string getwd() string + stdin() io.Reader stdout() io.Writer stderr() io.Writer - run(cmd *command, stdout io.Writer, stderr io.Writer) error + run(cmd *command, stdin io.Reader, stdout io.Writer, stderr io.Writer) error exec(cmd *command) error } @@ -49,6 +50,10 @@ func (env *processEnv) getwd() string { return env.wd } +func (env *processEnv) stdin() io.Reader { + return os.Stdin +} + func (env *processEnv) stdout() io.Writer { return os.Stdout } @@ -62,16 +67,36 @@ func (env *processEnv) exec(cmd *command) error { return syscall.Exec(execCmd.Path, execCmd.Args, execCmd.Env) } -func (env *processEnv) run(cmd *command, stdout io.Writer, stderr io.Writer) error { +func (env *processEnv) run(cmd *command, stdin io.Reader, stdout io.Writer, stderr io.Writer) error { execCmd := newExecCmd(env, cmd) + execCmd.Stdin = stdin execCmd.Stdout = stdout execCmd.Stderr = stderr + _, stdinIsFile := stdin.(*os.File) + _, stdinIsBytesReader := stdin.(*bytes.Reader) + if stdin != nil && !stdinIsFile && !stdinIsBytesReader { + // We can't use execCmd.Run() here as that blocks if stdin blocks, + // even if the underlying process has already terminated. We care + // especially about the case when stdin is an io.TeeReader for os.Stdin. + // See https://github.com/golang/go/issues/7990 for more details. + if err := execCmd.Start(); err != nil { + return err + } + if _, err := execCmd.Process.Wait(); err != nil { + return err + } + // Closing Stdin here as we didn't wait for the read to finish via + // execCmd.Wait to prevent race conditions. + os.Stdin.Close() + return nil + } return execCmd.Run() } type commandRecordingEnv struct { env - cmdResults []*commandResult + stdinReader io.Reader + cmdResults []*commandResult } type commandResult struct { Cmd *command `json:"cmd"` @@ -82,16 +107,20 @@ type commandResult struct { var _ env = (*commandRecordingEnv)(nil) +func (env *commandRecordingEnv) stdin() io.Reader { + return env.stdinReader +} + func (env *commandRecordingEnv) exec(cmd *command) error { // Note: We treat exec the same as run so that we can do work // after the call. - return env.run(cmd, env.stdout(), env.stderr()) + return env.run(cmd, env.stdin(), env.stdout(), env.stderr()) } -func (env *commandRecordingEnv) run(cmd *command, stdout io.Writer, stderr io.Writer) error { +func (env *commandRecordingEnv) run(cmd *command, stdin io.Reader, stdout io.Writer, stderr io.Writer) error { stdoutBuffer := &bytes.Buffer{} stderrBuffer := &bytes.Buffer{} - err := env.env.run(cmd, io.MultiWriter(stdout, stdoutBuffer), io.MultiWriter(stderr, stderrBuffer)) + err := env.env.run(cmd, stdin, io.MultiWriter(stdout, stdoutBuffer), io.MultiWriter(stderr, stderrBuffer)) if exitCode, ok := getExitCode(err); ok { env.cmdResults = append(env.cmdResults, &commandResult{ Cmd: cmd, @@ -114,9 +143,9 @@ func (env *printingEnv) exec(cmd *command) error { return env.env.exec(cmd) } -func (env *printingEnv) run(cmd *command, stdout io.Writer, stderr io.Writer) error { +func (env *printingEnv) run(cmd *command, stdin io.Reader, stdout io.Writer, stderr io.Writer) error { printCmd(env, cmd) - return env.env.run(cmd, stdout, stderr) + return env.env.run(cmd, stdin, stdout, stderr) } func printCmd(env env, cmd *command) { |