| // Copyright 2019 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| package botanist |
| |
| import ( |
| "context" |
| "os/exec" |
| "syscall" |
| ) |
| |
| // Run runs a command until completion or until a context is canceled, in |
| // which case the subprocess is killed so that no subprocesses it spun up are |
| // orphaned. |
| func Run(ctx context.Context, cmd exec.Cmd) error { |
| cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} |
| if err := cmd.Start(); err != nil { |
| return err |
| } |
| done := make(chan error) |
| go func() { |
| done <- cmd.Wait() |
| }() |
| |
| select { |
| case err := <-done: |
| return err |
| case <-ctx.Done(): |
| syscall.Kill(-cmd.Process.Pid, syscall.SIGKILL) |
| return ctx.Err() |
| } |
| } |