Merge pull request #4123 from keszybz/network-file-dropins

Network file dropins
This commit is contained in:
Martin Pitt 2016-09-17 10:00:19 +02:00 committed by GitHub
commit 6ac288a990
19 changed files with 295 additions and 192 deletions

View File

@ -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>

View File

@ -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 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>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>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>

View File

@ -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>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>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>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>
<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. -->
<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

View File

@ -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) \

View File

@ -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. */

View File

@ -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,

View File

@ -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);

View File

@ -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);

View File

@ -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,

View File

@ -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,

View File

@ -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,

View File

@ -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;
}

View File

@ -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;

View File

@ -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,

View File

@ -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, \

View File

@ -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(
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_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);

View File

@ -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);

View File

@ -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,

View File

@ -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,