Compare commits

...

40 Commits

Author SHA1 Message Date
ZIHCO 3d01d605c8
Merge 695d64bf2b into 39dd06dbc4 2025-04-18 09:36:38 +02:00
Yu Watanabe 39dd06dbc4 meson: build tests for nspawn even -Dnspawn= is disabled
Follow-up for d95818f522.
Fixes #36880.
2025-04-18 09:03:33 +02:00
Zbigniew Jędrzejewski-Szmek a30684b983
udev: several follow-ups for recent change about listening fds (#37162) 2025-04-18 08:48:08 +02:00
Yu Watanabe 8e7ef6abb8 NEWS: mention integration-tests meson option is deprecated
Follow-up for 710653d3bc.
2025-04-18 09:36:29 +09:00
Yu Watanabe f6a2a9ba93 daemon-util: remove existing fds with the same name from fdstore
Currently, all use cases of notify_push_fd()/notify_push_fdf()
assume that the name of each fd in the fdstore is unique.
For safety, let's remove the existing fds before pushing a new one
to avoid multiple fds with the same name stored in the fdstore.
2025-04-18 09:12:43 +09:00
Yu Watanabe 1785961660 udev: re-add unintentionally dropped error log
Follow-up for 9b6bf4e10e.
2025-04-18 09:06:09 +09:00
LuK1337 edc49209f1 rules: Make ADB and fastboot work out-of-the-box
d0db47dcdf/adb.h (199)
7199051aaf/fastboot/fastboot.cpp (244)
2025-04-18 06:06:35 +09:00
Lennart Poettering 2791b2bc3d shutdown: handle gracefully if a device disappears while we detach it
Let's gracefully handle cases where a device disappears in the time we
between our discovery and when we want to detach it, due to "auto-clear"
or a similar logic.

The loopback case already handled this quite OK, do the same for MD and
swap too.

Switch to ERRNO_IS_DEVICE_ABSENT() for all checks, just in case.

Also improve debug logging for all these cases, so we know exactly what
is going on.

This is inspired by #37160, but shouldn't really fix anything there, I
am pretty sure the ENODEV seen in that output stems from the STOP_ARRAY
call, not from the open().

Note that this does not change anything for the device mapper case,
because the DM subsystem does not return useful error codes to
userspace, hence everything is a complete mess there.
2025-04-18 06:03:03 +09:00
Yu Watanabe 7baf24c949
network/manager: hash_ops related cleanups (#37121) 2025-04-18 06:00:15 +09:00
Yu Watanabe ce921df8d1
network/network: hash_ops related cleanups (#37120) 2025-04-18 05:59:47 +09:00
Yu Watanabe c96a5d9912
misc: hash_ops related cleanups (#37117) 2025-04-18 05:59:15 +09:00
Yu Watanabe 6858c1fd8b
libudev: several trivial cleanups (#37106) 2025-04-18 05:58:41 +09:00
Stefan Hansson b1236ce38b missing_fcntl: Introduce O_ACCMODE_STRICT
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 causes problems for systemd on musl, as it changes the
behaviour of open_mkdir_at_full() to return -EINVAL if O_PATH is
included in flags due to the fact that O_ACCMODE includes O_SEARCH
(i.e. O_PATH). Consequently, this makes the test-fs-util test fail.

Upstream musl seems content with this behaviour and doesn't seem
interested in matching glibc's behaviour due to that defining it this
way allows for O_SEARCH to match POSIX better by allowing it to open
directories where read permission is missing. Apparently musl does some
emulation in other places to make this work more consistently as well.

Initially I took the approach of working around this by redefining
O_SEARCH as O_RDONLY if O_SEARCH == O_PATH. This fixes the test and is
the approach taken by both XZ[1] and Gzip[2][3], but was not taken as
redefining system headers potentially could be problematic.

Instead, introduce O_ACCMODE_STRICT which just is a copy of glibc's
O_ACCMODE and use it everywhere. This way we don't have to deal with
unusual definitions of O_ACCMODE from C standard libraries other than
glibc.

 [1]: https://git.tukaani.org/?p=xz.git;a=blob;f=src/xz/file_io.c;h=8c83269b13fa31284f7ea5f3627a1dfbce7d6e14;hb=HEAD#l72
 [2]: https://git.savannah.gnu.org/cgit/gnulib.git/tree/lib/fcntl.in.h
      (lines 380 and 396, commit d7f551b30f3f2a0fa57c1b10c12f4eea41a9b89e)
 [3]: https://lists.gnu.org/archive/html/bug-gzip/2025-01/msg00000.html
2025-04-18 05:22:06 +09:00
Daan De Meyer 710653d3bc test: Use meson add_test_setup() instead of environment variables
We add a default test setup that excludes the integration-tests suite
so that the integration tests don't run by default. This allows us to
get rid of $SYSTEMD_INTEGRATION_TESTS. Then, we add two extra setups:
'integration' and 'shell'. The 'integration' setup does not exclude the
integration-tests suite, and so can be used to run the integration tests.
The 'shell' setup does the same, but additionally sets $TEST_SHELL=1,
allowing to get rid of $TEST_SHELL in the docs.
2025-04-17 20:31:08 +02:00
Daan De Meyer d9826d303b mkosi: update mkosi commit reference to dbb4020beee2cdf250f93a425794f1cf8b0fe693
* dbb4020bee mkosi: Use tools tree by default in repository config
* a2407a305c dnf: Stop messing around with plugins
* eee382ebc6 Fix mkosi help
* 8d4f9969bb mkosi-obs: simplify generation of signed UEFI auth files
*   364dfc65eb Merge pull request #3661 from septatrix/ssh-runtime
|\
| * ab3b52841c Improve Ssh= documentation
| * 79878d7e6c Add new Ssh=auto and Ssh=runtime options
*   49036322c2 Merge pull request #3682 from DaanDeMeyer/history
|\
| * 96e512fe6e installer: Make sure package manager state is preserved in the image
| * b859a7cf0a Only copy repository metadata from specific subdirs from /var
| * c8bf8e4278 Rename cache_subdirs() to package_subdirs()
* |   54b59c4a2e Merge pull request #3696 from DaanDeMeyer/history-cli
|\ \
| * | 898d89e887 Rework version bumping
| * | cc45fe3bad Only write CLI arguments to history instead of full config
| * | 1def443097 Disallow using --rerun-build-scripts with --force again
| * | 87b03ee264 Rename get_configdir() to finalize_configdir()
| * | 9c1217a217 Get rid of to_json() methods on Args and Config
| |/
* | 124f551e77 mkosi-obs: do not publish roothash
* | fc86100e51 mkosi-obs: append certs from mkosi.uefi.db/ to 'db'
* | 8bee4cb8e2 Make sure sync scripts are executable
|/
* a7e90514fa Simplify tools tree out of date error
* f9956daba7 Fail if --rerun-build-scripts is used and tools is out of date
* d94bf56ae8 mkosi-initrd: add specific configuration for plymouth in Debian
* 8235ddbc5b Take shared lock in copy_ephemeral()
* 19c74d5ba5 Two follow ups for #3678
*   0d6f15e8c3 Merge pull request #3678 from DaanDeMeyer/history
|\
| * 5410c4c7af tests: Require genkey to be run once upfront
| * 86b8c611a1 tests: Drop unused tools field
| * c3d1bd0dde Rework history <=> sandbox integration
* fce4db970f zypper: display debugging output if ARG_DEBUG is set
* 2c052b9d45 Allow PCR signing settings to be overridden in sub-images
* 00c220225b zypper: do not fail if a package configured to be removed is not found
2025-04-17 18:30:17 +01:00
Luca Boccassi 10ed8cda58 Revert "mkosi: temporarily disable panic_on_warn"
The BRTFS issue that caused a spurious WARN has been fixed and
backported to Noble, so we can enable panic_on_warm again.

This reverts commit 930d65ccca.
2025-04-17 17:03:47 +01:00
ZIHCO 695d64bf2b machine-info: implement the etc/machine-info field for ANSI color 2025-04-15 16:58:35 +01:00
Yu Watanabe 52278e0634 network/wiphy: use hash_ops with destructor for managing Wiphy objects 2025-04-13 10:15:02 +09:00
Yu Watanabe 4cf443e644 network/link: use hash_ops with destructor for managing Link objects 2025-04-13 10:15:02 +09:00
Yu Watanabe a85f73fa55 network/network: use hash_ops with destructor for managing Network objects 2025-04-13 10:15:02 +09:00
Yu Watanabe 09ddaf2af3 hashmap: introduce ordered_hashmap_free_and_replace() 2025-04-13 10:15:02 +09:00
Yu Watanabe 919aeb666a network/network: use hash_ops with destructor for managing stacked netdevs 2025-04-13 10:15:02 +09:00
Yu Watanabe 1b25b88f82 network/bridge-fdb,mdb: use hash_ops with destructor 2025-04-13 10:10:29 +09:00
Yu Watanabe 5c6e6f5ad1 network/dhcp-server: use hash_ops with destructor for static lease 2025-04-13 10:10:29 +09:00
Yu Watanabe 10d786458c network/radv: use hash_ops with destructor for managing prefixes 2025-04-13 10:10:29 +09:00
Yu Watanabe d3af116afd network,udev: use hash_ops with destructor to manage SR-IOV configs 2025-04-13 10:09:53 +09:00
Yu Watanabe 32b5deb1b2 network/ndisc: replace set_free_free() with set_free()
They uses in_addr_prefix_hash_ops_free, hence set_free() is enough.
2025-04-13 10:09:45 +09:00
Yu Watanabe 6d1a69d0f0 network: use in6_addr_hash_ops_free in Network.ipv6_proxy_ndp_addresses
This also one adjustment to network_adjust_ipv6_proxy_ndp().
2025-04-13 10:09:45 +09:00
Yu Watanabe 25a9bd72ef network: use dns_name_hash_ops_free in dnssec negative trust anchors 2025-04-13 10:09:45 +09:00
Yu Watanabe 4100e0f207 sysv-generator: introduce hash_ops for SysvStub
This also renames free_sysvstub() -> sysvstub_free(), to follow our
usual coding style.
2025-04-13 10:00:57 +09:00
Yu Watanabe 765ffa12ee sysusers: use trivial_hash_ops_free for storing user/group name 2025-04-13 10:00:57 +09:00
Yu Watanabe 5f43554f90 sd-netlink: introduce custom hash_ops for GenericNetlinkFamily 2025-04-13 10:00:57 +09:00
Yu Watanabe 70669fa2fe sd-device-enumerator: use custom hash_ops with destructor 2025-04-13 10:00:57 +09:00
Yu Watanabe f92fac7e9b sd-device: replace set_free_free() with set_free()
These uses string_hash_ops_free, hence not set_free() is enough.
2025-04-13 10:00:57 +09:00
Yu Watanabe 855800aaec coredump: replace custom cleanup function with specific hash_ops with destructor 2025-04-13 10:00:57 +09:00
Yu Watanabe f8b0277101 analyze: replace set_free_free() with set_free()
set_put_strdup() uses &string_hash_ops_free, hence set_free() also
frees stored contents.
2025-04-13 10:00:57 +09:00
Yu Watanabe 9ee08c8dce libudev: use 'type* func()' style rather than 'type *func()' 2025-04-12 22:30:57 +09:00
Yu Watanabe 19aa8c0f0e libudev-list: use strdup_to()
No functional change, just refactoring.
2025-04-12 22:30:57 +09:00
Yu Watanabe 3e8a4defa8 libudev-list: use hashmap_dump_sorted() 2025-04-12 22:30:57 +09:00
Yu Watanabe 76a8f5ae4b libudev-list: use custom hash_ops with destructor for udev_list_entry 2025-04-12 22:30:57 +09:00
72 changed files with 653 additions and 391 deletions

View File

@ -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))" \

View File

@ -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
View File

@ -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:

View File

@ -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']

View File

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

View File

@ -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
@ -78,8 +78,7 @@ KernelCommandLine=
oops=panic oops=panic
panic=-1 panic=-1
softlockup_panic=1 softlockup_panic=1
# Disabled due to BTRFS issue, waiting for the fix to become available panic_on_warn=1
panic_on_warn=0
psi=1 psi=1
mitigations=off mitigations=off

View File

@ -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"

View File

@ -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(

View File

@ -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:

View File

@ -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

View File

@ -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) {

View File

@ -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)

View File

@ -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;

View File

@ -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();

View File

@ -15,6 +15,7 @@
#include "bus-get-properties.h" #include "bus-get-properties.h"
#include "bus-log-control-api.h" #include "bus-log-control-api.h"
#include "bus-polkit.h" #include "bus-polkit.h"
#include "color-util.h"
#include "constants.h" #include "constants.h"
#include "daemon-util.h" #include "daemon-util.h"
#include "device-private.h" #include "device-private.h"
@ -62,6 +63,7 @@ typedef enum {
PROP_LOCATION, PROP_LOCATION,
PROP_HARDWARE_VENDOR, PROP_HARDWARE_VENDOR,
PROP_HARDWARE_MODEL, PROP_HARDWARE_MODEL,
PROP_ANSI_COLOR,
/* Read from /etc/os-release (or /usr/lib/os-release) */ /* Read from /etc/os-release (or /usr/lib/os-release) */
PROP_OS_PRETTY_NAME, PROP_OS_PRETTY_NAME,
@ -166,7 +168,8 @@ static void context_read_machine_info(Context *c) {
(UINT64_C(1) << PROP_DEPLOYMENT) | (UINT64_C(1) << PROP_DEPLOYMENT) |
(UINT64_C(1) << PROP_LOCATION) | (UINT64_C(1) << PROP_LOCATION) |
(UINT64_C(1) << PROP_HARDWARE_VENDOR) | (UINT64_C(1) << PROP_HARDWARE_VENDOR) |
(UINT64_C(1) << PROP_HARDWARE_MODEL)); (UINT64_C(1) << PROP_HARDWARE_MODEL) |
(UINT64_C(1) << PROP_ANSI_COLOR));
r = parse_env_file(NULL, "/etc/machine-info", r = parse_env_file(NULL, "/etc/machine-info",
"PRETTY_HOSTNAME", &c->data[PROP_PRETTY_HOSTNAME], "PRETTY_HOSTNAME", &c->data[PROP_PRETTY_HOSTNAME],
@ -175,7 +178,8 @@ static void context_read_machine_info(Context *c) {
"DEPLOYMENT", &c->data[PROP_DEPLOYMENT], "DEPLOYMENT", &c->data[PROP_DEPLOYMENT],
"LOCATION", &c->data[PROP_LOCATION], "LOCATION", &c->data[PROP_LOCATION],
"HARDWARE_VENDOR", &c->data[PROP_HARDWARE_VENDOR], "HARDWARE_VENDOR", &c->data[PROP_HARDWARE_VENDOR],
"HARDWARE_MODEL", &c->data[PROP_HARDWARE_MODEL]); "HARDWARE_MODEL", &c->data[PROP_HARDWARE_MODEL],
"ANSI_COLOR", &c->data[PROP_ANSI_COLOR]);
if (r < 0 && r != -ENOENT) if (r < 0 && r != -ENOENT)
log_warning_errno(r, "Failed to read /etc/machine-info, ignoring: %m"); log_warning_errno(r, "Failed to read /etc/machine-info, ignoring: %m");
@ -488,6 +492,35 @@ static bool valid_deployment(const char *deployment) {
return in_charset(deployment, VALID_DEPLOYMENT_CHARS); return in_charset(deployment, VALID_DEPLOYMENT_CHARS);
} }
static const char* fallback_ansi_color(Context *c) {
uint64_t hash;
const uint8_t key[16] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f};
double h, s = 0.7, v = 0.9;
uint8_t r, g, b;
const char* hostname;
_cleanup_free_ char *color = NULL;
int k;
struct siphash state;
assert(c);
hostname = isempty(c->data[PROP_STATIC_HOSTNAME_SUBSTITUTED_WILDCARDS]) ? \
"localhost" : c->data[PROP_STATIC_HOSTNAME_SUBSTITUTED_WILDCARDS];
siphash24_init(&state, key);
string_hash_func(hostname, &state);
hash = siphash24_finalize(&state);
h = (double)(hash % 360);
hsv_to_rgb(h, s, v, &r, &g, &b);
k = asprintf(&color, "38;2;%u;%u;%u", r, g, b);
if (k < 0) {
log_oom();
return NULL;
}
return color;
}
static const char* fallback_chassis_by_virtualization(void) { static const char* fallback_chassis_by_virtualization(void) {
Virtualization v = detect_virtualization(); Virtualization v = detect_virtualization();
if (v < 0) { if (v < 0) {
@ -772,6 +805,7 @@ static int context_write_data_machine_info(Context *c) {
[PROP_CHASSIS] = "CHASSIS", [PROP_CHASSIS] = "CHASSIS",
[PROP_DEPLOYMENT] = "DEPLOYMENT", [PROP_DEPLOYMENT] = "DEPLOYMENT",
[PROP_LOCATION] = "LOCATION", [PROP_LOCATION] = "LOCATION",
[PROP_ANSI_COLOR] = "ANSI_COLOR",
}; };
_cleanup_strv_free_ char **l = NULL; _cleanup_strv_free_ char **l = NULL;
int r; int r;
@ -786,7 +820,7 @@ static int context_write_data_machine_info(Context *c) {
if (r < 0 && r != -ENOENT) if (r < 0 && r != -ENOENT)
return r; return r;
for (int p = PROP_PRETTY_HOSTNAME; p <= PROP_LOCATION; p++) { for (int p = PROP_PRETTY_HOSTNAME; p <= PROP_ANSI_COLOR; p++) {
assert(name[p]); assert(name[p]);
r = strv_env_assign(&l, name[p], empty_to_null(c->data[p])); r = strv_env_assign(&l, name[p], empty_to_null(c->data[p]));
@ -810,6 +844,30 @@ static int context_write_data_machine_info(Context *c) {
return 0; return 0;
} }
static int property_get_ansi_color(
sd_bus *bus,
const char *path,
const char *interface,
const char *property,
sd_bus_message *reply,
void *userdata,
sd_bus_error *error) {
Context *c = ASSERT_PTR(userdata);
_cleanup_free_ char *fallback = NULL;
const char *color;
context_read_etc_hostname(c);
context_read_machine_info(c);
if (isempty(c->data[PROP_ANSI_COLOR]))
color = fallback_ansi_color(c);
else
color = c->data[PROP_ANSI_COLOR];
return sd_bus_message_append(reply, "s", color);
}
static int property_get_hardware_property( static int property_get_hardware_property(
sd_bus_message *reply, sd_bus_message *reply,
Context *c, Context *c,
@ -1241,6 +1299,122 @@ static int validate_and_substitute_hostname(const char *name, char **ret_substit
return 1; return 1;
} }
static bool validate_ansi_color(const char *color) {
if (isempty(color))
return true;
if (string_has_cc(color, NULL))
return false;
_cleanup_strv_free_ char **parts = NULL;
int r = strv_split_full(&parts, color, ";", EXTRACT_DONT_COALESCE_SEPARATORS);
if (r < 0)
return false;
if (strv_length(parts) < 2)
return false;
unsigned code;
r = safe_atou(parts[0], &code);
if (r < 0)
return false;
if (code == 0) {
if (strv_length(parts) != 2)
return false;
r = safe_atou(parts[1], &code);
if (r < 0 || code > 255)
return false;
return true;
}
if (code == 38 || code == 48) {
r = safe_atou(parts[1], &code);
if (r < 0 || (code != 2 && code != 5))
return false;
if (code == 2) {
if (strv_length(parts) != 5)
return false;
for (int i = 2; i < 5; i++) {
r = safe_atou(parts[i], &code);
if (r < 0 || code > 255)
return false;
}
return true;
}
if (code == 5) {
if (strv_length(parts) != 3)
return false;
r = safe_atou(parts[2], &code);
if (r < 0 || code > 255)
return false;
return true;
}
}
return false;
}
static int method_set_ansi_color(sd_bus_message *m,void *userdata, sd_bus_error *error) {
Context *c = ASSERT_PTR(userdata);
const char *color;
int interactive, r;
assert(m);
r = sd_bus_message_read(m, "sb", &color, &interactive);
if (r < 0)
return r;
color = empty_to_null(color);
context_read_machine_info(c);
if (streq_ptr(color, c->data[PROP_ANSI_COLOR]))
return sd_bus_reply_method_return(m, NULL);
if (!isempty(color) && !validate_ansi_color(color))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid ANSI color '%s'", color);
r = bus_verify_polkit_async_full(
m,
"org.freedesktop.hostname1.set-machine-info",
NULL,
UID_INVALID,
interactive ? POLKIT_ALLOW_INTERACTIVE : 0,
&c->polkit_registry,
error);
if (r < 0)
return r;
if (r == 0)
return 1;
r = free_and_strdup_warn(&c->data[PROP_ANSI_COLOR], color);
if (r < 0)
return r;
r = context_write_data_machine_info(c);
if (r < 0) {
log_error_errno(r, "Failed to write machine info: %m");
if (ERRNO_IS_PRIVILEGE(r))
return sd_bus_error_set(error, BUS_ERROR_FILE_IS_PROTECTED, "Not allowed to update /etc/machine-info.");
if (r == -EROFS)
return sd_bus_error_set(error, BUS_ERROR_READ_ONLY_FILESYSTEM, "/etc/machine-info is in a read-only filesystem.");
return sd_bus_error_set_errnof(error, r, "Failed to write machine info: %m");
}
log_info("Changed ANSI color to '%s'", strna(c->data[PROP_ANSI_COLOR]));
(void) sd_bus_emit_properties_changed(
sd_bus_message_get_bus(m),
"/org/freedesktop/hostname1",
"org.freedesktop.hostname1",
"AnsiColor",
NULL);
return sd_bus_reply_method_return(m, NULL);
}
static int method_set_hostname(sd_bus_message *m, void *userdata, sd_bus_error *error) { static int method_set_hostname(sd_bus_message *m, void *userdata, sd_bus_error *error) {
Context *c = ASSERT_PTR(userdata); Context *c = ASSERT_PTR(userdata);
const char *name; const char *name;
@ -1535,7 +1709,7 @@ static int method_get_hardware_serial(sd_bus_message *m, void *userdata, sd_bus_
static int build_describe_response(Context *c, bool privileged, sd_json_variant **ret) { static int build_describe_response(Context *c, bool privileged, sd_json_variant **ret) {
_cleanup_free_ char *hn = NULL, *dhn = NULL, *in = NULL, _cleanup_free_ char *hn = NULL, *dhn = NULL, *in = NULL,
*chassis = NULL, *vendor = NULL, *model = NULL, *serial = NULL, *firmware_version = NULL, *chassis = NULL, *vendor = NULL, *model = NULL, *serial = NULL, *firmware_version = NULL,
*firmware_vendor = NULL, *chassis_asset_tag = NULL; *firmware_vendor = NULL, *chassis_asset_tag = NULL, *ansi_color = NULL;
_cleanup_strv_free_ char **os_release_pairs = NULL, **machine_info_pairs = NULL; _cleanup_strv_free_ char **os_release_pairs = NULL, **machine_info_pairs = NULL;
usec_t firmware_date = USEC_INFINITY, eol = USEC_INFINITY; usec_t firmware_date = USEC_INFINITY, eol = USEC_INFINITY;
_cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL; _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
@ -1626,6 +1800,7 @@ static int build_describe_response(Context *c, bool privileged, sd_json_variant
SD_JSON_BUILD_PAIR_STRING("HardwareSerial", serial), SD_JSON_BUILD_PAIR_STRING("HardwareSerial", serial),
SD_JSON_BUILD_PAIR_STRING("FirmwareVersion", firmware_version), SD_JSON_BUILD_PAIR_STRING("FirmwareVersion", firmware_version),
SD_JSON_BUILD_PAIR_STRING("FirmwareVendor", firmware_vendor), SD_JSON_BUILD_PAIR_STRING("FirmwareVendor", firmware_vendor),
SD_JSON_BUILD_PAIR_STRING("AnsiColor", ansi_color ?: c->data[PROP_ANSI_COLOR]),
JSON_BUILD_PAIR_FINITE_USEC("FirmwareDate", firmware_date), JSON_BUILD_PAIR_FINITE_USEC("FirmwareDate", firmware_date),
SD_JSON_BUILD_PAIR_ID128("MachineID", machine_id), SD_JSON_BUILD_PAIR_ID128("MachineID", machine_id),
SD_JSON_BUILD_PAIR_ID128("BootID", boot_id), SD_JSON_BUILD_PAIR_ID128("BootID", boot_id),
@ -1702,6 +1877,7 @@ static const sd_bus_vtable hostname_vtable[] = {
SD_BUS_PROPERTY("BootID", "ay", property_get_boot_id, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("BootID", "ay", property_get_boot_id, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("VSockCID", "u", property_get_vsock_cid, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("VSockCID", "u", property_get_vsock_cid, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("ChassisAssetTag", "s", property_get_chassis_asset_tag, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("ChassisAssetTag", "s", property_get_chassis_asset_tag, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("AnsiColor", "s", property_get_ansi_color, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_METHOD_WITH_ARGS("SetHostname", SD_BUS_METHOD_WITH_ARGS("SetHostname",
SD_BUS_ARGS("s", hostname, "b", interactive), SD_BUS_ARGS("s", hostname, "b", interactive),
@ -1754,6 +1930,12 @@ static const sd_bus_vtable hostname_vtable[] = {
method_describe, method_describe,
SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD_WITH_ARGS("SetAniColor",
SD_BUS_ARGS("s", color, "b", interactive),
SD_BUS_NO_RESULT,
method_set_ansi_color,
SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_VTABLE_END, SD_BUS_VTABLE_END,
}; };

View File

@ -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)

View File

@ -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++;

View File

@ -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"))

View File

@ -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;
} }

View File

@ -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;

View File

@ -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;

View File

@ -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]);
} }

View File

@ -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;
} }

View File

@ -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;
} }

View File

@ -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__));

View File

@ -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;

View File

@ -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;

View File

@ -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;
} }

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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();
} }

View File

@ -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;
} }

View File

@ -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)

View File

@ -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");

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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)

View File

@ -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);

View File

@ -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);
} }

