1
0
mirror of https://github.com/systemd/systemd synced 2026-03-26 08:44:55 +01:00

Compare commits

...

17 Commits

Author SHA1 Message Date
Luca Boccassi
67317e214e
Translations update from Fedora Weblate (#39998)
Translations update from [Fedora
Weblate](https://translate.fedoraproject.org) for
[systemd/main](https://translate.fedoraproject.org/projects/systemd/main/).



Current translation status:

![Weblate translation
status](https://translate.fedoraproject.org/widget/systemd/main/horizontal-auto.svg)
2025-12-05 14:24:23 +00:00
Daniel Rusek
bfaf63b509 po: Translated using Weblate (Czech)
Currently translated at 100.0% (264 of 264 strings)

Co-authored-by: Daniel Rusek <mail@asciiwolf.com>
Translate-URL: https://translate.fedoraproject.org/projects/systemd/main/cs/
Translation: systemd/main
2025-12-05 13:08:36 +00:00
Pavel Borecki
4b9cb0c391 po: Translated using Weblate (Czech)
Currently translated at 100.0% (264 of 264 strings)

Co-authored-by: Pavel Borecki <pavel.borecki@gmail.com>
Translate-URL: https://translate.fedoraproject.org/projects/systemd/main/cs/
Translation: systemd/main
2025-12-05 13:08:35 +00:00
Zbigniew Jędrzejewski-Szmek
12391431c2 machined: add description to varlink server, unify error messages
manager_varlink_init_resolve_hook and manager_varlink_init_userdb are very
similar, but one didn't set a description and the other one had an error
message which didn't print the offending path.

Define constants for the paths, and also change other similar constants
to have slightly shorter names. (It's an "address" and "path", but we don't
need to have both parts in the name, esp. that it makes the name very long.)
2025-12-05 12:17:06 +01:00
Zbigniew Jędrzejewski-Szmek
9454927c76
sd-netlink: read error message for NFNL_MSG_BATCH_BEGIN (#39967)
Before:
```
$ unshare --user --map-users=0:$(id -u):1 --map-groups=0:$(id -g):1 build/test-firewall-util
/* test_v6 */
src/test/test-firewall-util.c:34: Assertion failed: "r = fw_nftables_add_masquerade(nfnl, true, AF_INET6, &u1, 128)" failed with unexpected error: -110/ETIMEDOUT
Aborted (core dumped)
```

After:
```
$ unshare --user --map-users=0:$(id -u):1 --map-groups=0:$(id -g):1 /var/build/test-firewall-util
/* test_v6 */
test-firewall-util: Failed to add IPv6 masquerade, skipping tests: Operation not permitted
/* test_v4 */
test-firewall-util: Failed to add IPv4 masquerade, skipping tests: Operation not permitted
```
2025-12-05 12:12:03 +01:00
Colin Walters
3c85d99c79 man: Clarify secure-boot-enroll defaults
Clarify in the docs that `if-safe` is the default by noting
that in the text for it, but also moving it to the first mentioned
option.

Make explicit in `man systemd-boot` that the `secure-boot-enroll`
option is specified in the `loader.conf`

Update an outdated comment in boot.c around the same.

Signed-off-by: Colin Walters <walters@verbum.org>
2025-12-05 11:57:18 +01:00
Luca Boccassi
eb98ddd8b8 sysupdate: also mention patterns to match in error log on failure
The gpt uuid is not the only thing that needs to match, the pattern
does as well, so mention it in the error log if present
2025-12-05 10:09:38 +00:00
Zbigniew Jędrzejewski-Szmek
d9e894ef72
Fix systemctl start --verbose off-by-one logs (#39927) 2025-12-05 11:09:14 +01:00
Yu Watanabe
53f5aa3fd2 musl: introduce wrappers for getopt() and getopt_long()
musl's getopt_long() behaves something different in handling optional arguments:
```
$ journalctl _PID=1 _COMM=systemd --since 19:19:01 -n all --follow
Failed to add match 'all': Invalid argument
```
This introduces getopt_long_fix() that reorders the passed arguments to make
getopt_long() provided by musl works as what we expect.

Also, musl's getopt() always behaves POSIXLY_CORRECT mode, and stops parsing
arguments when a non-option string found. Let's always use getopt_long().
2025-12-05 11:01:09 +01:00
Yu Watanabe
84990e08e5 test-firewall-util: allow to run test-firewall-util
Now fw_nftables_add_masquerade() should return EOPNOTSUPP or so if
unprivileged. It is not necessary to skip whole tests earlier.
2025-12-04 08:24:28 +09:00
Yu Watanabe
691d63dbdd sd-netlink: also read the reply for NFNL_MSG_BATCH_BEGIN message
When we send a batch of nfnl messages, but e.g. without sufficient
privilege, the kernel may only return an error message for
NFNL_MSG_BATCH_BEGIN and ignore all later messages.
So, we need to read the response for the NFNL_MSG_BATCH_BEGIN,
and if it is an error ignore the replies for the rest.
2025-12-04 08:24:28 +09:00
Yu Watanabe
ea97ca9a06 sd-netlink: drop unused ret_messages argument
This is not only unused, the kernel never provide any meaningful reply
for batch message. Let's drop it.
2025-12-04 08:24:28 +09:00
Yu Watanabe
991703009e sd-netlink: introduce sd_netlink_ignore_serial()
When we send a message with NLM_F_ACK, but if later we are not
interested in the reply and do not want to call sd_netlink_read(),
the reply will be stored in the rqueue forever.

Let's introduce a way to ignore received message without waiting reply.
2025-12-04 08:24:28 +09:00
Yu Watanabe
32682ba02d sd-netlink: introduce netlink_now() and move timespan_to_timestamp()
When sd-event is attached to the sd-netlink object, use the timestamp of
the current event, otherwise call now().

This mostly change nothing. Preparation for later change.
2025-12-04 08:24:28 +09:00
Zbigniew Jędrzejewski-Szmek
21eb636aaa sd-notify: print a debug message when sd_notify() succeds
… and also when it fails, in the few cases where this wasn't done already.
When I was debugging https://github.com/systemd/systemd/issues/39048, it
was quite confusing that we print copious information about D-Bus messages
and all other steps we're undertaking, but nothing about the sd-notify
messages which are much more important. Add some debug messages for the
cases where we didn't print anything. (The case where $NOTIFY_SOCKET is
not set in left unchanged. The variable is often left unset and we don't
need to spam logs in that trivial case.)
2025-11-27 20:03:00 +01:00
Zbigniew Jędrzejewski-Szmek
f943ab6efb systemctl: stop showing last message from previous run
--lines=1 means that we show the last message about the unit, whatever it is:

$ SYSTEMD_LOG_LEVEL=debug systemctl --verbose start demo2
...
Invoking 'journalctl -q --follow --no-pager --lines=1 --synchronize-on-exit=yes --unit=demo2.service' as child.
...
Directory /var/log/journal/7d16833bfa924410851e2a193bcfd4ba added.
Journal effective settings seal=no keyed_hash=yes compress=ZSTD compress_threshold_bytes=8B
...
Reiterating files to get inotify watches established.
Considering root directory '/run/log/journal'.
Considering root directory '/var/log/journal'.
Considering directory '/var/log/journal/7d16833bfa924410851e2a193bcfd4ba'.
Nov 26 17:24:35 rawhide systemd[1]: Finished demo2.service.
...
Executing dbus call org.freedesktop.systemd1.Manager StartUnit(demo2.service, replace)
...
Job for demo2.service finished.
Got result done/Success for job demo2.service.
journal: Sending message: {"method":"io.systemd.Journal.Synchronize","parameters":{"offline":false}}
Nov 27 13:05:30 rawhide systemd[1]: Starting demo2.service...
Nov 27 13:05:30 rawhide systemd[1]: demo2.service: Deactivated successfully.
Nov 27 13:05:30 rawhide systemd[1]: Finished demo2.service.
...

We obviously should only show _new_ messages, hence change to --lines=0.
This works properly after the fix in the previous commit.

Fixes #39048.
2025-11-27 20:03:00 +01:00
Zbigniew Jędrzejewski-Szmek
ef90afd59e journal: send READY=1 also when --lines=0 is given
If --lines=0 is given, we'd skip the setup and not invoke sd_notify,
potentially blocking the caller. Change the condition for the callback
to also include that case. Since then the callback would always be
set, the 'if' statement is not necessary anymore.
2025-11-27 20:02:02 +01:00
25 changed files with 901 additions and 126 deletions

View File

@ -293,8 +293,10 @@
<para>Controls enrollment of secure boot keys found on the ESP if the system is in setup mode: <para>Controls enrollment of secure boot keys found on the ESP if the system is in setup mode:
<variablelist> <variablelist>
<varlistentry> <varlistentry>
<term><option>off</option></term> <term><option>if-safe</option></term>
<listitem><para>No action is taken.</para> <listitem><para>This is the default. Same behavior as <option>manual</option>, but will try to automatically
enroll the key named <literal>auto</literal> if it is considered to be safe. Currently, this is only
the case if the system is running inside a virtual machine.</para>
<xi:include href="version-info.xml" xpointer="v253"/></listitem> <xi:include href="version-info.xml" xpointer="v253"/></listitem>
</varlistentry> </varlistentry>
@ -308,10 +310,8 @@
</varlistentry> </varlistentry>
<varlistentry> <varlistentry>
<term><option>if-safe</option></term> <term><option>off</option></term>
<listitem><para>Same behavior as <option>manual</option>, but will try to automatically <listitem><para>No action is taken.</para>
enroll the key <literal>auto</literal> if it is considered to be safe. Currently, this is only
the case if the system is running inside a virtual machine.</para>
<xi:include href="version-info.xml" xpointer="v253"/></listitem> <xi:include href="version-info.xml" xpointer="v253"/></listitem>
</varlistentry> </varlistentry>

View File

@ -392,8 +392,9 @@
<para>Enrollment of Secure Boot variables can be performed manually or automatically if files are available <para>Enrollment of Secure Boot variables can be performed manually or automatically if files are available
under <filename>/loader/keys/<replaceable>NAME</replaceable>/{db,dbx,KEK,PK}.auth</filename>, <replaceable>NAME</replaceable> under <filename>/loader/keys/<replaceable>NAME</replaceable>/{db,dbx,KEK,PK}.auth</filename>, <replaceable>NAME</replaceable>
being the display name for the set of variables in the menu. If one of the sets is named <filename>auto</filename> being the display name for the set of variables in the menu. If one of the sets is named <filename>auto</filename>
then it might be enrolled automatically depending on whether <literal>secure-boot-enroll</literal> is set then it might be enrolled automatically depending on the execution environment and the value of the <literal>secure-boot-enroll</literal> option.
to force or not.</para> See
<citerefentry><refentrytitle>loader.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
</refsect1> </refsect1>
<refsect1> <refsect1>

View File

@ -2,24 +2,24 @@
# #
# Czech translation for systemd. # Czech translation for systemd.
# #
# Daniel Rusek <mail@asciiwolf.com>, 2022, 2023. # Daniel Rusek <mail@asciiwolf.com>, 2022, 2023, 2025.
# Pavel Borecki <pavel.borecki@gmail.com>, 2023, 2024. # Pavel Borecki <pavel.borecki@gmail.com>, 2023, 2024, 2025.
# Jan Kalabza <jan.kalabza@gmail.com>, 2025. # Jan Kalabza <jan.kalabza@gmail.com>, 2025.
msgid "" msgid ""
msgstr "" msgstr ""
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-11-26 01:17+0000\n" "POT-Creation-Date: 2025-11-26 01:17+0000\n"
"PO-Revision-Date: 2025-02-10 02:01+0000\n" "PO-Revision-Date: 2025-12-05 13:08+0000\n"
"Last-Translator: Jan Kalabza <jan.kalabza@gmail.com>\n" "Last-Translator: Daniel Rusek <mail@asciiwolf.com>\n"
"Language-Team: Czech <https://translate.fedoraproject.org/projects/systemd/" "Language-Team: Czech <https://translate.fedoraproject.org/projects/systemd/"
"main/cs/>\n" "main/cs/>\n"
"Language: cs\n" "Language: cs\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 " "Plural-Forms: nplurals=3; plural="
"|| n%100>=20) ? 1 : 2);\n" "(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
"X-Generator: Weblate 5.9.2\n" "X-Generator: Weblate 5.14.3\n"
#: src/core/org.freedesktop.systemd1.policy.in:22 #: src/core/org.freedesktop.systemd1.policy.in:22
msgid "Send passphrase back to system" msgid "Send passphrase back to system"
@ -120,7 +120,7 @@ msgstr "Aktualizujte svůj domovský adresář"
#: src/home/org.freedesktop.home1.policy:54 #: src/home/org.freedesktop.home1.policy:54
msgid "Authentication is required to update your home area." msgid "Authentication is required to update your home area."
msgstr "Pro aktualizaci domovské adresáře je nutné ověření." msgstr "Pro aktualizaci domovské adresáře je vyžadováno ověření."
#: src/home/org.freedesktop.home1.policy:63 #: src/home/org.freedesktop.home1.policy:63
msgid "Resize a home area" msgid "Resize a home area"
@ -146,17 +146,16 @@ msgstr "Aktivovat domovskou složku"
#: src/home/org.freedesktop.home1.policy:84 #: src/home/org.freedesktop.home1.policy:84
msgid "Authentication is required to activate a user's home area." msgid "Authentication is required to activate a user's home area."
msgstr "K aktivaci domovského adresáře uživatele je nutné ověření." msgstr "K aktivaci domovského adresáře uživatele je vyžadováno ověření."
#: src/home/org.freedesktop.home1.policy:93 #: src/home/org.freedesktop.home1.policy:93
msgid "Manage Home Directory Signing Keys" msgid "Manage Home Directory Signing Keys"
msgstr "" msgstr "Spravovat klíče pro podepisování domovské složky"
#: src/home/org.freedesktop.home1.policy:94 #: src/home/org.freedesktop.home1.policy:94
#, fuzzy
msgid "Authentication is required to manage signing keys for home directories." msgid "Authentication is required to manage signing keys for home directories."
msgstr "" msgstr ""
"Pro správu systémových služeb nebo dalších jednotek je vyžadováno ověření." "Pro správu klíčů pro podepisování domovských složek je vyžadováno ověření."
#: src/home/pam_systemd_home.c:333 #: src/home/pam_systemd_home.c:333
#, c-format #, c-format
@ -882,16 +881,15 @@ msgstr ""
"K vytvoření místního virtuálního počítače nebo kontejneru je nutné ověření." "K vytvoření místního virtuálního počítače nebo kontejneru je nutné ověření."
#: src/machine/org.freedesktop.machine1.policy:106 #: src/machine/org.freedesktop.machine1.policy:106
#, fuzzy
msgid "Register a local virtual machine or container" msgid "Register a local virtual machine or container"
msgstr "Vytvoření místního virtuálního počítače nebo kontejneru" msgstr "Zaregistrovat lokální virtuální stroj nebo kontejner"
#: src/machine/org.freedesktop.machine1.policy:107 #: src/machine/org.freedesktop.machine1.policy:107
#, fuzzy
msgid "" msgid ""
"Authentication is required to register a local virtual machine or container." "Authentication is required to register a local virtual machine or container."
msgstr "" msgstr ""
"K vytvoření místního virtuálního počítače nebo kontejneru je nutné ověření." "K zaregistrování lokálního virtuálního stroje nebo kontejneru je nutné "
"ověření."
#: src/machine/org.freedesktop.machine1.policy:116 #: src/machine/org.freedesktop.machine1.policy:116
msgid "Manage local virtual machine and container images" msgid "Manage local virtual machine and container images"
@ -1115,12 +1113,11 @@ msgstr "Pro přihlášení k odběru výsledků dotazu je vyžadováno ověřen
#: src/resolve/org.freedesktop.resolve1.policy:154 #: src/resolve/org.freedesktop.resolve1.policy:154
msgid "Subscribe to DNS configuration" msgid "Subscribe to DNS configuration"
msgstr "" msgstr "Přihlásit se k odběru nastavení DNS"
#: src/resolve/org.freedesktop.resolve1.policy:155 #: src/resolve/org.freedesktop.resolve1.policy:155
#, fuzzy
msgid "Authentication is required to subscribe to DNS configuration." msgid "Authentication is required to subscribe to DNS configuration."
msgstr "Pro přihlášení k odběru výsledků dotazu je vyžadováno ověření." msgstr "Pro přihlášení k odběru nastavení DNS je vyžadováno ověření."
#: src/resolve/org.freedesktop.resolve1.policy:165 #: src/resolve/org.freedesktop.resolve1.policy:165
msgid "Dump cache" msgid "Dump cache"
@ -1259,11 +1256,12 @@ msgid ""
msgstr "Pro odeslání UNIX signálu procesům „$(unit)” je vyžadováno ověření." msgstr "Pro odeslání UNIX signálu procesům „$(unit)” je vyžadováno ověření."
#: src/core/dbus-unit.c:620 #: src/core/dbus-unit.c:620
#, fuzzy
msgid "" msgid ""
"Authentication is required to send a UNIX signal to the processes of " "Authentication is required to send a UNIX signal to the processes of "
"subgroup of '$(unit)'." "subgroup of '$(unit)'."
msgstr "Pro odeslání UNIX signálu procesům „$(unit)” je vyžadováno ověření." msgstr ""
"Pro odeslání UNIX signálu procesům nebo podskupině „$(unit)” je vyžadováno "
"ověření."
#: src/core/dbus-unit.c:648 #: src/core/dbus-unit.c:648
msgid "Authentication is required to reset the \"failed\" state of '$(unit)'." msgid "Authentication is required to reset the \"failed\" state of '$(unit)'."

View File

@ -59,9 +59,13 @@
#define DEFAULT_RLIMIT_MEMLOCK (1024ULL*1024ULL*8ULL) #define DEFAULT_RLIMIT_MEMLOCK (1024ULL*1024ULL*8ULL)
/* Path where PID1 listens for varlink subscriptions from systemd-oomd to notify of changes in ManagedOOM settings. */ /* Path where PID1 listens for varlink subscriptions from systemd-oomd to notify of changes in ManagedOOM settings. */
#define VARLINK_ADDR_PATH_MANAGED_OOM_SYSTEM "/run/systemd/io.systemd.ManagedOOM" #define VARLINK_PATH_MANAGED_OOM_SYSTEM "/run/systemd/io.systemd.ManagedOOM"
/* Path where systemd-oomd listens for varlink connections from user managers to report changes in ManagedOOM settings. */ /* Path where systemd-oomd listens for varlink connections from user managers to report changes in ManagedOOM settings. */
#define VARLINK_ADDR_PATH_MANAGED_OOM_USER "/run/systemd/oom/io.systemd.ManagedOOM" #define VARLINK_PATH_MANAGED_OOM_USER "/run/systemd/oom/io.systemd.ManagedOOM"
/* Path where systemd-machined listens to userdb varlink queries */
#define VARLINK_PATH_MACHINED_USERDB "/run/systemd/userdb/io.systemd.Machine"
/* Path where systemd-machined listens to resolve.hook varlink queries */
#define VARLINK_PATH_MACHINED_RESOLVE_HOOK "/run/systemd/resolve.hook/io.systemd.Machine"
/* Recommended baseline - see README for details */ /* Recommended baseline - see README for details */
#define KERNEL_BASELINE_VERSION "5.7" #define KERNEL_BASELINE_VERSION "5.7"

View File

@ -2997,9 +2997,8 @@ static void config_load_all_entries(
config_add_system_entries(config); config_add_system_entries(config);
/* Find secure boot signing keys and autoload them if configured. Otherwise, create menu entries so /* Using the rules defined by the `secure-boot-enroll` variable, find secure boot signing keys
* that the user can load them manually. If the secure-boot-enroll variable is set to no (the * and perform operations like autoloading them or create menu entries if configured. */
* default), we do not even search for keys on the ESP */
(void) secure_boot_discover_keys(config, root_dir); (void) secure_boot_discover_keys(config, root_dir);
if (config->n_entries == 0) if (config->n_entries == 0)

View File

@ -169,7 +169,7 @@ static int managed_oom_vl_reply(sd_varlink *link, sd_json_variant *parameters, c
m->managed_oom_varlink = sd_varlink_unref(link); m->managed_oom_varlink = sd_varlink_unref(link);
log_debug("Reconnecting to %s", VARLINK_ADDR_PATH_MANAGED_OOM_USER); log_debug("Reconnecting to %s", VARLINK_PATH_MANAGED_OOM_USER);
r = manager_varlink_managed_oom_connect(m); r = manager_varlink_managed_oom_connect(m);
if (r <= 0) if (r <= 0)
@ -194,7 +194,7 @@ static int manager_varlink_managed_oom_connect(Manager *m) {
if (MANAGER_IS_TEST_RUN(m)) if (MANAGER_IS_TEST_RUN(m))
return 0; return 0;
r = sd_varlink_connect_address(&link, VARLINK_ADDR_PATH_MANAGED_OOM_USER); r = sd_varlink_connect_address(&link, VARLINK_PATH_MANAGED_OOM_USER);
if (r == -ENOENT) if (r == -ENOENT)
return 0; return 0;
if (ERRNO_IS_NEG_DISCONNECT(r)) { if (ERRNO_IS_NEG_DISCONNECT(r)) {
@ -202,7 +202,7 @@ static int manager_varlink_managed_oom_connect(Manager *m) {
return 0; return 0;
} }
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to connect to '%s': %m", VARLINK_ADDR_PATH_MANAGED_OOM_USER); return log_error_errno(r, "Failed to connect to '%s': %m", VARLINK_PATH_MANAGED_OOM_USER);
sd_varlink_set_userdata(link, m); sd_varlink_set_userdata(link, m);
@ -435,7 +435,7 @@ static int manager_varlink_init_system(Manager *m) {
if (!MANAGER_IS_TEST_RUN(m)) { if (!MANAGER_IS_TEST_RUN(m)) {
FOREACH_STRING(address, FOREACH_STRING(address,
"/run/systemd/userdb/io.systemd.DynamicUser", "/run/systemd/userdb/io.systemd.DynamicUser",
VARLINK_ADDR_PATH_MANAGED_OOM_SYSTEM, VARLINK_PATH_MANAGED_OOM_SYSTEM,
"/run/systemd/io.systemd.Manager") { "/run/systemd/io.systemd.Manager") {
/* We might have got sockets through deserialization. Do not bind to them twice. */ /* We might have got sockets through deserialization. Do not bind to them twice. */
if (!fresh && varlink_server_contains_socket(m->varlink_server, address)) if (!fresh && varlink_server_contains_socket(m->varlink_server, address))

29
src/include/musl/getopt.h Normal file
View File

@ -0,0 +1,29 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
/* getopt() is provided both in getopt.h and unistd.h. Hence, we need to tentatively undefine it. */
#undef getopt
#include_next <getopt.h>
/* musl's getopt() always behaves POSIXLY_CORRECT mode, and stops parsing arguments when a non-option string
* found. Let's always use getopt_long(). */
int getopt_fix(int argc, char * const *argv, const char *optstring);
#define getopt(argc, argv, optstring) getopt_fix(argc, argv, optstring)
/* musl's getopt_long() behaves something different in handling optional arguments.
* ========
* $ journalctl _PID=1 _COMM=systemd --since 19:19:01 -n all --follow
* Failed to add match 'all': Invalid argument
* ========
* Here, we introduce getopt_long_fix() that reorders the passed arguments to make getopt_long() provided by
* musl works as what we expect. */
int getopt_long_fix(
int argc,
char * const *argv,
const char *optstring,
const struct option *longopts,
int *longindex);
#define getopt_long(argc, argv, optstring, longopts, longindex) \
getopt_long_fix(argc, argv, optstring, longopts, longindex)

12
src/include/musl/unistd.h Normal file
View File

@ -0,0 +1,12 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
/* getopt() is provided both in getopt.h and unistd.h. Hence, we need to tentatively undefine it. */
#undef getopt
#include_next <unistd.h>
/* musl's getopt() always behaves POSIXLY_CORRECT mode, and stops parsing arguments when a non-option string
* found. Let's always use getopt_long(). */
int getopt_fix(int argc, char * const *argv, const char *optstring);
#define getopt(argc, argv, optstring) getopt_fix(argc, argv, optstring)

View File

@ -362,7 +362,9 @@ static int on_first_event(sd_event_source *s, void *userdata) {
return log_error_errno(r, "Failed to get cursor: %m"); return log_error_errno(r, "Failed to get cursor: %m");
} }
/* Setup and initial processing are done, we're ready to wait for more data. */
(void) sd_notify(/* unset_environment= */ false, "READY=1"); (void) sd_notify(/* unset_environment= */ false, "READY=1");
return 0; return 0;
} }
@ -472,11 +474,9 @@ static int setup_event(Context *c, int fd) {
else if (r < 0) else if (r < 0)
return log_error_errno(r, "Failed to add io event source for stdout: %m"); return log_error_errno(r, "Failed to add io event source for stdout: %m");
if (arg_lines != 0 || arg_since_set) { r = sd_event_add_defer(e, NULL, on_first_event, c);
r = sd_event_add_defer(e, NULL, on_first_event, c); if (r < 0)
if (r < 0) return log_error_errno(r, "Failed to add defer event source: %m");
return log_error_errno(r, "Failed to add defer event source: %m");
}
c->event = TAKE_PTR(e); c->event = TAKE_PTR(e);
return 0; return 0;
@ -583,6 +583,7 @@ int action_show(char **matches) {
return 0; return 0;
} }
/* Setup is done, we'll start processing data. */
(void) sd_notify(/* unset_environment= */ false, "READY=1"); (void) sd_notify(/* unset_environment= */ false, "READY=1");
r = show(&c); r = show(&c);

100
src/libc/musl/getopt.c Normal file
View File

@ -0,0 +1,100 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <getopt.h>
#include <stdbool.h>
#include <string.h>
static int first_non_opt = 0, last_non_opt = 0;
static bool non_opt_found = false, dash_dash = false;
static void shift(char * const *argv, int start, int end) {
char **av = (char**) argv;
char *saved = av[end];
for (int i = end; i > start; i--)
av[i] = av[i - 1];
av[start] = saved;
}
static void exchange(int argc, char * const *argv) {
/* input:
*
* first_non_opt last_non_opt optind
* | | |
* v v v
* aaaaa bbbbb ccccc --prev-opt prev-opt-arg ddddd --next-opt
*
* output:
* first_non_opt last_non_opt optind
* | | |
* v v v
* --prev-opt prev-opt-arg aaaaa bbbbb ccccc ddddd --next-opt
*/
/* First, move previous arguments. */
int c = optind - 1 - last_non_opt;
if (c > 0) {
for (int i = 0; i < c; i++)
shift(argv, first_non_opt, optind - 1);
first_non_opt += c;
last_non_opt += c;
}
/* Then, skip entries that do not start with '-'. */
while (optind < argc && (argv[optind][0] != '-' || argv[optind][1] == '\0')) {
if (!non_opt_found) {
first_non_opt = optind;
non_opt_found = true;
}
last_non_opt = optind;
optind++;
}
}
int getopt_long_fix(
int argc,
char * const *argv,
const char *optstring,
const struct option *longopts,
int *longindex) {
int r;
if (optind == 0 || first_non_opt == 0 || last_non_opt == 0) {
/* initialize musl's internal variables. */
(void) (getopt_long)(/* argc= */ -1, /* argv= */ NULL, /* optstring= */ NULL, /* longopts= */ NULL, /* longindex= */ NULL);
first_non_opt = last_non_opt = 1;
non_opt_found = dash_dash = false;
}
if (first_non_opt >= argc || last_non_opt >= argc || optind > argc || dash_dash)
return -1;
/* Do not shuffle arguments when optstring starts with '+' or '-'. */
if (!optstring || optstring[0] == '+' || optstring[0] == '-')
return (getopt_long)(argc, argv, optstring, longopts, longindex);
exchange(argc, argv);
if (optind < argc && strcmp(argv[optind], "--") == 0) {
if (first_non_opt < optind)
shift(argv, first_non_opt, optind);
first_non_opt++;
optind++;
dash_dash = true;
if (non_opt_found)
optind = first_non_opt;
return -1;
}
r = (getopt_long)(argc, argv, optstring, longopts, longindex);
if (r < 0 && non_opt_found)
optind = first_non_opt;
return r;
}
int getopt_fix(int argc, char * const *argv, const char *optstring) {
return getopt_long_fix(argc, argv, optstring, /* longopts= */ NULL, /* longindex= */ NULL);
}

View File

@ -5,6 +5,7 @@ if get_option('libc') != 'musl'
endif endif
libc_wrapper_sources += files( libc_wrapper_sources += files(
'getopt.c',
'printf.c', 'printf.c',
'stdio.c', 'stdio.c',
'stdlib.c', 'stdlib.c',

View File

@ -505,13 +505,14 @@ static int pid_notify_with_fds_internal(
if (r == -EPROTO) if (r == -EPROTO)
r = socket_address_parse_vsock(&address, e); r = socket_address_parse_vsock(&address, e);
if (r < 0) if (r < 0)
return r; return log_debug_errno(r, "Address NOTIFY_SOCKET='%s' is neither UNIX nor VSOCK, refusing: %m", e);
msghdr.msg_namelen = address.size; msghdr.msg_namelen = address.size;
/* If we didn't get an address (which is a normal pattern when specifying VSOCK tuples) error out, /* If we didn't get an address (which is a normal pattern when specifying VSOCK tuples) error out,
* we always require a specific CID. */ * we always require a specific CID. */
if (address.sockaddr.vm.svm_family == AF_VSOCK && address.sockaddr.vm.svm_cid == VMADDR_CID_ANY) if (address.sockaddr.vm.svm_family == AF_VSOCK && address.sockaddr.vm.svm_cid == VMADDR_CID_ANY)
return -EINVAL; return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
"VSOCK address in NOTIFY_SOCKET='%s' doesn't have CID, refusing.", e);
type = address.type == 0 ? SOCK_DGRAM : address.type; type = address.type == 0 ? SOCK_DGRAM : address.type;
@ -610,7 +611,8 @@ static int pid_notify_with_fds_internal(
} else { } else {
/* Unless we're using SOCK_STREAM, we expect to write all the contents immediately. */ /* Unless we're using SOCK_STREAM, we expect to write all the contents immediately. */
if (type != SOCK_STREAM && (size_t) n < iovec_total_size(msghdr.msg_iov, msghdr.msg_iovlen)) if (type != SOCK_STREAM && (size_t) n < iovec_total_size(msghdr.msg_iov, msghdr.msg_iovlen))
return -EIO; return log_debug_errno(SYNTHETIC_ERRNO(EIO),
"Incomplete notify message sent to '%s': %m", e);
/* Make sure we only send fds and ucred once, even if we're using SOCK_STREAM. */ /* Make sure we only send fds and ucred once, even if we're using SOCK_STREAM. */
msghdr.msg_control = NULL; msghdr.msg_control = NULL;
@ -631,6 +633,7 @@ static int pid_notify_with_fds_internal(
return log_debug_errno(SYNTHETIC_ERRNO(EPROTO), "Unexpectedly received data on notify socket."); return log_debug_errno(SYNTHETIC_ERRNO(EPROTO), "Unexpectedly received data on notify socket.");
} }
log_debug("Notify message sent to '%s': \"%s\"", e, state);
return 1; return 1;
} }

View File

@ -55,6 +55,11 @@ typedef struct sd_netlink_slot {
}; };
} sd_netlink_slot; } sd_netlink_slot;
typedef struct NetlinkIgnoredSerial {
uint32_t serial;
usec_t timeout_usec; /* timestamp in CLOCK_MONOTONIC */
} NetlinkIgnoredSerial;
typedef struct sd_netlink { typedef struct sd_netlink {
unsigned n_ref; unsigned n_ref;
@ -78,6 +83,7 @@ typedef struct sd_netlink {
bool processing:1; bool processing:1;
uint32_t serial; uint32_t serial;
Hashmap *ignored_serials;
struct Prioq *reply_callbacks_prioq; struct Prioq *reply_callbacks_prioq;
Hashmap *reply_callbacks; Hashmap *reply_callbacks;
@ -181,8 +187,7 @@ int sd_nfnl_call_batch(
sd_netlink *nfnl, sd_netlink *nfnl,
sd_netlink_message **messages, sd_netlink_message **messages,
size_t n_messages, size_t n_messages,
uint64_t usec, uint64_t usec);
sd_netlink_message ***ret_messages);
int sd_nfnl_message_new( int sd_nfnl_message_new(
sd_netlink *nfnl, sd_netlink *nfnl,
sd_netlink_message **ret, sd_netlink_message **ret,

View File

@ -7,7 +7,6 @@
#include "sd-netlink.h" #include "sd-netlink.h"
#include "alloc-util.h" #include "alloc-util.h"
#include "errno-util.h"
#include "iovec-util.h" #include "iovec-util.h"
#include "netlink-internal.h" #include "netlink-internal.h"
#include "netlink-util.h" #include "netlink-util.h"
@ -119,7 +118,7 @@ int sd_nfnl_send_batch(
return -ENOMEM; return -ENOMEM;
if (ret_serials) { if (ret_serials) {
serials = new(uint32_t, n_messages); serials = new(uint32_t, n_messages + 2);
if (!serials) if (!serials)
return -ENOMEM; return -ENOMEM;
} }
@ -133,6 +132,9 @@ int sd_nfnl_send_batch(
return r; return r;
netlink_seal_message(nfnl, batch_begin); netlink_seal_message(nfnl, batch_begin);
if (serials)
serials[c] = message_get_serial(batch_begin);
iovs[c++] = IOVEC_MAKE(batch_begin->hdr, batch_begin->hdr->nlmsg_len); iovs[c++] = IOVEC_MAKE(batch_begin->hdr, batch_begin->hdr->nlmsg_len);
for (size_t i = 0; i < n_messages; i++) { for (size_t i = 0; i < n_messages; i++) {
@ -147,7 +149,7 @@ int sd_nfnl_send_batch(
netlink_seal_message(nfnl, messages[i]); netlink_seal_message(nfnl, messages[i]);
if (serials) if (serials)
serials[i] = message_get_serial(messages[i]); serials[c] = message_get_serial(messages[i]);
/* It seems that the kernel accepts an arbitrary number. Let's set the lower 16 bits of the /* It seems that the kernel accepts an arbitrary number. Let's set the lower 16 bits of the
* serial of the first message. */ * serial of the first message. */
@ -161,6 +163,9 @@ int sd_nfnl_send_batch(
return r; return r;
netlink_seal_message(nfnl, batch_end); netlink_seal_message(nfnl, batch_end);
if (serials)
serials[c] = message_get_serial(batch_end);
iovs[c++] = IOVEC_MAKE(batch_end->hdr, batch_end->hdr->nlmsg_len); iovs[c++] = IOVEC_MAKE(batch_end->hdr, batch_end->hdr->nlmsg_len);
assert(c == n_messages + 2); assert(c == n_messages + 2);
@ -178,10 +183,8 @@ int sd_nfnl_call_batch(
sd_netlink *nfnl, sd_netlink *nfnl,
sd_netlink_message **messages, sd_netlink_message **messages,
size_t n_messages, size_t n_messages,
uint64_t usec, uint64_t usec) {
sd_netlink_message ***ret_messages) {
_cleanup_free_ sd_netlink_message **replies = NULL;
_cleanup_free_ uint32_t *serials = NULL; _cleanup_free_ uint32_t *serials = NULL;
int r; int r;
@ -190,26 +193,40 @@ int sd_nfnl_call_batch(
assert_return(messages, -EINVAL); assert_return(messages, -EINVAL);
assert_return(n_messages > 0, -EINVAL); assert_return(n_messages > 0, -EINVAL);
if (ret_messages) {
replies = new0(sd_netlink_message*, n_messages);
if (!replies)
return -ENOMEM;
}
r = sd_nfnl_send_batch(nfnl, messages, n_messages, &serials); r = sd_nfnl_send_batch(nfnl, messages, n_messages, &serials);
if (r < 0) if (r < 0)
return r; return r;
for (size_t i = 0; i < n_messages; i++) for (size_t i = 1; i <= n_messages; i++) {
RET_GATHER(r, /* If we have received an error, kernel may not send replies for later messages. Let's ignore
sd_netlink_read(nfnl, serials[i], usec, ret_messages ? replies + i : NULL)); * remaining replies. */
if (r < 0) if (r < 0) {
return r; (void) sd_netlink_ignore_serial(nfnl, serials[i], usec);
continue;
}
if (ret_messages) r = sd_netlink_read(nfnl, serials[i], usec, /* ret= */ NULL);
*ret_messages = TAKE_PTR(replies); if (r != -ETIMEDOUT)
continue;
return 0; /* The kernel returns some errors, e.g. unprivileged, to the BATCH_BEGIN. Hence, if we have
* not received any replies for the batch body, try to read an error in the reply for the
* batch begin. Note, since v6.10 (bf2ac490d28c21a349e9eef81edc45320fca4a3c), we can expect
* that the kernel always replies the batch begin and end. When we bump the kernel baseline,
* we can read the reply for the batch begin at first. */
int k = sd_netlink_read(nfnl, serials[0], usec, /* ret= */ NULL);
if (k < 0)
r = k;
serials[0] = 0; /* indicates that we have read the reply. */
}
/* Ignore replies for batch begin and end if we have not read them. */
if (serials[0] != 0)
(void) sd_netlink_ignore_serial(nfnl, serials[0], usec);
(void) sd_netlink_ignore_serial(nfnl, serials[n_messages + 1], usec);
return r;
} }
int sd_nfnl_nft_message_new_basechain( int sd_nfnl_nft_message_new_basechain(

View File

@ -222,6 +222,16 @@ static int netlink_queue_received_message(sd_netlink *nl, sd_netlink_message *m)
assert(nl); assert(nl);
assert(m); assert(m);
serial = message_get_serial(m);
if (serial != 0) {
NetlinkIgnoredSerial *s = hashmap_remove(nl->ignored_serials, UINT32_TO_PTR(serial));
if (s) {
/* We are not interested in the message anymore. */
free(s);
return 0;
}
}
if (ordered_set_size(nl->rqueue) >= NETLINK_RQUEUE_MAX) if (ordered_set_size(nl->rqueue) >= NETLINK_RQUEUE_MAX)
return log_debug_errno(SYNTHETIC_ERRNO(ENOBUFS), return log_debug_errno(SYNTHETIC_ERRNO(ENOBUFS),
"sd-netlink: exhausted the read queue size (%d)", NETLINK_RQUEUE_MAX); "sd-netlink: exhausted the read queue size (%d)", NETLINK_RQUEUE_MAX);
@ -235,7 +245,6 @@ static int netlink_queue_received_message(sd_netlink *nl, sd_netlink_message *m)
if (sd_netlink_message_is_broadcast(m)) if (sd_netlink_message_is_broadcast(m))
return 0; return 0;
serial = message_get_serial(m);
if (serial == 0) if (serial == 0)
return 0; return 0;

View File

@ -126,6 +126,8 @@ static sd_netlink *netlink_free(sd_netlink *nl) {
assert(nl); assert(nl);
hashmap_free(nl->ignored_serials);
ordered_set_free(nl->rqueue); ordered_set_free(nl->rqueue);
hashmap_free(nl->rqueue_by_serial); hashmap_free(nl->rqueue_by_serial);
hashmap_free(nl->rqueue_partial_by_serial); hashmap_free(nl->rqueue_partial_by_serial);
@ -152,6 +154,96 @@ static sd_netlink *netlink_free(sd_netlink *nl) {
DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_netlink, sd_netlink, netlink_free); DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_netlink, sd_netlink, netlink_free);
static usec_t netlink_now(sd_netlink *nl, clock_t clock) {
assert(nl);
usec_t now_usec;
if (nl->event && sd_event_now(nl->event, clock, &now_usec) > 0)
return now_usec;
return now(clock);
}
static usec_t timespan_to_timestamp(sd_netlink *nl, usec_t usec) {
static bool default_timeout_set = false;
static usec_t default_timeout;
int r;
assert(nl);
if (usec == 0) {
if (!default_timeout_set) {
const char *e;
default_timeout_set = true;
default_timeout = NETLINK_DEFAULT_TIMEOUT_USEC;
e = secure_getenv("SYSTEMD_NETLINK_DEFAULT_TIMEOUT");
if (e) {
r = parse_sec(e, &default_timeout);
if (r < 0)
log_debug_errno(r, "sd-netlink: Failed to parse $SYSTEMD_NETLINK_DEFAULT_TIMEOUT environment variable, ignoring: %m");
}
}
usec = default_timeout;
}
return usec_add(netlink_now(nl, CLOCK_MONOTONIC), usec);
}
static void netlink_trim_ignored_serials(sd_netlink *nl) {
NetlinkIgnoredSerial *s;
usec_t now_usec = 0;
assert(nl);
HASHMAP_FOREACH(s, nl->ignored_serials) {
if (s->timeout_usec == USEC_INFINITY)
continue;
if (now_usec == 0)
now_usec = netlink_now(nl, CLOCK_MONOTONIC);
if (s->timeout_usec < now_usec)
free(hashmap_remove(nl->ignored_serials, UINT32_TO_PTR(s->serial)));
}
}
int sd_netlink_ignore_serial(sd_netlink *nl, uint32_t serial, uint64_t timeout_usec) {
int r;
assert_return(nl, -EINVAL);
assert_return(!netlink_pid_changed(nl), -ECHILD);
assert_return(serial != 0, -EINVAL);
timeout_usec = timespan_to_timestamp(nl, timeout_usec);
NetlinkIgnoredSerial *existing = hashmap_get(nl->ignored_serials, UINT32_TO_PTR(serial));
if (existing) {
existing->timeout_usec = timeout_usec;
return 0;
}
netlink_trim_ignored_serials(nl);
_cleanup_free_ NetlinkIgnoredSerial *s = new(NetlinkIgnoredSerial, 1);
if (!s)
return -ENOMEM;
*s = (NetlinkIgnoredSerial) {
.serial = serial,
.timeout_usec = timeout_usec,
};
r = hashmap_ensure_put(&nl->ignored_serials, &trivial_hash_ops_value_free, UINT32_TO_PTR(s->serial), s);
if (r < 0)
return r;
TAKE_PTR(s);
return 0;
}
int sd_netlink_send( int sd_netlink_send(
sd_netlink *nl, sd_netlink *nl,
sd_netlink_message *message, sd_netlink_message *message,
@ -204,7 +296,6 @@ static int process_timeout(sd_netlink *nl) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
struct reply_callback *c; struct reply_callback *c;
sd_netlink_slot *slot; sd_netlink_slot *slot;
usec_t n;
int r; int r;
assert(nl); assert(nl);
@ -213,8 +304,7 @@ static int process_timeout(sd_netlink *nl) {
if (!c) if (!c)
return 0; return 0;
n = now(CLOCK_MONOTONIC); if (c->timeout > netlink_now(nl, CLOCK_MONOTONIC))
if (c->timeout > n)
return 0; return 0;
r = message_new_synthetic_error(nl, -ETIMEDOUT, c->serial, &m); r = message_new_synthetic_error(nl, -ETIMEDOUT, c->serial, &m);
@ -337,6 +427,8 @@ static int process_running(sd_netlink *nl, sd_netlink_message **ret) {
assert(nl); assert(nl);
netlink_trim_ignored_serials(nl);
r = process_timeout(nl); r = process_timeout(nl);
if (r != 0) if (r != 0)
goto null_message; goto null_message;
@ -384,32 +476,6 @@ int sd_netlink_process(sd_netlink *nl, sd_netlink_message **ret) {
return r; return r;
} }
static usec_t timespan_to_timestamp(usec_t usec) {
static bool default_timeout_set = false;
static usec_t default_timeout;
int r;
if (usec == 0) {
if (!default_timeout_set) {
const char *e;
default_timeout_set = true;
default_timeout = NETLINK_DEFAULT_TIMEOUT_USEC;
e = secure_getenv("SYSTEMD_NETLINK_DEFAULT_TIMEOUT");
if (e) {
r = parse_sec(e, &default_timeout);
if (r < 0)
log_debug_errno(r, "sd-netlink: Failed to parse $SYSTEMD_NETLINK_DEFAULT_TIMEOUT environment variable, ignoring: %m");
}
}
usec = default_timeout;
}
return usec_add(now(CLOCK_MONOTONIC), usec);
}
static int netlink_poll(sd_netlink *nl, bool need_more, usec_t timeout_usec) { static int netlink_poll(sd_netlink *nl, bool need_more, usec_t timeout_usec) {
usec_t m = USEC_INFINITY; usec_t m = USEC_INFINITY;
int r, e; int r, e;
@ -434,7 +500,7 @@ static int netlink_poll(sd_netlink *nl, bool need_more, usec_t timeout_usec) {
if (r < 0) if (r < 0)
return r; return r;
m = usec_sub_unsigned(until, now(CLOCK_MONOTONIC)); m = usec_sub_unsigned(until, netlink_now(nl, CLOCK_MONOTONIC));
} }
r = fd_wait_for_event(nl->fd, e, MIN(m, timeout_usec)); r = fd_wait_for_event(nl->fd, e, MIN(m, timeout_usec));
@ -508,7 +574,7 @@ int sd_netlink_call_async(
return r; return r;
slot->reply_callback.callback = callback; slot->reply_callback.callback = callback;
slot->reply_callback.timeout = timespan_to_timestamp(usec); slot->reply_callback.timeout = timespan_to_timestamp(nl, usec);
k = sd_netlink_send(nl, m, &slot->reply_callback.serial); k = sd_netlink_send(nl, m, &slot->reply_callback.serial);
if (k < 0) if (k < 0)
@ -549,7 +615,7 @@ int sd_netlink_read(
assert_return(nl, -EINVAL); assert_return(nl, -EINVAL);
assert_return(!netlink_pid_changed(nl), -ECHILD); assert_return(!netlink_pid_changed(nl), -ECHILD);
usec = timespan_to_timestamp(timeout); usec = timespan_to_timestamp(nl, timeout);
for (;;) { for (;;) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
@ -591,7 +657,7 @@ int sd_netlink_read(
if (usec != USEC_INFINITY) { if (usec != USEC_INFINITY) {
usec_t n; usec_t n;
n = now(CLOCK_MONOTONIC); n = netlink_now(nl, CLOCK_MONOTONIC);
if (n >= usec) if (n >= usec)
return -ETIMEDOUT; return -ETIMEDOUT;

View File

@ -6,6 +6,7 @@
#include "sd-varlink.h" #include "sd-varlink.h"
#include "bus-polkit.h" #include "bus-polkit.h"
#include "constants.h"
#include "discover-image.h" #include "discover-image.h"
#include "errno-util.h" #include "errno-util.h"
#include "format-util.h" #include "format-util.h"
@ -745,6 +746,8 @@ static int manager_varlink_init_userdb(Manager *m) {
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to allocate varlink server object: %m"); return log_error_errno(r, "Failed to allocate varlink server object: %m");
(void) sd_varlink_server_set_description(s, "varlink-userdb");
r = sd_varlink_server_add_interface(s, &vl_interface_io_systemd_UserDatabase); r = sd_varlink_server_add_interface(s, &vl_interface_io_systemd_UserDatabase);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to add UserDatabase interface to varlink server: %m"); return log_error_errno(r, "Failed to add UserDatabase interface to varlink server: %m");
@ -757,9 +760,9 @@ static int manager_varlink_init_userdb(Manager *m) {
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to register varlink methods: %m"); return log_error_errno(r, "Failed to register varlink methods: %m");
r = sd_varlink_server_listen_address(s, "/run/systemd/userdb/io.systemd.Machine", 0666 | SD_VARLINK_SERVER_MODE_MKDIR_0755); r = sd_varlink_server_listen_address(s, VARLINK_PATH_MACHINED_USERDB, 0666 | SD_VARLINK_SERVER_MODE_MKDIR_0755);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to bind to varlink socket '/run/systemd/userdb/io.systemd.Machine': %m"); return log_error_errno(r, "Failed to bind to varlink socket %s: %m", VARLINK_PATH_MACHINED_USERDB);
r = sd_varlink_server_attach_event(s, m->event, SD_EVENT_PRIORITY_NORMAL); r = sd_varlink_server_attach_event(s, m->event, SD_EVENT_PRIORITY_NORMAL);
if (r < 0) if (r < 0)
@ -889,9 +892,11 @@ static int manager_varlink_init_resolve_hook(Manager *m) {
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to bind on resolve hook disconnection events: %m"); return log_error_errno(r, "Failed to bind on resolve hook disconnection events: %m");
r = sd_varlink_server_listen_address(s, "/run/systemd/resolve.hook/io.systemd.Machine", 0666 | SD_VARLINK_SERVER_MODE_MKDIR_0755); r = sd_varlink_server_listen_address(s, VARLINK_PATH_MACHINED_RESOLVE_HOOK,
0666 | SD_VARLINK_SERVER_MODE_MKDIR_0755);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to bind to varlink socket: %m"); return log_error_errno(r, "Failed to bind to varlink socket %s: %m",
VARLINK_PATH_MACHINED_RESOLVE_HOOK);
r = sd_varlink_server_attach_event(s, m->event, SD_EVENT_PRIORITY_NORMAL); r = sd_varlink_server_attach_event(s, m->event, SD_EVENT_PRIORITY_NORMAL);
if (r < 0) if (r < 0)

View File

@ -334,9 +334,9 @@ static int acquire_managed_oom_connect(Manager *m) {
assert(m); assert(m);
assert(m->event); assert(m->event);
r = sd_varlink_connect_address(&link, VARLINK_ADDR_PATH_MANAGED_OOM_SYSTEM); r = sd_varlink_connect_address(&link, VARLINK_PATH_MANAGED_OOM_SYSTEM);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to connect to " VARLINK_ADDR_PATH_MANAGED_OOM_SYSTEM ": %m"); return log_error_errno(r, "Failed to connect to %s: %m", VARLINK_PATH_MANAGED_OOM_SYSTEM);
(void) sd_varlink_set_userdata(link, m); (void) sd_varlink_set_userdata(link, m);
(void) sd_varlink_set_description(link, "oomd"); (void) sd_varlink_set_description(link, "oomd");
@ -768,11 +768,12 @@ static int manager_varlink_init(Manager *m, int fd) {
return log_error_errno(r, "Failed to register varlink methods: %m"); return log_error_errno(r, "Failed to register varlink methods: %m");
if (fd < 0) if (fd < 0)
r = sd_varlink_server_listen_address(s, VARLINK_ADDR_PATH_MANAGED_OOM_USER, 0666); r = sd_varlink_server_listen_address(s, VARLINK_PATH_MANAGED_OOM_USER, 0666);
else else
r = sd_varlink_server_listen_fd(s, fd); r = sd_varlink_server_listen_fd(s, fd);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to bind to varlink socket '" VARLINK_ADDR_PATH_MANAGED_OOM_USER "': %m"); return log_error_errno(r, "Failed to bind to varlink socket %s: %m",
VARLINK_PATH_MANAGED_OOM_USER);
r = sd_varlink_server_attach_event(s, m->event, SD_EVENT_PRIORITY_NORMAL); r = sd_varlink_server_attach_event(s, m->event, SD_EVENT_PRIORITY_NORMAL);
if (r < 0) if (r < 0)

View File

@ -807,7 +807,7 @@ static int fw_nftables_init_family(sd_netlink *nfnl, int family) {
return r; return r;
assert(msgcnt < ELEMENTSOF(messages)); assert(msgcnt < ELEMENTSOF(messages));
r = sd_nfnl_call_batch(nfnl, messages, msgcnt, NFNL_DEFAULT_TIMEOUT_USECS, NULL); r = sd_nfnl_call_batch(nfnl, messages, msgcnt, NFNL_DEFAULT_TIMEOUT_USECS);
if (r < 0 && r != -EEXIST) if (r < 0 && r != -EEXIST)
return r; return r;
@ -919,7 +919,7 @@ int nft_set_element_modify_iprange(
if (r < 0) if (r < 0)
return r; return r;
return sd_nfnl_call_batch(nfnl, &m, 1, NFNL_DEFAULT_TIMEOUT_USECS, NULL); return sd_nfnl_call_batch(nfnl, &m, 1, NFNL_DEFAULT_TIMEOUT_USECS);
} }
int nft_set_element_modify_ip( int nft_set_element_modify_ip(
@ -959,7 +959,7 @@ int nft_set_element_modify_ip(
if (r < 0) if (r < 0)
return r; return r;
return sd_nfnl_call_batch(nfnl, &m, 1, NFNL_DEFAULT_TIMEOUT_USECS, NULL); return sd_nfnl_call_batch(nfnl, &m, 1, NFNL_DEFAULT_TIMEOUT_USECS);
} }
int nft_set_element_modify_any( int nft_set_element_modify_any(
@ -987,7 +987,7 @@ int nft_set_element_modify_any(
if (r < 0) if (r < 0)
return r; return r;
return sd_nfnl_call_batch(nfnl, &m, 1, NFNL_DEFAULT_TIMEOUT_USECS, NULL); return sd_nfnl_call_batch(nfnl, &m, 1, NFNL_DEFAULT_TIMEOUT_USECS);
} }
static int af_to_nfproto(int af) { static int af_to_nfproto(int af) {
@ -1124,7 +1124,7 @@ static int fw_nftables_add_local_dnat_internal(
return r; return r;
assert(msgcnt < ELEMENTSOF(messages)); assert(msgcnt < ELEMENTSOF(messages));
r = sd_nfnl_call_batch(nfnl, messages, msgcnt, NFNL_DEFAULT_TIMEOUT_USECS, NULL); r = sd_nfnl_call_batch(nfnl, messages, msgcnt, NFNL_DEFAULT_TIMEOUT_USECS);
if (r == -EOVERFLOW && af == AF_INET6) { if (r == -EOVERFLOW && af == AF_INET6) {
/* The current implementation of DNAT in systemd requires kernel's /* The current implementation of DNAT in systemd requires kernel's
* fdb9c405e35bdc6e305b9b4e20ebc141ed14fc81 (v5.8), and the older kernel returns * fdb9c405e35bdc6e305b9b4e20ebc141ed14fc81 (v5.8), and the older kernel returns

View File

@ -219,7 +219,7 @@ int journal_fork(RuntimeScope scope, char * const* units, PidRef *ret_pidref) {
"-q", "-q",
"--follow", "--follow",
"--no-pager", "--no-pager",
"--lines=1", "--lines=0",
"--synchronize-on-exit=yes"); "--synchronize-on-exit=yes");
if (!argv) if (!argv)
return log_oom_debug(); return log_oom_debug();

View File

@ -56,6 +56,8 @@ int sd_netlink_call_async(sd_netlink *nl, sd_netlink_slot **ret_slot, sd_netlink
int sd_netlink_call(sd_netlink *nl, sd_netlink_message *message, uint64_t timeout, sd_netlink_message **ret); int sd_netlink_call(sd_netlink *nl, sd_netlink_message *message, uint64_t timeout, sd_netlink_message **ret);
int sd_netlink_read(sd_netlink *nl, uint32_t serial, uint64_t timeout, sd_netlink_message **ret); int sd_netlink_read(sd_netlink *nl, uint32_t serial, uint64_t timeout, sd_netlink_message **ret);
int sd_netlink_ignore_serial(sd_netlink *nl, uint32_t serial, uint64_t timeout_usec);
int sd_netlink_get_events(sd_netlink *nl); int sd_netlink_get_events(sd_netlink *nl);
int sd_netlink_get_timeout(sd_netlink *nl, uint64_t *ret); int sd_netlink_get_timeout(sd_netlink *nl, uint64_t *ret);
int sd_netlink_process(sd_netlink *nl, sd_netlink_message **ret); int sd_netlink_process(sd_netlink *nl, sd_netlink_message **ret);

View File

@ -769,21 +769,32 @@ int transfer_vacuum(
limit = instances_max - space; limit = instances_max - space;
if (t->target.type == RESOURCE_PARTITION && space != UINT64_MAX) { if (t->target.type == RESOURCE_PARTITION && space != UINT64_MAX) {
_cleanup_free_ char *patterns = NULL;
uint64_t rm, remain; uint64_t rm, remain;
patterns = strv_join(t->target.patterns, "|");
if (!patterns)
(void) log_oom_debug();
/* If we are looking at a partition table, we also have to take into account how many /* If we are looking at a partition table, we also have to take into account how many
* partition slots of the right type are available */ * partition slots of the right type are available */
if (t->target.n_empty + t->target.n_instances < 2) if (t->target.n_empty + t->target.n_instances < 2)
return log_error_errno(SYNTHETIC_ERRNO(ENOSPC), return log_error_errno(SYNTHETIC_ERRNO(ENOSPC),
"Partition table has less than two partition slots of the right type " SD_ID128_UUID_FORMAT_STR " (%s), refusing.", "Partition table has less than two partition slots of the right type " SD_ID128_UUID_FORMAT_STR " (%s)%s%s%s, refusing.",
SD_ID128_FORMAT_VAL(t->target.partition_type.uuid), SD_ID128_FORMAT_VAL(t->target.partition_type.uuid),
gpt_partition_type_uuid_to_string(t->target.partition_type.uuid)); gpt_partition_type_uuid_to_string(t->target.partition_type.uuid),
!isempty(patterns) ? " and matching the expected pattern '" : "",
strempty(patterns),
!isempty(patterns) ? "'" : "");
if (space > t->target.n_empty + t->target.n_instances) if (space > t->target.n_empty + t->target.n_instances)
return log_error_errno(SYNTHETIC_ERRNO(ENOSPC), return log_error_errno(SYNTHETIC_ERRNO(ENOSPC),
"Partition table does not have enough partition slots of right type " SD_ID128_UUID_FORMAT_STR " (%s) for operation.", "Partition table does not have enough partition slots of right type " SD_ID128_UUID_FORMAT_STR " (%s)%s%s%s for operation.",
SD_ID128_FORMAT_VAL(t->target.partition_type.uuid), SD_ID128_FORMAT_VAL(t->target.partition_type.uuid),
gpt_partition_type_uuid_to_string(t->target.partition_type.uuid)); gpt_partition_type_uuid_to_string(t->target.partition_type.uuid),
!isempty(patterns) ? " and matching the expected pattern '" : "",
strempty(patterns),
!isempty(patterns) ? "'" : "");
if (space == t->target.n_empty + t->target.n_instances) if (space == t->target.n_empty + t->target.n_instances)
return log_error_errno(SYNTHETIC_ERRNO(ENOSPC), return log_error_errno(SYNTHETIC_ERRNO(ENOSPC),
"Asked to empty all partition table slots of the right type " SD_ID128_UUID_FORMAT_STR " (%s), can't allow that. One instance must always remain.", "Asked to empty all partition table slots of the right type " SD_ID128_UUID_FORMAT_STR " (%s), can't allow that. One instance must always remain.",

View File

@ -111,6 +111,7 @@ simple_tests += files(
'test-format-util.c', 'test-format-util.c',
'test-fs-util.c', 'test-fs-util.c',
'test-fstab-util.c', 'test-fstab-util.c',
'test-getopt.c',
'test-glob-util.c', 'test-glob-util.c',
'test-gpt.c', 'test-gpt.c',
'test-gunicode.c', 'test-gunicode.c',

View File

@ -1,8 +1,5 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <stdlib.h>
#include <unistd.h>
#include "sd-netlink.h" #include "sd-netlink.h"
#include "firewall-util.h" #include "firewall-util.h"
@ -79,9 +76,6 @@ TEST(v4) {
static int intro(void) { static int intro(void) {
int r; int r;
if (getuid() != 0)
return log_tests_skipped("not root");
ASSERT_OK_ERRNO(setenv("SYSTEMD_FIREWALL_UTIL_NFT_TABLE_NAME", "io.systemd-test.nat", /* overwrite = */ true)); ASSERT_OK_ERRNO(setenv("SYSTEMD_FIREWALL_UTIL_NFT_TABLE_NAME", "io.systemd-test.nat", /* overwrite = */ true));
ASSERT_OK_ERRNO(setenv("SYSTEMD_FIREWALL_UTIL_DNAT_MAP_NAME", "test_map_port_ipport", /* overwrite = */ true)); ASSERT_OK_ERRNO(setenv("SYSTEMD_FIREWALL_UTIL_DNAT_MAP_NAME", "test_map_port_ipport", /* overwrite = */ true));

516
src/test/test-getopt.c Normal file
View File

@ -0,0 +1,516 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <getopt.h>
#include "strv.h"
#include "tests.h"
typedef struct Entry {
int opt;
const char *argument;
const char *nextarg;
} Entry;
static void test_getopt_long_one(
char **argv,
const char *optstring,
const struct option *longopts,
const Entry *entries,
char **remaining) {
_cleanup_free_ char *joined = strv_join(argv, ", ");
log_debug("/* %s(%s) */", __func__, joined);
_cleanup_free_ char *saved_argv0 = NULL;
ASSERT_NOT_NULL(saved_argv0 = strdup(argv[0]));
int c, argc = strv_length(argv);
size_t i = 0, n_entries = 0;
for (const Entry *e = entries; e && e->opt != 0; e++)
n_entries++;
optind = 0;
while ((c = getopt_long(argc, argv, optstring, longopts, NULL)) >= 0) {
if (c < 0x100)
log_debug("%c: %s", c, strna(optarg));
else
log_debug("0x%x: %s", (unsigned) c, strna(optarg));
ASSERT_LT(i, n_entries);
ASSERT_EQ(c, entries[i].opt);
ASSERT_STREQ(optarg, entries[i].argument);
if (entries[i].nextarg)
ASSERT_STREQ(argv[optind], entries[i].nextarg);
i++;
}
ASSERT_EQ(i, n_entries);
ASSERT_LE(optind, argc);
ASSERT_EQ(argc - optind, (int) strv_length(remaining));
for (int j = optind; j < argc; j++)
ASSERT_STREQ(argv[j], remaining[j - optind]);
ASSERT_STREQ(argv[0], saved_argv0);
}
TEST(getopt_long) {
enum {
ARG_VERSION = 0x100,
ARG_REQUIRED,
ARG_OPTIONAL,
};
static const struct option options[] = {
{ "help", no_argument, NULL, 'h' },
{ "version" , no_argument, NULL, ARG_VERSION },
{ "required1", required_argument, NULL, 'r' },
{ "required2", required_argument, NULL, ARG_REQUIRED },
{ "optional1", optional_argument, NULL, 'o' },
{ "optional2", optional_argument, NULL, ARG_OPTIONAL },
{},
};
test_getopt_long_one(STRV_MAKE("arg0"),
"hr:o::", options,
NULL,
NULL);
test_getopt_long_one(STRV_MAKE("arg0",
"string1",
"string2",
"string3",
"string4"),
"hr:o::", options,
NULL,
STRV_MAKE("string1",
"string2",
"string3",
"string4"));
test_getopt_long_one(STRV_MAKE("arg0",
"--",
"string1",
"string2",
"string3",
"string4"),
"hr:o::", options,
NULL,
STRV_MAKE("string1",
"string2",
"string3",
"string4"));
test_getopt_long_one(STRV_MAKE("arg0",
"string1",
"string2",
"--",
"string3",
"string4"),
"hr:o::", options,
NULL,
STRV_MAKE("string1",
"string2",
"string3",
"string4"));
test_getopt_long_one(STRV_MAKE("arg0",
"string1",
"string2",
"string3",
"string4",
"--"),
"hr:o::", options,
NULL,
STRV_MAKE("string1",
"string2",
"string3",
"string4"));
test_getopt_long_one(STRV_MAKE("arg0",
"--help"),
"hr:o::", options,
(Entry[]) {
{ 'h', NULL },
{}
},
NULL);
test_getopt_long_one(STRV_MAKE("arg0",
"-h"),
"hr:o::", options,
(Entry[]) {
{ 'h', NULL },
{}
},
NULL);
test_getopt_long_one(STRV_MAKE("arg0",
"--help",
"string1",
"string2",
"string3",
"string4"),
"hr:o::", options,
(Entry[]) {
{ 'h', NULL },
{}
},
STRV_MAKE("string1",
"string2",
"string3",
"string4"));
test_getopt_long_one(STRV_MAKE("arg0",
"-h",
"string1",
"string2",
"string3",
"string4"),
"hr:o::", options,
(Entry[]) {
{ 'h', NULL },
{}
},
STRV_MAKE("string1",
"string2",
"string3",
"string4"));
test_getopt_long_one(STRV_MAKE("arg0",
"string1",
"string2",
"--help",
"string3",
"string4"),
"hr:o::", options,
(Entry[]) {
{ 'h', NULL },
{}
},
STRV_MAKE("string1",
"string2",
"string3",
"string4"));
test_getopt_long_one(STRV_MAKE("arg0",
"string1",
"string2",
"-h",
"string3",
"string4"),
"hr:o::", options,
(Entry[]) {
{ 'h', NULL },
{}
},
STRV_MAKE("string1",
"string2",
"string3",
"string4"));
test_getopt_long_one(STRV_MAKE("arg0",
"string1",
"string2",
"string3",
"string4",
"--help"),
"hr:o::", options,
(Entry[]) {
{ 'h', NULL },
{}
},
STRV_MAKE("string1",
"string2",
"string3",
"string4"));
test_getopt_long_one(STRV_MAKE("arg0",
"string1",
"string2",
"string3",
"string4",
"-h"),
"hr:o::", options,
(Entry[]) {
{ 'h', NULL },
{}
},
STRV_MAKE("string1",
"string2",
"string3",
"string4"));
test_getopt_long_one(STRV_MAKE("arg0",
"--required1", "reqarg1"),
"hr:o::", options,
(Entry[]) {
{ 'r', "reqarg1" },
{}
},
NULL);
test_getopt_long_one(STRV_MAKE("arg0",
"-r", "reqarg1"),
"hr:o::", options,
(Entry[]) {
{ 'r', "reqarg1" },
{}
},
NULL);
test_getopt_long_one(STRV_MAKE("arg0",
"string1",
"string2",
"-r", "reqarg1"),
"hr:o::", options,
(Entry[]) {
{ 'r', "reqarg1" },
{}
},
STRV_MAKE("string1",
"string2"));
test_getopt_long_one(STRV_MAKE("arg0",
"--optional1=optarg1"),
"hr:o::", options,
(Entry[]) {
{ 'o', "optarg1" },
{}
},
NULL);
test_getopt_long_one(STRV_MAKE("arg0",
"--optional1", "string1"),
"hr:o::", options,
(Entry[]) {
{ 'o', NULL, "string1" },
{}
},
STRV_MAKE("string1"));
test_getopt_long_one(STRV_MAKE("arg0",
"-ooptarg1"),
"hr:o::", options,
(Entry[]) {
{ 'o', "optarg1" },
{}
}, NULL);
test_getopt_long_one(STRV_MAKE("arg0",
"-o", "string1"),
"hr:o::", options,
(Entry[]) {
{ 'o', NULL, "string1" },
{}
},
STRV_MAKE("string1"));
test_getopt_long_one(STRV_MAKE("arg0",
"string1",
"--help",
"--version",
"string2",
"--required1", "reqarg1",
"--required2", "reqarg2",
"--required1=reqarg3",
"--required2=reqarg4",
"string3",
"--optional1", "string4",
"--optional2", "string5",
"--optional1=optarg1",
"--optional2=optarg2",
"-h",
"-r", "reqarg5",
"-rreqarg6",
"-ooptarg3",
"-o",
"string6",
"-o",
"-h",
"-o",
"--help",
"string7",
"-hooptarg4",
"-hrreqarg6",
"--",
"--help",
"--required1",
"--optional1"),
"hr:o::", options,
(Entry[]) {
{ 'h' },
{ ARG_VERSION },
{ 'r', "reqarg1" },
{ ARG_REQUIRED, "reqarg2" },
{ 'r', "reqarg3" },
{ ARG_REQUIRED, "reqarg4" },
{ 'o', NULL, "string4" },
{ ARG_OPTIONAL, NULL, "string5" },
{ 'o', "optarg1" },
{ ARG_OPTIONAL, "optarg2" },
{ 'h' },
{ 'r', "reqarg5" },
{ 'r', "reqarg6" },
{ 'o', "optarg3" },
{ 'o', NULL, "string6" },
{ 'o', NULL, "-h" },
{ 'h' },
{ 'o', NULL, "--help" },
{ 'h' },
{ 'h' },
{ 'o', "optarg4" },
{ 'h' },
{ 'r', "reqarg6" },
{}
},
STRV_MAKE("string1",
"string2",
"string3",
"string4",
"string5",
"string6",
"string7",
"--help",
"--required1",
"--optional1"));
}
static void test_getopt_one(
char **argv,
const char *optstring,
const Entry *entries,
char **remaining) {
_cleanup_free_ char *joined = strv_join(argv, ", ");
log_debug("/* %s(%s) */", __func__, joined);
_cleanup_free_ char *saved_argv0 = NULL;
ASSERT_NOT_NULL(saved_argv0 = strdup(argv[0]));
int c, argc = strv_length(argv);
size_t i = 0, n_entries = 0;
for (const Entry *e = entries; e && e->opt != 0; e++)
n_entries++;
optind = 0;
while ((c = getopt(argc, argv, optstring)) >= 0) {
log_debug("%c: %s", c, strna(optarg));
ASSERT_LT(i, n_entries);
ASSERT_EQ(c, entries[i].opt);
ASSERT_STREQ(optarg, entries[i].argument);
if (entries[i].nextarg)
ASSERT_STREQ(argv[optind], entries[i].nextarg);
i++;
}
ASSERT_EQ(i, n_entries);
ASSERT_LE(optind, argc);
ASSERT_EQ(argc - optind, (int) strv_length(remaining));
for (int j = optind; j < argc; j++)
ASSERT_STREQ(argv[j], remaining[j - optind]);
ASSERT_STREQ(argv[0], saved_argv0);
}
TEST(getopt) {
test_getopt_one(STRV_MAKE("arg0"),
"hr:o::",
NULL,
NULL);
test_getopt_one(STRV_MAKE("arg0",
"string1",
"string2"),
"hr:o::",
NULL,
STRV_MAKE("string1",
"string2"));
test_getopt_one(STRV_MAKE("arg0",
"-h"),
"hr:o::",
(Entry[]) {
{ 'h', NULL },
{}
},
NULL);
test_getopt_one(STRV_MAKE("arg0",
"-r", "reqarg1"),
"hr:o::",
(Entry[]) {
{ 'r', "reqarg1" },
{}
},
NULL);
test_getopt_one(STRV_MAKE("arg0",
"string1",
"string2",
"-r", "reqarg1"),
"hr:o::",
(Entry[]) {
{ 'r', "reqarg1" },
{}
},
STRV_MAKE("string1",
"string2"));
test_getopt_one(STRV_MAKE("arg0",
"-ooptarg1"),
"hr:o::",
(Entry[]) {
{ 'o', "optarg1" },
{}
},
NULL);
test_getopt_one(STRV_MAKE("arg0",
"-o", "string1"),
"hr:o::",
(Entry[]) {
{ 'o', NULL, "string1" },
{}
},
STRV_MAKE("string1"));
test_getopt_one(STRV_MAKE("arg0",
"string1",
"string2",
"string3",
"-h",
"-r", "reqarg5",
"-rreqarg6",
"-ooptarg3",
"-o",
"string6",
"-o",
"-h",
"-o",
"string7",
"-hooptarg4",
"-hrreqarg6"),
"hr:o::",
(Entry[]) {
{ 'h' },
{ 'r', "reqarg5" },
{ 'r', "reqarg6" },
{ 'o', "optarg3" },
{ 'o', NULL, "string6" },
{ 'o', NULL, "-h" },
{ 'h' },
{ 'o', NULL, "string7" },
{ 'h' },
{ 'o', "optarg4" },
{ 'h' },
{ 'r', "reqarg6" },
{}
},
STRV_MAKE("string1",
"string2",
"string3",
"string6",
"string7"));
}
DEFINE_TEST_MAIN(LOG_DEBUG);