Compare commits

...

16 Commits

Author SHA1 Message Date
Dan Streetman 40d33bdb9f
Merge 413f6e0f56 into 4b356c90dc 2024-11-23 08:07:20 -08:00
Ani Sinha 4b356c90dc measure: add 'dtbauto' option in help message
'dtbauto' command line was missing from the help string. Add it.
2024-11-23 12:43:34 +00:00
Léane GRASSER f28e16d14e 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-23 20:49:18 +09:00
Yu Watanabe 9e05e33871 networkd-test.py: fix interface state checker
After 259125d53d, network interfaces
declared by .netdev files are created after systemd-networkd sends READY
notification. So, even when networkd is started, the netdevs may not
be created yet, and 'ip' command may fail. Let's also check the return
code of the command.

This also
- drops never worked stdout checks,
- makes the test fail if the interface is not created within the timeout.
2024-11-23 17:33:43 +09:00
Lennart Poettering 95116bdfd5 nspawn: improve log message on bad incoming sd_notify() message
It's the PID that is wrong, not the UID/GID, be precise.
2024-11-23 17:33:17 +09:00
Lennart Poettering 2bd290ca02 nspawn: fix userns_mkdir() invocation
The wrong error code was logged.

But actually given that userns_mkdir() is fine with existing dirs, let's
drop the redundant conditionalization.

