sys: get rid of Regex dependency

Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
This commit is contained in:
Wolfgang Bumiller 2019-10-22 12:12:01 +02:00
parent b294fb1314
commit db83a675f0
2 changed files with 57 additions and 27 deletions

View File

@ -11,9 +11,7 @@ authors = [
failure = "0.1" failure = "0.1"
lazy_static = "1.1" lazy_static = "1.1"
libc = "0.2" libc = "0.2"
nix = "0.15"
proxmox-tools = { path = "../proxmox-tools" } proxmox-tools = { path = "../proxmox-tools" }
regex = "1.0"
# Docs should be able to reference the proxmox crate. # Docs should be able to reference the proxmox crate.
[dev-dependencies] [dev-dependencies]

View File

@ -2,12 +2,11 @@ use std::collections::HashSet;
use std::fs::OpenOptions; use std::fs::OpenOptions;
use std::io::{BufRead, BufReader}; use std::io::{BufRead, BufReader};
use std::net::{Ipv4Addr, Ipv6Addr}; use std::net::{Ipv4Addr, Ipv6Addr};
use std::u32; use std::str::FromStr;
use failure::*; use failure::*;
use lazy_static::lazy_static; use lazy_static::lazy_static;
use libc; use libc;
use regex::Regex;
use proxmox_tools::fs::file_read_firstline; use proxmox_tools::fs::file_read_firstline;
@ -40,34 +39,67 @@ pub fn read_proc_pid_stat(pid: libc::pid_t) -> Result<ProcFsPidStat, Error> {
} }
fn parse_proc_pid_stat(pid: libc::pid_t, statstr: &str) -> Result<ProcFsPidStat, Error> { fn parse_proc_pid_stat(pid: libc::pid_t, statstr: &str) -> Result<ProcFsPidStat, Error> {
lazy_static! { // It starts with the pid followed by a '('.
static ref REGEX: Regex = Regex::new(concat!( let cmdbeg = statstr
r"^(?P<pid>\d+) \(.*\) (?P<status>\S) -?\d+ -?\d+ -?\d+ -?\d+ -?\d+ \d+ \d+ \d+ \d+ \d+ ", .find('(')
r"(?P<utime>\d+) (?P<stime>\d+) -?\d+ -?\d+ -?\d+ -?\d+ -?\d+ 0 ", .ok_or_else(|| format_err!("missing '(' in /proc/PID/stat"))?;
r"(?P<starttime>\d+) (?P<vsize>\d+) (?P<rss>-?\d+) ",
r"\d+ \d+ \d+ \d+ \d+ \d+ \d+ \d+ \d+ \d+ \d+ \d+ \d+ -?\d+ -?\d+ \d+ \d+ \d+" if !statstr[..=cmdbeg].ends_with(" (") {
)).unwrap(); bail!("bad /proc/PID/stat line before the '('");
} }
if let Some(cap) = REGEX.captures(&statstr) { let stat_pid: u32 = statstr[..(cmdbeg - 1)]
if pid != cap["pid"].parse::<i32>().unwrap() { .parse()
.map_err(|e| format_err!("bad pid in /proc/PID/stat: {}", e))?;
if (pid as u32) != stat_pid {
bail!( bail!(
"unable to read pid stat for process '{}' - got wrong pid", "unexpected pid for process: found pid {} in /proc/{}/stat",
stat_pid,
pid pid
); );
} }
return Ok(ProcFsPidStat { // After the '(' we have an arbitrary command name, then ')' and the remaining values
status: cap["status"].as_bytes()[0], let cmdend = statstr
utime: cap["utime"].parse::<u64>().unwrap(), .rfind(')')
stime: cap["stime"].parse::<u64>().unwrap(), .ok_or_else(|| format_err!("missing ')' in /proc/PID/stat"))?;
starttime: cap["starttime"].parse::<u64>().unwrap(), let mut parts = statstr[cmdend + 1..].trim_start().split_ascii_whitespace();
vsize: cap["vsize"].parse::<u64>().unwrap(),
rss: cap["rss"].parse::<i64>().unwrap() * 4096, // helpers:
}); fn required<'a>(value: Option<&'a str>, what: &'static str) -> Result<&'a str, Error> {
value.ok_or_else(|| format_err!("missing '{}' in /proc/PID/stat", what))
} }
bail!("unable to read pid stat for process '{}'", pid); fn req_num<T>(value: Option<&str>, what: &'static str) -> Result<T, Error>
where
T: FromStr,
<T as FromStr>::Err: Into<Error>,
{
required(value, what)?.parse::<T>().map_err(|e| e.into())
}
fn req_byte(value: Option<&str>, what: &'static str) -> Result<u8, Error> {
let value = required(value, what)?;
if value.len() != 1 {
bail!("invalid '{}' in /proc/PID/stat", what);
}
Ok(value.as_bytes()[0])
}
let out = ProcFsPidStat {
status: req_byte(parts.next(), "status")?,
utime: req_num::<u64>(parts.nth(10), "utime")?,
stime: req_num::<u64>(parts.next(), "stime")?,
starttime: req_num::<u64>(parts.nth(6), "start_time")?,
vsize: req_num::<u64>(parts.next(), "vsize")?,
rss: req_num::<i64>(parts.next(), "rss")? * 4096,
};
let _ = req_num::<u64>(parts.next(), "it_real_value")?;
// and more...
Ok(out)
} }
#[test] #[test]