summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--man/systemd.netdev.xml53
-rw-r--r--man/systemd.network.xml59
-rw-r--r--man/systemd.unit.xml118
-rw-r--r--src/basic/def.h2
-rw-r--r--src/core/main.c2
-rw-r--r--src/coredump/coredump.c2
-rw-r--r--src/journal-remote/journal-remote.c2
-rw-r--r--src/journal-remote/journal-upload.c2
-rw-r--r--src/journal/journald-server.c2
-rw-r--r--src/login/logind.c2
-rw-r--r--src/network/networkd-conf.c2
-rw-r--r--src/network/networkd-netdev.c12
-rw-r--r--src/network/networkd-network.c33
-rw-r--r--src/resolve/resolved-conf.c2
-rw-r--r--src/shared/conf-parser.c72
-rw-r--r--src/shared/conf-parser.h48
-rw-r--r--src/shared/sleep-config.c2
-rw-r--r--src/timesync/timesyncd-conf.c2
-rwxr-xr-xtest/networkd-test.py82
19 files changed, 301 insertions, 198 deletions
diff --git a/man/systemd.netdev.xml b/man/systemd.netdev.xml
index 78f0e25a6f..c8b5a057f8 100644
--- a/man/systemd.netdev.xml
+++ b/man/systemd.netdev.xml
@@ -58,31 +58,38 @@
<citerefentry><refentrytitle>systemd-networkd</refentrytitle><manvolnum>8</manvolnum></citerefentry>.
</para>
- <para>Virtual Network Device files must have the extension
- <filename>.netdev</filename>; other extensions are ignored.
- Virtual network devices are created as soon as networkd is
- started. If a netdev with the specified name already exists,
- networkd will use that as-is rather than create its own. Note that
- the settings of the pre-existing netdev will not be changed by
+ <para>The main Virtual Network Device file must have the extension <filename>.netdev</filename>;
+ other extensions are ignored. Virtual network devices are created as soon as networkd is
+ started. If a netdev with the specified name already exists, networkd will use that as-is rather
+ than create its own. Note that the settings of the pre-existing netdev will not be changed by
networkd.</para>
- <para>The <filename>.netdev</filename> files are read from the
- files located in the system network directory
- <filename>/usr/lib/systemd/network</filename>, the volatile
- runtime network directory
- <filename>/run/systemd/network</filename> and the local
- administration network directory
- <filename>/etc/systemd/network</filename>. All configuration files
- are collectively sorted and processed in lexical order, regardless
- of the directories in which they live. However, files with
- identical filenames replace each other. Files in
- <filename>/etc</filename> have the highest priority, files in
- <filename>/run</filename> take precedence over files with the same
- name in <filename>/usr/lib</filename>. This can be used to
- override a system-supplied configuration file with a local file if
- needed. As a special case, an empty file (file size 0) or symlink
- with the same name pointing to <filename>/dev/null</filename>
- disables the configuration file entirely (it is "masked").</para>
+ <para>The <filename>.netdev</filename> files are read from the files located in the system
+ network directory <filename>/usr/lib/systemd/network</filename>, the volatile runtime network
+ directory <filename>/run/systemd/network</filename> and the local administration network
+ directory <filename>/etc/systemd/network</filename>. All configuration files are collectively
+ sorted and processed in lexical order, regardless of the directories in which they live.
+ However, files with identical filenames replace each other. Files in <filename>/etc</filename>
+ have the highest priority, files in <filename>/run</filename> take precedence over files with
+ the same name in <filename>/usr/lib</filename>. This can be used to override a system-supplied
+ configuration file with a local file if needed. As a special case, an empty file (file size 0)
+ or symlink with the same name pointing to <filename>/dev/null</filename> disables the
+ configuration file entirely (it is "masked").</para>
+
+ <para>Along with the netdev file <filename>foo.netdev</filename>, a "drop-in" directory
+ <filename>foo.netdev.d/</filename> may exist. All files with the suffix <literal>.conf</literal>
+ from this directory will be parsed after the file itself is parsed. This is useful to alter or
+ add configuration settings, without having to modify the main configuration file. Each drop-in
+ file must have appropriate section headers.</para>
+
+ <para>In addition to <filename>/etc/systemd/network</filename>, drop-in <literal>.d</literal>
+ directories can be placed in <filename>/usr/lib/systemd/network</filename> or
+ <filename>/run/systemd/network</filename> directories. Drop-in files in
+ <filename>/etc</filename> take precedence over those in <filename>/run</filename> which in turn
+ take precedence over those in <filename>/usr/lib</filename>. Drop-in files under any of these
+ directories take precedence over the main netdev file wherever located. (Of course, since
+ <filename>/run</filename> is temporary and <filename>/usr/lib</filename> is for vendors, it is
+ unlikely drop-ins should be used in either of those places.)</para>
</refsect1>
<refsect1>
diff --git a/man/systemd.network.xml b/man/systemd.network.xml
index c332cd7bdc..eb7d441842 100644
--- a/man/systemd.network.xml
+++ b/man/systemd.network.xml
@@ -58,31 +58,40 @@
<citerefentry><refentrytitle>systemd-networkd</refentrytitle><manvolnum>8</manvolnum></citerefentry>.
</para>
- <para>Network files must have the extension
- <filename>.network</filename>; other extensions are ignored.
- Networks are applied to links whenever the links appear.</para>
-
- <para>The <filename>.network</filename> files are read from the
- files located in the system network directory
- <filename>/usr/lib/systemd/network</filename>, the volatile
- runtime network directory
- <filename>/run/systemd/network</filename> and the local
- administration network directory
- <filename>/etc/systemd/network</filename>. All configuration files
- are collectively sorted and processed in lexical order, regardless
- of the directories in which they live. However, files with
- identical filenames replace each other. Files in
- <filename>/etc</filename> have the highest priority, files in
- <filename>/run</filename> take precedence over files with the same
- name in <filename>/usr/lib</filename>. This can be used to
- override a system-supplied configuration file with a local file if
- needed. As a special case, an empty file (file size 0) or symlink
- with the same name pointing to <filename>/dev/null</filename>
- disables the configuration file entirely (it is "masked").</para>
-
- <para>Note that an interface without any static IPv6 addresses configured, and neither DHCPv6 nor IPv6LL enabled,
- shall be considered to have no IPv6 support. IPv6 will be automatically disabled for that interface by writing "1"
- to <filename>/proc/sys/net/ipv6/conf/<replaceable>ifname</replaceable>/disable_ipv6</filename>.
+ <para>The main network file must have the extension <filename>.network</filename>; other
+ extensions are ignored. Networks are applied to links whenever the links appear.</para>
+
+ <para>The <filename>.network</filename> files are read from the files located in the system
+ network directory <filename>/usr/lib/systemd/network</filename>, the volatile runtime network
+ directory <filename>/run/systemd/network</filename> and the local administration network
+ directory <filename>/etc/systemd/network</filename>. All configuration files are collectively
+ sorted and processed in lexical order, regardless of the directories in which they live.
+ However, files with identical filenames replace each other. Files in <filename>/etc</filename>
+ have the highest priority, files in <filename>/run</filename> take precedence over files with
+ the same name in <filename>/usr/lib</filename>. This can be used to override a system-supplied
+ configuration file with a local file if needed. As a special case, an empty file (file size 0)
+ or symlink with the same name pointing to <filename>/dev/null</filename> disables the
+ configuration file entirely (it is "masked").</para>
+
+ <para>Along with the network file <filename>foo.network</filename>, a "drop-in" directory
+ <filename>foo.network.d/</filename> may exist. All files with the suffix
+ <literal>.conf</literal> from this directory will be parsed after the file itself is
+ parsed. This is useful to alter or add configuration settings, without having to modify the main
+ configuration file. Each drop-in file must have appropriate section headers.</para>
+
+ <para>In addition to <filename>/etc/systemd/network</filename>, drop-in <literal>.d</literal>
+ directories can be placed in <filename>/usr/lib/systemd/network</filename> or
+ <filename>/run/systemd/network</filename> directories. Drop-in files in
+ <filename>/etc</filename> take precedence over those in <filename>/run</filename> which in turn
+ take precedence over those in <filename>/usr/lib</filename>. Drop-in files under any of these
+ directories take precedence over the main netdev file wherever located. (Of course, since
+ <filename>/run</filename> is temporary and <filename>/usr/lib</filename> is for vendors, it is
+ unlikely drop-ins should be used in either of those places.)</para>
+
+ <para>Note that an interface without any static IPv6 addresses configured, and neither DHCPv6
+ nor IPv6LL enabled, shall be considered to have no IPv6 support. IPv6 will be automatically
+ disabled for that interface by writing "1" to
+ <filename>/proc/sys/net/ipv6/conf/<replaceable>ifname</replaceable>/disable_ipv6</filename>.
</para>
</refsect1>
diff --git a/man/systemd.unit.xml b/man/systemd.unit.xml
index f818e772a9..9778283fec 100644
--- a/man/systemd.unit.xml
+++ b/man/systemd.unit.xml
@@ -144,71 +144,71 @@
<option>false</option> and <option>off</option> are
equivalent.</para>
- <para>Time span values encoded in unit files can be written in various formats. A stand-alone number specifies a
- time in seconds. If suffixed with a time unit, the unit is honored. A concatenation of multiple values with units
- is supported, in which case the values are added up. Example: <literal>50</literal> refers to 50 seconds;
- <literal>2min 200ms</literal> refers to 2 minutes and 200 milliseconds, i.e. 120200 ms. The following time units
- are understood: <literal>s</literal>, <literal>min</literal>, <literal>h</literal>, <literal>d</literal>,
+ <para>Time span values encoded in unit files can be written in various formats. A stand-alone
+ number specifies a time in seconds. If suffixed with a time unit, the unit is honored. A
+ concatenation of multiple values with units is supported, in which case the values are added
+ up. Example: <literal>50</literal> refers to 50 seconds; <literal>2min 200ms</literal> refers to
+ 2 minutes and 200 milliseconds, i.e. 120200 ms. The following time units are understood:
+ <literal>s</literal>, <literal>min</literal>, <literal>h</literal>, <literal>d</literal>,
<literal>w</literal>, <literal>ms</literal>, <literal>us</literal>. For details see
<citerefentry><refentrytitle>systemd.time</refentrytitle><manvolnum>7</manvolnum></citerefentry>.</para>
- <para>Empty lines and lines starting with <literal>#</literal> or <literal>;</literal> are ignored. This may be
- used for commenting. Lines ending in a backslash are concatenated with the following line while reading and the
- backslash is replaced by a space character. This may be used to wrap long lines.</para>
-
- <para>Units can be aliased (have an alternative name), by creating a symlink from the new name to the existing name
- in one of the unit search paths. For example, <filename>systemd-networkd.service</filename> has the alias
- <filename>dbus-org.freedesktop.network1.service</filename>, created during installation as the symlink
- <filename>/usr/lib/systemd/system/dbus-org.freedesktop.network1.service</filename>. In addition, unit files may
- specify aliases through the <varname>Alias=</varname> directive in the [Install] section; those aliases are only
- effective when the unit is enabled. When the unit is enabled, symlinks will be created for those names, and removed
- when the unit is disabled. For example, <filename>reboot.target</filename> specifies
- <varname>Alias=ctrl-alt-del.target</varname>, so when enabled it will be invoked whenever CTRL+ALT+DEL is
- pressed. Alias names may be used in commands like <command>enable</command>, <command>disable</command>,
- <command>start</command>, <command>stop</command>, <command>status</command>, …, and in unit dependency directives
- <varname>Wants=</varname>, <varname>Requires=</varname>, <varname>Before=</varname>, <varname>After=</varname>, …,
- with the limitation that aliases specified through <varname>Alias=</varname> are only effective when the unit is
- enabled. Aliases cannot be used with the <command>preset</command> command.</para>
-
- <para>Along with a unit file <filename>foo.service</filename>, the
- directory <filename>foo.service.wants/</filename> may exist. All
- unit files symlinked from such a directory are implicitly added as
- dependencies of type <varname>Wants=</varname> to the unit. This
- is useful to hook units into the start-up of other units, without
- having to modify their unit files. For details about the semantics
- of <varname>Wants=</varname>, see below. The preferred way to
- create symlinks in the <filename>.wants/</filename> directory of a
- unit file is with the <command>enable</command> command of the
+ <para>Empty lines and lines starting with <literal>#</literal> or <literal>;</literal> are
+ ignored. This may be used for commenting. Lines ending in a backslash are concatenated with the
+ following line while reading and the backslash is replaced by a space character. This may be
+ used to wrap long lines.</para>
+
+ <para>Units can be aliased (have an alternative name), by creating a symlink from the new name
+ to the existing name in one of the unit search paths. For example,
+ <filename>systemd-networkd.service</filename> has the alias
+ <filename>dbus-org.freedesktop.network1.service</filename>, created during installation as the
+ symlink <filename>/usr/lib/systemd/system/dbus-org.freedesktop.network1.service</filename>. In
+ addition, unit files may specify aliases through the <varname>Alias=</varname> directive in the
+ [Install] section; those aliases are only effective when the unit is enabled. When the unit is
+ enabled, symlinks will be created for those names, and removed when the unit is disabled. For
+ example, <filename>reboot.target</filename> specifies
+ <varname>Alias=ctrl-alt-del.target</varname>, so when enabled it will be invoked whenever
+ CTRL+ALT+DEL is pressed. Alias names may be used in commands like <command>enable</command>,
+ <command>disable</command>, <command>start</command>, <command>stop</command>,
+ <command>status</command>, …, and in unit dependency directives <varname>Wants=</varname>,
+ <varname>Requires=</varname>, <varname>Before=</varname>, <varname>After=</varname>, …, with the
+ limitation that aliases specified through <varname>Alias=</varname> are only effective when the
+ unit is enabled. Aliases cannot be used with the <command>preset</command> command.</para>
+
+ <para>Along with a unit file <filename>foo.service</filename>, the directory
+ <filename>foo.service.wants/</filename> may exist. All unit files symlinked from such a
+ directory are implicitly added as dependencies of type <varname>Wants=</varname> to the unit.
+ This is useful to hook units into the start-up of other units, without having to modify their
+ unit files. For details about the semantics of <varname>Wants=</varname>, see below. The
+ preferred way to create symlinks in the <filename>.wants/</filename> directory of a unit file is
+ with the <command>enable</command> command of the
<citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>
- tool which reads information from the [Install] section of unit
- files (see below). A similar functionality exists for
- <varname>Requires=</varname> type dependencies as well, the
- directory suffix is <filename>.requires/</filename> in this
- case.</para>
+ tool which reads information from the [Install] section of unit files (see below). A similar
+ functionality exists for <varname>Requires=</varname> type dependencies as well, the directory
+ suffix is <filename>.requires/</filename> in this case.</para>
<para>Along with a unit file <filename>foo.service</filename>, a "drop-in" directory
- <filename>foo.service.d/</filename> may exist. All files with the suffix <literal>.conf</literal> from this
- directory will be parsed after the file itself is parsed. This is useful to alter or add configuration settings for
- a unit, without having to modify unit files. Each drop-in file must have appropriate section headers. Note that for
- instantiated units, this logic will first look for the instance <literal>.d/</literal> subdirectory and read its
- <literal>.conf</literal> files, followed by the template <literal>.d/</literal> subdirectory and the
- <literal>.conf</literal> files there. Also note that settings from the <literal>[Install]</literal> section are not
- honoured in drop-in unit files, and have no effect.</para>
-
- <para>In addition to <filename>/etc/systemd/system</filename>,
- the drop-in <literal>.conf</literal> files for system services
- can be placed in <filename>/usr/lib/systemd/system</filename> or
- <filename>/run/systemd/system</filename> directories. Drop-in
- files in <filename>/etc</filename> take precedence over those in
- <filename>/run</filename> which in turn take precedence over
- those in <filename>/usr/lib</filename>. Drop-in files under any of
- these directories take precedence over unit files wherever located.
- (Of course, since <filename>/run</filename> is temporary and
- <filename>/usr/lib</filename> is for vendors, it is unlikely
- drop-ins should be used in either of those places.)</para>
- <!-- Note that we do not document .include here, as we
- consider it mostly obsolete, and want people to
- use .d/ drop-ins instead. -->
+ <filename>foo.service.d/</filename> may exist. All files with the suffix
+ <literal>.conf</literal> from this directory will be parsed after the file itself is
+ parsed. This is useful to alter or add configuration settings for a unit, without having to
+ modify unit files. Each drop-in file must have appropriate section headers. Note that for
+ instantiated units, this logic will first look for the instance <literal>.d/</literal>
+ subdirectory and read its <literal>.conf</literal> files, followed by the template
+ <literal>.d/</literal> subdirectory and the <literal>.conf</literal> files there. Also note that
+ settings from the <literal>[Install]</literal> section are not honoured in drop-in unit files,
+ and have no effect.</para>
+
+ <para>In addition to <filename>/etc/systemd/system</filename>, the drop-in <literal>.d</literal>
+ directories for system services can be placed in <filename>/usr/lib/systemd/system</filename> or
+ <filename>/run/systemd/system</filename> directories. Drop-in files in <filename>/etc</filename>
+ take precedence over those in <filename>/run</filename> which in turn take precedence over those
+ in <filename>/usr/lib</filename>. Drop-in files under any of these directories take precedence
+ over unit files wherever located. (Of course, since <filename>/run</filename> is temporary and
+ <filename>/usr/lib</filename> is for vendors, it is unlikely drop-ins should be used in either
+ of those places.)</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>Some unit names reflect paths existing in the file system
namespace. Example: a device unit
diff --git a/src/basic/def.h b/src/basic/def.h
index 1a7a0f4928..2266eff650 100644
--- a/src/basic/def.h
+++ b/src/basic/def.h
@@ -79,7 +79,7 @@
#endif
/* Return a nulstr for a standard cascade of configuration paths,
- * suitable to pass to conf_files_list_nulstr() or config_parse_many()
+ * suitable to pass to conf_files_list_nulstr() or config_parse_many_nulstr()
* to implement drop-in directories for extending configuration
* files. */
#define CONF_PATHS_NULSTR(n) \
diff --git a/src/core/main.c b/src/core/main.c
index 7d8322ebd8..803307c9d5 100644
--- a/src/core/main.c
+++ b/src/core/main.c
@@ -715,7 +715,7 @@ static int parse_config_file(void) {
CONF_PATHS_NULSTR("systemd/system.conf.d") :
CONF_PATHS_NULSTR("systemd/user.conf.d");
- config_parse_many(fn, conf_dirs_nulstr, "Manager\0", config_item_table_lookup, items, false, NULL);
+ config_parse_many_nulstr(fn, conf_dirs_nulstr, "Manager\0", config_item_table_lookup, items, false, NULL);
/* Traditionally "0" was used to turn off the default unit timeouts. Fix this up so that we used USEC_INFINITY
* like everywhere else. */
diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c
index be724aed4e..9dea10b3e1 100644
--- a/src/coredump/coredump.c
+++ b/src/coredump/coredump.c
@@ -128,7 +128,7 @@ static int parse_config(void) {
{}
};
- return config_parse_many(PKGSYSCONFDIR "/coredump.conf",
+ return config_parse_many_nulstr(PKGSYSCONFDIR "/coredump.conf",
CONF_PATHS_NULSTR("systemd/coredump.conf.d"),
"Coredump\0",
config_item_table_lookup, items,
diff --git a/src/journal-remote/journal-remote.c b/src/journal-remote/journal-remote.c
index aebc4cafb4..a9009cfefe 100644
--- a/src/journal-remote/journal-remote.c
+++ b/src/journal-remote/journal-remote.c
@@ -1194,7 +1194,7 @@ static int parse_config(void) {
{ "Remote", "TrustedCertificateFile", config_parse_path, 0, &arg_trust },
{}};
- return config_parse_many(PKGSYSCONFDIR "/journal-remote.conf",
+ return config_parse_many_nulstr(PKGSYSCONFDIR "/journal-remote.conf",
CONF_PATHS_NULSTR("systemd/journal-remote.conf.d"),
"Remote\0", config_item_table_lookup, items,
false, NULL);
diff --git a/src/journal-remote/journal-upload.c b/src/journal-remote/journal-upload.c
index 4647cfdeb3..c0f967ab94 100644
--- a/src/journal-remote/journal-upload.c
+++ b/src/journal-remote/journal-upload.c
@@ -542,7 +542,7 @@ static int parse_config(void) {
{ "Upload", "TrustedCertificateFile", config_parse_path, 0, &arg_trust },
{}};
- return config_parse_many(PKGSYSCONFDIR "/journal-upload.conf",
+ return config_parse_many_nulstr(PKGSYSCONFDIR "/journal-upload.conf",
CONF_PATHS_NULSTR("systemd/journal-upload.conf.d"),
"Upload\0", config_item_table_lookup, items,
false, NULL);
diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c
index 3507910919..cc352dbae2 100644
--- a/src/journal/journald-server.c
+++ b/src/journal/journald-server.c
@@ -1474,7 +1474,7 @@ static int server_parse_proc_cmdline(Server *s) {
static int server_parse_config_file(Server *s) {
assert(s);
- return config_parse_many(PKGSYSCONFDIR "/journald.conf",
+ return config_parse_many_nulstr(PKGSYSCONFDIR "/journald.conf",
CONF_PATHS_NULSTR("systemd/journald.conf.d"),
"Journal\0",
config_item_perf_lookup, journald_gperf_lookup,
diff --git a/src/login/logind.c b/src/login/logind.c
index bbbf4aef57..a9a06f5e28 100644
--- a/src/login/logind.c
+++ b/src/login/logind.c
@@ -1002,7 +1002,7 @@ static int manager_dispatch_idle_action(sd_event_source *s, uint64_t t, void *us
static int manager_parse_config_file(Manager *m) {
assert(m);
- return config_parse_many(PKGSYSCONFDIR "/logind.conf",
+ return config_parse_many_nulstr(PKGSYSCONFDIR "/logind.conf",
CONF_PATHS_NULSTR("systemd/logind.conf.d"),
"Login\0",
config_item_perf_lookup, logind_gperf_lookup,
diff --git a/src/network/networkd-conf.c b/src/network/networkd-conf.c
index c03e2b2ebf..49bb8c18f6 100644
--- a/src/network/networkd-conf.c
+++ b/src/network/networkd-conf.c
@@ -29,7 +29,7 @@
int manager_parse_config_file(Manager *m) {
assert(m);
- return config_parse_many(PKGSYSCONFDIR "/networkd.conf",
+ return config_parse_many_nulstr(PKGSYSCONFDIR "/networkd.conf",
CONF_PATHS_NULSTR("systemd/networkd.conf.d"),
"DHCP\0",
config_item_perf_lookup, networkd_gperf_lookup,
diff --git a/src/network/networkd-netdev.c b/src/network/networkd-netdev.c
index 897de9bde5..a210ba1242 100644
--- a/src/network/networkd-netdev.c
+++ b/src/network/networkd-netdev.c
@@ -576,6 +576,7 @@ static int netdev_load_one(Manager *manager, const char *filename) {
_cleanup_netdev_unref_ NetDev *netdev = NULL;
_cleanup_free_ NetDev *netdev_raw = NULL;
_cleanup_fclose_ FILE *file = NULL;
+ const char *dropin_dirname;
int r;
assert(manager);
@@ -599,11 +600,12 @@ static int netdev_load_one(Manager *manager, const char *filename) {
return log_oom();
netdev_raw->kind = _NETDEV_KIND_INVALID;
+ dropin_dirname = strjoina(basename(filename), ".d");
- r = config_parse(NULL, filename, file,
- "Match\0NetDev\0",
- config_item_perf_lookup, network_netdev_gperf_lookup,
- true, false, true, netdev_raw);
+ r = config_parse_many(filename, network_dirs, dropin_dirname,
+ "Match\0NetDev\0",
+ config_item_perf_lookup, network_netdev_gperf_lookup,
+ true, netdev_raw);
if (r < 0)
return r;
@@ -619,7 +621,7 @@ static int netdev_load_one(Manager *manager, const char *filename) {
return 0;
if (netdev_raw->kind == _NETDEV_KIND_INVALID) {
- log_warning("NetDev with invalid Kind configured in %s. Ignoring", filename);
+ log_warning("NetDev has no Kind configured in %s. Ignoring", filename);
return 0;
}
diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c
index 91e51e9124..313abca762 100644
--- a/src/network/networkd-network.c
+++ b/src/network/networkd-network.c
@@ -40,6 +40,7 @@ static int network_load_one(Manager *manager, const char *filename) {
_cleanup_network_free_ Network *network = NULL;
_cleanup_fclose_ FILE *file = NULL;
char *d;
+ const char *dropin_dirname;
Route *route;
Address *address;
int r;
@@ -137,21 +138,23 @@ static int network_load_one(Manager *manager, const char *filename) {
network->arp = -1;
network->ipv6_accept_ra_use_dns = true;
- r = config_parse(NULL, filename, file,
- "Match\0"
- "Link\0"
- "Network\0"
- "Address\0"
- "Route\0"
- "DHCP\0"
- "DHCPv4\0" /* compat */
- "DHCPServer\0"
- "IPv6AcceptRA\0"
- "Bridge\0"
- "BridgeFDB\0"
- "BridgeVLAN\0",
- config_item_perf_lookup, network_network_gperf_lookup,
- false, false, true, network);
+ dropin_dirname = strjoina(network->name, ".network.d");
+
+ r = config_parse_many(filename, network_dirs, dropin_dirname,
+ "Match\0"
+ "Link\0"
+ "Network\0"
+ "Address\0"
+ "Route\0"
+ "DHCP\0"
+ "DHCPv4\0" /* compat */
+ "DHCPServer\0"
+ "IPv6AcceptRA\0"
+ "Bridge\0"
+ "BridgeFDB\0"
+ "BridgeVLAN\0",
+ config_item_perf_lookup, network_network_gperf_lookup,
+ false, network);
if (r < 0)
return r;
diff --git a/src/resolve/resolved-conf.c b/src/resolve/resolved-conf.c
index dd233e7c4a..83f7596ac8 100644
--- a/src/resolve/resolved-conf.c
+++ b/src/resolve/resolved-conf.c
@@ -221,7 +221,7 @@ int manager_parse_config_file(Manager *m) {
assert(m);
- r = config_parse_many(PKGSYSCONFDIR "/resolved.conf",
+ r = config_parse_many_nulstr(PKGSYSCONFDIR "/resolved.conf",
CONF_PATHS_NULSTR("systemd/resolved.conf.d"),
"Resolve\0",
config_item_perf_lookup, resolved_gperf_lookup,
diff --git a/src/shared/conf-parser.c b/src/shared/conf-parser.c
index f31d219418..2ec0155b71 100644
--- a/src/shared/conf-parser.c
+++ b/src/shared/conf-parser.c
@@ -396,22 +396,18 @@ int config_parse(const char *unit,
return 0;
}
-/* Parse each config file in the specified directories. */
-int config_parse_many(const char *conf_file,
- const char *conf_file_dirs,
- const char *sections,
- ConfigItemLookup lookup,
- const void *table,
- bool relaxed,
- void *userdata) {
- _cleanup_strv_free_ char **files = NULL;
+static int config_parse_many_files(
+ const char *conf_file,
+ char **files,
+ const char *sections,
+ ConfigItemLookup lookup,
+ const void *table,
+ bool relaxed,
+ void *userdata) {
+
char **fn;
int r;
- r = conf_files_list_nulstr(&files, ".conf", NULL, conf_file_dirs);
- if (r < 0)
- return r;
-
if (conf_file) {
r = config_parse(NULL, conf_file, NULL, sections, lookup, table, relaxed, false, true, userdata);
if (r < 0)
@@ -427,6 +423,56 @@ int config_parse_many(const char *conf_file,
return 0;
}
+/* Parse each config file in the directories specified as nulstr. */
+int config_parse_many_nulstr(
+ const char *conf_file,
+ const char *conf_file_dirs,
+ const char *sections,
+ ConfigItemLookup lookup,
+ const void *table,
+ bool relaxed,
+ void *userdata) {
+
+ _cleanup_strv_free_ char **files = NULL;
+ int r;
+
+ r = conf_files_list_nulstr(&files, ".conf", NULL, conf_file_dirs);
+ if (r < 0)
+ return r;
+
+ return config_parse_many_files(conf_file, files,
+ sections, lookup, table, relaxed, userdata);
+}
+
+/* Parse each config file in the directories specified as strv. */
+int config_parse_many(
+ const char *conf_file,
+ const char* const* conf_file_dirs,
+ const char *dropin_dirname,
+ const char *sections,
+ ConfigItemLookup lookup,
+ const void *table,
+ bool relaxed,
+ void *userdata) {
+
+ _cleanup_strv_free_ char **dropin_dirs = NULL;
+ _cleanup_strv_free_ char **files = NULL;
+ const char *suffix;
+ int r;
+
+ suffix = strjoina("/", dropin_dirname);
+ r = strv_extend_strv_concat(&dropin_dirs, (char**) conf_file_dirs, suffix);
+ if (r < 0)
+ return r;
+
+ r = conf_files_list_strv(&files, ".conf", NULL, (const char* const*) dropin_dirs);
+ if (r < 0)
+ return r;
+
+ return config_parse_many_files(conf_file, files,
+ sections, lookup, table, relaxed, userdata);
+}
+
#define DEFINE_PARSER(type, vartype, conv_func) \
int config_parse_##type( \
const char *unit, \
diff --git a/src/shared/conf-parser.h b/src/shared/conf-parser.h
index 3298dc0cea..26ff3df16f 100644
--- a/src/shared/conf-parser.h
+++ b/src/shared/conf-parser.h
@@ -84,24 +84,36 @@ int config_item_table_lookup(const void *table, const char *section, const char
* ConfigPerfItem tables */
int config_item_perf_lookup(const void *table, const char *section, const char *lvalue, ConfigParserCallback *func, int *ltype, void **data, void *userdata);
-int config_parse(const char *unit,
- const char *filename,
- FILE *f,
- const char *sections, /* nulstr */
- ConfigItemLookup lookup,
- const void *table,
- bool relaxed,
- bool allow_include,
- bool warn,
- void *userdata);
-
-int config_parse_many(const char *conf_file, /* possibly NULL */
- const char *conf_file_dirs, /* nulstr */
- const char *sections, /* nulstr */
- ConfigItemLookup lookup,
- const void *table,
- bool relaxed,
- void *userdata);
+int config_parse(
+ const char *unit,
+ const char *filename,
+ FILE *f,
+ const char *sections, /* nulstr */
+ ConfigItemLookup lookup,
+ const void *table,
+ bool relaxed,
+ bool allow_include,
+ bool warn,
+ void *userdata);
+
+int config_parse_many_nulstr(
+ const char *conf_file, /* possibly NULL */
+ const char *conf_file_dirs, /* nulstr */
+ const char *sections, /* nulstr */
+ ConfigItemLookup lookup,
+ const void *table,
+ bool relaxed,
+ void *userdata);
+
+int config_parse_many(
+ const char *conf_file, /* possibly NULL */
+ const char* const* conf_file_dirs,
+ const char *dropin_dirname,
+ const char *sections, /* nulstr */
+ ConfigItemLookup lookup,
+ const void *table,
+ bool relaxed,
+ void *userdata);
/* Generic parsers */
int config_parse_int(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);
diff --git a/src/shared/sleep-config.c b/src/shared/sleep-config.c
index f00624d0f2..ed31a80c8d 100644
--- a/src/shared/sleep-config.c
+++ b/src/shared/sleep-config.c
@@ -58,7 +58,7 @@ int parse_sleep_config(const char *verb, char ***_modes, char ***_states) {
{}
};
- config_parse_many(PKGSYSCONFDIR "/sleep.conf",
+ config_parse_many_nulstr(PKGSYSCONFDIR "/sleep.conf",
CONF_PATHS_NULSTR("systemd/sleep.conf.d"),
"Sleep\0", config_item_table_lookup, items,
false, NULL);
diff --git a/src/timesync/timesyncd-conf.c b/src/timesync/timesyncd-conf.c
index 20c64a3354..bf25b112e1 100644
--- a/src/timesync/timesyncd-conf.c
+++ b/src/timesync/timesyncd-conf.c
@@ -98,7 +98,7 @@ int config_parse_servers(
int manager_parse_config_file(Manager *m) {
assert(m);
- return config_parse_many(PKGSYSCONFDIR "/timesyncd.conf",
+ return config_parse_many_nulstr(PKGSYSCONFDIR "/timesyncd.conf",
CONF_PATHS_NULSTR("systemd/timesyncd.conf.d"),
"Time\0",
config_item_perf_lookup, timesyncd_gperf_lookup,
diff --git a/test/networkd-test.py b/test/networkd-test.py
index bfa1bf3580..baa1dc2a47 100755
--- a/test/networkd-test.py
+++ b/test/networkd-test.py
@@ -54,7 +54,6 @@ class ClientTestBase:
self.workdir_obj = tempfile.TemporaryDirectory()
self.workdir = self.workdir_obj.name
self.config = '/run/systemd/network/test_eth42.network'
- os.makedirs(os.path.dirname(self.config), exist_ok=True)
# avoid "Failed to open /dev/tty" errors in containers
os.environ['SYSTEMD_LOG_TARGET'] = 'journal'
@@ -77,10 +76,14 @@ class ClientTestBase:
def tearDown(self):
self.shutdown_iface()
- if os.path.exists(self.config):
- os.unlink(self.config)
subprocess.call(['systemctl', 'stop', 'systemd-networkd'])
+ def writeConfig(self, fname, contents):
+ os.makedirs(os.path.dirname(fname), exist_ok=True)
+ with open(fname, 'w') as f:
+ f.write(contents)
+ self.addCleanup(os.remove, fname)
+
def show_journal(self, unit):
'''Show journal of given unit since start of the test'''
@@ -107,8 +110,8 @@ class ClientTestBase:
def do_test(self, coldplug=True, ipv6=False, extra_opts='',
online_timeout=10, dhcp_mode='yes'):
subprocess.check_call(['systemctl', 'start', 'systemd-resolved'])
- with open(self.config, 'w') as f:
- f.write('''[Match]
+ self.writeConfig(self.config, '''\
+[Match]
Name=%s
[Network]
DHCP=%s
@@ -225,20 +228,18 @@ DHCP=%s
self.do_test(coldplug=False, ipv6=True)
def test_route_only_dns(self):
- with open('/run/systemd/network/myvpn.netdev', 'w') as f:
- f.write('''[NetDev]
+ self.writeConfig('/run/systemd/network/myvpn.netdev', '''\
+[NetDev]
Name=dummy0
Kind=dummy
MACAddress=12:34:56:78:9a:bc''')
- with open('/run/systemd/network/myvpn.network', 'w') as f:
- f.write('''[Match]
+ self.writeConfig('/run/systemd/network/myvpn.network', '''\
+[Match]
Name=dummy0
[Network]
Address=192.168.42.100
DNS=192.168.42.1
Domains= ~company''')
- self.addCleanup(os.remove, '/run/systemd/network/myvpn.netdev')
- self.addCleanup(os.remove, '/run/systemd/network/myvpn.network')
self.do_test(coldplug=True, ipv6=False,
extra_opts='IPv6AcceptRouterAdvertisements=False')
@@ -320,7 +321,8 @@ class NetworkdClientTest(ClientTestBase, unittest.TestCase):
(fd, script) = tempfile.mkstemp(prefix='networkd-router.sh')
self.addCleanup(os.remove, script)
with os.fdopen(fd, 'w+') as f:
- f.write('''#!/bin/sh -eu
+ f.write('''\
+#!/bin/sh -eu
mkdir -p /run/systemd/network
mkdir -p /run/systemd/netif
mount -t tmpfs none /run/systemd/network
@@ -398,20 +400,18 @@ exec $(systemctl cat systemd-networkd.service | sed -n '/^ExecStart=/ { s/^.*=//
# we don't use this interface for this test
self.if_router = None
- with open('/run/systemd/network/test.netdev', 'w') as f:
- f.write('''[NetDev]
+ self.writeConfig('/run/systemd/network/test.netdev', '''\
+[NetDev]
Name=dummy0
Kind=dummy
MACAddress=12:34:56:78:9a:bc''')
- with open('/run/systemd/network/test.network', 'w') as f:
- f.write('''[Match]
+ self.writeConfig('/run/systemd/network/test.network', '''\
+[Match]
Name=dummy0
[Network]
Address=192.168.42.100
DNS=192.168.42.1
Domains= one two three four five six seven eight nine ten''')
- self.addCleanup(os.remove, '/run/systemd/network/test.netdev')
- self.addCleanup(os.remove, '/run/systemd/network/test.network')
subprocess.check_call(['systemctl', 'start', 'systemd-networkd'])
@@ -432,23 +432,18 @@ Domains= one two three four five six seven eight nine ten''')
name_prefix = 'a' * 60
- with open('/run/systemd/network/test.netdev', 'w') as f:
- f.write('''[NetDev]
+ self.writeConfig('/run/systemd/network/test.netdev', '''\
+[NetDev]
Name=dummy0
Kind=dummy
MACAddress=12:34:56:78:9a:bc''')
- with open('/run/systemd/network/test.network', 'w') as f:
- f.write('''[Match]
+ self.writeConfig('/run/systemd/network/test.network', '''\
+[Match]
Name=dummy0
[Network]
Address=192.168.42.100
DNS=192.168.42.1
-Domains=''')
- for i in range(5):
- f.write('%s%i ' % (name_prefix, i))
-
- self.addCleanup(os.remove, '/run/systemd/network/test.netdev')
- self.addCleanup(os.remove, '/run/systemd/network/test.network')
+Domains={p}0 {p}1 {p}2 {p}3 {p}4'''.format(p=name_prefix))
subprocess.check_call(['systemctl', 'start', 'systemd-networkd'])
@@ -458,9 +453,38 @@ Domains=''')
if ' one' in contents:
break
time.sleep(0.1)
- self.assertRegex(contents, 'search .*%(p)s0 %(p)s1 %(p)s2' % {'p': name_prefix})
+ self.assertRegex(contents, 'search .*{p}0 {p}1 {p}2'.format(p=name_prefix))
self.assertIn('# Total length of all search domains is too long, remaining ones ignored.', contents)
+ def test_dropin(self):
+ # we don't use this interface for this test
+ self.if_router = None
+
+ self.writeConfig('/run/systemd/network/test.netdev', '''\
+[NetDev]
+Name=dummy0
+Kind=dummy
+MACAddress=12:34:56:78:9a:bc''')
+ self.writeConfig('/run/systemd/network/test.network', '''\
+[Match]
+Name=dummy0
+[Network]
+Address=192.168.42.100
+DNS=192.168.42.1''')
+ self.writeConfig('/run/systemd/network/test.network.d/dns.conf', '''\
+[Network]
+DNS=127.0.0.1''')
+
+ subprocess.check_call(['systemctl', 'start', 'systemd-networkd'])
+
+ for timeout in range(50):
+ with open(RESOLV_CONF) as f:
+ contents = f.read()
+ if ' 127.0.0.1' in contents:
+ break
+ time.sleep(0.1)
+ self.assertIn('nameserver 192.168.42.1\n', contents)
+ self.assertIn('nameserver 127.0.0.1\n', contents)
if __name__ == '__main__':
unittest.main(testRunner=unittest.TextTestRunner(stream=sys.stdout,