From 5a7b4cb6d540b783b1c0f26cee767cb146beb7fb Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Wed, 29 Sep 2021 15:26:42 -0700 Subject: [PATCH] Implement `getrlimit`. --- examples/process.rs | 61 +++++++++++++++++++ src/imp/libc/conv.rs | 5 ++ src/imp/libc/offset.rs | 33 ++++++++++- src/imp/libc/process/mod.rs | 2 + src/imp/libc/process/types.rs | 94 ++++++++++++++++++++++++++++++ src/imp/libc/syscalls.rs | 31 ++++++++++ src/imp/linux_raw/conv.rs | 1 - src/imp/linux_raw/process/mod.rs | 2 +- src/imp/linux_raw/process/types.rs | 40 +++++++++++++ src/imp/linux_raw/syscalls.rs | 92 ++++++++++++++++++++++++++--- src/process/mod.rs | 4 ++ src/process/rlimit.rs | 25 ++++++++ 12 files changed, 378 insertions(+), 12 deletions(-) create mode 100644 src/process/rlimit.rs diff --git a/examples/process.rs b/examples/process.rs index c04fea06..e877609e 100644 --- a/examples/process.rs +++ b/examples/process.rs @@ -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(()) } diff --git a/src/imp/libc/conv.rs b/src/imp/libc/conv.rs index c6a24b03..a07b9178 100644 --- a/src/imp/libc/conv.rs +++ b/src/imp/libc/conv.rs @@ -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 { if raw == -1 { diff --git a/src/imp/libc/offset.rs b/src/imp/libc/offset.rs index ade03a5f..2e062bce 100644 --- a/src/imp/libc/offset.rs +++ b/src/imp/libc/offset.rs @@ -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", diff --git a/src/imp/libc/process/mod.rs b/src/imp/libc/process/mod.rs index 2cf28803..c59c6359 100644 --- a/src/imp/libc/process/mod.rs +++ b/src/imp/libc/process/mod.rs @@ -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"))] diff --git a/src/imp/libc/process/types.rs b/src/imp/libc/process/types.rs index 355ef7eb..e1353cb1 100644 --- a/src/imp/libc/process/types.rs +++ b/src/imp/libc/process/types.rs @@ -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"))] diff --git a/src/imp/libc/syscalls.rs b/src/imp/libc/syscalls.rs index 73a7c436..5576aca0 100644 --- a/src/imp/libc/syscalls.rs +++ b/src/imp/libc/syscalls.rs @@ -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::::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; diff --git a/src/imp/linux_raw/conv.rs b/src/imp/linux_raw/conv.rs index 374f15ad..40e124e8 100644 --- a/src/imp/linux_raw/conv.rs +++ b/src/imp/linux_raw/conv.rs @@ -280,7 +280,6 @@ pub(super) unsafe fn ret(raw: RetReg) -> 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) { #[cfg(debug_assertions)] diff --git a/src/imp/linux_raw/process/mod.rs b/src/imp/linux_raw/process/mod.rs index 128f934a..196e45af 100644 --- a/src/imp/linux_raw/process/mod.rs +++ b/src/imp/linux_raw/process/mod.rs @@ -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, }; diff --git a/src/imp/linux_raw/process/types.rs b/src/imp/linux_raw/process/types.rs index 80769dcb..7eb6b895 100644 --- a/src/imp/linux_raw/process/types.rs +++ b/src/imp/linux_raw/process/types.rs @@ -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; diff --git a/src/imp/linux_raw/syscalls.rs b/src/imp/linux_raw/syscalls.rs index 8b6d2e80..a89f7b72 100644 --- a/src/imp/linux_raw/syscalls.rs +++ b/src/imp/linux_raw/syscalls.rs @@ -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::::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::::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; diff --git a/src/process/mod.rs b/src/process/mod.rs index 2bf1c485..d4f6ac0c 100644 --- a/src/process/mod.rs +++ b/src/process/mod.rs @@ -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}; diff --git a/src/process/rlimit.rs b/src/process/rlimit.rs new file mode 100644 index 00000000..d1e9962f --- /dev/null +++ b/src/process/rlimit.rs @@ -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, + /// Maximum, "hard", value that `current` may be dynamically increased to. + pub maximum: Option, +} + +/// `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) +}