use std::{io::Read, sync::OnceLock};
static IS_SANDBOXED: OnceLock<bool> = OnceLock::new();
fn is_flatpak() -> bool {
std::path::PathBuf::from("/.flatpak-info").exists()
}
fn is_snap() -> bool {
let pid = std::process::id();
let path = format!("/proc/{pid}/cgroup");
let mut file = match std::fs::File::open(path) {
Ok(file) => file,
Err(_) => return false,
};
let mut buffer = String::new();
match file.read_to_string(&mut buffer) {
Ok(_) => cgroup_v2_is_snap(&buffer),
Err(_) => false,
}
}
fn cgroup_v2_is_snap(cgroups: &str) -> bool {
cgroups
.lines()
.map(|line| {
let (n, rest) = line.split_once(':')?;
n.parse::<u32>().ok()?;
let unit = match rest.split_once(':') {
Some(("", unit)) => Some(unit),
Some(("freezer", unit)) => Some(unit),
Some(("name=systemd", unit)) => Some(unit),
_ => None,
}?;
let scope = std::path::Path::new(unit).file_name()?.to_str()?;
Some(scope.starts_with("snap."))
})
.any(|x| x.unwrap_or(false))
}
pub(crate) fn is_sandboxed() -> bool {
if let Some(cached_value) = IS_SANDBOXED.get() {
return *cached_value;
}
let new_value = is_flatpak() || is_snap();
*IS_SANDBOXED.get_or_init(|| new_value)
}