62 lines
1.7 KiB
Go
62 lines
1.7 KiB
Go
|
|
//go:build linux
|
||
|
|
|
||
|
|
package main
|
||
|
|
|
||
|
|
import (
|
||
|
|
"fmt"
|
||
|
|
"os"
|
||
|
|
"strconv"
|
||
|
|
"strings"
|
||
|
|
"syscall"
|
||
|
|
)
|
||
|
|
|
||
|
|
// spec:26174-planctl-context-tokens/R1.2+R6.3+D§3.3
|
||
|
|
// ppidOf returns the parent PID of pid by reading /proc/<pid>/status.
|
||
|
|
// Returns 0 on error.
|
||
|
|
func ppidOf(pid int) int {
|
||
|
|
data, err := os.ReadFile(fmt.Sprintf("/proc/%d/status", pid))
|
||
|
|
if err != nil {
|
||
|
|
return 0
|
||
|
|
}
|
||
|
|
for _, line := range strings.Split(string(data), "\n") {
|
||
|
|
if strings.HasPrefix(line, "PPid:") {
|
||
|
|
s := strings.TrimSpace(strings.TrimPrefix(line, "PPid:"))
|
||
|
|
n, err := strconv.Atoi(s)
|
||
|
|
if err != nil {
|
||
|
|
return 0
|
||
|
|
}
|
||
|
|
return n
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return 0
|
||
|
|
}
|
||
|
|
|
||
|
|
// spec:26174-planctl-context-tokens/R6.3+D§3.3
|
||
|
|
// processAlive reports whether a process with pid exists.
|
||
|
|
func processAlive(pid int) bool {
|
||
|
|
if pid <= 0 {
|
||
|
|
return false
|
||
|
|
}
|
||
|
|
return syscall.Kill(pid, 0) == nil
|
||
|
|
}
|
||
|
|
|
||
|
|
// spec:26174-planctl-context-tokens/R6.3+D§3.3+D§4.1
|
||
|
|
// processStartTimeSec returns the process start time as raw clock ticks since boot,
|
||
|
|
// read from /proc/<pid>/stat field 22 (starttime). The hook writes the same units
|
||
|
|
// (clock ticks) on Linux per §5.5/§4.1, so comparison units match.
|
||
|
|
//
|
||
|
|
// The name retains "Sec" for API symmetry with the macOS implementation (which
|
||
|
|
// returns epoch seconds). Within a platform both sides match; cross-platform
|
||
|
|
// comparison never happens.
|
||
|
|
//
|
||
|
|
// /proc/<pid>/stat is a single line: "pid (comm) state ppid ... starttime ...".
|
||
|
|
// `comm` can contain spaces and parens. We find the LAST ')' and tokenize the
|
||
|
|
// remainder so comm noise can't shift field indices.
|
||
|
|
func processStartTimeSec(pid int) (int64, error) {
|
||
|
|
data, err := os.ReadFile(fmt.Sprintf("/proc/%d/stat", pid))
|
||
|
|
if err != nil {
|
||
|
|
return 0, err
|
||
|
|
}
|
||
|
|
return parseStatStartTime(string(data))
|
||
|
|
}
|