ghostscope_process/pid/
types.rs1use super::procfs::INITIAL_PID_NAMESPACE_INO;
2use std::fmt;
3
4#[derive(Debug, Clone, Copy, PartialEq, Eq)]
5pub struct PidAttachRequest {
6 pub input_pid: u32,
11}
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq)]
14pub enum PidResolveSource {
15 DirectProcStatus,
17}
18
19impl fmt::Display for PidResolveSource {
20 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
21 match self {
22 PidResolveSource::DirectProcStatus => write!(f, "direct-proc-status"),
23 }
24 }
25}
26
27#[derive(Debug, Clone, Copy, PartialEq, Eq)]
28pub struct PidNamespaceId {
29 pub dev: Option<u64>,
34 pub inode: u64,
35}
36
37impl PidNamespaceId {
38 pub fn helper_dev_inode(self) -> Option<(u64, u64)> {
39 self.dev.map(|dev| (dev, self.inode))
40 }
41}
42
43#[derive(Debug, Clone)]
44pub struct PidViews {
45 pub proc_pid: u32,
52 pub host_pid: u32,
54 pub container_pid: Option<u32>,
56 pub pid_ns: Option<PidNamespaceId>,
58 pub nspid_chain: Option<Vec<u32>>,
60 pub source: PidResolveSource,
62}
63
64impl PidViews {
65 pub fn compact_display(&self) -> String {
66 let container = self
67 .container_pid
68 .map(|value| value.to_string())
69 .unwrap_or_else(|| "n/a".to_string());
70 let ns_inode = self
71 .pid_ns_inode()
72 .map(|value| value.to_string())
73 .unwrap_or_else(|| "n/a".to_string());
74 let ns_dev = self
75 .pid_ns_dev()
76 .map(|value| value.to_string())
77 .unwrap_or_else(|| "n/a".to_string());
78 let chain = self
79 .nspid_chain
80 .as_ref()
81 .map(|values| {
82 values
83 .iter()
84 .map(|value| value.to_string())
85 .collect::<Vec<_>>()
86 .join("->")
87 })
88 .unwrap_or_else(|| "n/a".to_string());
89
90 format!(
91 "proc_pid={} host_pid={} container_pid={} ns_dev={} ns_inode={} nspid_chain={} source={}",
92 self.proc_pid, self.host_pid, container, ns_dev, ns_inode, chain, self.source
93 )
94 }
95
96 pub fn has_explicit_host_mapping(&self) -> bool {
97 self.nspid_chain
98 .as_ref()
99 .map(|chain| chain.len() >= 2)
100 .unwrap_or(false)
101 }
102
103 pub fn is_initial_pid_namespace(&self) -> bool {
104 self.pid_ns_inode() == Some(INITIAL_PID_NAMESPACE_INO)
105 }
106
107 pub fn pid_ns_dev(&self) -> Option<u64> {
108 self.pid_ns.and_then(|pid_ns| pid_ns.dev)
109 }
110
111 pub fn pid_ns_inode(&self) -> Option<u64> {
112 self.pid_ns.map(|pid_ns| pid_ns.inode)
113 }
114}
115
116#[cfg(test)]
117mod tests {
118 use super::*;
119
120 #[test]
121 fn initial_pid_namespace_detection_works() {
122 let mut pid_views = PidViews {
123 proc_pid: 123,
124 host_pid: 123,
125 container_pid: None,
126 pid_ns: Some(PidNamespaceId {
127 dev: Some(1),
128 inode: INITIAL_PID_NAMESPACE_INO,
129 }),
130 nspid_chain: None,
131 source: PidResolveSource::DirectProcStatus,
132 };
133 assert!(pid_views.is_initial_pid_namespace());
134
135 pid_views.pid_ns = Some(PidNamespaceId {
136 dev: Some(1),
137 inode: INITIAL_PID_NAMESPACE_INO + 1,
138 });
139 assert!(!pid_views.is_initial_pid_namespace());
140 }
141}