diff options
-rw-r--r-- | man/systemd.netdev.xml | 53 | ||||
-rw-r--r-- | man/systemd.network.xml | 59 | ||||
-rw-r--r-- | man/systemd.unit.xml | 118 | ||||
-rw-r--r-- | src/basic/def.h | 2 | ||||
-rw-r--r-- | src/core/main.c | 2 | ||||
-rw-r--r-- | src/coredump/coredump.c | 2 | ||||
-rw-r--r-- | src/journal-remote/journal-remote.c | 2 | ||||
-rw-r--r-- | src/journal-remote/journal-upload.c | 2 | ||||
-rw-r--r-- | src/journal/journald-server.c | 2 | ||||
-rw-r--r-- | src/login/logind.c | 2 | ||||
-rw-r--r-- | src/network/networkd-conf.c | 2 | ||||
-rw-r--r-- | src/network/networkd-netdev.c | 12 | ||||
-rw-r--r-- | src/network/networkd-network.c | 33 | ||||
-rw-r--r-- | src/resolve/resolved-conf.c | 2 | ||||
-rw-r--r-- | src/shared/conf-parser.c | 72 | ||||
-rw-r--r-- | src/shared/conf-parser.h | 48 | ||||
-rw-r--r-- | src/shared/sleep-config.c | 2 | ||||
-rw-r--r-- | src/timesync/timesyncd-conf.c | 2 | ||||
-rwxr-xr-x | test/networkd-test.py | 82 |
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, |