findChildPIDs takes a parent PID and returns a slice of all descendant PIDs.
(parentPID int)
| 1067 | |
| 1068 | // findChildPIDs takes a parent PID and returns a slice of all descendant PIDs. |
| 1069 | func findChildPIDs(parentPID int) ([]int, error) { |
| 1070 | var childPIDs []int |
| 1071 | |
| 1072 | // Recursive helper function to find all descendants of a given PID. |
| 1073 | var findDescendants func(int) |
| 1074 | findDescendants = func(pid int) { |
| 1075 | procDirs, err := os.ReadDir("/proc") |
| 1076 | if err != nil { |
| 1077 | return |
| 1078 | } |
| 1079 | |
| 1080 | for _, procDir := range procDirs { |
| 1081 | if !procDir.IsDir() { |
| 1082 | continue |
| 1083 | } |
| 1084 | |
| 1085 | childPid, err := strconv.Atoi(procDir.Name()) |
| 1086 | if err != nil { |
| 1087 | continue |
| 1088 | } |
| 1089 | |
| 1090 | statusPath := filepath.Join("/proc", procDir.Name(), "status") |
| 1091 | statusBytes, err := os.ReadFile(statusPath) |
| 1092 | if err != nil { |
| 1093 | continue |
| 1094 | } |
| 1095 | |
| 1096 | status := string(statusBytes) |
| 1097 | for _, line := range strings.Split(status, "\n") { |
| 1098 | if strings.HasPrefix(line, "PPid:") { |
| 1099 | fields := strings.Fields(line) |
| 1100 | if len(fields) == 2 { |
| 1101 | ppid, err := strconv.Atoi(fields[1]) |
| 1102 | if err != nil { |
| 1103 | break |
| 1104 | } |
| 1105 | if ppid == pid { |
| 1106 | childPIDs = append(childPIDs, childPid) |
| 1107 | findDescendants(childPid) |
| 1108 | } |
| 1109 | } |
| 1110 | break |
| 1111 | } |
| 1112 | } |
| 1113 | } |
| 1114 | } |
| 1115 | |
| 1116 | // Start the recursion with the initial parent PID. |
| 1117 | findDescendants(parentPID) |
| 1118 | |
| 1119 | return childPIDs, nil |
| 1120 | } |
| 1121 | |
| 1122 | // GetAvailablePort finds and returns an available port on the system |
| 1123 | func GetAvailablePort() (uint32, error) { |
no test coverage detected