(pid int)
| 54 | } |
| 55 | |
| 56 | func (e *Engine) ensureProcessLocked(pid int) *process.Process { |
| 57 | if _, ok := e.processes[pid]; !ok { |
| 58 | tgid, err := getThreadGroupID(pid) |
| 59 | if err != nil { |
| 60 | panic(fmt.Errorf("read process: %w", err)) |
| 61 | } |
| 62 | if tgid != pid { |
| 63 | leader := e.ensureProcessLocked(tgid) |
| 64 | e.threads[pid] = leader |
| 65 | return leader |
| 66 | } |
| 67 | |
| 68 | p, err := process.New(e.global, e.itab, pid) |
| 69 | if err != nil { |
| 70 | panic(fmt.Errorf("new process: %w", err)) |
| 71 | } |
| 72 | |
| 73 | slog.Debug("observed new process", "proc", p) |
| 74 | |
| 75 | // Import the new process' known inodes as sockets. We do this with the |
| 76 | // engine locked because this needs to happen exactly once for each process |
| 77 | // and must happen before handling the process' first syscall. |
| 78 | if err := e.importInodes(p); err != nil { |
| 79 | panic(fmt.Errorf("new process %d: import inodes: %w", p.PID, err)) |
| 80 | } |
| 81 | |
| 82 | e.processes[pid] = p |
| 83 | go e.waitProcess(p) |
| 84 | } |
| 85 | |
| 86 | return e.processes[pid] |
| 87 | } |
| 88 | |
| 89 | func (e *Engine) importInodes(p *process.Process) error { |
| 90 | dirfd, err := unix.Open(fmt.Sprintf("/proc/%d/fd/", p.PID), unix.O_RDONLY, 0o700) |
no test coverage detected