1use crate::CoreError;
12use std::path::Path;
13
14#[derive(Debug, Clone, PartialEq, Eq)]
16pub struct ProcStatus {
17 pub name: String,
19 pub uid: u32,
21}
22
23pub fn read_proc_status(pid: i32) -> Result<ProcStatus, CoreError> {
29 read_proc_status_at("/proc", pid)
30}
31
32pub fn read_proc_status_at(proc_root: impl AsRef<Path>, pid: i32) -> Result<ProcStatus, CoreError> {
38 let path = proc_root.as_ref().join(pid.to_string()).join("status");
39 let content = std::fs::read_to_string(path).map_err(|err| io_error(err, "read_proc_status"))?;
40 parse_proc_status(&content)
41}
42
43pub fn read_proc_cmdline(pid: i32) -> Result<String, CoreError> {
52 read_proc_cmdline_at("/proc", pid)
53}
54
55pub fn read_proc_cmdline_at(proc_root: impl AsRef<Path>, pid: i32) -> Result<String, CoreError> {
64 let path = proc_root.as_ref().join(pid.to_string()).join("cmdline");
65 let bytes = std::fs::read(path).map_err(|err| io_error(err, "read_proc_cmdline"))?;
66 Ok(parse_proc_cmdline_bytes(&bytes))
67}
68
69pub(crate) fn parse_proc_cmdline_bytes(bytes: &[u8]) -> String {
70 String::from_utf8_lossy(bytes)
71 .trim_end_matches('\0')
72 .replace('\0', " ")
73}
74
75pub fn parse_proc_status(content: &str) -> Result<ProcStatus, CoreError> {
77 let mut name = None;
78 let mut uid = None;
79
80 for line in content.lines() {
81 if let Some(rest) = line.strip_prefix("Name:") {
82 name = Some(rest.trim().to_string());
83 } else if let Some(rest) = line.strip_prefix("Uid:") {
84 uid = rest
85 .split_whitespace()
86 .next()
87 .and_then(|value| value.parse::<u32>().ok());
88 }
89
90 if name.is_some() && uid.is_some() {
91 break;
92 }
93 }
94
95 match (name, uid) {
96 (Some(name), Some(uid)) => Ok(ProcStatus { name, uid }),
97 _ => Err(CoreError::sys(libc::EINVAL, "parse_proc_status")),
98 }
99}
100
101fn io_error(err: std::io::Error, op: &'static str) -> CoreError {
102 CoreError::sys(err.raw_os_error().unwrap_or(libc::EIO), op)
103}
104
105#[inline(always)]
110pub fn clock_ticks_per_second() -> Result<u64, CoreError> {
111 let ticks = unsafe { libc::sysconf(libc::_SC_CLK_TCK) };
112 if ticks <= 0 {
113 let code = std::io::Error::last_os_error()
114 .raw_os_error()
115 .unwrap_or(libc::EINVAL);
116 Err(CoreError::sys(code, "sysconf(_SC_CLK_TCK)"))
117 } else {
118 Ok(ticks as u64)
119 }
120}