Compare commits

...

40 Commits

Author SHA1 Message Date
Tuetuopay 17f0c71b62
Merge 9bc9b2e7bc into 39dd06dbc4 2025-04-18 09:37:31 +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
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
Tuetuopay 9bc9b2e7bc networkd/dhcp: copy dhcp-relay options in the request
With DHCP option concatenation being implemented using a new buffer,
code receives a temporary pointer whose lifetime is now much shorter.
Holding onto pointers to this buffer is invalid as it is freed as soon
as the options have finished parsing.

In the case of dhcp-relay related options, copy the memory in a
dedicated buffer to ensure proper lifetimes.
2025-04-03 10:59:20 +02:00
Tuetuopay 8289f8d88a networkd/dhcp: implement RFC3396 splitting for large DHCP options
A DHCP option is 255 bytes at most. However, some values may need more
data (e.g. Option 121 "Classless Static Routes"), for which the option
body has to be split in multiple option instances on the wire.

This patch implements option splitting on the wire in two scenarios:

- spreading the option across multiple instances when it takes up more
  than 255 bytes
- spreading the option across multiple buffers (e.g. options and file)
  when it does not fit in what's left
2025-04-03 10:59:20 +02:00
Tuetuopay e067c3d570 networkd/dhcp: implement draft-tojens-dhcp-option-concat-considerations
After RFC3396 got published, the real-world hit, and a finer-grained
strategy for concatenation was needed than "concatenate everything".

The draft (1) implements a few broad categories, from which is is easy
to define a concatenate-or-not strategy for each DHCP option. Long story
short, fixed-length options are not concatenated, while any
dynamic-length option are.

Please note that the classification is *unopinionated* as to the
behavior for each option. No attempts were made at making exceptions for
specific option types (e.g. long fixed-length options) as to keep the
implementation simple. However, efforts were made for easy iteration,
should any option be an exception.

1: https://www.ietf.org/archive/id/draft-tojens-dhcp-option-concat-considerations-01.html
2025-04-03 10:59:20 +02:00
Tuetuopay 734aa641d0 networkd/dhcp: implement RFC3396 for large DHCP options
A DHCP option is 255 bytes at most. However, some values may need more
data (e.g. Option 121 "Classless Static Routes"), for which the option
body is split in multiple option instances on the wire.

While the current implementation works well when the serializer splits
the option at logical boundaries (e.g. at the bounds of a whole route),
it fails as soon as it is split at arbitrary bytes boundaries.

This patch implements the aggregation of the option buffers in a single
large buffer as per the RFC, which is then fed to the actual parsing
functions.

Note: some options *require* support for concatenations, some of which
are already supported by networkd (opt 121 being a prime example).
2025-04-03 10:59:20 +02:00
71 changed files with 1228 additions and 403 deletions

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
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>
CHANGES WITH 257:

View File

@ -77,6 +77,20 @@ ENV{DDC_DEVICE}=="?*", TAG+="uaccess"
# media player raw devices (for user-mode drivers, Android SDK, etc.)
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
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
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"

View File

