1use std::io::{BufRead, BufReader};
2use std::path::{Path, PathBuf};
3
4use pathrs::flags::OpenFlags;
5use pathrs::procfs::{ProcfsBase, ProcfsHandle};
6use procfs::ProcError;
7use procfs::process::MountInfo;
8
9use super::controller_type::ControllerType;
10use crate::common::{self, WrappedIoError};
11
12pub const CGROUP_CONTROLLERS: &str = "cgroup.controllers";
13pub const CGROUP_SUBTREE_CONTROL: &str = "cgroup.subtree_control";
14
15#[derive(thiserror::Error, Debug)]
16pub enum V2UtilError {
17 #[error("io error: {0}")]
18 Io(#[from] std::io::Error),
19 #[error("io error: {0}")]
20 WrappedIo(#[from] WrappedIoError),
21 #[error("proc error: {0}")]
22 Proc(#[from] ProcError),
23 #[error("could not find mountpoint for unified")]
24 CouldNotFind,
25 #[error("cannot get available controllers. {0} does not exist")]
26 DoesNotExist(PathBuf),
27 #[error(transparent)]
28 Pathrs(#[from] pathrs::error::Error),
29}
30
31pub fn get_unified_mount_point() -> Result<PathBuf, V2UtilError> {
33 let reader = BufReader::new(ProcfsHandle::new()?.open(
34 ProcfsBase::ProcSelf,
35 "mountinfo",
36 OpenFlags::O_RDONLY | OpenFlags::O_CLOEXEC,
37 )?);
38
39 reader
40 .lines()
41 .map(|lr| {
42 lr.map_err(V2UtilError::Io)
43 .and_then(|s| MountInfo::from_line(&s).map_err(V2UtilError::from))
44 })
45 .find_map(|r| match r {
46 Ok(mi) if mi.fs_type == "cgroup2" => Some(Ok(mi.mount_point)),
47 Ok(_) => None,
48 Err(e) => Some(Err(e)),
49 })
50 .transpose()?
51 .ok_or(V2UtilError::CouldNotFind)
52}
53
54pub fn get_available_controllers<P: AsRef<Path>>(
57 root_path: P,
58) -> Result<Vec<ControllerType>, V2UtilError> {
59 let root_path = root_path.as_ref();
60 let controllers_path = root_path.join(CGROUP_CONTROLLERS);
61 if !controllers_path.exists() {
62 return Err(V2UtilError::DoesNotExist(controllers_path));
63 }
64
65 let mut controllers = Vec::new();
66 for controller in common::read_cgroup_file(controllers_path)?.split_whitespace() {
67 match controller {
68 "cpu" => controllers.push(ControllerType::Cpu),
69 "cpuset" => controllers.push(ControllerType::CpuSet),
70 "hugetlb" => controllers.push(ControllerType::HugeTlb),
71 "io" => controllers.push(ControllerType::Io),
72 "memory" => controllers.push(ControllerType::Memory),
73 "pids" => controllers.push(ControllerType::Pids),
74 tpe => tracing::warn!("Controller {} is not yet implemented.", tpe),
75 }
76 }
77
78 Ok(controllers)
79}