linux_api/
resource.rs

1use linux_syscall::{Result as _, syscall};
2use num_enum::{IntoPrimitive, TryFromPrimitive};
3use shadow_pod::Pod;
4
5use crate::{
6    bindings,
7    errno::Errno,
8    posix_types::{Pid, kernel_pid_t},
9};
10
11#[allow(non_camel_case_types)]
12pub type rusage = crate::bindings::linux_rusage;
13unsafe impl Pod for rusage {}
14
15#[allow(non_camel_case_types)]
16pub type rlimit = crate::bindings::linux_rlimit;
17unsafe impl Pod for rlimit {}
18
19#[allow(non_camel_case_types)]
20pub type rlimit64 = crate::bindings::linux_rlimit64;
21unsafe impl Pod for rlimit64 {}
22
23// `include/linux/resource.h` defines this as (~0ULL); for some reason
24// bindgen is generating LINUX_RLIM64_INFINITY as an i32, though.
25pub const RLIM64_INFINITY: u64 = bindings::LINUX_RLIM64_INFINITY as u64;
26const _: () = assert!(RLIM64_INFINITY == !0);
27
28// `include/asm-generic/resource.h` defines this as (~0UL); for some reason
29// bindgen is generating LINUX_RLIM_INFINITY as an i32, though.
30pub const RLIM_INFINITY: u64 = bindings::LINUX_RLIM_INFINITY as u64;
31const _: () = assert!(RLIM_INFINITY == !0);
32
33pub const RLIM_NLIMITS: u32 = crate::bindings::LINUX_RLIM_NLIMITS;
34
35// Resource  identifier, as used in getrlimit, setrlimit, prlimit.
36#[derive(Debug, Copy, Clone, Eq, PartialEq, IntoPrimitive, TryFromPrimitive)]
37#[repr(u32)]
38#[allow(non_camel_case_types)]
39pub enum Resource {
40    RLIMIT_CPU = bindings::LINUX_RLIMIT_CPU,
41    RLIMIT_FSIZE = bindings::LINUX_RLIMIT_FSIZE,
42    RLIMIT_DATA = bindings::LINUX_RLIMIT_DATA,
43    RLIMIT_STACK = bindings::LINUX_RLIMIT_STACK,
44    RLIMIT_CORE = bindings::LINUX_RLIMIT_CORE,
45    RLIMIT_RSS = bindings::LINUX_RLIMIT_RSS,
46    RLIMIT_NPROC = bindings::LINUX_RLIMIT_NPROC,
47    RLIMIT_NOFILE = bindings::LINUX_RLIMIT_NOFILE,
48    RLIMIT_MEMLOCK = bindings::LINUX_RLIMIT_MEMLOCK,
49    RLIMIT_AS = bindings::LINUX_RLIMIT_AS,
50    RLIMIT_LOCKS = bindings::LINUX_RLIMIT_LOCKS,
51    RLIMIT_SIGPENDING = bindings::LINUX_RLIMIT_SIGPENDING,
52    RLIMIT_MSGQUEUE = bindings::LINUX_RLIMIT_MSGQUEUE,
53    RLIMIT_NICE = bindings::LINUX_RLIMIT_NICE,
54    RLIMIT_RTPRIO = bindings::LINUX_RLIMIT_RTPRIO,
55    RLIMIT_RTTIME = bindings::LINUX_RLIMIT_RTTIME,
56}
57
58/// Call the `prlimit64` syscall
59///
60/// # Safety
61///
62/// Technically, calling this function can't violate Safety in the rust-language
63/// sense. It's been conservatively marked `unsafe` though, since in particular
64/// *lowering* resource limits  may result in those limits being exceeded, and
65/// resource limits being exceeded can result in surprising behaviors that may
66/// terminate the process or exercise rarely-used error-handling paths -
67/// primarily receiving fatal-by-default signals or related syscalls failing.
68///
69/// Similarly, technically passing non-dereferenceable pointers doesn't violate
70/// safety in this process - the kernel will safely fail to access them and
71/// return `EFAULT`.
72pub unsafe fn prlimit64_raw(
73    pid: kernel_pid_t,
74    resource: core::ffi::c_uint,
75    new_rlim: *const rlimit64,
76    old_rlim: *mut rlimit64,
77) -> Result<(), Errno> {
78    unsafe {
79        syscall!(
80            linux_syscall::SYS_prlimit64,
81            pid,
82            resource,
83            new_rlim,
84            old_rlim
85        )
86    }
87    .check()
88    .map_err(Errno::from)
89}
90
91/// Call the `prlimit64` syscall
92///
93/// # Safety
94///
95/// Technically, calling this function can't violate Safety in the rust-language
96/// sense. It's been conservatively marked `unsafe` though, since in particular
97/// *lowering* resource limits  may result in those limits being exceeded, and
98/// resource limits being exceeded can result in surprising behaviors that may
99/// terminate the process or exercise rarely-used error-handling paths -
100/// primarily receiving fatal-by-default signals or related syscalls failing.
101pub unsafe fn prlimit64(
102    pid: Pid,
103    resource: Resource,
104    new_rlim: Option<&rlimit64>,
105    old_rlim: Option<&mut rlimit64>,
106) -> Result<(), Errno> {
107    let pid = kernel_pid_t::from(pid.as_raw_nonzero());
108    let resource = core::ffi::c_uint::from(resource);
109    let new_rlim = match new_rlim {
110        Some(x) => core::ptr::from_ref(x),
111        None => core::ptr::null(),
112    };
113    let old_rlim = match old_rlim {
114        Some(x) => core::ptr::from_mut(x),
115        None => core::ptr::null_mut(),
116    };
117    unsafe { prlimit64_raw(pid, resource, new_rlim, old_rlim) }
118}