mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager
synced 2024-10-07 00:31:11 +00:00
systemd: merge branch systemd into main
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/1291
This commit is contained in:
commit
556bff1767
|
@ -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 \
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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))
|
||||
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);
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 (;;) {
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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! */
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
along with systemd; If not, see <https://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <inttypes.h>
|
||||
|
@ -36,7 +36,7 @@ enum {
|
|||
SD_DHCP6_CLIENT_EVENT_RESEND_EXPIRE = 10,
|
||||
SD_DHCP6_CLIENT_EVENT_RETRANS_MAX = 11,
|
||||
SD_DHCP6_CLIENT_EVENT_IP_ACQUIRE = 12,
|
||||
SD_DHCP6_CLIENT_EVENT_INFORMATION_REQUEST = 13,
|
||||
SD_DHCP6_CLIENT_EVENT_INFORMATION_REQUEST = 13
|
||||
};
|
||||
|
||||
/* https://www.iana.org/assignments/dhcpv6-parameters/dhcpv6-parameters.xhtml#dhcpv6-parameters-2 */
|
||||
|
@ -63,15 +63,15 @@ enum {
|
|||
SD_DHCP6_OPTION_RECONF_ACCEPT = 20, /* RFC 8415 */
|
||||
SD_DHCP6_OPTION_SIP_SERVER_DOMAIN_NAME = 21, /* RFC 3319 */
|
||||
SD_DHCP6_OPTION_SIP_SERVER_ADDRESS = 22, /* RFC 3319 */
|
||||
SD_DHCP6_OPTION_DNS_SERVERS = 23, /* RFC 3646 */
|
||||
SD_DHCP6_OPTION_DOMAIN_LIST = 24, /* RFC 3646 */
|
||||
SD_DHCP6_OPTION_DNS_SERVER = 23, /* RFC 3646 */
|
||||
SD_DHCP6_OPTION_DOMAIN = 24, /* RFC 3646 */
|
||||
SD_DHCP6_OPTION_IA_PD = 25, /* RFC 3633, RFC 8415 */
|
||||
SD_DHCP6_OPTION_IA_PD_PREFIX = 26, /* RFC 3633, RFC 8415 */
|
||||
SD_DHCP6_OPTION_NIS_SERVERS = 27, /* RFC 3898 */
|
||||
SD_DHCP6_OPTION_NISP_SERVERS = 28, /* RFC 3898 */
|
||||
SD_DHCP6_OPTION_NIS_SERVER = 27, /* RFC 3898 */
|
||||
SD_DHCP6_OPTION_NISP_SERVER = 28, /* RFC 3898 */
|
||||
SD_DHCP6_OPTION_NIS_DOMAIN_NAME = 29, /* RFC 3898 */
|
||||
SD_DHCP6_OPTION_NISP_DOMAIN_NAME = 30, /* RFC 3898 */
|
||||
SD_DHCP6_OPTION_SNTP_SERVERS = 31, /* RFC 4075, deprecated */
|
||||
SD_DHCP6_OPTION_SNTP_SERVER = 31, /* RFC 4075, deprecated */
|
||||
SD_DHCP6_OPTION_INFORMATION_REFRESH_TIME = 32, /* RFC 4242, 8415, sec. 21.23 */
|
||||
SD_DHCP6_OPTION_BCMCS_SERVER_D = 33, /* RFC 4280 */
|
||||
SD_DHCP6_OPTION_BCMCS_SERVER_A = 34, /* RFC 4280 */
|
||||
|
@ -183,7 +183,7 @@ enum {
|
|||
SD_DHCP6_OPTION_SLAP_QUAD = 140, /* RFC 8948 */
|
||||
SD_DHCP6_OPTION_V6_DOTS_RI = 141, /* RFC 8973 */
|
||||
SD_DHCP6_OPTION_V6_DOTS_ADDRESS = 142, /* RFC 8973 */
|
||||
SD_DHCP6_OPTION_IPV6_ADDRESS_ANDSF = 143, /* RFC 6153 */
|
||||
SD_DHCP6_OPTION_IPV6_ADDRESS_ANDSF = 143 /* RFC 6153 */
|
||||
/* option codes 144-65535 are unassigned */
|
||||
};
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
along with systemd; If not, see <https://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <inttypes.h>
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
along with systemd; If not, see <https://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <inttypes.h>
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
along with systemd; If not, see <https://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <inttypes.h>
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
along with systemd; If not, see <https://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <inttypes.h>
|
||||
|
@ -116,9 +116,11 @@ int sd_id128_get_boot_app_specific(sd_id128_t app_id, sd_id128_t *ret);
|
|||
#a #b #c #d "-" #e #f "-" #g #h "-" #i #j "-" #k #l #m #n #o #p
|
||||
|
||||
_sd_pure_ static __inline__ int sd_id128_equal(sd_id128_t a, sd_id128_t b) {
|
||||
return memcmp(&a, &b, 16) == 0;
|
||||
return a.qwords[0] == b.qwords[0] && a.qwords[1] == b.qwords[1];
|
||||
}
|
||||
|
||||
int sd_id128_string_equal(const char *s, sd_id128_t id);
|
||||
|
||||
_sd_pure_ static __inline__ int sd_id128_is_null(sd_id128_t a) {
|
||||
return a.qwords[0] == 0 && a.qwords[1] == 0;
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
along with systemd; If not, see <https://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <errno.h>
|
||||
|
@ -32,14 +32,14 @@ _SD_BEGIN_DECLARATIONS;
|
|||
typedef struct sd_lldp_rx sd_lldp_rx;
|
||||
typedef struct sd_lldp_neighbor sd_lldp_neighbor;
|
||||
|
||||
typedef enum sd_lldp_rx_event_t {
|
||||
__extension__ typedef enum sd_lldp_rx_event_t {
|
||||
SD_LLDP_RX_EVENT_ADDED,
|
||||
SD_LLDP_RX_EVENT_REMOVED,
|
||||
SD_LLDP_RX_EVENT_UPDATED,
|
||||
SD_LLDP_RX_EVENT_REFRESHED,
|
||||
_SD_LLDP_RX_EVENT_MAX,
|
||||
_SD_LLDP_RX_EVENT_INVALID = -EINVAL,
|
||||
_SD_ENUM_FORCE_S64(LLDP_RX_EVENT),
|
||||
_SD_ENUM_FORCE_S64(LLDP_RX_EVENT)
|
||||
} sd_lldp_rx_event_t;
|
||||
|
||||
typedef void (*sd_lldp_rx_callback_t)(sd_lldp_rx *lldp_rx, sd_lldp_rx_event_t event, sd_lldp_neighbor *n, void *userdata);
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
along with systemd; If not, see <https://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <inttypes.h>
|
||||
|
@ -34,7 +34,7 @@ enum {
|
|||
SD_LLDP_TYPE_SYSTEM_DESCRIPTION = 6,
|
||||
SD_LLDP_TYPE_SYSTEM_CAPABILITIES = 7,
|
||||
SD_LLDP_TYPE_MGMT_ADDRESS = 8,
|
||||
SD_LLDP_TYPE_PRIVATE = 127,
|
||||
SD_LLDP_TYPE_PRIVATE = 127
|
||||
};
|
||||
|
||||
/* IEEE 802.1AB-2009 Clause 8.5.2: Chassis subtypes */
|
||||
|
@ -46,7 +46,7 @@ enum {
|
|||
SD_LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS = 4,
|
||||
SD_LLDP_CHASSIS_SUBTYPE_NETWORK_ADDRESS = 5,
|
||||
SD_LLDP_CHASSIS_SUBTYPE_INTERFACE_NAME = 6,
|
||||
SD_LLDP_CHASSIS_SUBTYPE_LOCALLY_ASSIGNED = 7,
|
||||
SD_LLDP_CHASSIS_SUBTYPE_LOCALLY_ASSIGNED = 7
|
||||
};
|
||||
|
||||
/* IEEE 802.1AB-2009 Clause 8.5.3: Port subtype */
|
||||
|
@ -58,7 +58,7 @@ enum {
|
|||
SD_LLDP_PORT_SUBTYPE_NETWORK_ADDRESS = 4,
|
||||
SD_LLDP_PORT_SUBTYPE_INTERFACE_NAME = 5,
|
||||
SD_LLDP_PORT_SUBTYPE_AGENT_CIRCUIT_ID = 6,
|
||||
SD_LLDP_PORT_SUBTYPE_LOCALLY_ASSIGNED = 7,
|
||||
SD_LLDP_PORT_SUBTYPE_LOCALLY_ASSIGNED = 7
|
||||
};
|
||||
|
||||
/* IEEE 802.1AB-2009 Clause 8.5.8: System capabilities */
|
||||
|
@ -73,7 +73,7 @@ enum {
|
|||
SD_LLDP_SYSTEM_CAPABILITIES_STATION = 1 << 7,
|
||||
SD_LLDP_SYSTEM_CAPABILITIES_CVLAN = 1 << 8,
|
||||
SD_LLDP_SYSTEM_CAPABILITIES_SVLAN = 1 << 9,
|
||||
SD_LLDP_SYSTEM_CAPABILITIES_TPMR = 1 << 10,
|
||||
SD_LLDP_SYSTEM_CAPABILITIES_TPMR = 1 << 10
|
||||
};
|
||||
|
||||
#define SD_LLDP_SYSTEM_CAPABILITIES_ALL UINT16_MAX
|
||||
|
@ -107,7 +107,7 @@ enum {
|
|||
SD_LLDP_OUI_802_1_SUBTYPE_PROTOCOL_IDENTITY = 4,
|
||||
SD_LLDP_OUI_802_1_SUBTYPE_VID_USAGE_DIGEST = 5,
|
||||
SD_LLDP_OUI_802_1_SUBTYPE_MANAGEMENT_VID = 6,
|
||||
SD_LLDP_OUI_802_1_SUBTYPE_LINK_AGGREGATION = 7,
|
||||
SD_LLDP_OUI_802_1_SUBTYPE_LINK_AGGREGATION = 7
|
||||
};
|
||||
|
||||
/* IEEE 802.1AB-2009 Annex F */
|
||||
|
@ -115,7 +115,7 @@ enum {
|
|||
SD_LLDP_OUI_802_3_SUBTYPE_MAC_PHY_CONFIG_STATUS = 1,
|
||||
SD_LLDP_OUI_802_3_SUBTYPE_POWER_VIA_MDI = 2,
|
||||
SD_LLDP_OUI_802_3_SUBTYPE_LINK_AGGREGATION = 3,
|
||||
SD_LLDP_OUI_802_3_SUBTYPE_MAXIMUM_FRAME_SIZE = 4,
|
||||
SD_LLDP_OUI_802_3_SUBTYPE_MAXIMUM_FRAME_SIZE = 4
|
||||
};
|
||||
|
||||
_SD_END_DECLARATIONS;
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
along with systemd; If not, see <https://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <errno.h>
|
||||
|
@ -42,25 +42,25 @@ enum {
|
|||
SD_NDISC_OPTION_RDNSS = 25,
|
||||
SD_NDISC_OPTION_FLAGS_EXTENSION = 26,
|
||||
SD_NDISC_OPTION_DNSSL = 31,
|
||||
SD_NDISC_OPTION_CAPTIVE_PORTAL = 37,
|
||||
SD_NDISC_OPTION_CAPTIVE_PORTAL = 37
|
||||
};
|
||||
|
||||
/* Route preference, RFC 4191, Section 2.1 */
|
||||
enum {
|
||||
SD_NDISC_PREFERENCE_LOW = 3U,
|
||||
SD_NDISC_PREFERENCE_MEDIUM = 0U,
|
||||
SD_NDISC_PREFERENCE_HIGH = 1U,
|
||||
SD_NDISC_PREFERENCE_HIGH = 1U
|
||||
};
|
||||
|
||||
typedef struct sd_ndisc sd_ndisc;
|
||||
typedef struct sd_ndisc_router sd_ndisc_router;
|
||||
|
||||
typedef enum sd_ndisc_event_t {
|
||||
__extension__ typedef enum sd_ndisc_event_t {
|
||||
SD_NDISC_EVENT_TIMEOUT,
|
||||
SD_NDISC_EVENT_ROUTER,
|
||||
_SD_NDISC_EVENT_MAX,
|
||||
_SD_NDISC_EVENT_INVALID = -EINVAL,
|
||||
_SD_ENUM_FORCE_S64(NDISC_EVENT),
|
||||
_SD_ENUM_FORCE_S64(NDISC_EVENT)
|
||||
} sd_ndisc_event_t;
|
||||
|
||||
typedef void (*sd_ndisc_callback_t)(sd_ndisc *nd, sd_ndisc_event_t event, sd_ndisc_router *rt, void *userdata);
|
||||
|
@ -82,7 +82,6 @@ int sd_ndisc_set_ifname(sd_ndisc *nd, const char *interface_name);
|
|||
int sd_ndisc_get_ifname(sd_ndisc *nd, const char **ret);
|
||||
int sd_ndisc_set_mac(sd_ndisc *nd, const struct ether_addr *mac_addr);
|
||||
|
||||
int sd_ndisc_router_from_raw(sd_ndisc_router **ret, const void *raw, size_t raw_size);
|
||||
sd_ndisc_router *sd_ndisc_router_ref(sd_ndisc_router *rt);
|
||||
sd_ndisc_router *sd_ndisc_router_unref(sd_ndisc_router *rt);
|
||||
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
/* dummy header */
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
139
src/libnm-systemd-shared/src/basic/glyph-util.c
Normal file
139
src/libnm-systemd-shared/src/basic/glyph-util.c
Normal file
|
@ -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];
|
||||
}
|
60
src/libnm-systemd-shared/src/basic/glyph-util.h
Normal file
60
src/libnm-systemd-shared/src/basic/glyph-util.h
Normal file
|
@ -0,0 +1,60 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "macro.h"
|
||||
|
||||
typedef enum SpecialGlyph {
|
||||
SPECIAL_GLYPH_TREE_VERTICAL,
|
||||
SPECIAL_GLYPH_TREE_BRANCH,
|
||||
SPECIAL_GLYPH_TREE_RIGHT,
|
||||
SPECIAL_GLYPH_TREE_SPACE,
|
||||
SPECIAL_GLYPH_TREE_TOP,
|
||||
SPECIAL_GLYPH_VERTICAL_DOTTED,
|
||||
SPECIAL_GLYPH_TRIANGULAR_BULLET,
|
||||
SPECIAL_GLYPH_BLACK_CIRCLE,
|
||||
SPECIAL_GLYPH_WHITE_CIRCLE,
|
||||
SPECIAL_GLYPH_MULTIPLICATION_SIGN,
|
||||
SPECIAL_GLYPH_CIRCLE_ARROW,
|
||||
SPECIAL_GLYPH_BULLET,
|
||||
SPECIAL_GLYPH_MU,
|
||||
SPECIAL_GLYPH_CHECK_MARK,
|
||||
SPECIAL_GLYPH_CROSS_MARK,
|
||||
SPECIAL_GLYPH_ARROW_RIGHT,
|
||||
SPECIAL_GLYPH_ARROW_UP,
|
||||
SPECIAL_GLYPH_ARROW_DOWN,
|
||||
SPECIAL_GLYPH_ELLIPSIS,
|
||||
SPECIAL_GLYPH_LIGHT_SHADE,
|
||||
SPECIAL_GLYPH_DARK_SHADE,
|
||||
SPECIAL_GLYPH_SIGMA,
|
||||
SPECIAL_GLYPH_EXTERNAL_LINK,
|
||||
_SPECIAL_GLYPH_FIRST_EMOJI,
|
||||
SPECIAL_GLYPH_ECSTATIC_SMILEY = _SPECIAL_GLYPH_FIRST_EMOJI,
|
||||
SPECIAL_GLYPH_HAPPY_SMILEY,
|
||||
SPECIAL_GLYPH_SLIGHTLY_HAPPY_SMILEY,
|
||||
SPECIAL_GLYPH_NEUTRAL_SMILEY,
|
||||
SPECIAL_GLYPH_SLIGHTLY_UNHAPPY_SMILEY,
|
||||
SPECIAL_GLYPH_UNHAPPY_SMILEY,
|
||||
SPECIAL_GLYPH_DEPRESSED_SMILEY,
|
||||
SPECIAL_GLYPH_LOCK_AND_KEY,
|
||||
SPECIAL_GLYPH_TOUCH,
|
||||
SPECIAL_GLYPH_RECYCLING,
|
||||
SPECIAL_GLYPH_DOWNLOAD,
|
||||
SPECIAL_GLYPH_SPARKLES,
|
||||
_SPECIAL_GLYPH_MAX,
|
||||
_SPECIAL_GLYPH_INVALID = -EINVAL,
|
||||
} SpecialGlyph;
|
||||
|
||||
const char *special_glyph(SpecialGlyph code) _const_;
|
||||
|
||||
bool emoji_enabled(void);
|
||||
|
||||
static inline const char *special_glyph_check_mark(bool b) {
|
||||
return b ? special_glyph(SPECIAL_GLYPH_CHECK_MARK) : special_glyph(SPECIAL_GLYPH_CROSS_MARK);
|
||||
}
|
||||
|
||||
static inline const char *special_glyph_check_mark_space(bool b) {
|
||||
return b ? special_glyph(SPECIAL_GLYPH_CHECK_MARK) : " ";
|
||||
}
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 (n == SIZE_MAX) {
|
||||
if (set_contains(*s, (char*) p))
|
||||
return 0;
|
||||
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -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 == '-';
|
||||
}
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
|
376
src/libnm-systemd-shared/src/basic/locale-util.c
Normal file
376
src/libnm-systemd-shared/src/basic/locale-util.c
Normal file
|
@ -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 */
|
56
src/libnm-systemd-shared/src/basic/locale-util.h
Normal file
56
src/libnm-systemd-shared/src/basic/locale-util.h
Normal file
|
@ -0,0 +1,56 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#include <libintl.h>
|
||||
#include <locale.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "macro.h"
|
||||
|
||||
typedef enum LocaleVariable {
|
||||
/* We don't list LC_ALL here on purpose. People should be
|
||||
* using LANG instead. */
|
||||
|
||||
VARIABLE_LANG,
|
||||
VARIABLE_LANGUAGE,
|
||||
VARIABLE_LC_CTYPE,
|
||||
VARIABLE_LC_NUMERIC,
|
||||
VARIABLE_LC_TIME,
|
||||
VARIABLE_LC_COLLATE,
|
||||
VARIABLE_LC_MONETARY,
|
||||
VARIABLE_LC_MESSAGES,
|
||||
VARIABLE_LC_PAPER,
|
||||
VARIABLE_LC_NAME,
|
||||
VARIABLE_LC_ADDRESS,
|
||||
VARIABLE_LC_TELEPHONE,
|
||||
VARIABLE_LC_MEASUREMENT,
|
||||
VARIABLE_LC_IDENTIFICATION,
|
||||
_VARIABLE_LC_MAX,
|
||||
_VARIABLE_LC_INVALID = -EINVAL,
|
||||
} LocaleVariable;
|
||||
|
||||
int get_locales(char ***l);
|
||||
bool locale_is_valid(const char *name);
|
||||
int locale_is_installed(const char *name);
|
||||
|
||||
#define _(String) gettext(String)
|
||||
#define N_(String) String
|
||||
void init_gettext(void);
|
||||
|
||||
bool is_locale_utf8(void);
|
||||
|
||||
const char* locale_variable_to_string(LocaleVariable i) _const_;
|
||||
LocaleVariable locale_variable_from_string(const char *s) _pure_;
|
||||
|
||||
static inline void freelocalep(locale_t *p) {
|
||||
if (*p == (locale_t) 0)
|
||||
return;
|
||||
|
||||
freelocale(*p);
|
||||
}
|
||||
|
||||
void locale_variables_free(char* l[_VARIABLE_LC_MAX]);
|
||||
static inline void locale_variables_freep(char*(*l)[_VARIABLE_LC_MAX]) {
|
||||
locale_variables_free(*l);
|
||||
}
|
||||
void locale_variables_simplify(char *l[_VARIABLE_LC_MAX]);
|
|
@ -434,8 +434,16 @@ int log_emergency_level(void);
|
|||
|
||||
bool log_on_console(void) _pure_;
|
||||
|
||||
/* Helper to prepare various field for structured logging */
|
||||
/* Helper to wrap the main message in structured logging. The macro doesn't do much,
|
||||
* except to provide visual grouping of the format string and its arguments. */
|
||||
#if LOG_MESSAGE_VERIFICATION || defined(__COVERITY__)
|
||||
/* Do a fake formatting of the message string to let the scanner verify the arguments against the format
|
||||
* message. The variable will never be set to true, but we don't tell the compiler that :) */
|
||||
extern bool _log_message_dummy;
|
||||
# define LOG_MESSAGE(fmt, ...) "MESSAGE=%.0d" fmt, (_log_message_dummy && printf(fmt, ##__VA_ARGS__)), ##__VA_ARGS__
|
||||
#else
|
||||
# define LOG_MESSAGE(fmt, ...) "MESSAGE=" fmt, ##__VA_ARGS__
|
||||
#endif
|
||||
|
||||
void log_received_signal(int level, const struct signalfd_siginfo *si);
|
||||
|
||||
|
|
|
@ -11,24 +11,6 @@
|
|||
|
||||
#include "macro-fundamental.h"
|
||||
|
||||
#define _printf_(a, b) __attribute__((__format__(printf, a, b)))
|
||||
#ifdef __clang__
|
||||
# define _alloc_(...)
|
||||
#else
|
||||
# define _alloc_(...) __attribute__((__alloc_size__(__VA_ARGS__)))
|
||||
#endif
|
||||
#define _sentinel_ __attribute__((__sentinel__))
|
||||
#define _destructor_ __attribute__((__destructor__))
|
||||
#define _deprecated_ __attribute__((__deprecated__))
|
||||
#define _malloc_ __attribute__((__malloc__))
|
||||
#define _weak_ __attribute__((__weak__))
|
||||
#define _public_ __attribute__((__visibility__("default")))
|
||||
#define _hidden_ __attribute__((__visibility__("hidden")))
|
||||
#define _weakref_(x) __attribute__((__weakref__(#x)))
|
||||
#define _alignas_(x) __attribute__((__aligned__(__alignof__(x))))
|
||||
#define _alignptr_ __attribute__((__aligned__(sizeof(void*))))
|
||||
#define _warn_unused_result_ __attribute__((__warn_unused_result__))
|
||||
|
||||
#if !defined(HAS_FEATURE_MEMORY_SANITIZER)
|
||||
# if defined(__has_feature)
|
||||
# if __has_feature(memory_sanitizer)
|
||||
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
||||
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;
|
||||
#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;
|
||||
}
|
||||
}
|
||||
|
||||
fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY);
|
||||
if (fd < 0)
|
||||
return errno == ENOENT ? -ENOSYS : -errno;
|
||||
|
||||
return loop_read_exact(fd, p, n, true);
|
||||
}
|
||||
|
||||
static void clear_srand_initialization(void) {
|
||||
srand_called = false;
|
||||
}
|
||||
|
||||
void initialize_srand(void) {
|
||||
static bool pthread_atfork_registered = false;
|
||||
unsigned x;
|
||||
#if HAVE_SYS_AUXV_H
|
||||
const void *auxv;
|
||||
#endif
|
||||
if (srand_called)
|
||||
return;
|
||||
|
||||
#if HAVE_SYS_AUXV_H
|
||||
/* The kernel provides us with 16 bytes of entropy in auxv, so let's try to make use of that to seed
|
||||
* the pseudo-random generator. It's better than nothing... But let's first hash it to make it harder
|
||||
* to recover the original value by watching any pseudo-random bits we generate. After all the
|
||||
* AT_RANDOM data might be used by other stuff too (in particular: ASLR), and we probably shouldn't
|
||||
* leak the seed for that. */
|
||||
|
||||
auxv = ULONG_TO_PTR(getauxval(AT_RANDOM));
|
||||
if (auxv) {
|
||||
static const uint8_t auxval_hash_key[16] = {
|
||||
0x92, 0x6e, 0xfe, 0x1b, 0xcf, 0x00, 0x52, 0x9c, 0xcc, 0x42, 0xcf, 0xdc, 0x94, 0x1f, 0x81, 0x0f
|
||||
/* 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()
|
||||
};
|
||||
|
||||
x = (unsigned) siphash24(auxv, 16, auxval_hash_key);
|
||||
} else
|
||||
#if HAVE_SYS_AUXV_H
|
||||
memcpy(state.auxval, ULONG_TO_PTR(getauxval(AT_RANDOM)), sizeof(state.auxval));
|
||||
#endif
|
||||
x = 0;
|
||||
|
||||
x ^= (unsigned) now(CLOCK_REALTIME);
|
||||
x ^= (unsigned) gettid();
|
||||
while (n > 0) {
|
||||
struct sha256_ctx ctx;
|
||||
|
||||
srand(x);
|
||||
srand_called = true;
|
||||
|
||||
if (!pthread_atfork_registered) {
|
||||
(void) pthread_atfork(NULL, NULL, clear_srand_initialization);
|
||||
pthread_atfork_registered = true;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/* INT_MAX gives us only 31 bits, so use 24 out of that. */
|
||||
#if RAND_MAX >= INT_MAX
|
||||
assert_cc(RAND_MAX >= 16777215);
|
||||
# define RAND_STEP 3
|
||||
#else
|
||||
/* SHORT_INT_MAX or lower gives at most 15 bits, we just use 8 out of that. */
|
||||
assert_cc(RAND_MAX >= 255);
|
||||
# define RAND_STEP 1
|
||||
#endif
|
||||
|
||||
void pseudo_random_bytes(void *p, size_t n) {
|
||||
uint8_t *q;
|
||||
|
||||
/* This returns pseudo-random data using libc's rand() function. You probably never want to call this
|
||||
* directly, because why would you use this if you can get better stuff cheaply? Use random_bytes()
|
||||
* instead, see below: it will fall back to this function if there's nothing better to get, but only
|
||||
* then. */
|
||||
|
||||
initialize_srand();
|
||||
|
||||
for (q = p; q < (uint8_t*) p + n; q += RAND_STEP) {
|
||||
unsigned rr;
|
||||
|
||||
rr = (unsigned) rand();
|
||||
|
||||
#if RAND_STEP >= 3
|
||||
if ((size_t) (q - (uint8_t*) p + 2) < n)
|
||||
q[2] = rr >> 16;
|
||||
#endif
|
||||
#if RAND_STEP >= 2
|
||||
if ((size_t) (q - (uint8_t*) p + 1) < n)
|
||||
q[1] = rr >> 8;
|
||||
#endif
|
||||
q[0] = rr;
|
||||
sha256_finish_ctx(&ctx, p);
|
||||
p = (uint8_t *) p + SHA256_DIGEST_SIZE;
|
||||
n -= SHA256_DIGEST_SIZE;
|
||||
++state.block_id;
|
||||
}
|
||||
}
|
||||
|
||||
void random_bytes(void *p, size_t n) {
|
||||
static bool have_getrandom = true, have_grndinsecure = true;
|
||||
_cleanup_close_ int fd = -1;
|
||||
|
||||
/* This returns high quality randomness if we can get it cheaply. If we can't because for some reason
|
||||
* it is not available we'll try some crappy fallbacks.
|
||||
*
|
||||
* What this function will do:
|
||||
*
|
||||
* • Use getrandom(GRND_INSECURE) or /dev/urandom, to return high-quality random values if
|
||||
* they are cheaply available, or less high-quality random values if they are not.
|
||||
*
|
||||
* • This function will return pseudo-random data, generated via libc rand() if nothing
|
||||
* better is available.
|
||||
*
|
||||
* • This function will work fine in early boot
|
||||
*
|
||||
* • This function will always succeed
|
||||
*
|
||||
* What this function won't do:
|
||||
*
|
||||
* • This function will never fail: it will give you randomness no matter what. It might not
|
||||
* be high quality, but it will return some, possibly generated via libc's rand() call.
|
||||
*
|
||||
* • This function will never block: if the only way to get good randomness is a blocking,
|
||||
* synchronous getrandom() we'll instead provide you with pseudo-random data.
|
||||
*
|
||||
* This function is hence great for things like seeding hash tables, generating random numeric UNIX
|
||||
* user IDs (that are checked for collisions before use) and such.
|
||||
*
|
||||
* This function is hence not useful for generating UUIDs or cryptographic key material.
|
||||
*/
|
||||
|
||||
if (genuine_random_bytes(p, n, 0) >= 0)
|
||||
if (n == 0)
|
||||
return;
|
||||
|
||||
/* If for some reason some user made /dev/urandom unavailable to us, or the kernel has no entropy, use a PRNG instead. */
|
||||
pseudo_random_bytes(p, n);
|
||||
for (;;) {
|
||||
ssize_t l;
|
||||
|
||||
if (!have_getrandom)
|
||||
break;
|
||||
|
||||
l = getrandom(p, n, have_grndinsecure ? GRND_INSECURE : GRND_NONBLOCK);
|
||||
if (l > 0) {
|
||||
if ((size_t) l == n)
|
||||
return; /* Done reading, success. */
|
||||
p = (uint8_t *) p + l;
|
||||
n -= l;
|
||||
continue; /* Interrupted by a signal; keep going. */
|
||||
} else if (l == 0)
|
||||
break; /* Weird, so fallback to /dev/urandom. */
|
||||
else if (ERRNO_IS_NOT_SUPPORTED(errno)) {
|
||||
have_getrandom = false;
|
||||
break; /* No syscall, so fallback to /dev/urandom. */
|
||||
} else if (errno == EINVAL && have_grndinsecure) {
|
||||
have_grndinsecure = false;
|
||||
continue; /* No GRND_INSECURE; fallback to GRND_NONBLOCK. */
|
||||
} else if (errno == EAGAIN && !have_grndinsecure)
|
||||
break; /* Will block, but no GRND_INSECURE, so fallback to /dev/urandom. */
|
||||
|
||||
break; /* Unexpected, so just give up and fallback to /dev/urandom. */
|
||||
}
|
||||
|
||||
fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY);
|
||||
if (fd >= 0 && loop_read_exact(fd, p, n, false) == 0)
|
||||
return;
|
||||
|
||||
/* This is a terrible fallback. Oh well. */
|
||||
fallback_random_bytes(p, n);
|
||||
}
|
||||
|
||||
int crypto_random_bytes(void *p, size_t n) {
|
||||
static bool have_getrandom = true, seen_initialized = false;
|
||||
_cleanup_close_ int fd = -1;
|
||||
|
||||
if (n == 0)
|
||||
return 0;
|
||||
|
||||
for (;;) {
|
||||
ssize_t l;
|
||||
|
||||
if (!have_getrandom)
|
||||
break;
|
||||
|
||||
l = getrandom(p, n, 0);
|
||||
if (l > 0) {
|
||||
if ((size_t) l == n)
|
||||
return 0; /* Done reading, success. */
|
||||
p = (uint8_t *) p + l;
|
||||
n -= l;
|
||||
continue; /* Interrupted by a signal; keep going. */
|
||||
} else if (l == 0)
|
||||
return -EIO; /* Weird, should never happen. */
|
||||
else if (ERRNO_IS_NOT_SUPPORTED(errno)) {
|
||||
have_getrandom = false;
|
||||
break; /* No syscall, so fallback to /dev/urandom. */
|
||||
}
|
||||
return -errno;
|
||||
}
|
||||
|
||||
if (!seen_initialized) {
|
||||
_cleanup_close_ int ready_fd = -1;
|
||||
int r;
|
||||
|
||||
ready_fd = open("/dev/random", O_RDONLY|O_CLOEXEC|O_NOCTTY);
|
||||
if (ready_fd < 0)
|
||||
return -errno;
|
||||
r = fd_wait_for_event(ready_fd, POLLIN, USEC_INFINITY);
|
||||
if (r < 0)
|
||||
return r;
|
||||
seen_initialized = true;
|
||||
}
|
||||
|
||||
fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY);
|
||||
if (fd < 0)
|
||||
return -errno;
|
||||
return loop_read_exact(fd, p, n, false);
|
||||
}
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
|
|
|
@ -5,15 +5,8 @@
|
|||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef enum RandomFlags {
|
||||
RANDOM_BLOCK = 1 << 0, /* Rather block than return crap randomness (only if the kernel supports that) */
|
||||
} RandomFlags;
|
||||
|
||||
int genuine_random_bytes(void *p, size_t n, RandomFlags flags); /* returns "genuine" randomness, optionally filled up with pseudo random, if not enough is available */
|
||||
void pseudo_random_bytes(void *p, size_t n); /* returns only pseudo-randommess (but possibly seeded from something better) */
|
||||
void random_bytes(void *p, size_t n); /* returns genuine randomness if cheaply available, and pseudo randomness if not. */
|
||||
|
||||
void initialize_srand(void);
|
||||
void random_bytes(void *p, size_t n); /* Returns random bytes suitable for most uses, but may be insecure sometimes. */
|
||||
int crypto_random_bytes(void *p, size_t n); /* Returns secure random bytes after waiting for the RNG to initialize. */
|
||||
|
||||
static inline uint64_t random_u64(void) {
|
||||
uint64_t u;
|
||||
|
|
|
@ -127,9 +127,12 @@ int _set_ensure_consume(Set **s, const struct hash_ops *hash_ops, void *key HAS
|
|||
|
||||
int set_consume(Set *s, void *value);
|
||||
|
||||
int _set_put_strdup_full(Set **s, const struct hash_ops *hash_ops, const char *p HASHMAP_DEBUG_PARAMS);
|
||||
#define set_put_strdup_full(s, hash_ops, p) _set_put_strdup_full(s, hash_ops, p HASHMAP_DEBUG_SRC_ARGS)
|
||||
#define set_put_strdup(s, p) set_put_strdup_full(s, &string_hash_ops_free, p)
|
||||
int _set_put_strndup_full(Set **s, const struct hash_ops *hash_ops, const char *p, size_t n HASHMAP_DEBUG_PARAMS);
|
||||
#define set_put_strndup_full(s, hash_ops, p, n) _set_put_strndup_full(s, hash_ops, p, n HASHMAP_DEBUG_SRC_ARGS)
|
||||
#define set_put_strdup_full(s, hash_ops, p) set_put_strndup_full(s, hash_ops, p, SIZE_MAX)
|
||||
#define set_put_strndup(s, p, n) set_put_strndup_full(s, &string_hash_ops_free, p, n)
|
||||
#define set_put_strdup(s, p) set_put_strndup(s, p, SIZE_MAX)
|
||||
|
||||
int _set_put_strdupv_full(Set **s, const struct hash_ops *hash_ops, char **l HASHMAP_DEBUG_PARAMS);
|
||||
#define set_put_strdupv_full(s, hash_ops, l) _set_put_strdupv_full(s, hash_ops, l HASHMAP_DEBUG_SRC_ARGS)
|
||||
#define set_put_strdupv(s, l) set_put_strdupv_full(s, &string_hash_ops_free, l)
|
||||
|
@ -153,3 +156,5 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(Set*, set_free_free);
|
|||
int set_strjoin(Set *s, const char *separator, bool wrap_with_separator, char **ret);
|
||||
|
||||
bool set_equal(Set *a, Set *b);
|
||||
|
||||
bool set_fnmatch(Set *include_patterns, Set *exclude_patterns, const char *needle);
|
||||
|
|
|
@ -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,
|
||||
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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));
|
||||
/* 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))
|
||||
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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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); \
|
||||
|
|
|
@ -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 */
|
||||
return NULL; /* Not even enough space for the POSIX minimum (of 6)? In that
|
||||
* case, complain that it doesn't fit. */
|
||||
|
||||
/* So the time zone doesn't fit in fully, but the caller passed enough space for the POSIX
|
||||
* minimum time zone length. In this case suppress the timezone entirely, in order not to dump
|
||||
* an overly long, hard to read string on the user. This should be safe, because the user will
|
||||
* assume the local timezone anyway if none is shown. And so does parse_timestamp(). */
|
||||
/* So the time zone doesn't fit in fully, but the caller passed enough space for the
|
||||
* POSIX minimum time zone length. In this case suppress the timezone entirely, in
|
||||
* order not to dump an overly long, hard to read string on the user. This should be
|
||||
* safe, because the user will assume the local timezone anyway if none is shown. And
|
||||
* so does parse_timestamp(). */
|
||||
} else {
|
||||
buf[n++] = ' ';
|
||||
strcpy(buf + n, tm.tm_zone);
|
||||
|
@ -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;
|
||||
|
||||
|
|
|
@ -6,33 +6,47 @@
|
|||
#endif
|
||||
|
||||
#include <limits.h>
|
||||
#include "types-fundamental.h"
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define _align_(x) __attribute__((__aligned__(x)))
|
||||
#define _const_ __attribute__((__const__))
|
||||
#define _pure_ __attribute__((__pure__))
|
||||
#define _section_(x) __attribute__((__section__(x)))
|
||||
#define _packed_ __attribute__((__packed__))
|
||||
#define _retain_ __attribute__((__retain__))
|
||||
#define _used_ __attribute__((__used__))
|
||||
#define _unused_ __attribute__((__unused__))
|
||||
#define _alignas_(x) __attribute__((__aligned__(__alignof__(x))))
|
||||
#define _alignptr_ __attribute__((__aligned__(sizeof(void *))))
|
||||
#define _cleanup_(x) __attribute__((__cleanup__(x)))
|
||||
#define _const_ __attribute__((__const__))
|
||||
#define _deprecated_ __attribute__((__deprecated__))
|
||||
#define _destructor_ __attribute__((__destructor__))
|
||||
#define _hidden_ __attribute__((__visibility__("hidden")))
|
||||
#define _likely_(x) (__builtin_expect(!!(x), 1))
|
||||
#define _malloc_ __attribute__((__malloc__))
|
||||
#define _noreturn_ _Noreturn
|
||||
#define _packed_ __attribute__((__packed__))
|
||||
#define _printf_(a, b) __attribute__((__format__(printf, a, b)))
|
||||
#define _public_ __attribute__((__visibility__("default")))
|
||||
#define _pure_ __attribute__((__pure__))
|
||||
#define _retain_ __attribute__((__retain__))
|
||||
#define _returns_nonnull_ __attribute__((__returns_nonnull__))
|
||||
#define _section_(x) __attribute__((__section__(x)))
|
||||
#define _sentinel_ __attribute__((__sentinel__))
|
||||
#define _unlikely_(x) (__builtin_expect(!!(x), 0))
|
||||
#if __GNUC__ >= 7
|
||||
#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 _alloc_(...) __attribute__((__alloc_size__(__VA_ARGS__)))
|
||||
#endif
|
||||
|
||||
#if __GNUC__ >= 7 || (defined(__clang__) && __clang_major__ >= 10)
|
||||
# define _fallthrough_ __attribute__((__fallthrough__))
|
||||
#else
|
||||
# define _fallthrough_
|
||||
#endif
|
||||
/* Define C11 noreturn without <stdnoreturn.h> and even on older gcc
|
||||
* compiler versions */
|
||||
#ifndef _noreturn_
|
||||
#if __STDC_VERSION__ >= 201112L
|
||||
#define _noreturn_ _Noreturn
|
||||
#else
|
||||
#define _noreturn_ __attribute__((__noreturn__))
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define XSTRINGIFY(x) #x
|
||||
#define STRINGIFY(x) XSTRINGIFY(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__
|
||||
|
@ -103,8 +108,8 @@
|
|||
#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); \
|
||||
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( \
|
||||
|
|
293
src/libnm-systemd-shared/src/fundamental/sha256.c
Normal file
293
src/libnm-systemd-shared/src/fundamental/sha256.c
Normal file
|
@ -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;
|
||||
}
|
29
src/libnm-systemd-shared/src/fundamental/sha256.h
Normal file
29
src/libnm-systemd-shared/src/fundamental/sha256.h
Normal file
|
@ -0,0 +1,29 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#include "stdint.h"
|
||||
|
||||
#define SHA256_DIGEST_SIZE 32
|
||||
|
||||
struct sha256_ctx {
|
||||
uint32_t H[8];
|
||||
|
||||
union {
|
||||
uint64_t total64;
|
||||
#define TOTAL64_low (1 - (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__))
|
||||
#define TOTAL64_high (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
|
||||
uint32_t total[2];
|
||||
};
|
||||
|
||||
uint32_t buflen;
|
||||
|
||||
union {
|
||||
uint8_t buffer[128]; /* NB: always correctly aligned for UINT32. */
|
||||
uint32_t buffer32[32];
|
||||
uint64_t buffer64[16];
|
||||
};
|
||||
};
|
||||
|
||||
void sha256_init_ctx(struct sha256_ctx *ctx);
|
||||
void *sha256_finish_ctx(struct sha256_ctx *ctx, void *resbuf);
|
||||
void sha256_process_bytes(const void *buffer, size_t len, struct sha256_ctx *ctx);
|
|
@ -4,9 +4,9 @@
|
|||
|
||||
#ifndef SD_BOOT
|
||||
# include <ctype.h>
|
||||
|
||||
#include "macro.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 bool is_valid_version_char(sd_char a) {
|
||||
return ascii_isdigit(a) || ascii_isalpha(a) || IN_SET(a, '~', '-', '^', '.');
|
||||
}
|
||||
|
||||
static sd_bool is_valid_version_char(sd_char a) {
|
||||
return isdigit(a) || is_alpha(a) || IN_SET(a, '~', '-', '^', '.');
|
||||
}
|
||||
|
||||
sd_int strverscmp_improved(const sd_char *a, const sd_char *b) {
|
||||
|
||||
/* This is based on RPM's rpmvercmp(). But this explicitly handles '-' and '.', as we usually
|
||||
* want to directly compare strings which contain both version and release; e.g.
|
||||
* '247.2-3.1.fc33.x86_64' or '5.11.0-0.rc5.20210128git76c057c84d28.137.fc34'.
|
||||
* Unlike rpmvercmp(), this distiguishes e.g. 123a and 123.a, and 123a is newer.
|
||||
int strverscmp_improved(const sd_char *a, const sd_char *b) {
|
||||
/* This function is similar to strverscmp(3), but it treats '-' and '.' as separators.
|
||||
*
|
||||
* This splits the input strings into segments. Each segment is numeric or alpha, and may be
|
||||
* The logic is based on rpm's rpmvercmp(), but unlike rpmvercmp(), it distiguishes e.g.
|
||||
* '123a' and '123.a', with '123a' being newer.
|
||||
*
|
||||
* It allows direct comparison of strings which contain both a version and a release; e.g.
|
||||
* '247.2-3.1.fc33.x86_64' or '5.11.0-0.rc5.20210128git76c057c84d28.137.fc34'.
|
||||
*
|
||||
* The input string is split into segments. Each segment is numeric or alphabetic, and may be
|
||||
* prefixed with the following:
|
||||
* '~' : used for pre-releases, a segment prefixed with this is the oldest,
|
||||
* '-' : used for the separator between version and release,
|
||||
* '^' : used for patched releases, a segment with this is newer than one with '-'.
|
||||
* '.' : used for point releases.
|
||||
* Note, no prefix segment is the newest. All non-supported characters are dropped, and
|
||||
* handled as a separator of segments, e.g., 123_a is equivalent to 123a.
|
||||
* Note that no prefix segment is the newest. All non-supported characters are dropped, and
|
||||
* handled as a separator of segments, e.g., '123_a' is equivalent to '123a'.
|
||||
*
|
||||
* By using this, version strings can be sorted like following:
|
||||
* (older) 122.1
|
||||
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#ifdef SD_BOOT
|
||||
# include <efi.h>
|
||||
# include <efilib.h>
|
||||
# include "efi-string.h"
|
||||
#else
|
||||
# include <string.h>
|
||||
#endif
|
||||
|
@ -11,45 +12,52 @@
|
|||
#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 strlen strlen16
|
||||
# define strcmp strcmp16
|
||||
# define strncmp strncmp16
|
||||
# define strcasecmp strcasecmp16
|
||||
# define strncasecmp strncasecmp16
|
||||
# define STR_C(str) (L ## str)
|
||||
#define memcmp(a, b, n) CompareMem(a, b, n)
|
||||
typedef char16_t sd_char;
|
||||
#else
|
||||
# define STR_C(str) (str)
|
||||
typedef char sd_char;
|
||||
#endif
|
||||
|
||||
#define streq(a,b) (strcmp((a),(b)) == 0)
|
||||
#define strneq(a, b, n) (strncmp((a), (b), (n)) == 0)
|
||||
#define strcaseeq(a,b) (strcasecmp((a),(b)) == 0)
|
||||
#ifndef SD_BOOT
|
||||
#define strncaseeq(a, b, n) (strncasecmp((a), (b), (n)) == 0)
|
||||
#endif
|
||||
|
||||
static inline sd_int strcmp_ptr(const sd_char *a, const sd_char *b) {
|
||||
static inline int strcmp_ptr(const sd_char *a, const sd_char *b) {
|
||||
if (a && b)
|
||||
return strcmp(a, b);
|
||||
|
||||
return CMP(a, b);
|
||||
}
|
||||
|
||||
static inline sd_int strcasecmp_ptr(const sd_char *a, const sd_char *b) {
|
||||
static inline int strcasecmp_ptr(const sd_char *a, const sd_char *b) {
|
||||
if (a && b)
|
||||
return strcasecmp(a, b);
|
||||
|
||||
return CMP(a, b);
|
||||
}
|
||||
|
||||
static inline sd_bool streq_ptr(const sd_char *a, const sd_char *b) {
|
||||
static inline bool streq_ptr(const sd_char *a, const sd_char *b) {
|
||||
return strcmp_ptr(a, b) == 0;
|
||||
}
|
||||
|
||||
static inline sd_bool strcaseeq_ptr(const sd_char *a, const sd_char *b) {
|
||||
static inline bool strcaseeq_ptr(const sd_char *a, const sd_char *b) {
|
||||
return strcasecmp_ptr(a, b) == 0;
|
||||
}
|
||||
|
||||
static inline size_t strlen_ptr(const sd_char *s) {
|
||||
if (!s)
|
||||
return 0;
|
||||
|
||||
return strlen(s);
|
||||
}
|
||||
|
||||
sd_char *startswith(const sd_char *s, const sd_char *prefix) _pure_;
|
||||
#ifndef SD_BOOT
|
||||
sd_char *startswith_no_case(const sd_char *s, const sd_char *prefix) _pure_;
|
||||
|
@ -57,15 +65,23 @@ sd_char *startswith_no_case(const sd_char *s, const sd_char *prefix) _pure_;
|
|||
sd_char *endswith(const sd_char *s, const sd_char *postfix) _pure_;
|
||||
sd_char *endswith_no_case(const sd_char *s, const sd_char *postfix) _pure_;
|
||||
|
||||
static inline sd_bool isempty(const sd_char *a) {
|
||||
static inline bool isempty(const sd_char *a) {
|
||||
return !a || a[0] == '\0';
|
||||
}
|
||||
|
||||
static inline const sd_char *yes_no(sd_bool b) {
|
||||
static inline const sd_char *strempty(const sd_char *s) {
|
||||
return s ?: STR_C("");
|
||||
}
|
||||
|
||||
static inline const sd_char *yes_no(bool b) {
|
||||
return b ? STR_C("yes") : STR_C("no");
|
||||
}
|
||||
|
||||
sd_int strverscmp_improved(const sd_char *a, const sd_char *b);
|
||||
static inline const sd_char* comparison_operator(int result) {
|
||||
return result < 0 ? STR_C("<") : result > 0 ? STR_C(">") : STR_C("==");
|
||||
}
|
||||
|
||||
int strverscmp_improved(const sd_char *a, const sd_char *b);
|
||||
|
||||
/* Like startswith(), but operates on arbitrary memory blocks */
|
||||
static inline void *memory_startswith(const void *p, size_t sz, const sd_char *token) {
|
||||
|
@ -82,3 +98,19 @@ static inline void *memory_startswith(const void *p, size_t sz, const sd_char *t
|
|||
|
||||
return (uint8_t*) p + n;
|
||||
}
|
||||
|
||||
#define _STRV_FOREACH(s, l, i) \
|
||||
for (typeof(*(l)) *s, *i = (l); (s = i) && *i; i++)
|
||||
|
||||
#define STRV_FOREACH(s, l) \
|
||||
_STRV_FOREACH(s, l, UNIQ_T(i, UNIQ))
|
||||
|
||||
static inline bool ascii_isdigit(sd_char a) {
|
||||
/* A pure ASCII, locale independent version of isdigit() */
|
||||
return a >= '0' && a <= '9';
|
||||
}
|
||||
|
||||
static inline bool ascii_isalpha(sd_char a) {
|
||||
/* A pure ASCII, locale independent version of isalpha() */
|
||||
return (a >= 'a' && a <= 'z') || (a >= 'A' && a <= 'Z');
|
||||
}
|
||||
|
|
|
@ -1,39 +0,0 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
/* This defines a number of basic types that are one thing in userspace and another in the UEFI environment,
|
||||
* but mostly the same in concept and behaviour.
|
||||
*
|
||||
* Note: if the definition of these types/values has slightly different semantics in userspace and in the
|
||||
* UEFI environment then please prefix its name with "sd_" to make clear these types have special semantics,
|
||||
* and *we* defined them. Otherwise, if the types are effectively 100% identical in behaviour in userspace
|
||||
* and UEFI environment you can omit the prefix. (Examples: sd_char is 8 bit in userspace and 16 bit in UEFI
|
||||
* space hence it should have the sd_ prefix; but size_t in userspace and UINTN in UEFI environment are 100%
|
||||
* defined the same way ultimately, hence it's OK to just define size_t as alias to UINTN in UEFI
|
||||
* environment, so that size_t can be used everywhere, without any "sd_" prefix.)
|
||||
*
|
||||
* Note: we generally prefer the userspace names of types and concepts. i.e. if in doubt please name types
|
||||
* after the userspace vocabulary, and let's keep UEFI vocabulary specific to the UEFI build environment. */
|
||||
|
||||
#ifdef SD_BOOT
|
||||
#include <efi.h>
|
||||
|
||||
typedef BOOLEAN sd_bool;
|
||||
typedef CHAR16 sd_char;
|
||||
typedef INTN sd_int;
|
||||
typedef UINTN size_t;
|
||||
|
||||
#define sd_true TRUE
|
||||
#define sd_false FALSE
|
||||
#else
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef bool sd_bool;
|
||||
typedef char sd_char;
|
||||
typedef int sd_int;
|
||||
|
||||
#define sd_true true
|
||||
#define sd_false false
|
||||
|
||||
#endif
|
|
@ -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
|
||||
n += r + !first;
|
||||
first = false;
|
||||
|
||||
n += r;
|
||||
}
|
||||
|
||||
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,18 +1063,31 @@ 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)) {
|
||||
switch (x) {
|
||||
case 2:
|
||||
if (!srv_type_label_is_valid(a, an))
|
||||
break;
|
||||
|
||||
if (x >= 3 && srv_type_label_is_valid(c, cn)) {
|
||||
/* OK, got <type> . <type2> . <domain> */
|
||||
|
||||
name = NULL;
|
||||
|
||||
type = strjoin(a, ".", b);
|
||||
if (!type)
|
||||
return -ENOMEM;
|
||||
|
||||
d = q;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
if (!dns_service_name_label_is_valid(a, an))
|
||||
break;
|
||||
|
||||
if (dns_service_name_label_is_valid(a, an)) {
|
||||
/* OK, got <name> . <type> . <type2> . <domain> */
|
||||
|
||||
name = strndup(a, an);
|
||||
|
@ -1089,41 +1099,22 @@ int dns_service_split(const char *joined, char **_name, char **_type, char **_do
|
|||
return -ENOMEM;
|
||||
|
||||
d = p;
|
||||
goto finish;
|
||||
break;
|
||||
}
|
||||
|
||||
} else if (srv_type_label_is_valid(a, an)) {
|
||||
|
||||
/* OK, got <type> . <type2> . <domain> */
|
||||
|
||||
name = NULL;
|
||||
|
||||
type = strjoin(a, ".", b);
|
||||
if (!type)
|
||||
return -ENOMEM;
|
||||
|
||||
d = q;
|
||||
goto finish;
|
||||
}
|
||||
}
|
||||
|
||||
name = NULL;
|
||||
type = NULL;
|
||||
d = joined;
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue