//go:build unix package runner import ( "os" "os/exec" "os/signal" "syscall" ) // startSignalForwarding installs handlers for SIGINT, SIGTERM, and SIGHUP and // forwards them to proc. The returned stop function removes the handlers and // drains the channel; callers should defer-call it. // // We deliberately do NOT exit on signal receipt — the child gets the signal // and owns its shutdown lifecycle; we just relay and keep waiting for it. func startSignalForwarding(proc *os.Process) func() { ch := make(chan os.Signal, 4) signal.Notify(ch, syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP) done := make(chan struct{}) go func() { for { select { case sig := <-ch: _ = proc.Signal(sig) case <-done: return } } }() return func() { signal.Stop(ch) close(done) } } // extractSignal pulls the signal from an *exec.ExitError on Unix. // If the error wasn't a signal termination, ok is false. func extractSignal(exitErr *exec.ExitError) (syscall.Signal, bool) { ws, ok := exitErr.Sys().(syscall.WaitStatus) if !ok { return 0, false } if !ws.Signaled() { return 0, false } return ws.Signal(), true }