1use libc;
2
3#[derive(Copy, Clone, Debug, PartialEq, Eq, Ord, PartialOrd, Hash)]
4pub enum ResourceLimit {
5 Infinity,
6 Unknown,
7 Value(libc::rlim_t),
8}
9
10#[derive(Copy, Clone, Debug, PartialEq, Eq, Ord, PartialOrd, Hash)]
11pub struct ResourceLimits {
12 pub soft_limit: ResourceLimit,
13 pub hard_limit: ResourceLimit,
14}
15
16impl From<libc::rlimit> for ResourceLimits {
17 fn from(rs: libc::rlimit) -> Self {
18 let soft_limit = match rs.rlim_cur {
19 libc::RLIM_INFINITY => ResourceLimit::Infinity,
20 other => {
21 if libc::RLIM_SAVED_MAX != libc::RLIM_INFINITY && other == libc::RLIM_SAVED_MAX {
22 ResourceLimit::Unknown
23 } else if libc::RLIM_SAVED_CUR != libc::RLIM_INFINITY
24 && other == libc::RLIM_SAVED_CUR
25 {
26 ResourceLimit::Unknown
27 } else {
28 ResourceLimit::Value(other)
29 }
30 }
31 };
32 let hard_limit = match rs.rlim_max {
33 libc::RLIM_INFINITY => ResourceLimit::Infinity,
34 other => {
35 if libc::RLIM_SAVED_MAX != libc::RLIM_INFINITY && other == libc::RLIM_SAVED_MAX {
36 ResourceLimit::Unknown
37 } else if libc::RLIM_SAVED_CUR != libc::RLIM_INFINITY
38 && other == libc::RLIM_SAVED_CUR
39 {
40 ResourceLimit::Unknown
41 } else {
42 ResourceLimit::Value(other)
43 }
44 }
45 };
46 ResourceLimits {
47 soft_limit,
48 hard_limit,
49 }
50 }
51}
52
53impl Into<libc::rlimit> for ResourceLimits {
54 fn into(self: ResourceLimits) -> libc::rlimit {
55 let rlim_cur = match self.soft_limit {
56 ResourceLimit::Infinity => libc::RLIM_INFINITY,
57 ResourceLimit::Unknown => libc::RLIM_SAVED_CUR,
58 ResourceLimit::Value(n) => n,
59 };
60 let rlim_max = match self.hard_limit {
61 ResourceLimit::Infinity => libc::RLIM_INFINITY,
62 ResourceLimit::Unknown => libc::RLIM_SAVED_MAX,
63 ResourceLimit::Value(n) => n,
64 };
65 libc::rlimit { rlim_cur, rlim_max }
66 }
67}
68
69pub enum Resource {
70 CoreFileSize,
71 CPUTime,
72 DataSize,
73 FileSize,
74 OpenFiles,
75 StackSize,
76 TotalMemory,
77}
78
79impl Into<libc::__rlimit_resource_t> for Resource {
80 fn into(self: Resource) -> libc::__rlimit_resource_t {
81 match self {
82 Resource::CoreFileSize => libc::RLIMIT_CORE,
83 Resource::CPUTime => libc::RLIMIT_CPU,
84 Resource::DataSize => libc::RLIMIT_DATA,
85 Resource::FileSize => libc::RLIMIT_FSIZE,
86 Resource::OpenFiles => libc::RLIMIT_NOFILE,
87 Resource::StackSize => libc::RLIMIT_STACK,
88 Resource::TotalMemory => libc::RLIMIT_AS,
89 }
90 }
91}
92
93impl From<libc::__rlimit_resource_t> for Resource {
94 fn from(r: libc::__rlimit_resource_t) -> Self {
95 match r {
96 libc::RLIMIT_CORE => Resource::CoreFileSize,
97 libc::RLIMIT_CPU => Resource::CPUTime,
98 libc::RLIMIT_DATA => Resource::DataSize,
99 libc::RLIMIT_FSIZE => Resource::FileSize,
100 libc::RLIMIT_NOFILE => Resource::OpenFiles,
101 libc::RLIMIT_STACK => Resource::StackSize,
102 libc::RLIMIT_AS => Resource::TotalMemory,
103 _ => panic!("Invalid resource type code"),
104 }
105 }
106}
107
108#[derive(Copy, Clone, Debug, PartialEq, Eq, Ord, PartialOrd, Hash)]
110pub enum GetRLimitError {
111 Invalid,
114 Permission,
118}
119
120impl std::fmt::Display for GetRLimitError {
121 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
122 match *self {
123 Self::Invalid => write!(f, "EINVAL"),
124 Self::Permission => write!(f, "EPERM"),
125 }
126 }
127}
128
129impl std::error::Error for GetRLimitError {
130 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
131 match *self {
132 Self::Invalid => None,
133 Self::Permission => None,
134 }
135 }
136}
137
138pub fn get_resource_limit(resource: Resource) -> Result<ResourceLimits, GetRLimitError> {
140 let mut rlimit: libc::rlimit = libc::rlimit {
141 rlim_cur: 0,
142 rlim_max: 0,
143 };
144 unsafe {
145 match libc::getrlimit(resource.into(), &mut rlimit) {
146 0 => Ok(rlimit.into()),
147 -1 => {
148 let errno: *mut libc::c_int = libc::__errno_location();
149 Err(match *errno {
150 libc::EINVAL => GetRLimitError::Invalid,
151 libc::EPERM => GetRLimitError::Permission,
152 _ => panic!("Invalid error code"),
153 })
154 }
155 _ => panic!("Invalid error return"),
156 }
157 }
158}
159
160#[derive(Copy, Clone, Debug, PartialEq, Eq, Ord, PartialOrd, Hash)]
162pub enum SetRLimitError {
163 Invalid,
166}
167
168pub fn set_resource_limit(
170 resource: Resource,
171 r_limit: ResourceLimits,
172) -> Result<(), SetRLimitError> {
173 unsafe {
174 match libc::setrlimit(resource.into(), &r_limit.into()) {
175 0 => Ok(()),
176 -1 => {
177 let errno: *mut libc::c_int = libc::__errno_location();
178 Err(match *errno {
179 libc::EINVAL => SetRLimitError::Invalid,
180 _ => panic!("Invalid error code"),
181 })
182 }
183 _ => panic!("Invalid error return"),
184 }
185 }
186}