Skip to main content

running_process_platform_internal/
platform_linux_cmdline.rs

1
2    //! Linux `/proc/<pid>/cmdline` implementation. The kernel writes
3    //! argv as NUL-separated UTF-8 (typically — argv is opaque bytes,
4    //! we lossy-decode), with a trailing NUL.
5
6    pub fn read_process_cmdline(pid: u32) -> std::io::Result<String> {
7        if pid == 0 {
8            return Err(std::io::Error::new(
9                std::io::ErrorKind::InvalidInput,
10                "pid 0 is the kernel scheduler — not queryable",
11            ));
12        }
13        let path = format!("/proc/{pid}/cmdline");
14        let bytes = std::fs::read(&path)?;
15        // `/proc/<pid>/cmdline` is empty for kernel threads — return
16        // empty string rather than synthesizing fake separators.
17        if bytes.is_empty() {
18            return Ok(String::new());
19        }
20        // Drop the trailing NUL terminator if present, then turn
21        // remaining NUL separators into spaces so the result reads as
22        // a single shell-style command line (same convention as
23        // Windows NtQueryInformationProcess and macOS KERN_PROCARGS2,
24        // both of which return one logical command line per PID).
25        let mut trimmed = bytes.as_slice();
26        if trimmed.last() == Some(&0) {
27            trimmed = &trimmed[..trimmed.len() - 1];
28        }
29        let joined: Vec<u8> = trimmed
30            .iter()
31            .map(|b| if *b == 0 { b' ' } else { *b })
32            .collect();
33        Ok(String::from_utf8_lossy(&joined).into_owned())
34    }