diff options
author | Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl> | 2018-02-09 17:08:23 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-02-09 17:08:23 +0100 |
commit | 91761b1846a210323a83e2030ad88a9be5294ce2 (patch) | |
tree | a19cb07e26d2b09a29c9be3edaefbb3b1aff5bb9 | |
parent | 73969ab61c39357e6892747e43307fbf07cafbed (diff) | |
parent | 230cc99a0f84bc0a5d9d974f665a81060b264a70 (diff) | |
download | systemd-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.xml | 30 | ||||
-rw-r--r-- | man/systemd.generator.xml | 349 | ||||
-rw-r--r-- | man/systemd.unit.xml | 115 | ||||
-rw-r--r-- | shell-completion/bash/systemd-analyze | 10 | ||||
-rw-r--r-- | shell-completion/zsh/_systemd-analyze | 2 | ||||
-rw-r--r-- | src/analyze/analyze.c | 116 | ||||
-rw-r--r-- | src/libsystemd-network/sd-dhcp-client.c | 12 | ||||
-rw-r--r-- | src/libudev/libudev-device.c | 4 | ||||
-rw-r--r-- | src/network/netdev/vxlan.c | 4 | ||||
-rw-r--r-- | src/network/networkd-address.c | 2 | ||||
-rw-r--r-- | src/network/networkd-ipv6-proxy-ndp.c | 2 | ||||
-rw-r--r-- | src/network/networkd-network.c | 8 | ||||
-rw-r--r-- | src/shared/path-lookup.c | 27 | ||||
-rw-r--r-- | src/test/test-path-lookup.c | 32 | ||||
-rw-r--r-- | src/timedate/timedatectl.c | 2 | ||||
-rw-r--r-- | src/timesync/timesyncd.c | 2 | ||||
-rw-r--r-- | src/udev/cdrom_id/cdrom_id.c | 4 | ||||
-rw-r--r-- | src/udev/udev-node.c | 2 | ||||
-rw-r--r-- | src/udev/udevd.c | 2 |
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(×.unitsload_start_time, times.reverse_offset); subtract_timestamp(×.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; |