1use crate::bindings as C;
2use crate::resource::Resource;
3
4use std::{io, mem};
5
6pub 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#[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#[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#[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#[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}