@ -31,7 +31,7 @@ static void log_syntax_callback(const char *unit, int level, void *userdata) {
r = set_put_strdup(s, unit);
if (r < 0) {
set_free_free(*s);
set_free(*s);
*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) {
if (*s == POINTER_MAX)
return;
set_free_free(*s);
set_free(*s);
}
int verify_units(

View File

@ -1001,13 +1001,13 @@ int fd_verify_safe_flags_full(int fd, int extra_flags) {
if (flags < 0)
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)
return log_debug_errno(SYNTHETIC_ERRNO(EREMOTEIO),
"Unexpected flags set for extrinsic fd: 0%o",
(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) {
@ -1132,7 +1132,7 @@ int fds_are_same_mount(int fd1, int fd2) {
}
const char* accmode_to_string(int flags) {
switch (flags & O_ACCMODE) {
switch (flags & O_ACCMODE_STRICT) {
case O_RDONLY:
return "ro";
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))
return -EINVAL;
if ((flags & O_ACCMODE) != O_RDONLY)
if ((flags & O_ACCMODE_STRICT) != O_RDONLY)
return -EINVAL;
/* Note that O_DIRECTORY|O_NOFOLLOW is implied, but we allow specifying it anyway. The following

View File

@ -88,8 +88,10 @@ OrderedHashmap* _ordered_hashmap_new(const struct hash_ops *hash_ops HASHMAP_DE
#define hashmap_new(ops) _hashmap_new(ops HASHMAP_DEBUG_SRC_ARGS)
#define ordered_hashmap_new(ops) _ordered_hashmap_new(ops HASHMAP_DEBUG_SRC_ARGS)
#define hashmap_free_and_replace(a, b) \
#define hashmap_free_and_replace(a, b) \
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);
static inline Hashmap* hashmap_free(Hashmap *h) {

View File

@ -43,3 +43,9 @@
#ifndef AT_HANDLE_FID
#define AT_HANDLE_FID AT_REMOVEDIR
#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);
if (IN_SET(flags & O_ACCMODE, O_WRONLY, O_RDWR))
if (IN_SET(flags & O_ACCMODE_STRICT, O_WRONLY, O_RDWR))
flags |= O_CREAT;
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)
return r;
if ((flags & O_ACCMODE) == O_RDONLY)
if ((flags & O_ACCMODE_STRICT) == O_RDONLY)
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);
else
r = 0;

View File

@ -38,11 +38,10 @@ static VacuumCandidate* vacuum_candidate_free(VacuumCandidate *c) {
}
DEFINE_TRIVIAL_CLEANUP_FUNC(VacuumCandidate*, vacuum_candidate_free);
static Hashmap* vacuum_candidate_hashmap_free(Hashmap *h) {
return hashmap_free_with_destructor(h, vacuum_candidate_free);
}
DEFINE_TRIVIAL_CLEANUP_FUNC(Hashmap*, vacuum_candidate_hashmap_free);
DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
vacuum_candidate_hash_ops,
void, trivial_hash_func, trivial_compare_func,
VacuumCandidate, vacuum_candidate_free);
static int uid_from_file_name(const char *filename, uid_t *uid) {
const char *p, *e, *u;
@ -141,7 +140,7 @@ int coredump_vacuum(int exclude_fd, uint64_t keep_free, uint64_t max_use) {
}
for (;;) {
_cleanup_(vacuum_candidate_hashmap_freep) Hashmap *h = NULL;
_cleanup_hashmap_free_ Hashmap *h = NULL;
VacuumCandidate *worst = NULL;
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))
continue;
r = hashmap_ensure_allocated(&h, NULL);
if (r < 0)
return log_oom();
t = timespec_load(&st.st_mtim);
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;
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)
return log_oom();

View File

@ -23,7 +23,7 @@ struct sd_dhcp_raw_option {
LIST_FIELDS(struct sd_dhcp_raw_option, options);
uint8_t tag;
uint8_t length;
size_t length;
void *data;
};
@ -89,9 +89,9 @@ struct sd_dhcp_lease {
int dhcp_lease_new(sd_dhcp_lease **ret);
int dhcp_lease_parse_options(uint8_t code, uint8_t len, const void *option, void *userdata);
int dhcp_lease_parse_options(uint8_t code, size_t len, const void *option, void *userdata);
int dhcp_lease_parse_search_domains(const uint8_t *option, size_t len, char ***domains);
int dhcp_lease_insert_private_option(sd_dhcp_lease *lease, uint8_t tag, const void *data, uint8_t len);
int dhcp_lease_insert_private_option(sd_dhcp_lease *lease, uint8_t tag, const void *data, size_t len);
void dhcp_lease_set_timestamp(sd_dhcp_lease *lease, const triple_timestamp *timestamp);
int dhcp_lease_set_default_subnet_mask(sd_dhcp_lease *lease);

View File

@ -6,17 +6,28 @@
#include <errno.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/param.h>
#include "alloc-util.h"
#include "dhcp-option.h"
#include "dhcp-protocol.h"
#include "dhcp-server-internal.h"
#include "dns-domain.h"
#include "hash-funcs.h"
#include "hashmap.h"
#include "hostname-util.h"
#include "list.h"
#include "macro.h"
#include "memory-util.h"
#include "ordered-set.h"
#include "sd-dhcp-protocol.h"
#include "strv.h"
#include "unaligned.h"
#include "utf8.h"
static bool dhcp_option_can_merge(uint8_t code);
/* Append type-length value structure to the options buffer */
static int dhcp_option_append_tlv(uint8_t options[], size_t size, size_t *offset, uint8_t code, size_t optlen, const void *optval) {
assert(options);
@ -203,9 +214,9 @@ int dhcp_option_remove_option(uint8_t *options, size_t length, uint8_t option_co
return length - r;
}
int dhcp_option_append(DHCPMessage *message, size_t size, size_t *offset,
uint8_t overload,
uint8_t code, size_t optlen, const void *optval) {
static int dhcp_option_append_short(DHCPMessage *message, size_t size, size_t *offset,
uint8_t overload,
uint8_t code, size_t optlen, const void *optval) {
const bool use_file = overload & DHCP_OVERLOAD_FILE;
const bool use_sname = overload & DHCP_OVERLOAD_SNAME;
int r;
@ -276,10 +287,106 @@ int dhcp_option_append(DHCPMessage *message, size_t size, size_t *offset,
return -ENOBUFS;
}
static int parse_options(const uint8_t options[], size_t buflen, uint8_t *overload,
uint8_t *message_type, char **error_message, dhcp_option_callback_t cb,
void *userdata) {
uint8_t code, len;
static int dhcp_option_append_long(DHCPMessage *message, size_t size, size_t *offset,
uint8_t overload,
uint8_t code, size_t optlen, const uint8_t *optval) {
const bool use_file = overload & DHCP_OVERLOAD_FILE;
const bool use_sname = overload & DHCP_OVERLOAD_SNAME;
size_t available, to_write;
int r;
assert(message);
assert(offset);
/* If *offset is in range [0, size), we are writing to ->options,
* if *offset is in range [size, size + sizeof(message->file)) and use_file, we are writing to ->file,
* if *offset is in range [size + use_file*sizeof(message->file),
* size + use_file*sizeof(message->file) + sizeof(message->sname))
* and use_sname, we are writing to ->sname.
*/
while (optlen) {
if (*offset + 3 < size) {
/* still space in the options array for at least TL and end */
available = size - 3 - *offset;
to_write = MIN(available, MIN(optlen, (size_t)UINT8_MAX));
r = option_append(message->options, size, offset, code, to_write, optval);
if (r < 0)
return r;
optval += to_write;
optlen -= to_write;
if (to_write == available) {
/* close the options array */
r = option_append(message->options, size, offset,
SD_DHCP_OPTION_END, 0, NULL);
if (r < 0)
return r;
}
continue;
}
size_t file_offset = *offset - size;
if (use_file && file_offset + 3 < sizeof(message->file)) {
/* still space in the file array for at least TL and end */
available = sizeof(message->file) - 3 - file_offset;
to_write = MIN(available, MIN(optlen, (size_t)UINT8_MAX));
r = option_append(message->file, sizeof(message->file), &file_offset,
code, to_write, optval);
if (r < 0)
return r;
optval += to_write;
optlen -= to_write;
*offset = size + file_offset;
if (to_write == available) {
/* close the file array */
r = option_append(message->file, sizeof(message->file), &file_offset,
SD_DHCP_OPTION_END, 0, NULL);
if (r < 0)
return r;
}
continue;
}
size_t sname_offset = *offset - size - (use_file ? sizeof(message->file) : 0);
if (use_sname && sname_offset + 3 < sizeof(message->sname)) {
/* still space in the sname array for at least TL and end */
available = sizeof(message->sname) - 3 - sname_offset;
to_write = MIN(available, MIN(optlen, (size_t)UINT8_MAX));
r = option_append(message->sname, sizeof(message->sname), &sname_offset,
code, to_write, optval);
if (r < 0)
return r;
optval += to_write;
optlen -= to_write;
*offset = size + (use_file ? sizeof(message->file) : 0) + sname_offset;
}
return -ENOBUFS;
}
return 0;
}
int dhcp_option_append(DHCPMessage *message, size_t size, size_t *offset,
uint8_t overload,
uint8_t code, size_t optlen, const void *optval) {
if (dhcp_option_can_merge(code))
return dhcp_option_append_long(message, size, offset, overload, code, optlen, optval);
else
return dhcp_option_append_short(message, size, offset, overload, code, optlen, optval);
}
static int parse_options(const uint8_t options[], size_t buflen, uint8_t *message_type,
char **error_message, dhcp_option_callback_t cb, void *userdata) {
uint8_t code;
uint16_t len;
const uint8_t *option;
size_t offset = 0;
int r;
@ -287,18 +394,11 @@ static int parse_options(const uint8_t options[], size_t buflen, uint8_t *overlo
while (offset < buflen) {
code = options[offset++];
switch (code) {
case SD_DHCP_OPTION_PAD:
continue;
case SD_DHCP_OPTION_END:
return 0;
}
if (buflen < offset + 1)
if (buflen < offset + 2)
return -ENOBUFS;
len = options[offset++];
len = unaligned_read_be16(&options[offset]);
offset += 2;
if (buflen < offset + len)
return -EINVAL;
@ -333,14 +433,6 @@ static int parse_options(const uint8_t options[], size_t buflen, uint8_t *overlo
}
break;
case SD_DHCP_OPTION_OVERLOAD:
if (len != 1)
return -EINVAL;
if (overload)
*overload = *option;
break;
default:
if (cb)
@ -356,10 +448,387 @@ static int parse_options(const uint8_t options[], size_t buflen, uint8_t *overlo
return 0;
}
/* draft-tojens-dhcp-option-concat-considerations
*
* Not all DHCP options are created equal, and some may not be concatenation-compatible. The draft
* defines a few option categories, and there we define our strategy wrt. concatenation.
*
* 1. Fixed length options: let's not concatenate those. Splitting most of those options is a waste
* of space, thus it is unlikely that any agent split them.
* Treat each occurence as a separate instance, and keep the "parse at least one" behavior.
* Arguments can be made about "long" options (e.g. authentication options), as those can be
* split without wasting space. However, be conservative and don't try to concatenate them
* without further guidance.
* 2. Multiple-of-fixed-length options: let's eagerly concatenate those. If all instances have a
* valid mod length, then so does the resulting instance. And if the resulting concatenated
* option has an invalid length, so did (some of) the separate instances.
* 3. Arbitrary length options: let's be simple and also concatenate those.
*
* Note that this classification is *unopinionated* about the classification. Some options may be
* discussed as to whether they qualify as a category, or whether the category behavior makes
* sense.
* At the time of writing, SD_DHCP_OPTION_DIRECTORY_AGENT is suspect, as it's a multiple of
* fixed-length, but with a leading extra byte. In the light of both RFC3396 and the draft, the
* final behavior of concatenation is assumed to be best.
*/
static bool dhcp_option_can_merge(uint8_t code) {
switch (code) {
/* Fixed-length options */
case SD_DHCP_OPTION_SUBNET_MASK:
case SD_DHCP_OPTION_TIME_OFFSET:
case SD_DHCP_OPTION_BOOT_FILE_SIZE:
case SD_DHCP_OPTION_SWAP_SERVER:
case SD_DHCP_OPTION_FORWARD:
case SD_DHCP_OPTION_SOURCE_ROUTE:
case SD_DHCP_OPTION_DEFAULT_IP_TTL:
case SD_DHCP_OPTION_MTU_TIMEOUT:
case SD_DHCP_OPTION_MTU_INTERFACE:
case SD_DHCP_OPTION_MTU_SUBNET:
case SD_DHCP_OPTION_BROADCAST:
case SD_DHCP_OPTION_MASK_DISCOVERY:
case SD_DHCP_OPTION_MASK_SUPPLIER:
case SD_DHCP_OPTION_ROUTER_DISCOVERY:
case SD_DHCP_OPTION_ROUTER_REQUEST:
case SD_DHCP_OPTION_TRAILERS:
case SD_DHCP_OPTION_ARP_TIMEOUT:
case SD_DHCP_OPTION_ETHERNET:
case SD_DHCP_OPTION_DEFAULT_TCP_TTL:
case SD_DHCP_OPTION_KEEPALIVE_TIME:
case SD_DHCP_OPTION_KEEPALIVE_DATA:
case SD_DHCP_OPTION_NETBIOS_NODE_TYPE:
case SD_DHCP_OPTION_REQUESTED_IP_ADDRESS:
case SD_DHCP_OPTION_IP_ADDRESS_LEASE_TIME:
case SD_DHCP_OPTION_OVERLOAD:
case SD_DHCP_OPTION_MESSAGE_TYPE:
case SD_DHCP_OPTION_SERVER_IDENTIFIER:
case SD_DHCP_OPTION_MAXIMUM_MESSAGE_SIZE:
case SD_DHCP_OPTION_RENEWAL_TIME:
case SD_DHCP_OPTION_REBINDING_TIME:
case SD_DHCP_OPTION_NETWARE_IP_OPTION:
case SD_DHCP_OPTION_RAPID_COMMIT:
case SD_DHCP_OPTION_AUTHENTICATION:
case SD_DHCP_OPTION_CLIENT_LAST_TRANSACTION_TIME:
case SD_DHCP_OPTION_CLIENT_SYSTEM:
case SD_DHCP_OPTION_CLIENT_NDI:
case SD_DHCP_OPTION_UUID:
case SD_DHCP_OPTION_IPV6_ONLY_PREFERRED:
case SD_DHCP_OPTION_DHCP4O6_SOURCE_ADDRESS:
case SD_DHCP_OPTION_AUTO_CONFIG:
case SD_DHCP_OPTION_SUBNET_SELECTION:
case SD_DHCP_OPTION_GEOCONF:
case SD_DHCP_OPTION_GEOLOC:
case SD_DHCP_OPTION_BASE_TIME:
case SD_DHCP_OPTION_START_TIME_OF_STATE:
case SD_DHCP_OPTION_QUERY_START_TIME:
case SD_DHCP_OPTION_QUERY_END_TIME:
case SD_DHCP_OPTION_DHCP_STATE:
case SD_DHCP_OPTION_DATA_SOURCE:
case SD_DHCP_OPTION_PORT_PARAMS:
case SD_DHCP_OPTION_PXELINUX_MAGIC:
case SD_DHCP_OPTION_REBOOT_TIME:
case SD_DHCP_OPTION_6RD:
/* apple-specific, not documented, so be conservative */
case SD_DHCP_OPTION_LDAP:
case SD_DHCP_OPTION_NETINFO_ADDRESS:
case SD_DHCP_OPTION_NETINFO_TAG:
/* despite being a variable-length option, there are two sub-options defined in RFC3046, so
* it is expected to be so short that no splitting will happen. furthermore, it simplifies
* relay implementation.
*/
case SD_DHCP_OPTION_RELAY_AGENT_INFORMATION:
return false;
/* Multiple of fixed-length options */
case SD_DHCP_OPTION_ROUTER:
case SD_DHCP_OPTION_TIME_SERVER:
case SD_DHCP_OPTION_NAME_SERVER:
case SD_DHCP_OPTION_DOMAIN_NAME_SERVER:
case SD_DHCP_OPTION_LOG_SERVER:
case SD_DHCP_OPTION_QUOTES_SERVER:
case SD_DHCP_OPTION_LPR_SERVER:
case SD_DHCP_OPTION_IMPRESS_SERVER:
case SD_DHCP_OPTION_RLP_SERVER:
case SD_DHCP_OPTION_POLICY_FILTER:
case SD_DHCP_OPTION_MTU_PLATEAU:
case SD_DHCP_OPTION_STATIC_ROUTE:
case SD_DHCP_OPTION_NIS_SERVER:
case SD_DHCP_OPTION_NTP_SERVER:
case SD_DHCP_OPTION_NETBIOS_NAME_SERVER:
case SD_DHCP_OPTION_NETBIOS_DIST_SERVER:
case SD_DHCP_OPTION_X_WINDOW_FONT:
case SD_DHCP_OPTION_X_WINDOW_MANAGER:
case SD_DHCP_OPTION_NIS_SERVER_ADDR:
case SD_DHCP_OPTION_HOME_AGENT_ADDRESSES:
case SD_DHCP_OPTION_SMTP_SERVER:
case SD_DHCP_OPTION_POP3_SERVER:
case SD_DHCP_OPTION_NNTP_SERVER:
case SD_DHCP_OPTION_WWW_SERVER:
case SD_DHCP_OPTION_FINGER_SERVER:
case SD_DHCP_OPTION_IRC_SERVER:
case SD_DHCP_OPTION_STREETTALK_SERVER:
case SD_DHCP_OPTION_STDA_SERVER:
case SD_DHCP_OPTION_DIRECTORY_AGENT: /* multiple of four plus one */
case SD_DHCP_OPTION_NDS_SERVER:
case SD_DHCP_OPTION_BCMCS_CONTROLLER_ADDRESS:
case SD_DHCP_OPTION_ASSOCIATED_IP:
case SD_DHCP_OPTION_NAME_SERVICE_SEARCH:
case SD_DHCP_OPTION_PANA_AGENT:
case SD_DHCP_OPTION_CAPWAP_AC_ADDRESS:
case SD_DHCP_OPTION_ANDSF_ADDRESS:
case SD_DHCP_OPTION_TFTP_SERVER_ADDRESS:
/* Arbitrary length options */
case SD_DHCP_OPTION_HOST_NAME:
case SD_DHCP_OPTION_MERIT_DUMP_FILE:
case SD_DHCP_OPTION_DOMAIN_NAME:
case SD_DHCP_OPTION_ROOT_PATH:
case SD_DHCP_OPTION_EXTENSION_FILE:
case SD_DHCP_OPTION_NIS_DOMAIN:
case SD_DHCP_OPTION_VENDOR_SPECIFIC:
case SD_DHCP_OPTION_NETBIOS_SCOPE:
case SD_DHCP_OPTION_PARAMETER_REQUEST_LIST:
case SD_DHCP_OPTION_ERROR_MESSAGE:
case SD_DHCP_OPTION_VENDOR_CLASS_IDENTIFIER:
case SD_DHCP_OPTION_CLIENT_IDENTIFIER:
case SD_DHCP_OPTION_NIS_DOMAIN_NAME:
case SD_DHCP_OPTION_BOOT_SERVER_NAME:
case SD_DHCP_OPTION_BOOT_FILENAME:
case SD_DHCP_OPTION_USER_CLASS:
case SD_DHCP_OPTION_SERVICE_SCOPE:
case SD_DHCP_OPTION_ISNS:
case SD_DHCP_OPTION_USER_AUTHENTICATION:
case SD_DHCP_OPTION_POSIX_TIMEZONE:
case SD_DHCP_OPTION_TZDB_TIMEZONE:
case SD_DHCP_OPTION_DHCP_CAPTIVE_PORTAL:
case SD_DHCP_OPTION_LOST_SERVER_FQDN:
case SD_DHCP_OPTION_FORCERENEW_NONCE_CAPABLE:
case SD_DHCP_OPTION_DOTS_RI:
case SD_DHCP_OPTION_STATUS_CODE:
case SD_DHCP_OPTION_CONFIGURATION_FILE:
case SD_DHCP_OPTION_PATH_PREFIX:
case SD_DHCP_OPTION_ACCESS_DOMAIN:
case SD_DHCP_OPTION_SUBNET_ALLOCATION:
case SD_DHCP_OPTION_VIRTUAL_SUBNET_SELECTION:
case SD_DHCP_OPTION_PRIVATE_PROXY_AUTODISCOVERY:
/* MUST implement DHCP option concatenation as per RFC3396 */
case SD_DHCP_OPTION_FQDN:
case SD_DHCP_OPTION_BCMCS_CONTROLLER_DOMAIN_NAME:
case SD_DHCP_OPTION_GEOCONF_CIVIC:
case SD_DHCP_OPTION_DOMAIN_SEARCH:
case SD_DHCP_OPTION_SIP_SERVER: /* RFC3396 is mentioned as "work in progress" */
case SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE:
case SD_DHCP_OPTION_CABLELABS_CLIENT_CONFIGURATION:
case SD_DHCP_OPTION_VENDOR_CLASS:
case SD_DHCP_OPTION_VENDOR_SPECIFIC_INFORMATION:
case SD_DHCP_OPTION_MOS_ADDRESS:
case SD_DHCP_OPTION_MOS_FQDN:
case SD_DHCP_OPTION_SIP_SERVICE_DOMAIN:
case SD_DHCP_OPTION_SZTP_REDIRECT:
case SD_DHCP_OPTION_RDNSS_SELECTION:
case SD_DHCP_OPTION_DOTS_ADDRESS:
case SD_DHCP_OPTION_PCP_SERVER:
case SD_DHCP_OPTION_PRIVATE_CLASSLESS_STATIC_ROUTE: /* Microsoft's version of 121 */
/* RFC2242: [...] and its maximum length is 255.
* While the length of the option is bounded, and fits in one option, the does not need
* splitting to fit in an option. However, due to the option being potentially be long,
* agents may decide to split the option e.g. across the option and sname fields.
* Let's support concatenation for this option.
*/
case SD_DHCP_OPTION_NETWARE_IP_DOMAIN:
/* RFC2241: The maximum possible length for this option is 255 bytes.
* Same reasoning as the previous one.
*/
case SD_DHCP_OPTION_NDS_TREE_NAME:
/* RFC2241: A single DHCP option can only contain 255 octets. Since an NDS context name can
* be longer than that, this option can appear more than once in the DHCP packet.
* The contents of all NDS Context options in the packet should be concatenated as
* suggested in the DHCP specification [3, page 24] to get the complete NDS
* context. A single encoded character could be split between two NDS Context
* Options.
* This basically describes what RFC3396 later formalizes, but predates it.
*/
case SD_DHCP_OPTION_NDS_CONTEXT:
/* RFC8520: The entire option MUST NOT exceed 255 octets.
* Same as with 2242: it may be split across multiple instances of the option.
*/
case SD_DHCP_OPTION_MUD_URL:
return true;
default:
return false;
}
}
struct MergeOptionNode {
const uint8_t *data;
LIST_FIELDS(struct MergeOptionNode, options);
};
static struct MergeOptionNode* merge_option_free(struct MergeOptionNode *head) {
LIST_CLEAR(options, head, free);
return NULL;
}
DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(merge_option_node_ops,
void,
trivial_hash_func,
trivial_compare_func,
struct MergeOptionNode,
merge_option_free);
static int dhcp_option_merge_append(const uint8_t *buf, size_t buflen, OrderedHashmap *opts,
size_t *tot_len, uint8_t *overload) {
size_t offset = 0;
struct MergeOptionNode *head, *next;
while (offset < buflen) {
const uint8_t *data = &buf[offset];
uint8_t code = buf[offset++];
switch (code) {
case SD_DHCP_OPTION_PAD:
continue;
case SD_DHCP_OPTION_END:
return 0;
}
if (buflen < offset + 1)
return -ENOBUFS;
uint8_t len = buf[offset++];
if (buflen < offset + len)
return -EINVAL;
switch (code) {
case SD_DHCP_OPTION_OVERLOAD:
if (len != 1)
return -EINVAL;
if (overload)
*overload = buf[offset];
offset++;
continue;
}
next = new(struct MergeOptionNode, 1);
if (!next)
return -ENOMEM;
LIST_INIT(options, next);
next->data = data;
head = ordered_hashmap_get(opts, UINT_TO_PTR(code));
if (head)
LIST_APPEND(options, head, next);
else {
int r = ordered_hashmap_put(opts, UINT_TO_PTR(code), next);
if (r < 0) {
free(next);
return r;
}
}
if (!head || !dhcp_option_can_merge(code))
*tot_len += 3; /* option code + 16-bit length */
offset += len;
*tot_len += len;
}
return 0;
}
/* RFC3396 specifies how DHCP options longer than 255 bytes should be handled.
*
* Option is to be repeated multiple times and treated as one, long, option. However, the cut can
* happen at byte boundaries, and clients MUST assume no semantic meaning whatsoever from this cut.
* In practice, this means the cut can happen anywhere in the middle of a semantic unit of the
* option (e.g. DHCP option 121 (Classless Static Routes) can be split in the middle of a route).
*
* With the current architecture of stateless callbacks that take a whole chunk of memory, it
* becomes hard to retain data between two consecutive callbacks without major changes to the
* architecture.
*
* This function will merge DHCP options by concatenating options of the same type, producing a new
* TLV buffer, but using u16 len fields instead of u8. This works due to a DHCP message size having
* an inherent upper bound, lower than u16::MAX.
*
* Basically, this produces the aggregated option buffer the RFC talks about.
*/
static int dhcp_option_merge(const DHCPMessage *message, size_t buflen, uint8_t **ret_merged) {
_cleanup_ordered_hashmap_free_ OrderedHashmap *opts;
uint8_t *aggregate, overload = 0;
size_t tot_len = 0;
int r = 0;
opts = ordered_hashmap_new(&merge_option_node_ops);
if (!opts)
return -ENOMEM;
/* RFC3396 5. The Aggregate Option Buffer
*
* [...], an option that doesn't fit into one field can't overlap the boundary into
* another field - the encoding agent must instead break the option into two parts and
* store one part in each buffer.
*
* To simplify this discussion, we will talk about an aggregate option buffer, which will
* be the aggregate of the three buffers. [...] The aggregate option buffer is made up of
* the optional parameters field, the file field, and the sname field, in that order.
*
* Since options cannot overlap from one field to another, it is safe to read them in
* isolation.
*/
r = dhcp_option_merge_append(message->options, buflen, opts, &tot_len, &overload);
if (r < 0)
return r;
if (overload & DHCP_OVERLOAD_FILE) {
r = dhcp_option_merge_append(message->file, sizeof(message->file), opts, &tot_len, NULL);
if (r < 0)
return r;
}
if (overload & DHCP_OVERLOAD_SNAME) {
r = dhcp_option_merge_append(message->sname, sizeof(message->sname), opts, &tot_len, NULL);
if (r < 0)
return r;
}
/* Consolidate in a new buffer */
aggregate = new(uint8_t, tot_len);
if (!aggregate)
return r;
size_t offset = 0;
struct MergeOptionNode *head;
ORDERED_HASHMAP_FOREACH(head, opts) {
uint8_t code = head->data[0];
if (dhcp_option_can_merge(code)) {
uint8_t *opt_base = &aggregate[offset];
offset += 3;
size_t len = 0;
LIST_FOREACH(options, opt, head) {
size_t optlen = opt->data[1];
memcpy_safe(&aggregate[offset], &opt->data[2], optlen);
offset += optlen;
len += optlen;
}
opt_base[0] = code;
unaligned_write_be16(&opt_base[1], len);
} else
LIST_FOREACH(options, opt, head) {
size_t optlen = opt->data[1];
aggregate[offset] = code;
unaligned_write_be16(&aggregate[offset + 1], (uint16_t)optlen);
memcpy_safe(&aggregate[offset + 3], &opt->data[2], optlen);
offset += 3 + optlen;
}
}
*ret_merged = aggregate;
return tot_len;
}
int dhcp_option_parse(DHCPMessage *message, size_t len, dhcp_option_callback_t cb, void *userdata, char **ret_error_message) {
_cleanup_free_ char *error_message = NULL;
uint8_t overload = 0;
uint8_t message_type = 0;
_cleanup_free_ uint8_t *options = NULL;
int r;
if (!message)
@ -370,21 +839,14 @@ int dhcp_option_parse(DHCPMessage *message, size_t len, dhcp_option_callback_t c
len -= sizeof(DHCPMessage);
r = parse_options(message->options, len, &overload, &message_type, &error_message, cb, userdata);
r = dhcp_option_merge(message, len, &options);
if (r < 0)
return r;
len = r;
if (overload & DHCP_OVERLOAD_FILE) {
r = parse_options(message->file, sizeof(message->file), NULL, &message_type, &error_message, cb, userdata);
if (r < 0)
return r;
}
if (overload & DHCP_OVERLOAD_SNAME) {
r = parse_options(message->sname, sizeof(message->sname), NULL, &message_type, &error_message, cb, userdata);
if (r < 0)
return r;
}
r = parse_options(options, len, &message_type, &error_message, cb, userdata);
if (r < 0)
return r;
if (message_type == 0)
return -ENOMSG;

View File

@ -35,7 +35,7 @@ int dhcp_option_append(
int dhcp_option_find_option(uint8_t *options, size_t length, uint8_t wanted_code, size_t *ret_offset);
int dhcp_option_remove_option(uint8_t *options, size_t buflen, uint8_t option_code);
typedef int (*dhcp_option_callback_t)(uint8_t code, uint8_t len, const void *option, void *userdata);
typedef int (*dhcp_option_callback_t)(uint8_t code, size_t len, const void *option, void *userdata);
int dhcp_option_parse(
DHCPMessage *message,

View File

@ -90,9 +90,10 @@ typedef struct DHCPRequest {
be32_t server_id;
be32_t requested_ip;
usec_t lifetime;
const uint8_t *agent_info_option;
uint8_t *agent_info_option;
size_t agent_info_option_len;
char *hostname;
const uint8_t *parameter_request_list;
uint8_t *parameter_request_list;
size_t parameter_request_list_len;
bool rapid_commit;
triple_timestamp timestamp;

View File

@ -847,7 +847,7 @@ static int lease_parse_6rd(sd_dhcp_lease *lease, const uint8_t *option, size_t l
return 0;
}
int dhcp_lease_parse_options(uint8_t code, uint8_t len, const void *option, void *userdata) {
int dhcp_lease_parse_options(uint8_t code, size_t len, const void *option, void *userdata) {
sd_dhcp_lease *lease = ASSERT_PTR(userdata);
int r;
@ -1173,7 +1173,7 @@ int dhcp_lease_parse_search_domains(const uint8_t *option, size_t len, char ***d
return cnt;
}
int dhcp_lease_insert_private_option(sd_dhcp_lease *lease, uint8_t tag, const void *data, uint8_t len) {
int dhcp_lease_insert_private_option(sd_dhcp_lease *lease, uint8_t tag, const void *data, size_t len) {
struct sd_dhcp_raw_option *option, *before = NULL;
assert(lease);

View File

@ -448,11 +448,17 @@ int dhcp_server_send_packet(sd_dhcp_server *server,
return r;
if (req->agent_info_option) {
size_t opt_full_length = *(req->agent_info_option + 1) + 2;
/* should not happen as we don't merge the relay agent information option. see
dhcp_option_can_merge for reference */
if (req->agent_info_option_len > UINT8_MAX)
return -EINVAL;
/* there must be space left for SD_DHCP_OPTION_END */
if (optoffset + opt_full_length < req->max_optlen) {
memcpy(packet->dhcp.options + optoffset, req->agent_info_option, opt_full_length);
optoffset += opt_full_length;
if (optoffset + req->agent_info_option_len + 2 < req->max_optlen) {
packet->dhcp.options[optoffset] = SD_DHCP_OPTION_RELAY_AGENT_INFORMATION;
packet->dhcp.options[optoffset + 1] = req->agent_info_option_len;
memcpy(&packet->dhcp.options[optoffset + 2], req->agent_info_option,
req->agent_info_option_len);
optoffset += req->agent_info_option_len + 2;
}
}
@ -729,7 +735,7 @@ static int server_send_forcerenew(
sizeof(DHCPMessage) + optoffset);
}
static int parse_request(uint8_t code, uint8_t len, const void *option, void *userdata) {
static int parse_request(uint8_t code, size_t len, const void *option, void *userdata) {
DHCPRequest *req = ASSERT_PTR(userdata);
int r;
@ -761,9 +767,13 @@ static int parse_request(uint8_t code, uint8_t len, const void *option, void *us
break;
case SD_DHCP_OPTION_RELAY_AGENT_INFORMATION:
req->agent_info_option = (uint8_t*)option - 2;
if (req->agent_info_option)
mfree(req->agent_info_option);
req->agent_info_option = new(uint8_t, len);
memcpy(req->agent_info_option, option, len);
req->agent_info_option_len = len;
break;
case SD_DHCP_OPTION_HOST_NAME: {
_cleanup_free_ char *p = NULL;
@ -775,7 +785,10 @@ static int parse_request(uint8_t code, uint8_t len, const void *option, void *us
break;
}
case SD_DHCP_OPTION_PARAMETER_REQUEST_LIST:
req->parameter_request_list = option;
if (req->parameter_request_list)
mfree(req->parameter_request_list);
req->parameter_request_list = new(uint8_t, len);
memcpy(req->parameter_request_list, option, len);
req->parameter_request_list_len = len;
break;
@ -792,6 +805,8 @@ static DHCPRequest* dhcp_request_free(DHCPRequest *req) {
return NULL;
free(req->hostname);
free(req->agent_info_option);
free(req->parameter_request_list);
return mfree(req);
}

View File

@ -161,7 +161,7 @@ static void test_dhcp_identifier_set_iaid(void) {
#endif
}
static int check_options(uint8_t code, uint8_t len, const void *option, void *userdata) {
static int check_options(uint8_t code, size_t len, const void *option, void *userdata) {
switch (code) {
case SD_DHCP_OPTION_CLIENT_IDENTIFIER: {
sd_dhcp_duid duid;

View File

@ -12,8 +12,15 @@
#include "ether-addr-util.h"
#include "macro.h"
#include "memory-util.h"
#include "sd-dhcp-protocol.h"
#include "tests.h"
struct opt_overrides {
uint8_t code;
uint8_t data[128];
size_t len;
};
struct option_desc {
uint8_t sname[64];
int snamelen;
@ -22,6 +29,8 @@ struct option_desc {
uint8_t options[128];
int len;
bool success;
struct opt_overrides overrides[16];
int overrideslen;
int filepos;
int snamepos;
int pos;
@ -52,6 +61,74 @@ static struct option_desc option_tests[] = {
{ 222, 3, 1, 2, 3 }, 5,
{ SD_DHCP_OPTION_OVERLOAD, 1,
DHCP_OVERLOAD_FILE|DHCP_OVERLOAD_SNAME }, 3, true, },
/* test RFC3396: option split across multiple options, cut at an arbitrary byte boundary.
* Example here for a routing table, where the split is in the middle of the route.
* In practice, this will happen when the routes don't fit in a single option, but the
* behavior will likely be the same.
*/
{
.options = {
SD_DHCP_OPTION_MESSAGE_TYPE, 1, DHCP_ACK,
SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE, 4, 22, 172, 16, 0,
SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE, 4, 0, 0, 0, 0,
},
.len = 15,
.success = true,
/* the whole option must be reconstituted, so let's override the payload */
.overrides = {{
.code = SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE,
.data = {22, 172, 16, 0, 0, 0, 0, 0},
.len = 8,
}},
.overrideslen = 1,
},
/* test draft-tojens-dhcp-option-concat-considerations: not all options should be
* concatenated. Concatenation-requiring is already tested by the previous test.
* test fixed-length options.
*/
{
.options = {
SD_DHCP_OPTION_MESSAGE_TYPE, 1, DHCP_ACK,
SD_DHCP_OPTION_SUBNET_MASK, 4, 255, 255, 255, 0,
SD_DHCP_OPTION_SUBNET_MASK, 4, 255, 255, 255, 0,
},
.len = 15,
.success = true,
/* no overrides: option should not be concatenated */
},
/* test multiple of fixed-length */
{
.options = {
SD_DHCP_OPTION_MESSAGE_TYPE, 1, DHCP_ACK,
SD_DHCP_OPTION_DOMAIN_NAME_SERVER, 3, 8, 8, 8,
SD_DHCP_OPTION_DOMAIN_NAME_SERVER, 5, 8, 1, 1, 1, 1,
},
.len = 15,
.success = true,
.overrides = {{
.code = SD_DHCP_OPTION_DOMAIN_NAME_SERVER,
.data = {8, 8, 8, 8, 1, 1, 1, 1},
.len = 8,
}},
.overrideslen = 1,
},
/* test arbitrary length */
{
.options = {
SD_DHCP_OPTION_MESSAGE_TYPE, 1, DHCP_ACK,
SD_DHCP_OPTION_HOST_NAME, 3, 'f', 'o', 'o',
SD_DHCP_OPTION_HOST_NAME, 3, 'b', 'a', 'r',
SD_DHCP_OPTION_HOST_NAME, 3, 'b', 'a', 'z',
},
.len = 18,
.success = true,
.overrides = {{
.code = SD_DHCP_OPTION_HOST_NAME,
.data = "foobarbaz",
.len = 9,
}},
.overrideslen = 1,
},
};
static const char *dhcp_type(int type) {
@ -143,12 +220,13 @@ static void test_ignore_opts(uint8_t *descoption, int *descpos, int *desclen) {
}
}
static int test_options_cb(uint8_t code, uint8_t len, const void *option, void *userdata) {
static int test_options_cb(uint8_t code, size_t len, const void *option, void *userdata) {
struct option_desc *desc = userdata;
uint8_t *descoption = NULL;
int *desclen = NULL, *descpos = NULL;
uint8_t optcode = 0;
uint8_t optlen = 0;
size_t descoption_offset;
assert_se((!desc && !code && !len) || desc);
@ -193,9 +271,18 @@ static int test_options_cb(uint8_t code, uint8_t len, const void *option, void *
optcode = descoption[*descpos];
optlen = descoption[*descpos + 1];
descoption_offset = *descpos + 2;
for (int i = 0; i < desc->overrideslen; i++)
if (desc->overrides[i].code == optcode) {
optlen = desc->overrides[i].len;
descoption = desc->overrides[i].data;
descoption_offset = 0;
break;
}
if (verbose)
printf("DHCP code %2d(%2d) len %2d(%2d) ", code, optcode,
printf("DHCP code %2d(%2d) len %4zu(%2d) ", code, optcode,
len, optlen);
assert_se(code == optcode);
@ -205,9 +292,9 @@ static int test_options_cb(uint8_t code, uint8_t len, const void *option, void *
if (verbose)
printf("0x%02x(0x%02x) ",
((uint8_t*) option)[i],
descoption[*descpos + 2 + i]);
descoption[descoption_offset + i]);
assert_se(((uint8_t*) option)[i] == descoption[*descpos + 2 + i]);
assert_se(((uint8_t*) option)[i] == descoption[descoption_offset + i]);
}
if (verbose)
@ -362,6 +449,170 @@ static void test_option_set(void) {
printf ("\n");
}
struct long_option_test {
const char *name;
struct {
uint8_t code;
size_t len;
uint8_t data[1024];
} option;
size_t max_optlen;
bool use_file;
bool success;
uint8_t expected_option[500];
size_t expected_optlen;
uint8_t expected_file[128];
size_t expected_filelen;
};
static struct long_option_test long_option_tests[] = {
{
.name = "test that a regular option can be serialized",
.option.code = SD_DHCP_OPTION_SUBNET_MASK,
.option.len = 4,
.option.data = {255, 255, 255, 0},
.max_optlen = 128,
.success = true,
.expected_option = {SD_DHCP_OPTION_SUBNET_MASK, 4, 255, 255, 255, 0},
.expected_optlen = 6,
},
{
.name = "test that a regular option fails if there is not enough space",
.option.code = SD_DHCP_OPTION_SUBNET_MASK,
.option.len = 4,
.option.data = {255, 255, 255, 0},
.max_optlen = 2,
.success = false,
},
{
.name = "test that a regular option fallbacks to the file buffer when allowed",
.option.code = SD_DHCP_OPTION_SUBNET_MASK,
.option.len = 4,
.option.data = {255, 255, 255, 0},
.max_optlen = 2,
.use_file = true,
.success = true,
.expected_option = {SD_DHCP_OPTION_END, SD_DHCP_OPTION_PAD},
.expected_optlen = 2,
.expected_file = {SD_DHCP_OPTION_SUBNET_MASK, 4, 255, 255, 255, 0},
.expected_filelen = 6,
},
{
.name = "test that a mergeable long option is split across two options (RFC3396)",
.option.code = SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE,
.option.len = 256, /* one byte short to fit in one option! */
.option.data = {
24, 10, 0, 0, 1, 2, 3, 4, 24, 10, 0, 1, 1, 2, 3, 4,
24, 10, 0, 2, 1, 2, 3, 4, 24, 10, 0, 3, 1, 2, 3, 4,
24, 10, 0, 4, 1, 2, 3, 4, 24, 10, 0, 5, 1, 2, 3, 4,
24, 10, 0, 6, 1, 2, 3, 4, 24, 10, 0, 7, 1, 2, 3, 4,
24, 10, 0, 8, 1, 2, 3, 4, 24, 10, 0, 9, 1, 2, 3, 4,
24, 10, 0, 10, 1, 2, 3, 4, 24, 10, 0, 11, 1, 2, 3, 4,
24, 10, 0, 12, 1, 2, 3, 4, 24, 10, 0, 13, 1, 2, 3, 4,
24, 10, 0, 14, 1, 2, 3, 4, 24, 10, 0, 15, 1, 2, 3, 4,
24, 10, 0, 16, 1, 2, 3, 4, 24, 10, 0, 17, 1, 2, 3, 4,
24, 10, 0, 18, 1, 2, 3, 4, 24, 10, 0, 19, 1, 2, 3, 4,
24, 10, 0, 20, 1, 2, 3, 4, 24, 10, 0, 21, 1, 2, 3, 4,
24, 10, 0, 22, 1, 2, 3, 4, 24, 10, 0, 23, 1, 2, 3, 4,
24, 10, 0, 24, 1, 2, 3, 4, 24, 10, 0, 25, 1, 2, 3, 4,
24, 10, 0, 26, 1, 2, 3, 4, 24, 10, 0, 27, 1, 2, 3, 4,
24, 10, 0, 28, 1, 2, 3, 4, 24, 10, 0, 29, 1, 2, 3, 4,
24, 10, 0, 30, 1, 2, 3, 4, 24, 10, 0, 31, 1, 2, 3, 4,
},
.max_optlen = 500,
.success = true,
.expected_option = {
SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE, 255,
24, 10, 0, 0, 1, 2, 3, 4, 24, 10, 0, 1, 1, 2, 3, 4,
24, 10, 0, 2, 1, 2, 3, 4, 24, 10, 0, 3, 1, 2, 3, 4,
24, 10, 0, 4, 1, 2, 3, 4, 24, 10, 0, 5, 1, 2, 3, 4,
24, 10, 0, 6, 1, 2, 3, 4, 24, 10, 0, 7, 1, 2, 3, 4,
24, 10, 0, 8, 1, 2, 3, 4, 24, 10, 0, 9, 1, 2, 3, 4,
24, 10, 0, 10, 1, 2, 3, 4, 24, 10, 0, 11, 1, 2, 3, 4,
24, 10, 0, 12, 1, 2, 3, 4, 24, 10, 0, 13, 1, 2, 3, 4,
24, 10, 0, 14, 1, 2, 3, 4, 24, 10, 0, 15, 1, 2, 3, 4,
24, 10, 0, 16, 1, 2, 3, 4, 24, 10, 0, 17, 1, 2, 3, 4,
24, 10, 0, 18, 1, 2, 3, 4, 24, 10, 0, 19, 1, 2, 3, 4,
24, 10, 0, 20, 1, 2, 3, 4, 24, 10, 0, 21, 1, 2, 3, 4,
24, 10, 0, 22, 1, 2, 3, 4, 24, 10, 0, 23, 1, 2, 3, 4,
24, 10, 0, 24, 1, 2, 3, 4, 24, 10, 0, 25, 1, 2, 3, 4,
24, 10, 0, 26, 1, 2, 3, 4, 24, 10, 0, 27, 1, 2, 3, 4,
24, 10, 0, 28, 1, 2, 3, 4, 24, 10, 0, 29, 1, 2, 3, 4,
24, 10, 0, 30, 1, 2, 3, 4, 24, 10, 0, 31, 1, 2, 3,
SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE, 1,
4,
},
.expected_optlen = 260,
},
{
.name = "test that a mergeable option is split across options and file if needed",
.option.code = SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE,
.option.len = 8,
.option.data = {24, 10, 0, 0, 1, 2, 3, 4},
.max_optlen = 8,
.use_file = true,
.success = true,
.expected_option = {
SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE, 5, 24, 10, 0, 0, 1,
SD_DHCP_OPTION_END,
},
.expected_optlen = 8,
.expected_file = {SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE, 3, 2, 3, 4},
.expected_filelen = 5,
},
};
static void test_option_append_long(struct long_option_test *desc) {
_cleanup_free_ DHCPMessage *result = NULL;
uint8_t overload = 0;
size_t offset = 0;
int r;
if (verbose)
printf(">>> %s\n", desc->name);
result = malloc0(sizeof(DHCPMessage) + desc->max_optlen);
assert_se(result);
if (desc->use_file)
overload |= DHCP_OVERLOAD_FILE;
r = dhcp_option_append(result, desc->max_optlen, &offset, overload,
desc->option.code, desc->option.len, desc->option.data);
if (verbose)
printf("dhcp_option_append=%d, offset=%zu\n", r, offset);
if (!desc->success) {
assert_se(r < 0);
return;
}
assert_se(r == 0);
assert_se(offset == desc->expected_optlen + desc->expected_filelen);
if (verbose)
printf("opts: ");
for (unsigned i = 0; i < desc->expected_optlen; i++) {
if (verbose)
printf("0x%02x(0x%02x) ", result->options[i], desc->expected_option[i]);
if (verbose && result->options[i] != desc->expected_option[i])
printf("\n");
assert_se(result->options[i] == desc->expected_option[i]);
}
if (verbose)
printf("\n");
if (verbose)
printf("file: ");
for (unsigned i = 0; i < desc->expected_filelen; i++) {
if (verbose)
printf("0x%02x(0x%02x) ", result->file[i], desc->expected_file[i]);
if (verbose && result->file[i] != desc->expected_file[i])
printf("\n");
assert_se(result->file[i] == desc->expected_file[i]);
}
if (verbose)
printf("\n");
}
int main(int argc, char *argv[]) {
test_setup_logging(LOG_DEBUG);
@ -373,6 +624,9 @@ int main(int argc, char *argv[]) {
FOREACH_ELEMENT(desc, option_tests)
test_options(desc);
FOREACH_ELEMENT(desc, long_option_tests)
test_option_append_long(desc);
test_option_set();
FOREACH_ELEMENT(desc, option_tests) {

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) {
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);
enumerator->devices = mfree(enumerator->devices);
enumerator->n_devices = 0;
@ -471,6 +471,11 @@ failed:
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) {
const char *syspath;
int r;
@ -482,7 +487,7 @@ int device_enumerator_add_device(sd_device_enumerator *enumerator, sd_device *de
if (r < 0)
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))
return 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) {
assert(device);
device->all_tags = set_free_free(device->all_tags);
device->current_tags = set_free_free(device->current_tags);
device->all_tags = set_free(device->all_tags);
device->current_tags = set_free(device->current_tags);
device->property_tags_outdated = true;
device->tags_generation++;
}
@ -701,7 +701,7 @@ void device_cleanup_tags(sd_device *device) {
void device_cleanup_devlinks(sd_device *device) {
assert(device);
set_free_free(device->devlinks);
set_free(device->devlinks);
device->devlinks = NULL;
device->property_devlinks_outdated = true;
device->devlinks_generation++;

View File

@ -98,7 +98,7 @@ DEFINE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
JournalFile, journal_file_close);
static int mmap_prot_from_open_flags(int flags) {
switch (flags & O_ACCMODE) {
switch (flags & O_ACCMODE_STRICT) {
case O_RDONLY:
return PROT_READ;
case O_WRONLY:
@ -4075,10 +4075,10 @@ int journal_file_open(
assert(mmap_cache);
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;
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;
if (fname && (open_flags & O_CREAT) && !endswith(fname, ".journal"))

View File

@ -1,7 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <fcntl.h>
#include <inttypes.h>
#include <sys/uio.h>
@ -15,6 +14,7 @@
#include "compress.h"
#include "hashmap.h"
#include "journal-def.h"
#include "missing_fcntl.h"
#include "mmap-cache.h"
#include "sparse-endian.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) {
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_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) {
assert(nl);
nl->genl_family_by_name = hashmap_free_with_destructor(nl->genl_family_by_name, genl_family_free);
nl->genl_family_by_id = hashmap_free_with_destructor(nl->genl_family_by_id, genl_family_free);
nl->genl_family_by_name = hashmap_free(nl->genl_family_by_name);
nl->genl_family_by_id = hashmap_free(nl->genl_family_by_id);
}
static int genl_family_new_unsupported(
@ -80,7 +90,7 @@ static int genl_family_new_unsupported(
if (!f->name)
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)
return r;
@ -190,11 +200,11 @@ static int genl_family_new(
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)
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) {
hashmap_remove(nl->genl_family_by_id, UINT_TO_PTR(f->id));
return r;

View File

@ -6,5 +6,5 @@
struct udev_device;
struct udev_device *udev_device_new(struct udev *udev, sd_device *device);
sd_device *udev_device_get_sd_device(struct udev_device *udev_device);
struct udev_device* udev_device_new(struct udev *udev, sd_device *device);
sd_device* udev_device_get_sd_device(struct udev_device *udev_device);

View File

@ -120,7 +120,7 @@ _public_ dev_t udev_device_get_devnum(struct udev_device *udev_device) {
*
* Returns: the driver name string, or #NULL if there is no driver attached.
**/
_public_ const char *udev_device_get_driver(struct udev_device *udev_device) {
_public_ const char* udev_device_get_driver(struct udev_device *udev_device) {
const char *driver;
int r;
@ -141,7 +141,7 @@ _public_ const char *udev_device_get_driver(struct udev_device *udev_device) {
*
* Returns: the devtype name of the udev device, or #NULL if it cannot be determined
**/
_public_ const char *udev_device_get_devtype(struct udev_device *udev_device) {
_public_ const char* udev_device_get_devtype(struct udev_device *udev_device) {
const char *devtype;
int r;
@ -165,7 +165,7 @@ _public_ const char *udev_device_get_devtype(struct udev_device *udev_device) {
*
* Returns: the subsystem name of the udev device, or #NULL if it cannot be determined
**/
_public_ const char *udev_device_get_subsystem(struct udev_device *udev_device) {
_public_ const char* udev_device_get_subsystem(struct udev_device *udev_device) {
const char *subsystem;
int r;
@ -187,7 +187,7 @@ _public_ const char *udev_device_get_subsystem(struct udev_device *udev_device)
*
* Returns: the property string, or #NULL if there is no such property.
**/
_public_ const char *udev_device_get_property_value(struct udev_device *udev_device, const char *key) {
_public_ const char* udev_device_get_property_value(struct udev_device *udev_device, const char *key) {
const char *value;
int r;
@ -200,7 +200,7 @@ _public_ const char *udev_device_get_property_value(struct udev_device *udev_dev
return value;
}
struct udev_device *udev_device_new(struct udev *udev, sd_device *device) {
struct udev_device* udev_device_new(struct udev *udev, sd_device *device) {
_cleanup_(udev_list_freep) struct udev_list *properties = NULL, *all_tags = NULL, *current_tags = NULL, *sysattrs = NULL, *devlinks = NULL;
struct udev_device *udev_device;
@ -254,7 +254,7 @@ struct udev_device *udev_device_new(struct udev *udev, sd_device *device) {
*
* Returns: a new udev device, or #NULL, if it does not exist
**/
_public_ struct udev_device *udev_device_new_from_syspath(struct udev *udev, const char *syspath) {
_public_ struct udev_device* udev_device_new_from_syspath(struct udev *udev, const char *syspath) {
_cleanup_(sd_device_unrefp) sd_device *device = NULL;
int r;
@ -281,7 +281,7 @@ _public_ struct udev_device *udev_device_new_from_syspath(struct udev *udev, con
*
* Returns: a new udev device, or #NULL, if it does not exist
**/
_public_ struct udev_device *udev_device_new_from_devnum(struct udev *udev, char type, dev_t devnum) {
_public_ struct udev_device* udev_device_new_from_devnum(struct udev *udev, char type, dev_t devnum) {
_cleanup_(sd_device_unrefp) sd_device *device = NULL;
int r;
@ -310,7 +310,7 @@ _public_ struct udev_device *udev_device_new_from_devnum(struct udev *udev, char
*
* Returns: a new udev device, or #NULL, if it does not exist
**/
_public_ struct udev_device *udev_device_new_from_device_id(struct udev *udev, const char *id) {
_public_ struct udev_device* udev_device_new_from_device_id(struct udev *udev, const char *id) {
_cleanup_(sd_device_unrefp) sd_device *device = NULL;
int r;
@ -336,7 +336,7 @@ _public_ struct udev_device *udev_device_new_from_device_id(struct udev *udev, c
*
* Returns: a new udev device, or #NULL, if it does not exist
**/
_public_ struct udev_device *udev_device_new_from_subsystem_sysname(struct udev *udev, const char *subsystem, const char *sysname) {
_public_ struct udev_device* udev_device_new_from_subsystem_sysname(struct udev *udev, const char *subsystem, const char *sysname) {
_cleanup_(sd_device_unrefp) sd_device *device = NULL;
int r;
@ -361,7 +361,7 @@ _public_ struct udev_device *udev_device_new_from_subsystem_sysname(struct udev
*
* Returns: a new udev device, or #NULL, if it does not exist
**/
_public_ struct udev_device *udev_device_new_from_environment(struct udev *udev) {
_public_ struct udev_device* udev_device_new_from_environment(struct udev *udev) {
_cleanup_(sd_device_unrefp) sd_device *device = NULL;
int r;
@ -372,7 +372,7 @@ _public_ struct udev_device *udev_device_new_from_environment(struct udev *udev)
return udev_device_new(udev, device);
}
static struct udev_device *device_new_from_parent(struct udev_device *child) {
static struct udev_device* device_new_from_parent(struct udev_device *child) {
sd_device *parent;
int r;
@ -403,7 +403,7 @@ static struct udev_device *device_new_from_parent(struct udev_device *child) {
*
* Returns: a new udev device, or #NULL, if it no parent exist.
**/
_public_ struct udev_device *udev_device_get_parent(struct udev_device *udev_device) {
_public_ struct udev_device* udev_device_get_parent(struct udev_device *udev_device) {
assert_return_errno(udev_device, NULL, EINVAL);
if (!udev_device->parent_set) {
@ -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.
**/
_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;
int r;
@ -467,13 +471,13 @@ _public_ struct udev_device *udev_device_get_parent_with_subsystem_devtype(struc
*
* Returns: the udev library context
**/
_public_ struct udev *udev_device_get_udev(struct udev_device *udev_device) {
_public_ struct udev* udev_device_get_udev(struct udev_device *udev_device) {
assert_return_errno(udev_device, NULL, EINVAL);
return udev_device->udev;
}
static struct udev_device *udev_device_free(struct udev_device *udev_device) {
static struct udev_device* udev_device_free(struct udev_device *udev_device) {
assert(udev_device);
sd_device_unref(udev_device->device);
@ -517,7 +521,7 @@ DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(struct udev_device, udev_device, udev_devic
*
* Returns: the devpath of the udev device
**/
_public_ const char *udev_device_get_devpath(struct udev_device *udev_device) {
_public_ const char* udev_device_get_devpath(struct udev_device *udev_device) {
const char *devpath;
int r;
@ -539,7 +543,7 @@ _public_ const char *udev_device_get_devpath(struct udev_device *udev_device) {
*
* Returns: the sys path of the udev device
**/
_public_ const char *udev_device_get_syspath(struct udev_device *udev_device) {
_public_ const char* udev_device_get_syspath(struct udev_device *udev_device) {
const char *syspath;
int r;
@ -560,7 +564,7 @@ _public_ const char *udev_device_get_syspath(struct udev_device *udev_device) {
*
* Returns: the name string of the device
**/
_public_ const char *udev_device_get_sysname(struct udev_device *udev_device) {
_public_ const char* udev_device_get_sysname(struct udev_device *udev_device) {
const char *sysname;
int r;
@ -581,7 +585,7 @@ _public_ const char *udev_device_get_sysname(struct udev_device *udev_device) {
*
* Returns: the trailing number string of the device name
**/
_public_ const char *udev_device_get_sysnum(struct udev_device *udev_device) {
_public_ const char* udev_device_get_sysnum(struct udev_device *udev_device) {
const char *sysnum;
int r;
@ -605,7 +609,7 @@ _public_ const char *udev_device_get_sysnum(struct udev_device *udev_device) {
*
* Returns: the device node file name of the udev device, or #NULL if no device node exists
**/
_public_ const char *udev_device_get_devnode(struct udev_device *udev_device) {
_public_ const char* udev_device_get_devnode(struct udev_device *udev_device) {
const char *devnode;
int r;
@ -631,7 +635,7 @@ _public_ const char *udev_device_get_devnode(struct udev_device *udev_device) {
*
* Returns: the first entry of the device node link list
**/
_public_ struct udev_list_entry *udev_device_get_devlinks_list_entry(struct udev_device *udev_device) {
_public_ struct udev_list_entry* udev_device_get_devlinks_list_entry(struct udev_device *udev_device) {
assert_return_errno(udev_device, NULL, EINVAL);
if (device_get_devlinks_generation(udev_device->device) != udev_device->devlinks_generation ||
@ -661,7 +665,7 @@ _public_ struct udev_list_entry *udev_device_get_devlinks_list_entry(struct udev
*
* Returns: the first entry of the property list
**/
_public_ struct udev_list_entry *udev_device_get_properties_list_entry(struct udev_device *udev_device) {
_public_ struct udev_list_entry* udev_device_get_properties_list_entry(struct udev_device *udev_device) {
assert_return_errno(udev_device, NULL, EINVAL);
if (device_get_properties_generation(udev_device->device) != udev_device->properties_generation ||
@ -689,7 +693,7 @@ _public_ struct udev_list_entry *udev_device_get_properties_list_entry(struct ud
*
* Returns: the kernel action value, or #NULL if there is no action value available.
**/
_public_ const char *udev_device_get_action(struct udev_device *udev_device) {
_public_ const char* udev_device_get_action(struct udev_device *udev_device) {
sd_device_action_t action;
assert_return_errno(udev_device, NULL, EINVAL);
@ -735,7 +739,7 @@ _public_ unsigned long long int udev_device_get_usec_since_initialized(struct ud
*
* Returns: the content of a sys attribute file, or #NULL if there is no sys attribute value.
**/
_public_ const char *udev_device_get_sysattr_value(struct udev_device *udev_device, const char *sysattr) {
_public_ const char* udev_device_get_sysattr_value(struct udev_device *udev_device, const char *sysattr) {
const char *value;
int r;
@ -780,7 +784,7 @@ _public_ int udev_device_set_sysattr_value(struct udev_device *udev_device, cons
*
* Returns: the first entry of the property list
**/
_public_ struct udev_list_entry *udev_device_get_sysattr_list_entry(struct udev_device *udev_device) {
_public_ struct udev_list_entry* udev_device_get_sysattr_list_entry(struct udev_device *udev_device) {
assert_return_errno(udev_device, NULL, EINVAL);
if (!udev_device->sysattrs_read) {
@ -832,7 +836,7 @@ _public_ int udev_device_get_is_initialized(struct udev_device *udev_device) {
*
* Returns: the first entry of the tag list
**/
_public_ struct udev_list_entry *udev_device_get_tags_list_entry(struct udev_device *udev_device) {
_public_ struct udev_list_entry* udev_device_get_tags_list_entry(struct udev_device *udev_device) {
assert_return_errno(udev_device, NULL, EINVAL);
if (device_get_tags_generation(udev_device->device) != udev_device->all_tags_generation ||
@ -850,7 +854,7 @@ _public_ struct udev_list_entry *udev_device_get_tags_list_entry(struct udev_dev
return udev_list_get_entry(udev_device->all_tags);
}
_public_ struct udev_list_entry *udev_device_get_current_tags_list_entry(struct udev_device *udev_device) {
_public_ struct udev_list_entry* udev_device_get_current_tags_list_entry(struct udev_device *udev_device) {
assert_return_errno(udev_device, NULL, EINVAL);
if (device_get_tags_generation(udev_device->device) != udev_device->current_tags_generation ||
@ -889,7 +893,7 @@ _public_ int udev_device_has_current_tag(struct udev_device *udev_device, const
return sd_device_has_current_tag(udev_device->device, tag) > 0;
}
sd_device *udev_device_get_sd_device(struct udev_device *udev_device) {
sd_device* udev_device_get_sd_device(struct udev_device *udev_device) {
assert(udev_device);
return udev_device->device;

View File

@ -49,7 +49,7 @@ struct udev_enumerate {
*
* Returns: an enumeration context.
**/
_public_ struct udev_enumerate *udev_enumerate_new(struct udev *udev) {
_public_ struct udev_enumerate* udev_enumerate_new(struct udev *udev) {
_cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
_cleanup_(udev_list_freep) struct udev_list *list = NULL;
struct udev_enumerate *udev_enumerate;
@ -81,7 +81,7 @@ _public_ struct udev_enumerate *udev_enumerate_new(struct udev *udev) {
return udev_enumerate;
}
static struct udev_enumerate *udev_enumerate_free(struct udev_enumerate *udev_enumerate) {
static struct udev_enumerate* udev_enumerate_free(struct udev_enumerate *udev_enumerate) {
assert(udev_enumerate);
udev_list_free(udev_enumerate->devices_list);
@ -117,7 +117,7 @@ DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(struct udev_enumerate, udev_enumerate, udev
*
* Returns: a pointer to the context.
*/
_public_ struct udev *udev_enumerate_get_udev(struct udev_enumerate *udev_enumerate) {
_public_ struct udev* udev_enumerate_get_udev(struct udev_enumerate *udev_enumerate) {
assert_return_errno(udev_enumerate, NULL, EINVAL);
return udev_enumerate->udev;
@ -131,7 +131,7 @@ _public_ struct udev *udev_enumerate_get_udev(struct udev_enumerate *udev_enumer
*
* Returns: a udev_list_entry.
*/
_public_ struct udev_list_entry *udev_enumerate_get_list_entry(struct udev_enumerate *udev_enumerate) {
_public_ struct udev_list_entry* udev_enumerate_get_list_entry(struct udev_enumerate *udev_enumerate) {
struct udev_list_entry *e;
assert_return_errno(udev_enumerate, NULL, EINVAL);

View File

@ -34,7 +34,7 @@ struct udev_hwdb {
*
* Returns: a hwdb context.
**/
_public_ struct udev_hwdb *udev_hwdb_new(struct udev *udev) {
_public_ struct udev_hwdb* udev_hwdb_new(struct udev *udev) {
_cleanup_(udev_list_freep) struct udev_list *list = NULL;
_cleanup_(sd_hwdb_unrefp) sd_hwdb *hwdb_internal = NULL;
struct udev_hwdb *hwdb;
@ -61,7 +61,7 @@ _public_ struct udev_hwdb *udev_hwdb_new(struct udev *udev) {
return hwdb;
}
static struct udev_hwdb *udev_hwdb_free(struct udev_hwdb *hwdb) {
static struct udev_hwdb* udev_hwdb_free(struct udev_hwdb *hwdb) {
assert(hwdb);
sd_hwdb_unref(hwdb->hwdb);
@ -102,7 +102,7 @@ DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(struct udev_hwdb, udev_hwdb, udev_hwdb_free
*
* Returns: a udev_list_entry.
*/
_public_ struct udev_list_entry *udev_hwdb_get_properties_list_entry(struct udev_hwdb *hwdb, const char *modalias, unsigned flags) {
_public_ struct udev_list_entry* udev_hwdb_get_properties_list_entry(struct udev_hwdb *hwdb, const char *modalias, unsigned flags) {
const char *key, *value;
struct udev_list_entry *e;

View File

@ -7,10 +7,10 @@
struct udev_list;
struct udev_list *udev_list_new(bool unique);
struct udev_list* udev_list_new(bool unique);
void udev_list_cleanup(struct udev_list *list);
struct udev_list *udev_list_free(struct udev_list *list);
DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev_list *, udev_list_free);
struct udev_list* udev_list_free(struct udev_list *list);
DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev_list*, udev_list_free);
struct udev_list_entry *udev_list_get_entry(struct udev_list *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_get_entry(struct udev_list *list);
struct udev_list_entry* udev_list_entry_add(struct udev_list *list, const char *name, const char *value);

View File

@ -4,7 +4,6 @@
#include "hashmap.h"
#include "libudev-list-internal.h"
#include "list.h"
#include "sort-util.h"
/**
* SECTION:libudev-list
@ -34,7 +33,7 @@ struct udev_list {
bool uptodate:1;
};
static struct udev_list_entry *udev_list_entry_free(struct udev_list_entry *entry) {
static struct udev_list_entry* udev_list_entry_free(struct udev_list_entry *entry) {
if (!entry)
return NULL;
@ -52,9 +51,14 @@ static struct udev_list_entry *udev_list_entry_free(struct udev_list_entry *entr
return mfree(entry);
}
DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev_list_entry *, udev_list_entry_free);
DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev_list_entry*, udev_list_entry_free);
struct udev_list *udev_list_new(bool unique) {
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 *list;
list = new(struct udev_list, 1);
@ -68,36 +72,26 @@ struct udev_list *udev_list_new(bool unique) {
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_free_ char *name = NULL, *value = NULL;
assert(list);
assert(_name);
assert(name);
name = strdup(_name);
if (!name)
return NULL;
if (_value) {
value = strdup(_value);
if (!value)
return NULL;
}
entry = new(struct udev_list_entry, 1);
entry = new0(struct udev_list_entry, 1);
if (!entry)
return NULL;
*entry = (struct udev_list_entry) {
.name = TAKE_PTR(name),
.value = TAKE_PTR(value),
};
if (strdup_to(&entry->name, name) < 0)
return NULL;
if (strdup_to(&entry->value, value) < 0)
return NULL;
if (list->unique) {
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;
list->uptodate = false;
@ -115,13 +109,13 @@ void udev_list_cleanup(struct udev_list *list) {
if (list->unique) {
list->uptodate = false;
hashmap_clear_with_destructor(list->unique_entries, udev_list_entry_free);
hashmap_clear(list->unique_entries);
} else
LIST_FOREACH(entries, i, list->entries)
udev_list_entry_free(i);
}
struct udev_list *udev_list_free(struct udev_list *list) {
struct udev_list* udev_list_free(struct udev_list *list) {
if (!list)
return NULL;
@ -131,11 +125,7 @@ struct udev_list *udev_list_free(struct udev_list *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)
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));
else {
_cleanup_free_ struct udev_list_entry **buf = NULL;
struct udev_list_entry *entry, **p;
buf = new(struct udev_list_entry *, n);
if (!buf)
if (hashmap_dump_sorted(list->unique_entries, (void***) &buf, /* ret_n = */ NULL) < 0)
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--)
LIST_PREPEND(entries, list->entries, buf[j-1]);
}
@ -181,7 +163,7 @@ struct udev_list_entry *udev_list_get_entry(struct udev_list *list) {
*
* Returns: udev_list_entry, #NULL if no more entries are available.
*/
_public_ struct udev_list_entry *udev_list_entry_get_next(struct udev_list_entry *list_entry) {
_public_ struct udev_list_entry* udev_list_entry_get_next(struct udev_list_entry *list_entry) {
if (!list_entry)
return NULL;
if (list_entry->list->unique && !list_entry->list->uptodate)
@ -198,7 +180,7 @@ _public_ struct udev_list_entry *udev_list_entry_get_next(struct udev_list_entry
*
* Returns: udev_list_entry, #NULL if no matching entry is found.
*/
_public_ struct udev_list_entry *udev_list_entry_get_by_name(struct udev_list_entry *list_entry, const char *name) {
_public_ struct udev_list_entry* udev_list_entry_get_by_name(struct udev_list_entry *list_entry, const char *name) {
if (!list_entry)
return NULL;
if (!list_entry->list->unique || !list_entry->list->uptodate)
@ -214,7 +196,7 @@ _public_ struct udev_list_entry *udev_list_entry_get_by_name(struct udev_list_en
*
* Returns: the name string of this entry.
*/
_public_ const char *udev_list_entry_get_name(struct udev_list_entry *list_entry) {
_public_ const char* udev_list_entry_get_name(struct udev_list_entry *list_entry) {
if (!list_entry)
return NULL;
return list_entry->name;
@ -228,7 +210,7 @@ _public_ const char *udev_list_entry_get_name(struct udev_list_entry *list_entry
*
* Returns: the value string of this entry.
*/
_public_ const char *udev_list_entry_get_value(struct udev_list_entry *list_entry) {
_public_ const char* udev_list_entry_get_value(struct udev_list_entry *list_entry) {
if (!list_entry)
return NULL;
return list_entry->value;

View File

@ -63,7 +63,7 @@ static MonitorNetlinkGroup monitor_netlink_group_from_string(const char *name) {
*
* Returns: a new udev monitor, or #NULL, in case of an error
**/
_public_ struct udev_monitor *udev_monitor_new_from_netlink(struct udev *udev, const char *name) {
_public_ struct udev_monitor* udev_monitor_new_from_netlink(struct udev *udev, const char *name) {
_cleanup_(sd_device_monitor_unrefp) sd_device_monitor *m = NULL;
struct udev_monitor *udev_monitor;
MonitorNetlinkGroup g;
@ -133,7 +133,7 @@ _public_ int udev_monitor_set_receive_buffer_size(struct udev_monitor *udev_moni
return sd_device_monitor_set_receive_buffer_size(udev_monitor->monitor, (size_t) size);
}
static struct udev_monitor *udev_monitor_free(struct udev_monitor *udev_monitor) {
static struct udev_monitor* udev_monitor_free(struct udev_monitor *udev_monitor) {
assert(udev_monitor);
sd_device_monitor_unref(udev_monitor->monitor);
@ -169,7 +169,7 @@ DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(struct udev_monitor, udev_monitor, udev_mon
*
* Returns: the udev library context
**/
_public_ struct udev *udev_monitor_get_udev(struct udev_monitor *udev_monitor) {
_public_ struct udev* udev_monitor_get_udev(struct udev_monitor *udev_monitor) {
assert_return(udev_monitor, NULL);
return udev_monitor->udev;
@ -236,7 +236,7 @@ static int udev_monitor_receive_sd_device(struct udev_monitor *udev_monitor, sd_
*
* Returns: a new udev device, or #NULL, in case of an error
**/
_public_ struct udev_device *udev_monitor_receive_device(struct udev_monitor *udev_monitor) {
_public_ struct udev_device* udev_monitor_receive_device(struct udev_monitor *udev_monitor) {
_cleanup_(sd_device_unrefp) sd_device *device = NULL;
int r;

View File

@ -40,7 +40,7 @@ struct udev_queue {
*
* Returns: the udev queue context, or #NULL on error.
**/
_public_ struct udev_queue *udev_queue_new(struct udev *udev) {
_public_ struct udev_queue* udev_queue_new(struct udev *udev) {
struct udev_queue *udev_queue;
udev_queue = new(struct udev_queue, 1);
@ -56,7 +56,7 @@ _public_ struct udev_queue *udev_queue_new(struct udev *udev) {
return udev_queue;
}
static struct udev_queue *udev_queue_free(struct udev_queue *udev_queue) {
static struct udev_queue* udev_queue_free(struct udev_queue *udev_queue) {
assert(udev_queue);
safe_close(udev_queue->fd);
@ -91,7 +91,7 @@ DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(struct udev_queue, udev_queue, udev_queue_f
*
* Returns: the udev library context.
**/
_public_ struct udev *udev_queue_get_udev(struct udev_queue *udev_queue) {
_public_ struct udev* udev_queue_get_udev(struct udev_queue *udev_queue) {
assert_return_errno(udev_queue, NULL, EINVAL);
return udev_queue->udev;
@ -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.
**/
_public_ int udev_queue_get_seqnum_sequence_is_finished(struct udev_queue *udev_queue,
unsigned long long int start, unsigned long long int end) {
_public_ int udev_queue_get_seqnum_sequence_is_finished(
struct udev_queue *udev_queue,
unsigned long long int start,
unsigned long long int end) {
return udev_queue_is_empty() > 0;
}
@ -181,7 +184,7 @@ _public_ int udev_queue_get_seqnum_is_finished(struct udev_queue *udev_queue, un
*
* Returns: NULL.
**/
_public_ struct udev_list_entry *udev_queue_get_queued_list_entry(struct udev_queue *udev_queue) {
_public_ struct udev_list_entry* udev_queue_get_queued_list_entry(struct udev_queue *udev_queue) {
return_with_errno(NULL, ENODATA);
}

View File

@ -36,7 +36,7 @@ struct udev {
*
* Returns: stored userdata
**/
_public_ void *udev_get_userdata(struct udev *udev) {
_public_ void* udev_get_userdata(struct udev *udev) {
assert_return(udev, NULL);
return udev->userdata;
@ -66,7 +66,7 @@ _public_ void udev_set_userdata(struct udev *udev, void *userdata) {
*
* Returns: a new udev library context
**/
_public_ struct udev *udev_new(void) {
_public_ struct udev* udev_new(void) {
struct udev *udev;
udev = new(struct udev, 1);
@ -99,7 +99,7 @@ DEFINE_PUBLIC_TRIVIAL_REF_FUNC(struct udev, udev);
*
* Returns: the passed udev library context if it has still an active reference, or #NULL otherwise.
**/
_public_ struct udev *udev_unref(struct udev *udev) {
_public_ struct udev* udev_unref(struct udev *udev) {
if (!udev)
return NULL;
@ -123,10 +123,14 @@ _public_ struct udev *udev_unref(struct udev *udev) {
*
**/
_public_ void udev_set_log_fn(
struct udev *udev,
void (*log_fn)(struct udev *udev,
int priority, const char *file, int line, const char *fn,
const char *format, va_list args)) {
struct udev *udev,
void (*log_fn)(struct udev *udev,
int priority,
const char *file,
int line,
const char *fn,
const char *format,
va_list args)) {
return;
}

View File

@ -18,16 +18,21 @@ extern "C" {
* allows custom logging
*/
struct udev;
struct udev *udev_ref(struct udev *udev);
struct udev *udev_unref(struct udev *udev);
struct udev *udev_new(void);
void udev_set_log_fn(struct udev *udev,
void (*log_fn)(struct udev *udev,
int priority, const char *file, int line, const char *fn,
const char *format, va_list args)) __attribute__((__deprecated__));
struct udev* udev_ref(struct udev *udev);
struct udev* udev_unref(struct udev *udev);
struct udev* udev_new(void);
void udev_set_log_fn(
struct udev *udev,
void (*log_fn)(struct udev *udev,
int priority,
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__));
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);
void udev_set_userdata(struct udev *udev, void *userdata);
/*
@ -36,8 +41,8 @@ void udev_set_userdata(struct udev *udev, void *userdata);
* access to libudev generated lists
*/
struct udev_list_entry;
struct udev_list_entry *udev_list_entry_get_next(struct udev_list_entry *list_entry);
struct udev_list_entry *udev_list_entry_get_by_name(struct udev_list_entry *list_entry, const char *name);
struct udev_list_entry* udev_list_entry_get_next(struct udev_list_entry *list_entry);
struct udev_list_entry* udev_list_entry_get_by_name(struct udev_list_entry *list_entry, const char *name);
const char* udev_list_entry_get_name(struct udev_list_entry *list_entry);
const char* udev_list_entry_get_value(struct udev_list_entry *list_entry);
/**
@ -58,18 +63,20 @@ const char* udev_list_entry_get_value(struct udev_list_entry *list_entry);
* access to sysfs/kernel devices
*/
struct udev_device;
struct udev_device *udev_device_ref(struct udev_device *udev_device);
struct udev_device *udev_device_unref(struct udev_device *udev_device);
struct udev *udev_device_get_udev(struct udev_device *udev_device);
struct udev_device *udev_device_new_from_syspath(struct udev *udev, const char *syspath);
struct udev_device *udev_device_new_from_devnum(struct udev *udev, char type, dev_t devnum);
struct udev_device *udev_device_new_from_subsystem_sysname(struct udev *udev, const char *subsystem, const char *sysname);
struct udev_device *udev_device_new_from_device_id(struct udev *udev, const char *id);
struct udev_device *udev_device_new_from_environment(struct udev *udev);
struct udev_device* udev_device_ref(struct udev_device *udev_device);
struct udev_device* udev_device_unref(struct udev_device *udev_device);
struct udev* udev_device_get_udev(struct udev_device *udev_device);
struct udev_device* udev_device_new_from_syspath(struct udev *udev, const char *syspath);
struct udev_device* udev_device_new_from_devnum(struct udev *udev, char type, dev_t devnum);
struct udev_device* udev_device_new_from_subsystem_sysname(struct udev *udev, const char *subsystem, const char *sysname);
struct udev_device* udev_device_new_from_device_id(struct udev *udev, const char *id);
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 */
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,
const char *subsystem, const char *devtype);
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,
const char *subsystem,
const char *devtype);
/* retrieve device properties */
const char* udev_device_get_devpath(struct udev_device *udev_device);
const char* udev_device_get_subsystem(struct udev_device *udev_device);
@ -79,11 +86,11 @@ const char* udev_device_get_sysname(struct udev_device *udev_device);
const char* udev_device_get_sysnum(struct udev_device *udev_device);
const char* udev_device_get_devnode(struct udev_device *udev_device);
int udev_device_get_is_initialized(struct udev_device *udev_device);
struct udev_list_entry *udev_device_get_devlinks_list_entry(struct udev_device *udev_device);
struct udev_list_entry *udev_device_get_properties_list_entry(struct udev_device *udev_device);
struct udev_list_entry *udev_device_get_tags_list_entry(struct udev_device *udev_device);
struct udev_list_entry *udev_device_get_current_tags_list_entry(struct udev_device *udev_device);
struct udev_list_entry *udev_device_get_sysattr_list_entry(struct udev_device *udev_device);
struct udev_list_entry* udev_device_get_devlinks_list_entry(struct udev_device *udev_device);
struct udev_list_entry* udev_device_get_properties_list_entry(struct udev_device *udev_device);
struct udev_list_entry* udev_device_get_tags_list_entry(struct udev_device *udev_device);
struct udev_list_entry* udev_device_get_current_tags_list_entry(struct udev_device *udev_device);
struct udev_list_entry* udev_device_get_sysattr_list_entry(struct udev_device *udev_device);
const char* udev_device_get_property_value(struct udev_device *udev_device, const char *key);
const char* udev_device_get_driver(struct udev_device *udev_device);
dev_t udev_device_get_devnum(struct udev_device *udev_device);
@ -101,19 +108,21 @@ int udev_device_has_current_tag(struct udev_device *udev_device, const char *tag
* access to kernel uevents and udev events
*/
struct udev_monitor;
struct udev_monitor *udev_monitor_ref(struct udev_monitor *udev_monitor);
struct udev_monitor *udev_monitor_unref(struct udev_monitor *udev_monitor);
struct udev *udev_monitor_get_udev(struct udev_monitor *udev_monitor);
struct udev_monitor* udev_monitor_ref(struct udev_monitor *udev_monitor);
struct udev_monitor* udev_monitor_unref(struct udev_monitor *udev_monitor);
struct udev* udev_monitor_get_udev(struct udev_monitor *udev_monitor);
/* kernel and udev generated events over netlink */
struct udev_monitor *udev_monitor_new_from_netlink(struct udev *udev, const char *name);
struct udev_monitor* udev_monitor_new_from_netlink(struct udev *udev, const char *name);
/* bind socket */
int udev_monitor_enable_receiving(struct udev_monitor *udev_monitor);
int udev_monitor_set_receive_buffer_size(struct udev_monitor *udev_monitor, int size);
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 */
int udev_monitor_filter_add_match_subsystem_devtype(struct udev_monitor *udev_monitor,
const char *subsystem, const char *devtype);
int udev_monitor_filter_add_match_subsystem_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_update(struct udev_monitor *udev_monitor);
int udev_monitor_filter_remove(struct udev_monitor *udev_monitor);
@ -124,10 +133,10 @@ int udev_monitor_filter_remove(struct udev_monitor *udev_monitor);
* search sysfs for specific devices and provide a sorted list
*/
struct udev_enumerate;
struct udev_enumerate *udev_enumerate_ref(struct udev_enumerate *udev_enumerate);
struct udev_enumerate *udev_enumerate_unref(struct udev_enumerate *udev_enumerate);
struct udev *udev_enumerate_get_udev(struct udev_enumerate *udev_enumerate);
struct udev_enumerate *udev_enumerate_new(struct udev *udev);
struct udev_enumerate* udev_enumerate_ref(struct udev_enumerate *udev_enumerate);
struct udev_enumerate* udev_enumerate_unref(struct udev_enumerate *udev_enumerate);
struct udev* udev_enumerate_get_udev(struct udev_enumerate *udev_enumerate);
struct udev_enumerate* udev_enumerate_new(struct udev *udev);
/* device properties filter */
int udev_enumerate_add_match_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem);
int udev_enumerate_add_nomatch_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem);
@ -143,7 +152,7 @@ int udev_enumerate_add_syspath(struct udev_enumerate *udev_enumerate, const char
int udev_enumerate_scan_devices(struct udev_enumerate *udev_enumerate);
int udev_enumerate_scan_subsystems(struct udev_enumerate *udev_enumerate);
/* return device list */
struct udev_list_entry *udev_enumerate_get_list_entry(struct udev_enumerate *udev_enumerate);
struct udev_list_entry* udev_enumerate_get_list_entry(struct udev_enumerate *udev_enumerate);
/*
* udev_queue
@ -151,20 +160,22 @@ struct udev_list_entry *udev_enumerate_get_list_entry(struct udev_enumerate *ude
* access to the currently running udev events
*/
struct udev_queue;
struct udev_queue *udev_queue_ref(struct udev_queue *udev_queue);
struct udev_queue *udev_queue_unref(struct udev_queue *udev_queue);
struct udev *udev_queue_get_udev(struct udev_queue *udev_queue);
struct udev_queue *udev_queue_new(struct udev *udev);
struct udev_queue* udev_queue_ref(struct udev_queue *udev_queue);
struct udev_queue* udev_queue_unref(struct udev_queue *udev_queue);
struct udev* udev_queue_get_udev(struct udev_queue *udev_queue);
struct udev_queue* udev_queue_new(struct udev *udev);
unsigned long long int udev_queue_get_kernel_seqnum(struct udev_queue *udev_queue) __attribute__((__deprecated__));
unsigned long long int udev_queue_get_udev_seqnum(struct udev_queue *udev_queue) __attribute__((__deprecated__));
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_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,
unsigned long long int start, unsigned long long int end) __attribute__((__deprecated__));
int udev_queue_get_seqnum_sequence_is_finished(
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_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__));
/*
* udev_hwdb
@ -172,10 +183,10 @@ struct udev_list_entry *udev_queue_get_queued_list_entry(struct udev_queue *udev
* access to the static hardware properties database
*/
struct udev_hwdb;
struct udev_hwdb *udev_hwdb_new(struct udev *udev);
struct udev_hwdb *udev_hwdb_ref(struct udev_hwdb *hwdb);
struct udev_hwdb *udev_hwdb_unref(struct udev_hwdb *hwdb);
struct udev_list_entry *udev_hwdb_get_properties_list_entry(struct udev_hwdb *hwdb, const char *modalias, unsigned flags);
struct udev_hwdb* udev_hwdb_new(struct udev *udev);
struct udev_hwdb* udev_hwdb_ref(struct udev_hwdb *hwdb);
struct udev_hwdb* udev_hwdb_unref(struct udev_hwdb *hwdb);
struct udev_list_entry* udev_hwdb_get_properties_list_entry(struct udev_hwdb *hwdb, const char *modalias, unsigned flags);
/*
* udev_util

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);
if (flags < 0)
return -errno;
if ((flags & O_ACCMODE) != O_RDWR)
if ((flags & O_ACCMODE_STRICT) != O_RDWR)
return -EACCES;
if (FLAGS_SET(flags, O_PATH))
return -ENOTTY;

View File

@ -99,7 +99,7 @@ static int validate_image_fd(int fd, MountImageParameters *p) {
if (fl < 0)
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:
p->read_only = true;

View File

@ -22,8 +22,7 @@
#define STATIC_BRIDGE_FDB_ENTRIES_PER_NETWORK_MAX 1024U
/* remove and FDB entry. */
BridgeFDB *bridge_fdb_free(BridgeFDB *fdb) {
static BridgeFDB* bridge_fdb_free(BridgeFDB *fdb) {
if (!fdb)
return NULL;
@ -40,7 +39,11 @@ BridgeFDB *bridge_fdb_free(BridgeFDB *fdb) {
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(
Network *network,
const char *filename,
@ -83,13 +86,12 @@ static int bridge_fdb_new_static(
.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)
return r;
/* return allocated FDB structure. */
*ret = TAKE_PTR(fdb);
return 0;
}

View File

@ -40,8 +40,6 @@ typedef struct BridgeFDB {
int outgoing_ifindex;
} BridgeFDB;
BridgeFDB *bridge_fdb_free(BridgeFDB *fdb);
void network_drop_invalid_bridge_fdb_entries(Network *network);
int link_request_static_bridge_fdb(Link *link);

View File

@ -10,13 +10,13 @@
#include "networkd-manager.h"
#include "networkd-network.h"
#include "networkd-queue.h"
#include "networkd-util.h"
#include "string-util.h"
#include "vlan-util.h"
#define STATIC_BRIDGE_MDB_ENTRIES_PER_NETWORK_MAX 1024U
/* remove MDB entry. */
BridgeMDB *bridge_mdb_free(BridgeMDB *mdb) {
static BridgeMDB* bridge_mdb_free(BridgeMDB *mdb) {
if (!mdb)
return NULL;
@ -32,7 +32,11 @@ BridgeMDB *bridge_mdb_free(BridgeMDB *mdb) {
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(
Network *network,
const char *filename,
@ -74,7 +78,7 @@ static int bridge_mdb_new_static(
.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)
return r;

View File

@ -5,7 +5,6 @@
#include "conf-parser.h"
#include "in-addr-util.h"
#include "networkd-util.h"
typedef struct Link Link;
typedef struct Network Network;
@ -30,8 +29,6 @@ typedef struct BridgeMDB {
uint16_t vlan_id;
} BridgeMDB;
BridgeMDB *bridge_mdb_free(BridgeMDB *mdb);
void network_drop_invalid_bridge_mdb_entries(Network *network);
int link_request_static_bridge_mdb(Link *link);

View File

@ -7,9 +7,7 @@
#include "networkd-network.h"
#include "networkd-util.h"
DEFINE_SECTION_CLEANUP_FUNCTIONS(DHCPStaticLease, dhcp_static_lease_free);
DHCPStaticLease *dhcp_static_lease_free(DHCPStaticLease *static_lease) {
static DHCPStaticLease* dhcp_static_lease_free(DHCPStaticLease *static_lease) {
if (!static_lease)
return NULL;
@ -21,6 +19,13 @@ DHCPStaticLease *dhcp_static_lease_free(DHCPStaticLease *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) {
DHCPStaticLease *p;
@ -60,7 +65,8 @@ static int lease_new_static(Network *network, const char *filename, unsigned sec
static_lease->network = network;
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)
return r;

View File

@ -19,7 +19,6 @@ typedef struct DHCPStaticLease {
size_t client_id_size;
} DHCPStaticLease;
DHCPStaticLease *dhcp_static_lease_free(DHCPStaticLease *lease);
void network_drop_invalid_static_leases(Network *network);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_static_lease_address);

View File

@ -281,7 +281,7 @@ int config_parse_dnssec_negative_trust_anchors(
assert(rvalue);
if (isempty(rvalue)) {
*nta = set_free_free(*nta);
*nta = set_free(*nta);
return 0;
}
@ -306,7 +306,7 @@ int config_parse_dnssec_negative_trust_anchors(
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)
return log_oom();
}

View File

@ -22,7 +22,13 @@ void network_adjust_ipv6_proxy_ndp(Network *network) {
log_once(LOG_WARNING,
"%s: IPv6 proxy NDP addresses are set, but IPv6 is not supported by kernel, "
"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);
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;
}
@ -170,11 +176,9 @@ int config_parse_ipv6_proxy_ndp_address(
if (!address)
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)
return log_oom();
if (r > 0)
TAKE_PTR(address);
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) {
_cleanup_set_free_free_ Set *ns = NULL;
_cleanup_set_free_ Set *ns = NULL;
_cleanup_strv_free_ char **ntas = NULL;
Link *l = ASSERT_PTR(userdata);
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);
}
ns = set_new(&dns_name_hash_ops);
ns = set_new(&dns_name_hash_ops_free);
if (!ns)
return -ENOMEM;
@ -523,8 +523,7 @@ int bus_link_method_set_dnssec_negative_trust_anchors(sd_bus_message *message, v
if (r == 0)
return 1; /* Polkit will call us back */
set_free_free(l->dnssec_negative_trust_anchors);
l->dnssec_negative_trust_anchors = TAKE_PTR(ns);
set_free_and_replace(l->dnssec_negative_trust_anchors, ns);
r = link_save_and_clean_full(l, /* also_save_manager = */ true);
if (r < 0)

View File

@ -231,7 +231,7 @@ void link_dns_settings_clear(Link *link) {
link->dnssec_mode = _DNSSEC_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) {
@ -261,7 +261,7 @@ static void link_free_engines(Link *link) {
link->radv = sd_radv_unref(link->radv);
}
static Link *link_free(Link *link) {
static Link* link_free(Link *link) {
assert(link);
(void) link_clear_sysctl_shadows(link);
@ -295,7 +295,7 @@ static Link *link_free(Link *link) {
hashmap_free(link->bound_to_links);
hashmap_free(link->bound_by_links);
set_free_with_destructor(link->slaves, link_unref);
set_free(link->slaves);
network_unref(link->network);
@ -307,6 +307,11 @@ static Link *link_free(Link *link) {
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) {
Link *link;
@ -985,7 +990,7 @@ static int link_append_to_master(Link *link) {
if (link_get_master(link, &master) < 0)
return 0;
r = set_ensure_put(&master->slaves, NULL, link);
r = set_ensure_put(&master->slaves, &link_hash_ops, link);
if (r <= 0)
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,
};
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)
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;
} Link;
extern const struct hash_ops link_hash_ops;
typedef int (*link_netlink_message_handler_t)(sd_netlink*, sd_netlink_message*, Link*);
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->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->dirty_links = set_free(m->dirty_links);
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_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->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
* 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->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);

View File

@ -89,11 +89,11 @@ void network_adjust_ndisc(Network *network) {
/* When RouterAllowList=, PrefixAllowList= or RouteAllowList= are specified, then
* RouterDenyList=, PrefixDenyList= or RouteDenyList= are ignored, respectively. */
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))
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))
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);

View File

@ -44,6 +44,16 @@
#include "strv.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) {
const char *kind_string;
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)
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)
return log_oom();
if (r < 0)
log_warning_errno(r, "%s: Failed to add NetDev '%s' to network, ignoring: %m",
network->filename, (const char *) name);
netdev = NULL;
TAKE_PTR(netdev);
}
return 0;
@ -291,11 +301,6 @@ int network_verify(Network *network) {
if (network->keep_configuration < 0)
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);
if (r < 0)
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)
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)
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) {
OrderedHashmap *new_networks = NULL;
_cleanup_ordered_hashmap_free_ OrderedHashmap *new_networks = NULL;
Network *n, *old;
int r;
@ -653,7 +658,7 @@ int network_reload(Manager *manager) {
r = network_load(manager, &new_networks);
if (r < 0)
goto failure;
return r;
ORDERED_HASHMAP_FOREACH(n, new_networks) {
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. */
r = ordered_hashmap_replace(new_networks, old->name, old);
if (r < 0)
goto failure;
return r;
network_ref(old);
network_unref(n);
}
ordered_hashmap_free_with_destructor(manager->networks, network_unref);
manager->networks = new_networks;
ordered_hashmap_free_and_replace(manager->networks, new_networks);
r = manager_build_dhcp_pd_subnet_ids(manager);
if (r < 0)
@ -693,11 +697,6 @@ int network_reload(Manager *manager) {
return r;
return 0;
failure:
ordered_hashmap_free_with_destructor(new_networks, network_unref);
return r;
}
int manager_build_dhcp_pd_subnet_ids(Manager *manager) {
@ -752,7 +751,7 @@ static Network *network_free(Network *network) {
free(network->dns);
ordered_set_free(network->search_domains);
ordered_set_free(network->route_domains);
set_free_free(network->dnssec_negative_trust_anchors);
set_free(network->dnssec_negative_trust_anchors);
/* DHCP server */
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->bond);
netdev_unref(network->vrf);
hashmap_free_with_destructor(network->stacked_netdevs, netdev_unref);
hashmap_free(network->stacked_netdevs);
/* static configs */
set_free_free(network->ipv6_proxy_ndp_addresses);
set_free(network->ipv6_proxy_ndp_addresses);
ordered_hashmap_free(network->addresses_by_section);
hashmap_free(network->routes_by_section);
ordered_hashmap_free(network->nexthops_by_section);
hashmap_free_with_destructor(network->bridge_fdb_entries_by_section, bridge_fdb_free);
hashmap_free_with_destructor(network->bridge_mdb_entries_by_section, bridge_mdb_free);
hashmap_free(network->bridge_fdb_entries_by_section);
hashmap_free(network->bridge_mdb_entries_by_section);
ordered_hashmap_free(network->neighbors_by_section);
hashmap_free(network->address_labels_by_section);
hashmap_free_with_destructor(network->prefixes_by_section, prefix_free);
hashmap_free_with_destructor(network->route_prefixes_by_section, route_prefix_free);
hashmap_free_with_destructor(network->pref64_prefixes_by_section, prefix64_free);
hashmap_free(network->prefixes_by_section);
hashmap_free(network->route_prefixes_by_section);
hashmap_free(network->pref64_prefixes_by_section);
hashmap_free(network->rules_by_section);
hashmap_free_with_destructor(network->dhcp_static_leases_by_section, dhcp_static_lease_free);
ordered_hashmap_free_with_destructor(network->sr_iov_by_section, sr_iov_free);
hashmap_free(network->dhcp_static_leases_by_section);
ordered_hashmap_free(network->sr_iov_by_section);
hashmap_free(network->qdiscs_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;
}
Prefix* prefix_free(Prefix *prefix) {
static Prefix* prefix_free(Prefix *prefix) {
if (!prefix)
return NULL;
@ -52,6 +52,11 @@ Prefix* prefix_free(Prefix *prefix) {
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) {
_cleanup_(config_section_freep) ConfigSection *n = 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,
};
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)
return r;
@ -95,7 +100,7 @@ static int prefix_new_static(Network *network, const char *filename, unsigned se
return 0;
}
RoutePrefix* route_prefix_free(RoutePrefix *prefix) {
static RoutePrefix* route_prefix_free(RoutePrefix *prefix) {
if (!prefix)
return NULL;
@ -111,6 +116,11 @@ RoutePrefix* route_prefix_free(RoutePrefix *prefix) {
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) {
_cleanup_(config_section_freep) ConfigSection *n = 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,
};
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)
return r;
@ -151,7 +161,7 @@ static int route_prefix_new_static(Network *network, const char *filename, unsig
return 0;
}
Prefix64* prefix64_free(Prefix64 *prefix) {
static Prefix64* prefix64_free(Prefix64 *prefix) {
if (!prefix)
return NULL;
@ -167,6 +177,11 @@ Prefix64* prefix64_free(Prefix64 *prefix) {
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) {
_cleanup_(config_section_freep) ConfigSection *n = 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,
};
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)
return r;
@ -809,9 +824,9 @@ void network_adjust_radv(Network *network) {
}
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->route_prefixes_by_section = hashmap_free_with_destructor(network->route_prefixes_by_section, route_prefix_free);
network->pref64_prefixes_by_section = hashmap_free_with_destructor(network->pref64_prefixes_by_section, prefix64_free);
network->prefixes_by_section = hashmap_free(network->prefixes_by_section);
network->route_prefixes_by_section = hashmap_free(network->route_prefixes_by_section);
network->pref64_prefixes_by_section = hashmap_free(network->pref64_prefixes_by_section);
}
if (!network->router_prefix_delegation)

View File

@ -52,10 +52,6 @@ typedef struct Prefix64 {
sd_ndisc_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);
int link_request_radv_addresses(Link *link);

View File

@ -947,8 +947,6 @@ static int link_save(Link *link) {
}
void link_dirty(Link *link) {
int r;
assert(link);
assert(link->manager);
@ -962,10 +960,9 @@ void link_dirty(Link *link) {
/* Also mark manager dirty as link is dirty */
link->manager->dirty = true;
r = set_ensure_put(&link->manager->dirty_links, NULL, link);
if (r <= 0)
/* Ignore allocation errors and don't take another ref if the link was already dirty */
return;
if (set_ensure_put(&link->manager->dirty_links, &link_hash_ops, link) <= 0)
return; /* Ignore allocation errors and don't take another ref if the link was already dirty */
link_ref(link);
}

View File

@ -12,7 +12,7 @@
#include "udev-util.h"
#include "wifi-util.h"
Wiphy *wiphy_free(Wiphy *w) {
static Wiphy* wiphy_free(Wiphy *w) {
if (!w)
return NULL;
@ -29,6 +29,13 @@ Wiphy *wiphy_free(Wiphy *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) {
_cleanup_(wiphy_freep) Wiphy *w = 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),
};
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)
return r;

View File

@ -31,9 +31,6 @@ typedef struct Wiphy {
RFKillState rfkill_state;
} 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_name(Manager *manager, const char *name, Wiphy **ret);

View File

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

View File

@ -56,6 +56,9 @@ int notify_push_fd(int fd, const char *name) {
if (!state)
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);
}

View File

@ -146,13 +146,13 @@ int memfd_clone_fd(int fd, const char *name, int mode) {
assert(fd >= 0);
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);
if (fstat(fd, &st) < 0)
return -errno;
ro = (mode & O_ACCMODE) == O_RDONLY;
ro = (mode & O_ACCMODE_STRICT) == O_RDONLY;
exec = st.st_mode & 0111;
mfd = memfd_create_wrapper(name,

View File

@ -504,7 +504,7 @@ int journal_file_open_reliably(
-EIDRM)) /* File has been deleted */
return r;
if ((open_flags & O_ACCMODE) == O_RDONLY)
if ((open_flags & O_ACCMODE_STRICT) == O_RDONLY)
return r;
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
* sequence number and ID. */
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,
mmap_cache, /* template = */ NULL, &old_file);
if (r < 0)

View File

@ -500,7 +500,7 @@ static int loop_device_make_internal(
.block_size = sector_size,
.info = {
/* 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_sizelimit = size == UINT64_MAX ? 0 : size,
},

View File

@ -9,6 +9,25 @@
#include "stdio-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) {
SRIOV *sr_iov;
@ -57,7 +76,7 @@ static int sr_iov_new_static(OrderedHashmap **sr_iov_by_section, const char *fil
if (r < 0)
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)
return r;
@ -68,18 +87,6 @@ static int sr_iov_new_static(OrderedHashmap **sr_iov_by_section, const char *fil
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) {
assert(sr_iov);
assert(state);

View File

@ -32,7 +32,6 @@ typedef struct SRIOV {
struct ether_addr mac;
} SRIOV;
SRIOV *sr_iov_free(SRIOV *sr_iov);
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_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_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_boolean);
CONFIG_PARSER_PROTOTYPE(config_parse_sr_iov_link_state);

View File

@ -17,6 +17,7 @@
#include "blockdev-util.h"
#include "detach-loopback.h"
#include "device-util.h"
#include "errno-util.h"
#include "fd-util.h"
#include "shutdown.h"
@ -106,8 +107,12 @@ static int delete_loopback(const char *device) {
fd = open(device, O_RDONLY|O_CLOEXEC);
if (fd < 0) {
log_debug_errno(errno, "Failed to open loopback device %s: %m", device);
return errno == ENOENT ? 0 : -errno;
if (ERRNO_IS_DEVICE_ABSENT(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

View File

@ -131,12 +131,21 @@ static int delete_md(RaidDevice *m) {
assert(m->path);
fd = open(m->path, O_RDONLY|O_CLOEXEC|O_EXCL);
if (fd < 0)
return -errno;
if (fd < 0) {
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);
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) {
@ -164,8 +173,9 @@ static int md_points_list_detach(RaidDevice **head, bool *changed, bool last_try
n_failed++;
continue;
}
if (r > 0)
*changed = true;
*changed = true;
raid_device_free(head, m);
}

View File

@ -7,6 +7,7 @@
#include "alloc-util.h"
#include "detach-swap.h"
#include "errno-util.h"
#include "libmount-util.h"
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) {
int n_failed = 0;
int n_failed = 0, r;
assert(head);
assert(changed);
LIST_FOREACH(swap_device, m, *head) {
log_info("Deactivating swap %s.", m->path);
if (swapoff(m->path) < 0) {
log_warning_errno(errno, "Could not deactivate swap %s: %m", m->path);
r = RET_NERRNO(swapoff(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++;
continue;
}
} else
*changed = true;
*changed = true;
swap_device_free(head, m);
}

View File

@ -21,7 +21,11 @@
_SD_BEGIN_DECLARATIONS;
/* https://www.iana.org/assignments/bootp-dhcp-parameters/bootp-dhcp-parameters.xhtml#options */
/* https://www.iana.org/assignments/bootp-dhcp-parameters/bootp-dhcp-parameters.xhtml#options
*
* When adding a new option, please update the option classification in dhcp-option.c function
* `dhcp_option_can_merge` relative to their RFC3396 behavior.
*/
enum {
SD_DHCP_OPTION_PAD = 0, /* [RFC2132] */
SD_DHCP_OPTION_SUBNET_MASK = 1, /* [RFC2132] */

View File

@ -143,7 +143,7 @@ static void context_done(Context *c) {
hashmap_free(c->database_by_gid);
hashmap_free(c->database_by_groupname);
set_free_free(c->names);
set_free(c->names);
uid_range_free(c->uid_range);
}
@ -231,9 +231,8 @@ static int load_user_database(Context *c) {
if (!n)
return -ENOMEM;
/* Note that we use NULL hash_ops (i.e. trivial_hash_ops) here, so identical strings can
* exist in the set. */
r = set_ensure_consume(&c->names, /* hash_ops= */ NULL, n);
/* Note that we use trivial_hash_ops_free here, so identical strings can exist in the set. */
r = set_ensure_consume(&c->names, &trivial_hash_ops_free, n);
if (r < 0)
return r;
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)
return -ENOMEM;
/* Note that we use NULL hash_ops (i.e. trivial_hash_ops) here, so identical strings can
* exist in the set. */
r = set_ensure_consume(&c->names, /* hash_ops= */ NULL, n);
/* Note that we use trivial_hash_ops_free here, so identical strings can exist in the set. */
r = set_ensure_consume(&c->names, &trivial_hash_ops_free, n);
if (r < 0)
return r;
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;
} SysvStub;
static SysvStub* free_sysvstub(SysvStub *s) {
static SysvStub* sysvstub_free(SysvStub *s) {
if (!s)
return NULL;
@ -78,11 +78,12 @@ static SysvStub* free_sysvstub(SysvStub *s) {
strv_free(s->wanted_by);
return mfree(s);
}
DEFINE_TRIVIAL_CLEANUP_FUNC(SysvStub*, free_sysvstub);
DEFINE_TRIVIAL_CLEANUP_FUNC(SysvStub*, sysvstub_free);
static void free_sysvstub_hashmapp(Hashmap **h) {
hashmap_free_with_destructor(*h, free_sysvstub);
}
DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
sysvstub_hash_ops,
char, string_hash_func, string_compare_func,
SysvStub, sysvstub_free);
static int add_alias(const char *service, const char *alias) {
_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)) {
_cleanup_free_ char *fpath = NULL, *name = NULL;
_cleanup_(free_sysvstubp) SysvStub *service = NULL;
_cleanup_(sysvstub_freep) SysvStub *service = NULL;
struct stat st;
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) {
_cleanup_(free_sysvstub_hashmapp) Hashmap *all_services = NULL;
_cleanup_hashmap_free_ Hashmap *all_services = NULL;
_cleanup_(lookup_paths_done) LookupPaths lp = {};
SysvStub *service;
int r;
@ -910,7 +911,7 @@ static int run(const char *dest, const char *dest_early, const char *dest_late)
if (r < 0)
return r;
all_services = hashmap_new(&string_hash_ops);
all_services = hashmap_new(&sysvstub_hash_ops);
if (!all_services)
return log_oom();

View File

@ -1104,7 +1104,7 @@ TEST(fdopen_independent) {
zero(buf);
assert_se(fread(buf, 1, sizeof(buf), f) == strlen(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));
f = safe_fclose(f);
@ -1112,7 +1112,7 @@ TEST(fdopen_independent) {
zero(buf);
assert_se(fread(buf, 1, sizeof(buf), f) == strlen(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));
f = safe_fclose(f);
@ -1120,7 +1120,7 @@ TEST(fdopen_independent) {
zero(buf);
assert_se(fread(buf, 1, sizeof(buf), f) == strlen(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));
f = safe_fclose(f);
}

View File

@ -75,7 +75,7 @@ static LinkConfig* link_config_free(LinkConfig *config) {
erase_and_free(config->wol_password);
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);
}

View File

@ -553,9 +553,6 @@ int manager_serialize_config(Manager *manager) {
if (r < 0)
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");
if (r < 0)
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);
if (n < 0)
return n;
return log_error_errno(n, "Failed to listen on fds: %m");
for (int i = 0; i < n; i++) {
int fd = SD_LISTEN_FDS_START + i;

View File

@ -60,7 +60,7 @@ sanitize_address_undefined = custom_target(
'fuzzers',
' '.join(fuzz_c_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('werror') ? '--werror' : '',
sanitize_auto_features