Implement getrlimit.

This commit is contained in:
Dan Gohman
2021-09-29 15:26:42 -07:00
parent 4a257d2c1a
commit 5a7b4cb6d5
12 changed files with 378 additions and 12 deletions
+61
View File
@@ -19,5 +19,66 @@ fn main() -> io::Result<()> {
"Current working directory: {}",
getcwd(Default::default())?.to_string_lossy()
);
println!("Cpu Limit: {:?}", getrlimit(Resource::Cpu));
println!("Fsize Limit: {:?}", getrlimit(Resource::Fsize));
println!("Data Limit: {:?}", getrlimit(Resource::Data));
println!("Stack Limit: {:?}", getrlimit(Resource::Stack));
println!("Core Limit: {:?}", getrlimit(Resource::Core));
println!("Rss Limit: {:?}", getrlimit(Resource::Rss));
println!("Nproc Limit: {:?}", getrlimit(Resource::Nproc));
println!("Nofile Limit: {:?}", getrlimit(Resource::Nofile));
println!("Memlock Limit: {:?}", getrlimit(Resource::Memlock));
#[cfg(not(target_os = "openbsd"))]
println!("As Limit: {:?}", getrlimit(Resource::As));
#[cfg(not(any(
target_os = "freebsd",
target_os = "ios",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd",
)))]
println!("Locks Limit: {:?}", getrlimit(Resource::Locks));
#[cfg(not(any(
target_os = "freebsd",
target_os = "ios",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd",
)))]
println!("Sigpending Limit: {:?}", getrlimit(Resource::Sigpending));
#[cfg(not(any(
target_os = "freebsd",
target_os = "ios",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd",
)))]
println!("Msgqueue Limit: {:?}", getrlimit(Resource::Msgqueue));
#[cfg(not(any(
target_os = "freebsd",
target_os = "ios",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd",
)))]
println!("Nice Limit: {:?}", getrlimit(Resource::Nice));
#[cfg(not(any(
target_os = "freebsd",
target_os = "ios",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd",
)))]
println!("Rtprio Limit: {:?}", getrlimit(Resource::Rtprio));
#[cfg(not(any(
target_os = "emscripten",
target_os = "freebsd",
target_os = "android",
target_os = "ios",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd",
)))]
println!("Rttime Limit: {:?}", getrlimit(Resource::Rttime));
Ok(())
}
+5
View File
@@ -54,6 +54,11 @@ pub(super) fn nonnegative_ret(raw: c_int) -> io::Result<()> {
}
}
#[inline]
pub(super) unsafe fn ret_infallible(raw: c_int) {
debug_assert_eq!(raw, 0);
}
#[inline]
pub(super) fn ret_c_int(raw: c_int) -> io::Result<c_int> {
if raw == -1 {
+32 -1
View File
@@ -18,6 +18,7 @@ pub(super) use libc::{
))]
pub(super) use libc::{
fstat64 as libc_fstat, fstatat64 as libc_fstatat, lseek64 as libc_lseek, off64_t as libc_off_t,
rlimit64 as libc_rlimit,
};
#[cfg(not(any(
@@ -29,13 +30,43 @@ pub(super) use libc::{
)))]
pub(super) use libc::mmap as libc_mmap;
#[cfg(not(any(
target_os = "android",
target_os = "linux",
target_os = "emscripten",
target_os = "fuchsia",
target_os = "l4re",
target_os = "redox",
target_os = "wasi",
)))]
pub(super) use libc::{rlimit as libc_rlimit, RLIM_INFINITY as LIBC_RLIM_INFINITY};
#[cfg(not(any(
target_os = "android",
target_os = "fuchsia",
target_os = "emscripten",
target_os = "l4re",
target_os = "linux",
target_os = "wasi",
)))]
pub(super) use libc::getrlimit as libc_getrlimit;
// TODO: Add `RLIM64_INFINITY` to upstream libc.
#[cfg(any(
target_os = "android",
target_os = "linux",
target_os = "emscripten",
target_os = "l4re",
))]
pub(super) use libc::mmap64 as libc_mmap;
pub(super) const LIBC_RLIM_INFINITY: u64 = !0u64;
#[cfg(any(
target_os = "android",
target_os = "linux",
target_os = "emscripten",
target_os = "l4re",
))]
pub(super) use libc::{getrlimit64 as libc_getrlimit, mmap64 as libc_mmap};
#[cfg(not(any(
target_os = "android",
+2
View File
@@ -4,6 +4,8 @@ mod types;
#[cfg(any(target_os = "android", target_os = "linux"))]
pub(crate) use auxv::linux_hwcap;
pub(crate) use auxv::page_size;
#[cfg(not(any(target_os = "fuchsia", target_os = "redox", target_os = "wasi")))]
pub use types::Resource;
#[cfg(any(target_os = "android", target_os = "linux"))]
pub use types::{MembarrierCommand, RawCpuid};
#[cfg(not(target_os = "wasi"))]
+94
View File
@@ -35,6 +35,100 @@ pub enum MembarrierCommand {
RegisterPrivateExpeditedRseq = 256,
}
/// A resource value for use with [`getrlimit`].
///
/// [`getrlimit`]: crate::process::getrlimit
#[cfg(not(any(target_os = "fuchsia", target_os = "redox", target_os = "wasi")))]
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[repr(i32)]
pub enum Resource {
/// `RLIMIT_CPU`
Cpu = libc::RLIMIT_CPU as c_int,
/// `RLIMIT_FSIZE`
Fsize = libc::RLIMIT_FSIZE as c_int,
/// `RLIMIT_DATA`
Data = libc::RLIMIT_DATA as c_int,
/// `RLIMIT_STACK`
Stack = libc::RLIMIT_STACK as c_int,
/// `RLIMIT_CORE`
Core = libc::RLIMIT_CORE as c_int,
/// `RLIMIT_RSS`
#[cfg(not(any(target_os = "ios", target_os = "macos")))]
Rss = libc::RLIMIT_RSS as c_int,
/// `RLIMIT_NPROC`
Nproc = libc::RLIMIT_NPROC as c_int,
/// `RLIMIT_NOFILE`
Nofile = libc::RLIMIT_NOFILE as c_int,
/// `RLIMIT_MEMLOCK`
Memlock = libc::RLIMIT_MEMLOCK as c_int,
/// `RLIMIT_AS`
#[cfg(not(target_os = "openbsd"))]
As = libc::RLIMIT_AS as c_int,
/// `RLIMIT_LOCKS`
#[cfg(not(any(
target_os = "freebsd",
target_os = "ios",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd",
)))]
Locks = libc::RLIMIT_LOCKS as c_int,
/// `RLIMIT_SIGPENDING`
#[cfg(not(any(
target_os = "freebsd",
target_os = "ios",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd",
)))]
Sigpending = libc::RLIMIT_SIGPENDING as c_int,
/// `RLIMIT_MSGQUEUE`
#[cfg(not(any(
target_os = "freebsd",
target_os = "ios",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd",
)))]
Msgqueue = libc::RLIMIT_MSGQUEUE as c_int,
/// `RLIMIT_NICE`
#[cfg(not(any(
target_os = "freebsd",
target_os = "ios",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd",
)))]
Nice = libc::RLIMIT_NICE as c_int,
/// `RLIMIT_RTPRIO`
#[cfg(not(any(
target_os = "freebsd",
target_os = "ios",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd",
)))]
Rtprio = libc::RLIMIT_RTPRIO as c_int,
/// `RLIMIT_RTTIME`
#[cfg(not(any(
target_os = "emscripten",
target_os = "freebsd",
target_os = "android",
target_os = "ios",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd",
)))]
Rttime = libc::RLIMIT_RTTIME as c_int,
}
#[cfg(any(target_os = "ios", target_os = "macos"))]
impl Resource {
/// `RLIMIT_RSS`
#[allow(non_upper_case_globals)]
pub const Rss: Self = Self::As;
}
pub const EXIT_SUCCESS: c_int = libc::EXIT_SUCCESS;
pub const EXIT_FAILURE: c_int = libc::EXIT_FAILURE;
#[cfg(not(target_os = "wasi"))]
+31
View File
@@ -1,3 +1,5 @@
#[cfg(not(any(target_os = "fuchsia", target_os = "redox", target_os = "wasi")))]
use super::conv::ret_infallible;
#[cfg(not(any(
target_os = "freebsd",
target_os = "ios",
@@ -60,6 +62,8 @@ use super::net::{
use super::offset::libc_fallocate;
#[cfg(not(any(target_os = "netbsd", target_os = "redox", target_os = "wasi")))]
use super::offset::libc_fstatfs;
#[cfg(not(any(target_os = "fuchsia", target_os = "wasi")))]
use super::offset::libc_getrlimit;
#[cfg(not(target_os = "wasi"))]
use super::offset::libc_mmap;
#[cfg(not(any(
@@ -84,13 +88,19 @@ use super::offset::libc_posix_fallocate;
use super::offset::{libc_fstat, libc_fstatat, libc_lseek, libc_off_t, libc_pread, libc_pwrite};
#[cfg(all(target_os = "linux", target_env = "gnu"))]
use super::offset::{libc_preadv2, libc_pwritev2};
#[cfg(not(any(target_os = "fuchsia", target_os = "redox", target_os = "wasi")))]
use super::offset::{libc_rlimit, LIBC_RLIM_INFINITY};
#[cfg(not(target_os = "wasi"))]
use super::process::RawUname;
#[cfg(not(any(target_os = "fuchsia", target_os = "redox", target_os = "wasi")))]
use super::process::Resource;
#[cfg(target_os = "linux")]
use super::rand::GetRandomFlags;
use super::time::Timespec;
use crate::as_ptr;
use crate::io::{self, OwnedFd, RawFd};
#[cfg(not(any(target_os = "fuchsia", target_os = "redox", target_os = "wasi")))]
use crate::process::Rlimit;
#[cfg(any(target_os = "android", target_os = "linux"))]
use crate::process::{Cpuid, MembarrierCommand, MembarrierQuery};
#[cfg(not(target_os = "wasi"))]
@@ -2227,6 +2237,27 @@ pub(crate) fn setpriority_process(pid: Pid, priority: i32) -> io::Result<()> {
}
}
#[cfg(not(any(target_os = "fuchsia", target_os = "redox", target_os = "wasi")))]
#[inline]
pub(crate) fn getrlimit(limit: Resource) -> Rlimit {
let mut result = MaybeUninit::<libc_rlimit>::uninit();
unsafe {
ret_infallible(libc_getrlimit(limit as _, result.as_mut_ptr()));
let result = result.assume_init();
let current = if result.rlim_cur == LIBC_RLIM_INFINITY {
None
} else {
result.rlim_cur.try_into().ok()
};
let maximum = if result.rlim_max == LIBC_RLIM_INFINITY {
None
} else {
result.rlim_max.try_into().ok()
};
Rlimit { current, maximum }
}
}
#[cfg(not(any(target_os = "redox", target_os = "wasi")))]
pub(crate) mod sockopt {
use crate::net::sockopt::Timeout;
-1
View File
@@ -280,7 +280,6 @@ pub(super) unsafe fn ret(raw: RetReg<R0>) -> io::Result<()> {
///
/// The caller must ensure that this is the return value of a syscall which
/// always returns `()`.
#[cfg(target_arch = "x86_64")]
#[inline]
pub(super) unsafe fn ret_infallible(_raw: RetReg<R0>) {
#[cfg(debug_assertions)]
+1 -1
View File
@@ -4,6 +4,6 @@ mod types;
pub(super) use auxv::{exe_phdrs, sysinfo_ehdr};
pub(crate) use auxv::{linux_hwcap, page_size};
pub use types::{
MembarrierCommand, RawCpuid, RawGid, RawPid, RawUid, RawUname, EXIT_FAILURE,
MembarrierCommand, RawCpuid, RawGid, RawPid, RawUid, RawUname, Resource, EXIT_FAILURE,
EXIT_SIGNALED_SIGABRT, EXIT_SUCCESS,
};
+40
View File
@@ -34,6 +34,46 @@ pub enum MembarrierCommand {
linux_raw_sys::v5_11::general::membarrier_cmd::MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_RSEQ as _,
}
/// A resource value for use with [`getrlimit`].
///
/// [`getrlimit`]: crate::process::getrlimit
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[repr(u32)]
pub enum Resource {
/// `RLIMIT_CPU`
Cpu = linux_raw_sys::general::RLIMIT_CPU,
/// `RLIMIT_FSIZE`
Fsize = linux_raw_sys::general::RLIMIT_FSIZE,
/// `RLIMIT_DATA`
Data = linux_raw_sys::general::RLIMIT_DATA,
/// `RLIMIT_STACK`
Stack = linux_raw_sys::general::RLIMIT_STACK,
/// `RLIMIT_CORE`
Core = linux_raw_sys::general::RLIMIT_CORE,
/// `RLIMIT_RSS`
Rss = linux_raw_sys::general::RLIMIT_RSS,
/// `RLIMIT_NPROC`
Nproc = linux_raw_sys::general::RLIMIT_NPROC,
/// `RLIMIT_NOFILE`
Nofile = linux_raw_sys::general::RLIMIT_NOFILE,
/// `RLIMIT_MEMLOCK`
Memlock = linux_raw_sys::general::RLIMIT_MEMLOCK,
/// `RLIMIT_AS`
As = linux_raw_sys::general::RLIMIT_AS,
/// `RLIMIT_LOCKS`
Locks = linux_raw_sys::general::RLIMIT_LOCKS,
/// `RLIMIT_SIGPENDING`
Sigpending = linux_raw_sys::general::RLIMIT_SIGPENDING,
/// `RLIMIT_MSGQUEUE`
Msgqueue = linux_raw_sys::general::RLIMIT_MSGQUEUE,
/// `RLIMIT_NICE`
Nice = linux_raw_sys::general::RLIMIT_NICE,
/// `RLIMIT_RTPRIO`
Rtprio = linux_raw_sys::general::RLIMIT_RTPRIO,
/// `RLIMIT_RTTIME`
Rttime = linux_raw_sys::general::RLIMIT_RTTIME,
}
pub const EXIT_SUCCESS: c_int = 0;
pub const EXIT_FAILURE: c_int = 1;
pub const EXIT_SIGNALED_SIGABRT: c_int = 128 + linux_raw_sys::general::SIGABRT as i32;
+83 -9
View File
@@ -23,13 +23,12 @@ use super::arch::choose::{
};
#[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
use super::conv::opt_ref;
#[cfg(target_arch = "x86_64")]
use super::conv::ret_infallible;
use super::conv::{
borrowed_fd, by_mut, by_ref, c_int, c_str, c_uint, clockid_t, const_void_star, dev_t, mode_as,
no_fd, oflags, oflags_for_open_how, opt_c_str, opt_mut, out, pass_usize, raw_fd, ret,
ret_c_int, ret_c_uint, ret_discarded_fd, ret_owned_fd, ret_usize, ret_usize_infallible,
ret_void_star, size_of, slice, slice_just_addr, slice_mut, socklen_t, void_star, zero,
ret_c_int, ret_c_uint, ret_discarded_fd, ret_infallible, ret_owned_fd, ret_usize,
ret_usize_infallible, ret_void_star, size_of, slice, slice_just_addr, slice_mut, socklen_t,
void_star, zero,
};
use super::fs::{
Access, Advice as FsAdvice, AtFlags, FallocateFlags, FdFlags, FlockOperation, MemfdFlags, Mode,
@@ -46,7 +45,7 @@ use super::net::{
AddressFamily, Protocol, RecvFlags, SendFlags, Shutdown, SocketAddr, SocketAddrUnix,
SocketFlags, SocketType,
};
use super::process::RawUname;
use super::process::{RawUname, Resource};
use super::rand::GetRandomFlags;
use super::reg::nr;
#[cfg(target_arch = "x86")]
@@ -56,7 +55,7 @@ use super::time::{ClockId, Timespec};
use crate::io;
use crate::io::{OwnedFd, RawFd};
use crate::path::DecInt;
use crate::process::{Cpuid, Gid, MembarrierCommand, MembarrierQuery, Pid, Uid};
use crate::process::{Cpuid, Gid, MembarrierCommand, MembarrierQuery, Pid, Rlimit, Uid};
use crate::time::NanosleepRelativeResult;
use io_lifetimes::{AsFd, BorrowedFd};
#[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
@@ -112,8 +111,8 @@ use linux_raw_sys::general::{__NR_recv, __NR_send};
use linux_raw_sys::v5_11::general::{__NR_openat2, open_how};
use linux_raw_sys::v5_4::general::{
__NR_copy_file_range, __NR_eventfd2, __NR_getrandom, __NR_membarrier, __NR_memfd_create,
__NR_mlock2, __NR_preadv2, __NR_pwritev2, __NR_renameat2, __NR_statx, __NR_userfaultfd, statx,
F_GETPIPE_SZ, F_GET_SEALS, F_SETPIPE_SZ,
__NR_mlock2, __NR_preadv2, __NR_prlimit64, __NR_pwritev2, __NR_renameat2, __NR_statx,
__NR_userfaultfd, statx, F_GETPIPE_SZ, F_GET_SEALS, F_SETPIPE_SZ,
};
use std::convert::TryInto;
use std::ffi::CStr;
@@ -138,7 +137,7 @@ use {
general::timespec as __kernel_old_timespec,
general::{
__NR__llseek, __NR_fcntl64, __NR_fstat64, __NR_fstatat64, __NR_fstatfs64,
__NR_ftruncate64, __NR_sendfile64,
__NR_ftruncate64, __NR_getrlimit, __NR_sendfile64,
},
v5_4::general::{
__NR_clock_getres_time64, __NR_clock_nanosleep_time64, __NR_futex_time64,
@@ -3364,6 +3363,81 @@ pub unsafe fn futex(
))
}
#[inline]
pub(crate) fn getrlimit(limit: Resource) -> Rlimit {
let mut result = MaybeUninit::<linux_raw_sys::v5_4::general::rlimit64>::uninit();
#[cfg(target_pointer_width = "32")]
unsafe {
match ret(syscall4(
nr(__NR_prlimit64),
c_uint(0),
c_uint(limit as c_uint),
void_star(std::ptr::null_mut()),
out(&mut result),
)) {
Ok(()) => {
let result = result.assume_init();
let current =
if result.rlim_cur == linux_raw_sys::v5_4::general::RLIM64_INFINITY as _ {
None
} else {
Some(result.rlim_cur)
};
let maximum =
if result.rlim_max == linux_raw_sys::v5_4::general::RLIM64_INFINITY as _ {
None
} else {
Some(result.rlim_max)
};
Rlimit { current, maximum }
}
Err(e) => {
debug_assert_eq!(e, io::Error::NOSYS);
let mut result = MaybeUninit::<linux_raw_sys::general::rlimit>::uninit();
ret_infallible(syscall2(
nr(__NR_getrlimit),
c_uint(limit as c_uint),
out(&mut result),
));
let result = result.assume_init();
let current = if result.rlim_cur == linux_raw_sys::general::RLIM_INFINITY as _ {
None
} else {
result.rlim_cur.try_into().ok()
};
let maximum = if result.rlim_max == linux_raw_sys::general::RLIM_INFINITY as _ {
None
} else {
result.rlim_cur.try_into().ok()
};
Rlimit { current, maximum }
}
}
}
#[cfg(target_pointer_width = "64")]
unsafe {
ret_infallible(syscall4(
nr(__NR_prlimit64),
c_uint(0),
c_uint(limit as c_uint),
void_star(std::ptr::null_mut()),
out(&mut result),
));
let result = result.assume_init();
let current = if result.rlim_cur == linux_raw_sys::general::RLIM_INFINITY as _ {
None
} else {
Some(result.rlim_cur)
};
let maximum = if result.rlim_max == linux_raw_sys::general::RLIM_INFINITY as _ {
None
} else {
Some(result.rlim_max)
};
Rlimit { current, maximum }
}
}
pub(crate) mod sockopt {
use crate::io;
use crate::net::sockopt::Timeout;
+4
View File
@@ -12,6 +12,8 @@ mod id;
mod membarrier;
#[cfg(not(any(target_os = "fuchsia", target_os = "wasi")))] // WASI doesn't have [gs]etpriority.
mod priority;
#[cfg(not(any(target_os = "fuchsia", target_os = "redox", target_os = "wasi")))]
mod rlimit;
mod sched;
#[cfg(not(target_os = "wasi"))] // WASI doesn't have uname.
mod uname;
@@ -44,6 +46,8 @@ pub use priority::{
getpriority_pgrp, getpriority_process, getpriority_user, setpriority_pgrp, setpriority_process,
setpriority_user,
};
#[cfg(not(any(target_os = "fuchsia", target_os = "redox", target_os = "wasi")))]
pub use rlimit::{getrlimit, Resource, Rlimit};
pub use sched::sched_yield;
#[cfg(not(target_os = "wasi"))]
pub use uname::{uname, Uname};
+25
View File
@@ -0,0 +1,25 @@
use crate::imp;
pub use crate::imp::process::Resource;
/// `struct rlimit`—Current and maximum values used in [`getrlimit`].
#[derive(Debug)]
pub struct Rlimit {
/// Current effective, "soft", limit.
pub current: Option<u64>,
/// Maximum, "hard", value that `current` may be dynamically increased to.
pub maximum: Option<u64>,
}
/// `getrlimit(resource)`—Get a process resource limit value.
///
/// # References
/// - [POSIX]
/// - [Linux]
///
/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/getrlimit.html
/// [Linux]: https://man7.org/linux/man-pages/man2/getrlimit.2.html
#[inline]
pub fn getrlimit(resource: Resource) -> Rlimit {
imp::syscalls::getrlimit(resource)
}