diff --git a/src/context/context.rs b/src/context/context.rs index bc2a76c620..ee1ab7cf63 100644 --- a/src/context/context.rs +++ b/src/context/context.rs @@ -150,6 +150,10 @@ pub struct Context { pub session: usize, /// Context start time in nanoseconds since boot. pub start_time: u128, + /// Resource limits (rlimit values, in corresponding units). + /// Indexed by RLIMIT_* constants from . + /// RLIM_INFINITY (u64::MAX) means unlimited. + pub rlimits: [u64; 16], // TODO: id can reappear after wraparound? pub owner_proc_id: Option, @@ -222,6 +226,7 @@ impl Context { pgrp: 0, session: 0, start_time: 0, + rlimits: [u64::MAX; 16], // All unlimited (RLIM_INFINITY) #[cfg(feature = "syscall_debug")] syscall_debug_info: crate::syscall::debug::SyscallDebugInfo::default(), diff --git a/src/scheme/proc.rs b/src/scheme/proc.rs index a75638a5f3..725bc3af4a 100644 --- a/src/scheme/proc.rs +++ b/src/scheme/proc.rs @@ -176,6 +176,9 @@ enum ContextHandle { ProcStatm { pid: usize, }, + ProcLimits { + pid: usize, + }, } #[derive(Clone)] struct Handle { @@ -397,6 +400,7 @@ impl ProcScheme { (Some("status"), None) => Some(ContextHandle::ProcStatus { pid }), (Some("maps"), None) => Some(ContextHandle::ProcMaps { pid }), (Some("statm"), None) => Some(ContextHandle::ProcStatm { pid }), + (Some("limits"), None) => Some(ContextHandle::ProcLimits { pid }), _ => None, } } @@ -1962,6 +1966,46 @@ impl ContextHandle { ); read_from(buf, output.as_bytes(), offset) } + ContextHandle::ProcLimits { pid } => { + let context = proc_context(*pid, token).ok_or(Error::new(ESRCH))?; + let rlimits = context.read(token.token()).rlimits; + // Linux 7.1 fs/proc/array.c:proc_pid_limits() format + // 16 RLIMITs with soft/hard values and units string + let names = [ + ("Max cpu time", "seconds"), + ("Max file size", "bytes"), + ("Max data size", "bytes"), + ("Max stack size", "bytes"), + ("Max core file size", "bytes"), + ("Max resident set", "bytes"), + ("Max processes", "processes"), + ("Max open files", "files"), + ("Max locked memory", "bytes"), + ("Max address space", "bytes"), + ("Max file locks", "locks"), + ("Max sigpending", "signals"), + ("Max msgqueue size", "bytes"), + ("Max nice priority", "0"), + ("Max realtime priority", "0"), + ("Max realtime timeout", "us"), + ]; + let format_limit = |v: u64| -> alloc::string::String { + if v == u64::MAX { String::from("unlimited") } + else { alloc::format!("{}", v) } + }; + let mut output = String::from( + "Limit Soft Limit Hard Limit Units\n", + ); + for (i, (name, units)) in names.iter().enumerate() { + let soft = format_limit(rlimits[i]); + let hard = format_limit(if i + 16 < rlimits.len() { rlimits[i + 16] } else { u64::MAX }); + output.push_str(&alloc::format!( + "{:<24} {:>20} {:>20} {}\n", + name, soft, hard, units + )); + } + read_from(buf, output.as_bytes(), offset) + } ContextHandle::ProcRoot | ContextHandle::ProcDir { .. } => Err(Error::new(EBADF)), ContextHandle::MmapMinAddr(addrspace) => { let mut token = token.token();