Follow-up for: a1fcaa1549
2024-11-23 17:33:06 +09:00
Yu Watanabe 1e9fb1d456 shutdown: propagate one more error from sync_making_progress()
No functional change, just refactoring, as anyway all errors will be
ignored by the caller.
2024-11-23 17:32:51 +09:00
Yu Watanabe 56c761f8c6
namespace-util: handle -ENOSPC by userns_acquire() gracefully in is_idmapping_supported() (#35313)
Follow-up for edae62120f.
Fixes #35311.
2024-11-23 17:32:23 +09:00
Yu Watanabe b76730f3fe shutdown: close DM block device before issuing DM_DEV_REMOVE ioctl
Otherwise, the ioctl() may fail with EBUSY.

Follow-up for b4b66b2662.
Hopefully fixes #35243.
2024-11-23 17:31:36 +09:00
Yu Watanabe 3dda236c5c basic/linux: update kernel headers from v6.12 2024-11-23 17:31:12 +09:00
Zbigniew Jędrzejewski-Szmek 5598454a3f Undeprecate commandline params forcequotacheck, fastboot, and forcefsck
Those are historical names, but there is nothing wrong with them. The files on
/ (/fastboot, /forcefsck, and /forcequotacheck) are problematic because they
require a modification of the root file system. But the commandline params work
fine. They have the obvious advantage compared to our "modern" option that they
are much easier to type without looking up the spelling in the docs. Undeprecate
them to avoid unnecessary churn.
2024-11-23 17:30:56 +09:00
Yu Watanabe 2994ca354b namespace-util: update log messages 2024-11-23 06:52:48 +09:00
Yu Watanabe eb14b993bb namespace-util: handle -ENOSPC by userns_acquire() gracefully in is_idmapping_supported()
Follow-up for edae62120f.
Fixes #35311.
2024-11-23 06:52:38 +09: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
23 changed files with 1405 additions and 108 deletions

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-20 19:13+0000\n"
"PO-Revision-Date: 2024-11-23 10:38+0000\n"
"Last-Translator: Léane GRASSER <leane.grasser@proton.me>\n"
"Language-Team: French <https://translate.fedoraproject.org/projects/systemd/"
"main/fr/>\n"
@ -1258,7 +1258,7 @@ msgstr ""
#: src/sysupdate/org.freedesktop.sysupdate1.policy:75
msgid "Manage optional features"
msgstr "Gérer les fonctionnalités en option"
msgstr "Gérer les fonctionnalités facultatives"
#: src/sysupdate/org.freedesktop.sysupdate1.policy:76
msgid "Authentication is required to manage optional features"

View File

@ -21,7 +21,7 @@
#define AUTOFS_MIN_PROTO_VERSION 3
#define AUTOFS_MAX_PROTO_VERSION 5
#define AUTOFS_PROTO_SUBVERSION 5
#define AUTOFS_PROTO_SUBVERSION 6
/*
* The wait_queue_token (autofs_wqt_t) is part of a structure which is passed

View File

@ -1121,6 +1121,9 @@ enum bpf_attach_type {
#define MAX_BPF_ATTACH_TYPE __MAX_BPF_ATTACH_TYPE
/* Add BPF_LINK_TYPE(type, name) in bpf_types.h to keep bpf_link_type_strs[]
* in sync with the definitions below.
*/
enum bpf_link_type {
BPF_LINK_TYPE_UNSPEC = 0,
BPF_LINK_TYPE_RAW_TRACEPOINT = 1,
@ -2851,7 +2854,7 @@ union bpf_attr {
* **TCP_SYNCNT**, **TCP_USER_TIMEOUT**, **TCP_NOTSENT_LOWAT**,
* **TCP_NODELAY**, **TCP_MAXSEG**, **TCP_WINDOW_CLAMP**,
* **TCP_THIN_LINEAR_TIMEOUTS**, **TCP_BPF_DELACK_MAX**,
* **TCP_BPF_RTO_MIN**.
* **TCP_BPF_RTO_MIN**, **TCP_BPF_SOCK_OPS_CB_FLAGS**.
* * **IPPROTO_IP**, which supports *optname* **IP_TOS**.
* * **IPPROTO_IPV6**, which supports the following *optname*\ s:
* **IPV6_TCLASS**, **IPV6_AUTOFLOWLABEL**.
@ -5519,11 +5522,12 @@ union bpf_attr {
* **-EOPNOTSUPP** if the hash calculation failed or **-EINVAL** if
* invalid arguments are passed.
*
* void *bpf_kptr_xchg(void *map_value, void *ptr)
* void *bpf_kptr_xchg(void *dst, void *ptr)
* Description
* Exchange kptr at pointer *map_value* with *ptr*, and return the
* old value. *ptr* can be NULL, otherwise it must be a referenced
* pointer which will be released when this helper is called.
* Exchange kptr at pointer *dst* with *ptr*, and return the old value.
* *dst* can be map value or local kptr. *ptr* can be NULL, otherwise
* it must be a referenced pointer which will be released when this helper
* is called.
* Return
* The old value of kptr (which can be NULL). The returned pointer
* if not NULL, is a reference which must be released using its
@ -6046,11 +6050,6 @@ enum {
BPF_F_MARK_ENFORCE = (1ULL << 6),
};
/* BPF_FUNC_clone_redirect and BPF_FUNC_redirect flags. */
enum {
BPF_F_INGRESS = (1ULL << 0),
};
/* BPF_FUNC_skb_set_tunnel_key and BPF_FUNC_skb_get_tunnel_key flags. */
enum {
BPF_F_TUNINFO_IPV6 = (1ULL << 0),
@ -6197,10 +6196,12 @@ enum {
BPF_F_BPRM_SECUREEXEC = (1ULL << 0),
};
/* Flags for bpf_redirect_map helper */
/* Flags for bpf_redirect and bpf_redirect_map helpers */
enum {
BPF_F_BROADCAST = (1ULL << 3),
BPF_F_EXCLUDE_INGRESS = (1ULL << 4),
BPF_F_INGRESS = (1ULL << 0), /* used for skb path */
BPF_F_BROADCAST = (1ULL << 3), /* used for XDP path */
BPF_F_EXCLUDE_INGRESS = (1ULL << 4), /* used for XDP path */
#define BPF_F_REDIRECT_FLAGS (BPF_F_INGRESS | BPF_F_BROADCAST | BPF_F_EXCLUDE_INGRESS)
};
#define __bpf_md_ptr(type, name) \
@ -7080,6 +7081,7 @@ enum {
TCP_BPF_SYN = 1005, /* Copy the TCP header */
TCP_BPF_SYN_IP = 1006, /* Copy the IP[46] and TCP header */
TCP_BPF_SYN_MAC = 1007, /* Copy the MAC, IP[46], and TCP header */
TCP_BPF_SOCK_OPS_CB_FLAGS = 1008, /* Get or Set TCP sock ops flags */
};
enum {
@ -7512,4 +7514,13 @@ struct bpf_iter_num {
__u64 __opaque[1];
} __attribute__((aligned(8)));
/*
* Flags to control BPF kfunc behaviour.
* - BPF_F_PAD_ZEROS: Pad destination buffer with zeros. (See the respective
* helper documentation for details.)
*/
enum bpf_kfunc_flags {
BPF_F_PAD_ZEROS = (1ULL << 0),
};
#endif /* __LINUX_BPF_H__ */

View File

@ -28,6 +28,23 @@
#define _BITUL(x) (_UL(1) << (x))
#define _BITULL(x) (_ULL(1) << (x))
#if !defined(__ASSEMBLY__)
/*
* Missing __asm__ support
*
* __BIT128() would not work in the __asm__ code, as it shifts an
* 'unsigned __init128' data type as direct representation of
* 128 bit constants is not supported in the gcc compiler, as
* they get silently truncated.
*
* TODO: Please revisit this implementation when gcc compiler
* starts representing 128 bit constants directly like long
* and unsigned long etc. Subsequently drop the comment for
* GENMASK_U128() which would then start supporting __asm__ code.
*/
#define _BIT128(x) ((unsigned __int128)(1) << (x))
#endif
#define __ALIGN_KERNEL(x, a) __ALIGN_KERNEL_MASK(x, (__typeof__(x))(a) - 1)
#define __ALIGN_KERNEL_MASK(x, mask) (((x) + (mask)) & ~(mask))

View File

@ -2531,4 +2531,20 @@ struct ethtool_link_settings {
* __u32 map_lp_advertising[link_mode_masks_nwords];
*/
};
/**
* enum phy_upstream - Represents the upstream component a given PHY device
* is connected to, as in what is on the other end of the MII bus. Most PHYs
* will be attached to an Ethernet MAC controller, but in some cases, there's
* an intermediate PHY used as a media-converter, which will driver another
* MII interface as its output.
* @PHY_UPSTREAM_MAC: Upstream component is a MAC (a switch port,
* or ethernet controller)
* @PHY_UPSTREAM_PHY: Upstream component is a PHY (likely a media converter)
*/
enum phy_upstream {
PHY_UPSTREAM_MAC,
PHY_UPSTREAM_PHY,
};
#endif /* _LINUX_ETHTOOL_H */

View File

@ -67,6 +67,7 @@ enum {
FRA_IP_PROTO, /* ip proto */
FRA_SPORT_RANGE, /* sport */
FRA_DPORT_RANGE, /* dport */
FRA_DSCP, /* dscp */
__FRA_MAX
};

View File

@ -230,8 +230,8 @@ struct tpacket_hdr_v1 {
* ts_first_pkt:
* Is always the time-stamp when the block was opened.
* Case a) ZERO packets
* No packets to deal with but atleast you know the
* time-interval of this block.
* No packets to deal with but at least you know
* the time-interval of this block.
* Case b) Non-zero packets
* Use the ts of the first packet in the block.
*
@ -265,7 +265,8 @@ enum tpacket_versions {
- struct tpacket_hdr
- pad to TPACKET_ALIGNMENT=16
- struct sockaddr_ll
- Gap, chosen so that packet data (Start+tp_net) alignes to TPACKET_ALIGNMENT=16
- Gap, chosen so that packet data (Start+tp_net) aligns to
TPACKET_ALIGNMENT=16
- Start+tp_mac: [ Optional MAC header ]
- Start+tp_net: Packet data, aligned to TPACKET_ALIGNMENT=16.
- Pad to align to TPACKET_ALIGNMENT=16

View File

@ -141,7 +141,7 @@ struct in_addr {
*/
#define IP_PMTUDISC_INTERFACE 4
/* weaker version of IP_PMTUDISC_INTERFACE, which allows packets to get
* fragmented if they exeed the interface mtu
* fragmented if they exceed the interface mtu
*/
#define IP_PMTUDISC_OMIT 5

View File

@ -140,25 +140,6 @@
#endif /* _NETINET_IN_H */
/* Coordinate with glibc netipx/ipx.h header. */
#if defined(__NETIPX_IPX_H)
#define __UAPI_DEF_SOCKADDR_IPX 0
#define __UAPI_DEF_IPX_ROUTE_DEFINITION 0
#define __UAPI_DEF_IPX_INTERFACE_DEFINITION 0
#define __UAPI_DEF_IPX_CONFIG_DATA 0
#define __UAPI_DEF_IPX_ROUTE_DEF 0
#else /* defined(__NETIPX_IPX_H) */
#define __UAPI_DEF_SOCKADDR_IPX 1
#define __UAPI_DEF_IPX_ROUTE_DEFINITION 1
#define __UAPI_DEF_IPX_INTERFACE_DEFINITION 1
#define __UAPI_DEF_IPX_CONFIG_DATA 1
#define __UAPI_DEF_IPX_ROUTE_DEF 1
#endif /* defined(__NETIPX_IPX_H) */
/* Definitions for xattr.h */
#if defined(_SYS_XATTR_H)
#define __UAPI_DEF_XATTR 0
@ -240,23 +221,6 @@
#define __UAPI_DEF_IP6_MTUINFO 1
#endif
/* Definitions for ipx.h */
#ifndef __UAPI_DEF_SOCKADDR_IPX
#define __UAPI_DEF_SOCKADDR_IPX 1
#endif
#ifndef __UAPI_DEF_IPX_ROUTE_DEFINITION
#define __UAPI_DEF_IPX_ROUTE_DEFINITION 1
#endif
#ifndef __UAPI_DEF_IPX_INTERFACE_DEFINITION
#define __UAPI_DEF_IPX_INTERFACE_DEFINITION 1
#endif
#ifndef __UAPI_DEF_IPX_CONFIG_DATA
#define __UAPI_DEF_IPX_CONFIG_DATA 1
#endif
#ifndef __UAPI_DEF_IPX_ROUTE_DEF
#define __UAPI_DEF_IPX_ROUTE_DEF 1
#endif
/* Definitions for xattr.h */
#ifndef __UAPI_DEF_XATTR
#define __UAPI_DEF_XATTR 1

View File

@ -436,7 +436,7 @@ enum nft_set_elem_flags {
* @NFTA_SET_ELEM_KEY: key value (NLA_NESTED: nft_data)
* @NFTA_SET_ELEM_DATA: data value of mapping (NLA_NESTED: nft_data_attributes)
* @NFTA_SET_ELEM_FLAGS: bitmask of nft_set_elem_flags (NLA_U32)
* @NFTA_SET_ELEM_TIMEOUT: timeout value (NLA_U64)
* @NFTA_SET_ELEM_TIMEOUT: timeout value, zero means never times out (NLA_U64)
* @NFTA_SET_ELEM_EXPIRATION: expiration time (NLA_U64)
* @NFTA_SET_ELEM_USERDATA: user data (NLA_BINARY)
* @NFTA_SET_ELEM_EXPR: expression (NLA_NESTED: nft_expr_attributes)
@ -1694,7 +1694,7 @@ enum nft_flowtable_flags {
*
* @NFTA_FLOWTABLE_TABLE: name of the table containing the expression (NLA_STRING)
* @NFTA_FLOWTABLE_NAME: name of this flow table (NLA_STRING)
* @NFTA_FLOWTABLE_HOOK: netfilter hook configuration(NLA_U32)
* @NFTA_FLOWTABLE_HOOK: netfilter hook configuration (NLA_NESTED)
* @NFTA_FLOWTABLE_USE: number of references to this flow table (NLA_U32)
* @NFTA_FLOWTABLE_HANDLE: object handle (NLA_U64)
* @NFTA_FLOWTABLE_FLAGS: flags (NLA_U32)

View File

@ -16,10 +16,15 @@ struct nhmsg {
struct nexthop_grp {
__u32 id; /* nexthop id - must exist */
__u8 weight; /* weight of this nexthop */
__u8 resvd1;
__u8 weight_high; /* high order bits of weight */
__u16 resvd2;
};
static __inline__ __u16 nexthop_grp_weight(const struct nexthop_grp *entry)
{
return ((entry->weight_high << 8) | entry->weight) + 1;
}
enum {
NEXTHOP_GRP_TYPE_MPATH, /* hash-threshold nexthop group
* default type if not specified
@ -33,6 +38,9 @@ enum {
#define NHA_OP_FLAG_DUMP_STATS BIT(0)
#define NHA_OP_FLAG_DUMP_HW_STATS BIT(1)
/* Response OP_FLAGS. */
#define NHA_OP_FLAG_RESP_GRP_RESVD_0 BIT(31) /* Dump clears resvd fields. */
enum {
NHA_UNSPEC,
NHA_ID, /* u32; id for nexthop. id == 0 means auto-assign */

View File

@ -531,20 +531,24 @@ int is_idmapping_supported(const char *path) {
userns_fd = userns_acquire(uid_map, gid_map);
if (ERRNO_IS_NEG_NOT_SUPPORTED(userns_fd) || ERRNO_IS_NEG_PRIVILEGE(userns_fd))
return false;
if (userns_fd == -ENOSPC) {
log_debug_errno(userns_fd, "Failed to acquire new user namespace, user.max_user_namespaces seems to be exhausted or maybe even zero, assuming ID-mapping is not supported: %m");
return false;
}
if (userns_fd < 0)
return log_debug_errno(userns_fd, "ID-mapping supported namespace acquire failed for '%s' : %m", path);
return log_debug_errno(userns_fd, "Failed to acquire new user namespace for checking if '%s' supports ID-mapping: %m", path);
dir_fd = RET_NERRNO(open(path, O_RDONLY | O_CLOEXEC | O_NOFOLLOW));
if (ERRNO_IS_NEG_NOT_SUPPORTED(dir_fd))
return false;
if (dir_fd < 0)
return log_debug_errno(dir_fd, "ID-mapping supported open failed for '%s' : %m", path);
return log_debug_errno(dir_fd, "Failed to open '%s', cannot determine if ID-mapping is supported: %m", path);
mount_fd = RET_NERRNO(open_tree(dir_fd, "", AT_EMPTY_PATH | OPEN_TREE_CLONE | OPEN_TREE_CLOEXEC));
if (ERRNO_IS_NEG_NOT_SUPPORTED(mount_fd) || ERRNO_IS_NEG_PRIVILEGE(mount_fd) || mount_fd == -EINVAL)
return false;
if (mount_fd < 0)
return log_debug_errno(mount_fd, "ID-mapping supported open_tree failed for '%s' : %m", path);
return log_debug_errno(mount_fd, "Failed to open mount tree '%s', cannot determine if ID-mapping is supported: %m", path);
r = RET_NERRNO(mount_setattr(mount_fd, "", AT_EMPTY_PATH,
&(struct mount_attr) {
@ -554,7 +558,7 @@ int is_idmapping_supported(const char *path) {
if (ERRNO_IS_NEG_NOT_SUPPORTED(r) || ERRNO_IS_NEG_PRIVILEGE(r) || r == -EINVAL)
return false;
if (r < 0)
return log_debug_errno(r, "ID-mapping supported setattr failed for '%s' : %m", path);
return log_debug_errno(r, "Failed to set mount attribute to '%s', cannot determine if ID-mapping is supported: %m", path);
return true;
}

View File

@ -98,16 +98,11 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
}
}
#if HAVE_SYSV_COMPAT
else if (streq(key, "fastboot") && !value) {
log_warning("Please pass 'fsck.mode=skip' rather than 'fastboot' on the kernel command line.");
else if (streq(key, "fastboot") && !value)
arg_skip = true;
} else if (streq(key, "forcefsck") && !value) {
log_warning("Please pass 'fsck.mode=force' rather than 'forcefsck' on the kernel command line.");
else if (streq(key, "forcefsck") && !value)
arg_force = true;
}
#endif
return 0;
}

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

@ -108,6 +108,7 @@ static int help(int argc, char *argv[], void *userdata) {
" --ucode=PATH Path to microcode image file %7$s .ucode\n"
" --splash=PATH Path to splash bitmap file %7$s .splash\n"
" --dtb=PATH Path to DeviceTree file %7$s .dtb\n"
" --dtbauto=PATH Path to DeviceTree file for auto selection %7$s .dtbauto\n"
" --uname=PATH Path to 'uname -r' file %7$s .uname\n"
" --sbat=PATH Path to SBAT file %7$s .sbat\n"
" --pcrpkey=PATH Path to public key for PCR signatures %7$s .pcrpkey\n"

View File

@ -2280,10 +2280,9 @@ static int copy_devnode_one(const char *dest, const char *node, bool ignore_mkno
r = path_extract_directory(from, &parent);
if (r < 0)
return log_error_errno(r, "Failed to extract directory from %s: %m", from);
if (!path_equal(parent, "/dev/")) {
if (userns_mkdir(dest, parent, 0755, 0, 0) < 0)
r = userns_mkdir(dest, parent, 0755, 0, 0);
if (r < 0)
return log_error_errno(r, "Failed to create directory %s: %m", parent);
}
if (mknod(to, st.st_mode, st.st_rdev) < 0) {
r = -errno; /* Save the original error code. */
@ -4654,7 +4653,7 @@ static int nspawn_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t r
ucred = CMSG_FIND_DATA(&msghdr, SOL_SOCKET, SCM_CREDENTIALS, struct ucred);
if (!ucred || ucred->pid != inner_child_pid) {
log_debug("Received notify message without valid credentials. Ignoring.");
log_debug("Received notify message from process that is not the payload's PID 1. Ignoring.");
return 0;
}

View File

@ -36,14 +36,9 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
arg_skip = true;
else
log_warning("Invalid quotacheck.mode= value, ignoring: %s", value);
}
#if HAVE_SYSV_COMPAT
else if (streq(key, "forcequotacheck") && !value) {
log_warning("Please use 'quotacheck.mode=force' rather than 'forcequotacheck' on the kernel command line. Proceeding anyway.");
} else if (streq(key, "forcequotacheck") && !value)
arg_force = true;
}
#endif
return 0;
}

View File

@ -98,15 +98,17 @@ static int delete_dm(DeviceMapper *m) {
assert(major(m->devnum) != 0);
assert(m->path);
fd = open(m->path, O_RDONLY|O_CLOEXEC|O_NONBLOCK);
if (fd < 0)
log_debug_errno(errno, "Failed to open DM block device %s for syncing, ignoring: %m", m->path);
else {
(void) sync_with_progress(fd);
fd = safe_close(fd);
}
fd = open("/dev/mapper/control", O_RDWR|O_CLOEXEC);
if (fd < 0)
return -errno;
_cleanup_close_ int block_fd = open(m->path, O_RDONLY|O_CLOEXEC|O_NONBLOCK);
if (block_fd < 0)
log_debug_errno(errno, "Failed to open DM block device %s for syncing, ignoring: %m", m->path);
else
(void) sync_with_progress(block_fd);
return log_debug_errno(errno, "Failed to open /dev/mapper/control: %m");
return RET_NERRNO(ioctl(fd, DM_DEV_REMOVE, &(struct dm_ioctl) {
.version = {

View File

@ -211,10 +211,8 @@ static int sync_making_progress(unsigned long long *prev_dirty) {
continue;
errno = 0;
if (sscanf(line, "%*s %llu %*s", &ull) != 1) {
log_warning_errno(errno_or_else(EIO), "Failed to parse /proc/meminfo field, ignoring: %m");
return false;
}
if (sscanf(line, "%*s %llu %*s", &ull) != 1)
return log_warning_errno(errno_or_else(EIO), "Failed to parse /proc/meminfo field: %m");
val += ull;
}

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',

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

@ -960,10 +960,13 @@ exec $(systemctl cat systemd-networkd.service | sed -n '/^ExecStart=/ {{ s/^.*=/
# wait until devices got created
for _ in range(50):
out = subprocess.check_output(['ip', 'a', 'show', 'dev', self.if_router])
if b'state UP' in out and b'scope global' in out:
if subprocess.run(['ip', 'link', 'show', 'dev', self.if_router],
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL).returncode == 0:
break
time.sleep(0.1)
else:
subprocess.call(['ip', 'link', 'show', 'dev', self.if_router])
self.fail('Timed out waiting for {ifr} created.'.format(ifr=self.if_router))
def shutdown_iface(self):
'''Remove test interface and stop DHCP server'''