mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2025-12-28 16:50:16 +01:00
systemd: merge branch systemd into main
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/897
This commit is contained in:
commit
fbf3952274
24 changed files with 222 additions and 137 deletions
|
|
@ -14,6 +14,7 @@
|
|||
#include "network-util.h"
|
||||
#include "siphash24.h"
|
||||
#include "sparse-endian.h"
|
||||
#include "stat-util.h"
|
||||
#include "stdio-util.h"
|
||||
#include "udev-util.h"
|
||||
#include "virt.h"
|
||||
|
|
@ -166,38 +167,40 @@ int dhcp_identifier_set_iaid(
|
|||
const uint8_t *mac,
|
||||
size_t mac_len,
|
||||
bool legacy_unstable_byteorder,
|
||||
bool use_mac,
|
||||
void *_id) {
|
||||
#if 0 /* NM_IGNORED */
|
||||
|
||||
/* name is a pointer to memory in the sd_device struct, so must
|
||||
* have the same scope */
|
||||
_cleanup_(sd_device_unrefp) sd_device *device = NULL;
|
||||
const char *name = NULL;
|
||||
uint64_t id;
|
||||
uint32_t id32;
|
||||
uint64_t id;
|
||||
int r;
|
||||
|
||||
if (detect_container() <= 0) {
|
||||
/* not in a container, udev will be around */
|
||||
char ifindex_str[1 + DECIMAL_STR_MAX(int)];
|
||||
int r;
|
||||
if (path_is_read_only_fs("/sys") <= 0 && !use_mac) {
|
||||
/* udev should be around */
|
||||
|
||||
xsprintf(ifindex_str, "n%d", ifindex);
|
||||
if (sd_device_new_from_device_id(&device, ifindex_str) >= 0) {
|
||||
r = sd_device_get_is_initialized(device);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
/* not yet ready */
|
||||
return -EBUSY;
|
||||
r = sd_device_new_from_ifindex(&device, ifindex);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = device_is_renaming(device);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r > 0)
|
||||
/* device is under renaming */
|
||||
return -EBUSY;
|
||||
r = sd_device_get_is_initialized(device);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
/* not yet ready */
|
||||
return -EBUSY;
|
||||
|
||||
name = net_get_name_persistent(device);
|
||||
}
|
||||
r = device_is_renaming(device);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r > 0)
|
||||
/* device is under renaming */
|
||||
return -EBUSY;
|
||||
|
||||
name = net_get_name_persistent(device);
|
||||
}
|
||||
|
||||
if (name)
|
||||
|
|
|
|||
|
|
@ -59,4 +59,4 @@ int dhcp_identifier_set_duid_llt(struct duid *duid, usec_t t, const uint8_t *add
|
|||
int dhcp_identifier_set_duid_ll(struct duid *duid, const uint8_t *addr, size_t addr_len, uint16_t arp_type, size_t *len);
|
||||
int dhcp_identifier_set_duid_en(struct duid *duid, size_t *len);
|
||||
int dhcp_identifier_set_duid_uuid(struct duid *duid, size_t *len);
|
||||
int dhcp_identifier_set_iaid(int ifindex, const uint8_t *mac, size_t mac_len, bool legacy_unstable_byteorder, void *_id);
|
||||
int dhcp_identifier_set_iaid(int ifindex, const uint8_t *mac, size_t mac_len, bool legacy_unstable_byteorder, bool use_mac, void *_id);
|
||||
|
|
|
|||
|
|
@ -30,6 +30,8 @@ typedef struct DHCPServerData {
|
|||
|
||||
extern const struct hash_ops dhcp_option_hash_ops;
|
||||
|
||||
typedef struct sd_dhcp_client sd_dhcp_client;
|
||||
|
||||
int dhcp_network_bind_raw_socket(int ifindex, union sockaddr_union *link, uint32_t xid,
|
||||
const uint8_t *mac_addr, size_t mac_addr_len,
|
||||
const uint8_t *bcast_addr, size_t bcast_addr_len,
|
||||
|
|
@ -62,6 +64,8 @@ void dhcp_packet_append_ip_headers(DHCPPacket *packet, be32_t source_addr,
|
|||
|
||||
int dhcp_packet_verify_headers(DHCPPacket *packet, size_t len, bool checksum, uint16_t port);
|
||||
|
||||
void dhcp_client_set_test_mode(sd_dhcp_client *client, bool test_mode);
|
||||
|
||||
/* If we are invoking callbacks of a dhcp-client, ensure unreffing the
|
||||
* client from the callback doesn't destroy the object we are working
|
||||
* on */
|
||||
|
|
|
|||
|
|
@ -91,6 +91,8 @@ typedef struct DHCP6IA {
|
|||
LIST_HEAD(DHCP6Address, addresses);
|
||||
} DHCP6IA;
|
||||
|
||||
typedef struct sd_dhcp6_client sd_dhcp6_client;
|
||||
|
||||
int dhcp6_option_append(uint8_t **buf, size_t *buflen, uint16_t code,
|
||||
size_t optlen, const void *optval);
|
||||
int dhcp6_option_append_ia(uint8_t **buf, size_t *buflen, const DHCP6IA *ia);
|
||||
|
|
@ -118,6 +120,8 @@ int dhcp6_message_type_from_string(const char *s) _pure_;
|
|||
const char *dhcp6_message_status_to_string(int s) _const_;
|
||||
int dhcp6_message_status_from_string(const char *s) _pure_;
|
||||
|
||||
void dhcp6_client_set_test_mode(sd_dhcp6_client *client, bool test_mode);
|
||||
|
||||
#define log_dhcp6_client_errno(client, error, fmt, ...) \
|
||||
log_interface_prefix_full_errno( \
|
||||
"DHCPv6 client: ", \
|
||||
|
|
|
|||
|
|
@ -119,6 +119,9 @@ struct sd_dhcp_client {
|
|||
sd_dhcp_lease *lease;
|
||||
usec_t start_delay;
|
||||
int ip_service_type;
|
||||
|
||||
/* Ignore ifindex when generating iaid. See dhcp_identifier_set_iaid(). */
|
||||
bool test_mode;
|
||||
};
|
||||
|
||||
static const uint8_t default_req_opts[] = {
|
||||
|
|
@ -470,7 +473,8 @@ static int dhcp_client_set_iaid_duid_internal(
|
|||
else {
|
||||
r = dhcp_identifier_set_iaid(client->ifindex, client->mac_addr,
|
||||
client->mac_addr_len,
|
||||
true,
|
||||
/* legacy_unstable_byteorder = */ true,
|
||||
/* use_mac = */ client->test_mode,
|
||||
&client->client_id.ns.iaid);
|
||||
if (r < 0)
|
||||
return log_dhcp_client_errno(client, r, "Failed to set IAID: %m");
|
||||
|
|
@ -560,6 +564,12 @@ int sd_dhcp_client_set_duid_llt(
|
|||
}
|
||||
#endif /* NM_IGNORED */
|
||||
|
||||
void dhcp_client_set_test_mode(sd_dhcp_client *client, bool test_mode) {
|
||||
assert(client);
|
||||
|
||||
client->test_mode = test_mode;
|
||||
}
|
||||
|
||||
int sd_dhcp_client_set_hostname(
|
||||
sd_dhcp_client *client,
|
||||
const char *hostname) {
|
||||
|
|
@ -865,7 +875,9 @@ static int client_message_init(
|
|||
client->client_id.type = 255;
|
||||
|
||||
r = dhcp_identifier_set_iaid(client->ifindex, client->mac_addr, client->mac_addr_len,
|
||||
true, &client->client_id.ns.iaid);
|
||||
/* legacy_unstable_byteorder = */ true,
|
||||
/* use_mac = */ client->test_mode,
|
||||
&client->client_id.ns.iaid);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
|
|
|||
|
|
@ -90,6 +90,9 @@ struct sd_dhcp6_client {
|
|||
usec_t information_refresh_time_usec;
|
||||
OrderedHashmap *extra_options;
|
||||
OrderedHashmap *vendor_options;
|
||||
|
||||
/* Ignore ifindex when generating iaid. See dhcp_identifier_set_iaid(). */
|
||||
bool test_mode;
|
||||
};
|
||||
|
||||
static const uint16_t default_req_opts[] = {
|
||||
|
|
@ -408,6 +411,12 @@ int sd_dhcp6_client_set_iaid(sd_dhcp6_client *client, uint32_t iaid) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
void dhcp6_client_set_test_mode(sd_dhcp6_client *client, bool test_mode) {
|
||||
assert(client);
|
||||
|
||||
client->test_mode = test_mode;
|
||||
}
|
||||
|
||||
int sd_dhcp6_client_get_iaid(sd_dhcp6_client *client, uint32_t *iaid) {
|
||||
assert_return(client, -EINVAL);
|
||||
assert_return(iaid, -EINVAL);
|
||||
|
|
@ -1083,7 +1092,10 @@ static int client_ensure_iaid(sd_dhcp6_client *client) {
|
|||
if (client->iaid_set)
|
||||
return 0;
|
||||
|
||||
r = dhcp_identifier_set_iaid(client->ifindex, client->mac_addr, client->mac_addr_len, true, &iaid);
|
||||
r = dhcp_identifier_set_iaid(client->ifindex, client->mac_addr, client->mac_addr_len,
|
||||
/* legacy_unstable_byteorder = */ true,
|
||||
/* use_mac = */ client->test_mode,
|
||||
&iaid);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
|
|
|||
|
|
@ -170,10 +170,9 @@ static int pending_prioq_compare(const void *a, const void *b) {
|
|||
assert(y->pending);
|
||||
|
||||
/* Enabled ones first */
|
||||
if (x->enabled != SD_EVENT_OFF && y->enabled == SD_EVENT_OFF)
|
||||
return -1;
|
||||
if (x->enabled == SD_EVENT_OFF && y->enabled != SD_EVENT_OFF)
|
||||
return 1;
|
||||
r = CMP(x->enabled == SD_EVENT_OFF, y->enabled == SD_EVENT_OFF);
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
/* Non rate-limited ones first. */
|
||||
r = CMP(!!x->ratelimited, !!y->ratelimited);
|
||||
|
|
@ -197,10 +196,9 @@ static int prepare_prioq_compare(const void *a, const void *b) {
|
|||
assert(y->prepare);
|
||||
|
||||
/* Enabled ones first */
|
||||
if (x->enabled != SD_EVENT_OFF && y->enabled == SD_EVENT_OFF)
|
||||
return -1;
|
||||
if (x->enabled == SD_EVENT_OFF && y->enabled != SD_EVENT_OFF)
|
||||
return 1;
|
||||
r = CMP(x->enabled == SD_EVENT_OFF, y->enabled == SD_EVENT_OFF);
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
/* Non rate-limited ones first. */
|
||||
r = CMP(!!x->ratelimited, !!y->ratelimited);
|
||||
|
|
@ -239,25 +237,6 @@ static usec_t time_event_source_next(const sd_event_source *s) {
|
|||
return USEC_INFINITY;
|
||||
}
|
||||
|
||||
static int earliest_time_prioq_compare(const void *a, const void *b) {
|
||||
const sd_event_source *x = a, *y = b;
|
||||
|
||||
/* Enabled ones first */
|
||||
if (x->enabled != SD_EVENT_OFF && y->enabled == SD_EVENT_OFF)
|
||||
return -1;
|
||||
if (x->enabled == SD_EVENT_OFF && y->enabled != SD_EVENT_OFF)
|
||||
return 1;
|
||||
|
||||
/* Move the pending ones to the end */
|
||||
if (!x->pending && y->pending)
|
||||
return -1;
|
||||
if (x->pending && !y->pending)
|
||||
return 1;
|
||||
|
||||
/* Order by time */
|
||||
return CMP(time_event_source_next(x), time_event_source_next(y));
|
||||
}
|
||||
|
||||
static usec_t time_event_source_latest(const sd_event_source *s) {
|
||||
assert(s);
|
||||
|
||||
|
|
@ -276,36 +255,51 @@ static usec_t time_event_source_latest(const sd_event_source *s) {
|
|||
return USEC_INFINITY;
|
||||
}
|
||||
|
||||
static int latest_time_prioq_compare(const void *a, const void *b) {
|
||||
static bool event_source_timer_candidate(const sd_event_source *s) {
|
||||
assert(s);
|
||||
|
||||
/* Returns true for event sources that either are not pending yet (i.e. where it's worth to mark them pending)
|
||||
* or which are currently ratelimited (i.e. where it's worth leaving the ratelimited state) */
|
||||
return !s->pending || s->ratelimited;
|
||||
}
|
||||
|
||||
static int time_prioq_compare(const void *a, const void *b, usec_t (*time_func)(const sd_event_source *s)) {
|
||||
const sd_event_source *x = a, *y = b;
|
||||
int r;
|
||||
|
||||
/* Enabled ones first */
|
||||
if (x->enabled != SD_EVENT_OFF && y->enabled == SD_EVENT_OFF)
|
||||
return -1;
|
||||
if (x->enabled == SD_EVENT_OFF && y->enabled != SD_EVENT_OFF)
|
||||
return 1;
|
||||
r = CMP(x->enabled == SD_EVENT_OFF, y->enabled == SD_EVENT_OFF);
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
/* Move the pending ones to the end */
|
||||
if (!x->pending && y->pending)
|
||||
return -1;
|
||||
if (x->pending && !y->pending)
|
||||
return 1;
|
||||
/* Order "non-pending OR ratelimited" before "pending AND not-ratelimited" */
|
||||
r = CMP(!event_source_timer_candidate(x), !event_source_timer_candidate(y));
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
/* Order by time */
|
||||
return CMP(time_event_source_latest(x), time_event_source_latest(y));
|
||||
return CMP(time_func(x), time_func(y));
|
||||
}
|
||||
|
||||
static int earliest_time_prioq_compare(const void *a, const void *b) {
|
||||
return time_prioq_compare(a, b, time_event_source_next);
|
||||
}
|
||||
|
||||
static int latest_time_prioq_compare(const void *a, const void *b) {
|
||||
return time_prioq_compare(a, b, time_event_source_latest);
|
||||
}
|
||||
|
||||
static int exit_prioq_compare(const void *a, const void *b) {
|
||||
const sd_event_source *x = a, *y = b;
|
||||
int r;
|
||||
|
||||
assert(x->type == SOURCE_EXIT);
|
||||
assert(y->type == SOURCE_EXIT);
|
||||
|
||||
/* Enabled ones first */
|
||||
if (x->enabled != SD_EVENT_OFF && y->enabled == SD_EVENT_OFF)
|
||||
return -1;
|
||||
if (x->enabled == SD_EVENT_OFF && y->enabled != SD_EVENT_OFF)
|
||||
return 1;
|
||||
r = CMP(x->enabled == SD_EVENT_OFF, y->enabled == SD_EVENT_OFF);
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
/* Lower priority values first */
|
||||
return CMP(x->priority, y->priority);
|
||||
|
|
@ -779,14 +773,15 @@ static void event_source_time_prioq_reshuffle(sd_event_source *s) {
|
|||
assert(s);
|
||||
|
||||
/* Called whenever the event source's timer ordering properties changed, i.e. time, accuracy,
|
||||
* pending, enable state. Makes sure the two prioq's are ordered properly again. */
|
||||
* pending, enable state, and ratelimiting state. Makes sure the two prioq's are ordered
|
||||
* properly again. */
|
||||
|
||||
if (s->ratelimited)
|
||||
d = &s->event->monotonic;
|
||||
else {
|
||||
assert(EVENT_SOURCE_IS_TIME(s->type));
|
||||
else if (EVENT_SOURCE_IS_TIME(s->type))
|
||||
assert_se(d = event_get_clock_data(s->event, s->type));
|
||||
}
|
||||
else
|
||||
return; /* no-op for an event source which is neither a timer nor ratelimited. */
|
||||
|
||||
prioq_reshuffle(d->earliest, s, &s->earliest_index);
|
||||
prioq_reshuffle(d->latest, s, &s->latest_index);
|
||||
|
|
@ -2379,14 +2374,6 @@ static int event_source_offline(
|
|||
source_io_unregister(s);
|
||||
break;
|
||||
|
||||
case SOURCE_TIME_REALTIME:
|
||||
case SOURCE_TIME_BOOTTIME:
|
||||
case SOURCE_TIME_MONOTONIC:
|
||||
case SOURCE_TIME_REALTIME_ALARM:
|
||||
case SOURCE_TIME_BOOTTIME_ALARM:
|
||||
event_source_time_prioq_reshuffle(s);
|
||||
break;
|
||||
|
||||
case SOURCE_SIGNAL:
|
||||
event_gc_signal_data(s->event, &s->priority, s->signal.sig);
|
||||
break;
|
||||
|
|
@ -2407,6 +2394,11 @@ static int event_source_offline(
|
|||
prioq_reshuffle(s->event->exit, s, &s->exit.prioq_index);
|
||||
break;
|
||||
|
||||
case SOURCE_TIME_REALTIME:
|
||||
case SOURCE_TIME_BOOTTIME:
|
||||
case SOURCE_TIME_MONOTONIC:
|
||||
case SOURCE_TIME_REALTIME_ALARM:
|
||||
case SOURCE_TIME_BOOTTIME_ALARM:
|
||||
case SOURCE_DEFER:
|
||||
case SOURCE_POST:
|
||||
case SOURCE_INOTIFY:
|
||||
|
|
@ -2416,6 +2408,9 @@ static int event_source_offline(
|
|||
assert_not_reached("Wut? I shouldn't exist.");
|
||||
}
|
||||
|
||||
/* Always reshuffle time prioq, as the ratelimited flag may be changed. */
|
||||
event_source_time_prioq_reshuffle(s);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
@ -2505,22 +2500,11 @@ static int event_source_online(
|
|||
s->ratelimited = ratelimited;
|
||||
|
||||
/* Non-failing operations below */
|
||||
switch (s->type) {
|
||||
case SOURCE_TIME_REALTIME:
|
||||
case SOURCE_TIME_BOOTTIME:
|
||||
case SOURCE_TIME_MONOTONIC:
|
||||
case SOURCE_TIME_REALTIME_ALARM:
|
||||
case SOURCE_TIME_BOOTTIME_ALARM:
|
||||
event_source_time_prioq_reshuffle(s);
|
||||
break;
|
||||
|
||||
case SOURCE_EXIT:
|
||||
if (s->type == SOURCE_EXIT)
|
||||
prioq_reshuffle(s->event->exit, s, &s->exit.prioq_index);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
/* Always reshuffle time prioq, as the ratelimited flag may be changed. */
|
||||
event_source_time_prioq_reshuffle(s);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -2990,8 +2974,8 @@ static int event_arm_timer(
|
|||
|
||||
if (!d->needs_rearm)
|
||||
return 0;
|
||||
else
|
||||
d->needs_rearm = false;
|
||||
|
||||
d->needs_rearm = false;
|
||||
|
||||
a = prioq_peek(d->earliest);
|
||||
if (!a || a->enabled == SD_EVENT_OFF || time_event_source_next(a) == USEC_INFINITY) {
|
||||
|
|
@ -3687,8 +3671,8 @@ static int arm_watchdog(sd_event *e) {
|
|||
assert(e->watchdog_fd >= 0);
|
||||
|
||||
t = sleep_between(e,
|
||||
e->watchdog_last + (e->watchdog_period / 2),
|
||||
e->watchdog_last + (e->watchdog_period * 3 / 4));
|
||||
usec_add(e->watchdog_last, (e->watchdog_period / 2)),
|
||||
usec_add(e->watchdog_last, (e->watchdog_period * 3 / 4)));
|
||||
|
||||
timespec_store(&its.it_value, t);
|
||||
|
||||
|
|
|
|||
|
|
@ -63,7 +63,9 @@ int sd_id128_get_boot_app_specific(sd_id128_t app_id, sd_id128_t *ret);
|
|||
#define SD_ID128_FORMAT_STR "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
|
||||
#define SD_ID128_FORMAT_VAL(x) (x).bytes[0], (x).bytes[1], (x).bytes[2], (x).bytes[3], (x).bytes[4], (x).bytes[5], (x).bytes[6], (x).bytes[7], (x).bytes[8], (x).bytes[9], (x).bytes[10], (x).bytes[11], (x).bytes[12], (x).bytes[13], (x).bytes[14], (x).bytes[15]
|
||||
|
||||
/* Like SD_ID128_FORMAT_STR, but formats as UUID, not in plain format */
|
||||
/* Like SD_ID128_FORMAT_STR, but formats as UUID, not in plain format (Strictly Big Endian byte order,
|
||||
* i.e. treats everything as RFC4122 Variant 1 UUIDs, even if variant says otherwise, but matching other
|
||||
* Linux userspace behaviour.) */
|
||||
#define SD_ID128_UUID_FORMAT_STR "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x"
|
||||
|
||||
#define SD_ID128_CONST_STR(x) \
|
||||
|
|
@ -105,6 +107,9 @@ int sd_id128_get_boot_app_specific(sd_id128_t app_id, sd_id128_t *ret);
|
|||
#define SD_ID128_MAKE_STR(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) \
|
||||
#a #b #c #d #e #f #g #h #i #j #k #l #m #n #o #p
|
||||
|
||||
#define SD_ID128_MAKE_UUID_STR(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) \
|
||||
#a #b #c #d "-" #e #f "-" #g #h "-" #i #j "-" #k #l #m #n #o #p
|
||||
|
||||
_sd_pure_ static __inline__ int sd_id128_equal(sd_id128_t a, sd_id128_t b) {
|
||||
return memcmp(&a, &b, 16) == 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -79,6 +79,13 @@ void* memdup_suffix0(const void *p, size_t l); /* We can't use _alloc_() here, s
|
|||
memcpy_safe(_q_, p, _l_); \
|
||||
})
|
||||
|
||||
static inline void unsetp(void *p) {
|
||||
/* A trivial "destructor" that can be used in cases where we want to
|
||||
* unset a pointer from a _cleanup_ function. */
|
||||
|
||||
*(void**)p = NULL;
|
||||
}
|
||||
|
||||
static inline void freep(void *p) {
|
||||
*(void**)p = mfree(*(void**) p);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,13 +12,13 @@
|
|||
#include "macro.h"
|
||||
#include "string-util.h"
|
||||
|
||||
char* hw_addr_to_string(const hw_addr_data *addr, char buffer[HW_ADDR_TO_STRING_MAX]) {
|
||||
char* hw_addr_to_string(const struct hw_addr_data *addr, char buffer[HW_ADDR_TO_STRING_MAX]) {
|
||||
assert(addr);
|
||||
assert(buffer);
|
||||
assert(addr->length <= HW_ADDR_MAX_SIZE);
|
||||
|
||||
for (size_t i = 0; i < addr->length; i++) {
|
||||
sprintf(&buffer[3*i], "%02"PRIx8, addr->addr.bytes[i]);
|
||||
sprintf(&buffer[3*i], "%02"PRIx8, addr->bytes[i]);
|
||||
if (i < addr->length - 1)
|
||||
buffer[3*i + 2] = ':';
|
||||
}
|
||||
|
|
@ -26,6 +26,19 @@ char* hw_addr_to_string(const hw_addr_data *addr, char buffer[HW_ADDR_TO_STRING_
|
|||
return buffer;
|
||||
}
|
||||
|
||||
int hw_addr_compare(const struct hw_addr_data *a, const struct hw_addr_data *b) {
|
||||
int r;
|
||||
|
||||
assert(a);
|
||||
assert(b);
|
||||
|
||||
r = CMP(a->length, b->length);
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
return memcmp(a->bytes, b->bytes, a->length);
|
||||
}
|
||||
|
||||
char* ether_addr_to_string(const struct ether_addr *addr, char buffer[ETHER_ADDR_TO_STRING_MAX]) {
|
||||
assert(addr);
|
||||
assert(buffer);
|
||||
|
|
|
|||
|
|
@ -11,24 +11,30 @@
|
|||
* defines a macro of the same name with a much lower size. */
|
||||
#define HW_ADDR_MAX_SIZE 32
|
||||
|
||||
union hw_addr_union {
|
||||
struct ether_addr ether;
|
||||
uint8_t infiniband[INFINIBAND_ALEN];
|
||||
uint8_t bytes[HW_ADDR_MAX_SIZE];
|
||||
struct hw_addr_data {
|
||||
size_t length;
|
||||
union {
|
||||
struct ether_addr ether;
|
||||
uint8_t infiniband[INFINIBAND_ALEN];
|
||||
uint8_t bytes[HW_ADDR_MAX_SIZE];
|
||||
};
|
||||
};
|
||||
|
||||
typedef struct hw_addr_data {
|
||||
union hw_addr_union addr;
|
||||
size_t length;
|
||||
} hw_addr_data;
|
||||
|
||||
#define HW_ADDR_TO_STRING_MAX (3*HW_ADDR_MAX_SIZE)
|
||||
char* hw_addr_to_string(const hw_addr_data *addr, char buffer[HW_ADDR_TO_STRING_MAX]);
|
||||
char* hw_addr_to_string(const struct hw_addr_data *addr, char buffer[HW_ADDR_TO_STRING_MAX]);
|
||||
|
||||
/* Use only as function argument, never stand-alone! */
|
||||
#define HW_ADDR_TO_STR(hw_addr) hw_addr_to_string((hw_addr), (char[HW_ADDR_TO_STRING_MAX]){})
|
||||
|
||||
#define HW_ADDR_NULL ((const hw_addr_data){})
|
||||
#define HW_ADDR_NULL ((const struct hw_addr_data){})
|
||||
|
||||
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) {
|
||||
return hw_addr_compare(a, b) == 0;
|
||||
}
|
||||
static inline bool hw_addr_is_null(const struct hw_addr_data *addr) {
|
||||
return hw_addr_equal(addr, &HW_ADDR_NULL);
|
||||
}
|
||||
|
||||
#define ETHER_ADDR_FORMAT_STR "%02X%02X%02X%02X%02X%02X"
|
||||
#define ETHER_ADDR_FORMAT_VAL(x) (x).ether_addr_octet[0], (x).ether_addr_octet[1], (x).ether_addr_octet[2], (x).ether_addr_octet[3], (x).ether_addr_octet[4], (x).ether_addr_octet[5]
|
||||
|
|
@ -36,6 +42,8 @@ char* hw_addr_to_string(const hw_addr_data *addr, char buffer[HW_ADDR_TO_STRING_
|
|||
#define ETHER_ADDR_TO_STRING_MAX (3*6)
|
||||
char* ether_addr_to_string(const struct ether_addr *addr, char buffer[ETHER_ADDR_TO_STRING_MAX]);
|
||||
int ether_addr_to_string_alloc(const struct ether_addr *addr, char **ret);
|
||||
/* Use only as function argument, never stand-alone! */
|
||||
#define ETHER_ADDR_TO_STR(addr) ether_addr_to_string((addr), (char[ETHER_ADDR_TO_STRING_MAX]){})
|
||||
|
||||
int ether_addr_compare(const struct ether_addr *a, const struct ether_addr *b);
|
||||
static inline bool ether_addr_equal(const struct ether_addr *a, const struct ether_addr *b) {
|
||||
|
|
|
|||
|
|
@ -29,8 +29,17 @@
|
|||
#include "string-util.h"
|
||||
#include "tmpfile-util.h"
|
||||
|
||||
/* The maximum size of the file we'll read in one go. */
|
||||
#define READ_FULL_BYTES_MAX (4U*1024U*1024U - 1)
|
||||
/* The maximum size of the file we'll read in one go in read_full_file() (64M). */
|
||||
#define READ_FULL_BYTES_MAX (64U*1024U*1024U - 1U)
|
||||
|
||||
/* The maximum size of virtual files we'll read in one go in read_virtual_file() (4M). Note that this limit
|
||||
* is different (and much lower) than the READ_FULL_BYTES_MAX limit. This reflects the fact that we use
|
||||
* different strategies for reading virtual and regular files: virtual files are generally size constrained:
|
||||
* there we allocate the full buffer size in advance. Regular files OTOH can be much larger, and here we grow
|
||||
* the allocations exponentially in a loop. In glibc large allocations are immediately backed by mmap()
|
||||
* making them relatively slow (measurably so). Thus, when allocating the full buffer in advance the large
|
||||
* limit is a problem. When allocating piecemeal it's not. Hence pick two distinct limits. */
|
||||
#define READ_VIRTUAL_BYTES_MAX (4U*1024U*1024U - 1U)
|
||||
|
||||
int fopen_unlocked(const char *path, const char *options, FILE **ret) {
|
||||
assert(ret);
|
||||
|
|
@ -392,7 +401,7 @@ int read_virtual_file(const char *filename, size_t max_size, char **ret_contents
|
|||
if (fd < 0)
|
||||
return -errno;
|
||||
|
||||
assert(max_size <= READ_FULL_BYTES_MAX || max_size == SIZE_MAX);
|
||||
assert(max_size <= READ_VIRTUAL_BYTES_MAX || max_size == SIZE_MAX);
|
||||
|
||||
/* Limit the number of attempts to read the number of bytes returned by fstat(). */
|
||||
n_retries = 3;
|
||||
|
|
@ -407,7 +416,7 @@ int read_virtual_file(const char *filename, size_t max_size, char **ret_contents
|
|||
return -EBADF;
|
||||
|
||||
/* Be prepared for files from /proc which generally report a file size of 0. */
|
||||
assert_cc(READ_FULL_BYTES_MAX < SSIZE_MAX);
|
||||
assert_cc(READ_VIRTUAL_BYTES_MAX < SSIZE_MAX);
|
||||
if (st.st_size > 0 && n_retries > 1) {
|
||||
/* Let's use the file size if we have more than 1 attempt left. On the last attempt
|
||||
* we'll ignore the file size */
|
||||
|
|
@ -421,13 +430,13 @@ int read_virtual_file(const char *filename, size_t max_size, char **ret_contents
|
|||
} else {
|
||||
size = MIN((size_t) st.st_size, max_size);
|
||||
|
||||
if (size > READ_FULL_BYTES_MAX)
|
||||
if (size > READ_VIRTUAL_BYTES_MAX)
|
||||
return -EFBIG;
|
||||
}
|
||||
|
||||
n_retries--;
|
||||
} else {
|
||||
size = MIN(READ_FULL_BYTES_MAX, max_size);
|
||||
size = MIN(READ_VIRTUAL_BYTES_MAX, max_size);
|
||||
n_retries = 0;
|
||||
}
|
||||
|
||||
|
|
@ -436,7 +445,7 @@ int read_virtual_file(const char *filename, size_t max_size, char **ret_contents
|
|||
return -ENOMEM;
|
||||
|
||||
/* Use a bigger allocation if we got it anyway, but not more than the limit. */
|
||||
size = MIN3(MALLOC_SIZEOF_SAFE(buf) - 1, max_size, READ_FULL_BYTES_MAX);
|
||||
size = MIN3(MALLOC_SIZEOF_SAFE(buf) - 1, max_size, READ_VIRTUAL_BYTES_MAX);
|
||||
|
||||
for (;;) {
|
||||
ssize_t k;
|
||||
|
|
@ -576,7 +585,7 @@ int read_full_stream_full(
|
|||
}
|
||||
memcpy_safe(t, buf, n);
|
||||
explicit_bzero_safe(buf, n);
|
||||
buf = mfree(buf);
|
||||
free(buf);
|
||||
} else {
|
||||
t = realloc(buf, n_next + 1);
|
||||
if (!t)
|
||||
|
|
|
|||
|
|
@ -744,7 +744,7 @@ int inotify_add_watch_and_warn(int fd, const char *pathname, uint32_t mask) {
|
|||
return wd;
|
||||
}
|
||||
|
||||
static bool unsafe_transition(const struct stat *a, const struct stat *b) {
|
||||
bool unsafe_transition(const struct stat *a, const struct stat *b) {
|
||||
/* Returns true if the transition from a to b is safe, i.e. that we never transition from unprivileged to
|
||||
* privileged files or directories. Why bother? So that unprivileged code can't symlink to privileged files
|
||||
* making us believe we read something safe even though it isn't safe in the specific context we open it in. */
|
||||
|
|
|
|||
|
|
@ -94,6 +94,8 @@ enum {
|
|||
CHASE_WARN = 1 << 7, /* Emit an appropriate warning when an error is encountered */
|
||||
};
|
||||
|
||||
bool unsafe_transition(const struct stat *a, const struct stat *b);
|
||||
|
||||
/* How many iterations to execute before returning -ELOOP */
|
||||
#define CHASE_SYMLINKS_MAX 32
|
||||
|
||||
|
|
|
|||
|
|
@ -530,6 +530,16 @@ char base64char(int x) {
|
|||
}
|
||||
#endif /* NM_IGNORED */
|
||||
|
||||
/* This is almost base64char(), but not entirely, as it uses the "url and filename safe" alphabet,
|
||||
* since we don't want "/" appear in interface names (since interfaces appear in sysfs as filenames).
|
||||
* See section #5 of RFC 4648. */
|
||||
char urlsafe_base64char(int x) {
|
||||
static const char table[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"abcdefghijklmnopqrstuvwxyz"
|
||||
"0123456789-_";
|
||||
return table[x & 63];
|
||||
}
|
||||
|
||||
int unbase64char(char c) {
|
||||
unsigned offset;
|
||||
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ char base32hexchar(int x) _const_;
|
|||
int unbase32hexchar(char c) _const_;
|
||||
|
||||
char base64char(int x) _const_;
|
||||
char urlsafe_base64char(int x) _const_;
|
||||
int unbase64char(char c) _const_;
|
||||
|
||||
char *base32hexmem(const void *p, size_t l, bool padding);
|
||||
|
|
|
|||
|
|
@ -123,6 +123,12 @@ int in_addr_is_localhost(int family, const union in_addr_union *u) {
|
|||
return -EAFNOSUPPORT;
|
||||
}
|
||||
|
||||
bool in6_addr_is_ipv4_mapped_address(const struct in6_addr *a) {
|
||||
return a->s6_addr32[0] == 0 &&
|
||||
a->s6_addr32[1] == 0 &&
|
||||
a->s6_addr32[2] == htobe32(UINT32_C(0x0000ffff));
|
||||
}
|
||||
|
||||
bool in4_addr_equal(const struct in_addr *a, const struct in_addr *b) {
|
||||
assert(a);
|
||||
assert(b);
|
||||
|
|
|
|||
|
|
@ -58,6 +58,7 @@ int in_addr_is_localhost(int family, const union in_addr_union *u);
|
|||
|
||||
bool in4_addr_is_local_multicast(const struct in_addr *a);
|
||||
bool in4_addr_is_non_local(const struct in_addr *a);
|
||||
bool in6_addr_is_ipv4_mapped_address(const struct in6_addr *a);
|
||||
|
||||
bool in4_addr_equal(const struct in_addr *a, const struct in_addr *b);
|
||||
bool in6_addr_equal(const struct in6_addr *a, const struct in6_addr *b);
|
||||
|
|
|
|||
|
|
@ -722,7 +722,7 @@ int find_executable_full(const char *name, bool use_path_envvar, char **ret_file
|
|||
}
|
||||
|
||||
bool paths_check_timestamp(const char* const* paths, usec_t *timestamp, bool update) {
|
||||
bool changed = false;
|
||||
bool changed = false, originally_unset;
|
||||
const char* const* i;
|
||||
|
||||
assert(timestamp);
|
||||
|
|
@ -730,6 +730,8 @@ bool paths_check_timestamp(const char* const* paths, usec_t *timestamp, bool upd
|
|||
if (!paths)
|
||||
return false;
|
||||
|
||||
originally_unset = *timestamp == 0;
|
||||
|
||||
STRV_FOREACH(i, paths) {
|
||||
struct stat stats;
|
||||
usec_t u;
|
||||
|
|
@ -739,11 +741,11 @@ bool paths_check_timestamp(const char* const* paths, usec_t *timestamp, bool upd
|
|||
|
||||
u = timespec_load(&stats.st_mtim);
|
||||
|
||||
/* first check */
|
||||
/* check first */
|
||||
if (*timestamp >= u)
|
||||
continue;
|
||||
|
||||
log_debug("timestamp of '%s' changed", *i);
|
||||
log_debug(originally_unset ? "Loaded timestamp for '%s'." : "Timestamp of '%s' changed.", *i);
|
||||
|
||||
/* update timestamp */
|
||||
if (update) {
|
||||
|
|
|
|||
|
|
@ -826,7 +826,7 @@ int wait_for_terminate_with_timeout(pid_t pid, usec_t timeout) {
|
|||
/* Assuming we woke due to the child exiting. */
|
||||
if (waitid(P_PID, pid, &status, WEXITED|WNOHANG) == 0) {
|
||||
if (status.si_pid == pid) {
|
||||
/* This is the correct child.*/
|
||||
/* This is the correct child. */
|
||||
if (status.si_code == CLD_EXITED)
|
||||
return (status.si_status == 0) ? 0 : -EPROTO;
|
||||
else
|
||||
|
|
|
|||
|
|
@ -190,7 +190,7 @@ int genuine_random_bytes(void *p, size_t n, RandomFlags flags) {
|
|||
* invocations or so. That's because we don't really care about the quality here. We
|
||||
* generally prefer using RDRAND if the caller allows us to, since this way we won't upset
|
||||
* the kernel's random subsystem by accessing it before the pool is initialized (after all it
|
||||
* will kmsg log about every attempt to do so)..*/
|
||||
* will kmsg log about every attempt to do so). */
|
||||
for (;;) {
|
||||
unsigned long u;
|
||||
size_t m;
|
||||
|
|
|
|||
|
|
@ -112,7 +112,7 @@ int socket_address_verify(const SocketAddress *a, bool strict) {
|
|||
/* If there's no embedded NUL byte, then the size needs to match the whole
|
||||
* structure or the structure with one extra NUL byte suffixed. (Yeah, Linux is awful,
|
||||
* and considers both equivalent: getsockname() even extends sockaddr_un beyond its
|
||||
* size if the path is non NUL terminated.)*/
|
||||
* size if the path is non NUL terminated.) */
|
||||
if (!IN_SET(a->size, sizeof(a->sockaddr.un.sun_path), sizeof(a->sockaddr.un.sun_path)+1))
|
||||
return -EINVAL;
|
||||
}
|
||||
|
|
@ -1204,7 +1204,7 @@ int sockaddr_un_set_path(struct sockaddr_un *ret, const char *path) {
|
|||
/* Don't allow paths larger than the space in sockaddr_un. Note that we are a tiny bit more restrictive than
|
||||
* the kernel is: we insist on NUL termination (both for abstract namespace and regular file system socket
|
||||
* addresses!), which the kernel doesn't. We do this to reduce chance of incompatibility with other apps that
|
||||
* do not expect non-NUL terminated file system path*/
|
||||
* do not expect non-NUL terminated file system path. */
|
||||
if (l+1 > sizeof(ret->sun_path))
|
||||
return -EINVAL;
|
||||
|
||||
|
|
|
|||
|
|
@ -1035,7 +1035,7 @@ int parse_time(const char *t, usec_t *usec, usec_t default_unit) {
|
|||
|
||||
s = extract_multiplier(p + strspn(p, WHITESPACE), &multiplier);
|
||||
if (s == p && *s != '\0')
|
||||
/* Don't allow '12.34.56', but accept '12.34 .56' or '12.34s.56'*/
|
||||
/* Don't allow '12.34.56', but accept '12.34 .56' or '12.34s.56' */
|
||||
return -EINVAL;
|
||||
|
||||
p = s;
|
||||
|
|
@ -1063,7 +1063,7 @@ int parse_time(const char *t, usec_t *usec, usec_t default_unit) {
|
|||
r += k;
|
||||
}
|
||||
|
||||
/* Don't allow "0.-0", "3.+1", "3. 1", "3.sec" or "3.hoge"*/
|
||||
/* Don't allow "0.-0", "3.+1", "3. 1", "3.sec" or "3.hoge" */
|
||||
if (b == e + 1)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
|
@ -1210,7 +1210,7 @@ int parse_nsec(const char *t, nsec_t *nsec) {
|
|||
|
||||
s = extract_nsec_multiplier(p + strspn(p, WHITESPACE), &multiplier);
|
||||
if (s == p && *s != '\0')
|
||||
/* Don't allow '12.34.56', but accept '12.34 .56' or '12.34s.56'*/
|
||||
/* Don't allow '12.34.56', but accept '12.34 .56' or '12.34s.56' */
|
||||
return -EINVAL;
|
||||
|
||||
p = s;
|
||||
|
|
@ -1238,7 +1238,7 @@ int parse_nsec(const char *t, nsec_t *nsec) {
|
|||
r += k;
|
||||
}
|
||||
|
||||
/* Don't allow "0.-0", "3.+1", "3. 1", "3.sec" or "3.hoge"*/
|
||||
/* Don't allow "0.-0", "3.+1", "3. 1", "3.sec" or "3.hoge" */
|
||||
if (b == e + 1)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
|
@ -1445,7 +1445,7 @@ int get_timezone(char **ret) {
|
|||
|
||||
r = readlink_malloc("/etc/localtime", &t);
|
||||
if (r == -ENOENT) {
|
||||
/* If the symlink does not exist, assume "UTC", like glibc does*/
|
||||
/* If the symlink does not exist, assume "UTC", like glibc does */
|
||||
z = strdup("UTC");
|
||||
if (!z)
|
||||
return -ENOMEM;
|
||||
|
|
|
|||
|
|
@ -79,6 +79,7 @@ sd_char* endswith_no_case(const sd_char *s, const sd_char *postfix) {
|
|||
return (sd_char*) s + sl - pl;
|
||||
}
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
#ifdef SD_BOOT
|
||||
static sd_bool isdigit(sd_char a) {
|
||||
return a >= '0' && a <= '9';
|
||||
|
|
@ -154,7 +155,7 @@ sd_int strverscmp_improved(const sd_char *a, const sd_char *b) {
|
|||
* Note that except for '~' prefixed segments, a string has more segments is newer.
|
||||
* So, this check must be after the '~' check. */
|
||||
if (*a == '\0' || *b == '\0')
|
||||
return strcmp(a, b);
|
||||
return CMP(*a, *b);
|
||||
|
||||
/* Handle '-', which separates version and release, e.g 123.4-3.1.fc33.x86_64 */
|
||||
if (*a == '-' || *b == '-') {
|
||||
|
|
@ -196,9 +197,9 @@ sd_int strverscmp_improved(const sd_char *a, const sd_char *b) {
|
|||
|
||||
/* Find the leading numeric segments. One may be an empty string. So,
|
||||
* numeric segments are always newer than alpha segments. */
|
||||
for (aa = a; *aa != '\0' && isdigit(*aa); aa++)
|
||||
for (aa = a; isdigit(*aa); aa++)
|
||||
;
|
||||
for (bb = b; *bb != '\0' && isdigit(*bb); bb++)
|
||||
for (bb = b; isdigit(*bb); bb++)
|
||||
;
|
||||
|
||||
/* To compare numeric segments without parsing their values, first compare the
|
||||
|
|
@ -213,9 +214,9 @@ sd_int strverscmp_improved(const sd_char *a, const sd_char *b) {
|
|||
return r;
|
||||
} else {
|
||||
/* Find the leading non-numeric segments. */
|
||||
for (aa = a; *aa != '\0' && is_alpha(*aa); aa++)
|
||||
for (aa = a; is_alpha(*aa); aa++)
|
||||
;
|
||||
for (bb = b; *bb != '\0' && is_alpha(*bb); bb++)
|
||||
for (bb = b; is_alpha(*bb); bb++)
|
||||
;
|
||||
|
||||
/* Note that the segments are usually not NUL-terminated. */
|
||||
|
|
@ -234,3 +235,4 @@ sd_int strverscmp_improved(const sd_char *a, const sd_char *b) {
|
|||
b = bb;
|
||||
}
|
||||
}
|
||||
#endif /* NM_IGNORED */
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue