mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager
synced 2024-10-07 00:31:11 +00:00
systemd: update code from upstream (2022-07-05)
This is a direct dump from systemd git. $ git clean -fdx && \ git cat-file -p HEAD | sed '1,/^======$/ d' | bash - && \ git add . ====== SYSTEMD_DIR=../systemd COMMIT=87a3a4a802b9fcfd92299e2984741835ed50fef4 ( cd "$SYSTEMD_DIR" git checkout "$COMMIT" git reset --hard git clean -fdx ) git ls-files -z :/src/libnm-systemd-core/src/ \ :/src/libnm-systemd-shared/src/ \ :/src/libnm-std-aux/unaligned.h | \ xargs -0 rm -f nm_copy_sd_shared() { mkdir -p "./src/libnm-systemd-shared/$(dirname "$1")" cp "$SYSTEMD_DIR/$1" "./src/libnm-systemd-shared/$1" } nm_copy_sd_core() { mkdir -p "./src/libnm-systemd-core/$(dirname "$1")" cp "$SYSTEMD_DIR/$1" "./src/libnm-systemd-core/$1" } nm_copy_sd_stdaux() { mkdir -p "./src/libnm-std-aux/" cp "$SYSTEMD_DIR/$1" "./src/libnm-std-aux/${1##*/}" } nm_copy_sd_core "src/libsystemd-network/arp-util.c" nm_copy_sd_core "src/libsystemd-network/arp-util.h" nm_copy_sd_core "src/libsystemd-network/dhcp-identifier.c" nm_copy_sd_core "src/libsystemd-network/dhcp-identifier.h" nm_copy_sd_core "src/libsystemd-network/dhcp-internal.h" nm_copy_sd_core "src/libsystemd-network/dhcp-lease-internal.h" nm_copy_sd_core "src/libsystemd-network/dhcp-network.c" nm_copy_sd_core "src/libsystemd-network/dhcp-protocol.h" nm_copy_sd_core "src/libsystemd-network/dhcp6-internal.h" nm_copy_sd_core "src/libsystemd-network/dhcp6-lease-internal.h" nm_copy_sd_core "src/libsystemd-network/dhcp6-network.c" nm_copy_sd_core "src/libsystemd-network/dhcp6-option.c" nm_copy_sd_core "src/libsystemd-network/dhcp6-option.h" nm_copy_sd_core "src/libsystemd-network/dhcp6-protocol.c" nm_copy_sd_core "src/libsystemd-network/dhcp6-protocol.h" nm_copy_sd_core "src/libsystemd-network/lldp-neighbor.c" nm_copy_sd_core "src/libsystemd-network/lldp-neighbor.h" nm_copy_sd_core "src/libsystemd-network/lldp-network.c" nm_copy_sd_core "src/libsystemd-network/lldp-network.h" nm_copy_sd_core "src/libsystemd-network/lldp-rx-internal.h" nm_copy_sd_core "src/libsystemd-network/network-common.c" nm_copy_sd_core "src/libsystemd-network/network-common.h" nm_copy_sd_core "src/libsystemd-network/network-internal.h" nm_copy_sd_core "src/libsystemd-network/sd-dhcp-client.c" nm_copy_sd_core "src/libsystemd-network/sd-dhcp6-client.c" nm_copy_sd_core "src/libsystemd-network/sd-dhcp6-lease.c" nm_copy_sd_core "src/libsystemd-network/sd-lldp-rx.c" nm_copy_sd_core "src/libsystemd/sd-event/event-source.h" nm_copy_sd_core "src/libsystemd/sd-event/event-util.c" nm_copy_sd_core "src/libsystemd/sd-event/event-util.h" nm_copy_sd_core "src/libsystemd/sd-event/sd-event.c" nm_copy_sd_core "src/libsystemd/sd-id128/id128-util.c" nm_copy_sd_core "src/libsystemd/sd-id128/id128-util.h" nm_copy_sd_core "src/libsystemd/sd-id128/sd-id128.c" nm_copy_sd_core "src/systemd/_sd-common.h" nm_copy_sd_core "src/systemd/sd-dhcp6-client.h" nm_copy_sd_core "src/systemd/sd-dhcp6-lease.h" nm_copy_sd_core "src/systemd/sd-dhcp6-option.h" nm_copy_sd_core "src/systemd/sd-event.h" nm_copy_sd_core "src/systemd/sd-id128.h" nm_copy_sd_core "src/systemd/sd-lldp-rx.h" nm_copy_sd_core "src/systemd/sd-lldp.h" nm_copy_sd_core "src/systemd/sd-ndisc.h" nm_copy_sd_shared "src/basic/alloc-util.c" nm_copy_sd_shared "src/basic/alloc-util.h" nm_copy_sd_shared "src/basic/async.h" nm_copy_sd_shared "src/basic/cgroup-util.h" nm_copy_sd_shared "src/basic/dns-def.h" nm_copy_sd_shared "src/basic/env-file.c" nm_copy_sd_shared "src/basic/env-file.h" nm_copy_sd_shared "src/basic/env-util.c" nm_copy_sd_shared "src/basic/env-util.h" nm_copy_sd_shared "src/basic/errno-util.h" nm_copy_sd_shared "src/basic/escape.c" nm_copy_sd_shared "src/basic/escape.h" nm_copy_sd_shared "src/basic/ether-addr-util.c" nm_copy_sd_shared "src/basic/ether-addr-util.h" nm_copy_sd_shared "src/basic/extract-word.c" nm_copy_sd_shared "src/basic/extract-word.h" nm_copy_sd_shared "src/basic/fd-util.c" nm_copy_sd_shared "src/basic/fd-util.h" nm_copy_sd_shared "src/basic/fileio.c" nm_copy_sd_shared "src/basic/fileio.h" nm_copy_sd_shared "src/basic/format-util.c" nm_copy_sd_shared "src/basic/format-util.h" nm_copy_sd_shared "src/basic/fs-util.c" nm_copy_sd_shared "src/basic/fs-util.h" nm_copy_sd_shared "src/basic/glyph-util.c" nm_copy_sd_shared "src/basic/glyph-util.h" nm_copy_sd_shared "src/basic/hash-funcs.c" nm_copy_sd_shared "src/basic/hash-funcs.h" nm_copy_sd_shared "src/basic/hashmap.c" nm_copy_sd_shared "src/basic/hashmap.h" nm_copy_sd_shared "src/basic/hexdecoct.c" nm_copy_sd_shared "src/basic/hexdecoct.h" nm_copy_sd_shared "src/basic/hostname-util.c" nm_copy_sd_shared "src/basic/hostname-util.h" nm_copy_sd_shared "src/basic/in-addr-util.c" nm_copy_sd_shared "src/basic/in-addr-util.h" nm_copy_sd_shared "src/basic/inotify-util.c" nm_copy_sd_shared "src/basic/inotify-util.h" nm_copy_sd_shared "src/basic/io-util.c" nm_copy_sd_shared "src/basic/io-util.h" nm_copy_sd_shared "src/basic/list.h" nm_copy_sd_shared "src/basic/locale-util.c" nm_copy_sd_shared "src/basic/locale-util.h" nm_copy_sd_shared "src/basic/log.h" nm_copy_sd_shared "src/basic/macro.h" nm_copy_sd_shared "src/basic/memory-util.c" nm_copy_sd_shared "src/basic/memory-util.h" nm_copy_sd_shared "src/basic/mempool.c" nm_copy_sd_shared "src/basic/mempool.h" nm_copy_sd_shared "src/basic/missing_fcntl.h" nm_copy_sd_shared "src/basic/missing_random.h" nm_copy_sd_shared "src/basic/missing_socket.h" nm_copy_sd_shared "src/basic/missing_stat.h" nm_copy_sd_shared "src/basic/missing_syscall.h" nm_copy_sd_shared "src/basic/missing_type.h" nm_copy_sd_shared "src/basic/ordered-set.c" nm_copy_sd_shared "src/basic/ordered-set.h" nm_copy_sd_shared "src/basic/parse-util.c" nm_copy_sd_shared "src/basic/parse-util.h" nm_copy_sd_shared "src/basic/path-util.c" nm_copy_sd_shared "src/basic/path-util.h" nm_copy_sd_shared "src/basic/prioq.c" nm_copy_sd_shared "src/basic/prioq.h" nm_copy_sd_shared "src/basic/process-util.c" nm_copy_sd_shared "src/basic/process-util.h" nm_copy_sd_shared "src/basic/random-util.c" nm_copy_sd_shared "src/basic/random-util.h" nm_copy_sd_shared "src/basic/ratelimit.c" nm_copy_sd_shared "src/basic/ratelimit.h" nm_copy_sd_shared "src/basic/set.h" nm_copy_sd_shared "src/basic/signal-util.c" nm_copy_sd_shared "src/basic/signal-util.h" nm_copy_sd_shared "src/basic/siphash24.h" nm_copy_sd_shared "src/basic/socket-util.c" nm_copy_sd_shared "src/basic/socket-util.h" nm_copy_sd_shared "src/basic/sort-util.h" nm_copy_sd_shared "src/basic/sparse-endian.h" nm_copy_sd_shared "src/basic/stat-util.c" nm_copy_sd_shared "src/basic/stat-util.h" nm_copy_sd_shared "src/basic/stdio-util.h" nm_copy_sd_shared "src/basic/string-table.c" nm_copy_sd_shared "src/basic/string-table.h" nm_copy_sd_shared "src/basic/string-util.c" nm_copy_sd_shared "src/basic/string-util.h" nm_copy_sd_shared "src/basic/strv.c" nm_copy_sd_shared "src/basic/strv.h" nm_copy_sd_shared "src/basic/strxcpyx.c" nm_copy_sd_shared "src/basic/strxcpyx.h" nm_copy_sd_shared "src/basic/time-util.c" nm_copy_sd_shared "src/basic/time-util.h" nm_copy_sd_shared "src/basic/tmpfile-util.c" nm_copy_sd_shared "src/basic/tmpfile-util.h" nm_copy_sd_shared "src/basic/umask-util.h" nm_copy_sd_shared "src/basic/user-util.h" nm_copy_sd_shared "src/basic/utf8.c" nm_copy_sd_shared "src/basic/utf8.h" nm_copy_sd_shared "src/basic/util.c" nm_copy_sd_shared "src/basic/util.h" nm_copy_sd_shared "src/fundamental/macro-fundamental.h" nm_copy_sd_shared "src/fundamental/sha256.c" nm_copy_sd_shared "src/fundamental/sha256.h" nm_copy_sd_shared "src/fundamental/string-util-fundamental.c" nm_copy_sd_shared "src/fundamental/string-util-fundamental.h" nm_copy_sd_shared "src/shared/dns-domain.c" nm_copy_sd_shared "src/shared/dns-domain.h" nm_copy_sd_shared "src/shared/log-link.h" nm_copy_sd_shared "src/shared/web-util.c" nm_copy_sd_shared "src/shared/web-util.h" nm_copy_sd_stdaux "src/basic/unaligned.h"
This commit is contained in:
parent
7b3466fc4c
commit
3a603c8764
|
@ -11,7 +11,6 @@
|
|||
#include "netif-util.h"
|
||||
#include "siphash24.h"
|
||||
#include "sparse-endian.h"
|
||||
#include "stat-util.h"
|
||||
#include "string-table.h"
|
||||
#include "udev-util.h"
|
||||
|
||||
|
@ -213,7 +212,7 @@ int dhcp_identifier_set_iaid(
|
|||
uint64_t id;
|
||||
int r;
|
||||
|
||||
if (path_is_read_only_fs("/sys") <= 0 && !use_mac) {
|
||||
if (udev_available() && !use_mac) {
|
||||
/* udev should be around */
|
||||
|
||||
r = sd_device_new_from_ifindex(&device, ifindex);
|
||||
|
|
|
@ -1,438 +0,0 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
/***
|
||||
Copyright © 2013 Intel Corporation. All rights reserved.
|
||||
***/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "dhcp-internal.h"
|
||||
#include "dhcp-server-internal.h"
|
||||
#include "memory-util.h"
|
||||
#include "strv.h"
|
||||
#include "utf8.h"
|
||||
|
||||
/* Append type-length value structure to the options buffer */
|
||||
static int dhcp_option_append_tlv(uint8_t options[], size_t size, size_t *offset, uint8_t code, size_t optlen, const void *optval) {
|
||||
assert(options);
|
||||
assert(size > 0);
|
||||
assert(offset);
|
||||
assert(optlen <= UINT8_MAX);
|
||||
assert(*offset < size);
|
||||
|
||||
if (*offset + 2 + optlen > size)
|
||||
return -ENOBUFS;
|
||||
|
||||
options[*offset] = code;
|
||||
options[*offset + 1] = optlen;
|
||||
|
||||
memcpy_safe(&options[*offset + 2], optval, optlen);
|
||||
*offset += 2 + optlen;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int option_append(uint8_t options[], size_t size, size_t *offset,
|
||||
uint8_t code, size_t optlen, const void *optval) {
|
||||
assert(options);
|
||||
assert(size > 0);
|
||||
assert(offset);
|
||||
|
||||
int r;
|
||||
|
||||
if (code != SD_DHCP_OPTION_END)
|
||||
/* always make sure there is space for an END option */
|
||||
size--;
|
||||
|
||||
switch (code) {
|
||||
|
||||
case SD_DHCP_OPTION_PAD:
|
||||
case SD_DHCP_OPTION_END:
|
||||
if (*offset + 1 > size)
|
||||
return -ENOBUFS;
|
||||
|
||||
options[*offset] = code;
|
||||
*offset += 1;
|
||||
break;
|
||||
|
||||
case SD_DHCP_OPTION_USER_CLASS: {
|
||||
size_t total = 0;
|
||||
|
||||
if (strv_isempty((char **) optval))
|
||||
return -EINVAL;
|
||||
|
||||
STRV_FOREACH(s, (char **) optval) {
|
||||
size_t len = strlen(*s);
|
||||
|
||||
if (len > 255 || len == 0)
|
||||
return -EINVAL;
|
||||
|
||||
total += 1 + len;
|
||||
}
|
||||
|
||||
if (*offset + 2 + total > size)
|
||||
return -ENOBUFS;
|
||||
|
||||
options[*offset] = code;
|
||||
options[*offset + 1] = total;
|
||||
*offset += 2;
|
||||
|
||||
STRV_FOREACH(s, (char **) optval) {
|
||||
size_t len = strlen(*s);
|
||||
|
||||
options[*offset] = len;
|
||||
memcpy(&options[*offset + 1], *s, len);
|
||||
*offset += 1 + len;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case SD_DHCP_OPTION_SIP_SERVER:
|
||||
if (*offset + 3 + optlen > size)
|
||||
return -ENOBUFS;
|
||||
|
||||
options[*offset] = code;
|
||||
options[*offset + 1] = optlen + 1;
|
||||
options[*offset + 2] = 1;
|
||||
|
||||
memcpy_safe(&options[*offset + 3], optval, optlen);
|
||||
*offset += 3 + optlen;
|
||||
|
||||
break;
|
||||
case SD_DHCP_OPTION_VENDOR_SPECIFIC: {
|
||||
OrderedSet *s = (OrderedSet *) optval;
|
||||
struct sd_dhcp_option *p;
|
||||
size_t l = 0;
|
||||
|
||||
ORDERED_SET_FOREACH(p, s)
|
||||
l += p->length + 2;
|
||||
|
||||
if (*offset + l + 2 > size)
|
||||
return -ENOBUFS;
|
||||
|
||||
options[*offset] = code;
|
||||
options[*offset + 1] = l;
|
||||
*offset += 2;
|
||||
|
||||
ORDERED_SET_FOREACH(p, s) {
|
||||
r = dhcp_option_append_tlv(options, size, offset, p->option, p->length, p->data);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SD_DHCP_OPTION_RELAY_AGENT_INFORMATION: {
|
||||
sd_dhcp_server *server = (sd_dhcp_server *) optval;
|
||||
size_t current_offset = *offset + 2;
|
||||
|
||||
if (server->agent_circuit_id) {
|
||||
r = dhcp_option_append_tlv(options, size, ¤t_offset, SD_DHCP_RELAY_AGENT_CIRCUIT_ID,
|
||||
strlen(server->agent_circuit_id), server->agent_circuit_id);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
if (server->agent_remote_id) {
|
||||
r = dhcp_option_append_tlv(options, size, ¤t_offset, SD_DHCP_RELAY_AGENT_REMOTE_ID,
|
||||
strlen(server->agent_remote_id), server->agent_remote_id);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
options[*offset] = code;
|
||||
options[*offset + 1] = current_offset - *offset - 2;
|
||||
assert(current_offset - *offset - 2 <= UINT8_MAX);
|
||||
*offset = current_offset;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return dhcp_option_append_tlv(options, size, offset, code, optlen, optval);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int option_length(uint8_t *options, size_t length, size_t offset) {
|
||||
assert(options);
|
||||
assert(offset < length);
|
||||
|
||||
if (IN_SET(options[offset], SD_DHCP_OPTION_PAD, SD_DHCP_OPTION_END))
|
||||
return 1;
|
||||
if (length < offset + 2)
|
||||
return -ENOBUFS;
|
||||
|
||||
/* validating that buffer is long enough */
|
||||
if (length < offset + 2 + options[offset + 1])
|
||||
return -ENOBUFS;
|
||||
|
||||
return options[offset + 1] + 2;
|
||||
}
|
||||
|
||||
int dhcp_option_find_option(uint8_t *options, size_t length, uint8_t code, size_t *ret_offset) {
|
||||
int r;
|
||||
|
||||
assert(options);
|
||||
assert(ret_offset);
|
||||
|
||||
for (size_t offset = 0; offset < length; offset += r) {
|
||||
r = option_length(options, length, offset);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (code == options[offset]) {
|
||||
*ret_offset = offset;
|
||||
return r;
|
||||
}
|
||||
}
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
int dhcp_option_remove_option(uint8_t *options, size_t length, uint8_t option_code) {
|
||||
int r;
|
||||
size_t offset;
|
||||
|
||||
assert(options);
|
||||
|
||||
r = dhcp_option_find_option(options, length, option_code, &offset);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
memmove(options + offset, options + offset + r, length - offset - r);
|
||||
return length - r;
|
||||
}
|
||||
|
||||
int dhcp_option_append(DHCPMessage *message, size_t size, size_t *offset,
|
||||
uint8_t overload,
|
||||
uint8_t code, size_t optlen, const void *optval) {
|
||||
const bool use_file = overload & DHCP_OVERLOAD_FILE;
|
||||
const bool use_sname = overload & DHCP_OVERLOAD_SNAME;
|
||||
int r;
|
||||
|
||||
assert(message);
|
||||
assert(offset);
|
||||
|
||||
/* If *offset is in range [0, size), we are writing to ->options,
|
||||
* if *offset is in range [size, size + sizeof(message->file)) and use_file, we are writing to ->file,
|
||||
* if *offset is in range [size + use_file*sizeof(message->file), size + use_file*sizeof(message->file) + sizeof(message->sname))
|
||||
* and use_sname, we are writing to ->sname.
|
||||
*/
|
||||
|
||||
if (*offset < size) {
|
||||
/* still space in the options array */
|
||||
r = option_append(message->options, size, offset, code, optlen, optval);
|
||||
if (r >= 0)
|
||||
return 0;
|
||||
else if (r == -ENOBUFS && (use_file || use_sname)) {
|
||||
/* did not fit, but we have more buffers to try
|
||||
close the options array and move the offset to its end */
|
||||
r = option_append(message->options, size, offset, SD_DHCP_OPTION_END, 0, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
*offset = size;
|
||||
} else
|
||||
return r;
|
||||
}
|
||||
|
||||
if (use_file) {
|
||||
size_t file_offset = *offset - size;
|
||||
|
||||
if (file_offset < sizeof(message->file)) {
|
||||
/* still space in the 'file' array */
|
||||
r = option_append(message->file, sizeof(message->file), &file_offset, code, optlen, optval);
|
||||
if (r >= 0) {
|
||||
*offset = size + file_offset;
|
||||
return 0;
|
||||
} else if (r == -ENOBUFS && use_sname) {
|
||||
/* did not fit, but we have more buffers to try
|
||||
close the file array and move the offset to its end */
|
||||
r = option_append(message->file, sizeof(message->file), &file_offset, SD_DHCP_OPTION_END, 0, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
*offset = size + sizeof(message->file);
|
||||
} else
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
if (use_sname) {
|
||||
size_t sname_offset = *offset - size - use_file*sizeof(message->file);
|
||||
|
||||
if (sname_offset < sizeof(message->sname)) {
|
||||
/* still space in the 'sname' array */
|
||||
r = option_append(message->sname, sizeof(message->sname), &sname_offset, code, optlen, optval);
|
||||
if (r >= 0) {
|
||||
*offset = size + use_file*sizeof(message->file) + sname_offset;
|
||||
return 0;
|
||||
} else
|
||||
/* no space, or other error, give up */
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
return -ENOBUFS;
|
||||
}
|
||||
|
||||
static int parse_options(const uint8_t options[], size_t buflen, uint8_t *overload,
|
||||
uint8_t *message_type, char **error_message, dhcp_option_callback_t cb,
|
||||
void *userdata) {
|
||||
uint8_t code, len;
|
||||
const uint8_t *option;
|
||||
size_t offset = 0;
|
||||
|
||||
while (offset < buflen) {
|
||||
code = options[offset ++];
|
||||
|
||||
switch (code) {
|
||||
case SD_DHCP_OPTION_PAD:
|
||||
continue;
|
||||
|
||||
case SD_DHCP_OPTION_END:
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (buflen < offset + 1)
|
||||
return -ENOBUFS;
|
||||
|
||||
len = options[offset ++];
|
||||
|
||||
if (buflen < offset + len)
|
||||
return -EINVAL;
|
||||
|
||||
option = &options[offset];
|
||||
|
||||
switch (code) {
|
||||
case SD_DHCP_OPTION_MESSAGE_TYPE:
|
||||
if (len != 1)
|
||||
return -EINVAL;
|
||||
|
||||
if (message_type)
|
||||
*message_type = *option;
|
||||
|
||||
break;
|
||||
|
||||
case SD_DHCP_OPTION_ERROR_MESSAGE:
|
||||
if (len == 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (error_message) {
|
||||
_cleanup_free_ char *string = NULL;
|
||||
|
||||
/* Accept a trailing NUL byte */
|
||||
if (memchr(option, 0, len - 1))
|
||||
return -EINVAL;
|
||||
|
||||
string = memdup_suffix0((const char *) option, len);
|
||||
if (!string)
|
||||
return -ENOMEM;
|
||||
|
||||
if (!ascii_is_valid(string))
|
||||
return -EINVAL;
|
||||
|
||||
free_and_replace(*error_message, string);
|
||||
}
|
||||
|
||||
break;
|
||||
case SD_DHCP_OPTION_OVERLOAD:
|
||||
if (len != 1)
|
||||
return -EINVAL;
|
||||
|
||||
if (overload)
|
||||
*overload = *option;
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
if (cb)
|
||||
cb(code, len, option, userdata);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
offset += len;
|
||||
}
|
||||
|
||||
if (offset < buflen)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dhcp_option_parse(DHCPMessage *message, size_t len, dhcp_option_callback_t cb, void *userdata, char **_error_message) {
|
||||
_cleanup_free_ char *error_message = NULL;
|
||||
uint8_t overload = 0;
|
||||
uint8_t message_type = 0;
|
||||
int r;
|
||||
|
||||
if (!message)
|
||||
return -EINVAL;
|
||||
|
||||
if (len < sizeof(DHCPMessage))
|
||||
return -EINVAL;
|
||||
|
||||
len -= sizeof(DHCPMessage);
|
||||
|
||||
r = parse_options(message->options, len, &overload, &message_type, &error_message, cb, userdata);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (overload & DHCP_OVERLOAD_FILE) {
|
||||
r = parse_options(message->file, sizeof(message->file), NULL, &message_type, &error_message, cb, userdata);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (overload & DHCP_OVERLOAD_SNAME) {
|
||||
r = parse_options(message->sname, sizeof(message->sname), NULL, &message_type, &error_message, cb, userdata);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (message_type == 0)
|
||||
return -ENOMSG;
|
||||
|
||||
if (_error_message && IN_SET(message_type, DHCP_NAK, DHCP_DECLINE))
|
||||
*_error_message = TAKE_PTR(error_message);
|
||||
|
||||
return message_type;
|
||||
}
|
||||
|
||||
static sd_dhcp_option* dhcp_option_free(sd_dhcp_option *i) {
|
||||
if (!i)
|
||||
return NULL;
|
||||
|
||||
free(i->data);
|
||||
return mfree(i);
|
||||
}
|
||||
|
||||
int sd_dhcp_option_new(uint8_t option, const void *data, size_t length, sd_dhcp_option **ret) {
|
||||
assert_return(ret, -EINVAL);
|
||||
assert_return(length == 0 || data, -EINVAL);
|
||||
|
||||
_cleanup_free_ void *q = memdup(data, length);
|
||||
if (!q)
|
||||
return -ENOMEM;
|
||||
|
||||
sd_dhcp_option *p = new(sd_dhcp_option, 1);
|
||||
if (!p)
|
||||
return -ENOMEM;
|
||||
|
||||
*p = (sd_dhcp_option) {
|
||||
.n_ref = 1,
|
||||
.option = option,
|
||||
.length = length,
|
||||
.data = TAKE_PTR(q),
|
||||
};
|
||||
|
||||
*ret = TAKE_PTR(p);
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_dhcp_option, sd_dhcp_option, dhcp_option_free);
|
||||
DEFINE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
|
||||
dhcp_option_hash_ops,
|
||||
void,
|
||||
trivial_hash_func,
|
||||
trivial_compare_func,
|
||||
sd_dhcp_option,
|
||||
sd_dhcp_option_unref);
|
|
@ -1,194 +0,0 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
/***
|
||||
Copyright © 2013 Intel Corporation. All rights reserved.
|
||||
***/
|
||||
|
||||
#include <errno.h>
|
||||
#include <net/ethernet.h>
|
||||
#include <net/if_arp.h>
|
||||
#include <string.h>
|
||||
|
||||
#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,
|
||||
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(chaddr || hlen == 0);
|
||||
|
||||
message->op = op;
|
||||
message->htype = arp_type;
|
||||
|
||||
/* 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);
|
||||
|
||||
r = dhcp_option_append(message, optlen, &offset, 0,
|
||||
SD_DHCP_OPTION_MESSAGE_TYPE, 1, &type);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
*optoffset = offset;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16_t dhcp_packet_checksum(uint8_t *buf, size_t len) {
|
||||
uint64_t *buf_64 = (uint64_t*)buf;
|
||||
uint64_t *end_64 = buf_64 + (len / sizeof(uint64_t));
|
||||
uint64_t sum = 0;
|
||||
|
||||
/* See RFC1071 */
|
||||
|
||||
while (buf_64 < end_64) {
|
||||
sum += *buf_64;
|
||||
if (sum < *buf_64)
|
||||
/* wrap around in one's complement */
|
||||
sum++;
|
||||
|
||||
buf_64++;
|
||||
}
|
||||
|
||||
if (len % sizeof(uint64_t)) {
|
||||
/* If the buffer is not aligned to 64-bit, we need
|
||||
to zero-pad the last few bytes and add them in */
|
||||
uint64_t buf_tail = 0;
|
||||
|
||||
memcpy(&buf_tail, buf_64, len % sizeof(uint64_t));
|
||||
|
||||
sum += buf_tail;
|
||||
if (sum < buf_tail)
|
||||
/* wrap around */
|
||||
sum++;
|
||||
}
|
||||
|
||||
while (sum >> 16)
|
||||
sum = (sum & 0xffff) + (sum >> 16);
|
||||
|
||||
return ~sum;
|
||||
}
|
||||
|
||||
void dhcp_packet_append_ip_headers(DHCPPacket *packet, be32_t source_addr,
|
||||
uint16_t source_port, be32_t destination_addr,
|
||||
uint16_t destination_port, uint16_t len, int ip_service_type) {
|
||||
packet->ip.version = IPVERSION;
|
||||
packet->ip.ihl = DHCP_IP_SIZE / 4;
|
||||
packet->ip.tot_len = htobe16(len);
|
||||
|
||||
if (ip_service_type >= 0)
|
||||
packet->ip.tos = ip_service_type;
|
||||
else
|
||||
packet->ip.tos = IPTOS_CLASS_CS6;
|
||||
|
||||
packet->ip.protocol = IPPROTO_UDP;
|
||||
packet->ip.saddr = source_addr;
|
||||
packet->ip.daddr = destination_addr;
|
||||
|
||||
packet->udp.source = htobe16(source_port);
|
||||
packet->udp.dest = htobe16(destination_port);
|
||||
|
||||
packet->udp.len = htobe16(len - DHCP_IP_SIZE);
|
||||
|
||||
packet->ip.check = packet->udp.len;
|
||||
packet->udp.check = dhcp_packet_checksum((uint8_t*)&packet->ip.ttl, len - 8);
|
||||
|
||||
packet->ip.ttl = IPDEFTTL;
|
||||
packet->ip.check = 0;
|
||||
packet->ip.check = dhcp_packet_checksum((uint8_t*)&packet->ip, DHCP_IP_SIZE);
|
||||
}
|
||||
|
||||
int dhcp_packet_verify_headers(DHCPPacket *packet, size_t len, bool checksum, uint16_t port) {
|
||||
size_t hdrlen;
|
||||
|
||||
assert(packet);
|
||||
|
||||
/* IP */
|
||||
|
||||
if (packet->ip.version != IPVERSION)
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"ignoring packet: not IPv4");
|
||||
|
||||
if (packet->ip.ihl < 5)
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"ignoring packet: IPv4 IHL (%u words) invalid",
|
||||
packet->ip.ihl);
|
||||
|
||||
hdrlen = packet->ip.ihl * 4;
|
||||
if (hdrlen < 20)
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"ignoring packet: IPv4 IHL (%zu bytes) "
|
||||
"smaller than minimum (20 bytes)",
|
||||
hdrlen);
|
||||
|
||||
if (len < hdrlen)
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"ignoring packet: packet (%zu bytes) "
|
||||
"smaller than expected (%zu) by IP header",
|
||||
len, hdrlen);
|
||||
|
||||
/* UDP */
|
||||
|
||||
if (packet->ip.protocol != IPPROTO_UDP)
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"ignoring packet: not UDP");
|
||||
|
||||
if (len < hdrlen + be16toh(packet->udp.len))
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"ignoring packet: packet (%zu bytes) "
|
||||
"smaller than expected (%zu) by UDP header",
|
||||
len, hdrlen + be16toh(packet->udp.len));
|
||||
|
||||
if (be16toh(packet->udp.dest) != port)
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"ignoring packet: to port %u, which "
|
||||
"is not the DHCP client port (%u)",
|
||||
be16toh(packet->udp.dest), port);
|
||||
|
||||
/* checksums - computing these is relatively expensive, so only do it
|
||||
if all the other checks have passed
|
||||
*/
|
||||
|
||||
if (dhcp_packet_checksum((uint8_t*)&packet->ip, hdrlen))
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"ignoring packet: invalid IP checksum");
|
||||
|
||||
if (checksum && packet->udp.check) {
|
||||
packet->ip.check = packet->udp.len;
|
||||
packet->ip.ttl = 0;
|
||||
|
||||
if (dhcp_packet_checksum((uint8_t*)&packet->ip.ttl,
|
||||
be16toh(packet->udp.len) + 12))
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"ignoring packet: invalid UDP checksum");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -64,7 +64,7 @@ struct sd_dhcp6_client {
|
|||
struct duid duid;
|
||||
size_t duid_len;
|
||||
be16_t *req_opts;
|
||||
size_t req_opts_len;
|
||||
size_t n_req_opts;
|
||||
char *fqdn;
|
||||
char *mudurl;
|
||||
char **user_class;
|
||||
|
|
|
@ -51,18 +51,20 @@ bool dhcp6_option_can_request(uint16_t option) {
|
|||
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:
|
||||
case SD_DHCP6_OPTION_DNS_SERVER:
|
||||
case SD_DHCP6_OPTION_DOMAIN:
|
||||
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_SERVER:
|
||||
case SD_DHCP6_OPTION_NISP_SERVER:
|
||||
case SD_DHCP6_OPTION_NIS_DOMAIN_NAME:
|
||||
case SD_DHCP6_OPTION_NISP_DOMAIN_NAME:
|
||||
case SD_DHCP6_OPTION_SNTP_SERVERS:
|
||||
case SD_DHCP6_OPTION_SNTP_SERVER:
|
||||
return true;
|
||||
case SD_DHCP6_OPTION_INFORMATION_REFRESH_TIME:
|
||||
return false; /* This is automatically set when sending INFORMATION_REQUEST message. */
|
||||
case SD_DHCP6_OPTION_BCMCS_SERVER_D:
|
||||
case SD_DHCP6_OPTION_BCMCS_SERVER_A:
|
||||
case SD_DHCP6_OPTION_GEOCONF_CIVIC:
|
||||
|
@ -124,9 +126,9 @@ bool dhcp6_option_can_request(uint16_t option) {
|
|||
case SD_DHCP6_OPTION_CLIENT_LINKLAYER_ADDR:
|
||||
case SD_DHCP6_OPTION_LINK_ADDRESS:
|
||||
case SD_DHCP6_OPTION_RADIUS:
|
||||
case SD_DHCP6_OPTION_SOL_MAX_RT: /* Automatically set when sending SOLICIT message. */
|
||||
case SD_DHCP6_OPTION_INF_MAX_RT: /* Automatically set when sending INFORMATION_REQUEST message. */
|
||||
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:
|
||||
|
|
|
@ -116,6 +116,9 @@ sd_lldp_neighbor *lldp_neighbor_unlink(sd_lldp_neighbor *n) {
|
|||
sd_lldp_neighbor *lldp_neighbor_new(size_t raw_size) {
|
||||
sd_lldp_neighbor *n;
|
||||
|
||||
if (raw_size > SIZE_MAX - ALIGN(sizeof(sd_lldp_neighbor)))
|
||||
return NULL;
|
||||
|
||||
n = malloc0(ALIGN(sizeof(sd_lldp_neighbor)) + raw_size);
|
||||
if (!n)
|
||||
return NULL;
|
||||
|
@ -649,7 +652,8 @@ int sd_lldp_neighbor_from_raw(sd_lldp_neighbor **ret, const void *raw, size_t ra
|
|||
if (!n)
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy(LLDP_NEIGHBOR_RAW(n), raw, raw_size);
|
||||
memcpy_safe(LLDP_NEIGHBOR_RAW(n), raw, raw_size);
|
||||
|
||||
r = lldp_neighbor_parse(n);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
|
|
@ -1,241 +0,0 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <linux/if.h>
|
||||
#include <netinet/ether.h>
|
||||
|
||||
#include "sd-ndisc.h"
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "dhcp-lease-internal.h"
|
||||
#include "extract-word.h"
|
||||
#include "hexdecoct.h"
|
||||
#include "log.h"
|
||||
#include "network-internal.h"
|
||||
#include "parse-util.h"
|
||||
|
||||
size_t serialize_in_addrs(FILE *f,
|
||||
const struct in_addr *addresses,
|
||||
size_t size,
|
||||
bool *with_leading_space,
|
||||
bool (*predicate)(const struct in_addr *addr)) {
|
||||
assert(f);
|
||||
assert(addresses);
|
||||
|
||||
size_t count = 0;
|
||||
bool _space = false;
|
||||
if (!with_leading_space)
|
||||
with_leading_space = &_space;
|
||||
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
char sbuf[INET_ADDRSTRLEN];
|
||||
|
||||
if (predicate && !predicate(&addresses[i]))
|
||||
continue;
|
||||
|
||||
if (*with_leading_space)
|
||||
fputc(' ', f);
|
||||
fputs(inet_ntop(AF_INET, &addresses[i], sbuf, sizeof(sbuf)), f);
|
||||
count++;
|
||||
*with_leading_space = true;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
int deserialize_in_addrs(struct in_addr **ret, const char *string) {
|
||||
_cleanup_free_ struct in_addr *addresses = NULL;
|
||||
int size = 0;
|
||||
|
||||
assert(ret);
|
||||
assert(string);
|
||||
|
||||
for (;;) {
|
||||
_cleanup_free_ char *word = NULL;
|
||||
struct in_addr *new_addresses;
|
||||
int r;
|
||||
|
||||
r = extract_first_word(&string, &word, NULL, 0);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
break;
|
||||
|
||||
new_addresses = reallocarray(addresses, size + 1, sizeof(struct in_addr));
|
||||
if (!new_addresses)
|
||||
return -ENOMEM;
|
||||
else
|
||||
addresses = new_addresses;
|
||||
|
||||
r = inet_pton(AF_INET, word, &(addresses[size]));
|
||||
if (r <= 0)
|
||||
continue;
|
||||
|
||||
size++;
|
||||
}
|
||||
|
||||
*ret = size > 0 ? TAKE_PTR(addresses) : NULL;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
void serialize_in6_addrs(FILE *f, const struct in6_addr *addresses, size_t size, bool *with_leading_space) {
|
||||
assert(f);
|
||||
assert(addresses);
|
||||
assert(size);
|
||||
|
||||
bool _space = false;
|
||||
if (!with_leading_space)
|
||||
with_leading_space = &_space;
|
||||
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
char buffer[INET6_ADDRSTRLEN];
|
||||
|
||||
if (*with_leading_space)
|
||||
fputc(' ', f);
|
||||
fputs(inet_ntop(AF_INET6, addresses+i, buffer, sizeof(buffer)), f);
|
||||
*with_leading_space = true;
|
||||
}
|
||||
}
|
||||
|
||||
int deserialize_in6_addrs(struct in6_addr **ret, const char *string) {
|
||||
_cleanup_free_ struct in6_addr *addresses = NULL;
|
||||
int size = 0;
|
||||
|
||||
assert(ret);
|
||||
assert(string);
|
||||
|
||||
for (;;) {
|
||||
_cleanup_free_ char *word = NULL;
|
||||
struct in6_addr *new_addresses;
|
||||
int r;
|
||||
|
||||
r = extract_first_word(&string, &word, NULL, 0);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
break;
|
||||
|
||||
new_addresses = reallocarray(addresses, size + 1, sizeof(struct in6_addr));
|
||||
if (!new_addresses)
|
||||
return -ENOMEM;
|
||||
else
|
||||
addresses = new_addresses;
|
||||
|
||||
r = inet_pton(AF_INET6, word, &(addresses[size]));
|
||||
if (r <= 0)
|
||||
continue;
|
||||
|
||||
size++;
|
||||
}
|
||||
|
||||
*ret = TAKE_PTR(addresses);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
void serialize_dhcp_routes(FILE *f, const char *key, sd_dhcp_route **routes, size_t size) {
|
||||
assert(f);
|
||||
assert(key);
|
||||
assert(routes);
|
||||
assert(size);
|
||||
|
||||
fprintf(f, "%s=", key);
|
||||
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
char sbuf[INET_ADDRSTRLEN];
|
||||
struct in_addr dest, gw;
|
||||
uint8_t length;
|
||||
|
||||
assert_se(sd_dhcp_route_get_destination(routes[i], &dest) >= 0);
|
||||
assert_se(sd_dhcp_route_get_gateway(routes[i], &gw) >= 0);
|
||||
assert_se(sd_dhcp_route_get_destination_prefix_length(routes[i], &length) >= 0);
|
||||
|
||||
fprintf(f, "%s/%" PRIu8, inet_ntop(AF_INET, &dest, sbuf, sizeof sbuf), length);
|
||||
fprintf(f, ",%s%s", inet_ntop(AF_INET, &gw, sbuf, sizeof sbuf), i < size - 1 ? " ": "");
|
||||
}
|
||||
|
||||
fputs("\n", f);
|
||||
}
|
||||
|
||||
int deserialize_dhcp_routes(struct sd_dhcp_route **ret, size_t *ret_size, const char *string) {
|
||||
_cleanup_free_ struct sd_dhcp_route *routes = NULL;
|
||||
size_t size = 0;
|
||||
|
||||
assert(ret);
|
||||
assert(ret_size);
|
||||
assert(string);
|
||||
|
||||
/* WORD FORMAT: dst_ip/dst_prefixlen,gw_ip */
|
||||
for (;;) {
|
||||
_cleanup_free_ char *word = NULL;
|
||||
char *tok, *tok_end;
|
||||
unsigned n;
|
||||
int r;
|
||||
|
||||
r = extract_first_word(&string, &word, NULL, 0);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
break;
|
||||
|
||||
if (!GREEDY_REALLOC(routes, size + 1))
|
||||
return -ENOMEM;
|
||||
|
||||
tok = word;
|
||||
|
||||
/* get the subnet */
|
||||
tok_end = strchr(tok, '/');
|
||||
if (!tok_end)
|
||||
continue;
|
||||
*tok_end = '\0';
|
||||
|
||||
r = inet_aton(tok, &routes[size].dst_addr);
|
||||
if (r == 0)
|
||||
continue;
|
||||
|
||||
tok = tok_end + 1;
|
||||
|
||||
/* get the prefixlen */
|
||||
tok_end = strchr(tok, ',');
|
||||
if (!tok_end)
|
||||
continue;
|
||||
|
||||
*tok_end = '\0';
|
||||
|
||||
r = safe_atou(tok, &n);
|
||||
if (r < 0 || n > 32)
|
||||
continue;
|
||||
|
||||
routes[size].dst_prefixlen = (uint8_t) n;
|
||||
tok = tok_end + 1;
|
||||
|
||||
/* get the gateway */
|
||||
r = inet_aton(tok, &routes[size].gw_addr);
|
||||
if (r == 0)
|
||||
continue;
|
||||
|
||||
size++;
|
||||
}
|
||||
|
||||
*ret_size = size;
|
||||
*ret = TAKE_PTR(routes);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int serialize_dhcp_option(FILE *f, const char *key, const void *data, size_t size) {
|
||||
_cleanup_free_ char *hex_buf = NULL;
|
||||
|
||||
assert(f);
|
||||
assert(key);
|
||||
assert(data);
|
||||
|
||||
hex_buf = hexmem(data, size);
|
||||
if (!hex_buf)
|
||||
return -ENOMEM;
|
||||
|
||||
fprintf(f, "%s=%s\n", key, hex_buf);
|
||||
|
||||
return 0;
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -23,16 +23,10 @@
|
|||
#include "io-util.h"
|
||||
#include "random-util.h"
|
||||
#include "socket-util.h"
|
||||
#include "sort-util.h"
|
||||
#include "strv.h"
|
||||
#include "web-util.h"
|
||||
|
||||
static const uint16_t default_req_opts[] = {
|
||||
SD_DHCP6_OPTION_DNS_SERVERS,
|
||||
SD_DHCP6_OPTION_DOMAIN_LIST,
|
||||
SD_DHCP6_OPTION_NTP_SERVER,
|
||||
SD_DHCP6_OPTION_SNTP_SERVERS,
|
||||
};
|
||||
|
||||
#define DHCP6_CLIENT_DONT_DESTROY(client) \
|
||||
_cleanup_(sd_dhcp6_client_unrefp) _unused_ sd_dhcp6_client *_dont_destroy_##client = sd_dhcp6_client_ref(client)
|
||||
|
||||
|
@ -371,8 +365,12 @@ int sd_dhcp6_client_get_information_request(sd_dhcp6_client *client, int *enable
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int be16_compare_func(const be16_t *a, const be16_t *b) {
|
||||
return CMP(be16toh(*a), be16toh(*b));
|
||||
}
|
||||
|
||||
int sd_dhcp6_client_set_request_option(sd_dhcp6_client *client, uint16_t option) {
|
||||
size_t t;
|
||||
be16_t opt;
|
||||
|
||||
assert_return(client, -EINVAL);
|
||||
assert_return(!sd_dhcp6_client_is_running(client), -EBUSY);
|
||||
|
@ -380,15 +378,17 @@ int sd_dhcp6_client_set_request_option(sd_dhcp6_client *client, uint16_t option)
|
|||
if (!dhcp6_option_can_request(option))
|
||||
return -EINVAL;
|
||||
|
||||
for (t = 0; t < client->req_opts_len; t++)
|
||||
if (client->req_opts[t] == htobe16(option))
|
||||
return -EEXIST;
|
||||
opt = htobe16(option);
|
||||
if (typesafe_bsearch(&opt, client->req_opts, client->n_req_opts, be16_compare_func))
|
||||
return -EEXIST;
|
||||
|
||||
if (!GREEDY_REALLOC(client->req_opts, client->req_opts_len + 1))
|
||||
if (!GREEDY_REALLOC(client->req_opts, client->n_req_opts + 1))
|
||||
return -ENOMEM;
|
||||
|
||||
client->req_opts[client->req_opts_len++] = htobe16(option);
|
||||
client->req_opts[client->n_req_opts++] = opt;
|
||||
|
||||
/* Sort immediately to make the above binary search will work for the next time. */
|
||||
typesafe_qsort(client->req_opts, client->n_req_opts, be16_compare_func);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -635,6 +635,51 @@ static DHCP6MessageType client_message_type_from_state(sd_dhcp6_client *client)
|
|||
}
|
||||
}
|
||||
|
||||
static int client_append_oro(sd_dhcp6_client *client, uint8_t **opt, size_t *optlen) {
|
||||
_cleanup_free_ be16_t *buf = NULL;
|
||||
be16_t *req_opts;
|
||||
size_t n;
|
||||
|
||||
assert(client);
|
||||
assert(opt);
|
||||
assert(optlen);
|
||||
|
||||
switch (client->state) {
|
||||
case DHCP6_STATE_INFORMATION_REQUEST:
|
||||
n = client->n_req_opts;
|
||||
buf = new(be16_t, n + 2);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy_safe(buf, client->req_opts, n * sizeof(be16_t));
|
||||
buf[n++] = htobe16(SD_DHCP6_OPTION_INFORMATION_REFRESH_TIME); /* RFC 8415 section 21.23 */
|
||||
buf[n++] = htobe16(SD_DHCP6_OPTION_INF_MAX_RT); /* RFC 8415 section 21.25 */
|
||||
|
||||
typesafe_qsort(buf, n, be16_compare_func);
|
||||
req_opts = buf;
|
||||
break;
|
||||
|
||||
case DHCP6_STATE_SOLICITATION:
|
||||
n = client->n_req_opts;
|
||||
buf = new(be16_t, n + 1);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy_safe(buf, client->req_opts, n * sizeof(be16_t));
|
||||
buf[n++] = htobe16(SD_DHCP6_OPTION_SOL_MAX_RT); /* RFC 8415 section 21.24 */
|
||||
|
||||
typesafe_qsort(buf, n, be16_compare_func);
|
||||
req_opts = buf;
|
||||
break;
|
||||
|
||||
default:
|
||||
n = client->n_req_opts;
|
||||
req_opts = client->req_opts;
|
||||
}
|
||||
|
||||
return dhcp6_option_append(opt, optlen, SD_DHCP6_OPTION_ORO, n * sizeof(be16_t), req_opts);
|
||||
}
|
||||
|
||||
int dhcp6_client_send_message(sd_dhcp6_client *client) {
|
||||
_cleanup_free_ DHCP6Message *message = NULL;
|
||||
struct in6_addr all_servers =
|
||||
|
@ -712,9 +757,7 @@ int dhcp6_client_send_message(sd_dhcp6_client *client) {
|
|||
return r;
|
||||
}
|
||||
|
||||
r = dhcp6_option_append(&opt, &optlen, SD_DHCP6_OPTION_ORO,
|
||||
client->req_opts_len * sizeof(be16_t),
|
||||
client->req_opts);
|
||||
r = client_append_oro(client, &opt, &optlen);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
@ -1301,13 +1344,10 @@ int sd_dhcp6_client_start(sd_dhcp6_client *client) {
|
|||
|
||||
if (client->fd < 0) {
|
||||
r = dhcp6_network_bind_udp_socket(client->ifindex, &client->local_address);
|
||||
if (r < 0) {
|
||||
_cleanup_free_ char *p = NULL;
|
||||
|
||||
(void) in6_addr_to_string(&client->local_address, &p);
|
||||
if (r < 0)
|
||||
return log_dhcp6_client_errno(client, r,
|
||||
"Failed to bind to UDP socket at address %s: %m", strna(p));
|
||||
}
|
||||
"Failed to bind to UDP socket at address %s: %m",
|
||||
IN6_ADDR_TO_STRING(&client->local_address));
|
||||
|
||||
client->fd = r;
|
||||
}
|
||||
|
@ -1341,7 +1381,7 @@ int sd_dhcp6_client_start(sd_dhcp6_client *client) {
|
|||
}
|
||||
|
||||
log_dhcp6_client(client, "Starting in %s mode",
|
||||
client->information_request ? "Information request" : "Managed");
|
||||
client->information_request ? "Information request" : "Solicit");
|
||||
|
||||
return client_start_transaction(client, state);
|
||||
}
|
||||
|
@ -1413,18 +1453,9 @@ DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_dhcp6_client, sd_dhcp6_client, dhcp6_client_fre
|
|||
|
||||
int sd_dhcp6_client_new(sd_dhcp6_client **ret) {
|
||||
_cleanup_(sd_dhcp6_client_unrefp) sd_dhcp6_client *client = NULL;
|
||||
_cleanup_free_ be16_t *req_opts = NULL;
|
||||
size_t t;
|
||||
|
||||
assert_return(ret, -EINVAL);
|
||||
|
||||
req_opts = new(be16_t, ELEMENTSOF(default_req_opts));
|
||||
if (!req_opts)
|
||||
return -ENOMEM;
|
||||
|
||||
for (t = 0; t < ELEMENTSOF(default_req_opts); t++)
|
||||
req_opts[t] = htobe16(default_req_opts[t]);
|
||||
|
||||
client = new(sd_dhcp6_client, 1);
|
||||
if (!client)
|
||||
return -ENOMEM;
|
||||
|
@ -1436,8 +1467,6 @@ int sd_dhcp6_client_new(sd_dhcp6_client **ret) {
|
|||
.ifindex = -1,
|
||||
.request_ia = DHCP6_REQUEST_IA_NA | DHCP6_REQUEST_IA_PD,
|
||||
.fd = -1,
|
||||
.req_opts_len = ELEMENTSOF(default_req_opts),
|
||||
.req_opts = TAKE_PTR(req_opts),
|
||||
};
|
||||
|
||||
*ret = TAKE_PTR(client);
|
||||
|
|
|
@ -570,14 +570,14 @@ static int dhcp6_lease_parse_message(
|
|||
|
||||
break;
|
||||
|
||||
case SD_DHCP6_OPTION_DNS_SERVERS:
|
||||
case SD_DHCP6_OPTION_DNS_SERVER:
|
||||
r = dhcp6_lease_add_dns(lease, optval, optlen);
|
||||
if (r < 0)
|
||||
log_dhcp6_client_errno(client, r, "Failed to parse DNS server option, ignoring: %m");
|
||||
|
||||
break;
|
||||
|
||||
case SD_DHCP6_OPTION_DOMAIN_LIST:
|
||||
case SD_DHCP6_OPTION_DOMAIN:
|
||||
r = dhcp6_lease_add_domains(lease, optval, optlen);
|
||||
if (r < 0)
|
||||
log_dhcp6_client_errno(client, r, "Failed to parse domain list option, ignoring: %m");
|
||||
|
@ -591,7 +591,7 @@ static int dhcp6_lease_parse_message(
|
|||
|
||||
break;
|
||||
|
||||
case SD_DHCP6_OPTION_SNTP_SERVERS:
|
||||
case SD_DHCP6_OPTION_SNTP_SERVER:
|
||||
r = dhcp6_lease_add_sntp(lease, optval, optlen);
|
||||
if (r < 0)
|
||||
log_dhcp6_client_errno(client, r, "Failed to parse SNTP server option, ignoring: %m");
|
||||
|
|
|
@ -1,380 +0,0 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
/***
|
||||
Copyright © 2014 Axis Communications AB. All rights reserved.
|
||||
***/
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "sd-id128.h"
|
||||
#include "sd-ipv4acd.h"
|
||||
#include "sd-ipv4ll.h"
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "ether-addr-util.h"
|
||||
#include "in-addr-util.h"
|
||||
#include "network-common.h"
|
||||
#include "random-util.h"
|
||||
#include "siphash24.h"
|
||||
#include "sparse-endian.h"
|
||||
#include "string-util.h"
|
||||
#include "util.h"
|
||||
|
||||
#define IPV4LL_NETWORK UINT32_C(0xA9FE0000)
|
||||
#define IPV4LL_NETMASK UINT32_C(0xFFFF0000)
|
||||
|
||||
#define IPV4LL_DONT_DESTROY(ll) \
|
||||
_cleanup_(sd_ipv4ll_unrefp) _unused_ sd_ipv4ll *_dont_destroy_##ll = sd_ipv4ll_ref(ll)
|
||||
|
||||
struct sd_ipv4ll {
|
||||
unsigned n_ref;
|
||||
|
||||
sd_ipv4acd *acd;
|
||||
|
||||
be32_t address; /* the address pushed to ACD */
|
||||
struct ether_addr mac;
|
||||
|
||||
struct {
|
||||
le64_t value;
|
||||
le64_t generation;
|
||||
} seed;
|
||||
bool seed_set;
|
||||
|
||||
/* External */
|
||||
be32_t claimed_address;
|
||||
|
||||
sd_ipv4ll_callback_t callback;
|
||||
void *userdata;
|
||||
|
||||
sd_ipv4ll_check_mac_callback_t check_mac_callback;
|
||||
void *check_mac_userdata;
|
||||
};
|
||||
|
||||
#define log_ipv4ll_errno(ll, error, fmt, ...) \
|
||||
log_interface_prefix_full_errno( \
|
||||
"IPv4LL: ", \
|
||||
sd_ipv4ll, ll, \
|
||||
error, fmt, ##__VA_ARGS__)
|
||||
#define log_ipv4ll(ll, fmt, ...) \
|
||||
log_interface_prefix_full_errno_zerook( \
|
||||
"IPv4LL: ", \
|
||||
sd_ipv4ll, ll, \
|
||||
0, fmt, ##__VA_ARGS__)
|
||||
|
||||
static void ipv4ll_on_acd(sd_ipv4acd *acd, int event, void *userdata);
|
||||
static int ipv4ll_check_mac(sd_ipv4acd *acd, const struct ether_addr *mac, void *userdata);
|
||||
|
||||
static sd_ipv4ll *ipv4ll_free(sd_ipv4ll *ll) {
|
||||
assert(ll);
|
||||
|
||||
sd_ipv4acd_unref(ll->acd);
|
||||
return mfree(ll);
|
||||
}
|
||||
|
||||
DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_ipv4ll, sd_ipv4ll, ipv4ll_free);
|
||||
|
||||
int sd_ipv4ll_new(sd_ipv4ll **ret) {
|
||||
_cleanup_(sd_ipv4ll_unrefp) sd_ipv4ll *ll = NULL;
|
||||
int r;
|
||||
|
||||
assert_return(ret, -EINVAL);
|
||||
|
||||
ll = new0(sd_ipv4ll, 1);
|
||||
if (!ll)
|
||||
return -ENOMEM;
|
||||
|
||||
ll->n_ref = 1;
|
||||
|
||||
r = sd_ipv4acd_new(&ll->acd);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_ipv4acd_set_callback(ll->acd, ipv4ll_on_acd, ll);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_ipv4acd_set_check_mac_callback(ll->acd, ipv4ll_check_mac, ll);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
*ret = TAKE_PTR(ll);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_ipv4ll_stop(sd_ipv4ll *ll) {
|
||||
if (!ll)
|
||||
return 0;
|
||||
|
||||
return sd_ipv4acd_stop(ll->acd);
|
||||
}
|
||||
|
||||
int sd_ipv4ll_set_ifindex(sd_ipv4ll *ll, int ifindex) {
|
||||
assert_return(ll, -EINVAL);
|
||||
assert_return(ifindex > 0, -EINVAL);
|
||||
assert_return(sd_ipv4ll_is_running(ll) == 0, -EBUSY);
|
||||
|
||||
return sd_ipv4acd_set_ifindex(ll->acd, ifindex);
|
||||
}
|
||||
|
||||
int sd_ipv4ll_get_ifindex(sd_ipv4ll *ll) {
|
||||
if (!ll)
|
||||
return -EINVAL;
|
||||
|
||||
return sd_ipv4acd_get_ifindex(ll->acd);
|
||||
}
|
||||
|
||||
int sd_ipv4ll_set_ifname(sd_ipv4ll *ll, const char *ifname) {
|
||||
assert_return(ll, -EINVAL);
|
||||
assert_return(ifname, -EINVAL);
|
||||
|
||||
return sd_ipv4acd_set_ifname(ll->acd, ifname);
|
||||
}
|
||||
|
||||
int sd_ipv4ll_get_ifname(sd_ipv4ll *ll, const char **ret) {
|
||||
assert_return(ll, -EINVAL);
|
||||
|
||||
return sd_ipv4acd_get_ifname(ll->acd, ret);
|
||||
}
|
||||
|
||||
int sd_ipv4ll_set_mac(sd_ipv4ll *ll, const struct ether_addr *addr) {
|
||||
int r;
|
||||
|
||||
assert_return(ll, -EINVAL);
|
||||
assert_return(addr, -EINVAL);
|
||||
assert_return(!ether_addr_is_null(addr), -EINVAL);
|
||||
|
||||
r = sd_ipv4acd_set_mac(ll->acd, addr);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
ll->mac = *addr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_ipv4ll_detach_event(sd_ipv4ll *ll) {
|
||||
assert_return(ll, -EINVAL);
|
||||
|
||||
return sd_ipv4acd_detach_event(ll->acd);
|
||||
}
|
||||
|
||||
int sd_ipv4ll_attach_event(sd_ipv4ll *ll, sd_event *event, int64_t priority) {
|
||||
assert_return(ll, -EINVAL);
|
||||
|
||||
return sd_ipv4acd_attach_event(ll->acd, event, priority);
|
||||
}
|
||||
|
||||
int sd_ipv4ll_set_callback(sd_ipv4ll *ll, sd_ipv4ll_callback_t cb, void *userdata) {
|
||||
assert_return(ll, -EINVAL);
|
||||
|
||||
ll->callback = cb;
|
||||
ll->userdata = userdata;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_ipv4ll_set_check_mac_callback(sd_ipv4ll *ll, sd_ipv4ll_check_mac_callback_t cb, void *userdata) {
|
||||
assert_return(ll, -EINVAL);
|
||||
|
||||
ll->check_mac_callback = cb;
|
||||
ll->check_mac_userdata = userdata;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_ipv4ll_get_address(sd_ipv4ll *ll, struct in_addr *address) {
|
||||
assert_return(ll, -EINVAL);
|
||||
assert_return(address, -EINVAL);
|
||||
|
||||
if (ll->claimed_address == 0)
|
||||
return -ENOENT;
|
||||
|
||||
address->s_addr = ll->claimed_address;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_ipv4ll_set_address_seed(sd_ipv4ll *ll, uint64_t seed) {
|
||||
assert_return(ll, -EINVAL);
|
||||
assert_return(sd_ipv4ll_is_running(ll) == 0, -EBUSY);
|
||||
|
||||
ll->seed.value = htole64(seed);
|
||||
ll->seed_set = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_ipv4ll_is_running(sd_ipv4ll *ll) {
|
||||
assert_return(ll, false);
|
||||
|
||||
return sd_ipv4acd_is_running(ll->acd);
|
||||
}
|
||||
|
||||
static bool ipv4ll_address_is_valid(const struct in_addr *address) {
|
||||
assert(address);
|
||||
|
||||
if (!in4_addr_is_link_local(address))
|
||||
return false;
|
||||
|
||||
return !IN_SET(be32toh(address->s_addr) & 0x0000FF00U, 0x0000U, 0xFF00U);
|
||||
}
|
||||
|
||||
int sd_ipv4ll_set_address(sd_ipv4ll *ll, const struct in_addr *address) {
|
||||
int r;
|
||||
|
||||
assert_return(ll, -EINVAL);
|
||||
assert_return(address, -EINVAL);
|
||||
assert_return(ipv4ll_address_is_valid(address), -EINVAL);
|
||||
|
||||
r = sd_ipv4acd_set_address(ll->acd, address);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
ll->address = address->s_addr;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define PICK_HASH_KEY SD_ID128_MAKE(15,ac,82,a6,d6,3f,49,78,98,77,5d,0c,69,02,94,0b)
|
||||
|
||||
static int ipv4ll_pick_address(sd_ipv4ll *ll) {
|
||||
_cleanup_free_ char *address = NULL;
|
||||
be32_t addr;
|
||||
|
||||
assert(ll);
|
||||
|
||||
do {
|
||||
uint64_t h;
|
||||
|
||||
h = siphash24(&ll->seed, sizeof(ll->seed), PICK_HASH_KEY.bytes);
|
||||
|
||||
/* Increase the generation counter by one */
|
||||
ll->seed.generation = htole64(le64toh(ll->seed.generation) + 1);
|
||||
|
||||
addr = htobe32((h & UINT32_C(0x0000FFFF)) | IPV4LL_NETWORK);
|
||||
} while (addr == ll->address ||
|
||||
IN_SET(be32toh(addr) & 0x0000FF00U, 0x0000U, 0xFF00U));
|
||||
|
||||
(void) in_addr_to_string(AF_INET, &(union in_addr_union) { .in.s_addr = addr }, &address);
|
||||
log_ipv4ll(ll, "Picked new IP address %s.", strna(address));
|
||||
|
||||
return sd_ipv4ll_set_address(ll, &(struct in_addr) { addr });
|
||||
}
|
||||
|
||||
#define MAC_HASH_KEY SD_ID128_MAKE(df,04,22,98,3f,ad,14,52,f9,87,2e,d1,9c,70,e2,f2)
|
||||
|
||||
static int ipv4ll_start_internal(sd_ipv4ll *ll, bool reset_generation) {
|
||||
int r;
|
||||
bool picked_address = false;
|
||||
|
||||
assert_return(ll, -EINVAL);
|
||||
assert_return(!ether_addr_is_null(&ll->mac), -EINVAL);
|
||||
|
||||
/* If no random seed is set, generate some from the MAC address */
|
||||
if (!ll->seed_set)
|
||||
ll->seed.value = htole64(siphash24(ll->mac.ether_addr_octet, ETH_ALEN, MAC_HASH_KEY.bytes));
|
||||
|
||||
if (reset_generation)
|
||||
ll->seed.generation = 0;
|
||||
|
||||
if (ll->address == 0) {
|
||||
r = ipv4ll_pick_address(ll);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
picked_address = true;
|
||||
}
|
||||
|
||||
r = sd_ipv4acd_start(ll->acd, reset_generation);
|
||||
if (r < 0) {
|
||||
|
||||
/* We couldn't start? If so, let's forget the picked address again, the user might make a change and
|
||||
* retry, and we want the new data to take effect when picking an address. */
|
||||
if (picked_address)
|
||||
ll->address = 0;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int sd_ipv4ll_start(sd_ipv4ll *ll) {
|
||||
assert_return(ll, -EINVAL);
|
||||
|
||||
if (sd_ipv4ll_is_running(ll))
|
||||
return 0;
|
||||
|
||||
return ipv4ll_start_internal(ll, true);
|
||||
}
|
||||
|
||||
int sd_ipv4ll_restart(sd_ipv4ll *ll) {
|
||||
ll->address = 0;
|
||||
|
||||
return ipv4ll_start_internal(ll, false);
|
||||
}
|
||||
|
||||
static void ipv4ll_client_notify(sd_ipv4ll *ll, int event) {
|
||||
assert(ll);
|
||||
|
||||
if (ll->callback)
|
||||
ll->callback(ll, event, ll->userdata);
|
||||
}
|
||||
|
||||
void ipv4ll_on_acd(sd_ipv4acd *acd, int event, void *userdata) {
|
||||
sd_ipv4ll *ll = userdata;
|
||||
IPV4LL_DONT_DESTROY(ll);
|
||||
int r;
|
||||
|
||||
assert(acd);
|
||||
assert(ll);
|
||||
|
||||
switch (event) {
|
||||
|
||||
case SD_IPV4ACD_EVENT_STOP:
|
||||
ipv4ll_client_notify(ll, SD_IPV4LL_EVENT_STOP);
|
||||
ll->claimed_address = 0;
|
||||
break;
|
||||
|
||||
case SD_IPV4ACD_EVENT_BIND:
|
||||
ll->claimed_address = ll->address;
|
||||
ipv4ll_client_notify(ll, SD_IPV4LL_EVENT_BIND);
|
||||
break;
|
||||
|
||||
case SD_IPV4ACD_EVENT_CONFLICT:
|
||||
/* if an address was already bound we must call up to the
|
||||
user to handle this, otherwise we just try again */
|
||||
if (ll->claimed_address != 0) {
|
||||
ipv4ll_client_notify(ll, SD_IPV4LL_EVENT_CONFLICT);
|
||||
|
||||
ll->claimed_address = 0;
|
||||
} else {
|
||||
r = sd_ipv4ll_restart(ll);
|
||||
if (r < 0)
|
||||
goto error;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
assert_not_reached();
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
error:
|
||||
ipv4ll_client_notify(ll, SD_IPV4LL_EVENT_STOP);
|
||||
}
|
||||
|
||||
static int ipv4ll_check_mac(sd_ipv4acd *acd, const struct ether_addr *mac, void *userdata) {
|
||||
sd_ipv4ll *ll = userdata;
|
||||
|
||||
assert(ll);
|
||||
|
||||
if (ll->check_mac_callback)
|
||||
return ll->check_mac_callback(ll, mac, ll->check_mac_userdata);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -109,20 +109,6 @@ int event_reset_time_relative(
|
|||
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;
|
||||
|
||||
return sd_event_source_set_enabled(s, SD_EVENT_OFF);
|
||||
}
|
||||
|
||||
int event_source_is_enabled(sd_event_source *s) {
|
||||
if (!s)
|
||||
return false;
|
||||
|
||||
return sd_event_source_get_enabled(s, NULL);
|
||||
}
|
||||
|
||||
int event_add_time_change(sd_event *e, sd_event_source **ret, sd_event_io_handler_t callback, void *userdata) {
|
||||
_cleanup_(sd_event_source_unrefp) sd_event_source *s = NULL;
|
||||
_cleanup_close_ int fd = -1;
|
||||
|
|
|
@ -27,7 +27,8 @@ int event_reset_time_relative(
|
|||
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);
|
||||
static inline int event_source_disable(sd_event_source *s) {
|
||||
return sd_event_source_set_enabled(s, SD_EVENT_OFF);
|
||||
}
|
||||
|
||||
int event_add_time_change(sd_event *e, sd_event_source **ret, sd_event_io_handler_t callback, void *userdata);
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "event-source.h"
|
||||
#include "fd-util.h"
|
||||
#include "fs-util.h"
|
||||
#include "glyph-util.h"
|
||||
#include "hashmap.h"
|
||||
#include "list.h"
|
||||
#include "macro.h"
|
||||
|
@ -405,7 +406,8 @@ _public_ int sd_event_new(sd_event** ret) {
|
|||
e->epoll_fd = fd_move_above_stdio(e->epoll_fd);
|
||||
|
||||
if (secure_getenv("SD_EVENT_PROFILE_DELAYS")) {
|
||||
log_debug("Event loop profiling enabled. Logarithmic histogram of event loop iterations in the range 2^0 … 2^63 us will be logged every 5s.");
|
||||
log_debug("Event loop profiling enabled. Logarithmic histogram of event loop iterations in the range 2^0 %s 2^63 us will be logged every 5s.",
|
||||
special_glyph(SPECIAL_GLYPH_ELLIPSIS));
|
||||
e->profile_delays = true;
|
||||
}
|
||||
|
||||
|
@ -706,6 +708,9 @@ static void event_unmask_signal_data(sd_event *e, struct signal_data *d, int sig
|
|||
return;
|
||||
}
|
||||
|
||||
if (event_pid_changed(e))
|
||||
return;
|
||||
|
||||
assert(d->fd >= 0);
|
||||
|
||||
if (signalfd(d->fd, &d->sigset, SFD_NONBLOCK|SFD_CLOEXEC) < 0)
|
||||
|
@ -851,6 +856,9 @@ static void source_disconnect(sd_event_source *s) {
|
|||
break;
|
||||
|
||||
case SOURCE_CHILD:
|
||||
if (event_pid_changed(s->event))
|
||||
s->child.process_owned = false;
|
||||
|
||||
if (s->child.pid > 0) {
|
||||
if (event_source_is_online(s)) {
|
||||
assert(s->event->n_online_child_sources > 0);
|
||||
|
@ -1426,7 +1434,6 @@ _public_ int sd_event_add_child(
|
|||
return -ENOMEM;
|
||||
|
||||
s->wakeup = WAKEUP_EVENT_SOURCE;
|
||||
s->child.pid = pid;
|
||||
s->child.options = options;
|
||||
s->child.callback = callback;
|
||||
s->userdata = userdata;
|
||||
|
@ -1436,7 +1443,7 @@ _public_ int sd_event_add_child(
|
|||
* pin the PID, and make regular waitid() handling race-free. */
|
||||
|
||||
if (shall_use_pidfd()) {
|
||||
s->child.pidfd = pidfd_open(s->child.pid, 0);
|
||||
s->child.pidfd = pidfd_open(pid, 0);
|
||||
if (s->child.pidfd < 0) {
|
||||
/* Propagate errors unless the syscall is not supported or blocked */
|
||||
if (!ERRNO_IS_NOT_SUPPORTED(errno) && !ERRNO_IS_PRIVILEGE(errno))
|
||||
|
@ -1446,10 +1453,6 @@ _public_ int sd_event_add_child(
|
|||
} else
|
||||
s->child.pidfd = -1;
|
||||
|
||||
r = hashmap_put(e->child_sources, PID_TO_PTR(pid), s);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (EVENT_SOURCE_WATCH_PIDFD(s)) {
|
||||
/* We have a pidfd and we only want to watch for exit */
|
||||
r = source_child_pidfd_register(s, s->enabled);
|
||||
|
@ -1465,6 +1468,12 @@ _public_ int sd_event_add_child(
|
|||
e->need_process_child = true;
|
||||
}
|
||||
|
||||
r = hashmap_put(e->child_sources, PID_TO_PTR(pid), s);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* These must be done after everything succeeds. */
|
||||
s->child.pid = pid;
|
||||
e->n_online_child_sources++;
|
||||
|
||||
if (ret)
|
||||
|
@ -1691,7 +1700,8 @@ static void event_free_inotify_data(sd_event *e, struct inotify_data *d) {
|
|||
assert_se(hashmap_remove(e->inotify_data, &d->priority) == d);
|
||||
|
||||
if (d->fd >= 0) {
|
||||
if (epoll_ctl(e->epoll_fd, EPOLL_CTL_DEL, d->fd, NULL) < 0)
|
||||
if (!event_pid_changed(e) &&
|
||||
epoll_ctl(e->epoll_fd, EPOLL_CTL_DEL, d->fd, NULL) < 0)
|
||||
log_debug_errno(errno, "Failed to remove inotify fd from epoll, ignoring: %m");
|
||||
|
||||
safe_close(d->fd);
|
||||
|
@ -1791,7 +1801,7 @@ static void event_free_inode_data(
|
|||
if (!d)
|
||||
return;
|
||||
|
||||
assert(!d->event_sources);
|
||||
assert(LIST_IS_EMPTY(d->event_sources));
|
||||
|
||||
if (d->fd >= 0) {
|
||||
LIST_REMOVE(to_close, e->inode_data_to_close, d);
|
||||
|
@ -1801,7 +1811,7 @@ static void event_free_inode_data(
|
|||
if (d->inotify_data) {
|
||||
|
||||
if (d->wd >= 0) {
|
||||
if (d->inotify_data->fd >= 0) {
|
||||
if (d->inotify_data->fd >= 0 && !event_pid_changed(e)) {
|
||||
/* So here's a problem. At the time this runs the watch descriptor might already be
|
||||
* invalidated, because an IN_IGNORED event might be queued right the moment we enter
|
||||
* the syscall. Hence, whenever we get EINVAL, ignore it entirely, since it's a very
|
||||
|
@ -1854,7 +1864,7 @@ static void event_gc_inode_data(
|
|||
if (!d)
|
||||
return;
|
||||
|
||||
if (d->event_sources)
|
||||
if (!LIST_IS_EMPTY(d->event_sources))
|
||||
return;
|
||||
|
||||
inotify_data = d->inotify_data;
|
||||
|
@ -2403,6 +2413,10 @@ fail:
|
|||
}
|
||||
|
||||
_public_ int sd_event_source_get_enabled(sd_event_source *s, int *ret) {
|
||||
/* Quick mode: the event source doesn't exist and we only want to query boolean enablement state. */
|
||||
if (!s && !ret)
|
||||
return false;
|
||||
|
||||
assert_return(s, -EINVAL);
|
||||
assert_return(!event_pid_changed(s->event), -ECHILD);
|
||||
|
||||
|
@ -2580,8 +2594,13 @@ static int event_source_online(
|
|||
_public_ int sd_event_source_set_enabled(sd_event_source *s, int m) {
|
||||
int r;
|
||||
|
||||
assert_return(s, -EINVAL);
|
||||
assert_return(IN_SET(m, SD_EVENT_OFF, SD_EVENT_ON, SD_EVENT_ONESHOT), -EINVAL);
|
||||
|
||||
/* Quick mode: if the source doesn't exist, SD_EVENT_OFF is a noop. */
|
||||
if (m == SD_EVENT_OFF && !s)
|
||||
return 0;
|
||||
|
||||
assert_return(s, -EINVAL);
|
||||
assert_return(!event_pid_changed(s->event), -ECHILD);
|
||||
|
||||
/* If we are dead anyway, we are fine with turning off sources, but everything else needs to fail. */
|
||||
|
@ -3218,23 +3237,16 @@ static int process_child(sd_event *e, int64_t threshold, int64_t *ret_min_priori
|
|||
|
||||
e->need_process_child = false;
|
||||
|
||||
/*
|
||||
So, this is ugly. We iteratively invoke waitid() with P_PID
|
||||
+ WNOHANG for each PID we wait for, instead of using
|
||||
P_ALL. This is because we only want to get child
|
||||
information of very specific child processes, and not all
|
||||
of them. We might not have processed the SIGCHLD even of a
|
||||
previous invocation and we don't want to maintain a
|
||||
unbounded *per-child* event queue, hence we really don't
|
||||
want anything flushed out of the kernel's queue that we
|
||||
don't care about. Since this is O(n) this means that if you
|
||||
have a lot of processes you probably want to handle SIGCHLD
|
||||
yourself.
|
||||
|
||||
We do not reap the children here (by using WNOWAIT), this
|
||||
is only done after the event source is dispatched so that
|
||||
the callback still sees the process as a zombie.
|
||||
*/
|
||||
/* So, this is ugly. We iteratively invoke waitid() with P_PID + WNOHANG for each PID we wait
|
||||
* for, instead of using P_ALL. This is because we only want to get child information of very
|
||||
* specific child processes, and not all of them. We might not have processed the SIGCHLD event
|
||||
* of a previous invocation and we don't want to maintain a unbounded *per-child* event queue,
|
||||
* hence we really don't want anything flushed out of the kernel's queue that we don't care
|
||||
* about. Since this is O(n) this means that if you have a lot of processes you probably want
|
||||
* to handle SIGCHLD yourself.
|
||||
*
|
||||
* We do not reap the children here (by using WNOWAIT), this is only done after the event
|
||||
* source is dispatched so that the callback still sees the process as a zombie. */
|
||||
|
||||
HASHMAP_FOREACH(s, e->child_sources) {
|
||||
assert(s->type == SOURCE_CHILD);
|
||||
|
@ -3251,7 +3263,9 @@ static int process_child(sd_event *e, int64_t threshold, int64_t *ret_min_priori
|
|||
if (s->child.exited)
|
||||
continue;
|
||||
|
||||
if (EVENT_SOURCE_WATCH_PIDFD(s)) /* There's a usable pidfd known for this event source? then don't waitid() for it here */
|
||||
if (EVENT_SOURCE_WATCH_PIDFD(s))
|
||||
/* There's a usable pidfd known for this event source? Then don't waitid() for
|
||||
* it here */
|
||||
continue;
|
||||
|
||||
zero(s->child.siginfo);
|
||||
|
@ -3266,10 +3280,9 @@ static int process_child(sd_event *e, int64_t threshold, int64_t *ret_min_priori
|
|||
s->child.exited = true;
|
||||
|
||||
if (!zombie && (s->child.options & WEXITED)) {
|
||||
/* If the child isn't dead then let's
|
||||
* immediately remove the state change
|
||||
* from the queue, since there's no
|
||||
* benefit in leaving it queued */
|
||||
/* If the child isn't dead then let's immediately remove the state
|
||||
* change from the queue, since there's no benefit in leaving it
|
||||
* queued. */
|
||||
|
||||
assert(s->child.options & (WSTOPPED|WCONTINUED));
|
||||
(void) waitid(P_PID, s->child.pid, &s->child.siginfo, WNOHANG|(s->child.options & (WSTOPPED|WCONTINUED)));
|
||||
|
@ -3324,19 +3337,16 @@ static int process_signal(sd_event *e, struct signal_data *d, uint32_t events, i
|
|||
assert_return(events == EPOLLIN, -EIO);
|
||||
assert(min_priority);
|
||||
|
||||
/* If there's a signal queued on this priority and SIGCHLD is
|
||||
on this priority too, then make sure to recheck the
|
||||
children we watch. This is because we only ever dequeue
|
||||
the first signal per priority, and if we dequeue one, and
|
||||
SIGCHLD might be enqueued later we wouldn't know, but we
|
||||
might have higher priority children we care about hence we
|
||||
need to check that explicitly. */
|
||||
/* If there's a signal queued on this priority and SIGCHLD is on this priority too, then make
|
||||
* sure to recheck the children we watch. This is because we only ever dequeue the first signal
|
||||
* per priority, and if we dequeue one, and SIGCHLD might be enqueued later we wouldn't know,
|
||||
* but we might have higher priority children we care about hence we need to check that
|
||||
* explicitly. */
|
||||
|
||||
if (sigismember(&d->sigset, SIGCHLD))
|
||||
e->need_process_child = true;
|
||||
|
||||
/* If there's already an event source pending for this
|
||||
* priority we don't read another */
|
||||
/* If there's already an event source pending for this priority we don't read another */
|
||||
if (d->current)
|
||||
return 0;
|
||||
|
||||
|
@ -3875,7 +3885,7 @@ _public_ int sd_event_prepare(sd_event *e) {
|
|||
|
||||
event_close_inode_data_fds(e);
|
||||
|
||||
if (event_next_pending(e) || e->need_process_child)
|
||||
if (event_next_pending(e) || e->need_process_child || !LIST_IS_EMPTY(e->inotify_data_buffered))
|
||||
goto pending;
|
||||
|
||||
e->state = SD_EVENT_ARMED;
|
||||
|
@ -3955,7 +3965,7 @@ static int process_epoll(sd_event *e, usec_t timeout, int64_t threshold, int64_t
|
|||
n_event_max = MALLOC_ELEMENTSOF(e->event_queue);
|
||||
|
||||
/* If we still have inotify data buffered, then query the other fds, but don't wait on it */
|
||||
if (e->inotify_data_buffered)
|
||||
if (!LIST_IS_EMPTY(e->inotify_data_buffered))
|
||||
timeout = 0;
|
||||
|
||||
for (;;) {
|
||||
|
|
|
@ -25,9 +25,9 @@ bool id128_is_valid(const char *s) {
|
|||
for (i = 0; i < l; i++) {
|
||||
char c = s[i];
|
||||
|
||||
if (!(c >= '0' && c <= '9') &&
|
||||
!(c >= 'a' && c <= 'z') &&
|
||||
!(c >= 'A' && c <= 'Z'))
|
||||
if (!ascii_isdigit(c) &&
|
||||
!(c >= 'a' && c <= 'f') &&
|
||||
!(c >= 'A' && c <= 'F'))
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -42,9 +42,9 @@ bool id128_is_valid(const char *s) {
|
|||
if (c != '-')
|
||||
return false;
|
||||
} else {
|
||||
if (!(c >= '0' && c <= '9') &&
|
||||
!(c >= 'a' && c <= 'z') &&
|
||||
!(c >= 'A' && c <= 'Z'))
|
||||
if (!ascii_isdigit(c) &&
|
||||
!(c >= 'a' && c <= 'f') &&
|
||||
!(c >= 'A' && c <= 'F'))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -206,19 +206,3 @@ int id128_get_product(sd_id128_t *ret) {
|
|||
*ret = uuid;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int id128_equal_string(const char *s, sd_id128_t id) {
|
||||
sd_id128_t parsed;
|
||||
int r;
|
||||
|
||||
if (!s)
|
||||
return false;
|
||||
|
||||
/* Checks if the specified string matches a valid string representation of the specified 128 bit ID/uuid */
|
||||
|
||||
r = sd_id128_from_string(s, &parsed);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return sd_id128_equal(parsed, id);
|
||||
}
|
||||
|
|
|
@ -34,5 +34,3 @@ extern const struct hash_ops id128_hash_ops;
|
|||
sd_id128_t id128_make_v4_uuid(sd_id128_t id);
|
||||
|
||||
int id128_get_product(sd_id128_t *ret);
|
||||
|
||||
int id128_equal_string(const char *s, sd_id128_t id);
|
||||
|
|
|
@ -101,6 +101,22 @@ _public_ int sd_id128_from_string(const char s[], sd_id128_t *ret) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
_public_ int sd_id128_string_equal(const char *s, sd_id128_t id) {
|
||||
sd_id128_t parsed;
|
||||
int r;
|
||||
|
||||
if (!s)
|
||||
return false;
|
||||
|
||||
/* Checks if the specified string matches a valid string representation of the specified 128 bit ID/uuid */
|
||||
|
||||
r = sd_id128_from_string(s, &parsed);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return sd_id128_equal(parsed, id);
|
||||
}
|
||||
|
||||
_public_ int sd_id128_get_machine(sd_id128_t *ret) {
|
||||
static thread_local sd_id128_t saved_machine_id = {};
|
||||
int r;
|
||||
|
@ -256,7 +272,10 @@ _public_ int sd_id128_get_invocation(sd_id128_t *ret) {
|
|||
/* We first check the environment. The environment variable is primarily relevant for user
|
||||
* services, and sufficiently safe as long as no privilege boundary is involved. */
|
||||
r = get_invocation_from_environment(&saved_invocation_id);
|
||||
if (r < 0 && r != -ENXIO)
|
||||
if (r >= 0) {
|
||||
*ret = saved_invocation_id;
|
||||
return 0;
|
||||
} else if (r != -ENXIO)
|
||||
return r;
|
||||
|
||||
/* The kernel keyring is relevant for system services (as for user services we don't store
|
||||
|
@ -272,13 +291,10 @@ _public_ int sd_id128_get_invocation(sd_id128_t *ret) {
|
|||
|
||||
_public_ int sd_id128_randomize(sd_id128_t *ret) {
|
||||
sd_id128_t t;
|
||||
int r;
|
||||
|
||||
assert_return(ret, -EINVAL);
|
||||
|
||||
r = genuine_random_bytes(&t, sizeof(t), 0);
|
||||
if (r < 0)
|
||||
return r;
|
||||
random_bytes(&t, sizeof(t));
|
||||
|
||||
/* Turn this into a valid v4 UUID, to be nice. Note that we
|
||||
* only guarantee this for newly generated UUIDs, not for
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
along with systemd; If not, see <https://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
/* This is a private header; never even think of including this directly! */
|
||||
|
|
|
@ -1,345 +0,0 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#ifndef foosddhcpclienthfoo
|
||||
#define foosddhcpclienthfoo
|
||||
|
||||
/***
|
||||
Copyright © 2013 Intel Corporation. All rights reserved.
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <net/ethernet.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/types.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "sd-dhcp-lease.h"
|
||||
#include "sd-dhcp-option.h"
|
||||
#include "sd-event.h"
|
||||
|
||||
#include "_sd-common.h"
|
||||
|
||||
_SD_BEGIN_DECLARATIONS;
|
||||
|
||||
enum {
|
||||
SD_DHCP_CLIENT_EVENT_STOP = 0,
|
||||
SD_DHCP_CLIENT_EVENT_IP_ACQUIRE = 1,
|
||||
SD_DHCP_CLIENT_EVENT_IP_CHANGE = 2,
|
||||
SD_DHCP_CLIENT_EVENT_EXPIRED = 3,
|
||||
SD_DHCP_CLIENT_EVENT_RENEW = 4,
|
||||
SD_DHCP_CLIENT_EVENT_SELECTING = 5,
|
||||
SD_DHCP_CLIENT_EVENT_TRANSIENT_FAILURE = 6, /* Sent when we have not received a reply after the first few attempts.
|
||||
* The client may want to start acquiring link-local addresses. */
|
||||
};
|
||||
|
||||
/* https://www.iana.org/assignments/bootp-dhcp-parameters/bootp-dhcp-parameters.xhtml#options */
|
||||
enum {
|
||||
SD_DHCP_OPTION_PAD = 0, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_SUBNET_MASK = 1, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_TIME_OFFSET = 2, /* [RFC2132], deprecated by 100 and 101 */
|
||||
SD_DHCP_OPTION_ROUTER = 3, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_TIME_SERVER = 4, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_NAME_SERVER = 5, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_DOMAIN_NAME_SERVER = 6, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_LOG_SERVER = 7, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_QUOTES_SERVER = 8, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_LPR_SERVER = 9, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_IMPRESS_SERVER = 10, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_RLP_SERVER = 11, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_HOST_NAME = 12, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_BOOT_FILE_SIZE = 13, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_MERIT_DUMP_FILE = 14, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_DOMAIN_NAME = 15, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_SWAP_SERVER = 16, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_ROOT_PATH = 17, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_EXTENSION_FILE = 18, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_FORWARD = 19, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_SOURCE_ROUTE = 20, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_POLICY_FILTER = 21, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_MAX_DATAGRAM_ASSEMBLY = 22, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_DEFAULT_IP_TTL = 23, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_MTU_TIMEOUT = 24, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_MTU_PLATEAU = 25, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_MTU_INTERFACE = 26, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_MTU_SUBNET = 27, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_BROADCAST = 28, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_MASK_DISCOVERY = 29, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_MASK_SUPPLIER = 30, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_ROUTER_DISCOVERY = 31, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_ROUTER_REQUEST = 32, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_STATIC_ROUTE = 33, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_TRAILERS = 34, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_ARP_TIMEOUT = 35, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_ETHERNET = 36, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_DEFAULT_TCP_TTL = 37, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_KEEPALIVE_TIME = 38, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_KEEPALIVE_DATA = 39, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_NIS_DOMAIN = 40, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_NIS_SERVER = 41, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_NTP_SERVER = 42, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_VENDOR_SPECIFIC = 43, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_NETBIOS_NAME_SERVER = 44, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_NETBIOS_DIST_SERVER = 45, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_NETBIOS_NODE_TYPE = 46, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_NETBIOS_SCOPE = 47, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_X_WINDOW_FONT = 48, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_X_WINDOW_MANAGER = 49, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_REQUESTED_IP_ADDRESS = 50, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_IP_ADDRESS_LEASE_TIME = 51, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_OVERLOAD = 52, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_MESSAGE_TYPE = 53, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_SERVER_IDENTIFIER = 54, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_PARAMETER_REQUEST_LIST = 55, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_ERROR_MESSAGE = 56, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_MAXIMUM_MESSAGE_SIZE = 57, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_RENEWAL_TIME = 58, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_REBINDING_TIME = 59, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_VENDOR_CLASS_IDENTIFIER = 60, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_CLIENT_IDENTIFIER = 61, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_NETWARE_IP_DOMAIN = 62, /* [RFC2242] */
|
||||
SD_DHCP_OPTION_NETWARE_IP_OPTION = 63, /* [RFC2242] */
|
||||
SD_DHCP_OPTION_NIS_DOMAIN_NAME = 64, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_NIS_SERVER_ADDR = 65, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_BOOT_SERVER_NAME = 66, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_BOOT_FILENAME = 67, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_HOME_AGENT_ADDRESSES = 68, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_SMTP_SERVER = 69, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_POP3_SERVER = 70, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_NNTP_SERVER = 71, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_WWW_SERVER = 72, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_FINGER_SERVER = 73, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_IRC_SERVER = 74, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_STREETTALK_SERVER = 75, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_STDA_SERVER = 76, /* [RFC2132] */
|
||||
SD_DHCP_OPTION_USER_CLASS = 77, /* [RFC3004] */
|
||||
SD_DHCP_OPTION_DIRECTORY_AGENT = 78, /* [RFC2610] */
|
||||
SD_DHCP_OPTION_SERVICE_SCOPE = 79, /* [RFC2610] */
|
||||
SD_DHCP_OPTION_RAPID_COMMIT = 80, /* [RFC4039] */
|
||||
SD_DHCP_OPTION_FQDN = 81, /* [RFC4702] */
|
||||
SD_DHCP_OPTION_RELAY_AGENT_INFORMATION = 82, /* [RFC3046] */
|
||||
SD_DHCP_OPTION_ISNS = 83, /* [RFC4174] */
|
||||
/* option code 84 is unassigned [RFC3679] */
|
||||
SD_DHCP_OPTION_NDS_SERVER = 85, /* [RFC2241] */
|
||||
SD_DHCP_OPTION_NDS_TREE_NAME = 86, /* [RFC2241] */
|
||||
SD_DHCP_OPTION_NDS_CONTEXT = 87, /* [RFC2241] */
|
||||
SD_DHCP_OPTION_BCMCS_CONTROLLER_DOMAIN_NAM = 88, /* [RFC4280] */
|
||||
SD_DHCP_OPTION_BCMCS_CONTROLLER_ADDRESS = 89, /* [RFC4280] */
|
||||
SD_DHCP_OPTION_AUTHENTICATION = 90, /* [RFC3118] */
|
||||
SD_DHCP_OPTION_CLIENT_LAST_TRANSACTION_TIME = 91, /* [RFC4388] */
|
||||
SD_DHCP_OPTION_ASSOCIATED_IP = 92, /* [RFC4388] */
|
||||
SD_DHCP_OPTION_CLIENT_SYSTEM = 93, /* [RFC4578] */
|
||||
SD_DHCP_OPTION_CLIENT_NDI = 94, /* [RFC4578] */
|
||||
SD_DHCP_OPTION_LDAP = 95, /* [RFC3679] */
|
||||
/* option code 96 is unassigned [RFC3679] */
|
||||
SD_DHCP_OPTION_UUID = 97, /* [RFC4578] */
|
||||
SD_DHCP_OPTION_USER_AUTHENTICATION = 98, /* [RFC2485] */
|
||||
SD_DHCP_OPTION_GEOCONF_CIVIC = 99, /* [RFC4776] */
|
||||
SD_DHCP_OPTION_POSIX_TIMEZONE = 100, /* [RFC4833] */
|
||||
SD_DHCP_OPTION_TZDB_TIMEZONE = 101, /* [RFC4833] */
|
||||
/* option codes 102-107 are unassigned [RFC3679] */
|
||||
SD_DHCP_OPTION_IPV6_ONLY_PREFERRED = 108, /* [RFC8925] */
|
||||
SD_DHCP_OPTION_DHCP4O6_SOURCE_ADDRESS = 109, /* [RFC8539] */
|
||||
/* option codes 110-111 are unassigned [RFC3679] */
|
||||
SD_DHCP_OPTION_NETINFO_ADDRESS = 112, /* [RFC3679] */
|
||||
SD_DHCP_OPTION_NETINFO_TAG = 113, /* [RFC3679] */
|
||||
SD_DHCP_OPTION_DHCP_CAPTIVE_PORTAL = 114, /* [RFC8910] */
|
||||
/* option code 115 is unassigned [RFC3679] */
|
||||
SD_DHCP_OPTION_AUTO_CONFIG = 116, /* [RFC2563] */
|
||||
SD_DHCP_OPTION_NAME_SERVICE_SEARCH = 117, /* [RFC2937] */
|
||||
SD_DHCP_OPTION_SUBNET_SELECTION = 118, /* [RFC3011] */
|
||||
SD_DHCP_OPTION_DOMAIN_SEARCH = 119, /* [RFC3397] */
|
||||
SD_DHCP_OPTION_SIP_SERVER = 120, /* [RFC3361] */
|
||||
SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE = 121, /* [RFC3442] */
|
||||
SD_DHCP_OPTION_CABLELABS_CLIENT_CONFIGURATION = 122, /* [RFC3495] */
|
||||
SD_DHCP_OPTION_GEOCONF = 123, /* [RFC6225] */
|
||||
SD_DHCP_OPTION_VENDOR_CLASS = 124, /* [RFC3925] */
|
||||
SD_DHCP_OPTION_VENDOR_SPECIFIC_INFORMATION = 125, /* [RFC3925] */
|
||||
/* option codes 126-127 are unassigned [RFC3679] */
|
||||
/* option codes 128-135 are assigned to use by PXE, but they are vendor specific [RFC4578] */
|
||||
SD_DHCP_OPTION_PANA_AGENT = 136, /* [RFC5192] */
|
||||
SD_DHCP_OPTION_LOST_SERVER_FQDN = 137, /* [RFC5223] */
|
||||
SD_DHCP_OPTION_CAPWAP_AC_ADDRESS = 138, /* [RFC5417] */
|
||||
SD_DHCP_OPTION_MOS_ADDRESS = 139, /* [RFC5678] */
|
||||
SD_DHCP_OPTION_MOS_FQDN = 140, /* [RFC5678] */
|
||||
SD_DHCP_OPTION_SIP_SERVICE_DOMAINS = 141, /* [RFC6011] */
|
||||
SD_DHCP_OPTION_ANDSF_ADDRESS = 142, /* [RFC6153] */
|
||||
SD_DHCP_OPTION_SZTP_REDIRECT = 143, /* [RFC8572] */
|
||||
SD_DHCP_OPTION_GEOLOC = 144, /* [RFC6225] */
|
||||
SD_DHCP_OPTION_FORCERENEW_NONCE_CAPABLE = 145, /* [RFC6704] */
|
||||
SD_DHCP_OPTION_RDNSS_SELECTION = 146, /* [RFC6731] */
|
||||
SD_DHCP_OPTION_DOTS_RI = 147, /* [RFC8973] */
|
||||
SD_DHCP_OPTION_DOTS_ADDRESS = 148, /* [RFC8973] */
|
||||
/* option code 149 is unassigned [RFC3942] */
|
||||
SD_DHCP_OPTION_TFTP_SERVER_ADDRESS = 150, /* [RFC5859] */
|
||||
SD_DHCP_OPTION_STATUS_CODE = 151, /* [RFC6926] */
|
||||
SD_DHCP_OPTION_BASE_TIME = 152, /* [RFC6926] */
|
||||
SD_DHCP_OPTION_START_TIME_OF_STATE = 153, /* [RFC6926] */
|
||||
SD_DHCP_OPTION_QUERY_START_TIME = 154, /* [RFC6926] */
|
||||
SD_DHCP_OPTION_QUERY_END_TIME = 155, /* [RFC6926] */
|
||||
SD_DHCP_OPTION_DHCP_STATE = 156, /* [RFC6926] */
|
||||
SD_DHCP_OPTION_DATA_SOURCE = 157, /* [RFC6926] */
|
||||
SD_DHCP_OPTION_PCP_SERVER = 158, /* [RFC7291] */
|
||||
SD_DHCP_OPTION_PORT_PARAMS = 159, /* [RFC7618] */
|
||||
/* option code 160 is unassigned [RFC7710][RFC8910] */
|
||||
SD_DHCP_OPTION_MUD_URL = 161, /* [RFC8520] */
|
||||
/* option codes 162-174 are unassigned [RFC3942] */
|
||||
/* option codes 175-177 are temporary assigned. */
|
||||
/* option codes 178-207 are unassigned [RFC3942] */
|
||||
SD_DHCP_OPTION_PXELINUX_MAGIC = 208, /* [RFC5071] Deprecated */
|
||||
SD_DHCP_OPTION_CONFIGURATION_FILE = 209, /* [RFC5071] */
|
||||
SD_DHCP_OPTION_PATH_PREFIX = 210, /* [RFC5071] */
|
||||
SD_DHCP_OPTION_REBOOT_TIME = 211, /* [RFC5071] */
|
||||
SD_DHCP_OPTION_6RD = 212, /* [RFC5969] */
|
||||
SD_DHCP_OPTION_ACCESS_DOMAIN = 213, /* [RFC5986] */
|
||||
/* option codes 214-219 are unassigned */
|
||||
SD_DHCP_OPTION_SUBNET_ALLOCATION = 220, /* [RFC6656] */
|
||||
SD_DHCP_OPTION_VIRTUAL_SUBNET_SELECTION = 221, /* [RFC6607] */
|
||||
/* option codes 222-223 are unassigned [RFC3942] */
|
||||
/* option codes 224-254 are reserved for private use */
|
||||
SD_DHCP_OPTION_PRIVATE_BASE = 224,
|
||||
SD_DHCP_OPTION_PRIVATE_CLASSLESS_STATIC_ROUTE = 249, /* [RFC7844] */
|
||||
SD_DHCP_OPTION_PRIVATE_PROXY_AUTODISCOVERY = 252, /* [RFC7844] */
|
||||
SD_DHCP_OPTION_PRIVATE_LAST = 254,
|
||||
SD_DHCP_OPTION_END = 255, /* [RFC2132] */
|
||||
};
|
||||
|
||||
/* Suboptions for SD_DHCP_OPTION_RELAY_AGENT_INFORMATION option */
|
||||
enum {
|
||||
SD_DHCP_RELAY_AGENT_CIRCUIT_ID = 1,
|
||||
SD_DHCP_RELAY_AGENT_REMOTE_ID = 2,
|
||||
};
|
||||
|
||||
typedef struct sd_dhcp_client sd_dhcp_client;
|
||||
|
||||
typedef int (*sd_dhcp_client_callback_t)(sd_dhcp_client *client, int event, void *userdata);
|
||||
int sd_dhcp_client_set_callback(
|
||||
sd_dhcp_client *client,
|
||||
sd_dhcp_client_callback_t cb,
|
||||
void *userdata);
|
||||
|
||||
int sd_dhcp_client_set_request_option(
|
||||
sd_dhcp_client *client,
|
||||
uint8_t option);
|
||||
int sd_dhcp_client_set_request_address(
|
||||
sd_dhcp_client *client,
|
||||
const struct in_addr *last_address);
|
||||
int sd_dhcp_client_set_request_broadcast(
|
||||
sd_dhcp_client *client,
|
||||
int broadcast);
|
||||
int sd_dhcp_client_set_ifindex(
|
||||
sd_dhcp_client *client,
|
||||
int interface_index);
|
||||
int sd_dhcp_client_set_ifname(
|
||||
sd_dhcp_client *client,
|
||||
const char *interface_name);
|
||||
int sd_dhcp_client_get_ifname(sd_dhcp_client *client, const char **ret);
|
||||
int sd_dhcp_client_set_mac(
|
||||
sd_dhcp_client *client,
|
||||
const uint8_t *addr,
|
||||
const uint8_t *bcast_addr,
|
||||
size_t addr_len,
|
||||
uint16_t arp_type);
|
||||
int sd_dhcp_client_set_client_id(
|
||||
sd_dhcp_client *client,
|
||||
uint8_t type,
|
||||
const uint8_t *data,
|
||||
size_t data_len);
|
||||
int sd_dhcp_client_set_iaid_duid(
|
||||
sd_dhcp_client *client,
|
||||
bool iaid_set,
|
||||
uint32_t iaid,
|
||||
uint16_t duid_type,
|
||||
const void *duid,
|
||||
size_t duid_len);
|
||||
int sd_dhcp_client_set_iaid_duid_llt(
|
||||
sd_dhcp_client *client,
|
||||
bool iaid_set,
|
||||
uint32_t iaid,
|
||||
uint64_t llt_time);
|
||||
int sd_dhcp_client_set_duid(
|
||||
sd_dhcp_client *client,
|
||||
uint16_t duid_type,
|
||||
const void *duid,
|
||||
size_t duid_len);
|
||||
int sd_dhcp_client_set_duid_llt(
|
||||
sd_dhcp_client *client,
|
||||
uint64_t llt_time);
|
||||
int sd_dhcp_client_get_client_id(
|
||||
sd_dhcp_client *client,
|
||||
uint8_t *type,
|
||||
const uint8_t **data,
|
||||
size_t *data_len);
|
||||
int sd_dhcp_client_set_mtu(
|
||||
sd_dhcp_client *client,
|
||||
uint32_t mtu);
|
||||
int sd_dhcp_client_set_max_attempts(
|
||||
sd_dhcp_client *client,
|
||||
uint64_t attempt);
|
||||
int sd_dhcp_client_set_client_port(
|
||||
sd_dhcp_client *client,
|
||||
uint16_t port);
|
||||
int sd_dhcp_client_set_hostname(
|
||||
sd_dhcp_client *client,
|
||||
const char *hostname);
|
||||
int sd_dhcp_client_set_vendor_class_identifier(
|
||||
sd_dhcp_client *client,
|
||||
const char *vci);
|
||||
int sd_dhcp_client_set_mud_url(
|
||||
sd_dhcp_client *client,
|
||||
const char *mudurl);
|
||||
int sd_dhcp_client_set_user_class(
|
||||
sd_dhcp_client *client,
|
||||
char * const *user_class);
|
||||
int sd_dhcp_client_get_lease(
|
||||
sd_dhcp_client *client,
|
||||
sd_dhcp_lease **ret);
|
||||
int sd_dhcp_client_set_service_type(
|
||||
sd_dhcp_client *client,
|
||||
int type);
|
||||
int sd_dhcp_client_set_fallback_lease_lifetime(
|
||||
sd_dhcp_client *client,
|
||||
uint32_t fallback_lease_lifetime);
|
||||
|
||||
int sd_dhcp_client_add_option(sd_dhcp_client *client, sd_dhcp_option *v);
|
||||
int sd_dhcp_client_add_vendor_option(sd_dhcp_client *client, sd_dhcp_option *v);
|
||||
|
||||
int sd_dhcp_client_is_running(sd_dhcp_client *client);
|
||||
int sd_dhcp_client_stop(sd_dhcp_client *client);
|
||||
int sd_dhcp_client_start(sd_dhcp_client *client);
|
||||
int sd_dhcp_client_send_release(sd_dhcp_client *client);
|
||||
int sd_dhcp_client_send_decline(sd_dhcp_client *client);
|
||||
int sd_dhcp_client_send_renew(sd_dhcp_client *client);
|
||||
|
||||
sd_dhcp_client *sd_dhcp_client_ref(sd_dhcp_client *client);
|
||||
sd_dhcp_client *sd_dhcp_client_unref(sd_dhcp_client *client);
|
||||
|
||||
/* NOTE: anonymize parameter is used to initialize PRL memory with different
|
||||
* options when using RFC7844 Anonymity Profiles */
|
||||
int sd_dhcp_client_new(sd_dhcp_client **ret, int anonymize);
|
||||
|
||||
int sd_dhcp_client_id_to_string(const void *data, size_t len, char **ret);
|
||||
|
||||
int sd_dhcp_client_attach_event(
|
||||
sd_dhcp_client *client,
|
||||
sd_event *event,
|
||||
int64_t priority);
|
||||
int sd_dhcp_client_detach_event(sd_dhcp_client *client);
|
||||
sd_event *sd_dhcp_client_get_event(sd_dhcp_client *client);
|
||||
|
||||
_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_dhcp_client, sd_dhcp_client_unref);
|
||||
|
||||
_SD_END_DECLARATIONS;
|
||||
|
||||
#endif
|
|
@ -1,91 +0,0 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#ifndef foosddhcpleasehfoo
|
||||
#define foosddhcpleasehfoo
|
||||
|
||||
/***
|
||||
Copyright © 2013 Intel Corporation. All rights reserved.
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <errno.h>
|
||||
#include <inttypes.h>
|
||||
#include <net/ethernet.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "_sd-common.h"
|
||||
|
||||
_SD_BEGIN_DECLARATIONS;
|
||||
|
||||
typedef struct sd_dhcp_lease sd_dhcp_lease;
|
||||
typedef struct sd_dhcp_route sd_dhcp_route;
|
||||
|
||||
sd_dhcp_lease *sd_dhcp_lease_ref(sd_dhcp_lease *lease);
|
||||
sd_dhcp_lease *sd_dhcp_lease_unref(sd_dhcp_lease *lease);
|
||||
|
||||
typedef enum sd_dhcp_lease_server_type_t {
|
||||
SD_DHCP_LEASE_DNS,
|
||||
SD_DHCP_LEASE_NTP,
|
||||
SD_DHCP_LEASE_SIP,
|
||||
SD_DHCP_LEASE_POP3,
|
||||
SD_DHCP_LEASE_SMTP,
|
||||
SD_DHCP_LEASE_LPR,
|
||||
_SD_DHCP_LEASE_SERVER_TYPE_MAX,
|
||||
_SD_DHCP_LEASE_SERVER_TYPE_INVALID = -EINVAL,
|
||||
_SD_ENUM_FORCE_S64(DHCP_LEASE_SERVER_TYPE),
|
||||
} sd_dhcp_lease_server_type_t;
|
||||
|
||||
int sd_dhcp_lease_get_address(sd_dhcp_lease *lease, struct in_addr *addr);
|
||||
int sd_dhcp_lease_get_lifetime(sd_dhcp_lease *lease, uint32_t *lifetime);
|
||||
int sd_dhcp_lease_get_t1(sd_dhcp_lease *lease, uint32_t *t1);
|
||||
int sd_dhcp_lease_get_t2(sd_dhcp_lease *lease, uint32_t *t2);
|
||||
int sd_dhcp_lease_get_broadcast(sd_dhcp_lease *lease, struct in_addr *addr);
|
||||
int sd_dhcp_lease_get_netmask(sd_dhcp_lease *lease, struct in_addr *addr);
|
||||
int sd_dhcp_lease_get_router(sd_dhcp_lease *lease, const struct in_addr **addr);
|
||||
int sd_dhcp_lease_get_next_server(sd_dhcp_lease *lease, struct in_addr *addr);
|
||||
int sd_dhcp_lease_get_server_identifier(sd_dhcp_lease *lease, struct in_addr *addr);
|
||||
int sd_dhcp_lease_get_servers(sd_dhcp_lease *lease, sd_dhcp_lease_server_type_t what, const struct in_addr **addr);
|
||||
int sd_dhcp_lease_get_dns(sd_dhcp_lease *lease, const struct in_addr **addr);
|
||||
int sd_dhcp_lease_get_ntp(sd_dhcp_lease *lease, const struct in_addr **addr);
|
||||
int sd_dhcp_lease_get_sip(sd_dhcp_lease *lease, const struct in_addr **addr);
|
||||
int sd_dhcp_lease_get_pop3(sd_dhcp_lease *lease, const struct in_addr **addr);
|
||||
int sd_dhcp_lease_get_smtp(sd_dhcp_lease *lease, const struct in_addr **addr);
|
||||
int sd_dhcp_lease_get_lpr(sd_dhcp_lease *lease, const struct in_addr **addr);
|
||||
int sd_dhcp_lease_get_mtu(sd_dhcp_lease *lease, uint16_t *mtu);
|
||||
int sd_dhcp_lease_get_domainname(sd_dhcp_lease *lease, const char **domainname);
|
||||
int sd_dhcp_lease_get_search_domains(sd_dhcp_lease *lease, char ***domains);
|
||||
int sd_dhcp_lease_get_hostname(sd_dhcp_lease *lease, const char **hostname);
|
||||
int sd_dhcp_lease_get_root_path(sd_dhcp_lease *lease, const char **root_path);
|
||||
int sd_dhcp_lease_get_static_routes(sd_dhcp_lease *lease, sd_dhcp_route ***ret);
|
||||
int sd_dhcp_lease_get_classless_routes(sd_dhcp_lease *lease, sd_dhcp_route ***ret);
|
||||
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);
|
||||
int sd_dhcp_route_get_gateway(sd_dhcp_route *route, struct in_addr *gateway);
|
||||
|
||||
_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_dhcp_lease, sd_dhcp_lease_unref);
|
||||
|
||||
_SD_END_DECLARATIONS;
|
||||
|
||||
#endif
|
|
@ -1,38 +0,0 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#ifndef foosddhcpoptionhfoo
|
||||
#define foosddhcpoptionhfoo
|
||||
|
||||
/***
|
||||
Copyright © 2013 Intel Corporation. All rights reserved.
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "_sd-common.h"
|
||||
|
||||
_SD_BEGIN_DECLARATIONS;
|
||||
|
||||
typedef struct sd_dhcp_option sd_dhcp_option;
|
||||
|
||||
int sd_dhcp_option_new(uint8_t option, const void *data, size_t length, sd_dhcp_option **ret);
|
||||
sd_dhcp_option *sd_dhcp_option_ref(sd_dhcp_option *ra);
|
||||
sd_dhcp_option *sd_dhcp_option_unref(sd_dhcp_option *ra);
|
||||
|
||||
_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_dhcp_option, sd_dhcp_option_unref);
|
||||
|
||||
_SD_END_DECLARATIONS;
|
||||
|
||||
#endif
|
|
@ -16,7 +16,7 @@
|
|||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
along with systemd; If not, see <https://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <inttypes.h>
|
||||
|
@ -36,7 +36,7 @@ enum {
|
|||
SD_DHCP6_CLIENT_EVENT_RESEND_EXPIRE = 10,
|
||||
SD_DHCP6_CLIENT_EVENT_RETRANS_MAX = 11,
|
||||
SD_DHCP6_CLIENT_EVENT_IP_ACQUIRE = 12,
|
||||
SD_DHCP6_CLIENT_EVENT_INFORMATION_REQUEST = 13,
|
||||
SD_DHCP6_CLIENT_EVENT_INFORMATION_REQUEST = 13
|
||||
};
|
||||
|
||||
/* https://www.iana.org/assignments/dhcpv6-parameters/dhcpv6-parameters.xhtml#dhcpv6-parameters-2 */
|
||||
|
@ -63,15 +63,15 @@ enum {
|
|||
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_DNS_SERVER = 23, /* RFC 3646 */
|
||||
SD_DHCP6_OPTION_DOMAIN = 24, /* RFC 3646 */
|
||||
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_SERVER = 27, /* RFC 3898 */
|
||||
SD_DHCP6_OPTION_NISP_SERVER = 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_SNTP_SERVER = 31, /* RFC 4075, deprecated */
|
||||
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 */
|
||||
|
@ -183,7 +183,7 @@ enum {
|
|||
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 */
|
||||
SD_DHCP6_OPTION_IPV6_ADDRESS_ANDSF = 143 /* RFC 6153 */
|
||||
/* option codes 144-65535 are unassigned */
|
||||
};
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
along with systemd; If not, see <https://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <inttypes.h>
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
along with systemd; If not, see <https://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <inttypes.h>
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
along with systemd; If not, see <https://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <inttypes.h>
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
along with systemd; If not, see <https://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <inttypes.h>
|
||||
|
@ -116,9 +116,11 @@ int sd_id128_get_boot_app_specific(sd_id128_t app_id, sd_id128_t *ret);
|
|||
#a #b #c #d "-" #e #f "-" #g #h "-" #i #j "-" #k #l #m #n #o #p
|
||||
|
||||
_sd_pure_ static __inline__ int sd_id128_equal(sd_id128_t a, sd_id128_t b) {
|
||||
return memcmp(&a, &b, 16) == 0;
|
||||
return a.qwords[0] == b.qwords[0] && a.qwords[1] == b.qwords[1];
|
||||
}
|
||||
|
||||
int sd_id128_string_equal(const char *s, sd_id128_t id);
|
||||
|
||||
_sd_pure_ static __inline__ int sd_id128_is_null(sd_id128_t a) {
|
||||
return a.qwords[0] == 0 && a.qwords[1] == 0;
|
||||
}
|
||||
|
|
|
@ -1,63 +0,0 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#ifndef foosdipv4acdfoo
|
||||
#define foosdipv4acdfoo
|
||||
|
||||
/***
|
||||
Copyright © 2014 Axis Communications AB. All rights reserved.
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <net/ethernet.h>
|
||||
#include <netinet/in.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "sd-event.h"
|
||||
|
||||
#include "_sd-common.h"
|
||||
|
||||
_SD_BEGIN_DECLARATIONS;
|
||||
|
||||
enum {
|
||||
SD_IPV4ACD_EVENT_STOP = 0,
|
||||
SD_IPV4ACD_EVENT_BIND = 1,
|
||||
SD_IPV4ACD_EVENT_CONFLICT = 2,
|
||||
};
|
||||
|
||||
typedef struct sd_ipv4acd sd_ipv4acd;
|
||||
typedef void (*sd_ipv4acd_callback_t)(sd_ipv4acd *acd, int event, void *userdata);
|
||||
typedef int (*sd_ipv4acd_check_mac_callback_t)(sd_ipv4acd *acd, const struct ether_addr *mac, void *userdata);
|
||||
|
||||
int sd_ipv4acd_detach_event(sd_ipv4acd *acd);
|
||||
int sd_ipv4acd_attach_event(sd_ipv4acd *acd, sd_event *event, int64_t priority);
|
||||
int sd_ipv4acd_get_address(sd_ipv4acd *acd, struct in_addr *address);
|
||||
int sd_ipv4acd_set_callback(sd_ipv4acd *acd, sd_ipv4acd_callback_t cb, void *userdata);
|
||||
int sd_ipv4acd_set_check_mac_callback(sd_ipv4acd *acd, sd_ipv4acd_check_mac_callback_t cb, void *userdata);
|
||||
int sd_ipv4acd_set_mac(sd_ipv4acd *acd, const struct ether_addr *addr);
|
||||
int sd_ipv4acd_set_ifindex(sd_ipv4acd *acd, int interface_index);
|
||||
int sd_ipv4acd_get_ifindex(sd_ipv4acd *acd);
|
||||
int sd_ipv4acd_set_ifname(sd_ipv4acd *acd, const char *interface_name);
|
||||
int sd_ipv4acd_get_ifname(sd_ipv4acd *acd, const char **ret);
|
||||
int sd_ipv4acd_set_address(sd_ipv4acd *acd, const struct in_addr *address);
|
||||
int sd_ipv4acd_is_running(sd_ipv4acd *acd);
|
||||
int sd_ipv4acd_start(sd_ipv4acd *acd, bool reset_conflicts);
|
||||
int sd_ipv4acd_stop(sd_ipv4acd *acd);
|
||||
sd_ipv4acd *sd_ipv4acd_ref(sd_ipv4acd *acd);
|
||||
sd_ipv4acd *sd_ipv4acd_unref(sd_ipv4acd *acd);
|
||||
int sd_ipv4acd_new(sd_ipv4acd **ret);
|
||||
|
||||
_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_ipv4acd, sd_ipv4acd_unref);
|
||||
|
||||
_SD_END_DECLARATIONS;
|
||||
|
||||
#endif
|
|
@ -1,65 +0,0 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#ifndef foosdipv4llfoo
|
||||
#define foosdipv4llfoo
|
||||
|
||||
/***
|
||||
Copyright © 2014 Axis Communications AB. All rights reserved.
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <net/ethernet.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include "sd-event.h"
|
||||
|
||||
#include "_sd-common.h"
|
||||
|
||||
_SD_BEGIN_DECLARATIONS;
|
||||
|
||||
enum {
|
||||
SD_IPV4LL_EVENT_STOP = 0,
|
||||
SD_IPV4LL_EVENT_BIND = 1,
|
||||
SD_IPV4LL_EVENT_CONFLICT = 2,
|
||||
};
|
||||
|
||||
typedef struct sd_ipv4ll sd_ipv4ll;
|
||||
typedef void (*sd_ipv4ll_callback_t)(sd_ipv4ll *ll, int event, void *userdata);
|
||||
typedef int (*sd_ipv4ll_check_mac_callback_t)(sd_ipv4ll *ll, const struct ether_addr *mac, void *userdata);
|
||||
|
||||
int sd_ipv4ll_detach_event(sd_ipv4ll *ll);
|
||||
int sd_ipv4ll_attach_event(sd_ipv4ll *ll, sd_event *event, int64_t priority);
|
||||
int sd_ipv4ll_get_address(sd_ipv4ll *ll, struct in_addr *address);
|
||||
int sd_ipv4ll_set_callback(sd_ipv4ll *ll, sd_ipv4ll_callback_t cb, void *userdata);
|
||||
int sd_ipv4ll_set_check_mac_callback(sd_ipv4ll *ll, sd_ipv4ll_check_mac_callback_t cb, void *userdata);
|
||||
int sd_ipv4ll_set_mac(sd_ipv4ll *ll, const struct ether_addr *addr);
|
||||
int sd_ipv4ll_set_ifindex(sd_ipv4ll *ll, int interface_index);
|
||||
int sd_ipv4ll_get_ifindex(sd_ipv4ll *ll);
|
||||
int sd_ipv4ll_set_ifname(sd_ipv4ll *ll, const char *interface_name);
|
||||
int sd_ipv4ll_get_ifname(sd_ipv4ll *ll, const char **ret);
|
||||
int sd_ipv4ll_set_address(sd_ipv4ll *ll, const struct in_addr *address);
|
||||
int sd_ipv4ll_set_address_seed(sd_ipv4ll *ll, uint64_t seed);
|
||||
int sd_ipv4ll_is_running(sd_ipv4ll *ll);
|
||||
int sd_ipv4ll_restart(sd_ipv4ll *ll);
|
||||
int sd_ipv4ll_start(sd_ipv4ll *ll);
|
||||
int sd_ipv4ll_stop(sd_ipv4ll *ll);
|
||||
sd_ipv4ll *sd_ipv4ll_ref(sd_ipv4ll *ll);
|
||||
sd_ipv4ll *sd_ipv4ll_unref(sd_ipv4ll *ll);
|
||||
int sd_ipv4ll_new(sd_ipv4ll **ret);
|
||||
|
||||
_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_ipv4ll, sd_ipv4ll_unref);
|
||||
|
||||
_SD_END_DECLARATIONS;
|
||||
|
||||
#endif
|
|
@ -14,7 +14,7 @@
|
|||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
along with systemd; If not, see <https://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <errno.h>
|
||||
|
@ -32,14 +32,14 @@ _SD_BEGIN_DECLARATIONS;
|
|||
typedef struct sd_lldp_rx sd_lldp_rx;
|
||||
typedef struct sd_lldp_neighbor sd_lldp_neighbor;
|
||||
|
||||
typedef enum sd_lldp_rx_event_t {
|
||||
__extension__ typedef enum sd_lldp_rx_event_t {
|
||||
SD_LLDP_RX_EVENT_ADDED,
|
||||
SD_LLDP_RX_EVENT_REMOVED,
|
||||
SD_LLDP_RX_EVENT_UPDATED,
|
||||
SD_LLDP_RX_EVENT_REFRESHED,
|
||||
_SD_LLDP_RX_EVENT_MAX,
|
||||
_SD_LLDP_RX_EVENT_INVALID = -EINVAL,
|
||||
_SD_ENUM_FORCE_S64(LLDP_RX_EVENT),
|
||||
_SD_ENUM_FORCE_S64(LLDP_RX_EVENT)
|
||||
} sd_lldp_rx_event_t;
|
||||
|
||||
typedef void (*sd_lldp_rx_callback_t)(sd_lldp_rx *lldp_rx, sd_lldp_rx_event_t event, sd_lldp_neighbor *n, void *userdata);
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
along with systemd; If not, see <https://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <inttypes.h>
|
||||
|
@ -34,7 +34,7 @@ enum {
|
|||
SD_LLDP_TYPE_SYSTEM_DESCRIPTION = 6,
|
||||
SD_LLDP_TYPE_SYSTEM_CAPABILITIES = 7,
|
||||
SD_LLDP_TYPE_MGMT_ADDRESS = 8,
|
||||
SD_LLDP_TYPE_PRIVATE = 127,
|
||||
SD_LLDP_TYPE_PRIVATE = 127
|
||||
};
|
||||
|
||||
/* IEEE 802.1AB-2009 Clause 8.5.2: Chassis subtypes */
|
||||
|
@ -46,7 +46,7 @@ enum {
|
|||
SD_LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS = 4,
|
||||
SD_LLDP_CHASSIS_SUBTYPE_NETWORK_ADDRESS = 5,
|
||||
SD_LLDP_CHASSIS_SUBTYPE_INTERFACE_NAME = 6,
|
||||
SD_LLDP_CHASSIS_SUBTYPE_LOCALLY_ASSIGNED = 7,
|
||||
SD_LLDP_CHASSIS_SUBTYPE_LOCALLY_ASSIGNED = 7
|
||||
};
|
||||
|
||||
/* IEEE 802.1AB-2009 Clause 8.5.3: Port subtype */
|
||||
|
@ -58,7 +58,7 @@ enum {
|
|||
SD_LLDP_PORT_SUBTYPE_NETWORK_ADDRESS = 4,
|
||||
SD_LLDP_PORT_SUBTYPE_INTERFACE_NAME = 5,
|
||||
SD_LLDP_PORT_SUBTYPE_AGENT_CIRCUIT_ID = 6,
|
||||
SD_LLDP_PORT_SUBTYPE_LOCALLY_ASSIGNED = 7,
|
||||
SD_LLDP_PORT_SUBTYPE_LOCALLY_ASSIGNED = 7
|
||||
};
|
||||
|
||||
/* IEEE 802.1AB-2009 Clause 8.5.8: System capabilities */
|
||||
|
@ -73,7 +73,7 @@ enum {
|
|||
SD_LLDP_SYSTEM_CAPABILITIES_STATION = 1 << 7,
|
||||
SD_LLDP_SYSTEM_CAPABILITIES_CVLAN = 1 << 8,
|
||||
SD_LLDP_SYSTEM_CAPABILITIES_SVLAN = 1 << 9,
|
||||
SD_LLDP_SYSTEM_CAPABILITIES_TPMR = 1 << 10,
|
||||
SD_LLDP_SYSTEM_CAPABILITIES_TPMR = 1 << 10
|
||||
};
|
||||
|
||||
#define SD_LLDP_SYSTEM_CAPABILITIES_ALL UINT16_MAX
|
||||
|
@ -107,7 +107,7 @@ enum {
|
|||
SD_LLDP_OUI_802_1_SUBTYPE_PROTOCOL_IDENTITY = 4,
|
||||
SD_LLDP_OUI_802_1_SUBTYPE_VID_USAGE_DIGEST = 5,
|
||||
SD_LLDP_OUI_802_1_SUBTYPE_MANAGEMENT_VID = 6,
|
||||
SD_LLDP_OUI_802_1_SUBTYPE_LINK_AGGREGATION = 7,
|
||||
SD_LLDP_OUI_802_1_SUBTYPE_LINK_AGGREGATION = 7
|
||||
};
|
||||
|
||||
/* IEEE 802.1AB-2009 Annex F */
|
||||
|
@ -115,7 +115,7 @@ enum {
|
|||
SD_LLDP_OUI_802_3_SUBTYPE_MAC_PHY_CONFIG_STATUS = 1,
|
||||
SD_LLDP_OUI_802_3_SUBTYPE_POWER_VIA_MDI = 2,
|
||||
SD_LLDP_OUI_802_3_SUBTYPE_LINK_AGGREGATION = 3,
|
||||
SD_LLDP_OUI_802_3_SUBTYPE_MAXIMUM_FRAME_SIZE = 4,
|
||||
SD_LLDP_OUI_802_3_SUBTYPE_MAXIMUM_FRAME_SIZE = 4
|
||||
};
|
||||
|
||||
_SD_END_DECLARATIONS;
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
along with systemd; If not, see <https://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <errno.h>
|
||||
|
@ -42,25 +42,25 @@ enum {
|
|||
SD_NDISC_OPTION_RDNSS = 25,
|
||||
SD_NDISC_OPTION_FLAGS_EXTENSION = 26,
|
||||
SD_NDISC_OPTION_DNSSL = 31,
|
||||
SD_NDISC_OPTION_CAPTIVE_PORTAL = 37,
|
||||
SD_NDISC_OPTION_CAPTIVE_PORTAL = 37
|
||||
};
|
||||
|
||||
/* Route preference, RFC 4191, Section 2.1 */
|
||||
enum {
|
||||
SD_NDISC_PREFERENCE_LOW = 3U,
|
||||
SD_NDISC_PREFERENCE_MEDIUM = 0U,
|
||||
SD_NDISC_PREFERENCE_HIGH = 1U,
|
||||
SD_NDISC_PREFERENCE_HIGH = 1U
|
||||
};
|
||||
|
||||
typedef struct sd_ndisc sd_ndisc;
|
||||
typedef struct sd_ndisc_router sd_ndisc_router;
|
||||
|
||||
typedef enum sd_ndisc_event_t {
|
||||
__extension__ typedef enum sd_ndisc_event_t {
|
||||
SD_NDISC_EVENT_TIMEOUT,
|
||||
SD_NDISC_EVENT_ROUTER,
|
||||
_SD_NDISC_EVENT_MAX,
|
||||
_SD_NDISC_EVENT_INVALID = -EINVAL,
|
||||
_SD_ENUM_FORCE_S64(NDISC_EVENT),
|
||||
_SD_ENUM_FORCE_S64(NDISC_EVENT)
|
||||
} sd_ndisc_event_t;
|
||||
|
||||
typedef void (*sd_ndisc_callback_t)(sd_ndisc *nd, sd_ndisc_event_t event, sd_ndisc_router *rt, void *userdata);
|
||||
|
@ -82,7 +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_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);
|
||||
|
||||
|
|
|
@ -55,8 +55,8 @@ typedef void* (*mfree_func_t)(void *p);
|
|||
typeof(a)* _a = &(a); \
|
||||
typeof(b)* _b = &(b); \
|
||||
free(*_a); \
|
||||
(*_a) = (*_b); \
|
||||
(*_b) = NULL; \
|
||||
*_a = *_b; \
|
||||
*_b = NULL; \
|
||||
0; \
|
||||
})
|
||||
|
||||
|
@ -174,23 +174,13 @@ void* greedy_realloc0(void **p, size_t need, size_t size);
|
|||
* is compatible with _FORTIFY_SOURCES. If _FORTIFY_SOURCES is used many memory operations will take the
|
||||
* object size as returned by __builtin_object_size() into account. Hence, let's return the smaller size of
|
||||
* malloc_usable_size() and __builtin_object_size() here, so that we definitely operate in safe territory by
|
||||
* both the compiler's and libc's standards. Note that _FORTIFY_SOURCES=3 handles also dynamically allocated
|
||||
* objects and thus it's safer using __builtin_dynamic_object_size if _FORTIFY_SOURCES=3 is used (#22801).
|
||||
* Moreover, when NULL is passed malloc_usable_size() is documented to return zero, and
|
||||
* both the compiler's and libc's standards. Note that __builtin_object_size() evaluates to SIZE_MAX if the
|
||||
* size cannot be determined, hence the MIN() expression should be safe with dynamically sized memory,
|
||||
* too. Moreover, when NULL is passed malloc_usable_size() is documented to return zero, and
|
||||
* __builtin_object_size() returns SIZE_MAX too, hence we also return a sensible value of 0 in this corner
|
||||
* case. */
|
||||
|
||||
#if defined __has_builtin
|
||||
# if __has_builtin(__builtin_dynamic_object_size)
|
||||
# define MALLOC_SIZEOF_SAFE(x) \
|
||||
MIN(malloc_usable_size(x), __builtin_dynamic_object_size(x, 0))
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef MALLOC_SIZEOF_SAFE
|
||||
#define MALLOC_SIZEOF_SAFE(x) \
|
||||
MIN(malloc_usable_size(x), __builtin_object_size(x, 0))
|
||||
#endif
|
||||
|
||||
/* Inspired by ELEMENTSOF() but operates on malloc()'ed memory areas: typesafely returns the number of items
|
||||
* that fit into the specified memory block */
|
||||
|
|
|
@ -32,7 +32,7 @@ static bool env_name_is_valid_n(const char *e, size_t n) {
|
|||
if (n <= 0)
|
||||
return false;
|
||||
|
||||
if (e[0] >= '0' && e[0] <= '9')
|
||||
if (ascii_isdigit(e[0]))
|
||||
return false;
|
||||
|
||||
/* POSIX says the overall size of the environment block cannot
|
||||
|
|
|
@ -763,8 +763,7 @@ int read_full_file_full(
|
|||
|
||||
r = xfopenat(dir_fd, filename, "re", 0, &f);
|
||||
if (r < 0) {
|
||||
_cleanup_close_ int dfd = -1, sk = -1;
|
||||
union sockaddr_union sa;
|
||||
_cleanup_close_ int sk = -1;
|
||||
|
||||
/* ENXIO is what Linux returns if we open a node that is an AF_UNIX socket */
|
||||
if (r != -ENXIO)
|
||||
|
@ -776,23 +775,7 @@ int read_full_file_full(
|
|||
|
||||
/* Seeking is not supported on AF_UNIX sockets */
|
||||
if (offset != UINT64_MAX)
|
||||
return -ESPIPE;
|
||||
|
||||
if (dir_fd == AT_FDCWD)
|
||||
r = sockaddr_un_set_path(&sa.un, filename);
|
||||
else {
|
||||
/* If we shall operate relative to some directory, then let's use O_PATH first to
|
||||
* open the socket inode, and then connect to it via /proc/self/fd/. We have to do
|
||||
* this since there's not connectat() that takes a directory fd as first arg. */
|
||||
|
||||
dfd = openat(dir_fd, filename, O_PATH|O_CLOEXEC);
|
||||
if (dfd < 0)
|
||||
return -errno;
|
||||
|
||||
r = sockaddr_un_set_path(&sa.un, FORMAT_PROC_FD_PATH(dfd));
|
||||
}
|
||||
if (r < 0)
|
||||
return r;
|
||||
return -ENXIO;
|
||||
|
||||
sk = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0);
|
||||
if (sk < 0)
|
||||
|
@ -809,12 +792,14 @@ int read_full_file_full(
|
|||
return r;
|
||||
|
||||
if (bind(sk, &bsa.sa, r) < 0)
|
||||
return r;
|
||||
return -errno;
|
||||
}
|
||||
|
||||
if (connect(sk, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0)
|
||||
return errno == ENOTSOCK ? -ENXIO : -errno; /* propagate original error if this is
|
||||
* not a socket after all */
|
||||
r = connect_unix_path(sk, dir_fd, filename);
|
||||
if (IN_SET(r, -ENOTSOCK, -EINVAL)) /* propagate original error if this is not a socket after all */
|
||||
return -ENXIO;
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (shutdown(sk, SHUT_WR) < 0)
|
||||
return -errno;
|
||||
|
|
|
@ -155,24 +155,23 @@ int readlink_malloc(const char *p, char **ret) {
|
|||
}
|
||||
|
||||
int readlink_value(const char *p, char **ret) {
|
||||
_cleanup_free_ char *link = NULL;
|
||||
char *value;
|
||||
_cleanup_free_ char *link = NULL, *name = NULL;
|
||||
int r;
|
||||
|
||||
assert(p);
|
||||
assert(ret);
|
||||
|
||||
r = readlink_malloc(p, &link);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
value = basename(link);
|
||||
if (!value)
|
||||
return -ENOENT;
|
||||
|
||||
value = strdup(value);
|
||||
if (!value)
|
||||
return -ENOMEM;
|
||||
|
||||
*ret = value;
|
||||
r = path_extract_filename(link, &name);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == O_DIRECTORY)
|
||||
return -EINVAL;
|
||||
|
||||
*ret = TAKE_PTR(name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
137
src/libnm-systemd-shared/src/basic/glyph-util.c
Normal file
137
src/libnm-systemd-shared/src/basic/glyph-util.c
Normal file
|
@ -0,0 +1,137 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include "env-util.h"
|
||||
#include "glyph-util.h"
|
||||
#include "locale-util.h"
|
||||
#include "strv.h"
|
||||
|
||||
bool emoji_enabled(void) {
|
||||
static int cached_emoji_enabled = -1;
|
||||
|
||||
if (cached_emoji_enabled < 0) {
|
||||
int val;
|
||||
|
||||
val = getenv_bool("SYSTEMD_EMOJI");
|
||||
if (val < 0)
|
||||
cached_emoji_enabled =
|
||||
is_locale_utf8() &&
|
||||
!STRPTR_IN_SET(getenv("TERM"), "dumb", "linux");
|
||||
else
|
||||
cached_emoji_enabled = val;
|
||||
}
|
||||
|
||||
return cached_emoji_enabled;
|
||||
}
|
||||
|
||||
const char *special_glyph(SpecialGlyph code) {
|
||||
|
||||
/* A list of a number of interesting unicode glyphs we can use to decorate our output. It's probably wise to be
|
||||
* conservative here, and primarily stick to the glyphs defined in the eurlatgr font, so that display still
|
||||
* works reasonably well on the Linux console. For details see:
|
||||
*
|
||||
* http://git.altlinux.org/people/legion/packages/kbd.git?p=kbd.git;a=blob;f=data/consolefonts/README.eurlatgr
|
||||
*/
|
||||
|
||||
static const char* const draw_table[2][_SPECIAL_GLYPH_MAX] = {
|
||||
/* ASCII fallback */
|
||||
[false] = {
|
||||
[SPECIAL_GLYPH_TREE_VERTICAL] = "| ",
|
||||
[SPECIAL_GLYPH_TREE_BRANCH] = "|-",
|
||||
[SPECIAL_GLYPH_TREE_RIGHT] = "`-",
|
||||
[SPECIAL_GLYPH_TREE_SPACE] = " ",
|
||||
[SPECIAL_GLYPH_TREE_TOP] = ",-",
|
||||
[SPECIAL_GLYPH_VERTICAL_DOTTED] = ":",
|
||||
[SPECIAL_GLYPH_TRIANGULAR_BULLET] = ">",
|
||||
[SPECIAL_GLYPH_BLACK_CIRCLE] = "*",
|
||||
[SPECIAL_GLYPH_WHITE_CIRCLE] = "*",
|
||||
[SPECIAL_GLYPH_MULTIPLICATION_SIGN] = "x",
|
||||
[SPECIAL_GLYPH_CIRCLE_ARROW] = "*",
|
||||
[SPECIAL_GLYPH_BULLET] = "*",
|
||||
[SPECIAL_GLYPH_MU] = "u",
|
||||
[SPECIAL_GLYPH_CHECK_MARK] = "+",
|
||||
[SPECIAL_GLYPH_CROSS_MARK] = "-",
|
||||
[SPECIAL_GLYPH_LIGHT_SHADE] = "-",
|
||||
[SPECIAL_GLYPH_DARK_SHADE] = "X",
|
||||
[SPECIAL_GLYPH_SIGMA] = "S",
|
||||
[SPECIAL_GLYPH_ARROW_RIGHT] = "->",
|
||||
[SPECIAL_GLYPH_ARROW_UP] = "^",
|
||||
[SPECIAL_GLYPH_ARROW_DOWN] = "v",
|
||||
[SPECIAL_GLYPH_ELLIPSIS] = "...",
|
||||
[SPECIAL_GLYPH_EXTERNAL_LINK] = "[LNK]",
|
||||
[SPECIAL_GLYPH_ECSTATIC_SMILEY] = ":-]",
|
||||
[SPECIAL_GLYPH_HAPPY_SMILEY] = ":-}",
|
||||
[SPECIAL_GLYPH_SLIGHTLY_HAPPY_SMILEY] = ":-)",
|
||||
[SPECIAL_GLYPH_NEUTRAL_SMILEY] = ":-|",
|
||||
[SPECIAL_GLYPH_SLIGHTLY_UNHAPPY_SMILEY] = ":-(",
|
||||
[SPECIAL_GLYPH_UNHAPPY_SMILEY] = ":-{",
|
||||
[SPECIAL_GLYPH_DEPRESSED_SMILEY] = ":-[",
|
||||
[SPECIAL_GLYPH_LOCK_AND_KEY] = "o-,",
|
||||
[SPECIAL_GLYPH_TOUCH] = "O=", /* Yeah, not very convincing, can you do it better? */
|
||||
[SPECIAL_GLYPH_RECYCLING] = "~",
|
||||
[SPECIAL_GLYPH_DOWNLOAD] = "\\",
|
||||
[SPECIAL_GLYPH_SPARKLES] = "*",
|
||||
},
|
||||
|
||||
/* UTF-8 */
|
||||
[true] = {
|
||||
/* The following are multiple glyphs in both ASCII and in UNICODE */
|
||||
[SPECIAL_GLYPH_TREE_VERTICAL] = u8"│ ",
|
||||
[SPECIAL_GLYPH_TREE_BRANCH] = u8"├─",
|
||||
[SPECIAL_GLYPH_TREE_RIGHT] = u8"└─",
|
||||
[SPECIAL_GLYPH_TREE_SPACE] = u8" ",
|
||||
[SPECIAL_GLYPH_TREE_TOP] = u8"┌─",
|
||||
|
||||
/* Single glyphs in both cases */
|
||||
[SPECIAL_GLYPH_VERTICAL_DOTTED] = u8"┆",
|
||||
[SPECIAL_GLYPH_TRIANGULAR_BULLET] = u8"‣",
|
||||
[SPECIAL_GLYPH_BLACK_CIRCLE] = u8"●",
|
||||
[SPECIAL_GLYPH_WHITE_CIRCLE] = u8"○",
|
||||
[SPECIAL_GLYPH_MULTIPLICATION_SIGN] = u8"×",
|
||||
[SPECIAL_GLYPH_CIRCLE_ARROW] = u8"↻",
|
||||
[SPECIAL_GLYPH_BULLET] = u8"•",
|
||||
[SPECIAL_GLYPH_MU] = u8"μ", /* actually called: GREEK SMALL LETTER MU */
|
||||
[SPECIAL_GLYPH_CHECK_MARK] = u8"✓",
|
||||
[SPECIAL_GLYPH_CROSS_MARK] = u8"✗", /* actually called: BALLOT X */
|
||||
[SPECIAL_GLYPH_LIGHT_SHADE] = u8"░",
|
||||
[SPECIAL_GLYPH_DARK_SHADE] = u8"▒",
|
||||
[SPECIAL_GLYPH_SIGMA] = u8"Σ",
|
||||
[SPECIAL_GLYPH_ARROW_UP] = u8"↑", /* actually called: UPWARDS ARROW */
|
||||
[SPECIAL_GLYPH_ARROW_DOWN] = u8"↓", /* actually called: DOWNWARDS ARROW */
|
||||
|
||||
/* Single glyph in Unicode, two in ASCII */
|
||||
[SPECIAL_GLYPH_ARROW_RIGHT] = u8"→", /* actually called: RIGHTWARDS ARROW */
|
||||
|
||||
/* Single glyph in Unicode, three in ASCII */
|
||||
[SPECIAL_GLYPH_ELLIPSIS] = u8"…", /* actually called: HORIZONTAL ELLIPSIS */
|
||||
|
||||
/* Three glyphs in Unicode, five in ASCII */
|
||||
[SPECIAL_GLYPH_EXTERNAL_LINK] = u8"[🡕]", /* actually called: NORTH EAST SANS-SERIF ARROW, enclosed in [] */
|
||||
|
||||
/* These smileys are a single glyph in Unicode, and three in ASCII */
|
||||
[SPECIAL_GLYPH_ECSTATIC_SMILEY] = u8"😇", /* actually called: SMILING FACE WITH HALO */
|
||||
[SPECIAL_GLYPH_HAPPY_SMILEY] = u8"😀", /* actually called: GRINNING FACE */
|
||||
[SPECIAL_GLYPH_SLIGHTLY_HAPPY_SMILEY] = u8"🙂", /* actually called: SLIGHTLY SMILING FACE */
|
||||
[SPECIAL_GLYPH_NEUTRAL_SMILEY] = u8"😐", /* actually called: NEUTRAL FACE */
|
||||
[SPECIAL_GLYPH_SLIGHTLY_UNHAPPY_SMILEY] = u8"🙁", /* actually called: SLIGHTLY FROWNING FACE */
|
||||
[SPECIAL_GLYPH_UNHAPPY_SMILEY] = u8"😨", /* actually called: FEARFUL FACE */
|
||||
[SPECIAL_GLYPH_DEPRESSED_SMILEY] = u8"🤢", /* actually called: NAUSEATED FACE */
|
||||
|
||||
/* This emoji is a single character cell glyph in Unicode, and three in ASCII */
|
||||
[SPECIAL_GLYPH_LOCK_AND_KEY] = u8"🔐", /* actually called: CLOSED LOCK WITH KEY */
|
||||
|
||||
/* This emoji is a single character cell glyph in Unicode, and two in ASCII */
|
||||
[SPECIAL_GLYPH_TOUCH] = u8"👆", /* actually called: BACKHAND INDEX POINTING UP */
|
||||
|
||||
/* These three emojis are single character cell glyphs in Unicode and also in ASCII. */
|
||||
[SPECIAL_GLYPH_RECYCLING] = u8"♻️", /* actually called: UNIVERSAL RECYCLNG SYMBOL */
|
||||
[SPECIAL_GLYPH_DOWNLOAD] = u8"⤵️", /* actually called: RIGHT ARROW CURVING DOWN */
|
||||
[SPECIAL_GLYPH_SPARKLES] = u8"✨",
|
||||
},
|
||||
};
|
||||
|
||||
if (code < 0)
|
||||
return NULL;
|
||||
|
||||
assert(code < _SPECIAL_GLYPH_MAX);
|
||||
return draw_table[code >= _SPECIAL_GLYPH_FIRST_EMOJI ? emoji_enabled() : is_locale_utf8()][code];
|
||||
}
|
60
src/libnm-systemd-shared/src/basic/glyph-util.h
Normal file
60
src/libnm-systemd-shared/src/basic/glyph-util.h
Normal file
|
@ -0,0 +1,60 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "macro.h"
|
||||
|
||||
typedef enum SpecialGlyph {
|
||||
SPECIAL_GLYPH_TREE_VERTICAL,
|
||||
SPECIAL_GLYPH_TREE_BRANCH,
|
||||
SPECIAL_GLYPH_TREE_RIGHT,
|
||||
SPECIAL_GLYPH_TREE_SPACE,
|
||||
SPECIAL_GLYPH_TREE_TOP,
|
||||
SPECIAL_GLYPH_VERTICAL_DOTTED,
|
||||
SPECIAL_GLYPH_TRIANGULAR_BULLET,
|
||||
SPECIAL_GLYPH_BLACK_CIRCLE,
|
||||
SPECIAL_GLYPH_WHITE_CIRCLE,
|
||||
SPECIAL_GLYPH_MULTIPLICATION_SIGN,
|
||||
SPECIAL_GLYPH_CIRCLE_ARROW,
|
||||
SPECIAL_GLYPH_BULLET,
|
||||
SPECIAL_GLYPH_MU,
|
||||
SPECIAL_GLYPH_CHECK_MARK,
|
||||
SPECIAL_GLYPH_CROSS_MARK,
|
||||
SPECIAL_GLYPH_ARROW_RIGHT,
|
||||
SPECIAL_GLYPH_ARROW_UP,
|
||||
SPECIAL_GLYPH_ARROW_DOWN,
|
||||
SPECIAL_GLYPH_ELLIPSIS,
|
||||
SPECIAL_GLYPH_LIGHT_SHADE,
|
||||
SPECIAL_GLYPH_DARK_SHADE,
|
||||
SPECIAL_GLYPH_SIGMA,
|
||||
SPECIAL_GLYPH_EXTERNAL_LINK,
|
||||
_SPECIAL_GLYPH_FIRST_EMOJI,
|
||||
SPECIAL_GLYPH_ECSTATIC_SMILEY = _SPECIAL_GLYPH_FIRST_EMOJI,
|
||||
SPECIAL_GLYPH_HAPPY_SMILEY,
|
||||
SPECIAL_GLYPH_SLIGHTLY_HAPPY_SMILEY,
|
||||
SPECIAL_GLYPH_NEUTRAL_SMILEY,
|
||||
SPECIAL_GLYPH_SLIGHTLY_UNHAPPY_SMILEY,
|
||||
SPECIAL_GLYPH_UNHAPPY_SMILEY,
|
||||
SPECIAL_GLYPH_DEPRESSED_SMILEY,
|
||||
SPECIAL_GLYPH_LOCK_AND_KEY,
|
||||
SPECIAL_GLYPH_TOUCH,
|
||||
SPECIAL_GLYPH_RECYCLING,
|
||||
SPECIAL_GLYPH_DOWNLOAD,
|
||||
SPECIAL_GLYPH_SPARKLES,
|
||||
_SPECIAL_GLYPH_MAX,
|
||||
_SPECIAL_GLYPH_INVALID = -EINVAL,
|
||||
} SpecialGlyph;
|
||||
|
||||
const char *special_glyph(SpecialGlyph code) _const_;
|
||||
|
||||
bool emoji_enabled(void);
|
||||
|
||||
static inline const char *special_glyph_check_mark(bool b) {
|
||||
return b ? special_glyph(SPECIAL_GLYPH_CHECK_MARK) : special_glyph(SPECIAL_GLYPH_CROSS_MARK);
|
||||
}
|
||||
|
||||
static inline const char *special_glyph_check_mark_space(bool b) {
|
||||
return b ? special_glyph(SPECIAL_GLYPH_CHECK_MARK) : " ";
|
||||
}
|
|
@ -102,10 +102,16 @@ DEFINE_HASH_OPS(uint64_hash_ops, uint64_t, uint64_hash_func, uint64_compare_func
|
|||
void devt_hash_func(const dev_t *p, struct siphash *state) {
|
||||
siphash24_compress(p, sizeof(dev_t), state);
|
||||
}
|
||||
#endif
|
||||
|
||||
int devt_compare_func(const dev_t *a, const dev_t *b) {
|
||||
return CMP(*a, *b);
|
||||
int r;
|
||||
|
||||
r = CMP(major(*a), major(*b));
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
return CMP(minor(*a), minor(*b));
|
||||
}
|
||||
|
||||
DEFINE_HASH_OPS(devt_hash_ops, dev_t, devt_hash_func, devt_compare_func);
|
||||
#endif
|
||||
|
|
|
@ -102,10 +102,9 @@ extern const struct hash_ops uint64_hash_ops;
|
|||
* 64bit archs. Yuck! */
|
||||
#if SIZEOF_DEV_T != 8
|
||||
void devt_hash_func(const dev_t *p, struct siphash *state) _pure_;
|
||||
int devt_compare_func(const dev_t *a, const dev_t *b) _pure_;
|
||||
extern const struct hash_ops devt_hash_ops;
|
||||
#else
|
||||
#define devt_hash_func uint64_hash_func
|
||||
#define devt_compare_func uint64_compare_func
|
||||
#define devt_hash_ops uint64_hash_ops
|
||||
#endif
|
||||
|
||||
int devt_compare_func(const dev_t *a, const dev_t *b) _pure_;
|
||||
extern const struct hash_ops devt_hash_ops;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include <errno.h>
|
||||
#include <fnmatch.h>
|
||||
#include <pthread.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
@ -770,16 +771,15 @@ static void shared_hash_key_initialize(void) {
|
|||
static struct HashmapBase* hashmap_base_new(const struct hash_ops *hash_ops, enum HashmapType type HASHMAP_DEBUG_PARAMS) {
|
||||
HashmapBase *h;
|
||||
const struct hashmap_type_info *hi = &hashmap_type_info[type];
|
||||
bool up;
|
||||
|
||||
up = mempool_enabled();
|
||||
bool use_pool = mempool_enabled && mempool_enabled();
|
||||
|
||||
h = up ? mempool_alloc0_tile(hi->mempool) : malloc0(hi->head_size);
|
||||
h = use_pool ? mempool_alloc0_tile(hi->mempool) : malloc0(hi->head_size);
|
||||
if (!h)
|
||||
return NULL;
|
||||
|
||||
h->type = type;
|
||||
h->from_pool = up;
|
||||
h->from_pool = use_pool;
|
||||
h->hash_ops = hash_ops ?: &trivial_hash_ops;
|
||||
|
||||
if (type == HASHMAP_TYPE_ORDERED) {
|
||||
|
@ -1841,7 +1841,7 @@ int _hashmap_put_strdup_full(Hashmap **h, const struct hash_ops *hash_ops, const
|
|||
return r;
|
||||
}
|
||||
|
||||
int _set_put_strdup_full(Set **s, const struct hash_ops *hash_ops, const char *p HASHMAP_DEBUG_PARAMS) {
|
||||
int _set_put_strndup_full(Set **s, const struct hash_ops *hash_ops, const char *p, size_t n HASHMAP_DEBUG_PARAMS) {
|
||||
char *c;
|
||||
int r;
|
||||
|
||||
|
@ -1852,10 +1852,13 @@ int _set_put_strdup_full(Set **s, const struct hash_ops *hash_ops, const char *p
|
|||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (set_contains(*s, (char*) p))
|
||||
return 0;
|
||||
if (n == SIZE_MAX) {
|
||||
if (set_contains(*s, (char*) p))
|
||||
return 0;
|
||||
|
||||
c = strdup(p);
|
||||
c = strdup(p);
|
||||
} else
|
||||
c = strndup(p, n);
|
||||
if (!c)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -1868,7 +1871,7 @@ int _set_put_strdupv_full(Set **s, const struct hash_ops *hash_ops, char **l HA
|
|||
assert(s);
|
||||
|
||||
STRV_FOREACH(i, l) {
|
||||
r = _set_put_strdup_full(s, hash_ops, *i HASHMAP_DEBUG_PASS_ARGS);
|
||||
r = _set_put_strndup_full(s, hash_ops, *i, SIZE_MAX HASHMAP_DEBUG_PASS_ARGS);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
@ -2070,3 +2073,27 @@ bool set_equal(Set *a, Set *b) {
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool set_fnmatch_one(Set *patterns, const char *needle) {
|
||||
const char *p;
|
||||
|
||||
assert(needle);
|
||||
|
||||
SET_FOREACH(p, patterns)
|
||||
if (fnmatch(p, needle, 0) == 0)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool set_fnmatch(Set *include_patterns, Set *exclude_patterns, const char *needle) {
|
||||
assert(needle);
|
||||
|
||||
if (set_fnmatch_one(exclude_patterns, needle))
|
||||
return false;
|
||||
|
||||
if (set_isempty(include_patterns))
|
||||
return true;
|
||||
|
||||
return set_fnmatch_one(include_patterns, needle);
|
||||
}
|
||||
|
|
|
@ -75,10 +75,8 @@ int gethostname_full(GetHostnameFlags flags, char **ret) {
|
|||
bool valid_ldh_char(char c) {
|
||||
/* "LDH" → "Letters, digits, hyphens", as per RFC 5890, Section 2.3.1 */
|
||||
|
||||
return
|
||||
(c >= 'a' && c <= 'z') ||
|
||||
(c >= 'A' && c <= 'Z') ||
|
||||
(c >= '0' && c <= '9') ||
|
||||
return ascii_isalpha(c) ||
|
||||
ascii_isdigit(c) ||
|
||||
c == '-';
|
||||
}
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "macro.h"
|
||||
#include "parse-util.h"
|
||||
#include "random-util.h"
|
||||
#include "stdio-util.h"
|
||||
#include "string-util.h"
|
||||
#include "strxcpyx.h"
|
||||
#include "util.h"
|
||||
|
@ -444,44 +445,33 @@ int in_addr_to_string(int family, const union in_addr_union *u, char **ret) {
|
|||
return -ENOMEM;
|
||||
|
||||
errno = 0;
|
||||
if (!inet_ntop(family, u, x, l))
|
||||
if (!typesafe_inet_ntop(family, u, x, l))
|
||||
return errno_or_else(EINVAL);
|
||||
|
||||
*ret = TAKE_PTR(x);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int in_addr_prefix_to_string(int family, const union in_addr_union *u, unsigned prefixlen, char **ret) {
|
||||
_cleanup_free_ char *x = NULL;
|
||||
char *p;
|
||||
size_t l;
|
||||
int in_addr_prefix_to_string(
|
||||
int family,
|
||||
const union in_addr_union *u,
|
||||
unsigned prefixlen,
|
||||
char *buf,
|
||||
size_t buf_len) {
|
||||
|
||||
assert(u);
|
||||
assert(ret);
|
||||
assert(buf);
|
||||
|
||||
if (family == AF_INET)
|
||||
l = INET_ADDRSTRLEN + 3;
|
||||
else if (family == AF_INET6)
|
||||
l = INET6_ADDRSTRLEN + 4;
|
||||
else
|
||||
if (!IN_SET(family, AF_INET, AF_INET6))
|
||||
return -EAFNOSUPPORT;
|
||||
|
||||
if (prefixlen > FAMILY_ADDRESS_SIZE(family) * 8)
|
||||
return -EINVAL;
|
||||
|
||||
x = new(char, l);
|
||||
if (!x)
|
||||
return -ENOMEM;
|
||||
|
||||
errno = 0;
|
||||
if (!inet_ntop(family, u, x, l))
|
||||
return errno_or_else(EINVAL);
|
||||
if (!typesafe_inet_ntop(family, u, buf, buf_len))
|
||||
return errno_or_else(ENOSPC);
|
||||
|
||||
p = x + strlen(x);
|
||||
l -= strlen(x);
|
||||
(void) strpcpyf(&p, l, "/%u", prefixlen);
|
||||
|
||||
*ret = TAKE_PTR(x);
|
||||
size_t l = strlen(buf);
|
||||
if (!snprintf_ok(buf + l, buf_len - l, "/%u", prefixlen))
|
||||
return -ENOSPC;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
#include <stddef.h>
|
||||
#include <sys/socket.h>
|
||||
|
@ -68,14 +69,62 @@ int in_addr_prefix_range(
|
|||
unsigned prefixlen,
|
||||
union in_addr_union *ret_start,
|
||||
union in_addr_union *ret_end);
|
||||
|
||||
int in_addr_to_string(int family, const union in_addr_union *u, char **ret);
|
||||
static inline int in6_addr_to_string(const struct in6_addr *u, char **ret) {
|
||||
return in_addr_to_string(AF_INET6, (const union in_addr_union*) u, ret);
|
||||
}
|
||||
int in_addr_prefix_to_string(int family, const union in_addr_union *u, unsigned prefixlen, char **ret);
|
||||
static inline int in6_addr_prefix_to_string(const struct in6_addr *u, unsigned prefixlen, char **ret) {
|
||||
return in_addr_prefix_to_string(AF_INET6, (const union in_addr_union*) u, prefixlen, ret);
|
||||
|
||||
static inline const char* typesafe_inet_ntop(int family, const union in_addr_union *a, char *buf, size_t len) {
|
||||
return inet_ntop(family, a, buf, len);
|
||||
}
|
||||
static inline const char* typesafe_inet_ntop4(const struct in_addr *a, char *buf, size_t len) {
|
||||
return inet_ntop(AF_INET, a, buf, len);
|
||||
}
|
||||
static inline const char* typesafe_inet_ntop6(const struct in6_addr *a, char *buf, size_t len) {
|
||||
return inet_ntop(AF_INET6, a, buf, len);
|
||||
}
|
||||
|
||||
/* 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 IN_ADDR_MAX CONST_MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN)
|
||||
#define IN_ADDR_TO_STRING(family, addr) typesafe_inet_ntop(family, addr, (char[IN_ADDR_MAX]){}, IN_ADDR_MAX)
|
||||
#define IN4_ADDR_TO_STRING(addr) typesafe_inet_ntop4(addr, (char[INET_ADDRSTRLEN]){}, INET_ADDRSTRLEN)
|
||||
#define IN6_ADDR_TO_STRING(addr) typesafe_inet_ntop6(addr, (char[INET6_ADDRSTRLEN]){}, INET6_ADDRSTRLEN)
|
||||
|
||||
int in_addr_prefix_to_string(
|
||||
int family,
|
||||
const union in_addr_union *u,
|
||||
unsigned prefixlen,
|
||||
char *buf,
|
||||
size_t buf_len);
|
||||
|
||||
static inline const char* _in_addr_prefix_to_string(
|
||||
int family,
|
||||
const union in_addr_union *u,
|
||||
unsigned prefixlen,
|
||||
char *buf,
|
||||
size_t buf_len) {
|
||||
/* We assume that this is called with an appropriately sized buffer and can never fail. */
|
||||
assert_se(in_addr_prefix_to_string(family, u, prefixlen, buf, buf_len) == 0);
|
||||
return buf;
|
||||
}
|
||||
static inline const char* _in4_addr_prefix_to_string(const struct in_addr *a, unsigned prefixlen, char *buf, size_t buf_len) {
|
||||
return _in_addr_prefix_to_string(AF_INET, (const union in_addr_union *) a, prefixlen, buf, buf_len);
|
||||
}
|
||||
static inline const char* _in6_addr_prefix_to_string(const struct in6_addr *a, unsigned prefixlen, char *buf, size_t buf_len) {
|
||||
return _in_addr_prefix_to_string(AF_INET6, (const union in_addr_union *) a, prefixlen, buf, buf_len);
|
||||
}
|
||||
|
||||
#define PREFIX_SUFFIX_MAX (1 + DECIMAL_STR_MAX(unsigned))
|
||||
#define IN_ADDR_PREFIX_TO_STRING(family, addr, prefixlen) \
|
||||
_in_addr_prefix_to_string(family, addr, prefixlen, (char[IN_ADDR_MAX + PREFIX_SUFFIX_MAX]){}, IN_ADDR_MAX + PREFIX_SUFFIX_MAX)
|
||||
#define IN4_ADDR_PREFIX_TO_STRING(addr, prefixlen) \
|
||||
_in4_addr_prefix_to_string(addr, prefixlen, (char[INET_ADDRSTRLEN + PREFIX_SUFFIX_MAX]){}, INET_ADDRSTRLEN + PREFIX_SUFFIX_MAX)
|
||||
#define IN6_ADDR_PREFIX_TO_STRING(addr, prefixlen) \
|
||||
_in6_addr_prefix_to_string(addr, prefixlen, (char[INET6_ADDRSTRLEN + PREFIX_SUFFIX_MAX]){}, INET6_ADDRSTRLEN + PREFIX_SUFFIX_MAX)
|
||||
|
||||
int in_addr_port_ifindex_name_to_string(int family, const union in_addr_union *u, uint16_t port, int ifindex, const char *server_name, char **ret);
|
||||
static inline int in_addr_ifindex_to_string(int family, const union in_addr_union *u, int ifindex, char **ret) {
|
||||
return in_addr_port_ifindex_name_to_string(family, u, 0, ifindex, NULL, ret);
|
||||
|
|
370
src/libnm-systemd-shared/src/basic/locale-util.c
Normal file
370
src/libnm-systemd-shared/src/basic/locale-util.c
Normal file
|
@ -0,0 +1,370 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <langinfo.h>
|
||||
#include <libintl.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "def.h"
|
||||
#include "dirent-util.h"
|
||||
#include "env-util.h"
|
||||
#include "fd-util.h"
|
||||
#include "fileio.h"
|
||||
#include "hashmap.h"
|
||||
#include "locale-util.h"
|
||||
#include "path-util.h"
|
||||
#include "set.h"
|
||||
#include "string-table.h"
|
||||
#include "string-util.h"
|
||||
#include "strv.h"
|
||||
#include "utf8.h"
|
||||
|
||||
static char *normalize_locale(const char *name) {
|
||||
const char *e;
|
||||
|
||||
/* Locale names are weird: glibc has some magic rules when looking for the charset name on disk: it
|
||||
* lowercases everything, and removes most special chars. This means the official .UTF-8 suffix
|
||||
* becomes .utf8 when looking things up on disk. When enumerating locales, let's do the reverse
|
||||
* operation, and go back to ".UTF-8" which appears to be the more commonly accepted name. We only do
|
||||
* that for UTF-8 however, since it's kinda the only charset that matters. */
|
||||
|
||||
e = endswith(name, ".utf8");
|
||||
if (e) {
|
||||
_cleanup_free_ char *prefix = NULL;
|
||||
|
||||
prefix = strndup(name, e - name);
|
||||
if (!prefix)
|
||||
return NULL;
|
||||
|
||||
return strjoin(prefix, ".UTF-8");
|
||||
}
|
||||
|
||||
e = strstr(name, ".utf8@");
|
||||
if (e) {
|
||||
_cleanup_free_ char *prefix = NULL;
|
||||
|
||||
prefix = strndup(name, e - name);
|
||||
if (!prefix)
|
||||
return NULL;
|
||||
|
||||
return strjoin(prefix, ".UTF-8@", e + 6);
|
||||
}
|
||||
|
||||
return strdup(name);
|
||||
}
|
||||
|
||||
static int add_locales_from_archive(Set *locales) {
|
||||
/* Stolen from glibc... */
|
||||
|
||||
struct locarhead {
|
||||
uint32_t magic;
|
||||
/* Serial number. */
|
||||
uint32_t serial;
|
||||
/* Name hash table. */
|
||||
uint32_t namehash_offset;
|
||||
uint32_t namehash_used;
|
||||
uint32_t namehash_size;
|
||||
/* String table. */
|
||||
uint32_t string_offset;
|
||||
uint32_t string_used;
|
||||
uint32_t string_size;
|
||||
/* Table with locale records. */
|
||||
uint32_t locrectab_offset;
|
||||
uint32_t locrectab_used;
|
||||
uint32_t locrectab_size;
|
||||
/* MD5 sum hash table. */
|
||||
uint32_t sumhash_offset;
|
||||
uint32_t sumhash_used;
|
||||
uint32_t sumhash_size;
|
||||
};
|
||||
|
||||
struct namehashent {
|
||||
/* Hash value of the name. */
|
||||
uint32_t hashval;
|
||||
/* Offset of the name in the string table. */
|
||||
uint32_t name_offset;
|
||||
/* Offset of the locale record. */
|
||||
uint32_t locrec_offset;
|
||||
};
|
||||
|
||||
const struct locarhead *h;
|
||||
const struct namehashent *e;
|
||||
const void *p = MAP_FAILED;
|
||||
_cleanup_close_ int fd = -1;
|
||||
size_t sz = 0;
|
||||
struct stat st;
|
||||
int r;
|
||||
|
||||
fd = open("/usr/lib/locale/locale-archive", O_RDONLY|O_NOCTTY|O_CLOEXEC);
|
||||
if (fd < 0)
|
||||
return errno == ENOENT ? 0 : -errno;
|
||||
|
||||
if (fstat(fd, &st) < 0)
|
||||
return -errno;
|
||||
|
||||
if (!S_ISREG(st.st_mode))
|
||||
return -EBADMSG;
|
||||
|
||||
if (st.st_size < (off_t) sizeof(struct locarhead))
|
||||
return -EBADMSG;
|
||||
|
||||
if (file_offset_beyond_memory_size(st.st_size))
|
||||
return -EFBIG;
|
||||
|
||||
p = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
|
||||
if (p == MAP_FAILED)
|
||||
return -errno;
|
||||
|
||||
h = (const struct locarhead *) p;
|
||||
if (h->magic != 0xde020109 ||
|
||||
h->namehash_offset + h->namehash_size > st.st_size ||
|
||||
h->string_offset + h->string_size > st.st_size ||
|
||||
h->locrectab_offset + h->locrectab_size > st.st_size ||
|
||||
h->sumhash_offset + h->sumhash_size > st.st_size) {
|
||||
r = -EBADMSG;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
e = (const struct namehashent*) ((const uint8_t*) p + h->namehash_offset);
|
||||
for (size_t i = 0; i < h->namehash_size; i++) {
|
||||
char *z;
|
||||
|
||||
if (e[i].locrec_offset == 0)
|
||||
continue;
|
||||
|
||||
if (!utf8_is_valid((char*) p + e[i].name_offset))
|
||||
continue;
|
||||
|
||||
z = normalize_locale((char*) p + e[i].name_offset);
|
||||
if (!z) {
|
||||
r = -ENOMEM;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
r = set_consume(locales, z);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
}
|
||||
|
||||
r = 0;
|
||||
|
||||
finish:
|
||||
if (p != MAP_FAILED)
|
||||
munmap((void*) p, sz);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int add_locales_from_libdir(Set *locales) {
|
||||
_cleanup_closedir_ DIR *dir = NULL;
|
||||
int r;
|
||||
|
||||
dir = opendir("/usr/lib/locale");
|
||||
if (!dir)
|
||||
return errno == ENOENT ? 0 : -errno;
|
||||
|
||||
FOREACH_DIRENT(de, dir, return -errno) {
|
||||
char *z;
|
||||
|
||||
if (de->d_type != DT_DIR)
|
||||
continue;
|
||||
|
||||
z = normalize_locale(de->d_name);
|
||||
if (!z)
|
||||
return -ENOMEM;
|
||||
|
||||
r = set_consume(locales, z);
|
||||
if (r < 0 && r != -EEXIST)
|
||||
return r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int get_locales(char ***ret) {
|
||||
_cleanup_set_free_free_ Set *locales = NULL;
|
||||
_cleanup_strv_free_ char **l = NULL;
|
||||
int r;
|
||||
|
||||
locales = set_new(&string_hash_ops);
|
||||
if (!locales)
|
||||
return -ENOMEM;
|
||||
|
||||
r = add_locales_from_archive(locales);
|
||||
if (r < 0 && r != -ENOENT)
|
||||
return r;
|
||||
|
||||
r = add_locales_from_libdir(locales);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
char *locale;
|
||||
SET_FOREACH(locale, locales) {
|
||||
r = locale_is_installed(locale);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
free(set_remove(locales, locale));
|
||||
}
|
||||
|
||||
l = set_get_strv(locales);
|
||||
if (!l)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Now, all elements are owned by strv 'l'. Hence, do not call set_free_free(). */
|
||||
locales = set_free(locales);
|
||||
|
||||
r = getenv_bool("SYSTEMD_LIST_NON_UTF8_LOCALES");
|
||||
if (r == -ENXIO || r == 0) {
|
||||
char **a, **b;
|
||||
|
||||
/* Filter out non-UTF-8 locales, because it's 2019, by default */
|
||||
for (a = b = l; *a; a++) {
|
||||
|
||||
if (endswith(*a, "UTF-8") ||
|
||||
strstr(*a, ".UTF-8@"))
|
||||
*(b++) = *a;
|
||||
else
|
||||
free(*a);
|
||||
}
|
||||
|
||||
*b = NULL;
|
||||
|
||||
} else if (r < 0)
|
||||
log_debug_errno(r, "Failed to parse $SYSTEMD_LIST_NON_UTF8_LOCALES as boolean");
|
||||
|
||||
strv_sort(l);
|
||||
|
||||
*ret = TAKE_PTR(l);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool locale_is_valid(const char *name) {
|
||||
|
||||
if (isempty(name))
|
||||
return false;
|
||||
|
||||
if (strlen(name) >= 128)
|
||||
return false;
|
||||
|
||||
if (!utf8_is_valid(name))
|
||||
return false;
|
||||
|
||||
if (!filename_is_valid(name))
|
||||
return false;
|
||||
|
||||
if (!string_is_safe(name))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int locale_is_installed(const char *name) {
|
||||
if (!locale_is_valid(name))
|
||||
return false;
|
||||
|
||||
if (STR_IN_SET(name, "C", "POSIX")) /* These ones are always OK */
|
||||
return true;
|
||||
|
||||
_cleanup_(freelocalep) locale_t loc =
|
||||
newlocale(LC_ALL_MASK, name, 0);
|
||||
if (loc == (locale_t) 0)
|
||||
return errno == ENOMEM ? -ENOMEM : false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void init_gettext(void) {
|
||||
setlocale(LC_ALL, "");
|
||||
textdomain(GETTEXT_PACKAGE);
|
||||
}
|
||||
|
||||
bool is_locale_utf8(void) {
|
||||
const char *set;
|
||||
static int cached_answer = -1;
|
||||
|
||||
/* Note that we default to 'true' here, since today UTF8 is
|
||||
* pretty much supported everywhere. */
|
||||
|
||||
if (cached_answer >= 0)
|
||||
goto out;
|
||||
|
||||
if (!setlocale(LC_ALL, "")) {
|
||||
cached_answer = true;
|
||||
goto out;
|
||||
}
|
||||
|
||||
set = nl_langinfo(CODESET);
|
||||
if (!set) {
|
||||
cached_answer = true;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (streq(set, "UTF-8")) {
|
||||
cached_answer = true;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* For LC_CTYPE=="C" return true, because CTYPE is effectively
|
||||
* unset and everything can do to UTF-8 nowadays. */
|
||||
set = setlocale(LC_CTYPE, NULL);
|
||||
if (!set) {
|
||||
cached_answer = true;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Check result, but ignore the result if C was set
|
||||
* explicitly. */
|
||||
cached_answer =
|
||||
STR_IN_SET(set, "C", "POSIX") &&
|
||||
!getenv("LC_ALL") &&
|
||||
!getenv("LC_CTYPE") &&
|
||||
!getenv("LANG");
|
||||
|
||||
out:
|
||||
return (bool) cached_answer;
|
||||
}
|
||||
|
||||
void locale_variables_free(char *l[_VARIABLE_LC_MAX]) {
|
||||
if (!l)
|
||||
return;
|
||||
|
||||
for (LocaleVariable i = 0; i < _VARIABLE_LC_MAX; i++)
|
||||
l[i] = mfree(l[i]);
|
||||
}
|
||||
|
||||
void locale_variables_simplify(char *l[_VARIABLE_LC_MAX]) {
|
||||
assert(l);
|
||||
|
||||
for (LocaleVariable p = 0; p < _VARIABLE_LC_MAX; p++) {
|
||||
if (p == VARIABLE_LANG)
|
||||
continue;
|
||||
if (isempty(l[p]) || streq_ptr(l[VARIABLE_LANG], l[p]))
|
||||
l[p] = mfree(l[p]);
|
||||
}
|
||||
}
|
||||
|
||||
static const char * const locale_variable_table[_VARIABLE_LC_MAX] = {
|
||||
[VARIABLE_LANG] = "LANG",
|
||||
[VARIABLE_LANGUAGE] = "LANGUAGE",
|
||||
[VARIABLE_LC_CTYPE] = "LC_CTYPE",
|
||||
[VARIABLE_LC_NUMERIC] = "LC_NUMERIC",
|
||||
[VARIABLE_LC_TIME] = "LC_TIME",
|
||||
[VARIABLE_LC_COLLATE] = "LC_COLLATE",
|
||||
[VARIABLE_LC_MONETARY] = "LC_MONETARY",
|
||||
[VARIABLE_LC_MESSAGES] = "LC_MESSAGES",
|
||||
[VARIABLE_LC_PAPER] = "LC_PAPER",
|
||||
[VARIABLE_LC_NAME] = "LC_NAME",
|
||||
[VARIABLE_LC_ADDRESS] = "LC_ADDRESS",
|
||||
[VARIABLE_LC_TELEPHONE] = "LC_TELEPHONE",
|
||||
[VARIABLE_LC_MEASUREMENT] = "LC_MEASUREMENT",
|
||||
[VARIABLE_LC_IDENTIFICATION] = "LC_IDENTIFICATION"
|
||||
};
|
||||
|
||||
DEFINE_STRING_TABLE_LOOKUP(locale_variable, LocaleVariable);
|
56
src/libnm-systemd-shared/src/basic/locale-util.h
Normal file
56
src/libnm-systemd-shared/src/basic/locale-util.h
Normal file
|
@ -0,0 +1,56 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#include <libintl.h>
|
||||
#include <locale.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "macro.h"
|
||||
|
||||
typedef enum LocaleVariable {
|
||||
/* We don't list LC_ALL here on purpose. People should be
|
||||
* using LANG instead. */
|
||||
|
||||
VARIABLE_LANG,
|
||||
VARIABLE_LANGUAGE,
|
||||
VARIABLE_LC_CTYPE,
|
||||
VARIABLE_LC_NUMERIC,
|
||||
VARIABLE_LC_TIME,
|
||||
VARIABLE_LC_COLLATE,
|
||||
VARIABLE_LC_MONETARY,
|
||||
VARIABLE_LC_MESSAGES,
|
||||
VARIABLE_LC_PAPER,
|
||||
VARIABLE_LC_NAME,
|
||||
VARIABLE_LC_ADDRESS,
|
||||
VARIABLE_LC_TELEPHONE,
|
||||
VARIABLE_LC_MEASUREMENT,
|
||||
VARIABLE_LC_IDENTIFICATION,
|
||||
_VARIABLE_LC_MAX,
|
||||
_VARIABLE_LC_INVALID = -EINVAL,
|
||||
} LocaleVariable;
|
||||
|
||||
int get_locales(char ***l);
|
||||
bool locale_is_valid(const char *name);
|
||||
int locale_is_installed(const char *name);
|
||||
|
||||
#define _(String) gettext(String)
|
||||
#define N_(String) String
|
||||
void init_gettext(void);
|
||||
|
||||
bool is_locale_utf8(void);
|
||||
|
||||
const char* locale_variable_to_string(LocaleVariable i) _const_;
|
||||
LocaleVariable locale_variable_from_string(const char *s) _pure_;
|
||||
|
||||
static inline void freelocalep(locale_t *p) {
|
||||
if (*p == (locale_t) 0)
|
||||
return;
|
||||
|
||||
freelocale(*p);
|
||||
}
|
||||
|
||||
void locale_variables_free(char* l[_VARIABLE_LC_MAX]);
|
||||
static inline void locale_variables_freep(char*(*l)[_VARIABLE_LC_MAX]) {
|
||||
locale_variables_free(*l);
|
||||
}
|
||||
void locale_variables_simplify(char *l[_VARIABLE_LC_MAX]);
|
|
@ -298,8 +298,16 @@ int log_emergency_level(void);
|
|||
|
||||
bool log_on_console(void) _pure_;
|
||||
|
||||
/* Helper to prepare various field for structured logging */
|
||||
#define LOG_MESSAGE(fmt, ...) "MESSAGE=" fmt, ##__VA_ARGS__
|
||||
/* Helper to wrap the main message in structured logging. The macro doesn't do much,
|
||||
* except to provide visual grouping of the format string and its arguments. */
|
||||
#if LOG_MESSAGE_VERIFICATION || defined(__COVERITY__)
|
||||
/* Do a fake formatting of the message string to let the scanner verify the arguments against the format
|
||||
* message. The variable will never be set to true, but we don't tell the compiler that :) */
|
||||
extern bool _log_message_dummy;
|
||||
# define LOG_MESSAGE(fmt, ...) "MESSAGE=%.0d" fmt, (_log_message_dummy && printf(fmt, ##__VA_ARGS__)), ##__VA_ARGS__
|
||||
#else
|
||||
# define LOG_MESSAGE(fmt, ...) "MESSAGE=" fmt, ##__VA_ARGS__
|
||||
#endif
|
||||
|
||||
void log_received_signal(int level, const struct signalfd_siginfo *si);
|
||||
|
||||
|
|
|
@ -11,24 +11,6 @@
|
|||
|
||||
#include "macro-fundamental.h"
|
||||
|
||||
#define _printf_(a, b) __attribute__((__format__(printf, a, b)))
|
||||
#ifdef __clang__
|
||||
# define _alloc_(...)
|
||||
#else
|
||||
# define _alloc_(...) __attribute__((__alloc_size__(__VA_ARGS__)))
|
||||
#endif
|
||||
#define _sentinel_ __attribute__((__sentinel__))
|
||||
#define _destructor_ __attribute__((__destructor__))
|
||||
#define _deprecated_ __attribute__((__deprecated__))
|
||||
#define _malloc_ __attribute__((__malloc__))
|
||||
#define _weak_ __attribute__((__weak__))
|
||||
#define _public_ __attribute__((__visibility__("default")))
|
||||
#define _hidden_ __attribute__((__visibility__("hidden")))
|
||||
#define _weakref_(x) __attribute__((__weakref__(#x)))
|
||||
#define _alignas_(x) __attribute__((__aligned__(__alignof__(x))))
|
||||
#define _alignptr_ __attribute__((__aligned__(sizeof(void*))))
|
||||
#define _warn_unused_result_ __attribute__((__warn_unused_result__))
|
||||
|
||||
#if !defined(HAS_FEATURE_MEMORY_SANITIZER)
|
||||
# if defined(__has_feature)
|
||||
# if __has_feature(memory_sanitizer)
|
||||
|
@ -128,25 +110,6 @@
|
|||
#error "neither int nor long are four bytes long?!?"
|
||||
#endif
|
||||
|
||||
/* Rounds up */
|
||||
|
||||
#define ALIGN4(l) (((l) + 3) & ~3)
|
||||
#define ALIGN8(l) (((l) + 7) & ~7)
|
||||
|
||||
#if __SIZEOF_POINTER__ == 8
|
||||
#define ALIGN(l) ALIGN8(l)
|
||||
#elif __SIZEOF_POINTER__ == 4
|
||||
#define ALIGN(l) ALIGN4(l)
|
||||
#else
|
||||
#error "Wut? Pointers are neither 4 nor 8 bytes long?"
|
||||
#endif
|
||||
|
||||
#define ALIGN_PTR(p) ((void*) ALIGN((unsigned long) (p)))
|
||||
#define ALIGN4_PTR(p) ((void*) ALIGN4((unsigned long) (p)))
|
||||
#define ALIGN8_PTR(p) ((void*) ALIGN8((unsigned long) (p)))
|
||||
|
||||
#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) */
|
||||
static inline unsigned long ALIGN_POWER2(unsigned long u) {
|
||||
|
||||
|
@ -361,7 +324,7 @@ static inline int __coverity_check_and_return__(int condition) {
|
|||
#ifndef thread_local
|
||||
/*
|
||||
* Don't break on glibc < 2.16 that doesn't define __STDC_NO_THREADS__
|
||||
* see http://gcc.gnu.org/bugzilla/show_bug.cgi?id=53769
|
||||
* see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53769
|
||||
*/
|
||||
#if __STDC_VERSION__ >= 201112L && !(defined(__STDC_NO_THREADS__) || (defined(__GNU_LIBRARY__) && __GLIBC__ == 2 && __GLIBC_MINOR__ < 16))
|
||||
#define thread_local _Thread_local
|
||||
|
@ -396,8 +359,12 @@ static inline int __coverity_check_and_return__(int condition) {
|
|||
if (!p) \
|
||||
return NULL; \
|
||||
\
|
||||
assert(p->n_ref > 0); \
|
||||
p->n_ref++; \
|
||||
/* For type check. */ \
|
||||
unsigned *q = &p->n_ref; \
|
||||
assert(*q > 0); \
|
||||
assert_se(*q < UINT_MAX); \
|
||||
\
|
||||
(*q)++; \
|
||||
return p; \
|
||||
}
|
||||
|
||||
|
@ -453,8 +420,15 @@ static inline int __coverity_check_and_return__(int condition) {
|
|||
_copy; \
|
||||
})
|
||||
|
||||
#define saturate_add(x, y, limit) \
|
||||
({ \
|
||||
typeof(limit) _x = (x); \
|
||||
typeof(limit) _y = (y); \
|
||||
_x > (limit) || _y >= (limit) - _x ? (limit) : _x + _y; \
|
||||
})
|
||||
|
||||
static inline size_t size_add(size_t x, size_t y) {
|
||||
return y >= SIZE_MAX - x ? SIZE_MAX : x + y;
|
||||
return saturate_add(x, y, SIZE_MAX);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
|
|
|
@ -3,12 +3,9 @@
|
|||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "env-util.h"
|
||||
#include "macro.h"
|
||||
#include "memory-util.h"
|
||||
#include "mempool.h"
|
||||
#include "process-util.h"
|
||||
#include "util.h"
|
||||
|
||||
struct pool {
|
||||
struct pool *next;
|
||||
|
@ -73,20 +70,6 @@ void mempool_free_tile(struct mempool *mp, void *p) {
|
|||
mp->freelist = p;
|
||||
}
|
||||
|
||||
bool mempool_enabled(void) {
|
||||
static int b = -1;
|
||||
|
||||
if (!is_main_thread())
|
||||
return false;
|
||||
|
||||
if (!mempool_use_allowed)
|
||||
b = false;
|
||||
if (b < 0)
|
||||
b = getenv_bool("SYSTEMD_MEMPOOL") != 0;
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
#if VALGRIND
|
||||
void mempool_drop(struct mempool *mp) {
|
||||
struct pool *p = mp->first_pool;
|
||||
|
|
|
@ -23,8 +23,7 @@ static struct mempool pool_name = { \
|
|||
.at_least = alloc_at_least, \
|
||||
}
|
||||
|
||||
extern const bool mempool_use_allowed;
|
||||
bool mempool_enabled(void);
|
||||
__attribute__((weak)) bool mempool_enabled(void);
|
||||
|
||||
#if VALGRIND
|
||||
void mempool_drop(struct mempool *mp);
|
||||
|
|
|
@ -74,6 +74,10 @@ static inline char** ordered_set_get_strv(OrderedSet *s) {
|
|||
return _hashmap_get_strv(HASHMAP_BASE((OrderedHashmap*) s));
|
||||
}
|
||||
|
||||
static inline int ordered_set_reserve(OrderedSet *s, unsigned entries_add) {
|
||||
return ordered_hashmap_reserve((OrderedHashmap*) s, entries_add);
|
||||
}
|
||||
|
||||
int ordered_set_consume(OrderedSet *s, void *p);
|
||||
int _ordered_set_put_strdup(OrderedSet **s, const char *p HASHMAP_DEBUG_PARAMS);
|
||||
#define ordered_set_put_strdup(s, p) _ordered_set_put_strdup(s, p HASHMAP_DEBUG_SRC_ARGS)
|
||||
|
|
|
@ -210,7 +210,7 @@ int parse_size(const char *t, uint64_t base, uint64_t *size) {
|
|||
e++;
|
||||
|
||||
/* strtoull() itself would accept space/+/- */
|
||||
if (*e >= '0' && *e <= '9') {
|
||||
if (ascii_isdigit(*e)) {
|
||||
unsigned long long l2;
|
||||
char *e2;
|
||||
|
||||
|
@ -599,7 +599,7 @@ int parse_fractional_part_u(const char **p, size_t digits, unsigned *res) {
|
|||
|
||||
/* accept any number of digits, strtoull is limited to 19 */
|
||||
for (size_t i = 0; i < digits; i++,s++) {
|
||||
if (*s < '0' || *s > '9') {
|
||||
if (!ascii_isdigit(*s)) {
|
||||
if (i == 0)
|
||||
return -EINVAL;
|
||||
|
||||
|
@ -692,34 +692,6 @@ int parse_ip_prefix_length(const char *s, int *ret) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int parse_dev(const char *s, dev_t *ret) {
|
||||
const char *major;
|
||||
unsigned x, y;
|
||||
size_t n;
|
||||
int r;
|
||||
|
||||
n = strspn(s, DIGITS);
|
||||
if (n == 0)
|
||||
return -EINVAL;
|
||||
if (s[n] != ':')
|
||||
return -EINVAL;
|
||||
|
||||
major = strndupa_safe(s, n);
|
||||
r = safe_atou(major, &x);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = safe_atou(s + n + 1, &y);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (!DEVICE_MAJOR_VALID(x) || !DEVICE_MINOR_VALID(y))
|
||||
return -ERANGE;
|
||||
|
||||
*ret = makedev(x, y);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int parse_oom_score_adjust(const char *s, int *ret) {
|
||||
int r, v;
|
||||
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
typedef unsigned long loadavg_t;
|
||||
|
||||
int parse_boolean(const char *v) _pure_;
|
||||
int parse_dev(const char *s, dev_t *ret);
|
||||
int parse_pid(const char *s, pid_t* ret_pid);
|
||||
int parse_mode(const char *s, mode_t *ret);
|
||||
int parse_ifindex(const char *s);
|
||||
|
|
|
@ -17,17 +17,13 @@
|
|||
#include "extract-word.h"
|
||||
#include "fd-util.h"
|
||||
#include "fs-util.h"
|
||||
#include "glob-util.h"
|
||||
#include "log.h"
|
||||
#include "macro.h"
|
||||
#include "nulstr-util.h"
|
||||
#include "parse-util.h"
|
||||
#include "path-util.h"
|
||||
#include "stat-util.h"
|
||||
#include "string-util.h"
|
||||
#include "strv.h"
|
||||
#include "time-util.h"
|
||||
#include "utf8.h"
|
||||
|
||||
int path_split_and_make_absolute(const char *p, char ***ret) {
|
||||
char **l;
|
||||
|
@ -376,52 +372,6 @@ char *path_simplify(char *path) {
|
|||
return path;
|
||||
}
|
||||
|
||||
int path_simplify_and_warn(
|
||||
char *path,
|
||||
unsigned flag,
|
||||
const char *unit,
|
||||
const char *filename,
|
||||
unsigned line,
|
||||
const char *lvalue) {
|
||||
|
||||
bool fatal = flag & PATH_CHECK_FATAL;
|
||||
|
||||
assert(!FLAGS_SET(flag, PATH_CHECK_ABSOLUTE | PATH_CHECK_RELATIVE));
|
||||
|
||||
if (!utf8_is_valid(path))
|
||||
return log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, path);
|
||||
|
||||
if (flag & (PATH_CHECK_ABSOLUTE | PATH_CHECK_RELATIVE)) {
|
||||
bool absolute;
|
||||
|
||||
absolute = path_is_absolute(path);
|
||||
|
||||
if (!absolute && (flag & PATH_CHECK_ABSOLUTE))
|
||||
return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL),
|
||||
"%s= path is not absolute%s: %s",
|
||||
lvalue, fatal ? "" : ", ignoring", path);
|
||||
|
||||
if (absolute && (flag & PATH_CHECK_RELATIVE))
|
||||
return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL),
|
||||
"%s= path is absolute%s: %s",
|
||||
lvalue, fatal ? "" : ", ignoring", path);
|
||||
}
|
||||
|
||||
path_simplify(path);
|
||||
|
||||
if (!path_is_valid(path))
|
||||
return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL),
|
||||
"%s= path has invalid length (%zu bytes)%s.",
|
||||
lvalue, strlen(path), fatal ? "" : ", ignoring");
|
||||
|
||||
if (!path_is_normalized(path))
|
||||
return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL),
|
||||
"%s= path is not normalized%s: %s",
|
||||
lvalue, fatal ? "" : ", ignoring", path);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *path_startswith_full(const char *path, const char *prefix, bool accept_dot_dot) {
|
||||
assert(path);
|
||||
assert(prefix);
|
||||
|
@ -1314,74 +1264,6 @@ bool valid_device_allow_pattern(const char *path) {
|
|||
return valid_device_node_path(path);
|
||||
}
|
||||
|
||||
int systemd_installation_has_version(const char *root, unsigned minimal_version) {
|
||||
const char *pattern;
|
||||
int r;
|
||||
|
||||
/* Try to guess if systemd installation is later than the specified version. This
|
||||
* is hacky and likely to yield false negatives, particularly if the installation
|
||||
* is non-standard. False positives should be relatively rare.
|
||||
*/
|
||||
|
||||
NULSTR_FOREACH(pattern,
|
||||
/* /lib works for systems without usr-merge, and for systems with a sane
|
||||
* usr-merge, where /lib is a symlink to /usr/lib. /usr/lib is necessary
|
||||
* for Gentoo which does a merge without making /lib a symlink.
|
||||
*/
|
||||
"lib/systemd/libsystemd-shared-*.so\0"
|
||||
"lib64/systemd/libsystemd-shared-*.so\0"
|
||||
"usr/lib/systemd/libsystemd-shared-*.so\0"
|
||||
"usr/lib64/systemd/libsystemd-shared-*.so\0") {
|
||||
|
||||
_cleanup_strv_free_ char **names = NULL;
|
||||
_cleanup_free_ char *path = NULL;
|
||||
char *c;
|
||||
|
||||
path = path_join(root, pattern);
|
||||
if (!path)
|
||||
return -ENOMEM;
|
||||
|
||||
r = glob_extend(&names, path, 0);
|
||||
if (r == -ENOENT)
|
||||
continue;
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
assert_se(c = endswith(path, "*.so"));
|
||||
*c = '\0'; /* truncate the glob part */
|
||||
|
||||
STRV_FOREACH(name, names) {
|
||||
/* This is most likely to run only once, hence let's not optimize anything. */
|
||||
char *t, *t2;
|
||||
unsigned version;
|
||||
|
||||
t = startswith(*name, path);
|
||||
if (!t)
|
||||
continue;
|
||||
|
||||
t2 = endswith(t, ".so");
|
||||
if (!t2)
|
||||
continue;
|
||||
|
||||
t2[0] = '\0'; /* truncate the suffix */
|
||||
|
||||
r = safe_atou(t, &version);
|
||||
if (r < 0) {
|
||||
log_debug_errno(r, "Found libsystemd shared at \"%s.so\", but failed to parse version: %m", *name);
|
||||
continue;
|
||||
}
|
||||
|
||||
log_debug("Found libsystemd shared at \"%s.so\", version %u (%s).",
|
||||
*name, version,
|
||||
version >= minimal_version ? "OK" : "too old");
|
||||
if (version >= minimal_version)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool dot_or_dot_dot(const char *path) {
|
||||
if (!path)
|
||||
return false;
|
||||
|
|
|
@ -77,14 +77,6 @@ char* path_extend_internal(char **x, ...);
|
|||
|
||||
char* path_simplify(char *path);
|
||||
|
||||
enum {
|
||||
PATH_CHECK_FATAL = 1 << 0, /* If not set, then error message is appended with 'ignoring'. */
|
||||
PATH_CHECK_ABSOLUTE = 1 << 1,
|
||||
PATH_CHECK_RELATIVE = 1 << 2,
|
||||
};
|
||||
|
||||
int path_simplify_and_warn(char *path, unsigned flag, const char *unit, const char *filename, unsigned line, const char *lvalue);
|
||||
|
||||
static inline bool path_equal_ptr(const char *a, const char *b) {
|
||||
return !!a == !!b && (!a || path_equal(a, b));
|
||||
}
|
||||
|
@ -181,8 +173,6 @@ bool is_device_path(const char *path);
|
|||
bool valid_device_node_path(const char *path);
|
||||
bool valid_device_allow_pattern(const char *path);
|
||||
|
||||
int systemd_installation_has_version(const char *root, unsigned minimal_version);
|
||||
|
||||
bool dot_or_dot_dot(const char *path);
|
||||
|
||||
static inline const char *skip_dev_prefix(const char *p) {
|
||||
|
|
|
@ -1026,7 +1026,7 @@ bool oom_score_adjust_is_valid(int oa) {
|
|||
}
|
||||
|
||||
unsigned long personality_from_string(const char *p) {
|
||||
int architecture;
|
||||
Architecture architecture;
|
||||
|
||||
if (!p)
|
||||
return PERSONALITY_INVALID;
|
||||
|
@ -1050,7 +1050,7 @@ unsigned long personality_from_string(const char *p) {
|
|||
}
|
||||
|
||||
const char* personality_to_string(unsigned long p) {
|
||||
int architecture = _ARCHITECTURE_INVALID;
|
||||
Architecture architecture = _ARCHITECTURE_INVALID;
|
||||
|
||||
if (p == PER_LINUX)
|
||||
architecture = native_architecture();
|
||||
|
|
|
@ -30,185 +30,142 @@
|
|||
#include "missing_syscall.h"
|
||||
#include "parse-util.h"
|
||||
#include "random-util.h"
|
||||
#include "siphash24.h"
|
||||
#include "sha256.h"
|
||||
#include "time-util.h"
|
||||
|
||||
static bool srand_called = false;
|
||||
/* This is a "best effort" kind of thing, but has no real security value.
|
||||
* So, this should only be used by random_bytes(), which is not meant for
|
||||
* crypto. This could be made better, but we're *not* trying to roll a
|
||||
* userspace prng here, or even have forward secrecy, but rather just do
|
||||
* the shortest thing that is at least better than libc rand(). */
|
||||
static void fallback_random_bytes(void *p, size_t n) {
|
||||
static thread_local uint64_t fallback_counter = 0;
|
||||
struct {
|
||||
char label[32];
|
||||
uint64_t call_id, block_id;
|
||||
usec_t stamp_mono, stamp_real;
|
||||
pid_t pid, tid;
|
||||
uint8_t auxval[16];
|
||||
} state = {
|
||||
/* Arbitrary domain separation to prevent other usage of AT_RANDOM from clashing. */
|
||||
.label = "systemd fallback random bytes v1",
|
||||
.call_id = fallback_counter++,
|
||||
.stamp_mono = now(CLOCK_MONOTONIC),
|
||||
.stamp_real = now(CLOCK_REALTIME),
|
||||
.pid = getpid(),
|
||||
.tid = gettid()
|
||||
};
|
||||
|
||||
int genuine_random_bytes(void *p, size_t n, RandomFlags flags) {
|
||||
static int have_syscall = -1;
|
||||
_cleanup_close_ int fd = -1;
|
||||
#if HAVE_SYS_AUXV_H
|
||||
memcpy(state.auxval, ULONG_TO_PTR(getauxval(AT_RANDOM)), sizeof(state.auxval));
|
||||
#endif
|
||||
|
||||
/* Gathers some high-quality randomness from the kernel. This call won't block, unless the RANDOM_BLOCK
|
||||
* flag is set. If it doesn't block, it will still always return some data from the kernel, regardless
|
||||
* of whether the random pool is fully initialized or not. When creating cryptographic key material you
|
||||
* should always use RANDOM_BLOCK. */
|
||||
while (n > 0) {
|
||||
struct sha256_ctx ctx;
|
||||
|
||||
if (n == 0)
|
||||
return 0;
|
||||
|
||||
/* Use the getrandom() syscall unless we know we don't have it. */
|
||||
if (have_syscall != 0 && !HAS_FEATURE_MEMORY_SANITIZER) {
|
||||
for (;;) {
|
||||
ssize_t l = getrandom(p, n, FLAGS_SET(flags, RANDOM_BLOCK) ? 0 : GRND_INSECURE);
|
||||
|
||||
if (l > 0) {
|
||||
have_syscall = true;
|
||||
|
||||
if ((size_t) l == n)
|
||||
return 0; /* Yay, success! */
|
||||
|
||||
/* We didn't get enough data, so try again */
|
||||
assert((size_t) l < n);
|
||||
p = (uint8_t*) p + l;
|
||||
n -= l;
|
||||
continue;
|
||||
|
||||
} else if (l == 0) {
|
||||
have_syscall = true;
|
||||
return -EIO;
|
||||
|
||||
} else if (ERRNO_IS_NOT_SUPPORTED(errno)) {
|
||||
/* We lack the syscall, continue with reading from /dev/urandom. */
|
||||
have_syscall = false;
|
||||
break;
|
||||
|
||||
} else if (errno == EINVAL) {
|
||||
/* If we previously passed GRND_INSECURE, and this flag isn't known, then
|
||||
* we're likely running an old kernel which has getrandom() but not
|
||||
* GRND_INSECURE. In this case, fall back to /dev/urandom. */
|
||||
if (!FLAGS_SET(flags, RANDOM_BLOCK))
|
||||
break;
|
||||
|
||||
return -errno;
|
||||
} else
|
||||
return -errno;
|
||||
sha256_init_ctx(&ctx);
|
||||
sha256_process_bytes(&state, sizeof(state), &ctx);
|
||||
if (n < SHA256_DIGEST_SIZE) {
|
||||
uint8_t partial[SHA256_DIGEST_SIZE];
|
||||
sha256_finish_ctx(&ctx, partial);
|
||||
memcpy(p, partial, n);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY);
|
||||
if (fd < 0)
|
||||
return errno == ENOENT ? -ENOSYS : -errno;
|
||||
|
||||
return loop_read_exact(fd, p, n, true);
|
||||
}
|
||||
|
||||
static void clear_srand_initialization(void) {
|
||||
srand_called = false;
|
||||
}
|
||||
|
||||
void initialize_srand(void) {
|
||||
static bool pthread_atfork_registered = false;
|
||||
unsigned x;
|
||||
#if HAVE_SYS_AUXV_H
|
||||
const void *auxv;
|
||||
#endif
|
||||
if (srand_called)
|
||||
return;
|
||||
|
||||
#if HAVE_SYS_AUXV_H
|
||||
/* The kernel provides us with 16 bytes of entropy in auxv, so let's try to make use of that to seed
|
||||
* the pseudo-random generator. It's better than nothing... But let's first hash it to make it harder
|
||||
* to recover the original value by watching any pseudo-random bits we generate. After all the
|
||||
* AT_RANDOM data might be used by other stuff too (in particular: ASLR), and we probably shouldn't
|
||||
* leak the seed for that. */
|
||||
|
||||
auxv = ULONG_TO_PTR(getauxval(AT_RANDOM));
|
||||
if (auxv) {
|
||||
static const uint8_t auxval_hash_key[16] = {
|
||||
0x92, 0x6e, 0xfe, 0x1b, 0xcf, 0x00, 0x52, 0x9c, 0xcc, 0x42, 0xcf, 0xdc, 0x94, 0x1f, 0x81, 0x0f
|
||||
};
|
||||
|
||||
x = (unsigned) siphash24(auxv, 16, auxval_hash_key);
|
||||
} else
|
||||
#endif
|
||||
x = 0;
|
||||
|
||||
x ^= (unsigned) now(CLOCK_REALTIME);
|
||||
x ^= (unsigned) gettid();
|
||||
|
||||
srand(x);
|
||||
srand_called = true;
|
||||
|
||||
if (!pthread_atfork_registered) {
|
||||
(void) pthread_atfork(NULL, NULL, clear_srand_initialization);
|
||||
pthread_atfork_registered = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* INT_MAX gives us only 31 bits, so use 24 out of that. */
|
||||
#if RAND_MAX >= INT_MAX
|
||||
assert_cc(RAND_MAX >= 16777215);
|
||||
# define RAND_STEP 3
|
||||
#else
|
||||
/* SHORT_INT_MAX or lower gives at most 15 bits, we just use 8 out of that. */
|
||||
assert_cc(RAND_MAX >= 255);
|
||||
# define RAND_STEP 1
|
||||
#endif
|
||||
|
||||
void pseudo_random_bytes(void *p, size_t n) {
|
||||
uint8_t *q;
|
||||
|
||||
/* This returns pseudo-random data using libc's rand() function. You probably never want to call this
|
||||
* directly, because why would you use this if you can get better stuff cheaply? Use random_bytes()
|
||||
* instead, see below: it will fall back to this function if there's nothing better to get, but only
|
||||
* then. */
|
||||
|
||||
initialize_srand();
|
||||
|
||||
for (q = p; q < (uint8_t*) p + n; q += RAND_STEP) {
|
||||
unsigned rr;
|
||||
|
||||
rr = (unsigned) rand();
|
||||
|
||||
#if RAND_STEP >= 3
|
||||
if ((size_t) (q - (uint8_t*) p + 2) < n)
|
||||
q[2] = rr >> 16;
|
||||
#endif
|
||||
#if RAND_STEP >= 2
|
||||
if ((size_t) (q - (uint8_t*) p + 1) < n)
|
||||
q[1] = rr >> 8;
|
||||
#endif
|
||||
q[0] = rr;
|
||||
sha256_finish_ctx(&ctx, p);
|
||||
p = (uint8_t *) p + SHA256_DIGEST_SIZE;
|
||||
n -= SHA256_DIGEST_SIZE;
|
||||
++state.block_id;
|
||||
}
|
||||
}
|
||||
|
||||
void random_bytes(void *p, size_t n) {
|
||||
static bool have_getrandom = true, have_grndinsecure = true;
|
||||
_cleanup_close_ int fd = -1;
|
||||
|
||||
/* This returns high quality randomness if we can get it cheaply. If we can't because for some reason
|
||||
* it is not available we'll try some crappy fallbacks.
|
||||
*
|
||||
* What this function will do:
|
||||
*
|
||||
* • Use getrandom(GRND_INSECURE) or /dev/urandom, to return high-quality random values if
|
||||
* they are cheaply available, or less high-quality random values if they are not.
|
||||
*
|
||||
* • This function will return pseudo-random data, generated via libc rand() if nothing
|
||||
* better is available.
|
||||
*
|
||||
* • This function will work fine in early boot
|
||||
*
|
||||
* • This function will always succeed
|
||||
*
|
||||
* What this function won't do:
|
||||
*
|
||||
* • This function will never fail: it will give you randomness no matter what. It might not
|
||||
* be high quality, but it will return some, possibly generated via libc's rand() call.
|
||||
*
|
||||
* • This function will never block: if the only way to get good randomness is a blocking,
|
||||
* synchronous getrandom() we'll instead provide you with pseudo-random data.
|
||||
*
|
||||
* This function is hence great for things like seeding hash tables, generating random numeric UNIX
|
||||
* user IDs (that are checked for collisions before use) and such.
|
||||
*
|
||||
* This function is hence not useful for generating UUIDs or cryptographic key material.
|
||||
*/
|
||||
|
||||
if (genuine_random_bytes(p, n, 0) >= 0)
|
||||
if (n == 0)
|
||||
return;
|
||||
|
||||
/* If for some reason some user made /dev/urandom unavailable to us, or the kernel has no entropy, use a PRNG instead. */
|
||||
pseudo_random_bytes(p, n);
|
||||
for (;;) {
|
||||
ssize_t l;
|
||||
|
||||
if (!have_getrandom)
|
||||
break;
|
||||
|
||||
l = getrandom(p, n, have_grndinsecure ? GRND_INSECURE : GRND_NONBLOCK);
|
||||
if (l > 0) {
|
||||
if ((size_t) l == n)
|
||||
return; /* Done reading, success. */
|
||||
p = (uint8_t *) p + l;
|
||||
n -= l;
|
||||
continue; /* Interrupted by a signal; keep going. */
|
||||
} else if (l == 0)
|
||||
break; /* Weird, so fallback to /dev/urandom. */
|
||||
else if (ERRNO_IS_NOT_SUPPORTED(errno)) {
|
||||
have_getrandom = false;
|
||||
break; /* No syscall, so fallback to /dev/urandom. */
|
||||
} else if (errno == EINVAL && have_grndinsecure) {
|
||||
have_grndinsecure = false;
|
||||
continue; /* No GRND_INSECURE; fallback to GRND_NONBLOCK. */
|
||||
} else if (errno == EAGAIN && !have_grndinsecure)
|
||||
break; /* Will block, but no GRND_INSECURE, so fallback to /dev/urandom. */
|
||||
|
||||
break; /* Unexpected, so just give up and fallback to /dev/urandom. */
|
||||
}
|
||||
|
||||
fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY);
|
||||
if (fd >= 0 && loop_read_exact(fd, p, n, false) == 0)
|
||||
return;
|
||||
|
||||
/* This is a terrible fallback. Oh well. */
|
||||
fallback_random_bytes(p, n);
|
||||
}
|
||||
|
||||
int crypto_random_bytes(void *p, size_t n) {
|
||||
static bool have_getrandom = true, seen_initialized = false;
|
||||
_cleanup_close_ int fd = -1;
|
||||
|
||||
if (n == 0)
|
||||
return 0;
|
||||
|
||||
for (;;) {
|
||||
ssize_t l;
|
||||
|
||||
if (!have_getrandom)
|
||||
break;
|
||||
|
||||
l = getrandom(p, n, 0);
|
||||
if (l > 0) {
|
||||
if ((size_t) l == n)
|
||||
return 0; /* Done reading, success. */
|
||||
p = (uint8_t *) p + l;
|
||||
n -= l;
|
||||
continue; /* Interrupted by a signal; keep going. */
|
||||
} else if (l == 0)
|
||||
return -EIO; /* Weird, should never happen. */
|
||||
else if (ERRNO_IS_NOT_SUPPORTED(errno)) {
|
||||
have_getrandom = false;
|
||||
break; /* No syscall, so fallback to /dev/urandom. */
|
||||
}
|
||||
return -errno;
|
||||
}
|
||||
|
||||
if (!seen_initialized) {
|
||||
_cleanup_close_ int ready_fd = -1;
|
||||
int r;
|
||||
|
||||
ready_fd = open("/dev/random", O_RDONLY|O_CLOEXEC|O_NOCTTY);
|
||||
if (ready_fd < 0)
|
||||
return -errno;
|
||||
r = fd_wait_for_event(ready_fd, POLLIN, USEC_INFINITY);
|
||||
if (r < 0)
|
||||
return r;
|
||||
seen_initialized = true;
|
||||
}
|
||||
|
||||
fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY);
|
||||
if (fd < 0)
|
||||
return -errno;
|
||||
return loop_read_exact(fd, p, n, false);
|
||||
}
|
||||
|
||||
size_t random_pool_size(void) {
|
||||
|
|
|
@ -5,15 +5,8 @@
|
|||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef enum RandomFlags {
|
||||
RANDOM_BLOCK = 1 << 0, /* Rather block than return crap randomness (only if the kernel supports that) */
|
||||
} RandomFlags;
|
||||
|
||||
int genuine_random_bytes(void *p, size_t n, RandomFlags flags); /* returns "genuine" randomness, optionally filled up with pseudo random, if not enough is available */
|
||||
void pseudo_random_bytes(void *p, size_t n); /* returns only pseudo-randommess (but possibly seeded from something better) */
|
||||
void random_bytes(void *p, size_t n); /* returns genuine randomness if cheaply available, and pseudo randomness if not. */
|
||||
|
||||
void initialize_srand(void);
|
||||
void random_bytes(void *p, size_t n); /* Returns random bytes suitable for most uses, but may be insecure sometimes. */
|
||||
int crypto_random_bytes(void *p, size_t n); /* Returns secure random bytes after waiting for the RNG to initialize. */
|
||||
|
||||
static inline uint64_t random_u64(void) {
|
||||
uint64_t u;
|
||||
|
|
|
@ -127,9 +127,12 @@ int _set_ensure_consume(Set **s, const struct hash_ops *hash_ops, void *key HAS
|
|||
|
||||
int set_consume(Set *s, void *value);
|
||||
|
||||
int _set_put_strdup_full(Set **s, const struct hash_ops *hash_ops, const char *p HASHMAP_DEBUG_PARAMS);
|
||||
#define set_put_strdup_full(s, hash_ops, p) _set_put_strdup_full(s, hash_ops, p HASHMAP_DEBUG_SRC_ARGS)
|
||||
#define set_put_strdup(s, p) set_put_strdup_full(s, &string_hash_ops_free, p)
|
||||
int _set_put_strndup_full(Set **s, const struct hash_ops *hash_ops, const char *p, size_t n HASHMAP_DEBUG_PARAMS);
|
||||
#define set_put_strndup_full(s, hash_ops, p, n) _set_put_strndup_full(s, hash_ops, p, n HASHMAP_DEBUG_SRC_ARGS)
|
||||
#define set_put_strdup_full(s, hash_ops, p) set_put_strndup_full(s, hash_ops, p, SIZE_MAX)
|
||||
#define set_put_strndup(s, p, n) set_put_strndup_full(s, &string_hash_ops_free, p, n)
|
||||
#define set_put_strdup(s, p) set_put_strndup(s, p, SIZE_MAX)
|
||||
|
||||
int _set_put_strdupv_full(Set **s, const struct hash_ops *hash_ops, char **l HASHMAP_DEBUG_PARAMS);
|
||||
#define set_put_strdupv_full(s, hash_ops, l) _set_put_strdupv_full(s, hash_ops, l HASHMAP_DEBUG_SRC_ARGS)
|
||||
#define set_put_strdupv(s, l) set_put_strdupv_full(s, &string_hash_ops_free, l)
|
||||
|
@ -153,3 +156,5 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(Set*, set_free_free);
|
|||
int set_strjoin(Set *s, const char *separator, bool wrap_with_separator, char **ret);
|
||||
|
||||
bool set_equal(Set *a, Set *b);
|
||||
|
||||
bool set_fnmatch(Set *include_patterns, Set *exclude_patterns, const char *needle);
|
||||
|
|
|
@ -490,9 +490,7 @@ int sockaddr_pretty(
|
|||
if (r < 0)
|
||||
return -ENOMEM;
|
||||
} else {
|
||||
char a[INET6_ADDRSTRLEN];
|
||||
|
||||
inet_ntop(AF_INET6, &sa->in6.sin6_addr, a, sizeof(a));
|
||||
const char *a = IN6_ADDR_TO_STRING(&sa->in6.sin6_addr);
|
||||
|
||||
if (include_port) {
|
||||
if (asprintf(&p,
|
||||
|
@ -651,24 +649,24 @@ int socknameinfo_pretty(union sockaddr_union *sa, socklen_t salen, char **_ret)
|
|||
}
|
||||
|
||||
static const char* const netlink_family_table[] = {
|
||||
[NETLINK_ROUTE] = "route",
|
||||
[NETLINK_FIREWALL] = "firewall",
|
||||
[NETLINK_INET_DIAG] = "inet-diag",
|
||||
[NETLINK_NFLOG] = "nflog",
|
||||
[NETLINK_XFRM] = "xfrm",
|
||||
[NETLINK_SELINUX] = "selinux",
|
||||
[NETLINK_ISCSI] = "iscsi",
|
||||
[NETLINK_AUDIT] = "audit",
|
||||
[NETLINK_FIB_LOOKUP] = "fib-lookup",
|
||||
[NETLINK_CONNECTOR] = "connector",
|
||||
[NETLINK_NETFILTER] = "netfilter",
|
||||
[NETLINK_IP6_FW] = "ip6-fw",
|
||||
[NETLINK_DNRTMSG] = "dnrtmsg",
|
||||
[NETLINK_ROUTE] = "route",
|
||||
[NETLINK_FIREWALL] = "firewall",
|
||||
[NETLINK_INET_DIAG] = "inet-diag",
|
||||
[NETLINK_NFLOG] = "nflog",
|
||||
[NETLINK_XFRM] = "xfrm",
|
||||
[NETLINK_SELINUX] = "selinux",
|
||||
[NETLINK_ISCSI] = "iscsi",
|
||||
[NETLINK_AUDIT] = "audit",
|
||||
[NETLINK_FIB_LOOKUP] = "fib-lookup",
|
||||
[NETLINK_CONNECTOR] = "connector",
|
||||
[NETLINK_NETFILTER] = "netfilter",
|
||||
[NETLINK_IP6_FW] = "ip6-fw",
|
||||
[NETLINK_DNRTMSG] = "dnrtmsg",
|
||||
[NETLINK_KOBJECT_UEVENT] = "kobject-uevent",
|
||||
[NETLINK_GENERIC] = "generic",
|
||||
[NETLINK_SCSITRANSPORT] = "scsitransport",
|
||||
[NETLINK_ECRYPTFS] = "ecryptfs",
|
||||
[NETLINK_RDMA] = "rdma",
|
||||
[NETLINK_GENERIC] = "generic",
|
||||
[NETLINK_SCSITRANSPORT] = "scsitransport",
|
||||
[NETLINK_ECRYPTFS] = "ecryptfs",
|
||||
[NETLINK_RDMA] = "rdma",
|
||||
};
|
||||
|
||||
DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(netlink_family, int, INT_MAX);
|
||||
|
@ -775,10 +773,10 @@ int fd_set_rcvbuf(int fd, size_t n, bool increase) {
|
|||
}
|
||||
|
||||
static const char* const ip_tos_table[] = {
|
||||
[IPTOS_LOWDELAY] = "low-delay",
|
||||
[IPTOS_THROUGHPUT] = "throughput",
|
||||
[IPTOS_LOWDELAY] = "low-delay",
|
||||
[IPTOS_THROUGHPUT] = "throughput",
|
||||
[IPTOS_RELIABILITY] = "reliability",
|
||||
[IPTOS_LOWCOST] = "low-cost",
|
||||
[IPTOS_LOWCOST] = "low-cost",
|
||||
};
|
||||
|
||||
DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(ip_tos, int, 0xff);
|
||||
|
@ -835,7 +833,7 @@ bool ifname_valid_full(const char *p, IfnameValidFlags flags) {
|
|||
if (!ifname_valid_char(*t))
|
||||
return false;
|
||||
|
||||
numeric = numeric && (*t >= '0' && *t <= '9');
|
||||
numeric = numeric && ascii_isdigit(*t);
|
||||
}
|
||||
|
||||
/* It's fully numeric but didn't parse as valid ifindex above? if so, it must be too large or zero or
|
||||
|
@ -1236,7 +1234,10 @@ int sockaddr_un_set_path(struct sockaddr_un *ret, const char *path) {
|
|||
* addresses!), which the kernel doesn't. We do this to reduce chance of incompatibility with other apps that
|
||||
* do not expect non-NUL terminated file system path. */
|
||||
if (l+1 > sizeof(ret->sun_path))
|
||||
return -EINVAL;
|
||||
return path[0] == '@' ? -EINVAL : -ENAMETOOLONG; /* return a recognizable error if this is
|
||||
* too long to fit into a sockaddr_un, but
|
||||
* is a file system path, and thus might be
|
||||
* connectible via O_PATH indirection. */
|
||||
|
||||
*ret = (struct sockaddr_un) {
|
||||
.sun_family = AF_UNIX,
|
||||
|
@ -1423,3 +1424,51 @@ int socket_get_mtu(int fd, int af, size_t *ret) {
|
|||
*ret = (size_t) mtu;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int connect_unix_path(int fd, int dir_fd, const char *path) {
|
||||
_cleanup_close_ int inode_fd = -1;
|
||||
union sockaddr_union sa = {
|
||||
.un.sun_family = AF_UNIX,
|
||||
};
|
||||
size_t path_len;
|
||||
socklen_t salen;
|
||||
|
||||
assert(fd >= 0);
|
||||
assert(dir_fd == AT_FDCWD || dir_fd >= 0);
|
||||
assert(path);
|
||||
|
||||
/* Connects to the specified AF_UNIX socket in the file system. Works around the 108 byte size limit
|
||||
* in sockaddr_un, by going via O_PATH if needed. This hence works for any kind of path. */
|
||||
|
||||
path_len = strlen(path);
|
||||
|
||||
/* Refuse zero length path early, to make sure AF_UNIX stack won't mistake this for an abstract
|
||||
* namespace path, since first char is NUL */
|
||||
if (path_len <= 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (dir_fd == AT_FDCWD && path_len < sizeof(sa.un.sun_path)) {
|
||||
memcpy(sa.un.sun_path, path, path_len + 1);
|
||||
salen = offsetof(struct sockaddr_un, sun_path) + path_len + 1;
|
||||
} else {
|
||||
const char *proc;
|
||||
size_t proc_len;
|
||||
|
||||
/* If dir_fd is specified, then we need to go the indirect O_PATH route, because connectat()
|
||||
* does not exist. If the path is too long, we also need to take the indirect route, since we
|
||||
* can't fit this into a sockaddr_un directly. */
|
||||
|
||||
inode_fd = openat(dir_fd, path, O_PATH|O_CLOEXEC);
|
||||
if (inode_fd < 0)
|
||||
return -errno;
|
||||
|
||||
proc = FORMAT_PROC_FD_PATH(inode_fd);
|
||||
proc_len = strlen(proc);
|
||||
|
||||
assert(proc_len < sizeof(sa.un.sun_path));
|
||||
memcpy(sa.un.sun_path, proc, proc_len + 1);
|
||||
salen = offsetof(struct sockaddr_un, sun_path) + proc_len + 1;
|
||||
}
|
||||
|
||||
return RET_NERRNO(connect(fd, &sa.sa, salen));
|
||||
}
|
||||
|
|
|
@ -129,7 +129,7 @@ static inline int fd_inc_sndbuf(int fd, size_t n) {
|
|||
return fd_set_sndbuf(fd, n, true);
|
||||
}
|
||||
int fd_set_rcvbuf(int fd, size_t n, bool increase);
|
||||
static inline int fd_inc_rcvbuf(int fd, size_t n) {
|
||||
static inline int fd_increase_rxbuf(int fd, size_t n) {
|
||||
return fd_set_rcvbuf(fd, n, true);
|
||||
}
|
||||
|
||||
|
@ -224,9 +224,9 @@ struct cmsghdr* cmsg_find(struct msghdr *mh, int level, int type, socklen_t leng
|
|||
strnlen(_sa->sun_path, sizeof(_sa->sun_path))+1); \
|
||||
})
|
||||
|
||||
#define SOCKADDR_LEN(sa) \
|
||||
#define SOCKADDR_LEN(saddr) \
|
||||
({ \
|
||||
const union sockaddr_union *__sa = &(sa); \
|
||||
const union sockaddr_union *__sa = &(saddr); \
|
||||
size_t _len; \
|
||||
switch (__sa->sa.sa_family) { \
|
||||
case AF_INET: \
|
||||
|
@ -332,3 +332,5 @@ 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 }
|
||||
|
||||
int connect_unix_path(int fd, int dir_fd, const char *path);
|
||||
|
|
|
@ -71,13 +71,10 @@ int is_device_node(const char *path) {
|
|||
return !!(S_ISBLK(info.st_mode) || S_ISCHR(info.st_mode));
|
||||
}
|
||||
|
||||
int dir_is_empty_at(int dir_fd, const char *path) {
|
||||
int dir_is_empty_at(int dir_fd, const char *path, bool ignore_hidden_or_backup) {
|
||||
_cleanup_close_ int fd = -1;
|
||||
/* 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;
|
||||
struct dirent *buf;
|
||||
size_t m;
|
||||
|
||||
if (path) {
|
||||
assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
|
||||
|
@ -99,15 +96,30 @@ int dir_is_empty_at(int dir_fd, const char *path) {
|
|||
return fd;
|
||||
}
|
||||
|
||||
n = getdents64(fd, &buffer, sizeof(buffer));
|
||||
if (n < 0)
|
||||
return -errno;
|
||||
/* 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. If
|
||||
* 'ignore_hidden_or_backup' is true we'll allocate a bit more, since we might skip over a bunch of
|
||||
* entries that we end up ignoring. */
|
||||
m = (ignore_hidden_or_backup ? 16 : 3) * DIRENT_SIZE_MAX;
|
||||
buf = alloca(m);
|
||||
|
||||
msan_unpoison(&buffer, n);
|
||||
for (;;) {
|
||||
struct dirent *de;
|
||||
ssize_t n;
|
||||
|
||||
FOREACH_DIRENT_IN_BUFFER(de, &buffer.de, n)
|
||||
if (!dot_or_dot_dot(de->d_name))
|
||||
return 0;
|
||||
n = getdents64(fd, buf, m);
|
||||
if (n < 0)
|
||||
return -errno;
|
||||
if (n == 0)
|
||||
break;
|
||||
|
||||
assert((size_t) n <= m);
|
||||
msan_unpoison(buf, n);
|
||||
|
||||
FOREACH_DIRENT_IN_BUFFER(de, buf, n)
|
||||
if (!(ignore_hidden_or_backup ? hidden_or_backup_file(de->d_name) : dot_or_dot_dot(de->d_name)))
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@ -314,101 +326,6 @@ int fd_verify_directory(int fd) {
|
|||
return stat_verify_directory(&st);
|
||||
}
|
||||
|
||||
int device_path_make_major_minor(mode_t mode, dev_t devno, char **ret) {
|
||||
const char *t;
|
||||
|
||||
/* Generates the /dev/{char|block}/MAJOR:MINOR path for a dev_t */
|
||||
|
||||
if (S_ISCHR(mode))
|
||||
t = "char";
|
||||
else if (S_ISBLK(mode))
|
||||
t = "block";
|
||||
else
|
||||
return -ENODEV;
|
||||
|
||||
if (asprintf(ret, "/dev/%s/%u:%u", t, major(devno), minor(devno)) < 0)
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int device_path_make_canonical(mode_t mode, dev_t devno, char **ret) {
|
||||
_cleanup_free_ char *p = NULL;
|
||||
int r;
|
||||
|
||||
/* Finds the canonical path for a device, i.e. resolves the /dev/{char|block}/MAJOR:MINOR path to the end. */
|
||||
|
||||
assert(ret);
|
||||
|
||||
if (major(devno) == 0 && minor(devno) == 0) {
|
||||
char *s;
|
||||
|
||||
/* A special hack to make sure our 'inaccessible' device nodes work. They won't have symlinks in
|
||||
* /dev/block/ and /dev/char/, hence we handle them specially here. */
|
||||
|
||||
if (S_ISCHR(mode))
|
||||
s = strdup("/run/systemd/inaccessible/chr");
|
||||
else if (S_ISBLK(mode))
|
||||
s = strdup("/run/systemd/inaccessible/blk");
|
||||
else
|
||||
return -ENODEV;
|
||||
|
||||
if (!s)
|
||||
return -ENOMEM;
|
||||
|
||||
*ret = s;
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = device_path_make_major_minor(mode, devno, &p);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return chase_symlinks(p, NULL, 0, ret, NULL);
|
||||
}
|
||||
|
||||
int device_path_parse_major_minor(const char *path, mode_t *ret_mode, dev_t *ret_devno) {
|
||||
mode_t mode;
|
||||
dev_t devno;
|
||||
int r;
|
||||
|
||||
/* Tries to extract the major/minor directly from the device path if we can. Handles /dev/block/ and /dev/char/
|
||||
* paths, as well out synthetic inaccessible device nodes. Never goes to disk. Returns -ENODEV if the device
|
||||
* path cannot be parsed like this. */
|
||||
|
||||
if (path_equal(path, "/run/systemd/inaccessible/chr")) {
|
||||
mode = S_IFCHR;
|
||||
devno = makedev(0, 0);
|
||||
} else if (path_equal(path, "/run/systemd/inaccessible/blk")) {
|
||||
mode = S_IFBLK;
|
||||
devno = makedev(0, 0);
|
||||
} else {
|
||||
const char *w;
|
||||
|
||||
w = path_startswith(path, "/dev/block/");
|
||||
if (w)
|
||||
mode = S_IFBLK;
|
||||
else {
|
||||
w = path_startswith(path, "/dev/char/");
|
||||
if (!w)
|
||||
return -ENODEV;
|
||||
|
||||
mode = S_IFCHR;
|
||||
}
|
||||
|
||||
r = parse_dev(w, &devno);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (ret_mode)
|
||||
*ret_mode = mode;
|
||||
if (ret_devno)
|
||||
*ret_devno = devno;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int proc_mounted(void) {
|
||||
int r;
|
||||
|
||||
|
|
|
@ -17,17 +17,9 @@ int is_dir(const char *path, bool follow);
|
|||
int is_dir_fd(int fd);
|
||||
int is_device_node(const char *path);
|
||||
|
||||
int dir_is_empty_at(int dir_fd, const char *path);
|
||||
static inline int dir_is_empty(const char *path) {
|
||||
return dir_is_empty_at(AT_FDCWD, path);
|
||||
}
|
||||
|
||||
static inline int dir_is_populated(const char *path) {
|
||||
int r;
|
||||
r = dir_is_empty(path);
|
||||
if (r < 0)
|
||||
return r;
|
||||
return !r;
|
||||
int dir_is_empty_at(int dir_fd, const char *path, bool ignore_hidden_or_backup);
|
||||
static inline int dir_is_empty(const char *path, bool ignore_hidden_or_backup) {
|
||||
return dir_is_empty_at(AT_FDCWD, path, ignore_hidden_or_backup);
|
||||
}
|
||||
|
||||
bool null_or_empty(struct stat *st) _pure_;
|
||||
|
@ -71,29 +63,6 @@ int fd_verify_regular(int fd);
|
|||
int stat_verify_directory(const struct stat *st);
|
||||
int fd_verify_directory(int fd);
|
||||
|
||||
/* glibc and the Linux kernel have different ideas about the major/minor size. These calls will check whether the
|
||||
* specified major is valid by the Linux kernel's standards, not by glibc's. Linux has 20bits of minor, and 12 bits of
|
||||
* major space. See MINORBITS in linux/kdev_t.h in the kernel sources. (If you wonder why we define _y here, instead of
|
||||
* comparing directly >= 0: it's to trick out -Wtype-limits, which would otherwise complain if the type is unsigned, as
|
||||
* such a test would be pointless in such a case.) */
|
||||
|
||||
#define DEVICE_MAJOR_VALID(x) \
|
||||
({ \
|
||||
typeof(x) _x = (x), _y = 0; \
|
||||
_x >= _y && _x < (UINT32_C(1) << 12); \
|
||||
\
|
||||
})
|
||||
|
||||
#define DEVICE_MINOR_VALID(x) \
|
||||
({ \
|
||||
typeof(x) _x = (x), _y = 0; \
|
||||
_x >= _y && _x < (UINT32_C(1) << 20); \
|
||||
})
|
||||
|
||||
int device_path_make_major_minor(mode_t mode, dev_t devno, char **ret);
|
||||
int device_path_make_canonical(mode_t mode, dev_t devno, char **ret);
|
||||
int device_path_parse_major_minor(const char *path, mode_t *ret_mode, dev_t *ret_devno);
|
||||
|
||||
int proc_mounted(void);
|
||||
|
||||
bool stat_inode_same(const struct stat *a, const struct stat *b);
|
||||
|
@ -119,9 +88,3 @@ int statx_fallback(int dfd, const char *path, int flags, unsigned mask, struct s
|
|||
struct new_statx nsx; \
|
||||
} var
|
||||
#endif
|
||||
|
||||
static inline bool devid_set_and_equal(dev_t a, dev_t b) {
|
||||
/* Returns true if a and b definitely refer to the same device. If either is zero, this means "don't
|
||||
* know" and we'll return false */
|
||||
return a == b && a != 0;
|
||||
}
|
||||
|
|
|
@ -1162,3 +1162,30 @@ bool streq_skip_trailing_chars(const char *s1, const char *s2, const char *ok) {
|
|||
|
||||
return in_charset(s1, ok) && in_charset(s2, ok);
|
||||
}
|
||||
|
||||
char *string_replace_char(char *str, char old_char, char new_char) {
|
||||
assert(str);
|
||||
assert(old_char != '\0');
|
||||
assert(new_char != '\0');
|
||||
assert(old_char != new_char);
|
||||
|
||||
for (char *p = strchr(str, old_char); p; p = strchr(p + 1, old_char))
|
||||
*p = new_char;
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
size_t strspn_from_end(const char *str, const char *accept) {
|
||||
size_t n = 0;
|
||||
|
||||
if (isempty(str))
|
||||
return 0;
|
||||
|
||||
if (isempty(accept))
|
||||
return 0;
|
||||
|
||||
for (const char *p = str + strlen(str); p > str && strchr(accept, p[-1]); p--)
|
||||
n++;
|
||||
|
||||
return n;
|
||||
}
|
||||
|
|
|
@ -10,17 +10,18 @@
|
|||
#include "string-util-fundamental.h"
|
||||
|
||||
/* What is interpreted as whitespace? */
|
||||
#define WHITESPACE " \t\n\r"
|
||||
#define NEWLINE "\n\r"
|
||||
#define QUOTES "\"\'"
|
||||
#define COMMENTS "#;"
|
||||
#define GLOB_CHARS "*?["
|
||||
#define DIGITS "0123456789"
|
||||
#define LOWERCASE_LETTERS "abcdefghijklmnopqrstuvwxyz"
|
||||
#define UPPERCASE_LETTERS "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
#define LETTERS LOWERCASE_LETTERS UPPERCASE_LETTERS
|
||||
#define ALPHANUMERICAL LETTERS DIGITS
|
||||
#define HEXDIGITS DIGITS "abcdefABCDEF"
|
||||
#define WHITESPACE " \t\n\r"
|
||||
#define NEWLINE "\n\r"
|
||||
#define QUOTES "\"\'"
|
||||
#define COMMENTS "#;"
|
||||
#define GLOB_CHARS "*?["
|
||||
#define DIGITS "0123456789"
|
||||
#define LOWERCASE_LETTERS "abcdefghijklmnopqrstuvwxyz"
|
||||
#define UPPERCASE_LETTERS "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
#define LETTERS LOWERCASE_LETTERS UPPERCASE_LETTERS
|
||||
#define ALPHANUMERICAL LETTERS DIGITS
|
||||
#define HEXDIGITS DIGITS "abcdefABCDEF"
|
||||
#define LOWERCASE_HEXDIGITS DIGITS "abcdef"
|
||||
|
||||
static inline char* strstr_ptr(const char *haystack, const char *needle) {
|
||||
if (!haystack || !needle)
|
||||
|
@ -28,10 +29,6 @@ static inline char* strstr_ptr(const char *haystack, const char *needle) {
|
|||
return strstr(haystack, needle);
|
||||
}
|
||||
|
||||
static inline const char* strempty(const char *s) {
|
||||
return s ?: "";
|
||||
}
|
||||
|
||||
static inline const char* strnull(const char *s) {
|
||||
return s ?: "(null)";
|
||||
}
|
||||
|
@ -180,13 +177,6 @@ int free_and_strndup(char **p, const char *s, size_t l);
|
|||
|
||||
bool string_is_safe(const char *p) _pure_;
|
||||
|
||||
static inline size_t strlen_ptr(const char *s) {
|
||||
if (!s)
|
||||
return 0;
|
||||
|
||||
return strlen(s);
|
||||
}
|
||||
|
||||
DISABLE_WARNING_STRINGOP_TRUNCATION;
|
||||
static inline void strncpy_exact(char *buf, const char *src, size_t buf_len) {
|
||||
strncpy(buf, src, buf_len);
|
||||
|
@ -232,3 +222,7 @@ static inline int string_contains_word(const char *string, const char *separator
|
|||
}
|
||||
|
||||
bool streq_skip_trailing_chars(const char *s1, const char *s2, const char *ok);
|
||||
|
||||
char *string_replace_char(char *str, char old_char, char new_char);
|
||||
|
||||
size_t strspn_from_end(const char *str, const char *accept);
|
||||
|
|
|
@ -351,7 +351,7 @@ int strv_split_colon_pairs(char ***t, const char *s) {
|
|||
return (int) n;
|
||||
}
|
||||
|
||||
char* strv_join_full(char * const *l, const char *separator, const char *prefix, bool unescape_separators) {
|
||||
char* strv_join_full(char * const *l, const char *separator, const char *prefix, bool escape_separator) {
|
||||
char *r, *e;
|
||||
size_t n, k, m;
|
||||
|
||||
|
@ -361,7 +361,7 @@ char* strv_join_full(char * const *l, const char *separator, const char *prefix,
|
|||
k = strlen(separator);
|
||||
m = strlen_ptr(prefix);
|
||||
|
||||
if (unescape_separators) /* If there separator is multi-char, we won't know how to escape it. */
|
||||
if (escape_separator) /* If the separator was multi-char, we wouldn't know how to escape it. */
|
||||
assert(k == 1);
|
||||
|
||||
n = 0;
|
||||
|
@ -369,7 +369,7 @@ char* strv_join_full(char * const *l, const char *separator, const char *prefix,
|
|||
if (s != l)
|
||||
n += k;
|
||||
|
||||
bool needs_escaping = unescape_separators && strchr(*s, separator[0]);
|
||||
bool needs_escaping = escape_separator && strchr(*s, *separator);
|
||||
|
||||
n += m + strlen(*s) * (1 + needs_escaping);
|
||||
}
|
||||
|
@ -386,11 +386,11 @@ char* strv_join_full(char * const *l, const char *separator, const char *prefix,
|
|||
if (prefix)
|
||||
e = stpcpy(e, prefix);
|
||||
|
||||
bool needs_escaping = unescape_separators && strchr(*s, separator[0]);
|
||||
bool needs_escaping = escape_separator && strchr(*s, *separator);
|
||||
|
||||
if (needs_escaping)
|
||||
for (size_t i = 0; (*s)[i]; i++) {
|
||||
if ((*s)[i] == separator[0])
|
||||
if ((*s)[i] == *separator)
|
||||
*(e++) = '\\';
|
||||
*(e++) = (*s)[i];
|
||||
}
|
||||
|
@ -403,27 +403,33 @@ char* strv_join_full(char * const *l, const char *separator, const char *prefix,
|
|||
return r;
|
||||
}
|
||||
|
||||
int strv_push(char ***l, char *value) {
|
||||
char **c;
|
||||
size_t n;
|
||||
int strv_push_with_size(char ***l, size_t *n, char *value) {
|
||||
/* n is a pointer to a variable to store the size of l.
|
||||
* If not given (i.e. n is NULL or *n is SIZE_MAX), size will be calculated using strv_length().
|
||||
* If n is not NULL, the size after the push will be returned.
|
||||
* If value is empty, no action is taken and *n is not set. */
|
||||
|
||||
if (!value)
|
||||
return 0;
|
||||
|
||||
n = strv_length(*l);
|
||||
size_t size = n ? *n : SIZE_MAX;
|
||||
if (size == SIZE_MAX)
|
||||
size = strv_length(*l);
|
||||
|
||||
/* Check for overflow */
|
||||
if (n > SIZE_MAX-2)
|
||||
if (size > SIZE_MAX-2)
|
||||
return -ENOMEM;
|
||||
|
||||
c = reallocarray(*l, GREEDY_ALLOC_ROUND_UP(n + 2), sizeof(char*));
|
||||
char **c = reallocarray(*l, GREEDY_ALLOC_ROUND_UP(size + 2), sizeof(char*));
|
||||
if (!c)
|
||||
return -ENOMEM;
|
||||
|
||||
c[n] = value;
|
||||
c[n+1] = NULL;
|
||||
c[size] = value;
|
||||
c[size+1] = NULL;
|
||||
|
||||
*l = c;
|
||||
if (n)
|
||||
*n = size + 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -484,10 +490,10 @@ int strv_insert(char ***l, size_t position, char *value) {
|
|||
return free_and_replace(*l, c);
|
||||
}
|
||||
|
||||
int strv_consume(char ***l, char *value) {
|
||||
int strv_consume_with_size(char ***l, size_t *n, char *value) {
|
||||
int r;
|
||||
|
||||
r = strv_push(l, value);
|
||||
r = strv_push_with_size(l, n, value);
|
||||
if (r < 0)
|
||||
free(value);
|
||||
|
||||
|
@ -529,7 +535,7 @@ int strv_prepend(char ***l, const char *value) {
|
|||
return strv_consume_prepend(l, v);
|
||||
}
|
||||
|
||||
int strv_extend(char ***l, const char *value) {
|
||||
int strv_extend_with_size(char ***l, size_t *n, const char *value) {
|
||||
char *v;
|
||||
|
||||
if (!value)
|
||||
|
@ -539,7 +545,7 @@ int strv_extend(char ***l, const char *value) {
|
|||
if (!v)
|
||||
return -ENOMEM;
|
||||
|
||||
return strv_consume(l, v);
|
||||
return strv_consume_with_size(l, n, v);
|
||||
}
|
||||
|
||||
int strv_extend_front(char ***l, const char *value) {
|
||||
|
|
|
@ -35,18 +35,36 @@ size_t strv_length(char * const *l) _pure_;
|
|||
int strv_extend_strv(char ***a, char * const *b, bool filter_duplicates);
|
||||
int strv_extend_strv_concat(char ***a, char * const *b, const char *suffix);
|
||||
int strv_prepend(char ***l, const char *value);
|
||||
int strv_extend(char ***l, const char *value);
|
||||
|
||||
/* _with_size() are lower-level functions where the size can be provided externally,
|
||||
* which allows us to skip iterating over the strv to find the end, which saves
|
||||
* a bit of time and reduces the complexity of appending from O(n²) to O(n). */
|
||||
|
||||
int strv_extend_with_size(char ***l, size_t *n, const char *value);
|
||||
static inline int strv_extend(char ***l, const char *value) {
|
||||
return strv_extend_with_size(l, NULL, value);
|
||||
}
|
||||
|
||||
int strv_extendf(char ***l, const char *format, ...) _printf_(2,0);
|
||||
int strv_extend_front(char ***l, const char *value);
|
||||
int strv_push(char ***l, char *value);
|
||||
|
||||
int strv_push_with_size(char ***l, size_t *n, char *value);
|
||||
static inline int strv_push(char ***l, char *value) {
|
||||
return strv_push_with_size(l, NULL, value);
|
||||
}
|
||||
int strv_push_pair(char ***l, char *a, char *b);
|
||||
|
||||
int strv_insert(char ***l, size_t position, char *value);
|
||||
|
||||
static inline int strv_push_prepend(char ***l, char *value) {
|
||||
return strv_insert(l, 0, value);
|
||||
}
|
||||
|
||||
int strv_consume(char ***l, char *value);
|
||||
int strv_consume_with_size(char ***l, size_t *n, char *value);
|
||||
static inline int strv_consume(char ***l, char *value) {
|
||||
return strv_consume_with_size(l, NULL, value);
|
||||
}
|
||||
|
||||
int strv_consume_pair(char ***l, char *a, char *b);
|
||||
int strv_consume_prepend(char ***l, char *value);
|
||||
|
||||
|
@ -77,7 +95,7 @@ int strv_split_full(char ***t, const char *s, const char *separators, ExtractFla
|
|||
static inline char** strv_split(const char *s, const char *separators) {
|
||||
char **ret;
|
||||
|
||||
if (strv_split_full(&ret, s, separators, 0) < 0)
|
||||
if (strv_split_full(&ret, s, separators, EXTRACT_RETAIN_ESCAPE) < 0)
|
||||
return NULL;
|
||||
|
||||
return ret;
|
||||
|
@ -101,7 +119,7 @@ static inline char** strv_split_newlines(const char *s) {
|
|||
* string in the vector is an empty string. */
|
||||
int strv_split_colon_pairs(char ***t, const char *s);
|
||||
|
||||
char* strv_join_full(char * const *l, const char *separator, const char *prefix, bool escape_separtor);
|
||||
char* strv_join_full(char * const *l, const char *separator, const char *prefix, bool escape_separator);
|
||||
static inline char *strv_join(char * const *l, const char *separator) {
|
||||
return strv_join_full(l, separator, NULL, false);
|
||||
}
|
||||
|
@ -122,12 +140,6 @@ static inline int strv_from_nulstr(char ***a, const char *nulstr) {
|
|||
|
||||
bool strv_overlap(char * const *a, char * const *b) _pure_;
|
||||
|
||||
#define _STRV_FOREACH(s, l, i) \
|
||||
for (typeof(*(l)) *s, *i = (l); (s = i) && *i; i++)
|
||||
|
||||
#define STRV_FOREACH(s, l) \
|
||||
_STRV_FOREACH(s, l, UNIQ_T(i, UNIQ))
|
||||
|
||||
#define _STRV_FOREACH_BACKWARDS(s, l, h, i) \
|
||||
for (typeof(*(l)) *s, *h = (l), *i = ({ \
|
||||
size_t _len = strv_length(h); \
|
||||
|
|
|
@ -29,10 +29,10 @@
|
|||
|
||||
static clockid_t map_clock_id(clockid_t c) {
|
||||
|
||||
/* Some more exotic archs (s390, ppc, …) lack the "ALARM" flavour of the clocks. Thus, clock_gettime() will
|
||||
* fail for them. Since they are essentially the same as their non-ALARM pendants (their only difference is
|
||||
* when timers are set on them), let's just map them accordingly. This way, we can get the correct time even on
|
||||
* those archs. */
|
||||
/* Some more exotic archs (s390, ppc, …) lack the "ALARM" flavour of the clocks. Thus,
|
||||
* clock_gettime() will fail for them. Since they are essentially the same as their non-ALARM
|
||||
* pendants (their only difference is when timers are set on them), let's just map them
|
||||
* accordingly. This way, we can get the correct time even on those archs. */
|
||||
|
||||
switch (c) {
|
||||
|
||||
|
@ -295,8 +295,8 @@ char *format_timestamp_style(
|
|||
usec_t t,
|
||||
TimestampStyle style) {
|
||||
|
||||
/* The weekdays in non-localized (English) form. We use this instead of the localized form, so that our
|
||||
* generated timestamps may be parsed with parse_timestamp(), and always read the same. */
|
||||
/* The weekdays in non-localized (English) form. We use this instead of the localized form, so that
|
||||
* our generated timestamps may be parsed with parse_timestamp(), and always read the same. */
|
||||
static const char * const weekdays[] = {
|
||||
[0] = "Sun",
|
||||
[1] = "Mon",
|
||||
|
@ -383,8 +383,8 @@ char *format_timestamp_style(
|
|||
/* Append the timezone */
|
||||
n = strlen(buf);
|
||||
if (utc) {
|
||||
/* If this is UTC then let's explicitly use the "UTC" string here, because gmtime_r() normally uses the
|
||||
* obsolete "GMT" instead. */
|
||||
/* If this is UTC then let's explicitly use the "UTC" string here, because gmtime_r()
|
||||
* normally uses the obsolete "GMT" instead. */
|
||||
if (n + 5 > l)
|
||||
return NULL; /* "UTC" doesn't fit. */
|
||||
|
||||
|
@ -399,12 +399,14 @@ char *format_timestamp_style(
|
|||
/* The full time zone does not fit in. Yuck. */
|
||||
|
||||
if (n + 1 + _POSIX_TZNAME_MAX + 1 > l)
|
||||
return NULL; /* Not even enough space for the POSIX minimum (of 6)? In that case, complain that it doesn't fit */
|
||||
return NULL; /* Not even enough space for the POSIX minimum (of 6)? In that
|
||||
* case, complain that it doesn't fit. */
|
||||
|
||||
/* So the time zone doesn't fit in fully, but the caller passed enough space for the POSIX
|
||||
* minimum time zone length. In this case suppress the timezone entirely, in order not to dump
|
||||
* an overly long, hard to read string on the user. This should be safe, because the user will
|
||||
* assume the local timezone anyway if none is shown. And so does parse_timestamp(). */
|
||||
/* So the time zone doesn't fit in fully, but the caller passed enough space for the
|
||||
* POSIX minimum time zone length. In this case suppress the timezone entirely, in
|
||||
* order not to dump an overly long, hard to read string on the user. This should be
|
||||
* safe, because the user will assume the local timezone anyway if none is shown. And
|
||||
* so does parse_timestamp(). */
|
||||
} else {
|
||||
buf[n++] = ' ';
|
||||
strcpy(buf + n, tm.tm_zone);
|
||||
|
@ -700,10 +702,11 @@ static int parse_timestamp_impl(const char *t, usec_t *usec, bool with_tz) {
|
|||
|
||||
tzset();
|
||||
|
||||
/* See if the timestamp is suffixed by either the DST or non-DST local timezone. Note that we only
|
||||
* support the local timezones here, nothing else. Not because we wouldn't want to, but simply because
|
||||
* there are no nice APIs available to cover this. By accepting the local time zone strings, we make
|
||||
* sure that all timestamps written by format_timestamp() can be parsed correctly, even though we don't
|
||||
/* See if the timestamp is suffixed by either the DST or non-DST local timezone. Note
|
||||
* that we only support the local timezones here, nothing else. Not because we
|
||||
* wouldn't want to, but simply because there are no nice APIs available to cover
|
||||
* this. By accepting the local time zone strings, we make sure that all timestamps
|
||||
* written by format_timestamp() can be parsed correctly, even though we don't
|
||||
* support arbitrary timezone specifications. */
|
||||
|
||||
for (j = 0; j <= 1; j++) {
|
||||
|
@ -1408,9 +1411,8 @@ int verify_timezone(const char *name, int log_level) {
|
|||
return -EINVAL;
|
||||
|
||||
for (p = name; *p; p++) {
|
||||
if (!(*p >= '0' && *p <= '9') &&
|
||||
!(*p >= 'a' && *p <= 'z') &&
|
||||
!(*p >= 'A' && *p <= 'Z') &&
|
||||
if (!ascii_isdigit(*p) &&
|
||||
!ascii_isalpha(*p) &&
|
||||
!IN_SET(*p, '-', '_', '+', '/'))
|
||||
return -EINVAL;
|
||||
|
||||
|
|
|
@ -2,36 +2,50 @@
|
|||
#pragma once
|
||||
|
||||
#ifndef SD_BOOT
|
||||
#include <assert.h>
|
||||
# include <assert.h>
|
||||
#endif
|
||||
|
||||
#include <limits.h>
|
||||
#include "types-fundamental.h"
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.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 _alignas_(x) __attribute__((__aligned__(__alignof__(x))))
|
||||
#define _alignptr_ __attribute__((__aligned__(sizeof(void *))))
|
||||
#define _cleanup_(x) __attribute__((__cleanup__(x)))
|
||||
#define _const_ __attribute__((__const__))
|
||||
#define _deprecated_ __attribute__((__deprecated__))
|
||||
#define _destructor_ __attribute__((__destructor__))
|
||||
#define _hidden_ __attribute__((__visibility__("hidden")))
|
||||
#define _likely_(x) (__builtin_expect(!!(x), 1))
|
||||
#define _unlikely_(x) (__builtin_expect(!!(x), 0))
|
||||
#if __GNUC__ >= 7
|
||||
#define _fallthrough_ __attribute__((__fallthrough__))
|
||||
#else
|
||||
#define _fallthrough_
|
||||
#endif
|
||||
/* Define C11 noreturn without <stdnoreturn.h> and even on older gcc
|
||||
* compiler versions */
|
||||
#ifndef _noreturn_
|
||||
#if __STDC_VERSION__ >= 201112L
|
||||
#define _malloc_ __attribute__((__malloc__))
|
||||
#define _noreturn_ _Noreturn
|
||||
#define _packed_ __attribute__((__packed__))
|
||||
#define _printf_(a, b) __attribute__((__format__(printf, a, b)))
|
||||
#define _public_ __attribute__((__visibility__("default")))
|
||||
#define _pure_ __attribute__((__pure__))
|
||||
#define _retain_ __attribute__((__retain__))
|
||||
#define _returns_nonnull_ __attribute__((__returns_nonnull__))
|
||||
#define _section_(x) __attribute__((__section__(x)))
|
||||
#define _sentinel_ __attribute__((__sentinel__))
|
||||
#define _unlikely_(x) (__builtin_expect(!!(x), 0))
|
||||
#define _unused_ __attribute__((__unused__))
|
||||
#define _used_ __attribute__((__used__))
|
||||
#define _warn_unused_result_ __attribute__((__warn_unused_result__))
|
||||
#define _weak_ __attribute__((__weak__))
|
||||
#define _weakref_(x) __attribute__((__weakref__(#x)))
|
||||
|
||||
#ifdef __clang__
|
||||
# define _alloc_(...)
|
||||
#else
|
||||
#define _noreturn_ __attribute__((__noreturn__))
|
||||
# define _alloc_(...) __attribute__((__alloc_size__(__VA_ARGS__)))
|
||||
#endif
|
||||
|
||||
#if __GNUC__ >= 7 || __clang__
|
||||
# define _fallthrough_ __attribute__((__fallthrough__))
|
||||
#else
|
||||
# define _fallthrough_
|
||||
#endif
|
||||
|
||||
#define XSTRINGIFY(x) #x
|
||||
|
@ -53,7 +67,7 @@
|
|||
#define CONCATENATE(x, y) XCONCATENATE(x, y)
|
||||
|
||||
#ifdef SD_BOOT
|
||||
void efi_assert(const char *expr, const char *file, unsigned line, const char *function) _noreturn_;
|
||||
_noreturn_ void efi_assert(const char *expr, const char *file, unsigned line, const char *function);
|
||||
|
||||
#ifdef NDEBUG
|
||||
#define assert(expr)
|
||||
|
@ -62,10 +76,8 @@
|
|||
#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 static_assert _Static_assert
|
||||
#define assert_se(expr) ({ _likely_(expr) ? VOID_0 : efi_assert(#expr, __FILE__, __LINE__, __PRETTY_FUNCTION__); })
|
||||
|
||||
#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. */
|
||||
|
@ -83,15 +95,8 @@
|
|||
_expr_; \
|
||||
})
|
||||
|
||||
#if defined(static_assert)
|
||||
#define assert_cc(expr) \
|
||||
static_assert(expr, #expr)
|
||||
#else
|
||||
#define assert_cc(expr) \
|
||||
struct CONCATENATE(_assert_struct_, __COUNTER__) { \
|
||||
char x[(expr) ? 0 : -1]; \
|
||||
}
|
||||
#endif
|
||||
#define assert_cc(expr) static_assert(expr, #expr)
|
||||
|
||||
|
||||
#define UNIQ_T(x, uniq) CONCATENATE(__unique_prefix_, CONCATENATE(x, uniq))
|
||||
#define UNIQ __COUNTER__
|
||||
|
@ -101,10 +106,10 @@
|
|||
* on this macro will run concurrently to all other code conditionalized
|
||||
* the same way, there's no ordering or completion enforced. */
|
||||
#define ONCE __ONCE(UNIQ_T(_once_, UNIQ))
|
||||
#define __ONCE(o) \
|
||||
({ \
|
||||
static sd_bool (o) = sd_false; \
|
||||
__sync_bool_compare_and_swap(&(o), sd_false, sd_true); \
|
||||
#define __ONCE(o) \
|
||||
({ \
|
||||
static bool (o) = false; \
|
||||
__sync_bool_compare_and_swap(&(o), false, true); \
|
||||
})
|
||||
|
||||
#undef MAX
|
||||
|
@ -254,7 +259,7 @@
|
|||
|
||||
#define IN_SET(x, ...) \
|
||||
({ \
|
||||
sd_bool _found = sd_false; \
|
||||
bool _found = 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 \
|
||||
|
@ -263,7 +268,7 @@
|
|||
assert_cc(ELEMENTSOF(__assert_in_set) <= 20); \
|
||||
switch (x) { \
|
||||
FOR_EACH_MAKE_CASE(__VA_ARGS__) \
|
||||
_found = sd_true; \
|
||||
_found = true; \
|
||||
break; \
|
||||
default: \
|
||||
break; \
|
||||
|
@ -295,9 +300,6 @@
|
|||
})
|
||||
|
||||
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);
|
||||
|
@ -315,6 +317,14 @@ static inline size_t ALIGN_TO(size_t l, size_t ali) {
|
|||
return ((l + ali - 1) & ~(ali - 1));
|
||||
}
|
||||
|
||||
#define ALIGN4(l) ALIGN_TO(l, 4)
|
||||
#define ALIGN8(l) ALIGN_TO(l, 8)
|
||||
#ifndef SD_BOOT
|
||||
/* libefi also provides ALIGN, and we do not use them in sd-boot explicitly. */
|
||||
#define ALIGN(l) ALIGN_TO(l, sizeof(void*))
|
||||
#define ALIGN_PTR(p) ((void*) ALIGN((uintptr_t) (p)))
|
||||
#endif
|
||||
|
||||
/* Same as ALIGN_TO but callable in constant contexts. */
|
||||
#define CONST_ALIGN_TO(l, ali) \
|
||||
__builtin_choose_expr( \
|
||||
|
|
291
src/libnm-systemd-shared/src/fundamental/sha256.c
Normal file
291
src/libnm-systemd-shared/src/fundamental/sha256.c
Normal file
|
@ -0,0 +1,291 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
/* Stolen from glibc and converted to our style. In glibc it comes with the following copyright blurb: */
|
||||
|
||||
/* Functions to compute SHA256 message digest of files or memory blocks.
|
||||
according to the definition of SHA256 in FIPS 180-2.
|
||||
Copyright (C) 2007-2022 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; if not, see
|
||||
<https://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <stdbool.h>
|
||||
#ifdef SD_BOOT
|
||||
# include "efi-string.h"
|
||||
#else
|
||||
# include <string.h>
|
||||
#endif
|
||||
|
||||
#include "macro-fundamental.h"
|
||||
#include "sha256.h"
|
||||
|
||||
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||
# define SWAP(n) \
|
||||
(((n) << 24) | (((n) & 0xff00) << 8) | (((n) >> 8) & 0xff00) | ((n) >> 24))
|
||||
# define SWAP64(n) \
|
||||
(((n) << 56) \
|
||||
| (((n) & 0xff00) << 40) \
|
||||
| (((n) & 0xff0000) << 24) \
|
||||
| (((n) & 0xff000000) << 8) \
|
||||
| (((n) >> 8) & 0xff000000) \
|
||||
| (((n) >> 24) & 0xff0000) \
|
||||
| (((n) >> 40) & 0xff00) \
|
||||
| ((n) >> 56))
|
||||
#else
|
||||
# define SWAP(n) (n)
|
||||
# define SWAP64(n) (n)
|
||||
#endif
|
||||
|
||||
/* The condition below is from glibc's string/string-inline.c.
|
||||
* See definition of _STRING_INLINE_unaligned. */
|
||||
#if !defined(__mc68020__) && !defined(__s390__) && !defined(__i386__)
|
||||
# define UNALIGNED_P(p) (((uintptr_t) p) % __alignof__(uint32_t) != 0)
|
||||
#else
|
||||
# define UNALIGNED_P(p) false
|
||||
#endif
|
||||
|
||||
/* This array contains the bytes used to pad the buffer to the next
|
||||
64-byte boundary. (FIPS 180-2:5.1.1) */
|
||||
static const uint8_t fillbuf[64] = {
|
||||
0x80, 0 /* , 0, 0, ... */
|
||||
};
|
||||
|
||||
/* Constants for SHA256 from FIPS 180-2:4.2.2. */
|
||||
static const uint32_t K[64] = {
|
||||
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
|
||||
0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
|
||||
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
|
||||
0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
|
||||
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
|
||||
0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
|
||||
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
|
||||
0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
|
||||
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
|
||||
0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
|
||||
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
|
||||
0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
|
||||
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
|
||||
0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
|
||||
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
|
||||
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
|
||||
};
|
||||
|
||||
static void sha256_process_block(const void *, size_t, struct sha256_ctx *);
|
||||
|
||||
/* Initialize structure containing state of computation.
|
||||
(FIPS 180-2:5.3.2) */
|
||||
void sha256_init_ctx(struct sha256_ctx *ctx) {
|
||||
assert(ctx);
|
||||
|
||||
ctx->H[0] = 0x6a09e667;
|
||||
ctx->H[1] = 0xbb67ae85;
|
||||
ctx->H[2] = 0x3c6ef372;
|
||||
ctx->H[3] = 0xa54ff53a;
|
||||
ctx->H[4] = 0x510e527f;
|
||||
ctx->H[5] = 0x9b05688c;
|
||||
ctx->H[6] = 0x1f83d9ab;
|
||||
ctx->H[7] = 0x5be0cd19;
|
||||
|
||||
ctx->total64 = 0;
|
||||
ctx->buflen = 0;
|
||||
}
|
||||
|
||||
/* Process the remaining bytes in the internal buffer and the usual
|
||||
prolog according to the standard and write the result to RESBUF. */
|
||||
void *sha256_finish_ctx(struct sha256_ctx *ctx, void *resbuf) {
|
||||
/* Take yet unprocessed bytes into account. */
|
||||
uint32_t bytes = ctx->buflen;
|
||||
size_t pad;
|
||||
|
||||
assert(ctx);
|
||||
assert(resbuf);
|
||||
|
||||
/* Now count remaining bytes. */
|
||||
ctx->total64 += bytes;
|
||||
|
||||
pad = bytes >= 56 ? 64 + 56 - bytes : 56 - bytes;
|
||||
memcpy(&ctx->buffer[bytes], fillbuf, pad);
|
||||
|
||||
/* Put the 64-bit file length in *bits* at the end of the buffer. */
|
||||
ctx->buffer32[(bytes + pad + 4) / 4] = SWAP(ctx->total[TOTAL64_low] << 3);
|
||||
ctx->buffer32[(bytes + pad) / 4] = SWAP((ctx->total[TOTAL64_high] << 3)
|
||||
| (ctx->total[TOTAL64_low] >> 29));
|
||||
|
||||
/* Process last bytes. */
|
||||
sha256_process_block(ctx->buffer, bytes + pad + 8, ctx);
|
||||
|
||||
/* Put result from CTX in first 32 bytes following RESBUF. */
|
||||
for (size_t i = 0; i < 8; ++i)
|
||||
if (UNALIGNED_P(resbuf))
|
||||
memcpy((uint8_t*) resbuf + i * sizeof(uint32_t), (uint32_t[]) { SWAP(ctx->H[i]) }, sizeof(uint32_t));
|
||||
else
|
||||
((uint32_t *) resbuf)[i] = SWAP(ctx->H[i]);
|
||||
|
||||
return resbuf;
|
||||
}
|
||||
|
||||
void sha256_process_bytes(const void *buffer, size_t len, struct sha256_ctx *ctx) {
|
||||
assert(buffer);
|
||||
assert(ctx);
|
||||
|
||||
/* When we already have some bits in our internal buffer concatenate
|
||||
both inputs first. */
|
||||
|
||||
if (ctx->buflen != 0) {
|
||||
size_t left_over = ctx->buflen;
|
||||
size_t add = 128 - left_over > len ? len : 128 - left_over;
|
||||
|
||||
memcpy(&ctx->buffer[left_over], buffer, add);
|
||||
ctx->buflen += add;
|
||||
|
||||
if (ctx->buflen > 64) {
|
||||
sha256_process_block(ctx->buffer, ctx->buflen & ~63, ctx);
|
||||
|
||||
ctx->buflen &= 63;
|
||||
/* The regions in the following copy operation cannot overlap. */
|
||||
memcpy(ctx->buffer, &ctx->buffer[(left_over + add) & ~63],
|
||||
ctx->buflen);
|
||||
}
|
||||
|
||||
buffer = (const char *) buffer + add;
|
||||
len -= add;
|
||||
}
|
||||
|
||||
/* Process available complete blocks. */
|
||||
if (len >= 64) {
|
||||
if (UNALIGNED_P(buffer))
|
||||
while (len > 64) {
|
||||
memcpy(ctx->buffer, buffer, 64);
|
||||
sha256_process_block(ctx->buffer, 64, ctx);
|
||||
buffer = (const char *) buffer + 64;
|
||||
len -= 64;
|
||||
}
|
||||
else {
|
||||
sha256_process_block(buffer, len & ~63, ctx);
|
||||
buffer = (const char *) buffer + (len & ~63);
|
||||
len &= 63;
|
||||
}
|
||||
}
|
||||
|
||||
/* Move remaining bytes into internal buffer. */
|
||||
if (len > 0) {
|
||||
size_t left_over = ctx->buflen;
|
||||
|
||||
memcpy(&ctx->buffer[left_over], buffer, len);
|
||||
left_over += len;
|
||||
if (left_over >= 64) {
|
||||
sha256_process_block(ctx->buffer, 64, ctx);
|
||||
left_over -= 64;
|
||||
memcpy(ctx->buffer, &ctx->buffer[64], left_over);
|
||||
}
|
||||
ctx->buflen = left_over;
|
||||
}
|
||||
}
|
||||
|
||||
/* Process LEN bytes of BUFFER, accumulating context into CTX.
|
||||
It is assumed that LEN % 64 == 0. */
|
||||
static void sha256_process_block(const void *buffer, size_t len, struct sha256_ctx *ctx) {
|
||||
const uint32_t *words = buffer;
|
||||
size_t nwords = len / sizeof(uint32_t);
|
||||
|
||||
assert(buffer);
|
||||
assert(ctx);
|
||||
|
||||
uint32_t a = ctx->H[0];
|
||||
uint32_t b = ctx->H[1];
|
||||
uint32_t c = ctx->H[2];
|
||||
uint32_t d = ctx->H[3];
|
||||
uint32_t e = ctx->H[4];
|
||||
uint32_t f = ctx->H[5];
|
||||
uint32_t g = ctx->H[6];
|
||||
uint32_t h = ctx->H[7];
|
||||
|
||||
/* First increment the byte count. FIPS 180-2 specifies the possible
|
||||
length of the file up to 2^64 bits. Here we only compute the
|
||||
number of bytes. */
|
||||
ctx->total64 += len;
|
||||
|
||||
/* Process all bytes in the buffer with 64 bytes in each round of
|
||||
the loop. */
|
||||
while (nwords > 0) {
|
||||
uint32_t W[64];
|
||||
uint32_t a_save = a;
|
||||
uint32_t b_save = b;
|
||||
uint32_t c_save = c;
|
||||
uint32_t d_save = d;
|
||||
uint32_t e_save = e;
|
||||
uint32_t f_save = f;
|
||||
uint32_t g_save = g;
|
||||
uint32_t h_save = h;
|
||||
|
||||
/* Operators defined in FIPS 180-2:4.1.2. */
|
||||
#define Ch(x, y, z) ((x & y) ^ (~x & z))
|
||||
#define Maj(x, y, z) ((x & y) ^ (x & z) ^ (y & z))
|
||||
#define S0(x) (CYCLIC (x, 2) ^ CYCLIC (x, 13) ^ CYCLIC (x, 22))
|
||||
#define S1(x) (CYCLIC (x, 6) ^ CYCLIC (x, 11) ^ CYCLIC (x, 25))
|
||||
#define R0(x) (CYCLIC (x, 7) ^ CYCLIC (x, 18) ^ (x >> 3))
|
||||
#define R1(x) (CYCLIC (x, 17) ^ CYCLIC (x, 19) ^ (x >> 10))
|
||||
|
||||
/* It is unfortunate that C does not provide an operator for
|
||||
cyclic rotation. Hope the C compiler is smart enough. */
|
||||
#define CYCLIC(w, s) ((w >> s) | (w << (32 - s)))
|
||||
|
||||
/* Compute the message schedule according to FIPS 180-2:6.2.2 step 2. */
|
||||
for (size_t t = 0; t < 16; ++t) {
|
||||
W[t] = SWAP (*words);
|
||||
++words;
|
||||
}
|
||||
for (size_t t = 16; t < 64; ++t)
|
||||
W[t] = R1 (W[t - 2]) + W[t - 7] + R0 (W[t - 15]) + W[t - 16];
|
||||
|
||||
/* The actual computation according to FIPS 180-2:6.2.2 step 3. */
|
||||
for (size_t t = 0; t < 64; ++t) {
|
||||
uint32_t T1 = h + S1 (e) + Ch (e, f, g) + K[t] + W[t];
|
||||
uint32_t T2 = S0 (a) + Maj (a, b, c);
|
||||
h = g;
|
||||
g = f;
|
||||
f = e;
|
||||
e = d + T1;
|
||||
d = c;
|
||||
c = b;
|
||||
b = a;
|
||||
a = T1 + T2;
|
||||
}
|
||||
|
||||
/* Add the starting values of the context according to FIPS 180-2:6.2.2
|
||||
step 4. */
|
||||
a += a_save;
|
||||
b += b_save;
|
||||
c += c_save;
|
||||
d += d_save;
|
||||
e += e_save;
|
||||
f += f_save;
|
||||
g += g_save;
|
||||
h += h_save;
|
||||
|
||||
/* Prepare for the next round. */
|
||||
nwords -= 16;
|
||||
}
|
||||
|
||||
/* Put checksum in context given as argument. */
|
||||
ctx->H[0] = a;
|
||||
ctx->H[1] = b;
|
||||
ctx->H[2] = c;
|
||||
ctx->H[3] = d;
|
||||
ctx->H[4] = e;
|
||||
ctx->H[5] = f;
|
||||
ctx->H[6] = g;
|
||||
ctx->H[7] = h;
|
||||
}
|
29
src/libnm-systemd-shared/src/fundamental/sha256.h
Normal file
29
src/libnm-systemd-shared/src/fundamental/sha256.h
Normal file
|
@ -0,0 +1,29 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#include "stdint.h"
|
||||
|
||||
#define SHA256_DIGEST_SIZE 32
|
||||
|
||||
struct sha256_ctx {
|
||||
uint32_t H[8];
|
||||
|
||||
union {
|
||||
uint64_t total64;
|
||||
#define TOTAL64_low (1 - (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__))
|
||||
#define TOTAL64_high (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
|
||||
uint32_t total[2];
|
||||
};
|
||||
|
||||
uint32_t buflen;
|
||||
|
||||
union {
|
||||
uint8_t buffer[128]; /* NB: always correctly aligned for UINT32. */
|
||||
uint32_t buffer32[32];
|
||||
uint64_t buffer64[16];
|
||||
};
|
||||
};
|
||||
|
||||
void sha256_init_ctx(struct sha256_ctx *ctx);
|
||||
void *sha256_finish_ctx(struct sha256_ctx *ctx, void *resbuf);
|
||||
void sha256_process_bytes(const void *buffer, size_t len, struct sha256_ctx *ctx);
|
|
@ -1,10 +1,10 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#ifndef SD_BOOT
|
||||
#include <ctype.h>
|
||||
|
||||
#include "macro.h"
|
||||
# include <ctype.h>
|
||||
#endif
|
||||
|
||||
#include "macro-fundamental.h"
|
||||
#include "string-util-fundamental.h"
|
||||
|
||||
sd_char *startswith(const sd_char *s, const sd_char *prefix) {
|
||||
|
@ -77,36 +77,27 @@ sd_char* endswith_no_case(const sd_char *s, const sd_char *postfix) {
|
|||
return (sd_char*) s + sl - pl;
|
||||
}
|
||||
|
||||
#ifdef SD_BOOT
|
||||
static sd_bool isdigit(sd_char a) {
|
||||
return a >= '0' && a <= '9';
|
||||
}
|
||||
#endif
|
||||
|
||||
static sd_bool is_alpha(sd_char a) {
|
||||
/* Locale independent version of isalpha(). */
|
||||
return (a >= 'a' && a <= 'z') || (a >= 'A' && a <= 'Z');
|
||||
static bool is_valid_version_char(sd_char a) {
|
||||
return ascii_isdigit(a) || ascii_isalpha(a) || IN_SET(a, '~', '-', '^', '.');
|
||||
}
|
||||
|
||||
static sd_bool is_valid_version_char(sd_char a) {
|
||||
return isdigit(a) || is_alpha(a) || IN_SET(a, '~', '-', '^', '.');
|
||||
}
|
||||
|
||||
sd_int strverscmp_improved(const sd_char *a, const sd_char *b) {
|
||||
|
||||
/* This is based on RPM's rpmvercmp(). But this explicitly handles '-' and '.', as we usually
|
||||
* want to directly compare strings which contain both version and release; e.g.
|
||||
* '247.2-3.1.fc33.x86_64' or '5.11.0-0.rc5.20210128git76c057c84d28.137.fc34'.
|
||||
* Unlike rpmvercmp(), this distiguishes e.g. 123a and 123.a, and 123a is newer.
|
||||
int strverscmp_improved(const sd_char *a, const sd_char *b) {
|
||||
/* This function is similar to strverscmp(3), but it treats '-' and '.' as separators.
|
||||
*
|
||||
* This splits the input strings into segments. Each segment is numeric or alpha, and may be
|
||||
* The logic is based on rpm's rpmvercmp(), but unlike rpmvercmp(), it distiguishes e.g.
|
||||
* '123a' and '123.a', with '123a' being newer.
|
||||
*
|
||||
* It allows direct comparison of strings which contain both a version and a release; e.g.
|
||||
* '247.2-3.1.fc33.x86_64' or '5.11.0-0.rc5.20210128git76c057c84d28.137.fc34'.
|
||||
*
|
||||
* The input string is split into segments. Each segment is numeric or alphabetic, and may be
|
||||
* prefixed with the following:
|
||||
* '~' : used for pre-releases, a segment prefixed with this is the oldest,
|
||||
* '-' : used for the separator between version and release,
|
||||
* '^' : used for patched releases, a segment with this is newer than one with '-'.
|
||||
* '.' : used for point releases.
|
||||
* Note, no prefix segment is the newest. All non-supported characters are dropped, and
|
||||
* handled as a separator of segments, e.g., 123_a is equivalent to 123a.
|
||||
* Note that no prefix segment is the newest. All non-supported characters are dropped, and
|
||||
* handled as a separator of segments, e.g., '123_a' is equivalent to '123a'.
|
||||
*
|
||||
* By using this, version strings can be sorted like following:
|
||||
* (older) 122.1
|
||||
|
@ -123,12 +114,12 @@ sd_int strverscmp_improved(const sd_char *a, const sd_char *b) {
|
|||
* (newer) 124-1
|
||||
*/
|
||||
|
||||
if (isempty(a) || isempty(b))
|
||||
return strcmp_ptr(a, b);
|
||||
a = strempty(a);
|
||||
b = strempty(b);
|
||||
|
||||
for (;;) {
|
||||
const sd_char *aa, *bb;
|
||||
sd_int r;
|
||||
int r;
|
||||
|
||||
/* Drop leading invalid characters. */
|
||||
while (*a != '\0' && !is_valid_version_char(*a))
|
||||
|
@ -149,7 +140,7 @@ sd_int strverscmp_improved(const sd_char *a, const sd_char *b) {
|
|||
}
|
||||
|
||||
/* If at least one string reaches the end, then longer is newer.
|
||||
* Note that except for '~' prefixed segments, a string has more segments is newer.
|
||||
* Note that except for '~' prefixed segments, a string which has more segments is newer.
|
||||
* So, this check must be after the '~' check. */
|
||||
if (*a == '\0' || *b == '\0')
|
||||
return CMP(*a, *b);
|
||||
|
@ -185,20 +176,25 @@ sd_int strverscmp_improved(const sd_char *a, const sd_char *b) {
|
|||
b++;
|
||||
}
|
||||
|
||||
if (isdigit(*a) || isdigit(*b)) {
|
||||
if (ascii_isdigit(*a) || ascii_isdigit(*b)) {
|
||||
/* Find the leading numeric segments. One may be an empty string. So,
|
||||
* numeric segments are always newer than alpha segments. */
|
||||
for (aa = a; ascii_isdigit(*aa); aa++)
|
||||
;
|
||||
for (bb = b; ascii_isdigit(*bb); bb++)
|
||||
;
|
||||
|
||||
/* Check if one of the strings was empty, but the other not. */
|
||||
r = CMP(a != aa, b != bb);
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
/* Skip leading '0', to make 00123 equivalent to 123. */
|
||||
while (*a == '0')
|
||||
a++;
|
||||
while (*b == '0')
|
||||
b++;
|
||||
|
||||
/* Find the leading numeric segments. One may be an empty string. So,
|
||||
* numeric segments are always newer than alpha segments. */
|
||||
for (aa = a; isdigit(*aa); aa++)
|
||||
;
|
||||
for (bb = b; isdigit(*bb); bb++)
|
||||
;
|
||||
|
||||
/* To compare numeric segments without parsing their values, first compare the
|
||||
* lengths of the segments. Eg. 12345 vs 123, longer is newer. */
|
||||
r = CMP(aa - a, bb - b);
|
||||
|
@ -206,18 +202,18 @@ sd_int strverscmp_improved(const sd_char *a, const sd_char *b) {
|
|||
return r;
|
||||
|
||||
/* Then, compare them as strings. */
|
||||
r = strncmp(a, b, aa - a);
|
||||
r = CMP(strncmp(a, b, aa - a), 0);
|
||||
if (r != 0)
|
||||
return r;
|
||||
} else {
|
||||
/* Find the leading non-numeric segments. */
|
||||
for (aa = a; is_alpha(*aa); aa++)
|
||||
for (aa = a; ascii_isalpha(*aa); aa++)
|
||||
;
|
||||
for (bb = b; is_alpha(*bb); bb++)
|
||||
for (bb = b; ascii_isalpha(*bb); bb++)
|
||||
;
|
||||
|
||||
/* Note that the segments are usually not NUL-terminated. */
|
||||
r = strncmp(a, b, MIN(aa - a, bb - b));
|
||||
r = CMP(strncmp(a, b, MIN(aa - a, bb - b)), 0);
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
|
@ -227,7 +223,7 @@ sd_int strverscmp_improved(const sd_char *a, const sd_char *b) {
|
|||
return r;
|
||||
}
|
||||
|
||||
/* The current segments are equivalent. Let's compare the next one. */
|
||||
/* The current segments are equivalent. Let's move to the next one. */
|
||||
a = aa;
|
||||
b = bb;
|
||||
}
|
||||
|
|
|
@ -2,54 +2,62 @@
|
|||
#pragma once
|
||||
|
||||
#ifdef SD_BOOT
|
||||
#include <efi.h>
|
||||
#include <efilib.h>
|
||||
# include <efi.h>
|
||||
# include <efilib.h>
|
||||
# include "efi-string.h"
|
||||
#else
|
||||
#include <string.h>
|
||||
# include <string.h>
|
||||
#endif
|
||||
|
||||
#include "macro-fundamental.h"
|
||||
|
||||
#ifdef SD_BOOT
|
||||
#define strlen(a) StrLen((a))
|
||||
#define strcmp(a, b) StrCmp((a), (b))
|
||||
#define strncmp(a, b, n) StrnCmp((a), (b), (n))
|
||||
#define strcasecmp(a, b) StriCmp((a), (b))
|
||||
#define STR_C(str) (L ## str)
|
||||
#define memcmp(a, b, n) CompareMem(a, b, n)
|
||||
# define strlen strlen16
|
||||
# define strcmp strcmp16
|
||||
# define strncmp strncmp16
|
||||
# define strcasecmp strcasecmp16
|
||||
# define strncasecmp strncasecmp16
|
||||
# define STR_C(str) (L ## str)
|
||||
typedef char16_t sd_char;
|
||||
#else
|
||||
#define STR_C(str) (str)
|
||||
# define STR_C(str) (str)
|
||||
typedef char sd_char;
|
||||
#endif
|
||||
|
||||
#define streq(a,b) (strcmp((a),(b)) == 0)
|
||||
#define strneq(a, b, n) (strncmp((a), (b), (n)) == 0)
|
||||
#define strcaseeq(a,b) (strcasecmp((a),(b)) == 0)
|
||||
#ifndef SD_BOOT
|
||||
#define strncaseeq(a, b, n) (strncasecmp((a), (b), (n)) == 0)
|
||||
#endif
|
||||
|
||||
static inline sd_int strcmp_ptr(const sd_char *a, const sd_char *b) {
|
||||
static inline int strcmp_ptr(const sd_char *a, const sd_char *b) {
|
||||
if (a && b)
|
||||
return strcmp(a, b);
|
||||
|
||||
return CMP(a, b);
|
||||
}
|
||||
|
||||
static inline sd_int strcasecmp_ptr(const sd_char *a, const sd_char *b) {
|
||||
static inline int strcasecmp_ptr(const sd_char *a, const sd_char *b) {
|
||||
if (a && b)
|
||||
return strcasecmp(a, b);
|
||||
|
||||
return CMP(a, b);
|
||||
}
|
||||
|
||||
static inline sd_bool streq_ptr(const sd_char *a, const sd_char *b) {
|
||||
static inline bool streq_ptr(const sd_char *a, const sd_char *b) {
|
||||
return strcmp_ptr(a, b) == 0;
|
||||
}
|
||||
|
||||
static inline sd_bool strcaseeq_ptr(const sd_char *a, const sd_char *b) {
|
||||
static inline bool strcaseeq_ptr(const sd_char *a, const sd_char *b) {
|
||||
return strcasecmp_ptr(a, b) == 0;
|
||||
}
|
||||
|
||||
static inline size_t strlen_ptr(const sd_char *s) {
|
||||
if (!s)
|
||||
return 0;
|
||||
|
||||
return strlen(s);
|
||||
}
|
||||
|
||||
sd_char *startswith(const sd_char *s, const sd_char *prefix) _pure_;
|
||||
#ifndef SD_BOOT
|
||||
sd_char *startswith_no_case(const sd_char *s, const sd_char *prefix) _pure_;
|
||||
|
@ -57,15 +65,23 @@ sd_char *startswith_no_case(const sd_char *s, const sd_char *prefix) _pure_;
|
|||
sd_char *endswith(const sd_char *s, const sd_char *postfix) _pure_;
|
||||
sd_char *endswith_no_case(const sd_char *s, const sd_char *postfix) _pure_;
|
||||
|
||||
static inline sd_bool isempty(const sd_char *a) {
|
||||
static inline bool isempty(const sd_char *a) {
|
||||
return !a || a[0] == '\0';
|
||||
}
|
||||
|
||||
static inline const sd_char *yes_no(sd_bool b) {
|
||||
static inline const sd_char *strempty(const sd_char *s) {
|
||||
return s ?: STR_C("");
|
||||
}
|
||||
|
||||
static inline const sd_char *yes_no(bool b) {
|
||||
return b ? STR_C("yes") : STR_C("no");
|
||||
}
|
||||
|
||||
sd_int strverscmp_improved(const sd_char *a, const sd_char *b);
|
||||
static inline const sd_char* comparison_operator(int result) {
|
||||
return result < 0 ? STR_C("<") : result > 0 ? STR_C(">") : STR_C("==");
|
||||
}
|
||||
|
||||
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, size_t sz, const sd_char *token) {
|
||||
|
@ -82,3 +98,19 @@ static inline void *memory_startswith(const void *p, size_t sz, const sd_char *t
|
|||
|
||||
return (uint8_t*) p + n;
|
||||
}
|
||||
|
||||
#define _STRV_FOREACH(s, l, i) \
|
||||
for (typeof(*(l)) *s, *i = (l); (s = i) && *i; i++)
|
||||
|
||||
#define STRV_FOREACH(s, l) \
|
||||
_STRV_FOREACH(s, l, UNIQ_T(i, UNIQ))
|
||||
|
||||
static inline bool ascii_isdigit(sd_char a) {
|
||||
/* A pure ASCII, locale independent version of isdigit() */
|
||||
return a >= '0' && a <= '9';
|
||||
}
|
||||
|
||||
static inline bool ascii_isalpha(sd_char a) {
|
||||
/* A pure ASCII, locale independent version of isalpha() */
|
||||
return (a >= 'a' && a <= 'z') || (a >= 'A' && a <= 'Z');
|
||||
}
|
||||
|
|
|
@ -1,39 +0,0 @@
|
|||
/* 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
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
#include "alloc-util.h"
|
||||
#include "dns-domain.h"
|
||||
#include "glyph-util.h"
|
||||
#include "hashmap.h"
|
||||
#include "hexdecoct.h"
|
||||
#include "hostname-util.h"
|
||||
|
@ -235,9 +236,8 @@ int dns_label_escape(const char *p, size_t l, char *dest, size_t sz) {
|
|||
sz -= 2;
|
||||
|
||||
} else if (IN_SET(*p, '_', '-') ||
|
||||
(*p >= '0' && *p <= '9') ||
|
||||
(*p >= 'a' && *p <= 'z') ||
|
||||
(*p >= 'A' && *p <= 'Z')) {
|
||||
ascii_isdigit(*p) ||
|
||||
ascii_isalpha(*p)) {
|
||||
|
||||
/* Proper character */
|
||||
|
||||
|
@ -450,12 +450,8 @@ int dns_name_concat(const char *a, const char *b, DNSLabelFlags flags, char **_r
|
|||
return r;
|
||||
}
|
||||
|
||||
if (!first)
|
||||
n++;
|
||||
else
|
||||
first = false;
|
||||
|
||||
n += r;
|
||||
n += r + !first;
|
||||
first = false;
|
||||
}
|
||||
|
||||
finish:
|
||||
|
@ -910,15 +906,13 @@ static bool srv_type_label_is_valid(const char *label, size_t n) {
|
|||
return false;
|
||||
|
||||
/* Second char must be a letter */
|
||||
if (!(label[1] >= 'A' && label[1] <= 'Z') &&
|
||||
!(label[1] >= 'a' && label[1] <= 'z'))
|
||||
if (!ascii_isalpha(label[1]))
|
||||
return false;
|
||||
|
||||
/* Third and further chars must be alphanumeric or a hyphen */
|
||||
for (k = 2; k < n; k++) {
|
||||
if (!(label[k] >= 'A' && label[k] <= 'Z') &&
|
||||
!(label[k] >= 'a' && label[k] <= 'z') &&
|
||||
!(label[k] >= '0' && label[k] <= '9') &&
|
||||
if (!ascii_isalpha(label[k]) &&
|
||||
!ascii_isdigit(label[k]) &&
|
||||
label[k] != '-')
|
||||
return false;
|
||||
}
|
||||
|
@ -1026,10 +1020,10 @@ static bool dns_service_name_label_is_valid(const char *label, size_t n) {
|
|||
return dns_service_name_is_valid(s);
|
||||
}
|
||||
|
||||
int dns_service_split(const char *joined, char **_name, char **_type, char **_domain) {
|
||||
int dns_service_split(const char *joined, char **ret_name, char **ret_type, char **ret_domain) {
|
||||
_cleanup_free_ char *name = NULL, *type = NULL, *domain = NULL;
|
||||
const char *p = joined, *q = NULL, *d = NULL;
|
||||
char a[DNS_LABEL_MAX], b[DNS_LABEL_MAX], c[DNS_LABEL_MAX];
|
||||
const char *p = joined, *q = NULL, *d = joined;
|
||||
char a[DNS_LABEL_MAX+1], b[DNS_LABEL_MAX+1], c[DNS_LABEL_MAX+1];
|
||||
int an, bn, cn, r;
|
||||
unsigned x = 0;
|
||||
|
||||
|
@ -1049,6 +1043,9 @@ int dns_service_split(const char *joined, char **_name, char **_type, char **_do
|
|||
return bn;
|
||||
|
||||
if (bn > 0) {
|
||||
if (!srv_type_label_is_valid(b, bn))
|
||||
goto finish;
|
||||
|
||||
x++;
|
||||
|
||||
/* If there was a second label, try to get the third one */
|
||||
|
@ -1057,64 +1054,58 @@ int dns_service_split(const char *joined, char **_name, char **_type, char **_do
|
|||
if (cn < 0)
|
||||
return cn;
|
||||
|
||||
if (cn > 0)
|
||||
if (cn > 0 && srv_type_label_is_valid(c, cn))
|
||||
x++;
|
||||
} else
|
||||
cn = 0;
|
||||
} else
|
||||
an = 0;
|
||||
|
||||
if (x >= 2 && srv_type_label_is_valid(b, bn)) {
|
||||
|
||||
if (x >= 3 && srv_type_label_is_valid(c, cn)) {
|
||||
|
||||
if (dns_service_name_label_is_valid(a, an)) {
|
||||
/* OK, got <name> . <type> . <type2> . <domain> */
|
||||
|
||||
name = strndup(a, an);
|
||||
if (!name)
|
||||
return -ENOMEM;
|
||||
|
||||
type = strjoin(b, ".", c);
|
||||
if (!type)
|
||||
return -ENOMEM;
|
||||
|
||||
d = p;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
} else if (srv_type_label_is_valid(a, an)) {
|
||||
|
||||
/* OK, got <type> . <type2> . <domain> */
|
||||
|
||||
name = NULL;
|
||||
|
||||
type = strjoin(a, ".", b);
|
||||
if (!type)
|
||||
return -ENOMEM;
|
||||
|
||||
d = q;
|
||||
goto finish;
|
||||
}
|
||||
}
|
||||
|
||||
name = NULL;
|
||||
type = NULL;
|
||||
d = joined;
|
||||
switch (x) {
|
||||
case 2:
|
||||
if (!srv_type_label_is_valid(a, an))
|
||||
break;
|
||||
|
||||
/* OK, got <type> . <type2> . <domain> */
|
||||
|
||||
name = NULL;
|
||||
|
||||
type = strjoin(a, ".", b);
|
||||
if (!type)
|
||||
return -ENOMEM;
|
||||
|
||||
d = q;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
if (!dns_service_name_label_is_valid(a, an))
|
||||
break;
|
||||
|
||||
/* OK, got <name> . <type> . <type2> . <domain> */
|
||||
|
||||
name = strndup(a, an);
|
||||
if (!name)
|
||||
return -ENOMEM;
|
||||
|
||||
type = strjoin(b, ".", c);
|
||||
if (!type)
|
||||
return -ENOMEM;
|
||||
|
||||
d = p;
|
||||
break;
|
||||
}
|
||||
|
||||
finish:
|
||||
r = dns_name_normalize(d, 0, &domain);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (_domain)
|
||||
*_domain = TAKE_PTR(domain);
|
||||
if (ret_domain)
|
||||
*ret_domain = TAKE_PTR(domain);
|
||||
|
||||
if (_type)
|
||||
*_type = TAKE_PTR(type);
|
||||
if (ret_type)
|
||||
*ret_type = TAKE_PTR(type);
|
||||
|
||||
if (_name)
|
||||
*_name = TAKE_PTR(name);
|
||||
if (ret_name)
|
||||
*ret_name = TAKE_PTR(name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1294,7 +1285,7 @@ int dns_name_apply_idna(const char *name, char **ret) {
|
|||
r = sym_idn2_lookup_u8((uint8_t*) name, (uint8_t**) &t,
|
||||
IDN2_NFC_INPUT | IDN2_TRANSITIONAL);
|
||||
|
||||
log_debug("idn2_lookup_u8: %s → %s", name, t);
|
||||
log_debug("idn2_lookup_u8: %s %s %s", name, special_glyph(SPECIAL_GLYPH_ARROW_RIGHT), t);
|
||||
if (r == IDN2_OK) {
|
||||
if (!startswith(name, "xn--")) {
|
||||
_cleanup_free_ char *s = NULL;
|
||||
|
@ -1308,8 +1299,9 @@ int dns_name_apply_idna(const char *name, char **ret) {
|
|||
}
|
||||
|
||||
if (!streq_ptr(name, s)) {
|
||||
log_debug("idn2 roundtrip failed: \"%s\" → \"%s\" → \"%s\", ignoring.",
|
||||
name, t, s);
|
||||
log_debug("idn2 roundtrip failed: \"%s\" %s \"%s\" %s \"%s\", ignoring.",
|
||||
name, special_glyph(SPECIAL_GLYPH_ARROW_RIGHT), t,
|
||||
special_glyph(SPECIAL_GLYPH_ARROW_RIGHT), s);
|
||||
*ret = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -40,8 +40,8 @@ static inline int dns_name_normalize(const char *s, DNSLabelFlags flags, char **
|
|||
static inline int dns_name_is_valid(const char *s) {
|
||||
int r;
|
||||
|
||||
/* dns_name_normalize() verifies as a side effect */
|
||||
r = dns_name_normalize(s, 0, NULL);
|
||||
/* dns_name_concat() verifies as a side effect */
|
||||
r = dns_name_concat(s, NULL, 0, NULL);
|
||||
if (r == -EINVAL)
|
||||
return 0;
|
||||
if (r < 0)
|
||||
|
@ -88,7 +88,7 @@ bool dnssd_srv_type_is_valid(const char *name);
|
|||
bool dns_service_name_is_valid(const char *name);
|
||||
|
||||
int dns_service_join(const char *name, const char *type, const char *domain, char **ret);
|
||||
int dns_service_split(const char *joined, char **name, char **type, char **domain);
|
||||
int dns_service_split(const char *joined, char **ret_name, char **ret_type, char **ret_domain);
|
||||
|
||||
int dns_name_suffix(const char *name, unsigned n_labels, const char **ret);
|
||||
int dns_name_count_labels(const char *name);
|
||||
|
|
Loading…
Reference in a new issue