1
0
mirror of https://github.com/systemd/systemd synced 2025-10-09 13:44:44 +02:00

Compare commits

...

17 Commits

Author SHA1 Message Date
Zbigniew Jędrzejewski-Szmek
a2123bf9d4
man: improve Description= documentation (#38101)
Fixes: #36165
2025-07-07 11:56:09 +02:00
Lennart Poettering
172dd81e92 man: improve Description= documentation
This is an attempt to address the issues raised in #36165.

Fixes: #36165
2025-07-07 11:21:25 +02:00
Lennart Poettering
d03714e4e4 tree-wide: "human readable" → "human-readable"
Apparently, the spelling with a hyphen is better style in the English
language.

Suggested by: #36165
2025-07-07 11:21:25 +02:00
dependabot[bot]
663108304a build(deps): bump github/codeql-action from 3.28.18 to 3.29.2
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 3.28.18 to 3.29.2.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](ff0a06e83c...181d5eefc2)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-version: 3.29.2
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-07 17:36:42 +09:00
Lennart Poettering
64a78cb082
Unify error messages for transient settings, fix handling of Ex variants (#38083) 2025-07-07 09:39:40 +02:00
Daan De Meyer
c97fd65417
Explicitly include more headers (#38100)
Continuation of 4f18ff2e29b8054f30b084abcabf5f689f4b340b.
2025-07-07 08:26:46 +02:00
Yu Watanabe
10b0bc476b timesync,test: explicitly include sys/timex.h when struct timex is used
struct timex is defined by sys/timex.h -> bits/timex.h.
Glibc includes the header in time.h, but let's explicitly include it
when the struct is used.

Similar to 4f18ff2e29b8054f30b084abcabf5f689f4b340b, but for sys/timex.h.
2025-07-07 12:44:18 +09:00
Yu Watanabe
83a047fe23 tree-wide: include sys/stat.h where necessary
These source files uses symbols provided by sys/stat.h, e.g. struct stat,
S_IFREG, S_IFBLK, and so on. Let's explicitly include sys/stat.h where
necessary.

Glibc's fcntl.h includes bits/stat.h, which provides these symbols, so
these symbols can be used without explicitly including sys/stat.h. But,
based on the discussion in #37922, we should explicitly include relevant
headers, and should not rely on the indirect inclusion.

Similar to 4f18ff2e29b8054f30b084abcabf5f689f4b340b, but for sys/stat.h.
2025-07-07 12:44:10 +09:00
Zbigniew Jędrzejewski-Szmek
228d84e37a systemd-analyze: stop printing Ex transient settings
The test will fail if we ever add one again in the future by mistake.
2025-07-06 18:17:47 +02:00
Zbigniew Jędrzejewski-Szmek
41288f2daf shared/bus-unit-util: fix PrivateTmp=/PrivateUsers=/ProtectControlGroups= and Ex variants
For some fields, we perform careful parsing and verification on the sender
side. For other fields, we accept any string or strv. I think that actually
this is fine: we should optimize for the correct case, i.e. the user runs a
command that is valid. The server must perform parsing in all cases, so doing
the verification on the sender side doesn't add value. When doing parsing
locally, in case of invalid or unsupported input, we would generate the error
message locally, so we would avoid the D-Bus call, but the message itself is
not better and from the user's point of view, the result is the same. And by
doing the parsing only on the server side, we deal better with the case where
the sender has an older version of the software. By not doing verification, we
implicitly "support" new values. And when the sender has a newer version that
supports additional fields, that does not help as long as the server uses an
older version. So in case of version mismatches, parsing on the server side is
as good or better.

Resolves https://github.com/systemd/systemd/issues/37174.
2025-07-06 18:17:45 +02:00
Zbigniew Jędrzejewski-Szmek
fb98c75e0e shared/bus-unit-util: tweak bus_append_exec_command to use Ex prop only if necessary
This changes little in behaviour, the conceptual part is more important. The
non-Ex variant is the actual name on the command line, and we should use the
non-Ex D-Bus property too, if it works. This increases compatibility with old
versions. But the code was mostly doing the right thing. Even the tests tested
the right thing.

Follow-up for b3d593673c5b8b0b7d781fd26ab2062ca6e7dbdb and
898fc00e794d714e2f01409bef440d910c22502a.

The test is simplified by taking advantage of the fact that both names
on the commandline are supposed to behave identically.

Partially resolves https://github.com/systemd/systemd/issues/37174.
2025-07-06 18:17:43 +02:00
Zbigniew Jędrzejewski-Szmek
6f06afde59 shared/bus-unit-util: rework error messages for NFTSet=
Let's be nice to the user and print the exact reason why we won't accept
a setting.
2025-07-06 18:06:51 +02:00
Zbigniew Jędrzejewski-Szmek
95a3cfcbf6 shared/bus-unit-util: rework error messages
We generally want to have error messages with a fixed structure that convey the
important information, i.e. field name, error value, and the offending text for
options that take short values. (The text is not printed for strings encoded with
base64 and hexmem or for credentials.)

Let's use a helper that prints the message in a fixed format in the majority of
cases. In the few places where a custom message is useful, the helper is not
used. The helper:
- prints the field name, value, and error info,
- quotes the value,
- handles -ENOMEM, so we don't need to handle it separately everywhere.

When this code was originally written, parse functions would return -1
as error. Nowadays day all return a good errno, so it is fine if we print
the corresponding strerror.
2025-07-06 18:06:49 +02:00
Zbigniew Jędrzejewski-Szmek
ce120ac823 shared/bus-unit-util: tweak error handling in bus_append_exec_command
exec_command_flags_to_strv() should not fail, unless we screwed up, so assert
instead of returning an error. Also, no need to strdup constant _PATH_BSHELL;
drop that so that we can get rid of the oom error handling. Finally, rename
l → cmdline for clarity.
2025-07-06 17:47:11 +02:00
Zbigniew Jędrzejewski-Szmek
8d853534ed shared/bus-unit-util: also send empty array for LogFilterPatterns=
Before, for empty input, we'd send an array with one item with an empty
pattern. Use the helper which sends an empty array instead.
bus_exec_context_set_transient_property() ignores items with an empty
pattern, so the result should be the same.

Request in review:
https://github.com/systemd/systemd/pull/37665#discussion_r2182375988.
2025-07-04 12:14:27 +02:00
Zbigniew Jędrzejewski-Szmek
743b09c42c test-bus-unit-util: add a test that attempts to serialize all know transient settings
The samples were partially generated using claude.ai. Those examples are
usually fairly boring. I tried to remove obvious repetitions and add some more
interesting examples, but certainly more edge cases could be added.

In some cases, we are quite lenient and do almost no verification on the sender
side.
2025-07-04 12:14:27 +02:00
Zbigniew Jędrzejewski-Szmek
892a24d42c shared/bus-unit-util: check errors before other conditions
As requested in post-merge review in
https://github.com/systemd/systemd/pull/37665#discussion_r2183755909.
2025-07-04 12:14:27 +02:00
33 changed files with 1396 additions and 241 deletions

View File

@ -68,7 +68,7 @@ jobs:
path: ./out/artifacts path: ./out/artifacts
- name: Upload Sarif - name: Upload Sarif
if: always() && steps.build.outcome == 'success' if: always() && steps.build.outcome == 'success'
uses: github/codeql-action/upload-sarif@ff0a06e83cb2de871e5a09832bc6a81e7276941f uses: github/codeql-action/upload-sarif@181d5eefc20863364f96762470ba6f862bdef56b
with: with:
# Path to SARIF file relative to the root of the repository # Path to SARIF file relative to the root of the repository
sarif_file: cifuzz-sarif/results.sarif sarif_file: cifuzz-sarif/results.sarif

View File

@ -45,7 +45,7 @@ jobs:
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
- name: Initialize CodeQL - name: Initialize CodeQL
uses: github/codeql-action/init@ff0a06e83cb2de871e5a09832bc6a81e7276941f uses: github/codeql-action/init@181d5eefc20863364f96762470ba6f862bdef56b
with: with:
languages: ${{ matrix.language }} languages: ${{ matrix.language }}
config-file: ./.github/codeql-config.yml config-file: ./.github/codeql-config.yml
@ -53,7 +53,7 @@ jobs:
- run: sudo -E .github/workflows/unit_tests.sh SETUP - run: sudo -E .github/workflows/unit_tests.sh SETUP
- name: Autobuild - name: Autobuild
uses: github/codeql-action/autobuild@ff0a06e83cb2de871e5a09832bc6a81e7276941f uses: github/codeql-action/autobuild@181d5eefc20863364f96762470ba6f862bdef56b
- name: Perform CodeQL Analysis - name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@ff0a06e83cb2de871e5a09832bc6a81e7276941f uses: github/codeql-action/analyze@181d5eefc20863364f96762470ba6f862bdef56b

6
NEWS
View File

@ -871,7 +871,7 @@ CHANGES WITH 258 in spe:
* userdbctl gained a new switch --from-file=. If used the tool will not * userdbctl gained a new switch --from-file=. If used the tool will not
look up a user or group record from the system's user database but look up a user or group record from the system's user database but
instead read it from the specified JSON file, and then present it in instead read it from the specified JSON file, and then present it in
the usual, human readable fashion. the usual, human-readable fashion.
* systemd-homed gained D-Bus API calls for listing, adding, removing and * systemd-homed gained D-Bus API calls for listing, adding, removing and
showing use record signing keys. showing use record signing keys.
@ -8016,7 +8016,7 @@ CHANGES WITH 248:
* systemd-hostnamed now exports the "HardwareVendor" and * systemd-hostnamed now exports the "HardwareVendor" and
"HardwareModel" D-Bus properties, which are supposed to contain a "HardwareModel" D-Bus properties, which are supposed to contain a
pair of cleaned up, human readable strings describing the system's pair of cleaned up, human-readable strings describing the system's
vendor and model. It's typically sourced from the firmware's DMI vendor and model. It's typically sourced from the firmware's DMI
tables, but may be augmented from a new hwdb database. hostnamectl tables, but may be augmented from a new hwdb database. hostnamectl
shows this in the status output. shows this in the status output.
@ -15502,7 +15502,7 @@ CHANGES WITH 220:
journal-nocow.conf tmpfiles file. journal-nocow.conf tmpfiles file.
* systemd-journald will now translate audit message types to * systemd-journald will now translate audit message types to
human readable identifiers when writing them to the human-readable identifiers when writing them to the
journal. This should improve readability of audit messages. journal. This should improve readability of audit messages.
* The LUKS logic gained support for the offset= and skip= * The LUKS logic gained support for the offset= and skip=

View File

@ -51,7 +51,7 @@ The text format of the .catalog files is as follows:
* Simple, UTF-8 text files, with usual line breaks at 76 chars. * Simple, UTF-8 text files, with usual line breaks at 76 chars.
URLs and suchlike where line-breaks are undesirable may use longer lines. URLs and suchlike where line-breaks are undesirable may use longer lines.
As catalog files need to be usable on text consoles it is essential that the 76 char line break rule is otherwise followed for human readable text. As catalog files need to be usable on text consoles it is essential that the 76 char line break rule is otherwise followed for human-readable text.
* Lines starting with `#` are ignored, and may be used for comments. * Lines starting with `#` are ignored, and may be used for comments.
* The files consist of a series of entries. * The files consist of a series of entries.
@ -63,7 +63,7 @@ The text format of the .catalog files is as follows:
Some header fields may appear more than once per entry. Some header fields may appear more than once per entry.
The following header fields are currently known (but additional fields may be added later): The following header fields are currently known (but additional fields may be added later):
* Subject: A short, one-line human readable description of the message * Subject: A short, one-line human-readable description of the message
* Defined-By: Who defined this message. * Defined-By: Who defined this message.
Usually a package name or suchlike Usually a package name or suchlike
@ -71,7 +71,7 @@ The text format of the .catalog files is as follows:
This can be a web URL or a telephone number in the tel:// namespace This can be a web URL or a telephone number in the tel:// namespace
* Documentation: URIs for further user, administrator or developer documentation on the log entry. URIs should be listed in order of relevance, the most relevant documentation first. * Documentation: URIs for further user, administrator or developer documentation on the log entry. URIs should be listed in order of relevance, the most relevant documentation first.
* An empty line * An empty line
* The actual catalog entry payload, as human readable prose. * The actual catalog entry payload, as human-readable prose.
Multiple paragraphs may be separated by empty lines. Multiple paragraphs may be separated by empty lines.
The prose should first describe the message and when it occurs, possibly followed by recommendations how to deal with the message and (if it is an error message) correct the problem at hand. The prose should first describe the message and when it occurs, possibly followed by recommendations how to deal with the message and (if it is an error message) correct the problem at hand.
This message text should be readable by users and administrators. This message text should be readable by users and administrators.

View File

@ -18,7 +18,7 @@ The stable interfaces are:
* **The command line interface** of `systemd`, `systemctl`, `loginctl`, `journalctl`, and all other command line utilities installed in `$PATH` and documented in a man page. * **The command line interface** of `systemd`, `systemctl`, `loginctl`, `journalctl`, and all other command line utilities installed in `$PATH` and documented in a man page.
We will make sure that scripts invoking these commands will continue to work with future versions of systemd. We will make sure that scripts invoking these commands will continue to work with future versions of systemd.
Note however that the output generated by these commands is generally not included in the promise, unless it is documented in the man page. Note however that the output generated by these commands is generally not included in the promise, unless it is documented in the man page.
Example: the output of `systemctl status` is not stable, but that of `systemctl show` is, because the former is intended to be human readable and the latter computer readable, and this is documented in the man page. Example: the output of `systemctl status` is not stable, but that of `systemctl show` is, because the former is intended to be human-readable and the latter computer readable, and this is documented in the man page.
* **The protocol spoken on the socket referred to by `$NOTIFY_SOCKET`**, as documented in * **The protocol spoken on the socket referred to by `$NOTIFY_SOCKET`**, as documented in
[sd_notify(3)](https://www.freedesktop.org/software/systemd/man/sd_notify.html). Note that, although using [sd_notify(3)](https://www.freedesktop.org/software/systemd/man/sd_notify.html). Note that, although using

View File

@ -52,7 +52,7 @@
matching specified characteristics. If no command is matching specified characteristics. If no command is
specified, this is the implied default.</para> specified, this is the implied default.</para>
<para>The output is designed to be human readable and contains a table with the following <para>The output is designed to be human-readable and contains a table with the following
columns:</para> columns:</para>
<variablelist> <variablelist>
<varlistentry> <varlistentry>

View File

@ -138,7 +138,7 @@
<literal>short</literal> or <literal>off</literal>. If <literal>pretty</literal> human-friendly <literal>short</literal> or <literal>off</literal>. If <literal>pretty</literal> human-friendly
whitespace and newlines are inserted in the output to make the JSON data more readable. If whitespace and newlines are inserted in the output to make the JSON data more readable. If
<literal>short</literal> all superfluous whitespace is suppressed. If <literal>off</literal> (the <literal>short</literal> all superfluous whitespace is suppressed. If <literal>off</literal> (the
default) the user information is not shown in JSON format but in a friendly human readable formatting default) the user information is not shown in JSON format but in a friendly human-readable formatting
instead. The <option>-j</option> option picks <literal>pretty</literal> when run interactively and instead. The <option>-j</option> option picks <literal>pretty</literal> when run interactively and
<literal>short</literal> otherwise.</para> <literal>short</literal> otherwise.</para>

View File

@ -743,8 +743,8 @@ node /org/freedesktop/login1 {
<literal>handle-suspend-key</literal>, <literal>handle-hibernate-key</literal>, <literal>handle-suspend-key</literal>, <literal>handle-hibernate-key</literal>,
<literal>handle-lid-switch</literal>, separated by colons, for inhibiting poweroff/reboot, <literal>handle-lid-switch</literal>, separated by colons, for inhibiting poweroff/reboot,
suspend/hibernate, the automatic idle logic, or hardware key handling. <varname>who</varname> should be suspend/hibernate, the automatic idle logic, or hardware key handling. <varname>who</varname> should be
a short human readable string identifying the application taking the lock. <varname>why</varname> a short human-readable string identifying the application taking the lock. <varname>why</varname>
should be a short human readable string identifying the reason why the lock is taken. Finally, should be a short human-readable string identifying the reason why the lock is taken. Finally,
<varname>mode</varname> is either <literal>block</literal> or <literal>delay</literal> which encodes <varname>mode</varname> is either <literal>block</literal> or <literal>delay</literal> which encodes
whether the inhibit shall be consider mandatory or whether it should just delay the operation to a whether the inhibit shall be consider mandatory or whether it should just delay the operation to a
certain maximum time, while the <literal>block-weak</literal> and variants will create an inhibitor certain maximum time, while the <literal>block-weak</literal> and variants will create an inhibitor

View File

@ -1370,7 +1370,7 @@ node /org/freedesktop/systemd1 {
<itemizedlist> <itemizedlist>
<listitem><para>The primary unit name as string</para></listitem> <listitem><para>The primary unit name as string</para></listitem>
<listitem><para>The human readable description string</para></listitem> <listitem><para>The human-readable description string</para></listitem>
<listitem><para>The load state (i.e. whether the unit file has been loaded <listitem><para>The load state (i.e. whether the unit file has been loaded
successfully)</para></listitem> successfully)</para></listitem>
@ -2518,7 +2518,7 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
the dependencies and their inverse dependencies (where this applies) as configured in the unit file or the dependencies and their inverse dependencies (where this applies) as configured in the unit file or
determined automatically.</para> determined automatically.</para>
<para><varname>Description</varname> contains the human readable description string for the <para><varname>Description</varname> contains the human-readable description string for the
unit.</para> unit.</para>
<para><varname>SourcePath</varname> contains the path to a configuration file this unit is <para><varname>SourcePath</varname> contains the path to a configuration file this unit is
@ -2638,7 +2638,7 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
<para><varname>LoadError</varname> contains a pair of strings. If the unit failed to load (as encoded <para><varname>LoadError</varname> contains a pair of strings. If the unit failed to load (as encoded
in <varname>LoadState</varname>, see above), then this will include a D-Bus error pair consisting of in <varname>LoadState</varname>, see above), then this will include a D-Bus error pair consisting of
the error ID and an explanatory human readable string of what happened. If it loaded successfully, this the error ID and an explanatory human-readable string of what happened. If it loaded successfully, this
will be a pair of empty strings.</para> will be a pair of empty strings.</para>
<para><varname>Transient</varname> contains a boolean that indicates whether the unit was created as a <para><varname>Transient</varname> contains a boolean that indicates whether the unit was created as a

View File

@ -455,7 +455,7 @@
produces the OS. This field is optional.</para> produces the OS. This field is optional.</para>
<para>This name is intended to be exposed in "About this system" UIs or software update UIs when <para>This name is intended to be exposed in "About this system" UIs or software update UIs when
needed to distinguish the OS vendor from the OS itself. It is intended to be human readable.</para> needed to distinguish the OS vendor from the OS itself. It is intended to be human-readable.</para>
<para>Examples: <literal>VENDOR_NAME="Fedora Project"</literal> for Fedora Linux, <para>Examples: <literal>VENDOR_NAME="Fedora Project"</literal> for Fedora Linux,
<literal>VENDOR_NAME="Canonical"</literal> for Ubuntu.</para> <literal>VENDOR_NAME="Canonical"</literal> for Ubuntu.</para>

View File

@ -76,7 +76,7 @@
example an error name such as example an error name such as
<literal>org.freedesktop.DBus.Error.NotSupported</literal> or the equivalent <literal>org.freedesktop.DBus.Error.NotSupported</literal> or the equivalent
symbolic <constant>SD_BUS_ERROR_NOT_SUPPORTED</constant>), and the symbolic <constant>SD_BUS_ERROR_NOT_SUPPORTED</constant>), and the
<parameter>message</parameter> field is set as the human readable error message <parameter>message</parameter> field is set as the human-readable error message
string if present. The error <parameter>e</parameter> must have the string if present. The error <parameter>e</parameter> must have the
<parameter>name</parameter> field set, see <parameter>name</parameter> field set, see
<citerefentry><refentrytitle>sd_bus_error_is_set</refentrytitle><manvolnum>3</manvolnum></citerefentry>. <citerefentry><refentrytitle>sd_bus_error_is_set</refentrytitle><manvolnum>3</manvolnum></citerefentry>.

View File

@ -161,7 +161,7 @@
<varlistentry> <varlistentry>
<term><option>--status=</option></term> <term><option>--status=</option></term>
<listitem><para>Send a free-form human readable status string for the daemon to the service <listitem><para>Send a free-form human-readable status string for the daemon to the service
manager. This option takes the status string as argument. This is equivalent to manager. This option takes the status string as argument. This is equivalent to
<command>systemd-notify STATUS=…</command>. For details about the semantics of this option see <command>systemd-notify STATUS=…</command>. For details about the semantics of this option see
<citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry>. This <citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry>. This

View File

@ -374,7 +374,7 @@
similar format as <literal>.osrel</literal> (i.e. an environment-variable-assignment-block-like list of similar format as <literal>.osrel</literal> (i.e. an environment-variable-assignment-block-like list of
newline separated strings). Currently two fields are defined: <literal>ID=</literal> is supposed to carry newline separated strings). Currently two fields are defined: <literal>ID=</literal> is supposed to carry
a short identifying string that identifies the profile a short identifying string that identifies the profile
(e.g. <literal>ID=factory-reset</literal>). <literal>TITLE=</literal> should contain a human readable (e.g. <literal>ID=factory-reset</literal>). <literal>TITLE=</literal> should contain a human-readable
string that may appear in the boot menu entry for this profile (e.g. <literal>TITLE='Factory Reset this string that may appear in the boot menu entry for this profile (e.g. <literal>TITLE='Factory Reset this
Device'</literal>).</para> Device'</literal>).</para>
</refsect1> </refsect1>

View File

@ -597,19 +597,21 @@
<variablelist class='unit-directives'> <variablelist class='unit-directives'>
<varlistentry> <varlistentry>
<term><varname>Description=</varname></term> <term><varname>Description=</varname></term>
<listitem><para>A short human readable title of the unit. This may be used by <listitem><para>A brief, meaningful, human-readable text identifying the unit. This may be used by
<command>systemd</command> (and other UIs) as a user-visible label for the unit, so this string <command>systemd</command> (and suitable UIs) as a user-visible label for the unit, so this string
should identify the unit rather than describe it, despite the name. This string also should not just should identify the unit rather than just describe it, despite the name. This string also should not
repeat the unit name. <literal>Apache2 Web Server</literal> is a good example. Bad examples are just repeat the unit name. <literal>Apache HTTP Server</literal> or <literal>Postfix Mail
<literal>high-performance lightweight HTTP server</literal> (too generic) or Server</literal> are good examples. Bad examples are <literal>high-performance lightweight HTTP
<literal>Apache2</literal> (meaningless for people who do not know Apache, duplicates the unit server</literal> (too generic) or <literal>Apache</literal> (meaningless for people who do not know
name). <command>systemd</command> may use this string as a noun in status messages (<literal>Starting the Apache HTTP server project, duplicates the unit name). <command>systemd</command> may use this
<replaceable>description</replaceable>...</literal>, <literal>Started string as a noun in status messages (<literal>Starting
<replaceable>description</replaceable>.</literal>, <literal>Reached target <replaceable>Description</replaceable>...</literal>, <literal>Started
<replaceable>description</replaceable>.</literal>, <literal>Failed to start <replaceable>Description</replaceable>.</literal>, <literal>Reached target
<replaceable>description</replaceable>.</literal>), so it should be capitalized, and should not be a <replaceable>Description</replaceable>.</literal>, <literal>Failed to start
full sentence, or a phrase with a continuous verb. Bad examples include <literal>exiting the <replaceable>Description</replaceable>.</literal>), so it should be capitalized, and should not be a
container</literal> or <literal>updating the database once per day.</literal>.</para> full sentence, or a phrase with a verb conjugated in the present continuous, or end in a full
stop. Bad examples include <literal>exiting the container</literal>, <literal>updating the database
once per day.</literal>, or <literal>OpenSSH server second instance daemon</literal>.</para>
<xi:include href="version-info.xml" xpointer="v201"/> <xi:include href="version-info.xml" xpointer="v201"/>
</listitem> </listitem>
@ -2563,7 +2565,7 @@ ExecStart=/usr/sbin/foo-daemon
the following contents:</para> the following contents:</para>
<programlisting>[Unit] <programlisting>[Unit]
Description=Some HTTP server Description=Some HTTP Server
After=remote-fs.target sqldb.service After=remote-fs.target sqldb.service
Requires=sqldb.service Requires=sqldb.service
AssertPathExists=/srv/webserver AssertPathExists=/srv/webserver
@ -2595,7 +2597,7 @@ WantedBy=multi-user.target</programlisting>
change the chosen settings:</para> change the chosen settings:</para>
<programlisting>[Unit] <programlisting>[Unit]
Description=Some HTTP server Description=Some HTTP Server
After=remote-fs.target sqldb.service <emphasis>memcached.service</emphasis> After=remote-fs.target sqldb.service <emphasis>memcached.service</emphasis>
Requires=sqldb.service <emphasis>memcached.service</emphasis> Requires=sqldb.service <emphasis>memcached.service</emphasis>
AssertPathExists=<emphasis>/srv/www</emphasis> AssertPathExists=<emphasis>/srv/www</emphasis>
@ -2653,7 +2655,7 @@ PrivateTmp=yes</programlisting>
<filename index='false'>/etc/systemd/system/failure-handler@.service</filename>:</para> <filename index='false'>/etc/systemd/system/failure-handler@.service</filename>:</para>
<programlisting>[Unit] <programlisting>[Unit]
Description=My failure handler for %i Description=My Failure Handler For %i
[Service] [Service]
Type=oneshot Type=oneshot

View File

@ -71,7 +71,7 @@
<varlistentry> <varlistentry>
<term><varname>Description=</varname></term> <term><varname>Description=</varname></term>
<listitem><para>A short human readable description of this feature. <listitem><para>A short human-readable description of this feature.
This may be used as a label for this feature, so the string should meaningfully identify the feature This may be used as a label for this feature, so the string should meaningfully identify the feature
among the features available in <filename>sysupdate.d/</filename>.</para> among the features available in <filename>sysupdate.d/</filename>.</para>

View File

@ -61,7 +61,7 @@
<literal>friendly</literal>, <literal>table</literal> or <literal>json</literal>. If <literal>friendly</literal>, <literal>table</literal> or <literal>json</literal>. If
<literal>classic</literal>, an output very close to the format of <filename>/etc/passwd</filename> or <literal>classic</literal>, an output very close to the format of <filename>/etc/passwd</filename> or
<filename>/etc/group</filename> is generated. If <literal>friendly</literal>, a more comprehensive and <filename>/etc/group</filename> is generated. If <literal>friendly</literal>, a more comprehensive and
user friendly, human readable output is generated. If <literal>table</literal>, a minimal, tabular user friendly, human-readable output is generated. If <literal>table</literal>, a minimal, tabular
output is generated. If <literal>json</literal>, a JSON formatted output is generated. Defaults to output is generated. If <literal>json</literal>, a JSON formatted output is generated. Defaults to
<literal>friendly</literal> if a user/group is specified on the command line, <literal>friendly</literal> if a user/group is specified on the command line,
<literal>table</literal> otherwise.</para> <literal>table</literal> otherwise.</para>

View File

@ -1,5 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <sys/stat.h>
#include <unistd.h> #include <unistd.h>
#include "alloc-util.h" #include "alloc-util.h"

View File

@ -100,9 +100,9 @@ typedef struct BootEntry {
char16_t *id; /* The unique identifier for this entry (typically the filename of the file defining the entry, possibly suffixed with a profile id) */ char16_t *id; /* The unique identifier for this entry (typically the filename of the file defining the entry, possibly suffixed with a profile id) */
char16_t *id_without_profile; /* same, but without any profile id suffixed */ char16_t *id_without_profile; /* same, but without any profile id suffixed */
char16_t *title_show; /* The string to actually display (this is made unique before showing) */ char16_t *title_show; /* The string to actually display (this is made unique before showing) */
char16_t *title; /* The raw (human readable) title string of the entry (not necessarily unique) */ char16_t *title; /* The raw (human-readable) title string of the entry (not necessarily unique) */
char16_t *sort_key; /* The string to use as primary sort key, usually ID= from os-release, possibly suffixed */ char16_t *sort_key; /* The string to use as primary sort key, usually ID= from os-release, possibly suffixed */
char16_t *version; /* The raw (human readable) version string of the entry */ char16_t *version; /* The raw (human-readable) version string of the entry */
char16_t *machine_id; char16_t *machine_id;
EFI_HANDLE *device; EFI_HANDLE *device;
LoaderType type; LoaderType type;

View File

@ -1,6 +1,7 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <getopt.h> #include <getopt.h>
#include <sys/stat.h>
#include "sd-varlink.h" #include "sd-varlink.h"

View File

@ -2393,7 +2393,7 @@ static int unit_log_resources(Unit *u) {
return log_oom(); return log_oom();
/* Invoked whenever a unit enters failed or dead state. Logs information about consumed resources if resource /* Invoked whenever a unit enters failed or dead state. Logs information about consumed resources if resource
* accounting was enabled for a unit. It does this in two ways: a friendly human readable string with reduced * accounting was enabled for a unit. It does this in two ways: a friendly human-readable string with reduced
* information and the complete data in structured fields. */ * information and the complete data in structured fields. */
(void) unit_get_cpu_usage(u, &cpu_nsec); (void) unit_get_cpu_usage(u, &cpu_nsec);

View File

@ -17,8 +17,8 @@ bool bootspec_pick_name_version_sort_key(
const sd_char *good_name, *good_version, *good_sort_key; const sd_char *good_name, *good_version, *good_sort_key;
/* Find the best human readable title, version string and sort key for a boot entry (using the /* Find the best human-readable title, version string and sort key for a boot entry (using the
* os-release(5) fields). Precise is preferred over vague, and human readable over machine * os-release(5) fields). Precise is preferred over vague, and human-readable over machine
* readable. Thus: * readable. Thus:
* *
* 1. First priority gets the PRETTY_NAME field, which is the primary string intended for display, * 1. First priority gets the PRETTY_NAME field, which is the primary string intended for display,
@ -28,7 +28,7 @@ bool bootspec_pick_name_version_sort_key(
* 2. Otherwise we go for IMAGE_ID and IMAGE_VERSION (thus we show details about the image, * 2. Otherwise we go for IMAGE_ID and IMAGE_VERSION (thus we show details about the image,
* i.e. specific combination of packages and configuration), if that concept applies. * i.e. specific combination of packages and configuration), if that concept applies.
* *
* 3. Otherwise we go for NAME and VERSION (i.e. human readable OS name and version) * 3. Otherwise we go for NAME and VERSION (i.e. human-readable OS name and version)
* *
* 4. Otherwise we go for ID and VERSION_ID (i.e. machine readable OS name and version) * 4. Otherwise we go for ID and VERSION_ID (i.e. machine readable OS name and version)
* *

View File

@ -2,6 +2,7 @@
#pragma once #pragma once
#include <fcntl.h> #include <fcntl.h>
#include <sys/stat.h>
#include "compress.h" #include "compress.h"
#include "forward.h" #include "forward.h"

View File

@ -2,6 +2,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <sys/mman.h> #include <sys/mman.h>
#include <sys/stat.h>
#include "alloc-util.h" #include "alloc-util.h"
#include "bitfield.h" #include "bitfield.h"

View File

@ -5,6 +5,7 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <sys/resource.h> #include <sys/resource.h>
#include <sys/stat.h>
#include <unistd.h> #include <unistd.h>
#include "sd-bus.h" #include "sd-bus.h"

View File

@ -19,7 +19,7 @@ typedef enum AskPasswordFlags {
/* Encapsulates the mostly static fields of a password query */ /* Encapsulates the mostly static fields of a password query */
typedef struct AskPasswordRequest { typedef struct AskPasswordRequest {
const char *message; /* The human readable password prompt when asking interactively */ const char *message; /* The human-readable password prompt when asking interactively */
const char *keyring; /* kernel keyring key name (key of "user" type) */ const char *keyring; /* kernel keyring key name (key of "user" type) */
const char *icon; /* freedesktop icon spec name */ const char *icon; /* freedesktop icon spec name */
const char *id; /* some identifier used for this prompt for the "ask-password" protocol */ const char *id; /* some identifier used for this prompt for the "ask-password" protocol */

View File

@ -76,6 +76,17 @@ static int warn_deprecated(_unused_ sd_bus_message *m, const char *field, const
return 1; return 1;
} }
static int parse_log_error(int error, const char *field, const char *eq) {
if (error == -ENOMEM)
return log_oom();
if (error != 0) /* Allow SYNTHETIC_ERRNO to be used, i.e. positive values. */
return log_error_errno(error, "Failed to parse %s= value '%s': %m", field, eq);
/* We don't log the error value for cases where we have a general "syntax error". */
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Invalid syntax for %s= value: '%s'", field, eq);
}
#define DEFINE_BUS_APPEND_PARSE_PTR(bus_type, cast_type, type, parse_func) \ #define DEFINE_BUS_APPEND_PARSE_PTR(bus_type, cast_type, type, parse_func) \
static int bus_append_##parse_func( \ static int bus_append_##parse_func( \
sd_bus_message *m, \ sd_bus_message *m, \
@ -86,7 +97,7 @@ static int warn_deprecated(_unused_ sd_bus_message *m, const char *field, const
\ \
r = parse_func(eq, &val); \ r = parse_func(eq, &val); \
if (r < 0) \ if (r < 0) \
return log_error_errno(r, "Failed to parse %s=%s: %m", field, eq); \ return parse_log_error(r, field, eq); \
\ \
r = sd_bus_message_append(m, "(sv)", field, \ r = sd_bus_message_append(m, "(sv)", field, \
bus_type, (cast_type) val); \ bus_type, (cast_type) val); \
@ -105,7 +116,7 @@ static int warn_deprecated(_unused_ sd_bus_message *m, const char *field, const
\ \
r = parse_func(eq); \ r = parse_func(eq); \
if (r < 0) \ if (r < 0) \
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to parse %s: %s", field, eq); \ return parse_log_error(r, field, eq); \
\ \
r = sd_bus_message_append(m, "(sv)", field, \ r = sd_bus_message_append(m, "(sv)", field, \
bus_type, (int32_t) r); \ bus_type, (int32_t) r); \
@ -175,10 +186,8 @@ static int bus_append_strv_full(sd_bus_message *m, const char *field, const char
_cleanup_free_ char *word = NULL; _cleanup_free_ char *word = NULL;
r = extract_first_word(&p, &word, /* separators= */ NULL, flags); r = extract_first_word(&p, &word, /* separators= */ NULL, flags);
if (r == -ENOMEM)
return log_oom();
if (r < 0) if (r < 0)
return log_error_errno(r, "Invalid syntax: %s", eq); return parse_log_error(r, field, eq);
if (r == 0) if (r == 0)
break; break;
@ -248,7 +257,7 @@ static int bus_append_parse_sec_rename(sd_bus_message *m, const char *field, con
r = parse_sec(eq, &t); r = parse_sec(eq, &t);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to parse %s=%s: %m", field, eq); return parse_log_error(r, field, eq);
l = strlen(field); l = strlen(field);
n = newa(char, l + 2); n = newa(char, l + 2);
@ -272,7 +281,7 @@ static int bus_append_parse_size(sd_bus_message *m, const char *field, const cha
r = parse_size(eq, /* base= */ 1024, &v); r = parse_size(eq, /* base= */ 1024, &v);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to parse %s=%s: %m", field, eq); return parse_log_error(r, field, eq);
r = sd_bus_message_append(m, "(sv)", field, "t", v); r = sd_bus_message_append(m, "(sv)", field, "t", v);
if (r < 0) if (r < 0)
@ -286,7 +295,7 @@ static int bus_append_parse_permyriad(sd_bus_message *m, const char *field, cons
r = parse_permyriad(eq); r = parse_permyriad(eq);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to parse %s=%s: %m", field, eq); return parse_log_error(r, field, eq);
/* Pass around scaled to 2^32-1 == 100% */ /* Pass around scaled to 2^32-1 == 100% */
r = sd_bus_message_append(m, "(sv)", field, "u", UINT32_SCALE_FROM_PERMYRIAD(r)); r = sd_bus_message_append(m, "(sv)", field, "u", UINT32_SCALE_FROM_PERMYRIAD(r));
@ -304,7 +313,7 @@ static int bus_append_parse_cpu_set(sd_bus_message *m, const char *field, const
r = parse_cpu_set(eq, &cpuset); r = parse_cpu_set(eq, &cpuset);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to parse %s value: %s", field, eq); return parse_log_error(r, field, eq);
r = cpu_set_to_dbus(&cpuset, &array, &allocated); r = cpu_set_to_dbus(&cpuset, &array, &allocated);
if (r < 0) if (r < 0)
@ -375,10 +384,10 @@ static int bus_append_parse_cpu_quota(sd_bus_message *m, const char *field, cons
x = USEC_INFINITY; x = USEC_INFINITY;
else { else {
r = parse_permyriad_unbounded(eq); r = parse_permyriad_unbounded(eq);
if (r == 0)
return log_error_errno(SYNTHETIC_ERRNO(ERANGE), "%s value too small.", field);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to parse %s=%s: %m", field, eq); return parse_log_error(r, field, eq);
if (r == 0)
return parse_log_error(SYNTHETIC_ERRNO(ERANGE), field, eq);
x = r * USEC_PER_SEC / 10000U; x = r * USEC_PER_SEC / 10000U;
} }
@ -426,9 +435,7 @@ static int bus_try_append_parse_cgroup_io_limit(sd_bus_message *m, const char *f
else { else {
const char *e = strchr(eq, ' '); const char *e = strchr(eq, ' ');
if (!e) if (!e)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), return parse_log_error(0, field, eq);
"Failed to parse %s value %s.",
field, eq);
const char *bandwidth = e + 1; const char *bandwidth = e + 1;
_cleanup_free_ char *path = strndup(eq, e - eq); _cleanup_free_ char *path = strndup(eq, e - eq);
@ -441,7 +448,7 @@ static int bus_try_append_parse_cgroup_io_limit(sd_bus_message *m, const char *f
else { else {
r = parse_size(bandwidth, 1000, &bytes); r = parse_size(bandwidth, 1000, &bytes);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to parse byte value %s: %m", bandwidth); return parse_log_error(r, field, eq);
} }
r = sd_bus_message_append(m, "(sv)", field, "a(st)", 1, path, bytes); r = sd_bus_message_append(m, "(sv)", field, "a(st)", 1, path, bytes);
@ -460,9 +467,7 @@ static int bus_append_parse_io_device_weight(sd_bus_message *m, const char *fiel
else { else {
const char *e = strchr(eq, ' '); const char *e = strchr(eq, ' ');
if (!e) if (!e)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), return parse_log_error(0, field, eq);
"Failed to parse %s value %s.",
field, eq);
const char *weight = e + 1; const char *weight = e + 1;
_cleanup_free_ char *path = strndup(eq, e - eq); _cleanup_free_ char *path = strndup(eq, e - eq);
@ -472,7 +477,7 @@ static int bus_append_parse_io_device_weight(sd_bus_message *m, const char *fiel
uint64_t u; uint64_t u;
r = safe_atou64(weight, &u); r = safe_atou64(weight, &u);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to parse %s value %s: %m", field, weight); return parse_log_error(r, field, weight);
r = sd_bus_message_append(m, "(sv)", field, "a(st)", 1, path, u); r = sd_bus_message_append(m, "(sv)", field, "a(st)", 1, path, u);
} }
@ -491,9 +496,7 @@ static int bus_append_parse_io_device_latency(sd_bus_message *m, const char *fie
else { else {
const char *e = strchr(eq, ' '); const char *e = strchr(eq, ' ');
if (!e) if (!e)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), return parse_log_error(0, field, eq);
"Failed to parse %s value %s.",
field, eq);
const char *target = e + 1; const char *target = e + 1;
_cleanup_free_ char *path = strndup(eq, e - eq); _cleanup_free_ char *path = strndup(eq, e - eq);
@ -503,7 +506,7 @@ static int bus_append_parse_io_device_latency(sd_bus_message *m, const char *fie
usec_t usec; usec_t usec;
r = parse_sec(target, &usec); r = parse_sec(target, &usec);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to parse %s value %s: %m", field, target); return parse_log_error(r, field, target);
r = sd_bus_message_append(m, "(sv)", field_usec, "a(st)", 1, path, usec); r = sd_bus_message_append(m, "(sv)", field_usec, "a(st)", 1, path, usec);
} }
@ -522,10 +525,8 @@ static int bus_append_bpf_program(sd_bus_message *m, const char *field, const ch
_cleanup_free_ char *word = NULL; _cleanup_free_ char *word = NULL;
r = extract_first_word(&eq, &word, ":", 0); r = extract_first_word(&eq, &word, ":", 0);
if (r == -ENOMEM)
return log_oom();
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to parse %s: %m", field); return parse_log_error(r, field, eq);
r = sd_bus_message_append(m, "(sv)", field, "a(ss)", 1, word, eq); r = sd_bus_message_append(m, "(sv)", field, "a(ss)", 1, word, eq);
} }
@ -545,10 +546,8 @@ static int bus_append_socket_filter(sd_bus_message *m, const char *field, const
uint16_t nr_ports, port_min; uint16_t nr_ports, port_min;
r = parse_socket_bind_item(eq, &family, &ip_protocol, &nr_ports, &port_min); r = parse_socket_bind_item(eq, &family, &ip_protocol, &nr_ports, &port_min);
if (r == -ENOMEM)
return log_oom();
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to parse %s", field); return parse_log_error(r, field, eq);
r = sd_bus_message_append( r = sd_bus_message_append(
m, "(sv)", field, "a(iiqq)", 1, family, ip_protocol, nr_ports, port_min); m, "(sv)", field, "a(iiqq)", 1, family, ip_protocol, nr_ports, port_min);
@ -561,10 +560,9 @@ static int bus_append_socket_filter(sd_bus_message *m, const char *field, const
static int bus_append_exec_command(sd_bus_message *m, const char *field, const char *eq) { static int bus_append_exec_command(sd_bus_message *m, const char *field, const char *eq) {
bool explicit_path = false, done = false, ambient_hack = false; bool explicit_path = false, done = false, ambient_hack = false;
_cleanup_strv_free_ char **l = NULL, **ex_opts = NULL; _cleanup_strv_free_ char **cmdline = NULL, **ex_opts = NULL;
_cleanup_free_ char *path = NULL, *upgraded_name = NULL; _cleanup_free_ char *_path = NULL;
ExecCommandFlags flags = 0; ExecCommandFlags flags = 0;
bool is_ex_prop = endswith(field, "Ex");
int r; int r;
do { do {
@ -639,43 +637,40 @@ static int bus_append_exec_command(sd_bus_message *m, const char *field, const c
} }
} while (!done); } while (!done);
if (!is_ex_prop && (flags & (EXEC_COMMAND_NO_ENV_EXPAND|EXEC_COMMAND_FULLY_PRIVILEGED|EXEC_COMMAND_NO_SETUID|EXEC_COMMAND_VIA_SHELL))) { bool ex_prop = flags & (EXEC_COMMAND_NO_ENV_EXPAND|EXEC_COMMAND_FULLY_PRIVILEGED|EXEC_COMMAND_NO_SETUID|EXEC_COMMAND_VIA_SHELL);
/* Upgrade the ExecXYZ= property to ExecXYZEx= for convenience */ if (ex_prop) {
is_ex_prop = true; /* We need to use ExecXYZEx=. */
if (!endswith(field, "Ex"))
field = strjoina(field, "Ex");
upgraded_name = strjoin(field, "Ex");
if (!upgraded_name)
return log_oom();
field = upgraded_name;
}
if (is_ex_prop) {
r = exec_command_flags_to_strv(flags, &ex_opts); r = exec_command_flags_to_strv(flags, &ex_opts);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to convert ExecCommandFlags to strv: %m"); return log_error_errno(r, "Failed to serialize ExecCommand flags: %m");
} else {
if (endswith(field, "Ex"))
field = strndupa_safe(field, strlen(field) - 2);
} }
if (FLAGS_SET(flags, EXEC_COMMAND_VIA_SHELL)) { const char *path = NULL;
path = strdup(_PATH_BSHELL); if (FLAGS_SET(flags, EXEC_COMMAND_VIA_SHELL))
if (!path) path = _PATH_BSHELL;
return log_oom(); else if (explicit_path) {
r = extract_first_word(&eq, &_path, NULL, EXTRACT_UNQUOTE|EXTRACT_CUNESCAPE);
} else if (explicit_path) {
r = extract_first_word(&eq, &path, NULL, EXTRACT_UNQUOTE|EXTRACT_CUNESCAPE);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to parse path: %m"); return parse_log_error(r, field, eq);
if (r == 0) if (r == 0)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "No executable path specified, refusing."); return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "No executable path specified for %s=, refusing.", field);
if (isempty(eq)) if (isempty(eq))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Got empty command line, refusing."); return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Got empty command line for %s=, refusing.", field);
path = _path;
} }
r = strv_split_full(&l, eq, NULL, EXTRACT_UNQUOTE|EXTRACT_CUNESCAPE); r = strv_split_full(&cmdline, eq, NULL, EXTRACT_UNQUOTE|EXTRACT_CUNESCAPE);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to parse command line: %m"); return parse_log_error(r, field, eq);
if (FLAGS_SET(flags, EXEC_COMMAND_VIA_SHELL)) { if (FLAGS_SET(flags, EXEC_COMMAND_VIA_SHELL)) {
r = strv_prepend(&l, explicit_path ? "-sh" : "sh"); r = strv_prepend(&cmdline, explicit_path ? "-sh" : "sh");
if (r < 0) if (r < 0)
return log_oom(); return log_oom();
} }
@ -688,29 +683,29 @@ static int bus_append_exec_command(sd_bus_message *m, const char *field, const c
if (r < 0) if (r < 0)
return bus_log_create_error(r); return bus_log_create_error(r);
r = sd_bus_message_open_container(m, 'v', is_ex_prop ? "a(sasas)" : "a(sasb)"); r = sd_bus_message_open_container(m, 'v', ex_prop ? "a(sasas)" : "a(sasb)");
if (r < 0) if (r < 0)
return bus_log_create_error(r); return bus_log_create_error(r);
r = sd_bus_message_open_container(m, 'a', is_ex_prop ? "(sasas)" : "(sasb)"); r = sd_bus_message_open_container(m, 'a', ex_prop ? "(sasas)" : "(sasb)");
if (r < 0) if (r < 0)
return bus_log_create_error(r); return bus_log_create_error(r);
if (!strv_isempty(l)) { if (!strv_isempty(cmdline)) {
r = sd_bus_message_open_container(m, 'r', ex_prop ? "sasas" : "sasb");
r = sd_bus_message_open_container(m, 'r', is_ex_prop ? "sasas" : "sasb");
if (r < 0) if (r < 0)
return bus_log_create_error(r); return bus_log_create_error(r);
r = sd_bus_message_append(m, "s", path ?: l[0]); r = sd_bus_message_append(m, "s", path ?: cmdline[0]);
if (r < 0) if (r < 0)
return bus_log_create_error(r); return bus_log_create_error(r);
r = sd_bus_message_append_strv(m, l); r = sd_bus_message_append_strv(m, cmdline);
if (r < 0) if (r < 0)
return bus_log_create_error(r); return bus_log_create_error(r);
r = is_ex_prop ? sd_bus_message_append_strv(m, ex_opts) : sd_bus_message_append(m, "b", FLAGS_SET(flags, EXEC_COMMAND_IGNORE_FAILURE)); r = ex_prop ? sd_bus_message_append_strv(m, ex_opts) :
sd_bus_message_append(m, "b", FLAGS_SET(flags, EXEC_COMMAND_IGNORE_FAILURE));
if (r < 0) if (r < 0)
return bus_log_create_error(r); return bus_log_create_error(r);
@ -742,7 +737,7 @@ static int bus_append_open_file(sd_bus_message *m, const char *field, const char
r = open_file_parse(eq, &of); r = open_file_parse(eq, &of);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to parse OpenFile= setting: %m"); return parse_log_error(r, field, eq);
r = sd_bus_message_append(m, "(sv)", field, "a(sst)", (size_t) 1, of->path, of->fdname, of->flags); r = sd_bus_message_append(m, "(sv)", field, "a(sst)", (size_t) 1, of->path, of->fdname, of->flags);
if (r < 0) if (r < 0)
@ -864,16 +859,14 @@ static int bus_append_parse_ip_address_filter(sd_bus_message *m, const char *fie
_cleanup_free_ char *word = NULL; _cleanup_free_ char *word = NULL;
r = extract_first_word(&eq, &word, NULL, 0); r = extract_first_word(&eq, &word, NULL, 0);
if (r < 0)
return parse_log_error(r, field, eq);
if (r == 0) if (r == 0)
break; break;
if (r == -ENOMEM)
return log_oom();
if (r < 0)
return log_error_errno(r, "Failed to parse %s: %s", field, eq);
r = in_addr_prefix_from_string_auto(word, &family, &prefix, &prefixlen); r = in_addr_prefix_from_string_auto(word, &family, &prefix, &prefixlen);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to parse IP address prefix: %s", word); return log_error_errno(r, "Failed to parse IP address prefix '%s': %m", word);
r = bus_append_ip_address_access(m, family, &prefix, prefixlen); r = bus_append_ip_address_access(m, family, &prefix, prefixlen);
if (r < 0) if (r < 0)
@ -948,34 +941,38 @@ static int bus_append_nft_set(sd_bus_message *m, const char *field, const char *
int source, nfproto; int source, nfproto;
r = extract_first_word(&p, &tuple, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE); r = extract_first_word(&p, &tuple, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE);
if (r == -ENOMEM)
return log_oom();
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to parse %s: %m", field); return parse_log_error(r, field, eq);
if (r == 0) if (r == 0)
break; break;
if (isempty(tuple)) if (isempty(tuple))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to parse %s.", field); return parse_log_error(0, field, eq);
q = tuple; q = tuple;
r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE, &source_str, &nfproto_str, &table, &set); r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE, &source_str, &nfproto_str, &table, &set);
if (r == -ENOMEM)
return log_oom();
if (r != 4 || !isempty(q)) if (r != 4 || !isempty(q))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to parse %s.", field); return parse_log_error(0, field, tuple);
assert(source_str); assert(source_str);
assert(nfproto_str); assert(nfproto_str);
assert(table); assert(table);
assert(set); assert(set);
source = nft_set_source_from_string(source_str); source = r = nft_set_source_from_string(source_str);
if (r < 0)
return log_error_errno(r, "Failed to parse NFT set source '%s': %m", source_str);
if (!IN_SET(source, NFT_SET_SOURCE_CGROUP, NFT_SET_SOURCE_USER, NFT_SET_SOURCE_GROUP)) if (!IN_SET(source, NFT_SET_SOURCE_CGROUP, NFT_SET_SOURCE_USER, NFT_SET_SOURCE_GROUP))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to parse %s.", field); return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Bad NFT set source value '%s'.",
nft_set_source_to_string(source));
nfproto = nfproto_from_string(nfproto_str); nfproto = r = nfproto_from_string(nfproto_str);
if (nfproto < 0 || !nft_identifier_valid(table) || !nft_identifier_valid(set)) if (r < 0)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to parse %s.", field); return log_error_errno(r, "Failed to parse nft protocol '%s': %m", nfproto_str);
if (!nft_identifier_valid(table))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Bad NFT identifier name '%s'.", table);
if (!nft_identifier_valid(set))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Bad NFT identifier name '%s'.", set);
r = sd_bus_message_append(m, "(iiss)", source, nfproto, table, set); r = sd_bus_message_append(m, "(iiss)", source, nfproto, table, set);
if (r < 0) if (r < 0)
@ -1025,12 +1022,8 @@ static int bus_append_set_credential(sd_bus_message *m, const char *field, const
const char *p = eq; const char *p = eq;
r = extract_first_word(&p, &word, ":", EXTRACT_DONT_COALESCE_SEPARATORS); r = extract_first_word(&p, &word, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
if (r == -ENOMEM) if (r <= 0 || !p)
return log_oom(); return parse_log_error(r < 0 ? r : 0, field, eq);
if (r < 0)
return log_error_errno(r, "Failed to parse %s= parameter: %s", field, eq);
if (r == 0 || !p)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Missing argument to %s=.", field);
r = sd_bus_message_open_container(m, 'a', "(say)"); r = sd_bus_message_open_container(m, 'a', "(say)");
if (r < 0) if (r < 0)
@ -1044,13 +1037,13 @@ static int bus_append_set_credential(sd_bus_message *m, const char *field, const
if (r < 0) if (r < 0)
return bus_log_create_error(r); return bus_log_create_error(r);
if (streq(field, "SetCredentialEncrypted")) { if (endswith(field, "Encrypted")) {
_cleanup_free_ void *decoded = NULL; _cleanup_free_ void *decoded = NULL;
size_t decoded_size; size_t decoded_size;
r = unbase64mem(p, &decoded, &decoded_size); r = unbase64mem(p, &decoded, &decoded_size);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to base64 decode encrypted credential: %m"); return log_error_errno(r, "Failed to decode base64 data for %s=: %m", field);
r = sd_bus_message_append_array(m, 'y', decoded, decoded_size); r = sd_bus_message_append_array(m, 'y', decoded, decoded_size);
} else { } else {
@ -1059,7 +1052,7 @@ static int bus_append_set_credential(sd_bus_message *m, const char *field, const
l = cunescape(p, UNESCAPE_ACCEPT_NUL, &unescaped); l = cunescape(p, UNESCAPE_ACCEPT_NUL, &unescaped);
if (l < 0) if (l < 0)
return log_error_errno(l, "Failed to unescape %s= value: %s", field, p); return log_error_errno(l, "Failed to unescape value for %s=: %s", field, p);
r = sd_bus_message_append_array(m, 'y', unescaped, l); r = sd_bus_message_append_array(m, 'y', unescaped, l);
} }
@ -1108,12 +1101,8 @@ static int bus_append_load_credential(sd_bus_message *m, const char *field, cons
const char *p = eq; const char *p = eq;
r = extract_first_word(&p, &word, ":", EXTRACT_DONT_COALESCE_SEPARATORS); r = extract_first_word(&p, &word, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
if (r == -ENOMEM) if (r <= 0)
return log_oom(); return parse_log_error(r, field, eq);
if (r < 0)
return log_error_errno(r, "Failed to parse %s= parameter: %s", field, eq);
if (r == 0)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Missing argument to %s=.", field);
if (isempty(p)) /* If only one field is specified, then this means "inherit from above" */ if (isempty(p)) /* If only one field is specified, then this means "inherit from above" */
p = eq; p = eq;
@ -1144,12 +1133,8 @@ static int bus_append_import_credential(sd_bus_message *m, const char *field, co
const char *p = eq; const char *p = eq;
r = extract_first_word(&p, &word, ":", EXTRACT_DONT_COALESCE_SEPARATORS); r = extract_first_word(&p, &word, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
if (r == -ENOMEM) if (r <= 0)
return log_oom(); return parse_log_error(r, field, eq);
if (r < 0)
return log_error_errno(r, "Failed to parse %s= parameter: %s", field, eq);
if (r == 0)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Missing argument to %s=.", field);
if (!p) if (!p)
r = sd_bus_message_append(m, "(sv)", "ImportCredential", "as", 1, eq); r = sd_bus_message_append(m, "(sv)", "ImportCredential", "as", 1, eq);
@ -1223,15 +1208,10 @@ static int bus_append_log_extra_fields(sd_bus_message *m, const char *field, con
} }
static int bus_append_log_filter_patterns(sd_bus_message *m, const char *field, const char *eq) { static int bus_append_log_filter_patterns(sd_bus_message *m, const char *field, const char *eq) {
int r; return bus_append_trivial_array(m, field, eq,
"a(bs)",
r = sd_bus_message_append(m, "(sv)", "LogFilterPatterns", "a(bs)", 1, eq[0] != '~',
eq[0] != '~', eq[0] != '~' ? eq : eq + 1);
eq[0] != '~' ? eq : eq + 1);
if (r < 0)
return bus_log_create_error(r);
return 1;
} }
static int bus_append_standard_inputs(sd_bus_message *m, const char *field, const char *eq) { static int bus_append_standard_inputs(sd_bus_message *m, const char *field, const char *eq) {
@ -1264,7 +1244,7 @@ static int bus_append_standard_input_text(sd_bus_message *m, const char *field,
l = cunescape(eq, 0, &unescaped); l = cunescape(eq, 0, &unescaped);
if (l < 0) if (l < 0)
return log_error_errno(l, "Failed to unescape text '%s': %m", eq); return log_error_errno(l, "Failed to unescape value for %s=: %s", field, eq);
if (!strextend(&unescaped, "\n")) if (!strextend(&unescaped, "\n"))
return log_oom(); return log_oom();
@ -1282,7 +1262,7 @@ static int bus_append_standard_input_data(sd_bus_message *m, const char *field,
r = unbase64mem(eq, &decoded, &sz); r = unbase64mem(eq, &decoded, &sz);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to decode base64 data '%s': %m", eq); return log_error_errno(r, "Failed to decode base64 data for %s=: %m", field);
return bus_append_byte_array(m, field, decoded, sz); return bus_append_byte_array(m, field, decoded, sz);
} }
@ -1296,12 +1276,12 @@ static int bus_try_append_resource_limit(sd_bus_message *m, const char *field, c
int rl = rlimit_from_string(suffix); int rl = rlimit_from_string(suffix);
if (rl < 0) if (rl < 0)
return log_error_errno(rl, "Unknown setting '%s'.", field); return 0; /* We let the generic error machinery handle this. */
struct rlimit l; struct rlimit l;
r = rlimit_parse(rl, eq, &l); r = rlimit_parse(rl, eq, &l);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to parse resource limit: %s", eq); return parse_log_error(r, field, eq);
r = sd_bus_message_append(m, "(sv)", field, "t", (uint64_t) l.rlim_max); r = sd_bus_message_append(m, "(sv)", field, "t", (uint64_t) l.rlim_max);
if (r < 0) if (r < 0)
@ -1349,7 +1329,7 @@ static int bus_append_capabilities(sd_bus_message *m, const char *field, const c
r = capability_set_from_string(p, &sum); r = capability_set_from_string(p, &sum);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to parse %s value %s: %m", field, eq); return parse_log_error(r, field, eq);
sum = invert ? ~sum : sum; sum = invert ? ~sum : sum;
@ -1386,7 +1366,7 @@ static int bus_append_numa_mask(sd_bus_message *m, const char *field, const char
} else { } else {
r = parse_cpu_set(eq, &nodes); r = parse_cpu_set(eq, &nodes);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to parse %s value: %s", field, eq); return parse_log_error(r, field, eq);
} }
r = cpu_set_to_dbus(&nodes, &array, &allocated); r = cpu_set_to_dbus(&nodes, &array, &allocated);
@ -1434,12 +1414,10 @@ static int bus_append_filter_list(sd_bus_message *m, const char *field, const ch
_cleanup_free_ char *word = NULL; _cleanup_free_ char *word = NULL;
r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE); r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
if (r < 0)
return parse_log_error(r, field, eq);
if (r == 0) if (r == 0)
break; break;
if (r == -ENOMEM)
return log_oom();
if (r < 0)
return log_error_errno(r, "Invalid syntax: %s", eq);
r = sd_bus_message_append_basic(m, 's', word); r = sd_bus_message_append_basic(m, 's', word);
if (r < 0) if (r < 0)
@ -1487,7 +1465,7 @@ static int bus_append_namespace_list(sd_bus_message *m, const char *field, const
r = namespace_flags_from_string(eq, &flags); r = namespace_flags_from_string(eq, &flags);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to parse %s value %s.", field, eq); return parse_log_error(r, field, eq);
} }
if (invert) if (invert)
@ -1528,7 +1506,7 @@ static int bus_append_bind_paths(sd_bus_message *m, const char *field, const cha
r = extract_first_word(&p, &source, ":" WHITESPACE, EXTRACT_UNQUOTE|EXTRACT_DONT_COALESCE_SEPARATORS); r = extract_first_word(&p, &source, ":" WHITESPACE, EXTRACT_UNQUOTE|EXTRACT_DONT_COALESCE_SEPARATORS);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to parse argument: %m"); return parse_log_error(r, field, eq);
if (r == 0) if (r == 0)
break; break;
@ -1541,7 +1519,7 @@ static int bus_append_bind_paths(sd_bus_message *m, const char *field, const cha
if (p && p[-1] == ':') { if (p && p[-1] == ':') {
r = extract_first_word(&p, &destination, ":" WHITESPACE, EXTRACT_UNQUOTE|EXTRACT_DONT_COALESCE_SEPARATORS); r = extract_first_word(&p, &destination, ":" WHITESPACE, EXTRACT_UNQUOTE|EXTRACT_DONT_COALESCE_SEPARATORS);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to parse argument: %m"); return parse_log_error(r, field, p);
if (r == 0) if (r == 0)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Missing argument after ':': %s", eq); "Missing argument after ':': %s", eq);
@ -1553,7 +1531,7 @@ static int bus_append_bind_paths(sd_bus_message *m, const char *field, const cha
r = extract_first_word(&p, &options, NULL, EXTRACT_UNQUOTE); r = extract_first_word(&p, &options, NULL, EXTRACT_UNQUOTE);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to parse argument: %m"); return parse_log_error(r, field, p);
if (isempty(options) || streq(options, "rbind")) if (isempty(options) || streq(options, "rbind"))
flags = MS_REC; flags = MS_REC;
@ -1612,17 +1590,14 @@ static int bus_append_temporary_file_system(sd_bus_message *m, const char *field
r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE); r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to parse argument: %m"); return parse_log_error(r, field, eq);
if (r == 0) if (r == 0)
break; break;
w = word; w = word;
r = extract_first_word(&w, &path, ":", EXTRACT_DONT_COALESCE_SEPARATORS); r = extract_first_word(&w, &path, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
if (r < 0) if (r <= 0)
return log_error_errno(r, "Failed to parse argument: %m"); return parse_log_error(r, field, eq);
if (r == 0)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Failed to parse argument: %s", p);
r = sd_bus_message_append(m, "(ss)", path, w); r = sd_bus_message_append(m, "(ss)", path, w);
if (r < 0) if (r < 0)
@ -1656,9 +1631,9 @@ static int bus_append_root_hash(sd_bus_message *m, const char *field, const char
/* We have a roothash to decode, eg: RootHash=012345789abcdef */ /* We have a roothash to decode, eg: RootHash=012345789abcdef */
r = unhexmem(eq, &roothash_decoded, &roothash_decoded_size); r = unhexmem(eq, &roothash_decoded, &roothash_decoded_size);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to decode RootHash= '%s': %m", eq); return log_error_errno(r, "Failed to decode base64 data for %s=: %m", field);
if (roothash_decoded_size < sizeof(sd_id128_t)) if (roothash_decoded_size < sizeof(sd_id128_t))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "RootHash= '%s' is too short.", eq); return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "%s value '%s' is too short.", field, eq);
return bus_append_byte_array(m, field, roothash_decoded, roothash_decoded_size); return bus_append_byte_array(m, field, roothash_decoded, roothash_decoded_size);
} }
@ -1675,13 +1650,13 @@ static int bus_append_root_hash_signature(sd_bus_message *m, const char *field,
if (!(value = startswith(eq, "base64:"))) if (!(value = startswith(eq, "base64:")))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Failed to decode %s=%s: neither a path nor starts with 'base64:'.", "Failed to decode %s value '%s': neither a path nor starts with 'base64:'.",
field, eq); field, eq);
/* We have a roothash signature to decode, eg: RootHashSignature=base64:012345789abcdef */ /* We have a roothash signature to decode, eg: RootHashSignature=base64:012345789abcdef */
r = unbase64mem(value, &roothash_sig_decoded, &roothash_sig_decoded_size); r = unbase64mem(value, &roothash_sig_decoded, &roothash_sig_decoded_size);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to decode %s=%s: %m", field, eq); return log_error_errno(r, "Failed to decode base64 data for %s=: %m", field);
return bus_append_byte_array(m, field, roothash_sig_decoded, roothash_sig_decoded_size); return bus_append_byte_array(m, field, roothash_sig_decoded, roothash_sig_decoded_size);
} }
@ -1709,7 +1684,7 @@ static int bus_append_root_image_options(sd_bus_message *m, const char *field, c
r = strv_split_colon_pairs(&l, p); r = strv_split_colon_pairs(&l, p);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to parse argument: %m"); return parse_log_error(r, field, eq);
STRV_FOREACH_PAIR(first, second, l) { STRV_FOREACH_PAIR(first, second, l) {
r = sd_bus_message_append(m, "(ss)", r = sd_bus_message_append(m, "(ss)",
@ -1761,14 +1736,14 @@ static int bus_append_mount_images(sd_bus_message *m, const char *field, const c
r = extract_first_word(&p, &tuple, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE); r = extract_first_word(&p, &tuple, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to parse %s property: %s", field, eq); return parse_log_error(r, field, eq);
if (r == 0) if (r == 0)
break; break;
q = tuple; q = tuple;
r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &first, &second); r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &first, &second);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to parse %s property: %s", field, eq); return parse_log_error(r, field, eq);
if (r == 0) if (r == 0)
continue; continue;
@ -1780,7 +1755,7 @@ static int bus_append_mount_images(sd_bus_message *m, const char *field, const c
if (isempty(second)) if (isempty(second))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Missing argument after ':' for %s: %s", field, eq); "Missing argument after ':' for %s=: '%s'", field, eq);
r = sd_bus_message_open_container(m, 'r', "ssba(ss)"); r = sd_bus_message_open_container(m, 'r', "ssba(ss)");
if (r < 0) if (r < 0)
@ -1799,7 +1774,7 @@ static int bus_append_mount_images(sd_bus_message *m, const char *field, const c
r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &partition, &mount_options); r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &partition, &mount_options);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to parse %s property: %s", field, eq); return parse_log_error(r, field, eq);
if (r == 0) if (r == 0)
break; break;
/* Single set of options, applying to the root partition/single filesystem */ /* Single set of options, applying to the root partition/single filesystem */
@ -1867,14 +1842,14 @@ static int bus_append_extension_images(sd_bus_message *m, const char *field, con
r = extract_first_word(&p, &tuple, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE); r = extract_first_word(&p, &tuple, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to parse %s property: %s", field, eq); return parse_log_error(r, field, eq);
if (r == 0) if (r == 0)
break; break;
q = tuple; q = tuple;
r = extract_first_word(&q, &source, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS); r = extract_first_word(&q, &source, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to parse %s property: %s", field, eq); return parse_log_error(r, field, eq);
if (r == 0) if (r == 0)
continue; continue;
@ -1901,7 +1876,7 @@ static int bus_append_extension_images(sd_bus_message *m, const char *field, con
r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &partition, &mount_options); r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &partition, &mount_options);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to parse %s property: %s", field, eq); return parse_log_error(r, field, eq);
if (r == 0) if (r == 0)
break; break;
/* Single set of options, applying to the root partition/single filesystem */ /* Single set of options, applying to the root partition/single filesystem */
@ -1956,14 +1931,14 @@ static int bus_append_directory(sd_bus_message *m, const char *field, const char
r = extract_first_word(&p, &tuple, NULL, EXTRACT_UNQUOTE); r = extract_first_word(&p, &tuple, NULL, EXTRACT_UNQUOTE);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to parse argument: %m"); return parse_log_error(r, field, eq);
if (r == 0) if (r == 0)
break; break;
const char *t = tuple; const char *t = tuple;
r = extract_many_words(&t, ":", EXTRACT_UNQUOTE|EXTRACT_DONT_COALESCE_SEPARATORS, &source, &dest, &flags); r = extract_many_words(&t, ":", EXTRACT_UNQUOTE|EXTRACT_DONT_COALESCE_SEPARATORS, &source, &dest, &flags);
if (r <= 0) if (r <= 0)
return log_error_errno(r ?: SYNTHETIC_ERRNO(EINVAL), "Failed to parse argument: %m"); return parse_log_error(r, field, eq);
path_simplify(source); path_simplify(source);
@ -1979,7 +1954,7 @@ static int bus_append_directory(sd_bus_message *m, const char *field, const char
} else { } else {
ExecDirectoryFlags exec_directory_flags = exec_directory_flags_from_string(flags); ExecDirectoryFlags exec_directory_flags = exec_directory_flags_from_string(flags);
if (exec_directory_flags < 0 || (exec_directory_flags & ~_EXEC_DIRECTORY_FLAGS_PUBLIC) != 0) if (exec_directory_flags < 0 || (exec_directory_flags & ~_EXEC_DIRECTORY_FLAGS_PUBLIC) != 0)
return log_error_errno(r, "Failed to parse flags: %s", flags); return log_error_errno(r, "Failed to parse flags for %s=: '%s'", field, flags);
if (!isempty(dest)) { if (!isempty(dest)) {
path_simplify(dest); path_simplify(dest);
@ -2097,7 +2072,7 @@ static int bus_append_protect_hostname(sd_bus_message *m, const char *field, con
const char *colon = strchr(eq, ':'); const char *colon = strchr(eq, ':');
if (colon) { if (colon) {
if (isempty(colon + 1)) if (isempty(colon + 1))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to parse argument: %s=%s", field, eq); return parse_log_error(0, field, eq);
_cleanup_free_ char *p = strndup(eq, colon - eq); _cleanup_free_ char *p = strndup(eq, colon - eq);
if (!p) if (!p)
@ -2113,6 +2088,28 @@ static int bus_append_protect_hostname(sd_bus_message *m, const char *field, con
return 1; return 1;
} }
static int bus_append_boolean_or_ex_string(sd_bus_message *m, const char *field, const char *eq) {
int r;
r = parse_boolean(eq);
if (r >= 0) {
if (endswith(field, "Ex"))
field = strndupa_safe(field, strlen(field) - 2);
r = sd_bus_message_append(m, "(sv)", field, "b", r);
} else {
if (!endswith(field, "Ex"))
field = strjoina(field, "Ex");
/* We allow any string through and let the server perform the verification. */
r = sd_bus_message_append(m, "(sv)", field, "s", eq);
}
if (r < 0)
return bus_log_create_error(r);
return 1;
}
static int bus_append_paths(sd_bus_message *m, const char *field, const char *eq) { static int bus_append_paths(sd_bus_message *m, const char *field, const char *eq) {
return bus_append_trivial_array(m, "Paths", eq, return bus_append_trivial_array(m, "Paths", eq,
"a(ss)", field, eq); "a(ss)", field, eq);
@ -2127,12 +2124,10 @@ static int bus_append_exit_status(sd_bus_message *m, const char *field, const ch
_cleanup_free_ char *word = NULL; _cleanup_free_ char *word = NULL;
r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE); r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
if (r < 0)
return parse_log_error(r, field, eq);
if (r == 0) if (r == 0)
break; break;
if (r == -ENOMEM)
return log_oom();
if (r < 0)
return log_error_errno(r, "Invalid syntax in %s: %s", field, eq);
/* We need to call exit_status_from_string() first, because we want /* We need to call exit_status_from_string() first, because we want
* to parse numbers as exit statuses, not signals. */ * to parse numbers as exit statuses, not signals. */
@ -2154,8 +2149,7 @@ static int bus_append_exit_status(sd_bus_message *m, const char *field, const ch
} else } else
/* original r from exit_status_to_string() */ /* original r from exit_status_to_string() */
return log_error_errno(r, "Invalid status or signal %s in %s: %m", return parse_log_error(r, field, word);
word, field);
} }
r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv"); r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
@ -2207,7 +2201,7 @@ static int bus_append_action_exit_status(sd_bus_message *m, const char *field, c
r = safe_atou8(eq, &u); r = safe_atou8(eq, &u);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to parse %s=%s", field, eq); return parse_log_error(r, field, eq);
r = sd_bus_message_append(m, "(sv)", field, "i", (int) u); r = sd_bus_message_append(m, "(sv)", field, "i", (int) u);
} }
@ -2233,7 +2227,7 @@ static int bus_append_timers_monotonic(sd_bus_message *m, const char *field, con
usec_t t; usec_t t;
r = parse_sec(eq, &t); r = parse_sec(eq, &t);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to parse %s=%s: %m", field, eq); return parse_log_error(r, field, eq);
r = sd_bus_message_append(m, "(sv)", "TimersMonotonic", "a(st)", 1, field, t); r = sd_bus_message_append(m, "(sv)", "TimersMonotonic", "a(st)", 1, field, t);
} }
@ -2391,9 +2385,6 @@ static const BusProperty execute_properties[] = {
{ "SyslogIdentifier", bus_append_string }, { "SyslogIdentifier", bus_append_string },
{ "ProtectSystem", bus_append_string }, { "ProtectSystem", bus_append_string },
{ "ProtectHome", bus_append_string }, { "ProtectHome", bus_append_string },
{ "PrivateTmpEx", bus_append_string },
{ "PrivateUsersEx", bus_append_string },
{ "ProtectControlGroupsEx", bus_append_string },
{ "SELinuxContext", bus_append_string }, { "SELinuxContext", bus_append_string },
{ "RootImage", bus_append_string }, { "RootImage", bus_append_string },
{ "RootVerity", bus_append_string }, { "RootVerity", bus_append_string },
@ -2413,10 +2404,8 @@ static const BusProperty execute_properties[] = {
{ "TTYVHangup", bus_append_parse_boolean }, { "TTYVHangup", bus_append_parse_boolean },
{ "TTYReset", bus_append_parse_boolean }, { "TTYReset", bus_append_parse_boolean },
{ "TTYVTDisallocate", bus_append_parse_boolean }, { "TTYVTDisallocate", bus_append_parse_boolean },
{ "PrivateTmp", bus_append_parse_boolean },
{ "PrivateDevices", bus_append_parse_boolean }, { "PrivateDevices", bus_append_parse_boolean },
{ "PrivateNetwork", bus_append_parse_boolean }, { "PrivateNetwork", bus_append_parse_boolean },
{ "PrivateUsers", bus_append_parse_boolean },
{ "PrivateMounts", bus_append_parse_boolean }, { "PrivateMounts", bus_append_parse_boolean },
{ "PrivateIPC", bus_append_parse_boolean }, { "PrivateIPC", bus_append_parse_boolean },
{ "NoNewPrivileges", bus_append_parse_boolean }, { "NoNewPrivileges", bus_append_parse_boolean },
@ -2429,7 +2418,6 @@ static const BusProperty execute_properties[] = {
{ "ProtectKernelModules", bus_append_parse_boolean }, { "ProtectKernelModules", bus_append_parse_boolean },
{ "ProtectKernelLogs", bus_append_parse_boolean }, { "ProtectKernelLogs", bus_append_parse_boolean },
{ "ProtectClock", bus_append_parse_boolean }, { "ProtectClock", bus_append_parse_boolean },
{ "ProtectControlGroups", bus_append_parse_boolean },
{ "MountAPIVFS", bus_append_parse_boolean }, { "MountAPIVFS", bus_append_parse_boolean },
{ "BindLogSockets", bus_append_parse_boolean }, { "BindLogSockets", bus_append_parse_boolean },
{ "CPUSchedulingResetOnFork", bus_append_parse_boolean }, { "CPUSchedulingResetOnFork", bus_append_parse_boolean },
@ -2484,7 +2472,7 @@ static const BusProperty execute_properties[] = {
{ "LoadCredential", bus_append_load_credential }, { "LoadCredential", bus_append_load_credential },
{ "LoadCredentialEncrypted", bus_append_load_credential }, { "LoadCredentialEncrypted", bus_append_load_credential },
{ "ImportCredential", bus_append_import_credential }, { "ImportCredential", bus_append_import_credential },
{ "ImportCredentialEx", bus_append_import_credential }, { "ImportCredentialEx", bus_append_import_credential }, /* compat */
{ "LogExtraFields", bus_append_log_extra_fields }, { "LogExtraFields", bus_append_log_extra_fields },
{ "LogFilterPatterns", bus_append_log_filter_patterns }, { "LogFilterPatterns", bus_append_log_filter_patterns },
{ "StandardInput", bus_append_standard_inputs }, { "StandardInput", bus_append_standard_inputs },
@ -2519,7 +2507,13 @@ static const BusProperty execute_properties[] = {
{ "CacheDirectory", bus_append_directory }, { "CacheDirectory", bus_append_directory },
{ "LogsDirectory", bus_append_directory }, { "LogsDirectory", bus_append_directory },
{ "ProtectHostname", bus_append_protect_hostname }, { "ProtectHostname", bus_append_protect_hostname },
{ "ProtectHostnameEx", bus_append_protect_hostname }, { "ProtectHostnameEx", bus_append_protect_hostname }, /* compat */
{ "PrivateTmp", bus_append_boolean_or_ex_string },
{ "PrivateTmpEx", bus_append_boolean_or_ex_string }, /* compat */
{ "ProtectControlGroups", bus_append_boolean_or_ex_string },
{ "ProtectControlGroupsEx", bus_append_boolean_or_ex_string }, /* compat */
{ "PrivateUsers", bus_append_boolean_or_ex_string },
{ "PrivateUsersEx", bus_append_boolean_or_ex_string }, /* compat */
{ NULL, bus_try_append_resource_limit, dump_resource_limits }, { NULL, bus_try_append_resource_limit, dump_resource_limits },
{} {}
@ -2609,19 +2603,19 @@ static const BusProperty service_properties[] = {
{ "FileDescriptorStoreMax", bus_append_safe_atou }, { "FileDescriptorStoreMax", bus_append_safe_atou },
{ "RestartSteps", bus_append_safe_atou }, { "RestartSteps", bus_append_safe_atou },
{ "ExecCondition", bus_append_exec_command }, { "ExecCondition", bus_append_exec_command },
{ "ExecConditionEx", bus_append_exec_command }, /* compat */
{ "ExecStartPre", bus_append_exec_command }, { "ExecStartPre", bus_append_exec_command },
{ "ExecStartPreEx", bus_append_exec_command }, /* compat */
{ "ExecStart", bus_append_exec_command }, { "ExecStart", bus_append_exec_command },
{ "ExecStartEx", bus_append_exec_command }, /* compat */
{ "ExecStartPost", bus_append_exec_command }, { "ExecStartPost", bus_append_exec_command },
{ "ExecConditionEx", bus_append_exec_command }, { "ExecStartPostEx", bus_append_exec_command }, /* compat */
{ "ExecStartPreEx", bus_append_exec_command },
{ "ExecStartEx", bus_append_exec_command },
{ "ExecStartPostEx", bus_append_exec_command },
{ "ExecReload", bus_append_exec_command }, { "ExecReload", bus_append_exec_command },
{ "ExecReloadEx", bus_append_exec_command }, /* compat */
{ "ExecStop", bus_append_exec_command }, { "ExecStop", bus_append_exec_command },
{ "ExecStopEx", bus_append_exec_command }, /* compat */
{ "ExecStopPost", bus_append_exec_command }, { "ExecStopPost", bus_append_exec_command },
{ "ExecReloadEx", bus_append_exec_command }, { "ExecStopPostEx", bus_append_exec_command }, /* compat */
{ "ExecStopEx", bus_append_exec_command },
{ "ExecStopPostEx", bus_append_exec_command },
{ "RestartPreventExitStatus", bus_append_exit_status }, { "RestartPreventExitStatus", bus_append_exit_status },
{ "RestartForceExitStatus", bus_append_exit_status }, { "RestartForceExitStatus", bus_append_exit_status },
{ "SuccessExitStatus", bus_append_exit_status }, { "SuccessExitStatus", bus_append_exit_status },
@ -2886,9 +2880,11 @@ void bus_dump_transient_settings(UnitType t) {
for (const BusProperty *item = *tables; item->convert; item++) { for (const BusProperty *item = *tables; item->convert; item++) {
assert(item->name || item->dump); assert(item->name || item->dump);
/* Do not print deprecated names */ /* Do not print deprecated names. All "Ex" variants are deprecated. */
if (item->convert == warn_deprecated) if (item->convert == warn_deprecated)
continue; continue;
if (item->name && endswith(item->name, "Ex"))
continue;
if (item->name) if (item->name)
puts(item->name); puts(item->name);

View File

@ -271,7 +271,7 @@ static int systemctl_help(void) {
" For kill, wait until service stopped\n" " For kill, wait until service stopped\n"
" --no-block Do not wait until operation finished\n" " --no-block Do not wait until operation finished\n"
" --no-wall Don't send wall message before halt/power-off/reboot\n" " --no-wall Don't send wall message before halt/power-off/reboot\n"
" --message=MESSAGE Specify human readable reason for system shutdown\n" " --message=MESSAGE Specify human-readable reason for system shutdown\n"
" --no-reload Don't reload daemon after en-/dis-abling unit files\n" " --no-reload Don't reload daemon after en-/dis-abling unit files\n"
" --legend=BOOL Enable/disable the legend (column headers and hints)\n" " --legend=BOOL Enable/disable the legend (column headers and hints)\n"
" --no-pager Do not pipe output into a pager\n" " --no-pager Do not pipe output into a pager\n"

View File

@ -189,9 +189,9 @@ int sd_is_mq(int fd, const char *path);
that describes the daemon state. This is free-form that describes the daemon state. This is free-form
and can be used for various purposes: general state and can be used for various purposes: general state
feedback, fsck-like programs could pass completion feedback, fsck-like programs could pass completion
percentages and failing programs could pass a human percentages and failing programs could pass a
readable error message. Example: "STATUS=Completed human-readable error message. Example:
66% of file system check..." "STATUS=Completed 66% of file system check..."
NOTIFYACCESS=... NOTIFYACCESS=...
Reset the access to the service status notification socket. Reset the access to the service status notification socket.

File diff suppressed because it is too large Load Diff

View File

@ -7,6 +7,7 @@
#include <string.h> #include <string.h>
#include <sys/resource.h> #include <sys/resource.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/timex.h>
#define __STDC_WANT_IEC_60559_TYPES_EXT__ #define __STDC_WANT_IEC_60559_TYPES_EXT__
#include <float.h> #include <float.h>

View File

@ -5,6 +5,7 @@
#include <netinet/in.h> #include <netinet/in.h>
#include <netinet/ip.h> #include <netinet/ip.h>
#include <resolv.h> #include <resolv.h>
#include <sys/timex.h>
#include <unistd.h> #include <unistd.h>
#include "sd-bus.h" #include "sd-bus.h"

View File

@ -20,25 +20,16 @@ property[7_seven]=ExecStopPost
# These should all get upgraded to the corresponding Ex property as the non-Ex variant # These should all get upgraded to the corresponding Ex property as the non-Ex variant
# does not support the ":" prefix (no-env-expand). # does not support the ":" prefix (no-env-expand).
for c in "${!property[@]}"; do for c in "${!property[@]}"; do
systemd-run --unit="$c" -r -p "Type=oneshot" -p "${property[$c]}=:/bin/echo \${$c}" /bin/true systemd-run --unit="$c" -r -p "Type=oneshot" -p "${property[$c]}=:/bin/echo \${$c}" true
systemctl show -p "${property[$c]}" "$c" | grep -F "path=/bin/echo ; argv[]=/bin/echo \${$c} ; ignore_errors=no" systemctl show -p "${property[$c]}" "$c" | grep -F "path=/bin/echo ; argv[]=/bin/echo \${$c} ; ignore_errors=no"
systemctl show -p "${property[$c]}Ex" "$c" | grep -F "path=/bin/echo ; argv[]=/bin/echo \${$c} ; flags=no-env-expand" systemctl show -p "${property[$c]}Ex" "$c" | grep -F "path=/bin/echo ; argv[]=/bin/echo \${$c} ; flags=no-env-expand"
done done
declare -A property_ex # Ex names on the commandline are supported for backward compat.
for c in "${!property[@]}"; do
property_ex[1_one_ex]=ExecConditionEx systemd-run --unit="${c}_ex" -r -p "Type=oneshot" -p "${property[$c]}Ex=:/bin/echo \${$c}" true
property_ex[2_two_ex]=ExecStartPreEx systemctl show -p "${property[$c]}" "$c" | grep -F "path=/bin/echo ; argv[]=/bin/echo \${$c} ; ignore_errors=no"
property_ex[3_three_ex]=ExecStartEx systemctl show -p "${property[$c]}Ex" "$c" | grep -F "path=/bin/echo ; argv[]=/bin/echo \${$c} ; flags=no-env-expand"
property_ex[4_four_ex]=ExecStartPostEx
property_ex[5_five_ex]=ExecReloadEx
property_ex[6_six_ex]=ExecStopEx
property_ex[7_seven_ex]=ExecStopPostEx
for c in "${!property_ex[@]}"; do
systemd-run --unit="$c" -r -p "Type=oneshot" -p "${property_ex[$c]}=:/bin/echo \${$c}" /bin/true
systemctl show -p "${property_ex[$c]%??}" "$c" | grep -F "path=/bin/echo ; argv[]=/bin/echo \${$c} ; ignore_errors=no"
systemctl show -p "${property_ex[$c]}" "$c" | grep -F "path=/bin/echo ; argv[]=/bin/echo \${$c} ; flags=no-env-expand"
done done
systemd-analyze log-level info systemd-analyze log-level info

View File

@ -1115,6 +1115,7 @@ systemd-analyze transient-settings mount | grep CPUQuotaPeriodSec
(! systemd-analyze transient-settings service | grep CPUAccounting ) (! systemd-analyze transient-settings service | grep CPUAccounting )
(! systemd-analyze transient-settings service | grep ConditionKernelVersion ) (! systemd-analyze transient-settings service | grep ConditionKernelVersion )
(! systemd-analyze transient-settings service | grep AssertKernelVersion ) (! systemd-analyze transient-settings service | grep AssertKernelVersion )
(! systemd-analyze transient-settings service socket timer path slice scope mount automount | grep -E 'Ex$' )
# check systemd-analyze unit-shell with a namespaced unit # check systemd-analyze unit-shell with a namespaced unit
UNIT_NAME="test-unit-shell.service" UNIT_NAME="test-unit-shell.service"