2 This file is part of systemd.
4 Copyright 2010 Lennart Poettering
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
21 #include <sys/resource.h>
23 #include "alloc-util.h"
24 #include "extract-word.h"
25 #include "formats-util.h"
28 #include "rlimit-util.h"
29 #include "string-table.h"
30 #include "time-util.h"
32 int setrlimit_closest(int resource
, const struct rlimit
*rlim
) {
33 struct rlimit highest
, fixed
;
37 if (setrlimit(resource
, rlim
) >= 0)
43 /* So we failed to set the desired setrlimit, then let's try
44 * to get as close as we can */
45 assert_se(getrlimit(resource
, &highest
) == 0);
47 fixed
.rlim_cur
= MIN(rlim
->rlim_cur
, highest
.rlim_max
);
48 fixed
.rlim_max
= MIN(rlim
->rlim_max
, highest
.rlim_max
);
50 if (setrlimit(resource
, &fixed
) < 0)
56 static int rlimit_parse_u64(const char *val
, rlim_t
*ret
) {
63 if (streq(val
, "infinity")) {
68 /* setrlimit(2) suggests rlim_t is always 64bit on Linux. */
69 assert_cc(sizeof(rlim_t
) == sizeof(uint64_t));
71 r
= safe_atou64(val
, &u
);
74 if (u
>= (uint64_t) RLIM_INFINITY
)
81 static int rlimit_parse_size(const char *val
, rlim_t
*ret
) {
88 if (streq(val
, "infinity")) {
93 r
= parse_size(val
, 1024, &u
);
96 if (u
>= (uint64_t) RLIM_INFINITY
)
103 static int rlimit_parse_sec(const char *val
, rlim_t
*ret
) {
111 if (streq(val
, "infinity")) {
112 *ret
= RLIM_INFINITY
;
116 r
= parse_sec(val
, &t
);
119 if (t
== USEC_INFINITY
) {
120 *ret
= RLIM_INFINITY
;
124 u
= (uint64_t) DIV_ROUND_UP(t
, USEC_PER_SEC
);
125 if (u
>= (uint64_t) RLIM_INFINITY
)
132 static int rlimit_parse_usec(const char *val
, rlim_t
*ret
) {
139 if (streq(val
, "infinity")) {
140 *ret
= RLIM_INFINITY
;
144 r
= parse_time(val
, &t
, 1);
147 if (t
== USEC_INFINITY
) {
148 *ret
= RLIM_INFINITY
;
156 static int rlimit_parse_nice(const char *val
, rlim_t
*ret
) {
160 /* So, Linux is weird. The range for RLIMIT_NICE is 40..1, mapping to the nice levels -20..19. However, the
161 * RLIMIT_NICE limit defaults to 0 by the kernel, i.e. a value that maps to nice level 20, which of course is
162 * bogus and does not exist. In order to permit parsing the RLIMIT_NICE of 0 here we hence implement a slight
163 * asymmetry: when parsing as positive nice level we permit 0..19. When parsing as negative nice level, we
164 * permit -20..0. But when parsing as raw resource limit value then we also allow the special value 0.
166 * Yeah, Linux is quality engineering sometimes... */
170 /* Prefixed with "+": Parse as positive user-friendly nice value */
171 r
= safe_atou64(val
+ 1, &rl
);
180 } else if (val
[0] == '-') {
182 /* Prefixed with "-": Parse as negative user-friendly nice value */
183 r
= safe_atou64(val
+ 1, &rl
);
187 if (rl
> (uint64_t) (-PRIO_MIN
))
193 /* Not prefixed: parse as raw resource limit value */
194 r
= safe_atou64(val
, &rl
);
198 if (rl
> (uint64_t) (20 - PRIO_MIN
))
206 static int (*const rlimit_parse_table
[_RLIMIT_MAX
])(const char *val
, rlim_t
*ret
) = {
207 [RLIMIT_CPU
] = rlimit_parse_sec
,
208 [RLIMIT_FSIZE
] = rlimit_parse_size
,
209 [RLIMIT_DATA
] = rlimit_parse_size
,
210 [RLIMIT_STACK
] = rlimit_parse_size
,
211 [RLIMIT_CORE
] = rlimit_parse_size
,
212 [RLIMIT_RSS
] = rlimit_parse_size
,
213 [RLIMIT_NOFILE
] = rlimit_parse_u64
,
214 [RLIMIT_AS
] = rlimit_parse_size
,
215 [RLIMIT_NPROC
] = rlimit_parse_u64
,
216 [RLIMIT_MEMLOCK
] = rlimit_parse_size
,
217 [RLIMIT_LOCKS
] = rlimit_parse_u64
,
218 [RLIMIT_SIGPENDING
] = rlimit_parse_u64
,
219 [RLIMIT_MSGQUEUE
] = rlimit_parse_size
,
220 [RLIMIT_NICE
] = rlimit_parse_nice
,
221 [RLIMIT_RTPRIO
] = rlimit_parse_u64
,
222 [RLIMIT_RTTIME
] = rlimit_parse_usec
,
225 int rlimit_parse_one(int resource
, const char *val
, rlim_t
*ret
) {
231 if (resource
>= _RLIMIT_MAX
)
234 return rlimit_parse_table
[resource
](val
, ret
);
237 int rlimit_parse(int resource
, const char *val
, struct rlimit
*ret
) {
238 _cleanup_free_
char *hard
= NULL
, *soft
= NULL
;
245 r
= extract_first_word(&val
, &soft
, ":", EXTRACT_DONT_COALESCE_SEPARATORS
);
251 r
= rlimit_parse_one(resource
, soft
, &sl
);
255 r
= extract_first_word(&val
, &hard
, ":", EXTRACT_DONT_COALESCE_SEPARATORS
);
263 r
= rlimit_parse_one(resource
, hard
, &hl
);
270 *ret
= (struct rlimit
) {
278 int rlimit_format(const struct rlimit
*rl
, char **ret
) {
284 if (rl
->rlim_cur
>= RLIM_INFINITY
&& rl
->rlim_max
>= RLIM_INFINITY
)
285 s
= strdup("infinity");
286 else if (rl
->rlim_cur
>= RLIM_INFINITY
)
287 (void) asprintf(&s
, "infinity:" RLIM_FMT
, rl
->rlim_max
);
288 else if (rl
->rlim_max
>= RLIM_INFINITY
)
289 (void) asprintf(&s
, RLIM_FMT
":infinity", rl
->rlim_cur
);
290 else if (rl
->rlim_cur
== rl
->rlim_max
)
291 (void) asprintf(&s
, RLIM_FMT
, rl
->rlim_cur
);
293 (void) asprintf(&s
, RLIM_FMT
":" RLIM_FMT
, rl
->rlim_cur
, rl
->rlim_max
);
302 static const char* const rlimit_table
[_RLIMIT_MAX
] = {
303 [RLIMIT_CPU
] = "LimitCPU",
304 [RLIMIT_FSIZE
] = "LimitFSIZE",
305 [RLIMIT_DATA
] = "LimitDATA",
306 [RLIMIT_STACK
] = "LimitSTACK",
307 [RLIMIT_CORE
] = "LimitCORE",
308 [RLIMIT_RSS
] = "LimitRSS",
309 [RLIMIT_NOFILE
] = "LimitNOFILE",
310 [RLIMIT_AS
] = "LimitAS",
311 [RLIMIT_NPROC
] = "LimitNPROC",
312 [RLIMIT_MEMLOCK
] = "LimitMEMLOCK",
313 [RLIMIT_LOCKS
] = "LimitLOCKS",
314 [RLIMIT_SIGPENDING
] = "LimitSIGPENDING",
315 [RLIMIT_MSGQUEUE
] = "LimitMSGQUEUE",
316 [RLIMIT_NICE
] = "LimitNICE",
317 [RLIMIT_RTPRIO
] = "LimitRTPRIO",
318 [RLIMIT_RTTIME
] = "LimitRTTIME"
321 DEFINE_STRING_TABLE_LOOKUP(rlimit
, int);