github.com/telepresenceio/telepresence/v2@v2.20.0-pro.6.0.20240517030216-236ea954e789/pkg/dpipe/dpipe.go (about) 1 package dpipe 2 3 import ( 4 "context" 5 "fmt" 6 "io" 7 "os/exec" //nolint:depguard // We want no logging and no soft-context signal handling 8 9 "github.com/datawire/dlib/dlog" 10 "github.com/telepresenceio/telepresence/v2/pkg/shellquote" 11 ) 12 13 func DPipe(ctx context.Context, peer io.ReadWriteCloser, cmdName string, cmdArgs ...string) error { 14 defer func() { 15 _ = peer.Close() 16 }() 17 18 cmd := exec.CommandContext(ctx, cmdName, cmdArgs...) 19 cmd.Stdin = peer 20 cmd.Stdout = peer 21 cmd.Stderr = dlog.StdLogger(ctx, dlog.LogLevelError).Writer() 22 23 cmdLine := shellquote.ShellString(cmd.Path, cmd.Args) 24 if err := cmd.Start(); err != nil { 25 return fmt.Errorf("failed to start %s: %w", cmdLine, err) 26 } 27 28 ctx = dlog.WithField(ctx, "exec.pid", cmd.Process.Pid) 29 dlog.Infof(ctx, "started command %s", cmdLine) 30 defer dlog.Infof(ctx, "ended command %s", cmdName) 31 runFinished := make(chan error) 32 go func() { 33 defer close(runFinished) 34 if err := cmd.Wait(); err != nil { 35 if !cmd.ProcessState.Success() && ctx.Err() == nil { 36 runFinished <- err 37 } 38 } 39 }() 40 41 select { 42 case <-ctx.Done(): 43 killProcess(ctx, cmd) 44 return nil 45 case err := <-runFinished: 46 return err 47 } 48 }