liboj-cgroups 0.1.0

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

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

#[derive(PartialEq, Eq, Debug)]
pub enum State {
    Thawed,
    Freezing,
    Frozen,
}

impl FromStr for State {
    type Err = io::Error;

    fn from_str(s: &str) -> io::Result<State> {
        match s {
            "THAWED" => Ok(State::Thawed),
            "FREEZING" => Ok(State::Freezing),
            "FROZEN" => Ok(State::Frozen),
            _ => Err(io::Error::new(
                io::ErrorKind::InvalidData,
                format!("failed to parse cgroup freezer state \"{}\"", s),
            )),
        }
    }
}

pub trait FreezerController: Controller {
    fn state(&self) -> Box<dyn '_ + AttrFile<State>>;
    fn self_freezing(&self) -> Box<dyn '_ + ReadAttr<bool>>;
    fn parent_freezing(&self) -> Box<dyn '_ + ReadAttr<bool>>;
}

impl FreezerController for HierarchyNode {
    fn state(&self) -> Box<dyn '_ + AttrFile<State>> {
        let file = self.as_path().join("freezer.state");
        Box::new(StateFile(file))
    }

    fn self_freezing(&self) -> Box<dyn '_ + ReadAttr<bool>> {
        let file = self.as_path().join("freezer.self_freezing");
        Box::new(FreezingFile(file))
    }

    fn parent_freezing(&self) -> Box<dyn '_ + ReadAttr<bool>> {
        let file = self.as_path().join("freezer.parent_freezing");
        Box::new(FreezingFile(file))
    }
}

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

impl<P: AsRef<Path>> ReadAttr<State> for StateFile<P> {
    fn read(&self) -> io::Result<State> {
        let s = fs::read_to_string(&self.0)?;
        Ok(s.trim().parse()?)
    }
}

impl<P: AsRef<Path>> WriteAttr<State> for StateFile<P> {
    fn write(&self, state: &State) -> io::Result<()> {
        let file = self.0.as_ref();
        match state {
            State::Thawed => fs::write(&file, "THAWED"),
            State::Frozen => fs::write(&file, "FROZEN"),
            State::Freezing => Err(io::Error::new(
                io::ErrorKind::InvalidData,
                format!("can not write FREEZING state to {}", file.display()),
            )),
        }
    }
}

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

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