rlimit/resource.rs
1#![deny(unsafe_code)]
2
3use crate::bindings as C;
4
5use std::error::Error;
6use std::fmt;
7use std::io;
8use std::str::FromStr;
9
10/// A kind of resource.
11///
12/// All resource constants are available on all unix platforms.
13/// Passing an unsupported resource to `[set|get|p]rlimit` will
14/// result in a custom IO error.
15///
16/// **Be careful**: The documentation of [`Resource`][Resource] constants are based on a few systems.
17/// It may be inconsistent with other platforms.
18///
19/// # References
20/// Linux: <https://man7.org/linux/man-pages/man2/getrlimit.2.html>
21///
22/// FreeBSD: <https://www.freebsd.org/cgi/man.cgi?query=getrlimit>
23///
24/// NetBSD: <https://man.netbsd.org/getrlimit.2>
25///
26/// [Resource]: struct.Resource.html
27///
28#[allow(clippy::doc_markdown)]
29#[derive(Clone, Copy, PartialEq, Eq, Hash)]
30pub struct Resource {
31 tag: u8,
32 value: u8,
33}
34
35impl fmt::Debug for Resource {
36 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
37 let idx = Self::VALUE_TABLE.iter().position(|v| v == self).unwrap();
38 write!(f, "Resource::{}", Self::IDENT_TABLE[idx])
39 }
40}
41
42impl FromStr for Resource {
43 type Err = ParseResourceError;
44
45 fn from_str(s: &str) -> Result<Self, Self::Err> {
46 let pos = Self::NAME_TABLE.iter().position(|&name| s == name);
47 match pos {
48 Some(idx) => Ok(Self::VALUE_TABLE[idx]),
49 None => Err(ParseResourceError { _priv: () }),
50 }
51 }
52}
53
54/// An error returned when parsing a `Resource` using [`from_str`] fails
55#[derive(Debug, Clone, PartialEq, Eq)]
56pub struct ParseResourceError {
57 /// private place holder
58 _priv: (),
59}
60
61impl fmt::Display for ParseResourceError {
62 #[inline]
63 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
64 write!(f, "failed to parse Resource")
65 }
66}
67
68impl Error for ParseResourceError {}
69
70macro_rules! declare_resource {
71 {$($(#[$attr:meta])* $id:ident = $tag:expr => $c_enum:ident,)+} => {
72 impl Resource{
73 $(
74 $(#[$attr])*
75 pub const $id: Self = Self{ tag: $tag, value: C::$c_enum as u8 };
76 )+
77 }
78
79 #[allow(unused_doc_comments)]
80 impl Resource{
81 const NAME_TABLE: &'static [&'static str] = &[
82 $(
83 $(#[$attr])*
84 {
85 stringify!($c_enum)
86 },
87 )+
88 ];
89
90 const VALUE_TABLE: &'static [Self] = &[
91 $(
92 $(#[$attr])*
93 {
94 Self::$id
95 },
96 )+
97 ];
98
99 const IDENT_TABLE: &'static [&'static str] = &[
100 $(
101 $(#[$attr])*
102 {
103 stringify!($id)
104 },
105 )+
106 ];
107 }
108
109 #[cfg(test)]
110 mod tests{
111 use super::*;
112
113 #[allow(unused_comparisons)]
114 #[allow(unused_doc_comments)]
115 #[test]
116 fn name_value(){
117 $(
118 $(#[$attr])*
119 {
120 assert_eq!(Resource::$id.as_name(), stringify!($c_enum));
121 assert_eq!(Resource::from_str(stringify!($c_enum)).unwrap(), Resource::$id);
122 }
123 )+
124 }
125
126 #[allow(unused_doc_comments)]
127 #[test]
128 fn unique_tag(){
129 use std::collections::HashSet;
130
131 let tags = [
132 $(
133 $(#[$attr])*
134 { $tag },
135 )+
136 ];
137
138 let s: HashSet<u16> = tags.iter().copied().collect();
139 assert_eq!(s.len(), Resource::NAME_TABLE.len());
140 }
141
142 #[allow(unused_doc_comments)]
143 #[test]
144 fn raw_eq(){
145 $(
146 $(#[$attr])*
147 {
148 assert_eq!(Resource::$id.as_raw(), C::$c_enum);
149 }
150 )+
151 }
152
153 #[allow(unused_doc_comments)]
154 #[test]
155 fn from_str(){
156 $(
157 $(#[$attr])*
158 {
159 assert_eq!(Resource::from_str(stringify!($c_enum)), Ok(Resource::$id));
160 }
161 )+
162
163 assert!(Resource::from_str("asdqwe").is_err());
164 }
165
166 }
167 };
168}
169
170impl Resource {
171 /// Set resource limits.
172 /// # Errors
173 /// See [`setrlimit`](fn.setrlimit.html)
174 #[inline]
175 pub fn set(self, soft: u64, hard: u64) -> io::Result<()> {
176 super::setrlimit(self, soft, hard)
177 }
178
179 /// Get resource limits.
180 /// # Errors
181 /// See [`getrlimit`](fn.getrlimit.html)
182 #[inline]
183 pub fn get(self) -> io::Result<(u64, u64)> {
184 super::getrlimit(self)
185 }
186
187 /// Returns the name of the resource.
188 ///
189 /// # Example
190 /// ```
191 /// # #[cfg(unix)]
192 /// # {
193 /// # use rlimit::Resource;
194 /// assert_eq!(Resource::NOFILE.as_name(), "RLIMIT_NOFILE");
195 /// # }
196 /// ```
197 #[must_use]
198 #[allow(clippy::missing_panics_doc)] // this method should never panic
199 pub fn as_name(self) -> &'static str {
200 let idx = Self::VALUE_TABLE.iter().position(|&v| v == self).unwrap();
201 Self::NAME_TABLE[idx]
202 }
203
204 /// Returns true if the current platform supports this resource.
205 #[must_use]
206 pub const fn is_supported(self) -> bool {
207 self.value != u8::MAX
208 }
209
210 /// `u8::MAX` indicates unsupported resource.
211 #[inline]
212 #[must_use]
213 pub(crate) const fn as_raw(self) -> u8 {
214 self.value
215 }
216}
217
218declare_resource! {
219 /// The maximum size (in bytes)
220 /// of the process's virtual memory (address space).
221 AS = 1 => RLIMIT_AS,
222
223
224 /// The maximum size (in bytes)
225 /// of a core file that the process may dump.
226 CORE = 2 => RLIMIT_CORE,
227
228
229 /// A limit (in seconds)
230 /// on the amount of CPU time that the process can consume.
231 CPU = 3 => RLIMIT_CPU,
232
233
234 /// The maximum size (in bytes)
235 /// of the process's data segment
236 /// (initialized data, uninitialized data, and heap).
237 DATA = 4 => RLIMIT_DATA,
238
239
240 /// The maximum size (in bytes)
241 /// of files that the process may create.
242 FSIZE = 5 => RLIMIT_FSIZE,
243
244
245 /// The maximum number of kqueues this user id is allowed to create.
246 KQUEUES = 6 => RLIMIT_KQUEUES,
247
248
249 /// (early Linux 2.4 only)
250 ///
251 /// A limit on the combined number
252 /// of `flock(2)` locks and `fcntl(2)` leases
253 /// that this process may establish.
254 LOCKS = 7 => RLIMIT_LOCKS,
255
256
257 /// The maximum number (in bytes)
258 /// of memory that may be locked into RAM.
259 MEMLOCK = 8 => RLIMIT_MEMLOCK,
260
261
262 /// A limit on the number
263 /// of bytes that can be allocated for POSIX message queues
264 /// for the real user ID of the calling process.
265 MSGQUEUE = 9 => RLIMIT_MSGQUEUE,
266
267
268 /// This specifies a ceiling
269 /// to which the process's nice value can be raised
270 /// using `setpriority(2)` or `nice(2)`.
271 NICE = 10 => RLIMIT_NICE,
272
273
274 /// This specifies a value
275 /// one greater than the maximum file descriptor number
276 /// that can be opened by this process.
277 NOFILE = 11 => RLIMIT_NOFILE,
278
279
280 /// The number of open vnode monitors.
281 NOVMON = 12 => RLIMIT_NOVMON,
282
283
284 /// A limit on the number of extant process (or, more precisely on Linux, threads)
285 /// for the real user ID of the calling process.
286 NPROC = 13 => RLIMIT_NPROC,
287
288
289 /// The maximum number of pseudo-terminals this user id is allowed to create.
290 NPTS = 14 => RLIMIT_NPTS,
291
292
293 /// The maximum number of simultaneous threads (Lightweight
294 /// Processes) for this user id. Kernel threads and the
295 /// first thread of each process are not counted against this
296 /// limit.
297 NTHR = 15 => RLIMIT_NTHR,
298
299
300 /// The maximum number of POSIX-type advisory-mode locks available to this user.
301 POSIXLOCKS = 16 => RLIMIT_POSIXLOCKS,
302
303
304 /// A limit (in bytes)
305 /// on the process's resident set
306 /// (the number of virtual pages resident in RAM).
307 RSS = 17 => RLIMIT_RSS,
308
309
310 /// This specifies a ceiling on the real-time priority
311 /// that may be set for this process
312 /// using `sched_setscheduler(2)` and `sched_setparam(2)`.
313 RTPRIO = 18 => RLIMIT_RTPRIO,
314
315
316 /// A limit (in microseconds) on the amount of CPU time
317 /// that a process scheduled under a real-time scheduling policy
318 /// may consume without making a blocking system call.
319 RTTIME = 19 => RLIMIT_RTTIME,
320
321
322 /// The maximum size (in bytes) of socket buffer usage for
323 /// this user. This limits the amount of network memory, and
324 /// hence the amount of mbufs, that this user may hold at any
325 /// time.
326 SBSIZE = 20 => RLIMIT_SBSIZE,
327
328
329 /// A limit on the number
330 /// of signals that may be queued
331 /// for the real user ID of the calling process.
332 SIGPENDING = 21 => RLIMIT_SIGPENDING,
333
334
335 /// The maximum size (in bytes)
336 /// of the process stack.
337 STACK = 22 => RLIMIT_STACK,
338
339
340 /// The maximum size (in bytes) of the swap space that may be
341 /// reserved or used by all of this user id's processes.
342 SWAP = 23 => RLIMIT_SWAP,
343
344
345 /// The number of shared locks a given user may create simultaneously.
346 UMTXP = 24 => RLIMIT_UMTXP,
347
348
349 /// An alias for RLIMIT_AS. The maximum size of a process's mapped address space in bytes.
350 VMEM = 25 => RLIMIT_VMEM,
351
352}