Repository: firecracker-microvm/firecracker
File: src/jailer/src/cgroup.rs (Rust)

Code before:

use std::collections::hash_map::Entry::{Occupied, Vacant};
use std::collections::HashMap;
use std::fmt::Debug;
use std::fs::{self, File};
use std::io::{BufRead, BufReader};
use std::path::{Path, PathBuf};
use std::process;

use regex::Regex;

use crate::{readln_special, writeln_special, JailerError};

// Holds information on a cgroup mount point discovered on the system
#[derive(Debug)]
struct CgroupMountPoint {
    dir: String,
    options: String,
}

// Allows creation of cgroups on the system for both versions
#[derive(Debug)]
pub struct CgroupBuilder<'a> {
    version: u8,
    hierarchies: HashMap<String, PathBuf>,
    mount_points: Vec<CgroupMountPoint>,
    proc_mounts_path: &'a str,
}

impl<'a> CgroupBuilder<'a> {
    // Creates the builder object
    // It will discover cgroup mount points and hierarchies configured
    // on the system and cache the info required to create cgroups later
    // within this hierarchies
    pub fn new(ver: u8, proc_mounts_path: &'a str) -> Result<Self, JailerError> {
        if ver != 1 && ver != 2 {
            return Err(JailerError::CgroupInvalidVersion(ver.to_string()));
        }

        let mut b = CgroupBuilder {
            version: ver,
            hierarchies: HashMap::new(),
            mount_points: Vec::new(),
            proc_mounts_path,
        };

        // search PROC_MOUNTS for cgroup mount points
        let f = File::open(b.proc_mounts_path)
            .map_err(|err| JailerError::FileOpen(PathBuf::from(&b.proc_mounts_path), err))?;

        // Regex courtesy of Filippo.

Review comment (suggestion):
This may use more memory than before.

It would be better to do:
```suggestion
pub struct CgroupBuilder {
    version: u8,
    hierarchies: HashMap<String, PathBuf>,
    mount_points: Vec<CgroupMountPoint>,
    proc_mounts_path: &'static str,
}
```

Code after:

use std::collections::hash_map::Entry::{Occupied, Vacant};
use std::collections::{HashMap, HashSet};
use std::fmt::Debug;
use std::fs::{self, File};
use std::io::{BufRead, BufReader};
use std::path::{Path, PathBuf};
use std::process;

use regex::Regex;

use crate::{readln_special, writeln_special, JailerError};

// Holds information on a cgroup mount point discovered on the system
#[derive(Debug)]
struct CgroupMountPoint {
    dir: String,
    options: String,
}

// Holds a cache of discovered mount points and cgroup hierarchies
#[derive(Debug)]
struct CgroupHierarchies {
    hierarchies: HashMap<String, PathBuf>,
    mount_points: Vec<CgroupMountPoint>,
}

impl CgroupHierarchies {
    // Constructs a new cache of hierarchies and mount points
    // It will discover cgroup mount points and hierarchies configured
    // on the system and cache the info required to create cgroups later
    // within this hierarchies
    fn new(ver: u8, proc_mounts_path: &str) -> Result<Self, JailerError> {
        let mut h = CgroupHierarchies {
            hierarchies: HashMap::new(),
            mount_points: Vec::new(),
        };

        // search PROC_MOUNTS for cgroup mount points
        let f = File::open(proc_mounts_path)
            .map_err(|err| JailerError::FileOpen(PathBuf::from(proc_mounts_path), err))?;

        // Regex courtesy of Filippo.
        // This will match on each line from /proc/mounts for both v1 and v2 mount points.
        //
        // /proc/mounts cointains lines that look like this:
        // cgroup2 /sys/fs/cgroup/unified cgroup2 rw,nosuid,nodev,noexec,relatime,nsdelegate 0 0
        // cgroup /sys/fs/cgroup/cpu,cpuacct cgroup rw,nosuid,nodev,noexec,relatime,cpu,cpuacct 0 0
        //
        // This Regex will extract:
        //      * "/sys/fs/cgroup/unified" in the "dir" capture group.