mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager
synced 2024-10-07 00:31:11 +00:00
systemd: merge branch systemd into main
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/1068
This commit is contained in:
commit
18cb8205b3
|
@ -2122,8 +2122,10 @@ src_libnm_systemd_shared_libnm_systemd_shared_la_SOURCES = \
|
|||
src/libnm-systemd-shared/sd-adapt-shared/dhcp-server-internal.h \
|
||||
src/libnm-systemd-shared/sd-adapt-shared/dirent-util.h \
|
||||
src/libnm-systemd-shared/sd-adapt-shared/errno-list.h \
|
||||
src/libnm-systemd-shared/sd-adapt-shared/filesystems.h \
|
||||
src/libnm-systemd-shared/sd-adapt-shared/glob-util.h \
|
||||
src/libnm-systemd-shared/sd-adapt-shared/gunicode.h \
|
||||
src/libnm-systemd-shared/sd-adapt-shared/hmac.h \
|
||||
src/libnm-systemd-shared/sd-adapt-shared/idn-util.h \
|
||||
src/libnm-systemd-shared/sd-adapt-shared/ioprio.h \
|
||||
src/libnm-systemd-shared/sd-adapt-shared/locale-util.h \
|
||||
|
@ -2138,6 +2140,7 @@ src_libnm_systemd_shared_libnm_systemd_shared_la_SOURCES = \
|
|||
src/libnm-systemd-shared/sd-adapt-shared/missing_timerfd.h \
|
||||
src/libnm-systemd-shared/sd-adapt-shared/mkdir.h \
|
||||
src/libnm-systemd-shared/sd-adapt-shared/namespace-util.h \
|
||||
src/libnm-systemd-shared/sd-adapt-shared/netif-util.h \
|
||||
src/libnm-systemd-shared/sd-adapt-shared/nm-sd-adapt-shared.h \
|
||||
src/libnm-systemd-shared/sd-adapt-shared/nulstr-util.h \
|
||||
src/libnm-systemd-shared/sd-adapt-shared/os-util.h \
|
||||
|
@ -2245,7 +2248,7 @@ src_libnm_systemd_shared_libnm_systemd_shared_la_SOURCES = \
|
|||
src/libnm-systemd-shared/src/fundamental/macro-fundamental.h \
|
||||
src/libnm-systemd-shared/src/fundamental/string-util-fundamental.c \
|
||||
src/libnm-systemd-shared/src/fundamental/string-util-fundamental.h \
|
||||
src/libnm-systemd-shared/src/fundamental/type.h \
|
||||
src/libnm-systemd-shared/src/fundamental/types-fundamental.h \
|
||||
src/libnm-systemd-shared/src/shared/dns-domain.c \
|
||||
src/libnm-systemd-shared/src/shared/dns-domain.h \
|
||||
src/libnm-systemd-shared/src/shared/log-link.h \
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
#include "unaligned.h"
|
||||
#include "util.h"
|
||||
|
||||
int arp_update_filter(int fd, const struct in_addr *a, const struct ether_addr *eth_mac) {
|
||||
int arp_update_filter(int fd, const struct in_addr *a, const struct ether_addr *mac) {
|
||||
struct sock_filter filter[] = {
|
||||
BPF_STMT(BPF_LD + BPF_W + BPF_LEN, 0), /* A <- packet length */
|
||||
BPF_JUMP(BPF_JMP + BPF_JGE + BPF_K, sizeof(struct ether_arp), 1, 0), /* packet >= arp packet ? */
|
||||
|
@ -38,30 +38,21 @@ int arp_update_filter(int fd, const struct in_addr *a, const struct ether_addr *
|
|||
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ARPOP_REPLY, 1, 0), /* protocol == reply ? */
|
||||
BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
|
||||
/* Sender Hardware Address must be different from our own */
|
||||
BPF_STMT(BPF_LD + BPF_IMM, unaligned_read_be32(ð_mac->ether_addr_octet[0])),/* A <- 4 bytes of client's MAC */
|
||||
BPF_STMT(BPF_MISC + BPF_TAX, 0), /* X <- A */
|
||||
BPF_STMT(BPF_LDX + BPF_IMM, unaligned_read_be32(&mac->ether_addr_octet[0])), /* X <- 4 bytes of client's MAC */
|
||||
BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(struct ether_arp, arp_sha)), /* A <- 4 bytes of SHA */
|
||||
BPF_STMT(BPF_ALU + BPF_XOR + BPF_X, 0), /* A xor X */
|
||||
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0, 0, 6), /* A == 0 ? */
|
||||
BPF_STMT(BPF_LD + BPF_IMM, unaligned_read_be16(ð_mac->ether_addr_octet[4])),/* A <- remainder of client's MAC */
|
||||
BPF_STMT(BPF_MISC + BPF_TAX, 0), /* X <- A */
|
||||
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_X, 0, 0, 4), /* A == X ? */
|
||||
BPF_STMT(BPF_LDX + BPF_IMM, unaligned_read_be16(&mac->ether_addr_octet[4])), /* X <- remainder of client's MAC */
|
||||
BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(struct ether_arp, arp_sha) + 4), /* A <- remainder of SHA */
|
||||
BPF_STMT(BPF_ALU + BPF_XOR + BPF_X, 0), /* A xor X */
|
||||
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0, 0, 1), /* A == 0 ? */
|
||||
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_X, 0, 0, 1), /* A == X ? */
|
||||
BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
|
||||
/* Sender Protocol Address or Target Protocol Address must be equal to the one we care about */
|
||||
BPF_STMT(BPF_LD + BPF_IMM, htobe32(a->s_addr)), /* A <- clients IP */
|
||||
BPF_STMT(BPF_MISC + BPF_TAX, 0), /* X <- A */
|
||||
BPF_STMT(BPF_LDX + BPF_IMM, htobe32(a->s_addr)), /* X <- clients IP */
|
||||
BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(struct ether_arp, arp_spa)), /* A <- SPA */
|
||||
BPF_STMT(BPF_ALU + BPF_XOR + BPF_X, 0), /* X xor A */
|
||||
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0, 0, 1), /* A == 0 ? */
|
||||
BPF_STMT(BPF_RET + BPF_K, 65535), /* return all */
|
||||
BPF_STMT(BPF_LD + BPF_IMM, htobe32(a->s_addr)), /* A <- clients IP */
|
||||
BPF_STMT(BPF_MISC + BPF_TAX, 0), /* X <- A */
|
||||
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_X, 0, 0, 1), /* A == X ? */
|
||||
BPF_STMT(BPF_RET + BPF_K, UINT32_MAX), /* accept */
|
||||
BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(struct ether_arp, arp_tpa)), /* A <- TPA */
|
||||
BPF_STMT(BPF_ALU + BPF_XOR + BPF_X, 0), /* X xor A */
|
||||
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0, 0, 1), /* A == 0 ? */
|
||||
BPF_STMT(BPF_RET + BPF_K, 65535), /* return all */
|
||||
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_X, 0, 0, 1), /* A == 0 ? */
|
||||
BPF_STMT(BPF_RET + BPF_K, UINT32_MAX), /* accept */
|
||||
BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
|
||||
};
|
||||
struct sock_fprog fprog = {
|
||||
|
@ -77,7 +68,7 @@ int arp_update_filter(int fd, const struct in_addr *a, const struct ether_addr *
|
|||
return 0;
|
||||
}
|
||||
|
||||
int arp_network_bind_raw_socket(int ifindex, const struct in_addr *a, const struct ether_addr *eth_mac) {
|
||||
int arp_network_bind_raw_socket(int ifindex, const struct in_addr *a, const struct ether_addr *mac) {
|
||||
union sockaddr_union link = {
|
||||
.ll.sll_family = AF_PACKET,
|
||||
.ll.sll_protocol = htobe16(ETH_P_ARP),
|
||||
|
@ -89,12 +80,13 @@ int arp_network_bind_raw_socket(int ifindex, const struct in_addr *a, const stru
|
|||
int r;
|
||||
|
||||
assert(ifindex > 0);
|
||||
assert(mac);
|
||||
|
||||
s = socket(AF_PACKET, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
|
||||
if (s < 0)
|
||||
return -errno;
|
||||
|
||||
r = arp_update_filter(s, a, eth_mac);
|
||||
r = arp_update_filter(s, a, mac);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
|
|
@ -11,8 +11,8 @@
|
|||
#include "socket-util.h"
|
||||
#include "sparse-endian.h"
|
||||
|
||||
int arp_update_filter(int fd, const struct in_addr *a, const struct ether_addr *eth_mac);
|
||||
int arp_network_bind_raw_socket(int ifindex, const struct in_addr *a, const struct ether_addr *eth_mac);
|
||||
int arp_update_filter(int fd, const struct in_addr *a, const struct ether_addr *mac);
|
||||
int arp_network_bind_raw_socket(int ifindex, const struct in_addr *a, const struct ether_addr *mac);
|
||||
|
||||
int arp_send_packet(
|
||||
int fd,
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
#include "dhcp-identifier.h"
|
||||
#include "dhcp6-protocol.h"
|
||||
#include "network-util.h"
|
||||
#include "netif-util.h"
|
||||
#include "siphash24.h"
|
||||
#include "sparse-endian.h"
|
||||
#include "stat-util.h"
|
||||
|
@ -200,7 +200,7 @@ int dhcp_identifier_set_iaid(
|
|||
/* device is under renaming */
|
||||
return -EBUSY;
|
||||
|
||||
name = net_get_name_persistent(device);
|
||||
name = net_get_persistent_name(device);
|
||||
}
|
||||
|
||||
if (name)
|
||||
|
@ -214,7 +214,7 @@ int dhcp_identifier_set_iaid(
|
|||
if (legacy_unstable_byteorder)
|
||||
/* for historical reasons (a bug), the bits were swapped and thus
|
||||
* the result was endianness dependent. Preserve that behavior. */
|
||||
id32 = __bswap_32(id32);
|
||||
id32 = bswap_32(id32);
|
||||
else
|
||||
/* the fixed behavior returns a stable byte order. Since LE is expected
|
||||
* to be more common, swap the bytes on LE to give the same as legacy
|
||||
|
|
|
@ -53,8 +53,8 @@ typedef int (*dhcp_option_callback_t)(uint8_t code, uint8_t len,
|
|||
int dhcp_option_parse(DHCPMessage *message, size_t len, dhcp_option_callback_t cb, void *userdata, char **error_message);
|
||||
|
||||
int dhcp_message_init(DHCPMessage *message, uint8_t op, uint32_t xid,
|
||||
uint8_t type, uint16_t arp_type, size_t optlen,
|
||||
size_t *optoffset);
|
||||
uint8_t type, uint16_t arp_type, uint8_t hlen, const uint8_t *chaddr,
|
||||
size_t optlen, size_t *optoffset);
|
||||
|
||||
uint16_t dhcp_packet_checksum(uint8_t *buf, size_t len);
|
||||
|
||||
|
|
|
@ -70,6 +70,12 @@ struct sd_dhcp_lease {
|
|||
|
||||
char *timezone;
|
||||
|
||||
uint8_t sixrd_ipv4masklen;
|
||||
uint8_t sixrd_prefixlen;
|
||||
struct in6_addr sixrd_prefix;
|
||||
struct in_addr *sixrd_br_addresses;
|
||||
size_t sixrd_n_br_addresses;
|
||||
|
||||
LIST_HEAD(struct sd_dhcp_raw_option, private_options);
|
||||
};
|
||||
|
||||
|
|
|
@ -60,24 +60,20 @@ static int _bind_raw_socket(int ifindex, union sockaddr_union *link,
|
|||
|
||||
/* We only support MAC address length to be either 0 or 6 (ETH_ALEN). Optionally
|
||||
* compare chaddr for ETH_ALEN bytes. */
|
||||
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETH_ALEN, 0, 12), /* A (the MAC address length) == ETH_ALEN ? */
|
||||
BPF_STMT(BPF_LD + BPF_IMM, unaligned_read_be32(ð_mac->ether_addr_octet[0])), /* A <- 4 bytes of client's MAC */
|
||||
BPF_STMT(BPF_MISC + BPF_TAX, 0), /* X <- A */
|
||||
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETH_ALEN, 0, 8), /* A (the MAC address length) == ETH_ALEN ? */
|
||||
BPF_STMT(BPF_LDX + BPF_IMM, unaligned_read_be32(ð_mac->ether_addr_octet[0])), /* X <- 4 bytes of client's MAC */
|
||||
BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(DHCPPacket, dhcp.chaddr)), /* A <- 4 bytes of MAC from dhcp.chaddr */
|
||||
BPF_STMT(BPF_ALU + BPF_XOR + BPF_X, 0), /* A xor X */
|
||||
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0, 1, 0), /* A == 0 ? */
|
||||
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_X, 0, 1, 0), /* A == X ? */
|
||||
BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
|
||||
BPF_STMT(BPF_LD + BPF_IMM, unaligned_read_be16(ð_mac->ether_addr_octet[4])), /* A <- remainder of client's MAC */
|
||||
BPF_STMT(BPF_MISC + BPF_TAX, 0), /* X <- A */
|
||||
BPF_STMT(BPF_LDX + BPF_IMM, unaligned_read_be16(ð_mac->ether_addr_octet[4])), /* X <- remainder of client's MAC */
|
||||
BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(DHCPPacket, dhcp.chaddr) + 4), /* A <- remainder of MAC from dhcp.chaddr */
|
||||
BPF_STMT(BPF_ALU + BPF_XOR + BPF_X, 0), /* A xor X */
|
||||
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0, 1, 0), /* A == 0 ? */
|
||||
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_X, 0, 1, 0), /* A == X ? */
|
||||
BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
|
||||
|
||||
BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(DHCPPacket, dhcp.magic)), /* A <- DHCP magic cookie */
|
||||
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, DHCP_MAGIC_COOKIE, 1, 0), /* cookie == DHCP magic cookie ? */
|
||||
BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
|
||||
BPF_STMT(BPF_RET + BPF_K, 65535), /* return all */
|
||||
BPF_STMT(BPF_RET + BPF_K, UINT32_MAX), /* accept */
|
||||
};
|
||||
struct sock_fprog fprog = {
|
||||
.len = ELEMENTSOF(filter),
|
||||
|
@ -117,10 +113,17 @@ static int _bind_raw_socket(int ifindex, union sockaddr_union *link,
|
|||
return TAKE_FD(s);
|
||||
}
|
||||
|
||||
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,
|
||||
uint16_t arp_type, uint16_t port) {
|
||||
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,
|
||||
uint16_t arp_type,
|
||||
uint16_t port) {
|
||||
|
||||
static const uint8_t eth_bcast[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
|
||||
/* Default broadcast address for IPoIB */
|
||||
static const uint8_t ib_bcast[] = {
|
||||
|
@ -174,7 +177,6 @@ int dhcp_network_bind_udp_socket(int ifindex, be32_t address, uint16_t port, int
|
|||
r = setsockopt_int(s, IPPROTO_IP, IP_TOS, ip_service_type);
|
||||
else
|
||||
r = setsockopt_int(s, IPPROTO_IP, IP_TOS, IPTOS_CLASS_CS6);
|
||||
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
@ -206,43 +208,49 @@ int dhcp_network_bind_udp_socket(int ifindex, be32_t address, uint16_t port, int
|
|||
return r;
|
||||
}
|
||||
|
||||
r = bind(s, &src.sa, sizeof(src.in));
|
||||
if (r < 0)
|
||||
if (bind(s, &src.sa, sizeof(src.in)) < 0)
|
||||
return -errno;
|
||||
|
||||
return TAKE_FD(s);
|
||||
}
|
||||
|
||||
int dhcp_network_send_raw_socket(int s, const union sockaddr_union *link,
|
||||
const void *packet, size_t len) {
|
||||
int r;
|
||||
int dhcp_network_send_raw_socket(
|
||||
int s,
|
||||
const union sockaddr_union *link,
|
||||
const void *packet,
|
||||
size_t len) {
|
||||
|
||||
/* Do not add assert(s >= 0) here, as this is called in fuzz-dhcp-server, and in that case this
|
||||
* function should fail with negative errno. */
|
||||
|
||||
assert(link);
|
||||
assert(packet);
|
||||
assert(len);
|
||||
assert(len > 0);
|
||||
|
||||
r = sendto(s, packet, len, 0, &link->sa, SOCKADDR_LL_LEN(link->ll));
|
||||
if (r < 0)
|
||||
if (sendto(s, packet, len, 0, &link->sa, SOCKADDR_LL_LEN(link->ll)) < 0)
|
||||
return -errno;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dhcp_network_send_udp_socket(int s, be32_t address, uint16_t port,
|
||||
const void *packet, size_t len) {
|
||||
int dhcp_network_send_udp_socket(
|
||||
int s,
|
||||
be32_t address,
|
||||
uint16_t port,
|
||||
const void *packet,
|
||||
size_t len) {
|
||||
|
||||
union sockaddr_union dest = {
|
||||
.in.sin_family = AF_INET,
|
||||
.in.sin_port = htobe16(port),
|
||||
.in.sin_addr.s_addr = address,
|
||||
};
|
||||
int r;
|
||||
|
||||
assert(s >= 0);
|
||||
assert(packet);
|
||||
assert(len);
|
||||
assert(len > 0);
|
||||
|
||||
r = sendto(s, packet, len, 0, &dest.sa, sizeof(dest.in));
|
||||
if (r < 0)
|
||||
if (sendto(s, packet, len, 0, &dest.sa, sizeof(dest.in)) < 0)
|
||||
return -errno;
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -12,21 +12,44 @@
|
|||
|
||||
#include "dhcp-internal.h"
|
||||
#include "dhcp-protocol.h"
|
||||
#include "memory-util.h"
|
||||
|
||||
#define DHCP_CLIENT_MIN_OPTIONS_SIZE 312
|
||||
|
||||
int dhcp_message_init(DHCPMessage *message, uint8_t op, uint32_t xid,
|
||||
uint8_t type, uint16_t arp_type, size_t optlen,
|
||||
int dhcp_message_init(
|
||||
DHCPMessage *message,
|
||||
uint8_t op,
|
||||
uint32_t xid,
|
||||
uint8_t type,
|
||||
uint16_t arp_type,
|
||||
uint8_t hlen,
|
||||
const uint8_t *chaddr,
|
||||
size_t optlen,
|
||||
size_t *optoffset) {
|
||||
|
||||
size_t offset = 0;
|
||||
int r;
|
||||
|
||||
assert(IN_SET(op, BOOTREQUEST, BOOTREPLY));
|
||||
assert(IN_SET(arp_type, ARPHRD_ETHER, ARPHRD_INFINIBAND));
|
||||
assert(chaddr || hlen == 0);
|
||||
|
||||
message->op = op;
|
||||
message->htype = arp_type;
|
||||
message->hlen = (arp_type == ARPHRD_ETHER) ? ETHER_ADDR_LEN : 0;
|
||||
|
||||
/* RFC2131 section 4.1.1:
|
||||
The client MUST include its hardware address in the ’chaddr’ field, if
|
||||
necessary for delivery of DHCP reply messages.
|
||||
|
||||
RFC 4390 section 2.1:
|
||||
A DHCP client, when working over an IPoIB interface, MUST follow the
|
||||
following rules:
|
||||
"htype" (hardware address type) MUST be 32 [ARPPARAM].
|
||||
"hlen" (hardware address length) MUST be 0.
|
||||
"chaddr" (client hardware address) field MUST be zeroed.
|
||||
*/
|
||||
message->hlen = (arp_type == ARPHRD_INFINIBAND) ? 0 : hlen;
|
||||
memcpy_safe(message->chaddr, chaddr, message->hlen);
|
||||
|
||||
message->xid = htobe32(xid);
|
||||
message->magic = htobe32(DHCP_MAGIC_COOKIE);
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "sd-event.h"
|
||||
#include "sd-dhcp6-client.h"
|
||||
|
||||
#include "dhcp6-protocol.h"
|
||||
#include "hashmap.h"
|
||||
#include "list.h"
|
||||
#include "macro.h"
|
||||
|
@ -93,6 +94,7 @@ typedef struct DHCP6IA {
|
|||
|
||||
typedef struct sd_dhcp6_client sd_dhcp6_client;
|
||||
|
||||
bool dhcp6_option_can_request(uint16_t option);
|
||||
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);
|
||||
|
@ -129,6 +131,12 @@ int dhcp6_network_bind_udp_socket(int ifindex, struct in6_addr *address);
|
|||
int dhcp6_network_send_udp_socket(int s, struct in6_addr *address,
|
||||
const void *packet, size_t len);
|
||||
|
||||
int client_parse_message(
|
||||
sd_dhcp6_client *client,
|
||||
DHCP6Message *message,
|
||||
size_t len,
|
||||
sd_dhcp6_lease *lease);
|
||||
|
||||
const char *dhcp6_message_type_to_string(int s) _const_;
|
||||
int dhcp6_message_type_from_string(const char *s) _pure_;
|
||||
const char *dhcp6_message_status_to_string(int s) _const_;
|
||||
|
|
|
@ -14,10 +14,14 @@
|
|||
struct sd_dhcp6_lease {
|
||||
unsigned n_ref;
|
||||
|
||||
uint8_t *clientid;
|
||||
size_t clientid_len;
|
||||
uint8_t *serverid;
|
||||
size_t serverid_len;
|
||||
uint8_t preference;
|
||||
bool rapid_commit;
|
||||
triple_timestamp timestamp;
|
||||
struct in6_addr server_address;
|
||||
|
||||
DHCP6IA ia;
|
||||
DHCP6IA pd;
|
||||
|
@ -39,17 +43,15 @@ struct sd_dhcp6_lease {
|
|||
int dhcp6_lease_ia_rebind_expire(const DHCP6IA *ia, uint32_t *expire);
|
||||
DHCP6IA *dhcp6_lease_free_ia(DHCP6IA *ia);
|
||||
|
||||
int dhcp6_lease_set_serverid(sd_dhcp6_lease *lease, const uint8_t *id,
|
||||
size_t len);
|
||||
int dhcp6_lease_get_serverid(sd_dhcp6_lease *lease, uint8_t **id, size_t *len);
|
||||
int dhcp6_lease_set_clientid(sd_dhcp6_lease *lease, const uint8_t *id, size_t len);
|
||||
int dhcp6_lease_get_clientid(sd_dhcp6_lease *lease, uint8_t **ret_id, size_t *ret_len);
|
||||
int dhcp6_lease_set_serverid(sd_dhcp6_lease *lease, const uint8_t *id, size_t len);
|
||||
int dhcp6_lease_get_serverid(sd_dhcp6_lease *lease, uint8_t **ret_id, size_t *ret_len);
|
||||
int dhcp6_lease_set_preference(sd_dhcp6_lease *lease, uint8_t preference);
|
||||
int dhcp6_lease_get_preference(sd_dhcp6_lease *lease, uint8_t *preference);
|
||||
int dhcp6_lease_set_rapid_commit(sd_dhcp6_lease *lease);
|
||||
int dhcp6_lease_get_rapid_commit(sd_dhcp6_lease *lease, bool *rapid_commit);
|
||||
|
||||
int dhcp6_lease_get_iaid(sd_dhcp6_lease *lease, be32_t *iaid);
|
||||
int dhcp6_lease_get_pd_iaid(sd_dhcp6_lease *lease, be32_t *iaid);
|
||||
|
||||
int dhcp6_lease_add_dns(sd_dhcp6_lease *lease, const uint8_t *optval, size_t optlen);
|
||||
int dhcp6_lease_add_domains(sd_dhcp6_lease *lease, const uint8_t *optval, size_t optlen);
|
||||
int dhcp6_lease_add_ntp(sd_dhcp6_lease *lease, const uint8_t *optval, size_t optlen);
|
||||
|
|
|
@ -49,6 +49,10 @@ int dhcp6_network_bind_udp_socket(int ifindex, struct in6_addr *local_address) {
|
|||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = setsockopt_int(s, SOL_SOCKET, SO_TIMESTAMP, true);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = bind(s, &src.sa, sizeof(src.in6));
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
|
|
|
@ -26,6 +26,193 @@
|
|||
#define DHCP6_OPTION_IA_PD_LEN (sizeof(struct ia_pd))
|
||||
#define DHCP6_OPTION_IA_TA_LEN (sizeof(struct ia_ta))
|
||||
|
||||
bool dhcp6_option_can_request(uint16_t option) {
|
||||
/* See Client ORO field in
|
||||
* https://www.iana.org/assignments/dhcpv6-parameters/dhcpv6-parameters.xhtml#dhcpv6-parameters-2 */
|
||||
|
||||
switch (option) {
|
||||
case SD_DHCP6_OPTION_CLIENTID:
|
||||
case SD_DHCP6_OPTION_SERVERID:
|
||||
case SD_DHCP6_OPTION_IA_NA:
|
||||
case SD_DHCP6_OPTION_IA_TA:
|
||||
case SD_DHCP6_OPTION_IAADDR:
|
||||
case SD_DHCP6_OPTION_ORO:
|
||||
case SD_DHCP6_OPTION_PREFERENCE:
|
||||
case SD_DHCP6_OPTION_ELAPSED_TIME:
|
||||
case SD_DHCP6_OPTION_RELAY_MSG:
|
||||
case SD_DHCP6_OPTION_AUTH:
|
||||
case SD_DHCP6_OPTION_UNICAST:
|
||||
case SD_DHCP6_OPTION_STATUS_CODE:
|
||||
case SD_DHCP6_OPTION_RAPID_COMMIT:
|
||||
case SD_DHCP6_OPTION_USER_CLASS:
|
||||
case SD_DHCP6_OPTION_VENDOR_CLASS:
|
||||
return false;
|
||||
case SD_DHCP6_OPTION_VENDOR_OPTS:
|
||||
return true;
|
||||
case SD_DHCP6_OPTION_INTERFACE_ID:
|
||||
case SD_DHCP6_OPTION_RECONF_MSG:
|
||||
case SD_DHCP6_OPTION_RECONF_ACCEPT:
|
||||
return false;
|
||||
case SD_DHCP6_OPTION_SIP_SERVER_DOMAIN_NAME:
|
||||
case SD_DHCP6_OPTION_SIP_SERVER_ADDRESS:
|
||||
case SD_DHCP6_OPTION_DNS_SERVERS:
|
||||
case SD_DHCP6_OPTION_DOMAIN_LIST:
|
||||
return true;
|
||||
case SD_DHCP6_OPTION_IA_PD:
|
||||
case SD_DHCP6_OPTION_IA_PD_PREFIX:
|
||||
return false;
|
||||
case SD_DHCP6_OPTION_NIS_SERVERS:
|
||||
case SD_DHCP6_OPTION_NISP_SERVERS:
|
||||
case SD_DHCP6_OPTION_NIS_DOMAIN_NAME:
|
||||
case SD_DHCP6_OPTION_NISP_DOMAIN_NAME:
|
||||
case SD_DHCP6_OPTION_SNTP_SERVERS:
|
||||
case SD_DHCP6_OPTION_INFORMATION_REFRESH_TIME:
|
||||
case SD_DHCP6_OPTION_BCMCS_SERVER_D:
|
||||
case SD_DHCP6_OPTION_BCMCS_SERVER_A:
|
||||
case SD_DHCP6_OPTION_GEOCONF_CIVIC:
|
||||
return true;
|
||||
case SD_DHCP6_OPTION_REMOTE_ID:
|
||||
case SD_DHCP6_OPTION_SUBSCRIBER_ID:
|
||||
return false;
|
||||
case SD_DHCP6_OPTION_CLIENT_FQDN:
|
||||
case SD_DHCP6_OPTION_PANA_AGENT:
|
||||
case SD_DHCP6_OPTION_NEW_POSIX_TIMEZONE:
|
||||
case SD_DHCP6_OPTION_NEW_TZDB_TIMEZONE:
|
||||
return true;
|
||||
case SD_DHCP6_OPTION_ERO:
|
||||
case SD_DHCP6_OPTION_LQ_QUERY:
|
||||
case SD_DHCP6_OPTION_CLIENT_DATA:
|
||||
case SD_DHCP6_OPTION_CLT_TIME:
|
||||
case SD_DHCP6_OPTION_LQ_RELAY_DATA:
|
||||
case SD_DHCP6_OPTION_LQ_CLIENT_LINK:
|
||||
return false;
|
||||
case SD_DHCP6_OPTION_MIP6_HNIDF:
|
||||
case SD_DHCP6_OPTION_MIP6_VDINF:
|
||||
case SD_DHCP6_OPTION_V6_LOST:
|
||||
case SD_DHCP6_OPTION_CAPWAP_AC_V6:
|
||||
return true;
|
||||
case SD_DHCP6_OPTION_RELAY_ID:
|
||||
return false;
|
||||
case SD_DHCP6_OPTION_IPV6_ADDRESS_MOS:
|
||||
case SD_DHCP6_OPTION_IPV6_FQDN_MOS:
|
||||
case SD_DHCP6_OPTION_NTP_SERVER:
|
||||
case SD_DHCP6_OPTION_V6_ACCESS_DOMAIN:
|
||||
case SD_DHCP6_OPTION_SIP_UA_CS_LIST:
|
||||
case SD_DHCP6_OPTION_BOOTFILE_URL:
|
||||
case SD_DHCP6_OPTION_BOOTFILE_PARAM:
|
||||
return true;
|
||||
case SD_DHCP6_OPTION_CLIENT_ARCH_TYPE:
|
||||
return false;
|
||||
case SD_DHCP6_OPTION_NII:
|
||||
case SD_DHCP6_OPTION_GEOLOCATION:
|
||||
case SD_DHCP6_OPTION_AFTR_NAME:
|
||||
case SD_DHCP6_OPTION_ERP_LOCAL_DOMAIN_NAME:
|
||||
return true;
|
||||
case SD_DHCP6_OPTION_RSOO:
|
||||
return false;
|
||||
case SD_DHCP6_OPTION_PD_EXCLUDE:
|
||||
return true;
|
||||
case SD_DHCP6_OPTION_VSS:
|
||||
return false;
|
||||
case SD_DHCP6_OPTION_MIP6_IDINF:
|
||||
case SD_DHCP6_OPTION_MIP6_UDINF:
|
||||
case SD_DHCP6_OPTION_MIP6_HNP:
|
||||
case SD_DHCP6_OPTION_MIP6_HAA:
|
||||
case SD_DHCP6_OPTION_MIP6_HAF:
|
||||
case SD_DHCP6_OPTION_RDNSS_SELECTION:
|
||||
case SD_DHCP6_OPTION_KRB_PRINCIPAL_NAME:
|
||||
case SD_DHCP6_OPTION_KRB_REALM_NAME:
|
||||
case SD_DHCP6_OPTION_KRB_DEFAULT_REALM_NAME:
|
||||
case SD_DHCP6_OPTION_KRB_KDC:
|
||||
return true;
|
||||
case SD_DHCP6_OPTION_CLIENT_LINKLAYER_ADDR:
|
||||
case SD_DHCP6_OPTION_LINK_ADDRESS:
|
||||
case SD_DHCP6_OPTION_RADIUS:
|
||||
return false;
|
||||
case SD_DHCP6_OPTION_SOL_MAX_RT:
|
||||
case SD_DHCP6_OPTION_INF_MAX_RT:
|
||||
case SD_DHCP6_OPTION_ADDRSEL:
|
||||
case SD_DHCP6_OPTION_ADDRSEL_TABLE:
|
||||
case SD_DHCP6_OPTION_V6_PCP_SERVER:
|
||||
return true;
|
||||
case SD_DHCP6_OPTION_DHCPV4_MSG:
|
||||
return false;
|
||||
case SD_DHCP6_OPTION_DHCP4_O_DHCP6_SERVER:
|
||||
return true;
|
||||
case SD_DHCP6_OPTION_S46_RULE:
|
||||
return false;
|
||||
case SD_DHCP6_OPTION_S46_BR:
|
||||
return true;
|
||||
case SD_DHCP6_OPTION_S46_DMR:
|
||||
case SD_DHCP6_OPTION_S46_V4V6BIND:
|
||||
case SD_DHCP6_OPTION_S46_PORTPARAMS:
|
||||
return false;
|
||||
case SD_DHCP6_OPTION_S46_CONT_MAPE:
|
||||
case SD_DHCP6_OPTION_S46_CONT_MAPT:
|
||||
case SD_DHCP6_OPTION_S46_CONT_LW:
|
||||
case SD_DHCP6_OPTION_4RD:
|
||||
case SD_DHCP6_OPTION_4RD_MAP_RULE:
|
||||
case SD_DHCP6_OPTION_4RD_NON_MAP_RULE:
|
||||
return true;
|
||||
case SD_DHCP6_OPTION_LQ_BASE_TIME:
|
||||
case SD_DHCP6_OPTION_LQ_START_TIME:
|
||||
case SD_DHCP6_OPTION_LQ_END_TIME:
|
||||
return false;
|
||||
case SD_DHCP6_OPTION_CAPTIVE_PORTAL:
|
||||
case SD_DHCP6_OPTION_MPL_PARAMETERS:
|
||||
return true;
|
||||
case SD_DHCP6_OPTION_ANI_ATT:
|
||||
case SD_DHCP6_OPTION_ANI_NETWORK_NAME:
|
||||
case SD_DHCP6_OPTION_ANI_AP_NAME:
|
||||
case SD_DHCP6_OPTION_ANI_AP_BSSID:
|
||||
case SD_DHCP6_OPTION_ANI_OPERATOR_ID:
|
||||
case SD_DHCP6_OPTION_ANI_OPERATOR_REALM:
|
||||
return false;
|
||||
case SD_DHCP6_OPTION_S46_PRIORITY:
|
||||
return true;
|
||||
case SD_DHCP6_OPTION_MUD_URL_V6:
|
||||
return false;
|
||||
case SD_DHCP6_OPTION_V6_PREFIX64:
|
||||
return true;
|
||||
case SD_DHCP6_OPTION_F_BINDING_STATUS:
|
||||
case SD_DHCP6_OPTION_F_CONNECT_FLAGS:
|
||||
case SD_DHCP6_OPTION_F_DNS_REMOVAL_INFO:
|
||||
case SD_DHCP6_OPTION_F_DNS_HOST_NAME:
|
||||
case SD_DHCP6_OPTION_F_DNS_ZONE_NAME:
|
||||
case SD_DHCP6_OPTION_F_DNS_FLAGS:
|
||||
case SD_DHCP6_OPTION_F_EXPIRATION_TIME:
|
||||
case SD_DHCP6_OPTION_F_MAX_UNACKED_BNDUPD:
|
||||
case SD_DHCP6_OPTION_F_MCLT:
|
||||
case SD_DHCP6_OPTION_F_PARTNER_LIFETIME:
|
||||
case SD_DHCP6_OPTION_F_PARTNER_LIFETIME_SENT:
|
||||
case SD_DHCP6_OPTION_F_PARTNER_DOWN_TIME:
|
||||
case SD_DHCP6_OPTION_F_PARTNER_RAW_CLT_TIME:
|
||||
case SD_DHCP6_OPTION_F_PROTOCOL_VERSION:
|
||||
case SD_DHCP6_OPTION_F_KEEPALIVE_TIME:
|
||||
case SD_DHCP6_OPTION_F_RECONFIGURE_DATA:
|
||||
case SD_DHCP6_OPTION_F_RELATIONSHIP_NAME:
|
||||
case SD_DHCP6_OPTION_F_SERVER_FLAGS:
|
||||
case SD_DHCP6_OPTION_F_SERVER_STATE:
|
||||
case SD_DHCP6_OPTION_F_START_TIME_OF_STATE:
|
||||
case SD_DHCP6_OPTION_F_STATE_EXPIRATION_TIME:
|
||||
case SD_DHCP6_OPTION_RELAY_PORT:
|
||||
return false;
|
||||
case SD_DHCP6_OPTION_V6_SZTP_REDIRECT:
|
||||
case SD_DHCP6_OPTION_S46_BIND_IPV6_PREFIX:
|
||||
return true;
|
||||
case SD_DHCP6_OPTION_IA_LL:
|
||||
case SD_DHCP6_OPTION_LLADDR:
|
||||
case SD_DHCP6_OPTION_SLAP_QUAD:
|
||||
return false;
|
||||
case SD_DHCP6_OPTION_V6_DOTS_RI:
|
||||
case SD_DHCP6_OPTION_V6_DOTS_ADDRESS:
|
||||
case SD_DHCP6_OPTION_IPV6_ADDRESS_ANDSF:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static int option_append_hdr(uint8_t **buf, size_t *buflen, uint16_t optcode, size_t optlen) {
|
||||
DHCP6Option *option;
|
||||
|
||||
|
@ -275,7 +462,7 @@ int dhcp6_option_append_fqdn(uint8_t **buf, size_t *buflen, const char *fqdn) {
|
|||
if (dns_name_is_single_label(fqdn))
|
||||
r--;
|
||||
|
||||
r = dhcp6_option_append(buf, buflen, SD_DHCP6_OPTION_FQDN, 1 + r, buffer);
|
||||
r = dhcp6_option_append(buf, buflen, SD_DHCP6_OPTION_CLIENT_FQDN, 1 + r, buffer);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
Copyright © 2014 Intel Corporation. All rights reserved.
|
||||
***/
|
||||
|
||||
#include <errno.h>
|
||||
#include <netinet/ip6.h>
|
||||
#include <netinet/udp.h>
|
||||
|
||||
|
@ -36,57 +37,83 @@ enum {
|
|||
DHCP6_PORT_CLIENT = 546,
|
||||
};
|
||||
|
||||
#define DHCP6_INF_TIMEOUT 1 * USEC_PER_SEC
|
||||
#define DHCP6_INF_MAX_RT 120 * USEC_PER_SEC
|
||||
#define DHCP6_SOL_MAX_DELAY 1 * USEC_PER_SEC
|
||||
#define DHCP6_SOL_TIMEOUT 1 * USEC_PER_SEC
|
||||
#define DHCP6_SOL_MAX_RT 120 * USEC_PER_SEC
|
||||
#define DHCP6_REQ_TIMEOUT 1 * USEC_PER_SEC
|
||||
#define DHCP6_REQ_MAX_RT 120 * USEC_PER_SEC
|
||||
#define DHCP6_INF_TIMEOUT (1 * USEC_PER_SEC)
|
||||
#define DHCP6_INF_MAX_RT (120 * USEC_PER_SEC)
|
||||
#define DHCP6_SOL_MAX_DELAY (1 * USEC_PER_SEC)
|
||||
#define DHCP6_SOL_TIMEOUT (1 * USEC_PER_SEC)
|
||||
#define DHCP6_SOL_MAX_RT (120 * USEC_PER_SEC)
|
||||
#define DHCP6_REQ_TIMEOUT (1 * USEC_PER_SEC)
|
||||
#define DHCP6_REQ_MAX_RT (120 * USEC_PER_SEC)
|
||||
#define DHCP6_REQ_MAX_RC 10
|
||||
#define DHCP6_REN_TIMEOUT 10 * USEC_PER_SEC
|
||||
#define DHCP6_REN_MAX_RT 600 * USEC_PER_SEC
|
||||
#define DHCP6_REB_TIMEOUT 10 * USEC_PER_SEC
|
||||
#define DHCP6_REB_MAX_RT 600 * USEC_PER_SEC
|
||||
#define DHCP6_REN_TIMEOUT (10 * USEC_PER_SEC)
|
||||
#define DHCP6_REN_MAX_RT (600 * USEC_PER_SEC)
|
||||
#define DHCP6_REB_TIMEOUT (10 * USEC_PER_SEC)
|
||||
#define DHCP6_REB_MAX_RT (600 * USEC_PER_SEC)
|
||||
|
||||
enum DHCP6State {
|
||||
DHCP6_STATE_STOPPED = 0,
|
||||
DHCP6_STATE_INFORMATION_REQUEST = 1,
|
||||
DHCP6_STATE_SOLICITATION = 2,
|
||||
DHCP6_STATE_REQUEST = 3,
|
||||
DHCP6_STATE_BOUND = 4,
|
||||
DHCP6_STATE_RENEW = 5,
|
||||
DHCP6_STATE_REBIND = 6,
|
||||
};
|
||||
typedef enum DHCP6State {
|
||||
DHCP6_STATE_STOPPED,
|
||||
DHCP6_STATE_INFORMATION_REQUEST,
|
||||
DHCP6_STATE_SOLICITATION,
|
||||
DHCP6_STATE_REQUEST,
|
||||
DHCP6_STATE_BOUND,
|
||||
DHCP6_STATE_RENEW,
|
||||
DHCP6_STATE_REBIND,
|
||||
_DHCP6_STATE_MAX,
|
||||
_DHCP6_STATE_INVALID = -EINVAL,
|
||||
} DHCP6State;
|
||||
|
||||
enum {
|
||||
DHCP6_SOLICIT = 1,
|
||||
DHCP6_ADVERTISE = 2,
|
||||
DHCP6_REQUEST = 3,
|
||||
DHCP6_CONFIRM = 4,
|
||||
DHCP6_RENEW = 5,
|
||||
DHCP6_REBIND = 6,
|
||||
DHCP6_REPLY = 7,
|
||||
DHCP6_RELEASE = 8,
|
||||
DHCP6_DECLINE = 9,
|
||||
DHCP6_RECONFIGURE = 10,
|
||||
DHCP6_INFORMATION_REQUEST = 11,
|
||||
DHCP6_RELAY_FORW = 12,
|
||||
DHCP6_RELAY_REPL = 13,
|
||||
_DHCP6_MESSAGE_MAX = 14,
|
||||
};
|
||||
/* https://www.iana.org/assignments/dhcpv6-parameters/dhcpv6-parameters.xhtml#dhcpv6-parameters-1 */
|
||||
typedef enum DHCP6MessageType {
|
||||
DHCP6_MESSAGE_SOLICIT = 1, /* RFC 8415 */
|
||||
DHCP6_MESSAGE_ADVERTISE = 2, /* RFC 8415 */
|
||||
DHCP6_MESSAGE_REQUEST = 3, /* RFC 8415 */
|
||||
DHCP6_MESSAGE_CONFIRM = 4, /* RFC 8415 */
|
||||
DHCP6_MESSAGE_RENEW = 5, /* RFC 8415 */
|
||||
DHCP6_MESSAGE_REBIND = 6, /* RFC 8415 */
|
||||
DHCP6_MESSAGE_REPLY = 7, /* RFC 8415 */
|
||||
DHCP6_MESSAGE_RELEASE = 8, /* RFC 8415 */
|
||||
DHCP6_MESSAGE_DECLINE = 9, /* RFC 8415 */
|
||||
DHCP6_MESSAGE_RECONFIGURE = 10, /* RFC 8415 */
|
||||
DHCP6_MESSAGE_INFORMATION_REQUEST = 11, /* RFC 8415 */
|
||||
DHCP6_MESSAGE_RELAY_FORWARD = 12, /* RFC 8415 */
|
||||
DHCP6_MESSAGE_RELAY_REPLY = 13, /* RFC 8415 */
|
||||
DHCP6_MESSAGE_LEASE_QUERY = 14, /* RFC 5007 */
|
||||
DHCP6_MESSAGE_LEASE_QUERY_REPLY = 15, /* RFC 5007 */
|
||||
DHCP6_MESSAGE_LEASE_QUERY_DONE = 16, /* RFC 5460 */
|
||||
DHCP6_MESSAGE_LEASE_QUERY_DATA = 17, /* RFC 5460 */
|
||||
DHCP6_MESSAGE_RECONFIGURE_REQUEST = 18, /* RFC 6977 */
|
||||
DHCP6_MESSAGE_RECONFIGURE_REPLY = 19, /* RFC 6977 */
|
||||
DHCP6_MESSAGE_DHCPV4_QUERY = 20, /* RFC 7341 */
|
||||
DHCP6_MESSAGE_DHCPV4_RESPONSE = 21, /* RFC 7341 */
|
||||
DHCP6_MESSAGE_ACTIVE_LEASE_QUERY = 22, /* RFC 7653 */
|
||||
DHCP6_MESSAGE_START_TLS = 23, /* RFC 7653 */
|
||||
DHCP6_MESSAGE_BINDING_UPDATE = 24, /* RFC 8156 */
|
||||
DHCP6_MESSAGE_BINDING_REPLY = 25, /* RFC 8156 */
|
||||
DHCP6_MESSAGE_POOL_REQUEST = 26, /* RFC 8156 */
|
||||
DHCP6_MESSAGE_POOL_RESPONSE = 27, /* RFC 8156 */
|
||||
DHCP6_MESSAGE_UPDATE_REQUEST = 28, /* RFC 8156 */
|
||||
DHCP6_MESSAGE_UPDATE_REQUEST_ALL = 29, /* RFC 8156 */
|
||||
DHCP6_MESSAGE_UPDATE_DONE = 30, /* RFC 8156 */
|
||||
DHCP6_MESSAGE_CONNECT = 31, /* RFC 8156 */
|
||||
DHCP6_MESSAGE_CONNECT_REPLY = 32, /* RFC 8156 */
|
||||
DHCP6_MESSAGE_DISCONNECT = 33, /* RFC 8156 */
|
||||
DHCP6_MESSAGE_STATE = 34, /* RFC 8156 */
|
||||
DHCP6_MESSAGE_CONTACT = 35, /* RFC 8156 */
|
||||
_DHCP6_MESSAGE_TYPE_MAX,
|
||||
_DHCP6_MESSAGE_TYPE_INVALID = -EINVAL,
|
||||
} DHCP6MessageType;
|
||||
|
||||
enum {
|
||||
typedef enum DHCP6NTPSubOption {
|
||||
DHCP6_NTP_SUBOPTION_SRV_ADDR = 1,
|
||||
DHCP6_NTP_SUBOPTION_MC_ADDR = 2,
|
||||
DHCP6_NTP_SUBOPTION_SRV_FQDN = 3,
|
||||
};
|
||||
} DHCP6NTPSubOption;
|
||||
|
||||
/*
|
||||
* RFC 8415, RFC 5007 and RFC 7653 status codes:
|
||||
* https://www.iana.org/assignments/dhcpv6-parameters/dhcpv6-parameters.xhtml#dhcpv6-parameters-5
|
||||
*/
|
||||
enum {
|
||||
typedef enum DHCP6Status {
|
||||
DHCP6_STATUS_SUCCESS = 0,
|
||||
DHCP6_STATUS_UNSPEC_FAIL = 1,
|
||||
DHCP6_STATUS_NO_ADDRS_AVAIL = 2,
|
||||
|
@ -110,11 +137,12 @@ enum {
|
|||
DHCP6_STATUS_SERVER_SHUTTING_DOWN = 20,
|
||||
DHCP6_STATUS_DNS_UPDATE_NOT_SUPPORTED = 21,
|
||||
DHCP6_STATUS_EXCESSIVE_TIME_SKEW = 22,
|
||||
_DHCP6_STATUS_MAX = 23,
|
||||
};
|
||||
_DHCP6_STATUS_MAX,
|
||||
_DHCP6_STATUS_INVALID = -EINVAL,
|
||||
} DHCP6Status;
|
||||
|
||||
enum {
|
||||
DHCP6_FQDN_FLAG_S = (1 << 0),
|
||||
DHCP6_FQDN_FLAG_O = (1 << 1),
|
||||
DHCP6_FQDN_FLAG_N = (1 << 2),
|
||||
};
|
||||
typedef enum DHCP6FQDNFlag {
|
||||
DHCP6_FQDN_FLAG_S = 1 << 0,
|
||||
DHCP6_FQDN_FLAG_O = 1 << 1,
|
||||
DHCP6_FQDN_FLAG_N = 1 << 2,
|
||||
} DHCP6FQDNFlag;
|
||||
|
|
|
@ -47,7 +47,7 @@ int lldp_neighbor_prioq_compare_func(const void *a, const void *b) {
|
|||
return CMP(x->until, y->until);
|
||||
}
|
||||
|
||||
_public_ sd_lldp_neighbor *sd_lldp_neighbor_ref(sd_lldp_neighbor *n) {
|
||||
sd_lldp_neighbor *sd_lldp_neighbor_ref(sd_lldp_neighbor *n) {
|
||||
if (!n)
|
||||
return NULL;
|
||||
|
||||
|
@ -72,7 +72,7 @@ static sd_lldp_neighbor *lldp_neighbor_free(sd_lldp_neighbor *n) {
|
|||
return mfree(n);
|
||||
}
|
||||
|
||||
_public_ sd_lldp_neighbor *sd_lldp_neighbor_unref(sd_lldp_neighbor *n) {
|
||||
sd_lldp_neighbor *sd_lldp_neighbor_unref(sd_lldp_neighbor *n) {
|
||||
|
||||
/* Drops one reference from the neighbor. Note that the object is not freed unless it is already unlinked from
|
||||
* the sd_lldp object. */
|
||||
|
@ -360,7 +360,7 @@ bool lldp_neighbor_equal(const sd_lldp_neighbor *a, const sd_lldp_neighbor *b) {
|
|||
return memcmp(LLDP_NEIGHBOR_RAW(a), LLDP_NEIGHBOR_RAW(b), a->raw_size) == 0;
|
||||
}
|
||||
|
||||
_public_ int sd_lldp_neighbor_get_source_address(sd_lldp_neighbor *n, struct ether_addr* address) {
|
||||
int sd_lldp_neighbor_get_source_address(sd_lldp_neighbor *n, struct ether_addr* address) {
|
||||
assert_return(n, -EINVAL);
|
||||
assert_return(address, -EINVAL);
|
||||
|
||||
|
@ -368,7 +368,7 @@ _public_ int sd_lldp_neighbor_get_source_address(sd_lldp_neighbor *n, struct eth
|
|||
return 0;
|
||||
}
|
||||
|
||||
_public_ int sd_lldp_neighbor_get_destination_address(sd_lldp_neighbor *n, struct ether_addr* address) {
|
||||
int sd_lldp_neighbor_get_destination_address(sd_lldp_neighbor *n, struct ether_addr* address) {
|
||||
assert_return(n, -EINVAL);
|
||||
assert_return(address, -EINVAL);
|
||||
|
||||
|
@ -376,7 +376,7 @@ _public_ int sd_lldp_neighbor_get_destination_address(sd_lldp_neighbor *n, struc
|
|||
return 0;
|
||||
}
|
||||
|
||||
_public_ int sd_lldp_neighbor_get_raw(sd_lldp_neighbor *n, const void **ret, size_t *size) {
|
||||
int sd_lldp_neighbor_get_raw(sd_lldp_neighbor *n, const void **ret, size_t *size) {
|
||||
assert_return(n, -EINVAL);
|
||||
assert_return(ret, -EINVAL);
|
||||
assert_return(size, -EINVAL);
|
||||
|
@ -387,7 +387,7 @@ _public_ int sd_lldp_neighbor_get_raw(sd_lldp_neighbor *n, const void **ret, siz
|
|||
return 0;
|
||||
}
|
||||
|
||||
_public_ int sd_lldp_neighbor_get_chassis_id(sd_lldp_neighbor *n, uint8_t *type, const void **ret, size_t *size) {
|
||||
int sd_lldp_neighbor_get_chassis_id(sd_lldp_neighbor *n, uint8_t *type, const void **ret, size_t *size) {
|
||||
assert_return(n, -EINVAL);
|
||||
assert_return(type, -EINVAL);
|
||||
assert_return(ret, -EINVAL);
|
||||
|
@ -440,7 +440,7 @@ static int format_network_address(const void *data, size_t sz, char **ret) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
_public_ int sd_lldp_neighbor_get_chassis_id_as_string(sd_lldp_neighbor *n, const char **ret) {
|
||||
int sd_lldp_neighbor_get_chassis_id_as_string(sd_lldp_neighbor *n, const char **ret) {
|
||||
char *k;
|
||||
int r;
|
||||
|
||||
|
@ -496,7 +496,7 @@ done:
|
|||
return 0;
|
||||
}
|
||||
|
||||
_public_ int sd_lldp_neighbor_get_port_id(sd_lldp_neighbor *n, uint8_t *type, const void **ret, size_t *size) {
|
||||
int sd_lldp_neighbor_get_port_id(sd_lldp_neighbor *n, uint8_t *type, const void **ret, size_t *size) {
|
||||
assert_return(n, -EINVAL);
|
||||
assert_return(type, -EINVAL);
|
||||
assert_return(ret, -EINVAL);
|
||||
|
@ -511,7 +511,7 @@ _public_ int sd_lldp_neighbor_get_port_id(sd_lldp_neighbor *n, uint8_t *type, co
|
|||
return 0;
|
||||
}
|
||||
|
||||
_public_ int sd_lldp_neighbor_get_port_id_as_string(sd_lldp_neighbor *n, const char **ret) {
|
||||
int sd_lldp_neighbor_get_port_id_as_string(sd_lldp_neighbor *n, const char **ret) {
|
||||
char *k;
|
||||
int r;
|
||||
|
||||
|
@ -566,7 +566,7 @@ done:
|
|||
return 0;
|
||||
}
|
||||
|
||||
_public_ int sd_lldp_neighbor_get_ttl(sd_lldp_neighbor *n, uint16_t *ret_sec) {
|
||||
int sd_lldp_neighbor_get_ttl(sd_lldp_neighbor *n, uint16_t *ret_sec) {
|
||||
assert_return(n, -EINVAL);
|
||||
assert_return(ret_sec, -EINVAL);
|
||||
|
||||
|
@ -574,7 +574,7 @@ _public_ int sd_lldp_neighbor_get_ttl(sd_lldp_neighbor *n, uint16_t *ret_sec) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
_public_ int sd_lldp_neighbor_get_system_name(sd_lldp_neighbor *n, const char **ret) {
|
||||
int sd_lldp_neighbor_get_system_name(sd_lldp_neighbor *n, const char **ret) {
|
||||
assert_return(n, -EINVAL);
|
||||
assert_return(ret, -EINVAL);
|
||||
|
||||
|
@ -585,7 +585,7 @@ _public_ int sd_lldp_neighbor_get_system_name(sd_lldp_neighbor *n, const char **
|
|||
return 0;
|
||||
}
|
||||
|
||||
_public_ int sd_lldp_neighbor_get_system_description(sd_lldp_neighbor *n, const char **ret) {
|
||||
int sd_lldp_neighbor_get_system_description(sd_lldp_neighbor *n, const char **ret) {
|
||||
assert_return(n, -EINVAL);
|
||||
assert_return(ret, -EINVAL);
|
||||
|
||||
|
@ -596,7 +596,7 @@ _public_ int sd_lldp_neighbor_get_system_description(sd_lldp_neighbor *n, const
|
|||
return 0;
|
||||
}
|
||||
|
||||
_public_ int sd_lldp_neighbor_get_port_description(sd_lldp_neighbor *n, const char **ret) {
|
||||
int sd_lldp_neighbor_get_port_description(sd_lldp_neighbor *n, const char **ret) {
|
||||
assert_return(n, -EINVAL);
|
||||
assert_return(ret, -EINVAL);
|
||||
|
||||
|
@ -607,7 +607,7 @@ _public_ int sd_lldp_neighbor_get_port_description(sd_lldp_neighbor *n, const ch
|
|||
return 0;
|
||||
}
|
||||
|
||||
_public_ int sd_lldp_neighbor_get_mud_url(sd_lldp_neighbor *n, const char **ret) {
|
||||
int sd_lldp_neighbor_get_mud_url(sd_lldp_neighbor *n, const char **ret) {
|
||||
assert_return(n, -EINVAL);
|
||||
assert_return(ret, -EINVAL);
|
||||
|
||||
|
@ -618,7 +618,7 @@ _public_ int sd_lldp_neighbor_get_mud_url(sd_lldp_neighbor *n, const char **ret)
|
|||
return 0;
|
||||
}
|
||||
|
||||
_public_ int sd_lldp_neighbor_get_system_capabilities(sd_lldp_neighbor *n, uint16_t *ret) {
|
||||
int sd_lldp_neighbor_get_system_capabilities(sd_lldp_neighbor *n, uint16_t *ret) {
|
||||
assert_return(n, -EINVAL);
|
||||
assert_return(ret, -EINVAL);
|
||||
|
||||
|
@ -629,7 +629,7 @@ _public_ int sd_lldp_neighbor_get_system_capabilities(sd_lldp_neighbor *n, uint1
|
|||
return 0;
|
||||
}
|
||||
|
||||
_public_ int sd_lldp_neighbor_get_enabled_capabilities(sd_lldp_neighbor *n, uint16_t *ret) {
|
||||
int sd_lldp_neighbor_get_enabled_capabilities(sd_lldp_neighbor *n, uint16_t *ret) {
|
||||
assert_return(n, -EINVAL);
|
||||
assert_return(ret, -EINVAL);
|
||||
|
||||
|
@ -640,7 +640,7 @@ _public_ int sd_lldp_neighbor_get_enabled_capabilities(sd_lldp_neighbor *n, uint
|
|||
return 0;
|
||||
}
|
||||
|
||||
_public_ int sd_lldp_neighbor_from_raw(sd_lldp_neighbor **ret, const void *raw, size_t raw_size) {
|
||||
int sd_lldp_neighbor_from_raw(sd_lldp_neighbor **ret, const void *raw, size_t raw_size) {
|
||||
_cleanup_(sd_lldp_neighbor_unrefp) sd_lldp_neighbor *n = NULL;
|
||||
int r;
|
||||
|
||||
|
@ -661,7 +661,7 @@ _public_ int sd_lldp_neighbor_from_raw(sd_lldp_neighbor **ret, const void *raw,
|
|||
return r;
|
||||
}
|
||||
|
||||
_public_ int sd_lldp_neighbor_tlv_rewind(sd_lldp_neighbor *n) {
|
||||
int sd_lldp_neighbor_tlv_rewind(sd_lldp_neighbor *n) {
|
||||
assert_return(n, -EINVAL);
|
||||
|
||||
assert(n->raw_size >= sizeof(struct ether_header));
|
||||
|
@ -670,7 +670,7 @@ _public_ int sd_lldp_neighbor_tlv_rewind(sd_lldp_neighbor *n) {
|
|||
return n->rindex < n->raw_size;
|
||||
}
|
||||
|
||||
_public_ int sd_lldp_neighbor_tlv_next(sd_lldp_neighbor *n) {
|
||||
int sd_lldp_neighbor_tlv_next(sd_lldp_neighbor *n) {
|
||||
size_t length;
|
||||
|
||||
assert_return(n, -EINVAL);
|
||||
|
@ -689,7 +689,7 @@ _public_ int sd_lldp_neighbor_tlv_next(sd_lldp_neighbor *n) {
|
|||
return n->rindex < n->raw_size;
|
||||
}
|
||||
|
||||
_public_ int sd_lldp_neighbor_tlv_get_type(sd_lldp_neighbor *n, uint8_t *type) {
|
||||
int sd_lldp_neighbor_tlv_get_type(sd_lldp_neighbor *n, uint8_t *type) {
|
||||
assert_return(n, -EINVAL);
|
||||
assert_return(type, -EINVAL);
|
||||
|
||||
|
@ -703,7 +703,7 @@ _public_ int sd_lldp_neighbor_tlv_get_type(sd_lldp_neighbor *n, uint8_t *type) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
_public_ int sd_lldp_neighbor_tlv_is_type(sd_lldp_neighbor *n, uint8_t type) {
|
||||
int sd_lldp_neighbor_tlv_is_type(sd_lldp_neighbor *n, uint8_t type) {
|
||||
uint8_t k;
|
||||
int r;
|
||||
|
||||
|
@ -716,7 +716,7 @@ _public_ int sd_lldp_neighbor_tlv_is_type(sd_lldp_neighbor *n, uint8_t type) {
|
|||
return type == k;
|
||||
}
|
||||
|
||||
_public_ int sd_lldp_neighbor_tlv_get_oui(sd_lldp_neighbor *n, uint8_t oui[_SD_ARRAY_STATIC 3], uint8_t *subtype) {
|
||||
int sd_lldp_neighbor_tlv_get_oui(sd_lldp_neighbor *n, uint8_t oui[_SD_ARRAY_STATIC 3], uint8_t *subtype) {
|
||||
const uint8_t *d;
|
||||
size_t length;
|
||||
int r;
|
||||
|
@ -745,7 +745,7 @@ _public_ int sd_lldp_neighbor_tlv_get_oui(sd_lldp_neighbor *n, uint8_t oui[_SD_A
|
|||
return 0;
|
||||
}
|
||||
|
||||
_public_ int sd_lldp_neighbor_tlv_is_oui(sd_lldp_neighbor *n, const uint8_t oui[_SD_ARRAY_STATIC 3], uint8_t subtype) {
|
||||
int sd_lldp_neighbor_tlv_is_oui(sd_lldp_neighbor *n, const uint8_t oui[_SD_ARRAY_STATIC 3], uint8_t subtype) {
|
||||
uint8_t k[3], st;
|
||||
int r;
|
||||
|
||||
|
@ -758,7 +758,7 @@ _public_ int sd_lldp_neighbor_tlv_is_oui(sd_lldp_neighbor *n, const uint8_t oui[
|
|||
return memcmp(k, oui, 3) == 0 && st == subtype;
|
||||
}
|
||||
|
||||
_public_ int sd_lldp_neighbor_tlv_get_raw(sd_lldp_neighbor *n, const void **ret, size_t *size) {
|
||||
int sd_lldp_neighbor_tlv_get_raw(sd_lldp_neighbor *n, const void **ret, size_t *size) {
|
||||
size_t length;
|
||||
|
||||
assert_return(n, -EINVAL);
|
||||
|
@ -780,7 +780,7 @@ _public_ int sd_lldp_neighbor_tlv_get_raw(sd_lldp_neighbor *n, const void **ret,
|
|||
return 0;
|
||||
}
|
||||
|
||||
_public_ int sd_lldp_neighbor_get_timestamp(sd_lldp_neighbor *n, clockid_t clock, uint64_t *ret) {
|
||||
int sd_lldp_neighbor_get_timestamp(sd_lldp_neighbor *n, clockid_t clock, uint64_t *ret) {
|
||||
assert_return(n, -EINVAL);
|
||||
assert_return(TRIPLE_TIMESTAMP_HAS_CLOCK(clock), -EOPNOTSUPP);
|
||||
assert_return(clock_supported(clock), -EOPNOTSUPP);
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
#include "socket-util.h"
|
||||
|
||||
int lldp_network_bind_raw_socket(int ifindex) {
|
||||
|
||||
static const struct sock_filter filter[] = {
|
||||
BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(struct ethhdr, h_dest)), /* A <- 4 bytes of destination MAC */
|
||||
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x0180c200, 1, 0), /* A != 01:80:c2:00 */
|
||||
|
@ -26,26 +25,21 @@ int lldp_network_bind_raw_socket(int ifindex) {
|
|||
BPF_STMT(BPF_RET + BPF_K, 0), /* drop packet */
|
||||
BPF_STMT(BPF_RET + BPF_K, UINT32_MAX), /* accept packet */
|
||||
};
|
||||
|
||||
static const struct sock_fprog fprog = {
|
||||
.len = ELEMENTSOF(filter),
|
||||
.filter = (struct sock_filter*) filter,
|
||||
};
|
||||
|
||||
struct packet_mreq mreq = {
|
||||
.mr_ifindex = ifindex,
|
||||
.mr_type = PACKET_MR_MULTICAST,
|
||||
.mr_alen = ETH_ALEN,
|
||||
.mr_address = { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x00 }
|
||||
};
|
||||
|
||||
union sockaddr_union saddrll = {
|
||||
.ll.sll_family = AF_PACKET,
|
||||
.ll.sll_ifindex = ifindex,
|
||||
};
|
||||
|
||||
_cleanup_close_ int fd = -1;
|
||||
int r;
|
||||
|
||||
assert(ifindex > 0);
|
||||
|
||||
|
@ -54,29 +48,24 @@ int lldp_network_bind_raw_socket(int ifindex) {
|
|||
if (fd < 0)
|
||||
return -errno;
|
||||
|
||||
r = setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &fprog, sizeof(fprog));
|
||||
if (r < 0)
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &fprog, sizeof(fprog)) < 0)
|
||||
return -errno;
|
||||
|
||||
/* customer bridge */
|
||||
r = setsockopt(fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
|
||||
if (r < 0)
|
||||
if (setsockopt(fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0)
|
||||
return -errno;
|
||||
|
||||
/* non TPMR bridge */
|
||||
mreq.mr_address[ETH_ALEN - 1] = 0x03;
|
||||
r = setsockopt(fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
|
||||
if (r < 0)
|
||||
if (setsockopt(fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0)
|
||||
return -errno;
|
||||
|
||||
/* nearest bridge */
|
||||
mreq.mr_address[ETH_ALEN - 1] = 0x0E;
|
||||
r = setsockopt(fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
|
||||
if (r < 0)
|
||||
if (setsockopt(fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0)
|
||||
return -errno;
|
||||
|
||||
r = bind(fd, &saddrll.sa, sizeof(saddrll.ll));
|
||||
if (r < 0)
|
||||
if (bind(fd, &saddrll.sa, sizeof(saddrll.ll)) < 0)
|
||||
return -errno;
|
||||
|
||||
return TAKE_FD(fd);
|
||||
|
|
|
@ -8,8 +8,10 @@
|
|||
int _e = (error); \
|
||||
if (DEBUG_LOGGING) { \
|
||||
const char *_n = NULL; \
|
||||
type *_v = (val); \
|
||||
\
|
||||
(void) type##_get_ifname(val, &_n); \
|
||||
if (_v) \
|
||||
(void) type##_get_ifname(_v, &_n); \
|
||||
log_interface_full_errno_zerook( \
|
||||
_n, LOG_DEBUG, _e, prefix fmt, \
|
||||
##__VA_ARGS__); \
|
||||
|
|
|
@ -837,7 +837,8 @@ static int client_message_init(
|
|||
return -ENOMEM;
|
||||
|
||||
r = dhcp_message_init(&packet->dhcp, BOOTREQUEST, client->xid, type,
|
||||
client->arp_type, optlen, &optoffset);
|
||||
client->arp_type, client->mac_addr_len, client->mac_addr,
|
||||
optlen, &optoffset);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
@ -853,7 +854,7 @@ static int client_message_init(
|
|||
secs = ((time_now - client->start_time) / USEC_PER_SEC) ? : 1;
|
||||
packet->dhcp.secs = htobe16(secs);
|
||||
|
||||
/* RFC2132 section 4.1
|
||||
/* RFC2131 section 4.1
|
||||
A client that cannot receive unicast IP datagrams until its protocol
|
||||
software has been configured with an IP address SHOULD set the
|
||||
BROADCAST bit in the 'flags' field to 1 in any DHCPDISCOVER or
|
||||
|
@ -867,15 +868,6 @@ static int client_message_init(
|
|||
if (client->request_broadcast || client->arp_type != ARPHRD_ETHER)
|
||||
packet->dhcp.flags = htobe16(0x8000);
|
||||
|
||||
/* RFC2132 section 4.1.1:
|
||||
The client MUST include its hardware address in the ’chaddr’ field, if
|
||||
necessary for delivery of DHCP reply messages. Non-Ethernet
|
||||
interfaces will leave 'chaddr' empty and use the client identifier
|
||||
instead (eg, RFC 4390 section 2.1).
|
||||
*/
|
||||
if (client->arp_type == ARPHRD_ETHER)
|
||||
memcpy(&packet->dhcp.chaddr, &client->mac_addr, ETH_ALEN);
|
||||
|
||||
/* If no client identifier exists, construct an RFC 4361-compliant one */
|
||||
if (client->client_id_len == 0) {
|
||||
size_t duid_len;
|
||||
|
@ -1935,13 +1927,13 @@ static int client_receive_message_udp(
|
|||
assert(client);
|
||||
|
||||
buflen = next_datagram_size_fd(fd);
|
||||
if (buflen == -ENETDOWN)
|
||||
/* the link is down. Don't return an error or the I/O event
|
||||
source will be disconnected and we won't be able to receive
|
||||
packets again when the link comes back. */
|
||||
if (buflen < 0) {
|
||||
if (ERRNO_IS_TRANSIENT(buflen) || ERRNO_IS_DISCONNECT(buflen))
|
||||
return 0;
|
||||
if (buflen < 0)
|
||||
return buflen;
|
||||
|
||||
log_dhcp_client_errno(client, buflen, "Failed to determine datagram size to read, ignoring: %m");
|
||||
return 0;
|
||||
}
|
||||
|
||||
message = malloc0(buflen);
|
||||
if (!message)
|
||||
|
@ -1949,12 +1941,11 @@ static int client_receive_message_udp(
|
|||
|
||||
len = recv(fd, message, buflen, 0);
|
||||
if (len < 0) {
|
||||
/* see comment above for why we shouldn't error out on ENETDOWN. */
|
||||
if (IN_SET(errno, EAGAIN, EINTR, ENETDOWN))
|
||||
if (ERRNO_IS_TRANSIENT(errno) || ERRNO_IS_DISCONNECT(errno))
|
||||
return 0;
|
||||
|
||||
return log_dhcp_client_errno(client, errno,
|
||||
"Could not receive message from UDP socket: %m");
|
||||
log_dhcp_client_errno(client, errno, "Could not receive message from UDP socket, ignoring: %m");
|
||||
return 0;
|
||||
}
|
||||
if ((size_t) len < sizeof(DHCPMessage)) {
|
||||
log_dhcp_client(client, "Too small to be a DHCP message: ignoring");
|
||||
|
@ -2000,7 +1991,9 @@ static int client_receive_message_udp(
|
|||
return 0;
|
||||
}
|
||||
|
||||
return client_handle_message(client, message, len);
|
||||
log_dhcp_client(client, "Received message from UDP socket, processing.");
|
||||
(void) client_handle_message(client, message, len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int client_receive_message_raw(
|
||||
|
@ -2028,10 +2021,13 @@ static int client_receive_message_raw(
|
|||
assert(client);
|
||||
|
||||
buflen = next_datagram_size_fd(fd);
|
||||
if (buflen == -ENETDOWN)
|
||||
if (buflen < 0) {
|
||||
if (ERRNO_IS_TRANSIENT(buflen) || ERRNO_IS_DISCONNECT(buflen))
|
||||
return 0;
|
||||
if (buflen < 0)
|
||||
return buflen;
|
||||
|
||||
log_dhcp_client_errno(client, buflen, "Failed to determine datagram size to read, ignoring: %m");
|
||||
return 0;
|
||||
}
|
||||
|
||||
packet = malloc0(buflen);
|
||||
if (!packet)
|
||||
|
@ -2040,12 +2036,13 @@ static int client_receive_message_raw(
|
|||
iov = IOVEC_MAKE(packet, buflen);
|
||||
|
||||
len = recvmsg_safe(fd, &msg, 0);
|
||||
if (IN_SET(len, -EAGAIN, -EINTR, -ENETDOWN))
|
||||
if (len < 0) {
|
||||
if (ERRNO_IS_TRANSIENT(len) || ERRNO_IS_DISCONNECT(len))
|
||||
return 0;
|
||||
if (len < 0)
|
||||
return log_dhcp_client_errno(client, len,
|
||||
"Could not receive message from raw socket: %m");
|
||||
|
||||
log_dhcp_client_errno(client, len, "Could not receive message from raw socket, ignoring: %m");
|
||||
return 0;
|
||||
}
|
||||
if ((size_t) len < sizeof(DHCPPacket))
|
||||
return 0;
|
||||
|
||||
|
@ -2061,7 +2058,9 @@ static int client_receive_message_raw(
|
|||
|
||||
len -= DHCP_IP_UDP_SIZE;
|
||||
|
||||
return client_handle_message(client, &packet->dhcp, len);
|
||||
log_dhcp_client(client, "Received message from RAW socket, processing.");
|
||||
(void) client_handle_message(client, &packet->dhcp, len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_dhcp_client_send_renew(sd_dhcp_client *client) {
|
||||
|
|
|
@ -107,12 +107,13 @@ int sd_dhcp_lease_get_servers(
|
|||
assert_return(lease, -EINVAL);
|
||||
assert_return(what >= 0, -EINVAL);
|
||||
assert_return(what < _SD_DHCP_LEASE_SERVER_TYPE_MAX, -EINVAL);
|
||||
assert_return(addr, -EINVAL);
|
||||
|
||||
if (lease->servers[what].size <= 0)
|
||||
return -ENODATA;
|
||||
|
||||
if (addr)
|
||||
*addr = lease->servers[what].addr;
|
||||
|
||||
return (int) lease->servers[what].size;
|
||||
}
|
||||
|
||||
|
@ -252,6 +253,33 @@ int sd_dhcp_lease_get_search_domains(sd_dhcp_lease *lease, char ***domains) {
|
|||
return -ENODATA;
|
||||
}
|
||||
|
||||
int sd_dhcp_lease_get_6rd(
|
||||
sd_dhcp_lease *lease,
|
||||
uint8_t *ret_ipv4masklen,
|
||||
uint8_t *ret_prefixlen,
|
||||
struct in6_addr *ret_prefix,
|
||||
const struct in_addr **ret_br_addresses,
|
||||
size_t *ret_n_br_addresses) {
|
||||
|
||||
assert_return(lease, -EINVAL);
|
||||
|
||||
if (lease->sixrd_n_br_addresses <= 0)
|
||||
return -ENODATA;
|
||||
|
||||
if (ret_ipv4masklen)
|
||||
*ret_ipv4masklen = lease->sixrd_ipv4masklen;
|
||||
if (ret_prefixlen)
|
||||
*ret_prefixlen = lease->sixrd_prefixlen;
|
||||
if (ret_prefix)
|
||||
*ret_prefix = lease->sixrd_prefix;
|
||||
if (ret_br_addresses)
|
||||
*ret_br_addresses = lease->sixrd_br_addresses;
|
||||
if (ret_n_br_addresses)
|
||||
*ret_n_br_addresses = lease->sixrd_n_br_addresses;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_dhcp_lease_get_vendor_specific(sd_dhcp_lease *lease, const void **data, size_t *data_len) {
|
||||
assert_return(lease, -EINVAL);
|
||||
assert_return(data, -EINVAL);
|
||||
|
@ -290,6 +318,7 @@ static sd_dhcp_lease *dhcp_lease_free(sd_dhcp_lease *lease) {
|
|||
free(lease->client_id);
|
||||
free(lease->vendor_specific);
|
||||
strv_free(lease->search_domains);
|
||||
free(lease->sixrd_br_addresses);
|
||||
return mfree(lease);
|
||||
}
|
||||
|
||||
|
@ -535,6 +564,61 @@ static int lease_parse_classless_routes(
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int lease_parse_6rd(sd_dhcp_lease *lease, const uint8_t *option, size_t len) {
|
||||
uint8_t ipv4masklen, prefixlen;
|
||||
struct in6_addr prefix;
|
||||
_cleanup_free_ struct in_addr *br_addresses = NULL;
|
||||
size_t n_br_addresses;
|
||||
|
||||
assert(lease);
|
||||
assert(option);
|
||||
|
||||
/* See RFC 5969 Section 7.1.1 */
|
||||
|
||||
if (lease->sixrd_n_br_addresses > 0)
|
||||
/* Multiple 6rd option?? */
|
||||
return -EINVAL;
|
||||
|
||||
/* option-length: The length of the DHCP option in octets (22 octets with one BR IPv4 address). */
|
||||
if (len < 2 + sizeof(struct in6_addr) + sizeof(struct in_addr) ||
|
||||
(len - 2 - sizeof(struct in6_addr)) % sizeof(struct in_addr) != 0)
|
||||
return -EINVAL;
|
||||
|
||||
/* IPv4MaskLen: The number of high-order bits that are identical across all CE IPv4 addresses
|
||||
* within a given 6rd domain. This may be any value between 0 and 32. Any value
|
||||
* greater than 32 is invalid. */
|
||||
ipv4masklen = option[0];
|
||||
if (ipv4masklen > 32)
|
||||
return -EINVAL;
|
||||
|
||||
/* 6rdPrefixLen: The IPv6 prefix length of the SP's 6rd IPv6 prefix in number of bits. For the
|
||||
* purpose of bounds checking by DHCP option processing, the sum of
|
||||
* (32 - IPv4MaskLen) + 6rdPrefixLen MUST be less than or equal to 128. */
|
||||
prefixlen = option[1];
|
||||
if (32 - ipv4masklen + prefixlen > 128)
|
||||
return -EINVAL;
|
||||
|
||||
/* 6rdPrefix: The service provider's 6rd IPv6 prefix represented as a 16-octet IPv6 address.
|
||||
* The bits in the prefix after the 6rdPrefixlen number of bits are reserved and
|
||||
* MUST be initialized to zero by the sender and ignored by the receiver. */
|
||||
memcpy(&prefix, option + 2, sizeof(struct in6_addr));
|
||||
(void) in6_addr_mask(&prefix, prefixlen);
|
||||
|
||||
/* 6rdBRIPv4Address: One or more IPv4 addresses of the 6rd Border Relay(s) for a given 6rd domain. */
|
||||
n_br_addresses = (len - 2 - sizeof(struct in6_addr)) / sizeof(struct in_addr);
|
||||
br_addresses = newdup(struct in_addr, option + 2 + sizeof(struct in6_addr), n_br_addresses);
|
||||
if (!br_addresses)
|
||||
return -ENOMEM;
|
||||
|
||||
lease->sixrd_ipv4masklen = ipv4masklen;
|
||||
lease->sixrd_prefixlen = prefixlen;
|
||||
lease->sixrd_prefix = prefix;
|
||||
lease->sixrd_br_addresses = TAKE_PTR(br_addresses);
|
||||
lease->sixrd_n_br_addresses = n_br_addresses;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dhcp_lease_parse_options(uint8_t code, uint8_t len, const void *option, void *userdata) {
|
||||
sd_dhcp_lease *lease = userdata;
|
||||
int r;
|
||||
|
@ -693,7 +777,7 @@ int dhcp_lease_parse_options(uint8_t code, uint8_t len, const void *option, void
|
|||
}
|
||||
|
||||
if (!timezone_is_valid(tz, LOG_DEBUG)) {
|
||||
log_debug_errno(r, "Timezone is not valid, ignoring: %m");
|
||||
log_debug("Timezone is not valid, ignoring.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -720,6 +804,12 @@ int dhcp_lease_parse_options(uint8_t code, uint8_t len, const void *option, void
|
|||
lease->vendor_specific_len = len;
|
||||
break;
|
||||
|
||||
case SD_DHCP_OPTION_6RD:
|
||||
r = lease_parse_6rd(lease, option, len);
|
||||
if (r < 0)
|
||||
log_debug_errno(r, "Failed to parse 6rd option, ignoring: %m");
|
||||
break;
|
||||
|
||||
case SD_DHCP_OPTION_PRIVATE_BASE ... SD_DHCP_OPTION_PRIVATE_LAST:
|
||||
r = dhcp_lease_insert_private_option(lease, code, option, len);
|
||||
if (r < 0)
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include "hexdecoct.h"
|
||||
#include "hostname-util.h"
|
||||
#include "in-addr-util.h"
|
||||
#include "io-util.h"
|
||||
#include "network-common.h"
|
||||
#include "random-util.h"
|
||||
#include "socket-util.h"
|
||||
|
@ -41,16 +42,16 @@
|
|||
#define IRT_MINIMUM (600 * USEC_PER_SEC)
|
||||
|
||||
/* what to request from the server, addresses (IA_NA) and/or prefixes (IA_PD) */
|
||||
enum {
|
||||
DHCP6_REQUEST_IA_NA = 1,
|
||||
DHCP6_REQUEST_IA_TA = 2, /* currently not used */
|
||||
DHCP6_REQUEST_IA_PD = 4,
|
||||
};
|
||||
typedef enum DHCP6RequestIA {
|
||||
DHCP6_REQUEST_IA_NA = 1 << 0,
|
||||
DHCP6_REQUEST_IA_TA = 1 << 1, /* currently not used */
|
||||
DHCP6_REQUEST_IA_PD = 1 << 2,
|
||||
} DHCP6RequestIA;
|
||||
|
||||
struct sd_dhcp6_client {
|
||||
unsigned n_ref;
|
||||
|
||||
enum DHCP6State state;
|
||||
DHCP6State state;
|
||||
sd_event *event;
|
||||
int event_priority;
|
||||
int ifindex;
|
||||
|
@ -64,7 +65,7 @@ struct sd_dhcp6_client {
|
|||
DHCP6IA ia_pd;
|
||||
sd_event_source *timeout_t1;
|
||||
sd_event_source *timeout_t2;
|
||||
unsigned request;
|
||||
DHCP6RequestIA request_ia;
|
||||
be32_t transaction_id;
|
||||
usec_t transaction_start;
|
||||
struct sd_dhcp6_lease *lease;
|
||||
|
@ -102,20 +103,42 @@ static const uint16_t default_req_opts[] = {
|
|||
SD_DHCP6_OPTION_SNTP_SERVERS,
|
||||
};
|
||||
|
||||
const char * dhcp6_message_type_table[_DHCP6_MESSAGE_MAX] = {
|
||||
[DHCP6_SOLICIT] = "SOLICIT",
|
||||
[DHCP6_ADVERTISE] = "ADVERTISE",
|
||||
[DHCP6_REQUEST] = "REQUEST",
|
||||
[DHCP6_CONFIRM] = "CONFIRM",
|
||||
[DHCP6_RENEW] = "RENEW",
|
||||
[DHCP6_REBIND] = "REBIND",
|
||||
[DHCP6_REPLY] = "REPLY",
|
||||
[DHCP6_RELEASE] = "RELEASE",
|
||||
[DHCP6_DECLINE] = "DECLINE",
|
||||
[DHCP6_RECONFIGURE] = "RECONFIGURE",
|
||||
[DHCP6_INFORMATION_REQUEST] = "INFORMATION-REQUEST",
|
||||
[DHCP6_RELAY_FORW] = "RELAY-FORW",
|
||||
[DHCP6_RELAY_REPL] = "RELAY-REPL",
|
||||
const char * dhcp6_message_type_table[_DHCP6_MESSAGE_TYPE_MAX] = {
|
||||
[DHCP6_MESSAGE_SOLICIT] = "Solicit",
|
||||
[DHCP6_MESSAGE_ADVERTISE] = "Advertise",
|
||||
[DHCP6_MESSAGE_REQUEST] = "Request",
|
||||
[DHCP6_MESSAGE_CONFIRM] = "Confirm",
|
||||
[DHCP6_MESSAGE_RENEW] = "Renew",
|
||||
[DHCP6_MESSAGE_REBIND] = "Rebind",
|
||||
[DHCP6_MESSAGE_REPLY] = "Reply",
|
||||
[DHCP6_MESSAGE_RELEASE] = "Release",
|
||||
[DHCP6_MESSAGE_DECLINE] = "Decline",
|
||||
[DHCP6_MESSAGE_RECONFIGURE] = "Reconfigure",
|
||||
[DHCP6_MESSAGE_INFORMATION_REQUEST] = "Information Request",
|
||||
[DHCP6_MESSAGE_RELAY_FORWARD] = "Relay Forward",
|
||||
[DHCP6_MESSAGE_RELAY_REPLY] = "Relay Reply",
|
||||
[DHCP6_MESSAGE_LEASE_QUERY] = "Lease Query",
|
||||
[DHCP6_MESSAGE_LEASE_QUERY_REPLY] = "Lease Query Reply",
|
||||
[DHCP6_MESSAGE_LEASE_QUERY_DONE] = "Lease Query Done",
|
||||
[DHCP6_MESSAGE_LEASE_QUERY_DATA] = "Lease Query Data",
|
||||
[DHCP6_MESSAGE_RECONFIGURE_REQUEST] = "Reconfigure Request",
|
||||
[DHCP6_MESSAGE_RECONFIGURE_REPLY] = "Reconfigure Reply",
|
||||
[DHCP6_MESSAGE_DHCPV4_QUERY] = "DHCPv4 Query",
|
||||
[DHCP6_MESSAGE_DHCPV4_RESPONSE] = "DHCPv4 Response",
|
||||
[DHCP6_MESSAGE_ACTIVE_LEASE_QUERY] = "Active Lease Query",
|
||||
[DHCP6_MESSAGE_START_TLS] = "Start TLS",
|
||||
[DHCP6_MESSAGE_BINDING_UPDATE] = "Binding Update",
|
||||
[DHCP6_MESSAGE_BINDING_REPLY] = "Binding Reply",
|
||||
[DHCP6_MESSAGE_POOL_REQUEST] = "Pool Request",
|
||||
[DHCP6_MESSAGE_POOL_RESPONSE] = "Pool Response",
|
||||
[DHCP6_MESSAGE_UPDATE_REQUEST] = "Update Request",
|
||||
[DHCP6_MESSAGE_UPDATE_REQUEST_ALL] = "Update Request All",
|
||||
[DHCP6_MESSAGE_UPDATE_DONE] = "Update Done",
|
||||
[DHCP6_MESSAGE_CONNECT] = "Connect",
|
||||
[DHCP6_MESSAGE_CONNECT_REPLY] = "Connect Reply",
|
||||
[DHCP6_MESSAGE_DISCONNECT] = "Disconnect",
|
||||
[DHCP6_MESSAGE_STATE] = "State",
|
||||
[DHCP6_MESSAGE_CONTACT] = "Contact",
|
||||
};
|
||||
|
||||
DEFINE_STRING_TABLE_LOOKUP(dhcp6_message_type, int);
|
||||
|
@ -151,7 +174,7 @@ DEFINE_STRING_TABLE_LOOKUP(dhcp6_message_status, int);
|
|||
#define DHCP6_CLIENT_DONT_DESTROY(client) \
|
||||
_cleanup_(sd_dhcp6_client_unrefp) _unused_ sd_dhcp6_client *_dont_destroy_##client = sd_dhcp6_client_ref(client)
|
||||
|
||||
static int client_start(sd_dhcp6_client *client, enum DHCP6State state);
|
||||
static int client_start(sd_dhcp6_client *client, DHCP6State state);
|
||||
|
||||
int sd_dhcp6_client_set_callback(
|
||||
sd_dhcp6_client *client,
|
||||
|
@ -234,10 +257,6 @@ int sd_dhcp6_client_set_mac(
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (client->mac_addr_len == addr_len &&
|
||||
memcmp(&client->mac_addr, addr, addr_len) == 0)
|
||||
return 0;
|
||||
|
||||
memcpy(&client->mac_addr, addr, addr_len);
|
||||
client->mac_addr_len = addr_len;
|
||||
client->arp_type = arp_type;
|
||||
|
@ -475,7 +494,7 @@ int sd_dhcp6_client_set_request_option(sd_dhcp6_client *client, uint16_t option)
|
|||
assert_return(client, -EINVAL);
|
||||
assert_return(client->state == DHCP6_STATE_STOPPED, -EBUSY);
|
||||
|
||||
if (option <= 0 || option >= UINT8_MAX)
|
||||
if (!dhcp6_option_can_request(option))
|
||||
return -EINVAL;
|
||||
|
||||
for (t = 0; t < client->req_opts_len; t++)
|
||||
|
@ -548,7 +567,7 @@ int sd_dhcp6_client_get_prefix_delegation(sd_dhcp6_client *client, int *delegati
|
|||
assert_return(client, -EINVAL);
|
||||
assert_return(delegation, -EINVAL);
|
||||
|
||||
*delegation = FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD);
|
||||
*delegation = FLAGS_SET(client->request_ia, DHCP6_REQUEST_IA_PD);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -556,7 +575,7 @@ int sd_dhcp6_client_get_prefix_delegation(sd_dhcp6_client *client, int *delegati
|
|||
int sd_dhcp6_client_set_prefix_delegation(sd_dhcp6_client *client, int delegation) {
|
||||
assert_return(client, -EINVAL);
|
||||
|
||||
SET_FLAG(client->request, DHCP6_REQUEST_IA_PD, delegation);
|
||||
SET_FLAG(client->request_ia, DHCP6_REQUEST_IA_PD, delegation);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -565,7 +584,7 @@ int sd_dhcp6_client_get_address_request(sd_dhcp6_client *client, int *request) {
|
|||
assert_return(client, -EINVAL);
|
||||
assert_return(request, -EINVAL);
|
||||
|
||||
*request = FLAGS_SET(client->request, DHCP6_REQUEST_IA_NA);
|
||||
*request = FLAGS_SET(client->request_ia, DHCP6_REQUEST_IA_NA);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -573,7 +592,7 @@ int sd_dhcp6_client_get_address_request(sd_dhcp6_client *client, int *request) {
|
|||
int sd_dhcp6_client_set_address_request(sd_dhcp6_client *client, int request) {
|
||||
assert_return(client, -EINVAL);
|
||||
|
||||
SET_FLAG(client->request, DHCP6_REQUEST_IA_NA, request);
|
||||
SET_FLAG(client->request_ia, DHCP6_REQUEST_IA_NA, request);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -678,11 +697,11 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
|
|||
|
||||
switch(client->state) {
|
||||
case DHCP6_STATE_INFORMATION_REQUEST:
|
||||
message->type = DHCP6_INFORMATION_REQUEST;
|
||||
message->type = DHCP6_MESSAGE_INFORMATION_REQUEST;
|
||||
|
||||
if (client->mudurl) {
|
||||
r = dhcp6_option_append(&opt, &optlen,
|
||||
SD_DHCP6_OPTION_MUD_URL, strlen(client->mudurl),
|
||||
SD_DHCP6_OPTION_MUD_URL_V6, strlen(client->mudurl),
|
||||
client->mudurl);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
@ -691,14 +710,14 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
|
|||
break;
|
||||
|
||||
case DHCP6_STATE_SOLICITATION:
|
||||
message->type = DHCP6_SOLICIT;
|
||||
message->type = DHCP6_MESSAGE_SOLICIT;
|
||||
|
||||
r = dhcp6_option_append(&opt, &optlen,
|
||||
SD_DHCP6_OPTION_RAPID_COMMIT, 0, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_NA)) {
|
||||
if (FLAGS_SET(client->request_ia, DHCP6_REQUEST_IA_NA)) {
|
||||
r = dhcp6_option_append_ia(&opt, &optlen,
|
||||
&client->ia_na);
|
||||
if (r < 0)
|
||||
|
@ -713,7 +732,7 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
|
|||
|
||||
if (client->mudurl) {
|
||||
r = dhcp6_option_append(&opt, &optlen,
|
||||
SD_DHCP6_OPTION_MUD_URL, strlen(client->mudurl),
|
||||
SD_DHCP6_OPTION_MUD_URL_V6, strlen(client->mudurl),
|
||||
client->mudurl);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
@ -738,7 +757,7 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
|
|||
return r;
|
||||
}
|
||||
|
||||
if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD)) {
|
||||
if (FLAGS_SET(client->request_ia, DHCP6_REQUEST_IA_PD)) {
|
||||
r = dhcp6_option_append_pd(&opt, &optlen, &client->ia_pd, &client->hint_pd_prefix);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
@ -750,9 +769,9 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
|
|||
case DHCP6_STATE_RENEW:
|
||||
|
||||
if (client->state == DHCP6_STATE_REQUEST)
|
||||
message->type = DHCP6_REQUEST;
|
||||
message->type = DHCP6_MESSAGE_REQUEST;
|
||||
else
|
||||
message->type = DHCP6_RENEW;
|
||||
message->type = DHCP6_MESSAGE_RENEW;
|
||||
|
||||
r = dhcp6_option_append(&opt, &optlen, SD_DHCP6_OPTION_SERVERID,
|
||||
client->lease->serverid_len,
|
||||
|
@ -760,7 +779,7 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
|
|||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_NA) && client->lease->ia.addresses) {
|
||||
if (FLAGS_SET(client->request_ia, DHCP6_REQUEST_IA_NA) && client->lease->ia.addresses) {
|
||||
r = dhcp6_option_append_ia(&opt, &optlen,
|
||||
&client->lease->ia);
|
||||
if (r < 0)
|
||||
|
@ -775,7 +794,7 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
|
|||
|
||||
if (client->mudurl) {
|
||||
r = dhcp6_option_append(&opt, &optlen,
|
||||
SD_DHCP6_OPTION_MUD_URL, strlen(client->mudurl),
|
||||
SD_DHCP6_OPTION_MUD_URL_V6, strlen(client->mudurl),
|
||||
client->mudurl);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
@ -799,7 +818,7 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
|
|||
return r;
|
||||
}
|
||||
|
||||
if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD) && client->lease->pd.addresses) {
|
||||
if (FLAGS_SET(client->request_ia, DHCP6_REQUEST_IA_PD) && client->lease->pd.addresses) {
|
||||
r = dhcp6_option_append_pd(&opt, &optlen, &client->lease->pd, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
@ -808,9 +827,9 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
|
|||
break;
|
||||
|
||||
case DHCP6_STATE_REBIND:
|
||||
message->type = DHCP6_REBIND;
|
||||
message->type = DHCP6_MESSAGE_REBIND;
|
||||
|
||||
if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_NA)) {
|
||||
if (FLAGS_SET(client->request_ia, DHCP6_REQUEST_IA_NA)) {
|
||||
r = dhcp6_option_append_ia(&opt, &optlen, &client->lease->ia);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
@ -824,7 +843,7 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
|
|||
|
||||
if (client->mudurl) {
|
||||
r = dhcp6_option_append(&opt, &optlen,
|
||||
SD_DHCP6_OPTION_MUD_URL, strlen(client->mudurl),
|
||||
SD_DHCP6_OPTION_MUD_URL_V6, strlen(client->mudurl),
|
||||
client->mudurl);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
@ -848,7 +867,7 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
|
|||
return r;
|
||||
}
|
||||
|
||||
if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD)) {
|
||||
if (FLAGS_SET(client->request_ia, DHCP6_REQUEST_IA_PD) && client->lease->pd.addresses) {
|
||||
r = dhcp6_option_append_pd(&opt, &optlen, &client->lease->pd, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
@ -859,6 +878,8 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
|
|||
case DHCP6_STATE_STOPPED:
|
||||
case DHCP6_STATE_BOUND:
|
||||
return -EINVAL;
|
||||
default:
|
||||
assert_not_reached();
|
||||
}
|
||||
|
||||
r = dhcp6_option_append(&opt, &optlen, SD_DHCP6_OPTION_ORO,
|
||||
|
@ -873,14 +894,12 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
|
|||
if (r < 0)
|
||||
return r;
|
||||
|
||||
elapsed_usec = time_now - client->transaction_start;
|
||||
if (elapsed_usec < 0xffff * USEC_PER_MSEC * 10)
|
||||
elapsed_time = htobe16(elapsed_usec / USEC_PER_MSEC / 10);
|
||||
else
|
||||
elapsed_time = 0xffff;
|
||||
|
||||
r = dhcp6_option_append(&opt, &optlen, SD_DHCP6_OPTION_ELAPSED_TIME,
|
||||
sizeof(elapsed_time), &elapsed_time);
|
||||
/* RFC 8415 Section 21.9.
|
||||
* A client MUST include an Elapsed Time option in messages to indicate how long the client has
|
||||
* been trying to complete a DHCP message exchange. */
|
||||
elapsed_usec = MIN(usec_sub_unsigned(time_now, client->transaction_start) / USEC_PER_MSEC / 10, (usec_t) UINT16_MAX);
|
||||
elapsed_time = htobe16(elapsed_usec);
|
||||
r = dhcp6_option_append(&opt, &optlen, SD_DHCP6_OPTION_ELAPSED_TIME, sizeof(elapsed_time), &elapsed_time);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
@ -936,7 +955,7 @@ static int client_timeout_t1(sd_event_source *s, uint64_t usec, void *userdata)
|
|||
static int client_timeout_resend_expire(sd_event_source *s, uint64_t usec, void *userdata) {
|
||||
sd_dhcp6_client *client = userdata;
|
||||
DHCP6_CLIENT_DONT_DESTROY(client);
|
||||
enum DHCP6State state;
|
||||
DHCP6State state;
|
||||
|
||||
assert(s);
|
||||
assert(client);
|
||||
|
@ -980,7 +999,7 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec, void *userda
|
|||
|
||||
case DHCP6_STATE_SOLICITATION:
|
||||
|
||||
if (client->retransmit_count && client->lease) {
|
||||
if (client->retransmit_count > 0 && client->lease) {
|
||||
client_start(client, DHCP6_STATE_REQUEST);
|
||||
return 0;
|
||||
}
|
||||
|
@ -1027,6 +1046,8 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec, void *userda
|
|||
case DHCP6_STATE_STOPPED:
|
||||
case DHCP6_STATE_BOUND:
|
||||
return 0;
|
||||
default:
|
||||
assert_not_reached();
|
||||
}
|
||||
|
||||
if (max_retransmit_count > 0 &&
|
||||
|
@ -1051,8 +1072,8 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec, void *userda
|
|||
client->retransmit_time += init_retransmit_time / 10;
|
||||
|
||||
} else {
|
||||
if (max_retransmit_time > 0 &&
|
||||
client->retransmit_time > max_retransmit_time / 2)
|
||||
assert(max_retransmit_time > 0);
|
||||
if (client->retransmit_time > max_retransmit_time / 2)
|
||||
client->retransmit_time = client_timeout_compute_random(max_retransmit_time);
|
||||
else
|
||||
client->retransmit_time += client_timeout_compute_random(client->retransmit_time);
|
||||
|
@ -1113,7 +1134,7 @@ static int client_ensure_iaid(sd_dhcp6_client *client) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int client_parse_message(
|
||||
int client_parse_message(
|
||||
sd_dhcp6_client *client,
|
||||
DHCP6Message *message,
|
||||
size_t len,
|
||||
|
@ -1121,7 +1142,6 @@ static int client_parse_message(
|
|||
|
||||
uint32_t lt_t1 = UINT32_MAX, lt_t2 = UINT32_MAX;
|
||||
usec_t irt = IRT_DEFAULT;
|
||||
bool clientid = false;
|
||||
int r;
|
||||
|
||||
assert(client);
|
||||
|
@ -1141,23 +1161,19 @@ static int client_parse_message(
|
|||
|
||||
switch (optcode) {
|
||||
case SD_DHCP6_OPTION_CLIENTID:
|
||||
if (clientid)
|
||||
return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL), "%s contains multiple clientids",
|
||||
if (dhcp6_lease_get_clientid(lease, NULL, NULL) >= 0)
|
||||
return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL), "%s contains multiple client IDs",
|
||||
dhcp6_message_type_to_string(message->type));
|
||||
|
||||
if (optlen != client->duid_len ||
|
||||
memcmp(&client->duid, optval, optlen) != 0)
|
||||
return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL), "%s DUID does not match",
|
||||
dhcp6_message_type_to_string(message->type));
|
||||
|
||||
clientid = true;
|
||||
r = dhcp6_lease_set_clientid(lease, optval, optlen);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
break;
|
||||
|
||||
case SD_DHCP6_OPTION_SERVERID:
|
||||
r = dhcp6_lease_get_serverid(lease, NULL, NULL);
|
||||
if (r >= 0)
|
||||
return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL), "%s contains multiple serverids",
|
||||
if (dhcp6_lease_get_serverid(lease, NULL, NULL) >= 0)
|
||||
return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL), "%s contains multiple server IDs",
|
||||
dhcp6_message_type_to_string(message->type));
|
||||
|
||||
r = dhcp6_lease_set_serverid(lease, optval, optlen);
|
||||
|
@ -1255,35 +1271,35 @@ static int client_parse_message(
|
|||
case SD_DHCP6_OPTION_DNS_SERVERS:
|
||||
r = dhcp6_lease_add_dns(lease, optval, optlen);
|
||||
if (r < 0)
|
||||
return r;
|
||||
log_dhcp6_client_errno(client, r, "Failed to parse DNS server option, ignoring: %m");
|
||||
|
||||
break;
|
||||
|
||||
case SD_DHCP6_OPTION_DOMAIN_LIST:
|
||||
r = dhcp6_lease_add_domains(lease, optval, optlen);
|
||||
if (r < 0)
|
||||
return r;
|
||||
log_dhcp6_client_errno(client, r, "Failed to parse domain list option, ignoring: %m");
|
||||
|
||||
break;
|
||||
|
||||
case SD_DHCP6_OPTION_NTP_SERVER:
|
||||
r = dhcp6_lease_add_ntp(lease, optval, optlen);
|
||||
if (r < 0)
|
||||
return r;
|
||||
log_dhcp6_client_errno(client, r, "Failed to parse NTP server option, ignoring: %m");
|
||||
|
||||
break;
|
||||
|
||||
case SD_DHCP6_OPTION_SNTP_SERVERS:
|
||||
r = dhcp6_lease_add_sntp(lease, optval, optlen);
|
||||
if (r < 0)
|
||||
return r;
|
||||
log_dhcp6_client_errno(client, r, "Failed to parse SNTP server option, ignoring: %m");
|
||||
|
||||
break;
|
||||
|
||||
case SD_DHCP6_OPTION_FQDN:
|
||||
case SD_DHCP6_OPTION_CLIENT_FQDN:
|
||||
r = dhcp6_lease_set_fqdn(lease, optval, optlen);
|
||||
if (r < 0)
|
||||
return r;
|
||||
log_dhcp6_client_errno(client, r, "Failed to parse FQDN option, ignoring: %m");
|
||||
|
||||
break;
|
||||
|
||||
|
@ -1296,8 +1312,15 @@ static int client_parse_message(
|
|||
}
|
||||
}
|
||||
|
||||
if (!clientid)
|
||||
return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL), "%s has incomplete options",
|
||||
uint8_t *clientid;
|
||||
size_t clientid_len;
|
||||
if (dhcp6_lease_get_clientid(lease, &clientid, &clientid_len) < 0)
|
||||
return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL), "%s message does not contain client ID. Ignoring.",
|
||||
dhcp6_message_type_to_string(message->type));
|
||||
|
||||
if (clientid_len != client->duid_len ||
|
||||
memcmp(clientid, &client->duid, clientid_len) != 0)
|
||||
return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL), "The client ID in %s message does not match. Ignoring.",
|
||||
dhcp6_message_type_to_string(message->type));
|
||||
|
||||
if (client->state != DHCP6_STATE_INFORMATION_REQUEST) {
|
||||
|
@ -1325,21 +1348,32 @@ static int client_parse_message(
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int client_receive_reply(sd_dhcp6_client *client, DHCP6Message *reply, size_t len) {
|
||||
static int client_receive_reply(
|
||||
sd_dhcp6_client *client,
|
||||
DHCP6Message *reply,
|
||||
size_t len,
|
||||
const triple_timestamp *t,
|
||||
const struct in6_addr *server_address) {
|
||||
|
||||
_cleanup_(sd_dhcp6_lease_unrefp) sd_dhcp6_lease *lease = NULL;
|
||||
bool rapid_commit;
|
||||
int r;
|
||||
|
||||
assert(client);
|
||||
assert(reply);
|
||||
assert(t);
|
||||
|
||||
if (reply->type != DHCP6_REPLY)
|
||||
if (reply->type != DHCP6_MESSAGE_REPLY)
|
||||
return 0;
|
||||
|
||||
r = dhcp6_lease_new(&lease);
|
||||
if (r < 0)
|
||||
return -ENOMEM;
|
||||
|
||||
lease->timestamp = *t;
|
||||
if (server_address)
|
||||
lease->server_address = *server_address;
|
||||
|
||||
r = client_parse_message(client, reply, len, lease);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
@ -1359,18 +1393,32 @@ static int client_receive_reply(sd_dhcp6_client *client, DHCP6Message *reply, si
|
|||
return DHCP6_STATE_BOUND;
|
||||
}
|
||||
|
||||
static int client_receive_advertise(sd_dhcp6_client *client, DHCP6Message *advertise, size_t len) {
|
||||
static int client_receive_advertise(
|
||||
sd_dhcp6_client *client,
|
||||
DHCP6Message *advertise,
|
||||
size_t len,
|
||||
const triple_timestamp *t,
|
||||
const struct in6_addr *server_address) {
|
||||
|
||||
_cleanup_(sd_dhcp6_lease_unrefp) sd_dhcp6_lease *lease = NULL;
|
||||
uint8_t pref_advertise = 0, pref_lease = 0;
|
||||
int r;
|
||||
|
||||
if (advertise->type != DHCP6_ADVERTISE)
|
||||
assert(client);
|
||||
assert(advertise);
|
||||
assert(t);
|
||||
|
||||
if (advertise->type != DHCP6_MESSAGE_ADVERTISE)
|
||||
return 0;
|
||||
|
||||
r = dhcp6_lease_new(&lease);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
lease->timestamp = *t;
|
||||
if (server_address)
|
||||
lease->server_address = *server_address;
|
||||
|
||||
r = client_parse_message(client, advertise, len, lease);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
@ -1401,7 +1449,22 @@ static int client_receive_message(
|
|||
|
||||
sd_dhcp6_client *client = userdata;
|
||||
DHCP6_CLIENT_DONT_DESTROY(client);
|
||||
/* This needs to be initialized with zero. See #20741. */
|
||||
CMSG_BUFFER_TYPE(CMSG_SPACE_TIMEVAL) control = {};
|
||||
struct iovec iov;
|
||||
union sockaddr_union sa = {};
|
||||
struct msghdr msg = {
|
||||
.msg_name = &sa.sa,
|
||||
.msg_namelen = sizeof(sa),
|
||||
.msg_iov = &iov,
|
||||
.msg_iovlen = 1,
|
||||
.msg_control = &control,
|
||||
.msg_controllen = sizeof(control),
|
||||
};
|
||||
struct cmsghdr *cmsg;
|
||||
triple_timestamp t = {};
|
||||
_cleanup_free_ DHCP6Message *message = NULL;
|
||||
struct in6_addr *server_address = NULL;
|
||||
ssize_t buflen, len;
|
||||
int r = 0;
|
||||
|
||||
|
@ -1410,52 +1473,59 @@ static int client_receive_message(
|
|||
assert(client->event);
|
||||
|
||||
buflen = next_datagram_size_fd(fd);
|
||||
if (buflen == -ENETDOWN)
|
||||
/* the link is down. Don't return an error or the I/O event
|
||||
source will be disconnected and we won't be able to receive
|
||||
packets again when the link comes back. */
|
||||
if (buflen < 0) {
|
||||
if (ERRNO_IS_TRANSIENT(buflen) || ERRNO_IS_DISCONNECT(buflen))
|
||||
return 0;
|
||||
if (buflen < 0)
|
||||
return buflen;
|
||||
|
||||
log_dhcp6_client_errno(client, buflen, "Failed to determine datagram size to read, ignoring: %m");
|
||||
return 0;
|
||||
}
|
||||
|
||||
message = malloc(buflen);
|
||||
if (!message)
|
||||
return -ENOMEM;
|
||||
|
||||
len = recv(fd, message, buflen, 0);
|
||||
iov = IOVEC_MAKE(message, buflen);
|
||||
|
||||
len = recvmsg_safe(fd, &msg, MSG_DONTWAIT);
|
||||
if (len < 0) {
|
||||
/* see comment above for why we shouldn't error out on ENETDOWN. */
|
||||
if (IN_SET(errno, EAGAIN, EINTR, ENETDOWN))
|
||||
if (ERRNO_IS_TRANSIENT(len) || ERRNO_IS_DISCONNECT(len))
|
||||
return 0;
|
||||
|
||||
return log_dhcp6_client_errno(client, errno, "Could not receive message from UDP socket: %m");
|
||||
|
||||
log_dhcp6_client_errno(client, len, "Could not receive message from UDP socket, ignoring: %m");
|
||||
return 0;
|
||||
}
|
||||
if ((size_t) len < sizeof(DHCP6Message)) {
|
||||
log_dhcp6_client(client, "Too small to be DHCP6 message: ignoring");
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch(message->type) {
|
||||
case DHCP6_SOLICIT:
|
||||
case DHCP6_REQUEST:
|
||||
case DHCP6_CONFIRM:
|
||||
case DHCP6_RENEW:
|
||||
case DHCP6_REBIND:
|
||||
case DHCP6_RELEASE:
|
||||
case DHCP6_DECLINE:
|
||||
case DHCP6_INFORMATION_REQUEST:
|
||||
case DHCP6_RELAY_FORW:
|
||||
case DHCP6_RELAY_REPL:
|
||||
/* msg_namelen == 0 happens when running the test-suite over a socketpair */
|
||||
if (msg.msg_namelen > 0) {
|
||||
if (msg.msg_namelen != sizeof(struct sockaddr_in6) || sa.in6.sin6_family != AF_INET6) {
|
||||
log_dhcp6_client(client, "Received message from invalid source, ignoring.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
case DHCP6_ADVERTISE:
|
||||
case DHCP6_REPLY:
|
||||
case DHCP6_RECONFIGURE:
|
||||
break;
|
||||
server_address = &sa.in6.sin6_addr;
|
||||
}
|
||||
|
||||
default:
|
||||
log_dhcp6_client(client, "Unknown message type %d", message->type);
|
||||
CMSG_FOREACH(cmsg, &msg) {
|
||||
if (cmsg->cmsg_level == SOL_SOCKET &&
|
||||
cmsg->cmsg_type == SO_TIMESTAMP &&
|
||||
cmsg->cmsg_len == CMSG_LEN(sizeof(struct timeval)))
|
||||
triple_timestamp_from_realtime(&t, timeval_load((struct timeval*) CMSG_DATA(cmsg)));
|
||||
}
|
||||
|
||||
if (!triple_timestamp_is_set(&t))
|
||||
triple_timestamp_get(&t);
|
||||
|
||||
if (!IN_SET(message->type, DHCP6_MESSAGE_ADVERTISE, DHCP6_MESSAGE_REPLY, DHCP6_MESSAGE_RECONFIGURE)) {
|
||||
const char *type_str = dhcp6_message_type_to_string(message->type);
|
||||
if (type_str)
|
||||
log_dhcp6_client(client, "Received unexpected %s message, ignoring.", type_str);
|
||||
else
|
||||
log_dhcp6_client(client, "Received unsupported message type %u, ignoring.", message->type);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1464,7 +1534,7 @@ static int client_receive_message(
|
|||
|
||||
switch (client->state) {
|
||||
case DHCP6_STATE_INFORMATION_REQUEST:
|
||||
r = client_receive_reply(client, message, len);
|
||||
r = client_receive_reply(client, message, len, &t, server_address);
|
||||
if (r < 0) {
|
||||
log_dhcp6_client_errno(client, r, "Failed to process received reply message, ignoring: %m");
|
||||
return 0;
|
||||
|
@ -1477,7 +1547,7 @@ static int client_receive_message(
|
|||
break;
|
||||
|
||||
case DHCP6_STATE_SOLICITATION:
|
||||
r = client_receive_advertise(client, message, len);
|
||||
r = client_receive_advertise(client, message, len, &t, server_address);
|
||||
if (r < 0) {
|
||||
log_dhcp6_client_errno(client, r, "Failed to process received advertise message, ignoring: %m");
|
||||
return 0;
|
||||
|
@ -1493,7 +1563,7 @@ static int client_receive_message(
|
|||
case DHCP6_STATE_RENEW:
|
||||
case DHCP6_STATE_REBIND:
|
||||
|
||||
r = client_receive_reply(client, message, len);
|
||||
r = client_receive_reply(client, message, len, &t, server_address);
|
||||
if (r < 0) {
|
||||
log_dhcp6_client_errno(client, r, "Failed to process received reply message, ignoring: %m");
|
||||
return 0;
|
||||
|
@ -1517,6 +1587,8 @@ static int client_receive_message(
|
|||
|
||||
case DHCP6_STATE_STOPPED:
|
||||
return 0;
|
||||
default:
|
||||
assert_not_reached();
|
||||
}
|
||||
|
||||
log_dhcp6_client(client, "Recv %s",
|
||||
|
@ -1530,14 +1602,14 @@ static int client_get_lifetime(sd_dhcp6_client *client, uint32_t *lifetime_t1,
|
|||
assert_return(client, -EINVAL);
|
||||
assert_return(client->lease, -EINVAL);
|
||||
|
||||
if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_NA) && client->lease->ia.addresses) {
|
||||
if (FLAGS_SET(client->request_ia, DHCP6_REQUEST_IA_NA) && client->lease->ia.addresses) {
|
||||
*lifetime_t1 = be32toh(client->lease->ia.ia_na.lifetime_t1);
|
||||
*lifetime_t2 = be32toh(client->lease->ia.ia_na.lifetime_t2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD) && client->lease->pd.addresses) {
|
||||
if (FLAGS_SET(client->request_ia, DHCP6_REQUEST_IA_PD) && client->lease->pd.addresses) {
|
||||
*lifetime_t1 = be32toh(client->lease->pd.ia_pd.lifetime_t1);
|
||||
*lifetime_t2 = be32toh(client->lease->pd.ia_pd.lifetime_t2);
|
||||
|
||||
|
@ -1547,7 +1619,7 @@ static int client_get_lifetime(sd_dhcp6_client *client, uint32_t *lifetime_t1,
|
|||
return -ENOMSG;
|
||||
}
|
||||
|
||||
static int client_start(sd_dhcp6_client *client, enum DHCP6State state) {
|
||||
static int client_start(sd_dhcp6_client *client, DHCP6State state) {
|
||||
int r;
|
||||
usec_t timeout, time_now;
|
||||
uint32_t lifetime_t1, lifetime_t2;
|
||||
|
@ -1647,6 +1719,8 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state) {
|
|||
client->state = state;
|
||||
|
||||
return 0;
|
||||
default:
|
||||
assert_not_reached();
|
||||
}
|
||||
|
||||
client->transaction_id = random_u32() & htobe32(0x00ffffff);
|
||||
|
@ -1685,7 +1759,7 @@ int sd_dhcp6_client_is_running(sd_dhcp6_client *client) {
|
|||
}
|
||||
|
||||
int sd_dhcp6_client_start(sd_dhcp6_client *client) {
|
||||
enum DHCP6State state = DHCP6_STATE_SOLICITATION;
|
||||
DHCP6State state = DHCP6_STATE_SOLICITATION;
|
||||
int r;
|
||||
|
||||
assert_return(client, -EINVAL);
|
||||
|
@ -1696,7 +1770,7 @@ int sd_dhcp6_client_start(sd_dhcp6_client *client) {
|
|||
if (client->state != DHCP6_STATE_STOPPED)
|
||||
return -EBUSY;
|
||||
|
||||
if (!client->information_request && !client->request)
|
||||
if (!client->information_request && client->request_ia == 0)
|
||||
return -EINVAL;
|
||||
|
||||
r = client_reset(client);
|
||||
|
@ -1824,7 +1898,7 @@ int sd_dhcp6_client_new(sd_dhcp6_client **ret) {
|
|||
.ia_na.type = SD_DHCP6_OPTION_IA_NA,
|
||||
.ia_pd.type = SD_DHCP6_OPTION_IA_PD,
|
||||
.ifindex = -1,
|
||||
.request = DHCP6_REQUEST_IA_NA,
|
||||
.request_ia = DHCP6_REQUEST_IA_NA | DHCP6_REQUEST_IA_PD,
|
||||
.fd = -1,
|
||||
.req_opts_len = ELEMENTSOF(default_req_opts),
|
||||
.hint_pd_prefix.iapdprefix.lifetime_preferred = (be32_t) -1,
|
||||
|
|
|
@ -13,6 +13,27 @@
|
|||
#include "strv.h"
|
||||
#include "util.h"
|
||||
|
||||
int sd_dhcp6_lease_get_timestamp(sd_dhcp6_lease *lease, clockid_t clock, uint64_t *ret) {
|
||||
assert_return(lease, -EINVAL);
|
||||
assert_return(TRIPLE_TIMESTAMP_HAS_CLOCK(clock), -EOPNOTSUPP);
|
||||
assert_return(clock_supported(clock), -EOPNOTSUPP);
|
||||
assert_return(ret, -EINVAL);
|
||||
|
||||
if (!triple_timestamp_is_set(&lease->timestamp))
|
||||
return -ENODATA;
|
||||
|
||||
*ret = triple_timestamp_by_clock(&lease->timestamp, clock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_dhcp6_lease_get_server_address(sd_dhcp6_lease *lease, struct in6_addr *ret) {
|
||||
assert_return(lease, -EINVAL);
|
||||
assert_return(ret, -EINVAL);
|
||||
|
||||
*ret = lease->server_address;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dhcp6_lease_ia_rebind_expire(const DHCP6IA *ia, uint32_t *expire) {
|
||||
DHCP6Address *addr;
|
||||
uint32_t valid = 0, t;
|
||||
|
@ -52,12 +73,43 @@ DHCP6IA *dhcp6_lease_free_ia(DHCP6IA *ia) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
int dhcp6_lease_set_serverid(sd_dhcp6_lease *lease, const uint8_t *id,
|
||||
size_t len) {
|
||||
int dhcp6_lease_set_clientid(sd_dhcp6_lease *lease, const uint8_t *id, size_t len) {
|
||||
uint8_t *clientid;
|
||||
|
||||
assert_return(lease, -EINVAL);
|
||||
assert_return(id, -EINVAL);
|
||||
assert_return(len > 0, -EINVAL);
|
||||
|
||||
clientid = memdup(id, len);
|
||||
if (!clientid)
|
||||
return -ENOMEM;
|
||||
|
||||
free_and_replace(lease->clientid, clientid);
|
||||
lease->clientid_len = len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dhcp6_lease_get_clientid(sd_dhcp6_lease *lease, uint8_t **ret_id, size_t *ret_len) {
|
||||
assert_return(lease, -EINVAL);
|
||||
|
||||
if (!lease->clientid)
|
||||
return -ENODATA;
|
||||
|
||||
if (ret_id)
|
||||
*ret_id = lease->clientid;
|
||||
if (ret_len)
|
||||
*ret_len = lease->clientid_len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dhcp6_lease_set_serverid(sd_dhcp6_lease *lease, const uint8_t *id, size_t len) {
|
||||
uint8_t *serverid;
|
||||
|
||||
assert_return(lease, -EINVAL);
|
||||
assert_return(id, -EINVAL);
|
||||
assert_return(len > 0, -EINVAL);
|
||||
|
||||
serverid = memdup(id, len);
|
||||
if (!serverid)
|
||||
|
@ -69,16 +121,16 @@ int dhcp6_lease_set_serverid(sd_dhcp6_lease *lease, const uint8_t *id,
|
|||
return 0;
|
||||
}
|
||||
|
||||
int dhcp6_lease_get_serverid(sd_dhcp6_lease *lease, uint8_t **id, size_t *len) {
|
||||
int dhcp6_lease_get_serverid(sd_dhcp6_lease *lease, uint8_t **ret_id, size_t *ret_len) {
|
||||
assert_return(lease, -EINVAL);
|
||||
|
||||
if (!lease->serverid)
|
||||
return -ENOMSG;
|
||||
return -ENODATA;
|
||||
|
||||
if (id)
|
||||
*id = lease->serverid;
|
||||
if (len)
|
||||
*len = lease->serverid_len;
|
||||
if (ret_id)
|
||||
*ret_id = lease->serverid;
|
||||
if (ret_len)
|
||||
*ret_len = lease->serverid_len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -119,24 +171,6 @@ int dhcp6_lease_get_rapid_commit(sd_dhcp6_lease *lease, bool *rapid_commit) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int dhcp6_lease_get_iaid(sd_dhcp6_lease *lease, be32_t *iaid) {
|
||||
assert_return(lease, -EINVAL);
|
||||
assert_return(iaid, -EINVAL);
|
||||
|
||||
*iaid = lease->ia.ia_na.id;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dhcp6_lease_get_pd_iaid(sd_dhcp6_lease *lease, be32_t *iaid) {
|
||||
assert_return(lease, -EINVAL);
|
||||
assert_return(iaid, -EINVAL);
|
||||
|
||||
*iaid = lease->pd.ia_pd.id;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_dhcp6_lease_get_address(sd_dhcp6_lease *lease, struct in6_addr *addr,
|
||||
uint32_t *lifetime_preferred,
|
||||
uint32_t *lifetime_valid) {
|
||||
|
@ -207,12 +241,13 @@ int dhcp6_lease_add_dns(sd_dhcp6_lease *lease, const uint8_t *optval, size_t opt
|
|||
|
||||
int sd_dhcp6_lease_get_dns(sd_dhcp6_lease *lease, const struct in6_addr **ret) {
|
||||
assert_return(lease, -EINVAL);
|
||||
assert_return(ret, -EINVAL);
|
||||
|
||||
if (!lease->dns)
|
||||
return -ENOENT;
|
||||
|
||||
if (ret)
|
||||
*ret = lease->dns;
|
||||
|
||||
return lease->dns_count;
|
||||
}
|
||||
|
||||
|
@ -305,15 +340,16 @@ int dhcp6_lease_add_sntp(sd_dhcp6_lease *lease, const uint8_t *optval, size_t op
|
|||
|
||||
int sd_dhcp6_lease_get_ntp_addrs(sd_dhcp6_lease *lease, const struct in6_addr **ret) {
|
||||
assert_return(lease, -EINVAL);
|
||||
assert_return(ret, -EINVAL);
|
||||
|
||||
if (lease->ntp) {
|
||||
if (ret)
|
||||
*ret = lease->ntp;
|
||||
return lease->ntp_count;
|
||||
}
|
||||
|
||||
if (lease->sntp && !lease->ntp_fqdn) {
|
||||
/* Fallback to the deprecated SNTP option. */
|
||||
if (ret)
|
||||
*ret = lease->sntp;
|
||||
return lease->sntp_count;
|
||||
}
|
||||
|
@ -323,11 +359,11 @@ int sd_dhcp6_lease_get_ntp_addrs(sd_dhcp6_lease *lease, const struct in6_addr **
|
|||
|
||||
int sd_dhcp6_lease_get_ntp_fqdn(sd_dhcp6_lease *lease, char ***ret) {
|
||||
assert_return(lease, -EINVAL);
|
||||
assert_return(ret, -EINVAL);
|
||||
|
||||
if (!lease->ntp_fqdn)
|
||||
return -ENOENT;
|
||||
|
||||
if (ret)
|
||||
*ret = lease->ntp_fqdn;
|
||||
return strv_length(lease->ntp_fqdn);
|
||||
}
|
||||
|
@ -366,6 +402,7 @@ static sd_dhcp6_lease *dhcp6_lease_free(sd_dhcp6_lease *lease) {
|
|||
if (!lease)
|
||||
return NULL;
|
||||
|
||||
free(lease->clientid);
|
||||
free(lease->serverid);
|
||||
dhcp6_lease_free_ia(&lease->ia);
|
||||
dhcp6_lease_free_ia(&lease->pd);
|
||||
|
|
|
@ -202,6 +202,9 @@ static int lldp_rx_receive_datagram(sd_event_source *s, int fd, uint32_t revents
|
|||
|
||||
space = next_datagram_size_fd(fd);
|
||||
if (space < 0) {
|
||||
if (ERRNO_IS_TRANSIENT(space) || ERRNO_IS_DISCONNECT(space))
|
||||
return 0;
|
||||
|
||||
log_lldp_rx_errno(lldp_rx, space, "Failed to determine datagram size to read, ignoring: %m");
|
||||
return 0;
|
||||
}
|
||||
|
@ -214,7 +217,7 @@ static int lldp_rx_receive_datagram(sd_event_source *s, int fd, uint32_t revents
|
|||
|
||||
length = recv(fd, LLDP_NEIGHBOR_RAW(n), n->raw_size, MSG_DONTWAIT);
|
||||
if (length < 0) {
|
||||
if (IN_SET(errno, EAGAIN, EINTR))
|
||||
if (ERRNO_IS_TRANSIENT(errno) || ERRNO_IS_DISCONNECT(errno))
|
||||
return 0;
|
||||
|
||||
log_lldp_rx_errno(lldp_rx, errno, "Failed to read LLDP datagram, ignoring: %m");
|
||||
|
@ -251,7 +254,7 @@ int sd_lldp_rx_is_running(sd_lldp_rx *lldp_rx) {
|
|||
return lldp_rx->fd >= 0;
|
||||
}
|
||||
|
||||
_public_ int sd_lldp_rx_start(sd_lldp_rx *lldp_rx) {
|
||||
int sd_lldp_rx_start(sd_lldp_rx *lldp_rx) {
|
||||
int r;
|
||||
|
||||
assert_return(lldp_rx, -EINVAL);
|
||||
|
@ -285,7 +288,7 @@ fail:
|
|||
return r;
|
||||
}
|
||||
|
||||
_public_ int sd_lldp_rx_stop(sd_lldp_rx *lldp_rx) {
|
||||
int sd_lldp_rx_stop(sd_lldp_rx *lldp_rx) {
|
||||
if (!sd_lldp_rx_is_running(lldp_rx))
|
||||
return 0;
|
||||
|
||||
|
@ -297,7 +300,7 @@ _public_ int sd_lldp_rx_stop(sd_lldp_rx *lldp_rx) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
_public_ int sd_lldp_rx_attach_event(sd_lldp_rx *lldp_rx, sd_event *event, int64_t priority) {
|
||||
int sd_lldp_rx_attach_event(sd_lldp_rx *lldp_rx, sd_event *event, int64_t priority) {
|
||||
int r;
|
||||
|
||||
assert_return(lldp_rx, -EINVAL);
|
||||
|
@ -317,7 +320,7 @@ _public_ int sd_lldp_rx_attach_event(sd_lldp_rx *lldp_rx, sd_event *event, int64
|
|||
return 0;
|
||||
}
|
||||
|
||||
_public_ int sd_lldp_rx_detach_event(sd_lldp_rx *lldp_rx) {
|
||||
int sd_lldp_rx_detach_event(sd_lldp_rx *lldp_rx) {
|
||||
assert_return(lldp_rx, -EINVAL);
|
||||
assert_return(!sd_lldp_rx_is_running(lldp_rx), -EBUSY);
|
||||
|
||||
|
@ -327,13 +330,13 @@ _public_ int sd_lldp_rx_detach_event(sd_lldp_rx *lldp_rx) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
_public_ sd_event* sd_lldp_rx_get_event(sd_lldp_rx *lldp_rx) {
|
||||
sd_event* sd_lldp_rx_get_event(sd_lldp_rx *lldp_rx) {
|
||||
assert_return(lldp_rx, NULL);
|
||||
|
||||
return lldp_rx->event;
|
||||
}
|
||||
|
||||
_public_ int sd_lldp_rx_set_callback(sd_lldp_rx *lldp_rx, sd_lldp_rx_callback_t cb, void *userdata) {
|
||||
int sd_lldp_rx_set_callback(sd_lldp_rx *lldp_rx, sd_lldp_rx_callback_t cb, void *userdata) {
|
||||
assert_return(lldp_rx, -EINVAL);
|
||||
|
||||
lldp_rx->callback = cb;
|
||||
|
@ -342,7 +345,7 @@ _public_ int sd_lldp_rx_set_callback(sd_lldp_rx *lldp_rx, sd_lldp_rx_callback_t
|
|||
return 0;
|
||||
}
|
||||
|
||||
_public_ int sd_lldp_rx_set_ifindex(sd_lldp_rx *lldp_rx, int ifindex) {
|
||||
int sd_lldp_rx_set_ifindex(sd_lldp_rx *lldp_rx, int ifindex) {
|
||||
assert_return(lldp_rx, -EINVAL);
|
||||
assert_return(ifindex > 0, -EINVAL);
|
||||
assert_return(!sd_lldp_rx_is_running(lldp_rx), -EBUSY);
|
||||
|
@ -394,7 +397,7 @@ static sd_lldp_rx *lldp_rx_free(sd_lldp_rx *lldp_rx) {
|
|||
|
||||
DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_lldp_rx, sd_lldp_rx, lldp_rx_free);
|
||||
|
||||
_public_ int sd_lldp_rx_new(sd_lldp_rx **ret) {
|
||||
int sd_lldp_rx_new(sd_lldp_rx **ret) {
|
||||
_cleanup_(sd_lldp_rx_unrefp) sd_lldp_rx *lldp_rx = NULL;
|
||||
|
||||
assert_return(ret, -EINVAL);
|
||||
|
@ -462,7 +465,7 @@ static inline int neighbor_compare_func(sd_lldp_neighbor * const *a, sd_lldp_nei
|
|||
return lldp_neighbor_id_compare_func(&(*a)->id, &(*b)->id);
|
||||
}
|
||||
|
||||
_public_ int sd_lldp_rx_get_neighbors(sd_lldp_rx *lldp_rx, sd_lldp_neighbor ***ret) {
|
||||
int sd_lldp_rx_get_neighbors(sd_lldp_rx *lldp_rx, sd_lldp_neighbor ***ret) {
|
||||
_cleanup_free_ sd_lldp_neighbor **l = NULL;
|
||||
sd_lldp_neighbor *n;
|
||||
int k = 0;
|
||||
|
@ -491,7 +494,7 @@ _public_ int sd_lldp_rx_get_neighbors(sd_lldp_rx *lldp_rx, sd_lldp_neighbor ***r
|
|||
return k;
|
||||
}
|
||||
|
||||
_public_ int sd_lldp_rx_set_neighbors_max(sd_lldp_rx *lldp_rx, uint64_t m) {
|
||||
int sd_lldp_rx_set_neighbors_max(sd_lldp_rx *lldp_rx, uint64_t m) {
|
||||
assert_return(lldp_rx, -EINVAL);
|
||||
assert_return(m > 0, -EINVAL);
|
||||
|
||||
|
@ -501,7 +504,7 @@ _public_ int sd_lldp_rx_set_neighbors_max(sd_lldp_rx *lldp_rx, uint64_t m) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
_public_ int sd_lldp_rx_match_capabilities(sd_lldp_rx *lldp_rx, uint16_t mask) {
|
||||
int sd_lldp_rx_match_capabilities(sd_lldp_rx *lldp_rx, uint16_t mask) {
|
||||
assert_return(lldp_rx, -EINVAL);
|
||||
assert_return(mask != 0, -EINVAL);
|
||||
|
||||
|
@ -510,7 +513,7 @@ _public_ int sd_lldp_rx_match_capabilities(sd_lldp_rx *lldp_rx, uint16_t mask) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
_public_ int sd_lldp_rx_set_filter_address(sd_lldp_rx *lldp_rx, const struct ether_addr *addr) {
|
||||
int sd_lldp_rx_set_filter_address(sd_lldp_rx *lldp_rx, const struct ether_addr *addr) {
|
||||
assert_return(lldp_rx, -EINVAL);
|
||||
|
||||
/* In order to deal nicely with bridges that send back our own packets, allow one address to be filtered, so
|
||||
|
|
|
@ -71,6 +71,7 @@ struct sd_event_source {
|
|||
uint64_t prepare_iteration;
|
||||
|
||||
sd_event_destroy_t destroy_callback;
|
||||
sd_event_handler_t ratelimit_expire_callback;
|
||||
|
||||
LIST_FIELDS(sd_event_source, sources);
|
||||
|
||||
|
@ -214,6 +215,11 @@ struct inotify_data {
|
|||
* the events locally if they can't be coalesced). */
|
||||
unsigned n_pending;
|
||||
|
||||
/* If this counter is non-zero, don't GC the inotify data object even if not used to watch any inode
|
||||
* anymore. This is useful to pin the object for a bit longer, after the last event source needing it
|
||||
* is gone. */
|
||||
unsigned n_busy;
|
||||
|
||||
/* A linked list of all inotify objects with data already read, that still need processing. We keep this list
|
||||
* to make it efficient to figure out what inotify objects to process data on next. */
|
||||
LIST_FIELDS(struct inotify_data, buffered);
|
||||
|
|
|
@ -86,6 +86,30 @@ int event_reset_time(
|
|||
return created;
|
||||
}
|
||||
|
||||
int event_reset_time_relative(
|
||||
sd_event *e,
|
||||
sd_event_source **s,
|
||||
clockid_t clock,
|
||||
uint64_t usec,
|
||||
uint64_t accuracy,
|
||||
sd_event_time_handler_t callback,
|
||||
void *userdata,
|
||||
int64_t priority,
|
||||
const char *description,
|
||||
bool force_reset) {
|
||||
|
||||
usec_t usec_now;
|
||||
int r;
|
||||
|
||||
assert(e);
|
||||
|
||||
r = sd_event_now(e, clock, &usec_now);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "sd-event: Failed to get the current time: %m");
|
||||
|
||||
return event_reset_time(e, s, clock, usec_add(usec_now, usec), accuracy, callback, userdata, priority, description, force_reset);
|
||||
}
|
||||
|
||||
int event_source_disable(sd_event_source *s) {
|
||||
if (!s)
|
||||
return 0;
|
||||
|
|
|
@ -5,9 +5,27 @@
|
|||
|
||||
#include "sd-event.h"
|
||||
|
||||
int event_reset_time(sd_event *e, sd_event_source **s,
|
||||
clockid_t clock, uint64_t usec, uint64_t accuracy,
|
||||
sd_event_time_handler_t callback, void *userdata,
|
||||
int64_t priority, const char *description, bool force_reset);
|
||||
int event_reset_time(
|
||||
sd_event *e,
|
||||
sd_event_source **s,
|
||||
clockid_t clock,
|
||||
uint64_t usec,
|
||||
uint64_t accuracy,
|
||||
sd_event_time_handler_t callback,
|
||||
void *userdata,
|
||||
int64_t priority,
|
||||
const char *description,
|
||||
bool force_reset);
|
||||
int event_reset_time_relative(
|
||||
sd_event *e,
|
||||
sd_event_source **s,
|
||||
clockid_t clock,
|
||||
uint64_t usec,
|
||||
uint64_t accuracy,
|
||||
sd_event_time_handler_t callback,
|
||||
void *userdata,
|
||||
int64_t priority,
|
||||
const char *description,
|
||||
bool force_reset);
|
||||
int event_source_disable(sd_event_source *s);
|
||||
int event_source_is_enabled(sd_event_source *s);
|
||||
|
|
|
@ -1824,6 +1824,29 @@ static void event_free_inode_data(
|
|||
free(d);
|
||||
}
|
||||
|
||||
static void event_gc_inotify_data(
|
||||
sd_event *e,
|
||||
struct inotify_data *d) {
|
||||
|
||||
assert(e);
|
||||
|
||||
/* GCs the inotify data object if we don't need it anymore. That's the case if we don't want to watch
|
||||
* any inode with it anymore, which in turn happens if no event source of this priority is interested
|
||||
* in any inode any longer. That said, we maintain an extra busy counter: if non-zero we'll delay GC
|
||||
* (under the expectation that the GC is called again once the counter is decremented). */
|
||||
|
||||
if (!d)
|
||||
return;
|
||||
|
||||
if (!hashmap_isempty(d->inodes))
|
||||
return;
|
||||
|
||||
if (d->n_busy > 0)
|
||||
return;
|
||||
|
||||
event_free_inotify_data(e, d);
|
||||
}
|
||||
|
||||
static void event_gc_inode_data(
|
||||
sd_event *e,
|
||||
struct inode_data *d) {
|
||||
|
@ -1841,8 +1864,7 @@ static void event_gc_inode_data(
|
|||
inotify_data = d->inotify_data;
|
||||
event_free_inode_data(e, d);
|
||||
|
||||
if (inotify_data && hashmap_isempty(inotify_data->inodes))
|
||||
event_free_inotify_data(e, inotify_data);
|
||||
event_gc_inotify_data(e, inotify_data);
|
||||
}
|
||||
|
||||
static int event_make_inode_data(
|
||||
|
@ -1971,24 +1993,25 @@ static int inotify_exit_callback(sd_event_source *s, const struct inotify_event
|
|||
return sd_event_exit(sd_event_source_get_event(s), PTR_TO_INT(userdata));
|
||||
}
|
||||
|
||||
_public_ int sd_event_add_inotify(
|
||||
static int event_add_inotify_fd_internal(
|
||||
sd_event *e,
|
||||
sd_event_source **ret,
|
||||
const char *path,
|
||||
int fd,
|
||||
bool donate,
|
||||
uint32_t mask,
|
||||
sd_event_inotify_handler_t callback,
|
||||
void *userdata) {
|
||||
|
||||
_cleanup_close_ int donated_fd = donate ? fd : -1;
|
||||
_cleanup_(source_freep) sd_event_source *s = NULL;
|
||||
struct inotify_data *inotify_data = NULL;
|
||||
struct inode_data *inode_data = NULL;
|
||||
_cleanup_close_ int fd = -1;
|
||||
_cleanup_(source_freep) sd_event_source *s = NULL;
|
||||
struct stat st;
|
||||
int r;
|
||||
|
||||
assert_return(e, -EINVAL);
|
||||
assert_return(e = event_resolve(e), -ENOPKG);
|
||||
assert_return(path, -EINVAL);
|
||||
assert_return(fd >= 0, -EBADF);
|
||||
assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
|
||||
assert_return(!event_pid_changed(e), -ECHILD);
|
||||
|
||||
|
@ -2001,12 +2024,6 @@ _public_ int sd_event_add_inotify(
|
|||
if (mask & IN_MASK_ADD)
|
||||
return -EINVAL;
|
||||
|
||||
fd = open(path, O_PATH|O_CLOEXEC|
|
||||
(mask & IN_ONLYDIR ? O_DIRECTORY : 0)|
|
||||
(mask & IN_DONT_FOLLOW ? O_NOFOLLOW : 0));
|
||||
if (fd < 0)
|
||||
return -errno;
|
||||
|
||||
if (fstat(fd, &st) < 0)
|
||||
return -errno;
|
||||
|
||||
|
@ -2026,14 +2043,24 @@ _public_ int sd_event_add_inotify(
|
|||
|
||||
r = event_make_inode_data(e, inotify_data, st.st_dev, st.st_ino, &inode_data);
|
||||
if (r < 0) {
|
||||
event_free_inotify_data(e, inotify_data);
|
||||
event_gc_inotify_data(e, inotify_data);
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Keep the O_PATH fd around until the first iteration of the loop, so that we can still change the priority of
|
||||
* the event source, until then, for which we need the original inode. */
|
||||
if (inode_data->fd < 0) {
|
||||
inode_data->fd = TAKE_FD(fd);
|
||||
if (donated_fd >= 0)
|
||||
inode_data->fd = TAKE_FD(donated_fd);
|
||||
else {
|
||||
inode_data->fd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
|
||||
if (inode_data->fd < 0) {
|
||||
r = -errno;
|
||||
event_gc_inode_data(e, inode_data);
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
LIST_PREPEND(to_close, e->inode_data_to_close, inode_data);
|
||||
}
|
||||
|
||||
|
@ -2046,8 +2073,6 @@ _public_ int sd_event_add_inotify(
|
|||
if (r < 0)
|
||||
return r;
|
||||
|
||||
(void) sd_event_source_set_description(s, path);
|
||||
|
||||
if (ret)
|
||||
*ret = s;
|
||||
TAKE_PTR(s);
|
||||
|
@ -2055,6 +2080,48 @@ _public_ int sd_event_add_inotify(
|
|||
return 0;
|
||||
}
|
||||
|
||||
_public_ int sd_event_add_inotify_fd(
|
||||
sd_event *e,
|
||||
sd_event_source **ret,
|
||||
int fd,
|
||||
uint32_t mask,
|
||||
sd_event_inotify_handler_t callback,
|
||||
void *userdata) {
|
||||
|
||||
return event_add_inotify_fd_internal(e, ret, fd, /* donate= */ false, mask, callback, userdata);
|
||||
}
|
||||
|
||||
_public_ int sd_event_add_inotify(
|
||||
sd_event *e,
|
||||
sd_event_source **ret,
|
||||
const char *path,
|
||||
uint32_t mask,
|
||||
sd_event_inotify_handler_t callback,
|
||||
void *userdata) {
|
||||
|
||||
sd_event_source *s = NULL; /* avoid false maybe-uninitialized warning */
|
||||
int fd, r;
|
||||
|
||||
assert_return(path, -EINVAL);
|
||||
|
||||
fd = open(path, O_PATH|O_CLOEXEC|
|
||||
(mask & IN_ONLYDIR ? O_DIRECTORY : 0)|
|
||||
(mask & IN_DONT_FOLLOW ? O_NOFOLLOW : 0));
|
||||
if (fd < 0)
|
||||
return -errno;
|
||||
|
||||
r = event_add_inotify_fd_internal(e, &s, fd, /* donate= */ true, mask, callback, userdata);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
(void) sd_event_source_set_description(s, path);
|
||||
|
||||
if (ret)
|
||||
*ret = s;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static sd_event_source* event_source_free(sd_event_source *s) {
|
||||
if (!s)
|
||||
return NULL;
|
||||
|
@ -2845,7 +2912,7 @@ fail:
|
|||
return r;
|
||||
}
|
||||
|
||||
static int event_source_leave_ratelimit(sd_event_source *s) {
|
||||
static int event_source_leave_ratelimit(sd_event_source *s, bool run_callback) {
|
||||
int r;
|
||||
|
||||
assert(s);
|
||||
|
@ -2877,6 +2944,30 @@ static int event_source_leave_ratelimit(sd_event_source *s) {
|
|||
ratelimit_reset(&s->rate_limit);
|
||||
|
||||
log_debug("Event source %p (%s) left rate limit state.", s, strna(s->description));
|
||||
|
||||
if (run_callback && s->ratelimit_expire_callback) {
|
||||
s->dispatching = true;
|
||||
r = s->ratelimit_expire_callback(s, s->userdata);
|
||||
s->dispatching = false;
|
||||
|
||||
if (r < 0) {
|
||||
log_debug_errno(r, "Ratelimit expiry callback of event source %s (type %s) returned error, %s: %m",
|
||||
strna(s->description),
|
||||
event_source_type_to_string(s->type),
|
||||
s->exit_on_failure ? "exiting" : "disabling");
|
||||
|
||||
if (s->exit_on_failure)
|
||||
(void) sd_event_exit(s->event, r);
|
||||
}
|
||||
|
||||
if (s->n_ref == 0)
|
||||
source_free(s);
|
||||
else if (r < 0)
|
||||
assert_se(sd_event_source_set_enabled(s, SD_EVENT_OFF) >= 0);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
|
@ -3055,7 +3146,7 @@ static int flush_timer(sd_event *e, int fd, uint32_t events, usec_t *next) {
|
|||
|
||||
ss = read(fd, &x, sizeof(x));
|
||||
if (ss < 0) {
|
||||
if (IN_SET(errno, EAGAIN, EINTR))
|
||||
if (ERRNO_IS_TRANSIENT(errno))
|
||||
return 0;
|
||||
|
||||
return -errno;
|
||||
|
@ -3076,6 +3167,7 @@ static int process_timer(
|
|||
struct clock_data *d) {
|
||||
|
||||
sd_event_source *s;
|
||||
bool callback_invoked = false;
|
||||
int r;
|
||||
|
||||
assert(e);
|
||||
|
@ -3093,9 +3185,11 @@ static int process_timer(
|
|||
* again. */
|
||||
assert(s->ratelimited);
|
||||
|
||||
r = event_source_leave_ratelimit(s);
|
||||
r = event_source_leave_ratelimit(s, /* run_callback */ true);
|
||||
if (r < 0)
|
||||
return r;
|
||||
else if (r == 1)
|
||||
callback_invoked = true;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
@ -3110,7 +3204,7 @@ static int process_timer(
|
|||
event_source_time_prioq_reshuffle(s);
|
||||
}
|
||||
|
||||
return 0;
|
||||
return callback_invoked;
|
||||
}
|
||||
|
||||
static int process_child(sd_event *e, int64_t threshold, int64_t *ret_min_priority) {
|
||||
|
@ -3258,7 +3352,7 @@ static int process_signal(sd_event *e, struct signal_data *d, uint32_t events, i
|
|||
|
||||
n = read(d->fd, &si, sizeof(si));
|
||||
if (n < 0) {
|
||||
if (IN_SET(errno, EAGAIN, EINTR))
|
||||
if (ERRNO_IS_TRANSIENT(errno))
|
||||
return 0;
|
||||
|
||||
return -errno;
|
||||
|
@ -3312,7 +3406,7 @@ static int event_inotify_data_read(sd_event *e, struct inotify_data *d, uint32_t
|
|||
|
||||
n = read(d->fd, &d->buffer, sizeof(d->buffer));
|
||||
if (n < 0) {
|
||||
if (IN_SET(errno, EAGAIN, EINTR))
|
||||
if (ERRNO_IS_TRANSIENT(errno))
|
||||
return 0;
|
||||
|
||||
return -errno;
|
||||
|
@ -3560,13 +3654,23 @@ static int source_dispatch(sd_event_source *s) {
|
|||
sz = offsetof(struct inotify_event, name) + d->buffer.ev.len;
|
||||
assert(d->buffer_filled >= sz);
|
||||
|
||||
/* If the inotify callback destroys the event source then this likely means we don't need to
|
||||
* watch the inode anymore, and thus also won't need the inotify object anymore. But if we'd
|
||||
* free it immediately, then we couldn't drop the event from the inotify event queue without
|
||||
* memory corruption anymore, as below. Hence, let's not free it immediately, but mark it
|
||||
* "busy" with a counter (which will ensure it's not GC'ed away prematurely). Let's then
|
||||
* explicitly GC it after we are done dropping the inotify event from the buffer. */
|
||||
d->n_busy++;
|
||||
r = s->inotify.callback(s, &d->buffer.ev, s->userdata);
|
||||
d->n_busy--;
|
||||
|
||||
/* When no event is pending anymore on this inotify object, then let's drop the event from the
|
||||
* buffer. */
|
||||
/* When no event is pending anymore on this inotify object, then let's drop the event from
|
||||
* the inotify event queue buffer. */
|
||||
if (d->n_pending == 0)
|
||||
event_inotify_data_drop(e, d, sz);
|
||||
|
||||
/* Now we don't want to access 'd' anymore, it's OK to GC now. */
|
||||
event_gc_inotify_data(e, d);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -3591,7 +3695,7 @@ static int source_dispatch(sd_event_source *s) {
|
|||
if (s->n_ref == 0)
|
||||
source_free(s);
|
||||
else if (r < 0)
|
||||
sd_event_source_set_enabled(s, SD_EVENT_OFF);
|
||||
assert_se(sd_event_source_set_enabled(s, SD_EVENT_OFF) >= 0);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@ -3632,7 +3736,7 @@ static int event_prepare(sd_event *e) {
|
|||
if (s->n_ref == 0)
|
||||
source_free(s);
|
||||
else if (r < 0)
|
||||
sd_event_source_set_enabled(s, SD_EVENT_OFF);
|
||||
assert_se(sd_event_source_set_enabled(s, SD_EVENT_OFF) >= 0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -3693,10 +3797,7 @@ static int arm_watchdog(sd_event *e) {
|
|||
if (its.it_value.tv_sec == 0 && its.it_value.tv_nsec == 0)
|
||||
its.it_value.tv_nsec = 1;
|
||||
|
||||
if (timerfd_settime(e->watchdog_fd, TFD_TIMER_ABSTIME, &its, NULL) < 0)
|
||||
return -errno;
|
||||
|
||||
return 0;
|
||||
return RET_NERRNO(timerfd_settime(e->watchdog_fd, TFD_TIMER_ABSTIME, &its, NULL));
|
||||
}
|
||||
|
||||
static int process_watchdog(sd_event *e) {
|
||||
|
@ -3806,7 +3907,7 @@ static int epoll_wait_usec(
|
|||
int maxevents,
|
||||
usec_t timeout) {
|
||||
|
||||
int r, msec;
|
||||
int msec;
|
||||
#if 0
|
||||
static bool epoll_pwait2_absent = false;
|
||||
|
||||
|
@ -3846,14 +3947,7 @@ static int epoll_wait_usec(
|
|||
msec = (int) k;
|
||||
}
|
||||
|
||||
r = epoll_wait(fd,
|
||||
events,
|
||||
maxevents,
|
||||
msec);
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
|
||||
return r;
|
||||
return RET_NERRNO(epoll_wait(fd, events, maxevents, msec));
|
||||
}
|
||||
|
||||
static int process_epoll(sd_event *e, usec_t timeout, int64_t threshold, int64_t *ret_min_priority) {
|
||||
|
@ -4024,6 +4118,10 @@ _public_ int sd_event_wait(sd_event *e, uint64_t timeout) {
|
|||
if (r < 0)
|
||||
goto finish;
|
||||
|
||||
r = process_inotify(e);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
|
||||
r = process_timer(e, e->timestamp.realtime, &e->realtime);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
|
@ -4032,10 +4130,6 @@ _public_ int sd_event_wait(sd_event *e, uint64_t timeout) {
|
|||
if (r < 0)
|
||||
goto finish;
|
||||
|
||||
r = process_timer(e, e->timestamp.monotonic, &e->monotonic);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
|
||||
r = process_timer(e, e->timestamp.realtime, &e->realtime_alarm);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
|
@ -4044,9 +4138,20 @@ _public_ int sd_event_wait(sd_event *e, uint64_t timeout) {
|
|||
if (r < 0)
|
||||
goto finish;
|
||||
|
||||
r = process_inotify(e);
|
||||
r = process_timer(e, e->timestamp.monotonic, &e->monotonic);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
else if (r == 1) {
|
||||
/* Ratelimit expiry callback was called. Let's postpone processing pending sources and
|
||||
* put loop in the initial state in order to evaluate (in the next iteration) also sources
|
||||
* there were potentially re-enabled by the callback.
|
||||
*
|
||||
* Wondering why we treat only this invocation of process_timer() differently? Once event
|
||||
* source is ratelimited we essentially transform it into CLOCK_MONOTONIC timer hence
|
||||
* ratelimit expiry callback is never called for any other timer type. */
|
||||
r = 0;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (event_next_pending(e)) {
|
||||
e->state = SD_EVENT_PENDING;
|
||||
|
@ -4117,7 +4222,7 @@ _public_ int sd_event_run(sd_event *e, uint64_t timeout) {
|
|||
|
||||
this_run = now(CLOCK_MONOTONIC);
|
||||
|
||||
l = u64log2(this_run - e->last_run_usec);
|
||||
l = log2u64(this_run - e->last_run_usec);
|
||||
assert(l < ELEMENTSOF(e->delays));
|
||||
e->delays[l]++;
|
||||
|
||||
|
@ -4416,7 +4521,7 @@ _public_ int sd_event_source_set_ratelimit(sd_event_source *s, uint64_t interval
|
|||
|
||||
/* When ratelimiting is configured we'll always reset the rate limit state first and start fresh,
|
||||
* non-ratelimited. */
|
||||
r = event_source_leave_ratelimit(s);
|
||||
r = event_source_leave_ratelimit(s, /* run_callback */ false);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
@ -4424,6 +4529,13 @@ _public_ int sd_event_source_set_ratelimit(sd_event_source *s, uint64_t interval
|
|||
return 0;
|
||||
}
|
||||
|
||||
_public_ int sd_event_source_set_ratelimit_expire_callback(sd_event_source *s, sd_event_handler_t callback) {
|
||||
assert_return(s, -EINVAL);
|
||||
|
||||
s->ratelimit_expire_callback = callback;
|
||||
return 0;
|
||||
}
|
||||
|
||||
_public_ int sd_event_source_get_ratelimit(sd_event_source *s, uint64_t *ret_interval, unsigned *ret_burst) {
|
||||
assert_return(s, -EINVAL);
|
||||
|
||||
|
|
|
@ -224,7 +224,7 @@ int id128_get_product(sd_id128_t *ret) {
|
|||
|
||||
r = id128_read("/sys/class/dmi/id/product_uuid", ID128_UUID, &uuid);
|
||||
if (r == -ENOENT)
|
||||
r = id128_read("/sys/firmware/devicetree/base/vm,uuid", ID128_UUID, &uuid);
|
||||
r = id128_read("/proc/device-tree/vm,uuid", ID128_UUID, &uuid);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
|
|
@ -6,21 +6,14 @@
|
|||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#if HAVE_OPENSSL
|
||||
#include <openssl/hmac.h>
|
||||
#include <openssl/sha.h>
|
||||
#endif
|
||||
|
||||
#include "sd-id128.h"
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "fd-util.h"
|
||||
#include "hexdecoct.h"
|
||||
#include "hmac.h"
|
||||
#include "id128-util.h"
|
||||
#include "io-util.h"
|
||||
#if !HAVE_OPENSSL
|
||||
#include "khash.h"
|
||||
#endif
|
||||
#include "macro.h"
|
||||
#include "missing_syscall.h"
|
||||
#include "random-util.h"
|
||||
|
@ -283,43 +276,15 @@ _public_ int sd_id128_randomize(sd_id128_t *ret) {
|
|||
}
|
||||
|
||||
static int get_app_specific(sd_id128_t base, sd_id128_t app_id, sd_id128_t *ret) {
|
||||
uint8_t hmac[SHA256_DIGEST_SIZE];
|
||||
sd_id128_t result;
|
||||
|
||||
assert(ret);
|
||||
|
||||
#if HAVE_OPENSSL
|
||||
/* We prefer doing this in-process, since we this means we are not dependent on kernel configuration,
|
||||
* and this also works in locked down container environments. But some distros don't like OpenSSL's
|
||||
* license and its (in-) compatibility with GPL2, hence also support khash */
|
||||
uint8_t md[256/8];
|
||||
if (!HMAC(EVP_sha256(),
|
||||
&base, sizeof(base),
|
||||
(const unsigned char*) &app_id, sizeof(app_id),
|
||||
md, NULL))
|
||||
return -ENOTRECOVERABLE;
|
||||
hmac_sha256(&base, sizeof(base), &app_id, sizeof(app_id), hmac);
|
||||
|
||||
/* Take only the first half. */
|
||||
memcpy(&result, md, MIN(sizeof(md), sizeof(result)));
|
||||
#else
|
||||
_cleanup_(khash_unrefp) khash *h = NULL;
|
||||
const void *p;
|
||||
int r;
|
||||
|
||||
r = khash_new_with_key(&h, "hmac(sha256)", &base, sizeof(base));
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = khash_put(h, &app_id, sizeof(app_id));
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = khash_digest_data(h, &p);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* We chop off the trailing 16 bytes */
|
||||
memcpy(&result, p, MIN(khash_get_size(h), sizeof(result)));
|
||||
#endif
|
||||
memcpy(&result, hmac, MIN(sizeof(hmac), sizeof(result)));
|
||||
|
||||
*ret = id128_make_v4_uuid(result);
|
||||
return 0;
|
||||
|
|
|
@ -97,6 +97,7 @@ enum {
|
|||
SD_DHCP_OPTION_SIP_SERVER = 120,
|
||||
SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE = 121,
|
||||
SD_DHCP_OPTION_MUD_URL = 161,
|
||||
SD_DHCP_OPTION_6RD = 212,
|
||||
SD_DHCP_OPTION_PRIVATE_BASE = 224,
|
||||
/* Windows 10 option to send when Anonymize=true */
|
||||
SD_DHCP_OPTION_PRIVATE_CLASSLESS_STATIC_ROUTE = 249,
|
||||
|
|
|
@ -71,6 +71,13 @@ int sd_dhcp_lease_get_routes(sd_dhcp_lease *lease, sd_dhcp_route ***routes);
|
|||
int sd_dhcp_lease_get_vendor_specific(sd_dhcp_lease *lease, const void **data, size_t *data_len);
|
||||
int sd_dhcp_lease_get_client_id(sd_dhcp_lease *lease, const void **client_id, size_t *client_id_len);
|
||||
int sd_dhcp_lease_get_timezone(sd_dhcp_lease *lease, const char **timezone);
|
||||
int sd_dhcp_lease_get_6rd(
|
||||
sd_dhcp_lease *lease,
|
||||
uint8_t *ret_ipv4masklen,
|
||||
uint8_t *ret_prefixlen,
|
||||
struct in6_addr *ret_prefix,
|
||||
const struct in_addr **ret_br_addresses,
|
||||
size_t *ret_n_br_addresses);
|
||||
|
||||
int sd_dhcp_route_get_destination(sd_dhcp_route *route, struct in_addr *destination);
|
||||
int sd_dhcp_route_get_destination_prefix_length(sd_dhcp_route *route, uint8_t *length);
|
||||
|
|
|
@ -39,44 +39,151 @@ enum {
|
|||
SD_DHCP6_CLIENT_EVENT_INFORMATION_REQUEST = 13,
|
||||
};
|
||||
|
||||
/* https://www.iana.org/assignments/dhcpv6-parameters/dhcpv6-parameters.xhtml#dhcpv6-parameters-2 */
|
||||
enum {
|
||||
SD_DHCP6_OPTION_CLIENTID = 1,
|
||||
SD_DHCP6_OPTION_SERVERID = 2,
|
||||
SD_DHCP6_OPTION_IA_NA = 3,
|
||||
SD_DHCP6_OPTION_IA_TA = 4,
|
||||
SD_DHCP6_OPTION_IAADDR = 5,
|
||||
SD_DHCP6_OPTION_ORO = 6,
|
||||
SD_DHCP6_OPTION_PREFERENCE = 7,
|
||||
SD_DHCP6_OPTION_ELAPSED_TIME = 8,
|
||||
SD_DHCP6_OPTION_RELAY_MSG = 9,
|
||||
SD_DHCP6_OPTION_CLIENTID = 1, /* RFC 8415 */
|
||||
SD_DHCP6_OPTION_SERVERID = 2, /* RFC 8415 */
|
||||
SD_DHCP6_OPTION_IA_NA = 3, /* RFC 8415 */
|
||||
SD_DHCP6_OPTION_IA_TA = 4, /* RFC 8415 */
|
||||
SD_DHCP6_OPTION_IAADDR = 5, /* RFC 8415 */
|
||||
SD_DHCP6_OPTION_ORO = 6, /* RFC 8415 */
|
||||
SD_DHCP6_OPTION_PREFERENCE = 7, /* RFC 8415 */
|
||||
SD_DHCP6_OPTION_ELAPSED_TIME = 8, /* RFC 8415 */
|
||||
SD_DHCP6_OPTION_RELAY_MSG = 9, /* RFC 8415 */
|
||||
/* option code 10 is unassigned */
|
||||
SD_DHCP6_OPTION_AUTH = 11,
|
||||
SD_DHCP6_OPTION_UNICAST = 12,
|
||||
SD_DHCP6_OPTION_STATUS_CODE = 13,
|
||||
SD_DHCP6_OPTION_RAPID_COMMIT = 14,
|
||||
SD_DHCP6_OPTION_USER_CLASS = 15,
|
||||
SD_DHCP6_OPTION_VENDOR_CLASS = 16,
|
||||
SD_DHCP6_OPTION_VENDOR_OPTS = 17,
|
||||
SD_DHCP6_OPTION_INTERFACE_ID = 18,
|
||||
SD_DHCP6_OPTION_RECONF_MSG = 19,
|
||||
SD_DHCP6_OPTION_RECONF_ACCEPT = 20,
|
||||
|
||||
SD_DHCP6_OPTION_AUTH = 11, /* RFC 8415 */
|
||||
SD_DHCP6_OPTION_UNICAST = 12, /* RFC 8415 */
|
||||
SD_DHCP6_OPTION_STATUS_CODE = 13, /* RFC 8415 */
|
||||
SD_DHCP6_OPTION_RAPID_COMMIT = 14, /* RFC 8415 */
|
||||
SD_DHCP6_OPTION_USER_CLASS = 15, /* RFC 8415 */
|
||||
SD_DHCP6_OPTION_VENDOR_CLASS = 16, /* RFC 8415 */
|
||||
SD_DHCP6_OPTION_VENDOR_OPTS = 17, /* RFC 8415 */
|
||||
SD_DHCP6_OPTION_INTERFACE_ID = 18, /* RFC 8415 */
|
||||
SD_DHCP6_OPTION_RECONF_MSG = 19, /* RFC 8415 */
|
||||
SD_DHCP6_OPTION_RECONF_ACCEPT = 20, /* RFC 8415 */
|
||||
SD_DHCP6_OPTION_SIP_SERVER_DOMAIN_NAME = 21, /* RFC 3319 */
|
||||
SD_DHCP6_OPTION_SIP_SERVER_ADDRESS = 22, /* RFC 3319 */
|
||||
SD_DHCP6_OPTION_DNS_SERVERS = 23, /* RFC 3646 */
|
||||
SD_DHCP6_OPTION_DOMAIN_LIST = 24, /* RFC 3646 */
|
||||
SD_DHCP6_OPTION_IA_PD = 25, /* RFC 3633, prefix delegation */
|
||||
SD_DHCP6_OPTION_IA_PD_PREFIX = 26, /* RFC 3633, prefix delegation */
|
||||
|
||||
SD_DHCP6_OPTION_IA_PD = 25, /* RFC 3633, RFC 8415 */
|
||||
SD_DHCP6_OPTION_IA_PD_PREFIX = 26, /* RFC 3633, RFC 8415 */
|
||||
SD_DHCP6_OPTION_NIS_SERVERS = 27, /* RFC 3898 */
|
||||
SD_DHCP6_OPTION_NISP_SERVERS = 28, /* RFC 3898 */
|
||||
SD_DHCP6_OPTION_NIS_DOMAIN_NAME = 29, /* RFC 3898 */
|
||||
SD_DHCP6_OPTION_NISP_DOMAIN_NAME = 30, /* RFC 3898 */
|
||||
SD_DHCP6_OPTION_SNTP_SERVERS = 31, /* RFC 4075, deprecated */
|
||||
SD_DHCP6_OPTION_INFORMATION_REFRESH_TIME = 32, /* RFC 8415, sec. 21.23 */
|
||||
|
||||
SD_DHCP6_OPTION_INFORMATION_REFRESH_TIME = 32, /* RFC 4242, 8415, sec. 21.23 */
|
||||
SD_DHCP6_OPTION_BCMCS_SERVER_D = 33, /* RFC 4280 */
|
||||
SD_DHCP6_OPTION_BCMCS_SERVER_A = 34, /* RFC 4280 */
|
||||
/* option code 35 is unassigned */
|
||||
|
||||
SD_DHCP6_OPTION_FQDN = 39, /* RFC 4704 */
|
||||
|
||||
SD_DHCP6_OPTION_GEOCONF_CIVIC = 36, /* RFC 4776 */
|
||||
SD_DHCP6_OPTION_REMOTE_ID = 37, /* RFC 4649 */
|
||||
SD_DHCP6_OPTION_SUBSCRIBER_ID = 38, /* RFC 4580 */
|
||||
SD_DHCP6_OPTION_CLIENT_FQDN = 39, /* RFC 4704 */
|
||||
SD_DHCP6_OPTION_PANA_AGENT = 40, /* RFC 5192 */
|
||||
SD_DHCP6_OPTION_NEW_POSIX_TIMEZONE = 41, /* RFC 4833 */
|
||||
SD_DHCP6_OPTION_NEW_TZDB_TIMEZONE = 42, /* RFC 4833 */
|
||||
SD_DHCP6_OPTION_ERO = 43, /* RFC 4994 */
|
||||
SD_DHCP6_OPTION_LQ_QUERY = 44, /* RFC 5007 */
|
||||
SD_DHCP6_OPTION_CLIENT_DATA = 45, /* RFC 5007 */
|
||||
SD_DHCP6_OPTION_CLT_TIME = 46, /* RFC 5007 */
|
||||
SD_DHCP6_OPTION_LQ_RELAY_DATA = 47, /* RFC 5007 */
|
||||
SD_DHCP6_OPTION_LQ_CLIENT_LINK = 48, /* RFC 5007 */
|
||||
SD_DHCP6_OPTION_MIP6_HNIDF = 49, /* RFC 6610 */
|
||||
SD_DHCP6_OPTION_MIP6_VDINF = 50, /* RFC 6610 */
|
||||
SD_DHCP6_OPTION_V6_LOST = 51, /* RFC 5223 */
|
||||
SD_DHCP6_OPTION_CAPWAP_AC_V6 = 52, /* RFC 5417 */
|
||||
SD_DHCP6_OPTION_RELAY_ID = 53, /* RFC 5460 */
|
||||
SD_DHCP6_OPTION_IPV6_ADDRESS_MOS = 54, /* RFC 5678 */
|
||||
SD_DHCP6_OPTION_IPV6_FQDN_MOS = 55, /* RFC 5678 */
|
||||
SD_DHCP6_OPTION_NTP_SERVER = 56, /* RFC 5908 */
|
||||
SD_DHCP6_OPTION_MUD_URL = 112, /* RFC 8250 */
|
||||
|
||||
/* option codes 89-142 are unassigned */
|
||||
SD_DHCP6_OPTION_V6_ACCESS_DOMAIN = 57, /* RFC 5986 */
|
||||
SD_DHCP6_OPTION_SIP_UA_CS_LIST = 58, /* RFC 6011 */
|
||||
SD_DHCP6_OPTION_BOOTFILE_URL = 59, /* RFC 5970 */
|
||||
SD_DHCP6_OPTION_BOOTFILE_PARAM = 60, /* RFC 5970 */
|
||||
SD_DHCP6_OPTION_CLIENT_ARCH_TYPE = 61, /* RFC 5970 */
|
||||
SD_DHCP6_OPTION_NII = 62, /* RFC 5970 */
|
||||
SD_DHCP6_OPTION_GEOLOCATION = 63, /* RFC 6225 */
|
||||
SD_DHCP6_OPTION_AFTR_NAME = 64, /* RFC 6334 */
|
||||
SD_DHCP6_OPTION_ERP_LOCAL_DOMAIN_NAME = 65, /* RFC 6440 */
|
||||
SD_DHCP6_OPTION_RSOO = 66, /* RFC 6422 */
|
||||
SD_DHCP6_OPTION_PD_EXCLUDE = 67, /* RFC 6603 */
|
||||
SD_DHCP6_OPTION_VSS = 68, /* RFC 6607 */
|
||||
SD_DHCP6_OPTION_MIP6_IDINF = 69, /* RFC 6610 */
|
||||
SD_DHCP6_OPTION_MIP6_UDINF = 70, /* RFC 6610 */
|
||||
SD_DHCP6_OPTION_MIP6_HNP = 71, /* RFC 6610 */
|
||||
SD_DHCP6_OPTION_MIP6_HAA = 72, /* RFC 6610 */
|
||||
SD_DHCP6_OPTION_MIP6_HAF = 73, /* RFC 6610 */
|
||||
SD_DHCP6_OPTION_RDNSS_SELECTION = 74, /* RFC 6731 */
|
||||
SD_DHCP6_OPTION_KRB_PRINCIPAL_NAME = 75, /* RFC 6784 */
|
||||
SD_DHCP6_OPTION_KRB_REALM_NAME = 76, /* RFC 6784 */
|
||||
SD_DHCP6_OPTION_KRB_DEFAULT_REALM_NAME = 77, /* RFC 6784 */
|
||||
SD_DHCP6_OPTION_KRB_KDC = 78, /* RFC 6784 */
|
||||
SD_DHCP6_OPTION_CLIENT_LINKLAYER_ADDR = 79, /* RFC 6939 */
|
||||
SD_DHCP6_OPTION_LINK_ADDRESS = 80, /* RFC 6977 */
|
||||
SD_DHCP6_OPTION_RADIUS = 81, /* RFC 7037 */
|
||||
SD_DHCP6_OPTION_SOL_MAX_RT = 82, /* RFC 7083, RFC 8415 */
|
||||
SD_DHCP6_OPTION_INF_MAX_RT = 83, /* RFC 7083, RFC 8415 */
|
||||
SD_DHCP6_OPTION_ADDRSEL = 84, /* RFC 7078 */
|
||||
SD_DHCP6_OPTION_ADDRSEL_TABLE = 85, /* RFC 7078 */
|
||||
SD_DHCP6_OPTION_V6_PCP_SERVER = 86, /* RFC 7291 */
|
||||
SD_DHCP6_OPTION_DHCPV4_MSG = 87, /* RFC 7341 */
|
||||
SD_DHCP6_OPTION_DHCP4_O_DHCP6_SERVER = 88, /* RFC 7341 */
|
||||
SD_DHCP6_OPTION_S46_RULE = 89, /* RFC 7598 */
|
||||
SD_DHCP6_OPTION_S46_BR = 90, /* RFC 7598, RFC 8539 */
|
||||
SD_DHCP6_OPTION_S46_DMR = 91, /* RFC 7598 */
|
||||
SD_DHCP6_OPTION_S46_V4V6BIND = 92, /* RFC 7598 */
|
||||
SD_DHCP6_OPTION_S46_PORTPARAMS = 93, /* RFC 7598 */
|
||||
SD_DHCP6_OPTION_S46_CONT_MAPE = 94, /* RFC 7598 */
|
||||
SD_DHCP6_OPTION_S46_CONT_MAPT = 95, /* RFC 7598 */
|
||||
SD_DHCP6_OPTION_S46_CONT_LW = 96, /* RFC 7598 */
|
||||
SD_DHCP6_OPTION_4RD = 97, /* RFC 7600 */
|
||||
SD_DHCP6_OPTION_4RD_MAP_RULE = 98, /* RFC 7600 */
|
||||
SD_DHCP6_OPTION_4RD_NON_MAP_RULE = 99, /* RFC 7600 */
|
||||
SD_DHCP6_OPTION_LQ_BASE_TIME = 100, /* RFC 7653 */
|
||||
SD_DHCP6_OPTION_LQ_START_TIME = 101, /* RFC 7653 */
|
||||
SD_DHCP6_OPTION_LQ_END_TIME = 102, /* RFC 7653 */
|
||||
SD_DHCP6_OPTION_CAPTIVE_PORTAL = 103, /* RFC 8910 */
|
||||
SD_DHCP6_OPTION_MPL_PARAMETERS = 104, /* RFC 7774 */
|
||||
SD_DHCP6_OPTION_ANI_ATT = 105, /* RFC 7839 */
|
||||
SD_DHCP6_OPTION_ANI_NETWORK_NAME = 106, /* RFC 7839 */
|
||||
SD_DHCP6_OPTION_ANI_AP_NAME = 107, /* RFC 7839 */
|
||||
SD_DHCP6_OPTION_ANI_AP_BSSID = 108, /* RFC 7839 */
|
||||
SD_DHCP6_OPTION_ANI_OPERATOR_ID = 109, /* RFC 7839 */
|
||||
SD_DHCP6_OPTION_ANI_OPERATOR_REALM = 110, /* RFC 7839 */
|
||||
SD_DHCP6_OPTION_S46_PRIORITY = 111, /* RFC 8026 */
|
||||
SD_DHCP6_OPTION_MUD_URL_V6 = 112, /* RFC 8520 */
|
||||
SD_DHCP6_OPTION_V6_PREFIX64 = 113, /* RFC 8115 */
|
||||
SD_DHCP6_OPTION_F_BINDING_STATUS = 114, /* RFC 8156 */
|
||||
SD_DHCP6_OPTION_F_CONNECT_FLAGS = 115, /* RFC 8156 */
|
||||
SD_DHCP6_OPTION_F_DNS_REMOVAL_INFO = 116, /* RFC 8156 */
|
||||
SD_DHCP6_OPTION_F_DNS_HOST_NAME = 117, /* RFC 8156 */
|
||||
SD_DHCP6_OPTION_F_DNS_ZONE_NAME = 118, /* RFC 8156 */
|
||||
SD_DHCP6_OPTION_F_DNS_FLAGS = 119, /* RFC 8156 */
|
||||
SD_DHCP6_OPTION_F_EXPIRATION_TIME = 120, /* RFC 8156 */
|
||||
SD_DHCP6_OPTION_F_MAX_UNACKED_BNDUPD = 121, /* RFC 8156 */
|
||||
SD_DHCP6_OPTION_F_MCLT = 122, /* RFC 8156 */
|
||||
SD_DHCP6_OPTION_F_PARTNER_LIFETIME = 123, /* RFC 8156 */
|
||||
SD_DHCP6_OPTION_F_PARTNER_LIFETIME_SENT = 124, /* RFC 8156 */
|
||||
SD_DHCP6_OPTION_F_PARTNER_DOWN_TIME = 125, /* RFC 8156 */
|
||||
SD_DHCP6_OPTION_F_PARTNER_RAW_CLT_TIME = 126, /* RFC 8156 */
|
||||
SD_DHCP6_OPTION_F_PROTOCOL_VERSION = 127, /* RFC 8156 */
|
||||
SD_DHCP6_OPTION_F_KEEPALIVE_TIME = 128, /* RFC 8156 */
|
||||
SD_DHCP6_OPTION_F_RECONFIGURE_DATA = 129, /* RFC 8156 */
|
||||
SD_DHCP6_OPTION_F_RELATIONSHIP_NAME = 130, /* RFC 8156 */
|
||||
SD_DHCP6_OPTION_F_SERVER_FLAGS = 131, /* RFC 8156 */
|
||||
SD_DHCP6_OPTION_F_SERVER_STATE = 132, /* RFC 8156 */
|
||||
SD_DHCP6_OPTION_F_START_TIME_OF_STATE = 133, /* RFC 8156 */
|
||||
SD_DHCP6_OPTION_F_STATE_EXPIRATION_TIME = 134, /* RFC 8156 */
|
||||
SD_DHCP6_OPTION_RELAY_PORT = 135, /* RFC 8357 */
|
||||
SD_DHCP6_OPTION_V6_SZTP_REDIRECT = 136, /* RFC 8572 */
|
||||
SD_DHCP6_OPTION_S46_BIND_IPV6_PREFIX = 137, /* RFC 8539 */
|
||||
SD_DHCP6_OPTION_IA_LL = 138, /* RFC 8947 */
|
||||
SD_DHCP6_OPTION_LLADDR = 139, /* RFC 8947 */
|
||||
SD_DHCP6_OPTION_SLAP_QUAD = 140, /* RFC 8948 */
|
||||
SD_DHCP6_OPTION_V6_DOTS_RI = 141, /* RFC 8973 */
|
||||
SD_DHCP6_OPTION_V6_DOTS_ADDRESS = 142, /* RFC 8973 */
|
||||
SD_DHCP6_OPTION_IPV6_ADDRESS_ANDSF = 143, /* RFC 6153 */
|
||||
/* option codes 144-65535 are unassigned */
|
||||
};
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
|
||||
#include <inttypes.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "_sd-common.h"
|
||||
|
||||
|
@ -28,6 +29,9 @@ _SD_BEGIN_DECLARATIONS;
|
|||
|
||||
typedef struct sd_dhcp6_lease sd_dhcp6_lease;
|
||||
|
||||
int sd_dhcp6_lease_get_timestamp(sd_dhcp6_lease *lease, clockid_t clock, uint64_t *ret);
|
||||
int sd_dhcp6_lease_get_server_address(sd_dhcp6_lease *lease, struct in6_addr *ret);
|
||||
|
||||
void sd_dhcp6_lease_reset_address_iter(sd_dhcp6_lease *lease);
|
||||
int sd_dhcp6_lease_get_address(sd_dhcp6_lease *lease,
|
||||
struct in6_addr *addr,
|
||||
|
|
|
@ -93,6 +93,7 @@ int sd_event_add_signal(sd_event *e, sd_event_source **s, int sig, sd_event_sign
|
|||
int sd_event_add_child(sd_event *e, sd_event_source **s, pid_t pid, int options, sd_event_child_handler_t callback, void *userdata);
|
||||
int sd_event_add_child_pidfd(sd_event *e, sd_event_source **s, int pidfd, int options, sd_event_child_handler_t callback, void *userdata);
|
||||
int sd_event_add_inotify(sd_event *e, sd_event_source **s, const char *path, uint32_t mask, sd_event_inotify_handler_t callback, void *userdata);
|
||||
int sd_event_add_inotify_fd(sd_event *e, sd_event_source **s, int fd, uint32_t mask, sd_event_inotify_handler_t callback, void *userdata);
|
||||
int sd_event_add_defer(sd_event *e, sd_event_source **s, sd_event_handler_t callback, void *userdata);
|
||||
int sd_event_add_post(sd_event *e, sd_event_source **s, sd_event_handler_t callback, void *userdata);
|
||||
int sd_event_add_exit(sd_event *e, sd_event_source **s, sd_event_handler_t callback, void *userdata);
|
||||
|
@ -165,6 +166,7 @@ int sd_event_source_set_exit_on_failure(sd_event_source *s, int b);
|
|||
int sd_event_source_set_ratelimit(sd_event_source *s, uint64_t interval_usec, unsigned burst);
|
||||
int sd_event_source_get_ratelimit(sd_event_source *s, uint64_t *ret_interval_usec, unsigned *ret_burst);
|
||||
int sd_event_source_is_ratelimited(sd_event_source *s);
|
||||
int sd_event_source_set_ratelimit_expire_callback(sd_event_source *s, sd_event_handler_t callback);
|
||||
|
||||
/* Define helpers so that __attribute__((cleanup(sd_event_unrefp))) and similar may be used. */
|
||||
_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_event, sd_event_unref);
|
||||
|
|
|
@ -82,9 +82,6 @@ int sd_ndisc_set_ifname(sd_ndisc *nd, const char *interface_name);
|
|||
int sd_ndisc_get_ifname(sd_ndisc *nd, const char **ret);
|
||||
int sd_ndisc_set_mac(sd_ndisc *nd, const struct ether_addr *mac_addr);
|
||||
|
||||
int sd_ndisc_get_mtu(sd_ndisc *nd, uint32_t *ret);
|
||||
int sd_ndisc_get_hop_limit(sd_ndisc *nd, uint8_t *ret);
|
||||
|
||||
int sd_ndisc_router_from_raw(sd_ndisc_router **ret, const void *raw, size_t raw_size);
|
||||
sd_ndisc_router *sd_ndisc_router_ref(sd_ndisc_router *rt);
|
||||
sd_ndisc_router *sd_ndisc_router_unref(sd_ndisc_router *rt);
|
||||
|
|
3
src/libnm-systemd-shared/sd-adapt-shared/filesystems.h
Normal file
3
src/libnm-systemd-shared/sd-adapt-shared/filesystems.h
Normal file
|
@ -0,0 +1,3 @@
|
|||
#pragma once
|
||||
|
||||
/* dummy header */
|
3
src/libnm-systemd-shared/sd-adapt-shared/hmac.h
Normal file
3
src/libnm-systemd-shared/sd-adapt-shared/hmac.h
Normal file
|
@ -0,0 +1,3 @@
|
|||
#pragma once
|
||||
|
||||
/* dummy header */
|
|
@ -1,3 +1,5 @@
|
|||
#pragma once
|
||||
|
||||
/* dummy header */
|
||||
|
||||
#include <linux/magic.h>
|
||||
|
|
3
src/libnm-systemd-shared/sd-adapt-shared/netif-util.h
Normal file
3
src/libnm-systemd-shared/sd-adapt-shared/netif-util.h
Normal file
|
@ -0,0 +1,3 @@
|
|||
#pragma once
|
||||
|
||||
/* dummy header */
|
|
@ -22,20 +22,25 @@ typedef void (*free_func_t)(void *p);
|
|||
|
||||
#define new0(t, n) ((t*) calloc((n) ?: 1, sizeof(t)))
|
||||
|
||||
#define alloca_safe(n) \
|
||||
({ \
|
||||
size_t _nn_ = n; \
|
||||
assert(_nn_ <= ALLOCA_MAX); \
|
||||
alloca(_nn_ == 0 ? 1 : _nn_); \
|
||||
}) \
|
||||
|
||||
#define newa(t, n) \
|
||||
({ \
|
||||
size_t _n_ = n; \
|
||||
assert(!size_multiply_overflow(sizeof(t), _n_)); \
|
||||
assert(sizeof(t)*_n_ <= ALLOCA_MAX); \
|
||||
(t*) alloca((sizeof(t)*_n_) ?: 1); \
|
||||
(t*) alloca_safe(sizeof(t)*_n_); \
|
||||
})
|
||||
|
||||
#define newa0(t, n) \
|
||||
({ \
|
||||
size_t _n_ = n; \
|
||||
assert(!size_multiply_overflow(sizeof(t), _n_)); \
|
||||
assert(sizeof(t)*_n_ <= ALLOCA_MAX); \
|
||||
(t*) alloca0((sizeof(t)*_n_) ?: 1); \
|
||||
(t*) alloca0((sizeof(t)*_n_)); \
|
||||
})
|
||||
|
||||
#define newdup(t, p, n) ((t*) memdup_multiply(p, sizeof(t), (n)))
|
||||
|
@ -44,12 +49,6 @@ typedef void (*free_func_t)(void *p);
|
|||
|
||||
#define malloc0(n) (calloc(1, (n) ?: 1))
|
||||
|
||||
#define mfree(memory) \
|
||||
({ \
|
||||
free(memory); \
|
||||
(typeof(memory)) NULL; \
|
||||
})
|
||||
|
||||
#define free_and_replace(a, b) \
|
||||
({ \
|
||||
typeof(a)* _a = &(a); \
|
||||
|
@ -67,8 +66,7 @@ void* memdup_suffix0(const void *p, size_t l); /* We can't use _alloc_() here, s
|
|||
({ \
|
||||
void *_q_; \
|
||||
size_t _l_ = l; \
|
||||
assert(_l_ <= ALLOCA_MAX); \
|
||||
_q_ = alloca(_l_ ?: 1); \
|
||||
_q_ = alloca_safe(_l_); \
|
||||
memcpy_safe(_q_, p, _l_); \
|
||||
})
|
||||
|
||||
|
@ -76,8 +74,7 @@ void* memdup_suffix0(const void *p, size_t l); /* We can't use _alloc_() here, s
|
|||
({ \
|
||||
void *_q_; \
|
||||
size_t _l_ = l; \
|
||||
assert(_l_ <= ALLOCA_MAX); \
|
||||
_q_ = alloca(_l_ + 1); \
|
||||
_q_ = alloca_safe(_l_ + 1); \
|
||||
((uint8_t*) _q_)[_l_] = 0; \
|
||||
memcpy_safe(_q_, p, _l_); \
|
||||
})
|
||||
|
@ -144,9 +141,8 @@ void* greedy_realloc0(void **p, size_t need, size_t size);
|
|||
({ \
|
||||
char *_new_; \
|
||||
size_t _len_ = n; \
|
||||
assert(_len_ <= ALLOCA_MAX); \
|
||||
_new_ = alloca(_len_ ?: 1); \
|
||||
(void *) memset(_new_, 0, _len_); \
|
||||
_new_ = alloca_safe(_len_); \
|
||||
memset(_new_, 0, _len_); \
|
||||
})
|
||||
|
||||
/* It's not clear what alignment glibc/gcc alloca() guarantee, hence provide a guaranteed safe version */
|
||||
|
@ -155,8 +151,7 @@ void* greedy_realloc0(void **p, size_t need, size_t size);
|
|||
void *_ptr_; \
|
||||
size_t _mask_ = (align) - 1; \
|
||||
size_t _size_ = size; \
|
||||
assert(_size_ <= ALLOCA_MAX); \
|
||||
_ptr_ = alloca((_size_ + _mask_) ?: 1); \
|
||||
_ptr_ = alloca_safe(_size_ + _mask_); \
|
||||
(void*)(((uintptr_t)_ptr_ + _mask_) & ~_mask_); \
|
||||
})
|
||||
|
||||
|
@ -165,7 +160,7 @@ void* greedy_realloc0(void **p, size_t need, size_t size);
|
|||
void *_new_; \
|
||||
size_t _xsize_ = (size); \
|
||||
_new_ = alloca_align(_xsize_, (align)); \
|
||||
(void*)memset(_new_, 0, _xsize_); \
|
||||
memset(_new_, 0, _xsize_); \
|
||||
})
|
||||
|
||||
#if HAS_FEATURE_MEMORY_SANITIZER
|
||||
|
@ -193,3 +188,19 @@ void* greedy_realloc0(void **p, size_t need, size_t size);
|
|||
__builtin_types_compatible_p(typeof(x), typeof(&*(x))), \
|
||||
MALLOC_SIZEOF_SAFE(x)/sizeof((x)[0]), \
|
||||
VOID_0))
|
||||
|
||||
|
||||
/* These are like strdupa()/strndupa(), but honour ALLOCA_MAX */
|
||||
#define strdupa_safe(s) \
|
||||
({ \
|
||||
const char *_t = (s); \
|
||||
(char*) memdupa_suffix0(_t, strlen(_t)); \
|
||||
})
|
||||
|
||||
#define strndupa_safe(s, n) \
|
||||
({ \
|
||||
const char *_t = (s); \
|
||||
(char*) memdupa_suffix0(_t, strnlen(_t, (n))); \
|
||||
})
|
||||
|
||||
#include "memory-util.h"
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <dirent.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
@ -33,6 +34,9 @@ typedef enum CGroupController {
|
|||
CGROUP_CONTROLLER_BPF_FOREIGN,
|
||||
CGROUP_CONTROLLER_BPF_SOCKET_BIND,
|
||||
CGROUP_CONTROLLER_BPF_RESTRICT_NETWORK_INTERFACES,
|
||||
/* The BPF hook implementing RestrictFileSystems= is not defined here.
|
||||
* It's applied as late as possible in exec_child() so we don't block
|
||||
* our own unit setup code. */
|
||||
|
||||
_CGROUP_CONTROLLER_MAX,
|
||||
_CGROUP_CONTROLLER_INVALID = -EINVAL,
|
||||
|
@ -123,6 +127,20 @@ static inline bool CGROUP_CPU_SHARES_IS_OK(uint64_t x) {
|
|||
(x >= CGROUP_CPU_SHARES_MIN && x <= CGROUP_CPU_SHARES_MAX);
|
||||
}
|
||||
|
||||
/* Special values for the special {blkio,io}.bfq.weight attribute */
|
||||
#define CGROUP_BFQ_WEIGHT_INVALID UINT64_MAX
|
||||
#define CGROUP_BFQ_WEIGHT_MIN UINT64_C(1)
|
||||
#define CGROUP_BFQ_WEIGHT_MAX UINT64_C(1000)
|
||||
#define CGROUP_BFQ_WEIGHT_DEFAULT UINT64_C(100)
|
||||
|
||||
/* Convert the normal io.weight value to io.bfq.weight */
|
||||
static inline uint64_t BFQ_WEIGHT(uint64_t io_weight) {
|
||||
return
|
||||
io_weight <= CGROUP_WEIGHT_DEFAULT ?
|
||||
CGROUP_BFQ_WEIGHT_DEFAULT - (CGROUP_WEIGHT_DEFAULT - io_weight) * (CGROUP_BFQ_WEIGHT_DEFAULT - CGROUP_BFQ_WEIGHT_MIN) / (CGROUP_WEIGHT_DEFAULT - CGROUP_WEIGHT_MIN) :
|
||||
CGROUP_BFQ_WEIGHT_DEFAULT + (io_weight - CGROUP_WEIGHT_DEFAULT) * (CGROUP_BFQ_WEIGHT_MAX - CGROUP_BFQ_WEIGHT_DEFAULT) / (CGROUP_WEIGHT_MAX - CGROUP_WEIGHT_DEFAULT);
|
||||
}
|
||||
|
||||
/* Special values for the blkio.weight attribute */
|
||||
#define CGROUP_BLKIO_WEIGHT_INVALID UINT64_MAX
|
||||
#define CGROUP_BLKIO_WEIGHT_MIN UINT64_C(10)
|
||||
|
@ -236,6 +254,7 @@ int cg_is_empty_recursive(const char *controller, const char *path);
|
|||
|
||||
int cg_get_root_path(char **path);
|
||||
|
||||
int cg_path_get_cgroupid(const char *path, uint64_t *ret);
|
||||
int cg_path_get_session(const char *path, char **session);
|
||||
int cg_path_get_owner_uid(const char *path, uid_t *uid);
|
||||
int cg_path_get_unit(const char *path, char **unit);
|
||||
|
@ -311,3 +330,12 @@ typedef enum ManagedOOMPreference {
|
|||
|
||||
const char* managed_oom_preference_to_string(ManagedOOMPreference a) _const_;
|
||||
ManagedOOMPreference managed_oom_preference_from_string(const char *s) _pure_;
|
||||
|
||||
/* The structure to pass to name_to_handle_at() on cgroupfs2 */
|
||||
typedef union {
|
||||
struct file_handle file_handle;
|
||||
uint8_t space[offsetof(struct file_handle, f_handle) + sizeof(uint64_t)];
|
||||
} cg_file_handle;
|
||||
|
||||
#define CG_FILE_HANDLE_INIT { .file_handle.handle_bytes = sizeof(uint64_t) }
|
||||
#define CG_FILE_HANDLE_CGROUPID(fh) (*(uint64_t*) (fh).file_handle.f_handle)
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
#include "alloc-util.h"
|
||||
#include "env-util.h"
|
||||
#include "errno-util.h"
|
||||
#include "escape.h"
|
||||
#include "extract-word.h"
|
||||
#include "macro.h"
|
||||
|
@ -397,7 +398,7 @@ int strv_env_replace_consume(char ***l, char *p) {
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
name = strndupa(p, t - p);
|
||||
name = strndupa_safe(p, t - p);
|
||||
|
||||
STRV_FOREACH(f, *l)
|
||||
if (env_entry_has_name(*f, name)) {
|
||||
|
@ -484,7 +485,7 @@ char *strv_env_get_n(char **l, const char *name, size_t k, unsigned flags) {
|
|||
if (flags & REPLACE_ENV_USE_ENVIRONMENT) {
|
||||
const char *t;
|
||||
|
||||
t = strndupa(name, k);
|
||||
t = strndupa_safe(name, k);
|
||||
return getenv(t);
|
||||
};
|
||||
|
||||
|
@ -791,15 +792,12 @@ int getenv_bool_secure(const char *p) {
|
|||
|
||||
#if 0 /* NM_IGNORED */
|
||||
int set_unset_env(const char *name, const char *value, bool overwrite) {
|
||||
int r;
|
||||
assert(name);
|
||||
|
||||
if (value)
|
||||
r = setenv(name, value, overwrite);
|
||||
else
|
||||
r = unsetenv(name);
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
return 0;
|
||||
return RET_NERRNO(setenv(name, value, overwrite));
|
||||
|
||||
return RET_NERRNO(unsetenv(name));
|
||||
}
|
||||
|
||||
int putenv_dup(const char *assignment, bool override) {
|
||||
|
@ -809,12 +807,10 @@ int putenv_dup(const char *assignment, bool override) {
|
|||
if (!e)
|
||||
return -EINVAL;
|
||||
|
||||
n = strndupa(assignment, e - assignment);
|
||||
n = strndupa_safe(assignment, e - assignment);
|
||||
|
||||
/* This is like putenv(), but uses setenv() so that our memory doesn't become part of environ[]. */
|
||||
if (setenv(n, e + 1, override) < 0)
|
||||
return -errno;
|
||||
return 0;
|
||||
return RET_NERRNO(setenv(n, e + 1, override));
|
||||
}
|
||||
|
||||
int setenv_systemd_exec_pid(bool update_only) {
|
||||
|
|
|
@ -31,6 +31,29 @@ static inline int negative_errno(void) {
|
|||
return -errno;
|
||||
}
|
||||
|
||||
static inline int RET_NERRNO(int ret) {
|
||||
|
||||
/* Helper to wrap system calls in to make them return negative errno errors. This brings system call
|
||||
* error handling in sync with how we usually handle errors in our own code, i.e. with immediate
|
||||
* returning of negative errno. Usage is like this:
|
||||
*
|
||||
* …
|
||||
* r = RET_NERRNO(unlink(t));
|
||||
* …
|
||||
*
|
||||
* or
|
||||
*
|
||||
* …
|
||||
* fd = RET_NERRNO(open("/etc/fstab", O_RDONLY|O_CLOEXEC));
|
||||
* …
|
||||
*/
|
||||
|
||||
if (ret < 0)
|
||||
return negative_errno();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline const char *strerror_safe(int error) {
|
||||
/* 'safe' here does NOT mean thread safety. */
|
||||
return strerror(abs(error)); /* lgtm [cpp/potentially-dangerous-function] */
|
||||
|
@ -47,6 +70,13 @@ static inline int errno_or_else(int fallback) {
|
|||
return -abs(fallback);
|
||||
}
|
||||
|
||||
/* For send()/recv() or read()/write(). */
|
||||
static inline bool ERRNO_IS_TRANSIENT(int r) {
|
||||
return IN_SET(abs(r),
|
||||
EAGAIN,
|
||||
EINTR);
|
||||
}
|
||||
|
||||
/* Hint #1: ENETUNREACH happens if we try to connect to "non-existing" special IP addresses, such as ::5.
|
||||
*
|
||||
* Hint #2: The kernel sends e.g., EHOSTUNREACH or ENONET to userspace in some ICMP error cases. See the
|
||||
|
@ -77,10 +107,8 @@ static inline bool ERRNO_IS_DISCONNECT(int r) {
|
|||
* the accept(2) man page. */
|
||||
static inline bool ERRNO_IS_ACCEPT_AGAIN(int r) {
|
||||
return ERRNO_IS_DISCONNECT(r) ||
|
||||
IN_SET(abs(r),
|
||||
EAGAIN,
|
||||
EINTR,
|
||||
EOPNOTSUPP);
|
||||
ERRNO_IS_TRANSIENT(r) ||
|
||||
abs(r) == EOPNOTSUPP;
|
||||
}
|
||||
|
||||
/* Resource exhaustion, could be our fault or general system trouble */
|
||||
|
|
|
@ -547,7 +547,7 @@ char* shell_maybe_quote(const char *s, ShellEscapeFlags flags) {
|
|||
return str_realloc(buf);
|
||||
}
|
||||
|
||||
char* quote_command_line(char **argv) {
|
||||
char* quote_command_line(char **argv, ShellEscapeFlags flags) {
|
||||
_cleanup_free_ char *result = NULL;
|
||||
|
||||
assert(argv);
|
||||
|
@ -556,7 +556,7 @@ char* quote_command_line(char **argv) {
|
|||
STRV_FOREACH(a, argv) {
|
||||
_cleanup_free_ char *t = NULL;
|
||||
|
||||
t = shell_maybe_quote(*a, SHELL_ESCAPE_EMPTY);
|
||||
t = shell_maybe_quote(*a, flags);
|
||||
if (!t)
|
||||
return NULL;
|
||||
|
||||
|
@ -564,6 +564,6 @@ char* quote_command_line(char **argv) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
return TAKE_PTR(result);
|
||||
return str_realloc(TAKE_PTR(result));
|
||||
}
|
||||
#endif /* NM_IGNORED */
|
||||
|
|
|
@ -69,4 +69,4 @@ char* escape_non_printable_full(const char *str, size_t console_width, XEscapeFl
|
|||
|
||||
char* shell_escape(const char *s, const char *bad);
|
||||
char* shell_maybe_quote(const char *s, ShellEscapeFlags flags);
|
||||
char* quote_command_line(char **argv);
|
||||
char* quote_command_line(char **argv, ShellEscapeFlags flags);
|
||||
|
|
|
@ -9,20 +9,29 @@
|
|||
#include <sys/types.h>
|
||||
|
||||
#include "ether-addr-util.h"
|
||||
#include "hexdecoct.h"
|
||||
#include "macro.h"
|
||||
#include "string-util.h"
|
||||
|
||||
char* hw_addr_to_string(const struct hw_addr_data *addr, char buffer[HW_ADDR_TO_STRING_MAX]) {
|
||||
char *hw_addr_to_string_full(
|
||||
const struct hw_addr_data *addr,
|
||||
HardwareAddressToStringFlags flags,
|
||||
char buffer[static 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->bytes[i]);
|
||||
if (i < addr->length - 1)
|
||||
buffer[3*i + 2] = ':';
|
||||
for (size_t i = 0, j = 0; i < addr->length; i++) {
|
||||
buffer[j++] = hexchar(addr->bytes[i] >> 4);
|
||||
buffer[j++] = hexchar(addr->bytes[i] & 0x0f);
|
||||
if (!FLAGS_SET(flags, HW_ADDR_TO_STRING_NO_COLON))
|
||||
buffer[j++] = ':';
|
||||
}
|
||||
|
||||
buffer[addr->length == 0 || FLAGS_SET(flags, HW_ADDR_TO_STRING_NO_COLON) ?
|
||||
addr->length * 2 :
|
||||
addr->length * 3 - 1] = '\0';
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
@ -39,7 +48,7 @@ int hw_addr_compare(const struct hw_addr_data *a, const struct hw_addr_data *b)
|
|||
return memcmp(a->bytes, b->bytes, a->length);
|
||||
}
|
||||
|
||||
static void hw_addr_hash_func(const struct hw_addr_data *p, struct siphash *state) {
|
||||
void hw_addr_hash_func(const struct hw_addr_data *p, struct siphash *state) {
|
||||
assert(p);
|
||||
assert(state);
|
||||
|
||||
|
@ -48,6 +57,7 @@ static void hw_addr_hash_func(const struct hw_addr_data *p, struct siphash *stat
|
|||
}
|
||||
|
||||
DEFINE_HASH_OPS(hw_addr_hash_ops, struct hw_addr_data, hw_addr_hash_func, hw_addr_compare);
|
||||
DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(hw_addr_hash_ops_free, struct hw_addr_data, hw_addr_hash_func, hw_addr_compare, free);
|
||||
|
||||
char* ether_addr_to_string(const struct ether_addr *addr, char buffer[ETHER_ADDR_TO_STRING_MAX]) {
|
||||
assert(addr);
|
||||
|
@ -93,75 +103,163 @@ static void ether_addr_hash_func(const struct ether_addr *p, struct siphash *sta
|
|||
}
|
||||
|
||||
DEFINE_HASH_OPS(ether_addr_hash_ops, struct ether_addr, ether_addr_hash_func, ether_addr_compare);
|
||||
DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(ether_addr_hash_ops_free, struct ether_addr, ether_addr_hash_func, ether_addr_compare, free);
|
||||
|
||||
int ether_addr_from_string(const char *s, struct ether_addr *ret) {
|
||||
size_t pos = 0, n, field;
|
||||
char sep = '\0';
|
||||
const char *hex = HEXDIGITS, *hexoff;
|
||||
static int parse_hw_addr_one_field(const char **s, char sep, size_t len, uint8_t *buf) {
|
||||
const char *hex = HEXDIGITS, *p;
|
||||
uint16_t data = 0;
|
||||
bool cont;
|
||||
|
||||
assert(s);
|
||||
assert(*s);
|
||||
assert(IN_SET(len, 1, 2));
|
||||
assert(buf);
|
||||
|
||||
p = *s;
|
||||
|
||||
for (size_t i = 0; i < len * 2; i++) {
|
||||
const char *hexoff;
|
||||
size_t x;
|
||||
bool touched;
|
||||
|
||||
#define parse_fields(v) \
|
||||
for (field = 0; field < ELEMENTSOF(v); field++) { \
|
||||
touched = false; \
|
||||
for (n = 0; n < (2 * sizeof(v[0])); n++) { \
|
||||
if (s[pos] == '\0') \
|
||||
break; \
|
||||
hexoff = strchr(hex, s[pos]); \
|
||||
if (!hexoff) \
|
||||
break; \
|
||||
assert(hexoff >= hex); \
|
||||
x = hexoff - hex; \
|
||||
if (x >= 16) \
|
||||
x -= 6; /* A-F */ \
|
||||
assert(x < 16); \
|
||||
touched = true; \
|
||||
v[field] <<= 4; \
|
||||
v[field] += x; \
|
||||
pos++; \
|
||||
} \
|
||||
if (!touched) \
|
||||
return -EINVAL; \
|
||||
if (field < (ELEMENTSOF(v)-1)) { \
|
||||
if (s[pos] != sep) \
|
||||
return -EINVAL; \
|
||||
else \
|
||||
pos++; \
|
||||
} \
|
||||
if (*p == '\0' || *p == sep) {
|
||||
if (i == 0)
|
||||
return -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
hexoff = strchr(hex, *p);
|
||||
if (!hexoff)
|
||||
return -EINVAL;
|
||||
|
||||
assert(hexoff >= hex);
|
||||
x = hexoff - hex;
|
||||
if (x >= 16)
|
||||
x -= 6; /* A-F */
|
||||
|
||||
assert(x < 16);
|
||||
data <<= 4;
|
||||
data += x;
|
||||
|
||||
p++;
|
||||
}
|
||||
|
||||
if (*p != '\0' && *p != sep)
|
||||
return -EINVAL;
|
||||
|
||||
switch (len) {
|
||||
case 1:
|
||||
buf[0] = data;
|
||||
break;
|
||||
case 2:
|
||||
buf[0] = (data & 0xff00) >> 8;
|
||||
buf[1] = data & 0xff;
|
||||
break;
|
||||
default:
|
||||
assert_not_reached();
|
||||
}
|
||||
|
||||
cont = *p == sep;
|
||||
*s = p + cont;
|
||||
return cont;
|
||||
}
|
||||
|
||||
int parse_hw_addr_full(const char *s, size_t expected_len, struct hw_addr_data *ret) {
|
||||
size_t field_size, max_len, len = 0;
|
||||
uint8_t bytes[HW_ADDR_MAX_SIZE];
|
||||
char sep;
|
||||
int r;
|
||||
|
||||
assert(s);
|
||||
assert(expected_len <= HW_ADDR_MAX_SIZE || expected_len == SIZE_MAX);
|
||||
assert(ret);
|
||||
|
||||
/* This accepts the following formats:
|
||||
*
|
||||
* Dot separated 2 bytes format: xxyy.zzaa.bbcc
|
||||
* Colon separated 1 bytes format: xx:yy:zz:aa:bb:cc
|
||||
* Hyphen separated 1 bytes format: xx-yy-zz-aa-bb-cc
|
||||
*
|
||||
* Moreover, if expected_len == 0, 4, or 16, this also accepts:
|
||||
*
|
||||
* IPv4 format: used by IPv4 tunnel, e.g. ipgre
|
||||
* IPv6 format: used by IPv6 tunnel, e.g. ip6gre
|
||||
*
|
||||
* The expected_len argument controls the length of acceptable addresses:
|
||||
*
|
||||
* 0: accepts 4 (AF_INET), 16 (AF_INET6), 6 (ETH_ALEN), or 20 (INFINIBAND_ALEN).
|
||||
* SIZE_MAX: accepts arbitrary length, but at least one separator must be included.
|
||||
* Otherwise: accepts addresses with matching length.
|
||||
*/
|
||||
|
||||
if (IN_SET(expected_len, 0, sizeof(struct in_addr), sizeof(struct in6_addr))) {
|
||||
union in_addr_union a;
|
||||
int family;
|
||||
|
||||
if (expected_len == 0)
|
||||
r = in_addr_from_string_auto(s, &family, &a);
|
||||
else {
|
||||
family = expected_len == sizeof(struct in_addr) ? AF_INET : AF_INET6;
|
||||
r = in_addr_from_string(family, s, &a);
|
||||
}
|
||||
if (r >= 0) {
|
||||
ret->length = FAMILY_ADDRESS_SIZE(family);
|
||||
memcpy(ret->bytes, a.bytes, ret->length);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
max_len =
|
||||
expected_len == 0 ? INFINIBAND_ALEN :
|
||||
expected_len == SIZE_MAX ? HW_ADDR_MAX_SIZE : expected_len;
|
||||
sep = s[strspn(s, HEXDIGITS)];
|
||||
|
||||
if (sep == '.')
|
||||
field_size = 2;
|
||||
else if (IN_SET(sep, ':', '-'))
|
||||
field_size = 1;
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
if (max_len % field_size != 0)
|
||||
return -EINVAL;
|
||||
|
||||
for (size_t i = 0; i < max_len / field_size; i++) {
|
||||
r = parse_hw_addr_one_field(&s, sep, field_size, bytes + i * field_size);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0) {
|
||||
len = (i + 1) * field_size;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (len == 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (expected_len == 0) {
|
||||
if (!IN_SET(len, 4, 16, ETH_ALEN, INFINIBAND_ALEN))
|
||||
return -EINVAL;
|
||||
} else if (expected_len != SIZE_MAX) {
|
||||
if (len != expected_len)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret->length = len;
|
||||
memcpy(ret->bytes, bytes, ret->length);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int parse_ether_addr(const char *s, struct ether_addr *ret) {
|
||||
struct hw_addr_data a;
|
||||
int r;
|
||||
|
||||
assert(s);
|
||||
assert(ret);
|
||||
|
||||
s += strspn(s, WHITESPACE);
|
||||
sep = s[strspn(s, hex)];
|
||||
|
||||
if (sep == '.') {
|
||||
uint16_t shorts[3] = { 0 };
|
||||
|
||||
parse_fields(shorts);
|
||||
|
||||
if (s[pos] != '\0')
|
||||
return -EINVAL;
|
||||
|
||||
for (n = 0; n < ELEMENTSOF(shorts); n++) {
|
||||
ret->ether_addr_octet[2*n] = ((shorts[n] & (uint16_t)0xff00) >> 8);
|
||||
ret->ether_addr_octet[2*n + 1] = (shorts[n] & (uint16_t)0x00ff);
|
||||
}
|
||||
|
||||
} else if (IN_SET(sep, ':', '-')) {
|
||||
struct ether_addr out = ETHER_ADDR_NULL;
|
||||
|
||||
parse_fields(out.ether_addr_octet);
|
||||
|
||||
if (s[pos] != '\0')
|
||||
return -EINVAL;
|
||||
|
||||
for (n = 0; n < ELEMENTSOF(out.ether_addr_octet); n++)
|
||||
ret->ether_addr_octet[n] = out.ether_addr_octet[n];
|
||||
|
||||
} else
|
||||
return -EINVAL;
|
||||
r = parse_hw_addr_full(s, ETH_ALEN, &a);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
*ret = a.ether;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -6,6 +6,9 @@
|
|||
#include <stdbool.h>
|
||||
|
||||
#include "hash-funcs.h"
|
||||
#include "in-addr-util.h"
|
||||
#include "macro.h"
|
||||
#include "memory-util.h"
|
||||
|
||||
/* This is MAX_ADDR_LEN as defined in linux/netdevice.h, but net/if_arp.h
|
||||
* defines a macro of the same name with a much lower size. */
|
||||
|
@ -16,29 +19,51 @@ struct hw_addr_data {
|
|||
union {
|
||||
struct ether_addr ether;
|
||||
uint8_t infiniband[INFINIBAND_ALEN];
|
||||
struct in_addr in;
|
||||
struct in6_addr in6;
|
||||
uint8_t bytes[HW_ADDR_MAX_SIZE];
|
||||
};
|
||||
};
|
||||
|
||||
int parse_hw_addr_full(const char *s, size_t expected_len, struct hw_addr_data *ret);
|
||||
static inline int parse_hw_addr(const char *s, struct hw_addr_data *ret) {
|
||||
return parse_hw_addr_full(s, 0, ret);
|
||||
}
|
||||
int parse_ether_addr(const char *s, struct ether_addr *ret);
|
||||
|
||||
typedef enum HardwareAddressToStringFlags {
|
||||
HW_ADDR_TO_STRING_NO_COLON = 1 << 0,
|
||||
} HardwareAddressToStringFlags;
|
||||
|
||||
#define HW_ADDR_TO_STRING_MAX (3*HW_ADDR_MAX_SIZE)
|
||||
char* hw_addr_to_string(const struct hw_addr_data *addr, char buffer[HW_ADDR_TO_STRING_MAX]);
|
||||
char *hw_addr_to_string_full(
|
||||
const struct hw_addr_data *addr,
|
||||
HardwareAddressToStringFlags flags,
|
||||
char buffer[static HW_ADDR_TO_STRING_MAX]);
|
||||
static inline char *hw_addr_to_string(const struct hw_addr_data *addr, char buffer[static HW_ADDR_TO_STRING_MAX]) {
|
||||
return hw_addr_to_string_full(addr, 0, buffer);
|
||||
}
|
||||
|
||||
/* Note: the lifetime of the compound literal is the immediately surrounding block,
|
||||
* see C11 §6.5.2.5, and
|
||||
* https://stackoverflow.com/questions/34880638/compound-literal-lifetime-and-if-blocks */
|
||||
#define HW_ADDR_TO_STR(hw_addr) hw_addr_to_string((hw_addr), (char[HW_ADDR_TO_STRING_MAX]){})
|
||||
#define HW_ADDR_TO_STR_FULL(hw_addr, flags) hw_addr_to_string_full((hw_addr), flags, (char[HW_ADDR_TO_STRING_MAX]){})
|
||||
#define HW_ADDR_TO_STR(hw_addr) HW_ADDR_TO_STR_FULL(hw_addr, 0)
|
||||
|
||||
#define HW_ADDR_NULL ((const struct hw_addr_data){})
|
||||
|
||||
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) {
|
||||
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);
|
||||
assert(addr);
|
||||
return addr->length == 0 || memeqzero(addr->bytes, addr->length);
|
||||
}
|
||||
|
||||
extern const struct hash_ops hw_addr_hash_ops;
|
||||
extern const struct hash_ops hw_addr_hash_ops_free;
|
||||
|
||||
#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]
|
||||
|
@ -60,6 +85,29 @@ static inline bool ether_addr_is_null(const struct ether_addr *addr) {
|
|||
return ether_addr_equal(addr, ÐER_ADDR_NULL);
|
||||
}
|
||||
|
||||
int ether_addr_from_string(const char *s, struct ether_addr *ret);
|
||||
static inline bool ether_addr_is_broadcast(const struct ether_addr *addr) {
|
||||
assert(addr);
|
||||
return memeqbyte(0xff, addr->ether_addr_octet, ETH_ALEN);
|
||||
}
|
||||
|
||||
static inline bool ether_addr_is_multicast(const struct ether_addr *addr) {
|
||||
assert(addr);
|
||||
return FLAGS_SET(addr->ether_addr_octet[0], 0x01);
|
||||
}
|
||||
|
||||
static inline bool ether_addr_is_unicast(const struct ether_addr *addr) {
|
||||
return !ether_addr_is_multicast(addr);
|
||||
}
|
||||
|
||||
static inline bool ether_addr_is_local(const struct ether_addr *addr) {
|
||||
/* Determine if the Ethernet address is locally-assigned one (IEEE 802) */
|
||||
assert(addr);
|
||||
return FLAGS_SET(addr->ether_addr_octet[0], 0x02);
|
||||
}
|
||||
|
||||
static inline bool ether_addr_is_global(const struct ether_addr *addr) {
|
||||
return !ether_addr_is_local(addr);
|
||||
}
|
||||
|
||||
extern const struct hash_ops ether_addr_hash_ops;
|
||||
extern const struct hash_ops ether_addr_hash_ops_free;
|
||||
|
|
|
@ -154,10 +154,7 @@ int fd_nonblock(int fd, bool nonblock) {
|
|||
if (nflags == flags)
|
||||
return 0;
|
||||
|
||||
if (fcntl(fd, F_SETFL, nflags) < 0)
|
||||
return -errno;
|
||||
|
||||
return 0;
|
||||
return RET_NERRNO(fcntl(fd, F_SETFL, nflags));
|
||||
}
|
||||
|
||||
int fd_cloexec(int fd, bool cloexec) {
|
||||
|
@ -173,10 +170,7 @@ int fd_cloexec(int fd, bool cloexec) {
|
|||
if (nflags == flags)
|
||||
return 0;
|
||||
|
||||
if (fcntl(fd, F_SETFD, nflags) < 0)
|
||||
return -errno;
|
||||
|
||||
return 0;
|
||||
return RET_NERRNO(fcntl(fd, F_SETFD, nflags));
|
||||
}
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
|
@ -190,7 +184,7 @@ _pure_ static bool fd_in_set(int fd, const int fdset[], size_t n_fdset) {
|
|||
return false;
|
||||
}
|
||||
|
||||
static int get_max_fd(void) {
|
||||
int get_max_fd(void) {
|
||||
struct rlimit rl;
|
||||
rlim_t m;
|
||||
|
||||
|
@ -211,37 +205,147 @@ static int get_max_fd(void) {
|
|||
return (int) (m - 1);
|
||||
}
|
||||
|
||||
int close_all_fds_full(int except[], size_t n_except, bool allow_alloc) {
|
||||
static int close_all_fds_frugal(const int except[], size_t n_except) {
|
||||
int max_fd, r = 0;
|
||||
|
||||
assert(n_except == 0 || except);
|
||||
|
||||
/* This is the inner fallback core of close_all_fds(). This never calls malloc() or opendir() or so
|
||||
* and hence is safe to be called in signal handler context. Most users should call close_all_fds(),
|
||||
* but when we assume we are called from signal handler context, then use this simpler call
|
||||
* instead. */
|
||||
|
||||
max_fd = get_max_fd();
|
||||
if (max_fd < 0)
|
||||
return max_fd;
|
||||
|
||||
/* Refuse to do the loop over more too many elements. It's better to fail immediately than to
|
||||
* spin the CPU for a long time. */
|
||||
if (max_fd > MAX_FD_LOOP_LIMIT)
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EPERM),
|
||||
"Refusing to loop over %d potential fds.",
|
||||
max_fd);
|
||||
|
||||
for (int fd = 3; fd >= 0; fd = fd < max_fd ? fd + 1 : -1) {
|
||||
int q;
|
||||
|
||||
if (fd_in_set(fd, except, n_except))
|
||||
continue;
|
||||
|
||||
q = close_nointr(fd);
|
||||
if (q < 0 && q != -EBADF && r >= 0)
|
||||
r = q;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static bool have_close_range = true; /* Assume we live in the future */
|
||||
|
||||
static int close_all_fds_special_case(const int except[], size_t n_except) {
|
||||
assert(n_except == 0 || except);
|
||||
|
||||
/* Handles a few common special cases separately, since they are common and can be optimized really
|
||||
* nicely, since we won't need sorting for them. Returns > 0 if the special casing worked, 0
|
||||
* otherwise. */
|
||||
|
||||
if (!have_close_range)
|
||||
return 0;
|
||||
|
||||
switch (n_except) {
|
||||
|
||||
case 0:
|
||||
/* Close everything. Yay! */
|
||||
|
||||
if (close_range(3, -1, 0) >= 0)
|
||||
return 1;
|
||||
|
||||
if (ERRNO_IS_NOT_SUPPORTED(errno) || ERRNO_IS_PRIVILEGE(errno)) {
|
||||
have_close_range = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -errno;
|
||||
|
||||
case 1:
|
||||
/* Close all but exactly one, then we don't need no sorting. This is a pretty common
|
||||
* case, hence let's handle it specially. */
|
||||
|
||||
if ((except[0] <= 3 || close_range(3, except[0]-1, 0) >= 0) &&
|
||||
(except[0] >= INT_MAX || close_range(MAX(3, except[0]+1), -1, 0) >= 0))
|
||||
return 1;
|
||||
|
||||
if (ERRNO_IS_NOT_SUPPORTED(errno) || ERRNO_IS_PRIVILEGE(errno)) {
|
||||
have_close_range = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -errno;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int close_all_fds_without_malloc(const int except[], size_t n_except) {
|
||||
int r;
|
||||
|
||||
assert(n_except == 0 || except);
|
||||
|
||||
r = close_all_fds_special_case(except, n_except);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r > 0) /* special case worked! */
|
||||
return 0;
|
||||
|
||||
return close_all_fds_frugal(except, n_except);
|
||||
}
|
||||
|
||||
int close_all_fds(const int except[], size_t n_except) {
|
||||
_cleanup_closedir_ DIR *d = NULL;
|
||||
int r = 0;
|
||||
|
||||
assert(n_except == 0 || except);
|
||||
|
||||
r = close_all_fds_special_case(except, n_except);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r > 0) /* special case worked! */
|
||||
return 0;
|
||||
|
||||
if (have_close_range) {
|
||||
_cleanup_free_ int *sorted_malloc = NULL;
|
||||
size_t n_sorted;
|
||||
int *sorted;
|
||||
|
||||
/* In the best case we have close_range() to close all fds between a start and an end fd,
|
||||
* which we can use on the "inverted" exception array, i.e. all intervals between all
|
||||
* adjacent pairs from the sorted exception array. This changes loop complexity from O(n)
|
||||
* where n is number of open fds to O(m⋅log(m)) where m is the number of fds to keep
|
||||
* open. Given that we assume n ≫ m that's preferable to us. */
|
||||
|
||||
if (n_except == 0) {
|
||||
/* Close everything. Yay! */
|
||||
assert(n_except < SIZE_MAX);
|
||||
n_sorted = n_except + 1;
|
||||
|
||||
if (close_range(3, -1, 0) >= 0)
|
||||
return 0;
|
||||
|
||||
if (ERRNO_IS_NOT_SUPPORTED(errno) || ERRNO_IS_PRIVILEGE(errno))
|
||||
have_close_range = false;
|
||||
if (n_sorted > 64) /* Use heap for large numbers of fds, stack otherwise */
|
||||
sorted = sorted_malloc = new(int, n_sorted);
|
||||
else
|
||||
return -errno;
|
||||
sorted = newa(int, n_sorted);
|
||||
|
||||
} else {
|
||||
typesafe_qsort(except, n_except, cmp_int);
|
||||
if (sorted) {
|
||||
memcpy(sorted, except, n_except * sizeof(int));
|
||||
|
||||
for (size_t i = 0; i < n_except; i++) {
|
||||
int start = i == 0 ? 2 : MAX(except[i-1], 2); /* The first three fds shall always remain open */
|
||||
int end = MAX(except[i], 2);
|
||||
/* Let's add fd 2 to the list of fds, to simplify the loop below, as this
|
||||
* allows us to cover the head of the array the same way as the body */
|
||||
sorted[n_sorted-1] = 2;
|
||||
|
||||
typesafe_qsort(sorted, n_sorted, cmp_int);
|
||||
|
||||
for (size_t i = 0; i < n_sorted-1; i++) {
|
||||
int start, end;
|
||||
|
||||
start = MAX(sorted[i], 2); /* The first three fds shall always remain open */
|
||||
end = MAX(sorted[i+1], 2);
|
||||
|
||||
assert(end >= start);
|
||||
|
||||
|
@ -250,40 +354,43 @@ int close_all_fds_full(int except[], size_t n_except, bool allow_alloc) {
|
|||
|
||||
/* Close everything between the start and end fds (both of which shall stay open) */
|
||||
if (close_range(start + 1, end - 1, 0) < 0) {
|
||||
if (ERRNO_IS_NOT_SUPPORTED(errno) || ERRNO_IS_PRIVILEGE(errno))
|
||||
have_close_range = false;
|
||||
else
|
||||
if (!ERRNO_IS_NOT_SUPPORTED(errno) && !ERRNO_IS_PRIVILEGE(errno))
|
||||
return -errno;
|
||||
goto opendir_fallback;
|
||||
|
||||
have_close_range = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (have_close_range) {
|
||||
/* The loop succeeded. Let's now close everything beyond the end */
|
||||
|
||||
if (except[n_except-1] >= INT_MAX) /* Don't let the addition below overflow */
|
||||
if (sorted[n_sorted-1] >= INT_MAX) /* Dont let the addition below overflow */
|
||||
return 0;
|
||||
|
||||
int start = MAX(except[n_except-1], 2);
|
||||
|
||||
if (close_range(start + 1, -1, 0) >= 0)
|
||||
if (close_range(sorted[n_sorted-1] + 1, -1, 0) >= 0)
|
||||
return 0;
|
||||
|
||||
if (ERRNO_IS_NOT_SUPPORTED(errno) || ERRNO_IS_PRIVILEGE(errno))
|
||||
have_close_range = false;
|
||||
else
|
||||
if (!ERRNO_IS_NOT_SUPPORTED(errno) && !ERRNO_IS_PRIVILEGE(errno))
|
||||
return -errno;
|
||||
|
||||
have_close_range = false;
|
||||
}
|
||||
}
|
||||
|
||||
/* Fallback for when close_range() is not supported */
|
||||
opendir_fallback:
|
||||
d = allow_alloc ? opendir("/proc/self/fd") : NULL;
|
||||
if (d) {
|
||||
struct dirent *de;
|
||||
/* Fallback on OOM or if close_range() is not supported */
|
||||
}
|
||||
|
||||
d = opendir("/proc/self/fd");
|
||||
if (!d)
|
||||
return close_all_fds_frugal(except, n_except); /* ultimate fallback if /proc/ is not available */
|
||||
|
||||
FOREACH_DIRENT(de, d, return -errno) {
|
||||
int fd = -1, q;
|
||||
|
||||
if (!IN_SET(de->d_type, DT_LNK, DT_UNKNOWN))
|
||||
continue;
|
||||
|
||||
if (safe_atoi(de->d_name, &fd) < 0)
|
||||
/* Let's better ignore this, just in case */
|
||||
continue;
|
||||
|
@ -305,34 +412,6 @@ int close_all_fds_full(int except[], size_t n_except, bool allow_alloc) {
|
|||
return r;
|
||||
}
|
||||
|
||||
/* Fallback for when /proc isn't available (for example in chroots) or when we cannot allocate by
|
||||
* brute-forcing through the file descriptor table. */
|
||||
|
||||
int max_fd = get_max_fd();
|
||||
if (max_fd < 0)
|
||||
return max_fd;
|
||||
|
||||
/* Refuse to do the loop over more too many elements. It's better to fail immediately than to
|
||||
* spin the CPU for a long time. */
|
||||
if (max_fd > MAX_FD_LOOP_LIMIT)
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EPERM),
|
||||
"/proc/self/fd is inaccessible. Refusing to loop over %d potential fds.",
|
||||
max_fd);
|
||||
|
||||
for (int fd = 3; fd >= 0; fd = fd < max_fd ? fd + 1 : -1) {
|
||||
int q;
|
||||
|
||||
if (fd_in_set(fd, except, n_except))
|
||||
continue;
|
||||
|
||||
q = close_nointr(fd);
|
||||
if (q < 0 && q != -EBADF && r >= 0)
|
||||
r = q;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int same_fd(int a, int b) {
|
||||
struct stat sta, stb;
|
||||
pid_t pid;
|
||||
|
@ -652,7 +731,7 @@ finish:
|
|||
}
|
||||
|
||||
int fd_reopen(int fd, int flags) {
|
||||
int new_fd;
|
||||
int new_fd, r;
|
||||
|
||||
/* Reopens the specified fd with new flags. This is useful for convert an O_PATH fd into a regular one, or to
|
||||
* turn O_RDWR fds into O_RDONLY fds.
|
||||
|
@ -661,15 +740,28 @@ int fd_reopen(int fd, int flags) {
|
|||
*
|
||||
* This implicitly resets the file read index to 0. */
|
||||
|
||||
if (FLAGS_SET(flags, O_DIRECTORY)) {
|
||||
/* If we shall reopen the fd as directory we can just go via "." and thus bypass the whole
|
||||
* magic /proc/ directory, and make ourselves independent of that being mounted. */
|
||||
new_fd = openat(fd, ".", flags);
|
||||
if (new_fd < 0)
|
||||
return -errno;
|
||||
|
||||
return new_fd;
|
||||
}
|
||||
|
||||
new_fd = open(FORMAT_PROC_FD_PATH(fd), flags);
|
||||
if (new_fd < 0) {
|
||||
if (errno != ENOENT)
|
||||
return -errno;
|
||||
|
||||
if (proc_mounted() == 0)
|
||||
r = proc_mounted();
|
||||
if (r == 0)
|
||||
return -ENOSYS; /* if we have no /proc/, the concept is not implementable */
|
||||
|
||||
return -ENOENT;
|
||||
return r > 0 ? -EBADF : -ENOENT; /* If /proc/ is definitely around then this means the fd is
|
||||
* not valid, otherwise let's propagate the original
|
||||
* error */
|
||||
}
|
||||
|
||||
return new_fd;
|
||||
|
@ -710,9 +802,6 @@ int btrfs_defrag_fd(int fd) {
|
|||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (ioctl(fd, BTRFS_IOC_DEFRAG, NULL) < 0)
|
||||
return -errno;
|
||||
|
||||
return 0;
|
||||
return RET_NERRNO(ioctl(fd, BTRFS_IOC_DEFRAG, NULL));
|
||||
}
|
||||
#endif /* NM_IGNORED */
|
||||
|
|
|
@ -57,10 +57,10 @@ DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(DIR*, closedir, NULL);
|
|||
int fd_nonblock(int fd, bool nonblock);
|
||||
int fd_cloexec(int fd, bool cloexec);
|
||||
|
||||
int close_all_fds_full(int except[], size_t n_except, bool allow_alloc);
|
||||
static inline int close_all_fds(int except[], size_t n_except) {
|
||||
return close_all_fds_full(except, n_except, true);
|
||||
}
|
||||
int get_max_fd(void);
|
||||
|
||||
int close_all_fds(const int except[], size_t n_except);
|
||||
int close_all_fds_without_malloc(const int except[], size_t n_except);
|
||||
|
||||
int same_fd(int a, int b);
|
||||
|
||||
|
@ -91,9 +91,10 @@ static inline int make_null_stdio(void) {
|
|||
/* Like TAKE_PTR() but for file descriptors, resetting them to -1 */
|
||||
#define TAKE_FD(fd) \
|
||||
({ \
|
||||
int _fd_ = (fd); \
|
||||
(fd) = -1; \
|
||||
_fd_; \
|
||||
int *_fd_ = &(fd); \
|
||||
int _ret_ = *_fd_; \
|
||||
*_fd_ = -1; \
|
||||
_ret_; \
|
||||
})
|
||||
|
||||
/* Like free_and_replace(), but for file descriptors */
|
||||
|
|
|
@ -169,7 +169,7 @@ int write_string_stream_ts(
|
|||
* it won't be equal to the new value. */
|
||||
if (read_virtual_file_fd(fd, strlen(line)+1, &t, NULL) > 0 &&
|
||||
streq_skip_trailing_chars(line, t, NEWLINE)) {
|
||||
log_debug("No change in value '%s', supressing write", line);
|
||||
log_debug("No change in value '%s', suppressing write", line);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -551,12 +551,25 @@ int read_virtual_file_fd(int fd, size_t max_size, char **ret_contents, size_t *r
|
|||
return !truncated;
|
||||
}
|
||||
|
||||
int read_virtual_file(const char *filename, size_t max_size, char **ret_contents, size_t *ret_size) {
|
||||
int read_virtual_file_at(
|
||||
int dir_fd,
|
||||
const char *filename,
|
||||
size_t max_size,
|
||||
char **ret_contents,
|
||||
size_t *ret_size) {
|
||||
|
||||
_cleanup_close_ int fd = -1;
|
||||
|
||||
assert(filename);
|
||||
assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
|
||||
|
||||
fd = open(filename, O_RDONLY | O_NOCTTY | O_CLOEXEC);
|
||||
if (!filename) {
|
||||
if (dir_fd == AT_FDCWD)
|
||||
return -EBADF;
|
||||
|
||||
return read_virtual_file_fd(dir_fd, max_size, ret_contents, ret_size);
|
||||
}
|
||||
|
||||
fd = openat(dir_fd, filename, O_RDONLY | O_NOCTTY | O_CLOEXEC);
|
||||
if (fd < 0)
|
||||
return -errno;
|
||||
|
||||
|
@ -934,6 +947,9 @@ DIR *xopendirat(int fd, const char *name, int flags) {
|
|||
|
||||
assert(!(flags & O_CREAT));
|
||||
|
||||
if (fd == AT_FDCWD && flags == 0)
|
||||
return opendir(name);
|
||||
|
||||
nfd = openat(fd, name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|flags, 0);
|
||||
if (nfd < 0)
|
||||
return NULL;
|
||||
|
|
|
@ -69,7 +69,10 @@ static inline int read_full_file(const char *filename, char **ret_contents, size
|
|||
}
|
||||
|
||||
int read_virtual_file_fd(int fd, size_t max_size, char **ret_contents, size_t *ret_size);
|
||||
int read_virtual_file(const char *filename, size_t max_size, char **ret_contents, size_t *ret_size);
|
||||
int read_virtual_file_at(int dir_fd, const char *filename, size_t max_size, char **ret_contents, size_t *ret_size);
|
||||
static inline int read_virtual_file(const char *filename, size_t max_size, char **ret_contents, size_t *ret_size) {
|
||||
return read_virtual_file_at(AT_FDCWD, filename, max_size, ret_contents, ret_size);
|
||||
}
|
||||
static inline int read_full_virtual_file(const char *filename, char **ret_contents, size_t *ret_size) {
|
||||
return read_virtual_file(filename, SIZE_MAX, ret_contents, ret_size);
|
||||
}
|
||||
|
|
|
@ -26,11 +26,15 @@ assert_cc(sizeof(gid_t) == sizeof(uint32_t));
|
|||
# error Unknown time_t size
|
||||
#endif
|
||||
|
||||
#if defined __x86_64__ && defined __ILP32__
|
||||
#if 0 /* NM_IGNORED */
|
||||
#if SIZEOF_TIMEX_MEMBER == 8
|
||||
# define PRI_TIMEX PRIi64
|
||||
#else
|
||||
#elif SIZEOF_TIMEX_MEMBER == 4
|
||||
# define PRI_TIMEX "li"
|
||||
#else
|
||||
# error Unknown timex member size
|
||||
#endif
|
||||
#endif /* NM_IGNORED */
|
||||
|
||||
#if SIZEOF_RLIM_T == 8
|
||||
# define RLIM_FMT "%" PRIu64
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "fd-util.h"
|
||||
#include "fileio.h"
|
||||
#include "fs-util.h"
|
||||
#include "hostname-util.h"
|
||||
#include "log.h"
|
||||
#include "macro.h"
|
||||
#include "missing_fcntl.h"
|
||||
|
@ -31,18 +32,13 @@
|
|||
#include "strv.h"
|
||||
#include "time-util.h"
|
||||
#include "tmpfile-util.h"
|
||||
#include "umask-util.h"
|
||||
#include "user-util.h"
|
||||
#include "util.h"
|
||||
|
||||
int unlink_noerrno(const char *path) {
|
||||
PROTECT_ERRNO;
|
||||
int r;
|
||||
|
||||
r = unlink(path);
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
|
||||
return 0;
|
||||
return RET_NERRNO(unlink(path));
|
||||
}
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
|
@ -59,7 +55,7 @@ int rmdir_parents(const char *path, const char *stop) {
|
|||
if (!path_is_safe(stop))
|
||||
return -EINVAL;
|
||||
|
||||
p = strdupa(path);
|
||||
p = strdupa_safe(path);
|
||||
|
||||
for (;;) {
|
||||
char *slash = NULL;
|
||||
|
@ -99,8 +95,8 @@ int rename_noreplace(int olddirfd, const char *oldpath, int newdirfd, const char
|
|||
* want — though not atomic (i.e. for a short period both the new and the old filename will exist). */
|
||||
if (linkat(olddirfd, oldpath, newdirfd, newpath, 0) >= 0) {
|
||||
|
||||
if (unlinkat(olddirfd, oldpath, 0) < 0) {
|
||||
r = -errno; /* Backup errno before the following unlinkat() alters it */
|
||||
r = RET_NERRNO(unlinkat(olddirfd, oldpath, 0));
|
||||
if (r < 0) {
|
||||
(void) unlinkat(newdirfd, newpath, 0);
|
||||
return r;
|
||||
}
|
||||
|
@ -119,10 +115,7 @@ int rename_noreplace(int olddirfd, const char *oldpath, int newdirfd, const char
|
|||
if (errno != ENOENT)
|
||||
return -errno;
|
||||
|
||||
if (renameat(olddirfd, oldpath, newdirfd, newpath) < 0)
|
||||
return -errno;
|
||||
|
||||
return 0;
|
||||
return RET_NERRNO(renameat(olddirfd, oldpath, newdirfd, newpath));
|
||||
}
|
||||
#endif /* NM_IGNORED */
|
||||
|
||||
|
@ -290,14 +283,9 @@ int fchmod_and_chown_with_fallback(int fd, const char *path, mode_t mode, uid_t
|
|||
}
|
||||
|
||||
int fchmod_umask(int fd, mode_t m) {
|
||||
mode_t u;
|
||||
int r;
|
||||
_cleanup_umask_ mode_t u = umask(0777);
|
||||
|
||||
u = umask(0777);
|
||||
r = fchmod(fd, m & (~u)) < 0 ? -errno : 0;
|
||||
umask(u);
|
||||
|
||||
return r;
|
||||
return RET_NERRNO(fchmod(fd, m & (~u)));
|
||||
}
|
||||
|
||||
int fchmod_opath(int fd, mode_t m) {
|
||||
|
@ -550,7 +538,6 @@ int mkfifoat_atomic(int dirfd, const char *path, mode_t mode) {
|
|||
int get_files_in_directory(const char *path, char ***list) {
|
||||
_cleanup_strv_free_ char **l = NULL;
|
||||
_cleanup_closedir_ DIR *d = NULL;
|
||||
struct dirent *de;
|
||||
size_t n = 0;
|
||||
|
||||
assert(path);
|
||||
|
@ -830,7 +817,7 @@ int unlinkat_deallocate(int fd, const char *name, UnlinkDeallocateFlags flags) {
|
|||
|
||||
int open_parent(const char *path, int flags, mode_t mode) {
|
||||
_cleanup_free_ char *parent = NULL;
|
||||
int fd, r;
|
||||
int r;
|
||||
|
||||
r = path_extract_directory(path, &parent);
|
||||
if (r < 0)
|
||||
|
@ -844,11 +831,7 @@ int open_parent(const char *path, int flags, mode_t mode) {
|
|||
else if (!FLAGS_SET(flags, O_TMPFILE))
|
||||
flags |= O_DIRECTORY|O_RDONLY;
|
||||
|
||||
fd = open(parent, flags, mode);
|
||||
if (fd < 0)
|
||||
return -errno;
|
||||
|
||||
return fd;
|
||||
return RET_NERRNO(open(parent, flags, mode));
|
||||
}
|
||||
#endif /* NM_IGNORED */
|
||||
|
||||
|
@ -962,3 +945,152 @@ int posix_fallocate_loop(int fd, uint64_t offset, uint64_t size) {
|
|||
|
||||
return -EINTR;
|
||||
}
|
||||
|
||||
int parse_cifs_service(
|
||||
const char *s,
|
||||
char **ret_host,
|
||||
char **ret_service,
|
||||
char **ret_path) {
|
||||
|
||||
_cleanup_free_ char *h = NULL, *ss = NULL, *x = NULL;
|
||||
const char *p, *e, *d;
|
||||
char delimiter;
|
||||
|
||||
/* Parses a CIFS service in form of //host/service/path… and splitting it in three parts. The last
|
||||
* part is optional, in which case NULL is returned there. To maximize compatibility syntax with
|
||||
* backslashes instead of slashes is accepted too. */
|
||||
|
||||
if (!s)
|
||||
return -EINVAL;
|
||||
|
||||
p = startswith(s, "//");
|
||||
if (!p) {
|
||||
p = startswith(s, "\\\\");
|
||||
if (!p)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
delimiter = s[0];
|
||||
e = strchr(p, delimiter);
|
||||
if (!e)
|
||||
return -EINVAL;
|
||||
|
||||
h = strndup(p, e - p);
|
||||
if (!h)
|
||||
return -ENOMEM;
|
||||
|
||||
if (!hostname_is_valid(h, 0))
|
||||
return -EINVAL;
|
||||
|
||||
e++;
|
||||
|
||||
d = strchrnul(e, delimiter);
|
||||
|
||||
ss = strndup(e, d - e);
|
||||
if (!ss)
|
||||
return -ENOMEM;
|
||||
|
||||
if (!filename_is_valid(ss))
|
||||
return -EINVAL;
|
||||
|
||||
if (!isempty(d)) {
|
||||
x = strdup(skip_leading_chars(d, CHAR_TO_STR(delimiter)));
|
||||
if (!x)
|
||||
return -EINVAL;
|
||||
|
||||
/* Make sure to convert Windows-style "\" → Unix-style / */
|
||||
for (char *i = x; *i; i++)
|
||||
if (*i == delimiter)
|
||||
*i = '/';
|
||||
|
||||
if (!path_is_valid(x))
|
||||
return -EINVAL;
|
||||
|
||||
path_simplify(x);
|
||||
if (!path_is_normalized(x))
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (ret_host)
|
||||
*ret_host = TAKE_PTR(h);
|
||||
if (ret_service)
|
||||
*ret_service = TAKE_PTR(ss);
|
||||
if (ret_path)
|
||||
*ret_path = TAKE_PTR(x);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int open_mkdir_at(int dirfd, const char *path, int flags, mode_t mode) {
|
||||
_cleanup_close_ int fd = -1, parent_fd = -1;
|
||||
_cleanup_free_ char *fname = NULL;
|
||||
bool made;
|
||||
int r;
|
||||
|
||||
/* Creates a directory with mkdirat() and then opens it, in the "most atomic" fashion we can
|
||||
* do. Guarantees that the returned fd refers to a directory. If O_EXCL is specified will fail if the
|
||||
* dir already exists. Otherwise will open an existing dir, but only if it is one. */
|
||||
|
||||
if (flags & ~(O_RDONLY|O_CLOEXEC|O_DIRECTORY|O_EXCL|O_NOATIME|O_NOFOLLOW|O_PATH))
|
||||
return -EINVAL;
|
||||
if ((flags & O_ACCMODE) != O_RDONLY)
|
||||
return -EINVAL;
|
||||
|
||||
/* Note that O_DIRECTORY|O_NOFOLLOW is implied, but we allow specifying it anyway. The following
|
||||
* flags actually make sense to specify: O_CLOEXEC, O_EXCL, O_NOATIME, O_PATH */
|
||||
|
||||
if (isempty(path))
|
||||
return -EINVAL;
|
||||
|
||||
if (!filename_is_valid(path)) {
|
||||
_cleanup_free_ char *parent = NULL;
|
||||
|
||||
/* If this is not a valid filename, it's a path. Let's open the parent directory then, so
|
||||
* that we can pin it, and operate below it. */
|
||||
|
||||
r = path_extract_directory(path, &parent);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = path_extract_filename(path, &fname);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
parent_fd = openat(dirfd, parent, O_PATH|O_DIRECTORY|O_CLOEXEC);
|
||||
if (parent_fd < 0)
|
||||
return -errno;
|
||||
|
||||
dirfd = parent_fd;
|
||||
path = fname;
|
||||
}
|
||||
|
||||
r = RET_NERRNO(mkdirat(dirfd, path, mode));
|
||||
if (r == -EEXIST) {
|
||||
if (FLAGS_SET(flags, O_EXCL))
|
||||
return -EEXIST;
|
||||
|
||||
made = false;
|
||||
} else if (r < 0)
|
||||
return r;
|
||||
else
|
||||
made = true;
|
||||
|
||||
fd = RET_NERRNO(openat(dirfd, path, (flags & ~O_EXCL)|O_DIRECTORY|O_NOFOLLOW));
|
||||
if (fd < 0) {
|
||||
if (fd == -ENOENT) /* We got ENOENT? then someone else immediately removed it after we
|
||||
* created it. In that case let's return immediately without unlinking
|
||||
* anything, because there simply isn't anything to unlink anymore. */
|
||||
return -ENOENT;
|
||||
if (fd == -ELOOP) /* is a symlink? exists already → created by someone else, don't unlink */
|
||||
return -EEXIST;
|
||||
if (fd == -ENOTDIR) /* not a directory? exists already → created by someone else, don't unlink */
|
||||
return -EEXIST;
|
||||
|
||||
if (made)
|
||||
(void) unlinkat(dirfd, path, AT_REMOVEDIR);
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
return TAKE_FD(fd);
|
||||
}
|
||||
|
|
|
@ -47,7 +47,7 @@ int fd_warn_permissions(const char *path, int fd);
|
|||
int stat_warn_permissions(const char *path, const struct stat *st);
|
||||
|
||||
#define laccess(path, mode) \
|
||||
(faccessat(AT_FDCWD, (path), (mode), AT_SYMLINK_NOFOLLOW) < 0 ? -errno : 0)
|
||||
RET_NERRNO(faccessat(AT_FDCWD, (path), (mode), AT_SYMLINK_NOFOLLOW))
|
||||
|
||||
int touch_file(const char *path, bool parents, usec_t stamp, uid_t uid, gid_t gid, mode_t mode);
|
||||
int touch(const char *path);
|
||||
|
@ -106,3 +106,7 @@ static inline int conservative_rename(const char *oldpath, const char *newpath)
|
|||
}
|
||||
|
||||
int posix_fallocate_loop(int fd, uint64_t offset, uint64_t size);
|
||||
|
||||
int parse_cifs_service(const char *s, char **ret_host, char **ret_service, char **ret_path);
|
||||
|
||||
int open_mkdir_at(int dirfd, const char *path, int flags, mode_t mode);
|
||||
|
|
|
@ -49,8 +49,7 @@ int gethostname_full(GetHostnameFlags flags, char **ret) {
|
|||
assert_se(uname(&u) >= 0);
|
||||
|
||||
s = u.nodename;
|
||||
if (isempty(s) ||
|
||||
(!FLAGS_SET(flags, GET_HOSTNAME_ALLOW_NONE) && streq(s, "(none)")) ||
|
||||
if (isempty(s) || streq(s, "(none)") ||
|
||||
(!FLAGS_SET(flags, GET_HOSTNAME_ALLOW_LOCALHOST) && is_localhost(s)) ||
|
||||
(FLAGS_SET(flags, GET_HOSTNAME_SHORT) && s[0] == '.')) {
|
||||
if (!FLAGS_SET(flags, GET_HOSTNAME_FALLBACK_DEFAULT))
|
||||
|
|
|
@ -9,10 +9,9 @@
|
|||
#include "strv.h"
|
||||
|
||||
typedef enum GetHostnameFlags {
|
||||
GET_HOSTNAME_ALLOW_NONE = 1 << 0, /* accepts "(none)". */
|
||||
GET_HOSTNAME_ALLOW_LOCALHOST = 1 << 1, /* accepts "localhost" or friends. */
|
||||
GET_HOSTNAME_FALLBACK_DEFAULT = 1 << 2, /* use default hostname if no hostname is set. */
|
||||
GET_HOSTNAME_SHORT = 1 << 3, /* kills the FQDN part if present. */
|
||||
GET_HOSTNAME_ALLOW_LOCALHOST = 1 << 0, /* accepts "localhost" or friends. */
|
||||
GET_HOSTNAME_FALLBACK_DEFAULT = 1 << 1, /* use default hostname if no hostname is set. */
|
||||
GET_HOSTNAME_SHORT = 1 << 2, /* kills the FQDN part if present. */
|
||||
} GetHostnameFlags;
|
||||
|
||||
int gethostname_full(GetHostnameFlags flags, char **ret);
|
||||
|
|
|
@ -629,21 +629,19 @@ int in4_addr_default_subnet_mask(const struct in_addr *addr, struct in_addr *mas
|
|||
return 0;
|
||||
}
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
int in_addr_mask(int family, union in_addr_union *addr, unsigned char prefixlen) {
|
||||
assert(addr);
|
||||
|
||||
if (family == AF_INET) {
|
||||
int in4_addr_mask(struct in_addr *addr, unsigned char prefixlen) {
|
||||
struct in_addr mask;
|
||||
|
||||
assert(addr);
|
||||
|
||||
if (!in4_addr_prefixlen_to_netmask(&mask, prefixlen))
|
||||
return -EINVAL;
|
||||
|
||||
addr->in.s_addr &= mask.s_addr;
|
||||
addr->s_addr &= mask.s_addr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (family == AF_INET6) {
|
||||
int in6_addr_mask(struct in6_addr *addr, unsigned char prefixlen) {
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < 16; i++) {
|
||||
|
@ -652,42 +650,99 @@ int in_addr_mask(int family, union in_addr_union *addr, unsigned char prefixlen)
|
|||
if (prefixlen >= 8) {
|
||||
mask = 0xFF;
|
||||
prefixlen -= 8;
|
||||
} else {
|
||||
} else if (prefixlen > 0) {
|
||||
mask = 0xFF << (8 - prefixlen);
|
||||
prefixlen = 0;
|
||||
} else {
|
||||
assert(prefixlen == 0);
|
||||
mask = 0;
|
||||
}
|
||||
|
||||
addr->in6.s6_addr[i] &= mask;
|
||||
addr->s6_addr[i] &= mask;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
int in_addr_mask(int family, union in_addr_union *addr, unsigned char prefixlen) {
|
||||
assert(addr);
|
||||
|
||||
switch (family) {
|
||||
case AF_INET:
|
||||
return in4_addr_mask(&addr->in, prefixlen);
|
||||
case AF_INET6:
|
||||
return in6_addr_mask(&addr->in6, prefixlen);
|
||||
default:
|
||||
return -EAFNOSUPPORT;
|
||||
}
|
||||
}
|
||||
|
||||
int in_addr_prefix_covers(int family,
|
||||
const union in_addr_union *prefix,
|
||||
int in4_addr_prefix_covers(
|
||||
const struct in_addr *prefix,
|
||||
unsigned char prefixlen,
|
||||
const union in_addr_union *address) {
|
||||
const struct in_addr *address) {
|
||||
|
||||
union in_addr_union masked_prefix, masked_address;
|
||||
struct in_addr masked_prefix, masked_address;
|
||||
int r;
|
||||
|
||||
assert(prefix);
|
||||
assert(address);
|
||||
|
||||
masked_prefix = *prefix;
|
||||
r = in_addr_mask(family, &masked_prefix, prefixlen);
|
||||
r = in4_addr_mask(&masked_prefix, prefixlen);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
masked_address = *address;
|
||||
r = in_addr_mask(family, &masked_address, prefixlen);
|
||||
r = in4_addr_mask(&masked_address, prefixlen);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return in_addr_equal(family, &masked_prefix, &masked_address);
|
||||
return in4_addr_equal(&masked_prefix, &masked_address);
|
||||
}
|
||||
|
||||
int in6_addr_prefix_covers(
|
||||
const struct in6_addr *prefix,
|
||||
unsigned char prefixlen,
|
||||
const struct in6_addr *address) {
|
||||
|
||||
struct in6_addr masked_prefix, masked_address;
|
||||
int r;
|
||||
|
||||
assert(prefix);
|
||||
assert(address);
|
||||
|
||||
masked_prefix = *prefix;
|
||||
r = in6_addr_mask(&masked_prefix, prefixlen);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
masked_address = *address;
|
||||
r = in6_addr_mask(&masked_address, prefixlen);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return in6_addr_equal(&masked_prefix, &masked_address);
|
||||
}
|
||||
|
||||
int in_addr_prefix_covers(
|
||||
int family,
|
||||
const union in_addr_union *prefix,
|
||||
unsigned char prefixlen,
|
||||
const union in_addr_union *address) {
|
||||
|
||||
assert(prefix);
|
||||
assert(address);
|
||||
|
||||
switch (family) {
|
||||
case AF_INET:
|
||||
return in4_addr_prefix_covers(&prefix->in, prefixlen, &address->in);
|
||||
case AF_INET6:
|
||||
return in6_addr_prefix_covers(&prefix->in6, prefixlen, &address->in6);
|
||||
default:
|
||||
return -EAFNOSUPPORT;
|
||||
}
|
||||
}
|
||||
|
||||
int in_addr_parse_prefixlen(int family, const char *p, unsigned char *ret) {
|
||||
|
@ -855,4 +910,10 @@ int in6_addr_compare_func(const struct in6_addr *a, const struct in6_addr *b) {
|
|||
}
|
||||
|
||||
DEFINE_HASH_OPS(in6_addr_hash_ops, struct in6_addr, in6_addr_hash_func, in6_addr_compare_func);
|
||||
DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(
|
||||
in6_addr_hash_ops_free,
|
||||
struct in6_addr,
|
||||
in6_addr_hash_func,
|
||||
in6_addr_compare_func,
|
||||
free);
|
||||
#endif /* NM_IGNORED */
|
||||
|
|
|
@ -89,7 +89,11 @@ unsigned char in4_addr_netmask_to_prefixlen(const struct in_addr *addr);
|
|||
struct in_addr* in4_addr_prefixlen_to_netmask(struct in_addr *addr, unsigned char prefixlen);
|
||||
int in4_addr_default_prefixlen(const struct in_addr *addr, unsigned char *prefixlen);
|
||||
int in4_addr_default_subnet_mask(const struct in_addr *addr, struct in_addr *mask);
|
||||
int in4_addr_mask(struct in_addr *addr, unsigned char prefixlen);
|
||||
int in6_addr_mask(struct in6_addr *addr, unsigned char prefixlen);
|
||||
int in_addr_mask(int family, union in_addr_union *addr, unsigned char prefixlen);
|
||||
int in4_addr_prefix_covers(const struct in_addr *prefix, unsigned char prefixlen, const struct in_addr *address);
|
||||
int in6_addr_prefix_covers(const struct in6_addr *prefix, unsigned char prefixlen, const struct in6_addr *address);
|
||||
int in_addr_prefix_covers(int family, const union in_addr_union *prefix, unsigned char prefixlen, const union in_addr_union *address);
|
||||
int in_addr_parse_prefixlen(int family, const char *p, unsigned char *ret);
|
||||
int in_addr_prefix_from_string(const char *p, int family, union in_addr_union *ret_prefix, unsigned char *ret_prefixlen);
|
||||
|
@ -110,6 +114,13 @@ static inline size_t FAMILY_ADDRESS_SIZE(int family) {
|
|||
return family == AF_INET6 ? 16 : 4;
|
||||
}
|
||||
|
||||
#define FAMILY_ADDRESS_SIZE_SAFE(f) \
|
||||
({ \
|
||||
int _f = (f); \
|
||||
_f == AF_INET ? sizeof(struct in_addr) : \
|
||||
_f == AF_INET6 ? sizeof(struct in6_addr) : 0; \
|
||||
})
|
||||
|
||||
/* Workaround for clang, explicitly specify the maximum-size element here.
|
||||
* See also oss-fuzz#11344. */
|
||||
#define IN_ADDR_NULL ((union in_addr_union) { .in6 = {} })
|
||||
|
@ -119,6 +130,7 @@ int in6_addr_compare_func(const struct in6_addr *a, const struct in6_addr *b);
|
|||
|
||||
extern const struct hash_ops in_addr_data_hash_ops;
|
||||
extern const struct hash_ops in6_addr_hash_ops;
|
||||
extern const struct hash_ops in6_addr_hash_ops_free;
|
||||
|
||||
#define IPV4_ADDRESS_FMT_STR "%u.%u.%u.%u"
|
||||
#define IPV4_ADDRESS_FMT_VAL(address) \
|
||||
|
|
|
@ -4,15 +4,27 @@
|
|||
|
||||
#include "fd-util.h"
|
||||
#include "inotify-util.h"
|
||||
#include "stat-util.h"
|
||||
|
||||
int inotify_add_watch_fd(int fd, int what, uint32_t mask) {
|
||||
int wd;
|
||||
int wd, r;
|
||||
|
||||
/* This is like inotify_add_watch(), except that the file to watch is not referenced by a path, but by an fd */
|
||||
wd = inotify_add_watch(fd, FORMAT_PROC_FD_PATH(what), mask);
|
||||
if (wd < 0)
|
||||
if (wd < 0) {
|
||||
if (errno != ENOENT)
|
||||
return -errno;
|
||||
|
||||
/* Didn't work with ENOENT? If so, then either /proc/ isn't mounted, or the fd is bad */
|
||||
r = proc_mounted();
|
||||
if (r == 0)
|
||||
return -ENOSYS;
|
||||
if (r > 0)
|
||||
return -EBADF;
|
||||
|
||||
return -ENOENT; /* OK, no clue, let's propagate the original error */
|
||||
}
|
||||
|
||||
return wd;
|
||||
}
|
||||
|
||||
|
|
|
@ -134,7 +134,7 @@
|
|||
} while (false)
|
||||
|
||||
#define LIST_JUST_US(name,item) \
|
||||
(!(item)->name##_prev && !(item)->name##_next) \
|
||||
(!(item)->name##_prev && !(item)->name##_next)
|
||||
|
||||
#define LIST_FOREACH(name,i,head) \
|
||||
for ((i) = (head); (i); (i) = (i)->name##_next)
|
||||
|
@ -181,3 +181,12 @@
|
|||
} \
|
||||
(b) = NULL; \
|
||||
} while (false)
|
||||
|
||||
#define LIST_POP(name, a) \
|
||||
({ \
|
||||
typeof(a)* _a = &(a); \
|
||||
typeof(a) _p = *_a; \
|
||||
if (_p) \
|
||||
LIST_REMOVE(name, *_a, _p); \
|
||||
_p; \
|
||||
})
|
||||
|
|
|
@ -27,10 +27,14 @@ typedef enum LogTarget{
|
|||
_LOG_TARGET_INVALID = -EINVAL,
|
||||
} LogTarget;
|
||||
|
||||
/* Note to readers: << and >> have lower precedence than & and | */
|
||||
/* This log level disables logging completely. It can only be passed to log_set_max_level() and cannot be
|
||||
* used a regular log level. */
|
||||
#define LOG_NULL (LOG_EMERG - 1)
|
||||
|
||||
/* Note to readers: << and >> have lower precedence (are evaluated earlier) than & and | */
|
||||
#define SYNTHETIC_ERRNO(num) (1 << 30 | (num))
|
||||
#define IS_SYNTHETIC_ERRNO(val) ((val) >> 30 & 1)
|
||||
#define ERRNO_VALUE(val) (abs(val) & 255)
|
||||
#define ERRNO_VALUE(val) (abs(val) & ~(1 << 30))
|
||||
|
||||
/* The callback function to be invoked when syntax warnings are seen
|
||||
* in the unit files. */
|
||||
|
@ -90,6 +94,7 @@ int log_open(void);
|
|||
void log_close(void);
|
||||
void log_forget_fds(void);
|
||||
|
||||
void log_parse_environment_variables(void);
|
||||
void log_parse_environment(void);
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
#define _public_ __attribute__((__visibility__("default")))
|
||||
#define _hidden_ __attribute__((__visibility__("hidden")))
|
||||
#define _weakref_(x) __attribute__((__weakref__(#x)))
|
||||
#define _alignas_(x) __attribute__((__aligned__(__alignof(x))))
|
||||
#define _alignas_(x) __attribute__((__aligned__(__alignof__(x))))
|
||||
#define _alignptr_ __attribute__((__aligned__(sizeof(void*))))
|
||||
#define _warn_unused_result_ __attribute__((__warn_unused_result__))
|
||||
|
||||
|
@ -154,24 +154,6 @@
|
|||
#define ALIGN4_PTR(p) ((void*) ALIGN4((unsigned long) (p)))
|
||||
#define ALIGN8_PTR(p) ((void*) ALIGN8((unsigned long) (p)))
|
||||
|
||||
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
|
||||
|
||||
if (l > SIZE_MAX - (ali - 1))
|
||||
return SIZE_MAX; /* indicate overflow */
|
||||
|
||||
return ((l + ali - 1) & ~(ali - 1));
|
||||
}
|
||||
|
||||
#define ALIGN_TO_PTR(p, ali) ((void*) ALIGN_TO((unsigned long) (p), (ali)))
|
||||
|
||||
/* align to next higher power-of-2 (except for: 0 => 0, overflow => 0) */
|
||||
|
@ -355,13 +337,6 @@ static inline int __coverity_check_and_return__(int condition) {
|
|||
ans; \
|
||||
})
|
||||
|
||||
#define UPDATE_FLAG(orig, flag, b) \
|
||||
((b) ? ((orig) | (flag)) : ((orig) & ~(flag)))
|
||||
#define SET_FLAG(v, flag, b) \
|
||||
(v) = UPDATE_FLAG(v, flag, b)
|
||||
#define FLAGS_SET(v, flags) \
|
||||
((~(v) & (flags)) == 0)
|
||||
|
||||
#define SWAP_TWO(x, y) do { \
|
||||
typeof(x) _t = (x); \
|
||||
(x) = (y); \
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include <asm/sgidefs.h>
|
||||
#endif
|
||||
|
||||
#include "macro.h"
|
||||
#include "missing_keyctl.h"
|
||||
#include "missing_stat.h"
|
||||
#include "missing_syscall_def.h"
|
||||
|
@ -79,7 +80,8 @@ static inline int missing_memfd_create(const char *name, unsigned int flags) {
|
|||
/* ======================================================================= */
|
||||
|
||||
#if !HAVE_GETRANDOM
|
||||
static inline int missing_getrandom(void *buffer, size_t count, unsigned flags) {
|
||||
/* glibc says getrandom() returns ssize_t */
|
||||
static inline ssize_t missing_getrandom(void *buffer, size_t count, unsigned flags) {
|
||||
# ifdef __NR_getrandom
|
||||
return syscall(__NR_getrandom, buffer, count, flags);
|
||||
# else
|
||||
|
@ -466,8 +468,52 @@ struct mount_attr {
|
|||
struct mount_attr;
|
||||
#endif
|
||||
|
||||
#ifndef MOUNT_ATTR_RDONLY
|
||||
#define MOUNT_ATTR_RDONLY 0x00000001 /* Mount read-only */
|
||||
#endif
|
||||
|
||||
#ifndef MOUNT_ATTR_NOSUID
|
||||
#define MOUNT_ATTR_NOSUID 0x00000002 /* Ignore suid and sgid bits */
|
||||
#endif
|
||||
|
||||
#ifndef MOUNT_ATTR_NODEV
|
||||
#define MOUNT_ATTR_NODEV 0x00000004 /* Disallow access to device special files */
|
||||
#endif
|
||||
|
||||
#ifndef MOUNT_ATTR_NOEXEC
|
||||
#define MOUNT_ATTR_NOEXEC 0x00000008 /* Disallow program execution */
|
||||
#endif
|
||||
|
||||
#ifndef MOUNT_ATTR__ATIME
|
||||
#define MOUNT_ATTR__ATIME 0x00000070 /* Setting on how atime should be updated */
|
||||
#endif
|
||||
|
||||
#ifndef MOUNT_ATTR_RELATIME
|
||||
#define MOUNT_ATTR_RELATIME 0x00000000 /* - Update atime relative to mtime/ctime. */
|
||||
#endif
|
||||
|
||||
#ifndef MOUNT_ATTR_NOATIME
|
||||
#define MOUNT_ATTR_NOATIME 0x00000010 /* - Do not update access times. */
|
||||
#endif
|
||||
|
||||
#ifndef MOUNT_ATTR_STRICTATIME
|
||||
#define MOUNT_ATTR_STRICTATIME 0x00000020 /* - Always perform atime updates */
|
||||
#endif
|
||||
|
||||
#ifndef MOUNT_ATTR_NODIRATIME
|
||||
#define MOUNT_ATTR_NODIRATIME 0x00000080 /* Do not update directory access times */
|
||||
#endif
|
||||
|
||||
#ifndef MOUNT_ATTR_IDMAP
|
||||
#define MOUNT_ATTR_IDMAP 0x00100000
|
||||
#define MOUNT_ATTR_IDMAP 0x00100000 /* Idmap mount to @userns_fd in struct mount_attr. */
|
||||
#endif
|
||||
|
||||
#ifndef MOUNT_ATTR_NOSYMFOLLOW
|
||||
#define MOUNT_ATTR_NOSYMFOLLOW 0x00200000 /* Do not follow symlinks */
|
||||
#endif
|
||||
|
||||
#ifndef MOUNT_ATTR_SIZE_VER0
|
||||
#define MOUNT_ATTR_SIZE_VER0 32 /* sizeof first published struct */
|
||||
#endif
|
||||
|
||||
#ifndef AT_RECURSIVE
|
||||
|
@ -545,4 +591,20 @@ static inline int missing_move_mount(
|
|||
|
||||
# define move_mount missing_move_mount
|
||||
#endif
|
||||
|
||||
/* ======================================================================= */
|
||||
|
||||
#if !HAVE_GETDENTS64
|
||||
|
||||
static inline ssize_t missing_getdents64(int fd, void *buffer, size_t length) {
|
||||
# if defined __NR_getdents64 && __NR_getdents64 >= 0
|
||||
return syscall(__NR_getdents64, fd, buffer, length);
|
||||
# else
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
# endif
|
||||
}
|
||||
|
||||
# define getdents64 missing_getdents64
|
||||
#endif
|
||||
#endif /* NM_IGNORED */
|
||||
|
|
|
@ -651,7 +651,7 @@ int parse_ip_port(const char *s, uint16_t *ret) {
|
|||
uint16_t l;
|
||||
int r;
|
||||
|
||||
r = safe_atou16(s, &l);
|
||||
r = safe_atou16_full(s, SAFE_ATO_REFUSE_LEADING_WHITESPACE, &l);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
@ -711,7 +711,7 @@ int parse_dev(const char *s, dev_t *ret) {
|
|||
if (s[n] != ':')
|
||||
return -EINVAL;
|
||||
|
||||
major = strndupa(s, n);
|
||||
major = strndupa_safe(s, n);
|
||||
r = safe_atou(major, &x);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
@ -772,7 +772,7 @@ int parse_loadavg_fixed_point(const char *s, loadavg_t *ret) {
|
|||
if (!d)
|
||||
return -EINVAL;
|
||||
|
||||
i_str = strndupa(s, d - s);
|
||||
i_str = strndupa_safe(s, d - s);
|
||||
f_str = d + 1;
|
||||
|
||||
r = safe_atolu_full(i_str, 10, &i);
|
||||
|
|
|
@ -1246,8 +1246,6 @@ char *file_in_same_dir(const char *path, const char *filename) {
|
|||
}
|
||||
|
||||
bool hidden_or_backup_file(const char *filename) {
|
||||
const char *p;
|
||||
|
||||
assert(filename);
|
||||
|
||||
if (filename[0] == '.' ||
|
||||
|
@ -1257,24 +1255,25 @@ bool hidden_or_backup_file(const char *filename) {
|
|||
endswith(filename, "~"))
|
||||
return true;
|
||||
|
||||
p = strrchr(filename, '.');
|
||||
if (!p)
|
||||
const char *dot = strrchr(filename, '.');
|
||||
if (!dot)
|
||||
return false;
|
||||
|
||||
/* Please, let's not add more entries to the list below. If external projects think it's a good idea to come up
|
||||
* with always new suffixes and that everybody else should just adjust to that, then it really should be on
|
||||
* them. Hence, in future, let's not add any more entries. Instead, let's ask those packages to instead adopt
|
||||
* one of the generic suffixes/prefixes for hidden files or backups, possibly augmented with an additional
|
||||
* string. Specifically: there's now:
|
||||
/* Please, let's not add more entries to the list below. If external projects think it's a good idea
|
||||
* to come up with always new suffixes and that everybody else should just adjust to that, then it
|
||||
* really should be on them. Hence, in future, let's not add any more entries. Instead, let's ask
|
||||
* those packages to instead adopt one of the generic suffixes/prefixes for hidden files or backups,
|
||||
* possibly augmented with an additional string. Specifically: there's now:
|
||||
*
|
||||
* The generic suffixes "~" and ".bak" for backup files
|
||||
* The generic prefix "." for hidden files
|
||||
*
|
||||
* Thus, if a new package manager "foopkg" wants its own set of ".foopkg-new", ".foopkg-old", ".foopkg-dist"
|
||||
* or so registered, let's refuse that and ask them to use ".foopkg.new", ".foopkg.old" or ".foopkg~" instead.
|
||||
* Thus, if a new package manager "foopkg" wants its own set of ".foopkg-new", ".foopkg-old",
|
||||
* ".foopkg-dist" or so registered, let's refuse that and ask them to use ".foopkg.new",
|
||||
* ".foopkg.old" or ".foopkg~" instead.
|
||||
*/
|
||||
|
||||
return STR_IN_SET(p + 1,
|
||||
return STR_IN_SET(dot + 1,
|
||||
"rpmnew",
|
||||
"rpmsave",
|
||||
"rpmorig",
|
||||
|
@ -1296,15 +1295,16 @@ bool hidden_or_backup_file(const char *filename) {
|
|||
|
||||
bool is_device_path(const char *path) {
|
||||
|
||||
/* Returns true on paths that likely refer to a device, either by path in sysfs or to something in /dev */
|
||||
/* Returns true for paths that likely refer to a device, either by path in sysfs or to something in
|
||||
* /dev. */
|
||||
|
||||
return PATH_STARTSWITH_SET(path, "/dev/", "/sys/");
|
||||
}
|
||||
|
||||
bool valid_device_node_path(const char *path) {
|
||||
|
||||
/* Some superficial checks whether the specified path is a valid device node path, all without looking at the
|
||||
* actual device node. */
|
||||
/* Some superficial checks whether the specified path is a valid device node path, all without
|
||||
* looking at the actual device node. */
|
||||
|
||||
if (!PATH_STARTSWITH_SET(path, "/dev/", "/run/systemd/inaccessible/"))
|
||||
return false;
|
||||
|
@ -1318,8 +1318,8 @@ bool valid_device_node_path(const char *path) {
|
|||
bool valid_device_allow_pattern(const char *path) {
|
||||
assert(path);
|
||||
|
||||
/* Like valid_device_node_path(), but also allows full-subsystem expressions, like DeviceAllow= and DeviceDeny=
|
||||
* accept it */
|
||||
/* Like valid_device_node_path(), but also allows full-subsystem expressions like those accepted by
|
||||
* DeviceAllow= and DeviceDeny=. */
|
||||
|
||||
if (STARTSWITH_SET(path, "block-", "char-"))
|
||||
return true;
|
||||
|
@ -1412,8 +1412,8 @@ bool dot_or_dot_dot(const char *path) {
|
|||
#if 0 /* NM_IGNORED */
|
||||
bool empty_or_root(const char *path) {
|
||||
|
||||
/* For operations relative to some root directory, returns true if the specified root directory is redundant,
|
||||
* i.e. either / or NULL or the empty string or any equivalent. */
|
||||
/* For operations relative to some root directory, returns true if the specified root directory is
|
||||
* redundant, i.e. either / or NULL or the empty string or any equivalent. */
|
||||
|
||||
if (isempty(path))
|
||||
return true;
|
||||
|
|
|
@ -187,13 +187,13 @@ static int get_process_cmdline_nulstr(
|
|||
return r;
|
||||
}
|
||||
|
||||
int get_process_cmdline(pid_t pid, size_t max_columns, ProcessCmdlineFlags flags, char **line) {
|
||||
int get_process_cmdline(pid_t pid, size_t max_columns, ProcessCmdlineFlags flags, char **ret) {
|
||||
_cleanup_free_ char *t = NULL;
|
||||
size_t k;
|
||||
char *ans;
|
||||
|
||||
assert(line);
|
||||
assert(pid >= 0);
|
||||
assert(ret);
|
||||
|
||||
/* Retrieve and format a commandline. See above for discussion of retrieval options.
|
||||
*
|
||||
|
@ -220,25 +220,23 @@ int get_process_cmdline(pid_t pid, size_t max_columns, ProcessCmdlineFlags flags
|
|||
assert(!(flags & PROCESS_CMDLINE_USE_LOCALE));
|
||||
|
||||
_cleanup_strv_free_ char **args = NULL;
|
||||
char **p;
|
||||
|
||||
args = strv_parse_nulstr(t, k);
|
||||
if (!args)
|
||||
return -ENOMEM;
|
||||
|
||||
for (size_t i = 0; args[i]; i++) {
|
||||
char *e;
|
||||
/* Drop trailing empty strings. See issue #21186. */
|
||||
STRV_FOREACH_BACKWARDS(p, args) {
|
||||
if (!isempty(*p))
|
||||
break;
|
||||
|
||||
e = shell_maybe_quote(args[i], shflags);
|
||||
if (!e)
|
||||
return -ENOMEM;
|
||||
|
||||
free_and_replace(args[i], e);
|
||||
*p = mfree(*p);
|
||||
}
|
||||
|
||||
ans = strv_join(args, " ");
|
||||
ans = quote_command_line(args, shflags);
|
||||
if (!ans)
|
||||
return -ENOMEM;
|
||||
|
||||
} else {
|
||||
/* Arguments are separated by NULs. Let's replace those with spaces. */
|
||||
for (size_t i = 0; i < k - 1; i++)
|
||||
|
@ -257,7 +255,7 @@ int get_process_cmdline(pid_t pid, size_t max_columns, ProcessCmdlineFlags flags
|
|||
ans = str_realloc(ans);
|
||||
}
|
||||
|
||||
*line = ans;
|
||||
*ret = ans;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -464,29 +462,29 @@ int is_kernel_thread(pid_t pid) {
|
|||
return !!(flags & PF_KTHREAD);
|
||||
}
|
||||
|
||||
int get_process_capeff(pid_t pid, char **capeff) {
|
||||
int get_process_capeff(pid_t pid, char **ret) {
|
||||
const char *p;
|
||||
int r;
|
||||
|
||||
assert(capeff);
|
||||
assert(pid >= 0);
|
||||
assert(ret);
|
||||
|
||||
p = procfs_file_alloca(pid, "status");
|
||||
|
||||
r = get_proc_field(p, "CapEff", WHITESPACE, capeff);
|
||||
r = get_proc_field(p, "CapEff", WHITESPACE, ret);
|
||||
if (r == -ENOENT)
|
||||
return -ESRCH;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int get_process_link_contents(const char *proc_file, char **name) {
|
||||
static int get_process_link_contents(const char *proc_file, char **ret) {
|
||||
int r;
|
||||
|
||||
assert(proc_file);
|
||||
assert(name);
|
||||
assert(ret);
|
||||
|
||||
r = readlink_malloc(proc_file, name);
|
||||
r = readlink_malloc(proc_file, ret);
|
||||
if (r == -ENOENT)
|
||||
return -ESRCH;
|
||||
if (r < 0)
|
||||
|
@ -495,32 +493,33 @@ static int get_process_link_contents(const char *proc_file, char **name) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int get_process_exe(pid_t pid, char **name) {
|
||||
int get_process_exe(pid_t pid, char **ret) {
|
||||
const char *p;
|
||||
char *d;
|
||||
int r;
|
||||
|
||||
assert(pid >= 0);
|
||||
assert(ret);
|
||||
|
||||
p = procfs_file_alloca(pid, "exe");
|
||||
r = get_process_link_contents(p, name);
|
||||
r = get_process_link_contents(p, ret);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
d = endswith(*name, " (deleted)");
|
||||
d = endswith(*ret, " (deleted)");
|
||||
if (d)
|
||||
*d = '\0';
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_process_id(pid_t pid, const char *field, uid_t *uid) {
|
||||
static int get_process_id(pid_t pid, const char *field, uid_t *ret) {
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
const char *p;
|
||||
int r;
|
||||
|
||||
assert(field);
|
||||
assert(uid);
|
||||
assert(ret);
|
||||
|
||||
if (pid < 0)
|
||||
return -EINVAL;
|
||||
|
@ -550,60 +549,62 @@ static int get_process_id(pid_t pid, const char *field, uid_t *uid) {
|
|||
|
||||
l[strcspn(l, WHITESPACE)] = 0;
|
||||
|
||||
return parse_uid(l, uid);
|
||||
return parse_uid(l, ret);
|
||||
}
|
||||
}
|
||||
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
int get_process_uid(pid_t pid, uid_t *uid) {
|
||||
int get_process_uid(pid_t pid, uid_t *ret) {
|
||||
|
||||
if (pid == 0 || pid == getpid_cached()) {
|
||||
*uid = getuid();
|
||||
*ret = getuid();
|
||||
return 0;
|
||||
}
|
||||
|
||||
return get_process_id(pid, "Uid:", uid);
|
||||
return get_process_id(pid, "Uid:", ret);
|
||||
}
|
||||
|
||||
int get_process_gid(pid_t pid, gid_t *gid) {
|
||||
int get_process_gid(pid_t pid, gid_t *ret) {
|
||||
|
||||
if (pid == 0 || pid == getpid_cached()) {
|
||||
*gid = getgid();
|
||||
*ret = getgid();
|
||||
return 0;
|
||||
}
|
||||
|
||||
assert_cc(sizeof(uid_t) == sizeof(gid_t));
|
||||
return get_process_id(pid, "Gid:", gid);
|
||||
return get_process_id(pid, "Gid:", ret);
|
||||
}
|
||||
|
||||
int get_process_cwd(pid_t pid, char **cwd) {
|
||||
int get_process_cwd(pid_t pid, char **ret) {
|
||||
const char *p;
|
||||
|
||||
assert(pid >= 0);
|
||||
assert(ret);
|
||||
|
||||
if (pid == 0 || pid == getpid_cached())
|
||||
return safe_getcwd(cwd);
|
||||
return safe_getcwd(ret);
|
||||
|
||||
p = procfs_file_alloca(pid, "cwd");
|
||||
|
||||
return get_process_link_contents(p, cwd);
|
||||
return get_process_link_contents(p, ret);
|
||||
}
|
||||
|
||||
int get_process_root(pid_t pid, char **root) {
|
||||
int get_process_root(pid_t pid, char **ret) {
|
||||
const char *p;
|
||||
|
||||
assert(pid >= 0);
|
||||
assert(ret);
|
||||
|
||||
p = procfs_file_alloca(pid, "root");
|
||||
|
||||
return get_process_link_contents(p, root);
|
||||
return get_process_link_contents(p, ret);
|
||||
}
|
||||
|
||||
#define ENVIRONMENT_BLOCK_MAX (5U*1024U*1024U)
|
||||
|
||||
int get_process_environ(pid_t pid, char **env) {
|
||||
int get_process_environ(pid_t pid, char **ret) {
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
_cleanup_free_ char *outcome = NULL;
|
||||
size_t sz = 0;
|
||||
|
@ -611,7 +612,7 @@ int get_process_environ(pid_t pid, char **env) {
|
|||
int r;
|
||||
|
||||
assert(pid >= 0);
|
||||
assert(env);
|
||||
assert(ret);
|
||||
|
||||
p = procfs_file_alloca(pid, "environ");
|
||||
|
||||
|
@ -643,7 +644,7 @@ int get_process_environ(pid_t pid, char **env) {
|
|||
}
|
||||
|
||||
outcome[sz] = '\0';
|
||||
*env = TAKE_PTR(outcome);
|
||||
*ret = TAKE_PTR(outcome);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -702,13 +703,13 @@ int get_process_ppid(pid_t pid, pid_t *ret) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int get_process_umask(pid_t pid, mode_t *umask) {
|
||||
int get_process_umask(pid_t pid, mode_t *ret) {
|
||||
_cleanup_free_ char *m = NULL;
|
||||
const char *p;
|
||||
int r;
|
||||
|
||||
assert(umask);
|
||||
assert(pid >= 0);
|
||||
assert(ret);
|
||||
|
||||
p = procfs_file_alloca(pid, "status");
|
||||
|
||||
|
@ -716,7 +717,7 @@ int get_process_umask(pid_t pid, mode_t *umask) {
|
|||
if (r == -ENOENT)
|
||||
return -ESRCH;
|
||||
|
||||
return parse_mode(m, umask);
|
||||
return parse_mode(m, ret);
|
||||
}
|
||||
|
||||
int wait_for_terminate(pid_t pid, siginfo_t *status) {
|
||||
|
@ -830,7 +831,7 @@ int wait_for_terminate_with_timeout(pid_t pid, usec_t timeout) {
|
|||
if (n >= until)
|
||||
break;
|
||||
|
||||
r = sigtimedwait(&mask, NULL, timespec_store(&ts, until - n)) < 0 ? -errno : 0;
|
||||
r = RET_NERRNO(sigtimedwait(&mask, NULL, timespec_store(&ts, until - n)));
|
||||
/* Assuming we woke due to the child exiting. */
|
||||
if (waitid(P_PID, pid, &status, WEXITED|WNOHANG) == 0) {
|
||||
if (status.si_pid == pid) {
|
||||
|
@ -863,7 +864,7 @@ int wait_for_terminate_with_timeout(pid_t pid, usec_t timeout) {
|
|||
void sigkill_wait(pid_t pid) {
|
||||
assert(pid > 1);
|
||||
|
||||
if (kill(pid, SIGKILL) >= 0)
|
||||
(void) kill(pid, SIGKILL);
|
||||
(void) wait_for_terminate(pid, NULL);
|
||||
}
|
||||
|
||||
|
@ -881,14 +882,14 @@ void sigkill_waitp(pid_t *pid) {
|
|||
void sigterm_wait(pid_t pid) {
|
||||
assert(pid > 1);
|
||||
|
||||
if (kill_and_sigcont(pid, SIGTERM) >= 0)
|
||||
(void) kill_and_sigcont(pid, SIGTERM);
|
||||
(void) wait_for_terminate(pid, NULL);
|
||||
}
|
||||
|
||||
int kill_and_sigcont(pid_t pid, int sig) {
|
||||
int r;
|
||||
|
||||
r = kill(pid, sig) < 0 ? -errno : 0;
|
||||
r = RET_NERRNO(kill(pid, sig));
|
||||
|
||||
/* If this worked, also send SIGCONT, unless we already just sent a SIGCONT, or SIGKILL was sent which isn't
|
||||
* affected by a process being suspended anyway. */
|
||||
|
@ -1064,8 +1065,8 @@ unsigned long personality_from_string(const char *p) {
|
|||
|
||||
if (architecture == native_architecture())
|
||||
return PER_LINUX;
|
||||
#ifdef SECONDARY_ARCHITECTURE
|
||||
if (architecture == SECONDARY_ARCHITECTURE)
|
||||
#ifdef ARCHITECTURE_SECONDARY
|
||||
if (architecture == ARCHITECTURE_SECONDARY)
|
||||
return PER_LINUX32;
|
||||
#endif
|
||||
|
||||
|
@ -1077,9 +1078,9 @@ const char* personality_to_string(unsigned long p) {
|
|||
|
||||
if (p == PER_LINUX)
|
||||
architecture = native_architecture();
|
||||
#ifdef SECONDARY_ARCHITECTURE
|
||||
#ifdef ARCHITECTURE_SECONDARY
|
||||
else if (p == PER_LINUX32)
|
||||
architecture = SECONDARY_ARCHITECTURE;
|
||||
architecture = ARCHITECTURE_SECONDARY;
|
||||
#endif
|
||||
|
||||
if (architecture < 0)
|
||||
|
@ -1150,23 +1151,6 @@ int pid_compare_func(const pid_t *a, const pid_t *b) {
|
|||
/* Suitable for usage in qsort() */
|
||||
return CMP(*a, *b);
|
||||
}
|
||||
|
||||
int ioprio_parse_priority(const char *s, int *ret) {
|
||||
int i, r;
|
||||
|
||||
assert(s);
|
||||
assert(ret);
|
||||
|
||||
r = safe_atoi(s, &i);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (!ioprio_priority_is_valid(i))
|
||||
return -EINVAL;
|
||||
|
||||
*ret = i;
|
||||
return 0;
|
||||
}
|
||||
#endif /* NM_IGNORED */
|
||||
|
||||
/* The cached PID, possible values:
|
||||
|
@ -1256,7 +1240,7 @@ static void restore_sigsetp(sigset_t **ssp) {
|
|||
|
||||
int safe_fork_full(
|
||||
const char *name,
|
||||
int except_fds[],
|
||||
const int except_fds[],
|
||||
size_t n_except_fds,
|
||||
ForkFlags flags,
|
||||
pid_t *ret_pid) {
|
||||
|
@ -1451,7 +1435,7 @@ int safe_fork_full(
|
|||
int namespace_fork(
|
||||
const char *outer_name,
|
||||
const char *inner_name,
|
||||
int except_fds[],
|
||||
const int except_fds[],
|
||||
size_t n_except_fds,
|
||||
ForkFlags flags,
|
||||
int pidns_fd,
|
||||
|
@ -1467,8 +1451,7 @@ int namespace_fork(
|
|||
* process. This ensures that we are fully a member of the destination namespace, with pidns an all, so that
|
||||
* /proc/self/fd works correctly. */
|
||||
|
||||
r = safe_fork_full(outer_name, except_fds, n_except_fds,
|
||||
(flags|FORK_DEATHSIG) & ~(FORK_REOPEN_LOG|FORK_NEW_MOUNTNS|FORK_MOUNTNS_SLAVE), ret_pid);
|
||||
r = safe_fork_full(outer_name, except_fds, n_except_fds, (flags|FORK_DEATHSIG) & ~(FORK_REOPEN_LOG|FORK_NEW_MOUNTNS|FORK_MOUNTNS_SLAVE), ret_pid);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0) {
|
||||
|
@ -1513,7 +1496,7 @@ int set_oom_score_adjust(int value) {
|
|||
}
|
||||
|
||||
int get_oom_score_adjust(int *ret) {
|
||||
_cleanup_free_ char *t;
|
||||
_cleanup_free_ char *t = NULL;
|
||||
int r, a;
|
||||
|
||||
r = read_virtual_file("/proc/self/oom_score_adj", SIZE_MAX, &t, NULL);
|
||||
|
@ -1628,14 +1611,27 @@ bool invoked_as(char *argv[], const char *token) {
|
|||
return strstr(last_path_component(argv[0]), token);
|
||||
}
|
||||
|
||||
static const char *const ioprio_class_table[] = {
|
||||
[IOPRIO_CLASS_NONE] = "none",
|
||||
[IOPRIO_CLASS_RT] = "realtime",
|
||||
[IOPRIO_CLASS_BE] = "best-effort",
|
||||
[IOPRIO_CLASS_IDLE] = "idle",
|
||||
};
|
||||
_noreturn_ void freeze(void) {
|
||||
log_close();
|
||||
|
||||
/* Make sure nobody waits for us (i.e. on one of our sockets) anymore. Note that we use
|
||||
* close_all_fds_without_malloc() instead of plain close_all_fds() here, since we want this function
|
||||
* to be compatible with being called from signal handlers. */
|
||||
(void) close_all_fds_without_malloc(NULL, 0);
|
||||
|
||||
/* Let's not freeze right away, but keep reaping zombies. */
|
||||
for (;;) {
|
||||
siginfo_t si = {};
|
||||
|
||||
if (waitid(P_ALL, 0, &si, WEXITED) < 0 && errno != EINTR)
|
||||
break;
|
||||
}
|
||||
|
||||
/* waitid() failed with an unexpected error, things are really borked. Freeze now! */
|
||||
for (;;)
|
||||
pause();
|
||||
}
|
||||
|
||||
DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(ioprio_class, int, IOPRIO_N_CLASSES);
|
||||
|
||||
static const char *const sigchld_code_table[] = {
|
||||
[CLD_EXITED] = "exited",
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
#include "alloc-util.h"
|
||||
#include "format-util.h"
|
||||
#include "macro.h"
|
||||
#include "missing_ioprio.h"
|
||||
#include "time-util.h"
|
||||
|
||||
#define procfs_file_alloca(pid, field) \
|
||||
|
@ -39,17 +38,17 @@ typedef enum ProcessCmdlineFlags {
|
|||
PROCESS_CMDLINE_QUOTE_POSIX = 1 << 3,
|
||||
} ProcessCmdlineFlags;
|
||||
|
||||
int get_process_comm(pid_t pid, char **name);
|
||||
int get_process_cmdline(pid_t pid, size_t max_columns, ProcessCmdlineFlags flags, char **line);
|
||||
int get_process_exe(pid_t pid, char **name);
|
||||
int get_process_uid(pid_t pid, uid_t *uid);
|
||||
int get_process_gid(pid_t pid, gid_t *gid);
|
||||
int get_process_capeff(pid_t pid, char **capeff);
|
||||
int get_process_cwd(pid_t pid, char **cwd);
|
||||
int get_process_root(pid_t pid, char **root);
|
||||
int get_process_environ(pid_t pid, char **environ);
|
||||
int get_process_ppid(pid_t pid, pid_t *ppid);
|
||||
int get_process_umask(pid_t pid, mode_t *umask);
|
||||
int get_process_comm(pid_t pid, char **ret);
|
||||
int get_process_cmdline(pid_t pid, size_t max_columns, ProcessCmdlineFlags flags, char **ret);
|
||||
int get_process_exe(pid_t pid, char **ret);
|
||||
int get_process_uid(pid_t pid, uid_t *ret);
|
||||
int get_process_gid(pid_t pid, gid_t *ret);
|
||||
int get_process_capeff(pid_t pid, char **ret);
|
||||
int get_process_cwd(pid_t pid, char **ret);
|
||||
int get_process_root(pid_t pid, char **ret);
|
||||
int get_process_environ(pid_t pid, char **ret);
|
||||
int get_process_ppid(pid_t pid, pid_t *ret);
|
||||
int get_process_umask(pid_t pid, mode_t *ret);
|
||||
|
||||
int wait_for_terminate(pid_t pid, siginfo_t *status);
|
||||
|
||||
|
@ -97,9 +96,6 @@ const char *personality_to_string(unsigned long);
|
|||
int safe_personality(unsigned long p);
|
||||
int opinionated_personality(unsigned long *ret);
|
||||
|
||||
int ioprio_class_to_string_alloc(int i, char **s);
|
||||
int ioprio_class_from_string(const char *s);
|
||||
|
||||
const char *sigchld_code_to_string(int i) _const_;
|
||||
int sigchld_code_from_string(const char *s) _pure_;
|
||||
|
||||
|
@ -131,21 +127,11 @@ static inline bool sched_priority_is_valid(int i) {
|
|||
return i >= 0 && i <= sched_get_priority_max(SCHED_RR);
|
||||
}
|
||||
|
||||
static inline bool ioprio_class_is_valid(int i) {
|
||||
return IN_SET(i, IOPRIO_CLASS_NONE, IOPRIO_CLASS_RT, IOPRIO_CLASS_BE, IOPRIO_CLASS_IDLE);
|
||||
}
|
||||
|
||||
static inline bool ioprio_priority_is_valid(int i) {
|
||||
return i >= 0 && i < IOPRIO_BE_NR;
|
||||
}
|
||||
|
||||
static inline bool pid_is_valid(pid_t p) {
|
||||
return p > 0;
|
||||
}
|
||||
#endif /* NM_IGNORED */
|
||||
|
||||
int ioprio_parse_priority(const char *s, int *ret);
|
||||
|
||||
pid_t getpid_cached(void);
|
||||
void reset_cached_pid(void);
|
||||
|
||||
|
@ -168,13 +154,13 @@ typedef enum ForkFlags {
|
|||
FORK_NEW_USERNS = 1 << 13, /* Run child in its own user namespace */
|
||||
} ForkFlags;
|
||||
|
||||
int safe_fork_full(const char *name, int except_fds[], size_t n_except_fds, ForkFlags flags, pid_t *ret_pid);
|
||||
int safe_fork_full(const char *name, const int except_fds[], size_t n_except_fds, ForkFlags flags, pid_t *ret_pid);
|
||||
|
||||
static inline int safe_fork(const char *name, ForkFlags flags, pid_t *ret_pid) {
|
||||
return safe_fork_full(name, NULL, 0, flags, ret_pid);
|
||||
}
|
||||
|
||||
int namespace_fork(const char *outer_name, const char *inner_name, int except_fds[], size_t n_except_fds, ForkFlags flags, int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int root_fd, pid_t *ret_pid);
|
||||
int namespace_fork(const char *outer_name, const char *inner_name, const int except_fds[], size_t n_except_fds, ForkFlags flags, int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int root_fd, pid_t *ret_pid);
|
||||
|
||||
int set_oom_score_adjust(int value);
|
||||
int get_oom_score_adjust(int *ret);
|
||||
|
@ -194,8 +180,9 @@ assert_cc(TASKS_MAX <= (unsigned long) PID_T_MAX);
|
|||
/* Like TAKE_PTR() but for child PIDs, resetting them to 0 */
|
||||
#define TAKE_PID(pid) \
|
||||
({ \
|
||||
pid_t _pid_ = (pid); \
|
||||
(pid) = 0; \
|
||||
pid_t *_ppid_ = &(pid); \
|
||||
pid_t _pid_ = *_ppid_; \
|
||||
*_ppid_ = 0; \
|
||||
_pid_; \
|
||||
})
|
||||
|
||||
|
@ -204,3 +191,5 @@ int pidfd_get_pid(int fd, pid_t *ret);
|
|||
int setpriority_closest(int priority);
|
||||
|
||||
bool invoked_as(char *argv[], const char *token);
|
||||
|
||||
_noreturn_ void freeze(void);
|
||||
|
|
|
@ -163,7 +163,6 @@ int genuine_random_bytes(void *p, size_t n, RandomFlags flags) {
|
|||
static int have_syscall = -1;
|
||||
_cleanup_close_ int fd = -1;
|
||||
bool got_some = false;
|
||||
int r;
|
||||
|
||||
/* Gathers some high-quality randomness from the kernel (or potentially mid-quality randomness from
|
||||
* the CPU if the RANDOM_ALLOW_RDRAND flag is set). This call won't block, unless the RANDOM_BLOCK
|
||||
|
@ -222,25 +221,26 @@ int genuine_random_bytes(void *p, size_t n, RandomFlags flags) {
|
|||
if (have_syscall != 0 && !HAS_FEATURE_MEMORY_SANITIZER) {
|
||||
|
||||
for (;;) {
|
||||
ssize_t l;
|
||||
#if !HAVE_GETRANDOM
|
||||
/* NetworkManager Note: systemd calls the syscall directly in this case. Don't add that workaround.
|
||||
* If you don't compile against a libc that provides getrandom(), you don't get it. */
|
||||
r = -1;
|
||||
l = -1;
|
||||
errno = ENOSYS;
|
||||
#else
|
||||
r = getrandom(p, n,
|
||||
l = getrandom(p, n,
|
||||
(FLAGS_SET(flags, RANDOM_BLOCK) ? 0 : GRND_NONBLOCK) |
|
||||
(FLAGS_SET(flags, RANDOM_ALLOW_INSECURE) ? GRND_INSECURE : 0));
|
||||
#endif
|
||||
if (r > 0) {
|
||||
if (l > 0) {
|
||||
have_syscall = true;
|
||||
|
||||
if ((size_t) r == n)
|
||||
if ((size_t) l == n)
|
||||
return 0; /* Yay, success! */
|
||||
|
||||
assert((size_t) r < n);
|
||||
p = (uint8_t*) p + r;
|
||||
n -= r;
|
||||
assert((size_t) l < n);
|
||||
p = (uint8_t*) p + l;
|
||||
n -= l;
|
||||
|
||||
if (FLAGS_SET(flags, RANDOM_EXTEND_WITH_PSEUDO)) {
|
||||
/* Fill in the remaining bytes using pseudo-random values */
|
||||
|
@ -257,7 +257,7 @@ int genuine_random_bytes(void *p, size_t n, RandomFlags flags) {
|
|||
/* Fill in the rest with /dev/urandom */
|
||||
break;
|
||||
|
||||
} else if (r == 0) {
|
||||
} else if (l == 0) {
|
||||
have_syscall = true;
|
||||
return -EIO;
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include <errno.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "errno-util.h"
|
||||
#include "macro.h"
|
||||
#include "parse-util.h"
|
||||
#include "signal-util.h"
|
||||
|
@ -42,10 +43,7 @@ int reset_signal_mask(void) {
|
|||
if (sigemptyset(&ss) < 0)
|
||||
return -errno;
|
||||
|
||||
if (sigprocmask(SIG_SETMASK, &ss, NULL) < 0)
|
||||
return -errno;
|
||||
|
||||
return 0;
|
||||
return RET_NERRNO(sigprocmask(SIG_SETMASK, &ss, NULL));
|
||||
}
|
||||
|
||||
int sigaction_many_internal(const struct sigaction *sa, ...) {
|
||||
|
@ -122,7 +120,7 @@ int sigprocmask_many(int how, sigset_t *old, ...) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const char *const __signal_table[] = {
|
||||
static const char *const static_signal_table[] = {
|
||||
[SIGHUP] = "HUP",
|
||||
[SIGINT] = "INT",
|
||||
[SIGQUIT] = "QUIT",
|
||||
|
@ -158,13 +156,13 @@ static const char *const __signal_table[] = {
|
|||
[SIGSYS] = "SYS"
|
||||
};
|
||||
|
||||
DEFINE_PRIVATE_STRING_TABLE_LOOKUP(__signal, int);
|
||||
DEFINE_PRIVATE_STRING_TABLE_LOOKUP(static_signal, int);
|
||||
|
||||
const char *signal_to_string(int signo) {
|
||||
static thread_local char buf[STRLEN("RTMIN+") + DECIMAL_STR_MAX(int)];
|
||||
const char *name;
|
||||
|
||||
name = __signal_to_string(signo);
|
||||
name = static_signal_to_string(signo);
|
||||
if (name)
|
||||
return name;
|
||||
|
||||
|
@ -193,7 +191,7 @@ int signal_from_string(const char *s) {
|
|||
s += 3;
|
||||
|
||||
/* Check that the input is a signal name. */
|
||||
signo = __signal_from_string(s);
|
||||
signo = static_signal_from_string(s);
|
||||
if (signo > 0)
|
||||
return signo;
|
||||
|
||||
|
@ -250,11 +248,7 @@ int signal_is_blocked(int sig) {
|
|||
if (r != 0)
|
||||
return -r;
|
||||
|
||||
r = sigismember(&ss, sig);
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
|
||||
return r;
|
||||
return RET_NERRNO(sigismember(&ss, sig));
|
||||
}
|
||||
|
||||
int pop_pending_signal_internal(int sig, ...) {
|
||||
|
|
|
@ -405,6 +405,41 @@ const union in_addr_union *sockaddr_in_addr(const struct sockaddr *_sa) {
|
|||
}
|
||||
}
|
||||
|
||||
int sockaddr_set_in_addr(
|
||||
union sockaddr_union *u,
|
||||
int family,
|
||||
const union in_addr_union *a,
|
||||
uint16_t port) {
|
||||
|
||||
assert(u);
|
||||
assert(a);
|
||||
|
||||
switch (family) {
|
||||
|
||||
case AF_INET:
|
||||
u->in = (struct sockaddr_in) {
|
||||
.sin_family = AF_INET,
|
||||
.sin_addr = a->in,
|
||||
.sin_port = htobe16(port),
|
||||
};
|
||||
|
||||
return 0;
|
||||
|
||||
case AF_INET6:
|
||||
u->in6 = (struct sockaddr_in6) {
|
||||
.sin6_family = AF_INET6,
|
||||
.sin6_addr = a->in6,
|
||||
.sin6_port = htobe16(port),
|
||||
};
|
||||
|
||||
return 0;
|
||||
|
||||
default:
|
||||
return -EAFNOSUPPORT;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
int sockaddr_pretty(
|
||||
const struct sockaddr *_sa,
|
||||
socklen_t salen,
|
||||
|
@ -556,7 +591,7 @@ int getpeername_pretty(int fd, bool include_port, char **ret) {
|
|||
return -errno;
|
||||
|
||||
if (sa.sa.sa_family == AF_UNIX) {
|
||||
struct ucred ucred = {};
|
||||
struct ucred ucred = UCRED_INVALID;
|
||||
|
||||
/* UNIX connection sockets are anonymous, so let's use
|
||||
* PID/UID as pretty credentials instead */
|
||||
|
@ -1238,10 +1273,7 @@ int socket_bind_to_ifname(int fd, const char *ifname) {
|
|||
|
||||
/* Call with NULL to drop binding */
|
||||
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, ifname, strlen_ptr(ifname)) < 0)
|
||||
return -errno;
|
||||
|
||||
return 0;
|
||||
return RET_NERRNO(setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, ifname, strlen_ptr(ifname)));
|
||||
}
|
||||
|
||||
int socket_bind_to_ifindex(int fd, int ifindex) {
|
||||
|
@ -1250,13 +1282,9 @@ int socket_bind_to_ifindex(int fd, int ifindex) {
|
|||
|
||||
assert(fd >= 0);
|
||||
|
||||
if (ifindex <= 0) {
|
||||
if (ifindex <= 0)
|
||||
/* Drop binding */
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, NULL, 0) < 0)
|
||||
return -errno;
|
||||
|
||||
return 0;
|
||||
}
|
||||
return RET_NERRNO(setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, NULL, 0));
|
||||
|
||||
r = setsockopt_int(fd, SOL_SOCKET, SO_BINDTOIFINDEX, ifindex);
|
||||
if (r != -ENOPROTOOPT)
|
||||
|
@ -1345,16 +1373,10 @@ int socket_set_unicast_if(int fd, int af, int ifi) {
|
|||
switch (af) {
|
||||
|
||||
case AF_INET:
|
||||
if (setsockopt(fd, IPPROTO_IP, IP_UNICAST_IF, &ifindex_be, sizeof(ifindex_be)) < 0)
|
||||
return -errno;
|
||||
|
||||
return 0;
|
||||
return RET_NERRNO(setsockopt(fd, IPPROTO_IP, IP_UNICAST_IF, &ifindex_be, sizeof(ifindex_be)));
|
||||
|
||||
case AF_INET6:
|
||||
if (setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_IF, &ifindex_be, sizeof(ifindex_be)) < 0)
|
||||
return -errno;
|
||||
|
||||
return 0;
|
||||
return RET_NERRNO(setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_IF, &ifindex_be, sizeof(ifindex_be)));
|
||||
|
||||
default:
|
||||
return -EAFNOSUPPORT;
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <sys/un.h>
|
||||
|
||||
#include "errno-util.h"
|
||||
#include "in-addr-util.h"
|
||||
#include "macro.h"
|
||||
#include "missing_network.h"
|
||||
#include "missing_socket.h"
|
||||
|
@ -108,6 +109,7 @@ bool socket_ipv6_is_enabled(void);
|
|||
|
||||
int sockaddr_port(const struct sockaddr *_sa, unsigned *port);
|
||||
const union in_addr_union *sockaddr_in_addr(const struct sockaddr *sa);
|
||||
int sockaddr_set_in_addr(union sockaddr_union *u, int family, const union in_addr_union *a, uint16_t port);
|
||||
|
||||
int sockaddr_pretty(const struct sockaddr *_sa, socklen_t salen, bool translate_ipv6, bool include_port, char **ret);
|
||||
int getpeername_pretty(int fd, bool include_port, char **ret);
|
||||
|
@ -331,3 +333,6 @@ static inline int socket_set_recvfragsize(int fd, int af, bool b) {
|
|||
#endif /* NM_IGNORED */
|
||||
|
||||
int socket_get_mtu(int fd, int af, size_t *ret);
|
||||
|
||||
/* an initializer for struct ucred that initialized all fields to the invalid value appropriate for each */
|
||||
#define UCRED_INVALID { .pid = 0, .uid = UID_INVALID, .gid = GID_INVALID }
|
||||
|
|
|
@ -5,14 +5,20 @@
|
|||
|
||||
#include "macro.h"
|
||||
|
||||
/* This is the same as glibc's internal __compar_d_fn_t type. glibc exports a public comparison_fn_t, for the
|
||||
* external type __compar_fn_t, but doesn't do anything similar for __compar_d_fn_t. Let's hence do that
|
||||
* ourselves, picking a name that is obvious, but likely enough to not clash with glibc's choice of naming if
|
||||
* they should ever add one. */
|
||||
typedef int (*comparison_userdata_fn_t)(const void *, const void *, void *);
|
||||
|
||||
void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size,
|
||||
__compar_d_fn_t compar, void *arg);
|
||||
comparison_userdata_fn_t compar, void *arg);
|
||||
|
||||
#define typesafe_bsearch_r(k, b, n, func, userdata) \
|
||||
({ \
|
||||
const typeof(b[0]) *_k = k; \
|
||||
int (*_func_)(const typeof(b[0])*, const typeof(b[0])*, typeof(userdata)) = func; \
|
||||
xbsearch_r((const void*) _k, (b), (n), sizeof((b)[0]), (__compar_d_fn_t) _func_, userdata); \
|
||||
xbsearch_r((const void*) _k, (b), (n), sizeof((b)[0]), (comparison_userdata_fn_t) _func_, userdata); \
|
||||
})
|
||||
|
||||
/**
|
||||
|
@ -20,7 +26,7 @@ void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size,
|
|||
* that only if nmemb > 0.
|
||||
*/
|
||||
static inline void* bsearch_safe(const void *key, const void *base,
|
||||
size_t nmemb, size_t size, __compar_fn_t compar) {
|
||||
size_t nmemb, size_t size, comparison_fn_t compar) {
|
||||
if (nmemb <= 0)
|
||||
return NULL;
|
||||
|
||||
|
@ -32,14 +38,14 @@ static inline void* bsearch_safe(const void *key, const void *base,
|
|||
({ \
|
||||
const typeof(b[0]) *_k = k; \
|
||||
int (*_func_)(const typeof(b[0])*, const typeof(b[0])*) = func; \
|
||||
bsearch_safe((const void*) _k, (b), (n), sizeof((b)[0]), (__compar_fn_t) _func_); \
|
||||
bsearch_safe((const void*) _k, (b), (n), sizeof((b)[0]), (comparison_fn_t) _func_); \
|
||||
})
|
||||
|
||||
/**
|
||||
* Normal qsort requires base to be nonnull. Here were require
|
||||
* that only if nmemb > 0.
|
||||
*/
|
||||
static inline void _qsort_safe(void *base, size_t nmemb, size_t size, __compar_fn_t compar) {
|
||||
static inline void _qsort_safe(void *base, size_t nmemb, size_t size, comparison_fn_t compar) {
|
||||
if (nmemb <= 1)
|
||||
return;
|
||||
|
||||
|
@ -52,11 +58,11 @@ static inline void _qsort_safe(void *base, size_t nmemb, size_t size, __compar_f
|
|||
#define typesafe_qsort(p, n, func) \
|
||||
({ \
|
||||
int (*_func_)(const typeof(p[0])*, const typeof(p[0])*) = func; \
|
||||
_qsort_safe((p), (n), sizeof((p)[0]), (__compar_fn_t) _func_); \
|
||||
_qsort_safe((p), (n), sizeof((p)[0]), (comparison_fn_t) _func_); \
|
||||
})
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
static inline void qsort_r_safe(void *base, size_t nmemb, size_t size, __compar_d_fn_t compar, void *userdata) {
|
||||
static inline void qsort_r_safe(void *base, size_t nmemb, size_t size, comparison_userdata_fn_t compar, void *userdata) {
|
||||
if (nmemb <= 1)
|
||||
return;
|
||||
|
||||
|
@ -67,7 +73,7 @@ static inline void qsort_r_safe(void *base, size_t nmemb, size_t size, __compar_
|
|||
#define typesafe_qsort_r(p, n, func, userdata) \
|
||||
({ \
|
||||
int (*_func_)(const typeof(p[0])*, const typeof(p[0])*, typeof(userdata)) = func; \
|
||||
qsort_r_safe((p), (n), sizeof((p)[0]), (__compar_d_fn_t) _func_, userdata); \
|
||||
qsort_r_safe((p), (n), sizeof((p)[0]), (comparison_userdata_fn_t) _func_, userdata); \
|
||||
})
|
||||
#endif /* NM_IGNORED */
|
||||
|
||||
|
|
|
@ -55,9 +55,9 @@ typedef uint64_t __sd_bitwise be64_t;
|
|||
#undef le64toh
|
||||
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
#define bswap_16_on_le(x) __bswap_16(x)
|
||||
#define bswap_32_on_le(x) __bswap_32(x)
|
||||
#define bswap_64_on_le(x) __bswap_64(x)
|
||||
#define bswap_16_on_le(x) bswap_16(x)
|
||||
#define bswap_32_on_le(x) bswap_32(x)
|
||||
#define bswap_64_on_le(x) bswap_64(x)
|
||||
#define bswap_16_on_be(x) (x)
|
||||
#define bswap_32_on_be(x) (x)
|
||||
#define bswap_64_on_be(x) (x)
|
||||
|
@ -65,9 +65,9 @@ typedef uint64_t __sd_bitwise be64_t;
|
|||
#define bswap_16_on_le(x) (x)
|
||||
#define bswap_32_on_le(x) (x)
|
||||
#define bswap_64_on_le(x) (x)
|
||||
#define bswap_16_on_be(x) __bswap_16(x)
|
||||
#define bswap_32_on_be(x) __bswap_32(x)
|
||||
#define bswap_64_on_be(x) __bswap_64(x)
|
||||
#define bswap_16_on_be(x) bswap_16(x)
|
||||
#define bswap_32_on_be(x) bswap_32(x)
|
||||
#define bswap_64_on_be(x) bswap_64(x)
|
||||
#endif
|
||||
|
||||
static inline le16_t htole16(uint16_t value) { return (le16_t __sd_force) bswap_16_on_be(value); }
|
||||
|
|
|
@ -15,10 +15,13 @@
|
|||
#include "errno-util.h"
|
||||
#include "fd-util.h"
|
||||
#include "fileio.h"
|
||||
#include "filesystems.h"
|
||||
#include "fs-util.h"
|
||||
#include "macro.h"
|
||||
#include "missing_fs.h"
|
||||
#include "missing_magic.h"
|
||||
#include "missing_syscall.h"
|
||||
#include "nulstr-util.h"
|
||||
#include "parse-util.h"
|
||||
#include "stat-util.h"
|
||||
#include "string-util.h"
|
||||
|
@ -75,26 +78,40 @@ int is_device_node(const char *path) {
|
|||
|
||||
int dir_is_empty_at(int dir_fd, const char *path) {
|
||||
_cleanup_close_ int fd = -1;
|
||||
_cleanup_closedir_ DIR *d = NULL;
|
||||
/* Allocate space for at least 3 full dirents, since every dir has at least two entries ("." +
|
||||
* ".."), and only once we have seen if there's a third we know whether the dir is empty or not. */
|
||||
DEFINE_DIRENT_BUFFER(buffer, 3);
|
||||
struct dirent *de;
|
||||
ssize_t n;
|
||||
|
||||
if (path) {
|
||||
assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
|
||||
|
||||
fd = openat(dir_fd, path, O_RDONLY|O_DIRECTORY|O_CLOEXEC);
|
||||
if (fd < 0)
|
||||
return -errno;
|
||||
} else if (dir_fd == AT_FDCWD) {
|
||||
fd = open(".", O_RDONLY|O_DIRECTORY|O_CLOEXEC);
|
||||
if (fd < 0)
|
||||
return -errno;
|
||||
} else {
|
||||
/* Note that DUPing is not enough, as the internal pointer
|
||||
* would still be shared and moved by FOREACH_DIRENT. */
|
||||
fd = fd_reopen(dir_fd, O_CLOEXEC);
|
||||
/* Note that DUPing is not enough, as the internal pointer would still be shared and moved
|
||||
* getedents64(). */
|
||||
assert(dir_fd >= 0);
|
||||
|
||||
fd = fd_reopen(dir_fd, O_RDONLY|O_DIRECTORY|O_CLOEXEC);
|
||||
if (fd < 0)
|
||||
return fd;
|
||||
}
|
||||
|
||||
d = take_fdopendir(&fd);
|
||||
if (!d)
|
||||
n = getdents64(fd, &buffer, sizeof(buffer));
|
||||
if (n < 0)
|
||||
return -errno;
|
||||
|
||||
FOREACH_DIRENT(de, d, return -errno)
|
||||
msan_unpoison(&buffer, n);
|
||||
|
||||
FOREACH_DIRENT_IN_BUFFER(de, &buffer.de, n)
|
||||
if (!dot_or_dot_dot(de->d_name))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
|
@ -178,7 +195,6 @@ int files_same(const char *filea, const char *fileb, int flags) {
|
|||
a.st_ino == b.st_ino;
|
||||
}
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
bool is_fs_type(const struct statfs *s, statfs_f_type_t magic_value) {
|
||||
assert(s);
|
||||
assert_cc(sizeof(statfs_f_type_t) >= sizeof(s->f_type));
|
||||
|
@ -186,6 +202,7 @@ bool is_fs_type(const struct statfs *s, statfs_f_type_t magic_value) {
|
|||
return F_TYPE_EQUAL(s->f_type, magic_value);
|
||||
}
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
int fd_is_fs_type(int fd, statfs_f_type_t magic_value) {
|
||||
struct statfs s;
|
||||
|
||||
|
@ -194,6 +211,7 @@ int fd_is_fs_type(int fd, statfs_f_type_t magic_value) {
|
|||
|
||||
return is_fs_type(&s, magic_value);
|
||||
}
|
||||
#endif /* NM_IGNORE */
|
||||
|
||||
int path_is_fs_type(const char *path, statfs_f_type_t magic_value) {
|
||||
struct statfs s;
|
||||
|
@ -204,20 +222,13 @@ int path_is_fs_type(const char *path, statfs_f_type_t magic_value) {
|
|||
return is_fs_type(&s, magic_value);
|
||||
}
|
||||
|
||||
#if 0 /* NM_IGNORE */
|
||||
bool is_temporary_fs(const struct statfs *s) {
|
||||
return is_fs_type(s, TMPFS_MAGIC) ||
|
||||
is_fs_type(s, RAMFS_MAGIC);
|
||||
return fs_in_group(s, FILESYSTEM_SET_TEMPORARY);
|
||||
}
|
||||
|
||||
bool is_network_fs(const struct statfs *s) {
|
||||
return is_fs_type(s, CIFS_MAGIC_NUMBER) ||
|
||||
is_fs_type(s, CODA_SUPER_MAGIC) ||
|
||||
is_fs_type(s, NCP_SUPER_MAGIC) ||
|
||||
is_fs_type(s, NFS_SUPER_MAGIC) ||
|
||||
is_fs_type(s, SMB_SUPER_MAGIC) ||
|
||||
is_fs_type(s, V9FS_MAGIC) ||
|
||||
is_fs_type(s, AFS_SUPER_MAGIC) ||
|
||||
is_fs_type(s, OCFS2_SUPER_MAGIC);
|
||||
return fs_in_group(s, FILESYSTEM_SET_NETWORK);
|
||||
}
|
||||
|
||||
int fd_is_temporary_fs(int fd) {
|
||||
|
@ -395,6 +406,7 @@ int device_path_parse_major_minor(const char *path, mode_t *ret_mode, dev_t *ret
|
|||
|
||||
return 0;
|
||||
}
|
||||
#endif /* NM_IGNORED */
|
||||
|
||||
int proc_mounted(void) {
|
||||
int r;
|
||||
|
@ -408,6 +420,7 @@ int proc_mounted(void) {
|
|||
return r;
|
||||
}
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
bool stat_inode_unmodified(const struct stat *a, const struct stat *b) {
|
||||
|
||||
/* Returns if the specified stat structures reference the same, unmodified inode. This check tries to
|
||||
|
|
|
@ -60,6 +60,10 @@ static inline const char *empty_to_null(const char *p) {
|
|||
return isempty(p) ? NULL : p;
|
||||
}
|
||||
|
||||
static inline const char *empty_to_na(const char *p) {
|
||||
return isempty(p) ? "n/a" : p;
|
||||
}
|
||||
|
||||
static inline const char *empty_to_dash(const char *str) {
|
||||
return isempty(str) ? "-" : str;
|
||||
}
|
||||
|
|
|
@ -72,12 +72,10 @@ char *strv_find_startswith(char * const *l, const char *name) {
|
|||
}
|
||||
|
||||
char** strv_free(char **l) {
|
||||
char **k;
|
||||
|
||||
if (!l)
|
||||
return NULL;
|
||||
|
||||
for (k = l; *k; k++)
|
||||
for (char **k = l; *k; k++)
|
||||
free(*k);
|
||||
|
||||
return mfree(l);
|
||||
|
@ -176,7 +174,7 @@ char **strv_new_internal(const char *x, ...) {
|
|||
|
||||
int strv_extend_strv(char ***a, char * const *b, bool filter_duplicates) {
|
||||
char * const *s, **t;
|
||||
size_t p, q, i = 0, j;
|
||||
size_t p, q, i = 0;
|
||||
|
||||
assert(a);
|
||||
|
||||
|
@ -197,7 +195,6 @@ int strv_extend_strv(char ***a, char * const *b, bool filter_duplicates) {
|
|||
*a = t;
|
||||
|
||||
STRV_FOREACH(s, b) {
|
||||
|
||||
if (filter_duplicates && strv_contains(t, *s))
|
||||
continue;
|
||||
|
||||
|
@ -214,7 +211,7 @@ int strv_extend_strv(char ***a, char * const *b, bool filter_duplicates) {
|
|||
return (int) i;
|
||||
|
||||
rollback:
|
||||
for (j = 0; j < i; j++)
|
||||
for (size_t j = 0; j < i; j++)
|
||||
free(t[p + j]);
|
||||
|
||||
t[p] = NULL;
|
||||
|
@ -289,7 +286,6 @@ int strv_split_full(char ***t, const char *s, const char *separators, ExtractFla
|
|||
return -ENOMEM;
|
||||
|
||||
l[n++] = TAKE_PTR(word);
|
||||
|
||||
l[n] = NULL;
|
||||
}
|
||||
|
||||
|
@ -483,7 +479,7 @@ int strv_push_pair(char ***l, char *a, char *b) {
|
|||
|
||||
int strv_insert(char ***l, size_t position, char *value) {
|
||||
char **c;
|
||||
size_t n, m, i;
|
||||
size_t n, m;
|
||||
|
||||
if (!value)
|
||||
return 0;
|
||||
|
@ -500,18 +496,14 @@ int strv_insert(char ***l, size_t position, char *value) {
|
|||
if (!c)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < position; i++)
|
||||
for (size_t i = 0; i < position; i++)
|
||||
c[i] = (*l)[i];
|
||||
c[position] = value;
|
||||
for (i = position; i < n; i++)
|
||||
for (size_t i = position; i < n; i++)
|
||||
c[i+1] = (*l)[i];
|
||||
|
||||
c[n+1] = NULL;
|
||||
|
||||
free(*l);
|
||||
*l = c;
|
||||
|
||||
return 0;
|
||||
return free_and_replace(*l, c);
|
||||
}
|
||||
|
||||
int strv_consume(char ***l, char *value) {
|
||||
|
@ -663,7 +655,6 @@ char **strv_parse_nulstr(const char *s, size_t l) {
|
|||
* empty strings in s.
|
||||
*/
|
||||
|
||||
const char *p;
|
||||
size_t c = 0, i = 0;
|
||||
char **v;
|
||||
|
||||
|
@ -672,7 +663,7 @@ char **strv_parse_nulstr(const char *s, size_t l) {
|
|||
if (l <= 0)
|
||||
return new0(char*, 1);
|
||||
|
||||
for (p = s; p < s + l; p++)
|
||||
for (const char *p = s; p < s + l; p++)
|
||||
if (*p == 0)
|
||||
c++;
|
||||
|
||||
|
@ -683,8 +674,7 @@ char **strv_parse_nulstr(const char *s, size_t l) {
|
|||
if (!v)
|
||||
return NULL;
|
||||
|
||||
p = s;
|
||||
while (p < s + l) {
|
||||
for (const char *p = s; p < s + l; ) {
|
||||
const char *e;
|
||||
|
||||
e = memchr(p, 0, s + l - p);
|
||||
|
@ -837,13 +827,13 @@ int strv_extendf(char ***l, const char *format, ...) {
|
|||
}
|
||||
|
||||
char** strv_reverse(char **l) {
|
||||
size_t n, i;
|
||||
size_t n;
|
||||
|
||||
n = strv_length(l);
|
||||
if (n <= 1)
|
||||
return l;
|
||||
|
||||
for (i = 0; i < n / 2; i++)
|
||||
for (size_t i = 0; i < n / 2; i++)
|
||||
SWAP_TWO(l[i], l[n-1-i]);
|
||||
|
||||
return l;
|
||||
|
@ -882,18 +872,6 @@ bool strv_fnmatch_full(char* const* patterns, const char *s, int flags, size_t *
|
|||
return false;
|
||||
}
|
||||
|
||||
char ***strv_free_free(char ***l) {
|
||||
char ***i;
|
||||
|
||||
if (!l)
|
||||
return NULL;
|
||||
|
||||
for (i = l; *i; i++)
|
||||
strv_free(*i);
|
||||
|
||||
return mfree(l);
|
||||
}
|
||||
|
||||
char** strv_skip(char **l, size_t n) {
|
||||
|
||||
while (n > 0) {
|
||||
|
@ -907,7 +885,7 @@ char **strv_skip(char **l, size_t n) {
|
|||
}
|
||||
|
||||
int strv_extend_n(char ***l, const char *value, size_t n) {
|
||||
size_t i, j, k;
|
||||
size_t i, k;
|
||||
char **nl;
|
||||
|
||||
assert(l);
|
||||
|
@ -934,15 +912,15 @@ int strv_extend_n(char ***l, const char *value, size_t n) {
|
|||
if (!nl[i])
|
||||
goto rollback;
|
||||
}
|
||||
|
||||
nl[i] = NULL;
|
||||
|
||||
return 0;
|
||||
|
||||
rollback:
|
||||
for (j = k; j < i; j++)
|
||||
for (size_t j = k; j < i; j++)
|
||||
free(nl[j]);
|
||||
|
||||
nl[k] = NULL;
|
||||
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
|
|
|
@ -206,10 +206,13 @@ void strv_print(char * const *l);
|
|||
_found; \
|
||||
})
|
||||
|
||||
#define FOREACH_STRING(x, y, ...) \
|
||||
for (char **_l = STRV_MAKE(({ x = y; }), ##__VA_ARGS__); \
|
||||
#define _FOREACH_STRING(uniq, x, y, ...) \
|
||||
for (char **UNIQ_T(l, uniq) = STRV_MAKE(({ x = y; }), ##__VA_ARGS__); \
|
||||
x; \
|
||||
x = *(++_l))
|
||||
x = *(++UNIQ_T(l, uniq)))
|
||||
|
||||
#define FOREACH_STRING(x, y, ...) \
|
||||
_FOREACH_STRING(UNIQ, x, y, ##__VA_ARGS__)
|
||||
|
||||
char** strv_reverse(char **l);
|
||||
char** strv_shell_escape(char **l, const char *bad);
|
||||
|
@ -225,9 +228,6 @@ static inline bool strv_fnmatch_or_empty(char* const* patterns, const char *s, i
|
|||
strv_fnmatch_full(patterns, s, flags, NULL);
|
||||
}
|
||||
|
||||
char ***strv_free_free(char ***l);
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(char***, strv_free_free);
|
||||
|
||||
char** strv_skip(char **l, size_t n);
|
||||
|
||||
int strv_extend_n(char ***l, const char *value, size_t n);
|
||||
|
|
|
@ -17,57 +17,73 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "string-util.h"
|
||||
#include "strxcpyx.h"
|
||||
|
||||
size_t strnpcpy(char **dest, size_t size, const char *src, size_t len) {
|
||||
size_t strnpcpy_full(char **dest, size_t size, const char *src, size_t len, bool *ret_truncated) {
|
||||
bool truncated = false;
|
||||
|
||||
assert(dest);
|
||||
assert(src);
|
||||
|
||||
if (size == 0)
|
||||
if (size == 0) {
|
||||
if (ret_truncated)
|
||||
*ret_truncated = len > 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (len >= size) {
|
||||
if (size > 1)
|
||||
*dest = mempcpy(*dest, src, size-1);
|
||||
size = 0;
|
||||
truncated = true;
|
||||
} else if (len > 0) {
|
||||
*dest = mempcpy(*dest, src, len);
|
||||
size -= len;
|
||||
}
|
||||
|
||||
if (ret_truncated)
|
||||
*ret_truncated = truncated;
|
||||
|
||||
*dest[0] = '\0';
|
||||
return size;
|
||||
}
|
||||
|
||||
size_t strpcpy(char **dest, size_t size, const char *src) {
|
||||
size_t strpcpy_full(char **dest, size_t size, const char *src, bool *ret_truncated) {
|
||||
assert(dest);
|
||||
assert(src);
|
||||
|
||||
return strnpcpy(dest, size, src, strlen(src));
|
||||
return strnpcpy_full(dest, size, src, strlen(src), ret_truncated);
|
||||
}
|
||||
|
||||
size_t strpcpyf(char **dest, size_t size, const char *src, ...) {
|
||||
size_t strpcpyf_full(char **dest, size_t size, bool *ret_truncated, const char *src, ...) {
|
||||
bool truncated = false;
|
||||
va_list va;
|
||||
int i;
|
||||
|
||||
assert(dest);
|
||||
assert(src);
|
||||
|
||||
if (size == 0)
|
||||
return 0;
|
||||
|
||||
va_start(va, src);
|
||||
i = vsnprintf(*dest, size, src, va);
|
||||
va_end(va);
|
||||
|
||||
if (i < (int) size) {
|
||||
*dest += i;
|
||||
size -= i;
|
||||
} else
|
||||
} else {
|
||||
size = 0;
|
||||
va_end(va);
|
||||
truncated = i > 0;
|
||||
}
|
||||
|
||||
if (ret_truncated)
|
||||
*ret_truncated = truncated;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
size_t strpcpyl(char **dest, size_t size, const char *src, ...) {
|
||||
size_t strpcpyl_full(char **dest, size_t size, bool *ret_truncated, const char *src, ...) {
|
||||
bool truncated = false;
|
||||
va_list va;
|
||||
|
||||
assert(dest);
|
||||
|
@ -75,31 +91,38 @@ size_t strpcpyl(char **dest, size_t size, const char *src, ...) {
|
|||
|
||||
va_start(va, src);
|
||||
do {
|
||||
size = strpcpy(dest, size, src);
|
||||
bool t;
|
||||
|
||||
size = strpcpy_full(dest, size, src, &t);
|
||||
truncated = truncated || t;
|
||||
src = va_arg(va, char *);
|
||||
} while (src);
|
||||
va_end(va);
|
||||
|
||||
if (ret_truncated)
|
||||
*ret_truncated = truncated;
|
||||
return size;
|
||||
}
|
||||
|
||||
size_t strnscpy(char *dest, size_t size, const char *src, size_t len) {
|
||||
size_t strnscpy_full(char *dest, size_t size, const char *src, size_t len, bool *ret_truncated) {
|
||||
char *s;
|
||||
|
||||
assert(dest);
|
||||
assert(src);
|
||||
|
||||
s = dest;
|
||||
return strnpcpy(&s, size, src, len);
|
||||
return strnpcpy_full(&s, size, src, len, ret_truncated);
|
||||
}
|
||||
|
||||
size_t strscpy(char *dest, size_t size, const char *src) {
|
||||
size_t strscpy_full(char *dest, size_t size, const char *src, bool *ret_truncated) {
|
||||
assert(dest);
|
||||
assert(src);
|
||||
|
||||
return strnscpy(dest, size, src, strlen(src));
|
||||
return strnscpy_full(dest, size, src, strlen(src), ret_truncated);
|
||||
}
|
||||
|
||||
size_t strscpyl(char *dest, size_t size, const char *src, ...) {
|
||||
size_t strscpyl_full(char *dest, size_t size, bool *ret_truncated, const char *src, ...) {
|
||||
bool truncated = false;
|
||||
va_list va;
|
||||
char *s;
|
||||
|
||||
|
@ -109,10 +132,16 @@ size_t strscpyl(char *dest, size_t size, const char *src, ...) {
|
|||
va_start(va, src);
|
||||
s = dest;
|
||||
do {
|
||||
size = strpcpy(&s, size, src);
|
||||
bool t;
|
||||
|
||||
size = strpcpy_full(&s, size, src, &t);
|
||||
truncated = truncated || t;
|
||||
src = va_arg(va, char *);
|
||||
} while (src);
|
||||
va_end(va);
|
||||
|
||||
if (ret_truncated)
|
||||
*ret_truncated = truncated;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
|
|
@ -1,14 +1,33 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include "macro.h"
|
||||
|
||||
size_t strnpcpy(char **dest, size_t size, const char *src, size_t len);
|
||||
size_t strpcpy(char **dest, size_t size, const char *src);
|
||||
size_t strpcpyf(char **dest, size_t size, const char *src, ...) _printf_(3, 4);
|
||||
size_t strpcpyl(char **dest, size_t size, const char *src, ...) _sentinel_;
|
||||
size_t strnscpy(char *dest, size_t size, const char *src, size_t len);
|
||||
size_t strscpy(char *dest, size_t size, const char *src);
|
||||
size_t strscpyl(char *dest, size_t size, const char *src, ...) _sentinel_;
|
||||
size_t strnpcpy_full(char **dest, size_t size, const char *src, size_t len, bool *ret_truncated);
|
||||
static inline size_t strnpcpy(char **dest, size_t size, const char *src, size_t len) {
|
||||
return strnpcpy_full(dest, size, src, len, NULL);
|
||||
}
|
||||
size_t strpcpy_full(char **dest, size_t size, const char *src, bool *ret_truncated);
|
||||
static inline size_t strpcpy(char **dest, size_t size, const char *src) {
|
||||
return strpcpy_full(dest, size, src, NULL);
|
||||
}
|
||||
size_t strpcpyf_full(char **dest, size_t size, bool *ret_truncated, const char *src, ...) _printf_(4, 5);
|
||||
#define strpcpyf(dest, size, src, ...) \
|
||||
strpcpyf_full((dest), (size), NULL, (src), ##__VA_ARGS__)
|
||||
size_t strpcpyl_full(char **dest, size_t size, bool *ret_truncated, const char *src, ...) _sentinel_;
|
||||
#define strpcpyl(dest, size, src, ...) \
|
||||
strpcpyl_full((dest), (size), NULL, (src), ##__VA_ARGS__)
|
||||
size_t strnscpy_full(char *dest, size_t size, const char *src, size_t len, bool *ret_truncated);
|
||||
static inline size_t strnscpy(char *dest, size_t size, const char *src, size_t len) {
|
||||
return strnscpy_full(dest, size, src, len, NULL);
|
||||
}
|
||||
size_t strscpy_full(char *dest, size_t size, const char *src, bool *ret_truncated);
|
||||
static inline size_t strscpy(char *dest, size_t size, const char *src) {
|
||||
return strscpy_full(dest, size, src, NULL);
|
||||
}
|
||||
size_t strscpyl_full(char *dest, size_t size, bool *ret_truncated, const char *src, ...) _sentinel_;
|
||||
#define strscpyl(dest, size, src, ...) \
|
||||
strscpyl_full(dest, size, NULL, src, ##__VA_ARGS__)
|
||||
|
|
|
@ -271,7 +271,6 @@ struct timespec *timespec_store_nsec(struct timespec *ts, nsec_t n) {
|
|||
return ts;
|
||||
}
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
usec_t timeval_load(const struct timeval *tv) {
|
||||
assert(tv);
|
||||
|
||||
|
@ -286,6 +285,7 @@ usec_t timeval_load(const struct timeval *tv) {
|
|||
(usec_t) tv->tv_usec;
|
||||
}
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
struct timeval *timeval_store(struct timeval *tv, usec_t u) {
|
||||
assert(tv);
|
||||
|
||||
|
@ -676,7 +676,7 @@ static int parse_timestamp_impl(const char *t, usec_t *usec, bool with_tz) {
|
|||
goto finish;
|
||||
|
||||
} else if ((k = endswith(t, " ago"))) {
|
||||
t = strndupa(t, k - t);
|
||||
t = strndupa_safe(t, k - t);
|
||||
|
||||
r = parse_sec(t, &minus);
|
||||
if (r < 0)
|
||||
|
@ -685,7 +685,7 @@ static int parse_timestamp_impl(const char *t, usec_t *usec, bool with_tz) {
|
|||
goto finish;
|
||||
|
||||
} else if ((k = endswith(t, " left"))) {
|
||||
t = strndupa(t, k - t);
|
||||
t = strndupa_safe(t, k - t);
|
||||
|
||||
r = parse_sec(t, &plus);
|
||||
if (r < 0)
|
||||
|
@ -697,7 +697,7 @@ static int parse_timestamp_impl(const char *t, usec_t *usec, bool with_tz) {
|
|||
/* See if the timestamp is suffixed with UTC */
|
||||
utc = endswith_no_case(t, " UTC");
|
||||
if (utc)
|
||||
t = strndupa(t, utc - t);
|
||||
t = strndupa_safe(t, utc - t);
|
||||
else {
|
||||
const char *e = NULL;
|
||||
int j;
|
||||
|
@ -728,7 +728,7 @@ static int parse_timestamp_impl(const char *t, usec_t *usec, bool with_tz) {
|
|||
|
||||
if (IN_SET(j, 0, 1)) {
|
||||
/* Found one of the two timezones specified. */
|
||||
t = strndupa(t, e - t - 1);
|
||||
t = strndupa_safe(t, e - t - 1);
|
||||
dst = j;
|
||||
tzn = tzname[j];
|
||||
}
|
||||
|
@ -929,7 +929,7 @@ int parse_timestamp(const char *t, usec_t *usec) {
|
|||
|
||||
/* Cut off the timezone if we don't need it. */
|
||||
if (with_tz)
|
||||
t = strndupa(t, last_space - t);
|
||||
t = strndupa_safe(t, last_space - t);
|
||||
|
||||
shared->return_value = parse_timestamp_impl(t, &shared->usec, with_tz);
|
||||
|
||||
|
|
|
@ -67,16 +67,9 @@ int fopen_temporary(const char *path, FILE **ret_f, char **ret_temp_path) {
|
|||
|
||||
/* This is much like mkostemp() but is subject to umask(). */
|
||||
int mkostemp_safe(char *pattern) {
|
||||
int fd = -1; /* avoid false maybe-uninitialized warning */
|
||||
|
||||
assert(pattern);
|
||||
|
||||
RUN_WITH_UMASK(0077)
|
||||
fd = mkostemp(pattern, O_CLOEXEC);
|
||||
if (fd < 0)
|
||||
return -errno;
|
||||
|
||||
return fd;
|
||||
BLOCK_WITH_UMASK(0077);
|
||||
return RET_NERRNO(mkostemp(pattern, O_CLOEXEC));
|
||||
}
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
|
@ -288,8 +281,6 @@ int open_tmpfile_linkable(const char *target, int flags, char **ret_path) {
|
|||
}
|
||||
|
||||
int link_tmpfile(int fd, const char *path, const char *target) {
|
||||
int r;
|
||||
|
||||
assert(fd >= 0);
|
||||
assert(target);
|
||||
|
||||
|
@ -300,16 +291,10 @@ int link_tmpfile(int fd, const char *path, const char *target) {
|
|||
* Note that in both cases we will not replace existing files. This is because linkat() does not support this
|
||||
* operation currently (renameat2() does), and there is no nice way to emulate this. */
|
||||
|
||||
if (path) {
|
||||
r = rename_noreplace(AT_FDCWD, path, AT_FDCWD, target);
|
||||
if (r < 0)
|
||||
return r;
|
||||
} else {
|
||||
if (linkat(AT_FDCWD, FORMAT_PROC_FD_PATH(fd), AT_FDCWD, target, AT_SYMLINK_FOLLOW) < 0)
|
||||
return -errno;
|
||||
}
|
||||
if (path)
|
||||
return rename_noreplace(AT_FDCWD, path, AT_FDCWD, target);
|
||||
|
||||
return 0;
|
||||
return RET_NERRNO(linkat(AT_FDCWD, FORMAT_PROC_FD_PATH(fd), AT_FDCWD, target, AT_SYMLINK_FOLLOW));
|
||||
}
|
||||
|
||||
int mkdtemp_malloc(const char *template, char **ret) {
|
||||
|
|
|
@ -24,3 +24,6 @@ assert_cc((S_IFMT & 0777) == 0);
|
|||
for (_cleanup_umask_ mode_t _saved_umask_ = umask(mask) | S_IFMT; \
|
||||
FLAGS_SET(_saved_umask_, S_IFMT); \
|
||||
_saved_umask_ &= 0777)
|
||||
|
||||
#define BLOCK_WITH_UMASK(mask) \
|
||||
_unused_ _cleanup_umask_ mode_t _saved_umask_ = umask(mask);
|
||||
|
|
|
@ -112,6 +112,12 @@ bool is_nologin_shell(const char *shell);
|
|||
|
||||
int is_this_me(const char *username);
|
||||
|
||||
const char *get_home_root(void);
|
||||
|
||||
static inline bool hashed_password_is_locked_or_invalid(const char *password) {
|
||||
return password && password[0] != '$';
|
||||
}
|
||||
|
||||
/* A locked *and* invalid password for "struct spwd"'s .sp_pwdp and "struct passwd"'s .pw_passwd field */
|
||||
#define PASSWORD_LOCKED_AND_INVALID "!*"
|
||||
|
||||
|
|
|
@ -126,11 +126,9 @@ int utf8_encoded_to_unichar(const char *str, char32_t *ret_unichar) {
|
|||
}
|
||||
|
||||
bool utf8_is_printable_newline(const char* str, size_t length, bool allow_newline) {
|
||||
const char *p;
|
||||
|
||||
assert(str);
|
||||
|
||||
for (p = str; length > 0;) {
|
||||
for (const char *p = str; length > 0;) {
|
||||
int encoded_len, r;
|
||||
char32_t val;
|
||||
|
||||
|
@ -293,14 +291,12 @@ char *utf8_escape_non_printable_full(const char *str, size_t console_width, bool
|
|||
#endif /* NM_IGNORED */
|
||||
|
||||
char *ascii_is_valid(const char *str) {
|
||||
const char *p;
|
||||
|
||||
/* Check whether the string consists of valid ASCII bytes,
|
||||
* i.e values between 0 and 127, inclusive. */
|
||||
|
||||
assert(str);
|
||||
|
||||
for (p = str; *p; p++)
|
||||
for (const char *p = str; *p; p++)
|
||||
if ((unsigned char) *p >= 128)
|
||||
return NULL;
|
||||
|
||||
|
@ -322,6 +318,37 @@ char *ascii_is_valid_n(const char *str, size_t len) {
|
|||
}
|
||||
#endif /* NM_IGNORED */
|
||||
|
||||
int utf8_to_ascii(const char *str, char replacement_char, char **ret) {
|
||||
/* Convert to a string that has only ASCII chars, replacing anything that is not ASCII
|
||||
* by replacement_char. */
|
||||
|
||||
_cleanup_free_ char *ans = new(char, strlen(str) + 1);
|
||||
if (!ans)
|
||||
return -ENOMEM;
|
||||
|
||||
char *q = ans;
|
||||
|
||||
for (const char *p = str; *p; q++) {
|
||||
int l;
|
||||
|
||||
l = utf8_encoded_valid_unichar(p, SIZE_MAX);
|
||||
if (l < 0) /* Non-UTF-8, let's not even try to propagate the garbage */
|
||||
return l;
|
||||
|
||||
if (l == 1)
|
||||
*q = *p;
|
||||
else
|
||||
/* non-ASCII, we need to replace it */
|
||||
*q = replacement_char;
|
||||
|
||||
p += l;
|
||||
}
|
||||
*q = '\0';
|
||||
|
||||
*ret = TAKE_PTR(ans);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* utf8_encode_unichar() - Encode single UCS-4 character as UTF-8
|
||||
* @out_utf8: output buffer of at least 4 bytes or NULL
|
||||
|
|
|
@ -21,6 +21,8 @@ static inline char *utf8_is_valid(const char *s) {
|
|||
char *ascii_is_valid(const char *s) _pure_;
|
||||
char *ascii_is_valid_n(const char *str, size_t len);
|
||||
|
||||
int utf8_to_ascii(const char *str, char replacement_char, char **ret);
|
||||
|
||||
bool utf8_is_printable_newline(const char* str, size_t length, bool allow_newline) _pure_;
|
||||
#define utf8_is_printable(str, length) utf8_is_printable_newline(str, length, true)
|
||||
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
|
||||
#include "alloc-util.h"
|
||||
#include "build.h"
|
||||
#include "dirent-util.h"
|
||||
#include "env-file.h"
|
||||
#include "env-util.h"
|
||||
#include "fd-util.h"
|
||||
|
@ -118,71 +117,6 @@ void in_initrd_force(bool value) {
|
|||
saved_in_initrd = value;
|
||||
}
|
||||
|
||||
int on_ac_power(void) {
|
||||
bool found_offline = false, found_online = false;
|
||||
_cleanup_closedir_ DIR *d = NULL;
|
||||
struct dirent *de;
|
||||
|
||||
d = opendir("/sys/class/power_supply");
|
||||
if (!d)
|
||||
return errno == ENOENT ? true : -errno;
|
||||
|
||||
FOREACH_DIRENT(de, d, return -errno) {
|
||||
_cleanup_close_ int fd = -1, device = -1;
|
||||
char contents[6];
|
||||
ssize_t n;
|
||||
|
||||
device = openat(dirfd(d), de->d_name, O_DIRECTORY|O_RDONLY|O_CLOEXEC|O_NOCTTY);
|
||||
if (device < 0) {
|
||||
if (IN_SET(errno, ENOENT, ENOTDIR))
|
||||
continue;
|
||||
|
||||
return -errno;
|
||||
}
|
||||
|
||||
fd = openat(device, "type", O_RDONLY|O_CLOEXEC|O_NOCTTY);
|
||||
if (fd < 0) {
|
||||
if (errno == ENOENT)
|
||||
continue;
|
||||
|
||||
return -errno;
|
||||
}
|
||||
|
||||
n = read(fd, contents, sizeof(contents));
|
||||
if (n < 0)
|
||||
return -errno;
|
||||
|
||||
if (n != 6 || memcmp(contents, "Mains\n", 6))
|
||||
continue;
|
||||
|
||||
safe_close(fd);
|
||||
fd = openat(device, "online", O_RDONLY|O_CLOEXEC|O_NOCTTY);
|
||||
if (fd < 0) {
|
||||
if (errno == ENOENT)
|
||||
continue;
|
||||
|
||||
return -errno;
|
||||
}
|
||||
|
||||
n = read(fd, contents, sizeof(contents));
|
||||
if (n < 0)
|
||||
return -errno;
|
||||
|
||||
if (n != 2 || contents[1] != '\n')
|
||||
return -EIO;
|
||||
|
||||
if (contents[0] == '1') {
|
||||
found_online = true;
|
||||
break;
|
||||
} else if (contents[0] == '0')
|
||||
found_offline = true;
|
||||
else
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return found_online || !found_offline;
|
||||
}
|
||||
|
||||
int container_get_leader(const char *machine, pid_t *pid) {
|
||||
_cleanup_free_ char *s = NULL, *class = NULL;
|
||||
const char *p;
|
||||
|
|
|
@ -20,11 +20,18 @@ int prot_from_flags(int flags) _const_;
|
|||
bool in_initrd(void);
|
||||
void in_initrd_force(bool value);
|
||||
|
||||
int on_ac_power(void);
|
||||
/* Note: log2(0) == log2(1) == 0 here and below. */
|
||||
|
||||
static inline unsigned u64log2(uint64_t n) {
|
||||
#define CONST_LOG2ULL(x) ((x) > 1 ? (unsigned) __builtin_clzll(x) ^ 63U : 0)
|
||||
#define NONCONST_LOG2ULL(x) ({ \
|
||||
unsigned long long _x = (x); \
|
||||
_x > 1 ? (unsigned) __builtin_clzll(_x) ^ 63U : 0; \
|
||||
})
|
||||
#define LOG2ULL(x) __builtin_choose_expr(__builtin_constant_p(x), CONST_LOG2ULL(x), NONCONST_LOG2ULL(x))
|
||||
|
||||
static inline unsigned log2u64(uint64_t x) {
|
||||
#if __SIZEOF_LONG_LONG__ == 8
|
||||
return (n > 1) ? (unsigned) __builtin_clzll(n) ^ 63U : 0;
|
||||
return LOG2ULL(x);
|
||||
#else
|
||||
# error "Wut?"
|
||||
#endif
|
||||
|
@ -38,22 +45,23 @@ static inline unsigned u32ctz(uint32_t n) {
|
|||
#endif
|
||||
}
|
||||
|
||||
static inline unsigned log2i(int x) {
|
||||
assert(x > 0);
|
||||
#define CONST_LOG2U(x) ((x) > 1 ? __SIZEOF_INT__ * 8 - __builtin_clz(x) - 1 : 0)
|
||||
#define NONCONST_LOG2U(x) ({ \
|
||||
unsigned _x = (x); \
|
||||
_x > 1 ? __SIZEOF_INT__ * 8 - __builtin_clz(_x) - 1 : 0; \
|
||||
})
|
||||
#define LOG2U(x) __builtin_choose_expr(__builtin_constant_p(x), CONST_LOG2U(x), NONCONST_LOG2U(x))
|
||||
|
||||
return __SIZEOF_INT__ * 8 - __builtin_clz(x) - 1;
|
||||
static inline unsigned log2i(int x) {
|
||||
return LOG2U(x);
|
||||
}
|
||||
|
||||
static inline unsigned log2u(unsigned x) {
|
||||
assert(x > 0);
|
||||
|
||||
return sizeof(unsigned) * 8 - __builtin_clz(x) - 1;
|
||||
return LOG2U(x);
|
||||
}
|
||||
|
||||
static inline unsigned log2u_round_up(unsigned x) {
|
||||
assert(x > 0);
|
||||
|
||||
if (x == 1)
|
||||
if (x <= 1)
|
||||
return 0;
|
||||
|
||||
return log2u(x - 1) + 1;
|
||||
|
|
|
@ -5,13 +5,15 @@
|
|||
#include <assert.h>
|
||||
#endif
|
||||
|
||||
#include "type.h"
|
||||
#include <limits.h>
|
||||
#include "types-fundamental.h"
|
||||
|
||||
#define _align_(x) __attribute__((__aligned__(x)))
|
||||
#define _const_ __attribute__((__const__))
|
||||
#define _pure_ __attribute__((__pure__))
|
||||
#define _section_(x) __attribute__((__section__(x)))
|
||||
#define _packed_ __attribute__((__packed__))
|
||||
#define _retain_ __attribute__((__retain__))
|
||||
#define _used_ __attribute__((__used__))
|
||||
#define _unused_ __attribute__((__unused__))
|
||||
#define _cleanup_(x) __attribute__((__cleanup__(x)))
|
||||
|
@ -59,8 +61,19 @@
|
|||
#define assert(expr) ({ _likely_(expr) ? VOID_0 : efi_assert(#expr, __FILE__, __LINE__, __PRETTY_FUNCTION__); })
|
||||
#define assert_not_reached() efi_assert("Code should not be reached", __FILE__, __LINE__, __PRETTY_FUNCTION__)
|
||||
#endif
|
||||
|
||||
#define memcpy(a, b, c) CopyMem((a), (b), (c))
|
||||
#define free(a) FreePool(a)
|
||||
#endif
|
||||
|
||||
/* This passes the argument through after (if asserts are enabled) checking that it is not null. */
|
||||
#define ASSERT_PTR(expr) \
|
||||
({ \
|
||||
typeof(expr) _expr_ = (expr); \
|
||||
assert(_expr_); \
|
||||
_expr_; \
|
||||
})
|
||||
|
||||
#if defined(static_assert)
|
||||
#define assert_cc(expr) \
|
||||
static_assert(expr, #expr)
|
||||
|
@ -81,8 +94,8 @@
|
|||
#define ONCE __ONCE(UNIQ_T(_once_, UNIQ))
|
||||
#define __ONCE(o) \
|
||||
({ \
|
||||
static bool (o) = false; \
|
||||
__sync_bool_compare_and_swap(&(o), false, true); \
|
||||
static sd_bool (o) = sd_false; \
|
||||
__sync_bool_compare_and_swap(&(o), sd_false, sd_true); \
|
||||
})
|
||||
|
||||
#undef MAX
|
||||
|
@ -232,7 +245,7 @@
|
|||
|
||||
#define IN_SET(x, ...) \
|
||||
({ \
|
||||
sd_bool _found = false; \
|
||||
sd_bool _found = sd_false; \
|
||||
/* If the build breaks in the line below, you need to extend the case macros. (We use "long double" as \
|
||||
* type for the array, in the hope that checkers such as ubsan don't complain that the initializers for \
|
||||
* the array are not representable by the base type. Ideally we'd use typeof(x) as base type, but that \
|
||||
|
@ -241,7 +254,7 @@
|
|||
assert_cc(ELEMENTSOF(__assert_in_set) <= 20); \
|
||||
switch(x) { \
|
||||
FOR_EACH_MAKE_CASE(__VA_ARGS__) \
|
||||
_found = true; \
|
||||
_found = sd_true; \
|
||||
break; \
|
||||
default: \
|
||||
break; \
|
||||
|
@ -253,8 +266,9 @@
|
|||
* resets it to NULL. See: https://doc.rust-lang.org/std/option/enum.Option.html#method.take */
|
||||
#define TAKE_PTR(ptr) \
|
||||
({ \
|
||||
typeof(ptr) _ptr_ = (ptr); \
|
||||
(ptr) = NULL; \
|
||||
typeof(ptr) *_pptr_ = &(ptr); \
|
||||
typeof(ptr) _ptr_ = *_pptr_; \
|
||||
*_pptr_ = NULL; \
|
||||
_ptr_; \
|
||||
})
|
||||
|
||||
|
@ -264,3 +278,47 @@
|
|||
* @x: a string literal.
|
||||
*/
|
||||
#define STRLEN(x) (sizeof(""x"") - sizeof(typeof(x[0])))
|
||||
|
||||
#define mfree(memory) \
|
||||
({ \
|
||||
free(memory); \
|
||||
(typeof(memory)) NULL; \
|
||||
})
|
||||
|
||||
static inline size_t ALIGN_TO(size_t l, size_t ali) {
|
||||
/* sd-boot uses UINTN for size_t, let's make sure SIZE_MAX is correct. */
|
||||
assert_cc(SIZE_MAX == ~(size_t)0);
|
||||
|
||||
/* 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
|
||||
|
||||
if (l > SIZE_MAX - (ali - 1))
|
||||
return SIZE_MAX; /* indicate overflow */
|
||||
|
||||
return ((l + ali - 1) & ~(ali - 1));
|
||||
}
|
||||
|
||||
/* Same as ALIGN_TO but callable in constant contexts. */
|
||||
#define CONST_ALIGN_TO(l, ali) \
|
||||
__builtin_choose_expr( \
|
||||
__builtin_constant_p(l) && \
|
||||
__builtin_constant_p(ali) && \
|
||||
__builtin_popcountll(ali) == 1 && /* is power of 2? */ \
|
||||
(l <= SIZE_MAX - (ali - 1)), /* overflow? */ \
|
||||
((l) + (ali) - 1) & ~((ali) - 1), \
|
||||
VOID_0)
|
||||
|
||||
#define UPDATE_FLAG(orig, flag, b) \
|
||||
((b) ? ((orig) | (flag)) : ((orig) & ~(flag)))
|
||||
#define SET_FLAG(v, flag, b) \
|
||||
(v) = UPDATE_FLAG(v, flag, b)
|
||||
#define FLAGS_SET(v, flags) \
|
||||
((~(v) & (flags)) == 0)
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
#include "string-util-fundamental.h"
|
||||
|
||||
sd_char *startswith(const sd_char *s, const sd_char *prefix) {
|
||||
sd_size_t l;
|
||||
size_t l;
|
||||
|
||||
assert(s);
|
||||
assert(prefix);
|
||||
|
@ -24,7 +24,7 @@ sd_char *startswith(const sd_char *s, const sd_char *prefix) {
|
|||
|
||||
#ifndef SD_BOOT
|
||||
sd_char *startswith_no_case(const sd_char *s, const sd_char *prefix) {
|
||||
sd_size_t l;
|
||||
size_t l;
|
||||
|
||||
assert(s);
|
||||
assert(prefix);
|
||||
|
@ -38,7 +38,7 @@ sd_char *startswith_no_case(const sd_char *s, const sd_char *prefix) {
|
|||
#endif
|
||||
|
||||
sd_char* endswith(const sd_char *s, const sd_char *postfix) {
|
||||
sd_size_t sl, pl;
|
||||
size_t sl, pl;
|
||||
|
||||
assert(s);
|
||||
assert(postfix);
|
||||
|
@ -59,7 +59,7 @@ sd_char* endswith(const sd_char *s, const sd_char *postfix) {
|
|||
}
|
||||
|
||||
sd_char* endswith_no_case(const sd_char *s, const sd_char *postfix) {
|
||||
sd_size_t sl, pl;
|
||||
size_t sl, pl;
|
||||
|
||||
assert(s);
|
||||
assert(postfix);
|
||||
|
|
|
@ -68,10 +68,10 @@ static inline const sd_char *yes_no(sd_bool b) {
|
|||
sd_int strverscmp_improved(const sd_char *a, const sd_char *b);
|
||||
|
||||
/* Like startswith(), but operates on arbitrary memory blocks */
|
||||
static inline void *memory_startswith(const void *p, sd_size_t sz, const sd_char *token) {
|
||||
static inline void *memory_startswith(const void *p, size_t sz, const sd_char *token) {
|
||||
assert(token);
|
||||
|
||||
sd_size_t n = strlen(token) * sizeof(sd_char);
|
||||
size_t n = strlen(token) * sizeof(sd_char);
|
||||
if (sz < n)
|
||||
return NULL;
|
||||
|
||||
|
|
|
@ -1,22 +0,0 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#ifdef SD_BOOT
|
||||
#include <efi.h>
|
||||
|
||||
typedef BOOLEAN sd_bool;
|
||||
typedef CHAR16 sd_char;
|
||||
typedef INTN sd_int;
|
||||
typedef UINTN sd_size_t;
|
||||
|
||||
#define true TRUE
|
||||
#define false FALSE
|
||||
#else
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef bool sd_bool;
|
||||
typedef char sd_char;
|
||||
typedef int sd_int;
|
||||
typedef size_t sd_size_t;
|
||||
#endif
|
39
src/libnm-systemd-shared/src/fundamental/types-fundamental.h
Normal file
39
src/libnm-systemd-shared/src/fundamental/types-fundamental.h
Normal file
|
@ -0,0 +1,39 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
/* This defines a number of basic types that are one thing in userspace and another in the UEFI environment,
|
||||
* but mostly the same in concept and behaviour.
|
||||
*
|
||||
* Note: if the definition of these types/values has slightly different semantics in userspace and in the
|
||||
* UEFI environment then please prefix its name with "sd_" to make clear these types have special semantics,
|
||||
* and *we* defined them. Otherwise, if the types are effectively 100% identical in behaviour in userspace
|
||||
* and UEFI environment you can omit the prefix. (Examples: sd_char is 8 bit in userspace and 16 bit in UEFI
|
||||
* space hence it should have the sd_ prefix; but size_t in userspace and UINTN in UEFI environment are 100%
|
||||
* defined the same way ultimately, hence it's OK to just define size_t as alias to UINTN in UEFI
|
||||
* environment, so that size_t can be used everywhere, without any "sd_" prefix.)
|
||||
*
|
||||
* Note: we generally prefer the userspace names of types and concepts. i.e. if in doubt please name types
|
||||
* after the userspace vocabulary, and let's keep UEFI vocabulary specific to the UEFI build environment. */
|
||||
|
||||
#ifdef SD_BOOT
|
||||
#include <efi.h>
|
||||
|
||||
typedef BOOLEAN sd_bool;
|
||||
typedef CHAR16 sd_char;
|
||||
typedef INTN sd_int;
|
||||
typedef UINTN size_t;
|
||||
|
||||
#define sd_true TRUE
|
||||
#define sd_false FALSE
|
||||
#else
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef bool sd_bool;
|
||||
typedef char sd_char;
|
||||
typedef int sd_int;
|
||||
|
||||
#define sd_true true
|
||||
#define sd_false false
|
||||
|
||||
#endif
|
|
@ -687,7 +687,7 @@ int dns_name_change_suffix(const char *name, const char *old_suffix, const char
|
|||
}
|
||||
|
||||
/* Found it! Now generate the new name */
|
||||
prefix = strndupa(name, saved_before - name);
|
||||
prefix = strndupa_safe(name, saved_before - name);
|
||||
|
||||
r = dns_name_concat(prefix, new_suffix, 0, ret);
|
||||
if (r < 0)
|
||||
|
@ -1037,7 +1037,7 @@ static bool dns_service_name_label_is_valid(const char *label, size_t n) {
|
|||
if (memchr(label, 0, n))
|
||||
return false;
|
||||
|
||||
s = strndupa(label, n);
|
||||
s = strndupa_safe(label, n);
|
||||
return dns_service_name_is_valid(s);
|
||||
}
|
||||
|
||||
|
|
|
@ -62,6 +62,10 @@ static inline int dns_name_is_valid_ldh(const char *s) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
static inline bool dns_name_is_empty(const char *s) {
|
||||
return isempty(s) || streq(s, ".");
|
||||
}
|
||||
|
||||
void dns_name_hash_func(const char *s, struct siphash *state);
|
||||
int dns_name_compare_func(const char *a, const char *b);
|
||||
extern const struct hash_ops dns_name_hash_ops;
|
||||
|
|
Loading…
Reference in a new issue