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> {
26 read_proc_status_at("/proc", pid)
27}
28
29pub fn read_proc_status_at(proc_root: impl AsRef<Path>, pid: i32) -> Result<ProcStatus, CoreError> {
31 let path = proc_root.as_ref().join(pid.to_string()).join("status");
32 let content = std::fs::read_to_string(path).map_err(|err| io_error(err, "read_proc_status"))?;
33 parse_proc_status(&content)
34}
35
36pub fn read_proc_cmdline(pid: i32) -> Result<String, CoreError> {
41 read_proc_cmdline_at("/proc", pid)
42}
43
44pub fn read_proc_cmdline_at(proc_root: impl AsRef<Path>, pid: i32) -> Result<String, CoreError> {
49 let path = proc_root.as_ref().join(pid.to_string()).join("cmdline");
50 let bytes = std::fs::read(path).map_err(|err| io_error(err, "read_proc_cmdline"))?;
51 Ok(parse_proc_cmdline_bytes(&bytes))
52}
53
54pub(crate) fn parse_proc_cmdline_bytes(bytes: &[u8]) -> String {
55 String::from_utf8_lossy(bytes)
56 .trim_end_matches('\0')
57 .replace('\0', " ")
58}
59
60pub fn parse_proc_status(content: &str) -> Result<ProcStatus, CoreError> {
62 let mut name = None;
63 let mut uid = None;
64
65 for line in content.lines() {
66 if let Some(rest) = line.strip_prefix("Name:") {
67 name = Some(rest.trim().to_string());
68 } else if let Some(rest) = line.strip_prefix("Uid:") {
69 uid = rest
70 .split_whitespace()
71 .next()
72 .and_then(|value| value.parse::<u32>().ok());
73 }
74
75 if name.is_some() && uid.is_some() {
76 break;
77 }
78 }
79
80 match (name, uid) {
81 (Some(name), Some(uid)) => Ok(ProcStatus { name, uid }),
82 _ => Err(CoreError::sys(libc::EINVAL, "parse_proc_status")),
83 }
84}
85
86fn io_error(err: std::io::Error, op: &'static str) -> CoreError {
87 CoreError::sys(err.raw_os_error().unwrap_or(libc::EIO), op)
88}
89
90#[inline(always)]
92pub fn clock_ticks_per_second() -> Result<u64, CoreError> {
93 let ticks = unsafe { libc::sysconf(libc::_SC_CLK_TCK) };
94 if ticks <= 0 {
95 let code = std::io::Error::last_os_error()
96 .raw_os_error()
97 .unwrap_or(libc::EINVAL);
98 Err(CoreError::sys(code, "sysconf(_SC_CLK_TCK)"))
99 } else {
100 Ok(ticks as u64)
101 }
102}