rlimit/
unix.rs

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