Skip to content

Commit e74afc1

Browse files
authored
Revert "interp: send interrupt/kill signals to the whole process group" (mvdan#1244)
This reverts commit e256f53 and PR mvdan#1172 This reverted commit introduced a critical trade-off: interactive commands stopped worked (`ssh, `vim`, etc.). Since that fix was for an edge-case, it is not worth keeping that considering its side-effect. Closes mvdan#1242
1 parent 19def06 commit e74afc1

5 files changed

Lines changed: 15 additions & 49 deletions

File tree

cmd/gosh/main.go

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,7 @@ import (
1111
"fmt"
1212
"io"
1313
"os"
14-
"os/signal"
1514
"strings"
16-
"syscall"
1715

1816
"golang.org/x/term"
1917

@@ -37,49 +35,48 @@ func main() {
3735
}
3836

3937
func runAll() error {
40-
ctx, _ := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
41-
4238
r, err := interp.New(interp.Interactive(true), interp.StdIO(os.Stdin, os.Stdout, os.Stderr))
4339
if err != nil {
4440
return err
4541
}
4642

4743
if *command != "" {
48-
return run(ctx, r, strings.NewReader(*command), "")
44+
return run(r, strings.NewReader(*command), "")
4945
}
5046
if flag.NArg() == 0 {
5147
if term.IsTerminal(int(os.Stdin.Fd())) {
52-
return runInteractive(ctx, r, os.Stdin, os.Stdout, os.Stderr)
48+
return runInteractive(r, os.Stdin, os.Stdout, os.Stderr)
5349
}
54-
return run(ctx, r, os.Stdin, "")
50+
return run(r, os.Stdin, "")
5551
}
5652
for _, path := range flag.Args() {
57-
if err := runPath(ctx, r, path); err != nil {
53+
if err := runPath(r, path); err != nil {
5854
return err
5955
}
6056
}
6157
return nil
6258
}
6359

64-
func run(ctx context.Context, r *interp.Runner, reader io.Reader, name string) error {
60+
func run(r *interp.Runner, reader io.Reader, name string) error {
6561
prog, err := syntax.NewParser().Parse(reader, name)
6662
if err != nil {
6763
return err
6864
}
6965
r.Reset()
66+
ctx := context.Background()
7067
return r.Run(ctx, prog)
7168
}
7269

73-
func runPath(ctx context.Context, r *interp.Runner, path string) error {
70+
func runPath(r *interp.Runner, path string) error {
7471
f, err := os.Open(path)
7572
if err != nil {
7673
return err
7774
}
7875
defer f.Close()
79-
return run(ctx, r, f, path)
76+
return run(r, f, path)
8077
}
8178

82-
func runInteractive(ctx context.Context, r *interp.Runner, stdin io.Reader, stdout, stderr io.Writer) error {
79+
func runInteractive(r *interp.Runner, stdin io.Reader, stdout, stderr io.Writer) error {
8380
parser := syntax.NewParser()
8481
fmt.Fprintf(stdout, "$ ")
8582
for stmts, err := range parser.InteractiveSeq(stdin) {
@@ -90,6 +87,7 @@ func runInteractive(ctx context.Context, r *interp.Runner, stdin io.Reader, stdo
9087
fmt.Fprintf(stdout, "> ")
9188
continue
9289
}
90+
ctx := context.Background()
9391
for _, stmt := range stmts {
9492
err := r.Run(ctx, stmt)
9593
if r.Exited() {

cmd/gosh/main_test.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
package main
55

66
import (
7-
"context"
87
"fmt"
98
"io"
109
"os"
@@ -203,7 +202,7 @@ func TestInteractive(t *testing.T) {
203202
runner, _ := interp.New(interp.Interactive(true), interp.StdIO(inReader, outWriter, outWriter))
204203
errc := make(chan error, 1)
205204
go func() {
206-
errc <- runInteractive(context.Background(), runner, inReader, outWriter, outWriter)
205+
errc <- runInteractive(runner, inReader, outWriter, outWriter)
207206
// Discard the rest of the input.
208207
io.Copy(io.Discard, inReader)
209208
inReader.Close()
@@ -256,7 +255,7 @@ func TestInteractiveExit(t *testing.T) {
256255
}()
257256
w := io.Discard
258257
runner, _ := interp.New(interp.Interactive(true), interp.StdIO(inReader, w, w))
259-
if err := runInteractive(context.Background(), runner, inReader, w, w); err != nil {
258+
if err := runInteractive(runner, inReader, w, w); err != nil {
260259
t.Fatal("expected a nil error")
261260
}
262261
}

interp/handler.go

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -138,20 +138,19 @@ func DefaultExecHandler(killTimeout time.Duration) ExecHandlerFunc {
138138
Stdout: hc.Stdout,
139139
Stderr: hc.Stderr,
140140
}
141-
prepareCommand(&cmd)
142141

143142
err = cmd.Start()
144143
if err == nil {
145144
stopf := context.AfterFunc(ctx, func() {
146145
if killTimeout <= 0 || runtime.GOOS == "windows" {
147-
_ = killCommand(&cmd)
146+
_ = cmd.Process.Signal(os.Kill)
148147
return
149148
}
150-
_ = interruptCommand(&cmd)
149+
_ = cmd.Process.Signal(os.Interrupt)
151150
// TODO: don't sleep in this goroutine if the program
152151
// stops itself with the interrupt above.
153152
time.Sleep(killTimeout)
154-
_ = killCommand(&cmd)
153+
_ = cmd.Process.Signal(os.Kill)
155154
})
156155
defer stopf()
157156

interp/os_notunix.go

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ package interp
88
import (
99
"context"
1010
"fmt"
11-
"os/exec"
1211

1312
"mvdan.cc/sh/v3/syntax"
1413
)
@@ -56,16 +55,3 @@ type waitStatus struct{}
5655

5756
func (waitStatus) Signaled() bool { return false }
5857
func (waitStatus) Signal() int { return 0 }
59-
60-
// prepareCommand is a no-op.
61-
func prepareCommand(cmd *exec.Cmd) {}
62-
63-
// interruptCommand interrupts the process killing it.
64-
func interruptCommand(cmd *exec.Cmd) error {
65-
return cmd.Process.Kill()
66-
}
67-
68-
// killCommand kills the process by killing it.
69-
func killCommand(cmd *exec.Cmd) error {
70-
return cmd.Process.Kill()
71-
}

interp/os_unix.go

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ package interp
77

88
import (
99
"context"
10-
"os/exec"
1110
"os/user"
1211
"strconv"
1312
"syscall"
@@ -47,18 +46,3 @@ func (r *Runner) unTestOwnOrGrp(ctx context.Context, op syntax.UnTestOperator, x
4746
}
4847

4948
type waitStatus = syscall.WaitStatus
50-
51-
// prepareCommand sets the SysProcAttr for the command to create a new process group.
52-
func prepareCommand(cmd *exec.Cmd) {
53-
cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
54-
}
55-
56-
// interruptCommand interrupts the whole process group.
57-
func interruptCommand(cmd *exec.Cmd) error {
58-
return unix.Kill(-cmd.Process.Pid, unix.SIGINT)
59-
}
60-
61-
// killCommand kills the whole process group.
62-
func killCommand(cmd *exec.Cmd) error {
63-
return unix.Kill(-cmd.Process.Pid, unix.SIGKILL)
64-
}

0 commit comments

Comments
 (0)