summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2022-07-05 17:31:20 +0200
committerThomas Haller <thaller@redhat.com>2022-07-07 00:50:46 +0200
commit556bff17679c1705c258eb9ec6f02f645e61c017 (patch)
tree38cdbf82f898013c68d602995a8e18ae44cbee6a
parentb12281089ca298a75554012ee19a176cc17ed5c8 (diff)
parent3a603c87647c36c9f7d24dc727c81618ad06fca3 (diff)
downloadNetworkManager-556bff17679c1705c258eb9ec6f02f645e61c017.tar.gz
systemd: merge branch systemd into main
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/1291
-rw-r--r--Makefile.am8
-rw-r--r--src/libnm-systemd-core/src/libsystemd-network/dhcp-identifier.c3
-rw-r--r--src/libnm-systemd-core/src/libsystemd-network/dhcp6-internal.h2
-rw-r--r--src/libnm-systemd-core/src/libsystemd-network/dhcp6-option.c16
-rw-r--r--src/libnm-systemd-core/src/libsystemd-network/lldp-neighbor.c6
-rw-r--r--src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-client.c97
-rw-r--r--src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-lease.c6
-rw-r--r--src/libnm-systemd-core/src/libsystemd/sd-event/event-util.c14
-rw-r--r--src/libnm-systemd-core/src/libsystemd/sd-event/event-util.h5
-rw-r--r--src/libnm-systemd-core/src/libsystemd/sd-event/sd-event.c100
-rw-r--r--src/libnm-systemd-core/src/libsystemd/sd-id128/id128-util.c28
-rw-r--r--src/libnm-systemd-core/src/libsystemd/sd-id128/id128-util.h2
-rw-r--r--src/libnm-systemd-core/src/libsystemd/sd-id128/sd-id128.c26
-rw-r--r--src/libnm-systemd-core/src/systemd/_sd-common.h2
-rw-r--r--src/libnm-systemd-core/src/systemd/sd-dhcp6-client.h16
-rw-r--r--src/libnm-systemd-core/src/systemd/sd-dhcp6-lease.h2
-rw-r--r--src/libnm-systemd-core/src/systemd/sd-dhcp6-option.h2
-rw-r--r--src/libnm-systemd-core/src/systemd/sd-event.h2
-rw-r--r--src/libnm-systemd-core/src/systemd/sd-id128.h6
-rw-r--r--src/libnm-systemd-core/src/systemd/sd-lldp-rx.h6
-rw-r--r--src/libnm-systemd-core/src/systemd/sd-lldp.h14
-rw-r--r--src/libnm-systemd-core/src/systemd/sd-ndisc.h11
-rw-r--r--src/libnm-systemd-shared/meson.build3
-rw-r--r--src/libnm-systemd-shared/sd-adapt-shared/locale-util.h3
-rw-r--r--src/libnm-systemd-shared/sd-adapt-shared/nm-sd-adapt-shared.h2
-rw-r--r--src/libnm-systemd-shared/src/basic/alloc-util.h20
-rw-r--r--src/libnm-systemd-shared/src/basic/env-util.c2
-rw-r--r--src/libnm-systemd-shared/src/basic/fileio.c31
-rw-r--r--src/libnm-systemd-shared/src/basic/fs-util.c21
-rw-r--r--src/libnm-systemd-shared/src/basic/glyph-util.c139
-rw-r--r--src/libnm-systemd-shared/src/basic/glyph-util.h60
-rw-r--r--src/libnm-systemd-shared/src/basic/hash-funcs.c10
-rw-r--r--src/libnm-systemd-shared/src/basic/hash-funcs.h7
-rw-r--r--src/libnm-systemd-shared/src/basic/hashmap.c45
-rw-r--r--src/libnm-systemd-shared/src/basic/hostname-util.c6
-rw-r--r--src/libnm-systemd-shared/src/basic/in-addr-util.c40
-rw-r--r--src/libnm-systemd-shared/src/basic/in-addr-util.h55
-rw-r--r--src/libnm-systemd-shared/src/basic/locale-util.c376
-rw-r--r--src/libnm-systemd-shared/src/basic/locale-util.h56
-rw-r--r--src/libnm-systemd-shared/src/basic/log.h12
-rw-r--r--src/libnm-systemd-shared/src/basic/macro.h56
-rw-r--r--src/libnm-systemd-shared/src/basic/mempool.c17
-rw-r--r--src/libnm-systemd-shared/src/basic/mempool.h3
-rw-r--r--src/libnm-systemd-shared/src/basic/missing_syscall.h2
-rw-r--r--src/libnm-systemd-shared/src/basic/ordered-set.h4
-rw-r--r--src/libnm-systemd-shared/src/basic/parse-util.c32
-rw-r--r--src/libnm-systemd-shared/src/basic/parse-util.h1
-rw-r--r--src/libnm-systemd-shared/src/basic/path-util.c120
-rw-r--r--src/libnm-systemd-shared/src/basic/path-util.h10
-rw-r--r--src/libnm-systemd-shared/src/basic/process-util.c4
-rw-r--r--src/libnm-systemd-shared/src/basic/random-util.c278
-rw-r--r--src/libnm-systemd-shared/src/basic/random-util.h11
-rw-r--r--src/libnm-systemd-shared/src/basic/set.h11
-rw-r--r--src/libnm-systemd-shared/src/basic/socket-util.c99
-rw-r--r--src/libnm-systemd-shared/src/basic/socket-util.h8
-rw-r--r--src/libnm-systemd-shared/src/basic/stat-util.c133
-rw-r--r--src/libnm-systemd-shared/src/basic/stat-util.h43
-rw-r--r--src/libnm-systemd-shared/src/basic/string-util.c27
-rw-r--r--src/libnm-systemd-shared/src/basic/string-util.h38
-rw-r--r--src/libnm-systemd-shared/src/basic/strv.c40
-rw-r--r--src/libnm-systemd-shared/src/basic/strv.h34
-rw-r--r--src/libnm-systemd-shared/src/basic/time-util.c44
-rw-r--r--src/libnm-systemd-shared/src/fundamental/macro-fundamental.h90
-rw-r--r--src/libnm-systemd-shared/src/fundamental/sha256.c293
-rw-r--r--src/libnm-systemd-shared/src/fundamental/sha256.h29
-rw-r--r--src/libnm-systemd-shared/src/fundamental/string-util-fundamental.c78
-rw-r--r--src/libnm-systemd-shared/src/fundamental/string-util-fundamental.h70
-rw-r--r--src/libnm-systemd-shared/src/fundamental/types-fundamental.h39
-rw-r--r--src/libnm-systemd-shared/src/shared/dns-domain.c108
-rw-r--r--src/libnm-systemd-shared/src/shared/dns-domain.h6
70 files changed, 1872 insertions, 1118 deletions
diff --git a/Makefile.am b/Makefile.am
index 355984abae..8a7b2c35e7 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -2177,7 +2177,6 @@ src_libnm_systemd_shared_libnm_systemd_shared_la_SOURCES = \
src/libnm-systemd-shared/sd-adapt-shared/hmac.h \
src/libnm-systemd-shared/sd-adapt-shared/idn-util.h \
src/libnm-systemd-shared/sd-adapt-shared/ioprio.h \
- src/libnm-systemd-shared/sd-adapt-shared/locale-util.h \
src/libnm-systemd-shared/sd-adapt-shared/memfd-util.h \
src/libnm-systemd-shared/sd-adapt-shared/missing_fs.h \
src/libnm-systemd-shared/sd-adapt-shared/missing_ioprio.h \
@@ -2225,6 +2224,8 @@ src_libnm_systemd_shared_libnm_systemd_shared_la_SOURCES = \
src/libnm-systemd-shared/src/basic/format-util.h \
src/libnm-systemd-shared/src/basic/fs-util.c \
src/libnm-systemd-shared/src/basic/fs-util.h \
+ src/libnm-systemd-shared/src/basic/glyph-util.c \
+ src/libnm-systemd-shared/src/basic/glyph-util.h \
src/libnm-systemd-shared/src/basic/hash-funcs.c \
src/libnm-systemd-shared/src/basic/hash-funcs.h \
src/libnm-systemd-shared/src/basic/hashmap.c \
@@ -2240,6 +2241,8 @@ src_libnm_systemd_shared_libnm_systemd_shared_la_SOURCES = \
src/libnm-systemd-shared/src/basic/io-util.c \
src/libnm-systemd-shared/src/basic/io-util.h \
src/libnm-systemd-shared/src/basic/list.h \
+ src/libnm-systemd-shared/src/basic/locale-util.c \
+ src/libnm-systemd-shared/src/basic/locale-util.h \
src/libnm-systemd-shared/src/basic/log.h \
src/libnm-systemd-shared/src/basic/macro.h \
src/libnm-systemd-shared/src/basic/memory-util.c \
@@ -2295,9 +2298,10 @@ src_libnm_systemd_shared_libnm_systemd_shared_la_SOURCES = \
src/libnm-systemd-shared/src/basic/util.c \
src/libnm-systemd-shared/src/basic/util.h \
src/libnm-systemd-shared/src/fundamental/macro-fundamental.h \
+ src/libnm-systemd-shared/src/fundamental/sha256.c \
+ src/libnm-systemd-shared/src/fundamental/sha256.h \
src/libnm-systemd-shared/src/fundamental/string-util-fundamental.c \
src/libnm-systemd-shared/src/fundamental/string-util-fundamental.h \
- src/libnm-systemd-shared/src/fundamental/types-fundamental.h \
src/libnm-systemd-shared/src/shared/dns-domain.c \
src/libnm-systemd-shared/src/shared/dns-domain.h \
src/libnm-systemd-shared/src/shared/log-link.h \
diff --git a/src/libnm-systemd-core/src/libsystemd-network/dhcp-identifier.c b/src/libnm-systemd-core/src/libsystemd-network/dhcp-identifier.c
index f2d9421417..46410ca10f 100644
--- a/src/libnm-systemd-core/src/libsystemd-network/dhcp-identifier.c
+++ b/src/libnm-systemd-core/src/libsystemd-network/dhcp-identifier.c
@@ -13,7 +13,6 @@
#include "netif-util.h"
#include "siphash24.h"
#include "sparse-endian.h"
-#include "stat-util.h"
#include "string-table.h"
#include "udev-util.h"
@@ -220,7 +219,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);
diff --git a/src/libnm-systemd-core/src/libsystemd-network/dhcp6-internal.h b/src/libnm-systemd-core/src/libsystemd-network/dhcp6-internal.h
index 0d7813f613..176391ebec 100644
--- a/src/libnm-systemd-core/src/libsystemd-network/dhcp6-internal.h
+++ b/src/libnm-systemd-core/src/libsystemd-network/dhcp6-internal.h
@@ -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;
diff --git a/src/libnm-systemd-core/src/libsystemd-network/dhcp6-option.c b/src/libnm-systemd-core/src/libsystemd-network/dhcp6-option.c
index 03d563710d..e6b7f7d991 100644
--- a/src/libnm-systemd-core/src/libsystemd-network/dhcp6-option.c
+++ b/src/libnm-systemd-core/src/libsystemd-network/dhcp6-option.c
@@ -53,18 +53,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:
@@ -126,9 +128,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:
diff --git a/src/libnm-systemd-core/src/libsystemd-network/lldp-neighbor.c b/src/libnm-systemd-core/src/libsystemd-network/lldp-neighbor.c
index f56929ad65..d4aec944c7 100644
--- a/src/libnm-systemd-core/src/libsystemd-network/lldp-neighbor.c
+++ b/src/libnm-systemd-core/src/libsystemd-network/lldp-neighbor.c
@@ -118,6 +118,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;
@@ -651,7 +654,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;
diff --git a/src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-client.c b/src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-client.c
index 4394ef4937..27efabab4e 100644
--- a/src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-client.c
+++ b/src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-client.c
@@ -29,16 +29,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)
@@ -381,8 +375,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);
@@ -390,15 +388,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;
}
@@ -645,6 +645,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 =
@@ -722,9 +767,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;
@@ -1311,13 +1354,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;
}
@@ -1351,7 +1391,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);
}
@@ -1423,18 +1463,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;
@@ -1446,8 +1477,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);
diff --git a/src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-lease.c b/src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-lease.c
index fd47cb7351..00927d72e2 100644
--- a/src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-lease.c
+++ b/src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-lease.c
@@ -572,14 +572,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");
@@ -593,7 +593,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");
diff --git a/src/libnm-systemd-core/src/libsystemd/sd-event/event-util.c b/src/libnm-systemd-core/src/libsystemd/sd-event/event-util.c
index 6e3c2ce964..ebbd442261 100644
--- a/src/libnm-systemd-core/src/libsystemd/sd-event/event-util.c
+++ b/src/libnm-systemd-core/src/libsystemd/sd-event/event-util.c
@@ -111,20 +111,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);
-}
-
#if 0 /* NM_IGNORED */
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;
diff --git a/src/libnm-systemd-core/src/libsystemd/sd-event/event-util.h b/src/libnm-systemd-core/src/libsystemd/sd-event/event-util.h
index abd043bdcc..c185584412 100644
--- a/src/libnm-systemd-core/src/libsystemd/sd-event/event-util.h
+++ b/src/libnm-systemd-core/src/libsystemd/sd-event/event-util.h
@@ -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);
diff --git a/src/libnm-systemd-core/src/libsystemd/sd-event/sd-event.c b/src/libnm-systemd-core/src/libsystemd/sd-event/sd-event.c
index 240476e634..54081d1897 100644
--- a/src/libnm-systemd-core/src/libsystemd/sd-event/sd-event.c
+++ b/src/libnm-systemd-core/src/libsystemd/sd-event/sd-event.c
@@ -15,6 +15,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"
@@ -407,7 +408,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;
}
@@ -708,6 +710,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)
@@ -853,6 +858,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);
@@ -1429,7 +1437,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;
@@ -1439,7 +1446,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))
@@ -1449,10 +1456,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);
@@ -1468,6 +1471,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)
@@ -1695,7 +1704,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);
@@ -1795,7 +1805,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);
@@ -1805,7 +1815,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
@@ -1858,7 +1868,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;
@@ -2407,6 +2417,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);
@@ -2584,8 +2598,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. */
@@ -3222,23 +3241,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);
@@ -3255,7 +3267,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);
@@ -3270,10 +3284,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)));
@@ -3328,19 +3341,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;
@@ -3879,7 +3889,7 @@ _public_ int sd_event_prepare(sd_event *e) {
event_close_inode_data_fds(e);
- if (event_next_pending(e) || e->need_process_child)
+ if (event_next_pending(e) || e->need_process_child || !LIST_IS_EMPTY(e->inotify_data_buffered))
goto pending;
e->state = SD_EVENT_ARMED;
@@ -3959,7 +3969,7 @@ static int process_epoll(sd_event *e, usec_t timeout, int64_t threshold, int64_t
n_event_max = MALLOC_ELEMENTSOF(e->event_queue);
/* If we still have inotify data buffered, then query the other fds, but don't wait on it */
- if (e->inotify_data_buffered)
+ if (!LIST_IS_EMPTY(e->inotify_data_buffered))
timeout = 0;
for (;;) {
diff --git a/src/libnm-systemd-core/src/libsystemd/sd-id128/id128-util.c b/src/libnm-systemd-core/src/libsystemd/sd-id128/id128-util.c
index f1a3a42ea6..66247fd1e2 100644
--- a/src/libnm-systemd-core/src/libsystemd/sd-id128/id128-util.c
+++ b/src/libnm-systemd-core/src/libsystemd/sd-id128/id128-util.c
@@ -28,9 +28,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;
}
@@ -45,9 +45,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;
}
}
@@ -211,20 +211,4 @@ 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);
-}
#endif /* NM_IGNORED */
diff --git a/src/libnm-systemd-core/src/libsystemd/sd-id128/id128-util.h b/src/libnm-systemd-core/src/libsystemd/sd-id128/id128-util.h
index 65a278c8ee..17b180c10c 100644
--- a/src/libnm-systemd-core/src/libsystemd/sd-id128/id128-util.h
+++ b/src/libnm-systemd-core/src/libsystemd/sd-id128/id128-util.h
@@ -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);
diff --git a/src/libnm-systemd-core/src/libsystemd/sd-id128/sd-id128.c b/src/libnm-systemd-core/src/libsystemd/sd-id128/sd-id128.c
index 8e47e26e1e..b7d7788c9a 100644
--- a/src/libnm-systemd-core/src/libsystemd/sd-id128/sd-id128.c
+++ b/src/libnm-systemd-core/src/libsystemd/sd-id128/sd-id128.c
@@ -105,6 +105,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;
@@ -261,7 +277,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
@@ -277,13 +296,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
diff --git a/src/libnm-systemd-core/src/systemd/_sd-common.h b/src/libnm-systemd-core/src/systemd/_sd-common.h
index e121429640..38449463e2 100644
--- a/src/libnm-systemd-core/src/systemd/_sd-common.h
+++ b/src/libnm-systemd-core/src/systemd/_sd-common.h
@@ -14,7 +14,7 @@
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
+ along with systemd; If not, see <https://www.gnu.org/licenses/>.
***/
/* This is a private header; never even think of including this directly! */
diff --git a/src/libnm-systemd-core/src/systemd/sd-dhcp6-client.h b/src/libnm-systemd-core/src/systemd/sd-dhcp6-client.h
index d89b7d1c83..7fe60c356c 100644
--- a/src/libnm-systemd-core/src/systemd/sd-dhcp6-client.h
+++ b/src/libnm-systemd-core/src/systemd/sd-dhcp6-client.h
@@ -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 */
};
diff --git a/src/libnm-systemd-core/src/systemd/sd-dhcp6-lease.h b/src/libnm-systemd-core/src/systemd/sd-dhcp6-lease.h
index 472276def1..716f6fc17c 100644
--- a/src/libnm-systemd-core/src/systemd/sd-dhcp6-lease.h
+++ b/src/libnm-systemd-core/src/systemd/sd-dhcp6-lease.h
@@ -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>
diff --git a/src/libnm-systemd-core/src/systemd/sd-dhcp6-option.h b/src/libnm-systemd-core/src/systemd/sd-dhcp6-option.h
index ddb2c7cecd..b4b4671e4a 100644
--- a/src/libnm-systemd-core/src/systemd/sd-dhcp6-option.h
+++ b/src/libnm-systemd-core/src/systemd/sd-dhcp6-option.h
@@ -14,7 +14,7 @@
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
+ along with systemd; If not, see <https://www.gnu.org/licenses/>.
***/
#include <inttypes.h>
diff --git a/src/libnm-systemd-core/src/systemd/sd-event.h b/src/libnm-systemd-core/src/systemd/sd-event.h
index 63984eef15..e782339c4a 100644
--- a/src/libnm-systemd-core/src/systemd/sd-event.h
+++ b/src/libnm-systemd-core/src/systemd/sd-event.h
@@ -14,7 +14,7 @@
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
+ along with systemd; If not, see <https://www.gnu.org/licenses/>.
***/
#include <inttypes.h>
diff --git a/src/libnm-systemd-core/src/systemd/sd-id128.h b/src/libnm-systemd-core/src/systemd/sd-id128.h
index f7d3244bb3..3303c374ce 100644
--- a/src/libnm-systemd-core/src/systemd/sd-id128.h
+++ b/src/libnm-systemd-core/src/systemd/sd-id128.h
@@ -14,7 +14,7 @@
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
+ along with systemd; If not, see <https://www.gnu.org/licenses/>.
***/
#include <inttypes.h>
@@ -116,9 +116,11 @@ int sd_id128_get_boot_app_specific(sd_id128_t app_id, sd_id128_t *ret);
#a #b #c #d "-" #e #f "-" #g #h "-" #i #j "-" #k #l #m #n #o #p
_sd_pure_ static __inline__ int sd_id128_equal(sd_id128_t a, sd_id128_t b) {
- return memcmp(&a, &b, 16) == 0;
+ return a.qwords[0] == b.qwords[0] && a.qwords[1] == b.qwords[1];
}
+int sd_id128_string_equal(const char *s, sd_id128_t id);
+
_sd_pure_ static __inline__ int sd_id128_is_null(sd_id128_t a) {
return a.qwords[0] == 0 && a.qwords[1] == 0;
}
diff --git a/src/libnm-systemd-core/src/systemd/sd-lldp-rx.h b/src/libnm-systemd-core/src/systemd/sd-lldp-rx.h
index bfeac14ce3..504d7f59c1 100644
--- a/src/libnm-systemd-core/src/systemd/sd-lldp-rx.h
+++ b/src/libnm-systemd-core/src/systemd/sd-lldp-rx.h
@@ -14,7 +14,7 @@
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
+ along with systemd; If not, see <https://www.gnu.org/licenses/>.
***/
#include <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);
diff --git a/src/libnm-systemd-core/src/systemd/sd-lldp.h b/src/libnm-systemd-core/src/systemd/sd-lldp.h
index c32d789476..4069c5b299 100644
--- a/src/libnm-systemd-core/src/systemd/sd-lldp.h
+++ b/src/libnm-systemd-core/src/systemd/sd-lldp.h
@@ -14,7 +14,7 @@
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
+ along with systemd; If not, see <https://www.gnu.org/licenses/>.
***/
#include <inttypes.h>
@@ -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;
diff --git a/src/libnm-systemd-core/src/systemd/sd-ndisc.h b/src/libnm-systemd-core/src/systemd/sd-ndisc.h
index ab9ff55ddb..ee309a4253 100644
--- a/src/libnm-systemd-core/src/systemd/sd-ndisc.h
+++ b/src/libnm-systemd-core/src/systemd/sd-ndisc.h
@@ -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);
diff --git a/src/libnm-systemd-shared/meson.build b/src/libnm-systemd-shared/meson.build
index 05c81faf32..d8e7a31a3f 100644
--- a/src/libnm-systemd-shared/meson.build
+++ b/src/libnm-systemd-shared/meson.build
@@ -14,6 +14,7 @@ libnm_systemd_shared = static_library(
'src/basic/fileio.c',
'src/basic/format-util.c',
'src/basic/fs-util.c',
+ 'src/basic/glyph-util.c',
'src/basic/hash-funcs.c',
'src/basic/hashmap.c',
'src/basic/hexdecoct.c',
@@ -21,6 +22,7 @@ libnm_systemd_shared = static_library(
'src/basic/in-addr-util.c',
'src/basic/inotify-util.c',
'src/basic/io-util.c',
+ 'src/basic/locale-util.c',
'src/basic/memory-util.c',
'src/basic/mempool.c',
'src/basic/ordered-set.c',
@@ -41,6 +43,7 @@ libnm_systemd_shared = static_library(
'src/basic/tmpfile-util.c',
'src/basic/utf8.c',
'src/basic/util.c',
+ 'src/fundamental/sha256.c',
'src/fundamental/string-util-fundamental.c',
'src/shared/dns-domain.c',
'src/shared/web-util.c',
diff --git a/src/libnm-systemd-shared/sd-adapt-shared/locale-util.h b/src/libnm-systemd-shared/sd-adapt-shared/locale-util.h
deleted file mode 100644
index 637892c2d6..0000000000
--- a/src/libnm-systemd-shared/sd-adapt-shared/locale-util.h
+++ /dev/null
@@ -1,3 +0,0 @@
-#pragma once
-
-/* dummy header */
diff --git a/src/libnm-systemd-shared/sd-adapt-shared/nm-sd-adapt-shared.h b/src/libnm-systemd-shared/sd-adapt-shared/nm-sd-adapt-shared.h
index 586c3a7eb8..a3e490f569 100644
--- a/src/libnm-systemd-shared/sd-adapt-shared/nm-sd-adapt-shared.h
+++ b/src/libnm-systemd-shared/sd-adapt-shared/nm-sd-adapt-shared.h
@@ -53,6 +53,8 @@
#define BUILD_MODE_DEVELOPER (NM_MORE_ASSERTS > 0)
+#define LOG_MESSAGE_VERIFICATION (NM_MORE_ASSERTS > 0)
+
/*****************************************************************************/
/* systemd cannot be compiled with "-Wdeclaration-after-statement". In particular
diff --git a/src/libnm-systemd-shared/src/basic/alloc-util.h b/src/libnm-systemd-shared/src/basic/alloc-util.h
index 9dde770dab..13dab0304f 100644
--- a/src/libnm-systemd-shared/src/basic/alloc-util.h
+++ b/src/libnm-systemd-shared/src/basic/alloc-util.h
@@ -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 */
diff --git a/src/libnm-systemd-shared/src/basic/env-util.c b/src/libnm-systemd-shared/src/basic/env-util.c
index b4ac68116e..e869fad198 100644
--- a/src/libnm-systemd-shared/src/basic/env-util.c
+++ b/src/libnm-systemd-shared/src/basic/env-util.c
@@ -35,7 +35,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
diff --git a/src/libnm-systemd-shared/src/basic/fileio.c b/src/libnm-systemd-shared/src/basic/fileio.c
index 0ad8ae03b4..d996bc0215 100644
--- a/src/libnm-systemd-shared/src/basic/fileio.c
+++ b/src/libnm-systemd-shared/src/basic/fileio.c
@@ -767,8 +767,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)
@@ -780,23 +779,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)
@@ -813,12 +796,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;
diff --git a/src/libnm-systemd-shared/src/basic/fs-util.c b/src/libnm-systemd-shared/src/basic/fs-util.c
index dccfb27b52..1a951bd5d2 100644
--- a/src/libnm-systemd-shared/src/basic/fs-util.c
+++ b/src/libnm-systemd-shared/src/basic/fs-util.c
@@ -160,24 +160,23 @@ int readlink_malloc(const char *p, char **ret) {
#if 0 /* NM_IGNORED */
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;
}
diff --git a/src/libnm-systemd-shared/src/basic/glyph-util.c b/src/libnm-systemd-shared/src/basic/glyph-util.c
new file mode 100644
index 0000000000..ec851e8b91
--- /dev/null
+++ b/src/libnm-systemd-shared/src/basic/glyph-util.c
@@ -0,0 +1,139 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include "nm-sd-adapt-shared.h"
+
+#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];
+}
diff --git a/src/libnm-systemd-shared/src/basic/glyph-util.h b/src/libnm-systemd-shared/src/basic/glyph-util.h
new file mode 100644
index 0000000000..065dde8a62
--- /dev/null
+++ b/src/libnm-systemd-shared/src/basic/glyph-util.h
@@ -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) : " ";
+}
diff --git a/src/libnm-systemd-shared/src/basic/hash-funcs.c b/src/libnm-systemd-shared/src/basic/hash-funcs.c
index c1d28ff636..3a02699ad9 100644
--- a/src/libnm-systemd-shared/src/basic/hash-funcs.c
+++ b/src/libnm-systemd-shared/src/basic/hash-funcs.c
@@ -107,11 +107,17 @@ 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
#endif /* NM_IGNORED */
diff --git a/src/libnm-systemd-shared/src/basic/hash-funcs.h b/src/libnm-systemd-shared/src/basic/hash-funcs.h
index 023cfdf530..c537c6af7e 100644
--- a/src/libnm-systemd-shared/src/basic/hash-funcs.h
+++ b/src/libnm-systemd-shared/src/basic/hash-funcs.h
@@ -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;
diff --git a/src/libnm-systemd-shared/src/basic/hashmap.c b/src/libnm-systemd-shared/src/basic/hashmap.c
index e7dedc6d35..5d0ae6aa9a 100644
--- a/src/libnm-systemd-shared/src/basic/hashmap.c
+++ b/src/libnm-systemd-shared/src/basic/hashmap.c
@@ -3,6 +3,7 @@
#include "nm-sd-adapt-shared.h"
#include <errno.h>
+#include <fnmatch.h>
#include <pthread.h>
#include <stdint.h>
#include <stdlib.h>
@@ -772,16 +773,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) {
@@ -1845,7 +1845,7 @@ int _hashmap_put_strdup_full(Hashmap **h, const struct hash_ops *hash_ops, const
}
#endif /* NM_IGNORED */
-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;
@@ -1856,10 +1856,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;
@@ -1872,7 +1875,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;
@@ -2074,3 +2077,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);
+}
diff --git a/src/libnm-systemd-shared/src/basic/hostname-util.c b/src/libnm-systemd-shared/src/basic/hostname-util.c
index 692733ac53..1e94ce1392 100644
--- a/src/libnm-systemd-shared/src/basic/hostname-util.c
+++ b/src/libnm-systemd-shared/src/basic/hostname-util.c
@@ -79,10 +79,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 == '-';
}
diff --git a/src/libnm-systemd-shared/src/basic/in-addr-util.c b/src/libnm-systemd-shared/src/basic/in-addr-util.c
index 51a6b165f8..74322f9a44 100644
--- a/src/libnm-systemd-shared/src/basic/in-addr-util.c
+++ b/src/libnm-systemd-shared/src/basic/in-addr-util.c
@@ -16,6 +16,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"
@@ -450,7 +451,7 @@ 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);
@@ -458,37 +459,26 @@ int in_addr_to_string(int family, const union in_addr_union *u, char **ret) {
}
#if 0 /* NM_IGNORED */
-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;
}
#endif /* NM_IGNORED */
diff --git a/src/libnm-systemd-shared/src/basic/in-addr-util.h b/src/libnm-systemd-shared/src/basic/in-addr-util.h
index 5de87a9539..c1e7ef965d 100644
--- a/src/libnm-systemd-shared/src/basic/in-addr-util.h
+++ b/src/libnm-systemd-shared/src/basic/in-addr-util.h
@@ -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);
diff --git a/src/libnm-systemd-shared/src/basic/locale-util.c b/src/libnm-systemd-shared/src/basic/locale-util.c
new file mode 100644
index 0000000000..ae567345d3
--- /dev/null
+++ b/src/libnm-systemd-shared/src/basic/locale-util.c
@@ -0,0 +1,376 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include "nm-sd-adapt-shared.h"
+
+#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"
+
+#if 0 /* NM_IGNORED */
+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);
+}
+#endif /* NM_IGNORED */
+
+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;
+}
+
+#if 0 /* NM_IGNORED */
+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);
+#endif /* NM_IGNORED */
diff --git a/src/libnm-systemd-shared/src/basic/locale-util.h b/src/libnm-systemd-shared/src/basic/locale-util.h
new file mode 100644
index 0000000000..8990cb6a75
--- /dev/null
+++ b/src/libnm-systemd-shared/src/basic/locale-util.h
@@ -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]);
diff --git a/src/libnm-systemd-shared/src/basic/log.h b/src/libnm-systemd-shared/src/basic/log.h
index 6361eb0f1c..1bc84e46a3 100644
--- a/src/libnm-systemd-shared/src/basic/log.h
+++ b/src/libnm-systemd-shared/src/basic/log.h
@@ -434,8 +434,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);
diff --git a/src/libnm-systemd-shared/src/basic/macro.h b/src/libnm-systemd-shared/src/basic/macro.h
index 41d83b3eb6..630aad6464 100644
--- a/src/libnm-systemd-shared/src/basic/macro.h
+++ b/src/libnm-systemd-shared/src/basic/macro.h
@@ -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)
@@ -137,25 +119,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) {
@@ -370,7 +333,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
@@ -405,8 +368,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; \
}
@@ -462,8 +429,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 {
diff --git a/src/libnm-systemd-shared/src/basic/mempool.c b/src/libnm-systemd-shared/src/basic/mempool.c
index 46c449142c..53a719e00e 100644
--- a/src/libnm-systemd-shared/src/basic/mempool.c
+++ b/src/libnm-systemd-shared/src/basic/mempool.c
@@ -5,12 +5,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;
@@ -75,20 +72,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;
diff --git a/src/libnm-systemd-shared/src/basic/mempool.h b/src/libnm-systemd-shared/src/basic/mempool.h
index 0fe2f2789c..539ccbdf06 100644
--- a/src/libnm-systemd-shared/src/basic/mempool.h
+++ b/src/libnm-systemd-shared/src/basic/mempool.h
@@ -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);
diff --git a/src/libnm-systemd-shared/src/basic/missing_syscall.h b/src/libnm-systemd-shared/src/basic/missing_syscall.h
index e5bdc0e1cd..107f4b0199 100644
--- a/src/libnm-systemd-shared/src/basic/missing_syscall.h
+++ b/src/libnm-systemd-shared/src/basic/missing_syscall.h
@@ -76,6 +76,7 @@ static inline int missing_memfd_create(const char *name, unsigned int flags) {
# define memfd_create missing_memfd_create
#endif
+#endif /* NM_IGNORED */
/* ======================================================================= */
@@ -95,6 +96,7 @@ static inline ssize_t missing_getrandom(void *buffer, size_t count, unsigned fla
/* ======================================================================= */
+#if 0 /* NM_IGNORED */
/* The syscall has been defined since forever, but the glibc wrapper was missing. */
#if !HAVE_GETTID
static inline pid_t missing_gettid(void) {
diff --git a/src/libnm-systemd-shared/src/basic/ordered-set.h b/src/libnm-systemd-shared/src/basic/ordered-set.h
index c0650e0158..e73da20573 100644
--- a/src/libnm-systemd-shared/src/basic/ordered-set.h
+++ b/src/libnm-systemd-shared/src/basic/ordered-set.h
@@ -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)
diff --git a/src/libnm-systemd-shared/src/basic/parse-util.c b/src/libnm-systemd-shared/src/basic/parse-util.c
index 0a623c519d..d5dcaae81a 100644
--- a/src/libnm-systemd-shared/src/basic/parse-util.c
+++ b/src/libnm-systemd-shared/src/basic/parse-util.c
@@ -215,7 +215,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;
@@ -606,7 +606,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;
@@ -699,34 +699,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;
diff --git a/src/libnm-systemd-shared/src/basic/parse-util.h b/src/libnm-systemd-shared/src/basic/parse-util.h
index 8273124626..f2222dcffb 100644
--- a/src/libnm-systemd-shared/src/basic/parse-util.h
+++ b/src/libnm-systemd-shared/src/basic/parse-util.h
@@ -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);
diff --git a/src/libnm-systemd-shared/src/basic/path-util.c b/src/libnm-systemd-shared/src/basic/path-util.c
index f608845843..244336c1af 100644
--- a/src/libnm-systemd-shared/src/basic/path-util.c
+++ b/src/libnm-systemd-shared/src/basic/path-util.c
@@ -19,17 +19,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"
#if 0 /* NM_IGNORED */
int path_split_and_make_absolute(const char *p, char ***ret) {
@@ -380,54 +376,6 @@ char *path_simplify(char *path) {
return path;
}
-#if 0 /* NM_IGNORED */
-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;
-}
-#endif /* NM_IGNORED */
-
char *path_startswith_full(const char *path, const char *prefix, bool accept_dot_dot) {
assert(path);
assert(prefix);
@@ -1322,74 +1270,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;
-}
#endif /* NM_IGNORED */
bool dot_or_dot_dot(const char *path) {
diff --git a/src/libnm-systemd-shared/src/basic/path-util.h b/src/libnm-systemd-shared/src/basic/path-util.h
index fc41c86941..6f8bf116ff 100644
--- a/src/libnm-systemd-shared/src/basic/path-util.h
+++ b/src/libnm-systemd-shared/src/basic/path-util.h
@@ -79,14 +79,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));
}
@@ -183,8 +175,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) {
diff --git a/src/libnm-systemd-shared/src/basic/process-util.c b/src/libnm-systemd-shared/src/basic/process-util.c
index 83e3a71eef..bb3afe0b4e 100644
--- a/src/libnm-systemd-shared/src/basic/process-util.c
+++ b/src/libnm-systemd-shared/src/basic/process-util.c
@@ -1034,7 +1034,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;
@@ -1058,7 +1058,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();
diff --git a/src/libnm-systemd-shared/src/basic/random-util.c b/src/libnm-systemd-shared/src/basic/random-util.c
index e3f4ee720e..d576bff163 100644
--- a/src/libnm-systemd-shared/src/basic/random-util.c
+++ b/src/libnm-systemd-shared/src/basic/random-util.c
@@ -32,192 +32,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;
-
- /* 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. */
-
- 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 (;;) {
-#if HAVE_GETRANDOM
- ssize_t l = getrandom(p, n, FLAGS_SET(flags, RANDOM_BLOCK) ? 0 : GRND_INSECURE);
-#else
- /* NetworkManager Note: systemd calls the syscall directly in this case. Don't add that workaround.
- * If you don't compile against a libc that provides getrandom(), you don't get it. */
- ssize_t l = -1;
- errno = ENOSYS;
+#if HAVE_SYS_AUXV_H
+ memcpy(state.auxval, ULONG_TO_PTR(getauxval(AT_RANDOM)), sizeof(state.auxval));
#endif
- 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;
+ while (n > 0) {
+ struct sha256_ctx ctx;
+
+ 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;
}
+ sha256_finish_ctx(&ctx, p);
+ p = (uint8_t *) p + SHA256_DIGEST_SIZE;
+ n -= SHA256_DIGEST_SIZE;
+ ++state.block_id;
}
-
- 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 random_bytes(void *p, size_t n) {
+ static bool have_getrandom = true, have_grndinsecure = true;
+ _cleanup_close_ int fd = -1;
-void initialize_srand(void) {
- static bool pthread_atfork_registered = false;
- unsigned x;
-#if HAVE_SYS_AUXV_H
- const void *auxv;
-#endif
- if (srand_called)
+ if (n == 0)
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;
+ 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. */
}
-}
-
-/* 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. */
+ fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY);
+ if (fd >= 0 && loop_read_exact(fd, p, n, false) == 0)
+ return;
- initialize_srand();
+ /* This is a terrible fallback. Oh well. */
+ fallback_random_bytes(p, n);
+}
- for (q = p; q < (uint8_t*) p + n; q += RAND_STEP) {
- unsigned rr;
+int crypto_random_bytes(void *p, size_t n) {
+ static bool have_getrandom = true, seen_initialized = false;
+ _cleanup_close_ int fd = -1;
- rr = (unsigned) rand();
+ if (n == 0)
+ return 0;
-#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;
+ 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;
}
-}
-void random_bytes(void *p, size_t n) {
+ if (!seen_initialized) {
+ _cleanup_close_ int ready_fd = -1;
+ int r;
- /* 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)
- return;
+ 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;
+ }
- /* 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);
+ fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY);
+ if (fd < 0)
+ return -errno;
+ return loop_read_exact(fd, p, n, false);
}
#if 0 /* NM_IGNORED */
diff --git a/src/libnm-systemd-shared/src/basic/random-util.h b/src/libnm-systemd-shared/src/basic/random-util.h
index ccee32792f..2d99807272 100644
--- a/src/libnm-systemd-shared/src/basic/random-util.h
+++ b/src/libnm-systemd-shared/src/basic/random-util.h
@@ -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;
diff --git a/src/libnm-systemd-shared/src/basic/set.h b/src/libnm-systemd-shared/src/basic/set.h
index 5cae13160b..52cf63e2dd 100644
--- a/src/libnm-systemd-shared/src/basic/set.h
+++ b/src/libnm-systemd-shared/src/basic/set.h
@@ -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);
diff --git a/src/libnm-systemd-shared/src/basic/socket-util.c b/src/libnm-systemd-shared/src/basic/socket-util.c
index 6478fdee49..c155e352d0 100644
--- a/src/libnm-systemd-shared/src/basic/socket-util.c
+++ b/src/libnm-systemd-shared/src/basic/socket-util.c
@@ -495,9 +495,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,
@@ -656,24 +654,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);
@@ -780,10 +778,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);
@@ -841,7 +839,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
@@ -1248,7 +1246,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,
@@ -1437,3 +1438,51 @@ int socket_get_mtu(int fd, int af, size_t *ret) {
return 0;
}
#endif /* NM_IGNORED */
+
+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));
+}
diff --git a/src/libnm-systemd-shared/src/basic/socket-util.h b/src/libnm-systemd-shared/src/basic/socket-util.h
index 709da20645..cf9a0b356f 100644
--- a/src/libnm-systemd-shared/src/basic/socket-util.h
+++ b/src/libnm-systemd-shared/src/basic/socket-util.h
@@ -131,7 +131,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);
}
@@ -226,9 +226,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: \
@@ -336,3 +336,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);
diff --git a/src/libnm-systemd-shared/src/basic/stat-util.c b/src/libnm-systemd-shared/src/basic/stat-util.c
index fd32f25d28..f2041535f4 100644
--- a/src/libnm-systemd-shared/src/basic/stat-util.c
+++ b/src/libnm-systemd-shared/src/basic/stat-util.c
@@ -76,13 +76,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);
@@ -104,15 +101,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);
+
+ for (;;) {
+ struct dirent *de;
+ ssize_t n;
+
+ n = getdents64(fd, buf, m);
+ if (n < 0)
+ return -errno;
+ if (n == 0)
+ break;
- msan_unpoison(&buffer, n);
+ assert((size_t) n <= m);
+ msan_unpoison(buf, n);
- FOREACH_DIRENT_IN_BUFFER(de, &buffer.de, n)
- if (!dot_or_dot_dot(de->d_name))
- return 0;
+ 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;
}
@@ -324,101 +336,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;
-}
#endif /* NM_IGNORED */
int proc_mounted(void) {
diff --git a/src/libnm-systemd-shared/src/basic/stat-util.h b/src/libnm-systemd-shared/src/basic/stat-util.h
index 37513a43e7..7f0b3dc0af 100644
--- a/src/libnm-systemd-shared/src/basic/stat-util.h
+++ b/src/libnm-systemd-shared/src/basic/stat-util.h
@@ -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;
-}
diff --git a/src/libnm-systemd-shared/src/basic/string-util.c b/src/libnm-systemd-shared/src/basic/string-util.c
index fea22ec805..7cd4b055b3 100644
--- a/src/libnm-systemd-shared/src/basic/string-util.c
+++ b/src/libnm-systemd-shared/src/basic/string-util.c
@@ -1171,4 +1171,31 @@ 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;
+}
#endif /* NM_IGNORED */
diff --git a/src/libnm-systemd-shared/src/basic/string-util.h b/src/libnm-systemd-shared/src/basic/string-util.h
index a1d88fbb95..1dd46f7f20 100644
--- a/src/libnm-systemd-shared/src/basic/string-util.h
+++ b/src/libnm-systemd-shared/src/basic/string-util.h
@@ -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);
diff --git a/src/libnm-systemd-shared/src/basic/strv.c b/src/libnm-systemd-shared/src/basic/strv.c
index f2cb80fe2e..d9c586339d 100644
--- a/src/libnm-systemd-shared/src/basic/strv.c
+++ b/src/libnm-systemd-shared/src/basic/strv.c
@@ -357,7 +357,7 @@ int strv_split_colon_pairs(char ***t, const char *s) {
}
#endif /* NM_IGNORED */
-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;
@@ -367,7 +367,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;
@@ -375,7 +375,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);
}
@@ -392,11 +392,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];
}
@@ -409,27 +409,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;
}
@@ -490,10 +496,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);
@@ -535,7 +541,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)
@@ -545,7 +551,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) {
diff --git a/src/libnm-systemd-shared/src/basic/strv.h b/src/libnm-systemd-shared/src/basic/strv.h
index 2a858326c6..072739df35 100644
--- a/src/libnm-systemd-shared/src/basic/strv.h
+++ b/src/libnm-systemd-shared/src/basic/strv.h
@@ -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); \
diff --git a/src/libnm-systemd-shared/src/basic/time-util.c b/src/libnm-systemd-shared/src/basic/time-util.c
index 8476a6505f..0496ede3ee 100644
--- a/src/libnm-systemd-shared/src/basic/time-util.c
+++ b/src/libnm-systemd-shared/src/basic/time-util.c
@@ -31,10 +31,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) {
@@ -298,8 +298,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",
@@ -386,8 +386,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. */
@@ -402,12 +402,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 */
-
- /* 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(). */
+ 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(). */
} else {
buf[n++] = ' ';
strcpy(buf + n, tm.tm_zone);
@@ -705,10 +707,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++) {
@@ -1414,9 +1417,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;
diff --git a/src/libnm-systemd-shared/src/fundamental/macro-fundamental.h b/src/libnm-systemd-shared/src/fundamental/macro-fundamental.h
index 1c198f6ad9..a738b1f50e 100644
--- a/src/libnm-systemd-shared/src/fundamental/macro-fundamental.h
+++ b/src/libnm-systemd-shared/src/fundamental/macro-fundamental.h
@@ -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 _alignas_(x) __attribute__((__aligned__(__alignof__(x))))
+#define _alignptr_ __attribute__((__aligned__(sizeof(void *))))
+#define _cleanup_(x) __attribute__((__cleanup__(x)))
#define _const_ __attribute__((__const__))
-#define _pure_ __attribute__((__pure__))
-#define _section_(x) __attribute__((__section__(x)))
+#define _deprecated_ __attribute__((__deprecated__))
+#define _destructor_ __attribute__((__destructor__))
+#define _hidden_ __attribute__((__visibility__("hidden")))
+#define _likely_(x) (__builtin_expect(!!(x), 1))
+#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 _used_ __attribute__((__used__))
-#define _unused_ __attribute__((__unused__))
-#define _cleanup_(x) __attribute__((__cleanup__(x)))
-#define _likely_(x) (__builtin_expect(!!(x), 1))
+#define _returns_nonnull_ __attribute__((__returns_nonnull__))
+#define _section_(x) __attribute__((__section__(x)))
+#define _sentinel_ __attribute__((__sentinel__))
#define _unlikely_(x) (__builtin_expect(!!(x), 0))
-#if __GNUC__ >= 7
-#define _fallthrough_ __attribute__((__fallthrough__))
+#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 _fallthrough_
+# define _alloc_(...) __attribute__((__alloc_size__(__VA_ARGS__)))
#endif
-/* Define C11 noreturn without <stdnoreturn.h> and even on older gcc
- * compiler versions */
-#ifndef _noreturn_
-#if __STDC_VERSION__ >= 201112L
-#define _noreturn_ _Noreturn
+
+#if __GNUC__ >= 7 || (defined(__clang__) && __clang_major__ >= 10)
+# define _fallthrough_ __attribute__((__fallthrough__))
#else
-#define _noreturn_ __attribute__((__noreturn__))
-#endif
+# 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( \
diff --git a/src/libnm-systemd-shared/src/fundamental/sha256.c b/src/libnm-systemd-shared/src/fundamental/sha256.c
new file mode 100644
index 0000000000..0f3872ae9d
--- /dev/null
+++ b/src/libnm-systemd-shared/src/fundamental/sha256.c
@@ -0,0 +1,293 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include "nm-sd-adapt-shared.h"
+
+/* 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;
+}
diff --git a/src/libnm-systemd-shared/src/fundamental/sha256.h b/src/libnm-systemd-shared/src/fundamental/sha256.h
new file mode 100644
index 0000000000..f296f76ae8
--- /dev/null
+++ b/src/libnm-systemd-shared/src/fundamental/sha256.h
@@ -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);
diff --git a/src/libnm-systemd-shared/src/fundamental/string-util-fundamental.c b/src/libnm-systemd-shared/src/fundamental/string-util-fundamental.c
index 735697659c..33f2d860f5 100644
--- a/src/libnm-systemd-shared/src/fundamental/string-util-fundamental.c
+++ b/src/libnm-systemd-shared/src/fundamental/string-util-fundamental.c
@@ -3,10 +3,10 @@
#include "nm-sd-adapt-shared.h"
#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) {
@@ -80,36 +80,27 @@ sd_char* endswith_no_case(const sd_char *s, const sd_char *postfix) {
}
#if 0 /* NM_IGNORED */
-#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 sd_bool is_valid_version_char(sd_char a) {
- return isdigit(a) || is_alpha(a) || IN_SET(a, '~', '-', '^', '.');
+static bool is_valid_version_char(sd_char a) {
+ return ascii_isdigit(a) || ascii_isalpha(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.
+int strverscmp_improved(const sd_char *a, const sd_char *b) {
+ /* This function is similar to strverscmp(3), but it treats '-' and '.' as separators.
+ *
+ * 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'.
- * Unlike rpmvercmp(), this distiguishes e.g. 123a and 123.a, and 123a is newer.
*
- * This splits the input strings into segments. Each segment is numeric or alpha, and may be
+ * 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
@@ -126,12 +117,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))
@@ -152,7 +143,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);
@@ -188,20 +179,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);
@@ -209,18 +205,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;
@@ -230,7 +226,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;
}
diff --git a/src/libnm-systemd-shared/src/fundamental/string-util-fundamental.h b/src/libnm-systemd-shared/src/fundamental/string-util-fundamental.h
index dc0c1202be..ecf32e519f 100644
--- a/src/libnm-systemd-shared/src/fundamental/string-util-fundamental.h
+++ b/src/libnm-systemd-shared/src/fundamental/string-util-fundamental.h
@@ -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');
+}
diff --git a/src/libnm-systemd-shared/src/fundamental/types-fundamental.h b/src/libnm-systemd-shared/src/fundamental/types-fundamental.h
deleted file mode 100644
index 5977e40c6c..0000000000
--- a/src/libnm-systemd-shared/src/fundamental/types-fundamental.h
+++ /dev/null
@@ -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
diff --git a/src/libnm-systemd-shared/src/shared/dns-domain.c b/src/libnm-systemd-shared/src/shared/dns-domain.c
index e932b6935c..7bba3b18d1 100644
--- a/src/libnm-systemd-shared/src/shared/dns-domain.c
+++ b/src/libnm-systemd-shared/src/shared/dns-domain.c
@@ -9,6 +9,7 @@
#include "alloc-util.h"
#include "dns-domain.h"
+#include "glyph-util.h"
#include "hashmap.h"
#include "hexdecoct.h"
#include "hostname-util.h"
@@ -239,9 +240,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 */
@@ -456,12 +456,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:
@@ -919,15 +915,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;
}
@@ -1035,10 +1029,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;
@@ -1058,6 +1052,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 */
@@ -1066,64 +1063,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)) {
+ switch (x) {
+ case 2:
+ if (!srv_type_label_is_valid(a, an))
+ break;
- if (dns_service_name_label_is_valid(a, an)) {
- /* OK, got <name> . <type> . <type2> . <domain> */
+ /* OK, got <type> . <type2> . <domain> */
- name = strndup(a, an);
- if (!name)
- return -ENOMEM;
+ name = NULL;
- type = strjoin(b, ".", c);
- if (!type)
- return -ENOMEM;
+ type = strjoin(a, ".", b);
+ if (!type)
+ return -ENOMEM;
- d = p;
- goto finish;
- }
+ d = q;
+ break;
- } else if (srv_type_label_is_valid(a, an)) {
+ case 3:
+ if (!dns_service_name_label_is_valid(a, an))
+ break;
- /* OK, got <type> . <type2> . <domain> */
+ /* OK, got <name> . <type> . <type2> . <domain> */
- name = NULL;
+ name = strndup(a, an);
+ if (!name)
+ return -ENOMEM;
- type = strjoin(a, ".", b);
- if (!type)
- return -ENOMEM;
+ type = strjoin(b, ".", c);
+ if (!type)
+ return -ENOMEM;
- d = q;
- goto finish;
- }
+ d = p;
+ break;
}
- name = NULL;
- type = NULL;
- d = joined;
-
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;
}
@@ -1303,7 +1294,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;
@@ -1317,8 +1308,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;
}
diff --git a/src/libnm-systemd-shared/src/shared/dns-domain.h b/src/libnm-systemd-shared/src/shared/dns-domain.h
index ec174c0e51..828e924dfb 100644
--- a/src/libnm-systemd-shared/src/shared/dns-domain.h
+++ b/src/libnm-systemd-shared/src/shared/dns-domain.h
@@ -42,8 +42,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)
@@ -90,7 +90,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);