]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
parse-util: Introduce new parse_range function
authorFilipe Brandenburger <filbranden@google.com>
Tue, 13 Oct 2015 06:55:31 +0000 (23:55 -0700)
committerFilipe Brandenburger <filbranden@google.com>
Wed, 28 Oct 2015 00:56:26 +0000 (17:56 -0700)
This function will be useful for CPUAffinity settings that involve
ranges of CPUs.

Make it generic and include test coverage to prevent regressions.

src/basic/parse-util.c
src/basic/parse-util.h
src/test/test-util.c

index 2437fee60cc729b27cf16c42f2e24c82e233b9fd..1ee57836803fb6d4de82576eb626379bbaae3236 100644 (file)
@@ -19,6 +19,8 @@
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+#include "alloc-util.h"
+#include "extract-word.h"
 #include "parse-util.h"
 #include "string-util.h"
 #include "util.h"
@@ -207,6 +209,43 @@ int parse_size(const char *t, uint64_t base, uint64_t *size) {
         return 0;
 }
 
+int parse_range(const char *t, unsigned *lower, unsigned *upper) {
+        _cleanup_free_ char *word = NULL;
+        unsigned l, u;
+        int r;
+
+        assert(lower);
+        assert(upper);
+
+        /* Extract the lower bound. */
+        r = extract_first_word(&t, &word, "-", EXTRACT_DONT_COALESCE_SEPARATORS);
+        if (r < 0)
+                return r;
+        if (r == 0)
+                return -EINVAL;
+
+        r = safe_atou(word, &l);
+        if (r < 0)
+                return r;
+
+        /* Check for the upper bound and extract it if needed */
+        if (!t)
+                /* Single number with no dashes. */
+                u = l;
+        else if (!*t)
+                /* Trailing dash is an error. */
+                return -EINVAL;
+        else {
+                r = safe_atou(t, &u);
+                if (r < 0)
+                        return r;
+        }
+
+        *lower = l;
+        *upper = u;
+        return 0;
+}
+
 char *format_bytes(char *buf, size_t l, uint64_t t) {
         unsigned i;
 
index 72a619c38f8a801d14128ba5470d49946260f2ae..0e56848e26e9c9304e908b94a4c3e0a03cff87cb 100644 (file)
@@ -33,6 +33,7 @@ int parse_pid(const char *s, pid_t* ret_pid);
 int parse_mode(const char *s, mode_t *ret);
 
 int parse_size(const char *t, uint64_t base, uint64_t *size);
+int parse_range(const char *t, unsigned *lower, unsigned *upper);
 
 #define FORMAT_BYTES_MAX 8
 char *format_bytes(char *buf, size_t l, uint64_t t);
index b0eb77592ef357ab4faf812ae7e207f716a2021f..5d01d065236e52642c6f70d8e3db6998fdb47509 100644 (file)
@@ -979,6 +979,185 @@ static void test_parse_size(void) {
         assert_se(parse_size("-10B 20K", 1024, &bytes) == -ERANGE);
 }
 
+static void test_parse_range(void) {
+        unsigned lower, upper;
+
+        /* Successful cases */
+        assert_se(parse_range("111", &lower, &upper) == 0);
+        assert_se(lower == 111);
+        assert_se(upper == 111);
+
+        assert_se(parse_range("111-123", &lower, &upper) == 0);
+        assert_se(lower == 111);
+        assert_se(upper == 123);
+
+        assert_se(parse_range("123-111", &lower, &upper) == 0);
+        assert_se(lower == 123);
+        assert_se(upper == 111);
+
+        assert_se(parse_range("123-123", &lower, &upper) == 0);
+        assert_se(lower == 123);
+        assert_se(upper == 123);
+
+        assert_se(parse_range("0", &lower, &upper) == 0);
+        assert_se(lower == 0);
+        assert_se(upper == 0);
+
+        assert_se(parse_range("0-15", &lower, &upper) == 0);
+        assert_se(lower == 0);
+        assert_se(upper == 15);
+
+        assert_se(parse_range("15-0", &lower, &upper) == 0);
+        assert_se(lower == 15);
+        assert_se(upper == 0);
+
+        assert_se(parse_range("128-65535", &lower, &upper) == 0);
+        assert_se(lower == 128);
+        assert_se(upper == 65535);
+
+        assert_se(parse_range("1024-4294967295", &lower, &upper) == 0);
+        assert_se(lower == 1024);
+        assert_se(upper == 4294967295);
+
+        /* Leading whitespace is acceptable */
+        assert_se(parse_range(" 111", &lower, &upper) == 0);
+        assert_se(lower == 111);
+        assert_se(upper == 111);
+
+        assert_se(parse_range(" 111-123", &lower, &upper) == 0);
+        assert_se(lower == 111);
+        assert_se(upper == 123);
+
+        assert_se(parse_range("111- 123", &lower, &upper) == 0);
+        assert_se(lower == 111);
+        assert_se(upper == 123);
+
+        assert_se(parse_range("\t111-\t123", &lower, &upper) == 0);
+        assert_se(lower == 111);
+        assert_se(upper == 123);
+
+        assert_se(parse_range(" \t 111- \t 123", &lower, &upper) == 0);
+        assert_se(lower == 111);
+        assert_se(upper == 123);
+
+        /* Error cases, make sure they fail as expected */
+        lower = upper = 9999;
+        assert_se(parse_range("111garbage", &lower, &upper) == -EINVAL);
+        assert_se(lower == 9999);
+        assert_se(upper == 9999);
+
+        assert_se(parse_range("garbage111", &lower, &upper) == -EINVAL);
+        assert_se(lower == 9999);
+        assert_se(upper == 9999);
+
+        assert_se(parse_range("garbage", &lower, &upper) == -EINVAL);
+        assert_se(lower == 9999);
+        assert_se(upper == 9999);
+
+        assert_se(parse_range("111-123garbage", &lower, &upper) == -EINVAL);
+        assert_se(lower == 9999);
+        assert_se(upper == 9999);
+
+        assert_se(parse_range("111garbage-123", &lower, &upper) == -EINVAL);
+        assert_se(lower == 9999);
+        assert_se(upper == 9999);
+
+        /* Empty string */
+        lower = upper = 9999;
+        assert_se(parse_range("", &lower, &upper) == -EINVAL);
+        assert_se(lower == 9999);
+        assert_se(upper == 9999);
+
+        /* 111--123 will pass -123 to safe_atou which returns -ERANGE for negative */
+        assert_se(parse_range("111--123", &lower, &upper) == -ERANGE);
+        assert_se(lower == 9999);
+        assert_se(upper == 9999);
+
+        assert_se(parse_range("-111-123", &lower, &upper) == -EINVAL);
+        assert_se(lower == 9999);
+        assert_se(upper == 9999);
+
+        assert_se(parse_range("111-123-", &lower, &upper) == -EINVAL);
+        assert_se(lower == 9999);
+        assert_se(upper == 9999);
+
+        assert_se(parse_range("111.4-123", &lower, &upper) == -EINVAL);
+        assert_se(lower == 9999);
+        assert_se(upper == 9999);
+
+        assert_se(parse_range("111-123.4", &lower, &upper) == -EINVAL);
+        assert_se(lower == 9999);
+        assert_se(upper == 9999);
+
+        assert_se(parse_range("111,4-123", &lower, &upper) == -EINVAL);
+        assert_se(lower == 9999);
+        assert_se(upper == 9999);
+
+        assert_se(parse_range("111-123,4", &lower, &upper) == -EINVAL);
+        assert_se(lower == 9999);
+        assert_se(upper == 9999);
+
+        /* Error on trailing dash */
+        assert_se(parse_range("111-", &lower, &upper) == -EINVAL);
+        assert_se(lower == 9999);
+        assert_se(upper == 9999);
+
+        assert_se(parse_range("111-123-", &lower, &upper) == -EINVAL);
+        assert_se(lower == 9999);
+        assert_se(upper == 9999);
+
+        assert_se(parse_range("111--", &lower, &upper) == -EINVAL);
+        assert_se(lower == 9999);
+        assert_se(upper == 9999);
+
+        assert_se(parse_range("111- ", &lower, &upper) == -EINVAL);
+        assert_se(lower == 9999);
+        assert_se(upper == 9999);
+
+        /* Whitespace is not a separator */
+        assert_se(parse_range("111 123", &lower, &upper) == -EINVAL);
+        assert_se(lower == 9999);
+        assert_se(upper == 9999);
+
+        assert_se(parse_range("111\t123", &lower, &upper) == -EINVAL);
+        assert_se(lower == 9999);
+        assert_se(upper == 9999);
+
+        assert_se(parse_range("111 \t 123", &lower, &upper) == -EINVAL);
+        assert_se(lower == 9999);
+        assert_se(upper == 9999);
+
+        /* Trailing whitespace is invalid (from safe_atou) */
+        assert_se(parse_range("111 ", &lower, &upper) == -EINVAL);
+        assert_se(lower == 9999);
+        assert_se(upper == 9999);
+
+        assert_se(parse_range("111-123 ", &lower, &upper) == -EINVAL);
+        assert_se(lower == 9999);
+        assert_se(upper == 9999);
+
+        assert_se(parse_range("111 -123", &lower, &upper) == -EINVAL);
+        assert_se(lower == 9999);
+        assert_se(upper == 9999);
+
+        assert_se(parse_range("111 -123 ", &lower, &upper) == -EINVAL);
+        assert_se(lower == 9999);
+        assert_se(upper == 9999);
+
+        assert_se(parse_range("111\t-123\t", &lower, &upper) == -EINVAL);
+        assert_se(lower == 9999);
+        assert_se(upper == 9999);
+
+        assert_se(parse_range("111 \t -123 \t ", &lower, &upper) == -EINVAL);
+        assert_se(lower == 9999);
+        assert_se(upper == 9999);
+
+        /* Out of the "unsigned" range, this is 1<<64 */
+        assert_se(parse_range("0-18446744073709551616", &lower, &upper) == -ERANGE);
+        assert_se(lower == 9999);
+        assert_se(upper == 9999);
+}
+
 static void test_parse_cpu_set(void) {
         cpu_set_t *c = NULL;
         int ncpus;
@@ -2378,6 +2557,7 @@ int main(int argc, char *argv[]) {
         test_u64log2();
         test_protect_errno();
         test_parse_size();
+        test_parse_range();
         test_parse_cpu_set();
         test_config_parse_iec_uint64();
         test_strextend();