Skip to content

Commit ba42d04

Browse files
bors[bot]LMJW
andauthored
Merge #1302
1302: Add getrlimit and setrlimit r=asomers a=LMJW This PR is based on the previous PR #1190, which has not been updated for a very long time. I have fixed the segfault and compilation error of the original PR and rebased the changes to the latest master branch. Please let me know if anything need to been changed. Co-authored-by: LMJW <heysuperming@gmail.com>
2 parents 3c45e08 + cd004aa commit ba42d04

File tree

5 files changed

+224
-0
lines changed

5 files changed

+224
-0
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ This project adheres to [Semantic Versioning](https://semver.org/).
1818
(#[1472](https://github.com/nix-rust/nix/pull/1472))
1919
- Added `mknodat`.
2020
(#[1473](https://github.com/nix-rust/nix/pull/1473))
21+
- Added `setrlimit` and `getrlimit`.
22+
(#[1302](https://github.com/nix-rust/nix/pull/1302))
2123

2224
### Changed
2325

src/sys/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,9 @@ pub mod quota;
5959
#[cfg(any(target_os = "linux"))]
6060
pub mod reboot;
6161

62+
#[cfg(not(any(target_os = "redox", target_os = "fuchsia", target_os = "illumos")))]
63+
pub mod resource;
64+
6265
#[cfg(not(target_os = "redox"))]
6366
pub mod select;
6467

src/sys/resource.rs

Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
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(target_os = "netbsd", target_os = "freebsd")))]
53+
RLIMIT_AS,
54+
RLIMIT_CORE,
55+
RLIMIT_CPU,
56+
RLIMIT_DATA,
57+
RLIMIT_FSIZE,
58+
RLIMIT_NOFILE,
59+
RLIMIT_STACK,
60+
61+
#[cfg(target_os = "freebsd")]
62+
RLIMIT_KQUEUES,
63+
64+
#[cfg(any(target_os = "android", target_os = "linux"))]
65+
RLIMIT_LOCKS,
66+
67+
#[cfg(any(target_os = "android", target_os = "freebsd", target_os = "openbsd", target_os = "linux"))]
68+
RLIMIT_MEMLOCK,
69+
70+
#[cfg(any(target_os = "android", target_os = "linux"))]
71+
RLIMIT_MSGQUEUE,
72+
73+
#[cfg(any(target_os = "android", target_os = "linux"))]
74+
RLIMIT_NICE,
75+
76+
#[cfg(any(target_os = "android", target_os = "freebsd", target_os = "openbsd", target_os = "linux"))]
77+
RLIMIT_NPROC,
78+
79+
#[cfg(target_os = "freebsd")]
80+
RLIMIT_NPTS,
81+
82+
#[cfg(any(target_os = "android", target_os = "freebsd", target_os = "openbsd", target_os = "linux"))]
83+
RLIMIT_RSS,
84+
85+
#[cfg(any(target_os = "android", target_os = "linux"))]
86+
RLIMIT_RTPRIO,
87+
88+
#[cfg(any(target_os = "linux"))]
89+
RLIMIT_RTTIME,
90+
91+
#[cfg(any(target_os = "android", target_os = "linux"))]
92+
RLIMIT_SIGPENDING,
93+
94+
#[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
95+
RLIMIT_SBSIZE,
96+
97+
#[cfg(target_os = "freebsd")]
98+
RLIMIT_SWAP,
99+
100+
#[cfg(target_os = "freebsd")]
101+
RLIMIT_VMEM,
102+
}
103+
}
104+
105+
/// Get the current processes resource limits
106+
///
107+
/// A value of `None` indicates the value equals to `RLIM_INFINITY` which means
108+
/// there is no limit.
109+
///
110+
/// # Parameters
111+
///
112+
/// * `resource`: The [`Resource`] that we want to get the limits of.
113+
///
114+
/// # Examples
115+
///
116+
/// ```
117+
/// # use nix::sys::resource::{getrlimit, Resource};
118+
///
119+
/// let (soft_limit, hard_limit) = getrlimit(Resource::RLIMIT_NOFILE).unwrap();
120+
/// println!("current soft_limit: {:?}", soft_limit);
121+
/// println!("current hard_limit: {:?}", hard_limit);
122+
/// ```
123+
///
124+
/// # References
125+
///
126+
/// [getrlimit(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getrlimit.html#tag_16_215)
127+
///
128+
/// [`Resource`]: enum.Resource.html
129+
pub fn getrlimit(resource: Resource) -> Result<(Option<rlim_t>, Option<rlim_t>)> {
130+
let mut old_rlim = mem::MaybeUninit::<rlimit>::uninit();
131+
132+
cfg_if! {
133+
if #[cfg(all(target_os = "linux", target_env = "gnu"))]{
134+
let res = unsafe { libc::getrlimit(resource as __rlimit_resource_t, old_rlim.as_mut_ptr()) };
135+
}else{
136+
let res = unsafe { libc::getrlimit(resource as c_int, old_rlim.as_mut_ptr()) };
137+
}
138+
}
139+
140+
Errno::result(res).map(|_| {
141+
let rlimit { rlim_cur, rlim_max } = unsafe { old_rlim.assume_init() };
142+
(Some(rlim_cur), Some(rlim_max))
143+
})
144+
}
145+
146+
/// Set the current processes resource limits
147+
///
148+
/// # Parameters
149+
///
150+
/// * `resource`: The [`Resource`] that we want to set the limits of.
151+
/// * `soft_limit`: The value that the kernel enforces for the corresponding
152+
/// resource. Note: `None` input will be replaced by constant `RLIM_INFINITY`.
153+
/// * `hard_limit`: The ceiling for the soft limit. Must be lower or equal to
154+
/// the current hard limit for non-root users. Note: `None` input will be
155+
/// replaced by constant `RLIM_INFINITY`.
156+
///
157+
/// > Note: for some os (linux_gnu), setting hard_limit to `RLIM_INFINITY` can
158+
/// > results `EPERM` Error. So you will need to set the number explicitly.
159+
///
160+
/// # Examples
161+
///
162+
/// ```
163+
/// # use nix::sys::resource::{setrlimit, Resource};
164+
///
165+
/// let soft_limit = Some(1024);
166+
/// let hard_limit = Some(1048576);
167+
/// setrlimit(Resource::RLIMIT_NOFILE, soft_limit, hard_limit).unwrap();
168+
/// ```
169+
///
170+
/// # References
171+
///
172+
/// [setrlimit(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getrlimit.html#tag_16_215)
173+
///
174+
/// [`Resource`]: enum.Resource.html
175+
///
176+
/// Note: `setrlimit` provides a safe wrapper to libc's `setrlimit`.
177+
pub fn setrlimit(
178+
resource: Resource,
179+
soft_limit: Option<rlim_t>,
180+
hard_limit: Option<rlim_t>,
181+
) -> Result<()> {
182+
let new_rlim = rlimit {
183+
rlim_cur: soft_limit.unwrap_or(RLIM_INFINITY),
184+
rlim_max: hard_limit.unwrap_or(RLIM_INFINITY),
185+
};
186+
cfg_if! {
187+
if #[cfg(all(target_os = "linux", target_env = "gnu"))]{
188+
let res = unsafe { libc::setrlimit(resource as __rlimit_resource_t, &new_rlim as *const rlimit) };
189+
}else{
190+
let res = unsafe { libc::setrlimit(resource as c_int, &new_rlim as *const rlimit) };
191+
}
192+
}
193+
194+
Errno::result(res).map(drop)
195+
}

