55 lines
1.2 KiB
Go
55 lines
1.2 KiB
Go
//go:build windows
|
|
|
|
package codex
|
|
|
|
import (
|
|
"bytes"
|
|
"errors"
|
|
"fmt"
|
|
"os"
|
|
"os/exec"
|
|
"strconv"
|
|
"strings"
|
|
"syscall"
|
|
)
|
|
|
|
func prepareCmdForKill(cmd *exec.Cmd) {
|
|
if cmd == nil {
|
|
return
|
|
}
|
|
if cmd.SysProcAttr == nil {
|
|
cmd.SysProcAttr = &syscall.SysProcAttr{}
|
|
}
|
|
cmd.SysProcAttr.CreationFlags |= syscall.CREATE_NEW_PROCESS_GROUP
|
|
}
|
|
|
|
func forceKillCmd(cmd *exec.Cmd) error {
|
|
if cmd == nil || cmd.Process == nil {
|
|
return nil
|
|
}
|
|
killCmd := exec.Command("taskkill", "/T", "/F", "/PID", strconv.Itoa(cmd.Process.Pid))
|
|
output, err := killCmd.CombinedOutput()
|
|
if err == nil {
|
|
return nil
|
|
}
|
|
if bytes.Contains(bytes.ToLower(output), []byte("there is no running instance")) {
|
|
return nil
|
|
}
|
|
if bytes.Contains(bytes.ToLower(output), []byte("not found")) {
|
|
return nil
|
|
}
|
|
if killErr := cmd.Process.Kill(); killErr == nil || errors.Is(killErr, os.ErrProcessDone) {
|
|
return nil
|
|
} else {
|
|
return fmt.Errorf("taskkill failed: %w: %s; process kill fallback failed: %w", err, processKillOutput(output), killErr)
|
|
}
|
|
}
|
|
|
|
func processKillOutput(output []byte) string {
|
|
trimmed := strings.TrimSpace(string(output))
|
|
if trimmed == "" {
|
|
return "(empty output)"
|
|
}
|
|
return trimmed
|
|
}
|