Skip to content

Commit 3c7fc35

Browse files
committed
Make sure to kill potential sub-process on command exec.
exec.CommandContext calls cmd.Process.Kill(), whis only kills the Process itself, not any other processes it may have started.
1 parent 8fcdce6 commit 3c7fc35

File tree

1 file changed

+21
-13
lines changed

1 file changed

+21
-13
lines changed

internal/commands/commands.go

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
package commands
22

33
import (
4-
"context"
54
"fmt"
65
"io/ioutil"
76
"os/exec"
87
"sync"
8+
"syscall"
99
"time"
1010

1111
"github.com/gofrs/uuid"
@@ -88,12 +88,12 @@ func execute(command string, stdin []byte, environment map[string]string) ([]byt
8888
mux.RLock()
8989
defer mux.RUnlock()
9090

91-
cmd, ok := commands[command]
91+
cmdConfig, ok := commands[command]
9292
if !ok {
9393
return nil, nil, errors.New("command does not exist")
9494
}
9595

96-
cmdArgs, err := ParseCommandLine(cmd.Command)
96+
cmdArgs, err := ParseCommandLine(cmdConfig.Command)
9797
if err != nil {
9898
return nil, nil, errors.Wrap(err, "parse command error")
9999
}
@@ -105,28 +105,27 @@ func execute(command string, stdin []byte, environment map[string]string) ([]byt
105105
"command": command,
106106
"exec": cmdArgs[0],
107107
"args": cmdArgs[1:],
108-
"max_execution_duration": cmd.MaxExecutionDuration,
108+
"max_execution_duration": cmdConfig.MaxExecutionDuration,
109109
}).Info("commands: executing command")
110110

111-
ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(cmd.MaxExecutionDuration))
112-
defer cancel()
111+
cmd := exec.Command(cmdArgs[0], cmdArgs[1:]...)
112+
cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
113113

114-
cmdCtx := exec.CommandContext(ctx, cmdArgs[0], cmdArgs[1:]...)
115114
for k, v := range environment {
116-
cmdCtx.Env = append(cmdCtx.Env, fmt.Sprintf("%s=%s", k, v))
115+
cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", k, v))
117116
}
118117

119-
stdinPipe, err := cmdCtx.StdinPipe()
118+
stdinPipe, err := cmd.StdinPipe()
120119
if err != nil {
121120
return nil, nil, errors.Wrap(err, "get stdin pipe error")
122121
}
123122

124-
stdoutPipe, err := cmdCtx.StdoutPipe()
123+
stdoutPipe, err := cmd.StdoutPipe()
125124
if err != nil {
126125
return nil, nil, errors.Wrap(err, "get stdout pipe error")
127126
}
128127

129-
stderrPipe, err := cmdCtx.StderrPipe()
128+
stderrPipe, err := cmd.StderrPipe()
130129
if err != nil {
131130
return nil, nil, errors.Wrap(err, "get stderr pipe error")
132131
}
@@ -138,14 +137,23 @@ func execute(command string, stdin []byte, environment map[string]string) ([]byt
138137
}
139138
}()
140139

141-
if err := cmdCtx.Start(); err != nil {
140+
if err := cmd.Start(); err != nil {
142141
return nil, nil, errors.Wrap(err, "starting command error")
143142
}
144143

144+
time.AfterFunc(cmdConfig.MaxExecutionDuration, func() {
145+
pgid, err := syscall.Getpgid(cmd.Process.Pid)
146+
if err == nil {
147+
if err := syscall.Kill(-pgid, syscall.SIGKILL); err != nil {
148+
panic(err)
149+
}
150+
}
151+
})
152+
145153
stdoutB, _ := ioutil.ReadAll(stdoutPipe)
146154
stderrB, _ := ioutil.ReadAll(stderrPipe)
147155

148-
if err := cmdCtx.Wait(); err != nil {
156+
if err := cmd.Wait(); err != nil {
149157
return nil, nil, errors.Wrap(err, "waiting for command to finish error")
150158
}
151159

0 commit comments

Comments
 (0)