15954: Close fds if Wait() doesn't return after child is killed.
authorTom Clegg <tom@tomclegg.ca>
Thu, 20 Feb 2020 19:22:56 +0000 (14:22 -0500)
committerTom Clegg <tom@tomclegg.ca>
Thu, 20 Feb 2020 19:25:04 +0000 (14:25 -0500)
Otherwise, PassengerAgent processes accumulate.

Arvados-DCO-1.1-Signed-off-by: Tom Clegg <tom@tomclegg.ca>

lib/boot/cmd.go

index 78cfc7b87542e07bd4f4c5aaa639e88cec234dd2..b11cb89e43bbfd6c2b578796a8749a464a31ccb7 100644 (file)
@@ -444,15 +444,24 @@ func (boot *Booter) RunProgram(ctx context.Context, dir string, output io.Writer
        if !strings.HasPrefix(dir, "/") {
                logprefix = dir + ": " + logprefix
        }
-       stderr := &logPrefixer{Writer: boot.Stderr, Prefix: []byte("[" + logprefix + "] ")}
 
        cmd := exec.Command(boot.lookPath(prog), args...)
+       stdout, err := cmd.StdoutPipe()
+       if err != nil {
+               return err
+       }
+       stderr, err := cmd.StderrPipe()
+       if err != nil {
+               return err
+       }
+       logwriter := &logPrefixer{Writer: boot.Stderr, Prefix: []byte("[" + logprefix + "] ")}
+       go io.Copy(logwriter, stderr)
        if output == nil {
-               cmd.Stdout = stderr
+               go io.Copy(logwriter, stdout)
        } else {
-               cmd.Stdout = output
+               go io.Copy(output, stdout)
        }
-       cmd.Stderr = stderr
+
        if strings.HasPrefix(dir, "/") {
                cmd.Dir = dir
        } else {
@@ -474,13 +483,19 @@ func (boot *Booter) RunProgram(ctx context.Context, dir string, output io.Writer
                                cmd.Process.Signal(syscall.SIGTERM)
                                time.Sleep(5 * time.Second)
                                if !exited {
+                                       stdout.Close()
+                                       stderr.Close()
                                        log.WithField("PID", cmd.Process.Pid).Warn("still waiting for child process to exit 5s after SIGTERM")
                                }
                        }
                }
        }()
 
-       err := cmd.Run()
+       err = cmd.Start()
+       if err != nil {
+               return err
+       }
+       err = cmd.Wait()
        if err != nil && ctx.Err() == nil {
                // Only report errors that happen before the context ends.
                return fmt.Errorf("%s: error: %v", cmdline, err)