Skip to main content

sandbox_core/
util.rs

1//! Utility functions for sandbox operations
2
3use crate::error::{Result, SandboxError};
4use std::path::Path;
5
6/// Check if running as root
7pub fn is_root() -> bool {
8    unsafe { libc::geteuid() == 0 }
9}
10
11/// Get current UID
12pub fn get_uid() -> u32 {
13    unsafe { libc::geteuid() }
14}
15
16/// Get current GID
17pub fn get_gid() -> u32 {
18    unsafe { libc::getegid() }
19}
20
21/// Ensure we have root privileges
22pub fn require_root() -> Result<()> {
23    if !is_root() {
24        Err(SandboxError::PermissionDenied(
25            "This operation requires root privileges".to_string(),
26        ))
27    } else {
28        Ok(())
29    }
30}
31
32/// Check if cgroup v2 is available
33pub fn has_cgroup_v2() -> bool {
34    Path::new("/sys/fs/cgroup/cgroup.controllers").exists()
35}
36
37/// Check if a cgroup path exists
38pub fn cgroup_exists(path: &Path) -> bool {
39    path.exists()
40}
41
42/// Parse memory size string (e.g., "100M", "1G")
43pub fn parse_memory_size(s: &str) -> Result<u64> {
44    let s = s.trim().to_uppercase();
45
46    let (num_str, multiplier) = if s.ends_with("G") {
47        (&s[..s.len() - 1], 1024u64 * 1024 * 1024)
48    } else if s.ends_with("M") {
49        (&s[..s.len() - 1], 1024u64 * 1024)
50    } else if s.ends_with("K") {
51        (&s[..s.len() - 1], 1024u64)
52    } else if s.ends_with("B") {
53        (&s[..s.len() - 1], 1u64)
54    } else {
55        (s.as_str(), 1u64)
56    };
57
58    let num: u64 = num_str
59        .parse()
60        .map_err(|_| SandboxError::InvalidConfig(format!("Invalid memory size: {}", s)))?;
61
62    num.checked_mul(multiplier)
63        .ok_or_else(|| SandboxError::InvalidConfig(format!("Memory size overflow: {}", s)))
64}
65
66#[cfg(test)]
67mod tests {
68    use super::*;
69
70    #[test]
71    fn test_parse_memory_size_bytes() {
72        assert_eq!(parse_memory_size("100").unwrap(), 100);
73        assert_eq!(parse_memory_size("100B").unwrap(), 100);
74    }
75
76    #[test]
77    fn test_parse_memory_size_kilobytes() {
78        assert_eq!(parse_memory_size("1K").unwrap(), 1024);
79        assert_eq!(parse_memory_size("10K").unwrap(), 10 * 1024);
80    }
81
82    #[test]
83    fn test_parse_memory_size_megabytes() {
84        assert_eq!(parse_memory_size("1M").unwrap(), 1024 * 1024);
85        assert_eq!(parse_memory_size("100M").unwrap(), 100 * 1024 * 1024);
86    }
87
88    #[test]
89    fn test_parse_memory_size_gigabytes() {
90        assert_eq!(parse_memory_size("1G").unwrap(), 1024 * 1024 * 1024);
91        assert_eq!(parse_memory_size("2G").unwrap(), 2 * 1024 * 1024 * 1024);
92    }
93
94    #[test]
95    fn test_parse_memory_size_case_insensitive() {
96        assert_eq!(parse_memory_size("1m").unwrap(), 1024 * 1024);
97        assert_eq!(parse_memory_size("1g").unwrap(), 1024 * 1024 * 1024);
98    }
99
100    #[test]
101    fn test_parse_memory_size_whitespace() {
102        assert_eq!(parse_memory_size("  100M  ").unwrap(), 100 * 1024 * 1024);
103    }
104
105    #[test]
106    fn test_parse_memory_size_invalid() {
107        assert!(parse_memory_size("not_a_number").is_err());
108        assert!(parse_memory_size("10X").is_err());
109    }
110
111    #[test]
112    fn test_get_uid_gid() {
113        let uid = get_uid();
114        let gid = get_gid();
115        assert!(uid < u32::MAX);
116        assert!(gid < u32::MAX);
117    }
118
119    #[test]
120    fn test_is_root() {
121        let is_root_val = is_root();
122        assert_eq!(is_root_val, get_uid() == 0);
123    }
124
125    #[test]
126    fn test_has_cgroup_v2() {
127        // Just verify it returns a bool without panicking
128        let _ = has_cgroup_v2();
129    }
130
131    #[test]
132    fn test_cgroup_exists() {
133        assert!(cgroup_exists(Path::new("/")));
134        assert!(!cgroup_exists(Path::new(
135            "/nonexistent/path/that/should/not/exist"
136        )));
137    }
138}