Skip to main content

rlimit/unix/
resource.rs

1#![deny(unsafe_code)]
2
3use std::error::Error;
4use std::fmt;
5use std::io;
6use std::str::FromStr;
7
8#[cfg(all(target_os = "linux", target_env = "gnu"))]
9use libc::__rlimit_resource_t as resource_t;
10
11#[cfg(not(all(target_os = "linux", target_env = "gnu")))]
12use libc::c_int as resource_t;
13
14/// Integer type used for resource values.
15///
16/// The actual type of [`RawResource`][RawResource] can be different on different platforms.
17///
18/// [RawResource]: type.RawResource.html
19#[allow(clippy::module_name_repetitions)]
20pub type RawResource = resource_t;
21
22/// A kind of resource.
23///
24/// **Be careful**: The documentation of [`Resource`][Resource] constants are based on a few systems.
25/// It may be inconsistent with other platforms.
26///
27/// # References
28/// Linux: <https://man7.org/linux/man-pages/man2/getrlimit.2.html>
29///
30/// FreeBSD: <https://www.freebsd.org/cgi/man.cgi?query=getrlimit>
31///
32/// NetBSD: <https://man.netbsd.org/getrlimit.2>
33///
34/// [Resource]: struct.Resource.html
35///
36#[allow(clippy::doc_markdown)]
37#[derive(Clone, Copy, PartialEq, Eq, Hash)]
38pub struct Resource {
39    tag: u16,
40    value: u16,
41}
42
43impl fmt::Debug for Resource {
44    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
45        let idx = Self::VALUE_TABLE.iter().position(|v| v == self).unwrap();
46        write!(f, "Resource::{}", Self::IDENT_TABLE[idx])
47    }
48}
49
50impl FromStr for Resource {
51    type Err = ParseResourceError;
52
53    fn from_str(s: &str) -> Result<Self, Self::Err> {
54        let pos = Self::NAME_TABLE.iter().position(|&name| s == name);
55        match pos {
56            Some(idx) => Ok(Self::VALUE_TABLE[idx]),
57            None => Err(ParseResourceError { _priv: () }),
58        }
59    }
60}
61
62/// An error returned when parsing a `Resource` using [`from_str`] fails
63#[derive(Debug, Clone, PartialEq, Eq)]
64pub struct ParseResourceError {
65    /// private place holder
66    _priv: (),
67}
68
69impl fmt::Display for ParseResourceError {
70    #[inline]
71    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
72        write!(f, "failed to parse Resource")
73    }
74}
75
76impl Error for ParseResourceError {}
77
78macro_rules! declare_resource {
79    {$($(#[$attr:meta])* $id:ident = $tag:expr => $c_enum:ident,)+} => {
80        impl Resource{
81            $(
82                $(#[$attr])*
83                pub const $id: Self = Self{ tag: $tag, value: libc::$c_enum as u16 };
84            )+
85        }
86
87        #[allow(unused_doc_comments)]
88        impl Resource{
89            const NAME_TABLE: &'static [&'static str] = &[
90                $(
91                    $(#[$attr])*
92                    {
93                        stringify!($c_enum)
94                    },
95                )+
96            ];
97
98            const VALUE_TABLE: &'static [Self] = &[
99                $(
100                    $(#[$attr])*
101                    {
102                        Self::$id
103                    },
104                )+
105            ];
106
107            const IDENT_TABLE: &'static [&'static str] = &[
108                $(
109                    $(#[$attr])*
110                    {
111                        stringify!($id)
112                    },
113                )+
114            ];
115        }
116
117        #[cfg(test)]
118        mod tests{
119            use super::*;
120
121            #[allow(unused_comparisons)]
122            #[allow(unused_doc_comments)]
123            #[test]
124            fn name_value(){
125                $(
126                    $(#[$attr])*
127                    {
128                        assert_eq!(Resource::$id.as_name(), stringify!($c_enum));
129                        assert_eq!(Resource::from_str(stringify!($c_enum)).unwrap(), Resource::$id);
130                        assert!((0..=128).contains(&libc::$c_enum));
131                    }
132                )+
133            }
134
135            #[allow(unused_doc_comments)]
136            #[test]
137            fn unique_tag(){
138                use std::collections::HashSet;
139
140                let tags = [
141                    $(
142                        $(#[$attr])*
143                        { $tag },
144                    )+
145                ];
146
147                let s: HashSet<u16> = tags.iter().copied().collect();
148                assert_eq!(s.len(), Resource::NAME_TABLE.len());
149            }
150
151            #[allow(unused_doc_comments)]
152            #[test]
153            fn raw_eq(){
154                $(
155                    $(#[$attr])*
156                    {
157                        assert_eq!(Resource::$id.as_raw(), libc::$c_enum);
158                    }
159                )+
160            }
161
162            #[allow(unused_doc_comments)]
163            #[test]
164            fn from_str(){
165                $(
166                    $(#[$attr])*
167                    {
168                        assert_eq!(Resource::from_str(stringify!($c_enum)), Ok(Resource::$id));
169                    }
170                )+
171
172                assert!(Resource::from_str("asdqwe").is_err());
173            }
174
175            #[test]
176            fn available(){
177                assert_eq!(
178                    Resource::available_names().len(),
179                    Resource::available_resources().len()
180                );
181            }
182        }
183    };
184}
185
186impl Resource {
187    /// Set resource limits.
188    /// # Errors
189    /// See [`setrlimit`](fn.setrlimit.html)
190    #[inline]
191    pub fn set(self, soft: u64, hard: u64) -> io::Result<()> {
192        super::setrlimit(self, soft, hard)
193    }
194
195    /// Get resource limits.
196    /// # Errors
197    /// See [`getrlimit`](fn.getrlimit.html)
198    #[inline]
199    pub fn get(self) -> io::Result<(u64, u64)> {
200        super::getrlimit(self)
201    }
202
203    /// Returns the name of the resource.
204    ///
205    /// # Example
206    /// ```
207    /// # use rlimit::Resource;
208    /// assert_eq!(Resource::NOFILE.as_name(), "RLIMIT_NOFILE");
209    /// ```
210    #[must_use]
211    #[allow(clippy::missing_panics_doc)] // this method should never panic
212    pub fn as_name(self) -> &'static str {
213        let idx = Self::VALUE_TABLE.iter().position(|&v| v == self).unwrap();
214        Self::NAME_TABLE[idx]
215    }
216
217    /// Returns available resource names.
218    #[must_use]
219    pub const fn available_names() -> &'static [&'static str] {
220        Self::NAME_TABLE
221    }
222
223    /// Returns available resources.
224    #[must_use]
225    pub const fn available_resources() -> &'static [Self] {
226        Self::VALUE_TABLE
227    }
228
229    /// Returns the raw resource type.
230    ///
231    /// **Be careful**: The actual type of [`RawResource`][RawResource] can be different on different platforms.
232    ///
233    /// [RawResource]: type.RawResource.html
234    #[inline]
235    #[must_use]
236    pub const fn as_raw(self) -> RawResource {
237        self.value as _
238    }
239}
240
241// #begin-codegen
242// generated from rust-lang/libc 6568dacc81b2dd2edae571ab97bbca94bc662595
243declare_resource! {
244
245    /// The maximum size (in bytes)
246    /// of the process's virtual memory (address space).
247    #[cfg(any(
248        all(target_os = "linux", target_env = "gnu"),
249        all(target_os = "linux", target_env = "musl", any(target_arch = "x86", target_arch = "mips", target_arch = "powerpc", target_arch = "hexagon", target_arch = "arm")),
250        all(target_os = "linux", target_env = "musl", any(target_arch = "x86_64", target_arch = "aarch64", target_arch = "mips64", target_arch = "powerpc64")),
251        all(target_os = "linux", target_env = "uclibc", any(target_arch = "mips", target_arch = "mips64")),
252        any(target_os = "freebsd", target_os = "dragonfly"),
253        any(target_os = "macos", target_os = "ios"),
254        target_os = "android",
255        target_os = "emscripten",
256        target_os = "fuchsia",
257        target_os = "haiku",
258        target_os = "netbsd",
259        target_os = "solarish",
260    ))]
261    AS = 1 => RLIMIT_AS,
262
263
264    /// The maximum size (in bytes)
265    /// of a core file that the process may dump.
266    #[cfg(any(
267        all(target_os = "linux", target_env = "gnu"),
268        all(target_os = "linux", target_env = "musl"),
269        all(target_os = "linux", target_env = "uclibc"),
270        any(target_os = "freebsd", target_os = "dragonfly"),
271        any(target_os = "macos", target_os = "ios"),
272        any(target_os = "openbsd", target_os = "netbsd"),
273        target_os = "android",
274        target_os = "emscripten",
275        target_os = "fuchsia",
276        target_os = "haiku",
277        target_os = "solarish",
278    ))]
279    CORE = 2 => RLIMIT_CORE,
280
281
282    /// A limit (in seconds)
283    /// on the amount of CPU time that the process can consume.
284    #[cfg(any(
285        all(target_os = "linux", target_env = "gnu"),
286        all(target_os = "linux", target_env = "musl"),
287        all(target_os = "linux", target_env = "uclibc"),
288        any(target_os = "freebsd", target_os = "dragonfly"),
289        any(target_os = "macos", target_os = "ios"),
290        any(target_os = "openbsd", target_os = "netbsd"),
291        target_os = "android",
292        target_os = "emscripten",
293        target_os = "fuchsia",
294        target_os = "haiku",
295        target_os = "solarish",
296    ))]
297    CPU = 3 => RLIMIT_CPU,
298
299
300    /// The maximum size (in bytes)
301    /// of the process's data segment
302    /// (initialized data, uninitialized data, and heap).
303    #[cfg(any(
304        all(target_os = "linux", target_env = "gnu"),
305        all(target_os = "linux", target_env = "musl"),
306        all(target_os = "linux", target_env = "uclibc"),
307        any(target_os = "freebsd", target_os = "dragonfly"),
308        any(target_os = "macos", target_os = "ios"),
309        any(target_os = "openbsd", target_os = "netbsd"),
310        target_os = "android",
311        target_os = "emscripten",
312        target_os = "fuchsia",
313        target_os = "haiku",
314        target_os = "solarish",
315    ))]
316    DATA = 4 => RLIMIT_DATA,
317
318
319    /// The maximum size (in bytes)
320    /// of files that the process may create.
321    #[cfg(any(
322        all(target_os = "linux", target_env = "gnu"),
323        all(target_os = "linux", target_env = "musl"),
324        all(target_os = "linux", target_env = "uclibc"),
325        any(target_os = "freebsd", target_os = "dragonfly"),
326        any(target_os = "macos", target_os = "ios"),
327        any(target_os = "openbsd", target_os = "netbsd"),
328        target_os = "android",
329        target_os = "emscripten",
330        target_os = "fuchsia",
331        target_os = "haiku",
332        target_os = "solarish",
333    ))]
334    FSIZE = 5 => RLIMIT_FSIZE,
335
336
337    /// The maximum number of kqueues this user id is allowed to create.
338    #[cfg(any(
339        target_os = "freebsd",
340    ))]
341    KQUEUES = 6 => RLIMIT_KQUEUES,
342
343
344    /// (early Linux 2.4 only)
345    ///
346    /// A limit on the combined number
347    /// of `flock(2)` locks and `fcntl(2)` leases
348    /// that this process may establish.
349    #[cfg(any(
350        all(target_os = "linux", target_env = "gnu"),
351        all(target_os = "linux", target_env = "musl"),
352        all(target_os = "linux", target_env = "uclibc"),
353        target_os = "android",
354        target_os = "emscripten",
355        target_os = "fuchsia",
356    ))]
357    LOCKS = 7 => RLIMIT_LOCKS,
358
359
360    /// The maximum number (in bytes)
361    /// of memory that may be locked into RAM.
362    #[cfg(any(
363        all(target_os = "linux", target_env = "gnu"),
364        all(target_os = "linux", target_env = "musl", any(target_arch = "x86", target_arch = "mips", target_arch = "powerpc", target_arch = "hexagon", target_arch = "arm")),
365        all(target_os = "linux", target_env = "musl", any(target_arch = "x86_64", target_arch = "aarch64", target_arch = "mips64", target_arch = "powerpc64")),
366        all(target_os = "linux", target_env = "uclibc", any(target_arch = "mips", target_arch = "mips64")),
367        any(target_os = "freebsd", target_os = "dragonfly"),
368        any(target_os = "macos", target_os = "ios"),
369        any(target_os = "openbsd", target_os = "netbsd"),
370        target_os = "android",
371        target_os = "emscripten",
372        target_os = "fuchsia",
373    ))]
374    MEMLOCK = 8 => RLIMIT_MEMLOCK,
375
376
377    /// A limit on the number
378    /// of bytes that can be allocated for POSIX message queues
379    /// for the real user ID of the calling process.
380    #[cfg(any(
381        all(target_os = "linux", target_env = "gnu"),
382        all(target_os = "linux", target_env = "musl"),
383        all(target_os = "linux", target_env = "uclibc"),
384        target_os = "android",
385        target_os = "emscripten",
386        target_os = "fuchsia",
387    ))]
388    MSGQUEUE = 9 => RLIMIT_MSGQUEUE,
389
390
391    /// This specifies a ceiling
392    /// to which the process's nice value can be raised
393    /// using `setpriority(2)` or `nice(2)`.
394    #[cfg(any(
395        all(target_os = "linux", target_env = "gnu"),
396        all(target_os = "linux", target_env = "musl"),
397        all(target_os = "linux", target_env = "uclibc"),
398        target_os = "android",
399        target_os = "emscripten",
400        target_os = "fuchsia",
401    ))]
402    NICE = 10 => RLIMIT_NICE,
403
404
405    /// This specifies a value
406    /// one greater than the maximum file descriptor number
407    /// that can be opened by this process.
408    #[cfg(any(
409        all(target_os = "linux", target_env = "gnu"),
410        all(target_os = "linux", target_env = "musl", any(target_arch = "x86", target_arch = "mips", target_arch = "powerpc", target_arch = "hexagon", target_arch = "arm")),
411        all(target_os = "linux", target_env = "musl", any(target_arch = "x86_64", target_arch = "aarch64", target_arch = "mips64", target_arch = "powerpc64")),
412        all(target_os = "linux", target_env = "uclibc", any(target_arch = "mips", target_arch = "mips64")),
413        any(target_os = "freebsd", target_os = "dragonfly"),
414        any(target_os = "macos", target_os = "ios"),
415        any(target_os = "openbsd", target_os = "netbsd"),
416        target_os = "android",
417        target_os = "emscripten",
418        target_os = "fuchsia",
419        target_os = "haiku",
420        target_os = "solarish",
421    ))]
422    NOFILE = 11 => RLIMIT_NOFILE,
423
424
425    /// The number of open vnode monitors.
426    #[cfg(any(
427        target_os = "haiku",
428    ))]
429    NOVMON = 12 => RLIMIT_NOVMON,
430
431
432    /// A limit on the number of extant process (or, more precisely on Linux, threads)
433    /// for the real user ID of the calling process.
434    #[cfg(any(
435        all(target_os = "linux", target_env = "gnu"),
436        all(target_os = "linux", target_env = "musl", any(target_arch = "x86", target_arch = "mips", target_arch = "powerpc", target_arch = "hexagon", target_arch = "arm")),
437        all(target_os = "linux", target_env = "musl", any(target_arch = "x86_64", target_arch = "aarch64", target_arch = "mips64", target_arch = "powerpc64")),
438        all(target_os = "linux", target_env = "uclibc", any(target_arch = "mips", target_arch = "mips64")),
439        any(target_os = "freebsd", target_os = "dragonfly"),
440        any(target_os = "macos", target_os = "ios"),
441        any(target_os = "openbsd", target_os = "netbsd"),
442        target_os = "android",
443        target_os = "emscripten",
444        target_os = "fuchsia",
445    ))]
446    NPROC = 13 => RLIMIT_NPROC,
447
448
449    /// The maximum number of pseudo-terminals this user id is allowed to create.
450    #[cfg(any(
451        target_os = "freebsd",
452    ))]
453    NPTS = 14 => RLIMIT_NPTS,
454
455
456    /// The maximum number of simultaneous threads (Lightweight
457    /// Processes) for this user id.  Kernel threads and the
458    /// first thread of each process are not counted against this
459    /// limit.
460    #[cfg(any(
461        target_os = "netbsd",
462    ))]
463    NTHR = 15 => RLIMIT_NTHR,
464
465
466    /// The maximum number of POSIX-type advisory-mode locks available to this user.
467    #[cfg(any(
468        target_os = "dragonfly",
469    ))]
470    POSIXLOCKS = 16 => RLIMIT_POSIXLOCKS,
471
472
473    /// A limit (in bytes)
474    /// on the process's resident set
475    /// (the number of virtual pages resident in RAM).
476    #[cfg(any(
477        all(target_os = "linux", target_env = "gnu"),
478        all(target_os = "linux", target_env = "musl", any(target_arch = "x86", target_arch = "mips", target_arch = "powerpc", target_arch = "hexagon", target_arch = "arm")),
479        all(target_os = "linux", target_env = "musl", any(target_arch = "x86_64", target_arch = "aarch64", target_arch = "mips64", target_arch = "powerpc64")),
480        all(target_os = "linux", target_env = "uclibc", any(target_arch = "mips", target_arch = "mips64")),
481        any(target_os = "freebsd", target_os = "dragonfly"),
482        any(target_os = "macos", target_os = "ios"),
483        any(target_os = "openbsd", target_os = "netbsd"),
484        target_os = "android",
485        target_os = "emscripten",
486        target_os = "fuchsia",
487    ))]
488    RSS = 17 => RLIMIT_RSS,
489
490
491    /// This specifies a ceiling on the real-time priority
492    /// that may be set for this process
493    /// using `sched_setscheduler(2)` and `sched_setparam(2)`.
494    #[cfg(any(
495        all(target_os = "linux", target_env = "gnu"),
496        all(target_os = "linux", target_env = "musl"),
497        all(target_os = "linux", target_env = "uclibc"),
498        target_os = "android",
499        target_os = "emscripten",
500        target_os = "fuchsia",
501    ))]
502    RTPRIO = 18 => RLIMIT_RTPRIO,
503
504
505    /// A limit (in microseconds) on the amount of CPU time
506    /// that a process scheduled under a real-time scheduling policy
507    /// may consume without making a blocking system call.
508    #[cfg(any(
509        all(target_os = "linux", target_env = "gnu"),
510        all(target_os = "linux", target_env = "musl"),
511        target_os = "fuchsia",
512    ))]
513    RTTIME = 19 => RLIMIT_RTTIME,
514
515
516    /// The maximum size (in bytes) of socket buffer usage for
517    /// this user. This limits the amount of network memory, and
518    /// hence the amount of mbufs, that this user may hold at any
519    /// time.
520    #[cfg(any(
521        any(target_os = "freebsd", target_os = "dragonfly"),
522        target_os = "netbsd",
523    ))]
524    SBSIZE = 20 => RLIMIT_SBSIZE,
525
526
527    /// A limit on the number
528    /// of signals that may be queued
529    /// for the real user ID of the calling process.
530    #[cfg(any(
531        all(target_os = "linux", target_env = "gnu"),
532        all(target_os = "linux", target_env = "musl"),
533        all(target_os = "linux", target_env = "uclibc"),
534        target_os = "android",
535        target_os = "emscripten",
536        target_os = "fuchsia",
537    ))]
538    SIGPENDING = 21 => RLIMIT_SIGPENDING,
539
540
541    /// The maximum size (in bytes)
542    /// of the process stack.
543    #[cfg(any(
544        all(target_os = "linux", target_env = "gnu"),
545        all(target_os = "linux", target_env = "musl"),
546        all(target_os = "linux", target_env = "uclibc"),
547        any(target_os = "freebsd", target_os = "dragonfly"),
548        any(target_os = "macos", target_os = "ios"),
549        any(target_os = "openbsd", target_os = "netbsd"),
550        target_os = "android",
551        target_os = "emscripten",
552        target_os = "fuchsia",
553        target_os = "haiku",
554        target_os = "solarish",
555    ))]
556    STACK = 22 => RLIMIT_STACK,
557
558
559    /// The maximum size (in bytes) of the swap space that may be
560    /// reserved or used by all of this user id's processes.
561    #[cfg(any(
562        target_os = "freebsd",
563    ))]
564    SWAP = 23 => RLIMIT_SWAP,
565
566
567    /// The number of shared locks a given user may create simultaneously.
568    #[cfg(any(
569        target_os = "freebsd",
570    ))]
571    UMTXP = 24 => RLIMIT_UMTXP,
572
573
574    /// An alias for RLIMIT_AS. The maximum size of a process's mapped address space in bytes.
575    #[cfg(any(
576        any(target_os = "freebsd", target_os = "dragonfly"),
577        target_os = "solarish",
578    ))]
579    VMEM = 25 => RLIMIT_VMEM,
580
581}
582// #end-codegen