findXrayProcessesFromProc scans /proc directly (Linux-only)
(absPath string)
| 98 | |
| 99 | // findXrayProcessesFromProc scans /proc directly (Linux-only) |
| 100 | func findXrayProcessesFromProc(absPath string) ([]ProcessInfo, error) { |
| 101 | entries, err := os.ReadDir("/proc") |
| 102 | if err != nil { |
| 103 | return nil, err |
| 104 | } |
| 105 | |
| 106 | var processes []ProcessInfo |
| 107 | for _, entry := range entries { |
| 108 | if !entry.IsDir() { |
| 109 | continue |
| 110 | } |
| 111 | pid, err := strconv.Atoi(entry.Name()) |
| 112 | if err != nil || pid <= 0 { |
| 113 | continue |
| 114 | } |
| 115 | |
| 116 | // Check executable path |
| 117 | exePath, err := os.Readlink(fmt.Sprintf("/proc/%d/exe", pid)) |
| 118 | if err != nil { |
| 119 | continue |
| 120 | } |
| 121 | if !pathsMatch(exePath, absPath) { |
| 122 | continue |
| 123 | } |
| 124 | |
| 125 | statPath := fmt.Sprintf("/proc/%d/stat", pid) |
| 126 | data, err := os.ReadFile(statPath) |
| 127 | if err != nil { |
| 128 | continue |
| 129 | } |
| 130 | fields := strings.Fields(string(data)) |
| 131 | if len(fields) < 4 { |
| 132 | continue |
| 133 | } |
| 134 | state := fields[2] |
| 135 | ppid, err := strconv.Atoi(fields[3]) |
| 136 | if err != nil { |
| 137 | continue |
| 138 | } |
| 139 | |
| 140 | processes = append(processes, ProcessInfo{ |
| 141 | PID: pid, |
| 142 | PPID: ppid, |
| 143 | IsZombie: state == "Z" || state == "z", |
| 144 | }) |
| 145 | } |
| 146 | |
| 147 | return processes, nil |
| 148 | } |
| 149 | |
| 150 | // getProcessPath gets the full path of a process by PID on Unix |
| 151 | func getProcessPath(pid int) (string, error) { |
no test coverage detected