chiark / gitweb /
Move config_parse_join_controllers to shared, add test
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Fri, 16 Feb 2018 08:56:29 +0000 (09:56 +0100)
committerSven Eden <yamakuzure@gmx.net>
Wed, 30 May 2018 05:58:59 +0000 (07:58 +0200)
config_parse_join_controllers would free the destination argument on failure,
which is contrary to our normal style, where failed parsing has no effect.
Moving it to shared also allows a test to be added.

src/basic/strv.h
src/shared/conf-parser.c
src/shared/conf-parser.h
src/test/test-conf-parser.c

index 2ef6d325d5fcdde6fe9275981760bfb792d5c205..7e921be18dede212f19c8c5a435e0f87a7f0695b 100644 (file)
@@ -194,6 +194,7 @@ static inline bool strv_fnmatch_or_empty(char* const* patterns, const char *s, i
 }
 
 char ***strv_free_free(char ***l);
+DEFINE_TRIVIAL_CLEANUP_FUNC(char***, strv_free_free);
 
 char **strv_skip(char **l, size_t n);
 #endif // 0
index c8e74b0d904388b493de486f3841a9476ea6ecce..adb9ad4edd7fc311ded72e08322f87a37e23fbc3 100644 (file)
@@ -1039,3 +1039,108 @@ int config_parse_ip_port(
         return 0;
 }
 #endif // 0
+
+int config_parse_join_controllers(
+                const char *unit,
+                const char *filename,
+                unsigned line,
+                const char *section,
+                unsigned section_line,
+                const char *lvalue,
+                int ltype,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        char ****ret = data;
+        const char *whole_rvalue = rvalue;
+        unsigned n = 0;
+        _cleanup_(strv_free_freep) char ***controllers = NULL;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(ret);
+
+        for (;;) {
+                _cleanup_free_ char *word = NULL;
+                char **l;
+                int r;
+
+                r = extract_first_word(&rvalue, &word, NULL, EXTRACT_QUOTES);
+                if (r < 0) {
+                        log_syntax(unit, LOG_ERR, filename, line, r, "Invalid value for %s: %s", lvalue, whole_rvalue);
+                        return r;
+                }
+                if (r == 0)
+                        break;
+
+                l = strv_split(word, ",");
+                if (!l)
+                        return log_oom();
+                strv_uniq(l);
+
+                if (strv_length(l) <= 1) {
+                        strv_free(l);
+                        continue;
+                }
+
+                if (!controllers) {
+                        controllers = new(char**, 2);
+                        if (!controllers) {
+                                strv_free(l);
+                                return log_oom();
+                        }
+
+                        controllers[0] = l;
+                        controllers[1] = NULL;
+
+                        n = 1;
+                } else {
+                        char ***a;
+                        char ***t;
+
+                        t = new0(char**, n+2);
+                        if (!t) {
+                                strv_free(l);
+                                return log_oom();
+                        }
+
+                        n = 0;
+
+                        for (a = controllers; *a; a++)
+                                if (strv_overlap(*a, l)) {
+                                        if (strv_extend_strv(&l, *a, false) < 0) {
+                                                strv_free(l);
+                                                strv_free_free(t);
+                                                return log_oom();
+                                        }
+
+                                } else {
+                                        char **c;
+
+                                        c = strv_copy(*a);
+                                        if (!c) {
+                                                strv_free(l);
+                                                strv_free_free(t);
+                                                return log_oom();
+                                        }
+
+                                        t[n++] = c;
+                                }
+
+                        t[n++] = strv_uniq(l);
+
+                        strv_free_free(controllers);
+                        controllers = t;
+                }
+        }
+        if (!isempty(rvalue))
+                log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring.");
+
+        strv_free_free(*ret);
+        *ret = controllers;
+        controllers = NULL;
+
+        return 0;
+}
index aed80ee284ec940f0a86738dd6a122faeee03464..8555ddb158b84bc9cee0b542766104e6da98b909 100644 (file)
@@ -171,6 +171,7 @@ int config_parse_signal(GENERIC_PARSER_ARGS);
 int config_parse_personality(GENERIC_PARSER_ARGS);
 int config_parse_ifname(GENERIC_PARSER_ARGS);
 int config_parse_ip_port(GENERIC_PARSER_ARGS);
+int config_parse_join_controllers(GENERIC_PARSER_ARGS);
 
 #define DEFINE_CONFIG_PARSE_ENUM(function,name,type,msg)                \
         int function(GENERIC_PARSER_ARGS) {                             \
index 62dd558f0e190226af8d8536e7a1b7b9e026f3f7..fc68479540002d5f50442b1f696d503df6e66c04 100644 (file)
@@ -242,6 +242,43 @@ static void test_config_parse_iec_uint64(void) {
 }
 #endif // 0
 
+static void test_config_parse_join_controllers(void) {
+        int r;
+        _cleanup_(strv_free_freep) char ***c = NULL;
+        char ***c2;
+
+        /* Test normal operation */
+        r = config_parse_join_controllers(NULL, "example.conf", 11, "Section", 10, "JoinControllers", 0, "cpu,cpuacct net_cls,netprio", &c, NULL);
+        assert_se(r == 0);
+        assert_se(c);
+        assert_se(strv_length(c[0]) == 2);
+        assert_se(strv_equal(c[0], STRV_MAKE("cpu", "cpuacct")));
+        assert_se(strv_length(c[1]) == 2);
+        assert_se(strv_equal(c[1], STRV_MAKE("net_cls", "netprio")));
+        assert_se(c[2] == NULL);
+
+        /* Test special case of no mounted controllers */
+        r = config_parse_join_controllers(NULL, "example.conf", 12, "Section", 10, "JoinControllers", 0, "", &c, NULL);
+        assert_se(r == 0);
+        assert_se(c == NULL);
+
+        /* Test merging of overlapping lists */
+        r = config_parse_join_controllers(NULL, "example.conf", 13, "Section", 10, "JoinControllers", 0, "a,b b,c", &c, NULL);
+        assert_se(r == 0);
+        assert_se(c);
+        assert_se(strv_length(c[0]) == 3);
+        assert_se(strv_contains(c[0], "a"));
+        assert_se(strv_contains(c[0], "b"));
+        assert_se(strv_contains(c[0], "c"));
+        assert_se(c[1] == NULL);
+
+        /* Test ignoring of bad lines */
+        c2 = c;
+        r = config_parse_join_controllers(NULL, "example.conf", 14, "Section", 10, "JoinControllers", 0, "a,\"b ", &c, NULL);
+        assert_se(r < 0);
+        assert_se(c == c2);
+}
+
 #define x10(x) x x x x x x x x x x
 #define x100(x) x10(x10(x))
 #define x1000(x) x10(x100(x))
@@ -387,6 +424,7 @@ int main(int argc, char **argv) {
         test_config_parse_nsec();
         test_config_parse_iec_uint64();
 #endif // 0
+        test_config_parse_join_controllers();
 
         for (i = 0; i < ELEMENTSOF(config_file); i++)
                 test_config_parse(i, config_file[i]);