test/test.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ mod test_mq;
2424
#[cfg(not(target_os = "redox"))]
2525
mod test_net;
2626
mod test_nix_path;
27+
mod test_resource;
2728
mod test_poll;
2829
#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))]
2930
mod test_pty;

test/test_resource.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#[cfg(not(any(target_os = "redox", target_os = "fuchsia", target_os = "illumos")))]
2+
use nix::sys::resource::{getrlimit, setrlimit, Resource};
3+
4+
/// Tests the RLIMIT_NOFILE functionality of getrlimit(), where the resource RLIMIT_NOFILE refers
5+
/// to the maximum file descriptor number that can be opened by the process (aka the maximum number
6+
/// of file descriptors that the process can open, since Linux 4.5).
7+
///
8+
/// We first fetch the existing file descriptor maximum values using getrlimit(), then edit the
9+
/// soft limit to make sure it has a new and distinct value to the hard limit. We then setrlimit()
10+
/// to put the new soft limit in effect, and then getrlimit() once more to ensure the limits have
11+
/// been updated.
12+
#[test]
13+
#[cfg(not(any(target_os = "redox", target_os = "fuchsia", target_os = "illumos")))]
14+
pub fn test_resource_limits_nofile() {
15+
let (soft_limit, hard_limit) = getrlimit(Resource::RLIMIT_NOFILE).unwrap();
16+
17+
let soft_limit = Some(soft_limit.map_or(1024, |v| v - 1));
18+
assert_ne!(soft_limit, hard_limit);
19+
setrlimit(Resource::RLIMIT_NOFILE, soft_limit, hard_limit).unwrap();
20+
21+
let (new_soft_limit, _) = getrlimit(Resource::RLIMIT_NOFILE).unwrap();
22+
assert_eq!(new_soft_limit, soft_limit);
23+
}

0 commit comments

Comments
 (0)