Files

67 lines
1.1 KiB
Go

//go:build !windows
package externalcmd
import (
"errors"
"fmt"
"os"
"os/exec"
"syscall"
"github.com/kballard/go-shellquote"
)
func (c *Cmd) runOSSpecific(cmdstr string, env []string) error {
cmdParts, err := shellquote.Split(cmdstr)
if err != nil {
return err
}
for i, part := range cmdParts {
cmdParts[i] = expandEnv(part, c.Env)
}
cmd := exec.Command(cmdParts[0], cmdParts[1:]...)
cmd.Env = env
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
// set process group in order to allow killing subprocesses
cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
err = cmd.Start()
if err != nil {
return err
}
cmdDone := make(chan int)
go func() {
cmdDone <- func() int {
err2 := cmd.Wait()
if err2 == nil {
return 0
}
if ee, ok := errors.AsType[*exec.ExitError](err2); ok {
ee.ExitCode()
}
return 0
}()
}()
select {
case <-c.terminate:
// the minus is needed to kill all subprocesses
syscall.Kill(-cmd.Process.Pid, syscall.SIGINT) //nolint:errcheck
<-cmdDone
return errTerminated
case c := <-cmdDone:
if c != 0 {
return fmt.Errorf("command exited with code %d", c)
}
return nil
}
}