Skip to main content

libcgroups/v1/
util.rs

1use std::collections::HashMap;
2use std::io::{BufRead, BufReader};
3use std::path::PathBuf;
4
5use pathrs::flags::OpenFlags;
6use pathrs::procfs::{ProcfsBase, ProcfsHandle};
7use procfs::ProcError;
8use procfs::process::MountInfo;
9
10use super::ControllerType;
11use super::controller_type::CONTROLLERS;
12
13#[derive(thiserror::Error, Debug)]
14pub enum V1MountPointError {
15    #[error("io error: {0}")]
16    Io(#[from] std::io::Error),
17    #[error("failed to get mountinfo: {0}")]
18    MountInfo(ProcError),
19    #[error("could not find mountpoint for {subsystem}")]
20    NotFound { subsystem: ControllerType },
21    #[error(transparent)]
22    Pathrs(#[from] pathrs::error::Error),
23}
24
25/// List all cgroup v1 subsystem mount points on the system. This can include unsupported
26/// subsystems, comounted controllers and named hierarchies.
27pub fn list_subsystem_mount_points() -> Result<Vec<PathBuf>, V1MountPointError> {
28    let reader = BufReader::new(ProcfsHandle::new()?.open(
29        ProcfsBase::ProcSelf,
30        "mountinfo",
31        OpenFlags::O_RDONLY | OpenFlags::O_CLOEXEC,
32    )?);
33
34    reader
35        .lines()
36        .map(|lr| {
37            lr.map_err(V1MountPointError::Io)
38                .and_then(|line| MountInfo::from_line(&line).map_err(V1MountPointError::MountInfo))
39        })
40        .try_fold(Vec::new(), |mut mount_points, r| {
41            r.map(|m| {
42                if m.fs_type == "cgroup" {
43                    mount_points.push(m.mount_point);
44                }
45                mount_points
46            })
47        })
48}
49
50/// List the mount points of all currently supported cgroup subsystems.
51pub fn list_supported_mount_points() -> Result<HashMap<ControllerType, PathBuf>, V1MountPointError>
52{
53    let mut mount_paths = HashMap::with_capacity(CONTROLLERS.len());
54
55    for controller in CONTROLLERS {
56        if let Ok(mount_point) = get_subsystem_mount_point(controller) {
57            mount_paths.insert(controller.to_owned(), mount_point);
58        }
59    }
60
61    Ok(mount_paths)
62}
63
64pub fn get_subsystem_mount_point(subsystem: &ControllerType) -> Result<PathBuf, V1MountPointError> {
65    let subsystem_name = subsystem.to_string();
66    let reader = BufReader::new(ProcfsHandle::new()?.open(
67        ProcfsBase::ProcSelf,
68        "mountinfo",
69        OpenFlags::O_RDONLY | OpenFlags::O_CLOEXEC,
70    )?);
71
72    reader
73        .lines()
74        .map(|lr| {
75            lr.map_err(V1MountPointError::Io)
76                .and_then(|line| MountInfo::from_line(&line).map_err(V1MountPointError::MountInfo))
77        })
78        .find_map(|r| match r {
79            Err(e) => Some(Err(e)),
80            Ok(m) if m.fs_type == "cgroup" => {
81                // Some systems mount net_prio and net_cls in the same directory
82                // other systems mount them in their own directories. This
83                // should handle both cases.
84                let ok = match subsystem_name.as_str() {
85                    "net_cls" => ["net_cls,net_prio", "net_prio,net_cls", "net_cls"]
86                        .iter()
87                        .any(|s| m.mount_point.ends_with(s)),
88                    "net_prio" => ["net_cls,net_prio", "net_prio,net_cls", "net_prio"]
89                        .iter()
90                        .any(|s| m.mount_point.ends_with(s)),
91                    "cpu" => ["cpu,cpuacct", "cpu"]
92                        .iter()
93                        .any(|s| m.mount_point.ends_with(s)),
94                    "cpuacct" => ["cpu,cpuacct", "cpuacct"]
95                        .iter()
96                        .any(|s| m.mount_point.ends_with(s)),
97                    _ => m.mount_point.ends_with(&subsystem_name),
98                };
99                if ok { Some(Ok(m.mount_point)) } else { None }
100            }
101            Ok(_) => None,
102        })
103        .transpose()?
104        .ok_or(V1MountPointError::NotFound {
105            subsystem: *subsystem,
106        })
107}