1 //! Configure the process resource limits.
2 use cfg_if::cfg_if;
3 
4 use crate::errno::Errno;
5 use crate::Result;
6 pub use libc::rlim_t;
7 use std::mem;
8 
9 cfg_if! {
10     if #[cfg(all(target_os = "linux", target_env = "gnu"))]{
11         use libc::{__rlimit_resource_t, rlimit, RLIM_INFINITY};
12     }else if #[cfg(any(
13         target_os = "freebsd",
14         target_os = "openbsd",
15         target_os = "netbsd",
16         target_os = "macos",
17         target_os = "ios",
18         target_os = "android",
19         target_os = "dragonfly",
20         all(target_os = "linux", not(target_env = "gnu"))
21     ))]{
22         use libc::{c_int, rlimit, RLIM_INFINITY};
23     }
24 }
25 
26 libc_enum! {
27     /// The Resource enum is platform dependent. Check different platform
28     /// manuals for more details. Some platform links has been provided for
29     /// earier reference (non-exhaustive).
30     ///
31     /// * [Linux](https://man7.org/linux/man-pages/man2/getrlimit.2.html)
32     /// * [FreeBSD](https://www.freebsd.org/cgi/man.cgi?query=setrlimit)
33 
34     // linux-gnu uses u_int as resource enum, which is implemented in libc as
35     // well.
36     //
37     // https://gcc.gnu.org/legacy-ml/gcc/2015-08/msg00441.html
38     // https://github.com/rust-lang/libc/blob/master/src/unix/linux_like/linux/gnu/mod.rs
39     #[cfg_attr(all(target_os = "linux", target_env = "gnu"), repr(u32))]
40     #[cfg_attr(any(
41             target_os = "freebsd",
42             target_os = "openbsd",
43             target_os = "netbsd",
44             target_os = "macos",
45             target_os = "ios",
46             target_os = "android",
47             target_os = "dragonfly",
48             all(target_os = "linux", not(target_env = "gnu"))
49         ), repr(i32))]
50     #[non_exhaustive]
51     pub enum Resource {
52         #[cfg(not(any(
53                     target_os = "freebsd",
54                     target_os = "netbsd",
55                     target_os = "openbsd"
56         )))]
57         /// The maximum amount (in bytes) of virtual memory the process is
58         /// allowed to map.
59         RLIMIT_AS,
60         /// The largest size (in bytes) core(5) file that may be created.
61         RLIMIT_CORE,
62         /// The maximum amount of cpu time (in seconds) to be used by each
63         /// process.
64         RLIMIT_CPU,
65         /// The maximum size (in bytes) of the data segment for a process
66         RLIMIT_DATA,
67         /// The largest size (in bytes) file that may be created.
68         RLIMIT_FSIZE,
69         /// The maximum number of open files for this process.
70         RLIMIT_NOFILE,
71         /// The maximum size (in bytes) of the stack segment for a process.
72         RLIMIT_STACK,
73 
74         #[cfg(target_os = "freebsd")]
75         /// The maximum number of kqueues this user id is allowed to create.
76         RLIMIT_KQUEUES,
77 
78         #[cfg(any(target_os = "android", target_os = "linux"))]
79         /// A limit on the combined number of flock locks and fcntl leases that
80         /// this process may establish.
81         RLIMIT_LOCKS,
82 
83         #[cfg(any(target_os = "android", target_os = "freebsd", target_os = "openbsd", target_os = "linux"))]
84         /// The maximum size (in bytes) which a process may lock into memory
85         /// using the mlock(2) system call.
86         RLIMIT_MEMLOCK,
87 
88         #[cfg(any(target_os = "android", target_os = "linux"))]
89         /// A limit on the number of bytes that can be allocated for POSIX
90         /// message queues  for  the  real  user  ID  of  the  calling process.
91         RLIMIT_MSGQUEUE,
92 
93         #[cfg(any(target_os = "android", target_os = "linux"))]
94         /// A ceiling to which the process's nice value can be raised using
95         /// setpriority or nice.
96         RLIMIT_NICE,
97 
98         #[cfg(any(target_os = "android", target_os = "freebsd", target_os = "openbsd", target_os = "linux"))]
99         /// The maximum number of simultaneous processes for this user id.
100         RLIMIT_NPROC,
101 
102         #[cfg(target_os = "freebsd")]
103         /// The maximum number of pseudo-terminals this user id is allowed to
104         /// create.
105         RLIMIT_NPTS,
106 
107         #[cfg(any(target_os = "android", target_os = "freebsd", target_os = "openbsd", target_os = "linux"))]
108         /// When there is memory pressure and swap is available, prioritize
109         /// eviction of a process' resident pages beyond this amount (in bytes).
110         RLIMIT_RSS,
111 
112         #[cfg(any(target_os = "android", target_os = "linux"))]
113         /// A ceiling on the real-time priority that may be set for this process
114         /// using sched_setscheduler and  sched_set‐ param.
115         RLIMIT_RTPRIO,
116 
117         #[cfg(any(target_os = "linux"))]
118         /// A limit (in microseconds) on the amount of CPU time that a process
119         /// scheduled under a real-time scheduling policy may con‐ sume without
120         /// making a blocking system call.
121         RLIMIT_RTTIME,
122 
123         #[cfg(any(target_os = "android", target_os = "linux"))]
124         /// A limit on the number of signals that may be queued for the real
125         /// user ID of the  calling  process.
126         RLIMIT_SIGPENDING,
127 
128         #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
129         /// The maximum size (in bytes) of socket buffer usage for this user.
130         RLIMIT_SBSIZE,
131 
132         #[cfg(target_os = "freebsd")]
133         /// The maximum size (in bytes) of the swap space that may be reserved
134         /// or used by all of this user id's processes.
135         RLIMIT_SWAP,
136 
137         #[cfg(target_os = "freebsd")]
138         /// An alias for RLIMIT_AS.
139         RLIMIT_VMEM,
140     }
141 }
142 
143 /// Get the current processes resource limits
144 ///
145 /// A value of `None` indicates the value equals to `RLIM_INFINITY` which means
146 /// there is no limit.
147 ///
148 /// # Parameters
149 ///
150 /// * `resource`: The [`Resource`] that we want to get the limits of.
151 ///
152 /// # Examples
153 ///
154 /// ```
155 /// # use nix::sys::resource::{getrlimit, Resource};
156 ///
157 /// let (soft_limit, hard_limit) = getrlimit(Resource::RLIMIT_NOFILE).unwrap();
158 /// println!("current soft_limit: {:?}", soft_limit);
159 /// println!("current hard_limit: {:?}", hard_limit);
160 /// ```
161 ///
162 /// # References
163 ///
164 /// [getrlimit(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getrlimit.html#tag_16_215)
165 ///
166 /// [`Resource`]: enum.Resource.html
getrlimit(resource: Resource) -> Result<(Option<rlim_t>, Option<rlim_t>)>167 pub fn getrlimit(resource: Resource) -> Result<(Option<rlim_t>, Option<rlim_t>)> {
168     let mut old_rlim = mem::MaybeUninit::<rlimit>::uninit();
169 
170     cfg_if! {
171         if #[cfg(all(target_os = "linux", target_env = "gnu"))]{
172             let res = unsafe { libc::getrlimit(resource as __rlimit_resource_t, old_rlim.as_mut_ptr()) };
173         }else{
174             let res = unsafe { libc::getrlimit(resource as c_int, old_rlim.as_mut_ptr()) };
175         }
176     }
177 
178     Errno::result(res).map(|_| {
179         let rlimit { rlim_cur, rlim_max } = unsafe { old_rlim.assume_init() };
180         (Some(rlim_cur), Some(rlim_max))
181     })
182 }
183 
184 /// Set the current processes resource limits
185 ///
186 /// # Parameters
187 ///
188 /// * `resource`: The [`Resource`] that we want to set the limits of.
189 /// * `soft_limit`: The value that the kernel enforces for the corresponding
190 ///   resource. Note: `None` input will be replaced by constant `RLIM_INFINITY`.
191 /// * `hard_limit`: The ceiling for the soft limit. Must be lower or equal to
192 ///   the current hard limit for non-root users. Note: `None` input will be
193 ///   replaced by constant `RLIM_INFINITY`.
194 ///
195 /// > Note: for some os (linux_gnu), setting hard_limit to `RLIM_INFINITY` can
196 /// > results `EPERM` Error. So you will need to set the number explicitly.
197 ///
198 /// # Examples
199 ///
200 /// ```
201 /// # use nix::sys::resource::{setrlimit, Resource};
202 ///
203 /// let soft_limit = Some(512);
204 /// let hard_limit = Some(1024);
205 /// setrlimit(Resource::RLIMIT_NOFILE, soft_limit, hard_limit).unwrap();
206 /// ```
207 ///
208 /// # References
209 ///
210 /// [setrlimit(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getrlimit.html#tag_16_215)
211 ///
212 /// [`Resource`]: enum.Resource.html
213 ///
214 /// Note: `setrlimit` provides a safe wrapper to libc's `setrlimit`.
setrlimit( resource: Resource, soft_limit: Option<rlim_t>, hard_limit: Option<rlim_t>, ) -> Result<()>215 pub fn setrlimit(
216     resource: Resource,
217     soft_limit: Option<rlim_t>,
218     hard_limit: Option<rlim_t>,
219 ) -> Result<()> {
220     let new_rlim = rlimit {
221         rlim_cur: soft_limit.unwrap_or(RLIM_INFINITY),
222         rlim_max: hard_limit.unwrap_or(RLIM_INFINITY),
223     };
224     cfg_if! {
225         if #[cfg(all(target_os = "linux", target_env = "gnu"))]{
226             let res = unsafe { libc::setrlimit(resource as __rlimit_resource_t, &new_rlim as *const rlimit) };
227         }else{
228             let res = unsafe { libc::setrlimit(resource as c_int, &new_rlim as *const rlimit) };
229         }
230     }
231 
232     Errno::result(res).map(drop)
233 }
234