ghostscope_process/pid/
resolve.rs1use super::procfs::{
2 process_exists, read_nspid_chain, read_nspid_chain_from_status, read_pid_ns_id, read_status,
3};
4use super::types::{PidResolveSource, PidViews};
5
6fn push_unique_pid(pids: &mut Vec<u32>, pid: u32) {
7 if !pids.contains(&pid) {
8 pids.push(pid);
9 }
10}
11
12fn runtime_pid_candidates_from_chain(proc_pid: u32, nspid_chain: Option<&[u32]>) -> Vec<u32> {
13 let mut pids = Vec::new();
14 push_unique_pid(&mut pids, proc_pid);
15 if let Some(chain) = nspid_chain {
16 for pid in chain {
17 push_unique_pid(&mut pids, *pid);
18 }
19 }
20 pids
21}
22
23pub fn resolve_input_pid(input_pid: u32) -> anyhow::Result<PidViews> {
24 if !process_exists(input_pid) {
25 return Err(anyhow::anyhow!(
26 "Process with PID {} is not running. Use 'ps -p {}' to verify the process exists.\n\
27 Additional check: -p expects a PID visible in the current PID namespace.",
28 input_pid,
29 input_pid
30 ));
31 }
32
33 resolve_proc_pid(input_pid)
34}
35
36pub fn resolve_proc_pid(proc_pid: u32) -> anyhow::Result<PidViews> {
37 let status = read_status(proc_pid)?;
38 let nspid_chain = read_nspid_chain_from_status(&status);
39 let host_pid = nspid_chain
40 .as_ref()
41 .and_then(|chain| chain.first().copied())
42 .unwrap_or(proc_pid);
43 let container_pid = nspid_chain.as_ref().and_then(|chain| chain.last().copied());
44
45 Ok(PidViews {
46 proc_pid,
47 host_pid,
48 container_pid,
49 pid_ns: read_pid_ns_id(proc_pid),
50 nspid_chain,
51 source: PidResolveSource::DirectProcStatus,
52 })
53}
54
55pub fn host_pid_for_proc_pid(proc_pid: u32) -> u32 {
56 read_nspid_chain(proc_pid)
57 .and_then(|chain| chain.first().copied())
58 .unwrap_or(proc_pid)
59}
60
61pub fn resolve_proc_pid_for_event(event_pid: u32) -> u32 {
64 if std::path::Path::new(&format!("/proc/{event_pid}")).exists() {
65 return event_pid;
66 }
67
68 if let Ok(dir) = std::fs::read_dir("/proc") {
69 for ent in dir.flatten() {
70 let file_name = ent.file_name();
71 let Ok(proc_pid) = file_name.to_string_lossy().parse::<u32>() else {
72 continue;
73 };
74 let Some(chain) = read_nspid_chain(proc_pid) else {
75 continue;
76 };
77 if chain.first().copied() == Some(event_pid) {
78 return proc_pid;
79 }
80 }
81 }
82
83 event_pid
84}
85
86pub fn resolve_event_pid_for_proc(proc_pid: u32) -> u32 {
88 read_nspid_chain(proc_pid)
89 .and_then(|chain| chain.first().copied())
90 .unwrap_or(proc_pid)
91}
92
93pub fn runtime_pid_candidates_for_proc(proc_pid: u32) -> Vec<u32> {
99 let chain = read_nspid_chain(proc_pid);
100 runtime_pid_candidates_from_chain(proc_pid, chain.as_deref())
101}
102
103#[cfg(test)]
104mod tests {
105 use super::*;
106
107 #[test]
108 fn runtime_pid_candidates_include_proc_and_full_nspid_chain() {
109 assert_eq!(
110 runtime_pid_candidates_from_chain(445, Some(&[1000, 531, 17])),
111 vec![445, 1000, 531, 17]
112 );
113 }
114
115 #[test]
116 fn runtime_pid_candidates_deduplicate_proc_pid() {
117 assert_eq!(
118 runtime_pid_candidates_from_chain(531, Some(&[1000, 531, 17])),
119 vec![531, 1000, 17]
120 );
121 }
122}