use std::io::Read;
use std::io::Write;
use libc::getpgid;
use crate::{
error::{Error, Result},
utils::{self, str_from_u8},
};
#[derive(Debug, Default)]
pub struct Process {
pub pid: u32,
pub oom_score: i16,
}
impl Process {
pub fn from_pid(pid: u32, buf: &mut [u8]) -> Result<Self> {
let oom_score =
Self::oom_score_from_pid(pid, buf).or(Err(Error::ProcessNotFound("from_pid")))?;
Ok(Self { pid, oom_score })
}
#[allow(dead_code)]
pub fn this(buf: &mut [u8]) -> Result<Self> {
let pid = unsafe { libc::getpid() } as u32;
Self::from_pid(pid, buf)
}
pub fn is_alive_from_pid(pid: u32) -> bool {
let group_id = unsafe { getpgid(pid as i32) };
group_id > 0
}
pub fn is_alive(&self) -> bool {
Self::is_alive_from_pid(self.pid)
}
pub fn comm<'a>(&self, buf: &'a mut [u8]) -> Result<&'a str> {
write!(&mut *buf, "/proc/{}/comm\0", self.pid)?;
{
let mut file = utils::file_from_buffer(buf)?;
buf.fill(0);
let _ = file.read(buf)?;
}
str_from_u8(buf)
}
pub fn oom_score_from_pid(pid: u32, buf: &mut [u8]) -> Result<i16> {
write!(&mut *buf, "/proc/{}/oom_score\0", pid)?;
let contents = {
let mut file = utils::file_from_buffer(buf)?;
buf.fill(0);
let _ = file.read(buf)?;
str_from_u8(buf)?.trim()
};
Ok(contents.parse::<i16>()?)
}
pub fn vm_rss_kib(&self, buf: &mut [u8]) -> Result<i64> {
write!(&mut *buf, "/proc/{}/statm\0", self.pid)?;
let mut columns = {
let mut file = utils::file_from_buffer(buf)?;
buf.fill(0);
let _ = file.read(buf)?;
str_from_u8(buf)?.split_ascii_whitespace()
};
let vm_rss = columns
.nth(1)
.ok_or(Error::MalformedStatm)?
.parse::<i64>()?;
let page_size = utils::page_size()?;
let vm_rss_kib = vm_rss * page_size / 1024;
Ok(vm_rss_kib)
}
#[cfg(feature = "glob-ignore")]
pub fn is_unkillable(&self, buf: &mut [u8], patterns: &[glob::Pattern]) -> Result<bool> {
let comm = self.comm(buf)?.trim();
for pattern in patterns {
if pattern.matches(comm) {
println!(
"Skipping \"{}\" since it matches an unkillable pattern",
comm
);
return Ok(true);
}
}
Ok(false)
}
pub fn oom_score_adj(&self, buf: &mut [u8]) -> Result<i16> {
write!(&mut *buf, "/proc/{}/oom_score_adj\0", self.pid)?;
let contents = {
let mut file = utils::file_from_buffer(buf)?;
buf.fill(0);
let _ = file.read(buf)?;
str_from_u8(buf)?.trim()
};
Ok(contents.parse::<i16>()?)
}
}
#[cfg(test)]
mod tests {
use procfs;
fn this() -> ([u8; 100], crate::process::Process) {
let mut buf = [0_u8; 100];
(buf, crate::process::Process::this(&mut buf).unwrap())
}
#[test]
fn comm() {
let (mut buf, this) = this();
let comm = this.comm(&mut buf).unwrap();
let _this = procfs::process::Process::myself().unwrap();
let _comm = _this.stat.comm;
assert_eq!(comm.trim(), _comm)
}
#[test]
fn oom_score() {
let (_, this) = this();
let _this = procfs::process::Process::myself().unwrap();
assert_eq!(this.oom_score, _this.oom_score().unwrap() as i16);
}
#[test]
fn pid() {
let (_, this) = this();
let _this = procfs::process::Process::myself().unwrap();
assert_eq!(this.pid as i32, _this.pid);
}
}