-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <errno.h>
#include <limits.h>
#include "conf-files.h"
#include "conf-parser.h"
#include "def.h"
+#include "ether-addr-util.h"
#include "extract-word.h"
#include "fd-util.h"
#include "fileio.h"
#include "nulstr-util.h"
#include "parse-util.h"
#include "path-util.h"
+#include "percent-util.h"
#include "process-util.h"
#include "rlimit-util.h"
#include "sd-id128.h"
+#include "set.h"
#include "signal-util.h"
#include "socket-util.h"
#include "string-util.h"
k = strlen(l);
assert(k > 0);
- if (l[k-1] != ']') {
- log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid section header '%s'", l);
- return -EBADMSG;
- }
+ if (l[k-1] != ']')
+ return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EBADMSG), "Invalid section header '%s'", l);
n = strndup(l+1, k-2);
if (!n)
- return -ENOMEM;
+ return log_oom();
if (sections && !nulstr_contains(sections, n)) {
bool ignore = flags & CONFIG_PARSE_RELAXED;
}
/* Go through the file and parse each line */
-int config_parse(const char *unit,
- const char *filename,
- FILE *f,
- const char *sections,
- ConfigItemLookup lookup,
- const void *table,
- ConfigParseFlags flags,
- void *userdata,
- usec_t *ret_mtime) {
+int config_parse(
+ const char *unit,
+ const char *filename,
+ FILE *f,
+ const char *sections,
+ ConfigItemLookup lookup,
+ const void *table,
+ ConfigParseFlags flags,
+ void *userdata,
+ usec_t *ret_mtime) {
_cleanup_free_ char *section = NULL, *continuation = NULL;
_cleanup_fclose_ FILE *ours = NULL;
return -ENOBUFS;
}
- if (!strextend(&continuation, l, NULL)) {
+ if (!strextend(&continuation, l)) {
if (flags & CONFIG_PARSE_WARN)
log_oom();
return -ENOMEM;
if (ret_mtime)
*ret_mtime = mtime;
- return 0;
+ return 1;
}
static int config_parse_many_files(
- const char *conf_file,
+ const char* const* conf_files,
char **files,
const char *sections,
ConfigItemLookup lookup,
char **fn;
int r;
- if (conf_file) {
- r = config_parse(NULL, conf_file, NULL, sections, lookup, table, flags, userdata, &mtime);
+ /* First read the first found main config file. */
+ STRV_FOREACH(fn, (char**) conf_files) {
+ r = config_parse(NULL, *fn, NULL, sections, lookup, table, flags, userdata, &mtime);
if (r < 0)
return r;
+ if (r > 0)
+ break;
}
+ /* Then read all the drop-ins. */
STRV_FOREACH(fn, files) {
usec_t t;
r = config_parse(NULL, *fn, NULL, sections, lookup, table, flags, userdata, &t);
if (r < 0)
return r;
- if (t > mtime) /* Find the newest */
- mtime = t;
+ mtime = MAX(mtime, t); /* Find the newest */
}
if (ret_mtime)
if (r < 0)
return r;
- return config_parse_many_files(conf_file, files, sections, lookup, table, flags, userdata, ret_mtime);
+ return config_parse_many_files(STRV_MAKE_CONST(conf_file),
+ files, sections, lookup, table, flags, userdata,
+ ret_mtime);
}
/* Parse each config file in the directories specified as strv. */
int config_parse_many(
- const char *conf_file,
+ const char* const* conf_files,
const char* const* conf_file_dirs,
const char *dropin_dirname,
const char *sections,
if (r < 0)
return r;
- return config_parse_many_files(conf_file, files, sections, lookup, table, flags, userdata, ret_mtime);
+ return config_parse_many_files(conf_files, files, sections, lookup, table, flags, userdata, ret_mtime);
}
#define DEFINE_PARSER(type, vartype, conv_func) \
DEFINE_PARSER(sec_def_infinity, usec_t, parse_sec_def_infinity);
DEFINE_PARSER(mode, mode_t, parse_mode);
-int config_parse_iec_size(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) {
+int config_parse_iec_size(
+ 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) {
size_t *sz = data;
uint64_t v;
if (r >= 0 && (uint64_t) (size_t) v != v)
r = -ERANGE;
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse size value '%s', ignoring: %m", rvalue);
+ log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse size value '%s', ignoring: %m", rvalue);
return 0;
}
assert(data);
r = parse_size(rvalue, 1000, sz);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse size value '%s', ignoring: %m", rvalue);
- return 0;
- }
+ if (r < 0)
+ log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse size value '%s', ignoring: %m", rvalue);
return 0;
}
r = parse_size(rvalue, 1024, bytes);
if (r < 0)
- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse size value, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse size value, ignoring: %s", rvalue);
return 0;
}
-int config_parse_bool(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) {
+int config_parse_bool(
+ 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) {
int k;
bool *b = data;
k = parse_boolean(rvalue);
if (k < 0) {
- log_syntax(unit, LOG_ERR, filename, line, k,
+ log_syntax(unit, fatal ? LOG_ERR : LOG_WARNING, filename, line, k,
"Failed to parse boolean value%s: %s",
fatal ? "" : ", ignoring", rvalue);
return fatal ? -ENOEXEC : 0;
assert(rvalue);
r = sd_id128_from_string(rvalue, &t);
- if (r < 0)
- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse 128bit ID/UUID, ignoring: %s", rvalue);
- else if (sd_id128_is_null(t))
- log_syntax(unit, LOG_ERR, filename, line, 0, "128bit ID/UUID is all 0, ignoring: %s", rvalue);
+ if (r < 0) {
+ log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse 128bit ID/UUID, ignoring: %s", rvalue);
+ return 0;
+ }
+
+ if (sd_id128_is_null(t)) {
+ log_syntax(unit, LOG_WARNING, filename, line, 0, "128bit ID/UUID is all 0, ignoring: %s", rvalue);
+ return 0;
+ }
*result = t;
return 0;
k = parse_boolean(rvalue);
if (k < 0) {
- log_syntax(unit, LOG_ERR, filename, line, k, "Failed to parse boolean value, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_WARNING, filename, line, k, "Failed to parse boolean value, ignoring: %s", rvalue);
return 0;
}
- *t = !!k;
+ *t = k;
return 0;
}
assert(rvalue);
assert(data);
- if (free_and_strdup(s, empty_to_null(rvalue)) < 0)
- return log_oom();
-
- return 0;
+ return free_and_strdup_warn(s, empty_to_null(rvalue));
}
int config_parse_path(
return 0;
}
- for (;;) {
+ for (const char *p = rvalue;;) {
char *word = NULL;
- r = extract_first_word(&rvalue, &word, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE);
+ r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE);
if (r == 0)
- break;
+ return 0;
if (r == -ENOMEM)
return log_oom();
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
- break;
+ log_syntax(unit, LOG_WARNING, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
+ return 0;
}
r = strv_consume(sv, word);
if (r < 0)
return log_oom();
}
-
- return 0;
}
int config_parse_warn_compat(
x = log_facility_unshifted_from_string(rvalue);
if (x < 0) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse log facility, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_WARNING, filename, line, x, "Failed to parse log facility, ignoring: %s", rvalue);
return 0;
}
x = log_level_from_string(rvalue);
if (x < 0) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse log level, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_WARNING, filename, line, x, "Failed to parse log level, ignoring: %s", rvalue);
return 0;
}
r = signal_from_string(rvalue);
if (r <= 0) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse signal name, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse signal name, ignoring: %s", rvalue);
return 0;
}
else {
p = personality_from_string(rvalue);
if (p == PERSONALITY_INVALID) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse personality, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_WARNING, filename, line, 0, "Failed to parse personality, ignoring: %s", rvalue);
return 0;
}
}
}
if (!ifname_valid(rvalue)) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "Interface name is not valid or too long, ignoring assignment: %s", rvalue);
+ log_syntax(unit, LOG_WARNING, filename, line, 0, "Interface name is not valid or too long, ignoring assignment: %s", rvalue);
return 0;
}
_cleanup_strv_free_ char **names = NULL;
char ***s = data;
- const char *p;
int r;
assert(filename);
return 0;
}
- p = rvalue;
- for (;;) {
+ for (const char *p = rvalue;;) {
_cleanup_free_ char *word = NULL;
r = extract_first_word(&p, &word, NULL, 0);
+ if (r == -ENOMEM)
+ return log_oom();
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r,
+ log_syntax(unit, LOG_WARNING, filename, line, r,
"Failed to extract interface name, ignoring assignment: %s",
rvalue);
return 0;
break;
if (!ifname_valid_full(word, ltype)) {
- log_syntax(unit, LOG_ERR, filename, line, 0,
+ log_syntax(unit, LOG_WARNING, filename, line, 0,
"Interface name is not valid or too long, ignoring assignment: %s",
word);
continue;
r = parse_ip_port(rvalue, &port);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse port '%s'.", rvalue);
+ log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse port '%s'.", rvalue);
return 0;
}
r = parse_mtu(ltype, rvalue, mtu);
if (r == -ERANGE) {
- log_syntax(unit, LOG_ERR, filename, line, r,
+ log_syntax(unit, LOG_WARNING, filename, line, r,
"Maximum transfer unit (MTU) value out of range. Permitted range is %" PRIu32 "…%" PRIu32 ", ignoring: %s",
(uint32_t) (ltype == AF_INET6 ? IPV6_MIN_MTU : IPV4_MIN_MTU), (uint32_t) UINT32_MAX,
rvalue);
return 0;
}
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r,
+ log_syntax(unit, LOG_WARNING, filename, line, r,
"Failed to parse MTU value '%s', ignoring: %m", rvalue);
return 0;
}
return 0;
}
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse resource value, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse resource value, ignoring: %s", rvalue);
return 0;
}
return 0;
}
-int config_parse_permille(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) {
+int config_parse_permille(
+ 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) {
unsigned *permille = data;
int r;
r = parse_permille(rvalue);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r,
+ log_syntax(unit, LOG_WARNING, filename, line, r,
"Failed to parse permille value, ignoring: %s", rvalue);
return 0;
}
return 0;
}
-int config_parse_vlanprotocol(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) {
+int config_parse_vlanprotocol(
+ 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) {
+
int *vlan_protocol = data;
+
assert(filename);
assert(lvalue);
else if (STR_IN_SET(rvalue, "802.1q", "802.1Q"))
*vlan_protocol = ETH_P_8021Q;
else {
- log_syntax(unit, LOG_ERR, filename, line, 0,
+ log_syntax(unit, LOG_WARNING, filename, line, 0,
"Failed to parse VLAN protocol value, ignoring: %s", rvalue);
return 0;
}
return 0;
}
+
+int config_parse_hwaddr(
+ 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) {
+
+ _cleanup_free_ struct ether_addr *n = NULL;
+ struct ether_addr **hwaddr = data;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ if (isempty(rvalue)) {
+ *hwaddr = mfree(*hwaddr);
+ return 0;
+ }
+
+ n = new0(struct ether_addr, 1);
+ if (!n)
+ return log_oom();
+
+ r = ether_addr_from_string(rvalue, n);
+ if (r < 0) {
+ log_syntax(unit, LOG_WARNING, filename, line, r,
+ "Not a valid MAC address, ignoring assignment: %s", rvalue);
+ return 0;
+ }
+
+ free_and_replace(*hwaddr, n);
+
+ return 0;
+}
+
+int config_parse_hwaddrs(
+ 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) {
+
+ Set **hwaddrs = data;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ if (isempty(rvalue)) {
+ /* Empty assignment resets the list */
+ *hwaddrs = set_free_free(*hwaddrs);
+ return 0;
+ }
+
+ for (const char *p = rvalue;;) {
+ _cleanup_free_ char *word = NULL;
+ _cleanup_free_ struct ether_addr *n = NULL;
+
+ r = extract_first_word(&p, &word, NULL, 0);
+ if (r == 0)
+ return 0;
+ if (r == -ENOMEM)
+ return log_oom();
+ if (r < 0) {
+ log_syntax(unit, LOG_WARNING, filename, line, r,
+ "Invalid syntax, ignoring: %s", rvalue);
+ return 0;
+ }
+
+ n = new(struct ether_addr, 1);
+ if (!n)
+ return log_oom();
+
+ r = ether_addr_from_string(word, n);
+ if (r < 0) {
+ log_syntax(unit, LOG_WARNING, filename, line, r,
+ "Not a valid MAC address, ignoring: %s", word);
+ continue;
+ }
+
+ r = set_ensure_put(hwaddrs, ðer_addr_hash_ops, n);
+ if (r < 0)
+ return log_oom();
+ if (r > 0)
+ TAKE_PTR(n); /* avoid cleanup */
+ }
+}
+
+DEFINE_CONFIG_PARSE(config_parse_percent, parse_percent, "Failed to parse percent value");
+DEFINE_CONFIG_PARSE(config_parse_permyriad, parse_permyriad, "Failed to parse permyriad value");