liboj-cgroups 0.1.0

Cgroup wrapping for liboj
Documentation
use std::fs;
use std::io;
use std::path::Path;

use lazy_static::lazy_static;
use regex::Regex;

use super::Controller;
use crate::{
    attr_file::{AttrFile, ReadAttr, WriteAttr},
    hierarchy::HierarchyNode,
};

pub trait PidsController: Controller {
    fn current(&self) -> Box<dyn '_ + ReadAttr<usize>>;
    fn max(&self) -> Box<dyn '_ + AttrFile<Option<usize>>>;
    fn events(&self) -> Box<dyn '_ + ReadAttr<usize>>;
}

impl PidsController for HierarchyNode {
    fn current(&self) -> Box<dyn '_ + ReadAttr<usize>> {
        let file = self.as_path().join("pids.current");
        Box::new(CurrentFile(file))
    }

    fn max(&self) -> Box<dyn '_ + AttrFile<Option<usize>>> {
        let file = self.as_path().join("pids.max");
        Box::new(MaxFile(file))
    }

    fn events(&self) -> Box<dyn '_ + ReadAttr<usize>> {
        let file = self.as_path().join("pids.events");
        Box::new(EventFile(file))
    }
}

struct CurrentFile<P: AsRef<Path>>(P);

impl<P: AsRef<Path>> ReadAttr<usize> for CurrentFile<P> {
    fn read(&self) -> io::Result<usize> {
        let file = self.0.as_ref();
        let s = fs::read_to_string(&file)?;
        match s.trim().parse() {
            Ok(number) => Ok(number),
            Err(_) => Err(io::Error::new(
                io::ErrorKind::InvalidData,
                format!("failed to parse number of pids from {}", file.display()),
            )),
        }
    }
}

struct MaxFile<P: AsRef<Path>>(P);

impl<P: AsRef<Path>> ReadAttr<Option<usize>> for MaxFile<P> {
    fn read(&self) -> io::Result<Option<usize>> {
        lazy_static! {
            static ref RE: Regex = Regex::new(r"^(max|\d+)$").unwrap();
        }
        let file = self.0.as_ref();
        let s = fs::read_to_string(&file)?;
        match RE.captures(&s.trim()) {
            Some(cap) => match &cap[1] {
                "max" => Ok(None),
                number => Ok(Some(number.parse().unwrap())),
            },
            None => Err(io::Error::new(
                io::ErrorKind::InvalidData,
                format!("failed to read max pids limit from {}", file.display()),
            )),
        }
    }
}

impl<P: AsRef<Path>> WriteAttr<Option<usize>> for MaxFile<P> {
    fn write(&self, max: &Option<usize>) -> io::Result<()> {
        match max {
            Some(max) => fs::write(&self.0, format!("{}", max)),
            None => fs::write(&self.0, b"max"),
        }
    }
}

struct EventFile<P: AsRef<Path>>(P);

impl<P: AsRef<Path>> ReadAttr<usize> for EventFile<P> {
    fn read(&self) -> io::Result<usize> {
        lazy_static! {
            static ref RE: Regex = Regex::new(r"^max (\d+)$").unwrap();
        }
        let file = self.0.as_ref();
        let s = fs::read_to_string(&file)?;
        match RE.captures(&s.trim()) {
            Some(cap) => Ok(cap[1].parse().unwrap()),
            None => Err(io::Error::new(
                io::ErrorKind::InvalidData,
                format!("failed to read pids event from {}", file.display()),
            )),
        }
    }
}