1use crate::error::{Result, SandboxError};
4use std::path::Path;
5
6pub fn is_root() -> bool {
8 unsafe { libc::geteuid() == 0 }
9}
10
11pub fn get_uid() -> u32 {
13 unsafe { libc::geteuid() }
14}
15
16pub fn get_gid() -> u32 {
18 unsafe { libc::getegid() }
19}
20
21pub 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
32pub fn has_cgroup_v2() -> bool {
34 Path::new("/sys/fs/cgroup/cgroup.controllers").exists()
35}
36
37pub fn cgroup_exists(path: &Path) -> bool {
39 path.exists()
40}
41
42pub 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 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}