+/* SPDX-License-Identifier: LGPL-2.1+ */
/***
This file is part of systemd.
#include "alloc-util.h"
#include "extract-word.h"
-#include "formats-util.h"
+#include "format-util.h"
#include "macro.h"
#include "missing.h"
#include "rlimit-util.h"
/* So we failed to set the desired setrlimit, then let's try
* to get as close as we can */
- assert_se(getrlimit(resource, &highest) == 0);
+ if (getrlimit(resource, &highest) < 0)
+ return -errno;
fixed.rlim_cur = MIN(rlim->rlim_cur, highest.rlim_max);
fixed.rlim_max = MIN(rlim->rlim_max, highest.rlim_max);
return 0;
}
+static int rlimit_parse_nice(const char *val, rlim_t *ret) {
+ uint64_t rl;
+ int r;
+
+ /* So, Linux is weird. The range for RLIMIT_NICE is 40..1, mapping to the nice levels -20..19. However, the
+ * RLIMIT_NICE limit defaults to 0 by the kernel, i.e. a value that maps to nice level 20, which of course is
+ * bogus and does not exist. In order to permit parsing the RLIMIT_NICE of 0 here we hence implement a slight
+ * asymmetry: when parsing as positive nice level we permit 0..19. When parsing as negative nice level, we
+ * permit -20..0. But when parsing as raw resource limit value then we also allow the special value 0.
+ *
+ * Yeah, Linux is quality engineering sometimes... */
+
+ if (val[0] == '+') {
+
+ /* Prefixed with "+": Parse as positive user-friendly nice value */
+ r = safe_atou64(val + 1, &rl);
+ if (r < 0)
+ return r;
+
+ if (rl >= PRIO_MAX)
+ return -ERANGE;
+
+ rl = 20 - rl;
+
+ } else if (val[0] == '-') {
+
+ /* Prefixed with "-": Parse as negative user-friendly nice value */
+ r = safe_atou64(val + 1, &rl);
+ if (r < 0)
+ return r;
+
+ if (rl > (uint64_t) (-PRIO_MIN))
+ return -ERANGE;
+
+ rl = 20 + rl;
+ } else {
+
+ /* Not prefixed: parse as raw resource limit value */
+ r = safe_atou64(val, &rl);
+ if (r < 0)
+ return r;
+
+ if (rl > (uint64_t) (20 - PRIO_MIN))
+ return -ERANGE;
+ }
+
+ *ret = (rlim_t) rl;
+ return 0;
+}
+
static int (*const rlimit_parse_table[_RLIMIT_MAX])(const char *val, rlim_t *ret) = {
[RLIMIT_CPU] = rlimit_parse_sec,
[RLIMIT_FSIZE] = rlimit_parse_size,
[RLIMIT_LOCKS] = rlimit_parse_u64,
[RLIMIT_SIGPENDING] = rlimit_parse_u64,
[RLIMIT_MSGQUEUE] = rlimit_parse_size,
- [RLIMIT_NICE] = rlimit_parse_u64,
+ [RLIMIT_NICE] = rlimit_parse_nice,
[RLIMIT_RTPRIO] = rlimit_parse_u64,
[RLIMIT_RTTIME] = rlimit_parse_usec,
};