2026-03-28 17:14:39 +00:00
|
|
|
//go:build !windows
|
|
|
|
|
|
|
|
|
|
package pid
|
|
|
|
|
|
|
|
|
|
import (
|
2026-04-07 08:34:42 +00:00
|
|
|
"errors"
|
2026-06-04 09:50:54 +00:00
|
|
|
"fmt"
|
2026-03-28 17:14:39 +00:00
|
|
|
"os"
|
2026-06-04 09:50:54 +00:00
|
|
|
"strings"
|
2026-03-28 17:14:39 +00:00
|
|
|
"syscall"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// isProcessRunning checks whether a process with the given PID is alive
|
|
|
|
|
// on Unix-like systems using signal(0).
|
|
|
|
|
func isProcessRunning(pid int) bool {
|
|
|
|
|
if pid <= 0 {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
p, err := os.FindProcess(pid)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return false
|
|
|
|
|
}
|
2026-06-04 09:50:54 +00:00
|
|
|
// Signal(0) does not kill the process but checks existence on Unix.
|
2026-04-07 08:34:42 +00:00
|
|
|
err = p.Signal(syscall.Signal(0))
|
|
|
|
|
if err == nil {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
var errno syscall.Errno
|
|
|
|
|
// EPERM means the process exists but we are not allowed to signal it.
|
|
|
|
|
return errors.As(err, &errno) && errno == syscall.EPERM
|
2026-03-28 17:14:39 +00:00
|
|
|
}
|
2026-06-04 09:50:54 +00:00
|
|
|
|
|
|
|
|
// isPicoclawProcess reads /proc/<pid>/comm to confirm the process name
|
|
|
|
|
// contains "picoclaw". Returns false when the comm file can be read and
|
|
|
|
|
// the name does not match (e.g., PID was reused by an unrelated process).
|
|
|
|
|
// Returns true if /proc/<pid>/comm is unreadable so the call site falls
|
|
|
|
|
// back to trusting the liveness check alone.
|
|
|
|
|
func isPicoclawProcess(pid int) bool {
|
|
|
|
|
data, err := os.ReadFile(fmt.Sprintf("/proc/%d/comm", pid))
|
|
|
|
|
if err != nil {
|
|
|
|
|
return true // cannot verify — trust liveness check
|
|
|
|
|
}
|
|
|
|
|
return strings.Contains(strings.TrimSpace(string(data)), "picoclaw")
|
|
|
|
|
}
|