diff --git a/src/basic/strv.h b/src/basic/strv.h index 44fe1f279c..f169ac5d4f 100644 --- a/src/basic/strv.h +++ b/src/basic/strv.h @@ -179,6 +179,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); diff --git a/src/core/main.c b/src/core/main.c index 56200a8fad..44ebf4f1da 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -652,107 +652,6 @@ static int config_parse_crash_chvt( return 0; } -static 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) { - - const char *whole_rvalue = rvalue; - unsigned n = 0; - - assert(filename); - assert(lvalue); - assert(rvalue); - - arg_join_controllers = strv_free_free(arg_join_controllers); - - 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 (!arg_join_controllers) { - arg_join_controllers = new(char**, 2); - if (!arg_join_controllers) { - strv_free(l); - return log_oom(); - } - - arg_join_controllers[0] = l; - arg_join_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 = arg_join_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(arg_join_controllers); - arg_join_controllers = t; - } - } - if (!isempty(rvalue)) - log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring."); - - return 0; -} - static int parse_config_file(void) { const ConfigTableItem items[] = { diff --git a/src/core/manager.c b/src/core/manager.c index e4ef461ac7..d22c0e1d42 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -2710,7 +2710,6 @@ void manager_send_unit_plymouth(Manager *m, Unit *u) { } if (connect(fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0) { - if (!IN_SET(errno, EPIPE, EAGAIN, ENOENT, ECONNREFUSED, ECONNRESET, ECONNABORTED)) log_error_errno(errno, "connect() failed: %m"); return; diff --git a/src/shared/conf-parser.c b/src/shared/conf-parser.c index daddb7cf20..5c033e0ec0 100644 --- a/src/shared/conf-parser.c +++ b/src/shared/conf-parser.c @@ -1021,3 +1021,108 @@ int config_parse_ip_port( return 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; +} diff --git a/src/shared/conf-parser.h b/src/shared/conf-parser.h index 8cbb569696..908f530713 100644 --- a/src/shared/conf-parser.h +++ b/src/shared/conf-parser.h @@ -157,6 +157,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) { \ diff --git a/src/test/test-conf-parser.c b/src/test/test-conf-parser.c index 770bb9600f..84789e3bb8 100644 --- a/src/test/test-conf-parser.c +++ b/src/test/test-conf-parser.c @@ -226,6 +226,43 @@ static void test_config_parse_iec_uint64(void) { assert_se(config_parse_iec_uint64(NULL, "/this/file", 11, "Section", 22, "Size", 0, "4.5M", &offset, NULL) == 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)) @@ -365,6 +402,7 @@ int main(int argc, char **argv) { test_config_parse_sec(); test_config_parse_nsec(); test_config_parse_iec_uint64(); + test_config_parse_join_controllers(); for (i = 0; i < ELEMENTSOF(config_file); i++) test_config_parse(i, config_file[i]);