Compare commits

...

15 Commits

Author SHA1 Message Date
Dan Streetman c9ca8984bc
Merge 413f6e0f56 into 2e5b0412f9 2024-11-20 20:19:44 -08:00
Luca Boccassi 2e5b0412f9
network: update state files before replying bus method (#35255)
Follow-up for 2b07a3211b.

Fixes the failure found in
https://autopkgtest.ubuntu.com/results/autopkgtest-noble-upstream-systemd-ci-systemd-ci/noble/amd64/s/systemd-upstream/20241115_182040_92382@/log.gz
. Relevant logs:
```
Nov 16 02:48:36 systemd-networkd[2706]: veth99: Reconfiguring with /run/systemd/network/25-dhcp-client-ipv6-only.network.
Nov 16 02:48:36 systemd-networkd[2706]: veth99: NDISC: Started IPv6 Router Solicitation client
Nov 16 02:48:36 systemd-networkd[2706]: veth99: IPv6 Router Discovery is configured and started.
Nov 16 02:48:36 systemd-networkd[2706]: veth99: NDISC: Sent Router Solicitation, next solicitation in 3s
Nov 16 02:48:36 systemd-networkd[2706]: veth99: NDISC: Received Router Advertisement from fe80::1034:56ff:fe78:9abd: flags=0xc0(managed, other), preference=medium, lifetime=30min
Nov 16 02:48:36 systemd-networkd[2706]: veth99: NDISC: Invoking callback for 'router' event.
Nov 16 02:48:36 systemd-networkd[2706]: veth99: link_check_ready(): dynamic addressing protocols are enabled but none of them finished yet.
Nov 16 02:48:36 systemd-networkd[2706]: veth99: DHCPv6 client: Starting in Solicit mode
Nov 16 02:48:36 systemd-networkd[2706]: veth99: DHCPv6 client: State changed: stopped -> solicitation
Nov 16 02:48:36 systemd-networkd[2706]: veth99: Acquiring DHCPv6 lease on NDisc request
Nov 16 02:48:36 systemd-networkd[2706]: veth99: DHCPv6 client: Sent Solicit
Nov 16 02:48:36 systemd-networkd[2706]: veth99: DHCPv6 client: Next retransmission in 1s
Nov 16 02:48:37 systemd-networkd[2706]: veth99: DHCPv6 client: Sent Solicit
Nov 16 02:48:37 systemd-networkd[2706]: veth99: DHCPv6 client: Next retransmission in 1s
Nov 16 02:48:39 systemd-networkd[2706]: veth99: NDISC: Received Neighbor Advertisement from fe80::1034:56ff:fe78:9abd: Router=yes, Solicited=yes, Override=no
Nov 16 02:48:39 systemd-networkd[2706]: veth99: NDISC: Invoking callback for 'neighbor' event.
Nov 16 02:48:39 systemd-networkd[2706]: veth99: DHCPv6 client: Processed Reply message
Nov 16 02:48:39 systemd-networkd[2706]: veth99: DHCPv6 client: T1 expires in 50s
Nov 16 02:48:39 systemd-networkd[2706]: veth99: DHCPv6 client: T2 expires in 55s
Nov 16 02:48:39 systemd-networkd[2706]: veth99: DHCPv6 client: Valid lifetime expires in 2min
Nov 16 02:48:39 systemd-networkd[2706]: veth99: DHCPv6 client: State changed: solicitation -> bound
Nov 16 02:48:39 systemd-networkd[2706]: veth99: DHCPv6 address 2600::15/128 (valid for 1min 59s, preferred for 1min 59s)
Nov 16 02:48:41 systemd-networkd[2706]: veth99: Received updated DHCPv6 address (configured): 2600::15/128 (valid for 1min 58s, preferred for 1min 58s), flags: no-prefixroute, scope: global
Nov 16 02:48:41 systemd-networkd[2706]: veth99: DHCPv6 addresses and routes set.
Nov 16 02:48:41 systemd-networkd[2706]: veth99: link_check_ready(): IPv4LL:no DHCPv4:no DHCPv6:yes DHCP-PD:no NDisc:no
Nov 16 02:48:41 systemd-networkd[2706]: veth99: State changed: configuring -> configured
```
The interface veth99 entered the configured state after 5 seconds, but
at the same time, the `wait_online()` in the test script considered the
test failed.
The function `wait_online()` first invokes
`systemd-networkd-wait-online` with `--timeout=20`, then check setup
states of interfaces with 5 seconds timeout. So, the failure suggests
that `systemd-networkd-wait-online` finishes immediately, as the state
file was not updated when it is invoked, and thus it handles the
interface veth99 already in the configured state.
2024-11-20 23:36:35 +00:00
Martin Srebotnjak 69af4849aa po: Translated using Weblate (Slovenian)
Currently translated at 100.0% (257 of 257 strings)

Co-authored-by: Martin Srebotnjak <miles@filmsi.net>
Translate-URL: https://translate.fedoraproject.org/projects/systemd/main/sl/
Translation: systemd/main
2024-11-21 04:17:08 +09:00
Jiri Grönroos 18d4e0be89 po: Translated using Weblate (Finnish)
Currently translated at 100.0% (257 of 257 strings)

Co-authored-by: Jiri Grönroos <jiri.gronroos@iki.fi>
Translate-URL: https://translate.fedoraproject.org/projects/systemd/main/fi/
Translation: systemd/main
2024-11-21 04:17:08 +09:00
Dmytro Markevych 7d7b89a015 po: Translated using Weblate (Ukrainian)
Currently translated at 100.0% (257 of 257 strings)

Co-authored-by: Dmytro Markevych <hotr1pak@gmail.com>
Translate-URL: https://translate.fedoraproject.org/projects/systemd/main/uk/
Translation: systemd/main
2024-11-21 04:17:08 +09:00
Léane GRASSER 8a92365f79 po: Translated using Weblate (French)
Currently translated at 100.0% (257 of 257 strings)

Co-authored-by: Léane GRASSER <leane.grasser@proton.me>
Translate-URL: https://translate.fedoraproject.org/projects/systemd/main/fr/
Translation: systemd/main
2024-11-21 04:17:08 +09:00
Yu Watanabe 2b397d43ab test-network: actually check metric and preference
Otherwise, nexthop ID may contain e.g. 300, then
===
AssertionError: '300' unexpectedly found in
'default nhid 3860882700 via fe80::1034:56ff:fe78:9a99 proto ra metric 512 expires 1798sec pref high\n
 default nhid 2639230080 via fe80::1034:56ff:fe78:9a98 proto ra metric 2048 expires 1798sec pref low'
===
2024-11-21 03:43:35 +09:00
Yu Watanabe 9ad294efd0 network: update state files before replying bus method
Follow-up for 2b07a3211b.
2024-11-21 03:42:06 +09:00
Lennart Poettering f6793bbcf0 killall: gracefully handle processes inserted into containers via nsenter -a
"nsenter -a" doesn't migrate the specified process into the target
cgroup (it really should). Thus the cgroup will remain in a cgroup
that is (due to cgroup ns) outside our visibility. The kernel will
report the cgroup path of such cgroups as starting with "/../". Detect
that and print a reasonably error message instead of trying to resolve
that.
2024-11-20 18:11:38 +00:00
Mike Yuan f87863a8ff process-util: refuse to operate on remote PidRef
Follow-up for 7e3e540b88
2024-11-20 18:10:26 +00:00
Antonio Alvarez Feijoo 58c3c2886d cryptenroll: fix typo 2024-11-20 18:03:44 +00:00
Daan De Meyer dbbe895807 test-audit-util: Migrate to new assertion macros 2024-11-20 16:48:55 +00:00
Dan Streetman 413f6e0f56 test/test-variadic: add unit tests for variadic helper macros 2023-05-01 14:14:18 -04:00
Dan Streetman f3ab293474 fundamental/variadic-fundamental: add variadic helper macros
Adds VA_MACRO_HELPER() which allows calling another macro with temporary
variables, unique tokens, and/or existing variables protected from side
effects.

Also adds various other helper macros for dealing with variadic args, such as
VA_GROUP(), VA_IF(), VA_FIRST(), etc.
2023-05-01 14:14:18 -04:00
Dan Streetman b595c40c72 fundamental/macro-fundamental: allow stringifying variadic args, instead of just a single arg 2023-05-01 12:58:34 -04:00
15 changed files with 1364 additions and 50 deletions

View File

@ -3,12 +3,13 @@
# Finnish translation of systemd.
# Jan Kuparinen <copper_fin@hotmail.com>, 2021, 2022, 2023.
# Ricky Tigg <ricky.tigg@gmail.com>, 2022, 2024.
# Jiri Grönroos <jiri.gronroos@iki.fi>, 2024.
msgid ""
msgstr ""
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-11-06 14:42+0000\n"
"PO-Revision-Date: 2024-09-12 13:43+0000\n"
"Last-Translator: Ricky Tigg <ricky.tigg@gmail.com>\n"
"PO-Revision-Date: 2024-11-20 19:13+0000\n"
"Last-Translator: Jiri Grönroos <jiri.gronroos@iki.fi>\n"
"Language-Team: Finnish <https://translate.fedoraproject.org/projects/systemd/"
"main/fi/>\n"
"Language: fi\n"
@ -16,7 +17,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 5.7.2\n"
"X-Generator: Weblate 5.8.2\n"
#: src/core/org.freedesktop.systemd1.policy.in:22
msgid "Send passphrase back to system"
@ -112,14 +113,12 @@ msgid "Authentication is required to update a user's home area."
msgstr "Todennus vaaditaan käyttäjän kotialueen päivittämiseksi."
#: src/home/org.freedesktop.home1.policy:53
#, fuzzy
msgid "Update your home area"
msgstr "Päivitä kotialue"
#: src/home/org.freedesktop.home1.policy:54
#, fuzzy
msgid "Authentication is required to update your home area."
msgstr "Todennus vaaditaan käyttäjän kotialueen päivittämiseksi."
msgstr "Todennus vaaditaan kotialueen päivittämiseksi."
#: src/home/org.freedesktop.home1.policy:63
msgid "Resize a home area"
@ -1174,14 +1173,11 @@ msgstr "Todennus vaaditaan vanhojen järjestelmäpäivitysten puhdistamiseen."
#: src/sysupdate/org.freedesktop.sysupdate1.policy:75
msgid "Manage optional features"
msgstr ""
msgstr "Hallitse valinnaisia ominaisuuksia"
#: src/sysupdate/org.freedesktop.sysupdate1.policy:76
#, fuzzy
msgid "Authentication is required to manage optional features"
msgstr ""
"Todennus vaaditaan aktiivisten istuntojen, käyttäjien ja paikkojen "
"hallintaan."
msgstr "Todennus vaaditaan valinnaisten ominaisuuksien hallintaan"
#: src/timedate/org.freedesktop.timedate1.policy:22
msgid "Set system time"

View File

@ -12,7 +12,7 @@ msgid ""
msgstr ""
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-11-06 14:42+0000\n"
"PO-Revision-Date: 2024-11-07 09:30+0000\n"
"PO-Revision-Date: 2024-11-20 19:13+0000\n"
"Last-Translator: Léane GRASSER <leane.grasser@proton.me>\n"
"Language-Team: French <https://translate.fedoraproject.org/projects/systemd/"
"main/fr/>\n"
@ -360,8 +360,8 @@ msgid ""
"Authentication is required to set the statically configured local hostname, "
"as well as the pretty hostname."
msgstr ""
"Une authentification est requise pour définir le nom d'hôte local de manière "
"statique, ainsi que le nom d'hôte familier."
"Une authentification est requise pour définir le nom d'hôte local configuré "
"de manière statique, ainsi que le nom d'hôte convivial."
#: src/hostname/org.freedesktop.hostname1.policy:41
msgid "Set machine information"

View File

@ -7,7 +7,7 @@ msgstr ""
"Project-Id-Version: systemd\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-11-06 14:42+0000\n"
"PO-Revision-Date: 2024-08-26 19:38+0000\n"
"PO-Revision-Date: 2024-11-20 19:13+0000\n"
"Last-Translator: Martin Srebotnjak <miles@filmsi.net>\n"
"Language-Team: Slovenian <https://translate.fedoraproject.org/projects/"
"systemd/main/sl/>\n"
@ -17,7 +17,7 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=4; plural=n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || "
"n%100==4 ? 2 : 3;\n"
"X-Generator: Weblate 5.7\n"
"X-Generator: Weblate 5.8.2\n"
#: src/core/org.freedesktop.systemd1.policy.in:22
msgid "Send passphrase back to system"
@ -125,16 +125,13 @@ msgstr ""
"območja."
#: src/home/org.freedesktop.home1.policy:53
#, fuzzy
msgid "Update your home area"
msgstr "Posodobite domače območje"
#: src/home/org.freedesktop.home1.policy:54
#, fuzzy
msgid "Authentication is required to update your home area."
msgstr ""
"Preverjanje pristnosti je potrebno za posodobitev uporabnikovega domačega "
"območja."
"Preverjanje pristnosti je potrebno za posodobitev vašega domačega območja."
#: src/home/org.freedesktop.home1.policy:63
msgid "Resize a home area"
@ -1234,14 +1231,12 @@ msgstr ""
#: src/sysupdate/org.freedesktop.sysupdate1.policy:75
msgid "Manage optional features"
msgstr ""
msgstr "Upravljaj dodatne funkcionalnosti"
#: src/sysupdate/org.freedesktop.sysupdate1.policy:76
#, fuzzy
msgid "Authentication is required to manage optional features"
msgstr ""
"Preverjanje pristnosti je potrebno za upravljanje aktivnih sej, uporabnikov "
"in delovišč."
"Preverjanje pristnosti je potrebno za upravljanje dodatnih funkcionalnosti."
#: src/timedate/org.freedesktop.timedate1.policy:22
msgid "Set system time"

View File

@ -4,12 +4,13 @@
# Eugene Melnik <jeka7js@gmail.com>, 2014.
# Daniel Korostil <ted.korostiled@gmail.com>, 2014, 2016, 2018.
# Yuri Chornoivan <yurchor@ukr.net>, 2019, 2020, 2021, 2022, 2023, 2024.
# Dmytro Markevych <hotr1pak@gmail.com>, 2024.
msgid ""
msgstr ""
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-11-06 14:42+0000\n"
"PO-Revision-Date: 2024-08-24 10:36+0000\n"
"Last-Translator: Yuri Chornoivan <yurchor@ukr.net>\n"
"PO-Revision-Date: 2024-11-20 19:13+0000\n"
"Last-Translator: Dmytro Markevych <hotr1pak@gmail.com>\n"
"Language-Team: Ukrainian <https://translate.fedoraproject.org/projects/"
"systemd/main/uk/>\n"
"Language: uk\n"
@ -18,7 +19,7 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
"X-Generator: Weblate 5.7\n"
"X-Generator: Weblate 5.8.2\n"
#: src/core/org.freedesktop.systemd1.policy.in:22
msgid "Send passphrase back to system"
@ -118,14 +119,12 @@ msgid "Authentication is required to update a user's home area."
msgstr "Для оновлення домашньої теки користувача слід пройти розпізнавання."
#: src/home/org.freedesktop.home1.policy:53
#, fuzzy
msgid "Update your home area"
msgstr "Оновлення домашньої теки"
msgstr "Оновіть свій домашній простір"
#: src/home/org.freedesktop.home1.policy:54
#, fuzzy
msgid "Authentication is required to update your home area."
msgstr "Для оновлення домашньої теки користувача слід пройти розпізнавання."
msgstr "Для оновлення домашньої області потрібна автентифікація."
#: src/home/org.freedesktop.home1.policy:63
msgid "Resize a home area"
@ -1212,14 +1211,11 @@ msgstr "Для вилучення застарілих оновлень сист
#: src/sysupdate/org.freedesktop.sysupdate1.policy:75
msgid "Manage optional features"
msgstr ""
msgstr "Керування додатковими функціями"
#: src/sysupdate/org.freedesktop.sysupdate1.policy:76
#, fuzzy
msgid "Authentication is required to manage optional features"
msgstr ""
"Для того, щоб керувати сеансами, користувачами і робочими місцями, слід "
"пройти розпізнавання."
msgstr "Для керування додатковими функціями потрібна автентифікація"
#: src/timedate/org.freedesktop.timedate1.policy:22
msgid "Set system time"

View File

@ -803,6 +803,10 @@ int cg_pid_get_path(const char *controller, pid_t pid, char **ret_path) {
if (!path)
return -ENOMEM;
/* Refuse cgroup paths from outside our cgroup namespace */
if (startswith(path, "/../"))
return -EUNATCH;
/* Truncate suffix indicating the process is a zombie */
e = endswith(path, " (deleted)");
if (e)

View File

@ -102,8 +102,8 @@ int pid_get_comm(pid_t pid, char **ret) {
_cleanup_free_ char *escaped = NULL, *comm = NULL;
int r;
assert(ret);
assert(pid >= 0);
assert(ret);
if (pid == 0 || pid == getpid_cached()) {
comm = new0(char, TASK_COMM_LEN + 1); /* Must fit in 16 byte according to prctl(2) */
@ -143,6 +143,9 @@ int pidref_get_comm(const PidRef *pid, char **ret) {
if (!pidref_is_set(pid))
return -ESRCH;
if (pidref_is_remote(pid))
return -EREMOTE;
r = pid_get_comm(pid->pid, &comm);
if (r < 0)
return r;
@ -289,6 +292,9 @@ int pidref_get_cmdline(const PidRef *pid, size_t max_columns, ProcessCmdlineFlag
if (!pidref_is_set(pid))
return -ESRCH;
if (pidref_is_remote(pid))
return -EREMOTE;
r = pid_get_cmdline(pid->pid, max_columns, flags, &s);
if (r < 0)
return r;
@ -331,6 +337,9 @@ int pidref_get_cmdline_strv(const PidRef *pid, ProcessCmdlineFlags flags, char *
if (!pidref_is_set(pid))
return -ESRCH;
if (pidref_is_remote(pid))
return -EREMOTE;
r = pid_get_cmdline_strv(pid->pid, flags, &args);
if (r < 0)
return r;
@ -477,6 +486,9 @@ int pidref_is_kernel_thread(const PidRef *pid) {
if (!pidref_is_set(pid))
return -ESRCH;
if (pidref_is_remote(pid))
return -EREMOTE;
result = pid_is_kernel_thread(pid->pid);
if (result < 0)
return result;
@ -594,6 +606,9 @@ int pidref_get_uid(const PidRef *pid, uid_t *ret) {
if (!pidref_is_set(pid))
return -ESRCH;
if (pidref_is_remote(pid))
return -EREMOTE;
r = pid_get_uid(pid->pid, &uid);
if (r < 0)
return r;
@ -794,6 +809,9 @@ int pidref_get_start_time(const PidRef *pid, usec_t *ret) {
if (!pidref_is_set(pid))
return -ESRCH;
if (pidref_is_remote(pid))
return -EREMOTE;
r = pid_get_start_time(pid->pid, ret ? &t : NULL);
if (r < 0)
return r;
@ -1093,6 +1111,9 @@ int pidref_is_my_child(const PidRef *pid) {
if (!pidref_is_set(pid))
return -ESRCH;
if (pidref_is_remote(pid))
return -EREMOTE;
result = pid_is_my_child(pid->pid);
if (result < 0)
return result;
@ -1128,6 +1149,9 @@ int pidref_is_unwaited(const PidRef *pid) {
if (!pidref_is_set(pid))
return -ESRCH;
if (pidref_is_remote(pid))
return -EREMOTE;
if (pid->pid == 1 || pidref_is_self(pid))
return true;
@ -1169,6 +1193,9 @@ int pidref_is_alive(const PidRef *pidref) {
if (!pidref_is_set(pidref))
return -ESRCH;
if (pidref_is_remote(pidref))
return -EREMOTE;
result = pid_is_alive(pidref->pid);
if (result < 0) {
assert(result != -ESRCH);

View File

@ -193,7 +193,7 @@ int enroll_fido2(
fflush(stdout);
fprintf(stderr,
"\nPlease save this FIDO2 credential ID. It is required when unloocking the volume\n"
"\nPlease save this FIDO2 credential ID. It is required when unlocking the volume\n"
"using the associated FIDO2 keyslot which we just created. To configure automatic\n"
"unlocking using this FIDO2 token, add an appropriate entry to your /etc/crypttab\n"
"file, see %s for details.\n", link);

View File

@ -90,8 +90,8 @@
# define _fallthrough_
#endif
#define XSTRINGIFY(x) #x
#define STRINGIFY(x) XSTRINGIFY(x)
#define XSTRINGIFY(...) #__VA_ARGS__
#define STRINGIFY(...) XSTRINGIFY(__VA_ARGS__)
#ifndef __COVERITY__
# define VOID_0 ((void)0)

View File

@ -0,0 +1,555 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
/* This contains macros that all help simplify the use of macros with variadic args. Also provided is a macro
* 'helper' that helps provide some commonly used things, such as a unique variable name or temporary
* variable.
*
* Since the C preprocessor does not allow recursive macros, none of these macros may be used to call
* themselves, even indirectly (except by using a "trick"; e.g. see __VA_WRAP_RECURSE() below). If you get a
* compiler error complaining about "implicit declaration of function" for any of the macros here, it is most
* likely due to an attempt to use the macro recursively.
*
* Some macros operate based on if there are 'any variadic args' or 'no variadic args'; this distinction is
* based on the use of __VA_OPT__(). The description 'any variadic args' means __VA_OPT__() evaluates to its
* content, and 'no variadic args' means __VA_OPT__() evaluates to nothing. Note that whitespace is not a
* preprocessor token, so a single whitespace-only arg is the same as no args. For example these calls all
* evaluate to 2:
* VA_IF_ELSE(1,2)
* VA_IF_ELSE(1,2,)
* VA_IF_ELSE(1,2, )
* #define NONE
* VA_IF_ELSE(1,2,NONE)
* VA_IF_ELSE(1,2, NONE)
* However, this call evaluates to 1:
* VA_IF_ELSE(1,2,,)
*/
/* Wraps variadic args in a single group. This can be passed to macros that will then expand the group into
* all its variadic args. */
#define VA_GROUP(...) __VA_ARGS__
/* Evaluates to 'x' if any variadic args, otherwise 'y'. */
#define VA_IF_ELSE(x, y, ...) _VA_IF_ELSE_MACRO(__VA_ARGS__)(_VA_IF_ELSE_GROUP(x), _VA_IF_ELSE_GROUP(y))
#define _VA_IF_ELSE_GROUP(...) __VA_ARGS__
#define _VA_IF_ELSE_MACRO(...) __VA_IF_ELSE_MACRO(__VA_OPT__(1))
#define __VA_IF_ELSE_MACRO(o) _VA_IF_ELSE ## o
#define _VA_IF_ELSE1(x, y) x
#define _VA_IF_ELSE(x, y) y
/* Evaluates to nothing if no variadic args, otherwise 'x'. */
#define VA_IF(x, ...) VA_IF_ELSE(_VA_IF_GROUP(x), /*false*/, __VA_ARGS__)
#define _VA_IF_GROUP(...) __VA_ARGS__
/* Same as VA_IF() but negates the condition. */
#define VA_IF_NOT(x, ...) VA_IF_ELSE(/*true*/, _VA_IF_NOT_GROUP(x), __VA_ARGS__)
#define _VA_IF_NOT_GROUP(...) __VA_ARGS__
/* Evaluates to token 1 if no variadic args, otherwise nothing. */
#define VA_NOT(...) VA_IF_NOT(1, __VA_ARGS__)
/* Evaluates to the first variadic arg, otherwise nothing. */
#define VA_FIRST(...) VA_IF(_VA_FIRST(__VA_ARGS__), __VA_ARGS__)
#define _VA_FIRST(x, ...) x
/* Evaluates to the rest of the variadic args, after the first, otherwise nothing. */
#define VA_REST(...) VA_IF(_VA_REST(__VA_ARGS__), __VA_ARGS__)
#define _VA_REST(x, ...) __VA_ARGS__
/* Evaluates to token , if any variadic args, otherwise nothing. */
#define VA_COMMA(...) __VA_OPT__(,)
/* Evaluates to token 1 if both args are non-empty (ignoring whitespace), otherwise evaluates to nothing. */
#define VA_AND(x, y) VA_NOT(VA_NOT(x) VA_NOT(y))
/* Evaluates to token 1 if either arg is non-empty (ignoring whitespace), otherwise evaluates to nothing. */
#define VA_OR(x, y) VA_IF(1, x y)
/* Evaluates to nothing. */
#define VA_NOOP(...)
/* Similar to VA_GROUP(), but encloses the variadic args in (), so they are not expanded when passed to other
* macros. Unlike VA_GROUP(), this requires the final macro that actually uses the group contents to ungroup it
* using VA_UNPGROUP(), or to handle the () directly. */
#define VA_PGROUP(...) (__VA_ARGS__)
/* Converts a group of args protected with () into a normal VA_GROUP(). 'x' must be a pgroup, i.e. (...). */
#define VA_UNPGROUP(x) VA_GROUP x
/* Similar to VA_FIRST(), but x is a pgroup. Evaluates to the first arg if present, otherwise nothing. */
#define VA_PGROUP_FIRST(x) VA_FIRST(VA_UNPGROUP(x))
/* Similar to VA_REST(), but x is a pgroup. Evaluates to a pgroup of the args after the first. If there are
* no more args after the first, evaluates to an empty pgroup. */
#define VA_PGROUP_REST(x) VA_PGROUP(VA_REST(VA_UNPGROUP(x)))
/* Evaluates to token 1 if pgroup is empty, otherwise nothing. */
#define VA_PGROUP_EMPTY(x) VA_IF_NOT(1, VA_UNPGROUP(x))
/* Similar to VA_PGROUP_EMPTY() but negates the condition. */
#define VA_PGROUP_NOT_EMPTY(x) VA_NOT(VA_PGROUP_EMPTY(x))
/* Evaluates to 'macro' called with the expanded variadic args. */
#define VA_MACRO(macro, ...) macro(__VA_ARGS__)
/* Evaluates to x(__VA_ARGS__) if t is non-empty, otherwise y(__VA_ARGS__). */
#define VA_MACRO_IF_ELSE(x, y, t, ...) VA_IF_ELSE(x, y, t)(__VA_ARGS__)
/* Evaluates to m(__VA_ARGS__) if t is non-empty, otherwise nothing. */
#define VA_MACRO_IF(m, t, ...) VA_MACRO_IF_ELSE(m, VA_NOOP, t, __VA_ARGS__)
/* Evaluates to m(__VA_ARGS__) if t is empty, otherwise nothing. */
#define VA_MACRO_IF_NOT(m, t, ...) VA_MACRO_IF_ELSE(VA_NOOP, m, t, __VA_ARGS__)
/* Same as VA_MACRO() but takes a pgroup, which is unpgrouped before passing to the macro. */
#define VA_MACRO_PGROUP(macro, pgroup) VA_MACRO(macro, VA_UNPGROUP(pgroup))
/* Expands to 'macro' for each variadic arg, which will be called with:
* 1) the provided 'context'
* 2) a hex iteration number (starting at 0x0001)
* 3) the variadic arg
* 4...) the rest of the variadic args
*
* Each expansion of 'macro', except for the last, will be followed by 'separator' called with the same
* parameters as 'macro'.
*
* If there are no variadic args, this evaluates to 'zero' called with the single arg 'context'.
*
* If there are too many variadic args, this evaluates to 'toomany' called with the single arg 'context'.
*
* The 'macro', 'separator', 'zero', and 'toomany' parameters must be callable macros. The VA_WRAP_*() macros
* below may be used. The 'context' parameter may be anything and is not directly called (except by the
* VA_WRAP_*_CONTEXT() below). */
#define VA_WRAP(macro, separator, context, zero, toomany, ...) \
__VA_WRAP_RECURSE(macro, separator, context, zero, toomany, __VA_ARGS__)
/* These can be used for the VA_WRAP() 'macro' parameter. */
#define VA_WRAP_MACRO_CONTEXT(c, i, v, ...) c
#define VA_WRAP_MACRO_INDEX(c, i, v, ...) i
#define VA_WRAP_MACRO_LAST(c, i, v, ...) VA_IF_NOT(v, __VA_ARGS__)
#define VA_WRAP_MACRO_LAST_INDEX(c, i, v, ...) VA_IF_NOT(i, __VA_ARGS__)
#define VA_WRAP_MACRO_NONE(c, i, v, ...)
#define VA_WRAP_MACRO_VALUE(c, i, v, ...) v
/* These can be used for the VA_WRAP() 'separator' parameter. */
#define VA_WRAP_SEPARATOR_AND(c, i, v, ...) &&
#define VA_WRAP_SEPARATOR_COMMA(c, i, v, ...) ,
#define VA_WRAP_SEPARATOR_COMMA_IF_PREV(c, i, v, ...) VA_COMMA(v)
#define VA_WRAP_SEPARATOR_CONTEXT(c, i, v, ...) c
#define VA_WRAP_SEPARATOR_INDEX(c, i, v, ...) i
#define VA_WRAP_SEPARATOR_NONE(c, i, v, ...)
#define VA_WRAP_SEPARATOR_SEMICOLON(c, i, v, ...) ;
/* This can be used for the VA_WRAP() 'context' parameter. It is strictly to help with code readability, and
* is not required. */
#define VA_WRAP_CONTEXT_NONE
/* These can be used for the VA_WRAP() 'zero' parameter. */
#define VA_WRAP_ZERO_0(c) 0
#define VA_WRAP_ZERO_0x0000(c) 0x0000
#define VA_WRAP_ZERO_CONTEXT(c) c
#define VA_WRAP_ZERO_ERROR(c) _Pragma("GCC error \"Zero variadic args.\"")
#define VA_WRAP_ZERO_FALSE(c) false
#define VA_WRAP_ZERO_NONE(c)
#define VA_WRAP_ZERO_TRUE(c) true
#define VA_WRAP_ZERO_VOID_0(c) VOID_0
/* These can be used for the VA_WRAP() 'toomany' parameter. */
#define VA_WRAP_TOOMANY_CONTEXT(c) c
#define VA_WRAP_TOOMANY_ERROR(c) _Pragma("GCC error \"Too many variadic args.\"")
#define VA_WRAP_TOOMANY_FALSE(c) false
#define VA_WRAP_TOOMANY_NONE(c)
#define VA_WRAP_TOOMANY_TRUE(c) true
/* Simple version of VA_WRAP(); each variadic arg is wrapped by the provided macro, separated by commas. No
* context is used. Zero args evaluates to nothing. Toomany args results in error. */
#define VA_MACRO_FOREACH(macro, ...) \
VA_WRAP(macro, \
VA_WRAP_SEPARATOR_COMMA, \
VA_WRAP_CONTEXT_NONE, \
VA_WRAP_ZERO_NONE, \
VA_WRAP_TOOMANY_ERROR, \
__VA_ARGS__)
/* Expands to list of variadic args, with any "empty" (whitespace only) args removed. This processes the list
* twice, to remove a trailing comma if needed. */
#define VA_FILTER(...) \
VA_MACRO(VA_WRAP, \
VA_WRAP_MACRO_VALUE, \
VA_WRAP_SEPARATOR_COMMA_IF_PREV, \
VA_WRAP_CONTEXT_NONE, \
VA_WRAP_ZERO_NONE, \
VA_WRAP_TOOMANY_ERROR, \
VA_WRAP(VA_WRAP_MACRO_VALUE, \
VA_WRAP_SEPARATOR_COMMA_IF_PREV, \
VA_WRAP_CONTEXT_NONE, \
VA_WRAP_ZERO_NONE, \
VA_WRAP_TOOMANY_ERROR, \
__VA_ARGS__))
/* Evaluates to the number of variadic args. */
#define VA_NARGS(...) \
VA_WRAP(VA_WRAP_MACRO_LAST_INDEX, \
VA_WRAP_SEPARATOR_NONE, \
VA_WRAP_CONTEXT_NONE, \
VA_WRAP_ZERO_0x0000, \
VA_WRAP_TOOMANY_ERROR, \
__VA_ARGS__)
/* Evaluates to the last variadic arg. If there are no variadic args, evaluates to nothing. */
#define VA_LAST(...) \
VA_WRAP(VA_WRAP_MACRO_LAST, \
VA_WRAP_SEPARATOR_NONE, \
VA_WRAP_CONTEXT_NONE, \
VA_WRAP_ZERO_NONE, \
VA_WRAP_TOOMANY_ERROR, \
__VA_ARGS__)
#define _VA_DECLARATIONS(macro, name, ...) \
VA_WRAP(macro, \
VA_WRAP_SEPARATOR_SEMICOLON, \
name, \
VA_WRAP_ZERO_NONE, \
VA_WRAP_TOOMANY_ERROR, \
__VA_ARGS__)
#define _VA_DECLARATION_TOKEN(x, y) __VA_DECLARATION_TOKEN(x, y)
#define __VA_DECLARATION_TOKEN(x, y) x ## _ ## y
/* Evaluates to a variable declaration for each variadic arg. Each variadic arg must be a type. Each variable
* name is the concatenation of 'name', '_', and the variadic arg index (as a hex number). */
#define VA_DECLARATIONS(name, ...) \
_VA_DECLARATIONS(_VA_DECLARATION, name, __VA_ARGS__)
#define _VA_DECLARATION(c, i, v, ...) \
v _VA_DECLARATION_TOKEN(c, i)
/* Same as VA_DECLARATIONS(), but the variadic args must be variables (or constants). Each declaration
* uses __auto_type and is initialized to its corresponding variadic arg. */
#define VA_INITIALIZED_DECLARATIONS(name, ...) \
_VA_DECLARATIONS(_VA_INITIALIZED_DECLARATION, name, __VA_ARGS__)
#define _VA_INITIALIZED_DECLARATION(c, i, v, ...) \
_VA_DECLARATION(c, i, __auto_type, __VA_ARGS__) = (v)
/* Same as VA_INITIALIZED_DECLARATIONS(), but the temp variable is declared with const. */
#define VA_CONST_INITIALIZED_DECLARATIONS(name, ...) \
_VA_DECLARATIONS(_VA_CONST_INITIALIZED_DECLARATION, name, __VA_ARGS__)
#define _VA_CONST_INITIALIZED_DECLARATION(c, i, v, ...) \
const _VA_INITIALIZED_DECLARATION(c, i, v, __VA_ARGS__)
/* Evaluates to a comma-separated list of tokens by concatenating 'name' and a literal '_' with each variadic
* arg index. This will produce the same tokens as the variable names generated by VA_DECLARATIONS(). Note
* this does not actually evaluate any of the variadic args. */
#define VA_TOKENS(name, ...) \
VA_WRAP(_VA_TOKEN, \
VA_WRAP_SEPARATOR_COMMA, \
name, \
VA_WRAP_ZERO_NONE, \
VA_WRAP_TOOMANY_ERROR, \
__VA_ARGS__)
#define _VA_TOKEN(c, i, v, ...) _VA_DECLARATION_TOKEN(c, i)
/* Evaluates to a comma-separated list of unique tokens using UNIQ_T() for each variadic arg. This is similar
* to VA_TOKENS() but uses UNIQ_T() to generate the tokens. */
#define VA_UNIQ(...) \
VA_WRAP(_VA_UNIQ, \
VA_WRAP_SEPARATOR_COMMA, \
UNIQ, \
VA_WRAP_ZERO_NONE, \
VA_WRAP_TOOMANY_ERROR, \
__VA_ARGS__)
#define _VA_UNIQ(c, i, v, ...) UNIQ_T(v, c)
/* This is similar to VA_FILTER(), but we can't use VA_FILTER() because macros can't be used recursively, and
* this is called from inside a VA_WRAP() (which VA_FILTER() relies on). */
#define __VMH_GROUPS(g1, g2, g3, g4, g5) \
g1 VA_IF(VA_COMMA(g1), g2 g3 g4 g5) \
g2 VA_IF(VA_COMMA(g2), g3 g4 g5) \
g3 VA_IF(VA_COMMA(g3), g4 g5) \
g4 VA_IF(VA_COMMA(g4), g5) \
g5
#define __VMH_TOKEN(x, u) __va_macro_helper ## x ## u
#define __VMH_STATEMENT_EXPRESSION(macro, u, uniq, var, varinit, varconst, direct) \
({ \
VA_DECLARATIONS( __VMH_TOKEN(_var_, u), var); \
VA_INITIALIZED_DECLARATIONS( __VMH_TOKEN(_varinit_, u), varinit); \
VA_CONST_INITIALIZED_DECLARATIONS(__VMH_TOKEN(_varconst_, u), varconst); \
VA_MACRO(macro, \
__VMH_GROUPS(VA_UNIQ(uniq), \
VA_TOKENS(__VMH_TOKEN(_var_, u), var), \
VA_TOKENS(__VMH_TOKEN(_varinit_, u), varinit), \
VA_TOKENS(__VMH_TOKEN(_varconst_, u), varconst), \
VA_GROUP(direct))); \
})
#define __VMH_EXPRESSION(macro, u, uniq, var, varinit, varconst, direct) \
VA_MACRO(macro, \
__VMH_GROUPS(VA_UNIQ(uniq), VA_GROUP(direct),,,))
/* Calls 'macro' with a set of args based on the provided arg groups, in the order shown. Multiple args may
* be provided to each group by using VA_GROUP().
*
* Each arg in the 'uniq' group provides a unique token, named based on the arg token, to the macro in
* place of the arg. This is equivalent to UNIQ_T() for each arg.
*
* Each arg in the 'var' group provides a temporary variable of the specified type to the macro in place of
* the arg. All args in this group must be types.
*
* The 'varinit' group is similar to the 'var' group, but each arg must be a variable or constant, and each
* temporary variable is initialized to the value of the provided arg. The macro may use these args without
* any concern for side effects.
*
* The 'varconst' group is similar to the 'varinit' group, but the temporary variables are also marked as
* const. The macro should not modify args in this group.
*
* Each arg in the 'direct' group is provided directly to the macro. */
#define VA_MACRO_HELPER(macro, uniq, var, varinit, varconst, direct) \
VA_IF_ELSE(__VMH_STATEMENT_EXPRESSION, \
__VMH_EXPRESSION, \
var varinit varconst)(macro, \
UNIQ, \
VA_GROUP(uniq), \
VA_GROUP(var), \
VA_GROUP(varinit), \
VA_GROUP(varconst), \
VA_GROUP(direct))
/* Same as VA_MACRO_HELPER() but only with 'uniq' group; all variadic args are put in 'direct' group. */
#define VA_MACRO_UNIQ(macro, uniq, ...) \
VA_MACRO_HELPER(macro, \
VA_GROUP(uniq), \
/* var= */, \
/* varinit= */, \
/* varconst= */, \
VA_GROUP(__VA_ARGS__))
/* Same as VA_MACRO_HELPER() but only with 'var' group; all variadic args are put in 'direct' group. */
#define VA_MACRO_VAR(macro, var, ...) \
VA_MACRO_HELPER(macro, \
/* uniq= */, \
VA_GROUP(var), \
/* varinit= */, \
/* varconst= */, \
VA_GROUP(__VA_ARGS__))
/* Same as VA_MACRO_HELPER() but only with 'varinit' group; all variadic args are put in 'direct' group. */
#define VA_MACRO_VARINIT(macro, varinit, ...) \
VA_MACRO_HELPER(macro, \
/* uniq= */, \
/* var= */, \
VA_GROUP(varinit), \
/* varconst= */, \
VA_GROUP(__VA_ARGS__))
/* Same as VA_MACRO_HELPER() but only with 'varconst' group; all variadic args are put in 'direct' group. */
#define VA_MACRO_VARCONST(macro, varconst, ...) \
VA_MACRO_HELPER(macro, \
/* uniq= */, \
/* var= */, \
/* varinit= */, \
VA_GROUP(varconst), \
VA_GROUP(__VA_ARGS__))
/* Macros below are complex, internal-use-only macros and should not be used directly. They are used by the
* macros above. */
/* Integer increment at the preprocessor stage; each macro evaluates to the next integer. Overflow is not
* handled; f wraps to 0. */
#define __VAI0 1
#define __VAI1 2
#define __VAI2 3
#define __VAI3 4
#define __VAI4 5
#define __VAI5 6
#define __VAI6 7
#define __VAI7 8
#define __VAI8 9
#define __VAI9 a
#define __VAIa b
#define __VAIb c
#define __VAIc d
#define __VAId e
#define __VAIe f
#define __VAIf 0
/* Integer increment carryover; all macros evaluate to 0 except f, which evaluates to 1. */
#define __VAC0 0
#define __VAC1 0
#define __VAC2 0
#define __VAC3 0
#define __VAC4 0
#define __VAC5 0
#define __VAC6 0
#define __VAC7 0
#define __VAC8 0
#define __VAC9 0
#define __VACa 0
#define __VACb 0
#define __VACc 0
#define __VACd 0
#define __VACe 0
#define __VACf 1
/* Increment x based on carryover c. Requires x to be single hex digit (0-f) and carryover to be 0-1.
* Evaluates to 0 if x == f and c == 1, otherwise x+1 if c == 1, otherwise x. */
#define ___VAI(x, c) ____VAI(x, c)
#define ____VAI(x, c) ____VAI ## c(x)
#define ____VAI0(x) x
#define ____VAI1(x) __VAI ## x
/* Carryover of x based on carryover c. Requires x to be single hex digit (0-f) and carryover to be
* 0-1. Evaluates to 1 if x is f and c is 1, otherwise 0. */
#define ___VAC(x, c) ____VAC(x, c)
#define ____VAC(x, c) ____VAC ## c(x)
#define ____VAC0(x) 0
#define ____VAC1(x) __VAC ## x
/* Carryover of multiple digits. Each calculates the carryover of its digit, with 1 being the least
* significant digit, and 4 being the most significant digit. */
#define ___VAC1(x1) ___VAC(x1, 1)
#define ___VAC2(x2, x1) ___VAC(x2, ___VAC1(x1))
#define ___VAC3(x3, x2, x1) ___VAC(x3, ___VAC2(x2, x1))
#define ___VAC4(x4, x3, x2, x1) ___VAC(x4, ___VAC3(x3, x2, x1))
/* Increment with carryover across all digits. Each evaluate to their digit incremented if there is carryover
* from previous digits. */
#define ___VAI1(x1) ___VAI(x1, 1)
#define ___VAI2(x2, x1) ___VAI(x2, ___VAC1(x1))
#define ___VAI3(x3, x2, x1) ___VAI(x3, ___VAC2(x2, x1))
#define ___VAI4(x4, x3, x2, x1) ___VAI(x4, ___VAC3(x3, x2, x1))
/* Detect overflow. If all digits are f, this causes preprocessor error, otherwise this evaluates to
* nothing. */
#define ___VAIO(x4, x3, x2, x1) ____VAIO(___VAC4(x4, x3, x2, x1))
#define ____VAIO(c) _____VAIO(c)
#define _____VAIO(c) ______VAIO ## c()
#define ______VAIO0()
#define ______VAIO1() _Pragma("GCC error \"VA increment overflow\"")
/* Increment a 4-digit hex number. Requires pgroup to be a 4-digit hex number pgroup, e.g. (0,1,2,3)
* represents 0x0123. Evaluates to a 4-digit hex number pgroup that has been incremented by 1. On overflow, a
* preprocessor error is generated. */
#define __VAINC4(pgroup) ___VAINC4 pgroup
#define ___VAINC4(x4, x3, x2, x1) \
___VAIO(x4, x3, x2, x1) \
(___VAI4(x4, x3, x2, x1), \
___VAI3(x3, x2, x1), \
___VAI2(x2, x1), \
___VAI1(x1))
/* Convert a 4-digit hex number pgroup to a standard hex number. Requires pgroup to be a 4-digit hex number
* pgroup. Evaluates to a standard hex number for the pgroup, e.g. (a,b,c,d) evalutes to 0xabcd. */
#define __VANUM4(pgroup) ___VANUM4 pgroup
#define ___VANUM4(x4, x3, x2, x1) 0x ## x4 ## x3 ## x2 ## x1
/* Nested repeated evaluations. This is what controls when the 'toomany' VA_WRAP() parameter is evaluated. */
#define __VA_EVAL_0x0002(...) __VA_ARGS__
#define __VA_EVAL_0x0004(...) __VA_EVAL_0x0002(__VA_EVAL_0x0002(__VA_ARGS__))
#define __VA_EVAL_0x0008(...) __VA_EVAL_0x0004(__VA_EVAL_0x0004(__VA_ARGS__))
#define __VA_EVAL_0x0010(...) __VA_EVAL_0x0008(__VA_EVAL_0x0008(__VA_ARGS__))
#define __VA_EVAL_0x0020(...) __VA_EVAL_0x0010(__VA_EVAL_0x0010(__VA_ARGS__))
#define __VA_EVAL_0x0040(...) __VA_EVAL_0x0020(__VA_EVAL_0x0020(__VA_ARGS__))
#define __VA_EVAL_0x0080(...) __VA_EVAL_0x0040(__VA_EVAL_0x0040(__VA_ARGS__))
#define __VA_EVAL_0x0100(...) __VA_EVAL_0x0080(__VA_EVAL_0x0080(__VA_ARGS__))
#define __VA_EVAL_0x0200(...) __VA_EVAL_0x0100(__VA_EVAL_0x0100(__VA_ARGS__))
/* This should match the list of macros above. */
#define __VA_EVAL_STEPS (0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080, 0x0100, 0x0200)
/* Determine which __VA_EVAL_0x* macro to use for the given variadic args. This is a quick evaluation for the
* preprocessor and avoids unnecessary reevaluations for complex macro expansions. Evaluates to the smallest
* (least evaluations) __VA_EVAL_0x* macro token that can handle the number of provided variadic args. */
#define __VA_EVAL_MACRO(...) __VA_EVAL_MACRO_CHECK_EACH(__VA_EVAL_STEPS, __VA_ARGS__)
/* Re-evaluates for each step. If __VA_EVAL_STEPS is increased this may need to be increased. */
#define __VA_EVAL_MACRO_CHECK_EACH(steps, ...) __VA_EVAL_MACRO_EVAL16(__VA_EVAL_MACRO_CHECK(steps, __VA_ARGS__))
#define __VA_EVAL_MACRO_EVAL02(...) __VA_ARGS__
#define __VA_EVAL_MACRO_EVAL04(...) __VA_EVAL_MACRO_EVAL02(__VA_EVAL_MACRO_EVAL02(__VA_ARGS__))
#define __VA_EVAL_MACRO_EVAL08(...) __VA_EVAL_MACRO_EVAL04(__VA_EVAL_MACRO_EVAL04(__VA_ARGS__))
#define __VA_EVAL_MACRO_EVAL16(...) __VA_EVAL_MACRO_EVAL08(__VA_EVAL_MACRO_EVAL08(__VA_ARGS__))
/* Evaluates to the first __VA_EVAL_0x* macro name that can handle all the variadic args. If there are too
* many variadic args for the largest macro to handle, evaluates to nothing. Note this uses the same
* preprocessor recursion "trick" as __VA_WRAP_RECURSE() below. */
#define __VA_EVAL_MACRO_CHECK(steps, ...) \
___VA_EVAL_MACRO_CHECK \
VA_PGROUP(__VA_EVAL_MACRO_MORE(VA_PGROUP_FIRST(steps), __VA_ARGS__))(steps, __VA_ARGS__)
/* 'x' is the evaluation of __VA_EVAL_MACRO_MORE(); if it is empty, this evaluates to __VA_EVAL_MACRO_OK,
* otherwise the tested __VA_EVAL_0x* macro cannot handle all the variadic args, and this evaluates to
* __VA_EVAL_MACRO_NEXT. */
#define ___VA_EVAL_MACRO_CHECK(x) VA_IF_ELSE(__VA_EVAL_MACRO_NEXT, __VA_EVAL_MACRO_OK, x)
/* Move on to testing the next step (i.e. next 0x* value). */
#define __VA_EVAL_MACRO_NEXT(steps, ...) ___VA_EVAL_MACRO_NEXT(VA_PGROUP_REST(steps), __VA_ARGS__)
/* Test the next step value. If there are no more steps, evaluate to nothing. */
#define ___VA_EVAL_MACRO_NEXT(steps, ...) \
VA_MACRO_IF(__VA_EVAL_MACRO_CHECK, VA_PGROUP_NOT_EMPTY(steps), steps, __VA_ARGS__)
/* The first value of 'steps' is acceptable, so evaluate to the corresponding __VA_EVAL_* macro name. */
#define __VA_EVAL_MACRO_OK(steps, ...) ___VA_EVAL_MACRO_OK(VA_PGROUP_FIRST(steps))
#define ___VA_EVAL_MACRO_OK(n) ____VA_EVAL_MACRO_OK(n)
#define ____VA_EVAL_MACRO_OK(n) __VA_EVAL_ ## n
/* Bug in Centos Stream 8 gcc preprocessor doesn't correctly handle __VA_OPT__(); work around it. Once Centos
* Stream 8 is no longer supported, this can be dropped. */
#define __CENTOS_STREAM_8_NONE
#define __CENTOS_STREAM_8_BUG_CHECK() ___CENTOS_STREAM_8_BUG_CHECK(__CENTOS_STREAM_8_NONE)
#define ___CENTOS_STREAM_8_BUG_CHECK(...) __VA_OPT__(1)
#define __VA_EVAL_MACRO_MORE_IF_ONCE(...) __VA_OPT__(1)
#define __VA_EVAL_MACRO_MORE_IF_TWICE(...) __VA_EVAL_MACRO_MORE_IF_ONCE(__VA_ARGS__)
#define __VA_EVAL_MACRO_MORE_IF_MACRO() \
VA_IF_ELSE(__VA_EVAL_MACRO_MORE_IF_TWICE, \
__VA_EVAL_MACRO_MORE_IF_ONCE, \
__CENTOS_STREAM_8_BUG_CHECK())
#define __VA_EVAL_MACRO_MORE_IF() __VA_EVAL_MACRO_MORE_IF_MACRO()
/* Test if the __VA_EVAL_0x* macro for hex number 'n' can handle all the variadic args. Evaluates to 1 if
* there are remaining (unhandled) variadic args after all evaluations, otherwise nothing. */
#define __VA_EVAL_MACRO_MORE(n, ...) \
__VA_EVAL_MACRO_MORE_IF()(__VA_EVAL_MACRO_MORE_N(n)(__VA_OPT__(___VA_EVAL_MACRO_MORE(__VA_ARGS__))))
#define __VA_EVAL_MACRO_MORE_N(n) __VA_EVAL_ ## n
#define ___VA_EVAL_MACRO_MORE(v, ...) __VA_OPT__(___VA_EVAL_MACRO_MORE_NEXT VA_PGROUP()(__VA_ARGS__))
#define ___VA_EVAL_MACRO_MORE_NEXT() ___VA_EVAL_MACRO_MORE
/* Recursive macro evaluation. This is intended for use by VA_WRAP() above. This performs the actions
* described by VA_WRAP() for each variadic arg.
*
* This "trick" inspired by:
* https://www.scs.stanford.edu/~dm/blog/va-opt.html
* https://github.com/pfultz2/Cloak/wiki/C-Preprocessor-tricks,-tips,-and-idioms
*
* This determines the number of re-evaluations required for the provided number of variadic args, then calls
* the appropriate __VA_EVAL_0x*() macro with ___VA_WRAP_RECURSE(), providing the initial index of 0x0001. */
#define __VA_WRAP_RECURSE(macro, separator, context, zero, toomany, ...) \
VA_IF_ELSE(__VA_WRAP_RECURSE_NONZERO, \
__VA_WRAP_RECURSE_ZERO, \
__VA_ARGS__)(macro, separator, context, zero, toomany, __VA_ARGS__)
#define __VA_WRAP_RECURSE_ZERO(macro, separator, context, zero, toomany, ...) zero(context)
#define __VA_WRAP_RECURSE_NONZERO(macro, separator, context, zero, toomany, ...) \
__VA_WRAP_RECURSE_CHECK_TOOMANY(__VA_EVAL_MACRO(__VA_ARGS__), \
macro, separator, context, toomany, __VA_ARGS__)
#define __VA_WRAP_RECURSE_CHECK_TOOMANY(evalmacro, macro, separator, context, toomany, ...) \
VA_IF_ELSE(__VA_WRAP_RECURSE_EVAL, \
__VA_WRAP_RECURSE_TOOMANY, \
evalmacro)(evalmacro, macro, separator, context, toomany, __VA_ARGS__)
#define __VA_WRAP_RECURSE_TOOMANY(evalmacro, macro, separator, context, toomany, ...) toomany(context)
#define __VA_WRAP_RECURSE_EVAL(evalmacro, macro, separator, context, toomany, ...) \
evalmacro(___VA_WRAP_RECURSE(macro, \
separator, \
context, \
(0,0,0,1), \
__VA_ARGS__))
/* This is the "trick" macro, which evaluates to the current variadic arg 'value' wrapped by 'macro', and
* then (if there are remaining variadic args) followed by 'separator' followed by the "trick"; which is
* ___VA_WRAP_NEXT token and VA_PGROUP(). On the next re-evaluation, this (indirectly) evaluates recursively
* to ___VA_WRAP_RECURSE(). */
#define ___VA_WRAP_RECURSE(macro, separator, context, index, value, ...) \
___VA_WRAP_RECURSE_CALL(macro, \
VA_IF_ELSE(separator, VA_NOOP, __VA_ARGS__), \
VA_GROUP(context, __VANUM4(index), value, __VA_ARGS__)) \
__VA_OPT__(___VA_WRAP_NEXT VA_PGROUP()(macro, separator, context, __VAINC4(index), __VA_ARGS__))
#define ___VA_WRAP_RECURSE_CALL(macro, separator, args) macro(args)separator(args)
#define ___VA_WRAP_NEXT() ___VA_WRAP_RECURSE

View File

@ -1443,6 +1443,7 @@ int link_reconfigure_impl(Link *link, LinkReconfigurationFlag flags) {
}
typedef struct LinkReconfigurationData {
Manager *manager;
Link *link;
LinkReconfigurationFlag flags;
sd_bus_message *message;
@ -1473,6 +1474,12 @@ static void link_reconfiguration_data_destroy_callback(LinkReconfigurationData *
}
if (!data->counter || *data->counter <= 0) {
/* Update the state files before replying the bus method. Otherwise,
* systemd-networkd-wait-online following networkctl reload/reconfigure may read an
* outdated state file and wrongly handle an interface is already in the configured
* state. */
(void) manager_clean_all(data->manager);
r = sd_bus_reply_method_return(data->message, NULL);
if (r < 0)
log_warning_errno(r, "Failed to reply for DBus method, ignoring: %m");
@ -1521,6 +1528,7 @@ int link_reconfigure_full(Link *link, LinkReconfigurationFlag flags, sd_bus_mess
}
*data = (LinkReconfigurationData) {
.manager = link->manager,
.link = link_ref(link),
.flags = flags,
.message = sd_bus_message_ref(message), /* message may be NULL, but _ref() works fine. */

View File

@ -46,13 +46,17 @@ static bool argv_has_at(pid_t pid) {
return c == '@';
}
static bool is_survivor_cgroup(const PidRef *pid) {
static bool is_in_survivor_cgroup(const PidRef *pid) {
_cleanup_free_ char *cgroup_path = NULL;
int r;
assert(pidref_is_set(pid));
r = cg_pidref_get_path(/* root= */ NULL, pid, &cgroup_path);
if (r == -EUNATCH) {
log_warning_errno(r, "Process " PID_FMT " appears to originate in foreign namespace, ignoring.", pid->pid);
return true;
}
if (r < 0) {
log_warning_errno(r, "Failed to get cgroup path of process " PID_FMT ", ignoring: %m", pid->pid);
return false;
@ -86,7 +90,7 @@ static bool ignore_proc(const PidRef *pid, bool warn_rootfs) {
return true; /* also ignore processes where we can't determine this */
/* Ignore processes that are part of a cgroup marked with the user.survive_final_kill_signal xattr */
if (is_survivor_cgroup(pid))
if (is_in_survivor_cgroup(pid))
return true;
r = pidref_get_uid(pid, &uid);

View File

@ -188,6 +188,7 @@ simple_tests += files(
'test-user-record.c',
'test-user-util.c',
'test-utf8.c',
'test-variadic.c',
'test-verbs.c',
'test-vpick.c',
'test-web-util.c',

View File

@ -7,24 +7,26 @@ TEST(audit_loginuid_from_pid) {
_cleanup_(pidref_done) PidRef self = PIDREF_NULL, pid1 = PIDREF_NULL;
int r;
assert_se(pidref_set_self(&self) >= 0);
assert_se(pidref_set_pid(&pid1, 1) >= 0);
ASSERT_OK(pidref_set_self(&self));
ASSERT_OK(pidref_set_pid(&pid1, 1));
uid_t uid;
r = audit_loginuid_from_pid(&self, &uid);
assert_se(r >= 0 || r == -ENODATA);
if (r != -ENODATA)
ASSERT_OK(r);
if (r >= 0)
log_info("self audit login uid: " UID_FMT, uid);
assert_se(audit_loginuid_from_pid(&pid1, &uid) == -ENODATA);
ASSERT_ERROR(audit_loginuid_from_pid(&pid1, &uid), ENODATA);
uint32_t sessionid;
r = audit_session_from_pid(&self, &sessionid);
assert_se(r >= 0 || r == -ENODATA);
if (r != -ENODATA)
ASSERT_OK(r);
if (r >= 0)
log_info("self audit session id: %" PRIu32, sessionid);
assert_se(audit_session_from_pid(&pid1, &sessionid) == -ENODATA);
ASSERT_ERROR(audit_session_from_pid(&pid1, &sessionid), ENODATA);
}
static int intro(void) {

726
src/test/test-variadic.c Normal file
View File

@ -0,0 +1,726 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <stddef.h>
#include "log.h"
#include "string-util.h"
#include "tests.h"
#include "variadic-fundamental.h"
#define _MACRO_LOG(...) ({ log_info("%s", #__VA_ARGS__); 0; })
#define MACRO_LOG(...) _MACRO_LOG(__VA_ARGS__)
#define NONE
#define MACRO_NONE()
#define MACRO_IGNORE(...)
#define MACRO1(x, ...) (x)
#define MACRO2(x1, x2, ...) (x2)
#define MACRO_SUM12(x1, x2, ...) (x1 + x2)
#define MACRO_3ARG_SUM(x1, x2, x3) x1 + x2 + x3
#define MACRO_4ARG_SUM(x1, x2, x3, x4) x1 + x2 + x3 + x4
#define MACRO_VARG_1(x1, ...) x1
#define MACRO_VARG_2(x1, ...) MACRO_VARG_1(__VA_ARGS__)
#define MACRO_VARG_3(x1, ...) MACRO_VARG_2(__VA_ARGS__)
#define MACRO_VARG_4(x1, ...) MACRO_VARG_3(__VA_ARGS__)
#define MACRO_GROUP_VARG_1(x) MACRO_VARG_1(x)
#define MACRO_GROUP_VARG_2(x) MACRO_VARG_2(x)
#define MACRO_GROUP_VARG_3(x) MACRO_VARG_3(x)
#define MACRO_GROUP_VARG_4(x) MACRO_VARG_4(x)
#define MACRO_GROUP_3ARG_SUM(x) MACRO_3ARG_SUM(x)
#define MACRO_GROUP_4ARG_SUM(x) MACRO_4ARG_SUM(x)
#define MACRO_2GROUP_4ARG_3ARG_SUM(g1, g2) MACRO_4ARG_SUM(g1) + MACRO_3ARG_SUM(g2)
#define MACRO_2GROUP_VARG_3ARG_G2A2(g1, g2) MACRO_VARG_2(g2)
#define MACRO_2GROUP_4ARG_VARG_SUM_G1A4_G2A3(g1, g2) MACRO_VARG_4(g1) + MACRO_VARG_3(g2)
TEST(va_group) {
assert_se(MACRO_GROUP_VARG_4(VA_GROUP(1,2,3,4)) == 4);
assert_se(MACRO_GROUP_VARG_1(VA_GROUP(5,10,20)) == 5);
assert_se(MACRO_GROUP_3ARG_SUM(VA_GROUP(1, 1000, -2)) == 999);
assert_se(MACRO_GROUP_4ARG_SUM(VA_GROUP(1, 1, 1, 2)) == 5);
assert_se(MACRO_2GROUP_4ARG_3ARG_SUM(VA_GROUP(5,6,7,8), VA_GROUP(1,1,1)) == 29);
assert_se(MACRO_2GROUP_VARG_3ARG_G2A2(VA_GROUP(1,2,3,4,5,6,7,8,9), VA_GROUP(3,2,1)) == 2);
assert_se(MACRO_2GROUP_4ARG_VARG_SUM_G1A4_G2A3(VA_GROUP(4,3,2,1), VA_GROUP(9,8,7,6,5,4)) == 8);
}
#define V1() 1
#define V2() 2
#define VI6E7(x) VA_IF_ELSE(6, 7, x)
#define VI8E9(x) VA_IF_ELSE(8, 9, x)
TEST(va_if_else) {
assert_se(VA_IF_ELSE(1,2) == 2);
assert_se(VA_IF_ELSE(1,2,) == 2);
assert_se(VA_IF_ELSE(1,2, ) == 2);
assert_se(VA_IF_ELSE(1,2,NONE) == 2);
assert_se(VA_IF_ELSE(1,2, NONE) == 2);
assert_se(VA_IF_ELSE(1,2,,) == 1);
assert_se(VA_IF_ELSE(1, 2, ) == 2);
assert_se(VA_IF_ELSE(1, 2,NONE ) == 2);
assert_se(VA_IF_ELSE(1, 2, 1) == 1);
assert_se(VA_IF_ELSE(1, 2, "no") == 1);
assert_se(VA_IF_ELSE(1, 2, VA_IF(1, )) == 2);
assert_se(VA_IF_ELSE(1, 2, VA_IF(1, 1) ) == 1);
assert_se(VA_IF_ELSE(1, 2, VA_IF_NOT(1, )) == 1);
assert_se(VA_IF_ELSE(1, 2, VA_IF_NOT(1, 2)) == 2);
assert_se(VA_IF_ELSE(1, 2, VA_NOT()) == 1);
assert_se(VA_IF_ELSE(1, 2, VA_NOT(1)) == 2);
assert_se(VA_IF_ELSE(1, 2, VA_IF_ELSE(100, 200, )) == 1);
assert_se(VA_IF_ELSE(1, 2, VA_IF_ELSE(100, 200, 1)) == 1);
assert_se(VA_IF_ELSE(1, 2, VA_IF_ELSE(100, , )) == 2);
assert_se(VA_IF_ELSE(1, 2, VA_IF_ELSE(, 4 , )) == 1);
assert_se(VA_IF_ELSE(V1, V2, 1)() == 1);
assert_se(VA_IF_ELSE(V1, V2, )() == 2);
assert_se(VA_IF_ELSE(VI6E7, VI8E9, )(1) == 8);
assert_se(VA_IF_ELSE(VI6E7, VI8E9, 0)(1) == 6);
assert_se(VA_IF_ELSE(VI6E7, VI8E9, )() == 9);
assert_se(VA_IF_ELSE(VI6E7, VI8E9, 55)() == 7);
assert_se(VA_IF_ELSE(VA_IF_ELSE(3, 4, ), VA_IF_ELSE(5, 6, ), ) == 6);
assert_se(VA_IF_ELSE(VA_IF_ELSE(3, 4, ), VA_IF_ELSE(5, 6, ), 1) == 4);
assert_se(VA_IF_ELSE(VA_IF_ELSE(3, 4, ), VA_IF_ELSE(5, 6, 1), ) == 5);
assert_se(VA_IF_ELSE(VA_IF_ELSE(3, 4, ), VA_IF_ELSE(5, 6, 1), 1) == 4);
assert_se(VA_IF_ELSE(VA_IF_ELSE(3, 4, 1), VA_IF_ELSE(5, 6, ), ) == 6);
assert_se(VA_IF_ELSE(VA_IF_ELSE(3, 4, 1), VA_IF_ELSE(5, 6, ), 1) == 3);
assert_se(VA_IF_ELSE(VA_IF_ELSE(3, 4, 1), VA_IF_ELSE(5, 6, 1), ) == 5);
assert_se(VA_IF_ELSE(VA_IF_ELSE(3, 4, 1), VA_IF_ELSE(5, 6, 1), 1) == 3);
}
TEST(va_if) {
assert_se(VA_IF(123,1) == 123);
assert_se(VA_IF(1+,1) 0 == 1);
assert_se(VA_IF(1+,0) 0 == 1);
assert_se(VA_IF(1+,) 0 == 0);
assert_se(VA_IF(1+, )0 == 0);
assert_se(VA_IF(1+, VA_IF(2+, VA_IF(3+, 4))) 0 == 1);
assert_se(VA_IF(1+, VA_IF(2+, VA_IF(3+, ))) 0 == 0);
assert_se(VA_IF(1+, VA_IF(, VA_IF(3+, 4))) 0 == 0);
assert_se(streq(VA_IF("hi", VA_IF(x,1)) "", "hi"));
assert_se(!streq(VA_IF("hi", VA_IF(x,NONE)) "", "hi"));
}
TEST(va_if_not) {
assert_se(VA_IF_NOT(123,) == 123);
assert_se(VA_IF_NOT(1+,1) 0 == 0);
assert_se(VA_IF_NOT(1+,0) 0 == 0);
assert_se(VA_IF_NOT(1+,) 0 == 1);
assert_se(VA_IF_NOT(1+, )0 == 1);
assert_se(VA_IF_NOT(1+, VA_IF_NOT(2+, VA_IF_NOT(3+, 4))) 0 == 0);
assert_se(VA_IF_NOT(1+, VA_IF_NOT(2+, VA_IF_NOT(3+, ))) 0 == 1);
assert_se(VA_IF_NOT(1+, VA_IF_NOT(, VA_IF_NOT(3+, 4))) 0 == 1);
assert_se(!streq(VA_IF_NOT("hi", 1) "", "hi"));
assert_se(streq(VA_IF_NOT("hi", NONE) "", "hi"));
}
TEST(va_not) {
assert_se(streq(STRINGIFY(VA_NOT()), "1"));
assert_se(streq(STRINGIFY(VA_NOT( )), "1"));
assert_se(streq(STRINGIFY(VA_NOT(1)), ""));
assert_se(streq(STRINGIFY(VA_NOT(0)), ""));
assert_se(streq(STRINGIFY(VA_NOT(1,2,3)), ""));
assert_se(streq(STRINGIFY(VA_NOT(,1,)), ""));
assert_se(streq(STRINGIFY(VA_NOT(,1)), ""));
assert_se(streq(STRINGIFY(VA_NOT("")), ""));
assert_se(streq(STRINGIFY(VA_NOT("hi")), ""));
assert_se(streq(STRINGIFY(VA_NOT(VA_NOT())), ""));
assert_se(streq(STRINGIFY(VA_NOT(VA_NOT(2))), "1"));
assert_se(streq(STRINGIFY(VA_NOT(VA_NOT("hi"))), "1"));
assert_se(streq(STRINGIFY(VA_NOT(VA_NOT(VA_NOT(2)))), ""));
assert_se(streq(STRINGIFY(VA_NOT(VA_NOT(2),VA_NOT(3))), ""));
assert_se(streq(STRINGIFY(VA_NOT(VA_NOT(),VA_NOT(3))), ""));
assert_se(streq(STRINGIFY(VA_NOT(VA_NOT(2),VA_NOT())), ""));
}
TEST(va_first) {
assert_se(VA_FIRST(1,2,3) == 1);
assert_se(VA_FIRST(1+,2+) 0 == 1);
assert_se(VA_FIRST(1+) 0 == 1);
assert_se(VA_FIRST() 0 == 0);
assert_se(streq(STRINGIFY(VA_FIRST()), ""));
assert_se(streq(STRINGIFY(VA_FIRST( )), ""));
assert_se(streq(STRINGIFY(VA_FIRST(,)), ""));
assert_se(streq(STRINGIFY(VA_FIRST(NONE)), ""));
assert_se(streq(STRINGIFY(VA_FIRST( NONE )), ""));
assert_se(streq(STRINGIFY(VA_FIRST( NONE, )), ""));
assert_se(streq(STRINGIFY(VA_FIRST( NONE,1,3 )), ""));
}
TEST(va_rest) {
assert_se(VA_REST(1,3) == 3);
assert_se(VA_REST(1+,2+) 0 == 2);
assert_se(VA_REST(1+) 0 == 0);
assert_se(VA_REST() 0 == 0);
assert_se(streq(STRINGIFY(VA_REST(NONE,1)), "1"));
assert_se(streq(STRINGIFY(VA_REST(1,NONE,1)), ",1"));
assert_se(streq(STRINGIFY(VA_REST(1,NONE)), ""));
assert_se(VA_FIRST(VA_REST(1,2,3,4,5)) == 2);
int ia[] = { VA_REST(1,2,3,4,5) };
assert_se(ELEMENTSOF(ia) == 4);
assert_se(ia[0] == 2);
assert_se(ia[1] == 3);
assert_se(ia[2] == 4);
assert_se(ia[3] == 5);
}
TEST(va_comma) {
assert_se(streq("0 , 1, 2", STRINGIFY(0 VA_COMMA(0) 1, 2)));
assert_se(streq("0 , 1, 2", STRINGIFY(0 VA_COMMA(1) 1, 2)));
assert_se(streq("0 1, 2", STRINGIFY(0 VA_COMMA() 1, 2)));
}
TEST(va_and) {
assert_se(streq(STRINGIFY(VA_AND(1,2)), "1"));
assert_se(streq(STRINGIFY(VA_AND(,2)), ""));
assert_se(streq(STRINGIFY(VA_AND(1,)), ""));
assert_se(streq(STRINGIFY(VA_AND(,)), ""));
assert_se(streq(STRINGIFY(VA_AND( , )), ""));
assert_se(streq(STRINGIFY(VA_AND(1 , )), ""));
assert_se(streq(STRINGIFY(VA_AND( , 2 )), ""));
assert_se(streq(STRINGIFY(VA_AND( 1 , 2 )), "1"));
assert_se(streq(STRINGIFY(VA_AND("hi",2)), "1"));
assert_se(streq(STRINGIFY(VA_AND(1,"hi")), "1"));
assert_se(streq(STRINGIFY(VA_AND("hi","hi")), "1"));
assert_se(streq(STRINGIFY(VA_AND(VA_AND(1,2),2)), "1"));
assert_se(streq(STRINGIFY(VA_AND(VA_AND(1,),2)), ""));
assert_se(streq(STRINGIFY(VA_AND(VA_AND(1,2),)), ""));
assert_se(streq(STRINGIFY(VA_AND( VA_AND( , 1 ) , VA_AND( , ) )), ""));
assert_se(streq(STRINGIFY(VA_AND( VA_AND( , ) , VA_AND( , ) )), ""));
}
TEST(va_or) {
assert_se(streq(STRINGIFY(VA_OR(1,2)), "1"));
assert_se(streq(STRINGIFY(VA_OR(,2)), "1"));
assert_se(streq(STRINGIFY(VA_OR(1,)), "1"));
assert_se(streq(STRINGIFY(VA_OR(,)), ""));
assert_se(streq(STRINGIFY(VA_OR("hi",2)), "1"));
assert_se(streq(STRINGIFY(VA_OR(1,"hi")), "1"));
assert_se(streq(STRINGIFY(VA_OR("hi","hi")), "1"));
assert_se(streq(STRINGIFY(VA_OR("hi",)), "1"));
assert_se(streq(STRINGIFY(VA_OR(,"hi")), "1"));
assert_se(streq(STRINGIFY(VA_OR( , )), ""));
assert_se(streq(STRINGIFY(VA_OR(VA_OR(1,),)), "1"));
assert_se(streq(STRINGIFY(VA_OR(VA_OR(,),)), ""));
assert_se(streq(STRINGIFY(VA_OR(VA_OR(,),2)), "1"));
assert_se(streq(STRINGIFY(VA_OR( VA_OR(1,) , )), "1"));
assert_se(streq(STRINGIFY(VA_OR( VA_OR( , 1 ) , VA_OR( , ) )), "1"));
assert_se(streq(STRINGIFY(VA_OR( VA_OR( , ) , VA_OR( , ) )), ""));
}
TEST(va_macro) {
assert_se(VA_MACRO(MACRO1, 3,2,1) == 3);
assert_se(VA_MACRO(MACRO1, 4) == 4);
assert_se(VA_MACRO(MACRO2, 4,5) == 5);
assert_se(streq(VA_MACRO(MACRO2, 4,"hi"), "hi"));
}
#define VA_NARGS_MAX_LESS_1 \
1,2,3,4,5,6,7,8,9,a,b,c,d,e,f,010, \
1,2,3,4,5,6,7,8,9,a,b,c,d,e,f,020, \
1,2,3,4,5,6,7,8,9,a,b,c,d,e,f,030, \
1,2,3,4,5,6,7,8,9,a,b,c,d,e,f,040, \
1,2,3,4,5,6,7,8,9,a,b,c,d,e,f,050, \
1,2,3,4,5,6,7,8,9,a,b,c,d,e,f,060, \
1,2,3,4,5,6,7,8,9,a,b,c,d,e,f,070, \
1,2,3,4,5,6,7,8,9,a,b,c,d,e,f,080, \
1,2,3,4,5,6,7,8,9,a,b,c,d,e,f,090, \
1,2,3,4,5,6,7,8,9,a,b,c,d,e,f,0a0, \
1,2,3,4,5,6,7,8,9,a,b,c,d,e,f,0b0, \
1,2,3,4,5,6,7,8,9,a,b,c,d,e,f,0c0, \
1,2,3,4,5,6,7,8,9,a,b,c,d,e,f,0d0, \
1,2,3,4,5,6,7,8,9,a,b,c,d,e,f,0e0, \
1,2,3,4,5,6,7,8,9,a,b,c,d,e,f,0f0, \
1,2,3,4,5,6,7,8,9,a,b,c,d,e,f,100, \
1,2,3,4,5,6,7,8,9,a,b,c,d,e,f,110, \
1,2,3,4,5,6,7,8,9,a,b,c,d,e,f,120, \
1,2,3,4,5,6,7,8,9,a,b,c,d,e,f,130, \
1,2,3,4,5,6,7,8,9,a,b,c,d,e,f,140, \
1,2,3,4,5,6,7,8,9,a,b,c,d,e,f,150, \
1,2,3,4,5,6,7,8,9,a,b,c,d,e,f,160, \
1,2,3,4,5,6,7,8,9,a,b,c,d,e,f,170, \
1,2,3,4,5,6,7,8,9,a,b,c,d,e,f,180, \
1,2,3,4,5,6,7,8,9,a,b,c,d,e,f,190, \
1,2,3,4,5,6,7,8,9,a,b,c,d,e,f,1a0, \
1,2,3,4,5,6,7,8,9,a,b,c,d,e,f,1b0, \
1,2,3,4,5,6,7,8,9,a,b,c,d,e,f,1c0, \
1,2,3,4,5,6,7,8,9,a,b,c,d,e,f,1d0, \
1,2,3,4,5,6,7,8,9,a,b,c,d,e,f,1e0, \
1,2,3,4,5,6,7,8,9,a,b,c,d,e,f,1f0, \
1,2,3,4,5,6,7,8,9,a,b,c,d,e, 1ff
#define TEST_EQ_STR(expected, result) assert_se(streq(expected, STRINGIFY(result)))
#define XvX(c, i, v, ...) X v X
TEST(va_macro_foreach) {
TEST_EQ_STR("", VA_MACRO_FOREACH(XvX));
TEST_EQ_STR("", VA_MACRO_FOREACH(XvX,));
TEST_EQ_STR("", VA_MACRO_FOREACH(XvX, ));
TEST_EQ_STR("X 1 X", VA_MACRO_FOREACH(XvX, 1));
TEST_EQ_STR("X 1 X, X 2 X", VA_MACRO_FOREACH(XvX, 1, 2));
TEST_EQ_STR("X hi X", VA_MACRO_FOREACH(XvX, hi));
TEST_EQ_STR("X one X, X two X, X three X", VA_MACRO_FOREACH(XvX, one, two, three));
TEST_EQ_STR("X 1 X, X 2 X, X X, X 4 X, X 5 X", VA_MACRO_FOREACH(XvX, 1, 2, , 4, 5));
TEST_EQ_STR("X X, X 2 X, X 3 X, X 4 X, X 5 X", VA_MACRO_FOREACH(XvX, , 2, 3, 4, 5));
/* Note that if the final arg is empty (or only whitespace), it is not included. */
TEST_EQ_STR("X 1 X", VA_MACRO_FOREACH(XvX, 1,));
TEST_EQ_STR("X X, X 1 X", VA_MACRO_FOREACH(XvX, ,1));
TEST_EQ_STR("X 1 X", VA_MACRO_FOREACH(XvX, 1, ));
TEST_EQ_STR("X X, X 1 X", VA_MACRO_FOREACH(XvX,,1));
TEST_EQ_STR("X X, X 1 X", VA_MACRO_FOREACH(XvX,,1,));
TEST_EQ_STR("X X, X 1 X", VA_MACRO_FOREACH(XvX,,1, ));
TEST_EQ_STR("X X, X X, X X, X X", VA_MACRO_FOREACH(XvX, , , , , ));
TEST_EQ_STR("X X, X X, X X, X X, X 1 X", VA_MACRO_FOREACH(XvX, , , , , 1));
TEST_EQ_STR("X X, X X, X X, X X, X 1 X", VA_MACRO_FOREACH(XvX, , , , ,1));
TEST_EQ_STR("X X, X X, X X, X X", VA_MACRO_FOREACH(XvX,,,,,));
TEST_EQ_STR("X X, X X, X X, X X, X 1 X", VA_MACRO_FOREACH(XvX,,,,,1));
TEST_EQ_STR("X X, X X, X X, X X, X 1 X", VA_MACRO_FOREACH(XvX,,,,, 1));
}
TEST(va_filter) {
TEST_EQ_STR("0, 1, 2, 3, hi, later", VA_FILTER(0, 1, 2, 3, , , , hi, later, ));
TEST_EQ_STR("", VA_FILTER(, , , , ,));
TEST_EQ_STR("5", VA_FILTER(, , , , ,5));
TEST_EQ_STR("4, 5", VA_FILTER(4, , , , ,5));
TEST_EQ_STR("6, 7", VA_FILTER(, 6, 7, , ,));
TEST_EQ_STR("\"one\", \"two\"", VA_FILTER(, "one", ,"two" , ,));
}
#define TEST_NARGS(expect, expect_token, ...) \
({ \
assert_se(VA_NARGS(__VA_ARGS__) == expect); \
assert_se(streq(STRINGIFY(expect_token), STRINGIFY(VA_NARGS(__VA_ARGS__)))); \
assert_se(__builtin_constant_p(VA_NARGS(__VA_ARGS__))); \
})
TEST(va_nargs) {
_unused_ int i = 0;
_unused_ const char *hi = "hello";
TEST_NARGS(0, 0x0000);
TEST_NARGS(0, 0x0000,);
TEST_NARGS(0, 0x0000, );
TEST_NARGS(1, 0x0001, 1);
TEST_NARGS(1, 0x0001, "hello");
TEST_NARGS(1, 0x0001, "hello");
TEST_NARGS(1, 0x0001, i);
TEST_NARGS(1, 0x0001, i++);
TEST_NARGS(2, 0x0002, i, hi);
TEST_NARGS(16, 0x0010, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15);
}
TEST(va_last) {
_unused_ int i = 0;
_unused_ const char *hi = "hello";
assert_se(streq(STRINGIFY(VA_LAST()), ""));
assert_se(VA_LAST(1,2,10) == 10);
assert_se(streq(VA_LAST("hi", "there"), "there"));
assert_se(VA_LAST(1,2,i++) == 0);
assert_se(i == 1);
assert_se(VA_LAST(1,2,++i) == 2);
assert_se(i == 2);
assert_se(VA_LAST(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15) == 15);
assert_se(VA_LAST(VA_NARGS_MAX_LESS_1,123) == 123);
}
TEST(va_declarations) {
int i = 999;
VA_DECLARATIONS(test_decl, int, char*, uint64_t, typeof(i));
test_decl_0x0001 = 10;
test_decl_0x0002 = (char*)"hello";
test_decl_0x0003 = 0xffff000000000001;
test_decl_0x0004 = 8;
assert_se(test_decl_0x0001 == 10);
assert_se(__builtin_types_compatible_p(typeof(test_decl_0x0001), int));
assert_se(streq(test_decl_0x0002, "hello"));
assert_se(__builtin_types_compatible_p(typeof(test_decl_0x0002), char*));
assert_se(test_decl_0x0003 == 0xffff000000000001);
assert_se(__builtin_types_compatible_p(typeof(test_decl_0x0003), uint64_t));
assert_se(test_decl_0x0004 == 8);
assert_se(__builtin_types_compatible_p(typeof(test_decl_0x0004), int));
VA_DECLARATIONS();
VA_INITIALIZED_DECLARATIONS(test_i, test_decl_0x0003, test_decl_0x0004, i, test_decl_0x0002, test_decl_0x0001, i);
assert_se(__builtin_types_compatible_p(typeof(test_i_0x0001), uint64_t));
assert_se(test_i_0x0001 == 0xffff000000000001);
test_i_0x0001--;
assert_se(test_i_0x0001 == 0xffff000000000000);
assert_se(test_decl_0x0003 == 0xffff000000000001);
test_decl_0x0003 = 0xffff;
assert_se(test_i_0x0001 == 0xffff000000000000);
assert_se(__builtin_types_compatible_p(typeof(test_i_0x0002), int));
assert_se(test_i_0x0002 == 8);
test_i_0x0002--;
assert_se(test_i_0x0002 == 7);
assert_se(test_decl_0x0004 == 8);
test_decl_0x0004 = 50;
assert_se(test_i_0x0002 == 7);
assert_se(__builtin_types_compatible_p(typeof(test_i_0x0003), int));
assert_se(test_i_0x0003 == 999);
test_i_0x0003--;
assert_se(test_i_0x0003 == 998);
assert_se(i == 999);
i = 333;
assert_se(test_i_0x0003 == 998);
assert_se(__builtin_types_compatible_p(typeof(test_i_0x0004), char*));
assert_se(streq(test_i_0x0004, "hello"));
assert_se(streq(test_i_0x0004, test_decl_0x0002));
test_i_0x0004 = NULL;
assert_se(test_i_0x0004 == NULL);
assert_se(streq(test_decl_0x0002, "hello"));
assert_se(__builtin_types_compatible_p(typeof(test_i_0x0005), int));
assert_se(test_i_0x0005 == 10);
test_i_0x0005--;
assert_se(test_i_0x0005 == 9);
assert_se(test_decl_0x0001 == 10);
test_decl_0x0001 = 44;
assert_se(test_i_0x0005 == 9);
assert_se(__builtin_types_compatible_p(typeof(test_i_0x0006), int));
assert_se(test_i_0x0006 == 999);
test_i_0x0006--;
assert_se(test_i_0x0006 == 998);
assert_se(i == 333);
i = 222;
assert_se(test_i_0x0006 == 998);
VA_INITIALIZED_DECLARATIONS();
}
#define TEST_TOKENS(equal1, equal2, equal3, equal4, \
expect1, expect2, expect3, expect4, \
v1, v2, v3, v4) \
({ \
assert_se((expect1 == v1) == equal1); \
assert_se((expect2 == v2) == equal2); \
assert_se((expect3 == v3) == equal3); \
assert_se((expect4 == v4) == equal4); \
})
TEST(va_tokens) {
int i1 = 10, i2 = 100, i3 = 50, i4 = 99;
VA_INITIALIZED_DECLARATIONS(test_i_, i1, i2, i3, i4);
VA_MACRO(TEST_TOKENS, true, true, true, true, i1, i2, i3, i4, VA_TOKENS(test_i_, i1, i2, i3, i4));
VA_MACRO(TEST_TOKENS, true, true, true, true, 10, 100, i3, 99, VA_TOKENS(test_i_, i1, i2, i3, i4));
/* VA_TOKENS() doesn't actually use the variadic args, the tokens are based on index */
VA_MACRO(TEST_TOKENS, true, true, true, true, i1, i2, i3, i4, VA_TOKENS(test_i_, x, x, x, x));
VA_MACRO(TEST_TOKENS, true, false, true, false, i1, i4, i3, 1234, VA_TOKENS(test_i_, i1, i2, i3, i4));
}
#define TEST_UNIQ(x, y, z) \
_unused_ int x = 10; \
_unused_ const char *y = "hi"; \
_unused_ uint64_t z = 0xffff;
TEST(va_uniq) {
int x = 20;
const char *y = "still me";
uint64_t z = 0xf;
VA_MACRO(TEST_UNIQ, VA_UNIQ(first, second, third));
assert_se(x == 20);
assert_se(streq(y, "still me"));
assert_se(z == 0xf);
}
#define TEST_MACRO_SWAP(tmp, x, y) \
({ \
tmp = x; \
x = y; \
y = tmp; \
})
#define TEST_MACRO_ALL(u1, u2, v1, v2, vi1, vi2, vc1, vc2, d1, d2) \
({ \
int u1 = 100; \
char *u2 = (char*)"u2"; \
assert_se(u1 == 100); \
assert_se(streq(u2, "u2")); \
\
v1 = d1; \
v2 = d2; \
assert_se(v1 == 30); \
assert_se(streq(v2, "d2")); \
v1++; \
v2++; \
assert_se(v1 == 31); \
assert_se(streq(v2, "2")); \
\
assert_se(vi1 == 10); \
assert_se(streq(vi2, "vi2")); \
vi1++; \
vi2++; \
assert_se(vi1 == 11); \
assert_se(streq(vi2, "i2")); \
\
assert_se(vc1 == 20); \
assert_se(streq(vc2, "vc2")); \
\
assert_se(d1 == 30); \
assert_se(streq(d2, "d2")); \
\
d1 = u1; \
d2 = u2; \
assert_se(d1 == 100); \
assert_se(streq(d2, "u2")); \
\
d1 + 1000; \
})
TEST(va_macro_helper) {
int i1, i2;
i1 = 10;
i2 = 20;
VA_MACRO_HELPER(TEST_MACRO_SWAP,
/*uniq*/,
int,
/*varinit*/,
/*varconst*/,
VA_GROUP(i1, i2));
assert_se(i1 == 20);
assert_se(i2 == 10);
int vi1 = 10, vc1 = 20, d1 = 30;
char *vi2 = (char*)"vi2", *vc2 = (char*)"vc2", *d2 = (char*)"d2";
int all = VA_MACRO_HELPER(TEST_MACRO_ALL,
VA_GROUP(u1, u2),
VA_GROUP(int, char*),
VA_GROUP(vi1, vi2),
VA_GROUP(vc1, vc2),
VA_GROUP(d1, d2));
assert_se(all == 1100);
assert_se(vi1 == 10);
assert_se(streq(vi2, "vi2"));
assert_se(vc1 == 20);
assert_se(streq(vc2, "vc2"));
assert_se(d1 == 100);
assert_se(streq(d2, "u2"));
}
#define TEST_UNIQ_INT_X(_x) \
({ \
int _x = 5; \
_x++; \
})
#define TEST_UNIQ_INT_X_Y_Z(x, y, z, v, ...) \
({ \
int x = v; \
int y = VA_IF_ELSE(VA_FIRST(__VA_ARGS__), 100, __VA_ARGS__); \
int z = VA_IF_ELSE(VA_FIRST(VA_REST(__VA_ARGS__)), 2000, VA_REST(__VA_ARGS__)); \
x + y + z; \
})
TEST(va_macro_uniq) {
int x = 1, _x = 2;
int y = VA_MACRO_UNIQ(TEST_UNIQ_INT_X, _x);
assert_se(x == 1);
assert_se(_x == 2);
assert_se(y == 5);
int z = VA_MACRO_UNIQ(TEST_UNIQ_INT_X_Y_Z, VA_GROUP(x, y, z), x);
assert_se(x == 1);
assert_se(_x == 2);
assert_se(y == 5);
assert_se(z == 2101);
_x = VA_MACRO_UNIQ(TEST_UNIQ_INT_X_Y_Z, VA_GROUP(1, 2, z), 99);
assert_se(x == 1);
assert_se(_x == 2199);
assert_se(y == 5);
assert_se(z == 2101);
z = VA_MACRO_UNIQ(TEST_UNIQ_INT_X_Y_Z, VA_GROUP(_X, _Y, _Z), 5, 20);
assert_se(x == 1);
assert_se(_x == 2199);
assert_se(y == 5);
assert_se(z == 2025);
z = VA_MACRO_UNIQ(TEST_UNIQ_INT_X_Y_Z, VA_GROUP(_X, _Y, _Z), 7, 70, 5000);
assert_se(x == 1);
assert_se(_x == 2199);
assert_se(y == 5);
assert_se(z == 5077);
}
#define TEST_MACRO_INT_CHARP(x1, x2) \
({ \
assert_se(__builtin_types_compatible_p(typeof(x1), int)); \
assert_se(__builtin_types_compatible_p(typeof(x2), char*)); \
})
typedef struct { int a; } structabc;
#define TEST_MACRO_INTP_STRUCTABC_INT(x1, x2, x3) \
({ \
assert_se(__builtin_types_compatible_p(typeof(x1), int*)); \
assert_se(__builtin_types_compatible_p(typeof(x2), structabc)); \
assert_se(__builtin_types_compatible_p(typeof(x3), int)); \
})
#define TEST_MACRO_INT_TMP1(x) \
({ \
x = 7; \
x++; \
})
TEST(va_macro_var) {
int j = VA_MACRO_VAR(TEST_MACRO_INT_TMP1, int);
assert_se(j == 7);
assert_se(VA_MACRO_VAR(TEST_MACRO_INT_TMP1, int) == 7);
VA_MACRO_VAR(TEST_MACRO_INT_CHARP, VA_GROUP(int, char*));
VA_MACRO_VAR(TEST_MACRO_INTP_STRUCTABC_INT, VA_GROUP(int*, structabc, int));
}
#define MACRO_USE_TWICE_1L2_OR_B0(x1, x2) \
({ \
(x1 < x2) || (x1 == 0 && x2 == 0); \
})
#define MACRO_INT_USE_ARGS1_EVAL1(x1) \
({ \
_unused_ int x = x1; \
x1; \
})
#define MACRO_INT_USE_ARGS2_EVAL1(x1,x2) \
({ \
_unused_ int x = x1 + x2; \
x1; \
})
#define MACRO_INT_USE_ARGS2_EVAL2(x1,x2) \
({ \
_unused_ int x = x1 + x2; \
x2; \
})
#define MACRO_INT_USE_ARGS6_EVAL1(x1,x2,x3,x4,x5,x6) \
({ \
_unused_ int x = x1 + x2 + x3 + x4 + x5 + x6; \
x1; \
})
#define MACRO_INT_USE_ARGS6_EVAL4(x1,x2,x3,x4,x5,x6) \
({ \
_unused_ int x = x1 + x2 + x3 + x4 + x5 + x6; \
x4; \
})
TEST(va_macro_varinit) {
_unused_ int i = 1, j = 0, k = 5678;
assert_se(VA_MACRO_VARINIT(MACRO_INT_USE_ARGS1_EVAL1, 1) == 1);
assert_se(VA_MACRO_VARINIT(MACRO_INT_USE_ARGS2_EVAL1, VA_GROUP(1, 10)) == 1);
assert_se(VA_MACRO_VARINIT(MACRO_INT_USE_ARGS2_EVAL2, VA_GROUP(1, 10)) == 10);
assert_se(VA_MACRO_VARINIT(MACRO_INT_USE_ARGS6_EVAL1, VA_GROUP(100, 1000, 1, 0, 20, -80)) == 100);
assert_se(VA_MACRO_VARINIT(MACRO_INT_USE_ARGS6_EVAL4, VA_GROUP(-9,i,1,k,3,4)) == 5678);
assert_se(VA_MACRO_VARINIT(MACRO_SUM12, VA_GROUP(1,10)) == 11);
assert_se(VA_MACRO_VARINIT(MACRO_SUM12, VA_GROUP(10,k)) == 5688);
i = 1234;
assert_se(VA_MACRO_VARINIT(MACRO1, i) == 1234);
assert_se(VA_MACRO_VARINIT(MACRO1, 1234) == i);
i = 10;
j = 20;
assert_se(VA_MACRO_VARINIT(MACRO_USE_TWICE_1L2_OR_B0, VA_GROUP(i++, j--)) == 1);
assert_se(i == 11);
assert_se(j == 19);
assert_se(VA_MACRO_VARINIT(MACRO_USE_TWICE_1L2_OR_B0, VA_GROUP(j + 5, j + 10)) == 1);
assert_se(i == 11);
assert_se(j == 19);
i = 10;
j = 0;
assert_se(VA_MACRO_VARINIT(MACRO_USE_TWICE_1L2_OR_B0, VA_GROUP(i - 10, j)) == 1);
assert_se(i == 10);
assert_se(j == 0);
assert_se(VA_MACRO_VARINIT(MACRO_USE_TWICE_1L2_OR_B0, VA_GROUP(i, j--)) == 0);
assert_se(i == 10);
assert_se(j == -1);
}
TEST(va_macro_varconst) {
_unused_ int i = 1, j = 0, k = 4444;
assert_se(VA_MACRO_VARCONST(MACRO_INT_USE_ARGS1_EVAL1, 1) == 1);
assert_se(VA_MACRO_VARCONST(MACRO_INT_USE_ARGS2_EVAL2, VA_GROUP(1, 10)) == 10);
assert_se(VA_MACRO_VARCONST(MACRO_INT_USE_ARGS6_EVAL4, VA_GROUP(0,i,1,k,3,4)) == 4444);
assert_se(VA_MACRO_VARCONST(MACRO_INT_USE_ARGS6_EVAL1, VA_GROUP(i,2,2,3,4,k)) == 1);
assert_se(VA_MACRO_VARCONST(MACRO_INT_USE_ARGS6_EVAL1, VA_GROUP(1000,2,3,4,k,0)) == 1000);
assert_se(VA_MACRO_VARCONST(MACRO_SUM12, VA_GROUP(1,10)) == 11);
assert_se(VA_MACRO_VARCONST(MACRO_SUM12, VA_GROUP(k,1)) == 4445);
i = 1234;
assert_se(VA_MACRO_VARCONST(MACRO_INT_USE_ARGS1_EVAL1, i) == 1234);
assert_se(VA_MACRO_VARCONST(MACRO_INT_USE_ARGS1_EVAL1, 1234) == i);
}
TEST(va_toomany) {
/* Test assumes largest __VA_EVAL_0x*() macro is 0x0200. */
assert_se(VA_NARGS(VA_NARGS_MAX_LESS_1) == 0x1ff);
assert_se(VA_NARGS(VA_NARGS_MAX_LESS_1,1) == 0x200);
assert_se(VA_WRAP(VA_WRAP_MACRO_LAST,
VA_WRAP_SEPARATOR_NONE,
-1,
VA_WRAP_ZERO_NONE,
VA_WRAP_TOOMANY_CONTEXT,
VA_NARGS_MAX_LESS_1, -2) == -2);
assert_se(VA_WRAP(VA_WRAP_MACRO_LAST,
VA_WRAP_SEPARATOR_NONE,
-1,
VA_WRAP_ZERO_NONE,
VA_WRAP_TOOMANY_CONTEXT,
VA_NARGS_MAX_LESS_1, -2, -3) == -1);
}
TEST(va_number) {
assert_se(___VANUM4(4,3,2,1) == 0x4321);
assert_se(___VANUM4(f,f,f,f) == 0xffff);
assert_se(___VANUM4(0,0,0,0) == 0);
assert_se(___VANUM4(0,0,0,1) == 1);
assert_se(___VANUM4(0,1,0,0) == 0x100);
assert_se(___VANUM4(1,0,0,1) == 0x1001);
assert_se(__VANUM4((1,0,0,1)) == 0x1001);
}
TEST(va_inc) {
assert_se(__VANUM4(__VAINC4((1,2,3,4))) == 0x1235);
assert_se(__VANUM4(__VAINC4((0,0,0,0))) == 1);
assert_se(__VANUM4(__VAINC4((0,0,0,1))) == 2);
assert_se(__VANUM4(__VAINC4((1,0,0,0))) == 0x1001);
assert_se(__VANUM4(__VAINC4((f,f,f,e))) == 0xffff);
assert_se(__VANUM4(__VAINC4((e,f,f,e))) == 0xefff);
assert_se(__VANUM4(__VAINC4((e,f,e,f))) == 0xeff0);
assert_se(__VANUM4(__VAINC4((d,f,f,f))) == 0xe000);
}
DEFINE_TEST_MAIN(LOG_INFO);

View File

@ -6406,11 +6406,11 @@ class NetworkdRATests(unittest.TestCase, Utilities):
for i in [100, 200, 300, 512, 1024, 2048]:
if i not in [metric_1, metric_2]:
self.assertNotIn(f'{i}', output)
self.assertNotIn(f'metric {i} ', output)
for i in ['low', 'medium', 'high']:
if i not in [preference_1, preference_2]:
self.assertNotIn(f'{i}', output)
self.assertNotIn(f'pref {i}', output)
def test_router_preference(self):
copy_network_unit('25-veth-client.netdev',