platform

package
v0.12.46 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 20, 2026 License: Apache-2.0 Imports: 11 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func IsWSL

func IsWSL() bool

IsWSL returns true when running under Windows Subsystem for Linux.

func KillPID

func KillPID(pid int, gracefulTimeout int) error

KillPID sends SIGTERM to the process group for pid, waits up to gracefulTimeout seconds, then escalates to SIGKILL. On Windows it uses TerminateProcess.

func KillSessionJobObject added in v0.12.41

func KillSessionJobObject(handle uintptr) error

KillSessionJobObject is a no-op on non-Windows platforms. The session-wide process containment on Unix is implemented via POSIX process groups (see sessionpgid_unix.go's KillSessionPGID) so this stub exists only so cross-platform callers in internal/daemon can invoke the API unconditionally without build tags. The handle parameter is always zero on non-Windows (the client never reports a job handle when SessionJobHandle is unset) and this function returns nil immediately.

func KillSessionPGID added in v0.12.41

func KillSessionPGID(sessionPGID int, killSelfPID int, gracefulTimeout time.Duration, aggressive bool) error

KillSessionPGID sends SIGTERM to the POSIX process group identified by sessionPGID, waits up to gracefulTimeout for the group to drain, then escalates to SIGKILL. This is the session-shutdown equivalent of signalProcessGroup: it reaps every process that inherited the pgid from the PTY child session leader, including `npm run dev &` style jobs the coding agent spawned via non-interactive bash (which does not enable job control and therefore does not give backgrounded pipelines their own pgid).

aggressive selects SIGKILL immediately (used when the daemon is in aggressive-shutdown mode with a tight deadline, matching the existing ProcessManager.StopAll behavior).

killSelfPID is the caller's own PID. It is EXCLUDED from the kill so the daemon does not signal itself when it happens to share the pgid (it shouldn't, but defensive). Pass 0 to disable self-exclusion.

Returns an error only for the final verification step; best-effort EPERM and ESRCH during signal delivery are not reported since they are normal (the group may drain mid-loop).

func MembersOfPGID added in v0.12.41

func MembersOfPGID(pgid int) []int

MembersOfPGID returns the PIDs of every process currently in the given POSIX process group. Callers: session cleanup (to verify the pgid is empty after SIGKILL), orphan scanning (to find sessions whose leaders are gone but children still live), and tests.

On WSL2 the same /proc layout applies, so no special-casing is needed. On platforms without /proc this falls back to best-effort: Getpgid(pid) on every pid in Scan() output. Returns nil on error.

func ReadProcCmdline added in v0.12.42

func ReadProcCmdline(pid int) string

ReadProcCmdline returns the /proc/<pid>/cmdline contents with NUL separators rewritten to spaces, trimmed of any trailing whitespace. An empty string is returned on any read error or when the entry is empty (kernel threads, raced-away processes).

The returned string is suitable for substring matching against well-known invocations like "agnt run" or a daemon binary path. Callers must not attempt to round-trip it back into argv — the space-join is lossy for arguments that themselves contain spaces.

func ReadProcCwd added in v0.12.42

func ReadProcCwd(pid int) string

ReadProcCwd returns the resolved /proc/<pid>/cwd symlink target. An empty string is returned on any error (permission denied, process gone, non-Linux /proc without cwd entries). Callers must not assume the path is still meaningful if the target directory has been deleted — the kernel reports "(deleted)" suffixes in that case, which this function preserves verbatim so callers can detect it if they care.

Types

type AncestorInfo added in v0.12.42

type AncestorInfo struct {
	PID     int
	PPID    int
	Cmdline string
	Cwd     string
}

AncestorInfo captures the per-process fields consulted by daemon-startup ownership gates when deciding whether an orphan pgid is plausibly owned by this daemon. Populated from /proc/<pid>/{cmdline,cwd,stat}.

PID is the ancestor's PID. Cmdline is the NUL-joined /proc/<pid>/cmdline rewritten as a single space-delimited string for substring matching. Cwd is the resolved /proc/<pid>/cwd symlink. Any field may be the empty string if the source /proc entry was unreadable (races where the process disappeared mid-walk are tolerated).

