Skip to main content

ghostscope_process/pid/
runtime_env.rs

1use std::fmt;
2use std::fs;
3use std::path::Path;
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
6pub enum RuntimeEnvironment {
7    ContainerLikely,
8    HostLikely,
9    #[default]
10    Unknown,
11}
12
13impl fmt::Display for RuntimeEnvironment {
14    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
15        match self {
16            RuntimeEnvironment::ContainerLikely => write!(f, "container-likely"),
17            RuntimeEnvironment::HostLikely => write!(f, "host-likely"),
18            RuntimeEnvironment::Unknown => write!(f, "unknown"),
19        }
20    }
21}
22
23#[derive(Debug, Clone, Default)]
24pub struct RuntimeEnvironmentInfo {
25    pub environment: RuntimeEnvironment,
26    pub evidence: Vec<String>,
27}
28
29impl RuntimeEnvironmentInfo {
30    pub fn compact_display(&self) -> String {
31        let reason = if self.evidence.is_empty() {
32            "no-evidence".to_string()
33        } else {
34            self.evidence.join(", ")
35        };
36        format!("env={} evidence=[{}]", self.environment, reason)
37    }
38
39    pub fn is_container_likely(&self) -> bool {
40        self.environment == RuntimeEnvironment::ContainerLikely
41    }
42}
43
44pub fn detect_runtime_environment() -> RuntimeEnvironmentInfo {
45    let mut evidence = Vec::new();
46
47    if Path::new("/.dockerenv").is_file() {
48        evidence.push("/.dockerenv exists".to_string());
49    }
50    if Path::new("/run/.containerenv").is_file() {
51        evidence.push("/run/.containerenv exists".to_string());
52    }
53
54    if let Ok(cgroup) = fs::read_to_string("/proc/1/cgroup") {
55        let cgroup_lc = cgroup.to_lowercase();
56        let markers = [
57            "docker",
58            "containerd",
59            "kubepods",
60            "cri-containerd",
61            "libpod",
62        ];
63        for marker in markers {
64            if cgroup_lc.contains(marker) {
65                evidence.push(format!("/proc/1/cgroup contains '{marker}'"));
66                break;
67            }
68        }
69    }
70
71    let environment = if !evidence.is_empty() {
72        RuntimeEnvironment::ContainerLikely
73    } else if Path::new("/proc/1").exists() {
74        RuntimeEnvironment::HostLikely
75    } else {
76        RuntimeEnvironment::Unknown
77    };
78
79    RuntimeEnvironmentInfo {
80        environment,
81        evidence,
82    }
83}