View File

@ -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;

View File

@ -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);

View File

@ -1,9 +1,5 @@
# SPDX-License-Identifier: LGPL-2.1-or-later # SPDX-License-Identifier: LGPL-2.1-or-later
if conf.get('ENABLE_NSPAWN') != 1
subdir_done()
endif
libnspawn_core_sources = files( libnspawn_core_sources = files(
'nspawn-bind-user.c', 'nspawn-bind-user.c',
'nspawn-cgroup.c', 'nspawn-cgroup.c',
@ -52,6 +48,7 @@ executables += [
executable_template + { executable_template + {
'name' : 'systemd-nspawn', 'name' : 'systemd-nspawn',
'public' : true, 'public' : true,
'conditions' : ['ENABLE_NSPAWN'],
'sources' : files('nspawn.c'), 'sources' : files('nspawn.c'),
'link_with' : nspawn_libs, 'link_with' : nspawn_libs,
'dependencies' : [ 'dependencies' : [

View File

@ -56,6 +56,9 @@ int notify_push_fd(int fd, const char *name) {
if (!state) if (!state)
return -ENOMEM; return -ENOMEM;
/* Remove existing fds with the same name in fdstore. */
(void) notify_remove_fd_warn(name);
return sd_pid_notify_with_fds(0, /* unset_environment = */ false, state, &fd, 1); return sd_pid_notify_with_fds(0, /* unset_environment = */ false, state, &fd, 1);
} }

View File

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

View File

@ -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)

View File

@ -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,
}, },

View File

@ -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);

View File

@ -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);

View File

@ -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

View File

@ -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);
} }