func WalkParents added in v0.12.42

func WalkParents(pid int) []AncestorInfo

WalkParents walks the parent chain of pid upward, returning each visited ancestor as an AncestorInfo with Cmdline and Cwd prepopulated. The walk includes PID 1 (init) in the chain — in production that's /sbin/init or systemd, whose cmdline and cwd will not match any agnt pattern and therefore contribute no evidence to ownership gates. In a PID namespace (unshare), PID 1 may be a meaningful ancestor (e.g. the namespace's designated init), which is exactly why we visit it: the procisolation daemon tests need to resolve reparented grandchildren back to a PID-namespaced init that impersonates a live agnt run.

The walk stops when:

  1. The next ppid is <= 0 (we've gone past init or the PID is a kernel thread with no parent recorded).
  2. The current pid itself is 0 (/proc/0 does not exist).
  3. /proc/<pid>/stat cannot be read for the current pid (race: the ancestor vanished between visits).
  4. A cycle is detected (PID re-seen; defensive, should not happen).
  5. A safety limit of 64 ancestors is reached (defensive).

The returned slice does NOT include pid itself — only strict ancestors. Callers that want the starting pid in the chain should prepend it.

This function is used by the daemon-startup orphan-pgid ownership gate to find an ancestor whose cmdline/cwd identifies the candidate pgid as owned by this daemon. Errors reading individual ancestors are silently skipped: the walk proceeds with whatever it can read.

type OrphanPGID added in v0.12.41

type OrphanPGID struct {
	PGID    int   // process group ID (= original session leader PID)
	Members []int // live member PIDs currently in this pgid
}

OrphanPGID describes a POSIX process group whose session leader PID is no longer alive but whose members are still running, owned by the caller's euid, and not members of any of the exclude sets the caller provided.

Found by ScanOrphanedPGIDs. Consumed by daemon startup cleanup to reap sessions that leaked across a daemon restart (see Slice B of task O9QzO07vM8JB).

func ScanOrphanedPGIDs added in v0.12.41

func ScanOrphanedPGIDs(callerUID int, excludePGIDs map[int]bool) []OrphanPGID

ScanOrphanedPGIDs enumerates /proc and returns every pgid that qualifies as orphaned for the purpose of daemon-startup cleanup. A pgid is orphaned when ALL of the following are true:

  1. The pgid itself is > 1 (pid 0/1 are never treated as pgids).
  2. The pgid is NOT in excludePGIDs (typically: the caller's own pgid plus the pgid of the daemon process and any ancestor we don't want to kill).
  3. The leader PID (the process whose PID equals the pgid, i.e. the original session leader) does NOT currently exist. This is the "leader died, members reparented to init" case Slice B targets.
  4. At least one live process is still a member of the pgid.
  5. EVERY live member is owned by the caller's real uid. This is the safety barrier: if any member belongs to a different uid, we skip the entire pgid to avoid ever touching another user's processes. (root daemon, for example, must not reap a non-root user's pgids.)

callerUID is the uid that members must match. Pass syscall.Getuid() in production; tests pass an arbitrary value to exercise filtering paths.

Returns nil on /proc read error or when /proc is unavailable (non-Linux Unix). Callers that need absolute correctness on those platforms must layer their own fallback. On Linux and WSL2 /proc is always present.

type ProcInfo

type ProcInfo struct {
	PID     int
	PPID    int    // parent PID (0 if unavailable)
	Command string // basename of the executable
	Cmdline string // full command line
	Cwd     string // working directory (may be empty on some platforms)
}

ProcInfo describes a running process discovered via OS-level scanning.

func Scan

func Scan() ([]ProcInfo, error)

Scan returns all running processes by reading /proc on Linux.

func ScanWindows

func ScanWindows() ([]ProcInfo, error)

ScanWindows returns Windows-side processes when running under WSL. On non-WSL Unix this returns nil.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL