systemd: merge branch systemd into main

https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/1291
This commit is contained in:
Thomas Haller 2022-07-05 17:31:20 +02:00
commit 556bff1767
No known key found for this signature in database
GPG Key ID: 29C2366E4DFC5728
70 changed files with 1890 additions and 1136 deletions

View File

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

View File

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

View File

@ -64,7 +64,7 @@ struct sd_dhcp6_client {
struct duid duid;
size_t duid_len;
be16_t *req_opts;
size_t req_opts_len;
size_t n_req_opts;
char *fqdn;
char *mudurl;
char **user_class;

View File

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

View File

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

View File

@ -29,16 +29,10 @@
#include "io-util.h"
#include "random-util.h"
#include "socket-util.h"
#include "sort-util.h"
#include "strv.h"
#include "web-util.h"
static const uint16_t default_req_opts[] = {
SD_DHCP6_OPTION_DNS_SERVERS,
SD_DHCP6_OPTION_DOMAIN_LIST,
SD_DHCP6_OPTION_NTP_SERVER,
SD_DHCP6_OPTION_SNTP_SERVERS,
};
#define DHCP6_CLIENT_DONT_DESTROY(client) \
_cleanup_(sd_dhcp6_client_unrefp) _unused_ sd_dhcp6_client *_dont_destroy_##client = sd_dhcp6_client_ref(client)
@ -381,8 +375,12 @@ int sd_dhcp6_client_get_information_request(sd_dhcp6_client *client, int *enable
return 0;
}
static int be16_compare_func(const be16_t *a, const be16_t *b) {
return CMP(be16toh(*a), be16toh(*b));
}
int sd_dhcp6_client_set_request_option(sd_dhcp6_client *client, uint16_t option) {
size_t t;
be16_t opt;
assert_return(client, -EINVAL);
assert_return(!sd_dhcp6_client_is_running(client), -EBUSY);
@ -390,15 +388,17 @@ int sd_dhcp6_client_set_request_option(sd_dhcp6_client *client, uint16_t option)
if (!dhcp6_option_can_request(option))
return -EINVAL;
for (t = 0; t < client->req_opts_len; t++)
if (client->req_opts[t] == htobe16(option))
return -EEXIST;
opt = htobe16(option);
if (typesafe_bsearch(&opt, client->req_opts, client->n_req_opts, be16_compare_func))
return -EEXIST;
if (!GREEDY_REALLOC(client->req_opts, client->req_opts_len + 1))
if (!GREEDY_REALLOC(client->req_opts, client->n_req_opts + 1))
return -ENOMEM;
client->req_opts[client->req_opts_len++] = htobe16(option);
client->req_opts[client->n_req_opts++] = opt;
/* Sort immediately to make the above binary search will work for the next time. */
typesafe_qsort(client->req_opts, client->n_req_opts, be16_compare_func);
return 0;
}
@ -645,6 +645,51 @@ static DHCP6MessageType client_message_type_from_state(sd_dhcp6_client *client)
}
}
static int client_append_oro(sd_dhcp6_client *client, uint8_t **opt, size_t *optlen) {
_cleanup_free_ be16_t *buf = NULL;
be16_t *req_opts;
size_t n;
assert(client);
assert(opt);
assert(optlen);
switch (client->state) {
case DHCP6_STATE_INFORMATION_REQUEST:
n = client->n_req_opts;
buf = new(be16_t, n + 2);
if (!buf)
return -ENOMEM;
memcpy_safe(buf, client->req_opts, n * sizeof(be16_t));
buf[n++] = htobe16(SD_DHCP6_OPTION_INFORMATION_REFRESH_TIME); /* RFC 8415 section 21.23 */
buf[n++] = htobe16(SD_DHCP6_OPTION_INF_MAX_RT); /* RFC 8415 section 21.25 */
typesafe_qsort(buf, n, be16_compare_func);
req_opts = buf;
break;
case DHCP6_STATE_SOLICITATION:
n = client->n_req_opts;
buf = new(be16_t, n + 1);
if (!buf)
return -ENOMEM;
memcpy_safe(buf, client->req_opts, n * sizeof(be16_t));
buf[n++] = htobe16(SD_DHCP6_OPTION_SOL_MAX_RT); /* RFC 8415 section 21.24 */
typesafe_qsort(buf, n, be16_compare_func);
req_opts = buf;
break;
default:
n = client->n_req_opts;
req_opts = client->req_opts;
}
return dhcp6_option_append(opt, optlen, SD_DHCP6_OPTION_ORO, n * sizeof(be16_t), req_opts);
}
int dhcp6_client_send_message(sd_dhcp6_client *client) {
_cleanup_free_ DHCP6Message *message = NULL;
struct in6_addr all_servers =
@ -722,9 +767,7 @@ int dhcp6_client_send_message(sd_dhcp6_client *client) {
return r;
}
r = dhcp6_option_append(&opt, &optlen, SD_DHCP6_OPTION_ORO,
client->req_opts_len * sizeof(be16_t),
client->req_opts);
r = client_append_oro(client, &opt, &optlen);
if (r < 0)
return r;
@ -1311,13 +1354,10 @@ int sd_dhcp6_client_start(sd_dhcp6_client *client) {
if (client->fd < 0) {
r = dhcp6_network_bind_udp_socket(client->ifindex, &client->local_address);
if (r < 0) {
_cleanup_free_ char *p = NULL;
(void) in6_addr_to_string(&client->local_address, &p);
if (r < 0)
return log_dhcp6_client_errno(client, r,
"Failed to bind to UDP socket at address %s: %m", strna(p));
}
"Failed to bind to UDP socket at address %s: %m",
IN6_ADDR_TO_STRING(&client->local_address));
client->fd = r;
}
@ -1351,7 +1391,7 @@ int sd_dhcp6_client_start(sd_dhcp6_client *client) {
}
log_dhcp6_client(client, "Starting in %s mode",
client->information_request ? "Information request" : "Managed");
client->information_request ? "Information request" : "Solicit");
return client_start_transaction(client, state);
}
@ -1423,18 +1463,9 @@ DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_dhcp6_client, sd_dhcp6_client, dhcp6_client_fre
int sd_dhcp6_client_new(sd_dhcp6_client **ret) {
_cleanup_(sd_dhcp6_client_unrefp) sd_dhcp6_client *client = NULL;
_cleanup_free_ be16_t *req_opts = NULL;
size_t t;
assert_return(ret, -EINVAL);
req_opts = new(be16_t, ELEMENTSOF(default_req_opts));
if (!req_opts)
return -ENOMEM;
for (t = 0; t < ELEMENTSOF(default_req_opts); t++)
req_opts[t] = htobe16(default_req_opts[t]);
client = new(sd_dhcp6_client, 1);
if (!client)
return -ENOMEM;
@ -1446,8 +1477,6 @@ int sd_dhcp6_client_new(sd_dhcp6_client **ret) {
.ifindex = -1,
.request_ia = DHCP6_REQUEST_IA_NA | DHCP6_REQUEST_IA_PD,
.fd = -1,
.req_opts_len = ELEMENTSOF(default_req_opts),
.req_opts = TAKE_PTR(req_opts),
};
*ret = TAKE_PTR(client);

View File

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

View File

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

View File

@ -27,7 +27,8 @@ int event_reset_time_relative(
int64_t priority,
const char *description,
bool force_reset);
int event_source_disable(sd_event_source *s);
int event_source_is_enabled(sd_event_source *s);
static inline int event_source_disable(sd_event_source *s) {
return sd_event_source_set_enabled(s, SD_EVENT_OFF);
}
int event_add_time_change(sd_event *e, sd_event_source **ret, sd_event_io_handler_t callback, void *userdata);

View File

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

View File

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

View File

@ -34,5 +34,3 @@ extern const struct hash_ops id128_hash_ops;
sd_id128_t id128_make_v4_uuid(sd_id128_t id);
int id128_get_product(sd_id128_t *ret);
int id128_equal_string(const char *s, sd_id128_t id);

View File

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

View File

@ -14,7 +14,7 @@
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
along with systemd; If not, see <https://www.gnu.org/licenses/>.
***/
/* This is a private header; never even think of including this directly! */

View File

@ -16,7 +16,7 @@
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
along with systemd; If not, see <https://www.gnu.org/licenses/>.
***/
#include <inttypes.h>
@ -36,7 +36,7 @@ enum {
SD_DHCP6_CLIENT_EVENT_RESEND_EXPIRE = 10,
SD_DHCP6_CLIENT_EVENT_RETRANS_MAX = 11,
SD_DHCP6_CLIENT_EVENT_IP_ACQUIRE = 12,
SD_DHCP6_CLIENT_EVENT_INFORMATION_REQUEST = 13,
SD_DHCP6_CLIENT_EVENT_INFORMATION_REQUEST = 13
};
/* https://www.iana.org/assignments/dhcpv6-parameters/dhcpv6-parameters.xhtml#dhcpv6-parameters-2 */
@ -63,15 +63,15 @@ enum {
SD_DHCP6_OPTION_RECONF_ACCEPT = 20, /* RFC 8415 */
SD_DHCP6_OPTION_SIP_SERVER_DOMAIN_NAME = 21, /* RFC 3319 */
SD_DHCP6_OPTION_SIP_SERVER_ADDRESS = 22, /* RFC 3319 */
SD_DHCP6_OPTION_DNS_SERVERS = 23, /* RFC 3646 */
SD_DHCP6_OPTION_DOMAIN_LIST = 24, /* RFC 3646 */
SD_DHCP6_OPTION_DNS_SERVER = 23, /* RFC 3646 */
SD_DHCP6_OPTION_DOMAIN = 24, /* RFC 3646 */
SD_DHCP6_OPTION_IA_PD = 25, /* RFC 3633, RFC 8415 */
SD_DHCP6_OPTION_IA_PD_PREFIX = 26, /* RFC 3633, RFC 8415 */
SD_DHCP6_OPTION_NIS_SERVERS = 27, /* RFC 3898 */
SD_DHCP6_OPTION_NISP_SERVERS = 28, /* RFC 3898 */
SD_DHCP6_OPTION_NIS_SERVER = 27, /* RFC 3898 */
SD_DHCP6_OPTION_NISP_SERVER = 28, /* RFC 3898 */
SD_DHCP6_OPTION_NIS_DOMAIN_NAME = 29, /* RFC 3898 */
SD_DHCP6_OPTION_NISP_DOMAIN_NAME = 30, /* RFC 3898 */
SD_DHCP6_OPTION_SNTP_SERVERS = 31, /* RFC 4075, deprecated */
SD_DHCP6_OPTION_SNTP_SERVER = 31, /* RFC 4075, deprecated */
SD_DHCP6_OPTION_INFORMATION_REFRESH_TIME = 32, /* RFC 4242, 8415, sec. 21.23 */
SD_DHCP6_OPTION_BCMCS_SERVER_D = 33, /* RFC 4280 */
SD_DHCP6_OPTION_BCMCS_SERVER_A = 34, /* RFC 4280 */
@ -183,7 +183,7 @@ enum {
SD_DHCP6_OPTION_SLAP_QUAD = 140, /* RFC 8948 */
SD_DHCP6_OPTION_V6_DOTS_RI = 141, /* RFC 8973 */
SD_DHCP6_OPTION_V6_DOTS_ADDRESS = 142, /* RFC 8973 */
SD_DHCP6_OPTION_IPV6_ADDRESS_ANDSF = 143, /* RFC 6153 */
SD_DHCP6_OPTION_IPV6_ADDRESS_ANDSF = 143 /* RFC 6153 */
/* option codes 144-65535 are unassigned */
};

View File

@ -16,7 +16,7 @@
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
along with systemd; If not, see <https://www.gnu.org/licenses/>.
***/
#include <inttypes.h>

View File

@ -14,7 +14,7 @@
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
along with systemd; If not, see <https://www.gnu.org/licenses/>.
***/
#include <inttypes.h>

View File

@ -14,7 +14,7 @@
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
along with systemd; If not, see <https://www.gnu.org/licenses/>.
***/
#include <inttypes.h>

View File

@ -14,7 +14,7 @@
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
along with systemd; If not, see <https://www.gnu.org/licenses/>.
***/
#include <inttypes.h>
@ -116,9 +116,11 @@ int sd_id128_get_boot_app_specific(sd_id128_t app_id, sd_id128_t *ret);
#a #b #c #d "-" #e #f "-" #g #h "-" #i #j "-" #k #l #m #n #o #p
_sd_pure_ static __inline__ int sd_id128_equal(sd_id128_t a, sd_id128_t b) {
return memcmp(&a, &b, 16) == 0;
return a.qwords[0] == b.qwords[0] && a.qwords[1] == b.qwords[1];
}
int sd_id128_string_equal(const char *s, sd_id128_t id);
_sd_pure_ static __inline__ int sd_id128_is_null(sd_id128_t a) {
return a.qwords[0] == 0 && a.qwords[1] == 0;
}

View File

@ -14,7 +14,7 @@
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
along with systemd; If not, see <https://www.gnu.org/licenses/>.
***/
#include <errno.h>
@ -32,14 +32,14 @@ _SD_BEGIN_DECLARATIONS;
typedef struct sd_lldp_rx sd_lldp_rx;
typedef struct sd_lldp_neighbor sd_lldp_neighbor;
typedef enum sd_lldp_rx_event_t {
__extension__ typedef enum sd_lldp_rx_event_t {
SD_LLDP_RX_EVENT_ADDED,
SD_LLDP_RX_EVENT_REMOVED,
SD_LLDP_RX_EVENT_UPDATED,
SD_LLDP_RX_EVENT_REFRESHED,
_SD_LLDP_RX_EVENT_MAX,
_SD_LLDP_RX_EVENT_INVALID = -EINVAL,
_SD_ENUM_FORCE_S64(LLDP_RX_EVENT),
_SD_ENUM_FORCE_S64(LLDP_RX_EVENT)
} sd_lldp_rx_event_t;
typedef void (*sd_lldp_rx_callback_t)(sd_lldp_rx *lldp_rx, sd_lldp_rx_event_t event, sd_lldp_neighbor *n, void *userdata);

View File

@ -14,7 +14,7 @@
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
along with systemd; If not, see <https://www.gnu.org/licenses/>.
***/
#include <inttypes.h>
@ -34,7 +34,7 @@ enum {
SD_LLDP_TYPE_SYSTEM_DESCRIPTION = 6,
SD_LLDP_TYPE_SYSTEM_CAPABILITIES = 7,
SD_LLDP_TYPE_MGMT_ADDRESS = 8,
SD_LLDP_TYPE_PRIVATE = 127,
SD_LLDP_TYPE_PRIVATE = 127
};
/* IEEE 802.1AB-2009 Clause 8.5.2: Chassis subtypes */
@ -46,7 +46,7 @@ enum {
SD_LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS = 4,
SD_LLDP_CHASSIS_SUBTYPE_NETWORK_ADDRESS = 5,
SD_LLDP_CHASSIS_SUBTYPE_INTERFACE_NAME = 6,
SD_LLDP_CHASSIS_SUBTYPE_LOCALLY_ASSIGNED = 7,
SD_LLDP_CHASSIS_SUBTYPE_LOCALLY_ASSIGNED = 7
};
/* IEEE 802.1AB-2009 Clause 8.5.3: Port subtype */
@ -58,7 +58,7 @@ enum {
SD_LLDP_PORT_SUBTYPE_NETWORK_ADDRESS = 4,
SD_LLDP_PORT_SUBTYPE_INTERFACE_NAME = 5,
SD_LLDP_PORT_SUBTYPE_AGENT_CIRCUIT_ID = 6,
SD_LLDP_PORT_SUBTYPE_LOCALLY_ASSIGNED = 7,
SD_LLDP_PORT_SUBTYPE_LOCALLY_ASSIGNED = 7
};
/* IEEE 802.1AB-2009 Clause 8.5.8: System capabilities */
@ -73,7 +73,7 @@ enum {
SD_LLDP_SYSTEM_CAPABILITIES_STATION = 1 << 7,
SD_LLDP_SYSTEM_CAPABILITIES_CVLAN = 1 << 8,
SD_LLDP_SYSTEM_CAPABILITIES_SVLAN = 1 << 9,
SD_LLDP_SYSTEM_CAPABILITIES_TPMR = 1 << 10,
SD_LLDP_SYSTEM_CAPABILITIES_TPMR = 1 << 10
};
#define SD_LLDP_SYSTEM_CAPABILITIES_ALL UINT16_MAX
@ -107,7 +107,7 @@ enum {
SD_LLDP_OUI_802_1_SUBTYPE_PROTOCOL_IDENTITY = 4,
SD_LLDP_OUI_802_1_SUBTYPE_VID_USAGE_DIGEST = 5,
SD_LLDP_OUI_802_1_SUBTYPE_MANAGEMENT_VID = 6,
SD_LLDP_OUI_802_1_SUBTYPE_LINK_AGGREGATION = 7,
SD_LLDP_OUI_802_1_SUBTYPE_LINK_AGGREGATION = 7
};
/* IEEE 802.1AB-2009 Annex F */
@ -115,7 +115,7 @@ enum {
SD_LLDP_OUI_802_3_SUBTYPE_MAC_PHY_CONFIG_STATUS = 1,
SD_LLDP_OUI_802_3_SUBTYPE_POWER_VIA_MDI = 2,
SD_LLDP_OUI_802_3_SUBTYPE_LINK_AGGREGATION = 3,
SD_LLDP_OUI_802_3_SUBTYPE_MAXIMUM_FRAME_SIZE = 4,
SD_LLDP_OUI_802_3_SUBTYPE_MAXIMUM_FRAME_SIZE = 4
};
_SD_END_DECLARATIONS;

View File

@ -16,7 +16,7 @@
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
along with systemd; If not, see <https://www.gnu.org/licenses/>.
***/
#include <errno.h>
@ -42,25 +42,25 @@ enum {
SD_NDISC_OPTION_RDNSS = 25,
SD_NDISC_OPTION_FLAGS_EXTENSION = 26,
SD_NDISC_OPTION_DNSSL = 31,
SD_NDISC_OPTION_CAPTIVE_PORTAL = 37,
SD_NDISC_OPTION_CAPTIVE_PORTAL = 37
};
/* Route preference, RFC 4191, Section 2.1 */
enum {
SD_NDISC_PREFERENCE_LOW = 3U,
SD_NDISC_PREFERENCE_MEDIUM = 0U,
SD_NDISC_PREFERENCE_HIGH = 1U,
SD_NDISC_PREFERENCE_HIGH = 1U
};
typedef struct sd_ndisc sd_ndisc;
typedef struct sd_ndisc_router sd_ndisc_router;
typedef enum sd_ndisc_event_t {
__extension__ typedef enum sd_ndisc_event_t {
SD_NDISC_EVENT_TIMEOUT,
SD_NDISC_EVENT_ROUTER,
_SD_NDISC_EVENT_MAX,
_SD_NDISC_EVENT_INVALID = -EINVAL,
_SD_ENUM_FORCE_S64(NDISC_EVENT),
_SD_ENUM_FORCE_S64(NDISC_EVENT)
} sd_ndisc_event_t;
typedef void (*sd_ndisc_callback_t)(sd_ndisc *nd, sd_ndisc_event_t event, sd_ndisc_router *rt, void *userdata);
@ -82,7 +82,6 @@ int sd_ndisc_set_ifname(sd_ndisc *nd, const char *interface_name);
int sd_ndisc_get_ifname(sd_ndisc *nd, const char **ret);
int sd_ndisc_set_mac(sd_ndisc *nd, const struct ether_addr *mac_addr);
int sd_ndisc_router_from_raw(sd_ndisc_router **ret, const void *raw, size_t raw_size);
sd_ndisc_router *sd_ndisc_router_ref(sd_ndisc_router *rt);
sd_ndisc_router *sd_ndisc_router_unref(sd_ndisc_router *rt);

View File

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

View File

@ -1,3 +0,0 @@
#pragma once
/* dummy header */

View File

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

View File

@ -55,8 +55,8 @@ typedef void* (*mfree_func_t)(void *p);
typeof(a)* _a = &(a); \
typeof(b)* _b = &(b); \
free(*_a); \
(*_a) = (*_b); \
(*_b) = NULL; \
*_a = *_b; \
*_b = NULL; \
0; \
})
@ -174,23 +174,13 @@ void* greedy_realloc0(void **p, size_t need, size_t size);
* is compatible with _FORTIFY_SOURCES. If _FORTIFY_SOURCES is used many memory operations will take the
* object size as returned by __builtin_object_size() into account. Hence, let's return the smaller size of
* malloc_usable_size() and __builtin_object_size() here, so that we definitely operate in safe territory by
* both the compiler's and libc's standards. Note that _FORTIFY_SOURCES=3 handles also dynamically allocated
* objects and thus it's safer using __builtin_dynamic_object_size if _FORTIFY_SOURCES=3 is used (#22801).
* Moreover, when NULL is passed malloc_usable_size() is documented to return zero, and
* both the compiler's and libc's standards. Note that __builtin_object_size() evaluates to SIZE_MAX if the
* size cannot be determined, hence the MIN() expression should be safe with dynamically sized memory,
* too. Moreover, when NULL is passed malloc_usable_size() is documented to return zero, and
* __builtin_object_size() returns SIZE_MAX too, hence we also return a sensible value of 0 in this corner
* case. */
#if defined __has_builtin
# if __has_builtin(__builtin_dynamic_object_size)
# define MALLOC_SIZEOF_SAFE(x) \
MIN(malloc_usable_size(x), __builtin_dynamic_object_size(x, 0))
# endif
#endif
#ifndef MALLOC_SIZEOF_SAFE
#define MALLOC_SIZEOF_SAFE(x) \
MIN(malloc_usable_size(x), __builtin_object_size(x, 0))
#endif
/* Inspired by ELEMENTSOF() but operates on malloc()'ed memory areas: typesafely returns the number of items
* that fit into the specified memory block */

View File

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

View File

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

View File

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

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

View File

@ -0,0 +1,60 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <errno.h>
#include <stdbool.h>
#include "macro.h"
typedef enum SpecialGlyph {
SPECIAL_GLYPH_TREE_VERTICAL,
SPECIAL_GLYPH_TREE_BRANCH,
SPECIAL_GLYPH_TREE_RIGHT,
SPECIAL_GLYPH_TREE_SPACE,
SPECIAL_GLYPH_TREE_TOP,
SPECIAL_GLYPH_VERTICAL_DOTTED,
SPECIAL_GLYPH_TRIANGULAR_BULLET,
SPECIAL_GLYPH_BLACK_CIRCLE,
SPECIAL_GLYPH_WHITE_CIRCLE,
SPECIAL_GLYPH_MULTIPLICATION_SIGN,
SPECIAL_GLYPH_CIRCLE_ARROW,
SPECIAL_GLYPH_BULLET,
SPECIAL_GLYPH_MU,
SPECIAL_GLYPH_CHECK_MARK,
SPECIAL_GLYPH_CROSS_MARK,
SPECIAL_GLYPH_ARROW_RIGHT,
SPECIAL_GLYPH_ARROW_UP,
SPECIAL_GLYPH_ARROW_DOWN,
SPECIAL_GLYPH_ELLIPSIS,
SPECIAL_GLYPH_LIGHT_SHADE,
SPECIAL_GLYPH_DARK_SHADE,
SPECIAL_GLYPH_SIGMA,
SPECIAL_GLYPH_EXTERNAL_LINK,
_SPECIAL_GLYPH_FIRST_EMOJI,
SPECIAL_GLYPH_ECSTATIC_SMILEY = _SPECIAL_GLYPH_FIRST_EMOJI,
SPECIAL_GLYPH_HAPPY_SMILEY,
SPECIAL_GLYPH_SLIGHTLY_HAPPY_SMILEY,
SPECIAL_GLYPH_NEUTRAL_SMILEY,
SPECIAL_GLYPH_SLIGHTLY_UNHAPPY_SMILEY,
SPECIAL_GLYPH_UNHAPPY_SMILEY,
SPECIAL_GLYPH_DEPRESSED_SMILEY,
SPECIAL_GLYPH_LOCK_AND_KEY,
SPECIAL_GLYPH_TOUCH,
SPECIAL_GLYPH_RECYCLING,
SPECIAL_GLYPH_DOWNLOAD,
SPECIAL_GLYPH_SPARKLES,
_SPECIAL_GLYPH_MAX,
_SPECIAL_GLYPH_INVALID = -EINVAL,
} SpecialGlyph;
const char *special_glyph(SpecialGlyph code) _const_;
bool emoji_enabled(void);
static inline const char *special_glyph_check_mark(bool b) {
return b ? special_glyph(SPECIAL_GLYPH_CHECK_MARK) : special_glyph(SPECIAL_GLYPH_CROSS_MARK);
}
static inline const char *special_glyph_check_mark_space(bool b) {
return b ? special_glyph(SPECIAL_GLYPH_CHECK_MARK) : " ";
}

View File

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

View File

@ -102,10 +102,9 @@ extern const struct hash_ops uint64_hash_ops;
* 64bit archs. Yuck! */
#if SIZEOF_DEV_T != 8
void devt_hash_func(const dev_t *p, struct siphash *state) _pure_;
int devt_compare_func(const dev_t *a, const dev_t *b) _pure_;
extern const struct hash_ops devt_hash_ops;
#else
#define devt_hash_func uint64_hash_func
#define devt_compare_func uint64_compare_func
#define devt_hash_ops uint64_hash_ops
#endif
int devt_compare_func(const dev_t *a, const dev_t *b) _pure_;
extern const struct hash_ops devt_hash_ops;

View File

@ -3,6 +3,7 @@
#include "nm-sd-adapt-shared.h"
#include <errno.h>
#include <fnmatch.h>
#include <pthread.h>
#include <stdint.h>
#include <stdlib.h>
@ -772,16 +773,15 @@ static void shared_hash_key_initialize(void) {
static struct HashmapBase* hashmap_base_new(const struct hash_ops *hash_ops, enum HashmapType type HASHMAP_DEBUG_PARAMS) {
HashmapBase *h;
const struct hashmap_type_info *hi = &hashmap_type_info[type];
bool up;
up = mempool_enabled();
bool use_pool = mempool_enabled && mempool_enabled();
h = up ? mempool_alloc0_tile(hi->mempool) : malloc0(hi->head_size);
h = use_pool ? mempool_alloc0_tile(hi->mempool) : malloc0(hi->head_size);
if (!h)
return NULL;
h->type = type;
h->from_pool = up;
h->from_pool = use_pool;
h->hash_ops = hash_ops ?: &trivial_hash_ops;
if (type == HASHMAP_TYPE_ORDERED) {
@ -1845,7 +1845,7 @@ int _hashmap_put_strdup_full(Hashmap **h, const struct hash_ops *hash_ops, const
}
#endif /* NM_IGNORED */
int _set_put_strdup_full(Set **s, const struct hash_ops *hash_ops, const char *p HASHMAP_DEBUG_PARAMS) {
int _set_put_strndup_full(Set **s, const struct hash_ops *hash_ops, const char *p, size_t n HASHMAP_DEBUG_PARAMS) {
char *c;
int r;
@ -1856,10 +1856,13 @@ int _set_put_strdup_full(Set **s, const struct hash_ops *hash_ops, const char *p
if (r < 0)
return r;
if (set_contains(*s, (char*) p))
return 0;
if (n == SIZE_MAX) {
if (set_contains(*s, (char*) p))
return 0;
c = strdup(p);
c = strdup(p);
} else
c = strndup(p, n);
if (!c)
return -ENOMEM;
@ -1872,7 +1875,7 @@ int _set_put_strdupv_full(Set **s, const struct hash_ops *hash_ops, char **l HA
assert(s);
STRV_FOREACH(i, l) {
r = _set_put_strdup_full(s, hash_ops, *i HASHMAP_DEBUG_PASS_ARGS);
r = _set_put_strndup_full(s, hash_ops, *i, SIZE_MAX HASHMAP_DEBUG_PASS_ARGS);
if (r < 0)
return r;
@ -2074,3 +2077,27 @@ bool set_equal(Set *a, Set *b) {
return true;
}
static bool set_fnmatch_one(Set *patterns, const char *needle) {
const char *p;
assert(needle);
SET_FOREACH(p, patterns)
if (fnmatch(p, needle, 0) == 0)
return true;
return false;
}
bool set_fnmatch(Set *include_patterns, Set *exclude_patterns, const char *needle) {
assert(needle);
if (set_fnmatch_one(exclude_patterns, needle))
return false;
if (set_isempty(include_patterns))
return true;
return set_fnmatch_one(include_patterns, needle);
}

View File

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

View File

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

View File

@ -1,6 +1,7 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stddef.h>
#include <sys/socket.h>
@ -68,14 +69,62 @@ int in_addr_prefix_range(
unsigned prefixlen,
union in_addr_union *ret_start,
union in_addr_union *ret_end);
int in_addr_to_string(int family, const union in_addr_union *u, char **ret);
static inline int in6_addr_to_string(const struct in6_addr *u, char **ret) {
return in_addr_to_string(AF_INET6, (const union in_addr_union*) u, ret);
}
int in_addr_prefix_to_string(int family, const union in_addr_union *u, unsigned prefixlen, char **ret);
static inline int in6_addr_prefix_to_string(const struct in6_addr *u, unsigned prefixlen, char **ret) {
return in_addr_prefix_to_string(AF_INET6, (const union in_addr_union*) u, prefixlen, ret);
static inline const char* typesafe_inet_ntop(int family, const union in_addr_union *a, char *buf, size_t len) {
return inet_ntop(family, a, buf, len);
}
static inline const char* typesafe_inet_ntop4(const struct in_addr *a, char *buf, size_t len) {
return inet_ntop(AF_INET, a, buf, len);
}
static inline const char* typesafe_inet_ntop6(const struct in6_addr *a, char *buf, size_t len) {
return inet_ntop(AF_INET6, a, buf, len);
}
/* Note: the lifetime of the compound literal is the immediately surrounding block,
* see C11 §6.5.2.5, and
* https://stackoverflow.com/questions/34880638/compound-literal-lifetime-and-if-blocks */
#define IN_ADDR_MAX CONST_MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN)
#define IN_ADDR_TO_STRING(family, addr) typesafe_inet_ntop(family, addr, (char[IN_ADDR_MAX]){}, IN_ADDR_MAX)
#define IN4_ADDR_TO_STRING(addr) typesafe_inet_ntop4(addr, (char[INET_ADDRSTRLEN]){}, INET_ADDRSTRLEN)
#define IN6_ADDR_TO_STRING(addr) typesafe_inet_ntop6(addr, (char[INET6_ADDRSTRLEN]){}, INET6_ADDRSTRLEN)
int in_addr_prefix_to_string(
int family,
const union in_addr_union *u,
unsigned prefixlen,
char *buf,
size_t buf_len);
static inline const char* _in_addr_prefix_to_string(
int family,
const union in_addr_union *u,
unsigned prefixlen,
char *buf,
size_t buf_len) {
/* We assume that this is called with an appropriately sized buffer and can never fail. */
assert_se(in_addr_prefix_to_string(family, u, prefixlen, buf, buf_len) == 0);
return buf;
}
static inline const char* _in4_addr_prefix_to_string(const struct in_addr *a, unsigned prefixlen, char *buf, size_t buf_len) {
return _in_addr_prefix_to_string(AF_INET, (const union in_addr_union *) a, prefixlen, buf, buf_len);
}
static inline const char* _in6_addr_prefix_to_string(const struct in6_addr *a, unsigned prefixlen, char *buf, size_t buf_len) {
return _in_addr_prefix_to_string(AF_INET6, (const union in_addr_union *) a, prefixlen, buf, buf_len);
}
#define PREFIX_SUFFIX_MAX (1 + DECIMAL_STR_MAX(unsigned))
#define IN_ADDR_PREFIX_TO_STRING(family, addr, prefixlen) \
_in_addr_prefix_to_string(family, addr, prefixlen, (char[IN_ADDR_MAX + PREFIX_SUFFIX_MAX]){}, IN_ADDR_MAX + PREFIX_SUFFIX_MAX)
#define IN4_ADDR_PREFIX_TO_STRING(addr, prefixlen) \
_in4_addr_prefix_to_string(addr, prefixlen, (char[INET_ADDRSTRLEN + PREFIX_SUFFIX_MAX]){}, INET_ADDRSTRLEN + PREFIX_SUFFIX_MAX)
#define IN6_ADDR_PREFIX_TO_STRING(addr, prefixlen) \
_in6_addr_prefix_to_string(addr, prefixlen, (char[INET6_ADDRSTRLEN + PREFIX_SUFFIX_MAX]){}, INET6_ADDRSTRLEN + PREFIX_SUFFIX_MAX)
int in_addr_port_ifindex_name_to_string(int family, const union in_addr_union *u, uint16_t port, int ifindex, const char *server_name, char **ret);
static inline int in_addr_ifindex_to_string(int family, const union in_addr_union *u, int ifindex, char **ret) {
return in_addr_port_ifindex_name_to_string(family, u, 0, ifindex, NULL, ret);

View File

@ -0,0 +1,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 */

View File

@ -0,0 +1,56 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <libintl.h>
#include <locale.h>
#include <stdbool.h>
#include "macro.h"
typedef enum LocaleVariable {
/* We don't list LC_ALL here on purpose. People should be
* using LANG instead. */
VARIABLE_LANG,
VARIABLE_LANGUAGE,
VARIABLE_LC_CTYPE,
VARIABLE_LC_NUMERIC,
VARIABLE_LC_TIME,
VARIABLE_LC_COLLATE,
VARIABLE_LC_MONETARY,
VARIABLE_LC_MESSAGES,
VARIABLE_LC_PAPER,
VARIABLE_LC_NAME,
VARIABLE_LC_ADDRESS,
VARIABLE_LC_TELEPHONE,
VARIABLE_LC_MEASUREMENT,
VARIABLE_LC_IDENTIFICATION,
_VARIABLE_LC_MAX,
_VARIABLE_LC_INVALID = -EINVAL,
} LocaleVariable;
int get_locales(char ***l);
bool locale_is_valid(const char *name);
int locale_is_installed(const char *name);
#define _(String) gettext(String)
#define N_(String) String
void init_gettext(void);
bool is_locale_utf8(void);
const char* locale_variable_to_string(LocaleVariable i) _const_;
LocaleVariable locale_variable_from_string(const char *s) _pure_;
static inline void freelocalep(locale_t *p) {
if (*p == (locale_t) 0)
return;
freelocale(*p);
}
void locale_variables_free(char* l[_VARIABLE_LC_MAX]);
static inline void locale_variables_freep(char*(*l)[_VARIABLE_LC_MAX]) {
locale_variables_free(*l);
}
void locale_variables_simplify(char *l[_VARIABLE_LC_MAX]);

View File

@ -434,8 +434,16 @@ int log_emergency_level(void);
bool log_on_console(void) _pure_;
/* Helper to prepare various field for structured logging */
#define LOG_MESSAGE(fmt, ...) "MESSAGE=" fmt, ##__VA_ARGS__
/* Helper to wrap the main message in structured logging. The macro doesn't do much,
* except to provide visual grouping of the format string and its arguments. */
#if LOG_MESSAGE_VERIFICATION || defined(__COVERITY__)
/* Do a fake formatting of the message string to let the scanner verify the arguments against the format
* message. The variable will never be set to true, but we don't tell the compiler that :) */
extern bool _log_message_dummy;
# define LOG_MESSAGE(fmt, ...) "MESSAGE=%.0d" fmt, (_log_message_dummy && printf(fmt, ##__VA_ARGS__)), ##__VA_ARGS__
#else
# define LOG_MESSAGE(fmt, ...) "MESSAGE=" fmt, ##__VA_ARGS__
#endif
void log_received_signal(int level, const struct signalfd_siginfo *si);

View File

@ -11,24 +11,6 @@
#include "macro-fundamental.h"
#define _printf_(a, b) __attribute__((__format__(printf, a, b)))
#ifdef __clang__
# define _alloc_(...)
#else
# define _alloc_(...) __attribute__((__alloc_size__(__VA_ARGS__)))
#endif
#define _sentinel_ __attribute__((__sentinel__))
#define _destructor_ __attribute__((__destructor__))
#define _deprecated_ __attribute__((__deprecated__))
#define _malloc_ __attribute__((__malloc__))
#define _weak_ __attribute__((__weak__))
#define _public_ __attribute__((__visibility__("default")))
#define _hidden_ __attribute__((__visibility__("hidden")))
#define _weakref_(x) __attribute__((__weakref__(#x)))
#define _alignas_(x) __attribute__((__aligned__(__alignof__(x))))
#define _alignptr_ __attribute__((__aligned__(sizeof(void*))))
#define _warn_unused_result_ __attribute__((__warn_unused_result__))
#if !defined(HAS_FEATURE_MEMORY_SANITIZER)
# if defined(__has_feature)
# if __has_feature(memory_sanitizer)
@ -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 {

View File

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

View File

@ -23,8 +23,7 @@ static struct mempool pool_name = { \
.at_least = alloc_at_least, \
}
extern const bool mempool_use_allowed;
bool mempool_enabled(void);
__attribute__((weak)) bool mempool_enabled(void);
#if VALGRIND
void mempool_drop(struct mempool *mp);

View File

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

View File

@ -74,6 +74,10 @@ static inline char** ordered_set_get_strv(OrderedSet *s) {
return _hashmap_get_strv(HASHMAP_BASE((OrderedHashmap*) s));
}
static inline int ordered_set_reserve(OrderedSet *s, unsigned entries_add) {
return ordered_hashmap_reserve((OrderedHashmap*) s, entries_add);
}
int ordered_set_consume(OrderedSet *s, void *p);
int _ordered_set_put_strdup(OrderedSet **s, const char *p HASHMAP_DEBUG_PARAMS);
#define ordered_set_put_strdup(s, p) _ordered_set_put_strdup(s, p HASHMAP_DEBUG_SRC_ARGS)

View File

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

View File

@ -12,7 +12,6 @@
typedef unsigned long loadavg_t;
int parse_boolean(const char *v) _pure_;
int parse_dev(const char *s, dev_t *ret);
int parse_pid(const char *s, pid_t* ret_pid);
int parse_mode(const char *s, mode_t *ret);
int parse_ifindex(const char *s);

View File

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

View File

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

View File

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

View File

@ -32,192 +32,142 @@
#include "missing_syscall.h"
#include "parse-util.h"
#include "random-util.h"
#include "siphash24.h"
#include "sha256.h"
#include "time-util.h"
static bool srand_called = false;
/* This is a "best effort" kind of thing, but has no real security value.
* So, this should only be used by random_bytes(), which is not meant for
* crypto. This could be made better, but we're *not* trying to roll a
* userspace prng here, or even have forward secrecy, but rather just do
* the shortest thing that is at least better than libc rand(). */
static void fallback_random_bytes(void *p, size_t n) {
static thread_local uint64_t fallback_counter = 0;
struct {
char label[32];
uint64_t call_id, block_id;
usec_t stamp_mono, stamp_real;
pid_t pid, tid;
uint8_t auxval[16];
} state = {
/* Arbitrary domain separation to prevent other usage of AT_RANDOM from clashing. */
.label = "systemd fallback random bytes v1",
.call_id = fallback_counter++,
.stamp_mono = now(CLOCK_MONOTONIC),
.stamp_real = now(CLOCK_REALTIME),
.pid = getpid(),
.tid = gettid()
};
int genuine_random_bytes(void *p, size_t n, RandomFlags flags) {
static int have_syscall = -1;
_cleanup_close_ int fd = -1;
/* Gathers some high-quality randomness from the kernel. This call won't block, unless the RANDOM_BLOCK
* flag is set. If it doesn't block, it will still always return some data from the kernel, regardless
* of whether the random pool is fully initialized or not. When creating cryptographic key material you
* should always use RANDOM_BLOCK. */
if (n == 0)
return 0;
/* Use the getrandom() syscall unless we know we don't have it. */
if (have_syscall != 0 && !HAS_FEATURE_MEMORY_SANITIZER) {
for (;;) {
#if HAVE_GETRANDOM
ssize_t l = getrandom(p, n, FLAGS_SET(flags, RANDOM_BLOCK) ? 0 : GRND_INSECURE);
#else
/* NetworkManager Note: systemd calls the syscall directly in this case. Don't add that workaround.
* If you don't compile against a libc that provides getrandom(), you don't get it. */
ssize_t l = -1;
errno = ENOSYS;
#if HAVE_SYS_AUXV_H
memcpy(state.auxval, ULONG_TO_PTR(getauxval(AT_RANDOM)), sizeof(state.auxval));
#endif
if (l > 0) {
have_syscall = true;
while (n > 0) {
struct sha256_ctx ctx;
if ((size_t) l == n)
return 0; /* Yay, success! */
/* We didn't get enough data, so try again */
assert((size_t) l < n);
p = (uint8_t*) p + l;
n -= l;
continue;
} else if (l == 0) {
have_syscall = true;
return -EIO;
} else if (ERRNO_IS_NOT_SUPPORTED(errno)) {
/* We lack the syscall, continue with reading from /dev/urandom. */
have_syscall = false;
break;
} else if (errno == EINVAL) {
/* If we previously passed GRND_INSECURE, and this flag isn't known, then
* we're likely running an old kernel which has getrandom() but not
* GRND_INSECURE. In this case, fall back to /dev/urandom. */
if (!FLAGS_SET(flags, RANDOM_BLOCK))
break;
return -errno;
} else
return -errno;
sha256_init_ctx(&ctx);
sha256_process_bytes(&state, sizeof(state), &ctx);
if (n < SHA256_DIGEST_SIZE) {
uint8_t partial[SHA256_DIGEST_SIZE];
sha256_finish_ctx(&ctx, partial);
memcpy(p, partial, n);
break;
}
}
fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY);
if (fd < 0)
return errno == ENOENT ? -ENOSYS : -errno;
return loop_read_exact(fd, p, n, true);
}
static void clear_srand_initialization(void) {
srand_called = false;
}
void initialize_srand(void) {
static bool pthread_atfork_registered = false;
unsigned x;
#if HAVE_SYS_AUXV_H
const void *auxv;
#endif
if (srand_called)
return;
#if HAVE_SYS_AUXV_H
/* The kernel provides us with 16 bytes of entropy in auxv, so let's try to make use of that to seed
* the pseudo-random generator. It's better than nothing... But let's first hash it to make it harder
* to recover the original value by watching any pseudo-random bits we generate. After all the
* AT_RANDOM data might be used by other stuff too (in particular: ASLR), and we probably shouldn't
* leak the seed for that. */
auxv = ULONG_TO_PTR(getauxval(AT_RANDOM));
if (auxv) {
static const uint8_t auxval_hash_key[16] = {
0x92, 0x6e, 0xfe, 0x1b, 0xcf, 0x00, 0x52, 0x9c, 0xcc, 0x42, 0xcf, 0xdc, 0x94, 0x1f, 0x81, 0x0f
};
x = (unsigned) siphash24(auxv, 16, auxval_hash_key);
} else
#endif
x = 0;
x ^= (unsigned) now(CLOCK_REALTIME);
x ^= (unsigned) gettid();
srand(x);
srand_called = true;
if (!pthread_atfork_registered) {
(void) pthread_atfork(NULL, NULL, clear_srand_initialization);
pthread_atfork_registered = true;
}
}
/* INT_MAX gives us only 31 bits, so use 24 out of that. */
#if RAND_MAX >= INT_MAX
assert_cc(RAND_MAX >= 16777215);
# define RAND_STEP 3
#else
/* SHORT_INT_MAX or lower gives at most 15 bits, we just use 8 out of that. */
assert_cc(RAND_MAX >= 255);
# define RAND_STEP 1
#endif
void pseudo_random_bytes(void *p, size_t n) {
uint8_t *q;
/* This returns pseudo-random data using libc's rand() function. You probably never want to call this
* directly, because why would you use this if you can get better stuff cheaply? Use random_bytes()
* instead, see below: it will fall back to this function if there's nothing better to get, but only
* then. */
initialize_srand();
for (q = p; q < (uint8_t*) p + n; q += RAND_STEP) {
unsigned rr;
rr = (unsigned) rand();
#if RAND_STEP >= 3
if ((size_t) (q - (uint8_t*) p + 2) < n)
q[2] = rr >> 16;
#endif
#if RAND_STEP >= 2
if ((size_t) (q - (uint8_t*) p + 1) < n)
q[1] = rr >> 8;
#endif
q[0] = rr;
sha256_finish_ctx(&ctx, p);
p = (uint8_t *) p + SHA256_DIGEST_SIZE;
n -= SHA256_DIGEST_SIZE;
++state.block_id;
}
}
void random_bytes(void *p, size_t n) {
static bool have_getrandom = true, have_grndinsecure = true;
_cleanup_close_ int fd = -1;
/* This returns high quality randomness if we can get it cheaply. If we can't because for some reason
* it is not available we'll try some crappy fallbacks.
*
* What this function will do:
*
* Use getrandom(GRND_INSECURE) or /dev/urandom, to return high-quality random values if
* they are cheaply available, or less high-quality random values if they are not.
*
* This function will return pseudo-random data, generated via libc rand() if nothing
* better is available.
*
* This function will work fine in early boot
*
* This function will always succeed
*
* What this function won't do:
*
* This function will never fail: it will give you randomness no matter what. It might not
* be high quality, but it will return some, possibly generated via libc's rand() call.
*
* This function will never block: if the only way to get good randomness is a blocking,
* synchronous getrandom() we'll instead provide you with pseudo-random data.
*
* This function is hence great for things like seeding hash tables, generating random numeric UNIX
* user IDs (that are checked for collisions before use) and such.
*
* This function is hence not useful for generating UUIDs or cryptographic key material.
*/
if (genuine_random_bytes(p, n, 0) >= 0)
if (n == 0)
return;
/* If for some reason some user made /dev/urandom unavailable to us, or the kernel has no entropy, use a PRNG instead. */
pseudo_random_bytes(p, n);
for (;;) {
ssize_t l;
if (!have_getrandom)
break;
l = getrandom(p, n, have_grndinsecure ? GRND_INSECURE : GRND_NONBLOCK);
if (l > 0) {
if ((size_t) l == n)
return; /* Done reading, success. */
p = (uint8_t *) p + l;
n -= l;
continue; /* Interrupted by a signal; keep going. */
} else if (l == 0)
break; /* Weird, so fallback to /dev/urandom. */
else if (ERRNO_IS_NOT_SUPPORTED(errno)) {
have_getrandom = false;
break; /* No syscall, so fallback to /dev/urandom. */
} else if (errno == EINVAL && have_grndinsecure) {
have_grndinsecure = false;
continue; /* No GRND_INSECURE; fallback to GRND_NONBLOCK. */
} else if (errno == EAGAIN && !have_grndinsecure)
break; /* Will block, but no GRND_INSECURE, so fallback to /dev/urandom. */
break; /* Unexpected, so just give up and fallback to /dev/urandom. */
}
fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY);
if (fd >= 0 && loop_read_exact(fd, p, n, false) == 0)
return;
/* This is a terrible fallback. Oh well. */
fallback_random_bytes(p, n);
}
int crypto_random_bytes(void *p, size_t n) {
static bool have_getrandom = true, seen_initialized = false;
_cleanup_close_ int fd = -1;
if (n == 0)
return 0;
for (;;) {
ssize_t l;
if (!have_getrandom)
break;
l = getrandom(p, n, 0);
if (l > 0) {
if ((size_t) l == n)
return 0; /* Done reading, success. */
p = (uint8_t *) p + l;
n -= l;
continue; /* Interrupted by a signal; keep going. */
} else if (l == 0)
return -EIO; /* Weird, should never happen. */
else if (ERRNO_IS_NOT_SUPPORTED(errno)) {
have_getrandom = false;
break; /* No syscall, so fallback to /dev/urandom. */
}
return -errno;
}
if (!seen_initialized) {
_cleanup_close_ int ready_fd = -1;
int r;
ready_fd = open("/dev/random", O_RDONLY|O_CLOEXEC|O_NOCTTY);
if (ready_fd < 0)
return -errno;
r = fd_wait_for_event(ready_fd, POLLIN, USEC_INFINITY);
if (r < 0)
return r;
seen_initialized = true;
}
fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY);
if (fd < 0)
return -errno;
return loop_read_exact(fd, p, n, false);
}
#if 0 /* NM_IGNORED */

View File

@ -5,15 +5,8 @@
#include <stddef.h>
#include <stdint.h>
typedef enum RandomFlags {
RANDOM_BLOCK = 1 << 0, /* Rather block than return crap randomness (only if the kernel supports that) */
} RandomFlags;
int genuine_random_bytes(void *p, size_t n, RandomFlags flags); /* returns "genuine" randomness, optionally filled up with pseudo random, if not enough is available */
void pseudo_random_bytes(void *p, size_t n); /* returns only pseudo-randommess (but possibly seeded from something better) */
void random_bytes(void *p, size_t n); /* returns genuine randomness if cheaply available, and pseudo randomness if not. */
void initialize_srand(void);
void random_bytes(void *p, size_t n); /* Returns random bytes suitable for most uses, but may be insecure sometimes. */
int crypto_random_bytes(void *p, size_t n); /* Returns secure random bytes after waiting for the RNG to initialize. */
static inline uint64_t random_u64(void) {
uint64_t u;

View File

@ -127,9 +127,12 @@ int _set_ensure_consume(Set **s, const struct hash_ops *hash_ops, void *key HAS
int set_consume(Set *s, void *value);
int _set_put_strdup_full(Set **s, const struct hash_ops *hash_ops, const char *p HASHMAP_DEBUG_PARAMS);
#define set_put_strdup_full(s, hash_ops, p) _set_put_strdup_full(s, hash_ops, p HASHMAP_DEBUG_SRC_ARGS)
#define set_put_strdup(s, p) set_put_strdup_full(s, &string_hash_ops_free, p)
int _set_put_strndup_full(Set **s, const struct hash_ops *hash_ops, const char *p, size_t n HASHMAP_DEBUG_PARAMS);
#define set_put_strndup_full(s, hash_ops, p, n) _set_put_strndup_full(s, hash_ops, p, n HASHMAP_DEBUG_SRC_ARGS)
#define set_put_strdup_full(s, hash_ops, p) set_put_strndup_full(s, hash_ops, p, SIZE_MAX)
#define set_put_strndup(s, p, n) set_put_strndup_full(s, &string_hash_ops_free, p, n)
#define set_put_strdup(s, p) set_put_strndup(s, p, SIZE_MAX)
int _set_put_strdupv_full(Set **s, const struct hash_ops *hash_ops, char **l HASHMAP_DEBUG_PARAMS);
#define set_put_strdupv_full(s, hash_ops, l) _set_put_strdupv_full(s, hash_ops, l HASHMAP_DEBUG_SRC_ARGS)
#define set_put_strdupv(s, l) set_put_strdupv_full(s, &string_hash_ops_free, l)
@ -153,3 +156,5 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(Set*, set_free_free);
int set_strjoin(Set *s, const char *separator, bool wrap_with_separator, char **ret);
bool set_equal(Set *a, Set *b);
bool set_fnmatch(Set *include_patterns, Set *exclude_patterns, const char *needle);

View File

@ -495,9 +495,7 @@ int sockaddr_pretty(
if (r < 0)
return -ENOMEM;
} else {
char a[INET6_ADDRSTRLEN];
inet_ntop(AF_INET6, &sa->in6.sin6_addr, a, sizeof(a));
const char *a = IN6_ADDR_TO_STRING(&sa->in6.sin6_addr);
if (include_port) {
if (asprintf(&p,
@ -656,24 +654,24 @@ int socknameinfo_pretty(union sockaddr_union *sa, socklen_t salen, char **_ret)
}
static const char* const netlink_family_table[] = {
[NETLINK_ROUTE] = "route",
[NETLINK_FIREWALL] = "firewall",
[NETLINK_INET_DIAG] = "inet-diag",
[NETLINK_NFLOG] = "nflog",
[NETLINK_XFRM] = "xfrm",
[NETLINK_SELINUX] = "selinux",
[NETLINK_ISCSI] = "iscsi",
[NETLINK_AUDIT] = "audit",
[NETLINK_FIB_LOOKUP] = "fib-lookup",
[NETLINK_CONNECTOR] = "connector",
[NETLINK_NETFILTER] = "netfilter",
[NETLINK_IP6_FW] = "ip6-fw",
[NETLINK_DNRTMSG] = "dnrtmsg",
[NETLINK_ROUTE] = "route",
[NETLINK_FIREWALL] = "firewall",
[NETLINK_INET_DIAG] = "inet-diag",
[NETLINK_NFLOG] = "nflog",
[NETLINK_XFRM] = "xfrm",
[NETLINK_SELINUX] = "selinux",
[NETLINK_ISCSI] = "iscsi",
[NETLINK_AUDIT] = "audit",
[NETLINK_FIB_LOOKUP] = "fib-lookup",
[NETLINK_CONNECTOR] = "connector",
[NETLINK_NETFILTER] = "netfilter",
[NETLINK_IP6_FW] = "ip6-fw",
[NETLINK_DNRTMSG] = "dnrtmsg",
[NETLINK_KOBJECT_UEVENT] = "kobject-uevent",
[NETLINK_GENERIC] = "generic",
[NETLINK_SCSITRANSPORT] = "scsitransport",
[NETLINK_ECRYPTFS] = "ecryptfs",
[NETLINK_RDMA] = "rdma",
[NETLINK_GENERIC] = "generic",
[NETLINK_SCSITRANSPORT] = "scsitransport",
[NETLINK_ECRYPTFS] = "ecryptfs",
[NETLINK_RDMA] = "rdma",
};
DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(netlink_family, int, INT_MAX);
@ -780,10 +778,10 @@ int fd_set_rcvbuf(int fd, size_t n, bool increase) {
}
static const char* const ip_tos_table[] = {
[IPTOS_LOWDELAY] = "low-delay",
[IPTOS_THROUGHPUT] = "throughput",
[IPTOS_LOWDELAY] = "low-delay",
[IPTOS_THROUGHPUT] = "throughput",
[IPTOS_RELIABILITY] = "reliability",
[IPTOS_LOWCOST] = "low-cost",
[IPTOS_LOWCOST] = "low-cost",
};
DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(ip_tos, int, 0xff);
@ -841,7 +839,7 @@ bool ifname_valid_full(const char *p, IfnameValidFlags flags) {
if (!ifname_valid_char(*t))
return false;
numeric = numeric && (*t >= '0' && *t <= '9');
numeric = numeric && ascii_isdigit(*t);
}
/* It's fully numeric but didn't parse as valid ifindex above? if so, it must be too large or zero or
@ -1248,7 +1246,10 @@ int sockaddr_un_set_path(struct sockaddr_un *ret, const char *path) {
* addresses!), which the kernel doesn't. We do this to reduce chance of incompatibility with other apps that
* do not expect non-NUL terminated file system path. */
if (l+1 > sizeof(ret->sun_path))
return -EINVAL;
return path[0] == '@' ? -EINVAL : -ENAMETOOLONG; /* return a recognizable error if this is
* too long to fit into a sockaddr_un, but
* is a file system path, and thus might be
* connectible via O_PATH indirection. */
*ret = (struct sockaddr_un) {
.sun_family = AF_UNIX,
@ -1437,3 +1438,51 @@ int socket_get_mtu(int fd, int af, size_t *ret) {
return 0;
}
#endif /* NM_IGNORED */
int connect_unix_path(int fd, int dir_fd, const char *path) {
_cleanup_close_ int inode_fd = -1;
union sockaddr_union sa = {
.un.sun_family = AF_UNIX,
};
size_t path_len;
socklen_t salen;
assert(fd >= 0);
assert(dir_fd == AT_FDCWD || dir_fd >= 0);
assert(path);
/* Connects to the specified AF_UNIX socket in the file system. Works around the 108 byte size limit
* in sockaddr_un, by going via O_PATH if needed. This hence works for any kind of path. */
path_len = strlen(path);
/* Refuse zero length path early, to make sure AF_UNIX stack won't mistake this for an abstract
* namespace path, since first char is NUL */
if (path_len <= 0)
return -EINVAL;
if (dir_fd == AT_FDCWD && path_len < sizeof(sa.un.sun_path)) {
memcpy(sa.un.sun_path, path, path_len + 1);
salen = offsetof(struct sockaddr_un, sun_path) + path_len + 1;
} else {
const char *proc;
size_t proc_len;
/* If dir_fd is specified, then we need to go the indirect O_PATH route, because connectat()
* does not exist. If the path is too long, we also need to take the indirect route, since we
* can't fit this into a sockaddr_un directly. */
inode_fd = openat(dir_fd, path, O_PATH|O_CLOEXEC);
if (inode_fd < 0)
return -errno;
proc = FORMAT_PROC_FD_PATH(inode_fd);
proc_len = strlen(proc);
assert(proc_len < sizeof(sa.un.sun_path));
memcpy(sa.un.sun_path, proc, proc_len + 1);
salen = offsetof(struct sockaddr_un, sun_path) + proc_len + 1;
}
return RET_NERRNO(connect(fd, &sa.sa, salen));
}

View File

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

View File

@ -76,13 +76,10 @@ int is_device_node(const char *path) {
return !!(S_ISBLK(info.st_mode) || S_ISCHR(info.st_mode));
}
int dir_is_empty_at(int dir_fd, const char *path) {
int dir_is_empty_at(int dir_fd, const char *path, bool ignore_hidden_or_backup) {
_cleanup_close_ int fd = -1;
/* Allocate space for at least 3 full dirents, since every dir has at least two entries ("." +
* ".."), and only once we have seen if there's a third we know whether the dir is empty or not. */
DEFINE_DIRENT_BUFFER(buffer, 3);
struct dirent *de;
ssize_t n;
struct dirent *buf;
size_t m;
if (path) {
assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
@ -104,15 +101,30 @@ int dir_is_empty_at(int dir_fd, const char *path) {
return fd;
}
n = getdents64(fd, &buffer, sizeof(buffer));
if (n < 0)
return -errno;
/* Allocate space for at least 3 full dirents, since every dir has at least two entries ("." +
* ".."), and only once we have seen if there's a third we know whether the dir is empty or not. If
* 'ignore_hidden_or_backup' is true we'll allocate a bit more, since we might skip over a bunch of
* entries that we end up ignoring. */
m = (ignore_hidden_or_backup ? 16 : 3) * DIRENT_SIZE_MAX;
buf = alloca(m);
msan_unpoison(&buffer, n);
for (;;) {
struct dirent *de;
ssize_t n;
FOREACH_DIRENT_IN_BUFFER(de, &buffer.de, n)
if (!dot_or_dot_dot(de->d_name))
return 0;
n = getdents64(fd, buf, m);
if (n < 0)
return -errno;
if (n == 0)
break;
assert((size_t) n <= m);
msan_unpoison(buf, n);
FOREACH_DIRENT_IN_BUFFER(de, buf, n)
if (!(ignore_hidden_or_backup ? hidden_or_backup_file(de->d_name) : dot_or_dot_dot(de->d_name)))
return 0;
}
return 1;
}
@ -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) {

View File

@ -17,17 +17,9 @@ int is_dir(const char *path, bool follow);
int is_dir_fd(int fd);
int is_device_node(const char *path);
int dir_is_empty_at(int dir_fd, const char *path);
static inline int dir_is_empty(const char *path) {
return dir_is_empty_at(AT_FDCWD, path);
}
static inline int dir_is_populated(const char *path) {
int r;
r = dir_is_empty(path);
if (r < 0)
return r;
return !r;
int dir_is_empty_at(int dir_fd, const char *path, bool ignore_hidden_or_backup);
static inline int dir_is_empty(const char *path, bool ignore_hidden_or_backup) {
return dir_is_empty_at(AT_FDCWD, path, ignore_hidden_or_backup);
}
bool null_or_empty(struct stat *st) _pure_;
@ -71,29 +63,6 @@ int fd_verify_regular(int fd);
int stat_verify_directory(const struct stat *st);
int fd_verify_directory(int fd);
/* glibc and the Linux kernel have different ideas about the major/minor size. These calls will check whether the
* specified major is valid by the Linux kernel's standards, not by glibc's. Linux has 20bits of minor, and 12 bits of
* major space. See MINORBITS in linux/kdev_t.h in the kernel sources. (If you wonder why we define _y here, instead of
* comparing directly >= 0: it's to trick out -Wtype-limits, which would otherwise complain if the type is unsigned, as
* such a test would be pointless in such a case.) */
#define DEVICE_MAJOR_VALID(x) \
({ \
typeof(x) _x = (x), _y = 0; \
_x >= _y && _x < (UINT32_C(1) << 12); \
\
})
#define DEVICE_MINOR_VALID(x) \
({ \
typeof(x) _x = (x), _y = 0; \
_x >= _y && _x < (UINT32_C(1) << 20); \
})
int device_path_make_major_minor(mode_t mode, dev_t devno, char **ret);
int device_path_make_canonical(mode_t mode, dev_t devno, char **ret);
int device_path_parse_major_minor(const char *path, mode_t *ret_mode, dev_t *ret_devno);
int proc_mounted(void);
bool stat_inode_same(const struct stat *a, const struct stat *b);
@ -119,9 +88,3 @@ int statx_fallback(int dfd, const char *path, int flags, unsigned mask, struct s
struct new_statx nsx; \
} var
#endif
static inline bool devid_set_and_equal(dev_t a, dev_t b) {
/* Returns true if a and b definitely refer to the same device. If either is zero, this means "don't
* know" and we'll return false */
return a == b && a != 0;
}

View File

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

View File

@ -10,17 +10,18 @@
#include "string-util-fundamental.h"
/* What is interpreted as whitespace? */
#define WHITESPACE " \t\n\r"
#define NEWLINE "\n\r"
#define QUOTES "\"\'"
#define COMMENTS "#;"
#define GLOB_CHARS "*?["
#define DIGITS "0123456789"
#define LOWERCASE_LETTERS "abcdefghijklmnopqrstuvwxyz"
#define UPPERCASE_LETTERS "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
#define LETTERS LOWERCASE_LETTERS UPPERCASE_LETTERS
#define ALPHANUMERICAL LETTERS DIGITS
#define HEXDIGITS DIGITS "abcdefABCDEF"
#define WHITESPACE " \t\n\r"
#define NEWLINE "\n\r"
#define QUOTES "\"\'"
#define COMMENTS "#;"
#define GLOB_CHARS "*?["
#define DIGITS "0123456789"
#define LOWERCASE_LETTERS "abcdefghijklmnopqrstuvwxyz"
#define UPPERCASE_LETTERS "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
#define LETTERS LOWERCASE_LETTERS UPPERCASE_LETTERS
#define ALPHANUMERICAL LETTERS DIGITS
#define HEXDIGITS DIGITS "abcdefABCDEF"
#define LOWERCASE_HEXDIGITS DIGITS "abcdef"
static inline char* strstr_ptr(const char *haystack, const char *needle) {
if (!haystack || !needle)
@ -28,10 +29,6 @@ static inline char* strstr_ptr(const char *haystack, const char *needle) {
return strstr(haystack, needle);
}
static inline const char* strempty(const char *s) {
return s ?: "";
}
static inline const char* strnull(const char *s) {
return s ?: "(null)";
}
@ -180,13 +177,6 @@ int free_and_strndup(char **p, const char *s, size_t l);
bool string_is_safe(const char *p) _pure_;
static inline size_t strlen_ptr(const char *s) {
if (!s)
return 0;
return strlen(s);
}
DISABLE_WARNING_STRINGOP_TRUNCATION;
static inline void strncpy_exact(char *buf, const char *src, size_t buf_len) {
strncpy(buf, src, buf_len);
@ -232,3 +222,7 @@ static inline int string_contains_word(const char *string, const char *separator
}
bool streq_skip_trailing_chars(const char *s1, const char *s2, const char *ok);
char *string_replace_char(char *str, char old_char, char new_char);
size_t strspn_from_end(const char *str, const char *accept);

View File

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

View File

@ -35,18 +35,36 @@ size_t strv_length(char * const *l) _pure_;
int strv_extend_strv(char ***a, char * const *b, bool filter_duplicates);
int strv_extend_strv_concat(char ***a, char * const *b, const char *suffix);
int strv_prepend(char ***l, const char *value);
int strv_extend(char ***l, const char *value);
/* _with_size() are lower-level functions where the size can be provided externally,
* which allows us to skip iterating over the strv to find the end, which saves
* a bit of time and reduces the complexity of appending from O(n²) to O(n). */
int strv_extend_with_size(char ***l, size_t *n, const char *value);
static inline int strv_extend(char ***l, const char *value) {
return strv_extend_with_size(l, NULL, value);
}
int strv_extendf(char ***l, const char *format, ...) _printf_(2,0);
int strv_extend_front(char ***l, const char *value);
int strv_push(char ***l, char *value);
int strv_push_with_size(char ***l, size_t *n, char *value);
static inline int strv_push(char ***l, char *value) {
return strv_push_with_size(l, NULL, value);
}
int strv_push_pair(char ***l, char *a, char *b);
int strv_insert(char ***l, size_t position, char *value);
static inline int strv_push_prepend(char ***l, char *value) {
return strv_insert(l, 0, value);
}
int strv_consume(char ***l, char *value);
int strv_consume_with_size(char ***l, size_t *n, char *value);
static inline int strv_consume(char ***l, char *value) {
return strv_consume_with_size(l, NULL, value);
}
int strv_consume_pair(char ***l, char *a, char *b);
int strv_consume_prepend(char ***l, char *value);
@ -77,7 +95,7 @@ int strv_split_full(char ***t, const char *s, const char *separators, ExtractFla
static inline char** strv_split(const char *s, const char *separators) {
char **ret;
if (strv_split_full(&ret, s, separators, 0) < 0)
if (strv_split_full(&ret, s, separators, EXTRACT_RETAIN_ESCAPE) < 0)
return NULL;
return ret;
@ -101,7 +119,7 @@ static inline char** strv_split_newlines(const char *s) {
* string in the vector is an empty string. */
int strv_split_colon_pairs(char ***t, const char *s);
char* strv_join_full(char * const *l, const char *separator, const char *prefix, bool escape_separtor);
char* strv_join_full(char * const *l, const char *separator, const char *prefix, bool escape_separator);
static inline char *strv_join(char * const *l, const char *separator) {
return strv_join_full(l, separator, NULL, false);
}
@ -122,12 +140,6 @@ static inline int strv_from_nulstr(char ***a, const char *nulstr) {
bool strv_overlap(char * const *a, char * const *b) _pure_;
#define _STRV_FOREACH(s, l, i) \
for (typeof(*(l)) *s, *i = (l); (s = i) && *i; i++)
#define STRV_FOREACH(s, l) \
_STRV_FOREACH(s, l, UNIQ_T(i, UNIQ))
#define _STRV_FOREACH_BACKWARDS(s, l, h, i) \
for (typeof(*(l)) *s, *h = (l), *i = ({ \
size_t _len = strv_length(h); \

View File

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

View File

@ -2,36 +2,50 @@
#pragma once
#ifndef SD_BOOT
#include <assert.h>
# include <assert.h>
#endif
#include <limits.h>
#include "types-fundamental.h"
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#define _align_(x) __attribute__((__aligned__(x)))
#define _const_ __attribute__((__const__))
#define _pure_ __attribute__((__pure__))
#define _section_(x) __attribute__((__section__(x)))
#define _packed_ __attribute__((__packed__))
#define _retain_ __attribute__((__retain__))
#define _used_ __attribute__((__used__))
#define _unused_ __attribute__((__unused__))
#define _alignas_(x) __attribute__((__aligned__(__alignof__(x))))
#define _alignptr_ __attribute__((__aligned__(sizeof(void *))))
#define _cleanup_(x) __attribute__((__cleanup__(x)))
#define _const_ __attribute__((__const__))
#define _deprecated_ __attribute__((__deprecated__))
#define _destructor_ __attribute__((__destructor__))
#define _hidden_ __attribute__((__visibility__("hidden")))
#define _likely_(x) (__builtin_expect(!!(x), 1))
#define _unlikely_(x) (__builtin_expect(!!(x), 0))
#if __GNUC__ >= 7
#define _fallthrough_ __attribute__((__fallthrough__))
#else
#define _fallthrough_
#endif
/* Define C11 noreturn without <stdnoreturn.h> and even on older gcc
* compiler versions */
#ifndef _noreturn_
#if __STDC_VERSION__ >= 201112L
#define _malloc_ __attribute__((__malloc__))
#define _noreturn_ _Noreturn
#define _packed_ __attribute__((__packed__))
#define _printf_(a, b) __attribute__((__format__(printf, a, b)))
#define _public_ __attribute__((__visibility__("default")))
#define _pure_ __attribute__((__pure__))
#define _retain_ __attribute__((__retain__))
#define _returns_nonnull_ __attribute__((__returns_nonnull__))
#define _section_(x) __attribute__((__section__(x)))
#define _sentinel_ __attribute__((__sentinel__))
#define _unlikely_(x) (__builtin_expect(!!(x), 0))
#define _unused_ __attribute__((__unused__))
#define _used_ __attribute__((__used__))
#define _warn_unused_result_ __attribute__((__warn_unused_result__))
#define _weak_ __attribute__((__weak__))
#define _weakref_(x) __attribute__((__weakref__(#x)))
#ifdef __clang__
# define _alloc_(...)
#else
#define _noreturn_ __attribute__((__noreturn__))
# define _alloc_(...) __attribute__((__alloc_size__(__VA_ARGS__)))
#endif
#if __GNUC__ >= 7 || (defined(__clang__) && __clang_major__ >= 10)
# define _fallthrough_ __attribute__((__fallthrough__))
#else
# define _fallthrough_
#endif
#define XSTRINGIFY(x) #x
@ -53,7 +67,7 @@
#define CONCATENATE(x, y) XCONCATENATE(x, y)
#ifdef SD_BOOT
void efi_assert(const char *expr, const char *file, unsigned line, const char *function) _noreturn_;
_noreturn_ void efi_assert(const char *expr, const char *file, unsigned line, const char *function);
#ifdef NDEBUG
#define assert(expr)
@ -62,10 +76,8 @@
#define assert(expr) ({ _likely_(expr) ? VOID_0 : efi_assert(#expr, __FILE__, __LINE__, __PRETTY_FUNCTION__); })
#define assert_not_reached() efi_assert("Code should not be reached", __FILE__, __LINE__, __PRETTY_FUNCTION__)
#endif
#define static_assert _Static_assert
#define assert_se(expr) ({ _likely_(expr) ? VOID_0 : efi_assert(#expr, __FILE__, __LINE__, __PRETTY_FUNCTION__); })
#define memcpy(a, b, c) CopyMem((a), (b), (c))
#define free(a) FreePool(a)
#endif
/* This passes the argument through after (if asserts are enabled) checking that it is not null. */
@ -83,15 +95,8 @@
_expr_; \
})
#if defined(static_assert)
#define assert_cc(expr) \
static_assert(expr, #expr)
#else
#define assert_cc(expr) \
struct CONCATENATE(_assert_struct_, __COUNTER__) { \
char x[(expr) ? 0 : -1]; \
}
#endif
#define assert_cc(expr) static_assert(expr, #expr)
#define UNIQ_T(x, uniq) CONCATENATE(__unique_prefix_, CONCATENATE(x, uniq))
#define UNIQ __COUNTER__
@ -101,10 +106,10 @@
* on this macro will run concurrently to all other code conditionalized
* the same way, there's no ordering or completion enforced. */
#define ONCE __ONCE(UNIQ_T(_once_, UNIQ))
#define __ONCE(o) \
({ \
static sd_bool (o) = sd_false; \
__sync_bool_compare_and_swap(&(o), sd_false, sd_true); \
#define __ONCE(o) \
({ \
static bool (o) = false; \
__sync_bool_compare_and_swap(&(o), false, true); \
})
#undef MAX
@ -254,7 +259,7 @@
#define IN_SET(x, ...) \
({ \
sd_bool _found = sd_false; \
bool _found = false; \
/* If the build breaks in the line below, you need to extend the case macros. (We use "long double" as \
* type for the array, in the hope that checkers such as ubsan don't complain that the initializers for \
* the array are not representable by the base type. Ideally we'd use typeof(x) as base type, but that \
@ -263,7 +268,7 @@
assert_cc(ELEMENTSOF(__assert_in_set) <= 20); \
switch (x) { \
FOR_EACH_MAKE_CASE(__VA_ARGS__) \
_found = sd_true; \
_found = true; \
break; \
default: \
break; \
@ -295,9 +300,6 @@
})
static inline size_t ALIGN_TO(size_t l, size_t ali) {
/* sd-boot uses UINTN for size_t, let's make sure SIZE_MAX is correct. */
assert_cc(SIZE_MAX == ~(size_t)0);
/* Check that alignment is exponent of 2 */
#if SIZE_MAX == UINT_MAX
assert(__builtin_popcount(ali) == 1);
@ -315,6 +317,14 @@ static inline size_t ALIGN_TO(size_t l, size_t ali) {
return ((l + ali - 1) & ~(ali - 1));
}
#define ALIGN4(l) ALIGN_TO(l, 4)
#define ALIGN8(l) ALIGN_TO(l, 8)
#ifndef SD_BOOT
/* libefi also provides ALIGN, and we do not use them in sd-boot explicitly. */
#define ALIGN(l) ALIGN_TO(l, sizeof(void*))
#define ALIGN_PTR(p) ((void*) ALIGN((uintptr_t) (p)))
#endif
/* Same as ALIGN_TO but callable in constant contexts. */
#define CONST_ALIGN_TO(l, ali) \
__builtin_choose_expr( \

View File

@ -0,0 +1,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;
}

View File

@ -0,0 +1,29 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include "stdint.h"
#define SHA256_DIGEST_SIZE 32
struct sha256_ctx {
uint32_t H[8];
union {
uint64_t total64;
#define TOTAL64_low (1 - (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__))
#define TOTAL64_high (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
uint32_t total[2];
};
uint32_t buflen;
union {
uint8_t buffer[128]; /* NB: always correctly aligned for UINT32. */
uint32_t buffer32[32];
uint64_t buffer64[16];
};
};
void sha256_init_ctx(struct sha256_ctx *ctx);
void *sha256_finish_ctx(struct sha256_ctx *ctx, void *resbuf);
void sha256_process_bytes(const void *buffer, size_t len, struct sha256_ctx *ctx);

View File

@ -3,10 +3,10 @@
#include "nm-sd-adapt-shared.h"
#ifndef SD_BOOT
#include <ctype.h>
#include "macro.h"
# include <ctype.h>
#endif
#include "macro-fundamental.h"
#include "string-util-fundamental.h"
sd_char *startswith(const sd_char *s, const sd_char *prefix) {
@ -80,36 +80,27 @@ sd_char* endswith_no_case(const sd_char *s, const sd_char *postfix) {
}
#if 0 /* NM_IGNORED */
#ifdef SD_BOOT
static sd_bool isdigit(sd_char a) {
return a >= '0' && a <= '9';
}
#endif
static sd_bool is_alpha(sd_char a) {
/* Locale independent version of isalpha(). */
return (a >= 'a' && a <= 'z') || (a >= 'A' && a <= 'Z');
static 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;
}

View File

@ -2,54 +2,62 @@
#pragma once
#ifdef SD_BOOT
#include <efi.h>
#include <efilib.h>
# include <efi.h>
# include <efilib.h>
# include "efi-string.h"
#else
#include <string.h>
# include <string.h>
#endif
#include "macro-fundamental.h"
#ifdef SD_BOOT
#define strlen(a) StrLen((a))
#define strcmp(a, b) StrCmp((a), (b))
#define strncmp(a, b, n) StrnCmp((a), (b), (n))
#define strcasecmp(a, b) StriCmp((a), (b))
#define STR_C(str) (L ## str)
#define memcmp(a, b, n) CompareMem(a, b, n)
# define strlen strlen16
# define strcmp strcmp16
# define strncmp strncmp16
# define strcasecmp strcasecmp16
# define strncasecmp strncasecmp16
# define STR_C(str) (L ## str)
typedef char16_t sd_char;
#else
#define STR_C(str) (str)
# define STR_C(str) (str)
typedef char sd_char;
#endif
#define streq(a,b) (strcmp((a),(b)) == 0)
#define strneq(a, b, n) (strncmp((a), (b), (n)) == 0)
#define strcaseeq(a,b) (strcasecmp((a),(b)) == 0)
#ifndef SD_BOOT
#define strncaseeq(a, b, n) (strncasecmp((a), (b), (n)) == 0)
#endif
static inline sd_int strcmp_ptr(const sd_char *a, const sd_char *b) {
static inline int strcmp_ptr(const sd_char *a, const sd_char *b) {
if (a && b)
return strcmp(a, b);
return CMP(a, b);
}
static inline sd_int strcasecmp_ptr(const sd_char *a, const sd_char *b) {
static inline int strcasecmp_ptr(const sd_char *a, const sd_char *b) {
if (a && b)
return strcasecmp(a, b);
return CMP(a, b);
}
static inline sd_bool streq_ptr(const sd_char *a, const sd_char *b) {
static inline bool streq_ptr(const sd_char *a, const sd_char *b) {
return strcmp_ptr(a, b) == 0;
}
static inline sd_bool strcaseeq_ptr(const sd_char *a, const sd_char *b) {
static inline bool strcaseeq_ptr(const sd_char *a, const sd_char *b) {
return strcasecmp_ptr(a, b) == 0;
}
static inline size_t strlen_ptr(const sd_char *s) {
if (!s)
return 0;
return strlen(s);
}
sd_char *startswith(const sd_char *s, const sd_char *prefix) _pure_;
#ifndef SD_BOOT
sd_char *startswith_no_case(const sd_char *s, const sd_char *prefix) _pure_;
@ -57,15 +65,23 @@ sd_char *startswith_no_case(const sd_char *s, const sd_char *prefix) _pure_;
sd_char *endswith(const sd_char *s, const sd_char *postfix) _pure_;
sd_char *endswith_no_case(const sd_char *s, const sd_char *postfix) _pure_;
static inline sd_bool isempty(const sd_char *a) {
static inline bool isempty(const sd_char *a) {
return !a || a[0] == '\0';
}
static inline const sd_char *yes_no(sd_bool b) {
static inline const sd_char *strempty(const sd_char *s) {
return s ?: STR_C("");
}
static inline const sd_char *yes_no(bool b) {
return b ? STR_C("yes") : STR_C("no");
}
sd_int strverscmp_improved(const sd_char *a, const sd_char *b);
static inline const sd_char* comparison_operator(int result) {
return result < 0 ? STR_C("<") : result > 0 ? STR_C(">") : STR_C("==");
}
int strverscmp_improved(const sd_char *a, const sd_char *b);
/* Like startswith(), but operates on arbitrary memory blocks */
static inline void *memory_startswith(const void *p, size_t sz, const sd_char *token) {
@ -82,3 +98,19 @@ static inline void *memory_startswith(const void *p, size_t sz, const sd_char *t
return (uint8_t*) p + n;
}
#define _STRV_FOREACH(s, l, i) \
for (typeof(*(l)) *s, *i = (l); (s = i) && *i; i++)
#define STRV_FOREACH(s, l) \
_STRV_FOREACH(s, l, UNIQ_T(i, UNIQ))
static inline bool ascii_isdigit(sd_char a) {
/* A pure ASCII, locale independent version of isdigit() */
return a >= '0' && a <= '9';
}
static inline bool ascii_isalpha(sd_char a) {
/* A pure ASCII, locale independent version of isalpha() */
return (a >= 'a' && a <= 'z') || (a >= 'A' && a <= 'Z');
}

View File

@ -1,39 +0,0 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
/* This defines a number of basic types that are one thing in userspace and another in the UEFI environment,
* but mostly the same in concept and behaviour.
*
* Note: if the definition of these types/values has slightly different semantics in userspace and in the
* UEFI environment then please prefix its name with "sd_" to make clear these types have special semantics,
* and *we* defined them. Otherwise, if the types are effectively 100% identical in behaviour in userspace
* and UEFI environment you can omit the prefix. (Examples: sd_char is 8 bit in userspace and 16 bit in UEFI
* space hence it should have the sd_ prefix; but size_t in userspace and UINTN in UEFI environment are 100%
* defined the same way ultimately, hence it's OK to just define size_t as alias to UINTN in UEFI
* environment, so that size_t can be used everywhere, without any "sd_" prefix.)
*
* Note: we generally prefer the userspace names of types and concepts. i.e. if in doubt please name types
* after the userspace vocabulary, and let's keep UEFI vocabulary specific to the UEFI build environment. */
#ifdef SD_BOOT
#include <efi.h>
typedef BOOLEAN sd_bool;
typedef CHAR16 sd_char;
typedef INTN sd_int;
typedef UINTN size_t;
#define sd_true TRUE
#define sd_false FALSE
#else
#include <stdbool.h>
#include <stdint.h>
typedef bool sd_bool;
typedef char sd_char;
typedef int sd_int;
#define sd_true true
#define sd_false false
#endif

View File

@ -9,6 +9,7 @@
#include "alloc-util.h"
#include "dns-domain.h"
#include "glyph-util.h"
#include "hashmap.h"
#include "hexdecoct.h"
#include "hostname-util.h"
@ -239,9 +240,8 @@ int dns_label_escape(const char *p, size_t l, char *dest, size_t sz) {
sz -= 2;
} else if (IN_SET(*p, '_', '-') ||
(*p >= '0' && *p <= '9') ||
(*p >= 'a' && *p <= 'z') ||
(*p >= 'A' && *p <= 'Z')) {
ascii_isdigit(*p) ||
ascii_isalpha(*p)) {
/* Proper character */
@ -456,12 +456,8 @@ int dns_name_concat(const char *a, const char *b, DNSLabelFlags flags, char **_r
return r;
}
if (!first)
n++;
else
first = false;
n += r;
n += r + !first;
first = false;
}
finish:
@ -919,15 +915,13 @@ static bool srv_type_label_is_valid(const char *label, size_t n) {
return false;
/* Second char must be a letter */
if (!(label[1] >= 'A' && label[1] <= 'Z') &&
!(label[1] >= 'a' && label[1] <= 'z'))
if (!ascii_isalpha(label[1]))
return false;
/* Third and further chars must be alphanumeric or a hyphen */
for (k = 2; k < n; k++) {
if (!(label[k] >= 'A' && label[k] <= 'Z') &&
!(label[k] >= 'a' && label[k] <= 'z') &&
!(label[k] >= '0' && label[k] <= '9') &&
if (!ascii_isalpha(label[k]) &&
!ascii_isdigit(label[k]) &&
label[k] != '-')
return false;
}
@ -1035,10 +1029,10 @@ static bool dns_service_name_label_is_valid(const char *label, size_t n) {
return dns_service_name_is_valid(s);
}
int dns_service_split(const char *joined, char **_name, char **_type, char **_domain) {
int dns_service_split(const char *joined, char **ret_name, char **ret_type, char **ret_domain) {
_cleanup_free_ char *name = NULL, *type = NULL, *domain = NULL;
const char *p = joined, *q = NULL, *d = NULL;
char a[DNS_LABEL_MAX], b[DNS_LABEL_MAX], c[DNS_LABEL_MAX];
const char *p = joined, *q = NULL, *d = joined;
char a[DNS_LABEL_MAX+1], b[DNS_LABEL_MAX+1], c[DNS_LABEL_MAX+1];
int an, bn, cn, r;
unsigned x = 0;
@ -1058,6 +1052,9 @@ int dns_service_split(const char *joined, char **_name, char **_type, char **_do
return bn;
if (bn > 0) {
if (!srv_type_label_is_valid(b, bn))
goto finish;
x++;
/* If there was a second label, try to get the third one */
@ -1066,64 +1063,58 @@ int dns_service_split(const char *joined, char **_name, char **_type, char **_do
if (cn < 0)
return cn;
if (cn > 0)
if (cn > 0 && srv_type_label_is_valid(c, cn))
x++;
} else
cn = 0;
} else
an = 0;
if (x >= 2 && srv_type_label_is_valid(b, bn)) {
if (x >= 3 && srv_type_label_is_valid(c, cn)) {
if (dns_service_name_label_is_valid(a, an)) {
/* OK, got <name> . <type> . <type2> . <domain> */
name = strndup(a, an);
if (!name)
return -ENOMEM;
type = strjoin(b, ".", c);
if (!type)
return -ENOMEM;
d = p;
goto finish;
}
} else if (srv_type_label_is_valid(a, an)) {
/* OK, got <type> . <type2> . <domain> */
name = NULL;
type = strjoin(a, ".", b);
if (!type)
return -ENOMEM;
d = q;
goto finish;
}
}
name = NULL;
type = NULL;
d = joined;
switch (x) {
case 2:
if (!srv_type_label_is_valid(a, an))
break;
/* OK, got <type> . <type2> . <domain> */
name = NULL;
type = strjoin(a, ".", b);
if (!type)
return -ENOMEM;
d = q;
break;
case 3:
if (!dns_service_name_label_is_valid(a, an))
break;
/* OK, got <name> . <type> . <type2> . <domain> */
name = strndup(a, an);
if (!name)
return -ENOMEM;
type = strjoin(b, ".", c);
if (!type)
return -ENOMEM;
d = p;
break;
}
finish:
r = dns_name_normalize(d, 0, &domain);
if (r < 0)
return r;
if (_domain)
*_domain = TAKE_PTR(domain);
if (ret_domain)
*ret_domain = TAKE_PTR(domain);
if (_type)
*_type = TAKE_PTR(type);
if (ret_type)
*ret_type = TAKE_PTR(type);
if (_name)
*_name = TAKE_PTR(name);
if (ret_name)
*ret_name = TAKE_PTR(name);
return 0;
}
@ -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;
}

View File

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