View File

@ -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);
} }

View File

@ -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. */

View File

@ -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();

View File

@ -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);
} }

View File

@ -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);
} }

View File

@ -553,9 +553,6 @@ int manager_serialize_config(Manager *manager) {
if (r < 0) if (r < 0)
return log_warning_errno(r, "Failed to finalize serialization file: %m"); return log_warning_errno(r, "Failed to finalize serialization file: %m");
/* Remove the previous serialization to make it replaced with the new one. */
(void) notify_remove_fd_warn("config-serialization");
r = notify_push_fd(fileno(f), "config-serialization"); r = notify_push_fd(fileno(f), "config-serialization");
if (r < 0) if (r < 0)
return log_warning_errno(r, "Failed to push serialization fd to service manager: %m"); return log_warning_errno(r, "Failed to push serialization fd to service manager: %m");

View File

@ -1166,7 +1166,7 @@ static int manager_listen_fds(Manager *manager) {
int n = sd_listen_fds_with_names(/* unset_environment = */ true, &names); int n = sd_listen_fds_with_names(/* unset_environment = */ true, &names);
if (n < 0) if (n < 0)
return n; return log_error_errno(n, "Failed to listen on fds: %m");
for (int i = 0; i < n; i++) { for (int i = 0; i < n; i++) {
int fd = SD_LISTEN_FDS_START + i; int fd = SD_LISTEN_FDS_START + i;

View File

@ -60,7 +60,7 @@ sanitize_address_undefined = custom_target(
'fuzzers', 'fuzzers',
' '.join(fuzz_c_args + '-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION'), ' '.join(fuzz_c_args + '-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION'),
' '.join(fuzz_cpp_args + '-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION'), ' '.join(fuzz_cpp_args + '-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION'),
'-Dfuzz-tests=true -Db_lundef=false -Db_sanitize=address,undefined -Dnspawn=enabled --optimization=@0@ @1@ --auto-features=@2@'.format( '-Dfuzz-tests=true -Db_lundef=false -Db_sanitize=address,undefined --optimization=@0@ @1@ --auto-features=@2@'.format(
get_option('optimization'), get_option('optimization'),
get_option('werror') ? '--werror' : '', get_option('werror') ? '--werror' : '',
sanitize_auto_features sanitize_auto_features

View File

@ -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.

View File

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

View File

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

View File

@ -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')