diff --git a/internal/dind/dind.go b/internal/dind/dind.go index dcfc455..5ef4816 100644 --- a/internal/dind/dind.go +++ b/internal/dind/dind.go @@ -75,10 +75,7 @@ func Start(sessionID string) (*Instance, error) { // Stop removes the dind container and the shared network. Errors are printed to // stderr but not returned so that deferred calls always complete. func (i *Instance) Stop() { - if out, err := run("docker", "stop", i.ContainerName); err != nil { - fmt.Fprintf(os.Stderr, "construct: stop dind: %v\n%s\n", err, out) - } - if out, err := run("docker", "rm", i.ContainerName); err != nil { + if out, err := run("docker", "rm", "-f", i.ContainerName); err != nil { fmt.Fprintf(os.Stderr, "construct: rm dind: %v\n%s\n", err, out) } if out, err := run("docker", "network", "rm", i.NetworkName); err != nil { @@ -103,7 +100,11 @@ func (i *Instance) waitReady() error { } // run executes a command and returns its combined output and any error. +// It runs in its own process group so that SIGINT from Ctrl+C is not +// forwarded to the subprocess. func run(name string, args ...string) (string, error) { - out, err := exec.Command(name, args...).CombinedOutput() + cmd := exec.Command(name, args...) + setSysProcAttr(cmd) + out, err := cmd.CombinedOutput() return string(out), err } diff --git a/internal/dind/sysattr_unix.go b/internal/dind/sysattr_unix.go new file mode 100644 index 0000000..415e622 --- /dev/null +++ b/internal/dind/sysattr_unix.go @@ -0,0 +1,14 @@ +//go:build !windows + +package dind + +import ( + "os/exec" + "syscall" +) + +// setSysProcAttr places the command in its own process group so that a +// SIGINT from Ctrl+C on the terminal is not forwarded to the subprocess. +func setSysProcAttr(cmd *exec.Cmd) { + cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} +} diff --git a/internal/dind/sysattr_windows.go b/internal/dind/sysattr_windows.go new file mode 100644 index 0000000..55ef744 --- /dev/null +++ b/internal/dind/sysattr_windows.go @@ -0,0 +1,9 @@ +//go:build windows + +package dind + +import "os/exec" + +// setSysProcAttr is a no-op on Windows; process group isolation is not +// needed because Windows does not use POSIX process groups for signal delivery. +func setSysProcAttr(cmd *exec.Cmd) {}