//go:build linux package procctl import ( "fmt" "os" "os/exec" "syscall" "time" "safesight-agent/internal/log" ) func isAlive(pid int) (bool, error) { if pid <= 0 { return false, nil } p, err := os.FindProcess(pid) if err != nil { return false, err } if err := p.Signal(syscall.Signal(0)); err != nil { return false, nil } return true, nil } func startProcess(execPath, workDir, configPath string) (int, error) { cmd := exec.Command(execPath, "--config", configPath) cmd.Dir = workDir cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} if err := cmd.Start(); err != nil { return 0, fmt.Errorf("start media-server: %w", err) } pid := cmd.Process.Pid go func() { err := cmd.Wait() if err != nil { log.Warn(fmt.Sprintf("media-server exited pid=%d err=%v", pid, err)) } else { log.Info(fmt.Sprintf("media-server exited pid=%d", pid)) } }() return pid, nil } func stopProcess(pid int, timeout time.Duration) error { if pid <= 0 { return nil } p, err := os.FindProcess(pid) if err != nil { return err } _ = p.Signal(syscall.SIGTERM) deadline := time.Now().Add(timeout) for time.Now().Before(deadline) { alive, _ := isAlive(pid) if !alive { return nil } time.Sleep(100 * time.Millisecond) } _ = p.Signal(syscall.SIGKILL) deadline = time.Now().Add(2 * time.Second) for time.Now().Before(deadline) { alive, _ := isAlive(pid) if !alive { return nil } time.Sleep(100 * time.Millisecond) } return fmt.Errorf("failed to stop pid=%d", pid) }