The optional positional argument to "systemctl reboot" is now
being deprecated in favor of this option.
+ * Support for the .include syntax in unit files has been removed. The
+ concept has been obsolete for 6 years and we started warning about
+ its pending removal 2 years ago (also see NEWS file below). It's
+ finally gone now.
+
CHANGES WITH 245:
* A new tool "systemd-repart" has been added, that operates as an
operate on disk images directly. Specifically: bootctl, firstboot, tmpfiles,
sysusers, systemctl, repart, journalctl, coredumpctl.
+* seccomp: by default mask x32 ABI system wide on x86-64. it's on its way out
+
+* seccomp: don't install filters for ABIs that are masked anyway for the
+ specific service
+
+* seccomp: maybe merge all filters we install into one with that libseccomp API that allows merging.
+
* per-service credential system. Specifically: add LoadCredential= (for loading
cred from file), AcquireCredential= (for asking user for cred, via
ask-password), PassCredential= (for passing on credential systemd itself
<varlistentry>
<term><varname>RouteMetric=</varname></term>
<listitem>
- <para>Set the routing metric for routes specified by the
- DHCP server.</para>
+ <para>Set the routing metric for routes specified by the DHCP server. Defaults to 1024.</para>
</listitem>
</varlistentry>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><varname>RouteMetric=</varname></term>
+ <listitem>
+ <para>Set the routing metric for routes specified by the DHCP server. Defaults to 1024.</para>
+ </listitem>
+ </varlistentry>
+
<varlistentry>
<term><varname>RapidCommit=</varname></term>
<listitem>
<filename>foo-.service.d/10-override.conf</filename> would override
<filename>service.d/10-override.conf</filename>.</para>
- <!-- Note that we do not document .include here, as we consider it mostly obsolete, and want
- people to use .d/ drop-ins instead. -->
-
<para>Note that while systemd offers a flexible dependency system
between units it is recommended to use this functionality only
sparingly and instead rely on techniques such as bus-based or
#if ENABLE_EFI
/* Reads from efivarfs sometimes fail with EINTR. Retry that many times. */
-#define EFI_N_RETRIES 5
+#define EFI_N_RETRIES_NO_DELAY 20
+#define EFI_N_RETRIES_TOTAL 25
#define EFI_RETRY_DELAY (50 * USEC_PER_MSEC)
char* efi_variable_path(sd_id128_t vendor, const char *name) {
log_debug_errno(errno, "Reading from \"%s\" failed: %m", p);
if (errno != EINTR)
return -errno;
- if (try >= EFI_N_RETRIES)
+ if (try >= EFI_N_RETRIES_TOTAL)
return -EBUSY;
- (void) usleep(EFI_RETRY_DELAY);
+ if (try >= EFI_N_RETRIES_NO_DELAY)
+ (void) usleep(EFI_RETRY_DELAY);
}
if (n != sizeof(a))
/* Same as close_nointr(), but for fclose() */
+ errno = 0; /* Extra safety: if the FILE* object is not encapsulating an fd, it might not set errno
+ * correctly. Let's hence initialize it to zero first, so that we aren't confused by any
+ * prior errno here */
if (fclose(f) == 0)
return 0;
if (errno == EINTR)
return 0;
- return -errno;
+ return errno_or_else(EIO);
}
FILE* safe_fclose(FILE *f) {
return 0;
}
-int fd_warn_permissions(const char *path, int fd) {
- struct stat st;
-
- if (fstat(fd, &st) < 0)
- return -errno;
+int stat_warn_permissions(const char *path, const struct stat *st) {
+ assert(path);
+ assert(st);
/* Don't complain if we are reading something that is not a file, for example /dev/null */
- if (!S_ISREG(st.st_mode))
+ if (!S_ISREG(st->st_mode))
return 0;
- if (st.st_mode & 0111)
+ if (st->st_mode & 0111)
log_warning("Configuration file %s is marked executable. Please remove executable permission bits. Proceeding anyway.", path);
- if (st.st_mode & 0002)
+ if (st->st_mode & 0002)
log_warning("Configuration file %s is marked world-writable. Please remove world writability permission bits. Proceeding anyway.", path);
- if (getpid_cached() == 1 && (st.st_mode & 0044) != 0044)
+ if (getpid_cached() == 1 && (st->st_mode & 0044) != 0044)
log_warning("Configuration file %s is marked world-inaccessible. This has no effect as configuration data is accessible via APIs without restrictions. Proceeding anyway.", path);
return 0;
}
+int fd_warn_permissions(const char *path, int fd) {
+ struct stat st;
+
+ assert(path);
+ assert(fd >= 0);
+
+ if (fstat(fd, &st) < 0)
+ return -errno;
+
+ return stat_warn_permissions(path, &st);
+}
+
int touch_file(const char *path, bool parents, usec_t stamp, uid_t uid, gid_t gid, mode_t mode) {
char fdpath[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
_cleanup_close_ int fd = -1;
int fchmod_opath(int fd, mode_t m);
int fd_warn_permissions(const char *path, int fd);
+int stat_warn_permissions(const char *path, const struct stat *st);
#define laccess(path, mode) faccessat(AT_FDCWD, (path), (mode), AT_SYMLINK_NOFOLLOW)
}
STRV_FOREACH(f, u->dropin_paths)
- (void) config_parse(u->id, *f, NULL,
- UNIT_VTABLE(u)->sections,
- config_item_perf_lookup, load_fragment_gperf_lookup,
- 0, u);
-
- u->dropin_mtime = now(CLOCK_REALTIME);
+ (void) config_parse(
+ u->id, *f, NULL,
+ UNIT_VTABLE(u)->sections,
+ config_item_perf_lookup, load_fragment_gperf_lookup,
+ 0,
+ u,
+ &u->dropin_mtime);
return 0;
}
int unit_load_fragment(Unit *u) {
const char *fragment;
_cleanup_set_free_free_ Set *names = NULL;
- struct stat st;
int r;
assert(u);
if (fragment) {
/* Open the file, check if this is a mask, otherwise read. */
_cleanup_fclose_ FILE *f = NULL;
+ struct stat st;
/* Try to open the file name. A symlink is OK, for example for linked files or masks. We
* expect that all symlinks within the lookup paths have been already resolved, but we don't
r = config_parse(u->id, fragment, f,
UNIT_VTABLE(u)->sections,
config_item_perf_lookup, load_fragment_gperf_lookup,
- CONFIG_PARSE_ALLOW_INCLUDE, u);
+ 0,
+ u,
+ NULL);
if (r == -ENOEXEC)
log_unit_notice_errno(u, r, "Unit configuration has fatal error, unit will not be started.");
if (r < 0)
}
}
- if (u->source_path) {
- if (stat(u->source_path, &st) >= 0)
- u->source_mtime = timespec_load(&st.st_mtim);
- else
- u->source_mtime = 0;
- }
-
/* We do the merge dance here because for some unit types, the unit might have aliases which are not
* declared in the file system. In particular, this is true (and frequent) for device and swap units.
*/
CONF_PATHS_NULSTR("systemd/system.conf.d") :
CONF_PATHS_NULSTR("systemd/user.conf.d");
- (void) config_parse_many_nulstr(fn, conf_dirs_nulstr, "Manager\0", config_item_table_lookup, items, CONFIG_PARSE_WARN, NULL);
+ (void) config_parse_many_nulstr(
+ fn, conf_dirs_nulstr,
+ "Manager\0",
+ config_item_table_lookup, items,
+ CONFIG_PARSE_WARN,
+ NULL,
+ NULL);
/* Traditionally "0" was used to turn off the default unit timeouts. Fix this up so that we used USEC_INFINITY
* like everywhere else. */
* target unit needlessly. But we cannot be sure which drops-ins have already
* been loaded and which not, at least without doing complicated book-keeping,
* so let's always reread all drop-ins. */
- return unit_load_dropin(unit_follow_merge(u));
+ r = unit_load_dropin(unit_follow_merge(u));
+ if (r < 0)
+ return r;
+
+ if (u->source_path) {
+ struct stat st;
+
+ if (stat(u->source_path, &st) >= 0)
+ u->source_mtime = timespec_load(&st.st_mtim);
+ else
+ u->source_mtime = 0;
+ }
+
+ return 0;
}
void unit_add_to_target_deps_queue(Unit *u) {
{}
};
- return config_parse_many_nulstr(PKGSYSCONFDIR "/coredump.conf",
- CONF_PATHS_NULSTR("systemd/coredump.conf.d"),
- "Coredump\0",
- config_item_table_lookup, items,
- CONFIG_PARSE_WARN, NULL);
+ return config_parse_many_nulstr(
+ PKGSYSCONFDIR "/coredump.conf",
+ CONF_PATHS_NULSTR("systemd/coredump.conf.d"),
+ "Coredump\0",
+ config_item_table_lookup, items,
+ CONFIG_PARSE_WARN,
+ NULL,
+ NULL);
}
static uint64_t storage_size_max(void) {
name = strjoina("a.", unit_type_to_string(t));
assert_se(unit_new_for_name(m, unit_vtable[t]->object_size, name, &u) >= 0);
- (void) config_parse(name, name, f,
- UNIT_VTABLE(u)->sections,
- config_item_perf_lookup, load_fragment_gperf_lookup,
- CONFIG_PARSE_ALLOW_INCLUDE, u);
+ (void) config_parse(
+ name, name, f,
+ UNIT_VTABLE(u)->sections,
+ config_item_perf_lookup, load_fragment_gperf_lookup,
+ 0,
+ u,
+ NULL);
g = open_memstream_unlocked(&out, &out_size);
assert_se(g);
assert(m);
- r = config_parse_many_nulstr(PKGSYSCONFDIR "/homed.conf",
- CONF_PATHS_NULSTR("systemd/homed.conf.d"),
- "Home\0",
- config_item_perf_lookup, homed_gperf_lookup,
- CONFIG_PARSE_WARN, m);
+ r = config_parse_many_nulstr(
+ PKGSYSCONFDIR "/homed.conf",
+ CONF_PATHS_NULSTR("systemd/homed.conf.d"),
+ "Home\0",
+ config_item_perf_lookup, homed_gperf_lookup,
+ CONFIG_PARSE_WARN,
+ m,
+ NULL);
if (r < 0)
return r;
{}
};
- return config_parse_many_nulstr(PKGSYSCONFDIR "/journal-remote.conf",
- CONF_PATHS_NULSTR("systemd/journal-remote.conf.d"),
- "Remote\0", config_item_table_lookup, items,
- CONFIG_PARSE_WARN, NULL);
+ return config_parse_many_nulstr(
+ PKGSYSCONFDIR "/journal-remote.conf",
+ CONF_PATHS_NULSTR("systemd/journal-remote.conf.d"),
+ "Remote\0",
+ config_item_table_lookup, items,
+ CONFIG_PARSE_WARN,
+ NULL,
+ NULL);
}
static int help(void) {
{ "Upload", "ServerKeyFile", config_parse_path_or_ignore, 0, &arg_key },
{ "Upload", "ServerCertificateFile", config_parse_path_or_ignore, 0, &arg_cert },
{ "Upload", "TrustedCertificateFile", config_parse_path_or_ignore, 0, &arg_trust },
- {}};
+ {}
+ };
- return config_parse_many_nulstr(PKGSYSCONFDIR "/journal-upload.conf",
- CONF_PATHS_NULSTR("systemd/journal-upload.conf.d"),
- "Upload\0", config_item_table_lookup, items,
- CONFIG_PARSE_WARN, NULL);
+ return config_parse_many_nulstr(
+ PKGSYSCONFDIR "/journal-upload.conf",
+ CONF_PATHS_NULSTR("systemd/journal-upload.conf.d"),
+ "Upload\0",
+ config_item_table_lookup, items,
+ CONFIG_PARSE_WARN,
+ NULL,
+ NULL);
}
static int help(void) {
/* If we are running in namespace mode, load the namespace specific configuration file, and nothing else */
namespaced = strjoina(PKGSYSCONFDIR "/journald@", s->namespace, ".conf");
- r = config_parse(
- NULL,
- namespaced, NULL,
- "Journal\0",
- config_item_perf_lookup, journald_gperf_lookup,
- CONFIG_PARSE_WARN, s);
+ r = config_parse(NULL,
+ namespaced, NULL,
+ "Journal\0",
+ config_item_perf_lookup, journald_gperf_lookup,
+ CONFIG_PARSE_WARN, s,
+ NULL);
if (r < 0)
return r;
return 0;
}
- return config_parse_many_nulstr(PKGSYSCONFDIR "/journald.conf",
- CONF_PATHS_NULSTR("systemd/journald.conf.d"),
- "Journal\0",
- config_item_perf_lookup, journald_gperf_lookup,
- CONFIG_PARSE_WARN, s);
+ return config_parse_many_nulstr(
+ PKGSYSCONFDIR "/journald.conf",
+ CONF_PATHS_NULSTR("systemd/journald.conf.d"),
+ "Journal\0",
+ config_item_perf_lookup, journald_gperf_lookup,
+ CONFIG_PARSE_WARN, s, NULL);
}
static int server_dispatch_sync(sd_event_source *es, usec_t t, void *userdata) {
Set *match_permanent_mac,
char * const *match_paths,
char * const *match_drivers,
- char * const *match_types,
+ char * const *match_iftypes,
char * const *match_names,
char * const *match_property,
char * const *match_wifi_iftype,
char * const *match_ssid,
Set *match_bssid,
- unsigned short iftype,
sd_device *device,
const struct ether_addr *dev_mac,
const struct ether_addr *dev_permanent_mac,
+ const char *dev_driver,
+ unsigned short dev_iftype,
const char *dev_name,
char * const *alternative_names,
- enum nl80211_iftype wifi_iftype,
- const char *ssid,
- const struct ether_addr *bssid) {
+ enum nl80211_iftype dev_wifi_iftype,
+ const char *dev_ssid,
+ const struct ether_addr *dev_bssid) {
- const char *dev_path = NULL, *dev_driver = NULL, *mac_str;
- _cleanup_free_ char *dev_type;
+ _cleanup_free_ char *dev_iftype_str;
+ const char *dev_path = NULL;
- dev_type = link_get_type_string(iftype, device);
+ dev_iftype_str = link_get_type_string(dev_iftype, device);
if (device) {
+ const char *mac_str;
+
(void) sd_device_get_property_value(device, "ID_PATH", &dev_path);
- (void) sd_device_get_property_value(device, "ID_NET_DRIVER", &dev_driver);
+ if (!dev_driver)
+ (void) sd_device_get_property_value(device, "ID_NET_DRIVER", &dev_driver);
if (!dev_name)
(void) sd_device_get_sysname(device, &dev_name);
if (!dev_mac &&
if (!net_condition_test_strv(match_drivers, dev_driver))
return false;
- if (!net_condition_test_strv(match_types, dev_type))
+ if (!net_condition_test_strv(match_iftypes, dev_iftype_str))
return false;
if (!net_condition_test_ifname(match_names, dev_name, alternative_names))
if (!net_condition_test_property(match_property, device))
return false;
- if (!net_condition_test_strv(match_wifi_iftype, wifi_iftype_to_string(wifi_iftype)))
+ if (!net_condition_test_strv(match_wifi_iftype, wifi_iftype_to_string(dev_wifi_iftype)))
return false;
- if (!net_condition_test_strv(match_ssid, ssid))
+ if (!net_condition_test_strv(match_ssid, dev_ssid))
return false;
- if (match_bssid && (!bssid || !set_contains(match_bssid, bssid)))
+ if (match_bssid && (!dev_bssid || !set_contains(match_bssid, dev_bssid)))
return false;
return true;
char *link_get_type_string(unsigned short iftype, sd_device *device);
bool net_match_config(Set *match_mac,
Set *match_permanent_mac,
- char * const *match_path,
- char * const *match_driver,
- char * const *match_type,
- char * const *match_name,
+ char * const *match_paths,
+ char * const *match_drivers,
+ char * const *match_iftypes,
+ char * const *match_names,
char * const *match_property,
char * const *match_wifi_iftype,
char * const *match_ssid,
Set *match_bssid,
- unsigned short iftype,
sd_device *device,
const struct ether_addr *dev_mac,
const struct ether_addr *dev_permanent_mac,
+ const char *dev_driver,
+ unsigned short dev_iftype,
const char *dev_name,
char * const *alternative_names,
- enum nl80211_iftype wifi_iftype,
- const char *ssid,
- const struct ether_addr *bssid);
+ enum nl80211_iftype dev_wifi_iftype,
+ const char *dev_ssid,
+ const struct ether_addr *dev_bssid);
CONFIG_PARSER_PROTOTYPE(config_parse_net_condition);
CONFIG_PARSER_PROTOTYPE(config_parse_hwaddr);
int manager_parse_config_file(Manager *m) {
assert(m);
- return config_parse_many_nulstr(PKGSYSCONFDIR "/logind.conf",
- CONF_PATHS_NULSTR("systemd/logind.conf.d"),
- "Login\0",
- config_item_perf_lookup, logind_gperf_lookup,
- CONFIG_PARSE_WARN, m);
+ return config_parse_many_nulstr(
+ PKGSYSCONFDIR "/logind.conf",
+ CONF_PATHS_NULSTR("systemd/logind.conf.d"),
+ "Login\0",
+ config_item_perf_lookup, logind_gperf_lookup,
+ CONFIG_PARSE_WARN, m,
+ NULL);
}
int manager_add_device(Manager *m, const char *sysfs, bool master, Device **ret_device) {
};
dropin_dirname = strjoina(basename(filename), ".d");
- r = config_parse_many(filename, NETWORK_DIRS, dropin_dirname,
- NETDEV_COMMON_SECTIONS NETDEV_OTHER_SECTIONS,
- config_item_perf_lookup, network_netdev_gperf_lookup,
- CONFIG_PARSE_WARN, netdev_raw, NULL);
+ r = config_parse_many(
+ filename, NETWORK_DIRS, dropin_dirname,
+ NETDEV_COMMON_SECTIONS NETDEV_OTHER_SECTIONS,
+ config_item_perf_lookup, network_netdev_gperf_lookup,
+ CONFIG_PARSE_WARN,
+ netdev_raw,
+ NULL);
if (r < 0)
return r;
if (NETDEV_VTABLE(netdev)->init)
NETDEV_VTABLE(netdev)->init(netdev);
- r = config_parse_many(filename, NETWORK_DIRS, dropin_dirname,
- NETDEV_VTABLE(netdev)->sections,
- config_item_perf_lookup, network_netdev_gperf_lookup,
- CONFIG_PARSE_WARN, netdev, NULL);
+ r = config_parse_many(
+ filename, NETWORK_DIRS, dropin_dirname,
+ NETDEV_VTABLE(netdev)->sections,
+ config_item_perf_lookup, network_netdev_gperf_lookup,
+ CONFIG_PARSE_WARN,
+ netdev, NULL);
if (r < 0)
return r;
assert(m);
- r = config_parse_many_nulstr(PKGSYSCONFDIR "/networkd.conf",
- CONF_PATHS_NULSTR("systemd/networkd.conf.d"),
- "Network\0DHCP\0",
- config_item_perf_lookup, networkd_gperf_lookup,
- CONFIG_PARSE_WARN, m);
+ r = config_parse_many_nulstr(
+ PKGSYSCONFDIR "/networkd.conf",
+ CONF_PATHS_NULSTR("systemd/networkd.conf.d"),
+ "Network\0"
+ "DHCP\0",
+ config_item_perf_lookup, networkd_gperf_lookup,
+ CONFIG_PARSE_WARN,
+ m,
+ NULL);
if (r < 0)
return r;
#include "parse-util.h"
#include "string-table.h"
#include "strv.h"
-#include "web-util.h"
int config_parse_dhcp(
const char* unit,
return 0;
}
-int config_parse_dhcp_use_dns(
+int config_parse_dhcp_route_metric(
const char* unit,
const char *filename,
unsigned line,
void *userdata) {
Network *network = data;
+ uint32_t metric;
int r;
assert(filename);
assert(rvalue);
assert(data);
- r = parse_boolean(rvalue);
+ r = safe_atou32(rvalue, &metric);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r,
- "Failed to parse UseDNS=%s, ignoring assignment: %m", rvalue);
+ "Failed to parse RouteMetric=%s, ignoring assignment: %m", rvalue);
return 0;
}
- network->dhcp_use_dns = r;
- network->dhcp6_use_dns = r;
+ if (streq_ptr(section, "DHCPv4")) {
+ network->dhcp_route_metric = metric;
+ network->dhcp_route_metric_set = true;
+ } else if (streq_ptr(section, "DHCPv6")) {
+ network->dhcp6_route_metric = metric;
+ network->dhcp6_route_metric_set = true;
+ } else { /* [DHCP] section */
+ if (!network->dhcp_route_metric_set)
+ network->dhcp_route_metric = metric;
+ if (!network->dhcp6_route_metric_set)
+ network->dhcp6_route_metric = metric;
+ }
return 0;
}
-int config_parse_dhcp_use_sip(
+int config_parse_dhcp_use_dns(
const char* unit,
const char *filename,
unsigned line,
r = parse_boolean(rvalue);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r,
- "Failed to parse UseSIP=%s, ignoring assignment: %m", rvalue);
+ "Failed to parse UseDNS=%s, ignoring assignment: %m", rvalue);
return 0;
}
- network->dhcp_use_sip = r;
+ if (streq_ptr(section, "DHCPv4")) {
+ network->dhcp_use_dns = r;
+ network->dhcp_use_dns_set = true;
+ } else if (streq_ptr(section, "DHCPv6")) {
+ network->dhcp6_use_dns = r;
+ network->dhcp6_use_dns_set = true;
+ } else { /* [DHCP] section */
+ if (!network->dhcp_use_dns_set)
+ network->dhcp_use_dns = r;
+ if (!network->dhcp6_use_dns_set)
+ network->dhcp6_use_dns = r;
+ }
return 0;
}
return 0;
}
- network->dhcp_use_ntp = r;
- network->dhcp6_use_ntp = r;
+ if (streq_ptr(section, "DHCPv4")) {
+ network->dhcp_use_ntp = r;
+ network->dhcp_use_ntp_set = true;
+ } else if (streq_ptr(section, "DHCPv6")) {
+ network->dhcp6_use_ntp = r;
+ network->dhcp6_use_ntp_set = true;
+ } else { /* [DHCP] section */
+ if (!network->dhcp_use_ntp_set)
+ network->dhcp_use_ntp = r;
+ if (!network->dhcp6_use_ntp_set)
+ network->dhcp6_use_ntp = r;
+ }
return 0;
}
return 0;
}
-int config_parse_dhcp6_pd_hint(
- 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) {
-
- Network *network = data;
- int r;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- r = in_addr_prefix_from_string(rvalue, AF_INET6, (union in_addr_union *) &network->dhcp6_pd_address, &network->dhcp6_pd_length);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse PrefixDelegationHint=%s, ignoring assignment", rvalue);
- return 0;
- }
-
- if (network->dhcp6_pd_length < 1 || network->dhcp6_pd_length > 128) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid prefix length='%d', ignoring assignment", network->dhcp6_pd_length);
- network->dhcp6_pd_length = 0;
- return 0;
- }
-
- return 0;
-}
-
int config_parse_dhcp_user_class(
const char *unit,
const char *filename,
return 0;
}
-int config_parse_dhcp6_mud_url(
- 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_ char *unescaped = NULL;
- Network *network = data;
- int r;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
-
- if (isempty(rvalue)) {
- network->dhcp6_mudurl = mfree(network->dhcp6_mudurl);
- return 0;
- }
-
- r = cunescape(rvalue, 0, &unescaped);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r,
- "Failed to Failed to unescape MUD URL, ignoring: %s", rvalue);
- return 0;
- }
-
- if (!http_url_is_valid(unescaped) || strlen(unescaped) > UINT8_MAX) {
- log_syntax(unit, LOG_ERR, filename, line, 0,
- "Failed to parse MUD URL '%s', ignoring: %m", rvalue);
-
- return 0;
- }
-
- return free_and_replace(network->dhcp6_mudurl, unescaped);
-}
-
int config_parse_dhcp_send_option(
const char *unit,
const char *filename,
DHCPOptionDataType dhcp_option_data_type_from_string(const char *d) _pure_;
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp);
+CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_route_metric);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_use_dns);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_use_domains);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_use_ntp);
-CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_use_sip);
CONFIG_PARSER_PROTOTYPE(config_parse_iaid);
CONFIG_PARSER_PROTOTYPE(config_parse_section_route_table);
-CONFIG_PARSER_PROTOTYPE(config_parse_dhcp6_pd_hint);
-CONFIG_PARSER_PROTOTYPE(config_parse_dhcp6_mud_url);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_user_class);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_vendor_class);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_send_option);
#include "sd-dhcp6-client.h"
+#include "escape.h"
#include "hashmap.h"
#include "hostname-util.h"
#include "missing_network.h"
#include "siphash24.h"
#include "string-util.h"
#include "radv-internal.h"
+#include "web-util.h"
static int dhcp6_lease_address_acquired(sd_dhcp6_client *client, Link *link);
static Link *dhcp6_prefix_get(Manager *m, struct in6_addr *addr);
return 0;
}
+
+int config_parse_dhcp6_pd_hint(
+ 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) {
+
+ Network *network = data;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ r = in_addr_prefix_from_string(rvalue, AF_INET6, (union in_addr_union *) &network->dhcp6_pd_address, &network->dhcp6_pd_length);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse PrefixDelegationHint=%s, ignoring assignment", rvalue);
+ return 0;
+ }
+
+ if (network->dhcp6_pd_length < 1 || network->dhcp6_pd_length > 128) {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid prefix length='%d', ignoring assignment", network->dhcp6_pd_length);
+ network->dhcp6_pd_length = 0;
+ return 0;
+ }
+
+ return 0;
+}
+
+int config_parse_dhcp6_mud_url(
+ 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_ char *unescaped = NULL;
+ Network *network = data;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+
+ if (isempty(rvalue)) {
+ network->dhcp6_mudurl = mfree(network->dhcp6_mudurl);
+ return 0;
+ }
+
+ r = cunescape(rvalue, 0, &unescaped);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r,
+ "Failed to Failed to unescape MUD URL, ignoring: %s", rvalue);
+ return 0;
+ }
+
+ if (!http_url_is_valid(unescaped) || strlen(unescaped) > UINT8_MAX) {
+ log_syntax(unit, LOG_ERR, filename, line, 0,
+ "Failed to parse MUD URL '%s', ignoring: %m", rvalue);
+
+ return 0;
+ }
+
+ return free_and_replace(network->dhcp6_mudurl, unescaped);
+}
int dhcp6_request_address(Link *link, int ir);
int dhcp6_lease_pd_prefix_lost(sd_dhcp6_client *client, Link* link);
int dhcp6_prefix_remove(Manager *m, struct in6_addr *addr);
+
+CONFIG_PARSER_PROTOTYPE(config_parse_dhcp6_pd_hint);
+CONFIG_PARSER_PROTOTYPE(config_parse_dhcp6_mud_url);
if (r < 0)
log_link_debug_errno(link, r, "MAC address not found for new device, continuing without");
- r = ethtool_get_permanent_macaddr(NULL, link->ifname, &link->permanent_mac);
+ r = ethtool_get_permanent_macaddr(&manager->ethtool_fd, link->ifname, &link->permanent_mac);
if (r < 0)
log_link_debug_errno(link, r, "Permanent MAC address not found for new device, continuing without: %m");
+ r = ethtool_get_driver(&manager->ethtool_fd, link->ifname, &link->driver);
+ if (r < 0)
+ log_link_debug_errno(link, r, "Failed to get driver, continuing without: %m");
+
r = sd_netlink_message_read_strv(message, IFLA_PROP_LIST, IFLA_ALT_IFNAME, &link->alternative_names);
if (r < 0 && r != -ENODATA)
return r;
strv_free(link->alternative_names);
free(link->kind);
free(link->ssid);
+ free(link->driver);
(void) unlink(link->state_file);
free(link->state_file);
strv_free_and_replace(link->alternative_names, s);
}
- r = network_get(link->manager, link->iftype, link->sd_device, link->ifname, link->alternative_names,
- &link->mac, &link->permanent_mac, link->wlan_iftype, link->ssid, &link->bssid, &network);
+ r = network_get(link->manager, link->iftype, link->sd_device,
+ link->ifname, link->alternative_names, link->driver,
+ &link->mac, &link->permanent_mac,
+ link->wlan_iftype, link->ssid, &link->bssid, &network);
if (r == -ENOENT) {
link_enter_unmanaged(link);
return 0;
if (r < 0)
return r;
- r = network_get(link->manager, link->iftype, link->sd_device, link->ifname, link->alternative_names,
- &link->mac, &link->permanent_mac, link->wlan_iftype, link->ssid, &link->bssid, &network);
+ r = network_get(link->manager, link->iftype, link->sd_device,
+ link->ifname, link->alternative_names, link->driver,
+ &link->mac, &link->permanent_mac,
+ link->wlan_iftype, link->ssid, &link->bssid, &network);
if (r == -ENOENT) {
link_enter_unmanaged(link);
return 0;
struct in6_addr ipv6ll_address;
uint32_t mtu;
sd_device *sd_device;
+ char *driver;
/* wlan */
enum nl80211_iftype wlan_iftype;
*m = (Manager) {
.speed_meter_interval_usec = SPEED_METER_DEFAULT_TIME_INTERVAL,
.manage_foreign_routes = true,
+ .ethtool_fd = -1,
};
m->state_file = strdup("/run/systemd/netif/state");
free(m->dynamic_timezone);
free(m->dynamic_hostname);
+ safe_close(m->ethtool_fd);
+
free(m);
}
sd_bus *bus;
sd_device_monitor *device_monitor;
Hashmap *polkit_registry;
+ int ethtool_fd;
bool enumerating:1;
bool dirty:1;
route->family = AF_INET6;
route->table = link_get_ipv6_accept_ra_route_table(link);
- route->priority = link->network->dhcp_route_metric;
+ route->priority = link->network->dhcp6_route_metric;
route->protocol = RTPROT_RA;
route->pref = preference;
route->gw = gateway;
route->family = AF_INET6;
route->table = link_get_ipv6_accept_ra_route_table(link);
- route->priority = link->network->dhcp_route_metric;
+ route->priority = link->network->dhcp6_route_metric;
route->protocol = RTPROT_RA;
route->flags = RTM_F_PREFIX;
route->dst_prefixlen = prefixlen;
route->family = AF_INET6;
route->table = link_get_ipv6_accept_ra_route_table(link);
+ route->priority = link->network->dhcp6_route_metric;
route->protocol = RTPROT_RA;
route->pref = preference;
route->gw.in6 = gateway;
#include "networkd-dhcp-common.h"
#include "networkd-dhcp-server.h"
#include "networkd-dhcp4.h"
+#include "networkd-dhcp6.h"
#include "networkd-ipv4ll.h"
#include "networkd-ndisc.h"
#include "networkd-network.h"
NextHop.Id, config_parse_nexthop_id, 0, 0
NextHop.Gateway, config_parse_nexthop_gateway, 0, 0
DHCPv4.ClientIdentifier, config_parse_dhcp_client_identifier, 0, offsetof(Network, dhcp_client_identifier)
-DHCPv4.UseDNS, config_parse_bool, 0, offsetof(Network, dhcp_use_dns)
+DHCPv4.UseDNS, config_parse_dhcp_use_dns, 0, 0
DHCPv4.RoutesToDNS, config_parse_bool, 0, offsetof(Network, dhcp_routes_to_dns)
-DHCPv4.UseNTP, config_parse_bool, 0, offsetof(Network, dhcp_use_ntp)
+DHCPv4.UseNTP, config_parse_dhcp_use_ntp, 0, 0
DHCPv4.UseSIP, config_parse_bool, 0, offsetof(Network, dhcp_use_sip)
DHCPv4.UseMTU, config_parse_bool, 0, offsetof(Network, dhcp_use_mtu)
DHCPv4.UseHostname, config_parse_bool, 0, offsetof(Network, dhcp_use_hostname)
DHCPv4.UserClass, config_parse_dhcp_user_class, AF_INET, offsetof(Network, dhcp_user_class)
DHCPv4.DUIDType, config_parse_duid_type, 0, offsetof(Network, duid)
DHCPv4.DUIDRawData, config_parse_duid_rawdata, 0, offsetof(Network, duid)
-DHCPv4.RouteMetric, config_parse_unsigned, 0, offsetof(Network, dhcp_route_metric)
+DHCPv4.RouteMetric, config_parse_dhcp_route_metric, 0, 0
DHCPv4.RouteTable, config_parse_section_route_table, 0, 0
DHCPv4.UseTimezone, config_parse_bool, 0, offsetof(Network, dhcp_use_timezone)
DHCPv4.IAID, config_parse_iaid, 0, 0
DHCPv4.SendVendorOption, config_parse_dhcp_send_option, 0, offsetof(Network, dhcp_client_send_vendor_options)
DHCPv4.RouteMTUBytes, config_parse_mtu, AF_INET, offsetof(Network, dhcp_route_mtu)
DHCPv4.FallbackLeaseLifetimeSec, config_parse_dhcp_fallback_lease_lifetime, 0, 0
-DHCPv6.UseDNS, config_parse_bool, 0, offsetof(Network, dhcp6_use_dns)
-DHCPv6.UseNTP, config_parse_bool, 0, offsetof(Network, dhcp6_use_ntp)
+DHCPv6.UseDNS, config_parse_dhcp_use_dns, 0, 0
+DHCPv6.UseNTP, config_parse_dhcp_use_ntp, 0, 0
DHCPv6.RapidCommit, config_parse_bool, 0, offsetof(Network, rapid_commit)
DHCPv6.MUDURL, config_parse_dhcp6_mud_url, 0, 0
DHCPv6.RequestOptions, config_parse_dhcp_request_options, AF_INET6, 0
DHCPv6.PrefixDelegationHint, config_parse_dhcp6_pd_hint, 0, 0
DHCPv6.WithoutRA, config_parse_bool, 0, offsetof(Network, dhcp6_without_ra)
DHCPv6.SendOption, config_parse_dhcp_send_option, AF_INET6, offsetof(Network, dhcp6_client_send_options)
+DHCPv6.RouteMetric, config_parse_dhcp_route_metric, 0, 0
IPv6AcceptRA.UseAutonomousPrefix, config_parse_bool, 0, offsetof(Network, ipv6_accept_ra_use_autonomous_prefix)
IPv6AcceptRA.UseOnLinkPrefix, config_parse_bool, 0, offsetof(Network, ipv6_accept_ra_use_onlink_prefix)
IPv6AcceptRA.UseDNS, config_parse_bool, 0, offsetof(Network, ipv6_accept_ra_use_dns)
DHCP.UserClass, config_parse_dhcp_user_class, AF_INET, offsetof(Network, dhcp_user_class)
DHCP.DUIDType, config_parse_duid_type, 0, offsetof(Network, duid)
DHCP.DUIDRawData, config_parse_duid_rawdata, 0, offsetof(Network, duid)
-DHCP.RouteMetric, config_parse_unsigned, 0, offsetof(Network, dhcp_route_metric)
+DHCP.RouteMetric, config_parse_dhcp_route_metric, 0, 0
DHCP.RouteTable, config_parse_section_route_table, 0, 0
DHCP.UseTimezone, config_parse_bool, 0, offsetof(Network, dhcp_use_timezone)
DHCP.IAID, config_parse_iaid, 0, 0
int network_load_one(Manager *manager, OrderedHashmap **networks, const char *filename) {
_cleanup_free_ char *fname = NULL, *name = NULL;
_cleanup_(network_unrefp) Network *network = NULL;
- _cleanup_strv_free_ char **dropins = NULL;
_cleanup_fclose_ FILE *file = NULL;
const char *dropin_dirname;
char *d;
.dhcp_use_timezone = false,
.rapid_commit = true,
+ .dhcp6_route_metric = DHCP_ROUTE_METRIC,
.dhcp6_use_ntp = true,
.dhcp6_use_dns = true,
.ip_service_type = -1,
};
- r = config_parse_many(filename, NETWORK_DIRS, dropin_dirname,
- "Match\0"
- "Link\0"
- "Network\0"
- "Address\0"
- "Neighbor\0"
- "IPv6AddressLabel\0"
- "RoutingPolicyRule\0"
- "Route\0"
- "NextHop\0"
- "DHCP\0" /* compat */
- "DHCPv4\0"
- "DHCPv6\0"
- "DHCPServer\0"
- "IPv6AcceptRA\0"
- "IPv6NDPProxyAddress\0"
- "Bridge\0"
- "BridgeFDB\0"
- "BridgeVLAN\0"
- "IPv6PrefixDelegation\0"
- "IPv6Prefix\0"
- "IPv6RoutePrefix\0"
- "LLDP\0"
- "TrafficControlQueueingDiscipline\0"
- "CAN\0"
- "QDisc\0"
- "BFIFO\0"
- "CAKE\0"
- "ControlledDelay\0"
- "DeficitRoundRobinScheduler\0"
- "DeficitRoundRobinSchedulerClass\0"
- "PFIFO\0"
- "PFIFOFast\0"
- "PFIFOHeadDrop\0"
- "FairQueueing\0"
- "FairQueueingControlledDelay\0"
- "GenericRandomEarlyDetection\0"
- "HeavyHitterFilter\0"
- "HierarchyTokenBucket\0"
- "HierarchyTokenBucketClass\0"
- "NetworkEmulator\0"
- "PIE\0"
- "StochasticFairBlue\0"
- "StochasticFairnessQueueing\0"
- "TokenBucketFilter\0"
- "TrivialLinkEqualizer\0",
- config_item_perf_lookup, network_network_gperf_lookup,
- CONFIG_PARSE_WARN, network, &dropins);
+ r = config_parse_many(
+ filename, NETWORK_DIRS, dropin_dirname,
+ "Match\0"
+ "Link\0"
+ "Network\0"
+ "Address\0"
+ "Neighbor\0"
+ "IPv6AddressLabel\0"
+ "RoutingPolicyRule\0"
+ "Route\0"
+ "NextHop\0"
+ "DHCP\0" /* compat */
+ "DHCPv4\0"
+ "DHCPv6\0"
+ "DHCPServer\0"
+ "IPv6AcceptRA\0"
+ "IPv6NDPProxyAddress\0"
+ "Bridge\0"
+ "BridgeFDB\0"
+ "BridgeVLAN\0"
+ "IPv6PrefixDelegation\0"
+ "IPv6Prefix\0"
+ "IPv6RoutePrefix\0"
+ "LLDP\0"
+ "TrafficControlQueueingDiscipline\0"
+ "CAN\0"
+ "QDisc\0"
+ "BFIFO\0"
+ "CAKE\0"
+ "ControlledDelay\0"
+ "DeficitRoundRobinScheduler\0"
+ "DeficitRoundRobinSchedulerClass\0"
+ "PFIFO\0"
+ "PFIFOFast\0"
+ "PFIFOHeadDrop\0"
+ "FairQueueing\0"
+ "FairQueueingControlledDelay\0"
+ "GenericRandomEarlyDetection\0"
+ "HeavyHitterFilter\0"
+ "HierarchyTokenBucket\0"
+ "HierarchyTokenBucketClass\0"
+ "NetworkEmulator\0"
+ "PIE\0"
+ "StochasticFairBlue\0"
+ "StochasticFairnessQueueing\0"
+ "TokenBucketFilter\0"
+ "TrivialLinkEqualizer\0",
+ config_item_perf_lookup, network_network_gperf_lookup,
+ CONFIG_PARSE_WARN,
+ network,
+ &network->timestamp);
if (r < 0)
return r;
log_warning_errno(r, "%s: Failed to add default route on device, ignoring: %m",
network->filename);
- struct stat stats;
- if (stat(filename, &stats) >= 0)
- network->timestamp = timespec_load(&stats.st_mtim);
-
- char **f;
- STRV_FOREACH(f, dropins) {
- usec_t t;
-
- if (stat(*f, &stats) < 0) {
- network->timestamp = 0;
- break;
- }
-
- t = timespec_load(&stats.st_mtim);
- if (t > network->timestamp)
- network->timestamp = t;
- }
-
if (network_verify(network) < 0)
/* Ignore .network files that do not match the conditions. */
return 0;
}
int network_get(Manager *manager, unsigned short iftype, sd_device *device,
- const char *ifname, char * const *alternative_names,
- const struct ether_addr *address, const struct ether_addr *permanent_address,
+ const char *ifname, char * const *alternative_names, const char *driver,
+ const struct ether_addr *mac, const struct ether_addr *permanent_mac,
enum nl80211_iftype wlan_iftype, const char *ssid, const struct ether_addr *bssid,
Network **ret) {
Network *network;
network->match_path, network->match_driver,
network->match_type, network->match_name, network->match_property,
network->match_wlan_iftype, network->match_ssid, network->match_bssid,
- iftype, device, address, permanent_address,
+ device, mac, permanent_mac, driver, iftype,
ifname, alternative_names, wlan_iftype, ssid, bssid)) {
if (network->match_name && device) {
const char *attr;
char **dhcp_user_class;
char *dhcp_hostname;
uint64_t dhcp_max_attempts;
- unsigned dhcp_route_metric;
+ uint32_t dhcp_route_metric;
+ bool dhcp_route_metric_set;
uint32_t dhcp_route_table;
uint32_t dhcp_fallback_lease_lifetime;
uint32_t dhcp_route_mtu;
bool dhcp_send_hostname;
bool dhcp_broadcast;
bool dhcp_use_dns;
+ bool dhcp_use_dns_set;
bool dhcp_routes_to_dns;
bool dhcp_use_ntp;
+ bool dhcp_use_ntp_set;
bool dhcp_use_sip;
bool dhcp_use_mtu;
bool dhcp_use_routes;
/* DHCPv6 Client support*/
bool dhcp6_use_dns;
+ bool dhcp6_use_dns_set;
bool dhcp6_use_ntp;
+ bool dhcp6_use_ntp_set;
bool dhcp6_without_ra;
uint8_t dhcp6_pd_length;
+ uint32_t dhcp6_route_metric;
+ bool dhcp6_route_metric_set;
char *dhcp6_mudurl;
char **dhcp6_user_class;
char **dhcp6_vendor_class;
int network_verify(Network *network);
int network_get_by_name(Manager *manager, const char *name, Network **ret);
-int network_get(Manager *manager, unsigned short iftype, sd_device *device, const char *ifname, char * const *alternative_names,
+int network_get(Manager *manager, unsigned short iftype, sd_device *device,
+ const char *ifname, char * const *alternative_names, const char *driver,
const struct ether_addr *mac, const struct ether_addr *permanent_mac,
- enum nl80211_iftype wlan_iftype, const char *ssid,
- const struct ether_addr *bssid, Network **ret);
+ enum nl80211_iftype wlan_iftype, const char *ssid, const struct ether_addr *bssid,
+ Network **ret);
int network_apply(Network *network, Link *link);
void network_apply_anonymize_if_set(Network *network);
/* Let's hope that the test machine does not have a .network file that applies to loopback device…
* But it is still possible, so let's allow that case too. */
- r = network_get(manager, 0, loopback, "lo", NULL, &mac, &mac, 0, NULL, NULL, &network);
+ r = network_get(manager, 0, loopback, "lo", NULL, NULL, &mac, &mac, 0, NULL, NULL, &network);
if (r == -ENOENT)
/* The expected case */
assert_se(!network);
"Files\0",
config_item_perf_lookup, nspawn_gperf_lookup,
CONFIG_PARSE_WARN,
- s);
+ s, NULL);
if (r < 0)
return r;
};
int r;
- r = config_parse(NULL, path, NULL, "Partition\0", config_item_table_lookup, table, CONFIG_PARSE_WARN, p);
+ r = config_parse(NULL, path, NULL,
+ "Partition\0",
+ config_item_table_lookup, table,
+ CONFIG_PARSE_WARN,
+ p,
+ NULL);
if (r < 0)
return r;
{}
};
- return config_parse_many_nulstr(PKGSYSCONFDIR "/pstore.conf",
- CONF_PATHS_NULSTR("systemd/pstore.conf.d"),
- "PStore\0",
- config_item_table_lookup, items,
- CONFIG_PARSE_WARN, NULL);
+ return config_parse_many_nulstr(
+ PKGSYSCONFDIR "/pstore.conf",
+ CONF_PATHS_NULSTR("systemd/pstore.conf.d"),
+ "PStore\0",
+ config_item_table_lookup, items,
+ CONFIG_PARSE_WARN,
+ NULL,
+ NULL);
}
/* File list handling - PStoreEntry is the struct and
assert(m);
- r = config_parse_many_nulstr(PKGSYSCONFDIR "/resolved.conf",
- CONF_PATHS_NULSTR("systemd/resolved.conf.d"),
- "Resolve\0",
- config_item_perf_lookup, resolved_gperf_lookup,
- CONFIG_PARSE_WARN, m);
+ r = config_parse_many_nulstr(
+ PKGSYSCONFDIR "/resolved.conf",
+ CONF_PATHS_NULSTR("systemd/resolved.conf.d"),
+ "Resolve\0",
+ config_item_perf_lookup, resolved_gperf_lookup,
+ CONFIG_PARSE_WARN,
+ m,
+ NULL);
if (r < 0)
return r;
dropin_dirname = strjoina(service->name, ".dnssd.d");
- r = config_parse_many(filename, DNSSD_SERVICE_DIRS, dropin_dirname,
- "Service\0",
- config_item_perf_lookup, resolved_dnssd_gperf_lookup,
- false, service, NULL);
+ r = config_parse_many(
+ filename, DNSSD_SERVICE_DIRS, dropin_dirname,
+ "Service\0",
+ config_item_perf_lookup, resolved_dnssd_gperf_lookup,
+ CONFIG_PARSE_WARN,
+ service,
+ NULL);
if (r < 0)
return r;
char *l,
void *userdata) {
- char *e, *include;
+ char *e;
assert(filename);
assert(line > 0);
if (*l == '\n')
return 0;
- include = first_word(l, ".include");
- if (include) {
- _cleanup_free_ char *fn = NULL;
-
- /* .includes are a bad idea, we only support them here
- * for historical reasons. They create cyclic include
- * problems and make it difficult to detect
- * configuration file changes with an easy
- * stat(). Better approaches, such as .d/ drop-in
- * snippets exist.
- *
- * Support for them should be eventually removed. */
-
- if (!(flags & CONFIG_PARSE_ALLOW_INCLUDE)) {
- log_syntax(unit, LOG_ERR, filename, line, 0, ".include not allowed here. Ignoring.");
- return 0;
- }
-
- log_syntax(unit, LOG_WARNING, filename, line, 0,
- ".include directives are deprecated, and support for them will be removed in a future version of systemd. "
- "Please use drop-in files instead.");
-
- fn = file_in_same_dir(filename, strstrip(include));
- if (!fn)
- return -ENOMEM;
-
- return config_parse(unit, fn, NULL, sections, lookup, table, flags, userdata);
- }
-
if (!utf8_is_valid(l))
return log_syntax_invalid_utf8(unit, LOG_WARNING, filename, line, l);
ConfigItemLookup lookup,
const void *table,
ConfigParseFlags flags,
- void *userdata) {
+ void *userdata,
+ usec_t *ret_mtime) {
_cleanup_free_ char *section = NULL, *continuation = NULL;
_cleanup_fclose_ FILE *ours = NULL;
unsigned line = 0, section_line = 0;
bool section_ignored = false, bom_seen = false;
int r, fd;
+ usec_t mtime;
assert(filename);
assert(lookup);
}
fd = fileno(f);
- if (fd >= 0) /* stream might not have an fd, let's be careful hence */
- fd_warn_permissions(filename, fd);
+ if (fd >= 0) { /* stream might not have an fd, let's be careful hence */
+ struct stat st;
+
+ if (fstat(fd, &st) < 0)
+ return log_full_errno(FLAGS_SET(flags, CONFIG_PARSE_WARN) ? LOG_ERR : LOG_DEBUG, errno,
+ "Failed to fstat(%s): %m", filename);
+
+ (void) stat_warn_permissions(filename, &st);
+ mtime = timespec_load(&st.st_mtim);
+ }
for (;;) {
_cleanup_free_ char *buf = NULL;
return r;
}
if (r < 0) {
- if (CONFIG_PARSE_WARN)
+ if (FLAGS_SET(flags, CONFIG_PARSE_WARN))
log_error_errno(r, "%s:%u: Error while reading configuration file: %m", filename, line);
return r;
}
}
+ if (ret_mtime)
+ *ret_mtime = mtime;
+
return 0;
}
ConfigItemLookup lookup,
const void *table,
ConfigParseFlags flags,
- void *userdata) {
+ void *userdata,
+ usec_t *ret_mtime) {
+ usec_t mtime = 0;
char **fn;
int r;
if (conf_file) {
- r = config_parse(NULL, conf_file, NULL, sections, lookup, table, flags, userdata);
+ r = config_parse(NULL, conf_file, NULL, sections, lookup, table, flags, userdata, &mtime);
if (r < 0)
return r;
}
STRV_FOREACH(fn, files) {
- r = config_parse(NULL, *fn, NULL, sections, lookup, table, flags, userdata);
+ 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;
}
+ if (ret_mtime)
+ *ret_mtime = mtime;
+
return 0;
}
ConfigItemLookup lookup,
const void *table,
ConfigParseFlags flags,
- void *userdata) {
+ void *userdata,
+ usec_t *ret_mtime) {
_cleanup_strv_free_ char **files = NULL;
int r;
if (r < 0)
return r;
- return config_parse_many_files(conf_file, files, sections, lookup, table, flags, userdata);
+ return config_parse_many_files(conf_file, files, sections, lookup, table, flags, userdata, ret_mtime);
}
/* Parse each config file in the directories specified as strv. */
const void *table,
ConfigParseFlags flags,
void *userdata,
- char ***ret_dropins) {
+ usec_t *ret_mtime) {
_cleanup_strv_free_ char **dropin_dirs = NULL;
_cleanup_strv_free_ char **files = NULL;
if (r < 0)
return r;
- r = config_parse_many_files(conf_file, files, sections, lookup, table, flags, userdata);
- if (r < 0)
- return r;
-
- if (ret_dropins)
- *ret_dropins = TAKE_PTR(files);
-
- return 0;
+ return config_parse_many_files(conf_file, files, sections, lookup, table, flags, userdata, ret_mtime);
}
#define DEFINE_PARSER(type, vartype, conv_func) \
#include "alloc-util.h"
#include "log.h"
#include "macro.h"
+#include "time-util.h"
/* An abstract parser for simple, line based, shallow configuration files consisting of variable assignments only. */
typedef enum ConfigParseFlags {
CONFIG_PARSE_RELAXED = 1 << 0, /* Do not warn about unknown non-extension fields */
- CONFIG_PARSE_ALLOW_INCLUDE = 1 << 1, /* Allow the deprecated .include stanza */
- CONFIG_PARSE_WARN = 1 << 2, /* Emit non-debug messages */
+ CONFIG_PARSE_WARN = 1 << 1, /* Emit non-debug messages */
} ConfigParseFlags;
/* Argument list for parsers of specific configuration settings. */
const char *unit,
const char *filename,
FILE *f,
- const char *sections, /* nulstr */
+ const char *sections, /* nulstr */
ConfigItemLookup lookup,
const void *table,
ConfigParseFlags flags,
- void *userdata);
+ void *userdata,
+ usec_t *ret_mtime); /* possibly NULL */
int config_parse_many_nulstr(
const char *conf_file, /* possibly NULL */
ConfigItemLookup lookup,
const void *table,
ConfigParseFlags flags,
- void *userdata);
+ void *userdata,
+ usec_t *ret_mtime); /* possibly NULL */
int config_parse_many(
const char *conf_file, /* possibly NULL */
const void *table,
ConfigParseFlags flags,
void *userdata,
- char ***ret_dropins); /* possibly NULL */
+ usec_t *ret_mtime); /* possibly NULL */
CONFIG_PARSER_PROTOTYPE(config_parse_int);
CONFIG_PARSER_PROTOTYPE(config_parse_unsigned);
"-Target\0"
"-Timer\0",
config_item_table_lookup, items,
- CONFIG_PARSE_ALLOW_INCLUDE, info);
+ 0, info,
+ NULL);
if (r < 0)
return log_debug_errno(r, "Failed to parse %s: %m", info->name);
else
any = true;
+#if defined(__SNR_openat2)
+ /* The new openat2() system call can't be filtered sensibly, since it moves the flags parameter into
+ * an indirect structure. Let's block it entirely for now. That should be a reasonably OK thing to do
+ * for now, since openat2() is very new and code generally needs fallback logic anyway to be
+ * compatible with kernels that are not absolutely recent. */
+ r = seccomp_rule_add_exact(
+ seccomp,
+ SCMP_ACT_ERRNO(EPERM),
+ SCMP_SYS(openat2),
+ 0);
+ if (r < 0)
+ log_debug_errno(r, "Failed to add filter for openat2: %m");
+ else
+ any = true;
+#endif
+
r = seccomp_rule_add_exact(
seccomp,
SCMP_ACT_ERRNO(EPERM),
{}
};
- (void) config_parse_many_nulstr(PKGSYSCONFDIR "/sleep.conf",
- CONF_PATHS_NULSTR("systemd/sleep.conf.d"),
- "Sleep\0", config_item_table_lookup, items,
- CONFIG_PARSE_WARN, NULL);
+ (void) config_parse_many_nulstr(
+ PKGSYSCONFDIR "/sleep.conf",
+ CONF_PATHS_NULSTR("systemd/sleep.conf.d"),
+ "Sleep\0",
+ config_item_table_lookup, items,
+ CONFIG_PARSE_WARN,
+ NULL,
+ NULL);
/* use default values unless set */
sc->allow_suspend = allow_suspend != 0;
ConfigItemLookup lookup,
const void *table,
ConfigParseFlags flags,
- void *userdata)
+ void *userdata,
+ usec_t *ret_mtime)
*/
r = config_parse(NULL, name, f,
- "Section\0-NoWarnSection\0",
+ "Section\0"
+ "-NoWarnSection\0",
config_item_table_lookup, items,
- CONFIG_PARSE_WARN, NULL);
+ CONFIG_PARSE_WARN,
+ NULL,
+ NULL);
switch (i) {
case 0 ... 4:
assert(m);
- r = config_parse_many_nulstr(PKGSYSCONFDIR "/timesyncd.conf",
- CONF_PATHS_NULSTR("systemd/timesyncd.conf.d"),
- "Time\0",
- config_item_perf_lookup, timesyncd_gperf_lookup,
- CONFIG_PARSE_WARN, m);
+ r = config_parse_many_nulstr(
+ PKGSYSCONFDIR "/timesyncd.conf",
+ CONF_PATHS_NULSTR("systemd/timesyncd.conf.d"),
+ "Time\0",
+ config_item_perf_lookup, timesyncd_gperf_lookup,
+ CONFIG_PARSE_WARN,
+ m,
+ NULL);
if (r < 0)
return r;
r = config_parse(NULL, filename, NULL,
NULL,
config_item_table_lookup, items,
- CONFIG_PARSE_RELAXED|CONFIG_PARSE_WARN, NULL);
+ CONFIG_PARSE_RELAXED|CONFIG_PARSE_WARN,
+ NULL,
+ NULL);
if (r < 0)
return r;
r = config_parse(NULL, filename, file,
"Match\0Link\0",
config_item_perf_lookup, link_config_gperf_lookup,
- CONFIG_PARSE_WARN, link);
+ CONFIG_PARSE_WARN, link,
+ NULL);
if (r < 0)
return r;
LIST_FOREACH(links, link, ctx->links) {
if (net_match_config(link->match_mac, link->match_permanent_mac, link->match_path, link->match_driver,
link->match_type, link->match_name, link->match_property, NULL, NULL, NULL,
- iftype, device, NULL, &permanent_mac, NULL, NULL, 0, NULL, NULL)) {
+ device, NULL, &permanent_mac, NULL, iftype, NULL, NULL, 0, NULL, NULL)) {
if (link->match_name && !strv_contains(link->match_name, "*")) {
unsigned name_assign_type = NET_NAME_UNKNOWN;
r = config_parse(NULL, service->path, NULL,
"Desktop Entry\0",
xdg_config_item_table_lookup, items,
- CONFIG_PARSE_WARN, service);
+ CONFIG_PARSE_WARN, service,
+ NULL);
/* If parsing failed, only hide the file so it will still mask others. */
if (r < 0) {
log_warning_errno(r, "Failed to parse %s, ignoring it", service->path);
VendorClass=
AssignAcquiredDelegatedPrefixAddress=
SendVendorOption=
+RouteMetric=
[Route]
Destination=
Protocol=