Compare commits
37 Commits
01962dba58
...
ca59b10a4d
Author | SHA1 | Date |
---|---|---|
![]() |
ca59b10a4d | |
![]() |
8e7ef6abb8 | |
![]() |
edc49209f1 | |
![]() |
2791b2bc3d | |
![]() |
7baf24c949 | |
![]() |
ce921df8d1 | |
![]() |
c96a5d9912 | |
![]() |
6858c1fd8b | |
![]() |
b1236ce38b | |
![]() |
710653d3bc | |
![]() |
d9826d303b | |
![]() |
52278e0634 | |
![]() |
4cf443e644 | |
![]() |
a85f73fa55 | |
![]() |
09ddaf2af3 | |
![]() |
919aeb666a | |
![]() |
1b25b88f82 | |
![]() |
5c6e6f5ad1 | |
![]() |
10d786458c | |
![]() |
d3af116afd | |
![]() |
32b5deb1b2 | |
![]() |
6d1a69d0f0 | |
![]() |
25a9bd72ef | |
![]() |
4100e0f207 | |
![]() |
765ffa12ee | |
![]() |
5f43554f90 | |
![]() |
70669fa2fe | |
![]() |
f92fac7e9b | |
![]() |
855800aaec | |
![]() |
f8b0277101 | |
![]() |
9ee08c8dce | |
![]() |
19aa8c0f0e | |
![]() |
3e8a4defa8 | |
![]() |
76a8f5ae4b | |
![]() |
413f6e0f56 | |
![]() |
f3ab293474 | |
![]() |
b595c40c72 |
|
@ -25,7 +25,7 @@ jobs:
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
|
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
|
||||||
- uses: systemd/mkosi@7e4ec15aee6b98300b2ee14265bc647a716a9f8a
|
- uses: systemd/mkosi@dbb4020beee2cdf250f93a425794f1cf8b0fe693
|
||||||
|
|
||||||
# Freeing up disk space with rm -rf can take multiple minutes. Since we don't need the extra free space
|
# Freeing up disk space with rm -rf can take multiple minutes. Since we don't need the extra free space
|
||||||
# immediately, we remove the files in the background. However, we first move them to a different location
|
# immediately, we remove the files in the background. However, we first move them to a different location
|
||||||
|
@ -90,7 +90,6 @@ jobs:
|
||||||
sudo mkosi sandbox -- \
|
sudo mkosi sandbox -- \
|
||||||
meson setup \
|
meson setup \
|
||||||
--buildtype=debugoptimized \
|
--buildtype=debugoptimized \
|
||||||
-Dintegration-tests=true \
|
|
||||||
build
|
build
|
||||||
|
|
||||||
- name: Build image
|
- name: Build image
|
||||||
|
@ -120,7 +119,8 @@ jobs:
|
||||||
meson test \
|
meson test \
|
||||||
-C build \
|
-C build \
|
||||||
--no-rebuild \
|
--no-rebuild \
|
||||||
--suite integration-tests \
|
--setup=integration \
|
||||||
|
--suite=integration-tests \
|
||||||
--print-errorlogs \
|
--print-errorlogs \
|
||||||
--no-stdsplit \
|
--no-stdsplit \
|
||||||
--num-processes "$(($(nproc) - 1))" \
|
--num-processes "$(($(nproc) - 1))" \
|
||||||
|
|
|
@ -120,7 +120,7 @@ jobs:
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
|
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
|
||||||
- uses: systemd/mkosi@7e4ec15aee6b98300b2ee14265bc647a716a9f8a
|
- uses: systemd/mkosi@dbb4020beee2cdf250f93a425794f1cf8b0fe693
|
||||||
|
|
||||||
# Freeing up disk space with rm -rf can take multiple minutes. Since we don't need the extra free space
|
# Freeing up disk space with rm -rf can take multiple minutes. Since we don't need the extra free space
|
||||||
# immediately, we remove the files in the background. However, we first move them to a different location
|
# immediately, we remove the files in the background. However, we first move them to a different location
|
||||||
|
@ -197,7 +197,6 @@ jobs:
|
||||||
sudo mkosi sandbox -- \
|
sudo mkosi sandbox -- \
|
||||||
meson setup \
|
meson setup \
|
||||||
--buildtype=debugoptimized \
|
--buildtype=debugoptimized \
|
||||||
-Dintegration-tests=true \
|
|
||||||
-Dbpf-framework=disabled \
|
-Dbpf-framework=disabled \
|
||||||
build
|
build
|
||||||
|
|
||||||
|
@ -233,7 +232,8 @@ jobs:
|
||||||
meson test \
|
meson test \
|
||||||
-C build \
|
-C build \
|
||||||
--no-rebuild \
|
--no-rebuild \
|
||||||
--suite integration-tests \
|
--setup=integration \
|
||||||
|
--suite=integration-tests \
|
||||||
--print-errorlogs \
|
--print-errorlogs \
|
||||||
--no-stdsplit \
|
--no-stdsplit \
|
||||||
--num-processes "$(($(nproc) - 1))" \
|
--num-processes "$(($(nproc) - 1))" \
|
||||||
|
|
3
NEWS
3
NEWS
|
@ -96,6 +96,9 @@ CHANGES WITH 258 in spe:
|
||||||
continue to work, update to xf86-input-evdev >= 2.11.0 and
|
continue to work, update to xf86-input-evdev >= 2.11.0 and
|
||||||
xf86-input-libinput >= 1.5.0 before updating to systemd >= 258.
|
xf86-input-libinput >= 1.5.0 before updating to systemd >= 258.
|
||||||
|
|
||||||
|
* The meson option 'integration-tests' has been deprecated, and will be
|
||||||
|
removed in a future release.
|
||||||
|
|
||||||
— <place>, <date>
|
— <place>, <date>
|
||||||
|
|
||||||
CHANGES WITH 257:
|
CHANGES WITH 257:
|
||||||
|
|
11
meson.build
11
meson.build
|
@ -13,6 +13,12 @@ project('systemd', 'c',
|
||||||
meson_version : '>= 0.62.0',
|
meson_version : '>= 0.62.0',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
add_test_setup(
|
||||||
|
'default',
|
||||||
|
exclude_suites : ['integration-tests'],
|
||||||
|
is_default : true,
|
||||||
|
)
|
||||||
|
|
||||||
project_major_version = meson.project_version().split('.')[0].split('~')[0]
|
project_major_version = meson.project_version().split('.')[0].split('~')[0]
|
||||||
if meson.project_version().contains('.')
|
if meson.project_version().contains('.')
|
||||||
project_minor_version = meson.project_version().split('.')[-1].split('~')[0]
|
project_minor_version = meson.project_version().split('.')[-1].split('~')[0]
|
||||||
|
@ -339,7 +345,6 @@ meson_build_sh = find_program('tools/meson-build.sh')
|
||||||
want_tests = get_option('tests')
|
want_tests = get_option('tests')
|
||||||
want_slow_tests = want_tests != 'false' and get_option('slow-tests')
|
want_slow_tests = want_tests != 'false' and get_option('slow-tests')
|
||||||
want_fuzz_tests = want_tests != 'false' and get_option('fuzz-tests')
|
want_fuzz_tests = want_tests != 'false' and get_option('fuzz-tests')
|
||||||
want_integration_tests = want_tests != 'false' and get_option('integration-tests')
|
|
||||||
install_tests = want_tests != 'false' and get_option('install-tests')
|
install_tests = want_tests != 'false' and get_option('install-tests')
|
||||||
|
|
||||||
if add_languages('cpp', native : false, required : fuzzer_build)
|
if add_languages('cpp', native : false, required : fuzzer_build)
|
||||||
|
@ -2661,10 +2666,6 @@ endif
|
||||||
#####################################################################
|
#####################################################################
|
||||||
|
|
||||||
mkosi = find_program('mkosi', required : false)
|
mkosi = find_program('mkosi', required : false)
|
||||||
if want_integration_tests and not mkosi.found()
|
|
||||||
error('Could not find mkosi which is required to run the integration tests')
|
|
||||||
endif
|
|
||||||
|
|
||||||
mkosi_depends = public_programs
|
mkosi_depends = public_programs
|
||||||
|
|
||||||
foreach executable : ['systemd-journal-remote', 'systemd-sbsign', 'systemd-keyutil']
|
foreach executable : ['systemd-journal-remote', 'systemd-sbsign', 'systemd-keyutil']
|
||||||
|
|
|
@ -509,7 +509,7 @@ option('install-tests', type : 'boolean', value : false,
|
||||||
description : 'install test executables')
|
description : 'install test executables')
|
||||||
option('log-message-verification', type : 'feature', deprecated : { 'true' : 'enabled', 'false' : 'disabled' },
|
option('log-message-verification', type : 'feature', deprecated : { 'true' : 'enabled', 'false' : 'disabled' },
|
||||||
description : 'do fake printf() calls to verify format strings')
|
description : 'do fake printf() calls to verify format strings')
|
||||||
option('integration-tests', type : 'boolean', value : false,
|
option('integration-tests', type : 'boolean', value : false, deprecated : true,
|
||||||
description : 'run the integration tests')
|
description : 'run the integration tests')
|
||||||
|
|
||||||
option('ok-color', type : 'combo',
|
option('ok-color', type : 'combo',
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||||
|
|
||||||
[Config]
|
[Config]
|
||||||
MinimumVersion=commit:7e4ec15aee6b98300b2ee14265bc647a716a9f8a
|
MinimumVersion=commit:dbb4020beee2cdf250f93a425794f1cf8b0fe693
|
||||||
Dependencies=
|
Dependencies=
|
||||||
exitrd
|
exitrd
|
||||||
initrd
|
initrd
|
||||||
|
|
|
@ -77,6 +77,20 @@ ENV{DDC_DEVICE}=="?*", TAG+="uaccess"
|
||||||
# media player raw devices (for user-mode drivers, Android SDK, etc.)
|
# media player raw devices (for user-mode drivers, Android SDK, etc.)
|
||||||
SUBSYSTEM=="usb", ENV{ID_MEDIA_PLAYER}=="?*", TAG+="uaccess"
|
SUBSYSTEM=="usb", ENV{ID_MEDIA_PLAYER}=="?*", TAG+="uaccess"
|
||||||
|
|
||||||
|
# Android devices (ADB DbC, ADB, Fastboot)
|
||||||
|
# Used to interact with devices over Android Debug Bridge and Fastboot protocols, see:
|
||||||
|
# * https://developer.android.com/tools/adb
|
||||||
|
# * https://source.android.com/docs/setup/test/running
|
||||||
|
# * https://source.android.com/docs/setup/test/flash
|
||||||
|
#
|
||||||
|
# The bInterfaceClass and bInterfaceSubClass used are documented in source code here:
|
||||||
|
# * https://android.googlesource.com/platform/packages/modules/adb/+/d0db47dcdf941673f405e1095e6ffb5e565902e5/adb.h#199
|
||||||
|
# * https://android.googlesource.com/platform/system/core/+/7199051aaf0ddfa2849650933119307327d8669c/fastboot/fastboot.cpp#244
|
||||||
|
#
|
||||||
|
# Since it's using a generic vendor specific interface class, this can potentially result
|
||||||
|
# in a rare case where non-ADB/Fastboot device ends up with an ID_DEBUG_APPLIANCE="android".
|
||||||
|
SUBSYSTEM=="usb", ENV{ID_USB_INTERFACES}=="*:dc0201:*|*:ff4201:*|*:ff4203:*", ENV{ID_DEBUG_APPLIANCE}="android"
|
||||||
|
|
||||||
# software-defined radio communication devices
|
# software-defined radio communication devices
|
||||||
ENV{ID_SOFTWARE_RADIO}=="?*", TAG+="uaccess"
|
ENV{ID_SOFTWARE_RADIO}=="?*", TAG+="uaccess"
|
||||||
|
|
||||||
|
@ -111,4 +125,7 @@ SUBSYSTEM=="hidraw", ENV{ID_HARDWARE_WALLET}=="1", TAG+="uaccess"
|
||||||
# As defined in https://en.wikipedia.org/wiki/3Dconnexion
|
# As defined in https://en.wikipedia.org/wiki/3Dconnexion
|
||||||
SUBSYSTEM=="hidraw", ENV{ID_INPUT_3D_MOUSE}=="1", TAG+="uaccess"
|
SUBSYSTEM=="hidraw", ENV{ID_INPUT_3D_MOUSE}=="1", TAG+="uaccess"
|
||||||
|
|
||||||
|
# Debug interfaces (e.g. Android Debug Bridge)
|
||||||
|
ENV{ID_DEBUG_APPLIANCE}=="?*", TAG+="uaccess"
|
||||||
|
|
||||||
LABEL="uaccess_end"
|
LABEL="uaccess_end"
|
||||||
|
|
|
@ -31,7 +31,7 @@ static void log_syntax_callback(const char *unit, int level, void *userdata) {
|
||||||
|
|
||||||
r = set_put_strdup(s, unit);
|
r = set_put_strdup(s, unit);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
set_free_free(*s);
|
set_free(*s);
|
||||||
*s = POINTER_MAX;
|
*s = POINTER_MAX;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -265,7 +265,7 @@ static int verify_unit(Unit *u, bool check_man, const char *root) {
|
||||||
static void set_destroy_ignore_pointer_max(Set **s) {
|
static void set_destroy_ignore_pointer_max(Set **s) {
|
||||||
if (*s == POINTER_MAX)
|
if (*s == POINTER_MAX)
|
||||||
return;
|
return;
|
||||||
set_free_free(*s);
|
set_free(*s);
|
||||||
}
|
}
|
||||||
|
|
||||||
int verify_units(
|
int verify_units(
|
||||||
|
|
|
@ -1001,13 +1001,13 @@ int fd_verify_safe_flags_full(int fd, int extra_flags) {
|
||||||
if (flags < 0)
|
if (flags < 0)
|
||||||
return -errno;
|
return -errno;
|
||||||
|
|
||||||
unexpected_flags = flags & ~(O_ACCMODE|O_NOFOLLOW|RAW_O_LARGEFILE|extra_flags);
|
unexpected_flags = flags & ~(O_ACCMODE_STRICT|O_NOFOLLOW|RAW_O_LARGEFILE|extra_flags);
|
||||||
if (unexpected_flags != 0)
|
if (unexpected_flags != 0)
|
||||||
return log_debug_errno(SYNTHETIC_ERRNO(EREMOTEIO),
|
return log_debug_errno(SYNTHETIC_ERRNO(EREMOTEIO),
|
||||||
"Unexpected flags set for extrinsic fd: 0%o",
|
"Unexpected flags set for extrinsic fd: 0%o",
|
||||||
(unsigned) unexpected_flags);
|
(unsigned) unexpected_flags);
|
||||||
|
|
||||||
return flags & (O_ACCMODE | extra_flags); /* return the flags variable, but remove the noise */
|
return flags & (O_ACCMODE_STRICT | extra_flags); /* return the flags variable, but remove the noise */
|
||||||
}
|
}
|
||||||
|
|
||||||
int read_nr_open(void) {
|
int read_nr_open(void) {
|
||||||
|
@ -1132,7 +1132,7 @@ int fds_are_same_mount(int fd1, int fd2) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* accmode_to_string(int flags) {
|
const char* accmode_to_string(int flags) {
|
||||||
switch (flags & O_ACCMODE) {
|
switch (flags & O_ACCMODE_STRICT) {
|
||||||
case O_RDONLY:
|
case O_RDONLY:
|
||||||
return "ro";
|
return "ro";
|
||||||
case O_WRONLY:
|
case O_WRONLY:
|
||||||
|
|
|
@ -1036,7 +1036,7 @@ int open_mkdir_at_full(int dirfd, const char *path, int flags, XOpenFlags xopen_
|
||||||
|
|
||||||
if (flags & ~(O_RDONLY|O_CLOEXEC|O_DIRECTORY|O_EXCL|O_NOATIME|O_NOFOLLOW|O_PATH))
|
if (flags & ~(O_RDONLY|O_CLOEXEC|O_DIRECTORY|O_EXCL|O_NOATIME|O_NOFOLLOW|O_PATH))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if ((flags & O_ACCMODE) != O_RDONLY)
|
if ((flags & O_ACCMODE_STRICT) != O_RDONLY)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
/* Note that O_DIRECTORY|O_NOFOLLOW is implied, but we allow specifying it anyway. The following
|
/* Note that O_DIRECTORY|O_NOFOLLOW is implied, but we allow specifying it anyway. The following
|
||||||
|
|
|
@ -90,6 +90,8 @@ OrderedHashmap* _ordered_hashmap_new(const struct hash_ops *hash_ops HASHMAP_DE
|
||||||
|
|
||||||
#define hashmap_free_and_replace(a, b) \
|
#define hashmap_free_and_replace(a, b) \
|
||||||
free_and_replace_full(a, b, hashmap_free)
|
free_and_replace_full(a, b, hashmap_free)
|
||||||
|
#define ordered_hashmap_free_and_replace(a, b) \
|
||||||
|
free_and_replace_full(a, b, ordered_hashmap_free)
|
||||||
|
|
||||||
HashmapBase* _hashmap_free(HashmapBase *h, free_func_t default_free_key, free_func_t default_free_value);
|
HashmapBase* _hashmap_free(HashmapBase *h, free_func_t default_free_key, free_func_t default_free_value);
|
||||||
static inline Hashmap* hashmap_free(Hashmap *h) {
|
static inline Hashmap* hashmap_free(Hashmap *h) {
|
||||||
|
|
|
@ -43,3 +43,9 @@
|
||||||
#ifndef AT_HANDLE_FID
|
#ifndef AT_HANDLE_FID
|
||||||
#define AT_HANDLE_FID AT_REMOVEDIR
|
#define AT_HANDLE_FID AT_REMOVEDIR
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* On musl, O_ACCMODE is defined as (03|O_SEARCH), unlike glibc which defines it as
|
||||||
|
* (O_RDONLY|O_WRONLY|O_RDWR). Additionally, O_SEARCH is simply defined as O_PATH. This changes the behaviour
|
||||||
|
* of O_ACCMODE in certain situations, which we don't want. This definition is copied from glibc and works
|
||||||
|
* around the problems with musl's definition. */
|
||||||
|
#define O_ACCMODE_STRICT (O_RDONLY|O_WRONLY|O_RDWR)
|
||||||
|
|
|
@ -267,7 +267,7 @@ static int acquire_path(const char *path, int flags, mode_t mode) {
|
||||||
|
|
||||||
assert(path);
|
assert(path);
|
||||||
|
|
||||||
if (IN_SET(flags & O_ACCMODE, O_WRONLY, O_RDWR))
|
if (IN_SET(flags & O_ACCMODE_STRICT, O_WRONLY, O_RDWR))
|
||||||
flags |= O_CREAT;
|
flags |= O_CREAT;
|
||||||
|
|
||||||
fd = open(path, flags|O_NOCTTY, mode);
|
fd = open(path, flags|O_NOCTTY, mode);
|
||||||
|
@ -291,9 +291,9 @@ static int acquire_path(const char *path, int flags, mode_t mode) {
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
if ((flags & O_ACCMODE) == O_RDONLY)
|
if ((flags & O_ACCMODE_STRICT) == O_RDONLY)
|
||||||
r = shutdown(fd, SHUT_WR);
|
r = shutdown(fd, SHUT_WR);
|
||||||
else if ((flags & O_ACCMODE) == O_WRONLY)
|
else if ((flags & O_ACCMODE_STRICT) == O_WRONLY)
|
||||||
r = shutdown(fd, SHUT_RD);
|
r = shutdown(fd, SHUT_RD);
|
||||||
else
|
else
|
||||||
r = 0;
|
r = 0;
|
||||||
|
|
|
@ -38,11 +38,10 @@ static VacuumCandidate* vacuum_candidate_free(VacuumCandidate *c) {
|
||||||
}
|
}
|
||||||
DEFINE_TRIVIAL_CLEANUP_FUNC(VacuumCandidate*, vacuum_candidate_free);
|
DEFINE_TRIVIAL_CLEANUP_FUNC(VacuumCandidate*, vacuum_candidate_free);
|
||||||
|
|
||||||
static Hashmap* vacuum_candidate_hashmap_free(Hashmap *h) {
|
DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
|
||||||
return hashmap_free_with_destructor(h, vacuum_candidate_free);
|
vacuum_candidate_hash_ops,
|
||||||
}
|
void, trivial_hash_func, trivial_compare_func,
|
||||||
|
VacuumCandidate, vacuum_candidate_free);
|
||||||
DEFINE_TRIVIAL_CLEANUP_FUNC(Hashmap*, vacuum_candidate_hashmap_free);
|
|
||||||
|
|
||||||
static int uid_from_file_name(const char *filename, uid_t *uid) {
|
static int uid_from_file_name(const char *filename, uid_t *uid) {
|
||||||
const char *p, *e, *u;
|
const char *p, *e, *u;
|
||||||
|
@ -141,7 +140,7 @@ int coredump_vacuum(int exclude_fd, uint64_t keep_free, uint64_t max_use) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
_cleanup_(vacuum_candidate_hashmap_freep) Hashmap *h = NULL;
|
_cleanup_hashmap_free_ Hashmap *h = NULL;
|
||||||
VacuumCandidate *worst = NULL;
|
VacuumCandidate *worst = NULL;
|
||||||
uint64_t sum = 0;
|
uint64_t sum = 0;
|
||||||
|
|
||||||
|
@ -171,10 +170,6 @@ int coredump_vacuum(int exclude_fd, uint64_t keep_free, uint64_t max_use) {
|
||||||
if (exclude_fd >= 0 && stat_inode_same(&exclude_st, &st))
|
if (exclude_fd >= 0 && stat_inode_same(&exclude_st, &st))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
r = hashmap_ensure_allocated(&h, NULL);
|
|
||||||
if (r < 0)
|
|
||||||
return log_oom();
|
|
||||||
|
|
||||||
t = timespec_load(&st.st_mtim);
|
t = timespec_load(&st.st_mtim);
|
||||||
|
|
||||||
c = hashmap_get(h, UID_TO_PTR(uid));
|
c = hashmap_get(h, UID_TO_PTR(uid));
|
||||||
|
@ -197,7 +192,7 @@ int coredump_vacuum(int exclude_fd, uint64_t keep_free, uint64_t max_use) {
|
||||||
return r;
|
return r;
|
||||||
n->oldest_mtime = t;
|
n->oldest_mtime = t;
|
||||||
|
|
||||||
r = hashmap_put(h, UID_TO_PTR(uid), n);
|
r = hashmap_ensure_put(&h, &vacuum_candidate_hash_ops, UID_TO_PTR(uid), n);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_oom();
|
return log_oom();
|
||||||
|
|
||||||
|
|
|
@ -122,8 +122,8 @@
|
||||||
# define _nonnull_if_nonzero_(p, n)
|
# define _nonnull_if_nonzero_(p, n)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define XSTRINGIFY(x) #x
|
#define XSTRINGIFY(...) #__VA_ARGS__
|
||||||
#define STRINGIFY(x) XSTRINGIFY(x)
|
#define STRINGIFY(...) XSTRINGIFY(__VA_ARGS__)
|
||||||
|
|
||||||
/* C23 changed char8_t from char to unsigned char, hence we cannot pass u8 literals to e.g. fputs() without
|
/* C23 changed char8_t from char to unsigned char, hence we cannot pass u8 literals to e.g. fputs() without
|
||||||
* casting. Let's introduce our own way to declare UTF-8 literals, which casts u8 literals to const char*. */
|
* casting. Let's introduce our own way to declare UTF-8 literals, which casts u8 literals to const char*. */
|
||||||
|
|
|
@ -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
|
|
@ -91,7 +91,7 @@ static void device_unref_many(sd_device **devices, size_t n) {
|
||||||
static void device_enumerator_unref_devices(sd_device_enumerator *enumerator) {
|
static void device_enumerator_unref_devices(sd_device_enumerator *enumerator) {
|
||||||
assert(enumerator);
|
assert(enumerator);
|
||||||
|
|
||||||
hashmap_clear_with_destructor(enumerator->devices_by_syspath, sd_device_unref);
|
hashmap_clear(enumerator->devices_by_syspath);
|
||||||
device_unref_many(enumerator->devices, enumerator->n_devices);
|
device_unref_many(enumerator->devices, enumerator->n_devices);
|
||||||
enumerator->devices = mfree(enumerator->devices);
|
enumerator->devices = mfree(enumerator->devices);
|
||||||
enumerator->n_devices = 0;
|
enumerator->n_devices = 0;
|
||||||
|
@ -471,6 +471,11 @@ failed:
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
|
||||||
|
device_hash_ops_by_syspath,
|
||||||
|
char, path_hash_func, path_compare,
|
||||||
|
sd_device, sd_device_unref);
|
||||||
|
|
||||||
int device_enumerator_add_device(sd_device_enumerator *enumerator, sd_device *device) {
|
int device_enumerator_add_device(sd_device_enumerator *enumerator, sd_device *device) {
|
||||||
const char *syspath;
|
const char *syspath;
|
||||||
int r;
|
int r;
|
||||||
|
@ -482,7 +487,7 @@ int device_enumerator_add_device(sd_device_enumerator *enumerator, sd_device *de
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
r = hashmap_ensure_put(&enumerator->devices_by_syspath, &string_hash_ops, syspath, device);
|
r = hashmap_ensure_put(&enumerator->devices_by_syspath, &device_hash_ops_by_syspath, syspath, device);
|
||||||
if (IN_SET(r, -EEXIST, 0))
|
if (IN_SET(r, -EEXIST, 0))
|
||||||
return 0;
|
return 0;
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
|
|
|
@ -692,8 +692,8 @@ int device_clone_with_db(sd_device *device, sd_device **ret) {
|
||||||
void device_cleanup_tags(sd_device *device) {
|
void device_cleanup_tags(sd_device *device) {
|
||||||
assert(device);
|
assert(device);
|
||||||
|
|
||||||
device->all_tags = set_free_free(device->all_tags);
|
device->all_tags = set_free(device->all_tags);
|
||||||
device->current_tags = set_free_free(device->current_tags);
|
device->current_tags = set_free(device->current_tags);
|
||||||
device->property_tags_outdated = true;
|
device->property_tags_outdated = true;
|
||||||
device->tags_generation++;
|
device->tags_generation++;
|
||||||
}
|
}
|
||||||
|
@ -701,7 +701,7 @@ void device_cleanup_tags(sd_device *device) {
|
||||||
void device_cleanup_devlinks(sd_device *device) {
|
void device_cleanup_devlinks(sd_device *device) {
|
||||||
assert(device);
|
assert(device);
|
||||||
|
|
||||||
set_free_free(device->devlinks);
|
set_free(device->devlinks);
|
||||||
device->devlinks = NULL;
|
device->devlinks = NULL;
|
||||||
device->property_devlinks_outdated = true;
|
device->property_devlinks_outdated = true;
|
||||||
device->devlinks_generation++;
|
device->devlinks_generation++;
|
||||||
|
|
|
@ -98,7 +98,7 @@ DEFINE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
|
||||||
JournalFile, journal_file_close);
|
JournalFile, journal_file_close);
|
||||||
|
|
||||||
static int mmap_prot_from_open_flags(int flags) {
|
static int mmap_prot_from_open_flags(int flags) {
|
||||||
switch (flags & O_ACCMODE) {
|
switch (flags & O_ACCMODE_STRICT) {
|
||||||
case O_RDONLY:
|
case O_RDONLY:
|
||||||
return PROT_READ;
|
return PROT_READ;
|
||||||
case O_WRONLY:
|
case O_WRONLY:
|
||||||
|
@ -4075,10 +4075,10 @@ int journal_file_open(
|
||||||
assert(mmap_cache);
|
assert(mmap_cache);
|
||||||
assert(ret);
|
assert(ret);
|
||||||
|
|
||||||
if (!IN_SET((open_flags & O_ACCMODE), O_RDONLY, O_RDWR))
|
if (!IN_SET((open_flags & O_ACCMODE_STRICT), O_RDONLY, O_RDWR))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if ((open_flags & O_ACCMODE) == O_RDONLY && FLAGS_SET(open_flags, O_CREAT))
|
if ((open_flags & O_ACCMODE_STRICT) == O_RDONLY && FLAGS_SET(open_flags, O_CREAT))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (fname && (open_flags & O_CREAT) && !endswith(fname, ".journal"))
|
if (fname && (open_flags & O_CREAT) && !endswith(fname, ".journal"))
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <sys/uio.h>
|
#include <sys/uio.h>
|
||||||
|
|
||||||
|
@ -15,6 +14,7 @@
|
||||||
#include "compress.h"
|
#include "compress.h"
|
||||||
#include "hashmap.h"
|
#include "hashmap.h"
|
||||||
#include "journal-def.h"
|
#include "journal-def.h"
|
||||||
|
#include "missing_fcntl.h"
|
||||||
#include "mmap-cache.h"
|
#include "mmap-cache.h"
|
||||||
#include "sparse-endian.h"
|
#include "sparse-endian.h"
|
||||||
#include "time-util.h"
|
#include "time-util.h"
|
||||||
|
@ -391,5 +391,5 @@ static inline uint32_t COMPRESSION_TO_HEADER_INCOMPATIBLE_FLAG(Compression c) {
|
||||||
|
|
||||||
static inline bool journal_file_writable(JournalFile *f) {
|
static inline bool journal_file_writable(JournalFile *f) {
|
||||||
assert(f);
|
assert(f);
|
||||||
return (f->open_flags & O_ACCMODE) != O_RDONLY;
|
return (f->open_flags & O_ACCMODE_STRICT) != O_RDONLY;
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,11 +46,21 @@ static GenericNetlinkFamily *genl_family_free(GenericNetlinkFamily *f) {
|
||||||
|
|
||||||
DEFINE_TRIVIAL_CLEANUP_FUNC(GenericNetlinkFamily*, genl_family_free);
|
DEFINE_TRIVIAL_CLEANUP_FUNC(GenericNetlinkFamily*, genl_family_free);
|
||||||
|
|
||||||
|
DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
|
||||||
|
genl_family_hash_ops_by_name,
|
||||||
|
char, string_hash_func, string_compare_func,
|
||||||
|
GenericNetlinkFamily, genl_family_free);
|
||||||
|
|
||||||
|
DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
|
||||||
|
genl_family_hash_ops_by_id,
|
||||||
|
void, trivial_hash_func, trivial_compare_func,
|
||||||
|
GenericNetlinkFamily, genl_family_free);
|
||||||
|
|
||||||
void genl_clear_family(sd_netlink *nl) {
|
void genl_clear_family(sd_netlink *nl) {
|
||||||
assert(nl);
|
assert(nl);
|
||||||
|
|
||||||
nl->genl_family_by_name = hashmap_free_with_destructor(nl->genl_family_by_name, genl_family_free);
|
nl->genl_family_by_name = hashmap_free(nl->genl_family_by_name);
|
||||||
nl->genl_family_by_id = hashmap_free_with_destructor(nl->genl_family_by_id, genl_family_free);
|
nl->genl_family_by_id = hashmap_free(nl->genl_family_by_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int genl_family_new_unsupported(
|
static int genl_family_new_unsupported(
|
||||||
|
@ -80,7 +90,7 @@ static int genl_family_new_unsupported(
|
||||||
if (!f->name)
|
if (!f->name)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
r = hashmap_ensure_put(&nl->genl_family_by_name, &string_hash_ops, f->name, f);
|
r = hashmap_ensure_put(&nl->genl_family_by_name, &genl_family_hash_ops_by_name, f->name, f);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
@ -190,11 +200,11 @@ static int genl_family_new(
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = hashmap_ensure_put(&nl->genl_family_by_id, NULL, UINT_TO_PTR(f->id), f);
|
r = hashmap_ensure_put(&nl->genl_family_by_id, &genl_family_hash_ops_by_id, UINT_TO_PTR(f->id), f);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
r = hashmap_ensure_put(&nl->genl_family_by_name, &string_hash_ops, f->name, f);
|
r = hashmap_ensure_put(&nl->genl_family_by_name, &genl_family_hash_ops_by_name, f->name, f);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
hashmap_remove(nl->genl_family_by_id, UINT_TO_PTR(f->id));
|
hashmap_remove(nl->genl_family_by_id, UINT_TO_PTR(f->id));
|
||||||
return r;
|
return r;
|
||||||
|
|
|
@ -436,7 +436,11 @@ _public_ struct udev_device *udev_device_get_parent(struct udev_device *udev_dev
|
||||||
*
|
*
|
||||||
* Returns: a new udev device, or #NULL if no matching parent exists.
|
* Returns: a new udev device, or #NULL if no matching parent exists.
|
||||||
**/
|
**/
|
||||||
_public_ struct udev_device *udev_device_get_parent_with_subsystem_devtype(struct udev_device *udev_device, const char *subsystem, const char *devtype) {
|
_public_ struct udev_device* udev_device_get_parent_with_subsystem_devtype(
|
||||||
|
struct udev_device *udev_device,
|
||||||
|
const char *subsystem,
|
||||||
|
const char *devtype) {
|
||||||
|
|
||||||
sd_device *parent;
|
sd_device *parent;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
#include "hashmap.h"
|
#include "hashmap.h"
|
||||||
#include "libudev-list-internal.h"
|
#include "libudev-list-internal.h"
|
||||||
#include "list.h"
|
#include "list.h"
|
||||||
#include "sort-util.h"
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SECTION:libudev-list
|
* SECTION:libudev-list
|
||||||
|
@ -54,6 +53,11 @@ static struct udev_list_entry *udev_list_entry_free(struct udev_list_entry *entr
|
||||||
|
|
||||||
DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev_list_entry*, udev_list_entry_free);
|
DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev_list_entry*, udev_list_entry_free);
|
||||||
|
|
||||||
|
DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
|
||||||
|
udev_list_entry_hash_ops,
|
||||||
|
char, string_hash_func, string_compare_func,
|
||||||
|
struct udev_list_entry, udev_list_entry_free);
|
||||||
|
|
||||||
struct udev_list* udev_list_new(bool unique) {
|
struct udev_list* udev_list_new(bool unique) {
|
||||||
struct udev_list *list;
|
struct udev_list *list;
|
||||||
|
|
||||||
|
@ -68,36 +72,26 @@ struct udev_list *udev_list_new(bool unique) {
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct udev_list_entry *udev_list_entry_add(struct udev_list *list, const char *_name, const char *_value) {
|
struct udev_list_entry* udev_list_entry_add(struct udev_list *list, const char *name, const char *value) {
|
||||||
_cleanup_(udev_list_entry_freep) struct udev_list_entry *entry = NULL;
|
_cleanup_(udev_list_entry_freep) struct udev_list_entry *entry = NULL;
|
||||||
_cleanup_free_ char *name = NULL, *value = NULL;
|
|
||||||
|
|
||||||
assert(list);
|
assert(list);
|
||||||
assert(_name);
|
assert(name);
|
||||||
|
|
||||||
name = strdup(_name);
|
entry = new0(struct udev_list_entry, 1);
|
||||||
if (!name)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
if (_value) {
|
|
||||||
value = strdup(_value);
|
|
||||||
if (!value)
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
entry = new(struct udev_list_entry, 1);
|
|
||||||
if (!entry)
|
if (!entry)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
*entry = (struct udev_list_entry) {
|
if (strdup_to(&entry->name, name) < 0)
|
||||||
.name = TAKE_PTR(name),
|
return NULL;
|
||||||
.value = TAKE_PTR(value),
|
|
||||||
};
|
if (strdup_to(&entry->value, value) < 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
if (list->unique) {
|
if (list->unique) {
|
||||||
udev_list_entry_free(hashmap_get(list->unique_entries, entry->name));
|
udev_list_entry_free(hashmap_get(list->unique_entries, entry->name));
|
||||||
|
|
||||||
if (hashmap_ensure_put(&list->unique_entries, &string_hash_ops, entry->name, entry) < 0)
|
if (hashmap_ensure_put(&list->unique_entries, &udev_list_entry_hash_ops, entry->name, entry) < 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
list->uptodate = false;
|
list->uptodate = false;
|
||||||
|
@ -115,7 +109,7 @@ void udev_list_cleanup(struct udev_list *list) {
|
||||||
|
|
||||||
if (list->unique) {
|
if (list->unique) {
|
||||||
list->uptodate = false;
|
list->uptodate = false;
|
||||||
hashmap_clear_with_destructor(list->unique_entries, udev_list_entry_free);
|
hashmap_clear(list->unique_entries);
|
||||||
} else
|
} else
|
||||||
LIST_FOREACH(entries, i, list->entries)
|
LIST_FOREACH(entries, i, list->entries)
|
||||||
udev_list_entry_free(i);
|
udev_list_entry_free(i);
|
||||||
|
@ -131,10 +125,6 @@ struct udev_list *udev_list_free(struct udev_list *list) {
|
||||||
return mfree(list);
|
return mfree(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int udev_list_entry_compare_func(struct udev_list_entry * const *a, struct udev_list_entry * const *b) {
|
|
||||||
return strcmp((*a)->name, (*b)->name);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct udev_list_entry* udev_list_get_entry(struct udev_list *list) {
|
struct udev_list_entry* udev_list_get_entry(struct udev_list *list) {
|
||||||
if (!list)
|
if (!list)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -151,18 +141,10 @@ struct udev_list_entry *udev_list_get_entry(struct udev_list *list) {
|
||||||
LIST_PREPEND(entries, list->entries, hashmap_first(list->unique_entries));
|
LIST_PREPEND(entries, list->entries, hashmap_first(list->unique_entries));
|
||||||
else {
|
else {
|
||||||
_cleanup_free_ struct udev_list_entry **buf = NULL;
|
_cleanup_free_ struct udev_list_entry **buf = NULL;
|
||||||
struct udev_list_entry *entry, **p;
|
|
||||||
|
|
||||||
buf = new(struct udev_list_entry *, n);
|
if (hashmap_dump_sorted(list->unique_entries, (void***) &buf, /* ret_n = */ NULL) < 0)
|
||||||
if (!buf)
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
p = buf;
|
|
||||||
HASHMAP_FOREACH(entry, list->unique_entries)
|
|
||||||
*p++ = entry;
|
|
||||||
|
|
||||||
typesafe_qsort(buf, n, udev_list_entry_compare_func);
|
|
||||||
|
|
||||||
for (size_t j = n; j > 0; j--)
|
for (size_t j = n; j > 0; j--)
|
||||||
LIST_PREPEND(entries, list->entries, buf[j-1]);
|
LIST_PREPEND(entries, list->entries, buf[j-1]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -155,8 +155,11 @@ _public_ int udev_queue_get_queue_is_empty(struct udev_queue *udev_queue) {
|
||||||
*
|
*
|
||||||
* Returns: a flag indicating if udev is currently handling events.
|
* Returns: a flag indicating if udev is currently handling events.
|
||||||
**/
|
**/
|
||||||
_public_ int udev_queue_get_seqnum_sequence_is_finished(struct udev_queue *udev_queue,
|
_public_ int udev_queue_get_seqnum_sequence_is_finished(
|
||||||
unsigned long long int start, unsigned long long int end) {
|
struct udev_queue *udev_queue,
|
||||||
|
unsigned long long int start,
|
||||||
|
unsigned long long int end) {
|
||||||
|
|
||||||
return udev_queue_is_empty() > 0;
|
return udev_queue_is_empty() > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -125,8 +125,12 @@ _public_ struct udev *udev_unref(struct udev *udev) {
|
||||||
_public_ void udev_set_log_fn(
|
_public_ void udev_set_log_fn(
|
||||||
struct udev *udev,
|
struct udev *udev,
|
||||||
void (*log_fn)(struct udev *udev,
|
void (*log_fn)(struct udev *udev,
|
||||||
int priority, const char *file, int line, const char *fn,
|
int priority,
|
||||||
const char *format, va_list args)) {
|
const char *file,
|
||||||
|
int line,
|
||||||
|
const char *fn,
|
||||||
|
const char *format,
|
||||||
|
va_list args)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,10 +21,15 @@ struct udev;
|
||||||
struct udev* udev_ref(struct udev *udev);
|
struct udev* udev_ref(struct udev *udev);
|
||||||
struct udev* udev_unref(struct udev *udev);
|
struct udev* udev_unref(struct udev *udev);
|
||||||
struct udev* udev_new(void);
|
struct udev* udev_new(void);
|
||||||
void udev_set_log_fn(struct udev *udev,
|
void udev_set_log_fn(
|
||||||
|
struct udev *udev,
|
||||||
void (*log_fn)(struct udev *udev,
|
void (*log_fn)(struct udev *udev,
|
||||||
int priority, const char *file, int line, const char *fn,
|
int priority,
|
||||||
const char *format, va_list args)) __attribute__((__deprecated__));
|
const char *file,
|
||||||
|
int line,
|
||||||
|
const char *fn,
|
||||||
|
const char *format,
|
||||||
|
va_list args)) __attribute__((__deprecated__));
|
||||||
int udev_get_log_priority(struct udev *udev) __attribute__((__deprecated__));
|
int udev_get_log_priority(struct udev *udev) __attribute__((__deprecated__));
|
||||||
void udev_set_log_priority(struct udev *udev, int priority) __attribute__((__deprecated__));
|
void udev_set_log_priority(struct udev *udev, int priority) __attribute__((__deprecated__));
|
||||||
void* udev_get_userdata(struct udev *udev);
|
void* udev_get_userdata(struct udev *udev);
|
||||||
|
@ -68,8 +73,10 @@ struct udev_device *udev_device_new_from_device_id(struct udev *udev, const char
|
||||||
struct udev_device* udev_device_new_from_environment(struct udev *udev);
|
struct udev_device* udev_device_new_from_environment(struct udev *udev);
|
||||||
/* udev_device_get_parent_*() does not take a reference on the returned device, it is automatically unref'd with the parent */
|
/* udev_device_get_parent_*() does not take a reference on the returned device, it is automatically unref'd with the parent */
|
||||||
struct udev_device* udev_device_get_parent(struct udev_device *udev_device);
|
struct udev_device* udev_device_get_parent(struct udev_device *udev_device);
|
||||||
struct udev_device *udev_device_get_parent_with_subsystem_devtype(struct udev_device *udev_device,
|
struct udev_device* udev_device_get_parent_with_subsystem_devtype(
|
||||||
const char *subsystem, const char *devtype);
|
struct udev_device *udev_device,
|
||||||
|
const char *subsystem,
|
||||||
|
const char *devtype);
|
||||||
/* retrieve device properties */
|
/* retrieve device properties */
|
||||||
const char* udev_device_get_devpath(struct udev_device *udev_device);
|
const char* udev_device_get_devpath(struct udev_device *udev_device);
|
||||||
const char* udev_device_get_subsystem(struct udev_device *udev_device);
|
const char* udev_device_get_subsystem(struct udev_device *udev_device);
|
||||||
|
@ -112,8 +119,10 @@ int udev_monitor_set_receive_buffer_size(struct udev_monitor *udev_monitor, int
|
||||||
int udev_monitor_get_fd(struct udev_monitor *udev_monitor);
|
int udev_monitor_get_fd(struct udev_monitor *udev_monitor);
|
||||||
struct udev_device* udev_monitor_receive_device(struct udev_monitor *udev_monitor);
|
struct udev_device* udev_monitor_receive_device(struct udev_monitor *udev_monitor);
|
||||||
/* in-kernel socket filters to select messages that get delivered to a listener */
|
/* in-kernel socket filters to select messages that get delivered to a listener */
|
||||||
int udev_monitor_filter_add_match_subsystem_devtype(struct udev_monitor *udev_monitor,
|
int udev_monitor_filter_add_match_subsystem_devtype(
|
||||||
const char *subsystem, const char *devtype);
|
struct udev_monitor *udev_monitor,
|
||||||
|
const char *subsystem,
|
||||||
|
const char *devtype);
|
||||||
int udev_monitor_filter_add_match_tag(struct udev_monitor *udev_monitor, const char *tag);
|
int udev_monitor_filter_add_match_tag(struct udev_monitor *udev_monitor, const char *tag);
|
||||||
int udev_monitor_filter_update(struct udev_monitor *udev_monitor);
|
int udev_monitor_filter_update(struct udev_monitor *udev_monitor);
|
||||||
int udev_monitor_filter_remove(struct udev_monitor *udev_monitor);
|
int udev_monitor_filter_remove(struct udev_monitor *udev_monitor);
|
||||||
|
@ -160,8 +169,10 @@ unsigned long long int udev_queue_get_udev_seqnum(struct udev_queue *udev_queue)
|
||||||
int udev_queue_get_udev_is_active(struct udev_queue *udev_queue);
|
int udev_queue_get_udev_is_active(struct udev_queue *udev_queue);
|
||||||
int udev_queue_get_queue_is_empty(struct udev_queue *udev_queue);
|
int udev_queue_get_queue_is_empty(struct udev_queue *udev_queue);
|
||||||
int udev_queue_get_seqnum_is_finished(struct udev_queue *udev_queue, unsigned long long int seqnum) __attribute__((__deprecated__));
|
int udev_queue_get_seqnum_is_finished(struct udev_queue *udev_queue, unsigned long long int seqnum) __attribute__((__deprecated__));
|
||||||
int udev_queue_get_seqnum_sequence_is_finished(struct udev_queue *udev_queue,
|
int udev_queue_get_seqnum_sequence_is_finished(
|
||||||
unsigned long long int start, unsigned long long int end) __attribute__((__deprecated__));
|
struct udev_queue *udev_queue,
|
||||||
|
unsigned long long int start,
|
||||||
|
unsigned long long int end) __attribute__((__deprecated__));
|
||||||
int udev_queue_get_fd(struct udev_queue *udev_queue);
|
int udev_queue_get_fd(struct udev_queue *udev_queue);
|
||||||
int udev_queue_flush(struct udev_queue *udev_queue);
|
int udev_queue_flush(struct udev_queue *udev_queue);
|
||||||
struct udev_list_entry* udev_queue_get_queued_list_entry(struct udev_queue *udev_queue) __attribute__((__deprecated__));
|
struct udev_list_entry* udev_queue_get_queued_list_entry(struct udev_queue *udev_queue) __attribute__((__deprecated__));
|
||||||
|
|
|
@ -536,7 +536,7 @@ static int method_set_tty(sd_bus_message *message, void *userdata, sd_bus_error
|
||||||
flags = fcntl(fd, F_GETFL, 0);
|
flags = fcntl(fd, F_GETFL, 0);
|
||||||
if (flags < 0)
|
if (flags < 0)
|
||||||
return -errno;
|
return -errno;
|
||||||
if ((flags & O_ACCMODE) != O_RDWR)
|
if ((flags & O_ACCMODE_STRICT) != O_RDWR)
|
||||||
return -EACCES;
|
return -EACCES;
|
||||||
if (FLAGS_SET(flags, O_PATH))
|
if (FLAGS_SET(flags, O_PATH))
|
||||||
return -ENOTTY;
|
return -ENOTTY;
|
||||||
|
|
|
@ -99,7 +99,7 @@ static int validate_image_fd(int fd, MountImageParameters *p) {
|
||||||
if (fl < 0)
|
if (fl < 0)
|
||||||
return log_debug_errno(fl, "Image file descriptor has unsafe flags set: %m");
|
return log_debug_errno(fl, "Image file descriptor has unsafe flags set: %m");
|
||||||
|
|
||||||
switch (fl & O_ACCMODE) {
|
switch (fl & O_ACCMODE_STRICT) {
|
||||||
|
|
||||||
case O_RDONLY:
|
case O_RDONLY:
|
||||||
p->read_only = true;
|
p->read_only = true;
|
||||||
|
|
|
@ -22,8 +22,7 @@
|
||||||
|
|
||||||
#define STATIC_BRIDGE_FDB_ENTRIES_PER_NETWORK_MAX 1024U
|
#define STATIC_BRIDGE_FDB_ENTRIES_PER_NETWORK_MAX 1024U
|
||||||
|
|
||||||
/* remove and FDB entry. */
|
static BridgeFDB* bridge_fdb_free(BridgeFDB *fdb) {
|
||||||
BridgeFDB *bridge_fdb_free(BridgeFDB *fdb) {
|
|
||||||
if (!fdb)
|
if (!fdb)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
@ -40,7 +39,11 @@ BridgeFDB *bridge_fdb_free(BridgeFDB *fdb) {
|
||||||
|
|
||||||
DEFINE_SECTION_CLEANUP_FUNCTIONS(BridgeFDB, bridge_fdb_free);
|
DEFINE_SECTION_CLEANUP_FUNCTIONS(BridgeFDB, bridge_fdb_free);
|
||||||
|
|
||||||
/* create a new FDB entry or get an existing one. */
|
DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
|
||||||
|
bridge_fdb_hash_ops_by_section,
|
||||||
|
ConfigSection, config_section_hash_func, config_section_compare_func,
|
||||||
|
BridgeFDB, bridge_fdb_free);
|
||||||
|
|
||||||
static int bridge_fdb_new_static(
|
static int bridge_fdb_new_static(
|
||||||
Network *network,
|
Network *network,
|
||||||
const char *filename,
|
const char *filename,
|
||||||
|
@ -83,13 +86,12 @@ static int bridge_fdb_new_static(
|
||||||
.ntf_flags = NEIGHBOR_CACHE_ENTRY_FLAGS_SELF,
|
.ntf_flags = NEIGHBOR_CACHE_ENTRY_FLAGS_SELF,
|
||||||
};
|
};
|
||||||
|
|
||||||
r = hashmap_ensure_put(&network->bridge_fdb_entries_by_section, &config_section_hash_ops, fdb->section, fdb);
|
r = hashmap_ensure_put(&network->bridge_fdb_entries_by_section, &bridge_fdb_hash_ops_by_section, fdb->section, fdb);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
/* return allocated FDB structure. */
|
/* return allocated FDB structure. */
|
||||||
*ret = TAKE_PTR(fdb);
|
*ret = TAKE_PTR(fdb);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -40,8 +40,6 @@ typedef struct BridgeFDB {
|
||||||
int outgoing_ifindex;
|
int outgoing_ifindex;
|
||||||
} BridgeFDB;
|
} BridgeFDB;
|
||||||
|
|
||||||
BridgeFDB *bridge_fdb_free(BridgeFDB *fdb);
|
|
||||||
|
|
||||||
void network_drop_invalid_bridge_fdb_entries(Network *network);
|
void network_drop_invalid_bridge_fdb_entries(Network *network);
|
||||||
|
|
||||||
int link_request_static_bridge_fdb(Link *link);
|
int link_request_static_bridge_fdb(Link *link);
|
||||||
|
|
|
@ -10,13 +10,13 @@
|
||||||
#include "networkd-manager.h"
|
#include "networkd-manager.h"
|
||||||
#include "networkd-network.h"
|
#include "networkd-network.h"
|
||||||
#include "networkd-queue.h"
|
#include "networkd-queue.h"
|
||||||
|
#include "networkd-util.h"
|
||||||
#include "string-util.h"
|
#include "string-util.h"
|
||||||
#include "vlan-util.h"
|
#include "vlan-util.h"
|
||||||
|
|
||||||
#define STATIC_BRIDGE_MDB_ENTRIES_PER_NETWORK_MAX 1024U
|
#define STATIC_BRIDGE_MDB_ENTRIES_PER_NETWORK_MAX 1024U
|
||||||
|
|
||||||
/* remove MDB entry. */
|
static BridgeMDB* bridge_mdb_free(BridgeMDB *mdb) {
|
||||||
BridgeMDB *bridge_mdb_free(BridgeMDB *mdb) {
|
|
||||||
if (!mdb)
|
if (!mdb)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
@ -32,7 +32,11 @@ BridgeMDB *bridge_mdb_free(BridgeMDB *mdb) {
|
||||||
|
|
||||||
DEFINE_SECTION_CLEANUP_FUNCTIONS(BridgeMDB, bridge_mdb_free);
|
DEFINE_SECTION_CLEANUP_FUNCTIONS(BridgeMDB, bridge_mdb_free);
|
||||||
|
|
||||||
/* create a new MDB entry or get an existing one. */
|
DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
|
||||||
|
bridge_mdb_hash_ops_by_section,
|
||||||
|
ConfigSection, config_section_hash_func, config_section_compare_func,
|
||||||
|
BridgeMDB, bridge_mdb_free);
|
||||||
|
|
||||||
static int bridge_mdb_new_static(
|
static int bridge_mdb_new_static(
|
||||||
Network *network,
|
Network *network,
|
||||||
const char *filename,
|
const char *filename,
|
||||||
|
@ -74,7 +78,7 @@ static int bridge_mdb_new_static(
|
||||||
.type = _BRIDGE_MDB_ENTRY_TYPE_INVALID,
|
.type = _BRIDGE_MDB_ENTRY_TYPE_INVALID,
|
||||||
};
|
};
|
||||||
|
|
||||||
r = hashmap_ensure_put(&network->bridge_mdb_entries_by_section, &config_section_hash_ops, mdb->section, mdb);
|
r = hashmap_ensure_put(&network->bridge_mdb_entries_by_section, &bridge_mdb_hash_ops_by_section, mdb->section, mdb);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
|
|
||||||
#include "conf-parser.h"
|
#include "conf-parser.h"
|
||||||
#include "in-addr-util.h"
|
#include "in-addr-util.h"
|
||||||
#include "networkd-util.h"
|
|
||||||
|
|
||||||
typedef struct Link Link;
|
typedef struct Link Link;
|
||||||
typedef struct Network Network;
|
typedef struct Network Network;
|
||||||
|
@ -30,8 +29,6 @@ typedef struct BridgeMDB {
|
||||||
uint16_t vlan_id;
|
uint16_t vlan_id;
|
||||||
} BridgeMDB;
|
} BridgeMDB;
|
||||||
|
|
||||||
BridgeMDB *bridge_mdb_free(BridgeMDB *mdb);
|
|
||||||
|
|
||||||
void network_drop_invalid_bridge_mdb_entries(Network *network);
|
void network_drop_invalid_bridge_mdb_entries(Network *network);
|
||||||
|
|
||||||
int link_request_static_bridge_mdb(Link *link);
|
int link_request_static_bridge_mdb(Link *link);
|
||||||
|
|
|
@ -7,9 +7,7 @@
|
||||||
#include "networkd-network.h"
|
#include "networkd-network.h"
|
||||||
#include "networkd-util.h"
|
#include "networkd-util.h"
|
||||||
|
|
||||||
DEFINE_SECTION_CLEANUP_FUNCTIONS(DHCPStaticLease, dhcp_static_lease_free);
|
static DHCPStaticLease* dhcp_static_lease_free(DHCPStaticLease *static_lease) {
|
||||||
|
|
||||||
DHCPStaticLease *dhcp_static_lease_free(DHCPStaticLease *static_lease) {
|
|
||||||
if (!static_lease)
|
if (!static_lease)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
@ -21,6 +19,13 @@ DHCPStaticLease *dhcp_static_lease_free(DHCPStaticLease *static_lease) {
|
||||||
return mfree(static_lease);
|
return mfree(static_lease);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DEFINE_SECTION_CLEANUP_FUNCTIONS(DHCPStaticLease, dhcp_static_lease_free);
|
||||||
|
|
||||||
|
DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
|
||||||
|
static_lease_hash_ops_by_section,
|
||||||
|
ConfigSection, config_section_hash_func, config_section_compare_func,
|
||||||
|
DHCPStaticLease, dhcp_static_lease_free);
|
||||||
|
|
||||||
static int dhcp_static_lease_new(DHCPStaticLease **ret) {
|
static int dhcp_static_lease_new(DHCPStaticLease **ret) {
|
||||||
DHCPStaticLease *p;
|
DHCPStaticLease *p;
|
||||||
|
|
||||||
|
@ -60,7 +65,8 @@ static int lease_new_static(Network *network, const char *filename, unsigned sec
|
||||||
|
|
||||||
static_lease->network = network;
|
static_lease->network = network;
|
||||||
static_lease->section = TAKE_PTR(n);
|
static_lease->section = TAKE_PTR(n);
|
||||||
r = hashmap_ensure_put(&network->dhcp_static_leases_by_section, &config_section_hash_ops, static_lease->section, static_lease);
|
|
||||||
|
r = hashmap_ensure_put(&network->dhcp_static_leases_by_section, &static_lease_hash_ops_by_section, static_lease->section, static_lease);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,6 @@ typedef struct DHCPStaticLease {
|
||||||
size_t client_id_size;
|
size_t client_id_size;
|
||||||
} DHCPStaticLease;
|
} DHCPStaticLease;
|
||||||
|
|
||||||
DHCPStaticLease *dhcp_static_lease_free(DHCPStaticLease *lease);
|
|
||||||
void network_drop_invalid_static_leases(Network *network);
|
void network_drop_invalid_static_leases(Network *network);
|
||||||
|
|
||||||
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_static_lease_address);
|
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_static_lease_address);
|
||||||
|
|
|
@ -281,7 +281,7 @@ int config_parse_dnssec_negative_trust_anchors(
|
||||||
assert(rvalue);
|
assert(rvalue);
|
||||||
|
|
||||||
if (isempty(rvalue)) {
|
if (isempty(rvalue)) {
|
||||||
*nta = set_free_free(*nta);
|
*nta = set_free(*nta);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -306,7 +306,7 @@ int config_parse_dnssec_negative_trust_anchors(
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = set_ensure_consume(nta, &dns_name_hash_ops, TAKE_PTR(w));
|
r = set_ensure_consume(nta, &dns_name_hash_ops_free, TAKE_PTR(w));
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_oom();
|
return log_oom();
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,13 @@ void network_adjust_ipv6_proxy_ndp(Network *network) {
|
||||||
log_once(LOG_WARNING,
|
log_once(LOG_WARNING,
|
||||||
"%s: IPv6 proxy NDP addresses are set, but IPv6 is not supported by kernel, "
|
"%s: IPv6 proxy NDP addresses are set, but IPv6 is not supported by kernel, "
|
||||||
"Ignoring IPv6 proxy NDP addresses.", network->filename);
|
"Ignoring IPv6 proxy NDP addresses.", network->filename);
|
||||||
network->ipv6_proxy_ndp_addresses = set_free_free(network->ipv6_proxy_ndp_addresses);
|
network->ipv6_proxy_ndp_addresses = set_free(network->ipv6_proxy_ndp_addresses);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (network->ipv6_proxy_ndp == 0) {
|
||||||
|
log_warning("%s: IPv6ProxyNDP= is disabled. Ignoring IPv6ProxyNDPAddress=.", network->filename);
|
||||||
|
network->ipv6_proxy_ndp_addresses = set_free(network->ipv6_proxy_ndp_addresses);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -149,7 +155,7 @@ int config_parse_ipv6_proxy_ndp_address(
|
||||||
assert(rvalue);
|
assert(rvalue);
|
||||||
|
|
||||||
if (isempty(rvalue)) {
|
if (isempty(rvalue)) {
|
||||||
network->ipv6_proxy_ndp_addresses = set_free_free(network->ipv6_proxy_ndp_addresses);
|
network->ipv6_proxy_ndp_addresses = set_free(network->ipv6_proxy_ndp_addresses);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -170,11 +176,9 @@ int config_parse_ipv6_proxy_ndp_address(
|
||||||
if (!address)
|
if (!address)
|
||||||
return log_oom();
|
return log_oom();
|
||||||
|
|
||||||
r = set_ensure_put(&network->ipv6_proxy_ndp_addresses, &in6_addr_hash_ops, address);
|
r = set_ensure_consume(&network->ipv6_proxy_ndp_addresses, &in6_addr_hash_ops_free, TAKE_PTR(address));
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_oom();
|
return log_oom();
|
||||||
if (r > 0)
|
|
||||||
TAKE_PTR(address);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -479,7 +479,7 @@ int bus_link_method_set_dnssec(sd_bus_message *message, void *userdata, sd_bus_e
|
||||||
}
|
}
|
||||||
|
|
||||||
int bus_link_method_set_dnssec_negative_trust_anchors(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
int bus_link_method_set_dnssec_negative_trust_anchors(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
||||||
_cleanup_set_free_free_ Set *ns = NULL;
|
_cleanup_set_free_ Set *ns = NULL;
|
||||||
_cleanup_strv_free_ char **ntas = NULL;
|
_cleanup_strv_free_ char **ntas = NULL;
|
||||||
Link *l = ASSERT_PTR(userdata);
|
Link *l = ASSERT_PTR(userdata);
|
||||||
int r;
|
int r;
|
||||||
|
@ -502,7 +502,7 @@ int bus_link_method_set_dnssec_negative_trust_anchors(sd_bus_message *message, v
|
||||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid negative trust anchor domain: %s", *i);
|
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid negative trust anchor domain: %s", *i);
|
||||||
}
|
}
|
||||||
|
|
||||||
ns = set_new(&dns_name_hash_ops);
|
ns = set_new(&dns_name_hash_ops_free);
|
||||||
if (!ns)
|
if (!ns)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
@ -523,8 +523,7 @@ int bus_link_method_set_dnssec_negative_trust_anchors(sd_bus_message *message, v
|
||||||
if (r == 0)
|
if (r == 0)
|
||||||
return 1; /* Polkit will call us back */
|
return 1; /* Polkit will call us back */
|
||||||
|
|
||||||
set_free_free(l->dnssec_negative_trust_anchors);
|
set_free_and_replace(l->dnssec_negative_trust_anchors, ns);
|
||||||
l->dnssec_negative_trust_anchors = TAKE_PTR(ns);
|
|
||||||
|
|
||||||
r = link_save_and_clean_full(l, /* also_save_manager = */ true);
|
r = link_save_and_clean_full(l, /* also_save_manager = */ true);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
|
|
|
@ -231,7 +231,7 @@ void link_dns_settings_clear(Link *link) {
|
||||||
link->dnssec_mode = _DNSSEC_MODE_INVALID;
|
link->dnssec_mode = _DNSSEC_MODE_INVALID;
|
||||||
link->dns_over_tls_mode = _DNS_OVER_TLS_MODE_INVALID;
|
link->dns_over_tls_mode = _DNS_OVER_TLS_MODE_INVALID;
|
||||||
|
|
||||||
link->dnssec_negative_trust_anchors = set_free_free(link->dnssec_negative_trust_anchors);
|
link->dnssec_negative_trust_anchors = set_free(link->dnssec_negative_trust_anchors);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void link_free_engines(Link *link) {
|
static void link_free_engines(Link *link) {
|
||||||
|
@ -295,7 +295,7 @@ static Link *link_free(Link *link) {
|
||||||
hashmap_free(link->bound_to_links);
|
hashmap_free(link->bound_to_links);
|
||||||
hashmap_free(link->bound_by_links);
|
hashmap_free(link->bound_by_links);
|
||||||
|
|
||||||
set_free_with_destructor(link->slaves, link_unref);
|
set_free(link->slaves);
|
||||||
|
|
||||||
network_unref(link->network);
|
network_unref(link->network);
|
||||||
|
|
||||||
|
@ -307,6 +307,11 @@ static Link *link_free(Link *link) {
|
||||||
|
|
||||||
DEFINE_TRIVIAL_REF_UNREF_FUNC(Link, link, link_free);
|
DEFINE_TRIVIAL_REF_UNREF_FUNC(Link, link, link_free);
|
||||||
|
|
||||||
|
DEFINE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
|
||||||
|
link_hash_ops,
|
||||||
|
void, trivial_hash_func, trivial_compare_func,
|
||||||
|
Link, link_unref);
|
||||||
|
|
||||||
int link_get_by_index(Manager *m, int ifindex, Link **ret) {
|
int link_get_by_index(Manager *m, int ifindex, Link **ret) {
|
||||||
Link *link;
|
Link *link;
|
||||||
|
|
||||||
|
@ -985,7 +990,7 @@ static int link_append_to_master(Link *link) {
|
||||||
if (link_get_master(link, &master) < 0)
|
if (link_get_master(link, &master) < 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
r = set_ensure_put(&master->slaves, NULL, link);
|
r = set_ensure_put(&master->slaves, &link_hash_ops, link);
|
||||||
if (r <= 0)
|
if (r <= 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
@ -2746,7 +2751,7 @@ static int link_new(Manager *manager, sd_netlink_message *message, Link **ret) {
|
||||||
.dns_over_tls_mode = _DNS_OVER_TLS_MODE_INVALID,
|
.dns_over_tls_mode = _DNS_OVER_TLS_MODE_INVALID,
|
||||||
};
|
};
|
||||||
|
|
||||||
r = hashmap_ensure_put(&manager->links_by_index, NULL, INT_TO_PTR(link->ifindex), link);
|
r = hashmap_ensure_put(&manager->links_by_index, &link_hash_ops, INT_TO_PTR(link->ifindex), link);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_link_debug_errno(link, r, "Failed to store link into manager: %m");
|
return log_link_debug_errno(link, r, "Failed to store link into manager: %m");
|
||||||
|
|
||||||
|
|
|
@ -222,6 +222,8 @@ typedef struct Link {
|
||||||
char **ntp;
|
char **ntp;
|
||||||
} Link;
|
} Link;
|
||||||
|
|
||||||
|
extern const struct hash_ops link_hash_ops;
|
||||||
|
|
||||||
typedef int (*link_netlink_message_handler_t)(sd_netlink*, sd_netlink_message*, Link*);
|
typedef int (*link_netlink_message_handler_t)(sd_netlink*, sd_netlink_message*, Link*);
|
||||||
|
|
||||||
bool link_is_ready_to_configure(Link *link, bool allow_unmanaged);
|
bool link_is_ready_to_configure(Link *link, bool allow_unmanaged);
|
||||||
|
|
|
@ -672,15 +672,16 @@ Manager* manager_free(Manager *m) {
|
||||||
m->request_queue = ordered_set_free(m->request_queue);
|
m->request_queue = ordered_set_free(m->request_queue);
|
||||||
m->remove_request_queue = ordered_set_free(m->remove_request_queue);
|
m->remove_request_queue = ordered_set_free(m->remove_request_queue);
|
||||||
|
|
||||||
m->dirty_links = set_free_with_destructor(m->dirty_links, link_unref);
|
|
||||||
m->new_wlan_ifindices = set_free(m->new_wlan_ifindices);
|
m->new_wlan_ifindices = set_free(m->new_wlan_ifindices);
|
||||||
|
|
||||||
|
m->dirty_links = set_free(m->dirty_links);
|
||||||
m->links_by_name = hashmap_free(m->links_by_name);
|
m->links_by_name = hashmap_free(m->links_by_name);
|
||||||
m->links_by_hw_addr = hashmap_free(m->links_by_hw_addr);
|
m->links_by_hw_addr = hashmap_free(m->links_by_hw_addr);
|
||||||
m->links_by_dhcp_pd_subnet_prefix = hashmap_free(m->links_by_dhcp_pd_subnet_prefix);
|
m->links_by_dhcp_pd_subnet_prefix = hashmap_free(m->links_by_dhcp_pd_subnet_prefix);
|
||||||
m->links_by_index = hashmap_free_with_destructor(m->links_by_index, link_unref);
|
m->links_by_index = hashmap_free(m->links_by_index);
|
||||||
|
|
||||||
m->dhcp_pd_subnet_ids = set_free(m->dhcp_pd_subnet_ids);
|
m->dhcp_pd_subnet_ids = set_free(m->dhcp_pd_subnet_ids);
|
||||||
m->networks = ordered_hashmap_free_with_destructor(m->networks, network_unref);
|
m->networks = ordered_hashmap_free(m->networks);
|
||||||
|
|
||||||
/* The same object may be registered with multiple names, and netdev_detach() may drop multiple
|
/* The same object may be registered with multiple names, and netdev_detach() may drop multiple
|
||||||
* entries. Hence, hashmap_free_with_destructor() cannot be used. */
|
* entries. Hence, hashmap_free_with_destructor() cannot be used. */
|
||||||
|
@ -691,7 +692,7 @@ Manager* manager_free(Manager *m) {
|
||||||
m->tuntap_fds_by_name = hashmap_free(m->tuntap_fds_by_name);
|
m->tuntap_fds_by_name = hashmap_free(m->tuntap_fds_by_name);
|
||||||
|
|
||||||
m->wiphy_by_name = hashmap_free(m->wiphy_by_name);
|
m->wiphy_by_name = hashmap_free(m->wiphy_by_name);
|
||||||
m->wiphy_by_index = hashmap_free_with_destructor(m->wiphy_by_index, wiphy_free);
|
m->wiphy_by_index = hashmap_free(m->wiphy_by_index);
|
||||||
|
|
||||||
ordered_set_free(m->address_pools);
|
ordered_set_free(m->address_pools);
|
||||||
|
|
||||||
|
|
|
@ -89,11 +89,11 @@ void network_adjust_ndisc(Network *network) {
|
||||||
/* When RouterAllowList=, PrefixAllowList= or RouteAllowList= are specified, then
|
/* When RouterAllowList=, PrefixAllowList= or RouteAllowList= are specified, then
|
||||||
* RouterDenyList=, PrefixDenyList= or RouteDenyList= are ignored, respectively. */
|
* RouterDenyList=, PrefixDenyList= or RouteDenyList= are ignored, respectively. */
|
||||||
if (!set_isempty(network->ndisc_allow_listed_router))
|
if (!set_isempty(network->ndisc_allow_listed_router))
|
||||||
network->ndisc_deny_listed_router = set_free_free(network->ndisc_deny_listed_router);
|
network->ndisc_deny_listed_router = set_free(network->ndisc_deny_listed_router);
|
||||||
if (!set_isempty(network->ndisc_allow_listed_prefix))
|
if (!set_isempty(network->ndisc_allow_listed_prefix))
|
||||||
network->ndisc_deny_listed_prefix = set_free_free(network->ndisc_deny_listed_prefix);
|
network->ndisc_deny_listed_prefix = set_free(network->ndisc_deny_listed_prefix);
|
||||||
if (!set_isempty(network->ndisc_allow_listed_route_prefix))
|
if (!set_isempty(network->ndisc_allow_listed_route_prefix))
|
||||||
network->ndisc_deny_listed_route_prefix = set_free_free(network->ndisc_deny_listed_route_prefix);
|
network->ndisc_deny_listed_route_prefix = set_free(network->ndisc_deny_listed_route_prefix);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ndisc_check_ready(Link *link);
|
static int ndisc_check_ready(Link *link);
|
||||||
|
|
|
@ -44,6 +44,16 @@
|
||||||
#include "strv.h"
|
#include "strv.h"
|
||||||
#include "tclass.h"
|
#include "tclass.h"
|
||||||
|
|
||||||
|
DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
|
||||||
|
network_hash_ops,
|
||||||
|
char, string_hash_func, string_compare_func,
|
||||||
|
Network, network_unref);
|
||||||
|
|
||||||
|
DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
|
||||||
|
stacked_netdevs_hash_ops,
|
||||||
|
char, string_hash_func, string_compare_func,
|
||||||
|
NetDev, netdev_unref);
|
||||||
|
|
||||||
static int network_resolve_netdev_one(Network *network, const char *name, NetDevKind kind, NetDev **ret) {
|
static int network_resolve_netdev_one(Network *network, const char *name, NetDevKind kind, NetDev **ret) {
|
||||||
const char *kind_string;
|
const char *kind_string;
|
||||||
NetDev *netdev;
|
NetDev *netdev;
|
||||||
|
@ -105,14 +115,14 @@ static int network_resolve_stacked_netdevs(Network *network) {
|
||||||
if (network_resolve_netdev_one(network, name, PTR_TO_INT(kind), &netdev) <= 0)
|
if (network_resolve_netdev_one(network, name, PTR_TO_INT(kind), &netdev) <= 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
r = hashmap_ensure_put(&network->stacked_netdevs, &string_hash_ops, netdev->ifname, netdev);
|
r = hashmap_ensure_put(&network->stacked_netdevs, &stacked_netdevs_hash_ops, netdev->ifname, netdev);
|
||||||
if (r == -ENOMEM)
|
if (r == -ENOMEM)
|
||||||
return log_oom();
|
return log_oom();
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
log_warning_errno(r, "%s: Failed to add NetDev '%s' to network, ignoring: %m",
|
log_warning_errno(r, "%s: Failed to add NetDev '%s' to network, ignoring: %m",
|
||||||
network->filename, (const char *) name);
|
network->filename, (const char *) name);
|
||||||
|
|
||||||
netdev = NULL;
|
TAKE_PTR(netdev);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -291,11 +301,6 @@ int network_verify(Network *network) {
|
||||||
if (network->keep_configuration < 0)
|
if (network->keep_configuration < 0)
|
||||||
network->keep_configuration = KEEP_CONFIGURATION_NO;
|
network->keep_configuration = KEEP_CONFIGURATION_NO;
|
||||||
|
|
||||||
if (network->ipv6_proxy_ndp == 0 && !set_isempty(network->ipv6_proxy_ndp_addresses)) {
|
|
||||||
log_warning("%s: IPv6ProxyNDP= is disabled. Ignoring IPv6ProxyNDPAddress=.", network->filename);
|
|
||||||
network->ipv6_proxy_ndp_addresses = set_free_free(network->ipv6_proxy_ndp_addresses);
|
|
||||||
}
|
|
||||||
|
|
||||||
r = network_drop_invalid_addresses(network);
|
r = network_drop_invalid_addresses(network);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r; /* network_drop_invalid_addresses() logs internally. */
|
return r; /* network_drop_invalid_addresses() logs internally. */
|
||||||
|
@ -594,7 +599,7 @@ int network_load_one(Manager *manager, OrderedHashmap **networks, const char *fi
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r; /* network_verify() logs internally. */
|
return r; /* network_verify() logs internally. */
|
||||||
|
|
||||||
r = ordered_hashmap_ensure_put(networks, &string_hash_ops, network->name, network);
|
r = ordered_hashmap_ensure_put(networks, &network_hash_ops, network->name, network);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_warning_errno(r, "%s: Failed to store configuration into hashmap: %m", filename);
|
return log_warning_errno(r, "%s: Failed to store configuration into hashmap: %m", filename);
|
||||||
|
|
||||||
|
@ -645,7 +650,7 @@ static bool network_netdev_equal(Network *a, Network *b) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int network_reload(Manager *manager) {
|
int network_reload(Manager *manager) {
|
||||||
OrderedHashmap *new_networks = NULL;
|
_cleanup_ordered_hashmap_free_ OrderedHashmap *new_networks = NULL;
|
||||||
Network *n, *old;
|
Network *n, *old;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
|
@ -653,7 +658,7 @@ int network_reload(Manager *manager) {
|
||||||
|
|
||||||
r = network_load(manager, &new_networks);
|
r = network_load(manager, &new_networks);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
goto failure;
|
return r;
|
||||||
|
|
||||||
ORDERED_HASHMAP_FOREACH(n, new_networks) {
|
ORDERED_HASHMAP_FOREACH(n, new_networks) {
|
||||||
r = network_get_by_name(manager, n->name, &old);
|
r = network_get_by_name(manager, n->name, &old);
|
||||||
|
@ -675,14 +680,13 @@ int network_reload(Manager *manager) {
|
||||||
/* Nothing updated, use the existing Network object, and drop the new one. */
|
/* Nothing updated, use the existing Network object, and drop the new one. */
|
||||||
r = ordered_hashmap_replace(new_networks, old->name, old);
|
r = ordered_hashmap_replace(new_networks, old->name, old);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
goto failure;
|
return r;
|
||||||
|
|
||||||
network_ref(old);
|
network_ref(old);
|
||||||
network_unref(n);
|
network_unref(n);
|
||||||
}
|
}
|
||||||
|
|
||||||
ordered_hashmap_free_with_destructor(manager->networks, network_unref);
|
ordered_hashmap_free_and_replace(manager->networks, new_networks);
|
||||||
manager->networks = new_networks;
|
|
||||||
|
|
||||||
r = manager_build_dhcp_pd_subnet_ids(manager);
|
r = manager_build_dhcp_pd_subnet_ids(manager);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
|
@ -693,11 +697,6 @@ int network_reload(Manager *manager) {
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
failure:
|
|
||||||
ordered_hashmap_free_with_destructor(new_networks, network_unref);
|
|
||||||
|
|
||||||
return r;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int manager_build_dhcp_pd_subnet_ids(Manager *manager) {
|
int manager_build_dhcp_pd_subnet_ids(Manager *manager) {
|
||||||
|
@ -752,7 +751,7 @@ static Network *network_free(Network *network) {
|
||||||
free(network->dns);
|
free(network->dns);
|
||||||
ordered_set_free(network->search_domains);
|
ordered_set_free(network->search_domains);
|
||||||
ordered_set_free(network->route_domains);
|
ordered_set_free(network->route_domains);
|
||||||
set_free_free(network->dnssec_negative_trust_anchors);
|
set_free(network->dnssec_negative_trust_anchors);
|
||||||
|
|
||||||
/* DHCP server */
|
/* DHCP server */
|
||||||
free(network->dhcp_server_relay_agent_circuit_id);
|
free(network->dhcp_server_relay_agent_circuit_id);
|
||||||
|
@ -825,23 +824,23 @@ static Network *network_free(Network *network) {
|
||||||
netdev_unref(network->bridge);
|
netdev_unref(network->bridge);
|
||||||
netdev_unref(network->bond);
|
netdev_unref(network->bond);
|
||||||
netdev_unref(network->vrf);
|
netdev_unref(network->vrf);
|
||||||
hashmap_free_with_destructor(network->stacked_netdevs, netdev_unref);
|
hashmap_free(network->stacked_netdevs);
|
||||||
|
|
||||||
/* static configs */
|
/* static configs */
|
||||||
set_free_free(network->ipv6_proxy_ndp_addresses);
|
set_free(network->ipv6_proxy_ndp_addresses);
|
||||||
ordered_hashmap_free(network->addresses_by_section);
|
ordered_hashmap_free(network->addresses_by_section);
|
||||||
hashmap_free(network->routes_by_section);
|
hashmap_free(network->routes_by_section);
|
||||||
ordered_hashmap_free(network->nexthops_by_section);
|
ordered_hashmap_free(network->nexthops_by_section);
|
||||||
hashmap_free_with_destructor(network->bridge_fdb_entries_by_section, bridge_fdb_free);
|
hashmap_free(network->bridge_fdb_entries_by_section);
|
||||||
hashmap_free_with_destructor(network->bridge_mdb_entries_by_section, bridge_mdb_free);
|
hashmap_free(network->bridge_mdb_entries_by_section);
|
||||||
ordered_hashmap_free(network->neighbors_by_section);
|
ordered_hashmap_free(network->neighbors_by_section);
|
||||||
hashmap_free(network->address_labels_by_section);
|
hashmap_free(network->address_labels_by_section);
|
||||||
hashmap_free_with_destructor(network->prefixes_by_section, prefix_free);
|
hashmap_free(network->prefixes_by_section);
|
||||||
hashmap_free_with_destructor(network->route_prefixes_by_section, route_prefix_free);
|
hashmap_free(network->route_prefixes_by_section);
|
||||||
hashmap_free_with_destructor(network->pref64_prefixes_by_section, prefix64_free);
|
hashmap_free(network->pref64_prefixes_by_section);
|
||||||
hashmap_free(network->rules_by_section);
|
hashmap_free(network->rules_by_section);
|
||||||
hashmap_free_with_destructor(network->dhcp_static_leases_by_section, dhcp_static_lease_free);
|
hashmap_free(network->dhcp_static_leases_by_section);
|
||||||
ordered_hashmap_free_with_destructor(network->sr_iov_by_section, sr_iov_free);
|
ordered_hashmap_free(network->sr_iov_by_section);
|
||||||
hashmap_free(network->qdiscs_by_section);
|
hashmap_free(network->qdiscs_by_section);
|
||||||
hashmap_free(network->tclasses_by_section);
|
hashmap_free(network->tclasses_by_section);
|
||||||
|
|
||||||
|
|
|
@ -35,7 +35,7 @@ bool link_radv_enabled(Link *link) {
|
||||||
return link->network->router_prefix_delegation;
|
return link->network->router_prefix_delegation;
|
||||||
}
|
}
|
||||||
|
|
||||||
Prefix* prefix_free(Prefix *prefix) {
|
static Prefix* prefix_free(Prefix *prefix) {
|
||||||
if (!prefix)
|
if (!prefix)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
@ -52,6 +52,11 @@ Prefix* prefix_free(Prefix *prefix) {
|
||||||
|
|
||||||
DEFINE_SECTION_CLEANUP_FUNCTIONS(Prefix, prefix_free);
|
DEFINE_SECTION_CLEANUP_FUNCTIONS(Prefix, prefix_free);
|
||||||
|
|
||||||
|
DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
|
||||||
|
prefix_hash_ops_by_section,
|
||||||
|
ConfigSection, config_section_hash_func, config_section_compare_func,
|
||||||
|
Prefix, prefix_free);
|
||||||
|
|
||||||
static int prefix_new_static(Network *network, const char *filename, unsigned section_line, Prefix **ret) {
|
static int prefix_new_static(Network *network, const char *filename, unsigned section_line, Prefix **ret) {
|
||||||
_cleanup_(config_section_freep) ConfigSection *n = NULL;
|
_cleanup_(config_section_freep) ConfigSection *n = NULL;
|
||||||
_cleanup_(prefix_freep) Prefix *prefix = NULL;
|
_cleanup_(prefix_freep) Prefix *prefix = NULL;
|
||||||
|
@ -87,7 +92,7 @@ static int prefix_new_static(Network *network, const char *filename, unsigned se
|
||||||
.prefix.preferred_until = USEC_INFINITY,
|
.prefix.preferred_until = USEC_INFINITY,
|
||||||
};
|
};
|
||||||
|
|
||||||
r = hashmap_ensure_put(&network->prefixes_by_section, &config_section_hash_ops, prefix->section, prefix);
|
r = hashmap_ensure_put(&network->prefixes_by_section, &prefix_hash_ops_by_section, prefix->section, prefix);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
@ -95,7 +100,7 @@ static int prefix_new_static(Network *network, const char *filename, unsigned se
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
RoutePrefix* route_prefix_free(RoutePrefix *prefix) {
|
static RoutePrefix* route_prefix_free(RoutePrefix *prefix) {
|
||||||
if (!prefix)
|
if (!prefix)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
@ -111,6 +116,11 @@ RoutePrefix* route_prefix_free(RoutePrefix *prefix) {
|
||||||
|
|
||||||
DEFINE_SECTION_CLEANUP_FUNCTIONS(RoutePrefix, route_prefix_free);
|
DEFINE_SECTION_CLEANUP_FUNCTIONS(RoutePrefix, route_prefix_free);
|
||||||
|
|
||||||
|
DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
|
||||||
|
route_prefix_hash_ops_by_section,
|
||||||
|
ConfigSection, config_section_hash_func, config_section_compare_func,
|
||||||
|
RoutePrefix, route_prefix_free);
|
||||||
|
|
||||||
static int route_prefix_new_static(Network *network, const char *filename, unsigned section_line, RoutePrefix **ret) {
|
static int route_prefix_new_static(Network *network, const char *filename, unsigned section_line, RoutePrefix **ret) {
|
||||||
_cleanup_(config_section_freep) ConfigSection *n = NULL;
|
_cleanup_(config_section_freep) ConfigSection *n = NULL;
|
||||||
_cleanup_(route_prefix_freep) RoutePrefix *prefix = NULL;
|
_cleanup_(route_prefix_freep) RoutePrefix *prefix = NULL;
|
||||||
|
@ -143,7 +153,7 @@ static int route_prefix_new_static(Network *network, const char *filename, unsig
|
||||||
.route.valid_until = USEC_INFINITY,
|
.route.valid_until = USEC_INFINITY,
|
||||||
};
|
};
|
||||||
|
|
||||||
r = hashmap_ensure_put(&network->route_prefixes_by_section, &config_section_hash_ops, prefix->section, prefix);
|
r = hashmap_ensure_put(&network->route_prefixes_by_section, &route_prefix_hash_ops_by_section, prefix->section, prefix);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
@ -151,7 +161,7 @@ static int route_prefix_new_static(Network *network, const char *filename, unsig
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Prefix64* prefix64_free(Prefix64 *prefix) {
|
static Prefix64* prefix64_free(Prefix64 *prefix) {
|
||||||
if (!prefix)
|
if (!prefix)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
@ -167,6 +177,11 @@ Prefix64* prefix64_free(Prefix64 *prefix) {
|
||||||
|
|
||||||
DEFINE_SECTION_CLEANUP_FUNCTIONS(Prefix64, prefix64_free);
|
DEFINE_SECTION_CLEANUP_FUNCTIONS(Prefix64, prefix64_free);
|
||||||
|
|
||||||
|
DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
|
||||||
|
prefix64_hash_ops_by_section,
|
||||||
|
ConfigSection, config_section_hash_func, config_section_compare_func,
|
||||||
|
Prefix64, prefix64_free);
|
||||||
|
|
||||||
static int prefix64_new_static(Network *network, const char *filename, unsigned section_line, Prefix64 **ret) {
|
static int prefix64_new_static(Network *network, const char *filename, unsigned section_line, Prefix64 **ret) {
|
||||||
_cleanup_(config_section_freep) ConfigSection *n = NULL;
|
_cleanup_(config_section_freep) ConfigSection *n = NULL;
|
||||||
_cleanup_(prefix64_freep) Prefix64 *prefix = NULL;
|
_cleanup_(prefix64_freep) Prefix64 *prefix = NULL;
|
||||||
|
@ -199,7 +214,7 @@ static int prefix64_new_static(Network *network, const char *filename, unsigned
|
||||||
.prefix64.valid_until = USEC_INFINITY,
|
.prefix64.valid_until = USEC_INFINITY,
|
||||||
};
|
};
|
||||||
|
|
||||||
r = hashmap_ensure_put(&network->pref64_prefixes_by_section, &config_section_hash_ops, prefix->section, prefix);
|
r = hashmap_ensure_put(&network->pref64_prefixes_by_section, &prefix64_hash_ops_by_section, prefix->section, prefix);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
@ -809,9 +824,9 @@ void network_adjust_radv(Network *network) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!FLAGS_SET(network->router_prefix_delegation, RADV_PREFIX_DELEGATION_STATIC)) {
|
if (!FLAGS_SET(network->router_prefix_delegation, RADV_PREFIX_DELEGATION_STATIC)) {
|
||||||
network->prefixes_by_section = hashmap_free_with_destructor(network->prefixes_by_section, prefix_free);
|
network->prefixes_by_section = hashmap_free(network->prefixes_by_section);
|
||||||
network->route_prefixes_by_section = hashmap_free_with_destructor(network->route_prefixes_by_section, route_prefix_free);
|
network->route_prefixes_by_section = hashmap_free(network->route_prefixes_by_section);
|
||||||
network->pref64_prefixes_by_section = hashmap_free_with_destructor(network->pref64_prefixes_by_section, prefix64_free);
|
network->pref64_prefixes_by_section = hashmap_free(network->pref64_prefixes_by_section);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!network->router_prefix_delegation)
|
if (!network->router_prefix_delegation)
|
||||||
|
|
|
@ -52,10 +52,6 @@ typedef struct Prefix64 {
|
||||||
sd_ndisc_prefix64 prefix64;
|
sd_ndisc_prefix64 prefix64;
|
||||||
} Prefix64;
|
} Prefix64;
|
||||||
|
|
||||||
Prefix* prefix_free(Prefix *prefix);
|
|
||||||
RoutePrefix* route_prefix_free(RoutePrefix *prefix);
|
|
||||||
Prefix64* prefix64_free(Prefix64 *prefix);
|
|
||||||
|
|
||||||
void network_adjust_radv(Network *network);
|
void network_adjust_radv(Network *network);
|
||||||
|
|
||||||
int link_request_radv_addresses(Link *link);
|
int link_request_radv_addresses(Link *link);
|
||||||
|
|
|
@ -947,8 +947,6 @@ static int link_save(Link *link) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void link_dirty(Link *link) {
|
void link_dirty(Link *link) {
|
||||||
int r;
|
|
||||||
|
|
||||||
assert(link);
|
assert(link);
|
||||||
assert(link->manager);
|
assert(link->manager);
|
||||||
|
|
||||||
|
@ -962,10 +960,9 @@ void link_dirty(Link *link) {
|
||||||
/* Also mark manager dirty as link is dirty */
|
/* Also mark manager dirty as link is dirty */
|
||||||
link->manager->dirty = true;
|
link->manager->dirty = true;
|
||||||
|
|
||||||
r = set_ensure_put(&link->manager->dirty_links, NULL, link);
|
if (set_ensure_put(&link->manager->dirty_links, &link_hash_ops, link) <= 0)
|
||||||
if (r <= 0)
|
return; /* Ignore allocation errors and don't take another ref if the link was already dirty */
|
||||||
/* Ignore allocation errors and don't take another ref if the link was already dirty */
|
|
||||||
return;
|
|
||||||
link_ref(link);
|
link_ref(link);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
#include "udev-util.h"
|
#include "udev-util.h"
|
||||||
#include "wifi-util.h"
|
#include "wifi-util.h"
|
||||||
|
|
||||||
Wiphy *wiphy_free(Wiphy *w) {
|
static Wiphy* wiphy_free(Wiphy *w) {
|
||||||
if (!w)
|
if (!w)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
@ -29,6 +29,13 @@ Wiphy *wiphy_free(Wiphy *w) {
|
||||||
return mfree(w);
|
return mfree(w);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DEFINE_TRIVIAL_CLEANUP_FUNC(Wiphy*, wiphy_free);
|
||||||
|
|
||||||
|
DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
|
||||||
|
wiphy_hash_ops,
|
||||||
|
void, trivial_hash_func, trivial_compare_func,
|
||||||
|
Wiphy, wiphy_free);
|
||||||
|
|
||||||
static int wiphy_new(Manager *manager, sd_netlink_message *message, Wiphy **ret) {
|
static int wiphy_new(Manager *manager, sd_netlink_message *message, Wiphy **ret) {
|
||||||
_cleanup_(wiphy_freep) Wiphy *w = NULL;
|
_cleanup_(wiphy_freep) Wiphy *w = NULL;
|
||||||
_cleanup_free_ char *name = NULL;
|
_cleanup_free_ char *name = NULL;
|
||||||
|
@ -56,7 +63,7 @@ static int wiphy_new(Manager *manager, sd_netlink_message *message, Wiphy **ret)
|
||||||
.name = TAKE_PTR(name),
|
.name = TAKE_PTR(name),
|
||||||
};
|
};
|
||||||
|
|
||||||
r = hashmap_ensure_put(&manager->wiphy_by_index, NULL, UINT32_TO_PTR(w->index), w);
|
r = hashmap_ensure_put(&manager->wiphy_by_index, &wiphy_hash_ops, UINT32_TO_PTR(w->index), w);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
|
|
@ -31,9 +31,6 @@ typedef struct Wiphy {
|
||||||
RFKillState rfkill_state;
|
RFKillState rfkill_state;
|
||||||
} Wiphy;
|
} Wiphy;
|
||||||
|
|
||||||
Wiphy *wiphy_free(Wiphy *w);
|
|
||||||
DEFINE_TRIVIAL_CLEANUP_FUNC(Wiphy*, wiphy_free);
|
|
||||||
|
|
||||||
int wiphy_get_by_index(Manager *manager, uint32_t index, Wiphy **ret);
|
int wiphy_get_by_index(Manager *manager, uint32_t index, Wiphy **ret);
|
||||||
int wiphy_get_by_name(Manager *manager, const char *name, Wiphy **ret);
|
int wiphy_get_by_name(Manager *manager, const char *name, Wiphy **ret);
|
||||||
|
|
||||||
|
|
|
@ -146,13 +146,13 @@ int memfd_clone_fd(int fd, const char *name, int mode) {
|
||||||
|
|
||||||
assert(fd >= 0);
|
assert(fd >= 0);
|
||||||
assert(name);
|
assert(name);
|
||||||
assert(IN_SET(mode & O_ACCMODE, O_RDONLY, O_RDWR));
|
assert(IN_SET(mode & O_ACCMODE_STRICT, O_RDONLY, O_RDWR));
|
||||||
assert((mode & ~(O_RDONLY|O_RDWR|O_CLOEXEC)) == 0);
|
assert((mode & ~(O_RDONLY|O_RDWR|O_CLOEXEC)) == 0);
|
||||||
|
|
||||||
if (fstat(fd, &st) < 0)
|
if (fstat(fd, &st) < 0)
|
||||||
return -errno;
|
return -errno;
|
||||||
|
|
||||||
ro = (mode & O_ACCMODE) == O_RDONLY;
|
ro = (mode & O_ACCMODE_STRICT) == O_RDONLY;
|
||||||
exec = st.st_mode & 0111;
|
exec = st.st_mode & 0111;
|
||||||
|
|
||||||
mfd = memfd_create_wrapper(name,
|
mfd = memfd_create_wrapper(name,
|
||||||
|
|
|
@ -504,7 +504,7 @@ int journal_file_open_reliably(
|
||||||
-EIDRM)) /* File has been deleted */
|
-EIDRM)) /* File has been deleted */
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
if ((open_flags & O_ACCMODE) == O_RDONLY)
|
if ((open_flags & O_ACCMODE_STRICT) == O_RDONLY)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
if (!(open_flags & O_CREAT))
|
if (!(open_flags & O_CREAT))
|
||||||
|
@ -519,7 +519,7 @@ int journal_file_open_reliably(
|
||||||
/* The file is corrupted. Try opening it read-only as the template before rotating to inherit its
|
/* The file is corrupted. Try opening it read-only as the template before rotating to inherit its
|
||||||
* sequence number and ID. */
|
* sequence number and ID. */
|
||||||
r = journal_file_open(-EBADF, fname,
|
r = journal_file_open(-EBADF, fname,
|
||||||
(open_flags & ~(O_ACCMODE|O_CREAT|O_EXCL)) | O_RDONLY,
|
(open_flags & ~(O_ACCMODE_STRICT|O_CREAT|O_EXCL)) | O_RDONLY,
|
||||||
file_flags, 0, compress_threshold_bytes, NULL,
|
file_flags, 0, compress_threshold_bytes, NULL,
|
||||||
mmap_cache, /* template = */ NULL, &old_file);
|
mmap_cache, /* template = */ NULL, &old_file);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
|
|
|
@ -500,7 +500,7 @@ static int loop_device_make_internal(
|
||||||
.block_size = sector_size,
|
.block_size = sector_size,
|
||||||
.info = {
|
.info = {
|
||||||
/* Use the specified flags, but configure the read-only flag from the open flags, and force autoclear */
|
/* Use the specified flags, but configure the read-only flag from the open flags, and force autoclear */
|
||||||
.lo_flags = (loop_flags & ~LO_FLAGS_READ_ONLY) | ((open_flags & O_ACCMODE) == O_RDONLY ? LO_FLAGS_READ_ONLY : 0) | LO_FLAGS_AUTOCLEAR,
|
.lo_flags = (loop_flags & ~LO_FLAGS_READ_ONLY) | ((open_flags & O_ACCMODE_STRICT) == O_RDONLY ? LO_FLAGS_READ_ONLY : 0) | LO_FLAGS_AUTOCLEAR,
|
||||||
.lo_offset = offset,
|
.lo_offset = offset,
|
||||||
.lo_sizelimit = size == UINT64_MAX ? 0 : size,
|
.lo_sizelimit = size == UINT64_MAX ? 0 : size,
|
||||||
},
|
},
|
||||||
|
|
|
@ -9,6 +9,25 @@
|
||||||
#include "stdio-util.h"
|
#include "stdio-util.h"
|
||||||
#include "string-util.h"
|
#include "string-util.h"
|
||||||
|
|
||||||
|
static SRIOV* sr_iov_free(SRIOV *sr_iov) {
|
||||||
|
if (!sr_iov)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (sr_iov->sr_iov_by_section && sr_iov->section)
|
||||||
|
ordered_hashmap_remove(sr_iov->sr_iov_by_section, sr_iov->section);
|
||||||
|
|
||||||
|
config_section_free(sr_iov->section);
|
||||||
|
|
||||||
|
return mfree(sr_iov);
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFINE_SECTION_CLEANUP_FUNCTIONS(SRIOV, sr_iov_free);
|
||||||
|
|
||||||
|
DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
|
||||||
|
sr_iov_hash_ops_by_section,
|
||||||
|
ConfigSection, config_section_hash_func, config_section_compare_func,
|
||||||
|
SRIOV, sr_iov_free);
|
||||||
|
|
||||||
static int sr_iov_new(SRIOV **ret) {
|
static int sr_iov_new(SRIOV **ret) {
|
||||||
SRIOV *sr_iov;
|
SRIOV *sr_iov;
|
||||||
|
|
||||||
|
@ -57,7 +76,7 @@ static int sr_iov_new_static(OrderedHashmap **sr_iov_by_section, const char *fil
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
r = ordered_hashmap_ensure_put(sr_iov_by_section, &config_section_hash_ops, n, sr_iov);
|
r = ordered_hashmap_ensure_put(sr_iov_by_section, &sr_iov_hash_ops_by_section, n, sr_iov);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
@ -68,18 +87,6 @@ static int sr_iov_new_static(OrderedHashmap **sr_iov_by_section, const char *fil
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
SRIOV *sr_iov_free(SRIOV *sr_iov) {
|
|
||||||
if (!sr_iov)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
if (sr_iov->sr_iov_by_section && sr_iov->section)
|
|
||||||
ordered_hashmap_remove(sr_iov->sr_iov_by_section, sr_iov->section);
|
|
||||||
|
|
||||||
config_section_free(sr_iov->section);
|
|
||||||
|
|
||||||
return mfree(sr_iov);
|
|
||||||
}
|
|
||||||
|
|
||||||
void sr_iov_hash_func(const SRIOV *sr_iov, struct siphash *state) {
|
void sr_iov_hash_func(const SRIOV *sr_iov, struct siphash *state) {
|
||||||
assert(sr_iov);
|
assert(sr_iov);
|
||||||
assert(state);
|
assert(state);
|
||||||
|
|
|
@ -32,7 +32,6 @@ typedef struct SRIOV {
|
||||||
struct ether_addr mac;
|
struct ether_addr mac;
|
||||||
} SRIOV;
|
} SRIOV;
|
||||||
|
|
||||||
SRIOV *sr_iov_free(SRIOV *sr_iov);
|
|
||||||
void sr_iov_hash_func(const SRIOV *sr_iov, struct siphash *state);
|
void sr_iov_hash_func(const SRIOV *sr_iov, struct siphash *state);
|
||||||
int sr_iov_compare_func(const SRIOV *s1, const SRIOV *s2);
|
int sr_iov_compare_func(const SRIOV *s1, const SRIOV *s2);
|
||||||
int sr_iov_set_netlink_message(SRIOV *sr_iov, sd_netlink_message *req);
|
int sr_iov_set_netlink_message(SRIOV *sr_iov, sd_netlink_message *req);
|
||||||
|
@ -40,8 +39,6 @@ int sr_iov_get_num_vfs(sd_device *device, uint32_t *ret);
|
||||||
int sr_iov_set_num_vfs(sd_device *device, uint32_t num_vfs, OrderedHashmap *sr_iov_by_section);
|
int sr_iov_set_num_vfs(sd_device *device, uint32_t num_vfs, OrderedHashmap *sr_iov_by_section);
|
||||||
int sr_iov_drop_invalid_sections(uint32_t num_vfs, OrderedHashmap *sr_iov_by_section);
|
int sr_iov_drop_invalid_sections(uint32_t num_vfs, OrderedHashmap *sr_iov_by_section);
|
||||||
|
|
||||||
DEFINE_SECTION_CLEANUP_FUNCTIONS(SRIOV, sr_iov_free);
|
|
||||||
|
|
||||||
CONFIG_PARSER_PROTOTYPE(config_parse_sr_iov_uint32);
|
CONFIG_PARSER_PROTOTYPE(config_parse_sr_iov_uint32);
|
||||||
CONFIG_PARSER_PROTOTYPE(config_parse_sr_iov_boolean);
|
CONFIG_PARSER_PROTOTYPE(config_parse_sr_iov_boolean);
|
||||||
CONFIG_PARSER_PROTOTYPE(config_parse_sr_iov_link_state);
|
CONFIG_PARSER_PROTOTYPE(config_parse_sr_iov_link_state);
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#include "blockdev-util.h"
|
#include "blockdev-util.h"
|
||||||
#include "detach-loopback.h"
|
#include "detach-loopback.h"
|
||||||
#include "device-util.h"
|
#include "device-util.h"
|
||||||
|
#include "errno-util.h"
|
||||||
#include "fd-util.h"
|
#include "fd-util.h"
|
||||||
#include "shutdown.h"
|
#include "shutdown.h"
|
||||||
|
|
||||||
|
@ -106,8 +107,12 @@ static int delete_loopback(const char *device) {
|
||||||
|
|
||||||
fd = open(device, O_RDONLY|O_CLOEXEC);
|
fd = open(device, O_RDONLY|O_CLOEXEC);
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
log_debug_errno(errno, "Failed to open loopback device %s: %m", device);
|
if (ERRNO_IS_DEVICE_ABSENT(errno)) {
|
||||||
return errno == ENOENT ? 0 : -errno;
|
log_debug_errno(errno, "Tried to open loopback device '%s', but device disappeared by now, ignoring: %m", device);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return log_debug_errno(errno, "Failed to open loopback device '%s': %m", device);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Loopback block devices don't sync in-flight blocks when we clear the fd, hence sync explicitly
|
/* Loopback block devices don't sync in-flight blocks when we clear the fd, hence sync explicitly
|
||||||
|
|
|
@ -131,12 +131,21 @@ static int delete_md(RaidDevice *m) {
|
||||||
assert(m->path);
|
assert(m->path);
|
||||||
|
|
||||||
fd = open(m->path, O_RDONLY|O_CLOEXEC|O_EXCL);
|
fd = open(m->path, O_RDONLY|O_CLOEXEC|O_EXCL);
|
||||||
if (fd < 0)
|
if (fd < 0) {
|
||||||
return -errno;
|
if (ERRNO_IS_DEVICE_ABSENT(errno)) {
|
||||||
|
log_debug_errno(errno, "Tried to open MD device '%s', but device disappeared by now, ignoring: %m", m->path);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return log_debug_errno(errno, "Failed to open MD device '%s': %m", m->path);
|
||||||
|
}
|
||||||
|
|
||||||
(void) sync_with_progress(fd);
|
(void) sync_with_progress(fd);
|
||||||
|
|
||||||
return RET_NERRNO(ioctl(fd, STOP_ARRAY, NULL));
|
if (ioctl(fd, STOP_ARRAY, NULL) < 0)
|
||||||
|
return log_debug_errno(errno, "Failed to issue STOP_ARRAY on MD device '%s': %m", m->path);
|
||||||
|
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int md_points_list_detach(RaidDevice **head, bool *changed, bool last_try) {
|
static int md_points_list_detach(RaidDevice **head, bool *changed, bool last_try) {
|
||||||
|
@ -164,8 +173,9 @@ static int md_points_list_detach(RaidDevice **head, bool *changed, bool last_try
|
||||||
n_failed++;
|
n_failed++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (r > 0)
|
||||||
*changed = true;
|
*changed = true;
|
||||||
|
|
||||||
raid_device_free(head, m);
|
raid_device_free(head, m);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
#include "alloc-util.h"
|
#include "alloc-util.h"
|
||||||
#include "detach-swap.h"
|
#include "detach-swap.h"
|
||||||
|
#include "errno-util.h"
|
||||||
#include "libmount-util.h"
|
#include "libmount-util.h"
|
||||||
|
|
||||||
static void swap_device_free(SwapDevice **head, SwapDevice *m) {
|
static void swap_device_free(SwapDevice **head, SwapDevice *m) {
|
||||||
|
@ -74,20 +75,23 @@ int swap_list_get(const char *swaps, SwapDevice **head) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static int swap_points_list_off(SwapDevice **head, bool *changed) {
|
static int swap_points_list_off(SwapDevice **head, bool *changed) {
|
||||||
int n_failed = 0;
|
int n_failed = 0, r;
|
||||||
|
|
||||||
assert(head);
|
assert(head);
|
||||||
assert(changed);
|
assert(changed);
|
||||||
|
|
||||||
LIST_FOREACH(swap_device, m, *head) {
|
LIST_FOREACH(swap_device, m, *head) {
|
||||||
log_info("Deactivating swap %s.", m->path);
|
log_info("Deactivating swap %s.", m->path);
|
||||||
if (swapoff(m->path) < 0) {
|
r = RET_NERRNO(swapoff(m->path));
|
||||||
log_warning_errno(errno, "Could not deactivate swap %s: %m", m->path);
|
if (ERRNO_IS_NEG_DEVICE_ABSENT(r))
|
||||||
|
log_debug_errno(r, "Tried to deactivate swap '%s', but swap disappeared by now, ignoring: %m", m->path);
|
||||||
|
else if (r < 0) {
|
||||||
|
log_warning_errno(r, "Could not deactivate swap %s: %m", m->path);
|
||||||
n_failed++;
|
n_failed++;
|
||||||
continue;
|
continue;
|
||||||
}
|
} else
|
||||||
|
|
||||||
*changed = true;
|
*changed = true;
|
||||||
|
|
||||||
swap_device_free(head, m);
|
swap_device_free(head, m);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -143,7 +143,7 @@ static void context_done(Context *c) {
|
||||||
hashmap_free(c->database_by_gid);
|
hashmap_free(c->database_by_gid);
|
||||||
hashmap_free(c->database_by_groupname);
|
hashmap_free(c->database_by_groupname);
|
||||||
|
|
||||||
set_free_free(c->names);
|
set_free(c->names);
|
||||||
uid_range_free(c->uid_range);
|
uid_range_free(c->uid_range);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -231,9 +231,8 @@ static int load_user_database(Context *c) {
|
||||||
if (!n)
|
if (!n)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
/* Note that we use NULL hash_ops (i.e. trivial_hash_ops) here, so identical strings can
|
/* Note that we use trivial_hash_ops_free here, so identical strings can exist in the set. */
|
||||||
* exist in the set. */
|
r = set_ensure_consume(&c->names, &trivial_hash_ops_free, n);
|
||||||
r = set_ensure_consume(&c->names, /* hash_ops= */ NULL, n);
|
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
assert(r > 0); /* The set uses pointer comparisons, so n must not be in the set. */
|
assert(r > 0); /* The set uses pointer comparisons, so n must not be in the set. */
|
||||||
|
@ -274,9 +273,8 @@ static int load_group_database(Context *c) {
|
||||||
if (!n)
|
if (!n)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
/* Note that we use NULL hash_ops (i.e. trivial_hash_ops) here, so identical strings can
|
/* Note that we use trivial_hash_ops_free here, so identical strings can exist in the set. */
|
||||||
* exist in the set. */
|
r = set_ensure_consume(&c->names, &trivial_hash_ops_free, n);
|
||||||
r = set_ensure_consume(&c->names, /* hash_ops= */ NULL, n);
|
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
assert(r > 0); /* The set uses pointer comparisons, so n must not be in the set. */
|
assert(r > 0); /* The set uses pointer comparisons, so n must not be in the set. */
|
||||||
|
|
|
@ -64,7 +64,7 @@ typedef struct SysvStub {
|
||||||
bool loaded;
|
bool loaded;
|
||||||
} SysvStub;
|
} SysvStub;
|
||||||
|
|
||||||
static SysvStub* free_sysvstub(SysvStub *s) {
|
static SysvStub* sysvstub_free(SysvStub *s) {
|
||||||
if (!s)
|
if (!s)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
@ -78,11 +78,12 @@ static SysvStub* free_sysvstub(SysvStub *s) {
|
||||||
strv_free(s->wanted_by);
|
strv_free(s->wanted_by);
|
||||||
return mfree(s);
|
return mfree(s);
|
||||||
}
|
}
|
||||||
DEFINE_TRIVIAL_CLEANUP_FUNC(SysvStub*, free_sysvstub);
|
DEFINE_TRIVIAL_CLEANUP_FUNC(SysvStub*, sysvstub_free);
|
||||||
|
|
||||||
static void free_sysvstub_hashmapp(Hashmap **h) {
|
DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
|
||||||
hashmap_free_with_destructor(*h, free_sysvstub);
|
sysvstub_hash_ops,
|
||||||
}
|
char, string_hash_func, string_compare_func,
|
||||||
|
SysvStub, sysvstub_free);
|
||||||
|
|
||||||
static int add_alias(const char *service, const char *alias) {
|
static int add_alias(const char *service, const char *alias) {
|
||||||
_cleanup_free_ char *link = NULL;
|
_cleanup_free_ char *link = NULL;
|
||||||
|
@ -728,7 +729,7 @@ static int enumerate_sysv(const LookupPaths *lp, Hashmap *all_services) {
|
||||||
|
|
||||||
FOREACH_DIRENT(de, d, log_error_errno(errno, "Failed to enumerate directory %s, ignoring: %m", *path)) {
|
FOREACH_DIRENT(de, d, log_error_errno(errno, "Failed to enumerate directory %s, ignoring: %m", *path)) {
|
||||||
_cleanup_free_ char *fpath = NULL, *name = NULL;
|
_cleanup_free_ char *fpath = NULL, *name = NULL;
|
||||||
_cleanup_(free_sysvstubp) SysvStub *service = NULL;
|
_cleanup_(sysvstub_freep) SysvStub *service = NULL;
|
||||||
struct stat st;
|
struct stat st;
|
||||||
|
|
||||||
if (fstatat(dirfd(d), de->d_name, &st, 0) < 0) {
|
if (fstatat(dirfd(d), de->d_name, &st, 0) < 0) {
|
||||||
|
@ -894,7 +895,7 @@ finish:
|
||||||
}
|
}
|
||||||
|
|
||||||
static int run(const char *dest, const char *dest_early, const char *dest_late) {
|
static int run(const char *dest, const char *dest_early, const char *dest_late) {
|
||||||
_cleanup_(free_sysvstub_hashmapp) Hashmap *all_services = NULL;
|
_cleanup_hashmap_free_ Hashmap *all_services = NULL;
|
||||||
_cleanup_(lookup_paths_done) LookupPaths lp = {};
|
_cleanup_(lookup_paths_done) LookupPaths lp = {};
|
||||||
SysvStub *service;
|
SysvStub *service;
|
||||||
int r;
|
int r;
|
||||||
|
@ -910,7 +911,7 @@ static int run(const char *dest, const char *dest_early, const char *dest_late)
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
all_services = hashmap_new(&string_hash_ops);
|
all_services = hashmap_new(&sysvstub_hash_ops);
|
||||||
if (!all_services)
|
if (!all_services)
|
||||||
return log_oom();
|
return log_oom();
|
||||||
|
|
||||||
|
|
|
@ -193,6 +193,7 @@ simple_tests += files(
|
||||||
'test-user-record.c',
|
'test-user-record.c',
|
||||||
'test-user-util.c',
|
'test-user-util.c',
|
||||||
'test-utf8.c',
|
'test-utf8.c',
|
||||||
|
'test-variadic.c',
|
||||||
'test-verbs.c',
|
'test-verbs.c',
|
||||||
'test-vpick.c',
|
'test-vpick.c',
|
||||||
'test-web-util.c',
|
'test-web-util.c',
|
||||||
|
|
|
@ -1104,7 +1104,7 @@ TEST(fdopen_independent) {
|
||||||
zero(buf);
|
zero(buf);
|
||||||
assert_se(fread(buf, 1, sizeof(buf), f) == strlen(TEST_TEXT));
|
assert_se(fread(buf, 1, sizeof(buf), f) == strlen(TEST_TEXT));
|
||||||
ASSERT_STREQ(buf, TEST_TEXT);
|
ASSERT_STREQ(buf, TEST_TEXT);
|
||||||
assert_se((fcntl(fileno(f), F_GETFL) & O_ACCMODE) == O_RDONLY);
|
assert_se((fcntl(fileno(f), F_GETFL) & O_ACCMODE_STRICT) == O_RDONLY);
|
||||||
assert_se(FLAGS_SET(fcntl(fileno(f), F_GETFD), FD_CLOEXEC));
|
assert_se(FLAGS_SET(fcntl(fileno(f), F_GETFD), FD_CLOEXEC));
|
||||||
f = safe_fclose(f);
|
f = safe_fclose(f);
|
||||||
|
|
||||||
|
@ -1112,7 +1112,7 @@ TEST(fdopen_independent) {
|
||||||
zero(buf);
|
zero(buf);
|
||||||
assert_se(fread(buf, 1, sizeof(buf), f) == strlen(TEST_TEXT));
|
assert_se(fread(buf, 1, sizeof(buf), f) == strlen(TEST_TEXT));
|
||||||
ASSERT_STREQ(buf, TEST_TEXT);
|
ASSERT_STREQ(buf, TEST_TEXT);
|
||||||
assert_se((fcntl(fileno(f), F_GETFL) & O_ACCMODE) == O_RDONLY);
|
assert_se((fcntl(fileno(f), F_GETFL) & O_ACCMODE_STRICT) == O_RDONLY);
|
||||||
assert_se(!FLAGS_SET(fcntl(fileno(f), F_GETFD), FD_CLOEXEC));
|
assert_se(!FLAGS_SET(fcntl(fileno(f), F_GETFD), FD_CLOEXEC));
|
||||||
f = safe_fclose(f);
|
f = safe_fclose(f);
|
||||||
|
|
||||||
|
@ -1120,7 +1120,7 @@ TEST(fdopen_independent) {
|
||||||
zero(buf);
|
zero(buf);
|
||||||
assert_se(fread(buf, 1, sizeof(buf), f) == strlen(TEST_TEXT));
|
assert_se(fread(buf, 1, sizeof(buf), f) == strlen(TEST_TEXT));
|
||||||
ASSERT_STREQ(buf, TEST_TEXT);
|
ASSERT_STREQ(buf, TEST_TEXT);
|
||||||
assert_se((fcntl(fileno(f), F_GETFL) & O_ACCMODE) == O_RDWR);
|
assert_se((fcntl(fileno(f), F_GETFL) & O_ACCMODE_STRICT) == O_RDWR);
|
||||||
assert_se(FLAGS_SET(fcntl(fileno(f), F_GETFD), FD_CLOEXEC));
|
assert_se(FLAGS_SET(fcntl(fileno(f), F_GETFD), FD_CLOEXEC));
|
||||||
f = safe_fclose(f);
|
f = safe_fclose(f);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
|
@ -75,7 +75,7 @@ static LinkConfig* link_config_free(LinkConfig *config) {
|
||||||
erase_and_free(config->wol_password);
|
erase_and_free(config->wol_password);
|
||||||
cpu_set_free(config->rps_cpu_mask);
|
cpu_set_free(config->rps_cpu_mask);
|
||||||
|
|
||||||
ordered_hashmap_free_with_destructor(config->sr_iov_by_section, sr_iov_free);
|
ordered_hashmap_free(config->sr_iov_by_section);
|
||||||
|
|
||||||
return mfree(config);
|
return mfree(config);
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,14 +38,14 @@ directory (`OutputDirectory=`) to point to the other directory using `mkosi/mkos
|
||||||
After the image has been built, the integration tests can be run with:
|
After the image has been built, the integration tests can be run with:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
$ env SYSTEMD_INTEGRATION_TESTS=1 mkosi -f sandbox -- meson test -C build --suite integration-tests --num-processes "$(($(nproc) / 4))"
|
$ mkosi -f sandbox -- meson test -C build --setup=integration --suite integration-tests --num-processes "$(($(nproc) / 4))"
|
||||||
```
|
```
|
||||||
|
|
||||||
As usual, specific tests can be run in meson by appending the name of the test
|
As usual, specific tests can be run in meson by appending the name of the test
|
||||||
which is usually the name of the directory e.g.
|
which is usually the name of the directory e.g.
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
$ env SYSTEMD_INTEGRATION_TESTS=1 mkosi -f sandbox -- meson test -C build -v TEST-01-BASIC
|
$ mkosi -f sandbox -- meson test -C build --setup=integration -v TEST-01-BASIC
|
||||||
```
|
```
|
||||||
|
|
||||||
See `mkosi -f sandbox -- meson introspect build --tests` for a list of tests.
|
See `mkosi -f sandbox -- meson introspect build --tests` for a list of tests.
|
||||||
|
@ -55,7 +55,7 @@ To interactively debug a failing integration test, the `--interactive` option
|
||||||
newer:
|
newer:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
$ env SYSTEMD_INTEGRATION_TESTS=1 mkosi -f sandbox -- meson test -C build -i TEST-01-BASIC
|
$ mkosi -f sandbox -- meson test -C build --setup=integration -i TEST-01-BASIC
|
||||||
```
|
```
|
||||||
|
|
||||||
Due to limitations in meson, the integration tests do not yet depend on the
|
Due to limitations in meson, the integration tests do not yet depend on the
|
||||||
|
@ -64,7 +64,7 @@ running the integration tests. To rebuild the image and rerun a test, the
|
||||||
following command can be used:
|
following command can be used:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
$ mkosi -f sandbox -- meson compile -C build mkosi && env SYSTEMD_INTEGRATION_TESTS=1 mkosi -f sandbox -- meson test -C build -v TEST-01-BASIC
|
$ mkosi -f sandbox -- meson compile -C build mkosi && mkosi -f sandbox -- meson test -C build --setup=integration -v TEST-01-BASIC
|
||||||
```
|
```
|
||||||
|
|
||||||
The integration tests use the same mkosi configuration that's used when you run
|
The integration tests use the same mkosi configuration that's used when you run
|
||||||
|
@ -78,7 +78,7 @@ To iterate on an integration test, let's first get a shell in the integration te
|
||||||
the following:
|
the following:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
$ mkosi -f sandbox -- meson compile -C build mkosi && env SYSTEMD_INTEGRATION_TESTS=1 TEST_SHELL=1 mkosi -f sandbox -- meson test -C build -i TEST-01-BASIC
|
$ mkosi -f sandbox -- meson compile -C build mkosi && mkosi -f sandbox -- meson test -C build --setup=shell -i TEST-01-BASIC
|
||||||
```
|
```
|
||||||
|
|
||||||
This will get us a shell in the integration test environment after booting the machine without running the
|
This will get us a shell in the integration test environment after booting the machine without running the
|
||||||
|
@ -107,7 +107,7 @@ re-running the test will first install the new packages we just built, make a ne
|
||||||
the test again. You can keep running the loop of `mkosi -R`, `systemctl soft-reboot` and
|
the test again. You can keep running the loop of `mkosi -R`, `systemctl soft-reboot` and
|
||||||
`systemctl start ...` until the changes to the integration test are working.
|
`systemctl start ...` until the changes to the integration test are working.
|
||||||
|
|
||||||
If you're debugging a failing integration test (running `meson test --interactive` without `TEST_SHELL`),
|
If you're debugging a failing integration test (running `meson test --interactive`),
|
||||||
there's no need to run `systemctl start ...`, running `systemctl soft-reboot` on its own is sufficient to
|
there's no need to run `systemctl start ...`, running `systemctl soft-reboot` on its own is sufficient to
|
||||||
rerun the test.
|
rerun the test.
|
||||||
|
|
||||||
|
@ -120,10 +120,6 @@ rerun the test.
|
||||||
`TEST_NO_KVM=1`: Disable qemu KVM auto-detection (may be necessary when you're
|
`TEST_NO_KVM=1`: Disable qemu KVM auto-detection (may be necessary when you're
|
||||||
trying to run the *vanilla* qemu and have both qemu and qemu-kvm installed)
|
trying to run the *vanilla* qemu and have both qemu and qemu-kvm installed)
|
||||||
|
|
||||||
`TEST_SHELL=1`: Configure the machine to be more *user-friendly* for
|
|
||||||
interactive debugging (e.g. by setting a usable default terminal, suppressing
|
|
||||||
the shutdown after the test, etc.).
|
|
||||||
|
|
||||||
`TEST_MATCH_SUBTEST=subtest`: If the test makes use of `run_subtests` use this
|
`TEST_MATCH_SUBTEST=subtest`: If the test makes use of `run_subtests` use this
|
||||||
variable to provide a POSIX extended regex to run only subtests matching the
|
variable to provide a POSIX extended regex to run only subtests matching the
|
||||||
expression.
|
expression.
|
||||||
|
|
|
@ -361,7 +361,7 @@ def statfs(path: Path) -> str:
|
||||||
|
|
||||||
def main() -> None:
|
def main() -> None:
|
||||||
parser = argparse.ArgumentParser(description=__doc__)
|
parser = argparse.ArgumentParser(description=__doc__)
|
||||||
parser.add_argument('--mkosi', required=True)
|
parser.add_argument('--mkosi', default=None)
|
||||||
parser.add_argument('--meson-source-dir', required=True, type=Path)
|
parser.add_argument('--meson-source-dir', required=True, type=Path)
|
||||||
parser.add_argument('--meson-build-dir', required=True, type=Path)
|
parser.add_argument('--meson-build-dir', required=True, type=Path)
|
||||||
parser.add_argument('--name', required=True)
|
parser.add_argument('--name', required=True)
|
||||||
|
@ -379,6 +379,12 @@ def main() -> None:
|
||||||
parser.add_argument('mkosi_args', nargs='*')
|
parser.add_argument('mkosi_args', nargs='*')
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
if not args.mkosi:
|
||||||
|
args.mkosi = shutil.which('mkosi')
|
||||||
|
if not args.mkosi:
|
||||||
|
print('Could not find mkosi which is required to run the integration tests', file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
# The meson source directory can either be the top-level repository directory or the
|
# The meson source directory can either be the top-level repository directory or the
|
||||||
# test/integration-tests/standalone subdirectory in the repository directory. The mkosi configuration
|
# test/integration-tests/standalone subdirectory in the repository directory. The mkosi configuration
|
||||||
# will always be a parent directory of one of these directories and at most 4 levels upwards, so don't
|
# will always be a parent directory of one of these directories and at most 4 levels upwards, so don't
|
||||||
|
@ -395,13 +401,6 @@ def main() -> None:
|
||||||
)
|
)
|
||||||
exit(1)
|
exit(1)
|
||||||
|
|
||||||
if not bool(int(os.getenv('SYSTEMD_INTEGRATION_TESTS', '0'))):
|
|
||||||
print(
|
|
||||||
f'SYSTEMD_INTEGRATION_TESTS=1 not found in environment, skipping {args.name}',
|
|
||||||
file=sys.stderr,
|
|
||||||
)
|
|
||||||
exit(77)
|
|
||||||
|
|
||||||
if args.slow and not bool(int(os.getenv('SYSTEMD_SLOW_TESTS', '0'))):
|
if args.slow and not bool(int(os.getenv('SYSTEMD_SLOW_TESTS', '0'))):
|
||||||
print(
|
print(
|
||||||
f'SYSTEMD_SLOW_TESTS=1 not found in environment, skipping {args.name}',
|
f'SYSTEMD_SLOW_TESTS=1 not found in environment, skipping {args.name}',
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||||
|
|
||||||
|
# We'd give these more descriptive names but only alphanumeric characters are allowed.
|
||||||
|
add_test_setup('integration')
|
||||||
|
add_test_setup('shell', env : {'TEST_SHELL' : '1'})
|
||||||
|
|
||||||
integration_test_wrapper = find_program('integration-test-wrapper.py')
|
integration_test_wrapper = find_program('integration-test-wrapper.py')
|
||||||
integration_tests = []
|
integration_tests = []
|
||||||
integration_test_template = {
|
integration_test_template = {
|
||||||
|
@ -129,11 +133,11 @@ foreach integration_test : integration_tests
|
||||||
integration_test_args += ['--skip']
|
integration_test_args += ['--skip']
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if not mkosi.found()
|
if mkosi.found()
|
||||||
continue
|
integration_test_args += ['--mkosi', mkosi.full_path()]
|
||||||
endif
|
endif
|
||||||
|
|
||||||
integration_test_args += ['--mkosi', mkosi.full_path(), '--']
|
integration_test_args += ['--']
|
||||||
|
|
||||||
if integration_test['cmdline'].length() > 0
|
if integration_test['cmdline'].length() > 0
|
||||||
integration_test_args += [
|
integration_test_args += [
|
||||||
|
@ -151,19 +155,12 @@ foreach integration_test : integration_tests
|
||||||
|
|
||||||
integration_test_args += integration_test['mkosi-args']
|
integration_test_args += integration_test['mkosi-args']
|
||||||
|
|
||||||
integration_test_env = {}
|
|
||||||
|
|
||||||
if want_integration_tests
|
|
||||||
integration_test_env += {'SYSTEMD_INTEGRATION_TESTS': '1'}
|
|
||||||
endif
|
|
||||||
|
|
||||||
# We don't explicitly depend on the "mkosi" target because that means the image is rebuilt on every
|
# We don't explicitly depend on the "mkosi" target because that means the image is rebuilt on every
|
||||||
# "ninja -C build". Instead, the mkosi target has to be rebuilt manually before running the
|
# "ninja -C build". Instead, the mkosi target has to be rebuilt manually before running the
|
||||||
# integration tests with mkosi.
|
# integration tests with mkosi.
|
||||||
test(
|
test(
|
||||||
integration_test['name'],
|
integration_test['name'],
|
||||||
integration_test_wrapper,
|
integration_test_wrapper,
|
||||||
env : integration_test_env,
|
|
||||||
args : integration_test_args,
|
args : integration_test_args,
|
||||||
timeout : integration_test['timeout'],
|
timeout : integration_test['timeout'],
|
||||||
priority : integration_test['priority'],
|
priority : integration_test['priority'],
|
||||||
|
|
|
@ -16,7 +16,6 @@ project('systemd-testsuite',
|
||||||
|
|
||||||
fs = import('fs')
|
fs = import('fs')
|
||||||
mkosi = find_program('mkosi', required : true)
|
mkosi = find_program('mkosi', required : true)
|
||||||
want_integration_tests = true
|
|
||||||
|
|
||||||
# meson refuses .. in subdir() so we use a symlink to trick it into accepting it anyway.
|
# meson refuses .. in subdir() so we use a symlink to trick it into accepting it anyway.
|
||||||
subdir('integration-tests')
|
subdir('integration-tests')
|
||||||
|
|
Loading…
Reference in New Issue