1#[derive(Debug, Default, Eq, PartialEq)]
8pub struct Limit {
9 pub soft: Option<u32>,
10 pub hard: Option<u32>,
11}
12
13#[derive(Debug, Default, Eq, PartialEq)]
16pub struct Limits {
17 pub max_cpu_time: Limit,
18 pub max_file_size: Limit,
19 pub max_data_size: Limit,
20 pub max_stack_size: Limit,
21 pub max_core_file_size: Limit,
22 pub max_resident_set: Limit,
23 pub max_processes: Limit,
24 pub max_open_files: Limit,
25 pub max_locked_memory: Limit,
26 pub max_address_space: Limit,
27 pub max_file_locks: Limit,
28 pub max_pending_signals: Limit,
29 pub max_msgqueue_size: Limit,
30 pub max_nice_priority: Limit,
31 pub max_realtime_priority: Limit,
32 pub max_realtime_timeout: Limit,
33}
34
35impl Limits {
36 pub fn set_property_from_strings(&mut self, name: &str, soft_string: &str, hard_string: &str) {
57 use std::str::FromStr;
58
59 let lower_case = name.to_lowercase();
60
61 let soft = if soft_string == "unlimited" {
62 None
63 } else {
64 u32::from_str(soft_string).ok()
65 };
66
67 let hard = if hard_string == "unlimited" {
68 None
69 } else {
70 u32::from_str(hard_string).ok()
71 };
72
73 let new_limit = Limit { soft, hard };
74
75 match lower_case.as_str() {
76 "max cpu time" => self.max_cpu_time = new_limit,
77 "max file_size" => self.max_file_size = new_limit,
78 "max data size" => self.max_data_size = new_limit,
79 "max stack size" => self.max_stack_size = new_limit,
80 "max core file size" => self.max_core_file_size = new_limit,
81 "max resident set" => self.max_resident_set = new_limit,
82 "max processes" => self.max_processes = new_limit,
83 "max open files" => self.max_open_files = new_limit,
84 "max locked memory" => self.max_locked_memory = new_limit,
85 "max address space" => self.max_address_space = new_limit,
86 "max file locks" => self.max_file_locks = new_limit,
87 "max pending signals" => self.max_pending_signals = new_limit,
88 "max msgqueue size" => self.max_msgqueue_size = new_limit,
89 "max nice priority" => self.max_nice_priority = new_limit,
90 "max realtime priority" => self.max_realtime_priority = new_limit,
91 "max realtime timeout" => self.max_realtime_timeout = new_limit,
92 _ => (),
93 }
94 }
95}
96
97pub fn get_pid_limits(pid: u32) -> Result<Limits, crate::Error> {
111 let file_path = format!("/proc/{}/limits", pid);
113 let file = std::fs::File::open(&file_path)
114 .map_err(|io_error| crate::Error::ProcFileNotFound(file_path, io_error))?;
115 let reader = std::io::BufReader::new(file);
116
117 get_limits_from_reader(reader)
118}
119
120fn get_limits_from_reader<T>(reader: T) -> Result<Limits, crate::Error>
123where
124 T: std::io::BufRead,
125{
126 let mut limits = Limits::default();
127 let mut lines = std::io::BufRead::lines(reader).filter_map(Result::ok);
128
129 lines.next();
131
132 for line in lines {
133 let (property, values) = line.split_at(26);
136 let property = property.trim();
137 let values: Vec<&str> = values.split_whitespace().collect();
138 limits.set_property_from_strings(property, values[0], values[1]);
139 }
140
141 Ok(limits)
142}
143
144#[cfg(test)]
145mod tests {
146 use crate::{Limit, Limits};
147
148 #[test]
149 fn test_own_limits_does_not_panic() {
150 crate::get_own_limits().unwrap();
151 }
152
153 #[test]
154 fn test_pid_limits_does_not_panic() {
155 crate::get_pid_limits(1).unwrap();
156 }
157
158 #[test]
159 fn test_proc_file_not_found() {
160 let error = format!("{:?}", super::get_pid_limits(std::u32::MAX).unwrap_err());
161 let expected_error = String::from(
162 r#"ProcFileNotFound("/proc/4294967295/limits", Os { code: 2, kind: NotFound, message: "No such file or directory" })"#,
163 );
164
165 assert_eq!(error, expected_error);
166 }
167
168 #[test]
169 fn test_from_empty_string() {
170 let reader = std::io::Cursor::new("");
171 let limits = super::get_limits_from_reader(reader).unwrap();
172
173 let expected_limits = Limits::default();
174
175 assert_eq!(limits, expected_limits);
176 }
177
178 #[test]
179 fn test_from_correct_string() {
180 let reader = std::io::Cursor::new(
181 r#"Limit Soft Limit Hard Limit Units
182Max cpu time unlimited unlimited seconds
183Max file size unlimited unlimited bytes
184Max data size unlimited unlimited bytes
185Max stack size 8388608 unlimited bytes
186Max core file size unlimited unlimited bytes
187Max resident set unlimited unlimited bytes
188Max processes 62935 62935 processes
189Max open files 1024 524288 files
190Max locked memory 65536 65536 bytes
191Max address space unlimited unlimited bytes
192Max file locks unlimited unlimited locks
193Max pending signals 62935 62935 signals
194Max msgqueue size 819200 819200 bytes
195Max nice priority 0 0
196Max realtime priority 99 99
197Max realtime timeout unlimited unlimited us"#,
198 );
199 let limits = super::get_limits_from_reader(reader).unwrap();
200
201 let expected_limits = Limits {
202 max_cpu_time: Default::default(),
203 max_file_size: Default::default(),
204 max_data_size: Default::default(),
205 max_stack_size: Limit {
206 soft: Some(8388608),
207 hard: None,
208 },
209 max_core_file_size: Default::default(),
210 max_resident_set: Default::default(),
211 max_processes: Limit {
212 soft: Some(62935),
213 hard: Some(62935),
214 },
215 max_open_files: Limit {
216 soft: Some(1024),
217 hard: Some(524288),
218 },
219 max_locked_memory: Limit {
220 soft: Some(65536),
221 hard: Some(65536),
222 },
223 max_address_space: Default::default(),
224 max_file_locks: Default::default(),
225 max_pending_signals: Limit {
226 soft: Some(62935),
227 hard: Some(62935),
228 },
229 max_msgqueue_size: Limit {
230 soft: Some(819200),
231 hard: Some(819200),
232 },
233 max_nice_priority: Limit {
234 soft: Some(0),
235 hard: Some(0),
236 },
237 max_realtime_priority: Limit {
238 soft: Some(99),
239 hard: Some(99),
240 },
241 max_realtime_timeout: Default::default(),
242 };
243
244 assert_eq!(limits, expected_limits);
245 }
246}