]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/rlimit-util.c
Merge pull request #2508 from fishilico/selinux-logind
[thirdparty/systemd.git] / src / basic / rlimit-util.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2010 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <errno.h>
23 #include <sys/resource.h>
24
25 #include "alloc-util.h"
26 #include "extract-word.h"
27 #include "formats-util.h"
28 #include "macro.h"
29 #include "missing.h"
30 #include "rlimit-util.h"
31 #include "string-table.h"
32 #include "time-util.h"
33
34 int setrlimit_closest(int resource, const struct rlimit *rlim) {
35 struct rlimit highest, fixed;
36
37 assert(rlim);
38
39 if (setrlimit(resource, rlim) >= 0)
40 return 0;
41
42 if (errno != EPERM)
43 return -errno;
44
45 /* So we failed to set the desired setrlimit, then let's try
46 * to get as close as we can */
47 assert_se(getrlimit(resource, &highest) == 0);
48
49 fixed.rlim_cur = MIN(rlim->rlim_cur, highest.rlim_max);
50 fixed.rlim_max = MIN(rlim->rlim_max, highest.rlim_max);
51
52 if (setrlimit(resource, &fixed) < 0)
53 return -errno;
54
55 return 0;
56 }
57
58 static int rlimit_parse_u64(const char *val, rlim_t *ret) {
59 uint64_t u;
60 int r;
61
62 assert(val);
63 assert(ret);
64
65 if (streq(val, "infinity")) {
66 *ret = RLIM_INFINITY;
67 return 0;
68 }
69
70 /* setrlimit(2) suggests rlim_t is always 64bit on Linux. */
71 assert_cc(sizeof(rlim_t) == sizeof(uint64_t));
72
73 r = safe_atou64(val, &u);
74 if (r < 0)
75 return r;
76 if (u >= (uint64_t) RLIM_INFINITY)
77 return -ERANGE;
78
79 *ret = (rlim_t) u;
80 return 0;
81 }
82
83 static int rlimit_parse_size(const char *val, rlim_t *ret) {
84 uint64_t u;
85 int r;
86
87 assert(val);
88 assert(ret);
89
90 if (streq(val, "infinity")) {
91 *ret = RLIM_INFINITY;
92 return 0;
93 }
94
95 r = parse_size(val, 1024, &u);
96 if (r < 0)
97 return r;
98 if (u >= (uint64_t) RLIM_INFINITY)
99 return -ERANGE;
100
101 *ret = (rlim_t) u;
102 return 0;
103 }
104
105 static int rlimit_parse_sec(const char *val, rlim_t *ret) {
106 uint64_t u;
107 usec_t t;
108 int r;
109
110 assert(val);
111 assert(ret);
112
113 if (streq(val, "infinity")) {
114 *ret = RLIM_INFINITY;
115 return 0;
116 }
117
118 r = parse_sec(val, &t);
119 if (r < 0)
120 return r;
121 if (t == USEC_INFINITY) {
122 *ret = RLIM_INFINITY;
123 return 0;
124 }
125
126 u = (uint64_t) DIV_ROUND_UP(t, USEC_PER_SEC);
127 if (u >= (uint64_t) RLIM_INFINITY)
128 return -ERANGE;
129
130 *ret = (rlim_t) u;
131 return 0;
132 }
133
134 static int rlimit_parse_usec(const char *val, rlim_t *ret) {
135 usec_t t;
136 int r;
137
138 assert(val);
139 assert(ret);
140
141 if (streq(val, "infinity")) {
142 *ret = RLIM_INFINITY;
143 return 0;
144 }
145
146 r = parse_time(val, &t, 1);
147 if (r < 0)
148 return r;
149 if (t == USEC_INFINITY) {
150 *ret = RLIM_INFINITY;
151 return 0;
152 }
153
154 *ret = (rlim_t) t;
155 return 0;
156 }
157
158 static int (*const rlimit_parse_table[_RLIMIT_MAX])(const char *val, rlim_t *ret) = {
159 [RLIMIT_CPU] = rlimit_parse_sec,
160 [RLIMIT_FSIZE] = rlimit_parse_size,
161 [RLIMIT_DATA] = rlimit_parse_size,
162 [RLIMIT_STACK] = rlimit_parse_size,
163 [RLIMIT_CORE] = rlimit_parse_size,
164 [RLIMIT_RSS] = rlimit_parse_size,
165 [RLIMIT_NOFILE] = rlimit_parse_u64,
166 [RLIMIT_AS] = rlimit_parse_size,
167 [RLIMIT_NPROC] = rlimit_parse_u64,
168 [RLIMIT_MEMLOCK] = rlimit_parse_size,
169 [RLIMIT_LOCKS] = rlimit_parse_u64,
170 [RLIMIT_SIGPENDING] = rlimit_parse_u64,
171 [RLIMIT_MSGQUEUE] = rlimit_parse_size,
172 [RLIMIT_NICE] = rlimit_parse_u64,
173 [RLIMIT_RTPRIO] = rlimit_parse_u64,
174 [RLIMIT_RTTIME] = rlimit_parse_usec,
175 };
176
177 int rlimit_parse_one(int resource, const char *val, rlim_t *ret) {
178 assert(val);
179 assert(ret);
180
181 if (resource < 0)
182 return -EINVAL;
183 if (resource >= _RLIMIT_MAX)
184 return -EINVAL;
185
186 return rlimit_parse_table[resource](val, ret);
187 }
188
189 int rlimit_parse(int resource, const char *val, struct rlimit *ret) {
190 _cleanup_free_ char *hard = NULL, *soft = NULL;
191 rlim_t hl, sl;
192 int r;
193
194 assert(val);
195 assert(ret);
196
197 r = extract_first_word(&val, &soft, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
198 if (r < 0)
199 return r;
200 if (r == 0)
201 return -EINVAL;
202
203 r = rlimit_parse_one(resource, soft, &sl);
204 if (r < 0)
205 return r;
206
207 r = extract_first_word(&val, &hard, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
208 if (r < 0)
209 return r;
210 if (!isempty(val))
211 return -EINVAL;
212 if (r == 0)
213 hl = sl;
214 else {
215 r = rlimit_parse_one(resource, hard, &hl);
216 if (r < 0)
217 return r;
218 if (sl > hl)
219 return -EILSEQ;
220 }
221
222 *ret = (struct rlimit) {
223 .rlim_cur = sl,
224 .rlim_max = hl,
225 };
226
227 return 0;
228 }
229
230 int rlimit_format(const struct rlimit *rl, char **ret) {
231 char *s = NULL;
232
233 assert(rl);
234 assert(ret);
235
236 if (rl->rlim_cur >= RLIM_INFINITY && rl->rlim_max >= RLIM_INFINITY)
237 s = strdup("infinity");
238 else if (rl->rlim_cur >= RLIM_INFINITY)
239 (void) asprintf(&s, "infinity:" RLIM_FMT, rl->rlim_max);
240 else if (rl->rlim_max >= RLIM_INFINITY)
241 (void) asprintf(&s, RLIM_FMT ":infinity", rl->rlim_cur);
242 else if (rl->rlim_cur == rl->rlim_max)
243 (void) asprintf(&s, RLIM_FMT, rl->rlim_cur);
244 else
245 (void) asprintf(&s, RLIM_FMT ":" RLIM_FMT, rl->rlim_cur, rl->rlim_max);
246
247 if (!s)
248 return -ENOMEM;
249
250 *ret = s;
251 return 0;
252 }
253
254 static const char* const rlimit_table[_RLIMIT_MAX] = {
255 [RLIMIT_CPU] = "LimitCPU",
256 [RLIMIT_FSIZE] = "LimitFSIZE",
257 [RLIMIT_DATA] = "LimitDATA",
258 [RLIMIT_STACK] = "LimitSTACK",
259 [RLIMIT_CORE] = "LimitCORE",
260 [RLIMIT_RSS] = "LimitRSS",
261 [RLIMIT_NOFILE] = "LimitNOFILE",
262 [RLIMIT_AS] = "LimitAS",
263 [RLIMIT_NPROC] = "LimitNPROC",
264 [RLIMIT_MEMLOCK] = "LimitMEMLOCK",
265 [RLIMIT_LOCKS] = "LimitLOCKS",
266 [RLIMIT_SIGPENDING] = "LimitSIGPENDING",
267 [RLIMIT_MSGQUEUE] = "LimitMSGQUEUE",
268 [RLIMIT_NICE] = "LimitNICE",
269 [RLIMIT_RTPRIO] = "LimitRTPRIO",
270 [RLIMIT_RTTIME] = "LimitRTTIME"
271 };
272
273 DEFINE_STRING_TABLE_LOOKUP(rlimit, int);