1#![allow(non_camel_case_types)]
2
3mod resource;
4
5pub use self::resource::{RawResource, Resource};
6
7#[cfg(target_os = "linux")]
8group! {
9 mod proc_limits;
10 pub use self::proc_limits::{ProcLimit, ProcLimits};
11}
12
13#[cfg(any(target_os = "emscripten", target_os = "fuchsia", target_os = "linux",))]
16group! {
17 type c_rlimit = libc::rlimit64;
18 use libc::setrlimit64 as c_setrlimit;
19 use libc::getrlimit64 as c_getrlimit;
20 const RLIM_INFINITY: u64 = u64::MAX;
21 const RLIM_SAVED_CUR: u64 = u64::MAX;
22 const RLIM_SAVED_MAX: u64 = u64::MAX;
23}
24
25#[cfg(not(any(target_os = "emscripten", target_os = "fuchsia", target_os = "linux",)))]
26group! {
27 type c_rlimit = libc::rlimit;
28 use libc::setrlimit as c_setrlimit;
29 use libc::getrlimit as c_getrlimit;
30 #[cfg(any(
31 all(target_os = "linux", target_env = "gnu"),
32 all(target_os = "linux", target_env = "musl"),
33 all(target_os = "linux", target_env = "uclibc", target_arch = "arm"),
34 all(target_os = "linux", target_env = "uclibc", target_arch = "mips"),
35 all(target_os = "linux", target_env = "uclibc", target_arch = "mips64"),
36 all(target_os = "linux", target_env = "uclibc", target_arch = "x86_64"),
37 any(target_os = "freebsd", target_os = "dragonfly"),
38 any(target_os = "macos", target_os = "ios"),
39 any(target_os = "openbsd", target_os = "netbsd"),
40 target_os = "android",
41 target_os = "emscripten",
42 target_os = "fuchsia",
43 target_os = "solarish",
44 ))]
45 const RLIM_INFINITY: u64 = libc::RLIM_INFINITY as u64;
46 #[cfg(any(
47 any(target_os = "openbsd", target_os = "netbsd"),
48 target_os = "emscripten",
49 target_os = "fuchsia",
50 target_os = "linux",
51 ))]
52 const RLIM_SAVED_CUR: u64 = libc::RLIM_SAVED_CUR as u64;
53 #[cfg(any(
54 any(target_os = "openbsd", target_os = "netbsd"),
55 target_os = "emscripten",
56 target_os = "fuchsia",
57 target_os = "linux",
58 ))]
59 const RLIM_SAVED_MAX: u64 = libc::RLIM_SAVED_MAX as u64;
60}
61
62#[cfg(any(
64 all(target_os = "linux", target_env = "gnu"),
65 all(target_os = "linux", target_env = "musl"),
66 all(target_os = "linux", target_env = "uclibc", target_arch = "arm"),
67 all(target_os = "linux", target_env = "uclibc", target_arch = "mips"),
68 all(target_os = "linux", target_env = "uclibc", target_arch = "mips64"),
69 all(target_os = "linux", target_env = "uclibc", target_arch = "x86_64"),
70 any(target_os = "freebsd", target_os = "dragonfly"),
71 any(target_os = "macos", target_os = "ios"),
72 any(target_os = "openbsd", target_os = "netbsd"),
73 target_os = "android",
74 target_os = "emscripten",
75 target_os = "fuchsia",
76 target_os = "solarish",
77))]
78pub const INFINITY: u64 = RLIM_INFINITY;
79
80#[cfg(any(
82 any(target_os = "openbsd", target_os = "netbsd"),
83 target_os = "emscripten",
84 target_os = "fuchsia",
85 target_os = "linux",
86))]
87pub const SAVED_CUR: u64 = RLIM_SAVED_CUR;
88
89#[cfg(any(
91 any(target_os = "openbsd", target_os = "netbsd"),
92 target_os = "emscripten",
93 target_os = "fuchsia",
94 target_os = "linux",
95))]
96pub const SAVED_MAX: u64 = RLIM_SAVED_MAX;
97
98use std::io;
101use std::mem;
102
103use libc::c_int;
104
105#[cfg(target_os = "linux")]
106group! {
107 use std::ptr;
108 use libc::pid_t;
109}
110
111#[inline]
115pub fn setrlimit(resource: Resource, soft: u64, hard: u64) -> io::Result<()> {
116 let raw_resource = resource.as_raw();
117
118 let rlim = c_rlimit {
119 rlim_cur: soft.min(INFINITY) as _,
120 rlim_max: hard.min(INFINITY) as _,
121 };
122
123 let ret: c_int = unsafe { c_setrlimit(raw_resource, &rlim) };
124
125 if ret == 0 {
126 Ok(())
127 } else {
128 Err(io::Error::last_os_error())
129 }
130}
131
132#[inline]
136pub fn getrlimit(resource: Resource) -> io::Result<(u64, u64)> {
137 let raw_resource = resource.as_raw();
138
139 let mut rlim: c_rlimit = unsafe { mem::zeroed() };
140
141 let ret: c_int = unsafe { c_getrlimit(raw_resource, &mut rlim) };
142
143 if ret == 0 {
144 let soft = rlim.rlim_cur as u64;
145 let hard = rlim.rlim_max as u64;
146 Ok((soft, hard))
147 } else {
148 Err(io::Error::last_os_error())
149 }
150}
151
152#[inline]
156#[cfg(target_os = "linux")]
157pub fn prlimit(
158 pid: pid_t,
159 resource: Resource,
160 new_limit: Option<(u64, u64)>,
161 old_limit: Option<(&mut u64, &mut u64)>,
162) -> io::Result<()> {
163 let raw_resource = resource.as_raw();
164
165 let new_rlim: Option<libc::rlimit> = new_limit.map(|(soft, hard)| libc::rlimit {
166 rlim_cur: soft.min(INFINITY) as _,
167 rlim_max: hard.min(INFINITY) as _,
168 });
169
170 let new_rlimit_ptr: *const libc::rlimit = match new_rlim {
171 Some(ref rlim) => rlim,
172 None => ptr::null(),
173 };
174
175 let mut old_rlim: libc::rlimit = unsafe { mem::zeroed() };
176
177 let old_rlimit_ptr: *mut libc::rlimit = if old_limit.is_some() {
178 &mut old_rlim
179 } else {
180 ptr::null_mut()
181 };
182
183 let ret: c_int = unsafe { libc::prlimit(pid, raw_resource, new_rlimit_ptr, old_rlimit_ptr) };
184
185 if ret == 0 {
186 if let Some((soft, hard)) = old_limit {
187 *soft = old_rlim.rlim_cur as u64;
188 *hard = old_rlim.rlim_max as u64;
189 }
190
191 Ok(())
192 } else {
193 Err(io::Error::last_os_error())
194 }
195}