summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>2018-02-09 17:08:23 +0100
committerGitHub <noreply@github.com>2018-02-09 17:08:23 +0100
commit91761b1846a210323a83e2030ad88a9be5294ce2 (patch)
treea19cb07e26d2b09a29c9be3edaefbb3b1aff5bb9
parent73969ab61c39357e6892747e43307fbf07cafbed (diff)
parent230cc99a0f84bc0a5d9d974f665a81060b264a70 (diff)
downloadsystemd-91761b1846a210323a83e2030ad88a9be5294ce2.tar.gz
Merge pull request #8134 from keszybz/unit-load-paths
Various fixes to unit load paths, and systemd-analyze load-paths verb to list them
-rw-r--r--man/systemd-analyze.xml30
-rw-r--r--man/systemd.generator.xml349
-rw-r--r--man/systemd.unit.xml115
-rw-r--r--shell-completion/bash/systemd-analyze10
-rw-r--r--shell-completion/zsh/_systemd-analyze2
-rw-r--r--src/analyze/analyze.c116
-rw-r--r--src/libsystemd-network/sd-dhcp-client.c12
-rw-r--r--src/libudev/libudev-device.c4
-rw-r--r--src/network/netdev/vxlan.c4
-rw-r--r--src/network/networkd-address.c2
-rw-r--r--src/network/networkd-ipv6-proxy-ndp.c2
-rw-r--r--src/network/networkd-network.c8
-rw-r--r--src/shared/path-lookup.c27
-rw-r--r--src/test/test-path-lookup.c32
-rw-r--r--src/timedate/timedatectl.c2
-rw-r--r--src/timesync/timesyncd.c2
-rw-r--r--src/udev/cdrom_id/cdrom_id.c4
-rw-r--r--src/udev/udev-node.c2
-rw-r--r--src/udev/udevd.c2
19 files changed, 452 insertions, 273 deletions
diff --git a/man/systemd-analyze.xml b/man/systemd-analyze.xml
index 5caaa09aa4..97a9b2cca7 100644
--- a/man/systemd-analyze.xml
+++ b/man/systemd-analyze.xml
@@ -94,6 +94,11 @@
<cmdsynopsis>
<command>systemd-analyze</command>
<arg choice="opt" rep="repeat">OPTIONS</arg>
+ <arg choice="plain">unit-paths</arg>
+ </cmdsynopsis>
+ <cmdsynopsis>
+ <command>systemd-analyze</command>
+ <arg choice="opt" rep="repeat">OPTIONS</arg>
<arg choice="plain">log-level</arg>
<arg choice="opt"><replaceable>LEVEL</replaceable></arg>
</cmdsynopsis>
@@ -188,6 +193,18 @@
state. Its format is subject to change without notice and should
not be parsed by applications.</para>
+ <para><command>systemd-analyze unit-paths</command> outputs a list of all
+ directories from which unit files, <filename>.d</filename> overrides, and
+ <filename>.wants</filename>, <filename>.requires</filename> symlinks may be
+ loaded. Combine with <option>--user</option> to retrieve the list for the user
+ manager instance, and <option>--global</option> for the global configuration of
+ user manager instances. Note that this verb prints the list that is compiled into
+ <command>systemd-analyze</command> itself, and does not comunicate with the
+ running manager. Use
+ <programlisting>systemctl [--user] [--global] show -p UnitPath --value</programlisting>
+ to retrieve the actual list that the manager uses, with any empty directories
+ omitted.</para>
+
<para><command>systemd-analyze log-level</command>
prints the current log level of the <command>systemd</command> daemon.
If an optional argument <replaceable>LEVEL</replaceable> is provided, then the command changes the current log
@@ -243,6 +260,13 @@
<variablelist>
<varlistentry>
+ <term><option>--system</option></term>
+
+ <listitem><para>Operates on the system systemd instance. This
+ is the implied default.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><option>--user</option></term>
<listitem><para>Operates on the user systemd
@@ -250,10 +274,10 @@
</varlistentry>
<varlistentry>
- <term><option>--system</option></term>
+ <term><option>--global</option></term>
- <listitem><para>Operates on the system systemd instance. This
- is the implied default.</para></listitem>
+ <listitem><para>Operates on the system-wide configuration for
+ user systemd instance.</para></listitem>
</varlistentry>
<varlistentry>
diff --git a/man/systemd.generator.xml b/man/systemd.generator.xml
index 7ed6a2dc82..60ca0cecad 100644
--- a/man/systemd.generator.xml
+++ b/man/systemd.generator.xml
@@ -76,14 +76,33 @@
<refsect1>
<title>Description</title>
- <para>Generators are small executables that live in <filename>&systemgeneratordir;/</filename> and other
- directories listed above.
- <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry> will execute those
- binaries very early at bootup and at configuration reload time — before unit files are loaded. Generators may
- dynamically generate unit files (regular ones, instances as well as templates) and unit file
- <filename>.d/</filename> drop-ins, or create symbolic links to unit files to add additional dependencies or
- instantiate existing templates, thus extending or overriding existing definitions. Their main purpose is to convert
- configuration files that are not native unit files dynamically into native unit files.</para>
+ <para>Generators are small executables that live in
+ <filename>&systemgeneratordir;/</filename> and other directories listed above.
+ <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+ will execute those binaries very early at bootup and at configuration reload time
+ — before unit files are loaded. Their main purpose is to convert configuration
+ that is not native into dynamically generated unit files.</para>
+
+ <para>Each generator is called with three directory paths that are to be used for
+ generator output. In these three directories, generators may dynamically generate
+ unit files (regular ones, instances, as well as templates), unit file
+ <filename>.d/</filename> drop-ins, and create symbolic links to unit files to add
+ additional dependencies, create aliases, or instantiate existing templates. Those
+ directories are included in the unit load path of
+ <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+ allowing generated configuration to extend or override existing
+ definitions.</para>
+
+ <para>Directory paths for generator output differ by priority:
+ <filename>…/generator.early</filename> has priority higher than the admin
+ configuration in <filename>/etc</filename>, while
+ <filename>…/generator</filename> has lower priority than
+ <filename>/etc</filename> but higher than vendor configuration in
+ <filename>/usr</filename>, and <filename>…/generator.late</filename> has priority
+ lower than all other configuration. See the next section and the discussion of
+ unit load paths and unit overriding in
+ <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
+ </para>
<para>Generators are loaded from a set of paths determined during
compilation, as listed above. System and user generators are loaded
@@ -110,171 +129,153 @@
</refsect1>
<refsect1>
- <title>Writing generators</title>
+ <title>Output directories</title>
- <para>Generators are invoked with three arguments: paths to
- runtime directories where generators can place their generated
- unit files or symlinks.</para>
+ <para>Generators are invoked with three arguments: paths to directories where
+ generators can place their generated unit files or symlinks. By default those
+ paths are runtime directories that are included in the search path of
+ <command>systemd</command>, but a generator may be called with different paths
+ for debugging purposes.</para>
<orderedlist>
<listitem>
<para><parameter>normal-dir</parameter></para>
- <para>argv[1] may be used to override unit files in
- <filename>/usr</filename>, but not those in
- <filename>/run</filename> or in <filename>/etc</filename>.
- This means that unit files placed
- in this directory take precedence over vendor unit
- configuration but not over native user/administrator unit
- configuration.</para>
+ <para>In normal use this is <filename>/run/systemd/generator</filename> in
+ case of the system generators and
+ <filename>$XDG_RUNTIME_DIR/generator</filename> in case of the user
+ generators. Unit files placed in this directory take precedence over vendor
+ unit configuration but not over native user/administrator unit configuration.
+ </para>
</listitem>
<listitem>
<para><parameter>early-dir</parameter></para>
- <para>argv[2] may be used to override unit files in
- <filename>/usr</filename>, in <filename>/run</filename> and in
- <filename>/etc</filename>. This means that unit files placed
- in this directory take precedence over all configuration,
- both vendor and user/administrator.</para>
+ <para>In normal use this is <filename>/run/systemd/generator.early</filename>
+ in case of the system generators and
+ <filename>$XDG_RUNTIME_DIR/generator.early</filename> in case of the user
+ generators. Unit files placed in this directory override unit files in
+ <filename>/usr</filename>, <filename>/run</filename> and
+ <filename>/etc</filename>. This means that unit files placed in this
+ directory take precedence over all normal configuration, both vendor and
+ user/administrator.</para>
</listitem>
<listitem>
<para><parameter>late-dir</parameter></para>
- <para>argv[3] may be used to extend the unit file tree without
- overriding any other unit files. Any native configuration
- files supplied by the vendor or user/administrator take
- precedence over the generated ones placed in this directory.
- </para>
+ <para>In normal use this is <filename>/run/systemd/generator.late</filename>
+ in case of the system generators and
+ <filename>$XDG_RUNTIME_DIR/generator.late</filename> in case of the user
+ generators. This directory may be used to extend the unit file tree without
+ overriding any other unit files. Any native configuration files supplied by
+ the vendor or user/administrator take precedence.</para>
</listitem>
</orderedlist>
+ </refsect1>
+
+ <refsect1>
+ <title>Notes about writing generators</title>
+
+ <itemizedlist>
+ <listitem>
+ <para>All generators are executed in parallel. That means all executables are
+ started at the very same time and need to be able to cope with this
+ parallelism.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>Generators are run very early at boot and cannot rely on any external
+ services. They may not talk to any other process. That includes simple things
+ such as logging to
+ <citerefentry project='man-pages'><refentrytitle>syslog</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+ or <command>systemd</command> itself (this means: no
+ <citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>)!
+ Non-essential file systems like <filename>/var</filename> and
+ <filename>/home</filename> are mounted after generators have run. Generators
+ can however rely on the most basic kernel functionality to be available,
+ including a mounted <filename>/sys</filename>, <filename>/proc</filename>,
+ <filename>/dev</filename>, <filename>/usr</filename>.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>Units written by generators are removed when the configuration is
+ reloaded. That means the lifetime of the generated units is closely bound to
+ the reload cycles of <command>systemd</command> itself.</para>
+ </listitem>
+
+ <listitem>
+ <para>Generators should only be used to generate unit files and symlinks to
+ them, not any other kind of configuration. Due to the lifecycle logic
+ mentioned above, generators are not a good fit to generate dynamic
+ configuration for other services. If you need to generate dynamic
+ configuration for other services, do so in normal services you order before
+ the service in question.</para>
+ </listitem>
+
+ <listitem>
+ <para>Since
+ <citerefentry project='man-pages'><refentrytitle>syslog</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+
+ is not available (see above), log messages have to be written to
+ <filename>/dev/kmsg</filename> instead.</para>
+ </listitem>
+
+ <listitem>
+ <para>It is a good idea to use the <varname>SourcePath=</varname> directive
+ in generated unit files to specify the source configuration file you are
+ generating the unit from. This makes things more easily understood by the
+ user and also has the benefit that systemd can warn the user about
+ configuration files that changed on disk but have not been read yet by
+ systemd.</para>
+ </listitem>
- <refsect2>
- <title>Notes</title>
-
- <itemizedlist>
- <listitem>
- <para>
- All generators are executed in parallel. That means all
- executables are started at the very same time and need to
- be able to cope with this parallelism.
- </para>
- </listitem>
-
- <listitem>
- <para>
- Generators are run very early at boot and cannot rely on
- any external services. They may not talk to any other
- process. That includes simple things such as logging to
- <citerefentry project='man-pages'><refentrytitle>syslog</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
- or <command>systemd</command> itself (this means: no
- <citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>)!
- Non-essential file systems like
- <filename>/var</filename> and <filename>/home</filename>
- are mounted after generators have run. Generators
- can however rely on the most basic kernel functionality to be
- available, including a mounted <filename>/sys</filename>,
- <filename>/proc</filename>, <filename>/dev</filename>,
- <filename>/usr</filename>.
- </para>
- </listitem>
-
- <listitem>
- <para>
- Units written by generators are removed when the configuration
- is reloaded. That means the lifetime of the generated
- units is closely bound to the reload cycles of
- <command>systemd</command> itself.
- </para>
- </listitem>
-
- <listitem>
- <para>
- Generators should only be used to generate unit files and symlinks to them, not any other kind of
- configuration. Due to the lifecycle logic mentioned above, generators are not a good fit to generate
- dynamic configuration for other services. If you need to generate dynamic configuration for other services,
- do so in normal services you order before the service in question.
- </para>
- </listitem>
-
- <listitem>
- <para>
- Since
- <citerefentry project='man-pages'><refentrytitle>syslog</refentrytitle><manvolnum>3</manvolnum></citerefentry>
- is not available (see above), log messages have to be
- written to <filename>/dev/kmsg</filename> instead.
- </para>
- </listitem>
-
- <listitem>
- <para>
- It is a good idea to use the
- <varname>SourcePath=</varname> directive in generated unit
- files to specify the source configuration file you are
- generating the unit from. This makes things more easily
- understood by the user and also has the benefit that
- systemd can warn the user about configuration files that
- changed on disk but have not been read yet by systemd.
- </para>
- </listitem>
-
- <listitem>
- <para>
- Generators may write out dynamic unit files or just hook
- unit files into other units with the usual
- <filename>.wants/</filename> or
- <filename>.requires/</filename> symlinks. Often, it is
- nicer to simply instantiate a template unit file from
- <filename>/usr</filename> with a generator instead of
- writing out entirely dynamic unit files. Of course, this
- works only if a single parameter is to be used.
- </para>
- </listitem>
-
- <listitem>
- <para>
- If you are careful, you can implement generators in shell
- scripts. We do recommend C code however, since generators
- are executed synchronously and hence delay the
- entire boot if they are slow.
- </para>
- </listitem>
-
- <listitem>
- <para>Regarding overriding semantics: there are two rules we
- try to follow when thinking about the overriding semantics:
- </para>
-
- <orderedlist numeration="lowerroman">
- <listitem>
- <para>User configuration should override vendor
- configuration. This (mostly) means that stuff from
- <filename>/etc</filename> should override stuff from
- <filename>/usr</filename>.</para>
- </listitem>
-
- <listitem>
- <para>Native configuration should override non-native
- configuration. This (mostly) means that stuff you
- generate should never override native unit files for the
- same purpose.</para>
- </listitem>
- </orderedlist>
-
- <para>Of these two rules the first rule is probably the more
- important one and breaks the second one sometimes. Hence,
- when deciding whether to use argv[1], argv[2], or argv[3],
- your default choice should probably be argv[1].</para>
- </listitem>
-
- <listitem>
- <para>
- Instead of heading off now and writing all kind of
- generators for legacy configuration file formats, please
- think twice! It is often a better idea to just deprecate
- old stuff instead of keeping it artificially alive.
- </para>
- </listitem>
- </itemizedlist>
- </refsect2>
+ <listitem>
+ <para>Generators may write out dynamic unit files or just hook unit files
+ into other units with the usual <filename>.wants/</filename> or
+ <filename>.requires/</filename> symlinks. Often, it is nicer to simply
+ instantiate a template unit file from <filename>/usr</filename> with a
+ generator instead of writing out entirely dynamic unit files. Of course, this
+ works only if a single parameter is to be used.</para>
+ </listitem>
+
+ <listitem>
+ <para>If you are careful, you can implement generators in shell scripts. We
+ do recommend C code however, since generators are executed synchronously and
+ hence delay the entire boot if they are slow.</para>
+ </listitem>
+
+ <listitem>
+ <para>Regarding overriding semantics: there are two rules we try to follow
+ when thinking about the overriding semantics:</para>
+
+ <orderedlist numeration="lowerroman">
+ <listitem>
+ <para>User configuration should override vendor configuration. This
+ (mostly) means that stuff from <filename>/etc</filename> should override
+ stuff from <filename>/usr</filename>.</para>
+ </listitem>
+
+ <listitem>
+ <para>Native configuration should override non-native configuration. This
+ (mostly) means that stuff you generate should never override native unit
+ files for the same purpose.</para>
+ </listitem>
+ </orderedlist>
+
+ <para>Of these two rules the first rule is probably the more important one
+ and breaks the second one sometimes. Hence, when deciding whether to use
+ argv[1], argv[2], or argv[3], your default choice should probably be
+ argv[1].</para>
+ </listitem>
+
+ <listitem>
+ <para>Instead of heading off now and writing all kind of generators for
+ legacy configuration file formats, please think twice! It is often a better
+ idea to just deprecate old stuff instead of keeping it artificially alive.
+ </para>
+ </listitem>
+ </itemizedlist>
</refsect1>
<refsect1>
@@ -283,22 +284,18 @@
<title>systemd-fstab-generator</title>
<para><citerefentry><refentrytitle>systemd-fstab-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>
- converts <filename>/etc/fstab</filename> into native mount
- units. It uses argv[1] as location to place the generated unit
- files in order to allow the user to override
- <filename>/etc/fstab</filename> with her own native unit files,
- but also to ensure that <filename>/etc/fstab</filename>
- overrides any vendor default from <filename>/usr</filename>.
- </para>
-
- <para>After editing <filename>/etc/fstab</filename>, the user
- should invoke <command>systemctl daemon-reload</command>. This
- will re-run all generators and cause <command>systemd</command>
- to reload units from disk. To actually mount new directories
- added to <filename>fstab</filename>, <command>systemctl start
- <replaceable>/path/to/mountpoint</replaceable></command> or
- <command>systemctl start local-fs.target</command> may be used.
- </para>
+ converts <filename>/etc/fstab</filename> into native mount units. It uses
+ argv[1] as location to place the generated unit files in order to allow the
+ user to override <filename>/etc/fstab</filename> with her own native unit
+ files, but also to ensure that <filename>/etc/fstab</filename> overrides any
+ vendor default from <filename>/usr</filename>.</para>
+
+ <para>After editing <filename>/etc/fstab</filename>, the user should invoke
+ <command>systemctl daemon-reload</command>. This will re-run all generators and
+ cause <command>systemd</command> to reload units from disk. To actually mount
+ new directories added to <filename>fstab</filename>, <command>systemctl start
+ <replaceable>/path/to/mountpoint</replaceable></command> or <command>systemctl
+ start local-fs.target</command> may be used.</para>
</example>
<example>
@@ -307,9 +304,9 @@
<para><citerefentry><refentrytitle>systemd-system-update-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>
temporarily redirects <filename>default.target</filename> to
<filename>system-update.target</filename>, if a system update is
- scheduled. Since this needs to override the default user
- configuration for <filename>default.target</filename>, it uses
- argv[2]. For details about this logic, see
+ scheduled. Since this needs to override the default user configuration for
+ <filename>default.target</filename>, it uses argv[2]. For details about this
+ logic, see
<citerefentry><refentrytitle>systemd.offline-updates</refentrytitle><manvolnum>7</manvolnum></citerefentry>.
</para>
</example>
diff --git a/man/systemd.unit.xml b/man/systemd.unit.xml
index 90ca378e84..0e27c5dd8e 100644
--- a/man/systemd.unit.xml
+++ b/man/systemd.unit.xml
@@ -65,19 +65,31 @@
<filename><replaceable>slice</replaceable>.slice</filename>,
<filename><replaceable>scope</replaceable>.scope</filename></para>
- <para><literallayout><filename>/etc/systemd/system/*</filename>
+ <para><literallayout><filename>/etc/systemd/system.control/*</filename>
+<filename>/run/systemd/system.control/*</filename>
+<filename>/run/systemd/transient/*</filename>
+<filename>/run/systemd/generator.early/*</filename>
+<filename>/etc/systemd/system/*</filename>
<filename>/run/systemd/system/*</filename>
-<filename>/usr/lib/systemd/system/*</filename>
+<filename>/run/systemd/generator/*</filename>
<filename>…</filename>
+<filename>/usr/lib/systemd/system/*</filename>
+<filename>/run/systemd/generator.late/*</filename>
</literallayout></para>
- <para><literallayout><filename>~/.config/systemd/user/*</filename>
+ <para><literallayout><filename>~/.config/systemd/user.control/*</filename>
+<filename>$XDG_RUNTIME_DIR/systemd/user.control/*</filename>
+<filename>$XDG_RUNTIME_DIR/systemd/transient/*</filename>
+<filename>$XDG_RUNTIME_DIR/systemd/generator.early/*</filename>
+<filename>~/.config/systemd/user/*</filename>
<filename>/etc/systemd/user/*</filename>
<filename>$XDG_RUNTIME_DIR/systemd/user/*</filename>
<filename>/run/systemd/user/*</filename>
+<filename>$XDG_RUNTIME_DIR/systemd/generator/*</filename>
<filename>~/.local/share/systemd/user/*</filename>
-<filename>/usr/lib/systemd/user/*</filename>
<filename>…</filename>
+<filename>/usr/lib/systemd/user/*</filename>
+<filename>$XDG_RUNTIME_DIR/systemd/generator.late/*</filename>
</literallayout></para>
</refsynopsisdiv>
@@ -343,6 +355,22 @@
</thead>
<tbody>
<row>
+ <entry><filename>/etc/systemd/system.control</filename></entry>
+ <entry morerows="1">Persistent and transient configuration created using the dbus API</entry>
+ </row>
+ <row>
+ <entry><filename>/run/systemd/system.control</filename></entry>
+ </row>
+ <row>
+ <entry><filename>/run/systemd/transient</filename></entry>
+ <entry>Dynamic configuration for transient units</entry>
+ </row>
+ <row>
+ <entry><filename>/run/systemd/generator.early</filename></entry>
+ <entry>Generated units with high priority (see <replaceable>early-dir</replaceable> in <citerefentry
+ ><refentrytitle>system.generator</refentrytitle><manvolnum>7</manvolnum></citerefentry>)</entry>
+ </row>
+ <row>
<entry><filename>/etc/systemd/system</filename></entry>
<entry>Local configuration</entry>
</row>
@@ -351,8 +379,21 @@
<entry>Runtime units</entry>
</row>
<row>
+ <entry><filename>/run/systemd/generator</filename></entry>
+ <entry>Generated units with medium priority (see <replaceable>normal-dir</replaceable> in <citerefentry
+ ><refentrytitle>system.generator</refentrytitle><manvolnum>7</manvolnum></citerefentry>)</entry>
+ </row>
+ <row>
+ <entry><filename>/usr/local/lib/systemd/system</filename></entry>
+ <entry morerows="1">Units of installed packages</entry>
+ </row>
+ <row>
<entry><filename>/usr/lib/systemd/system</filename></entry>
- <entry>Units of installed packages</entry>
+ </row>
+ <row>
+ <entry><filename>/run/systemd/generator.late</filename></entry>
+ <entry>Generated units with low priority (see <replaceable>late-dir</replaceable> in <citerefentry
+ ><refentrytitle>system.generator</refentrytitle><manvolnum>7</manvolnum></citerefentry>)</entry>
</row>
</tbody>
</tgroup>
@@ -374,12 +415,25 @@
</thead>
<tbody>
<row>
- <entry><filename>$XDG_CONFIG_HOME/systemd/user</filename></entry>
- <entry>User configuration (only used when $XDG_CONFIG_HOME is set)</entry>
+ <entry><filename>$XDG_CONFIG_HOME/systemd/user.control</filename> or <filename
+ >~/.config/systemd/user.control</filename></entry>
+ <entry morerows="1">Persistent and transient configuration created using the dbus API (<varname>$XDG_CONFIG_HOME</varname> is used if set, <filename>~/.config</filename> otherwise)</entry>
+ </row>
+ <row>
+ <entry><filename>$XDG_RUNTIME_DIR/systemd/user.control</filename></entry>
+ </row>
+ <row>
+ <entry><filename>/run/systemd/transient</filename></entry>
+ <entry>Dynamic configuration for transient units</entry>
+ </row>
+ <row>
+ <entry><filename>/run/systemd/generator.early</filename></entry>
+ <entry>Generated units with high priority (see <replaceable>early-dir</replaceable> in <citerefentry
+ ><refentrytitle>system.generator</refentrytitle><manvolnum>7</manvolnum></citerefentry>)</entry>
</row>
<row>
- <entry><filename>$HOME/.config/systemd/user</filename></entry>
- <entry>User configuration (only used when $XDG_CONFIG_HOME is not set)</entry>
+ <entry><filename>$XDG_CONFIG_HOME/systemd/user</filename> or <filename>$HOME/.config/systemd/user</filename></entry>
+ <entry>User configuration (<varname>$XDG_CONFIG_HOME</varname> is used if set, <filename>~/.config</filename> otherwise)</entry>
</row>
<row>
<entry><filename>/etc/systemd/user</filename></entry>
@@ -394,27 +448,50 @@
<entry>Runtime units</entry>
</row>
<row>
- <entry><filename>$XDG_DATA_HOME/systemd/user</filename></entry>
- <entry>Units of packages that have been installed in the home directory (only used when $XDG_DATA_HOME is set)</entry>
+ <entry><filename>$XDG_RUNTIME_DIR/systemd/generator</filename></entry>
+ <entry>Generated units with medium priority (see <replaceable>normal-dir</replaceable> in <citerefentry
+ ><refentrytitle>system.generator</refentrytitle><manvolnum>7</manvolnum></citerefentry>)</entry>
</row>
<row>
- <entry><filename>$HOME/.local/share/systemd/user</filename></entry>
- <entry>Units of packages that have been installed in the home directory (only used when $XDG_DATA_HOME is not set)</entry>
+ <entry><filename>$XDG_DATA_HOME/systemd/user</filename> or <filename>$HOME/.local/share/systemd/user</filename></entry>
+ <entry>Units of packages that have been installed in the home directory (<varname>$XDG_DATA_HOME</varname> is used if set, <filename>~/.local/share</filename> otherwise)</entry>
+ </row>
+ <row>
+ <entry><filename>$dir/systemd/user</filename> for each <varname noindex='true'>$dir</varname> in <varname>$XDG_DATA_DIRS</varname></entry>
+ <entry>Additional locations for installed user units, one for each entry in <varname>$XDG_DATA_DIRS</varname></entry>
+ </row>
+ <row>
+ <entry><filename>/usr/local/lib/systemd/user</filename></entry>
+ <entry morerows="1">Units of packages that have been installed system-wide</entry>
</row>
<row>
<entry><filename>/usr/lib/systemd/user</filename></entry>
- <entry>Units of packages that have been installed system-wide</entry>
+ </row>
+ <row>
+ <entry><filename>$XDG_RUNTIME_DIR/systemd/generator.late</filename></entry>
+ <entry>Generated units with low priority (see <replaceable>late-dir</replaceable> in <citerefentry
+ ><refentrytitle>system.generator</refentrytitle><manvolnum>7</manvolnum></citerefentry>)</entry>
</row>
</tbody>
</tgroup>
</table>
- <para>Additional units might be loaded into systemd ("linked")
- from directories not on the unit load path. See the
- <command>link</command> command for
+ <para>The set of load paths for the user manager instance may be augmented or
+ changed using various environment variables. And environment variables may in
+ turn be set using environment generators, see
+ <citerefentry><refentrytitle>system.environment-generator</refentrytitle><manvolnum>7</manvolnum></citerefentry>.
+ In particular, <varname>$XDG_DATA_HOME</varname> and
+ <varname>$XDG_DATA_DIRS</varname> may be easily set using
+ <citerefentry><refentrytitle>systemd-environment-d-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>.
+ Thus, directories listed here are just the defaults. To see the actual list that
+ would be used based on compilation options and current environment use
+ <programlisting>systemd-analyze --user unit-paths</programlisting>
+ </para>
+
+ <para>Moreover, additional units might be loaded into systemd ("linked") from
+ directories not on the unit load path. See the <command>link</command> command
+ for
<citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>.
- Also, some units are dynamically created via a
- <citerefentry><refentrytitle>systemd.generator</refentrytitle><manvolnum>7</manvolnum></citerefentry>.
</para>
</refsect1>
diff --git a/shell-completion/bash/systemd-analyze b/shell-completion/bash/systemd-analyze
index fb30487613..a66ddccb02 100644
--- a/shell-completion/bash/systemd-analyze
+++ b/shell-completion/bash/systemd-analyze
@@ -36,13 +36,13 @@ _systemd_analyze() {
local cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]}
local -A OPTS=(
- [STANDALONE]='-h --help --version --system --user --order --require --no-pager
+ [STANDALONE]='-h --help --version --system --user --global --order --require --no-pager
--man=no --generators=yes'
[ARG]='-H --host -M --machine --fuzz --from-pattern --to-pattern'
)
local -A VERBS=(
- [STANDALONE]='time blame plot dump calendar'
+ [STANDALONE]='time blame plot dump unit-paths calendar'
[CRITICAL_CHAIN]='critical-chain'
[DOT]='dot'
[LOG_LEVEL]='log-level'
@@ -85,7 +85,7 @@ _systemd_analyze() {
elif __contains_word "$verb" ${VERBS[STANDALONE]}; then
if [[ $cur = -* ]]; then
- comps='--help --version --system --user'
+ comps='--help --version --system --user --global'
fi
elif __contains_word "$verb" ${VERBS[CRITICAL_CHAIN]}; then
@@ -95,7 +95,7 @@ _systemd_analyze() {
elif __contains_word "$verb" ${VERBS[DOT]}; then
if [[ $cur = -* ]]; then
- comps='--help --version --system --user --from-pattern --to-pattern --order --require'
+ comps='--help --version --system --user --global --from-pattern --to-pattern --order --require'
fi
elif __contains_word "$verb" ${VERBS[LOG_LEVEL]}; then
@@ -119,7 +119,7 @@ _systemd_analyze() {
elif __contains_word "$verb" ${VERBS[VERIFY]}; then
if [[ $cur = -* ]]; then
- comps='--help --version --system --user --man=no --generators=yes'
+ comps='--help --version --system --user --global --man=no --generators=yes'
else
comps=$( compgen -A file -- "$cur" )
compopt -o filenames
diff --git a/shell-completion/zsh/_systemd-analyze b/shell-completion/zsh/_systemd-analyze
index ae13f4bbde..bccdb951f1 100644
--- a/shell-completion/zsh/_systemd-analyze
+++ b/shell-completion/zsh/_systemd-analyze
@@ -33,6 +33,7 @@ _systemd_analyze_command(){
'plot:Output SVG graphic showing service initialization'
'dot:Dump dependency graph (in dot(1) format)'
'dump:Dump server status'
+ 'unit-paths':List unit load paths'
'log-level:Get/set systemd log threshold'
'log-target:Get/set systemd log target'
'service-watchdogs:Get/set service watchdog status'
@@ -62,6 +63,7 @@ _arguments \
'--version[Show package version]' \
'--system[Operate on system systemd instance]' \
'--user[Operate on user systemd instance]' \
+ '--global[Show global user instance config]' \
'--no-pager[Do not pipe output into a pager]' \
'--man=[Do (not) check for existence of man pages]:boolean:(1 0)' \
'--order[When generating graph for dot, show only order]' \
diff --git a/src/analyze/analyze.c b/src/analyze/analyze.c
index aab61e4de3..2d65fdbdb8 100644
--- a/src/analyze/analyze.c
+++ b/src/analyze/analyze.c
@@ -80,7 +80,7 @@ static usec_t arg_fuzz = 0;
static bool arg_no_pager = false;
static BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
static const char *arg_host = NULL;
-static bool arg_user = false;
+static UnitFileScope arg_scope = UNIT_FILE_SYSTEM;
static bool arg_man = true;
static bool arg_generators = false;
@@ -132,10 +132,12 @@ struct host_info {
};
static int acquire_bus(bool need_full_bus, sd_bus **bus) {
+ bool user = arg_scope != UNIT_FILE_SYSTEM;
+
if (need_full_bus)
- return bus_connect_transport(arg_transport, arg_host, arg_user, bus);
+ return bus_connect_transport(arg_transport, arg_host, user, bus);
else
- return bus_connect_transport_systemd(arg_transport, arg_host, arg_user, bus);
+ return bus_connect_transport_systemd(arg_transport, arg_host, user, bus);
}
static int bus_get_uint64_property(sd_bus *bus, const char *path, const char *interface, const char *property, uint64_t *val) {
@@ -294,7 +296,12 @@ static int acquire_boot_times(sd_bus *bus, struct boot_times **bt) {
return -EINPROGRESS;
}
- if (arg_user) {
+ if (arg_scope == UNIT_FILE_SYSTEM) {
+ if (times.initrd_time > 0)
+ times.kernel_done_time = times.initrd_time;
+ else
+ times.kernel_done_time = times.userspace_time;
+ } else {
/*
* User-instance-specific timestamps processing
* (see comment to reverse_offset in struct boot_times).
@@ -312,11 +319,6 @@ static int acquire_boot_times(sd_bus *bus, struct boot_times **bt) {
subtract_timestamp(&times.unitsload_start_time, times.reverse_offset);
subtract_timestamp(&times.unitsload_finish_time, times.reverse_offset);
- } else {
- if (times.initrd_time)
- times.kernel_done_time = times.initrd_time;
- else
- times.kernel_done_time = times.userspace_time;
}
cached = true;
@@ -439,8 +441,7 @@ static int acquire_time_data(sd_bus *bus, struct unit_times **out) {
return c;
fail:
- if (unit_times)
- free_unit_times(unit_times, (unsigned) c);
+ free_unit_times(unit_times, (unsigned) c);
return r;
}
@@ -537,11 +538,11 @@ static int pretty_boot_time(sd_bus *bus, char **_buf) {
size = sizeof(buf);
size = strpcpyf(&ptr, size, "Startup finished in ");
- if (t->firmware_time)
+ if (t->firmware_time > 0)
size = strpcpyf(&ptr, size, "%s (firmware) + ", format_timespan(ts, sizeof(ts), t->firmware_time - t->loader_time, USEC_PER_MSEC));
- if (t->loader_time)
+ if (t->loader_time > 0)
size = strpcpyf(&ptr, size, "%s (loader) + ", format_timespan(ts, sizeof(ts), t->loader_time, USEC_PER_MSEC));
- if (t->kernel_time)
+ if (t->kernel_time > 0)
size = strpcpyf(&ptr, size, "%s (kernel) + ", format_timespan(ts, sizeof(ts), t->kernel_done_time, USEC_PER_MSEC));
if (t->initrd_time > 0)
size = strpcpyf(&ptr, size, "%s (initrd) + ", format_timespan(ts, sizeof(ts), t->userspace_time - t->initrd_time, USEC_PER_MSEC));
@@ -550,7 +551,7 @@ static int pretty_boot_time(sd_bus *bus, char **_buf) {
if (t->kernel_time > 0)
strpcpyf(&ptr, size, "= %s", format_timespan(ts, sizeof(ts), t->firmware_time + t->finish_time, USEC_PER_MSEC));
- if (unit_id && (activated_time > 0 && activated_time != USEC_INFINITY))
+ if (unit_id && activated_time > 0 && activated_time != USEC_INFINITY)
size = strpcpyf(&ptr, size, "\n%s reached after %s in userspace", unit_id, format_timespan(ts, sizeof(ts), activated_time - t->userspace_time, USEC_PER_MSEC));
else if (unit_id && activated_time == 0)
size = strpcpyf(&ptr, size, "\n%s was never reached", unit_id);
@@ -629,14 +630,14 @@ static int analyze_plot(int argc, char *argv[], void *userdata) {
if (boot->firmware_time > boot->loader_time)
m++;
- if (boot->loader_time) {
+ if (boot->loader_time > 0) {
m++;
if (width < 1000.0)
width = 1000.0;
}
- if (boot->initrd_time)
+ if (boot->initrd_time > 0)
m++;
- if (boot->kernel_time)
+ if (boot->kernel_time > 0)
m++;
for (u = times; u < times + n; u++) {
@@ -725,22 +726,22 @@ static int analyze_plot(int argc, char *argv[], void *userdata) {
svg("<g transform=\"translate(%.3f,100)\">\n", 20.0 + (SCALE_X * boot->firmware_time));
svg_graph_box(m, -(double) boot->firmware_time, boot->finish_time);
- if (boot->firmware_time) {
+ if (boot->firmware_time > 0) {
svg_bar("firmware", -(double) boot->firmware_time, -(double) boot->loader_time, y);
svg_text(true, -(double) boot->firmware_time, y, "firmware");
y++;
}
- if (boot->loader_time) {
+ if (boot->loader_time > 0) {
svg_bar("loader", -(double) boot->loader_time, 0, y);
svg_text(true, -(double) boot->loader_time, y, "loader");
y++;
}
- if (boot->kernel_time) {
+ if (boot->kernel_time > 0) {
svg_bar("kernel", 0, boot->kernel_done_time, y);
svg_text(true, 0, y, "kernel");
y++;
}
- if (boot->initrd_time) {
+ if (boot->initrd_time > 0) {
svg_bar("initrd", boot->initrd_time, boot->userspace_time, y);
svg_text(true, boot->initrd_time, y, "initrd");
y++;
@@ -818,7 +819,7 @@ static int list_dependencies_print(const char *name, unsigned int level, unsigne
printf("%s", special_glyph(last ? TREE_RIGHT : TREE_BRANCH));
if (times) {
- if (times->time)
+ if (times->time > 0)
printf("%s%s @%s +%s%s", ansi_highlight_red(), name,
format_timespan(ts, sizeof(ts), times->activating - boot->userspace_time, USEC_PER_MSEC),
format_timespan(ts2, sizeof(ts2), times->time, USEC_PER_MSEC), ansi_normal());
@@ -864,6 +865,11 @@ static int list_dependencies_compare(const void *_a, const void *_b) {
return usb - usa;
}
+static bool times_in_range(const struct unit_times *times, const struct boot_times *boot) {
+ return times &&
+ times->activated > 0 && times->activated <= boot->finish_time;
+}
+
static int list_dependencies_one(sd_bus *bus, const char *name, unsigned int level, char ***units,
unsigned int branches) {
_cleanup_strv_free_ char **deps = NULL;
@@ -889,11 +895,9 @@ static int list_dependencies_one(sd_bus *bus, const char *name, unsigned int lev
STRV_FOREACH(c, deps) {
times = hashmap_get(unit_times_hashmap, *c);
- if (times
- && times->activated
- && times->activated <= boot->finish_time
- && (times->activated >= service_longest
- || service_longest == 0)) {
+ if (times_in_range(times, boot) &&
+ (times->activated >= service_longest
+ || service_longest == 0)) {
service_longest = times->activated;
break;
}
@@ -904,7 +908,8 @@ static int list_dependencies_one(sd_bus *bus, const char *name, unsigned int lev
STRV_FOREACH(c, deps) {
times = hashmap_get(unit_times_hashmap, *c);
- if (times && times->activated && times->activated <= boot->finish_time && (service_longest - times->activated) <= arg_fuzz)
+ if (times_in_range(times, boot) &&
+ service_longest - times->activated <= arg_fuzz)
to_print++;
}
@@ -913,10 +918,8 @@ static int list_dependencies_one(sd_bus *bus, const char *name, unsigned int lev
STRV_FOREACH(c, deps) {
times = hashmap_get(unit_times_hashmap, *c);
- if (!times
- || !times->activated
- || times->activated > boot->finish_time
- || service_longest - times->activated > arg_fuzz)
+ if (!times_in_range(times, boot) ||
+ service_longest - times->activated > arg_fuzz)
continue;
to_print--;
@@ -938,7 +941,7 @@ static int list_dependencies_one(sd_bus *bus, const char *name, unsigned int lev
if (r < 0)
return r;
- if (!to_print)
+ if (to_print == 0)
break;
}
return 0;
@@ -1414,6 +1417,21 @@ static int get_or_set_log_target(int argc, char *argv[], void *userdata) {
return (argc == 1) ? get_log_target(argc, argv, userdata) : set_log_target(argc, argv, userdata);
}
+static int dump_unit_paths(int argc, char *argv[], void *userdata) {
+ _cleanup_lookup_paths_free_ LookupPaths paths = {};
+ int r;
+ char **p;
+
+ r = lookup_paths_init(&paths, arg_scope, 0, NULL);
+ if (r < 0)
+ return log_error_errno(r, "lookup_paths_init() failed: %m");
+
+ STRV_FOREACH(p, paths.search_path)
+ puts(*p);
+
+ return 0;
+}
+
#if HAVE_SECCOMP
static void dump_syscall_filter(const SyscallFilterSet *set) {
const char *syscall;
@@ -1584,10 +1602,7 @@ static int service_watchdogs(int argc, char *argv[], void *userdata) {
}
static int do_verify(int argc, char *argv[], void *userdata) {
- return verify_units(strv_skip(argv, 1),
- arg_user ? UNIT_FILE_USER : UNIT_FILE_SYSTEM,
- arg_man,
- arg_generators);
+ return verify_units(strv_skip(argv, 1), arg_scope, arg_man, arg_generators);
}
static int help(int argc, char *argv[], void *userdata) {
@@ -1601,6 +1616,7 @@ static int help(int argc, char *argv[], void *userdata) {
" --no-pager Do not pipe output into a pager\n"
" --system Operate on system systemd instance\n"
" --user Operate on user systemd instance\n"
+ " --global Operate on global user configuration\n"
" -H --host=[USER@]HOST Operate on remote host\n"
" -M --machine=CONTAINER Operate on local container\n"
" --order Show only order in the graph\n"
@@ -1620,6 +1636,7 @@ static int help(int argc, char *argv[], void *userdata) {
" log-level [LEVEL] Get/set logging threshold for manager\n"
" log-target [TARGET] Get/set logging target for manager\n"
" dump Output state serialization of service manager\n"
+ " unit-paths List load directories for units\n"
" syscall-filter [NAME...] Print list of syscalls in seccomp filter\n"
" verify FILE... Check unit files for correctness\n"
" calendar SPEC... Validate repetitive calendar time events\n"
@@ -1638,8 +1655,9 @@ static int parse_argv(int argc, char *argv[]) {
ARG_VERSION = 0x100,
ARG_ORDER,
ARG_REQUIRE,
- ARG_USER,
ARG_SYSTEM,
+ ARG_USER,
+ ARG_GLOBAL,
ARG_DOT_FROM_PATTERN,
ARG_DOT_TO_PATTERN,
ARG_FUZZ,
@@ -1653,8 +1671,9 @@ static int parse_argv(int argc, char *argv[]) {
{ "version", no_argument, NULL, ARG_VERSION },
{ "order", no_argument, NULL, ARG_ORDER },
{ "require", no_argument, NULL, ARG_REQUIRE },
- { "user", no_argument, NULL, ARG_USER },
{ "system", no_argument, NULL, ARG_SYSTEM },
+ { "user", no_argument, NULL, ARG_USER },
+ { "global", no_argument, NULL, ARG_GLOBAL },
{ "from-pattern", required_argument, NULL, ARG_DOT_FROM_PATTERN },
{ "to-pattern", required_argument, NULL, ARG_DOT_TO_PATTERN },
{ "fuzz", required_argument, NULL, ARG_FUZZ },
@@ -1680,12 +1699,16 @@ static int parse_argv(int argc, char *argv[]) {
case ARG_VERSION:
return version();
+ case ARG_SYSTEM:
+ arg_scope = UNIT_FILE_SYSTEM;
+ break;
+
case ARG_USER:
- arg_user = true;
+ arg_scope = UNIT_FILE_USER;
break;
- case ARG_SYSTEM:
- arg_user = false;
+ case ARG_GLOBAL:
+ arg_scope = UNIT_FILE_GLOBAL;
break;
case ARG_ORDER:
@@ -1763,6 +1786,12 @@ static int parse_argv(int argc, char *argv[]) {
assert_not_reached("Unhandled option code.");
}
+ if (arg_scope == UNIT_FILE_GLOBAL &&
+ !STR_IN_SET(argv[optind] ?: "time", "dot", "unit-paths", "verify")) {
+ log_error("Option --global only makes sense with verbs dot, unit-paths, verify.");
+ return -EINVAL;
+ }
+
return 1; /* work to do */
}
@@ -1783,6 +1812,7 @@ int main(int argc, char *argv[]) {
{ "set-log-target", 2, 2, 0, set_log_target },
{ "get-log-target", VERB_ANY, 1, 0, get_log_target },
{ "dump", VERB_ANY, 1, 0, dump },
+ { "unit-paths", 1, 1, 0, dump_unit_paths },
{ "syscall-filter", VERB_ANY, VERB_ANY, 0, dump_syscall_filters },
{ "verify", 2, VERB_ANY, 0, do_verify },
{ "calendar", 2, VERB_ANY, 0, test_calendar },
diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c
index 228af69d88..33f3469f07 100644
--- a/src/libsystemd-network/sd-dhcp-client.c
+++ b/src/libsystemd-network/sd-dhcp-client.c
@@ -1260,9 +1260,9 @@ static int client_handle_offer(sd_dhcp_client *client, DHCPMessage *offer, size_
if (!lease->have_subnet_mask) {
r = dhcp_lease_set_default_subnet_mask(lease);
if (r < 0) {
- log_dhcp_client(client, "received lease lacks subnet "
- "mask, and a fallback one can not be "
- "generated, ignoring");
+ log_dhcp_client(client,
+ "received lease lacks subnet mask, "
+ "and a fallback one cannot be generated, ignoring");
return -ENOMSG;
}
}
@@ -1331,9 +1331,9 @@ static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *ack, size_t le
if (lease->subnet_mask == INADDR_ANY) {
r = dhcp_lease_set_default_subnet_mask(lease);
if (r < 0) {
- log_dhcp_client(client, "received lease lacks subnet "
- "mask, and a fallback one can not be "
- "generated, ignoring");
+ log_dhcp_client(client,
+ "received lease lacks subnet mask, "
+ "and a fallback one cannot be generated, ignoring");
return -ENOMSG;
}
}
diff --git a/src/libudev/libudev-device.c b/src/libudev/libudev-device.c
index 82df426491..8e65cfd40a 100644
--- a/src/libudev/libudev-device.c
+++ b/src/libudev/libudev-device.c
@@ -143,7 +143,7 @@ _public_ const char *udev_device_get_driver(struct udev_device *udev_device)
*
* Retrieve the devtype string of the udev device.
*
- * Returns: the devtype name of the udev device, or #NULL if it can not be determined
+ * Returns: the devtype name of the udev device, or #NULL if it cannot be determined
**/
_public_ const char *udev_device_get_devtype(struct udev_device *udev_device)
{
@@ -168,7 +168,7 @@ _public_ const char *udev_device_get_devtype(struct udev_device *udev_device)
* Retrieve the subsystem string of the udev device. The string does not
* contain any "/".
*
- * Returns: the subsystem name of the udev device, or #NULL if it can not be determined
+ * Returns: the subsystem name of the udev device, or #NULL if it cannot be determined
**/
_public_ const char *udev_device_get_subsystem(struct udev_device *udev_device)
{
diff --git a/src/network/netdev/vxlan.c b/src/network/netdev/vxlan.c
index ad050efeca..c9fd931718 100644
--- a/src/network/netdev/vxlan.c
+++ b/src/network/netdev/vxlan.c
@@ -200,14 +200,14 @@ int config_parse_vxlan_address(const char *unit,
if (streq(lvalue, "Group")) {
if (r <= 0) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "vxlan invalid multicast '%s' address, ignoring assignment: %s", lvalue, rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "vxlan %s invalid multicast address, ignoring assignment: %s", lvalue, rvalue);
return 0;
}
v->remote_family = f;
} else {
if (r > 0) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "vxlan %s can not be multicast address, ignoring assignment: %s", lvalue, rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "vxlan %s cannot be a multicast address, ignoring assignment: %s", lvalue, rvalue);
return 0;
}
diff --git a/src/network/networkd-address.c b/src/network/networkd-address.c
index ca5b54bdbf..7e722b1a2e 100644
--- a/src/network/networkd-address.c
+++ b/src/network/networkd-address.c
@@ -776,7 +776,7 @@ int config_parse_address(const char *unit,
if (!e && f == AF_INET) {
r = in4_addr_default_prefixlen(&buffer.in, &n->prefixlen);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Prefix length not specified, and a default one can not be deduced for '%s', ignoring assignment", address);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Prefix length not specified, and a default one cannot be deduced for '%s', ignoring assignment", address);
return 0;
}
}
diff --git a/src/network/networkd-ipv6-proxy-ndp.c b/src/network/networkd-ipv6-proxy-ndp.c
index 31b7c6b0f4..1a357ac8e6 100644
--- a/src/network/networkd-ipv6-proxy-ndp.c
+++ b/src/network/networkd-ipv6-proxy-ndp.c
@@ -142,7 +142,7 @@ int config_parse_ipv6_proxy_ndp_address(
r = in_addr_is_null(AF_INET6, &buffer);
if (r != 0) {
log_syntax(unit, LOG_ERR, filename, line, r,
- "IPv6 proxy NDP address can not be the ANY address, ignoring: %s", rvalue);
+ "IPv6 proxy NDP address cannot be the ANY address, ignoring: %s", rvalue);
return 0;
}
diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c
index 2dc3de3f6a..48da83c497 100644
--- a/src/network/networkd-network.c
+++ b/src/network/networkd-network.c
@@ -635,13 +635,13 @@ int config_parse_netdev(const char *unit,
case NETDEV_KIND_VCAN:
r = hashmap_put(network->stacked_netdevs, netdev->ifname, netdev);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Can not add NetDev '%s' to network: %m", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Cannot add NetDev '%s' to network: %m", rvalue);
return 0;
}
break;
default:
- assert_not_reached("Can not parse NetDev");
+ assert_not_reached("Cannot parse NetDev");
}
netdev_ref(netdev);
@@ -894,12 +894,12 @@ int config_parse_ipv6token(
r = in_addr_is_null(AF_INET6, &buffer);
if (r != 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "IPv6 token can not be the ANY address, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "IPv6 token cannot be the ANY address, ignoring: %s", rvalue);
return 0;
}
if ((buffer.in6.s6_addr32[0] | buffer.in6.s6_addr32[1]) != 0) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "IPv6 token can not be longer than 64 bits, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "IPv6 token cannot be longer than 64 bits, ignoring: %s", rvalue);
return 0;
}
diff --git a/src/shared/path-lookup.c b/src/shared/path-lookup.c
index d57c78a8b1..5f31831c99 100644
--- a/src/shared/path-lookup.c
+++ b/src/shared/path-lookup.c
@@ -169,6 +169,8 @@ int xdg_user_dirs(char ***ret_config_dirs, char ***ret_data_dirs) {
static char** user_dirs(
const char *persistent_config,
const char *runtime_config,
+ const char *global_persistent_config,
+ const char *global_runtime_config,
const char *generator,
const char *generator_early,
const char *generator_late,
@@ -209,12 +211,19 @@ static char** user_dirs(
if (strv_extend(&res, persistent_config) < 0)
return NULL;
+ /* global config has lower priority than the user config of the same type */
+ if (strv_extend(&res, global_persistent_config) < 0)
+ return NULL;
+
if (strv_extend_strv(&res, (char**) user_config_unit_paths, false) < 0)
return NULL;
if (strv_extend(&res, runtime_config) < 0)
return NULL;
+ if (strv_extend(&res, global_runtime_config) < 0)
+ return NULL;
+
if (strv_extend(&res, generator) < 0)
return NULL;
@@ -411,11 +420,11 @@ static int acquire_control_dirs(UnitFileScope scope, char **persistent, char **r
}
case UNIT_FILE_USER:
- r = xdg_user_config_dir(&a, "/systemd/system.control");
+ r = xdg_user_config_dir(&a, "/systemd/user.control");
if (r < 0 && r != -ENXIO)
return r;
- r = xdg_user_runtime_dir(runtime, "/systemd/system.control");
+ r = xdg_user_runtime_dir(runtime, "/systemd/user.control");
if (r < 0) {
if (r != -ENXIO)
return r;
@@ -484,6 +493,7 @@ int lookup_paths_init(
_cleanup_free_ char
*root = NULL,
*persistent_config = NULL, *runtime_config = NULL,
+ *global_persistent_config = NULL, *global_runtime_config = NULL,
*generator = NULL, *generator_early = NULL, *generator_late = NULL,
*transient = NULL,
*persistent_control = NULL, *runtime_control = NULL;
@@ -522,6 +532,12 @@ int lookup_paths_init(
if (r < 0)
return r;
+ if (scope == UNIT_FILE_USER) {
+ r = acquire_config_dirs(UNIT_FILE_GLOBAL, &global_persistent_config, &global_runtime_config);
+ if (r < 0)
+ return r;
+ }
+
if ((flags & LOOKUP_PATHS_EXCLUDE_GENERATED) == 0) {
/* Note: if XDG_RUNTIME_DIR is not set, this will fail completely with ENXIO */
r = acquire_generator_dirs(scope, tempdir,
@@ -610,20 +626,21 @@ int lookup_paths_init(
runtime_config,
"/run/systemd/user",
STRV_IFNOTNULL(generator),
- "/usr/local/lib/systemd/user",
"/usr/local/share/systemd/user",
+ "/usr/share/systemd/user",
+ "/usr/local/lib/systemd/user",
USER_DATA_UNIT_PATH,
"/usr/lib/systemd/user",
- "/usr/share/systemd/user",
STRV_IFNOTNULL(generator_late),
NULL);
break;
case UNIT_FILE_USER:
add = user_dirs(persistent_config, runtime_config,
+ global_persistent_config, global_runtime_config,
generator, generator_early, generator_late,
transient,
- persistent_config, runtime_control);
+ persistent_control, runtime_control);
break;
default:
diff --git a/src/test/test-path-lookup.c b/src/test/test-path-lookup.c
index 834b061980..0541033d77 100644
--- a/src/test/test-path-lookup.c
+++ b/src/test/test-path-lookup.c
@@ -52,6 +52,36 @@ static void test_paths(UnitFileScope scope) {
assert_se(rm_rf(template, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
}
+static void test_user_and_global_paths(void) {
+ _cleanup_lookup_paths_free_ LookupPaths lp_global = {}, lp_user = {};
+ char **u, **g, **p;
+ unsigned k = 0;
+
+ assert_se(unsetenv("SYSTEMD_UNIT_PATH") == 0);
+
+ assert_se(lookup_paths_init(&lp_global, UNIT_FILE_GLOBAL, 0, NULL) == 0);
+ assert_se(lookup_paths_init(&lp_user, UNIT_FILE_USER, 0, NULL) == 0);
+ g = lp_global.search_path;
+ u = lp_user.search_path;
+
+ /* Go over all entries in global search path, and verify
+ * that they also exist in the user search path. Skip any
+ * entries in user search path which don't exist in the global
+ * one, but not vice versa. */
+ log_info("/* %s */", __func__);
+ STRV_FOREACH(p, g) {
+ while (u[k] && !streq(*p, u[k])) {
+ log_info("+ %s", u[k]);
+ k++;
+ }
+ log_info(" %s", *p);
+ assert(u[k]); /* If NULL, we didn't find a matching entry */
+ k++;
+ }
+ STRV_FOREACH(p, u + k)
+ log_info("+ %s", *p);
+}
+
static void print_generator_binary_paths(UnitFileScope scope) {
_cleanup_strv_free_ char **paths;
char **dir;
@@ -72,6 +102,8 @@ int main(int argc, char **argv) {
test_paths(UNIT_FILE_USER);
test_paths(UNIT_FILE_GLOBAL);
+ test_user_and_global_paths();
+
print_generator_binary_paths(UNIT_FILE_SYSTEM);
print_generator_binary_paths(UNIT_FILE_USER);
diff --git a/src/timedate/timedatectl.c b/src/timedate/timedatectl.c
index 19a382c1b2..d0a510468e 100644
--- a/src/timedate/timedatectl.c
+++ b/src/timedate/timedatectl.c
@@ -136,7 +136,7 @@ static void print_status_info(const StatusInfo *i) {
if (i->rtc_local)
printf("\n%s"
"Warning: The system is configured to read the RTC time in the local time zone.\n"
- " This mode can not be fully supported. It will create various problems\n"
+ " This mode cannot be fully supported. It will create various problems\n"
" with time zone changes and daylight saving time adjustments. The RTC\n"
" time is never updated, it relies on external facilities to maintain it.\n"
" If at all possible, use RTC in UTC by calling\n"
diff --git a/src/timesync/timesyncd.c b/src/timesync/timesyncd.c
index bea800171b..3d7cfd5be5 100644
--- a/src/timesync/timesyncd.c
+++ b/src/timesync/timesyncd.c
@@ -147,7 +147,7 @@ int main(int argc, char *argv[]) {
if (clock_is_localtime(NULL) > 0) {
log_info("The system is configured to read the RTC time in the local time zone. "
- "This mode can not be fully supported. All system time to RTC updates are disabled.");
+ "This mode cannot be fully supported. All system time to RTC updates are disabled.");
m->rtc_local_time = true;
}
diff --git a/src/udev/cdrom_id/cdrom_id.c b/src/udev/cdrom_id/cdrom_id.c
index 9644861adc..5e7bebeb16 100644
--- a/src/udev/cdrom_id/cdrom_id.c
+++ b/src/udev/cdrom_id/cdrom_id.c
@@ -566,7 +566,7 @@ static int cd_profiles(struct udev *udev, int fd)
log_debug("GET CONFIGURATION: size of features buffer 0x%04x", len);
if (len > sizeof(features)) {
- log_debug("can not get features in a single query, truncating");
+ log_debug("cannot get features in a single query, truncating");
len = sizeof(features);
} else if (len <= 8)
len = sizeof(features);
@@ -588,7 +588,7 @@ static int cd_profiles(struct udev *udev, int fd)
log_debug("GET CONFIGURATION: size of features buffer 0x%04x", len);
if (len > sizeof(features)) {
- log_debug("can not get features in a single query, truncating");
+ log_debug("cannot get features in a single query, truncating");
len = sizeof(features);
}
diff --git a/src/udev/udev-node.c b/src/udev/udev-node.c
index bb845889cc..6a3ee93ca2 100644
--- a/src/udev/udev-node.c
+++ b/src/udev/udev-node.c
@@ -265,7 +265,7 @@ static int node_permissions_apply(struct udev_device *dev, bool apply,
mode |= S_IFCHR;
if (lstat(devnode, &stats) != 0) {
- err = log_debug_errno(errno, "can not stat() node '%s' (%m)", devnode);
+ err = log_debug_errno(errno, "cannot stat() node '%s' (%m)", devnode);
goto out;
}
diff --git a/src/udev/udevd.c b/src/udev/udevd.c
index 5c757d513f..615c4ed3e2 100644
--- a/src/udev/udevd.c
+++ b/src/udev/udevd.c
@@ -648,7 +648,7 @@ static bool is_devpath_busy(Manager *manager, struct event *event) {
/* check if queue contains events we depend on */
LIST_FOREACH(event, loop_event, manager->events) {
- /* we already found a later event, earlier can not block us, no need to check again */
+ /* we already found a later event, earlier cannot block us, no need to check again */
if (loop_event->seqnum < event->delaying_seqnum)
continue;