rlimit/
unix.rs

1use crate::bindings as C;
2use crate::resource::Resource;
3
4use std::{io, mem};
5
6/// A value indicating no limit.
7#[allow(clippy::unnecessary_cast)]
8pub const INFINITY: u64 = C::RLIM_INFINITY as u64;
9
10fn check_supported(resource: Resource) -> io::Result<()> {
11    let raw_resource = resource.as_raw();
12    if raw_resource == u8::MAX {
13        return Err(io::Error::new(io::ErrorKind::Other, "unsupported resource"));
14    }
15    Ok(())
16}
17
18/// Set resource limits.
19/// # Errors
20/// \[Linux\] See <https://man7.org/linux/man-pages/man2/setrlimit.2.html>
21#[allow(clippy::unnecessary_min_or_max)]
22#[inline]
23pub fn setrlimit(resource: Resource, soft: u64, hard: u64) -> io::Result<()> {
24    check_supported(resource)?;
25    let rlim = C::rlimit {
26        rlim_cur: soft.min(INFINITY) as _,
27        rlim_max: hard.min(INFINITY) as _,
28    };
29    #[allow(clippy::cast_lossless)]
30    let ret = unsafe { C::setrlimit(resource.as_raw() as _, &rlim) };
31    if ret == 0 {
32        Ok(())
33    } else {
34        Err(io::Error::last_os_error())
35    }
36}
37
38/// Get resource limits.
39/// # Errors
40/// \[Linux\] See <https://man7.org/linux/man-pages/man2/getrlimit.2.html>
41#[allow(clippy::unnecessary_min_or_max)]
42#[inline]
43pub fn getrlimit(resource: Resource) -> io::Result<(u64, u64)> {
44    check_supported(resource)?;
45    let mut rlim = unsafe { mem::zeroed() };
46    #[allow(clippy::cast_lossless)]
47    let ret = unsafe { C::getrlimit(resource.as_raw() as _, &mut rlim) };
48
49    #[allow(clippy::unnecessary_cast)]
50    if ret == 0 {
51        let soft = (rlim.rlim_cur as u64).min(INFINITY);
52        let hard = (rlim.rlim_max as u64).min(INFINITY);
53        Ok((soft, hard))
54    } else {
55        Err(io::Error::last_os_error())
56    }
57}
58
59/// The type of a process ID
60#[allow(non_camel_case_types)]
61#[cfg_attr(docsrs, doc(cfg(any(target_os = "linux", target_os = "android"))))]
62#[cfg(any(doc, target_os = "linux", target_os = "android"))]
63pub type pid_t = i32;
64
65/// Set and get the resource limits of an arbitrary process.
66/// # Errors
67/// See <https://man7.org/linux/man-pages/man2/prlimit.2.html>
68#[allow(clippy::unnecessary_min_or_max)]
69#[inline]
70#[cfg_attr(docsrs, doc(cfg(any(target_os = "linux", target_os = "android"))))]
71#[cfg(any(doc, rlimit__has_prlimit64))]
72pub fn prlimit(
73    pid: pid_t,
74    resource: Resource,
75    new_limit: Option<(u64, u64)>,
76    old_limit: Option<(&mut u64, &mut u64)>,
77) -> io::Result<()> {
78    check_supported(resource)?;
79
80    let new_rlim: Option<C::rlimit> = new_limit.map(|(soft, hard)| C::rlimit {
81        rlim_cur: soft.min(INFINITY) as _,
82        rlim_max: hard.min(INFINITY) as _,
83    });
84
85    let new_rlimit_ptr: *const C::rlimit = match new_rlim {
86        Some(ref rlim) => rlim,
87        None => std::ptr::null(),
88    };
89
90    let mut old_rlim: C::rlimit = unsafe { mem::zeroed() };
91
92    let old_rlimit_ptr: *mut C::rlimit = if old_limit.is_some() {
93        &mut old_rlim
94    } else {
95        std::ptr::null_mut()
96    };
97
98    #[allow(clippy::cast_lossless)]
99    let ret = unsafe { C::prlimit(pid, resource.as_raw() as _, new_rlimit_ptr, old_rlimit_ptr) };
100
101    if ret == 0 {
102        #[allow(clippy::unnecessary_cast)]
103        if let Some((soft, hard)) = old_limit {
104            *soft = (old_rlim.rlim_cur as u64).min(INFINITY);
105            *hard = (old_rlim.rlim_max as u64).min(INFINITY);
106        }
107
108        Ok(())
109    } else {
110        Err(io::Error::last_os_error())
111    }
112}