72 lines
2.0 KiB
Go
72 lines
2.0 KiB
Go
//go:build darwin
|
|
|
|
package main
|
|
|
|
import (
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
// macOS facts for the origin walk: one `ps` sweep with pid, ppid, tty and
|
|
// `comm`. "??" is no terminal.
|
|
//
|
|
// `comm` on macOS is argv[0] — usually a full path, because launchd and dyld
|
|
// exec with one, but chosen by the launcher all the same (Apple's ps maps the
|
|
// comm keyword to just_command, adv_cmds ps/keyword.c:101, which skips the
|
|
// kernel's saved exec_path to reach argv[0]). This file once said it was the
|
|
// kernel's path. Good enough to match the launchd inventory
|
|
// below; never an identity — procExe (agents_darwin.go) is that.
|
|
// No unit: launchd's label for a pid is a per-pid `launchctl procinfo`,
|
|
// too costly for a beat; interval jobs are recognised instead by matching
|
|
// the executable against the launchd inventory (originExtra.ScheduledExes).
|
|
|
|
func parsePSFacts(out string) map[int]procFacts {
|
|
m := map[int]procFacts{}
|
|
for _, line := range strings.Split(out, "\n") {
|
|
f := strings.Fields(line)
|
|
if len(f) < 4 {
|
|
continue
|
|
}
|
|
pid, err := strconv.Atoi(f[0])
|
|
if err != nil || pid <= 0 {
|
|
continue
|
|
}
|
|
ppid, _ := strconv.Atoi(f[1])
|
|
exe := strings.Join(f[3:], " ")
|
|
pf := procFacts{PID: pid, PPID: ppid, Comm: binBase(exe), Exe: exe}
|
|
if f[2] != "??" && f[2] != "-" {
|
|
pf.Interactive, pf.Detail = true, "tty "+f[2]
|
|
}
|
|
m[pid] = pf
|
|
}
|
|
return m
|
|
}
|
|
|
|
func procFactsReader() func(int) (procFacts, bool) {
|
|
var facts map[int]procFacts
|
|
return func(pid int) (procFacts, bool) {
|
|
if facts == nil {
|
|
facts = map[int]procFacts{}
|
|
if out, err := runTimed("ps", "-axo", "pid=,ppid=,tty=,comm="); err == nil {
|
|
facts = parsePSFacts(string(out))
|
|
}
|
|
}
|
|
f, ok := facts[pid]
|
|
return f, ok
|
|
}
|
|
}
|
|
|
|
func originExtras() originExtra {
|
|
exes := map[string]string{}
|
|
entries, _ := scanSchedulers()
|
|
for _, e := range entries {
|
|
if e.Kind != "launchd" || e.Schedule == "" {
|
|
continue
|
|
}
|
|
if argv := strings.Fields(e.Command); len(argv) > 0 {
|
|
exes[strings.ToLower(argv[0])] = e.Name
|
|
}
|
|
}
|
|
return originExtra{ScheduledExes: exes}
|
|
}
|