diff options
author | Thomas Haller <thaller@redhat.com> | 2022-08-11 10:15:02 +0200 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2022-08-11 21:51:58 +0200 |
commit | ad1bf3c5448e440f8f09be601fa37a69976dd79b (patch) | |
tree | 2f48ccdf9a0bc1314cd3e213e7877875093936c4 | |
parent | 082e6c96a1ea369b6666217663327c1d4fa481a4 (diff) | |
parent | 7c0de1517ce589e9fa2837eeb705b788d829d055 (diff) | |
download | NetworkManager-ad1bf3c5448e440f8f09be601fa37a69976dd79b.tar.gz |
systemd: merge branch systemd into main
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/1333
31 files changed, 282 insertions, 160 deletions
diff --git a/src/libnm-systemd-core/src/libsystemd-network/dhcp-identifier.c b/src/libnm-systemd-core/src/libsystemd-network/dhcp-identifier.c index 46410ca10f..2636d7967f 100644 --- a/src/libnm-systemd-core/src/libsystemd-network/dhcp-identifier.c +++ b/src/libnm-systemd-core/src/libsystemd-network/dhcp-identifier.c @@ -66,20 +66,26 @@ int dhcp_validate_duid_len(DUIDType duid_type, size_t duid_len, bool strict) { } #if 0 /* NM_IGNORED */ -static int dhcp_identifier_set_duid_llt(const uint8_t *addr, size_t addr_len, uint16_t arp_type, usec_t t, struct duid *ret_duid, size_t *ret_len) { +static int dhcp_identifier_set_duid_llt( + const struct hw_addr_data *hw_addr, + uint16_t arp_type, + usec_t t, + struct duid *ret_duid, + size_t *ret_len) { + uint16_t time_from_2000y; - assert(addr); + assert(hw_addr); assert(ret_duid); assert(ret_len); - if (addr_len == 0) + if (hw_addr->length == 0) return -EOPNOTSUPP; if (arp_type == ARPHRD_ETHER) - assert_return(addr_len == ETH_ALEN, -EINVAL); + assert_return(hw_addr->length == ETH_ALEN, -EINVAL); else if (arp_type == ARPHRD_INFINIBAND) - assert_return(addr_len == INFINIBAND_ALEN, -EINVAL); + assert_return(hw_addr->length == INFINIBAND_ALEN, -EINVAL); else return -EOPNOTSUPP; @@ -91,33 +97,38 @@ static int dhcp_identifier_set_duid_llt(const uint8_t *addr, size_t addr_len, ui unaligned_write_be16(&ret_duid->type, DUID_TYPE_LLT); unaligned_write_be16(&ret_duid->llt.htype, arp_type); unaligned_write_be32(&ret_duid->llt.time, time_from_2000y); - memcpy(ret_duid->llt.haddr, addr, addr_len); + memcpy(ret_duid->llt.haddr, hw_addr->bytes, hw_addr->length); - *ret_len = offsetof(struct duid, llt.haddr) + addr_len; + *ret_len = offsetof(struct duid, llt.haddr) + hw_addr->length; return 0; } -static int dhcp_identifier_set_duid_ll(const uint8_t *addr, size_t addr_len, uint16_t arp_type, struct duid *ret_duid, size_t *ret_len) { - assert(addr); +static int dhcp_identifier_set_duid_ll( + const struct hw_addr_data *hw_addr, + uint16_t arp_type, + struct duid *ret_duid, + size_t *ret_len) { + + assert(hw_addr); assert(ret_duid); assert(ret_len); - if (addr_len == 0) + if (hw_addr->length == 0) return -EOPNOTSUPP; if (arp_type == ARPHRD_ETHER) - assert_return(addr_len == ETH_ALEN, -EINVAL); + assert_return(hw_addr->length == ETH_ALEN, -EINVAL); else if (arp_type == ARPHRD_INFINIBAND) - assert_return(addr_len == INFINIBAND_ALEN, -EINVAL); + assert_return(hw_addr->length == INFINIBAND_ALEN, -EINVAL); else return -EOPNOTSUPP; unaligned_write_be16(&ret_duid->type, DUID_TYPE_LL); unaligned_write_be16(&ret_duid->ll.htype, arp_type); - memcpy(ret_duid->ll.haddr, addr, addr_len); + memcpy(ret_duid->ll.haddr, hw_addr->bytes, hw_addr->length); - *ret_len = offsetof(struct duid, ll.haddr) + addr_len; + *ret_len = offsetof(struct duid, ll.haddr) + hw_addr->length; return 0; } @@ -179,8 +190,7 @@ static int dhcp_identifier_set_duid_uuid(struct duid *ret_duid, size_t *ret_len) int dhcp_identifier_set_duid( DUIDType duid_type, - const uint8_t *addr, - size_t addr_len, + const struct hw_addr_data *hw_addr, uint16_t arp_type, usec_t llt_time, bool test_mode, @@ -189,11 +199,11 @@ int dhcp_identifier_set_duid( switch (duid_type) { case DUID_TYPE_LLT: - return dhcp_identifier_set_duid_llt(addr, addr_len, arp_type, llt_time, ret_duid, ret_len); + return dhcp_identifier_set_duid_llt(hw_addr, arp_type, llt_time, ret_duid, ret_len); case DUID_TYPE_EN: return dhcp_identifier_set_duid_en(test_mode, ret_duid, ret_len); case DUID_TYPE_LL: - return dhcp_identifier_set_duid_ll(addr, addr_len, arp_type, ret_duid, ret_len); + return dhcp_identifier_set_duid_ll(hw_addr, arp_type, ret_duid, ret_len); case DUID_TYPE_UUID: return dhcp_identifier_set_duid_uuid(ret_duid, ret_len); default: @@ -204,8 +214,7 @@ int dhcp_identifier_set_duid( int dhcp_identifier_set_iaid( int ifindex, - const uint8_t *mac, - size_t mac_len, + const struct hw_addr_data *hw_addr, bool legacy_unstable_byteorder, bool use_mac, void *ret) { @@ -219,6 +228,10 @@ int dhcp_identifier_set_iaid( uint64_t id; int r; + assert(ifindex > 0); + assert(hw_addr); + assert(ret); + if (udev_available() && !use_mac) { /* udev should be around */ @@ -247,7 +260,7 @@ int dhcp_identifier_set_iaid( id = siphash24(name, strlen(name), HASH_KEY.bytes); else /* fall back to MAC address if no predictable name available */ - id = siphash24(mac, mac_len, HASH_KEY.bytes); + id = siphash24(hw_addr->bytes, hw_addr->length, HASH_KEY.bytes); id32 = (id & 0xffffffff) ^ (id >> 32); diff --git a/src/libnm-systemd-core/src/libsystemd-network/dhcp-identifier.h b/src/libnm-systemd-core/src/libsystemd-network/dhcp-identifier.h index 697ba3bfbb..8acb8c3210 100644 --- a/src/libnm-systemd-core/src/libsystemd-network/dhcp-identifier.h +++ b/src/libnm-systemd-core/src/libsystemd-network/dhcp-identifier.h @@ -3,6 +3,7 @@ #include "sd-id128.h" +#include "ether-addr-util.h" #include "macro.h" #include "sparse-endian.h" #include "time-util.h" @@ -58,8 +59,7 @@ int dhcp_validate_duid_len(DUIDType duid_type, size_t duid_len, bool strict); int dhcp_identifier_set_duid_en(bool test_mode, struct duid *ret_duid, size_t *ret_len); int dhcp_identifier_set_duid( DUIDType duid_type, - const uint8_t *addr, - size_t addr_len, + const struct hw_addr_data *hw_addr, uint16_t arp_type, usec_t llt_time, bool test_mode, @@ -67,8 +67,7 @@ int dhcp_identifier_set_duid( size_t *ret_len); int dhcp_identifier_set_iaid( int ifindex, - const uint8_t *mac, - size_t mac_len, + const struct hw_addr_data *hw_addr, bool legacy_unstable_byteorder, bool use_mac, void *ret); diff --git a/src/libnm-systemd-core/src/libsystemd-network/dhcp6-internal.h b/src/libnm-systemd-core/src/libsystemd-network/dhcp6-internal.h index 176391ebec..65f6cb057f 100644 --- a/src/libnm-systemd-core/src/libsystemd-network/dhcp6-internal.h +++ b/src/libnm-systemd-core/src/libsystemd-network/dhcp6-internal.h @@ -71,6 +71,7 @@ struct sd_dhcp6_client { char **vendor_class; OrderedHashmap *extra_options; OrderedSet *vendor_options; + bool rapid_commit; struct sd_dhcp6_lease *lease; diff --git a/src/libnm-systemd-core/src/libsystemd-network/dhcp6-option.c b/src/libnm-systemd-core/src/libsystemd-network/dhcp6-option.c index e6b7f7d991..05f2a3838d 100644 --- a/src/libnm-systemd-core/src/libsystemd-network/dhcp6-option.c +++ b/src/libnm-systemd-core/src/libsystemd-network/dhcp6-option.c @@ -510,7 +510,7 @@ int dhcp6_option_parse( if (buflen < offsetof(DHCP6Option, data)) return -EBADMSG; - if (*offset >= buflen - offsetof(DHCP6Option, data)) + if (*offset > buflen - offsetof(DHCP6Option, data)) return -EBADMSG; len = unaligned_read_be16(buf + *offset + offsetof(DHCP6Option, len)); @@ -520,14 +520,14 @@ int dhcp6_option_parse( *ret_option_code = unaligned_read_be16(buf + *offset + offsetof(DHCP6Option, code)); *ret_option_data_len = len; - *ret_option_data = buf + *offset + offsetof(DHCP6Option, data); + *ret_option_data = len == 0 ? NULL : buf + *offset + offsetof(DHCP6Option, data); *offset += offsetof(DHCP6Option, data) + len; return 0; } int dhcp6_option_parse_status(const uint8_t *data, size_t data_len, char **ret_status_message) { - assert(data); + assert(data || data_len == 0); if (data_len < sizeof(uint16_t)) return -EBADMSG; @@ -805,7 +805,7 @@ int dhcp6_option_parse_addresses( struct in6_addr **addrs, size_t *count) { - assert(optval); + assert(optval || optlen == 0); assert(addrs); assert(count); @@ -828,8 +828,8 @@ static int parse_domain(const uint8_t **data, size_t *len, char **ret) { int r; assert(data); - assert(*data); assert(len); + assert(*data || *len == 0); assert(ret); optval = *data; @@ -893,7 +893,7 @@ int dhcp6_option_parse_domainname(const uint8_t *optval, size_t optlen, char **r _cleanup_free_ char *domain = NULL; int r; - assert(optval); + assert(optval || optlen == 0); assert(ret); r = parse_domain(&optval, &optlen, &domain); @@ -912,7 +912,7 @@ int dhcp6_option_parse_domainname_list(const uint8_t *optval, size_t optlen, cha _cleanup_strv_free_ char **names = NULL; int r; - assert(optval); + assert(optval || optlen == 0); assert(ret); if (optlen <= 1) diff --git a/src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-client.c b/src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-client.c index 27efabab4e..fbe15f003b 100644 --- a/src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-client.c +++ b/src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-client.c @@ -122,9 +122,8 @@ int sd_dhcp6_client_set_mac( return 0; } - memcpy(client->hw_addr.bytes, addr, addr_len); - client->hw_addr.length = addr_len; client->arp_type = arp_type; + hw_addr_set(&client->hw_addr, addr, addr_len); return 0; } @@ -223,8 +222,8 @@ static int dhcp6_client_set_duid_internal( } else { #if 0 /* NM_IGNORED */ - r = dhcp_identifier_set_duid(duid_type, client->hw_addr.bytes, client->hw_addr.length, - client->arp_type, llt_time, client->test_mode, &client->duid, &client->duid_len); + r = dhcp_identifier_set_duid(duid_type, &client->hw_addr, client->arp_type, llt_time, + client->test_mode, &client->duid, &client->duid_len); if (r == -EOPNOTSUPP) return log_dhcp6_client_errno(client, r, "Failed to set %s. MAC address is not set or " @@ -310,7 +309,7 @@ static int client_ensure_iaid(sd_dhcp6_client *client) { if (client->iaid_set) return 0; - r = dhcp_identifier_set_iaid(client->ifindex, client->hw_addr.bytes, client->hw_addr.length, + r = dhcp_identifier_set_iaid(client->ifindex, &client->hw_addr, /* legacy_unstable_byteorder = */ true, /* use_mac = */ client->test_mode, &iaid); @@ -501,6 +500,14 @@ int dhcp6_client_set_transaction_id(sd_dhcp6_client *client, uint32_t transactio return 0; } +int sd_dhcp6_client_set_rapid_commit(sd_dhcp6_client *client, int enable) { + assert_return(client, -EINVAL); + assert_return(!sd_dhcp6_client_is_running(client), -EBUSY); + + client->rapid_commit = enable; + return 0; +} + int sd_dhcp6_client_get_lease(sd_dhcp6_client *client, sd_dhcp6_lease **ret) { assert_return(client, -EINVAL); @@ -724,9 +731,11 @@ int dhcp6_client_send_message(sd_dhcp6_client *client) { break; case DHCP6_STATE_SOLICITATION: - r = dhcp6_option_append(&opt, &optlen, SD_DHCP6_OPTION_RAPID_COMMIT, 0, NULL); - if (r < 0) - return r; + if (client->rapid_commit) { + r = dhcp6_option_append(&opt, &optlen, SD_DHCP6_OPTION_RAPID_COMMIT, 0, NULL); + if (r < 0) + return r; + } r = client_append_common_options_in_managed_mode(client, &opt, &optlen, &client->ia_na, &client->ia_pd); @@ -1170,6 +1179,10 @@ static int client_process_advertise_or_rapid_commit_reply( if (message->type == DHCP6_MESSAGE_REPLY) { bool rapid_commit; + if (!client->rapid_commit) + return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL), + "Received unexpected reply message, even we sent a solicit message without the rapid commit option, ignoring."); + r = dhcp6_lease_get_rapid_commit(lease, &rapid_commit); if (r < 0) return r; @@ -1477,6 +1490,7 @@ int sd_dhcp6_client_new(sd_dhcp6_client **ret) { .ifindex = -1, .request_ia = DHCP6_REQUEST_IA_NA | DHCP6_REQUEST_IA_PD, .fd = -1, + .rapid_commit = true, }; *ret = TAKE_PTR(client); diff --git a/src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-lease.c b/src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-lease.c index 00927d72e2..55c7d627e4 100644 --- a/src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-lease.c +++ b/src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-lease.c @@ -469,7 +469,9 @@ static int dhcp6_lease_parse_message( r = dhcp6_option_parse(message->options, len, &offset, &optcode, &optlen, &optval); if (r < 0) - return r; + return log_dhcp6_client_errno(client, r, + "Failed to parse option header at offset %zu of total length %zu: %m", + offset, len); switch (optcode) { case SD_DHCP6_OPTION_CLIENTID: @@ -479,7 +481,7 @@ static int dhcp6_lease_parse_message( r = dhcp6_lease_set_clientid(lease, optval, optlen); if (r < 0) - return r; + return log_dhcp6_client_errno(client, r, "Failed to set client ID: %m"); break; @@ -490,17 +492,17 @@ static int dhcp6_lease_parse_message( r = dhcp6_lease_set_serverid(lease, optval, optlen); if (r < 0) - return r; + return log_dhcp6_client_errno(client, r, "Failed to set server ID: %m"); break; case SD_DHCP6_OPTION_PREFERENCE: if (optlen != 1) - return -EINVAL; + return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL), "Received invalid length for preference."); r = dhcp6_lease_set_preference(lease, optval[0]); if (r < 0) - return r; + return log_dhcp6_client_errno(client, r, "Failed to set preference: %m"); break; @@ -509,7 +511,7 @@ static int dhcp6_lease_parse_message( r = dhcp6_option_parse_status(optval, optlen, &msg); if (r < 0) - return r; + return log_dhcp6_client_errno(client, r, "Failed to parse status code: %m"); if (r > 0) return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL), @@ -529,9 +531,11 @@ static int dhcp6_lease_parse_message( r = dhcp6_option_parse_ia(client, client->ia_na.header.id, optcode, optlen, optval, &ia); if (r == -ENOMEM) - return r; - if (r < 0) + return log_oom_debug(); + if (r < 0) { + log_dhcp6_client_errno(client, r, "Failed to parse IA_NA option, ignoring: %m"); continue; + } if (lease->ia_na) { log_dhcp6_client(client, "Received duplicate matching IA_NA option, ignoring."); @@ -552,9 +556,11 @@ static int dhcp6_lease_parse_message( r = dhcp6_option_parse_ia(client, client->ia_pd.header.id, optcode, optlen, optval, &ia); if (r == -ENOMEM) - return r; - if (r < 0) + return log_oom_debug(); + if (r < 0) { + log_dhcp6_client_errno(client, r, "Failed to parse IA_PD option, ignoring: %m"); continue; + } if (lease->ia_pd) { log_dhcp6_client(client, "Received duplicate matching IA_PD option, ignoring."); @@ -566,9 +572,12 @@ static int dhcp6_lease_parse_message( break; } case SD_DHCP6_OPTION_RAPID_COMMIT: + if (optlen != 0) + log_dhcp6_client(client, "Received rapid commit option with an invalid length (%zu), ignoring.", optlen); + r = dhcp6_lease_set_rapid_commit(lease); if (r < 0) - return r; + return log_dhcp6_client_errno(client, r, "Failed to set rapid commit flag: %m"); break; @@ -609,7 +618,8 @@ static int dhcp6_lease_parse_message( case SD_DHCP6_OPTION_INFORMATION_REFRESH_TIME: if (optlen != 4) - return -EINVAL; + return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL), + "Received information refresh time option with an invalid length (%zu).", optlen); irt = unaligned_read_be32((be32_t *) optval) * USEC_PER_SEC; break; diff --git a/src/libnm-systemd-core/src/libsystemd/sd-event/sd-event.c b/src/libnm-systemd-core/src/libsystemd/sd-event/sd-event.c index 54081d1897..8b2c554cfa 100644 --- a/src/libnm-systemd-core/src/libsystemd/sd-event/sd-event.c +++ b/src/libnm-systemd-core/src/libsystemd/sd-event/sd-event.c @@ -51,19 +51,19 @@ static bool event_source_is_offline(sd_event_source *s) { } static const char* const event_source_type_table[_SOURCE_EVENT_SOURCE_TYPE_MAX] = { - [SOURCE_IO] = "io", - [SOURCE_TIME_REALTIME] = "realtime", - [SOURCE_TIME_BOOTTIME] = "bootime", - [SOURCE_TIME_MONOTONIC] = "monotonic", + [SOURCE_IO] = "io", + [SOURCE_TIME_REALTIME] = "realtime", + [SOURCE_TIME_BOOTTIME] = "bootime", + [SOURCE_TIME_MONOTONIC] = "monotonic", [SOURCE_TIME_REALTIME_ALARM] = "realtime-alarm", [SOURCE_TIME_BOOTTIME_ALARM] = "boottime-alarm", - [SOURCE_SIGNAL] = "signal", - [SOURCE_CHILD] = "child", - [SOURCE_DEFER] = "defer", - [SOURCE_POST] = "post", - [SOURCE_EXIT] = "exit", - [SOURCE_WATCHDOG] = "watchdog", - [SOURCE_INOTIFY] = "inotify", + [SOURCE_SIGNAL] = "signal", + [SOURCE_CHILD] = "child", + [SOURCE_DEFER] = "defer", + [SOURCE_POST] = "post", + [SOURCE_EXIT] = "exit", + [SOURCE_WATCHDOG] = "watchdog", + [SOURCE_INOTIFY] = "inotify", }; DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(event_source_type, int); @@ -126,10 +126,10 @@ struct sd_event { Hashmap *inotify_data; /* indexed by priority */ /* A list of inode structures that still have an fd open, that we need to close before the next loop iteration */ - LIST_HEAD(struct inode_data, inode_data_to_close); + LIST_HEAD(struct inode_data, inode_data_to_close_list); /* A list of inotify objects that already have events buffered which aren't processed yet */ - LIST_HEAD(struct inotify_data, inotify_data_buffered); + LIST_HEAD(struct inotify_data, buffered_inotify_data_list); pid_t original_pid; @@ -422,6 +422,8 @@ fail: } DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_event, sd_event, event_free); +#define PROTECT_EVENT(e) \ + _unused_ _cleanup_(sd_event_unrefp) sd_event *_ref = sd_event_ref(e); _public_ sd_event_source* sd_event_source_disable_unref(sd_event_source *s) { if (s) @@ -1696,7 +1698,7 @@ static void event_free_inotify_data(sd_event *e, struct inotify_data *d) { assert(hashmap_isempty(d->wd)); if (d->buffer_filled > 0) - LIST_REMOVE(buffered, e->inotify_data_buffered, d); + LIST_REMOVE(buffered, e->buffered_inotify_data_list, d); hashmap_free(d->inodes); hashmap_free(d->wd); @@ -1805,10 +1807,10 @@ static void event_free_inode_data( if (!d) return; - assert(LIST_IS_EMPTY(d->event_sources)); + assert(!d->event_sources); if (d->fd >= 0) { - LIST_REMOVE(to_close, e->inode_data_to_close, d); + LIST_REMOVE(to_close, e->inode_data_to_close_list, d); safe_close(d->fd); } @@ -1868,7 +1870,7 @@ static void event_gc_inode_data( if (!d) return; - if (!LIST_IS_EMPTY(d->event_sources)) + if (d->event_sources) return; inotify_data = d->inotify_data; @@ -2070,7 +2072,7 @@ static int event_add_inotify_fd_internal( } } - LIST_PREPEND(to_close, e->inode_data_to_close, inode_data); + LIST_PREPEND(to_close, e->inode_data_to_close_list, inode_data); } /* Link our event source to the inode data object */ @@ -2143,12 +2145,9 @@ static sd_event_source* event_source_free(sd_event_source *s) { * we still retain a valid event source object after * the callback. */ - if (s->dispatching) { - if (s->type == SOURCE_IO) - source_io_unregister(s); - + if (s->dispatching) source_disconnect(s); - } else + else source_free(s); return NULL; @@ -2357,7 +2356,7 @@ _public_ int sd_event_source_set_priority(sd_event_source *s, int64_t priority) goto fail; } - LIST_PREPEND(to_close, s->event->inode_data_to_close, new_inode_data); + LIST_PREPEND(to_close, s->event->inode_data_to_close_list, new_inode_data); } /* Move the event source to the new inode data structure */ @@ -3423,7 +3422,7 @@ static int event_inotify_data_read(sd_event *e, struct inotify_data *d, uint32_t assert(n > 0); d->buffer_filled = (size_t) n; - LIST_PREPEND(buffered, e->inotify_data_buffered, d); + LIST_PREPEND(buffered, e->buffered_inotify_data_list, d); return 1; } @@ -3441,7 +3440,7 @@ static void event_inotify_data_drop(sd_event *e, struct inotify_data *d, size_t d->buffer_filled -= sz; if (d->buffer_filled == 0) - LIST_REMOVE(buffered, e->inotify_data_buffered, d); + LIST_REMOVE(buffered, e->buffered_inotify_data_list, d); } static int event_inotify_data_process(sd_event *e, struct inotify_data *d) { @@ -3534,7 +3533,7 @@ static int process_inotify(sd_event *e) { assert(e); - LIST_FOREACH(buffered, d, e->inotify_data_buffered) { + LIST_FOREACH(buffered, d, e->buffered_inotify_data_list) { r = event_inotify_data_process(e, d); if (r < 0) return r; @@ -3546,8 +3545,8 @@ static int process_inotify(sd_event *e) { } static int source_dispatch(sd_event_source *s) { - _cleanup_(sd_event_unrefp) sd_event *saved_event = NULL; EventSourceType saved_type; + sd_event *saved_event; int r = 0; assert(s); @@ -3559,7 +3558,8 @@ static int source_dispatch(sd_event_source *s) { /* Similarly, store a reference to the event loop object, so that we can still access it after the * callback might have invalidated/disconnected the event source. */ - saved_event = sd_event_ref(s->event); + saved_event = s->event; + PROTECT_EVENT(saved_event); /* Check if we hit the ratelimit for this event source, and if so, let's disable it. */ assert(!s->ratelimited); @@ -3760,7 +3760,7 @@ static int dispatch_exit(sd_event *e) { return 0; } - _unused_ _cleanup_(sd_event_unrefp) sd_event *ref = sd_event_ref(e); + PROTECT_EVENT(e); e->iteration++; e->state = SD_EVENT_EXITING; r = source_dispatch(p); @@ -3831,11 +3831,11 @@ static void event_close_inode_data_fds(sd_event *e) { * for the inode). Hence, let's close them when entering the first iteration after they were added, as a * compromise. */ - while ((d = e->inode_data_to_close)) { + while ((d = e->inode_data_to_close_list)) { assert(d->fd >= 0); d->fd = safe_close(d->fd); - LIST_REMOVE(to_close, e->inode_data_to_close, d); + LIST_REMOVE(to_close, e->inode_data_to_close_list, d); } } @@ -3854,7 +3854,7 @@ _public_ int sd_event_prepare(sd_event *e) { assert_return(!e->default_event_ptr || e->tid == gettid(), -EREMOTEIO); /* Make sure that none of the preparation callbacks ends up freeing the event source under our feet */ - _unused_ _cleanup_(sd_event_unrefp) sd_event *ref = sd_event_ref(e); + PROTECT_EVENT(e); if (e->exit_requested) goto pending; @@ -3889,7 +3889,7 @@ _public_ int sd_event_prepare(sd_event *e) { event_close_inode_data_fds(e); - if (event_next_pending(e) || e->need_process_child || !LIST_IS_EMPTY(e->inotify_data_buffered)) + if (event_next_pending(e) || e->need_process_child || e->buffered_inotify_data_list) goto pending; e->state = SD_EVENT_ARMED; @@ -3969,7 +3969,7 @@ static int process_epoll(sd_event *e, usec_t timeout, int64_t threshold, int64_t n_event_max = MALLOC_ELEMENTSOF(e->event_queue); /* If we still have inotify data buffered, then query the other fds, but don't wait on it */ - if (!LIST_IS_EMPTY(e->inotify_data_buffered)) + if (e->buffered_inotify_data_list) timeout = 0; for (;;) { @@ -4184,7 +4184,7 @@ _public_ int sd_event_dispatch(sd_event *e) { p = event_next_pending(e); if (p) { - _unused_ _cleanup_(sd_event_unrefp) sd_event *ref = sd_event_ref(e); + PROTECT_EVENT(e); e->state = SD_EVENT_RUNNING; r = source_dispatch(p); @@ -4236,7 +4236,7 @@ _public_ int sd_event_run(sd_event *e, uint64_t timeout) { } /* Make sure that none of the preparation callbacks ends up freeing the event source under our feet */ - _unused_ _cleanup_(sd_event_unrefp) sd_event *ref = sd_event_ref(e); + PROTECT_EVENT(e); r = sd_event_prepare(e); if (r == 0) @@ -4266,7 +4266,7 @@ _public_ int sd_event_loop(sd_event *e) { assert_return(!event_pid_changed(e), -ECHILD); assert_return(e->state == SD_EVENT_INITIAL, -EBUSY); - _unused_ _cleanup_(sd_event_unrefp) sd_event *ref = sd_event_ref(e); + PROTECT_EVENT(e); while (e->state != SD_EVENT_FINISHED) { r = sd_event_run(e, UINT64_MAX); diff --git a/src/libnm-systemd-core/src/systemd/_sd-common.h b/src/libnm-systemd-core/src/systemd/_sd-common.h index 38449463e2..6f657c2254 100644 --- a/src/libnm-systemd-core/src/systemd/_sd-common.h +++ b/src/libnm-systemd-core/src/systemd/_sd-common.h @@ -85,7 +85,7 @@ typedef void (*_sd_destroy_t)(void *userdata); #endif #ifndef _SD_ARRAY_STATIC -# if __STDC_VERSION__ >= 199901L +# if __STDC_VERSION__ >= 199901L && !defined(__cplusplus) # define _SD_ARRAY_STATIC static # else # define _SD_ARRAY_STATIC diff --git a/src/libnm-systemd-core/src/systemd/sd-dhcp6-client.h b/src/libnm-systemd-core/src/systemd/sd-dhcp6-client.h index 7fe60c356c..2c66c51b78 100644 --- a/src/libnm-systemd-core/src/systemd/sd-dhcp6-client.h +++ b/src/libnm-systemd-core/src/systemd/sd-dhcp6-client.h @@ -262,6 +262,7 @@ int sd_dhcp6_client_set_address_request(sd_dhcp6_client *client, int request); int sd_dhcp6_client_add_vendor_option(sd_dhcp6_client *client, sd_dhcp6_option *v); +int sd_dhcp6_client_set_rapid_commit(sd_dhcp6_client *client, int enable); int sd_dhcp6_client_get_lease( sd_dhcp6_client *client, diff --git a/src/libnm-systemd-shared/sd-adapt-shared/nm-sd-adapt-shared.h b/src/libnm-systemd-shared/sd-adapt-shared/nm-sd-adapt-shared.h index a3e490f569..ee5a0a240d 100644 --- a/src/libnm-systemd-shared/sd-adapt-shared/nm-sd-adapt-shared.h +++ b/src/libnm-systemd-shared/sd-adapt-shared/nm-sd-adapt-shared.h @@ -51,6 +51,8 @@ #define LOG_TRACE 0 +#define WANT_LINUX_FS_H 0 + #define BUILD_MODE_DEVELOPER (NM_MORE_ASSERTS > 0) #define LOG_MESSAGE_VERIFICATION (NM_MORE_ASSERTS > 0) diff --git a/src/libnm-systemd-shared/src/basic/alloc-util.h b/src/libnm-systemd-shared/src/basic/alloc-util.h index 13dab0304f..b38db7d473 100644 --- a/src/libnm-systemd-shared/src/basic/alloc-util.h +++ b/src/libnm-systemd-shared/src/basic/alloc-util.h @@ -50,16 +50,30 @@ typedef void* (*mfree_func_t)(void *p); #define malloc0(n) (calloc(1, (n) ?: 1)) -#define free_and_replace(a, b) \ +#define free_and_replace_full(a, b, free_func) \ ({ \ typeof(a)* _a = &(a); \ typeof(b)* _b = &(b); \ - free(*_a); \ + free_func(*_a); \ *_a = *_b; \ *_b = NULL; \ 0; \ }) +#define free_and_replace(a, b) \ + free_and_replace_full(a, b, free) + +/* This is similar to free_and_replace_full(), but NULL is not assigned to 'b', and its reference counter is + * increased. */ +#define unref_and_replace_full(a, b, ref_func, unref_func) \ + ({ \ + typeof(a)* _a = &(a); \ + typeof(b) _b = ref_func(b); \ + unref_func(*_a); \ + *_a = _b; \ + 0; \ + }) + void* memdup(const void *p, size_t l) _alloc_(2); void* memdup_suffix0(const void *p, size_t l); /* We can't use _alloc_() here, since we return a buffer one byte larger than the specified size */ diff --git a/src/libnm-systemd-shared/src/basic/ether-addr-util.c b/src/libnm-systemd-shared/src/basic/ether-addr-util.c index 4504b6be1f..7984ddf4ad 100644 --- a/src/libnm-systemd-shared/src/basic/ether-addr-util.c +++ b/src/libnm-systemd-shared/src/basic/ether-addr-util.c @@ -35,6 +35,15 @@ char *hw_addr_to_string_full( return buffer; } +struct hw_addr_data *hw_addr_set(struct hw_addr_data *addr, const uint8_t *bytes, size_t length) { + assert(addr); + assert(length <= HW_ADDR_MAX_SIZE); + + addr->length = length; + memcpy_safe(addr->bytes, bytes, length); + return addr; +} + int hw_addr_compare(const struct hw_addr_data *a, const struct hw_addr_data *b) { int r; diff --git a/src/libnm-systemd-shared/src/basic/ether-addr-util.h b/src/libnm-systemd-shared/src/basic/ether-addr-util.h index 32f45fe813..83ed77d634 100644 --- a/src/libnm-systemd-shared/src/basic/ether-addr-util.h +++ b/src/libnm-systemd-shared/src/basic/ether-addr-util.h @@ -52,6 +52,8 @@ static inline char *hw_addr_to_string(const struct hw_addr_data *addr, char buff #define HW_ADDR_NULL ((const struct hw_addr_data){}) +struct hw_addr_data *hw_addr_set(struct hw_addr_data *addr, const uint8_t *bytes, size_t length); + void hw_addr_hash_func(const struct hw_addr_data *p, struct siphash *state); int hw_addr_compare(const struct hw_addr_data *a, const struct hw_addr_data *b); static inline bool hw_addr_equal(const struct hw_addr_data *a, const struct hw_addr_data *b) { diff --git a/src/libnm-systemd-shared/src/basic/fd-util.c b/src/libnm-systemd-shared/src/basic/fd-util.c index 53efeb401f..8029544570 100644 --- a/src/libnm-systemd-shared/src/basic/fd-util.c +++ b/src/libnm-systemd-shared/src/basic/fd-util.c @@ -5,7 +5,9 @@ #include <errno.h> #include <fcntl.h> #include <linux/btrfs.h> +#if WANT_LINUX_FS_H #include <linux/fs.h> +#endif #include <linux/magic.h> #include <sys/ioctl.h> #include <sys/resource.h> diff --git a/src/libnm-systemd-shared/src/basic/hash-funcs.c b/src/libnm-systemd-shared/src/basic/hash-funcs.c index 3a02699ad9..eed30f0944 100644 --- a/src/libnm-systemd-shared/src/basic/hash-funcs.c +++ b/src/libnm-systemd-shared/src/basic/hash-funcs.c @@ -6,6 +6,7 @@ #include "hash-funcs.h" #include "path-util.h" +#include "strv.h" void string_hash_func(const char *p, struct siphash *state) { siphash24_compress(p, strlen(p) + 1, state); @@ -17,6 +18,9 @@ DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(string_hash_ops_free, DEFINE_HASH_OPS_FULL(string_hash_ops_free_free, char, string_hash_func, string_compare_func, free, void, free); +DEFINE_HASH_OPS_FULL(string_hash_ops_free_strv_free, + char, string_hash_func, string_compare_func, free, + char*, strv_free); #if 0 /* NM_IGNORED */ void path_hash_func(const char *q, struct siphash *state) { diff --git a/src/libnm-systemd-shared/src/basic/hash-funcs.h b/src/libnm-systemd-shared/src/basic/hash-funcs.h index c537c6af7e..c14302ec72 100644 --- a/src/libnm-systemd-shared/src/basic/hash-funcs.h +++ b/src/libnm-systemd-shared/src/basic/hash-funcs.h @@ -78,6 +78,7 @@ void string_hash_func(const char *p, struct siphash *state); extern const struct hash_ops string_hash_ops; extern const struct hash_ops string_hash_ops_free; extern const struct hash_ops string_hash_ops_free_free; +extern const struct hash_ops string_hash_ops_free_strv_free; void path_hash_func(const char *p, struct siphash *state); extern const struct hash_ops path_hash_ops; diff --git a/src/libnm-systemd-shared/src/basic/hashmap.h b/src/libnm-systemd-shared/src/basic/hashmap.h index eafc08f658..91b3fe862b 100644 --- a/src/libnm-systemd-shared/src/basic/hashmap.h +++ b/src/libnm-systemd-shared/src/basic/hashmap.h @@ -90,12 +90,7 @@ OrderedHashmap* _ordered_hashmap_new(const struct hash_ops *hash_ops HASHMAP_DE #define ordered_hashmap_new(ops) _ordered_hashmap_new(ops HASHMAP_DEBUG_SRC_ARGS) #define hashmap_free_and_replace(a, b) \ - ({ \ - hashmap_free(a); \ - (a) = (b); \ - (b) = NULL; \ - 0; \ - }) + free_and_replace_full(a, b, 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) { diff --git a/src/libnm-systemd-shared/src/basic/in-addr-util.c b/src/libnm-systemd-shared/src/basic/in-addr-util.c index 74322f9a44..dc4446aeda 100644 --- a/src/libnm-systemd-shared/src/basic/in-addr-util.c +++ b/src/libnm-systemd-shared/src/basic/in-addr-util.c @@ -51,6 +51,20 @@ bool in4_addr_is_link_local(const struct in_addr *a) { return (be32toh(a->s_addr) & UINT32_C(0xFFFF0000)) == (UINT32_C(169) << 24 | UINT32_C(254) << 16); } +bool in4_addr_is_link_local_dynamic(const struct in_addr *a) { + assert(a); + + if (!in4_addr_is_link_local(a)) + return false; + + /* 169.254.0.0/24 and 169.254.255.0/24 must not be used for the dynamic IPv4LL assignment. + * See RFC 3927 Section 2.1: + * The IPv4 prefix 169.254/16 is registered with the IANA for this purpose. The first 256 and last + * 256 addresses in the 169.254/16 prefix are reserved for future use and MUST NOT be selected by a + * host using this dynamic configuration mechanism. */ + return !IN_SET(be32toh(a->s_addr) & 0x0000FF00U, 0x0000U, 0xFF00U); +} + bool in6_addr_is_link_local(const struct in6_addr *a) { assert(a); diff --git a/src/libnm-systemd-shared/src/basic/in-addr-util.h b/src/libnm-systemd-shared/src/basic/in-addr-util.h index c1e7ef965d..fbc60436c7 100644 --- a/src/libnm-systemd-shared/src/basic/in-addr-util.h +++ b/src/libnm-systemd-shared/src/basic/in-addr-util.h @@ -44,6 +44,7 @@ static inline bool in_addr_data_is_set(const struct in_addr_data *a) { int in_addr_is_multicast(int family, const union in_addr_union *u); bool in4_addr_is_link_local(const struct in_addr *a); +bool in4_addr_is_link_local_dynamic(const struct in_addr *a); bool in6_addr_is_link_local(const struct in6_addr *a); int in_addr_is_link_local(int family, const union in_addr_union *u); bool in6_addr_is_link_local_all_nodes(const struct in6_addr *a); diff --git a/src/libnm-systemd-shared/src/basic/list.h b/src/libnm-systemd-shared/src/basic/list.h index 58e83a6cb2..ca30039690 100644 --- a/src/libnm-systemd-shared/src/basic/list.h +++ b/src/libnm-systemd-shared/src/basic/list.h @@ -170,9 +170,6 @@ i != (p); \ i = i->name##_next ? i->name##_next : (head)) -#define LIST_IS_EMPTY(head) \ - (!(head)) - /* Join two lists tail to head: a->b, c->d to a->b->c->d and de-initialise second list */ #define LIST_JOIN(name,a,b) \ do { \ diff --git a/src/libnm-systemd-shared/src/basic/macro.h b/src/libnm-systemd-shared/src/basic/macro.h index 630aad6464..7380da1093 100644 --- a/src/libnm-systemd-shared/src/basic/macro.h +++ b/src/libnm-systemd-shared/src/basic/macro.h @@ -88,10 +88,6 @@ _Pragma("GCC diagnostic push") #endif -#define DISABLE_WARNING_FLOAT_EQUAL \ - _Pragma("GCC diagnostic push"); \ - _Pragma("GCC diagnostic ignored \"-Wfloat-equal\"") - #define DISABLE_WARNING_TYPE_LIMITS \ _Pragma("GCC diagnostic push"); \ _Pragma("GCC diagnostic ignored \"-Wtype-limits\"") diff --git a/src/libnm-systemd-shared/src/basic/path-util.c b/src/libnm-systemd-shared/src/basic/path-util.c index 244336c1af..3ba3510fce 100644 --- a/src/libnm-systemd-shared/src/basic/path-util.c +++ b/src/libnm-systemd-shared/src/basic/path-util.c @@ -1061,7 +1061,7 @@ int path_extract_filename(const char *path, char **ret) { return -ENOMEM; *ret = TAKE_PTR(a); - return strlen(c) > (size_t)r ? O_DIRECTORY : 0; + return strlen(c) > (size_t) r ? O_DIRECTORY : 0; } int path_extract_directory(const char *path, char **ret) { @@ -1115,7 +1115,7 @@ bool filename_is_valid(const char *p) { if (isempty(p)) return false; - if (dot_or_dot_dot(p)) + if (dot_or_dot_dot(p)) /* Yes, in this context we consider "." and ".." invalid */ return false; e = strchrnul(p, '/'); diff --git a/src/libnm-systemd-shared/src/basic/path-util.h b/src/libnm-systemd-shared/src/basic/path-util.h index 6f8bf116ff..c97c4540d3 100644 --- a/src/libnm-systemd-shared/src/basic/path-util.h +++ b/src/libnm-systemd-shared/src/basic/path-util.h @@ -45,12 +45,16 @@ #endif static inline bool is_path(const char *p) { - assert(p); + if (!p) /* A NULL pointer is definitely not a path */ + return false; + return strchr(p, '/'); } static inline bool path_is_absolute(const char *p) { - assert(p); + if (!p) /* A NULL pointer is definitely not an absolute path */ + return false; + return p[0] == '/'; } @@ -159,10 +163,10 @@ int path_extract_directory(const char *path, char **ret); bool filename_is_valid(const char *p) _pure_; bool path_is_valid_full(const char *p, bool accept_dot_dot) _pure_; static inline bool path_is_valid(const char *p) { - return path_is_valid_full(p, true); + return path_is_valid_full(p, /* accept_dot_dot= */ true); } static inline bool path_is_safe(const char *p) { - return path_is_valid_full(p, false); + return path_is_valid_full(p, /* accept_dot_dot= */ false); } bool path_is_normalized(const char *p) _pure_; diff --git a/src/libnm-systemd-shared/src/basic/process-util.c b/src/libnm-systemd-shared/src/basic/process-util.c index bb3afe0b4e..1c23a2f8f6 100644 --- a/src/libnm-systemd-shared/src/basic/process-util.c +++ b/src/libnm-systemd-shared/src/basic/process-util.c @@ -1156,7 +1156,7 @@ void reset_cached_pid(void) { pid_t getpid_cached(void) { static bool installed = false; - pid_t current_value; + pid_t current_value = CACHED_PID_UNSET; /* getpid_cached() is much like getpid(), but caches the value in local memory, to avoid having to invoke a * system call each time. This restores glibc behaviour from before 2.24, when getpid() was unconditionally @@ -1167,7 +1167,13 @@ pid_t getpid_cached(void) { * https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=c579f48edba88380635ab98cb612030e3ed8691e */ - current_value = __sync_val_compare_and_swap(&cached_pid, CACHED_PID_UNSET, CACHED_PID_BUSY); + __atomic_compare_exchange_n( + &cached_pid, + ¤t_value, + CACHED_PID_BUSY, + false, + __ATOMIC_SEQ_CST, + __ATOMIC_SEQ_CST); switch (current_value) { @@ -1589,6 +1595,30 @@ bool invoked_as(char *argv[], const char *token) { return strstr(last_path_component(argv[0]), token); } +bool invoked_by_systemd(void) { + int r; + + /* If the process is directly executed by PID1 (e.g. ExecStart= or generator), systemd-importd, + * or systemd-homed, then $SYSTEMD_EXEC_PID= is set, and read the command line. */ + const char *e = getenv("SYSTEMD_EXEC_PID"); + if (!e) + return false; + + if (streq(e, "*")) + /* For testing. */ + return true; + + pid_t p; + r = parse_pid(e, &p); + if (r < 0) { + /* We know that systemd sets the variable correctly. Something else must have set it. */ + log_debug_errno(r, "Failed to parse \"SYSTEMD_EXEC_PID=%s\", ignoring: %m", e); + return false; + } + + return getpid_cached() == p; +} + _noreturn_ void freeze(void) { log_close(); diff --git a/src/libnm-systemd-shared/src/basic/process-util.h b/src/libnm-systemd-shared/src/basic/process-util.h index c488c6a833..962f12d11c 100644 --- a/src/libnm-systemd-shared/src/basic/process-util.h +++ b/src/libnm-systemd-shared/src/basic/process-util.h @@ -192,6 +192,8 @@ int setpriority_closest(int priority); bool invoked_as(char *argv[], const char *token); +bool invoked_by_systemd(void); + _noreturn_ void freeze(void); bool argv_looks_like_help(int argc, char **argv); diff --git a/src/libnm-systemd-shared/src/basic/set.h b/src/libnm-systemd-shared/src/basic/set.h index 52cf63e2dd..618e729744 100644 --- a/src/libnm-systemd-shared/src/basic/set.h +++ b/src/libnm-systemd-shared/src/basic/set.h @@ -6,12 +6,7 @@ #include "macro.h" #define set_free_and_replace(a, b) \ - ({ \ - set_free(a); \ - (a) = (b); \ - (b) = NULL; \ - 0; \ - }) + free_and_replace_full(a, b, set_free) Set* _set_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS); #define set_new(ops) _set_new(ops HASHMAP_DEBUG_SRC_ARGS) diff --git a/src/libnm-systemd-shared/src/basic/stat-util.c b/src/libnm-systemd-shared/src/basic/stat-util.c index f2041535f4..8c5858ffed 100644 --- a/src/libnm-systemd-shared/src/basic/stat-util.c +++ b/src/libnm-systemd-shared/src/basic/stat-util.c @@ -39,16 +39,17 @@ int is_symlink(const char *path) { } #endif /* NM_IGNORED */ -int is_dir(const char* path, bool follow) { +int is_dir_full(int atfd, const char* path, bool follow) { struct stat st; int r; - assert(path); + assert(atfd >= 0 || atfd == AT_FDCWD); + assert(atfd >= 0 || path); - if (follow) - r = stat(path, &st); + if (path) + r = fstatat(atfd, path, &st, follow ? 0 : AT_SYMLINK_NOFOLLOW); else - r = lstat(path, &st); + r = fstat(atfd, &st); if (r < 0) return -errno; @@ -56,15 +57,6 @@ int is_dir(const char* path, bool follow) { } #if 0 /* NM_IGNORED */ -int is_dir_fd(int fd) { - struct stat st; - - if (fstat(fd, &st) < 0) - return -errno; - - return !!S_ISDIR(st.st_mode); -} - int is_device_node(const char *path) { struct stat info; diff --git a/src/libnm-systemd-shared/src/basic/stat-util.h b/src/libnm-systemd-shared/src/basic/stat-util.h index 7f0b3dc0af..56f15534aa 100644 --- a/src/libnm-systemd-shared/src/basic/stat-util.h +++ b/src/libnm-systemd-shared/src/basic/stat-util.h @@ -13,8 +13,13 @@ #include "missing_stat.h" int is_symlink(const char *path); -int is_dir(const char *path, bool follow); -int is_dir_fd(int fd); +int is_dir_full(int atfd, const char *fname, bool follow); +static inline int is_dir(const char *path, bool follow) { + return is_dir_full(AT_FDCWD, path, follow); +} +static inline int is_dir_fd(int fd) { + return is_dir_full(fd, NULL, false); +} int is_device_node(const char *path); int dir_is_empty_at(int dir_fd, const char *path, bool ignore_hidden_or_backup); diff --git a/src/libnm-systemd-shared/src/basic/strv.h b/src/libnm-systemd-shared/src/basic/strv.h index 072739df35..87ec6337bd 100644 --- a/src/libnm-systemd-shared/src/basic/strv.h +++ b/src/libnm-systemd-shared/src/basic/strv.h @@ -258,14 +258,7 @@ int strv_extend_n(char ***l, const char *value, size_t n); int fputstrv(FILE *f, char * const *l, const char *separator, bool *space); #define strv_free_and_replace(a, b) \ - ({ \ - char ***_a = &(a); \ - char ***_b = &(b); \ - strv_free(*_a); \ - (*_a) = (*_b); \ - (*_b) = NULL; \ - 0; \ - }) + free_and_replace_full(a, b, strv_free) extern const struct hash_ops string_strv_hash_ops; int _string_strv_hashmap_put(Hashmap **h, const char *key, const char *value HASHMAP_DEBUG_PARAMS); diff --git a/src/libnm-systemd-shared/src/basic/time-util.c b/src/libnm-systemd-shared/src/basic/time-util.c index 0496ede3ee..0c8f49292f 100644 --- a/src/libnm-systemd-shared/src/basic/time-util.c +++ b/src/libnm-systemd-shared/src/basic/time-util.c @@ -595,7 +595,7 @@ char *format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy) { t = b; } - n = MIN((size_t) k, l); + n = MIN((size_t) k, l-1); l -= n; p += n; diff --git a/src/libnm-systemd-shared/src/fundamental/macro-fundamental.h b/src/libnm-systemd-shared/src/fundamental/macro-fundamental.h index a738b1f50e..0ed9940311 100644 --- a/src/libnm-systemd-shared/src/fundamental/macro-fundamental.h +++ b/src/libnm-systemd-shared/src/fundamental/macro-fundamental.h @@ -95,6 +95,20 @@ _expr_; \ }) +#define ASSERT_NONNEG(expr) \ + ({ \ + typeof(expr) _expr_ = (expr), _zero = 0; \ + assert(_expr_ >= _zero); \ + _expr_; \ + }) + +#define ASSERT_SE_NONNEG(expr) \ + ({ \ + typeof(expr) _expr_ = (expr), _zero = 0; \ + assert_se(_expr_ >= _zero); \ + _expr_; \ + }) + #define assert_cc(expr) static_assert(expr, #expr) @@ -106,10 +120,10 @@ * on this macro will run concurrently to all other code conditionalized * the same way, there's no ordering or completion enforced. */ #define ONCE __ONCE(UNIQ_T(_once_, UNIQ)) -#define __ONCE(o) \ - ({ \ - static bool (o) = false; \ - __sync_bool_compare_and_swap(&(o), false, true); \ +#define __ONCE(o) \ + ({ \ + static bool (o) = false; \ + __atomic_exchange_n(&(o), true, __ATOMIC_SEQ_CST); \ }) #undef MAX @@ -186,6 +200,27 @@ MIN(_c, z); \ }) +/* Returns true if the passed integer is a positive power of two */ +#define CONST_ISPOWEROF2(x) \ + ((x) > 0 && ((x) & ((x) - 1)) == 0) + +#if 0 /* NM_IGNORED */ +#define ISPOWEROF2(x) \ + __builtin_choose_expr( \ + __builtin_constant_p(x), \ + CONST_ISPOWEROF2(x), \ + ({ \ + const typeof(x) _x = (x); \ + CONST_ISPOWEROF2(_x); \ + })) +#else /* NM_IGNORED */ +#define ISPOWEROF2(x) \ + ({ \ + const typeof(x) _x = (x); \ + CONST_ISPOWEROF2(_x); \ + }) +#endif /* NM_IGNORED */ + #define LESS_BY(a, b) __LESS_BY(UNIQ, (a), UNIQ, (b)) #define __LESS_BY(aq, a, bq, b) \ ({ \ @@ -300,16 +335,7 @@ }) static inline size_t ALIGN_TO(size_t l, size_t ali) { - /* Check that alignment is exponent of 2 */ -#if SIZE_MAX == UINT_MAX - assert(__builtin_popcount(ali) == 1); -#elif SIZE_MAX == ULONG_MAX - assert(__builtin_popcountl(ali) == 1); -#elif SIZE_MAX == ULLONG_MAX - assert(__builtin_popcountll(ali) == 1); -#else - #error "Unexpected size_t" -#endif + assert(ISPOWEROF2(ali)); if (l > SIZE_MAX - (ali - 1)) return SIZE_MAX; /* indicate overflow */ @@ -330,7 +356,7 @@ static inline size_t ALIGN_TO(size_t l, size_t ali) { __builtin_choose_expr( \ __builtin_constant_p(l) && \ __builtin_constant_p(ali) && \ - __builtin_popcountll(ali) == 1 && /* is power of 2? */ \ + CONST_ISPOWEROF2(ali) && \ (l <= SIZE_MAX - (ali - 1)), /* overflow? */ \ ((l) + (ali) - 1) & ~((ali) - 1), \ VOID_0) |