* Let's make sure that ExtractFlags fits into an unsigned int. */
assert_cc(sizeof(enum ExtractFlags) <= sizeof(unsigned));
-int extract_many_words(const char **p, const char *separators, unsigned flags, ...) {
+int extract_many_words_internal(const char **p, const char *separators, unsigned flags, ...) {
va_list ap;
- char **l;
- int n = 0, i, c, r;
+ unsigned n = 0;
+ int r;
- /* Parses a number of words from a string, stripping any
- * quotes if necessary. */
+ /* Parses a number of words from a string, stripping any quotes if necessary. */
assert(p);
/* Count how many words are expected */
va_start(ap, flags);
- for (;;) {
- if (!va_arg(ap, char **))
- break;
+ while (va_arg(ap, char**))
n++;
- }
va_end(ap);
- if (n <= 0)
+ if (n == 0)
return 0;
/* Read all words into a temporary array */
- l = newa0(char*, n);
- for (c = 0; c < n; c++) {
+ char **l = newa0(char*, n);
+ unsigned c;
+ for (c = 0; c < n; c++) {
r = extract_first_word(p, &l[c], separators, flags);
if (r < 0) {
free_many_charp(l, c);
return r;
}
-
if (r == 0)
break;
}
- /* If we managed to parse all words, return them in the passed
- * in parameters */
+ /* If we managed to parse all words, return them in the passed in parameters */
va_start(ap, flags);
- for (i = 0; i < n; i++) {
- char **v;
-
- v = va_arg(ap, char **);
- assert(v);
-
- *v = l[i];
+ FOREACH_ARRAY(i, l, n) {
+ char **v = ASSERT_PTR(va_arg(ap, char**));
+ *v = *i;
}
va_end(ap);
int extract_first_word(const char **p, char **ret, const char *separators, ExtractFlags flags);
int extract_first_word_and_warn(const char **p, char **ret, const char *separators, ExtractFlags flags, const char *unit, const char *filename, unsigned line, const char *rvalue);
-int extract_many_words(const char **p, const char *separators, unsigned flags, ...) _sentinel_;
+
+int extract_many_words_internal(const char **p, const char *separators, unsigned flags, ...) _sentinel_;
+#define extract_many_words(p, separators, flags, ...) \
+ extract_many_words_internal(p, separators, flags, ##__VA_ARGS__, NULL)
const char *p = tuple;
r = extract_many_words(&p, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS,
- &first, &second, NULL);
+ &first, &second);
if (r < 0)
return r;
if (r == 0)
/* Line format is:
* 'country codes' 'coordinates' 'timezone' 'comments' */
- r = extract_many_words(&p, NULL, 0, &cc, &co, &tz, NULL);
+ r = extract_many_words(&p, NULL, 0, &cc, &co, &tz);
if (r < 0)
continue;
* Link line format is:
* 'Link' 'target' 'alias'
* See 'man zic' for more detail. */
- r = extract_many_words(&p, NULL, 0, &type, &f1, &f2, NULL);
+ r = extract_many_words(&p, NULL, 0, &type, &f1, &f2);
if (r < 0)
continue;
/* Parse the serialization again, after a daemon reload */
- r = extract_many_words(&value, NULL, 0, &name, &s0, &s1, NULL);
+ r = extract_many_words(&value, NULL, 0, &name, &s0, &s1);
if (r != 3 || !isempty(value)) {
log_debug("Unable to parse dynamic user line.");
return;
_cleanup_free_ char *path = NULL, *rwm = NULL;
CGroupDevicePermissions p;
- r = extract_many_words(&val, " ", 0, &path, &rwm, NULL);
+ r = extract_many_words(&val, " ", 0, &path, &rwm);
if (r < 0)
return r;
if (r == 0)
_cleanup_free_ char *path = NULL, *weight = NULL;
CGroupIODeviceWeight *a = NULL;
- r = extract_many_words(&val, " ", 0, &path, &weight, NULL);
+ r = extract_many_words(&val, " ", 0, &path, &weight);
if (r < 0)
return r;
if (r != 2)
_cleanup_free_ char *path = NULL, *target = NULL;
CGroupIODeviceLatency *a = NULL;
- r = extract_many_words(&val, " ", 0, &path, &target, NULL);
+ r = extract_many_words(&val, " ", 0, &path, &target);
if (r < 0)
return r;
if (r != 2)
CGroupIODeviceLimit *limit = NULL;
CGroupIOLimitType t;
- r = extract_many_words(&val, "= ", 0, &type, &path, &limits, NULL);
+ r = extract_many_words(&val, "= ", 0, &type, &path, &limits);
if (r < 0)
return r;
if (r != 3)
_cleanup_free_ char *path = NULL, *weight = NULL;
CGroupBlockIODeviceWeight *a = NULL;
- r = extract_many_words(&val, " ", 0, &path, &weight, NULL);
+ r = extract_many_words(&val, " ", 0, &path, &weight);
if (r < 0)
return r;
if (r != 2)
_cleanup_free_ char *path = NULL, *bw = NULL;
CGroupBlockIODeviceBandwidth *a = NULL;
- r = extract_many_words(&val, " ", 0, &path, &bw, NULL);
+ r = extract_many_words(&val, " ", 0, &path, &bw);
if (r < 0)
return r;
if (r != 2)
_cleanup_free_ char *path = NULL, *bw = NULL;
CGroupBlockIODeviceBandwidth *a = NULL;
- r = extract_many_words(&val, " ", 0, &path, &bw, NULL);
+ r = extract_many_words(&val, " ", 0, &path, &bw);
if (r < 0)
return r;
if (r != 2)
_cleanup_free_ char *type = NULL, *path = NULL;
uint32_t t;
- r = extract_many_words(&val, " ", 0, &type, &path, NULL);
+ r = extract_many_words(&val, " ", 0, &type, &path);
if (r < 0)
return r;
if (r != 2)
_cleanup_free_ char *type = NULL, *prefix = NULL;
ExecDirectoryType dt;
- r = extract_many_words(&val, "= ", 0, &type, &prefix, NULL);
+ r = extract_many_words(&val, "= ", 0, &type, &prefix);
if (r < 0)
return r;
if (r == 0)
break;
p = word;
- r = extract_many_words(&p, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &partition, &mount_options, NULL);
+ r = extract_many_words(&p, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &partition, &mount_options);
if (r < 0)
return r;
if (r == 0)
_cleanup_free_ char *type = NULL, *mode = NULL;
ExecDirectoryType dt;
- r = extract_many_words(&val, "= ", 0, &type, &mode, NULL);
+ r = extract_many_words(&val, "= ", 0, &type, &mode);
if (r < 0)
return r;
if (r == 0 || !mode)
break;
p = tuple;
- r = extract_many_words(&p, ":", EXTRACT_UNESCAPE_SEPARATORS, &path, &only_create, NULL);
+ r = extract_many_words(&p, ":", EXTRACT_UNESCAPE_SEPARATORS, &path, &only_create);
if (r < 0)
return r;
if (r < 2)
} else if ((val = startswith(l, "exec-context-temporary-filesystems="))) {
_cleanup_free_ char *path = NULL, *options = NULL;
- r = extract_many_words(&val, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &path, &options, NULL);
+ r = extract_many_words(&val, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &path, &options);
if (r < 0)
return r;
if (r < 1)
_cleanup_free_ char *s_id = NULL, *s_errno_num = NULL;
int id, errno_num;
- r = extract_many_words(&val, NULL, 0, &s_id, &s_errno_num, NULL);
+ r = extract_many_words(&val, NULL, 0, &s_id, &s_errno_num);
if (r < 0)
return r;
if (r != 2)
_cleanup_free_ char *s_id = NULL, *s_errno_num = NULL;
int id, errno_num;
- r = extract_many_words(&val, " ", 0, &s_id, &s_errno_num, NULL);
+ r = extract_many_words(&val, " ", 0, &s_id, &s_errno_num);
if (r < 0)
return r;
if (r != 2)
_cleanup_(exec_set_credential_freep) ExecSetCredential *sc = NULL;
_cleanup_free_ char *id = NULL, *encrypted = NULL, *data = NULL;
- r = extract_many_words(&val, " ", 0, &id, &encrypted, &data, NULL);
+ r = extract_many_words(&val, " ", 0, &id, &encrypted, &data);
if (r < 0)
return r;
if (r != 3)
_cleanup_(exec_load_credential_freep) ExecLoadCredential *lc = NULL;
_cleanup_free_ char *id = NULL, *encrypted = NULL, *path = NULL;
- r = extract_many_words(&val, " ", 0, &id, &encrypted, &path, NULL);
+ r = extract_many_words(&val, " ", 0, &id, &encrypted, &path);
if (r < 0)
return r;
if (r != 3)
_cleanup_free_ char *src = NULL, *dest = NULL;
const char *q = tuple;
- r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &src, &dest, NULL);
+ r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &src, &dest);
if (r == -ENOMEM)
return log_oom();
if (r <= 0) {
return 0;
q = tuple;
- r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &first, &second, NULL);
+ r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &first, &second);
if (r == -ENOMEM)
return log_oom();
if (r < 0) {
MountOptions *o = NULL;
PartitionDesignator partition_designator;
- r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &partition, &mount_options, NULL);
+ r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &partition, &mount_options);
if (r == -ENOMEM)
return log_oom();
if (r < 0) {
MountOptions *o = NULL;
PartitionDesignator partition_designator;
- r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &partition, &mount_options, NULL);
+ r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &partition, &mount_options);
if (r == -ENOMEM)
return log_oom();
if (r < 0) {
assert(str);
r = extract_many_words(&str, ":", EXTRACT_CUNESCAPE | EXTRACT_DONT_COALESCE_SEPARATORS,
- &what, &where, &fstype, &options, NULL);
+ &what, &where, &fstype, &options);
if (r < 0)
return r;
if (r < 2)
assert(str);
r = extract_many_words(&str, ":", EXTRACT_CUNESCAPE | EXTRACT_DONT_COALESCE_SEPARATORS,
- &what, &options, NULL);
+ &what, &options);
if (r < 0)
return r;
if (r < 1)
}
const char *p = bios_date;
- r = extract_many_words(&p, "/", EXTRACT_DONT_COALESCE_SEPARATORS, &month, &day, &year, NULL);
+ r = extract_many_words(&p, "/", EXTRACT_DONT_COALESCE_SEPARATORS, &month, &day, &year);
if (r < 0)
return r;
if (r != 3) /* less than three args read? */
_cleanup_free_ char *high = NULL, *medium = NULL, *low = NULL;
const char *p = rvalue;
- r = extract_many_words(&p, ":", EXTRACT_DONT_COALESCE_SEPARATORS, &high, &medium, &low, NULL);
+ r = extract_many_words(&p, ":", EXTRACT_DONT_COALESCE_SEPARATORS, &high, &medium, &low);
if (r == -ENOMEM)
return log_oom();
if (r != 3 || !isempty(p)) {
assert(l);
assert(n);
- r = extract_many_words(&s, ":", EXTRACT_DONT_COALESCE_SEPARATORS, &source, &destination, NULL);
+ r = extract_many_words(&s, ":", EXTRACT_DONT_COALESCE_SEPARATORS, &source, &destination);
if (r < 0)
return r;
if (r == 0)
const char *q = rvalue;
r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_DONT_COALESCE_SEPARATORS|EXTRACT_UNQUOTE,
- &where, &options, NULL);
+ &where, &options);
if (r == -ENOMEM)
return log_oom();
if (r < 0) {
const char *q = rvalue;
r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_DONT_COALESCE_SEPARATORS|EXTRACT_UNQUOTE,
- &volume, &keyfile, &options, NULL);
+ &volume, &keyfile, &options);
if (r == -ENOMEM)
return log_oom();
if (r < 0) {
return -EINVAL;
}
- r = extract_many_words(&p, NULL, 0, &class, &type, NULL);
+ r = extract_many_words(&p, NULL, 0, &class, &type);
if (r < 0)
return log_warning_errno(r, "Unable to parse class and type in line %s:%u: %m", path, line);
if (r != 2) {
int a, dt;
size_t l;
- r = extract_many_words(&p, NULL, 0, &key_tag, &algorithm, &digest_type, NULL);
+ r = extract_many_words(&p, NULL, 0, &key_tag, &algorithm, &digest_type);
if (r < 0) {
log_warning_errno(r, "Failed to parse DS parameters on line %s:%u: %m", path, line);
return -EINVAL;
size_t l;
int a;
- r = extract_many_words(&p, NULL, 0, &flags, &protocol, &algorithm, NULL);
+ r = extract_many_words(&p, NULL, 0, &flags, &protocol, &algorithm);
if (r < 0)
return log_warning_errno(r, "Failed to parse DNSKEY parameters on line %s:%u: %m", path, line);
if (r != 3) {
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to parse %s", field);
q = tuple;
- r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE, &source_str, &nfproto_str, &table, &set, NULL);
+ r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE, &source_str, &nfproto_str, &table, &set);
if (r == -ENOMEM)
return log_oom();
if (r != 4 || !isempty(q))
break;
q = tuple;
- r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &first, &second, NULL);
+ r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &first, &second);
if (r < 0)
return log_error_errno(r, "Failed to parse MountImages= property: %s", eq);
if (r == 0)
for (;;) {
_cleanup_free_ char *partition = NULL, *mount_options = NULL;
- r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &partition, &mount_options, NULL);
+ r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &partition, &mount_options);
if (r < 0)
return log_error_errno(r, "Failed to parse MountImages= property: %s", eq);
if (r == 0)
for (;;) {
_cleanup_free_ char *partition = NULL, *mount_options = NULL;
- r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &partition, &mount_options, NULL);
+ r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &partition, &mount_options);
if (r < 0)
return log_error_errno(r, "Failed to parse ExtensionImages= property: %s", eq);
if (r == 0)
break;
const char *t = tuple;
- r = extract_many_words(&t, ":", EXTRACT_UNQUOTE|EXTRACT_DONT_COALESCE_SEPARATORS, &source, &destination, NULL);
+ r = extract_many_words(&t, ":", EXTRACT_UNQUOTE|EXTRACT_DONT_COALESCE_SEPARATORS, &source, &destination);
if (r <= 0)
return log_error_errno(r ?: SYNTHETIC_ERRNO(EINVAL), "Failed to parse argument: %m");
continue;
const char *p = *line;
- r = extract_many_words(&p, NULL, 0, &name, &hierarchy_id, &num, &enabled, NULL);
+ r = extract_many_words(&p, NULL, 0, &name, &hierarchy_id, &num, &enabled);
if (r < 0)
return log_debug_errno(r, "Error parsing /proc/cgroups line, ignoring: %m");
else if (r < 4) {
"io";
p = c->parameter;
- r = extract_many_words(&p, ":", 0, &first, &second, NULL);
+ r = extract_many_words(&p, ":", 0, &first, &second);
if (r <= 0)
return log_debug_errno(r < 0 ? r : SYNTHETIC_ERRNO(EINVAL), "Failed to parse condition parameter %s: %m", c->parameter);
/* If only one parameter is passed, then we look at the global system pressure rather than a specific cgroup. */
/* If a value including a specific timespan (in the intervals allowed by the kernel),
* parse it, otherwise we assume just a plain percentage that will be checked if it is
* smaller or equal to the current pressure average over 5 minutes. */
- r = extract_many_words(&value, "/", 0, &third, &fourth, NULL);
+ r = extract_many_words(&value, "/", 0, &third, &fourth);
if (r <= 0)
return log_debug_errno(r < 0 ? r : SYNTHETIC_ERRNO(EINVAL), "Failed to parse condition parameter %s: %m", c->parameter);
if (r == 1)
if (!of)
return -ENOMEM;
- r = extract_many_words(&v, ":", EXTRACT_DONT_COALESCE_SEPARATORS|EXTRACT_CUNESCAPE, &of->path, &of->fdname, &options, NULL);
+ r = extract_many_words(&v, ":", EXTRACT_DONT_COALESCE_SEPARATORS|EXTRACT_CUNESCAPE, &of->path, &of->fdname, &options);
if (r < 0)
return r;
if (r == 0)
break;
p = line;
- r = extract_many_words(&p, NULL, 0, &stored_hash_id, &stored_discharge_rate, NULL);
+ r = extract_many_words(&p, NULL, 0, &stored_hash_id, &stored_discharge_rate);
if (r < 0)
return log_debug_errno(r, "Failed to parse hash_id and discharge_rate read from " DISCHARGE_RATE_FILEPATH ": %m");
if (r != 2)
_cleanup_free_ char *partition = NULL, *mount_options = NULL;
const char *options = argv[4];
- r = extract_many_words(&options, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &partition, &mount_options, NULL);
+ r = extract_many_words(&options, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &partition, &mount_options);
if (r < 0)
return r;
/* Single set of options, applying to the root partition/single filesystem */
/* Parse columns */
p = buffer;
r = extract_many_words(&p, NULL, EXTRACT_UNQUOTE,
- &action, &name, &id, &description, &home, &shell, NULL);
+ &action, &name, &id, &description, &home, &shell);
if (r < 0)
return log_syntax(NULL, LOG_ERR, fname, line, r, "Syntax error.");
if (r < 2)
char *a, *b, *c, *d, *e, *f;
p = original = "foobar waldi piep";
- assert_se(extract_many_words(&p, NULL, 0, &a, &b, &c, NULL) == 3);
+ assert_se(extract_many_words(&p, NULL, 0, &a, &b, &c) == 3);
assert_se(isempty(p));
assert_se(streq_ptr(a, "foobar"));
assert_se(streq_ptr(b, "waldi"));
free(c);
p = original = "foobar:waldi:piep ba1:ba2";
- assert_se(extract_many_words(&p, ":" WHITESPACE, 0, &a, &b, &c, NULL) == 3);
+ assert_se(extract_many_words(&p, ":" WHITESPACE, 0, &a, &b, &c) == 3);
assert_se(!isempty(p));
assert_se(streq_ptr(a, "foobar"));
assert_se(streq_ptr(b, "waldi"));
assert_se(streq_ptr(c, "piep"));
- assert_se(extract_many_words(&p, ":" WHITESPACE, 0, &d, &e, &f, NULL) == 2);
+ assert_se(extract_many_words(&p, ":" WHITESPACE, 0, &d, &e, &f) == 2);
assert_se(isempty(p));
assert_se(streq_ptr(d, "ba1"));
assert_se(streq_ptr(e, "ba2"));
free(f);
p = original = "'foobar' wa\"ld\"i ";
- assert_se(extract_many_words(&p, NULL, 0, &a, &b, &c, NULL) == 2);
+ assert_se(extract_many_words(&p, NULL, 0, &a, &b, &c) == 2);
assert_se(isempty(p));
assert_se(streq_ptr(a, "'foobar'"));
assert_se(streq_ptr(b, "wa\"ld\"i"));
free(b);
p = original = "'foobar' wa\"ld\"i ";
- assert_se(extract_many_words(&p, NULL, EXTRACT_UNQUOTE, &a, &b, &c, NULL) == 2);
+ assert_se(extract_many_words(&p, NULL, EXTRACT_UNQUOTE, &a, &b, &c) == 2);
assert_se(isempty(p));
assert_se(streq_ptr(a, "foobar"));
assert_se(streq_ptr(b, "waldi"));
free(b);
p = original = "";
- assert_se(extract_many_words(&p, NULL, 0, &a, &b, &c, NULL) == 0);
+ assert_se(extract_many_words(&p, NULL, 0, &a, &b, &c) == 0);
assert_se(isempty(p));
assert_se(streq_ptr(a, NULL));
assert_se(streq_ptr(b, NULL));
assert_se(streq_ptr(c, NULL));
p = original = " ";
- assert_se(extract_many_words(&p, NULL, 0, &a, &b, &c, NULL) == 0);
+ assert_se(extract_many_words(&p, NULL, 0, &a, &b, &c) == 0);
assert_se(isempty(p));
assert_se(streq_ptr(a, NULL));
assert_se(streq_ptr(b, NULL));
assert_se(streq_ptr(c, NULL));
p = original = "foobar";
- assert_se(extract_many_words(&p, NULL, 0, NULL) == 0);
+ assert_se(extract_many_words(&p, NULL, 0) == 0);
assert_se(p == original);
p = original = "foobar waldi";
- assert_se(extract_many_words(&p, NULL, 0, &a, NULL) == 1);
+ assert_se(extract_many_words(&p, NULL, 0, &a) == 1);
assert_se(p == original+7);
assert_se(streq_ptr(a, "foobar"));
free(a);
p = original = " foobar ";
- assert_se(extract_many_words(&p, NULL, 0, &a, NULL) == 1);
+ assert_se(extract_many_words(&p, NULL, 0, &a) == 1);
assert_se(isempty(p));
assert_se(streq_ptr(a, "foobar"));
free(a);
if (*buf == '#')
continue;
- r = extract_many_words(&buf, "=\",\n", 0, &key, &value, NULL);
+ r = extract_many_words(&buf, "=\",\n", 0, &key, &value);
if (r < 2)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Error parsing config file line %d '%s'", lineno, buffer);
vendor_in = TAKE_PTR(value);
key = mfree(key);
- r = extract_many_words(&buf, "=\",\n", 0, &key, &value, NULL);
+ r = extract_many_words(&buf, "=\",\n", 0, &key, &value);
if (r < 2)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Error parsing config file line %d '%s'", lineno, buffer);
model_in = TAKE_PTR(value);
key = mfree(key);
- r = extract_many_words(&buf, "=\",\n", 0, &key, &value, NULL);
+ r = extract_many_words(&buf, "=\",\n", 0, &key, &value);
if (r < 2)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Error parsing config file line %d '%s'", lineno, buffer);
}
assert(key);
assert(value);
- r = extract_many_words(&s, "=", EXTRACT_DONT_COALESCE_SEPARATORS, &k, &v, NULL);
+ r = extract_many_words(&s, "=", EXTRACT_DONT_COALESCE_SEPARATORS, &k, &v);
if (r < 0)
return log_error_errno(r, "Failed to parse key/value pair %s: %m", s);
if (r < 2)