1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2010 Lennart Poettering
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.
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.
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/>.
23 #include <sys/resource.h>
25 #include "alloc-util.h"
26 #include "extract-word.h"
27 #include "formats-util.h"
30 #include "rlimit-util.h"
31 #include "string-table.h"
32 #include "time-util.h"
34 int setrlimit_closest(int resource
, const struct rlimit
*rlim
) {
35 struct rlimit highest
, fixed
;
39 if (setrlimit(resource
, rlim
) >= 0)
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);
49 fixed
.rlim_cur
= MIN(rlim
->rlim_cur
, highest
.rlim_max
);
50 fixed
.rlim_max
= MIN(rlim
->rlim_max
, highest
.rlim_max
);
52 if (setrlimit(resource
, &fixed
) < 0)
58 static int rlimit_parse_u64(const char *val
, rlim_t
*ret
) {
65 if (streq(val
, "infinity")) {
70 /* setrlimit(2) suggests rlim_t is always 64bit on Linux. */
71 assert_cc(sizeof(rlim_t
) == sizeof(uint64_t));
73 r
= safe_atou64(val
, &u
);
76 if (u
>= (uint64_t) RLIM_INFINITY
)
83 static int rlimit_parse_size(const char *val
, rlim_t
*ret
) {
90 if (streq(val
, "infinity")) {
95 r
= parse_size(val
, 1024, &u
);
98 if (u
>= (uint64_t) RLIM_INFINITY
)
105 static int rlimit_parse_sec(const char *val
, rlim_t
*ret
) {
113 if (streq(val
, "infinity")) {
114 *ret
= RLIM_INFINITY
;
118 r
= parse_sec(val
, &t
);
121 if (t
== USEC_INFINITY
) {
122 *ret
= RLIM_INFINITY
;
126 u
= (uint64_t) DIV_ROUND_UP(t
, USEC_PER_SEC
);
127 if (u
>= (uint64_t) RLIM_INFINITY
)
134 static int rlimit_parse_usec(const char *val
, rlim_t
*ret
) {
141 if (streq(val
, "infinity")) {
142 *ret
= RLIM_INFINITY
;
146 r
= parse_time(val
, &t
, 1);
149 if (t
== USEC_INFINITY
) {
150 *ret
= RLIM_INFINITY
;
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
,
177 int rlimit_parse_one(int resource
, const char *val
, rlim_t
*ret
) {
183 if (resource
>= _RLIMIT_MAX
)
186 return rlimit_parse_table
[resource
](val
, ret
);
189 int rlimit_parse(int resource
, const char *val
, struct rlimit
*ret
) {
190 _cleanup_free_
char *hard
= NULL
, *soft
= NULL
;
197 r
= extract_first_word(&val
, &soft
, ":", EXTRACT_DONT_COALESCE_SEPARATORS
);
203 r
= rlimit_parse_one(resource
, soft
, &sl
);
207 r
= extract_first_word(&val
, &hard
, ":", EXTRACT_DONT_COALESCE_SEPARATORS
);
215 r
= rlimit_parse_one(resource
, hard
, &hl
);
222 *ret
= (struct rlimit
) {
230 int rlimit_format(const struct rlimit
*rl
, char **ret
) {
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
);
245 (void) asprintf(&s
, RLIM_FMT
":" RLIM_FMT
, rl
->rlim_cur
, rl
->rlim_max
);
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"
273 DEFINE_STRING_TABLE_LOOKUP(rlimit
, int);