// +build !windows package internal import ( "log" "os/exec" "syscall" "time" ) // KillGrace is the amount of time we allow a process to shutdown before // sending a SIGKILL. const KillGrace = 5 * time.Second // WaitTimeout waits for the given command to finish with a timeout. // It assumes the command has already been started. // If the command times out, it attempts to kill the process. func WaitTimeout(c *exec.Cmd, timeout time.Duration) error { var kill *time.Timer term := time.AfterFunc(timeout, func() { err := c.Process.Signal(syscall.SIGTERM) if err != nil { log.Printf("E! [agent] Error terminating process: %s", err) return } kill = time.AfterFunc(KillGrace, func() { err := c.Process.Kill() if err != nil { log.Printf("E! [agent] Error killing process: %s", err) return } }) }) err := c.Wait() // Shutdown all timers if kill != nil { kill.Stop() } termSent := !term.Stop() // If the process exited without error treat it as success. This allows a // process to do a clean shutdown on signal. if err == nil { return nil } // If SIGTERM was sent then treat any process error as a timeout. if termSent { return TimeoutErr } // Otherwise there was an error unrelated to termination. return err }