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:
Thomas Haller 2022-07-05 14:53:45 +02:00
parent 7b3466fc4c
commit 3a603c8764
No known key found for this signature in database
GPG key ID: 29C2366E4DFC5728
75 changed files with 1868 additions and 4484 deletions

View file

@ -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);

View file

@ -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, &current_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, &current_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);

View file

@ -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;
}

View file

@ -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;

View file

@ -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:

View file

@ -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;

View file

@ -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

View file

@ -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);

View file

@ -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");

View file

@ -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;
}

View file

@ -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;

View file

@ -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);

View file

@ -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 (;;) {

View file

@ -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);
}

View file

@ -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);

View file

@ -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

View file

@ -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! */

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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 */
};

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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;
}

View file

@ -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

View file

@ -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

View file

@ -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);

View file

@ -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;

View file

@ -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);

View file

@ -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 */

View file

@ -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

View file

@ -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;

View file

@ -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;
}

View 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];
}

View 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) : " ";
}

View file

@ -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

View file

@ -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;

View file

@ -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);
}

View file

@ -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 == '-';
}

View file

@ -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;
}

View file

@ -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);

View 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);

View 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]);

View file

@ -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);

View file

@ -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 {

View file

@ -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;

View file

@ -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);

View file

@ -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)

View file

@ -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;

View file

@ -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);

View file

@ -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;

View file

@ -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) {

View file

@ -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();

View file

@ -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) {

View file

@ -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;

View file

@ -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);

View file

@ -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));
}

View file

@ -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);

View file

@ -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;

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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);

View file

@ -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) {

View file

@ -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); \

View file

@ -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;

View file

@ -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( \

View 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;
}

View 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);

View file

@ -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;
}

View file

@ -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');
}

View file

@ -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

View file

@ -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;
}

View file

@ -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);