]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/basic/rlimit-util.c
Add SPDX license identifiers to source files under the LGPL
[thirdparty/systemd.git] / src / basic / rlimit-util.c
index 8a921a27cbed8eda80d4b4fb3336219990b5ddbf..00648211d33820120c4d1c5c76b9b0b1ca7b0892 100644 (file)
@@ -1,5 +1,4 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
+/* SPDX-License-Identifier: LGPL-2.1+ */
 /***
   This file is part of systemd.
 
@@ -24,7 +23,7 @@
 
 #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"
@@ -44,7 +43,8 @@ int setrlimit_closest(int resource, const struct rlimit *rlim) {
 
         /* 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);
@@ -155,6 +155,56 @@ static int rlimit_parse_usec(const char *val, rlim_t *ret) {
         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,
@@ -169,7 +219,7 @@ static int (*const rlimit_parse_table[_RLIMIT_MAX])(const char *val, rlim_t *ret
         [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,
 };