package main import ( "bytes" "fmt" "os" "strconv" "strings" ) // readProcEnviron reads /proc/{pid}/environ (NUL-delimited KEY=VALUE pairs) // and returns the environment as a map. func readProcEnviron(procRoot string, pid int32) (map[string]string, error) { path := fmt.Sprintf("%s/%d/environ", procRoot, pid) data, err := os.ReadFile(path) if err != nil { return nil, err } env := make(map[string]string) for _, entry := range bytes.Split(data, []byte{0}) { if len(entry) == 0 { continue } parts := bytes.SplitN(entry, []byte("="), 2) if len(parts) == 2 { env[string(parts[0])] = string(parts[1]) } } return env, nil } // getParentPid reads /proc/{pid}/status and extracts the PPid field. // Returns 0 if pid 1 (init) is reached or the field cannot be parsed. func getParentPid(procRoot string, pid int32) (int32, error) { path := fmt.Sprintf("%s/%d/status", procRoot, pid) data, err := os.ReadFile(path) if err != nil { return 0, err } for _, line := range strings.Split(string(data), "\n") { if strings.HasPrefix(line, "PPid:") { fields := strings.Fields(line) if len(fields) >= 2 { ppid, err := strconv.ParseInt(fields[1], 10, 32) if err != nil { return 0, fmt.Errorf("parse PPid in %s: %w", path, err) } return int32(ppid), nil } } } return 0, fmt.Errorf("PPid not found in %s", path) }