Move config_parse_join_controllers to shared, add test

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.
This commit is contained in:
Zbigniew Jędrzejewski-Szmek 2018-02-16 09:56:29 +01:00
parent b48382e4e0
commit 9ecdba8cb7
6 changed files with 145 additions and 102 deletions

View File

@ -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);

View File

@ -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[] = {

View File

@ -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;

View File

@ -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;
}

View File

@ -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) { \

View File

@ -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]);