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}