systemd: update code from upstream (2022-10-04)
This is a direct dump from systemd git. $ git clean -fdx && \ git cat-file -p HEAD | sed '1,/^======$/ d' | bash - && \ git add . ====== SYSTEMD_DIR=../systemd COMMIT=f77c0840d505825f14ff30921752cb26778bf53e ( cd "$SYSTEMD_DIR" git checkout "$COMMIT" git reset --hard git clean -fdx ) git ls-files -z :/src/libnm-systemd-core/src/ \ :/src/libnm-systemd-shared/src/ \ :/src/libnm-std-aux/unaligned.h | \ xargs -0 rm -f nm_copy_sd_shared() { mkdir -p "./src/libnm-systemd-shared/$(dirname "$1")" cp "$SYSTEMD_DIR/$1" "./src/libnm-systemd-shared/$1" } nm_copy_sd_core() { mkdir -p "./src/libnm-systemd-core/$(dirname "$1")" cp "$SYSTEMD_DIR/$1" "./src/libnm-systemd-core/$1" } nm_copy_sd_stdaux() { mkdir -p "./src/libnm-std-aux/" cp "$SYSTEMD_DIR/$1" "./src/libnm-std-aux/${1##*/}" } nm_copy_sd_core "src/libsystemd-network/arp-util.c" nm_copy_sd_core "src/libsystemd-network/arp-util.h" nm_copy_sd_core "src/libsystemd-network/dhcp-identifier.c" nm_copy_sd_core "src/libsystemd-network/dhcp-identifier.h" nm_copy_sd_core "src/libsystemd-network/dhcp-lease-internal.h" nm_copy_sd_core "src/libsystemd-network/dhcp6-internal.h" nm_copy_sd_core "src/libsystemd-network/dhcp6-lease-internal.h" nm_copy_sd_core "src/libsystemd-network/dhcp6-network.c" nm_copy_sd_core "src/libsystemd-network/dhcp6-option.c" nm_copy_sd_core "src/libsystemd-network/dhcp6-option.h" nm_copy_sd_core "src/libsystemd-network/dhcp6-protocol.c" nm_copy_sd_core "src/libsystemd-network/dhcp6-protocol.h" nm_copy_sd_core "src/libsystemd-network/lldp-neighbor.c" nm_copy_sd_core "src/libsystemd-network/lldp-neighbor.h" nm_copy_sd_core "src/libsystemd-network/lldp-network.c" nm_copy_sd_core "src/libsystemd-network/lldp-network.h" nm_copy_sd_core "src/libsystemd-network/lldp-rx-internal.h" nm_copy_sd_core "src/libsystemd-network/network-common.c" nm_copy_sd_core "src/libsystemd-network/network-common.h" nm_copy_sd_core "src/libsystemd-network/network-internal.h" nm_copy_sd_core "src/libsystemd-network/sd-dhcp6-client.c" nm_copy_sd_core "src/libsystemd-network/sd-dhcp6-lease.c" nm_copy_sd_core "src/libsystemd-network/sd-lldp-rx.c" nm_copy_sd_core "src/libsystemd/sd-event/event-source.h" nm_copy_sd_core "src/libsystemd/sd-event/event-util.c" nm_copy_sd_core "src/libsystemd/sd-event/event-util.h" nm_copy_sd_core "src/libsystemd/sd-event/sd-event.c" nm_copy_sd_core "src/libsystemd/sd-id128/id128-util.c" nm_copy_sd_core "src/libsystemd/sd-id128/id128-util.h" nm_copy_sd_core "src/libsystemd/sd-id128/sd-id128.c" nm_copy_sd_core "src/systemd/_sd-common.h" nm_copy_sd_core "src/systemd/sd-dhcp6-client.h" nm_copy_sd_core "src/systemd/sd-dhcp6-lease.h" nm_copy_sd_core "src/systemd/sd-dhcp6-option.h" nm_copy_sd_core "src/systemd/sd-event.h" nm_copy_sd_core "src/systemd/sd-id128.h" nm_copy_sd_core "src/systemd/sd-lldp-rx.h" nm_copy_sd_core "src/systemd/sd-lldp.h" nm_copy_sd_core "src/systemd/sd-ndisc.h" nm_copy_sd_shared "src/basic/alloc-util.c" nm_copy_sd_shared "src/basic/alloc-util.h" nm_copy_sd_shared "src/basic/async.h" nm_copy_sd_shared "src/basic/cgroup-util.h" nm_copy_sd_shared "src/basic/dns-def.h" nm_copy_sd_shared "src/basic/env-file.c" nm_copy_sd_shared "src/basic/env-file.h" nm_copy_sd_shared "src/basic/env-util.c" nm_copy_sd_shared "src/basic/env-util.h" nm_copy_sd_shared "src/basic/errno-util.h" nm_copy_sd_shared "src/basic/escape.c" nm_copy_sd_shared "src/basic/escape.h" nm_copy_sd_shared "src/basic/ether-addr-util.c" nm_copy_sd_shared "src/basic/ether-addr-util.h" nm_copy_sd_shared "src/basic/extract-word.c" nm_copy_sd_shared "src/basic/extract-word.h" nm_copy_sd_shared "src/basic/fd-util.c" nm_copy_sd_shared "src/basic/fd-util.h" nm_copy_sd_shared "src/basic/fileio.c" nm_copy_sd_shared "src/basic/fileio.h" nm_copy_sd_shared "src/basic/format-util.c" nm_copy_sd_shared "src/basic/format-util.h" nm_copy_sd_shared "src/basic/fs-util.c" nm_copy_sd_shared "src/basic/fs-util.h" nm_copy_sd_shared "src/basic/glyph-util.c" nm_copy_sd_shared "src/basic/glyph-util.h" nm_copy_sd_shared "src/basic/hash-funcs.c" nm_copy_sd_shared "src/basic/hash-funcs.h" nm_copy_sd_shared "src/basic/hashmap.c" nm_copy_sd_shared "src/basic/hashmap.h" nm_copy_sd_shared "src/basic/hexdecoct.c" nm_copy_sd_shared "src/basic/hexdecoct.h" nm_copy_sd_shared "src/basic/hostname-util.c" nm_copy_sd_shared "src/basic/hostname-util.h" nm_copy_sd_shared "src/basic/in-addr-util.c" nm_copy_sd_shared "src/basic/in-addr-util.h" nm_copy_sd_shared "src/basic/inotify-util.c" nm_copy_sd_shared "src/basic/inotify-util.h" nm_copy_sd_shared "src/basic/io-util.c" nm_copy_sd_shared "src/basic/io-util.h" nm_copy_sd_shared "src/basic/list.h" nm_copy_sd_shared "src/basic/locale-util.c" nm_copy_sd_shared "src/basic/locale-util.h" nm_copy_sd_shared "src/basic/log.h" nm_copy_sd_shared "src/basic/macro.h" nm_copy_sd_shared "src/basic/memory-util.c" nm_copy_sd_shared "src/basic/memory-util.h" nm_copy_sd_shared "src/basic/mempool.c" nm_copy_sd_shared "src/basic/mempool.h" nm_copy_sd_shared "src/basic/missing_fcntl.h" nm_copy_sd_shared "src/basic/missing_random.h" nm_copy_sd_shared "src/basic/missing_socket.h" nm_copy_sd_shared "src/basic/missing_stat.h" nm_copy_sd_shared "src/basic/missing_syscall.h" nm_copy_sd_shared "src/basic/missing_type.h" nm_copy_sd_shared "src/basic/ordered-set.c" nm_copy_sd_shared "src/basic/ordered-set.h" nm_copy_sd_shared "src/basic/parse-util.c" nm_copy_sd_shared "src/basic/parse-util.h" nm_copy_sd_shared "src/basic/path-util.c" nm_copy_sd_shared "src/basic/path-util.h" nm_copy_sd_shared "src/basic/prioq.c" nm_copy_sd_shared "src/basic/prioq.h" nm_copy_sd_shared "src/basic/process-util.c" nm_copy_sd_shared "src/basic/process-util.h" nm_copy_sd_shared "src/basic/random-util.c" nm_copy_sd_shared "src/basic/random-util.h" nm_copy_sd_shared "src/basic/ratelimit.c" nm_copy_sd_shared "src/basic/ratelimit.h" nm_copy_sd_shared "src/basic/set.h" nm_copy_sd_shared "src/basic/signal-util.c" nm_copy_sd_shared "src/basic/signal-util.h" nm_copy_sd_shared "src/basic/siphash24.h" nm_copy_sd_shared "src/basic/socket-util.c" nm_copy_sd_shared "src/basic/socket-util.h" nm_copy_sd_shared "src/basic/sort-util.h" nm_copy_sd_shared "src/basic/sparse-endian.h" nm_copy_sd_shared "src/basic/stat-util.c" nm_copy_sd_shared "src/basic/stat-util.h" nm_copy_sd_shared "src/basic/stdio-util.h" nm_copy_sd_shared "src/basic/string-table.c" nm_copy_sd_shared "src/basic/string-table.h" nm_copy_sd_shared "src/basic/string-util.c" nm_copy_sd_shared "src/basic/string-util.h" nm_copy_sd_shared "src/basic/strv.c" nm_copy_sd_shared "src/basic/strv.h" nm_copy_sd_shared "src/basic/strxcpyx.c" nm_copy_sd_shared "src/basic/strxcpyx.h" nm_copy_sd_shared "src/basic/time-util.c" nm_copy_sd_shared "src/basic/time-util.h" nm_copy_sd_shared "src/basic/tmpfile-util.c" nm_copy_sd_shared "src/basic/tmpfile-util.h" nm_copy_sd_shared "src/basic/umask-util.h" nm_copy_sd_shared "src/basic/user-util.h" nm_copy_sd_shared "src/basic/utf8.c" nm_copy_sd_shared "src/basic/utf8.h" nm_copy_sd_shared "src/basic/util.c" nm_copy_sd_shared "src/basic/util.h" nm_copy_sd_shared "src/fundamental/macro-fundamental.h" nm_copy_sd_shared "src/fundamental/sha256.c" nm_copy_sd_shared "src/fundamental/sha256.h" nm_copy_sd_shared "src/fundamental/string-util-fundamental.c" nm_copy_sd_shared "src/fundamental/string-util-fundamental.h" nm_copy_sd_shared "src/shared/dns-domain.c" nm_copy_sd_shared "src/shared/dns-domain.h" nm_copy_sd_shared "src/shared/log-link.h" nm_copy_sd_shared "src/shared/web-util.c" nm_copy_sd_shared "src/shared/web-util.h" nm_copy_sd_stdaux "src/basic/unaligned.h"
This commit is contained in:
@@ -82,3 +82,14 @@ static const char * const dhcp6_message_status_table[_DHCP6_STATUS_MAX] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
DEFINE_STRING_TABLE_LOOKUP(dhcp6_message_status, DHCP6Status);
|
DEFINE_STRING_TABLE_LOOKUP(dhcp6_message_status, DHCP6Status);
|
||||||
|
|
||||||
|
int dhcp6_message_status_to_errno(DHCP6Status s) {
|
||||||
|
switch (s) {
|
||||||
|
case DHCP6_STATUS_SUCCESS:
|
||||||
|
return 0;
|
||||||
|
case DHCP6_STATUS_NO_BINDING:
|
||||||
|
return -EADDRNOTAVAIL;
|
||||||
|
default:
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -154,3 +154,4 @@ const char *dhcp6_message_type_to_string(DHCP6MessageType s) _const_;
|
|||||||
DHCP6MessageType dhcp6_message_type_from_string(const char *s) _pure_;
|
DHCP6MessageType dhcp6_message_type_from_string(const char *s) _pure_;
|
||||||
const char *dhcp6_message_status_to_string(DHCP6Status s) _const_;
|
const char *dhcp6_message_status_to_string(DHCP6Status s) _const_;
|
||||||
DHCP6Status dhcp6_message_status_from_string(const char *s) _pure_;
|
DHCP6Status dhcp6_message_status_from_string(const char *s) _pure_;
|
||||||
|
int dhcp6_message_status_to_errno(DHCP6Status s);
|
||||||
|
@@ -207,7 +207,7 @@ static int dhcp6_client_set_duid_internal(
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_dhcp6_client_errno(client, r, "Failed to validate length of DUID: %m");
|
return log_dhcp6_client_errno(client, r, "Failed to validate length of DUID: %m");
|
||||||
|
|
||||||
log_dhcp6_client(client, "Using DUID of type %u of incorrect length, proceeding.", duid_type);
|
log_dhcp6_client(client, "Using DUID of type %i of incorrect length, proceeding.", duid_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
client->duid.type = htobe16(duid_type);
|
client->duid.type = htobe16(duid_type);
|
||||||
@@ -543,13 +543,9 @@ static void client_notify(sd_dhcp6_client *client, int event) {
|
|||||||
client->callback(client, event, client->userdata);
|
client->callback(client, event, client->userdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void client_stop(sd_dhcp6_client *client, int error) {
|
static void client_cleanup(sd_dhcp6_client *client) {
|
||||||
DHCP6_CLIENT_DONT_DESTROY(client);
|
|
||||||
|
|
||||||
assert(client);
|
assert(client);
|
||||||
|
|
||||||
client_notify(client, error);
|
|
||||||
|
|
||||||
client->lease = sd_dhcp6_lease_unref(client->lease);
|
client->lease = sd_dhcp6_lease_unref(client->lease);
|
||||||
|
|
||||||
/* Reset IRT here. Otherwise, we cannot restart the client in the information requesting mode,
|
/* Reset IRT here. Otherwise, we cannot restart the client in the information requesting mode,
|
||||||
@@ -566,6 +562,16 @@ static void client_stop(sd_dhcp6_client *client, int error) {
|
|||||||
client_set_state(client, DHCP6_STATE_STOPPED);
|
client_set_state(client, DHCP6_STATE_STOPPED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void client_stop(sd_dhcp6_client *client, int error) {
|
||||||
|
DHCP6_CLIENT_DONT_DESTROY(client);
|
||||||
|
|
||||||
|
assert(client);
|
||||||
|
|
||||||
|
client_notify(client, error);
|
||||||
|
|
||||||
|
client_cleanup(client);
|
||||||
|
}
|
||||||
|
|
||||||
static int client_append_common_options_in_managed_mode(
|
static int client_append_common_options_in_managed_mode(
|
||||||
sd_dhcp6_client *client,
|
sd_dhcp6_client *client,
|
||||||
uint8_t **opt,
|
uint8_t **opt,
|
||||||
@@ -684,6 +690,9 @@ static int client_append_oro(sd_dhcp6_client *client, uint8_t **opt, size_t *opt
|
|||||||
req_opts = client->req_opts;
|
req_opts = client->req_opts;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (n == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
return dhcp6_option_append(opt, optlen, SD_DHCP6_OPTION_ORO, n * sizeof(be16_t), req_opts);
|
return dhcp6_option_append(opt, optlen, SD_DHCP6_OPTION_ORO, n * sizeof(be16_t), req_opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1133,6 +1142,20 @@ static int client_process_reply(
|
|||||||
return log_invalid_message_type(client, message);
|
return log_invalid_message_type(client, message);
|
||||||
|
|
||||||
r = dhcp6_lease_new_from_message(client, message, len, timestamp, server_address, &lease);
|
r = dhcp6_lease_new_from_message(client, message, len, timestamp, server_address, &lease);
|
||||||
|
if (r == -EADDRNOTAVAIL) {
|
||||||
|
|
||||||
|
/* If NoBinding status code is received, we cannot request the address anymore.
|
||||||
|
* Let's restart transaction from the beginning. */
|
||||||
|
|
||||||
|
if (client->state == DHCP6_STATE_REQUEST)
|
||||||
|
/* The lease is not acquired yet, hence it is not necessary to notify the restart. */
|
||||||
|
client_cleanup(client);
|
||||||
|
else
|
||||||
|
/* We need to notify the previous lease was expired. */
|
||||||
|
client_stop(client, SD_DHCP6_CLIENT_EVENT_RESEND_EXPIRE);
|
||||||
|
|
||||||
|
return client_start_transaction(client, DHCP6_STATE_SOLICITATION);
|
||||||
|
}
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_dhcp6_client_errno(client, r, "Failed to process received reply message, ignoring: %m");
|
return log_dhcp6_client_errno(client, r, "Failed to process received reply message, ignoring: %m");
|
||||||
|
|
||||||
|
@@ -512,7 +512,7 @@ static int dhcp6_lease_parse_message(
|
|||||||
return log_dhcp6_client_errno(client, r, "Failed to parse status code: %m");
|
return log_dhcp6_client_errno(client, r, "Failed to parse status code: %m");
|
||||||
|
|
||||||
if (r > 0)
|
if (r > 0)
|
||||||
return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL),
|
return log_dhcp6_client_errno(client, dhcp6_message_status_to_errno(r),
|
||||||
"Received %s message with non-zero status: %s%s%s",
|
"Received %s message with non-zero status: %s%s%s",
|
||||||
dhcp6_message_type_to_string(message->type),
|
dhcp6_message_type_to_string(message->type),
|
||||||
strempty(msg), isempty(msg) ? "" : ": ",
|
strempty(msg), isempty(msg) ? "" : ": ",
|
||||||
|
@@ -192,11 +192,10 @@ static int lldp_rx_handle_datagram(sd_lldp_rx *lldp_rx, sd_lldp_neighbor *n) {
|
|||||||
static int lldp_rx_receive_datagram(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
|
static int lldp_rx_receive_datagram(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
|
||||||
_cleanup_(sd_lldp_neighbor_unrefp) sd_lldp_neighbor *n = NULL;
|
_cleanup_(sd_lldp_neighbor_unrefp) sd_lldp_neighbor *n = NULL;
|
||||||
ssize_t space, length;
|
ssize_t space, length;
|
||||||
sd_lldp_rx *lldp_rx = userdata;
|
sd_lldp_rx *lldp_rx = ASSERT_PTR(userdata);
|
||||||
struct timespec ts;
|
struct timespec ts;
|
||||||
|
|
||||||
assert(fd >= 0);
|
assert(fd >= 0);
|
||||||
assert(lldp_rx);
|
|
||||||
|
|
||||||
space = next_datagram_size_fd(fd);
|
space = next_datagram_size_fd(fd);
|
||||||
if (space < 0) {
|
if (space < 0) {
|
||||||
|
@@ -99,6 +99,7 @@ struct sd_event_source {
|
|||||||
sd_event_signal_handler_t callback;
|
sd_event_signal_handler_t callback;
|
||||||
struct signalfd_siginfo siginfo;
|
struct signalfd_siginfo siginfo;
|
||||||
int sig;
|
int sig;
|
||||||
|
bool unblock;
|
||||||
} signal;
|
} signal;
|
||||||
struct {
|
struct {
|
||||||
sd_event_child_handler_t callback;
|
sd_event_child_handler_t callback;
|
||||||
|
@@ -153,6 +153,8 @@ struct sd_event {
|
|||||||
|
|
||||||
LIST_HEAD(sd_event_source, sources);
|
LIST_HEAD(sd_event_source, sources);
|
||||||
|
|
||||||
|
sd_event_source *sigint_event_source, *sigterm_event_source;
|
||||||
|
|
||||||
usec_t last_run_usec, last_log_usec;
|
usec_t last_run_usec, last_log_usec;
|
||||||
unsigned delays[sizeof(usec_t) * 8];
|
unsigned delays[sizeof(usec_t) * 8];
|
||||||
};
|
};
|
||||||
@@ -323,6 +325,9 @@ static sd_event *event_free(sd_event *e) {
|
|||||||
|
|
||||||
assert(e);
|
assert(e);
|
||||||
|
|
||||||
|
e->sigterm_event_source = sd_event_source_unref(e->sigterm_event_source);
|
||||||
|
e->sigint_event_source = sd_event_source_unref(e->sigint_event_source);
|
||||||
|
|
||||||
while ((s = e->sources)) {
|
while ((s = e->sources)) {
|
||||||
assert(s->floating);
|
assert(s->floating);
|
||||||
source_disconnect(s);
|
source_disconnect(s);
|
||||||
@@ -813,6 +818,7 @@ static void event_source_time_prioq_remove(
|
|||||||
|
|
||||||
static void source_disconnect(sd_event_source *s) {
|
static void source_disconnect(sd_event_source *s) {
|
||||||
sd_event *event;
|
sd_event *event;
|
||||||
|
int r;
|
||||||
|
|
||||||
assert(s);
|
assert(s);
|
||||||
|
|
||||||
@@ -853,6 +859,20 @@ static void source_disconnect(sd_event_source *s) {
|
|||||||
s->event->signal_sources[s->signal.sig] = NULL;
|
s->event->signal_sources[s->signal.sig] = NULL;
|
||||||
|
|
||||||
event_gc_signal_data(s->event, &s->priority, s->signal.sig);
|
event_gc_signal_data(s->event, &s->priority, s->signal.sig);
|
||||||
|
|
||||||
|
if (s->signal.unblock) {
|
||||||
|
sigset_t new_ss;
|
||||||
|
|
||||||
|
if (sigemptyset(&new_ss) < 0)
|
||||||
|
log_debug_errno(errno, "Failed to reset signal set, ignoring: %m");
|
||||||
|
else if (sigaddset(&new_ss, s->signal.sig) < 0)
|
||||||
|
log_debug_errno(errno, "Failed to add signal %i to signal mask, ignoring: %m", s->signal.sig);
|
||||||
|
else {
|
||||||
|
r = pthread_sigmask(SIG_UNBLOCK, &new_ss, NULL);
|
||||||
|
if (r != 0)
|
||||||
|
log_debug_errno(r, "Failed to unblock signal %i, ignoring: %m", s->signal.sig);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@@ -1328,16 +1348,25 @@ _public_ int sd_event_add_signal(
|
|||||||
|
|
||||||
_cleanup_(source_freep) sd_event_source *s = NULL;
|
_cleanup_(source_freep) sd_event_source *s = NULL;
|
||||||
struct signal_data *d;
|
struct signal_data *d;
|
||||||
|
sigset_t new_ss;
|
||||||
|
bool block_it;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert_return(e, -EINVAL);
|
assert_return(e, -EINVAL);
|
||||||
assert_return(e = event_resolve(e), -ENOPKG);
|
assert_return(e = event_resolve(e), -ENOPKG);
|
||||||
assert_return(SIGNAL_VALID(sig), -EINVAL);
|
|
||||||
assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
|
assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
|
||||||
assert_return(!event_pid_changed(e), -ECHILD);
|
assert_return(!event_pid_changed(e), -ECHILD);
|
||||||
|
|
||||||
if (!callback)
|
/* Let's make sure our special flag stays outside of the valid signal range */
|
||||||
callback = signal_exit_callback;
|
assert_cc(_NSIG < SD_EVENT_SIGNAL_PROCMASK);
|
||||||
|
|
||||||
|
if (sig & SD_EVENT_SIGNAL_PROCMASK) {
|
||||||
|
sig &= ~SD_EVENT_SIGNAL_PROCMASK;
|
||||||
|
assert_return(SIGNAL_VALID(sig), -EINVAL);
|
||||||
|
|
||||||
|
block_it = true;
|
||||||
|
} else {
|
||||||
|
assert_return(SIGNAL_VALID(sig), -EINVAL);
|
||||||
|
|
||||||
r = signal_is_blocked(sig);
|
r = signal_is_blocked(sig);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
@@ -1345,6 +1374,12 @@ _public_ int sd_event_add_signal(
|
|||||||
if (r == 0)
|
if (r == 0)
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
|
|
||||||
|
block_it = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!callback)
|
||||||
|
callback = signal_exit_callback;
|
||||||
|
|
||||||
if (!e->signal_sources) {
|
if (!e->signal_sources) {
|
||||||
e->signal_sources = new0(sd_event_source*, _NSIG);
|
e->signal_sources = new0(sd_event_source*, _NSIG);
|
||||||
if (!e->signal_sources)
|
if (!e->signal_sources)
|
||||||
@@ -1363,9 +1398,34 @@ _public_ int sd_event_add_signal(
|
|||||||
|
|
||||||
e->signal_sources[sig] = s;
|
e->signal_sources[sig] = s;
|
||||||
|
|
||||||
r = event_make_signal_data(e, sig, &d);
|
if (block_it) {
|
||||||
|
sigset_t old_ss;
|
||||||
|
|
||||||
|
if (sigemptyset(&new_ss) < 0)
|
||||||
|
return -errno;
|
||||||
|
|
||||||
|
if (sigaddset(&new_ss, sig) < 0)
|
||||||
|
return -errno;
|
||||||
|
|
||||||
|
r = pthread_sigmask(SIG_BLOCK, &new_ss, &old_ss);
|
||||||
|
if (r != 0)
|
||||||
|
return -r;
|
||||||
|
|
||||||
|
r = sigismember(&old_ss, sig);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
|
return -errno;
|
||||||
|
|
||||||
|
s->signal.unblock = !r;
|
||||||
|
} else
|
||||||
|
s->signal.unblock = false;
|
||||||
|
|
||||||
|
r = event_make_signal_data(e, sig, &d);
|
||||||
|
if (r < 0) {
|
||||||
|
if (s->signal.unblock)
|
||||||
|
(void) pthread_sigmask(SIG_UNBLOCK, &new_ss, NULL);
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
/* Use the signal name as description for the event source by default */
|
/* Use the signal name as description for the event source by default */
|
||||||
(void) sd_event_source_set_description(s, signal_to_string(sig));
|
(void) sd_event_source_set_description(s, signal_to_string(sig));
|
||||||
@@ -3823,7 +3883,7 @@ static void event_close_inode_data_fds(sd_event *e) {
|
|||||||
|
|
||||||
/* Close the fds pointing to the inodes to watch now. We need to close them as they might otherwise pin
|
/* Close the fds pointing to the inodes to watch now. We need to close them as they might otherwise pin
|
||||||
* filesystems. But we can't close them right-away as we need them as long as the user still wants to make
|
* filesystems. But we can't close them right-away as we need them as long as the user still wants to make
|
||||||
* adjustments to the even source, such as changing the priority (which requires us to remove and re-add a watch
|
* adjustments to the event source, such as changing the priority (which requires us to remove and re-add a watch
|
||||||
* for the inode). Hence, let's close them when entering the first iteration after they were added, as a
|
* for the inode). Hence, let's close them when entering the first iteration after they were added, as a
|
||||||
* compromise. */
|
* compromise. */
|
||||||
|
|
||||||
@@ -4531,8 +4591,8 @@ _public_ int sd_event_source_set_ratelimit_expire_callback(sd_event_source *s, s
|
|||||||
_public_ int sd_event_source_get_ratelimit(sd_event_source *s, uint64_t *ret_interval, unsigned *ret_burst) {
|
_public_ int sd_event_source_get_ratelimit(sd_event_source *s, uint64_t *ret_interval, unsigned *ret_burst) {
|
||||||
assert_return(s, -EINVAL);
|
assert_return(s, -EINVAL);
|
||||||
|
|
||||||
/* Querying whether an event source has ratelimiting configured is not a loggable offsense, hence
|
/* Querying whether an event source has ratelimiting configured is not a loggable offense, hence
|
||||||
* don't use assert_return(). Unlike turning on ratelimiting it's not really a programming error */
|
* don't use assert_return(). Unlike turning on ratelimiting it's not really a programming error. */
|
||||||
if (!EVENT_SOURCE_CAN_RATE_LIMIT(s->type))
|
if (!EVENT_SOURCE_CAN_RATE_LIMIT(s->type))
|
||||||
return -EDOM;
|
return -EDOM;
|
||||||
|
|
||||||
@@ -4558,3 +4618,55 @@ _public_ int sd_event_source_is_ratelimited(sd_event_source *s) {
|
|||||||
|
|
||||||
return s->ratelimited;
|
return s->ratelimited;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_public_ int sd_event_set_signal_exit(sd_event *e, int b) {
|
||||||
|
bool change = false;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert_return(e, -EINVAL);
|
||||||
|
|
||||||
|
if (b) {
|
||||||
|
/* We want to maintain pointers to these event sources, so that we can destroy them when told
|
||||||
|
* so. But we also don't want them to pin the event loop itself. Hence we mark them as
|
||||||
|
* floating after creation (and undo this before deleting them again). */
|
||||||
|
|
||||||
|
if (!e->sigint_event_source) {
|
||||||
|
r = sd_event_add_signal(e, &e->sigint_event_source, SIGINT | SD_EVENT_SIGNAL_PROCMASK, NULL, NULL);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
assert(sd_event_source_set_floating(e->sigint_event_source, true) >= 0);
|
||||||
|
change = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!e->sigterm_event_source) {
|
||||||
|
r = sd_event_add_signal(e, &e->sigterm_event_source, SIGTERM | SD_EVENT_SIGNAL_PROCMASK, NULL, NULL);
|
||||||
|
if (r < 0) {
|
||||||
|
if (change) {
|
||||||
|
assert(sd_event_source_set_floating(e->sigint_event_source, false) >= 0);
|
||||||
|
e->sigint_event_source = sd_event_source_unref(e->sigint_event_source);
|
||||||
|
}
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(sd_event_source_set_floating(e->sigterm_event_source, true) >= 0);
|
||||||
|
change = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
if (e->sigint_event_source) {
|
||||||
|
assert(sd_event_source_set_floating(e->sigint_event_source, false) >= 0);
|
||||||
|
e->sigint_event_source = sd_event_source_unref(e->sigint_event_source);
|
||||||
|
change = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e->sigterm_event_source) {
|
||||||
|
assert(sd_event_source_set_floating(e->sigterm_event_source, false) >= 0);
|
||||||
|
e->sigterm_event_source = sd_event_source_unref(e->sigterm_event_source);
|
||||||
|
change = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return change;
|
||||||
|
}
|
||||||
|
@@ -68,6 +68,8 @@ enum {
|
|||||||
SD_EVENT_PRIORITY_IDLE = 100
|
SD_EVENT_PRIORITY_IDLE = 100
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define SD_EVENT_SIGNAL_PROCMASK (1 << 30)
|
||||||
|
|
||||||
typedef int (*sd_event_handler_t)(sd_event_source *s, void *userdata);
|
typedef int (*sd_event_handler_t)(sd_event_source *s, void *userdata);
|
||||||
typedef int (*sd_event_io_handler_t)(sd_event_source *s, int fd, uint32_t revents, void *userdata);
|
typedef int (*sd_event_io_handler_t)(sd_event_source *s, int fd, uint32_t revents, void *userdata);
|
||||||
typedef int (*sd_event_time_handler_t)(sd_event_source *s, uint64_t usec, void *userdata);
|
typedef int (*sd_event_time_handler_t)(sd_event_source *s, uint64_t usec, void *userdata);
|
||||||
@@ -114,6 +116,7 @@ int sd_event_get_exit_code(sd_event *e, int *code);
|
|||||||
int sd_event_set_watchdog(sd_event *e, int b);
|
int sd_event_set_watchdog(sd_event *e, int b);
|
||||||
int sd_event_get_watchdog(sd_event *e);
|
int sd_event_get_watchdog(sd_event *e);
|
||||||
int sd_event_get_iteration(sd_event *e, uint64_t *ret);
|
int sd_event_get_iteration(sd_event *e, uint64_t *ret);
|
||||||
|
int sd_event_set_signal_exit(sd_event *e, int b);
|
||||||
|
|
||||||
sd_event_source* sd_event_source_ref(sd_event_source *s);
|
sd_event_source* sd_event_source_ref(sd_event_source *s);
|
||||||
sd_event_source* sd_event_source_unref(sd_event_source *s);
|
sd_event_source* sd_event_source_unref(sd_event_source *s);
|
||||||
|
@@ -86,6 +86,7 @@ bool cpu_accounting_is_cheap(void);
|
|||||||
|
|
||||||
/* Special values for all weight knobs on unified hierarchy */
|
/* Special values for all weight knobs on unified hierarchy */
|
||||||
#define CGROUP_WEIGHT_INVALID UINT64_MAX
|
#define CGROUP_WEIGHT_INVALID UINT64_MAX
|
||||||
|
#define CGROUP_WEIGHT_IDLE UINT64_C(0)
|
||||||
#define CGROUP_WEIGHT_MIN UINT64_C(1)
|
#define CGROUP_WEIGHT_MIN UINT64_C(1)
|
||||||
#define CGROUP_WEIGHT_MAX UINT64_C(10000)
|
#define CGROUP_WEIGHT_MAX UINT64_C(10000)
|
||||||
#define CGROUP_WEIGHT_DEFAULT UINT64_C(100)
|
#define CGROUP_WEIGHT_DEFAULT UINT64_C(100)
|
||||||
|
@@ -443,11 +443,9 @@ static int merge_env_file_push(
|
|||||||
const char *key, char *value,
|
const char *key, char *value,
|
||||||
void *userdata) {
|
void *userdata) {
|
||||||
|
|
||||||
char ***env = userdata;
|
char ***env = ASSERT_PTR(userdata);
|
||||||
char *expanded_value;
|
char *expanded_value;
|
||||||
|
|
||||||
assert(env);
|
|
||||||
|
|
||||||
if (!value) {
|
if (!value) {
|
||||||
log_error("%s:%u: invalid syntax (around \"%s\"), ignoring.", strna(filename), line, key);
|
log_error("%s:%u: invalid syntax (around \"%s\"), ignoring.", strna(filename), line, key);
|
||||||
return 0;
|
return 0;
|
||||||
|
@@ -776,6 +776,18 @@ int getenv_bool_secure(const char *p) {
|
|||||||
return parse_boolean(e);
|
return parse_boolean(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int getenv_uint64_secure(const char *p, uint64_t *ret) {
|
||||||
|
const char *e;
|
||||||
|
|
||||||
|
assert(p);
|
||||||
|
|
||||||
|
e = secure_getenv(p);
|
||||||
|
if (!e)
|
||||||
|
return -ENXIO;
|
||||||
|
|
||||||
|
return safe_atou64(e, ret);
|
||||||
|
}
|
||||||
|
|
||||||
int set_unset_env(const char *name, const char *value, bool overwrite) {
|
int set_unset_env(const char *name, const char *value, bool overwrite) {
|
||||||
assert(name);
|
assert(name);
|
||||||
|
|
||||||
|
@@ -57,6 +57,8 @@ char *strv_env_pairs_get(char **l, const char *name) _pure_;
|
|||||||
int getenv_bool(const char *p);
|
int getenv_bool(const char *p);
|
||||||
int getenv_bool_secure(const char *p);
|
int getenv_bool_secure(const char *p);
|
||||||
|
|
||||||
|
int getenv_uint64_secure(const char *p, uint64_t *ret);
|
||||||
|
|
||||||
/* Like setenv, but calls unsetenv if value == NULL. */
|
/* Like setenv, but calls unsetenv if value == NULL. */
|
||||||
int set_unset_env(const char *name, const char *value, bool overwrite);
|
int set_unset_env(const char *name, const char *value, bool overwrite);
|
||||||
|
|
||||||
|
@@ -654,7 +654,7 @@ int rearrange_stdio(int original_input_fd, int original_output_fd, int original_
|
|||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
|
||||||
CLOSE_AND_REPLACE(null_fd, copy);
|
close_and_replace(null_fd, copy);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -98,7 +98,7 @@ static inline int make_null_stdio(void) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
/* Like free_and_replace(), but for file descriptors */
|
/* Like free_and_replace(), but for file descriptors */
|
||||||
#define CLOSE_AND_REPLACE(a, b) \
|
#define close_and_replace(a, b) \
|
||||||
({ \
|
({ \
|
||||||
int *_fdp_ = &(a); \
|
int *_fdp_ = &(a); \
|
||||||
safe_close(*_fdp_); \
|
safe_close(*_fdp_); \
|
||||||
|
@@ -398,10 +398,6 @@ int touch_file(const char *path, bool parents, usec_t stamp, uid_t uid, gid_t gi
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int touch(const char *path) {
|
|
||||||
return touch_file(path, false, USEC_INFINITY, UID_INVALID, GID_INVALID, MODE_INVALID);
|
|
||||||
}
|
|
||||||
|
|
||||||
int symlink_idempotent(const char *from, const char *to, bool make_relative) {
|
int symlink_idempotent(const char *from, const char *to, bool make_relative) {
|
||||||
_cleanup_free_ char *relpath = NULL;
|
_cleanup_free_ char *relpath = NULL;
|
||||||
int r;
|
int r;
|
||||||
@@ -410,13 +406,7 @@ int symlink_idempotent(const char *from, const char *to, bool make_relative) {
|
|||||||
assert(to);
|
assert(to);
|
||||||
|
|
||||||
if (make_relative) {
|
if (make_relative) {
|
||||||
_cleanup_free_ char *parent = NULL;
|
r = path_make_relative_parent(to, from, &relpath);
|
||||||
|
|
||||||
r = path_extract_directory(to, &parent);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
r = path_make_relative(parent, from, &relpath);
|
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
@@ -442,29 +432,38 @@ int symlink_idempotent(const char *from, const char *to, bool make_relative) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int symlink_atomic(const char *from, const char *to) {
|
int symlinkat_atomic_full(const char *from, int atfd, const char *to, bool make_relative) {
|
||||||
_cleanup_free_ char *t = NULL;
|
_cleanup_free_ char *relpath = NULL, *t = NULL;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(from);
|
assert(from);
|
||||||
assert(to);
|
assert(to);
|
||||||
|
|
||||||
|
if (make_relative) {
|
||||||
|
r = path_make_relative_parent(to, from, &relpath);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
from = relpath;
|
||||||
|
}
|
||||||
|
|
||||||
r = tempfn_random(to, NULL, &t);
|
r = tempfn_random(to, NULL, &t);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
if (symlink(from, t) < 0)
|
if (symlinkat(from, atfd, t) < 0)
|
||||||
return -errno;
|
return -errno;
|
||||||
|
|
||||||
if (rename(t, to) < 0) {
|
r = RET_NERRNO(renameat(atfd, t, atfd, to));
|
||||||
unlink_noerrno(t);
|
if (r < 0) {
|
||||||
return -errno;
|
(void) unlinkat(atfd, t, 0);
|
||||||
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int mknod_atomic(const char *path, mode_t mode, dev_t dev) {
|
int mknodat_atomic(int atfd, const char *path, mode_t mode, dev_t dev) {
|
||||||
_cleanup_free_ char *t = NULL;
|
_cleanup_free_ char *t = NULL;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
@@ -474,58 +473,36 @@ int mknod_atomic(const char *path, mode_t mode, dev_t dev) {
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
if (mknod(t, mode, dev) < 0)
|
if (mknodat(atfd, t, mode, dev) < 0)
|
||||||
return -errno;
|
return -errno;
|
||||||
|
|
||||||
if (rename(t, path) < 0) {
|
r = RET_NERRNO(renameat(atfd, t, atfd, path));
|
||||||
unlink_noerrno(t);
|
if (r < 0) {
|
||||||
return -errno;
|
(void) unlinkat(atfd, t, 0);
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int mkfifo_atomic(const char *path, mode_t mode) {
|
|
||||||
_cleanup_free_ char *t = NULL;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
assert(path);
|
|
||||||
|
|
||||||
r = tempfn_random(path, NULL, &t);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
if (mkfifo(t, mode) < 0)
|
|
||||||
return -errno;
|
|
||||||
|
|
||||||
if (rename(t, path) < 0) {
|
|
||||||
unlink_noerrno(t);
|
|
||||||
return -errno;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int mkfifoat_atomic(int dirfd, const char *path, mode_t mode) {
|
int mkfifoat_atomic(int atfd, const char *path, mode_t mode) {
|
||||||
_cleanup_free_ char *t = NULL;
|
_cleanup_free_ char *t = NULL;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(path);
|
assert(path);
|
||||||
|
|
||||||
if (path_is_absolute(path))
|
|
||||||
return mkfifo_atomic(path, mode);
|
|
||||||
|
|
||||||
/* We're only interested in the (random) filename. */
|
/* We're only interested in the (random) filename. */
|
||||||
r = tempfn_random_child("", NULL, &t);
|
r = tempfn_random(path, NULL, &t);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
if (mkfifoat(dirfd, t, mode) < 0)
|
if (mkfifoat(atfd, t, mode) < 0)
|
||||||
return -errno;
|
return -errno;
|
||||||
|
|
||||||
if (renameat(dirfd, t, dirfd, path) < 0) {
|
r = RET_NERRNO(renameat(atfd, t, atfd, path));
|
||||||
unlink_noerrno(t);
|
if (r < 0) {
|
||||||
return -errno;
|
(void) unlinkat(atfd, t, 0);
|
||||||
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@@ -13,6 +13,7 @@
|
|||||||
#include "alloc-util.h"
|
#include "alloc-util.h"
|
||||||
#include "errno-util.h"
|
#include "errno-util.h"
|
||||||
#include "time-util.h"
|
#include "time-util.h"
|
||||||
|
#include "user-util.h"
|
||||||
|
|
||||||
#define MODE_INVALID ((mode_t) -1)
|
#define MODE_INVALID ((mode_t) -1)
|
||||||
|
|
||||||
@@ -50,14 +51,27 @@ int stat_warn_permissions(const char *path, const struct stat *st);
|
|||||||
RET_NERRNO(faccessat(AT_FDCWD, (path), (mode), AT_SYMLINK_NOFOLLOW))
|
RET_NERRNO(faccessat(AT_FDCWD, (path), (mode), AT_SYMLINK_NOFOLLOW))
|
||||||
|
|
||||||
int touch_file(const char *path, bool parents, usec_t stamp, uid_t uid, gid_t gid, mode_t mode);
|
int touch_file(const char *path, bool parents, usec_t stamp, uid_t uid, gid_t gid, mode_t mode);
|
||||||
int touch(const char *path);
|
|
||||||
|
static inline int touch(const char *path) {
|
||||||
|
return touch_file(path, false, USEC_INFINITY, UID_INVALID, GID_INVALID, MODE_INVALID);
|
||||||
|
}
|
||||||
|
|
||||||
int symlink_idempotent(const char *from, const char *to, bool make_relative);
|
int symlink_idempotent(const char *from, const char *to, bool make_relative);
|
||||||
|
|
||||||
int symlink_atomic(const char *from, const char *to);
|
int symlinkat_atomic_full(const char *from, int atfd, const char *to, bool make_relative);
|
||||||
int mknod_atomic(const char *path, mode_t mode, dev_t dev);
|
static inline int symlink_atomic(const char *from, const char *to) {
|
||||||
int mkfifo_atomic(const char *path, mode_t mode);
|
return symlinkat_atomic_full(from, AT_FDCWD, to, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
int mknodat_atomic(int atfd, const char *path, mode_t mode, dev_t dev);
|
||||||
|
static inline int mknod_atomic(const char *path, mode_t mode, dev_t dev) {
|
||||||
|
return mknodat_atomic(AT_FDCWD, path, mode, dev);
|
||||||
|
}
|
||||||
|
|
||||||
int mkfifoat_atomic(int dir_fd, const char *path, mode_t mode);
|
int mkfifoat_atomic(int dir_fd, const char *path, mode_t mode);
|
||||||
|
static inline int mkfifo_atomic(const char *path, mode_t mode) {
|
||||||
|
return mkfifoat_atomic(AT_FDCWD, path, mode);
|
||||||
|
}
|
||||||
|
|
||||||
int get_files_in_directory(const char *path, char ***list);
|
int get_files_in_directory(const char *path, char ***list);
|
||||||
|
|
||||||
|
@@ -53,6 +53,7 @@ const char *special_glyph(SpecialGlyph code) {
|
|||||||
[SPECIAL_GLYPH_LIGHT_SHADE] = "-",
|
[SPECIAL_GLYPH_LIGHT_SHADE] = "-",
|
||||||
[SPECIAL_GLYPH_DARK_SHADE] = "X",
|
[SPECIAL_GLYPH_DARK_SHADE] = "X",
|
||||||
[SPECIAL_GLYPH_SIGMA] = "S",
|
[SPECIAL_GLYPH_SIGMA] = "S",
|
||||||
|
[SPECIAL_GLYPH_ARROW_LEFT] = "<-",
|
||||||
[SPECIAL_GLYPH_ARROW_RIGHT] = "->",
|
[SPECIAL_GLYPH_ARROW_RIGHT] = "->",
|
||||||
[SPECIAL_GLYPH_ARROW_UP] = "^",
|
[SPECIAL_GLYPH_ARROW_UP] = "^",
|
||||||
[SPECIAL_GLYPH_ARROW_DOWN] = "v",
|
[SPECIAL_GLYPH_ARROW_DOWN] = "v",
|
||||||
@@ -99,6 +100,7 @@ const char *special_glyph(SpecialGlyph code) {
|
|||||||
[SPECIAL_GLYPH_ARROW_DOWN] = u8"↓", /* actually called: DOWNWARDS ARROW */
|
[SPECIAL_GLYPH_ARROW_DOWN] = u8"↓", /* actually called: DOWNWARDS ARROW */
|
||||||
|
|
||||||
/* Single glyph in Unicode, two in ASCII */
|
/* Single glyph in Unicode, two in ASCII */
|
||||||
|
[SPECIAL_GLYPH_ARROW_LEFT] = u8"←", /* actually called: LEFTWARDS ARROW */
|
||||||
[SPECIAL_GLYPH_ARROW_RIGHT] = u8"→", /* actually called: RIGHTWARDS ARROW */
|
[SPECIAL_GLYPH_ARROW_RIGHT] = u8"→", /* actually called: RIGHTWARDS ARROW */
|
||||||
|
|
||||||
/* Single glyph in Unicode, three in ASCII */
|
/* Single glyph in Unicode, three in ASCII */
|
||||||
|
@@ -22,6 +22,7 @@ typedef enum SpecialGlyph {
|
|||||||
SPECIAL_GLYPH_MU,
|
SPECIAL_GLYPH_MU,
|
||||||
SPECIAL_GLYPH_CHECK_MARK,
|
SPECIAL_GLYPH_CHECK_MARK,
|
||||||
SPECIAL_GLYPH_CROSS_MARK,
|
SPECIAL_GLYPH_CROSS_MARK,
|
||||||
|
SPECIAL_GLYPH_ARROW_LEFT,
|
||||||
SPECIAL_GLYPH_ARROW_RIGHT,
|
SPECIAL_GLYPH_ARROW_RIGHT,
|
||||||
SPECIAL_GLYPH_ARROW_UP,
|
SPECIAL_GLYPH_ARROW_UP,
|
||||||
SPECIAL_GLYPH_ARROW_DOWN,
|
SPECIAL_GLYPH_ARROW_DOWN,
|
||||||
|
@@ -1190,7 +1190,7 @@ static int resize_buckets(HashmapBase *h, unsigned entries_add) {
|
|||||||
} while (rehash_next);
|
} while (rehash_next);
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(n_rehashed == n_entries(h));
|
assert_se(n_rehashed == n_entries(h));
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -1882,11 +1882,10 @@ int _set_put_strdupv_full(Set **s, const struct hash_ops *hash_ops, char **l HA
|
|||||||
}
|
}
|
||||||
|
|
||||||
int set_put_strsplit(Set *s, const char *v, const char *separators, ExtractFlags flags) {
|
int set_put_strsplit(Set *s, const char *v, const char *separators, ExtractFlags flags) {
|
||||||
const char *p = v;
|
const char *p = ASSERT_PTR(v);
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(s);
|
assert(s);
|
||||||
assert(v);
|
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
char *word;
|
char *word;
|
||||||
@@ -2079,6 +2078,8 @@ static bool set_fnmatch_one(Set *patterns, const char *needle) {
|
|||||||
|
|
||||||
assert(needle);
|
assert(needle);
|
||||||
|
|
||||||
|
/* Any failure of fnmatch() is treated as equivalent to FNM_NOMATCH, i.e. as non-matching pattern */
|
||||||
|
|
||||||
SET_FOREACH(p, patterns)
|
SET_FOREACH(p, patterns)
|
||||||
if (fnmatch(p, needle, 0) == 0)
|
if (fnmatch(p, needle, 0) == 0)
|
||||||
return true;
|
return true;
|
||||||
|
@@ -586,6 +586,7 @@ unsigned char in4_addr_netmask_to_prefixlen(const struct in_addr *addr) {
|
|||||||
return 32U - u32ctz(be32toh(addr->s_addr));
|
return 32U - u32ctz(be32toh(addr->s_addr));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Calculate an IPv4 netmask from prefix length, for example /8 -> 255.0.0.0. */
|
||||||
struct in_addr* in4_addr_prefixlen_to_netmask(struct in_addr *addr, unsigned char prefixlen) {
|
struct in_addr* in4_addr_prefixlen_to_netmask(struct in_addr *addr, unsigned char prefixlen) {
|
||||||
assert(addr);
|
assert(addr);
|
||||||
assert(prefixlen <= 32);
|
assert(prefixlen <= 32);
|
||||||
@@ -599,6 +600,47 @@ struct in_addr* in4_addr_prefixlen_to_netmask(struct in_addr *addr, unsigned cha
|
|||||||
return addr;
|
return addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Calculate an IPv6 netmask from prefix length, for example /16 -> ffff::. */
|
||||||
|
struct in6_addr* in6_addr_prefixlen_to_netmask(struct in6_addr *addr, unsigned char prefixlen) {
|
||||||
|
assert(addr);
|
||||||
|
assert(prefixlen <= 128);
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < 16; i++) {
|
||||||
|
uint8_t mask;
|
||||||
|
|
||||||
|
if (prefixlen >= 8) {
|
||||||
|
mask = 0xFF;
|
||||||
|
prefixlen -= 8;
|
||||||
|
} else if (prefixlen > 0) {
|
||||||
|
mask = 0xFF << (8 - prefixlen);
|
||||||
|
prefixlen = 0;
|
||||||
|
} else {
|
||||||
|
assert(prefixlen == 0);
|
||||||
|
mask = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
addr->s6_addr[i] = mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Calculate an IPv4 or IPv6 netmask from prefix length, for example /8 -> 255.0.0.0 or /16 -> ffff::. */
|
||||||
|
int in_addr_prefixlen_to_netmask(int family, union in_addr_union *addr, unsigned char prefixlen) {
|
||||||
|
assert(addr);
|
||||||
|
|
||||||
|
switch (family) {
|
||||||
|
case AF_INET:
|
||||||
|
in4_addr_prefixlen_to_netmask(&addr->in, prefixlen);
|
||||||
|
return 0;
|
||||||
|
case AF_INET6:
|
||||||
|
in6_addr_prefixlen_to_netmask(&addr->in6, prefixlen);
|
||||||
|
return 0;
|
||||||
|
default:
|
||||||
|
return -EAFNOSUPPORT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int in4_addr_default_prefixlen(const struct in_addr *addr, unsigned char *prefixlen) {
|
int in4_addr_default_prefixlen(const struct in_addr *addr, unsigned char *prefixlen) {
|
||||||
uint8_t msb_octet = *(uint8_t*) addr;
|
uint8_t msb_octet = *(uint8_t*) addr;
|
||||||
|
|
||||||
|
@@ -138,6 +138,8 @@ int in_addr_from_string_auto(const char *s, int *ret_family, union in_addr_union
|
|||||||
|
|
||||||
unsigned char in4_addr_netmask_to_prefixlen(const struct in_addr *addr);
|
unsigned char in4_addr_netmask_to_prefixlen(const struct in_addr *addr);
|
||||||
struct in_addr* in4_addr_prefixlen_to_netmask(struct in_addr *addr, unsigned char prefixlen);
|
struct in_addr* in4_addr_prefixlen_to_netmask(struct in_addr *addr, unsigned char prefixlen);
|
||||||
|
struct in6_addr* in6_addr_prefixlen_to_netmask(struct in6_addr *addr, unsigned char prefixlen);
|
||||||
|
int in_addr_prefixlen_to_netmask(int family, union in_addr_union *addr, unsigned char prefixlen);
|
||||||
int in4_addr_default_prefixlen(const struct in_addr *addr, unsigned char *prefixlen);
|
int in4_addr_default_prefixlen(const struct in_addr *addr, unsigned char *prefixlen);
|
||||||
int in4_addr_default_subnet_mask(const struct in_addr *addr, struct in_addr *mask);
|
int in4_addr_default_subnet_mask(const struct in_addr *addr, struct in_addr *mask);
|
||||||
int in4_addr_mask(struct in_addr *addr, unsigned char prefixlen);
|
int in4_addr_mask(struct in_addr *addr, unsigned char prefixlen);
|
||||||
|
@@ -49,11 +49,10 @@ int flush_fd(int fd) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll) {
|
ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll) {
|
||||||
uint8_t *p = buf;
|
uint8_t *p = ASSERT_PTR(buf);
|
||||||
ssize_t n = 0;
|
ssize_t n = 0;
|
||||||
|
|
||||||
assert(fd >= 0);
|
assert(fd >= 0);
|
||||||
assert(buf);
|
|
||||||
|
|
||||||
/* If called with nbytes == 0, let's call read() at least
|
/* If called with nbytes == 0, let's call read() at least
|
||||||
* once, to validate the operation */
|
* once, to validate the operation */
|
||||||
@@ -108,10 +107,9 @@ int loop_read_exact(int fd, void *buf, size_t nbytes, bool do_poll) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int loop_write(int fd, const void *buf, size_t nbytes, bool do_poll) {
|
int loop_write(int fd, const void *buf, size_t nbytes, bool do_poll) {
|
||||||
const uint8_t *p = buf;
|
const uint8_t *p = ASSERT_PTR(buf);
|
||||||
|
|
||||||
assert(fd >= 0);
|
assert(fd >= 0);
|
||||||
assert(buf);
|
|
||||||
|
|
||||||
if (_unlikely_(nbytes > (size_t) SSIZE_MAX))
|
if (_unlikely_(nbytes > (size_t) SSIZE_MAX))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@@ -8,6 +8,7 @@
|
|||||||
#include <syslog.h>
|
#include <syslog.h>
|
||||||
|
|
||||||
#include "macro.h"
|
#include "macro.h"
|
||||||
|
#include "ratelimit.h"
|
||||||
|
|
||||||
/* Some structures we reference but don't want to pull in headers for */
|
/* Some structures we reference but don't want to pull in headers for */
|
||||||
struct iovec;
|
struct iovec;
|
||||||
@@ -367,3 +368,41 @@ int log_syntax_invalid_utf8_internal(
|
|||||||
#define DEBUG_LOGGING _unlikely_(log_get_max_level() >= LOG_DEBUG)
|
#define DEBUG_LOGGING _unlikely_(log_get_max_level() >= LOG_DEBUG)
|
||||||
|
|
||||||
void log_setup(void);
|
void log_setup(void);
|
||||||
|
|
||||||
|
typedef struct LogRateLimit {
|
||||||
|
int error;
|
||||||
|
int level;
|
||||||
|
RateLimit ratelimit;
|
||||||
|
} LogRateLimit;
|
||||||
|
|
||||||
|
#define log_ratelimit_internal(_level, _error, _format, _file, _line, _func, ...) \
|
||||||
|
({ \
|
||||||
|
int _log_ratelimit_error = (_error); \
|
||||||
|
int _log_ratelimit_level = (_level); \
|
||||||
|
static LogRateLimit _log_ratelimit = { \
|
||||||
|
.ratelimit = { \
|
||||||
|
.interval = 1 * USEC_PER_SEC, \
|
||||||
|
.burst = 1, \
|
||||||
|
}, \
|
||||||
|
}; \
|
||||||
|
unsigned _num_dropped_errors = ratelimit_num_dropped(&_log_ratelimit.ratelimit); \
|
||||||
|
if (_log_ratelimit_error != _log_ratelimit.error || _log_ratelimit_level != _log_ratelimit.level) { \
|
||||||
|
ratelimit_reset(&_log_ratelimit.ratelimit); \
|
||||||
|
_log_ratelimit.error = _log_ratelimit_error; \
|
||||||
|
_log_ratelimit.level = _log_ratelimit_level; \
|
||||||
|
} \
|
||||||
|
if (ratelimit_below(&_log_ratelimit.ratelimit)) \
|
||||||
|
_log_ratelimit_error = _num_dropped_errors > 0 \
|
||||||
|
? log_internal(_log_ratelimit_level, _log_ratelimit_error, _file, _line, _func, _format " (Dropped %u similar message(s))", __VA_ARGS__, _num_dropped_errors) \
|
||||||
|
: log_internal(_log_ratelimit_level, _log_ratelimit_error, _file, _line, _func, _format, __VA_ARGS__); \
|
||||||
|
_log_ratelimit_error; \
|
||||||
|
})
|
||||||
|
|
||||||
|
#define log_ratelimit_full_errno(level, error, format, ...) \
|
||||||
|
({ \
|
||||||
|
int _level = (level), _e = (error); \
|
||||||
|
_e = (log_get_max_level() >= LOG_PRI(_level)) \
|
||||||
|
? log_ratelimit_internal(_level, _e, format, PROJECT_FILE, __LINE__, __func__, __VA_ARGS__) \
|
||||||
|
: -ERRNO_VALUE(_e); \
|
||||||
|
_e < 0 ? _e : -ESTRPIPE; \
|
||||||
|
})
|
||||||
|
@@ -476,69 +476,31 @@ int safe_atolli(const char *s, long long int *ret_lli) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int safe_atou8(const char *s, uint8_t *ret) {
|
int safe_atou8_full(const char *s, unsigned base, uint8_t *ret) {
|
||||||
unsigned base = 0;
|
unsigned u;
|
||||||
unsigned long l;
|
int r;
|
||||||
char *x = NULL;
|
|
||||||
|
|
||||||
assert(s);
|
r = safe_atou_full(s, base, &u);
|
||||||
|
if (r < 0)
|
||||||
s += strspn(s, WHITESPACE);
|
return r;
|
||||||
s = mangle_base(s, &base);
|
if (u > UINT8_MAX)
|
||||||
|
|
||||||
errno = 0;
|
|
||||||
l = strtoul(s, &x, base);
|
|
||||||
if (errno > 0)
|
|
||||||
return -errno;
|
|
||||||
if (!x || x == s || *x != 0)
|
|
||||||
return -EINVAL;
|
|
||||||
if (l != 0 && s[0] == '-')
|
|
||||||
return -ERANGE;
|
|
||||||
if ((unsigned long) (uint8_t) l != l)
|
|
||||||
return -ERANGE;
|
return -ERANGE;
|
||||||
|
|
||||||
if (ret)
|
*ret = (uint8_t) u;
|
||||||
*ret = (uint8_t) l;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int safe_atou16_full(const char *s, unsigned base, uint16_t *ret) {
|
int safe_atou16_full(const char *s, unsigned base, uint16_t *ret) {
|
||||||
char *x = NULL;
|
unsigned u;
|
||||||
unsigned long l;
|
int r;
|
||||||
|
|
||||||
assert(s);
|
r = safe_atou_full(s, base, &u);
|
||||||
assert(SAFE_ATO_MASK_FLAGS(base) <= 16);
|
if (r < 0)
|
||||||
|
return r;
|
||||||
if (FLAGS_SET(base, SAFE_ATO_REFUSE_LEADING_WHITESPACE) &&
|
if (u > UINT16_MAX)
|
||||||
strchr(WHITESPACE, s[0]))
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
s += strspn(s, WHITESPACE);
|
|
||||||
|
|
||||||
if (FLAGS_SET(base, SAFE_ATO_REFUSE_PLUS_MINUS) &&
|
|
||||||
IN_SET(s[0], '+', '-'))
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
if (FLAGS_SET(base, SAFE_ATO_REFUSE_LEADING_ZERO) &&
|
|
||||||
s[0] == '0' && s[1] != 0)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
s = mangle_base(s, &base);
|
|
||||||
|
|
||||||
errno = 0;
|
|
||||||
l = strtoul(s, &x, SAFE_ATO_MASK_FLAGS(base));
|
|
||||||
if (errno > 0)
|
|
||||||
return -errno;
|
|
||||||
if (!x || x == s || *x != 0)
|
|
||||||
return -EINVAL;
|
|
||||||
if (l != 0 && s[0] == '-')
|
|
||||||
return -ERANGE;
|
|
||||||
if ((unsigned long) (uint16_t) l != l)
|
|
||||||
return -ERANGE;
|
return -ERANGE;
|
||||||
|
|
||||||
if (ret)
|
*ret = (uint16_t) u;
|
||||||
*ret = (uint16_t) l;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -36,7 +36,11 @@ static inline int safe_atou(const char *s, unsigned *ret_u) {
|
|||||||
int safe_atoi(const char *s, int *ret_i);
|
int safe_atoi(const char *s, int *ret_i);
|
||||||
int safe_atolli(const char *s, long long int *ret_i);
|
int safe_atolli(const char *s, long long int *ret_i);
|
||||||
|
|
||||||
int safe_atou8(const char *s, uint8_t *ret);
|
int safe_atou8_full(const char *s, unsigned base, uint8_t *ret);
|
||||||
|
|
||||||
|
static inline int safe_atou8(const char *s, uint8_t *ret) {
|
||||||
|
return safe_atou8_full(s, 0, ret);
|
||||||
|
}
|
||||||
|
|
||||||
int safe_atou16_full(const char *s, unsigned base, uint16_t *ret);
|
int safe_atou16_full(const char *s, unsigned base, uint16_t *ret);
|
||||||
|
|
||||||
|
@@ -1,22 +1,18 @@
|
|||||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <fnmatch.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
/* When we include libgen.h because we need dirname() we immediately
|
|
||||||
* undefine basename() since libgen.h defines it as a macro to the
|
|
||||||
* POSIX version which is really broken. We prefer GNU basename(). */
|
|
||||||
#include <libgen.h>
|
|
||||||
#undef basename
|
|
||||||
|
|
||||||
#include "alloc-util.h"
|
#include "alloc-util.h"
|
||||||
#include "chase-symlinks.h"
|
#include "chase-symlinks.h"
|
||||||
#include "extract-word.h"
|
#include "extract-word.h"
|
||||||
#include "fd-util.h"
|
#include "fd-util.h"
|
||||||
#include "fs-util.h"
|
#include "fs-util.h"
|
||||||
|
#include "glob-util.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "macro.h"
|
#include "macro.h"
|
||||||
#include "path-util.h"
|
#include "path-util.h"
|
||||||
@@ -197,6 +193,34 @@ int path_make_relative(const char *from, const char *to, char **ret) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int path_make_relative_parent(const char *from_child, const char *to, char **ret) {
|
||||||
|
_cleanup_free_ char *from = NULL;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(from_child);
|
||||||
|
assert(to);
|
||||||
|
assert(ret);
|
||||||
|
|
||||||
|
/* Similar to path_make_relative(), but provides the relative path from the parent directory of
|
||||||
|
* 'from_child'. This may be useful when creating relative symlink.
|
||||||
|
*
|
||||||
|
* E.g.
|
||||||
|
* - from = "/path/to/aaa", to = "/path/to/bbb"
|
||||||
|
* path_make_relative(from, to) = "../bbb"
|
||||||
|
* path_make_relative_parent(from, to) = "bbb"
|
||||||
|
*
|
||||||
|
* - from = "/path/to/aaa/bbb", to = "/path/to/ccc/ddd"
|
||||||
|
* path_make_relative(from, to) = "../../ccc/ddd"
|
||||||
|
* path_make_relative_parent(from, to) = "../ccc/ddd"
|
||||||
|
*/
|
||||||
|
|
||||||
|
r = path_extract_directory(from_child, &from);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
return path_make_relative(from, to, ret);
|
||||||
|
}
|
||||||
|
|
||||||
char* path_startswith_strv(const char *p, char **set) {
|
char* path_startswith_strv(const char *p, char **set) {
|
||||||
STRV_FOREACH(s, set) {
|
STRV_FOREACH(s, set) {
|
||||||
char *t;
|
char *t;
|
||||||
@@ -324,11 +348,9 @@ char **path_strv_resolve_uniq(char **l, const char *root) {
|
|||||||
|
|
||||||
char *path_simplify(char *path) {
|
char *path_simplify(char *path) {
|
||||||
bool add_slash = false;
|
bool add_slash = false;
|
||||||
char *f = path;
|
char *f = ASSERT_PTR(path);
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(path);
|
|
||||||
|
|
||||||
/* Removes redundant inner and trailing slashes. Also removes unnecessary dots.
|
/* Removes redundant inner and trailing slashes. Also removes unnecessary dots.
|
||||||
* Modifies the passed string in-place.
|
* Modifies the passed string in-place.
|
||||||
*
|
*
|
||||||
@@ -760,39 +782,27 @@ static int executable_is_good(const char *executable) {
|
|||||||
"/dev/null");
|
"/dev/null");
|
||||||
}
|
}
|
||||||
|
|
||||||
int fsck_exists(const char *fstype) {
|
int fsck_exists(void) {
|
||||||
|
return executable_is_good("fsck");
|
||||||
|
}
|
||||||
|
|
||||||
|
int fsck_exists_for_fstype(const char *fstype) {
|
||||||
const char *checker;
|
const char *checker;
|
||||||
|
int r;
|
||||||
|
|
||||||
assert(fstype);
|
assert(fstype);
|
||||||
|
|
||||||
if (streq(fstype, "auto"))
|
if (streq(fstype, "auto"))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
r = fsck_exists();
|
||||||
|
if (r <= 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
checker = strjoina("fsck.", fstype);
|
checker = strjoina("fsck.", fstype);
|
||||||
return executable_is_good(checker);
|
return executable_is_good(checker);
|
||||||
}
|
}
|
||||||
|
|
||||||
char* dirname_malloc(const char *path) {
|
|
||||||
char *d, *dir, *dir2;
|
|
||||||
|
|
||||||
assert(path);
|
|
||||||
|
|
||||||
d = strdup(path);
|
|
||||||
if (!d)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
dir = dirname(d);
|
|
||||||
assert(dir);
|
|
||||||
|
|
||||||
if (dir == d)
|
|
||||||
return d;
|
|
||||||
|
|
||||||
dir2 = strdup(dir);
|
|
||||||
free(d);
|
|
||||||
|
|
||||||
return dir2;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char *skip_slash_or_dot(const char *p) {
|
static const char *skip_slash_or_dot(const char *p) {
|
||||||
for (; !isempty(p); p++) {
|
for (; !isempty(p); p++) {
|
||||||
if (*p == '/')
|
if (*p == '/')
|
||||||
@@ -1310,3 +1320,66 @@ bool prefixed_path_strv_contains(char **l, const char *path) {
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int path_glob_can_match(const char *pattern, const char *prefix, char **ret) {
|
||||||
|
assert(pattern);
|
||||||
|
assert(prefix);
|
||||||
|
|
||||||
|
for (const char *a = pattern, *b = prefix;;) {
|
||||||
|
_cleanup_free_ char *g = NULL, *h = NULL;
|
||||||
|
const char *p, *q;
|
||||||
|
int r, s;
|
||||||
|
|
||||||
|
r = path_find_first_component(&a, /* accept_dot_dot = */ false, &p);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
s = path_find_first_component(&b, /* accept_dot_dot = */ false, &q);
|
||||||
|
if (s < 0)
|
||||||
|
return s;
|
||||||
|
|
||||||
|
if (s == 0) {
|
||||||
|
/* The pattern matches the prefix. */
|
||||||
|
if (ret) {
|
||||||
|
char *t;
|
||||||
|
|
||||||
|
t = path_join(prefix, p);
|
||||||
|
if (!t)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
*ret = t;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (r == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (r == s && strneq(p, q, r))
|
||||||
|
continue; /* common component. Check next. */
|
||||||
|
|
||||||
|
g = strndup(p, r);
|
||||||
|
if (!g)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
if (!string_is_glob(g))
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* We found a glob component. Check if the glob pattern matches the prefix component. */
|
||||||
|
|
||||||
|
h = strndup(q, s);
|
||||||
|
if (!h)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
r = fnmatch(g, h, 0);
|
||||||
|
if (r == FNM_NOMATCH)
|
||||||
|
break;
|
||||||
|
if (r != 0) /* Failure to process pattern? */
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The pattern does not match the prefix. */
|
||||||
|
if (ret)
|
||||||
|
*ret = NULL;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
@@ -61,6 +61,7 @@ char* path_make_absolute(const char *p, const char *prefix);
|
|||||||
int safe_getcwd(char **ret);
|
int safe_getcwd(char **ret);
|
||||||
int path_make_absolute_cwd(const char *p, char **ret);
|
int path_make_absolute_cwd(const char *p, char **ret);
|
||||||
int path_make_relative(const char *from, const char *to, char **ret);
|
int path_make_relative(const char *from, const char *to, char **ret);
|
||||||
|
int path_make_relative_parent(const char *from_child, const char *to, char **ret);
|
||||||
char *path_startswith_full(const char *path, const char *prefix, bool accept_dot_dot) _pure_;
|
char *path_startswith_full(const char *path, const char *prefix, bool accept_dot_dot) _pure_;
|
||||||
static inline char* path_startswith(const char *path, const char *prefix) {
|
static inline char* path_startswith(const char *path, const char *prefix) {
|
||||||
return path_startswith_full(path, prefix, true);
|
return path_startswith_full(path, prefix, true);
|
||||||
@@ -102,7 +103,8 @@ static inline int find_executable(const char *name, char **ret_filename) {
|
|||||||
|
|
||||||
bool paths_check_timestamp(const char* const* paths, usec_t *paths_ts_usec, bool update);
|
bool paths_check_timestamp(const char* const* paths, usec_t *paths_ts_usec, bool update);
|
||||||
|
|
||||||
int fsck_exists(const char *fstype);
|
int fsck_exists(void);
|
||||||
|
int fsck_exists_for_fstype(const char *fstype);
|
||||||
|
|
||||||
/* Iterates through the path prefixes of the specified path, going up
|
/* Iterates through the path prefixes of the specified path, going up
|
||||||
* the tree, to root. Also returns "" (and not "/"!) for the root
|
* the tree, to root. Also returns "" (and not "/"!) for the root
|
||||||
@@ -151,7 +153,6 @@ int fsck_exists(const char *fstype);
|
|||||||
_ret; \
|
_ret; \
|
||||||
})
|
})
|
||||||
|
|
||||||
char* dirname_malloc(const char *path);
|
|
||||||
int path_find_first_component(const char **p, bool accept_dot_dot, const char **ret);
|
int path_find_first_component(const char **p, bool accept_dot_dot, const char **ret);
|
||||||
int path_find_last_component(const char *path, bool accept_dot_dot, const char **next, const char **ret);
|
int path_find_last_component(const char *path, bool accept_dot_dot, const char **next, const char **ret);
|
||||||
const char *last_path_component(const char *path);
|
const char *last_path_component(const char *path);
|
||||||
@@ -196,3 +197,5 @@ static inline const char *empty_to_root(const char *path) {
|
|||||||
|
|
||||||
bool path_strv_contains(char **l, const char *path);
|
bool path_strv_contains(char **l, const char *path);
|
||||||
bool prefixed_path_strv_contains(char **l, const char *path);
|
bool prefixed_path_strv_contains(char **l, const char *path);
|
||||||
|
|
||||||
|
int path_glob_can_match(const char *pattern, const char *prefix, char **ret);
|
||||||
|
@@ -1,9 +1,5 @@
|
|||||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||||
|
|
||||||
#if defined(__i386__) || defined(__x86_64__)
|
|
||||||
#include <cpuid.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <elf.h>
|
#include <elf.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
@@ -33,11 +29,10 @@
|
|||||||
#include "sha256.h"
|
#include "sha256.h"
|
||||||
#include "time-util.h"
|
#include "time-util.h"
|
||||||
|
|
||||||
/* This is a "best effort" kind of thing, but has no real security value.
|
/* This is a "best effort" kind of thing, but has no real security value. So, this should only be used by
|
||||||
* So, this should only be used by random_bytes(), which is not meant for
|
* random_bytes(), which is not meant for crypto. This could be made better, but we're *not* trying to roll a
|
||||||
* 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
|
||||||
* userspace prng here, or even have forward secrecy, but rather just do
|
* better than libc rand(). */
|
||||||
* the shortest thing that is at least better than libc rand(). */
|
|
||||||
static void fallback_random_bytes(void *p, size_t n) {
|
static void fallback_random_bytes(void *p, size_t n) {
|
||||||
static thread_local uint64_t fallback_counter = 0;
|
static thread_local uint64_t fallback_counter = 0;
|
||||||
struct {
|
struct {
|
||||||
@@ -53,7 +48,7 @@ static void fallback_random_bytes(void *p, size_t n) {
|
|||||||
.stamp_mono = now(CLOCK_MONOTONIC),
|
.stamp_mono = now(CLOCK_MONOTONIC),
|
||||||
.stamp_real = now(CLOCK_REALTIME),
|
.stamp_real = now(CLOCK_REALTIME),
|
||||||
.pid = getpid(),
|
.pid = getpid(),
|
||||||
.tid = gettid()
|
.tid = gettid(),
|
||||||
};
|
};
|
||||||
|
|
||||||
#if HAVE_SYS_AUXV_H
|
#if HAVE_SYS_AUXV_H
|
||||||
|
@@ -30,9 +30,16 @@ bool ratelimit_below(RateLimit *r) {
|
|||||||
if (r->num < r->burst)
|
if (r->num < r->burst)
|
||||||
goto good;
|
goto good;
|
||||||
|
|
||||||
|
r->num++;
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
good:
|
good:
|
||||||
r->num++;
|
r->num++;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned ratelimit_num_dropped(RateLimit *r) {
|
||||||
|
assert(r);
|
||||||
|
|
||||||
|
return r->num > r->burst ? r->num - r->burst : 0;
|
||||||
|
}
|
||||||
|
@@ -4,7 +4,6 @@
|
|||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
#include "time-util.h"
|
#include "time-util.h"
|
||||||
#include "util.h"
|
|
||||||
|
|
||||||
typedef struct RateLimit {
|
typedef struct RateLimit {
|
||||||
usec_t interval; /* Keep those two fields first so they can be initialized easily: */
|
usec_t interval; /* Keep those two fields first so they can be initialized easily: */
|
||||||
@@ -22,3 +21,5 @@ static inline bool ratelimit_configured(RateLimit *rl) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool ratelimit_below(RateLimit *r);
|
bool ratelimit_below(RateLimit *r);
|
||||||
|
|
||||||
|
unsigned ratelimit_num_dropped(RateLimit *r);
|
||||||
|
@@ -360,6 +360,32 @@ bool stat_inode_unmodified(const struct stat *a, const struct stat *b) {
|
|||||||
(!(S_ISCHR(a->st_mode) || S_ISBLK(a->st_mode)) || a->st_rdev == b->st_rdev); /* if device node, also compare major/minor, because we can */
|
(!(S_ISCHR(a->st_mode) || S_ISBLK(a->st_mode)) || a->st_rdev == b->st_rdev); /* if device node, also compare major/minor, because we can */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool statx_inode_same(const struct statx *a, const struct statx *b) {
|
||||||
|
|
||||||
|
/* Same as stat_inode_same() but for struct statx */
|
||||||
|
|
||||||
|
return a && b &&
|
||||||
|
FLAGS_SET(a->stx_mask, STATX_TYPE|STATX_INO) && FLAGS_SET(b->stx_mask, STATX_TYPE|STATX_INO) &&
|
||||||
|
(a->stx_mode & S_IFMT) != 0 &&
|
||||||
|
((a->stx_mode ^ b->stx_mode) & S_IFMT) == 0 &&
|
||||||
|
a->stx_dev_major == b->stx_dev_major &&
|
||||||
|
a->stx_dev_minor == b->stx_dev_minor &&
|
||||||
|
a->stx_ino == b->stx_ino;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool statx_mount_same(const struct new_statx *a, const struct new_statx *b) {
|
||||||
|
if (!a || !b)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* if we have the mount ID, that's all we need */
|
||||||
|
if (FLAGS_SET(a->stx_mask, STATX_MNT_ID) && FLAGS_SET(b->stx_mask, STATX_MNT_ID))
|
||||||
|
return a->stx_mnt_id == b->stx_mnt_id;
|
||||||
|
|
||||||
|
/* Otherwise, major/minor of backing device must match */
|
||||||
|
return a->stx_dev_major == b->stx_dev_major &&
|
||||||
|
a->stx_dev_minor == b->stx_dev_minor;
|
||||||
|
}
|
||||||
|
|
||||||
int statx_fallback(int dfd, const char *path, int flags, unsigned mask, struct statx *sx) {
|
int statx_fallback(int dfd, const char *path, int flags, unsigned mask, struct statx *sx) {
|
||||||
static bool avoid_statx = false;
|
static bool avoid_statx = false;
|
||||||
struct stat st;
|
struct stat st;
|
||||||
|
@@ -73,6 +73,9 @@ int proc_mounted(void);
|
|||||||
bool stat_inode_same(const struct stat *a, const struct stat *b);
|
bool stat_inode_same(const struct stat *a, const struct stat *b);
|
||||||
bool stat_inode_unmodified(const struct stat *a, const struct stat *b);
|
bool stat_inode_unmodified(const struct stat *a, const struct stat *b);
|
||||||
|
|
||||||
|
bool statx_inode_same(const struct statx *a, const struct statx *b);
|
||||||
|
bool statx_mount_same(const struct new_statx *a, const struct new_statx *b);
|
||||||
|
|
||||||
int statx_fallback(int dfd, const char *path, int flags, unsigned mask, struct statx *sx);
|
int statx_fallback(int dfd, const char *path, int flags, unsigned mask, struct statx *sx);
|
||||||
|
|
||||||
#if HAS_FEATURE_MEMORY_SANITIZER
|
#if HAS_FEATURE_MEMORY_SANITIZER
|
||||||
|
@@ -521,6 +521,19 @@ char* strshorten(char *s, size_t l) {
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int strgrowpad0(char **s, size_t l) {
|
||||||
|
assert(s);
|
||||||
|
|
||||||
|
char *q = realloc(*s, l);
|
||||||
|
if (!q)
|
||||||
|
return -ENOMEM;
|
||||||
|
*s = q;
|
||||||
|
|
||||||
|
size_t sz = strlen(*s);
|
||||||
|
memzero(*s + sz, l - sz);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
char *strreplace(const char *text, const char *old_string, const char *new_string) {
|
char *strreplace(const char *text, const char *old_string, const char *new_string) {
|
||||||
size_t l, old_len, new_len;
|
size_t l, old_len, new_len;
|
||||||
char *t, *ret = NULL;
|
char *t, *ret = NULL;
|
||||||
|
@@ -152,6 +152,8 @@ char *cellescape(char *buf, size_t len, const char *s);
|
|||||||
|
|
||||||
char* strshorten(char *s, size_t l);
|
char* strshorten(char *s, size_t l);
|
||||||
|
|
||||||
|
int strgrowpad0(char **s, size_t l);
|
||||||
|
|
||||||
char *strreplace(const char *text, const char *old_string, const char *new_string);
|
char *strreplace(const char *text, const char *old_string, const char *new_string);
|
||||||
|
|
||||||
char *strip_tab_ansi(char **ibuf, size_t *_isz, size_t highlight[2]);
|
char *strip_tab_ansi(char **ibuf, size_t *_isz, size_t highlight[2]);
|
||||||
|
@@ -828,14 +828,27 @@ char** strv_shell_escape(char **l, const char *bad) {
|
|||||||
return l;
|
return l;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool strv_fnmatch_full(char* const* patterns, const char *s, int flags, size_t *matched_pos) {
|
bool strv_fnmatch_full(
|
||||||
for (size_t i = 0; patterns && patterns[i]; i++)
|
char* const* patterns,
|
||||||
|
const char *s,
|
||||||
|
int flags,
|
||||||
|
size_t *ret_matched_pos) {
|
||||||
|
|
||||||
|
assert(s);
|
||||||
|
|
||||||
|
if (patterns)
|
||||||
|
for (size_t i = 0; patterns[i]; i++)
|
||||||
|
/* NB: We treat all fnmatch() errors as equivalent to FNM_NOMATCH, i.e. if fnmatch() fails to
|
||||||
|
* process the pattern for some reason we'll consider this equivalent to non-matching. */
|
||||||
if (fnmatch(patterns[i], s, flags) == 0) {
|
if (fnmatch(patterns[i], s, flags) == 0) {
|
||||||
if (matched_pos)
|
if (ret_matched_pos)
|
||||||
*matched_pos = i;
|
*ret_matched_pos = i;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ret_matched_pos)
|
||||||
|
*ret_matched_pos = SIZE_MAX;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -240,7 +240,7 @@ void strv_print(char * const *l);
|
|||||||
char** strv_reverse(char **l);
|
char** strv_reverse(char **l);
|
||||||
char** strv_shell_escape(char **l, const char *bad);
|
char** strv_shell_escape(char **l, const char *bad);
|
||||||
|
|
||||||
bool strv_fnmatch_full(char* const* patterns, const char *s, int flags, size_t *matched_pos);
|
bool strv_fnmatch_full(char* const* patterns, const char *s, int flags, size_t *ret_matched_pos);
|
||||||
static inline bool strv_fnmatch(char* const* patterns, const char *s) {
|
static inline bool strv_fnmatch(char* const* patterns, const char *s) {
|
||||||
return strv_fnmatch_full(patterns, s, 0, NULL);
|
return strv_fnmatch_full(patterns, s, 0, NULL);
|
||||||
}
|
}
|
||||||
|
@@ -513,10 +513,9 @@ char *format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy) {
|
|||||||
{ "us", 1 },
|
{ "us", 1 },
|
||||||
};
|
};
|
||||||
|
|
||||||
char *p = buf;
|
char *p = ASSERT_PTR(buf);
|
||||||
bool something = false;
|
bool something = false;
|
||||||
|
|
||||||
assert(buf);
|
|
||||||
assert(l > 0);
|
assert(l > 0);
|
||||||
|
|
||||||
if (t == USEC_INFINITY) {
|
if (t == USEC_INFINITY) {
|
||||||
|
@@ -189,9 +189,14 @@ static inline usec_t usec_sub_unsigned(usec_t timestamp, usec_t delta) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline usec_t usec_sub_signed(usec_t timestamp, int64_t delta) {
|
static inline usec_t usec_sub_signed(usec_t timestamp, int64_t delta) {
|
||||||
|
if (delta == INT64_MIN) { /* prevent overflow */
|
||||||
|
assert_cc(-(INT64_MIN + 1) == INT64_MAX);
|
||||||
|
assert_cc(USEC_INFINITY > INT64_MAX);
|
||||||
|
return usec_add(timestamp, (usec_t) INT64_MAX + 1);
|
||||||
|
}
|
||||||
if (delta < 0)
|
if (delta < 0)
|
||||||
return usec_add(timestamp, (usec_t) (-delta));
|
return usec_add(timestamp, (usec_t) (-delta));
|
||||||
else
|
|
||||||
return usec_sub_unsigned(timestamp, (usec_t) delta);
|
return usec_sub_unsigned(timestamp, (usec_t) delta);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -86,20 +86,43 @@ int fmkostemp_safe(char *pattern, const char *mode, FILE **ret_f) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int tempfn_xxxxxx(const char *p, const char *extra, char **ret) {
|
static int tempfn_build(const char *p, const char *pre, const char *post, bool child, char **ret) {
|
||||||
_cleanup_free_ char *d = NULL, *fn = NULL, *nf = NULL;
|
_cleanup_free_ char *d = NULL, *fn = NULL, *nf = NULL, *result = NULL;
|
||||||
|
size_t len_pre, len_post, len_add;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
|
assert(p);
|
||||||
assert(ret);
|
assert(ret);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Turns this:
|
* Turns this:
|
||||||
* /foo/bar/waldo
|
* /foo/bar/waldo
|
||||||
*
|
*
|
||||||
* Into this:
|
* Into this :
|
||||||
* /foo/bar/.#<extra>waldoXXXXXX
|
* /foo/bar/waldo/.#<pre><post> (child == true)
|
||||||
|
* /foo/bar/.#<pre>waldo<post> (child == false)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
if (pre && strchr(pre, '/'))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (post && strchr(post, '/'))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
len_pre = strlen_ptr(pre);
|
||||||
|
len_post = strlen_ptr(post);
|
||||||
|
/* NAME_MAX is counted *without* the trailing NUL byte. */
|
||||||
|
if (len_pre > NAME_MAX - STRLEN(".#") ||
|
||||||
|
len_post > NAME_MAX - STRLEN(".#") - len_pre)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
len_add = len_pre + len_post + STRLEN(".#");
|
||||||
|
|
||||||
|
if (child) {
|
||||||
|
d = strdup(p);
|
||||||
|
if (!d)
|
||||||
|
return -ENOMEM;
|
||||||
|
} else {
|
||||||
r = path_extract_directory(p, &d);
|
r = path_extract_directory(p, &d);
|
||||||
if (r < 0 && r != -EDESTADDRREQ) /* EDESTADDRREQ → No directory specified, just a filename */
|
if (r < 0 && r != -EDESTADDRREQ) /* EDESTADDRREQ → No directory specified, just a filename */
|
||||||
return r;
|
return r;
|
||||||
@@ -108,28 +131,46 @@ int tempfn_xxxxxx(const char *p, const char *extra, char **ret) {
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
nf = strjoin(".#", strempty(extra), fn, "XXXXXX");
|
if (strlen(fn) > NAME_MAX - len_add)
|
||||||
|
/* We cannot simply prepend and append strings to the filename. Let's truncate the filename. */
|
||||||
|
fn[NAME_MAX - len_add] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
nf = strjoin(".#", strempty(pre), strempty(fn), strempty(post));
|
||||||
if (!nf)
|
if (!nf)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
if (!filename_is_valid(nf)) /* New name is not valid? (Maybe because too long?) Refuse. */
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
if (d) {
|
if (d) {
|
||||||
if (!path_extend(&d, nf))
|
if (!path_extend(&d, nf))
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
*ret = path_simplify(TAKE_PTR(d));
|
result = path_simplify(TAKE_PTR(d));
|
||||||
} else
|
} else
|
||||||
*ret = TAKE_PTR(nf);
|
result = TAKE_PTR(nf);
|
||||||
|
|
||||||
|
if (!path_is_valid(result)) /* New path is not valid? (Maybe because too long?) Refuse. */
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
*ret = TAKE_PTR(result);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int tempfn_random(const char *p, const char *extra, char **ret) {
|
int tempfn_xxxxxx(const char *p, const char *extra, char **ret) {
|
||||||
_cleanup_free_ char *d = NULL, *fn = NULL, *nf = NULL;
|
/*
|
||||||
int r;
|
* Turns this:
|
||||||
|
* /foo/bar/waldo
|
||||||
|
*
|
||||||
|
* Into this:
|
||||||
|
* /foo/bar/.#<extra>waldoXXXXXX
|
||||||
|
*/
|
||||||
|
|
||||||
|
return tempfn_build(p, extra, "XXXXXX", /* child = */ false, ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
int tempfn_random(const char *p, const char *extra, char **ret) {
|
||||||
|
_cleanup_free_ char *s = NULL;
|
||||||
|
|
||||||
|
assert(p);
|
||||||
assert(ret);
|
assert(ret);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -140,37 +181,14 @@ int tempfn_random(const char *p, const char *extra, char **ret) {
|
|||||||
* /foo/bar/.#<extra>waldobaa2a261115984a9
|
* /foo/bar/.#<extra>waldobaa2a261115984a9
|
||||||
*/
|
*/
|
||||||
|
|
||||||
r = path_extract_directory(p, &d);
|
if (asprintf(&s, "%016" PRIx64, random_u64()) < 0)
|
||||||
if (r < 0 && r != -EDESTADDRREQ) /* EDESTADDRREQ → No directory specified, just a filename */
|
|
||||||
return r;
|
|
||||||
|
|
||||||
r = path_extract_filename(p, &fn);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
if (asprintf(&nf, ".#%s%s%016" PRIx64,
|
|
||||||
strempty(extra),
|
|
||||||
fn,
|
|
||||||
random_u64()) < 0)
|
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
if (!filename_is_valid(nf)) /* Not valid? (maybe because too long now?) — refuse early */
|
return tempfn_build(p, extra, s, /* child = */ false, ret);
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
if (d) {
|
|
||||||
if (!path_extend(&d, nf))
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
*ret = path_simplify(TAKE_PTR(d));
|
|
||||||
} else
|
|
||||||
*ret = TAKE_PTR(nf);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int tempfn_random_child(const char *p, const char *extra, char **ret) {
|
int tempfn_random_child(const char *p, const char *extra, char **ret) {
|
||||||
char *t, *x;
|
_cleanup_free_ char *s = NULL;
|
||||||
uint64_t u;
|
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(ret);
|
assert(ret);
|
||||||
@@ -187,27 +205,10 @@ int tempfn_random_child(const char *p, const char *extra, char **ret) {
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
extra = strempty(extra);
|
if (asprintf(&s, "%016" PRIx64, random_u64()) < 0)
|
||||||
|
|
||||||
t = new(char, strlen(p) + 3 + strlen(extra) + 16 + 1);
|
|
||||||
if (!t)
|
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
if (isempty(p))
|
return tempfn_build(p, extra, s, /* child = */ true, ret);
|
||||||
x = stpcpy(stpcpy(t, ".#"), extra);
|
|
||||||
else
|
|
||||||
x = stpcpy(stpcpy(stpcpy(t, p), "/.#"), extra);
|
|
||||||
|
|
||||||
u = random_u64();
|
|
||||||
for (unsigned i = 0; i < 16; i++) {
|
|
||||||
*(x++) = hexchar(u & 0xF);
|
|
||||||
u >>= 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
*x = 0;
|
|
||||||
|
|
||||||
*ret = path_simplify(t);
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int open_tmpfile_unlinkable(const char *directory, int flags) {
|
int open_tmpfile_unlinkable(const char *directory, int flags) {
|
||||||
|
@@ -13,12 +13,12 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
/* Users managed by systemd-homed. See https://systemd.io/UIDS-GIDS for details how this range fits into the rest of the world */
|
/* Users managed by systemd-homed. See https://systemd.io/UIDS-GIDS for details how this range fits into the rest of the world */
|
||||||
#define HOME_UID_MIN 60001
|
#define HOME_UID_MIN ((uid_t) 60001)
|
||||||
#define HOME_UID_MAX 60513
|
#define HOME_UID_MAX ((uid_t) 60513)
|
||||||
|
|
||||||
/* Users mapped from host into a container */
|
/* Users mapped from host into a container */
|
||||||
#define MAP_UID_MIN 60514
|
#define MAP_UID_MIN ((uid_t) 60514)
|
||||||
#define MAP_UID_MAX 60577
|
#define MAP_UID_MAX ((uid_t) 60577)
|
||||||
|
|
||||||
bool uid_is_valid(uid_t uid);
|
bool uid_is_valid(uid_t uid);
|
||||||
|
|
||||||
@@ -55,7 +55,7 @@ int merge_gid_lists(const gid_t *list1, size_t size1, const gid_t *list2, size_t
|
|||||||
int getgroups_alloc(gid_t** gids);
|
int getgroups_alloc(gid_t** gids);
|
||||||
|
|
||||||
int get_home_dir(char **ret);
|
int get_home_dir(char **ret);
|
||||||
int get_shell(char **_ret);
|
int get_shell(char **ret);
|
||||||
|
|
||||||
int reset_uid_gid(void);
|
int reset_uid_gid(void);
|
||||||
|
|
||||||
@@ -67,9 +67,9 @@ int take_etc_passwd_lock(const char *root);
|
|||||||
#define UID_NOBODY ((uid_t) 65534U)
|
#define UID_NOBODY ((uid_t) 65534U)
|
||||||
#define GID_NOBODY ((gid_t) 65534U)
|
#define GID_NOBODY ((gid_t) 65534U)
|
||||||
|
|
||||||
/* If REMOUNT_IDMAP_HOST_ROOT is set for remount_idmap() we'll include a mapping here that maps the host root
|
/* If REMOUNT_IDMAPPING_HOST_ROOT is set for remount_idmap() we'll include a mapping here that maps the host
|
||||||
* user accessing the idmapped mount to the this user ID on the backing fs. This is the last valid UID in the
|
* root user accessing the idmapped mount to the this user ID on the backing fs. This is the last valid UID in
|
||||||
* *signed* 32bit range. You might wonder why precisely use this specific UID for this purpose? Well, we
|
* the *signed* 32bit range. You might wonder why precisely use this specific UID for this purpose? Well, we
|
||||||
* definitely cannot use the first 0…65536 UIDs for that, since in most cases that's precisely the file range
|
* definitely cannot use the first 0…65536 UIDs for that, since in most cases that's precisely the file range
|
||||||
* we intend to map to some high UID range, and since UID mappings have to be bijective we thus cannot use
|
* we intend to map to some high UID range, and since UID mappings have to be bijective we thus cannot use
|
||||||
* them at all. Furthermore the UID range beyond INT32_MAX (i.e. the range above the signed 32bit range) is
|
* them at all. Furthermore the UID range beyond INT32_MAX (i.e. the range above the signed 32bit range) is
|
||||||
@@ -130,6 +130,7 @@ int putsgent_sane(const struct sgrp *sg, FILE *stream);
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool is_nologin_shell(const char *shell);
|
bool is_nologin_shell(const char *shell);
|
||||||
|
const char* default_root_shell(const char *root);
|
||||||
|
|
||||||
int is_this_me(const char *username);
|
int is_this_me(const char *username);
|
||||||
|
|
||||||
|
@@ -81,18 +81,13 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* This passes the argument through after (if asserts are enabled) checking that it is not null. */
|
/* This passes the argument through after (if asserts are enabled) checking that it is not null. */
|
||||||
#define ASSERT_PTR(expr) \
|
#define ASSERT_PTR(expr) _ASSERT_PTR(expr, UNIQ_T(_expr_, UNIQ), assert)
|
||||||
|
#define ASSERT_SE_PTR(expr) _ASSERT_PTR(expr, UNIQ_T(_expr_, UNIQ), assert_se)
|
||||||
|
#define _ASSERT_PTR(expr, var, check) \
|
||||||
({ \
|
({ \
|
||||||
typeof(expr) _expr_ = (expr); \
|
typeof(expr) var = (expr); \
|
||||||
assert(_expr_); \
|
check(var); \
|
||||||
_expr_; \
|
var; \
|
||||||
})
|
|
||||||
|
|
||||||
#define ASSERT_SE_PTR(expr) \
|
|
||||||
({ \
|
|
||||||
typeof(expr) _expr_ = (expr); \
|
|
||||||
assert_se(_expr_); \
|
|
||||||
_expr_; \
|
|
||||||
})
|
})
|
||||||
|
|
||||||
#define ASSERT_NONNEG(expr) \
|
#define ASSERT_NONNEG(expr) \
|
||||||
|
@@ -104,7 +104,7 @@ void sha256_init_ctx(struct sha256_ctx *ctx) {
|
|||||||
|
|
||||||
/* Process the remaining bytes in the internal buffer and the usual
|
/* Process the remaining bytes in the internal buffer and the usual
|
||||||
prolog according to the standard and write the result to RESBUF. */
|
prolog according to the standard and write the result to RESBUF. */
|
||||||
void *sha256_finish_ctx(struct sha256_ctx *ctx, void *resbuf) {
|
uint8_t *sha256_finish_ctx(struct sha256_ctx *ctx, uint8_t resbuf[static SHA256_DIGEST_SIZE]) {
|
||||||
/* Take yet unprocessed bytes into account. */
|
/* Take yet unprocessed bytes into account. */
|
||||||
uint32_t bytes = ctx->buflen;
|
uint32_t bytes = ctx->buflen;
|
||||||
size_t pad;
|
size_t pad;
|
||||||
@@ -129,7 +129,7 @@ void *sha256_finish_ctx(struct sha256_ctx *ctx, void *resbuf) {
|
|||||||
/* Put result from CTX in first 32 bytes following RESBUF. */
|
/* Put result from CTX in first 32 bytes following RESBUF. */
|
||||||
for (size_t i = 0; i < 8; ++i)
|
for (size_t i = 0; i < 8; ++i)
|
||||||
if (UNALIGNED_P(resbuf))
|
if (UNALIGNED_P(resbuf))
|
||||||
memcpy((uint8_t*) resbuf + i * sizeof(uint32_t), (uint32_t[]) { SWAP(ctx->H[i]) }, sizeof(uint32_t));
|
memcpy(resbuf + i * sizeof(uint32_t), (uint32_t[]) { SWAP(ctx->H[i]) }, sizeof(uint32_t));
|
||||||
else
|
else
|
||||||
((uint32_t *) resbuf)[i] = SWAP(ctx->H[i]);
|
((uint32_t *) resbuf)[i] = SWAP(ctx->H[i]);
|
||||||
|
|
||||||
@@ -197,10 +197,9 @@ void sha256_process_bytes(const void *buffer, size_t len, struct sha256_ctx *ctx
|
|||||||
/* Process LEN bytes of BUFFER, accumulating context into CTX.
|
/* Process LEN bytes of BUFFER, accumulating context into CTX.
|
||||||
It is assumed that LEN % 64 == 0. */
|
It is assumed that LEN % 64 == 0. */
|
||||||
static void sha256_process_block(const void *buffer, size_t len, struct sha256_ctx *ctx) {
|
static void sha256_process_block(const void *buffer, size_t len, struct sha256_ctx *ctx) {
|
||||||
const uint32_t *words = buffer;
|
const uint32_t *words = ASSERT_PTR(buffer);
|
||||||
size_t nwords = len / sizeof(uint32_t);
|
size_t nwords = len / sizeof(uint32_t);
|
||||||
|
|
||||||
assert(buffer);
|
|
||||||
assert(ctx);
|
assert(ctx);
|
||||||
|
|
||||||
uint32_t a = ctx->H[0];
|
uint32_t a = ctx->H[0];
|
||||||
@@ -289,3 +288,10 @@ static void sha256_process_block(const void *buffer, size_t len, struct sha256_c
|
|||||||
ctx->H[6] = g;
|
ctx->H[6] = g;
|
||||||
ctx->H[7] = h;
|
ctx->H[7] = h;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint8_t* sha256_direct(const void *buffer, size_t sz, uint8_t result[static SHA256_DIGEST_SIZE]) {
|
||||||
|
struct sha256_ctx ctx;
|
||||||
|
sha256_init_ctx(&ctx);
|
||||||
|
sha256_process_bytes(buffer, sz, &ctx);
|
||||||
|
return sha256_finish_ctx(&ctx, result);
|
||||||
|
}
|
||||||
|
@@ -25,5 +25,9 @@ struct sha256_ctx {
|
|||||||
};
|
};
|
||||||
|
|
||||||
void sha256_init_ctx(struct sha256_ctx *ctx);
|
void sha256_init_ctx(struct sha256_ctx *ctx);
|
||||||
void *sha256_finish_ctx(struct sha256_ctx *ctx, void *resbuf);
|
uint8_t *sha256_finish_ctx(struct sha256_ctx *ctx, uint8_t resbuf[static SHA256_DIGEST_SIZE]);
|
||||||
void sha256_process_bytes(const void *buffer, size_t len, struct sha256_ctx *ctx);
|
void sha256_process_bytes(const void *buffer, size_t len, struct sha256_ctx *ctx);
|
||||||
|
|
||||||
|
uint8_t* sha256_direct(const void *buffer, size_t sz, uint8_t result[static SHA256_DIGEST_SIZE]);
|
||||||
|
|
||||||
|
#define SHA256_DIRECT(buffer, sz) sha256_direct(buffer, sz, (uint8_t[SHA256_DIGEST_SIZE]) {})
|
||||||
|
Reference in New Issue
Block a user