systemd: update code from upstream (2024-04-19)

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=fa6ea8095855696cf14cb65214020cdcdee79d6b

(
  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-fundamental.h \
                :/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/dhcp-duid-internal.h"
nm_copy_sd_core "src/libsystemd-network/dhcp6-client-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/network-common.c"
nm_copy_sd_core "src/libsystemd-network/network-common.h"
nm_copy_sd_core "src/libsystemd-network/network-internal.h"
nm_copy_sd_core "src/libsystemd-network/sd-dhcp-duid.c"
nm_copy_sd_core "src/libsystemd-network/sd-dhcp6-client.c"
nm_copy_sd_core "src/libsystemd-network/sd-dhcp6-lease.c"
nm_copy_sd_core "src/libsystemd/sd-device/device-internal.h"
nm_copy_sd_core "src/libsystemd/sd-device/device-private.c"
nm_copy_sd_core "src/libsystemd/sd-device/device-private.h"
nm_copy_sd_core "src/libsystemd/sd-device/device-util.h"
nm_copy_sd_core "src/libsystemd/sd-device/sd-device.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-device.h"
nm_copy_sd_core "src/systemd/sd-dhcp-duid.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-dhcp6-protocol.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-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/arphrd-util.h"
nm_copy_sd_shared "src/basic/btrfs.c"
nm_copy_sd_shared "src/basic/btrfs.h"
nm_copy_sd_shared "src/basic/cgroup-util.h"
nm_copy_sd_shared "src/basic/chase.h"
nm_copy_sd_shared "src/basic/constants.h"
nm_copy_sd_shared "src/basic/devnum-util.c"
nm_copy_sd_shared "src/basic/devnum-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/iovec-util.h"
nm_copy_sd_shared "src/basic/label.c"
nm_copy_sd_shared "src/basic/label.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/lock-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_threads.h"
nm_copy_sd_shared "src/basic/missing_type.h"
nm_copy_sd_shared "src/basic/namespace-util.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/origin-id.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/pidref.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/fundamental/logarithm.h"
nm_copy_sd_shared "src/fundamental/macro-fundamental.h"
nm_copy_sd_shared "src/fundamental/memory-util-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"
nm_copy_sd_stdaux "src/fundamental/unaligned-fundamental.h"
This commit is contained in:
Fernando Fernandez Mancera 2023-06-19 22:26:12 -04:00
parent bee8609c15
commit cd87004dfb
37 changed files with 512 additions and 633 deletions

View File

@ -214,7 +214,7 @@ int device_set_syspath(sd_device *device, const char *_syspath, bool verify) {
/* Only operate on sysfs, i.e. refuse going down into /sys/fs/cgroup/ or similar places where /* Only operate on sysfs, i.e. refuse going down into /sys/fs/cgroup/ or similar places where
* things are not arranged as kobjects in kernel, and hence don't necessarily have * things are not arranged as kobjects in kernel, and hence don't necessarily have
* kobject/attribute structure. */ * kobject/attribute structure. */
r = getenv_bool_secure("SYSTEMD_DEVICE_VERIFY_SYSFS"); r = secure_getenv_bool("SYSTEMD_DEVICE_VERIFY_SYSFS");
if (r < 0 && r != -ENXIO) if (r < 0 && r != -ENXIO)
log_debug_errno(r, "Failed to parse $SYSTEMD_DEVICE_VERIFY_SYSFS value: %m"); log_debug_errno(r, "Failed to parse $SYSTEMD_DEVICE_VERIFY_SYSFS value: %m");
if (r != 0) { if (r != 0) {
@ -728,7 +728,7 @@ int device_read_uevent_file(sd_device *device) {
_cleanup_free_ char *uevent = NULL; _cleanup_free_ char *uevent = NULL;
const char *syspath, *key = NULL, *value = NULL, *major = NULL, *minor = NULL; const char *syspath, *key = NULL, *value = NULL, *major = NULL, *minor = NULL;
char *path; char *path;
size_t uevent_len; size_t uevent_len = 0;
int r; int r;
enum { enum {
@ -1679,8 +1679,8 @@ int device_get_device_id(sd_device *device, const char **ret) {
int device_read_db_internal_filename(sd_device *device, const char *filename) { int device_read_db_internal_filename(sd_device *device, const char *filename) {
_cleanup_free_ char *db = NULL; _cleanup_free_ char *db = NULL;
const char *value; const char *value = NULL;
size_t db_len; size_t db_len = 0;
char key = '\0'; /* Unnecessary initialization to appease gcc-12.0.0-0.4.fc36 */ char key = '\0'; /* Unnecessary initialization to appease gcc-12.0.0-0.4.fc36 */
int r; int r;

View File

@ -1574,7 +1574,7 @@ static int child_exit_callback(sd_event_source *s, const siginfo_t *si, void *us
static bool shall_use_pidfd(void) { static bool shall_use_pidfd(void) {
/* Mostly relevant for debugging, i.e. this is used in test-event.c to test the event loop once with and once without pidfd */ /* Mostly relevant for debugging, i.e. this is used in test-event.c to test the event loop once with and once without pidfd */
return getenv_bool_secure("SYSTEMD_PIDFD") != 0; return secure_getenv_bool("SYSTEMD_PIDFD") != 0;
} }
_public_ int sd_event_add_child( _public_ int sd_event_add_child(
@ -4915,13 +4915,13 @@ _public_ int sd_event_get_state(sd_event *e) {
_public_ int sd_event_get_exit_code(sd_event *e, int *code) { _public_ int sd_event_get_exit_code(sd_event *e, int *code) {
assert_return(e, -EINVAL); assert_return(e, -EINVAL);
assert_return(e = event_resolve(e), -ENOPKG); assert_return(e = event_resolve(e), -ENOPKG);
assert_return(code, -EINVAL);
assert_return(!event_origin_changed(e), -ECHILD); assert_return(!event_origin_changed(e), -ECHILD);
if (!e->exit_requested) if (!e->exit_requested)
return -ENODATA; return -ENODATA;
*code = e->exit_code; if (code)
*code = e->exit_code;
return 0; return 0;
} }

View File

@ -139,7 +139,7 @@ int id128_read_at(int dir_fd, const char *path, Id128Flag f, sd_id128_t *ret) {
assert(dir_fd >= 0 || dir_fd == AT_FDCWD); assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
assert(path); assert(path);
fd = xopenat(dir_fd, path, O_RDONLY|O_CLOEXEC|O_NOCTTY, /* xopen_flags = */ 0, /* mode = */ 0); fd = xopenat(dir_fd, path, O_RDONLY|O_CLOEXEC|O_NOCTTY);
if (fd < 0) if (fd < 0)
return fd; return fd;
@ -185,7 +185,7 @@ int id128_write_at(int dir_fd, const char *path, Id128Flag f, sd_id128_t id) {
assert(dir_fd >= 0 || dir_fd == AT_FDCWD); assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
assert(path); assert(path);
fd = xopenat(dir_fd, path, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY|O_TRUNC, /* xopen_flags = */ 0, 0444); fd = xopenat_full(dir_fd, path, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY|O_TRUNC, /* xopen_flags = */ 0, 0444);
if (fd < 0) if (fd < 0)
return fd; return fd;

View File

@ -3,7 +3,6 @@
#define foosddhcpduidhfoo #define foosddhcpduidhfoo
/*** /***
Copyright © 2013 Intel Corporation. All rights reserved.
systemd is free software; you can redistribute it and/or modify it systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by 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 the Free Software Foundation; either version 2.1 of the License, or

View File

@ -26,35 +26,14 @@
#include <sys/types.h> #include <sys/types.h>
#include "sd-event.h" #include "sd-event.h"
#include "sd-ndisc-protocol.h"
#include "sd-ndisc-router.h"
#include "_sd-common.h" #include "_sd-common.h"
_SD_BEGIN_DECLARATIONS; _SD_BEGIN_DECLARATIONS;
/* Neighbor Discovery Options, RFC 4861, Section 4.6 and
* https://www.iana.org/assignments/icmpv6-parameters/icmpv6-parameters.xhtml#icmpv6-parameters-5 */
enum {
SD_NDISC_OPTION_SOURCE_LL_ADDRESS = 1,
SD_NDISC_OPTION_TARGET_LL_ADDRESS = 2,
SD_NDISC_OPTION_PREFIX_INFORMATION = 3,
SD_NDISC_OPTION_MTU = 5,
SD_NDISC_OPTION_ROUTE_INFORMATION = 24,
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_PREF64 = 38
};
/* Route preference, RFC 4191, Section 2.1 */
enum {
SD_NDISC_PREFERENCE_LOW = 3U,
SD_NDISC_PREFERENCE_MEDIUM = 0U,
SD_NDISC_PREFERENCE_HIGH = 1U
};
typedef struct sd_ndisc sd_ndisc; typedef struct sd_ndisc sd_ndisc;
typedef struct sd_ndisc_router sd_ndisc_router;
__extension__ typedef enum sd_ndisc_event_t { __extension__ typedef enum sd_ndisc_event_t {
SD_NDISC_EVENT_TIMEOUT, SD_NDISC_EVENT_TIMEOUT,
@ -64,14 +43,16 @@ __extension__ typedef enum sd_ndisc_event_t {
_SD_ENUM_FORCE_S64(NDISC_EVENT) _SD_ENUM_FORCE_S64(NDISC_EVENT)
} sd_ndisc_event_t; } sd_ndisc_event_t;
typedef void (*sd_ndisc_callback_t)(sd_ndisc *nd, sd_ndisc_event_t event, sd_ndisc_router *rt, void *userdata); typedef void (*sd_ndisc_callback_t)(sd_ndisc *nd, sd_ndisc_event_t event, void *message, void *userdata);
int sd_ndisc_new(sd_ndisc **ret); int sd_ndisc_new(sd_ndisc **ret);
sd_ndisc *sd_ndisc_ref(sd_ndisc *nd); sd_ndisc *sd_ndisc_ref(sd_ndisc *nd);
sd_ndisc *sd_ndisc_unref(sd_ndisc *nd); sd_ndisc *sd_ndisc_unref(sd_ndisc *nd);
_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_ndisc, sd_ndisc_unref);
int sd_ndisc_start(sd_ndisc *nd); int sd_ndisc_start(sd_ndisc *nd);
int sd_ndisc_stop(sd_ndisc *nd); int sd_ndisc_stop(sd_ndisc *nd);
int sd_ndisc_is_running(sd_ndisc *nd);
int sd_ndisc_attach_event(sd_ndisc *nd, sd_event *event, int64_t priority); int sd_ndisc_attach_event(sd_ndisc *nd, sd_event *event, int64_t priority);
int sd_ndisc_detach_event(sd_ndisc *nd); int sd_ndisc_detach_event(sd_ndisc *nd);
@ -81,69 +62,9 @@ int sd_ndisc_set_callback(sd_ndisc *nd, sd_ndisc_callback_t cb, void *userdata);
int sd_ndisc_set_ifindex(sd_ndisc *nd, int interface_index); int sd_ndisc_set_ifindex(sd_ndisc *nd, int interface_index);
int sd_ndisc_set_ifname(sd_ndisc *nd, const char *interface_name); 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_get_ifname(sd_ndisc *nd, const char **ret);
int sd_ndisc_set_link_local_address(sd_ndisc *nd, const struct in6_addr *addr);
int sd_ndisc_set_mac(sd_ndisc *nd, const struct ether_addr *mac_addr); int sd_ndisc_set_mac(sd_ndisc *nd, const struct ether_addr *mac_addr);
sd_ndisc_router *sd_ndisc_router_ref(sd_ndisc_router *rt);
sd_ndisc_router *sd_ndisc_router_unref(sd_ndisc_router *rt);
int sd_ndisc_router_get_address(sd_ndisc_router *rt, struct in6_addr *ret);
int sd_ndisc_router_get_timestamp(sd_ndisc_router *rt, clockid_t clock, uint64_t *ret);
int sd_ndisc_router_get_raw(sd_ndisc_router *rt, const void **ret, size_t *ret_size);
int sd_ndisc_router_get_hop_limit(sd_ndisc_router *rt, uint8_t *ret);
int sd_ndisc_router_get_icmp6_ratelimit(sd_ndisc_router *rt, uint64_t *ret);
int sd_ndisc_router_get_flags(sd_ndisc_router *rt, uint64_t *ret);
int sd_ndisc_router_get_preference(sd_ndisc_router *rt, unsigned *ret);
int sd_ndisc_router_get_lifetime(sd_ndisc_router *rt, uint64_t *ret);
int sd_ndisc_router_get_lifetime_timestamp(sd_ndisc_router *rt, clockid_t clock, uint64_t *ret);
int sd_ndisc_router_get_retransmission_time(sd_ndisc_router *rt, uint64_t *ret);
int sd_ndisc_router_get_mtu(sd_ndisc_router *rt, uint32_t *ret);
/* Generic option access */
int sd_ndisc_router_option_rewind(sd_ndisc_router *rt);
int sd_ndisc_router_option_next(sd_ndisc_router *rt);
int sd_ndisc_router_option_get_type(sd_ndisc_router *rt, uint8_t *ret);
int sd_ndisc_router_option_is_type(sd_ndisc_router *rt, uint8_t type);
int sd_ndisc_router_option_get_raw(sd_ndisc_router *rt, const void **ret, size_t *ret_size);
/* Specific option access: SD_NDISC_OPTION_PREFIX_INFORMATION */
int sd_ndisc_router_prefix_get_valid_lifetime(sd_ndisc_router *rt, uint64_t *ret);
int sd_ndisc_router_prefix_get_valid_lifetime_timestamp(sd_ndisc_router *rt, clockid_t clock, uint64_t *ret);
int sd_ndisc_router_prefix_get_preferred_lifetime(sd_ndisc_router *rt, uint64_t *ret);
int sd_ndisc_router_prefix_get_preferred_lifetime_timestamp(sd_ndisc_router *rt, clockid_t clock, uint64_t *ret);
int sd_ndisc_router_prefix_get_flags(sd_ndisc_router *rt, uint8_t *ret);
int sd_ndisc_router_prefix_get_address(sd_ndisc_router *rt, struct in6_addr *ret);
int sd_ndisc_router_prefix_get_prefixlen(sd_ndisc_router *rt, unsigned *ret);
/* Specific option access: SD_NDISC_OPTION_ROUTE_INFORMATION */
int sd_ndisc_router_route_get_lifetime(sd_ndisc_router *rt, uint64_t *ret);
int sd_ndisc_router_route_get_lifetime_timestamp(sd_ndisc_router *rt, clockid_t clock, uint64_t *ret);
int sd_ndisc_router_route_get_address(sd_ndisc_router *rt, struct in6_addr *ret);
int sd_ndisc_router_route_get_prefixlen(sd_ndisc_router *rt, unsigned *ret);
int sd_ndisc_router_route_get_preference(sd_ndisc_router *rt, unsigned *ret);
/* Specific option access: SD_NDISC_OPTION_RDNSS */
int sd_ndisc_router_rdnss_get_addresses(sd_ndisc_router *rt, const struct in6_addr **ret);
int sd_ndisc_router_rdnss_get_lifetime(sd_ndisc_router *rt, uint64_t *ret);
int sd_ndisc_router_rdnss_get_lifetime_timestamp(sd_ndisc_router *rt, clockid_t clock, uint64_t *ret);
/* Specific option access: SD_NDISC_OPTION_DNSSL */
int sd_ndisc_router_dnssl_get_domains(sd_ndisc_router *rt, char ***ret);
int sd_ndisc_router_dnssl_get_lifetime(sd_ndisc_router *rt, uint64_t *ret);
int sd_ndisc_router_dnssl_get_lifetime_timestamp(sd_ndisc_router *rt, clockid_t clock, uint64_t *ret);
/* Specific option access: SD_NDISC_OPTION_CAPTIVE_PORTAL */
int sd_ndisc_router_captive_portal_get_uri(sd_ndisc_router *rt, const char **ret, size_t *ret_size);
/* Specific option access: SD_NDISC_OPTION_PREF64 */
int sd_ndisc_router_prefix64_get_prefix(sd_ndisc_router *rt, struct in6_addr *ret);
int sd_ndisc_router_prefix64_get_prefixlen(sd_ndisc_router *rt, unsigned *ret);
int sd_ndisc_router_prefix64_get_lifetime(sd_ndisc_router *rt, uint64_t *ret);
int sd_ndisc_router_prefix64_get_lifetime_timestamp(sd_ndisc_router *rt, clockid_t clock, uint64_t *ret);
_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_ndisc, sd_ndisc_unref);
_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_ndisc_router, sd_ndisc_router_unref);
_SD_END_DECLARATIONS; _SD_END_DECLARATIONS;
#endif #endif

View File

@ -18,6 +18,7 @@
#include "stdio-util.h" #include "stdio-util.h"
#include "string-util.h" #include "string-util.h"
#include "strv.h" #include "strv.h"
#include "syslog-util.h"
#include "utf8.h" #include "utf8.h"
/* We follow bash for the character set. Different shells have different rules. */ /* We follow bash for the character set. Different shells have different rules. */
@ -309,19 +310,17 @@ char **strv_env_delete(char **x, size_t n_lists, ...) {
return TAKE_PTR(t); return TAKE_PTR(t);
} }
char **strv_env_unset(char **l, const char *p) { char** strv_env_unset(char **l, const char *p) {
char **f, **t; assert(p);
if (!l) if (!l)
return NULL; return NULL;
assert(p);
/* Drops every occurrence of the env var setting p in the /* Drops every occurrence of the env var setting p in the
* string list. Edits in-place. */ * string list. Edits in-place. */
char **f, **t;
for (f = t = l; *f; f++) { for (f = t = l; *f; f++) {
if (env_match(*f, p)) { if (env_match(*f, p)) {
free(*f); free(*f);
continue; continue;
@ -334,14 +333,13 @@ char **strv_env_unset(char **l, const char *p) {
return l; return l;
} }
char **strv_env_unset_many(char **l, ...) { char** strv_env_unset_many_internal(char **l, ...) {
char **f, **t;
if (!l) if (!l)
return NULL; return NULL;
/* Like strv_env_unset() but applies many at once. Edits in-place. */ /* Like strv_env_unset() but applies many at once. Edits in-place. */
char **f, **t;
for (f = t = l; *f; f++) { for (f = t = l; *f; f++) {
bool found = false; bool found = false;
const char *p; const char *p;
@ -349,12 +347,11 @@ char **strv_env_unset_many(char **l, ...) {
va_start(ap, l); va_start(ap, l);
while ((p = va_arg(ap, const char*))) { while ((p = va_arg(ap, const char*)))
if (env_match(*f, p)) { if (env_match(*f, p)) {
found = true; found = true;
break; break;
} }
}
va_end(ap); va_end(ap);
@ -966,7 +963,7 @@ int getenv_bool(const char *p) {
return parse_boolean(e); return parse_boolean(e);
} }
int getenv_bool_secure(const char *p) { int secure_getenv_bool(const char *p) {
const char *e; const char *e;
e = secure_getenv(p); e = secure_getenv(p);
@ -976,7 +973,7 @@ 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) { int secure_getenv_uint64(const char *p, uint64_t *ret) {
const char *e; const char *e;
assert(p); assert(p);
@ -1030,6 +1027,17 @@ int setenv_systemd_exec_pid(bool update_only) {
return 1; return 1;
} }
int setenv_systemd_log_level(void) {
_cleanup_free_ char *val = NULL;
int r;
r = log_level_to_string_alloc(log_get_max_level(), &val);
if (r < 0)
return r;
return RET_NERRNO(setenv("SYSTEMD_LOG_LEVEL", val, /* overwrite= */ true));
}
int getenv_path_list(const char *name, char ***ret_paths) { int getenv_path_list(const char *name, char ***ret_paths) {
_cleanup_strv_free_ char **l = NULL; _cleanup_strv_free_ char **l = NULL;
const char *e; const char *e;

View File

@ -43,8 +43,9 @@ char** _strv_env_merge(char **first, ...);
#define strv_env_merge(first, ...) _strv_env_merge(first, __VA_ARGS__, POINTER_MAX) #define strv_env_merge(first, ...) _strv_env_merge(first, __VA_ARGS__, POINTER_MAX)
char **strv_env_delete(char **x, size_t n_lists, ...); /* New copy */ char **strv_env_delete(char **x, size_t n_lists, ...); /* New copy */
char **strv_env_unset(char **l, const char *p); /* In place ... */ char** strv_env_unset(char **l, const char *p); /* In place ... */
char **strv_env_unset_many(char **l, ...) _sentinel_; char** strv_env_unset_many_internal(char **l, ...) _sentinel_;
#define strv_env_unset_many(l, ...) strv_env_unset_many_internal(l, __VA_ARGS__, NULL)
int strv_env_replace_consume(char ***l, char *p); /* In place ... */ int strv_env_replace_consume(char ***l, char *p); /* In place ... */
int strv_env_replace_strdup(char ***l, const char *assignment); int strv_env_replace_strdup(char ***l, const char *assignment);
int strv_env_replace_strdup_passthrough(char ***l, const char *assignment); int strv_env_replace_strdup_passthrough(char ***l, const char *assignment);
@ -61,9 +62,9 @@ static inline char* strv_env_get(char * const *x, const char *n) {
char *strv_env_pairs_get(char **l, const char *name) _pure_; 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 secure_getenv_bool(const char *p);
int getenv_uint64_secure(const char *p, uint64_t *ret); int secure_getenv_uint64(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);
@ -72,6 +73,7 @@ int set_unset_env(const char *name, const char *value, bool overwrite);
int putenv_dup(const char *assignment, bool override); int putenv_dup(const char *assignment, bool override);
int setenv_systemd_exec_pid(bool update_only); int setenv_systemd_exec_pid(bool update_only);
int setenv_systemd_log_level(void);
/* Parses and does sanity checks on an environment variable containing /* Parses and does sanity checks on an environment variable containing
* PATH-like colon-separated absolute paths */ * PATH-like colon-separated absolute paths */

View File

@ -244,52 +244,43 @@ int extract_first_word_and_warn(
* Let's make sure that ExtractFlags fits into an unsigned int. */ * Let's make sure that ExtractFlags fits into an unsigned int. */
assert_cc(sizeof(enum ExtractFlags) <= sizeof(unsigned)); assert_cc(sizeof(enum ExtractFlags) <= sizeof(unsigned));
int extract_many_words(const char **p, const char *separators, unsigned flags, ...) { int extract_many_words_internal(const char **p, const char *separators, unsigned flags, ...) {
va_list ap; va_list ap;
char **l; unsigned n = 0;
int n = 0, i, c, r; int r;
/* Parses a number of words from a string, stripping any /* Parses a number of words from a string, stripping any quotes if necessary. */
* quotes if necessary. */
assert(p); assert(p);
/* Count how many words are expected */ /* Count how many words are expected */
va_start(ap, flags); va_start(ap, flags);
for (;;) { while (va_arg(ap, char**))
if (!va_arg(ap, char **))
break;
n++; n++;
}
va_end(ap); va_end(ap);
if (n <= 0) if (n == 0)
return 0; return 0;
/* Read all words into a temporary array */ /* Read all words into a temporary array */
l = newa0(char*, n); char **l = newa0(char*, n);
for (c = 0; c < n; c++) { unsigned c;
for (c = 0; c < n; c++) {
r = extract_first_word(p, &l[c], separators, flags); r = extract_first_word(p, &l[c], separators, flags);
if (r < 0) { if (r < 0) {
free_many_charp(l, c); free_many_charp(l, c);
return r; return r;
} }
if (r == 0) if (r == 0)
break; break;
} }
/* If we managed to parse all words, return them in the passed /* If we managed to parse all words, return them in the passed in parameters */
* in parameters */
va_start(ap, flags); va_start(ap, flags);
for (i = 0; i < n; i++) { FOREACH_ARRAY(i, l, n) {
char **v; char **v = ASSERT_PTR(va_arg(ap, char**));
*v = *i;
v = va_arg(ap, char **);
assert(v);
*v = l[i];
} }
va_end(ap); va_end(ap);

View File

@ -19,4 +19,7 @@ typedef enum ExtractFlags {
int extract_first_word(const char **p, char **ret, const char *separators, ExtractFlags flags); int extract_first_word(const char **p, char **ret, const char *separators, ExtractFlags flags);
int extract_first_word_and_warn(const char **p, char **ret, const char *separators, ExtractFlags flags, const char *unit, const char *filename, unsigned line, const char *rvalue); int extract_first_word_and_warn(const char **p, char **ret, const char *separators, ExtractFlags flags, const char *unit, const char *filename, unsigned line, const char *rvalue);
int extract_many_words(const char **p, const char *separators, unsigned flags, ...) _sentinel_;
int extract_many_words_internal(const char **p, const char *separators, unsigned flags, ...) _sentinel_;
#define extract_many_words(p, separators, flags, ...) \
extract_many_words_internal(p, separators, flags, ##__VA_ARGS__, NULL)

View File

@ -308,7 +308,7 @@ static int close_all_fds_special_case(const int except[], size_t n_except) {
case 0: case 0:
/* Close everything. Yay! */ /* Close everything. Yay! */
if (close_range(3, -1, 0) >= 0) if (close_range(3, INT_MAX, 0) >= 0)
return 1; return 1;
if (ERRNO_IS_NOT_SUPPORTED(errno) || ERRNO_IS_PRIVILEGE(errno)) { if (ERRNO_IS_NOT_SUPPORTED(errno) || ERRNO_IS_PRIVILEGE(errno)) {
@ -419,7 +419,7 @@ int close_all_fds(const int except[], size_t n_except) {
if (sorted[n_sorted-1] >= INT_MAX) /* Dont let the addition below overflow */ if (sorted[n_sorted-1] >= INT_MAX) /* Dont let the addition below overflow */
return 0; return 0;
if (close_range(sorted[n_sorted-1] + 1, -1, 0) >= 0) if (close_range(sorted[n_sorted-1] + 1, INT_MAX, 0) >= 0)
return 0; return 0;
if (!ERRNO_IS_NOT_SUPPORTED(errno) && !ERRNO_IS_PRIVILEGE(errno)) if (!ERRNO_IS_NOT_SUPPORTED(errno) && !ERRNO_IS_PRIVILEGE(errno))
@ -464,6 +464,53 @@ int close_all_fds(const int except[], size_t n_except) {
return r; return r;
} }
int pack_fds(int fds[], size_t n_fds) {
if (n_fds <= 0)
return 0;
/* Shifts around the fds in the provided array such that they
* all end up packed next to each-other, in order, starting
* from SD_LISTEN_FDS_START. This must be called after close_all_fds();
* it is likely to freeze up otherwise. You should probably use safe_fork_full
* with FORK_CLOSE_ALL_FDS|FORK_PACK_FDS set, to ensure that this is done correctly.
* The fds array is modified in place with the new FD numbers. */
assert(fds);
for (int start = 0;;) {
int restart_from = -1;
for (int i = start; i < (int) n_fds; i++) {
int nfd;
/* Already at right index? */
if (fds[i] == i + 3)
continue;
nfd = fcntl(fds[i], F_DUPFD, i + 3);
if (nfd < 0)
return -errno;
safe_close(fds[i]);
fds[i] = nfd;
/* Hmm, the fd we wanted isn't free? Then
* let's remember that and try again from here */
if (nfd != i + 3 && restart_from < 0)
restart_from = i;
}
if (restart_from < 0)
break;
start = restart_from;
}
assert(fds[0] == 3);
return 0;
}
int same_fd(int a, int b) { int same_fd(int a, int b) {
struct stat sta, stb; struct stat sta, stb;
pid_t pid; pid_t pid;
@ -866,6 +913,38 @@ int fd_is_opath(int fd) {
return FLAGS_SET(r, O_PATH); return FLAGS_SET(r, O_PATH);
} }
int fd_verify_safe_flags(int fd) {
int flags, unexpected_flags;
/* Check if an extrinsic fd is safe to work on (by a privileged service). This ensures that clients
* can't trick a privileged service into giving access to a file the client doesn't already have
* access to (especially via something like O_PATH).
*
* O_NOFOLLOW: For some reason the kernel will return this flag from fcntl; it doesn't go away
* immediately after open(). It should have no effect whatsoever to an already-opened FD,
* and since we refuse O_PATH it should be safe.
*
* RAW_O_LARGEFILE: glibc secretly sets this and neglects to hide it from us if we call fcntl.
* See comment in missing_fcntl.h for more details about this.
*
* O_DIRECTORY: this is set for directories, which are totally fine
*/
assert(fd >= 0);
flags = fcntl(fd, F_GETFL);
if (flags < 0)
return -errno;
unexpected_flags = flags & ~(O_ACCMODE|O_NOFOLLOW|RAW_O_LARGEFILE|O_DIRECTORY);
if (unexpected_flags != 0)
return log_debug_errno(SYNTHETIC_ERRNO(EREMOTEIO),
"Unexpected flags set for extrinsic fd: 0%o",
(unsigned) unexpected_flags);
return 0;
}
int read_nr_open(void) { int read_nr_open(void) {
_cleanup_free_ char *nr_open = NULL; _cleanup_free_ char *nr_open = NULL;
int r; int r;

View File

@ -8,6 +8,7 @@
#include <sys/socket.h> #include <sys/socket.h>
#include "macro.h" #include "macro.h"
#include "missing_fcntl.h"
#include "stdio-util.h" #include "stdio-util.h"
/* maximum length of fdname */ /* maximum length of fdname */
@ -77,6 +78,8 @@ int get_max_fd(void);
int close_all_fds(const int except[], size_t n_except); int close_all_fds(const int except[], size_t n_except);
int close_all_fds_without_malloc(const int except[], size_t n_except); int close_all_fds_without_malloc(const int except[], size_t n_except);
int pack_fds(int fds[], size_t n);
int same_fd(int a, int b); int same_fd(int a, int b);
void cmsg_close_all(struct msghdr *mh); void cmsg_close_all(struct msghdr *mh);
@ -109,7 +112,10 @@ static inline int make_null_stdio(void) {
int fd_reopen(int fd, int flags); int fd_reopen(int fd, int flags);
int fd_reopen_condition(int fd, int flags, int mask, int *ret_new_fd); int fd_reopen_condition(int fd, int flags, int mask, int *ret_new_fd);
int fd_is_opath(int fd); int fd_is_opath(int fd);
int fd_verify_safe_flags(int fd);
int read_nr_open(void); int read_nr_open(void);
int fd_get_diskseq(int fd, uint64_t *ret); int fd_get_diskseq(int fd, uint64_t *ret);

View File

@ -18,6 +18,14 @@ assert_cc(sizeof(uid_t) == sizeof(uint32_t));
assert_cc(sizeof(gid_t) == sizeof(uint32_t)); assert_cc(sizeof(gid_t) == sizeof(uint32_t));
#define GID_FMT "%" PRIu32 #define GID_FMT "%" PRIu32
/* 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 FORMAT_UID(uid) \
snprintf_ok((char[DECIMAL_STR_MAX(uid_t)]){}, DECIMAL_STR_MAX(uid_t), UID_FMT, uid)
#define FORMAT_GID(gid) \
snprintf_ok((char[DECIMAL_STR_MAX(gid_t)]){}, DECIMAL_STR_MAX(gid_t), GID_FMT, gid)
#if SIZEOF_TIME_T == 8 #if SIZEOF_TIME_T == 8
# define PRI_TIME PRIi64 # define PRI_TIME PRIi64
#elif SIZEOF_TIME_T == 4 #elif SIZEOF_TIME_T == 4

View File

@ -116,7 +116,11 @@ int rename_noreplace(int olddirfd, const char *oldpath, int newdirfd, const char
int readlinkat_malloc(int fd, const char *p, char **ret) { int readlinkat_malloc(int fd, const char *p, char **ret) {
size_t l = PATH_MAX; size_t l = PATH_MAX;
assert(p); assert(fd >= 0 || fd == AT_FDCWD);
if (fd < 0 && isempty(p))
return -EISDIR; /* In this case, the fd points to the current working directory, and is
* definitely not a symlink. Let's return earlier. */
for (;;) { for (;;) {
_cleanup_free_ char *c = NULL; _cleanup_free_ char *c = NULL;
@ -126,7 +130,7 @@ int readlinkat_malloc(int fd, const char *p, char **ret) {
if (!c) if (!c)
return -ENOMEM; return -ENOMEM;
n = readlinkat(fd, p, c, l); n = readlinkat(fd, strempty(p), c, l);
if (n < 0) if (n < 0)
return -errno; return -errno;
@ -1050,7 +1054,7 @@ int open_mkdir_at(int dirfd, const char *path, int flags, mode_t mode) {
path = fname; path = fname;
} }
fd = xopenat(dirfd, path, flags|O_CREAT|O_DIRECTORY|O_NOFOLLOW, /* xopen_flags = */ 0, mode); fd = xopenat_full(dirfd, path, flags|O_CREAT|O_DIRECTORY|O_NOFOLLOW, /* xopen_flags = */ 0, mode);
if (IN_SET(fd, -ELOOP, -ENOTDIR)) if (IN_SET(fd, -ELOOP, -ENOTDIR))
return -EEXIST; return -EEXIST;
if (fd < 0) if (fd < 0)
@ -1106,7 +1110,7 @@ int openat_report_new(int dirfd, const char *pathname, int flags, mode_t mode, b
} }
} }
int xopenat(int dir_fd, const char *path, int open_flags, XOpenFlags xopen_flags, mode_t mode) { int xopenat_full(int dir_fd, const char *path, int open_flags, XOpenFlags xopen_flags, mode_t mode) {
_cleanup_close_ int fd = -EBADF; _cleanup_close_ int fd = -EBADF;
bool made = false; bool made = false;
int r; int r;
@ -1187,7 +1191,7 @@ int xopenat(int dir_fd, const char *path, int open_flags, XOpenFlags xopen_flags
return TAKE_FD(fd); return TAKE_FD(fd);
} }
int xopenat_lock( int xopenat_lock_full(
int dir_fd, int dir_fd,
const char *path, const char *path,
int open_flags, int open_flags,
@ -1210,7 +1214,7 @@ int xopenat_lock(
for (;;) { for (;;) {
struct stat st; struct stat st;
fd = xopenat(dir_fd, path, open_flags, xopen_flags, mode); fd = xopenat_full(dir_fd, path, open_flags, xopen_flags, mode);
if (fd < 0) if (fd < 0)
return fd; return fd;

View File

@ -137,6 +137,12 @@ typedef enum XOpenFlags {
XO_SUBVOLUME = 1 << 1, XO_SUBVOLUME = 1 << 1,
} XOpenFlags; } XOpenFlags;
int xopenat(int dir_fd, const char *path, int open_flags, XOpenFlags xopen_flags, mode_t mode); int xopenat_full(int dir_fd, const char *path, int open_flags, XOpenFlags xopen_flags, mode_t mode);
static inline int xopenat(int dir_fd, const char *path, int open_flags) {
return xopenat_full(dir_fd, path, open_flags, 0, 0);
}
int xopenat_lock(int dir_fd, const char *path, int open_flags, XOpenFlags xopen_flags, mode_t mode, LockType locktype, int operation); int xopenat_lock_full(int dir_fd, const char *path, int open_flags, XOpenFlags xopen_flags, mode_t mode, LockType locktype, int operation);
static inline int xopenat_lock(int dir_fd, const char *path, int open_flags, LockType locktype, int operation) {
return xopenat_lock_full(dir_fd, path, open_flags, 0, 0, locktype, operation);
}

View File

@ -41,6 +41,8 @@ const char *special_glyph_full(SpecialGlyph code, bool force_utf) {
[SPECIAL_GLYPH_TREE_SPACE] = " ", [SPECIAL_GLYPH_TREE_SPACE] = " ",
[SPECIAL_GLYPH_TREE_TOP] = ",-", [SPECIAL_GLYPH_TREE_TOP] = ",-",
[SPECIAL_GLYPH_VERTICAL_DOTTED] = ":", [SPECIAL_GLYPH_VERTICAL_DOTTED] = ":",
[SPECIAL_GLYPH_HORIZONTAL_DOTTED] = "-",
[SPECIAL_GLYPH_HORIZONTAL_FAT] = "=",
[SPECIAL_GLYPH_TRIANGULAR_BULLET] = ">", [SPECIAL_GLYPH_TRIANGULAR_BULLET] = ">",
[SPECIAL_GLYPH_BLACK_CIRCLE] = "*", [SPECIAL_GLYPH_BLACK_CIRCLE] = "*",
[SPECIAL_GLYPH_WHITE_CIRCLE] = "*", [SPECIAL_GLYPH_WHITE_CIRCLE] = "*",
@ -74,6 +76,10 @@ const char *special_glyph_full(SpecialGlyph code, bool force_utf) {
[SPECIAL_GLYPH_SPARKLES] = "*", [SPECIAL_GLYPH_SPARKLES] = "*",
[SPECIAL_GLYPH_LOW_BATTERY] = "!", [SPECIAL_GLYPH_LOW_BATTERY] = "!",
[SPECIAL_GLYPH_WARNING_SIGN] = "!", [SPECIAL_GLYPH_WARNING_SIGN] = "!",
[SPECIAL_GLYPH_RED_CIRCLE] = "o",
[SPECIAL_GLYPH_YELLOW_CIRCLE] = "o",
[SPECIAL_GLYPH_BLUE_CIRCLE] = "o",
[SPECIAL_GLYPH_GREEN_CIRCLE] = "o",
}, },
/* UTF-8 */ /* UTF-8 */
@ -87,6 +93,8 @@ const char *special_glyph_full(SpecialGlyph code, bool force_utf) {
/* Single glyphs in both cases */ /* Single glyphs in both cases */
[SPECIAL_GLYPH_VERTICAL_DOTTED] = u8"", [SPECIAL_GLYPH_VERTICAL_DOTTED] = u8"",
[SPECIAL_GLYPH_HORIZONTAL_DOTTED] = u8"",
[SPECIAL_GLYPH_HORIZONTAL_FAT] = u8"",
[SPECIAL_GLYPH_TRIANGULAR_BULLET] = u8"", [SPECIAL_GLYPH_TRIANGULAR_BULLET] = u8"",
[SPECIAL_GLYPH_BLACK_CIRCLE] = u8"", [SPECIAL_GLYPH_BLACK_CIRCLE] = u8"",
[SPECIAL_GLYPH_WHITE_CIRCLE] = u8"", [SPECIAL_GLYPH_WHITE_CIRCLE] = u8"",
@ -136,6 +144,11 @@ const char *special_glyph_full(SpecialGlyph code, bool force_utf) {
[SPECIAL_GLYPH_WARNING_SIGN] = u8"⚠️", [SPECIAL_GLYPH_WARNING_SIGN] = u8"⚠️",
[SPECIAL_GLYPH_COMPUTER_DISK] = u8"💽", [SPECIAL_GLYPH_COMPUTER_DISK] = u8"💽",
[SPECIAL_GLYPH_WORLD] = u8"🌍", [SPECIAL_GLYPH_WORLD] = u8"🌍",
[SPECIAL_GLYPH_RED_CIRCLE] = u8"🔴",
[SPECIAL_GLYPH_YELLOW_CIRCLE] = u8"🟡",
[SPECIAL_GLYPH_BLUE_CIRCLE] = u8"🔵",
[SPECIAL_GLYPH_GREEN_CIRCLE] = u8"🟢",
}, },
}; };

View File

@ -13,6 +13,8 @@ typedef enum SpecialGlyph {
SPECIAL_GLYPH_TREE_SPACE, SPECIAL_GLYPH_TREE_SPACE,
SPECIAL_GLYPH_TREE_TOP, SPECIAL_GLYPH_TREE_TOP,
SPECIAL_GLYPH_VERTICAL_DOTTED, SPECIAL_GLYPH_VERTICAL_DOTTED,
SPECIAL_GLYPH_HORIZONTAL_DOTTED,
SPECIAL_GLYPH_HORIZONTAL_FAT,
SPECIAL_GLYPH_TRIANGULAR_BULLET, SPECIAL_GLYPH_TRIANGULAR_BULLET,
SPECIAL_GLYPH_BLACK_CIRCLE, SPECIAL_GLYPH_BLACK_CIRCLE,
SPECIAL_GLYPH_WHITE_CIRCLE, SPECIAL_GLYPH_WHITE_CIRCLE,
@ -49,6 +51,10 @@ typedef enum SpecialGlyph {
SPECIAL_GLYPH_WARNING_SIGN, SPECIAL_GLYPH_WARNING_SIGN,
SPECIAL_GLYPH_COMPUTER_DISK, SPECIAL_GLYPH_COMPUTER_DISK,
SPECIAL_GLYPH_WORLD, SPECIAL_GLYPH_WORLD,
SPECIAL_GLYPH_RED_CIRCLE,
SPECIAL_GLYPH_YELLOW_CIRCLE,
SPECIAL_GLYPH_BLUE_CIRCLE,
SPECIAL_GLYPH_GREEN_CIRCLE,
_SPECIAL_GLYPH_MAX, _SPECIAL_GLYPH_MAX,
_SPECIAL_GLYPH_INVALID = -EINVAL, _SPECIAL_GLYPH_INVALID = -EINVAL,
} SpecialGlyph; } SpecialGlyph;

View File

@ -2120,24 +2120,27 @@ static int hashmap_entry_compare(
return compare((*a)->key, (*b)->key); return compare((*a)->key, (*b)->key);
} }
int _hashmap_dump_sorted(HashmapBase *h, void ***ret, size_t *ret_n) { static int _hashmap_dump_entries_sorted(
_cleanup_free_ struct hashmap_base_entry **entries = NULL; HashmapBase *h,
void ***ret,
size_t *ret_n) {
_cleanup_free_ void **entries = NULL;
Iterator iter; Iterator iter;
unsigned idx; unsigned idx;
size_t n = 0; size_t n = 0;
assert(ret); assert(ret);
assert(ret_n);
if (_hashmap_size(h) == 0) { if (_hashmap_size(h) == 0) {
*ret = NULL; *ret = NULL;
if (ret_n) *ret_n = 0;
*ret_n = 0;
return 0; return 0;
} }
/* We append one more element than needed so that the resulting array can be used as a strv. We /* We append one more element than needed so that the resulting array can be used as a strv. We
* don't count this entry in the returned size. */ * don't count this entry in the returned size. */
entries = new(struct hashmap_base_entry*, _hashmap_size(h) + 1); entries = new(void*, _hashmap_size(h) + 1);
if (!entries) if (!entries)
return -ENOMEM; return -ENOMEM;
@ -2147,13 +2150,47 @@ int _hashmap_dump_sorted(HashmapBase *h, void ***ret, size_t *ret_n) {
assert(n == _hashmap_size(h)); assert(n == _hashmap_size(h));
entries[n] = NULL; entries[n] = NULL;
typesafe_qsort_r(entries, n, hashmap_entry_compare, h->hash_ops->compare); typesafe_qsort_r((struct hashmap_base_entry**) entries, n,
hashmap_entry_compare, h->hash_ops->compare);
*ret = TAKE_PTR(entries);
*ret_n = n;
return 0;
}
int _hashmap_dump_keys_sorted(HashmapBase *h, void ***ret, size_t *ret_n) {
_cleanup_free_ void **entries = NULL;
size_t n;
int r;
r = _hashmap_dump_entries_sorted(h, &entries, &n);
if (r < 0)
return r;
/* Reuse the array. */ /* Reuse the array. */
FOREACH_ARRAY(e, entries, n) FOREACH_ARRAY(e, entries, n)
*e = entry_value(h, *e); *e = (void*) (*(struct hashmap_base_entry**) e)->key;
*ret = (void**) TAKE_PTR(entries); *ret = TAKE_PTR(entries);
if (ret_n)
*ret_n = n;
return 0;
}
int _hashmap_dump_sorted(HashmapBase *h, void ***ret, size_t *ret_n) {
_cleanup_free_ void **entries = NULL;
size_t n;
int r;
r = _hashmap_dump_entries_sorted(h, &entries, &n);
if (r < 0)
return r;
/* Reuse the array. */
FOREACH_ARRAY(e, entries, n)
*e = entry_value(h, *(struct hashmap_base_entry**) e);
*ret = TAKE_PTR(entries);
if (ret_n) if (ret_n)
*ret_n = n; *ret_n = n;
return 0; return 0;

View File

@ -39,8 +39,8 @@ typedef struct IteratedCache IteratedCache; /* Caches the iterated order of on
* by hashmap users, so the definition has to be here. Do not use its fields * by hashmap users, so the definition has to be here. Do not use its fields
* directly. */ * directly. */
typedef struct { typedef struct {
unsigned idx; /* index of an entry to be iterated next */
const void *next_key; /* expected value of that entry's key pointer */ const void *next_key; /* expected value of that entry's key pointer */
unsigned idx; /* index of an entry to be iterated next */
#if ENABLE_DEBUG_HASHMAP #if ENABLE_DEBUG_HASHMAP
unsigned put_count; /* hashmap's put_count recorded at start of iteration */ unsigned put_count; /* hashmap's put_count recorded at start of iteration */
unsigned rem_count; /* hashmap's rem_count in previous iteration */ unsigned rem_count; /* hashmap's rem_count in previous iteration */
@ -409,6 +409,14 @@ static inline int set_dump_sorted(Set *h, void ***ret, size_t *ret_n) {
return _hashmap_dump_sorted(HASHMAP_BASE(h), ret, ret_n); return _hashmap_dump_sorted(HASHMAP_BASE(h), ret, ret_n);
} }
int _hashmap_dump_keys_sorted(HashmapBase *h, void ***ret, size_t *ret_n);
static inline int hashmap_dump_keys_sorted(Hashmap *h, void ***ret, size_t *ret_n) {
return _hashmap_dump_keys_sorted(HASHMAP_BASE(h), ret, ret_n);
}
static inline int ordered_hashmap_dump_keys_sorted(OrderedHashmap *h, void ***ret, size_t *ret_n) {
return _hashmap_dump_keys_sorted(HASHMAP_BASE(h), ret, ret_n);
}
/* /*
* Hashmaps are iterated in unpredictable order. * Hashmaps are iterated in unpredictable order.
* OrderedHashmaps are an exception to this. They are iterated in the order * OrderedHashmaps are an exception to this. They are iterated in the order

View File

@ -91,14 +91,26 @@ bool in6_addr_is_link_local_all_nodes(const struct in6_addr *a) {
be32toh(a->s6_addr32[3]) == UINT32_C(0x00000001); be32toh(a->s6_addr32[3]) == UINT32_C(0x00000001);
} }
bool in4_addr_is_multicast(const struct in_addr *a) {
assert(a);
return IN_MULTICAST(be32toh(a->s_addr));
}
bool in6_addr_is_multicast(const struct in6_addr *a) {
assert(a);
return IN6_IS_ADDR_MULTICAST(a);
}
int in_addr_is_multicast(int family, const union in_addr_union *u) { int in_addr_is_multicast(int family, const union in_addr_union *u) {
assert(u); assert(u);
if (family == AF_INET) if (family == AF_INET)
return IN_MULTICAST(be32toh(u->in.s_addr)); return in4_addr_is_multicast(&u->in);
if (family == AF_INET6) if (family == AF_INET6)
return IN6_IS_ADDR_MULTICAST(&u->in6); return in6_addr_is_multicast(&u->in6);
return -EAFNOSUPPORT; return -EAFNOSUPPORT;
} }

View File

@ -40,6 +40,8 @@ static inline bool in_addr_data_is_set(const struct in_addr_data *a) {
return in_addr_data_is_null(a); return in_addr_data_is_null(a);
} }
bool in4_addr_is_multicast(const struct in_addr *a);
bool in6_addr_is_multicast(const struct in6_addr *a);
int in_addr_is_multicast(int family, const union in_addr_union *u); int in_addr_is_multicast(int family, const union in_addr_union *u);
bool in4_addr_is_link_local(const struct in_addr *a); bool in4_addr_is_link_local(const struct in_addr *a);

View File

@ -260,7 +260,10 @@ bool locale_is_valid(const char *name) {
if (!filename_is_valid(name)) if (!filename_is_valid(name))
return false; return false;
if (!string_is_safe(name)) /* Locales look like: ll_CC.ENC@variant, where ll and CC are alphabetic, ENC is alphanumeric with
* dashes, and variant seems to be alphabetic.
* See: https://www.gnu.org/software/gettext/manual/html_node/Locale-Names.html */
if (!in_charset(name, ALPHANUMERICAL "_.-@"))
return false; return false;
return true; return true;
@ -292,7 +295,7 @@ bool is_locale_utf8(void) {
if (cached_answer >= 0) if (cached_answer >= 0)
goto out; goto out;
r = getenv_bool_secure("SYSTEMD_UTF8"); r = secure_getenv_bool("SYSTEMD_UTF8");
if (r >= 0) { if (r >= 0) {
cached_answer = r; cached_answer = r;
goto out; goto out;

View File

@ -383,7 +383,7 @@ typedef struct LogRateLimit {
RateLimit ratelimit; RateLimit ratelimit;
} LogRateLimit; } LogRateLimit;
#define log_ratelimit_internal(_level, _error, _ratelimit, _format, _file, _line, _func, ...) \ #define log_ratelimit_internal(_level, _error, _ratelimit, _file, _line, _func, _format, ...) \
({ \ ({ \
int _log_ratelimit_error = (_error); \ int _log_ratelimit_error = (_error); \
int _log_ratelimit_level = (_level); \ int _log_ratelimit_level = (_level); \
@ -407,7 +407,7 @@ typedef struct LogRateLimit {
({ \ ({ \
int _level = (level), _e = (error); \ int _level = (level), _e = (error); \
_e = (log_get_max_level() >= LOG_PRI(_level)) \ _e = (log_get_max_level() >= LOG_PRI(_level)) \
? log_ratelimit_internal(_level, _e, _ratelimit, format, PROJECT_FILE, __LINE__, __func__, ##__VA_ARGS__) \ ? log_ratelimit_internal(_level, _e, _ratelimit, PROJECT_FILE, __LINE__, __func__, format, ##__VA_ARGS__) \
: -ERRNO_VALUE(_e); \ : -ERRNO_VALUE(_e); \
_e < 0 ? _e : -ESTRPIPE; \ _e < 0 ? _e : -ESTRPIPE; \
}) })

View File

@ -69,9 +69,26 @@
/* So O_LARGEFILE is generally implied by glibc, and defined to zero hence, because we only build in LFS /* So O_LARGEFILE is generally implied by glibc, and defined to zero hence, because we only build in LFS
* mode. However, when invoking fcntl(F_GETFL) the flag is ORed into the result anyway glibc does not mask * mode. However, when invoking fcntl(F_GETFL) the flag is ORed into the result anyway glibc does not mask
* it away. Which sucks. Let's define the actual value here, so that we can mask it ourselves. */ * it away. Which sucks. Let's define the actual value here, so that we can mask it ourselves.
*
* The precise definition is arch specific, so we use the values defined in the kernel (note that some
* are hexa and others are octal; duplicated as-is from the kernel definitions):
* - alpha, arm, arm64, m68k, mips, parisc, powerpc, sparc: each has a specific value;
* - others: they use the "generic" value (defined in include/uapi/asm-generic/fcntl.h) */
#if O_LARGEFILE != 0 #if O_LARGEFILE != 0
#define RAW_O_LARGEFILE O_LARGEFILE #define RAW_O_LARGEFILE O_LARGEFILE
#else #else
#define RAW_O_LARGEFILE 0100000 #if defined(__alpha__) || defined(__arm__) || defined(__aarch64__) || defined(__m68k__)
#define RAW_O_LARGEFILE 0400000
#elif defined(__mips__)
#define RAW_O_LARGEFILE 0x2000
#elif defined(__parisc__) || defined(__hppa__)
#define RAW_O_LARGEFILE 000004000
#elif defined(__powerpc__)
#define RAW_O_LARGEFILE 0200000
#elif defined(__sparc__)
#define RAW_O_LARGEFILE 0x40000
#else
#define RAW_O_LARGEFILE 00100000
#endif
#endif #endif

View File

@ -412,23 +412,14 @@ static inline int missing_execveat(int dirfd, const char *pathname,
/* ======================================================================= */ /* ======================================================================= */
#if !HAVE_CLOSE_RANGE #if !HAVE_CLOSE_RANGE
static inline int missing_close_range(int first_fd, int end_fd, unsigned flags) { static inline int missing_close_range(unsigned first_fd, unsigned end_fd, unsigned flags) {
# ifdef __NR_close_range # ifdef __NR_close_range
/* Kernel-side the syscall expects fds as unsigned integers (just like close() actually), while /* Kernel-side the syscall expects fds as unsigned integers (just like close() actually), while
* userspace exclusively uses signed integers for fds. We don't know just yet how glibc is going to * userspace exclusively uses signed integers for fds. glibc chose to expose it 1:1 however, hence we
* wrap this syscall, but let's assume it's going to be similar to what they do for close(), * do so here too, even if we end up passing signed fds to it most of the time. */
* i.e. make the same unsigned signed type change from the raw kernel syscall compared to the
* userspace wrapper. There's only one caveat for this: unlike for close() there's the special
* UINT_MAX fd value for the 'end_fd' argument. Let's safely map that to -1 here. And let's refuse
* any other negative values. */
if ((first_fd < 0) || (end_fd < 0 && end_fd != -1)) {
errno = -EBADF;
return -1;
}
return syscall(__NR_close_range, return syscall(__NR_close_range,
(unsigned) first_fd, first_fd,
end_fd == -1 ? UINT_MAX : (unsigned) end_fd, /* Of course, the compiler should figure out that this is the identity mapping IRL */ end_fd,
flags); flags);
# else # else
errno = ENOSYS; errno = ENOSYS;

View File

@ -53,3 +53,5 @@ static inline bool userns_shift_range_valid(uid_t shift, uid_t range) {
int userns_acquire(const char *uid_map, const char *gid_map); int userns_acquire(const char *uid_map, const char *gid_map);
int netns_acquire(void); int netns_acquire(void);
int in_same_namespace(pid_t pid1, pid_t pid2, NamespaceType type); int in_same_namespace(pid_t pid1, pid_t pid2, NamespaceType type);
int parse_userns_uid_range(const char *s, uid_t *ret_uid_shift, uid_t *ret_uid_range);

View File

@ -510,7 +510,7 @@ static int get_process_link_contents(pid_t pid, const char *proc_file, char **re
p = procfs_file_alloca(pid, proc_file); p = procfs_file_alloca(pid, proc_file);
r = readlink_malloc(p, ret); r = readlink_malloc(p, ret);
return r == -ENOENT ? -ESRCH : r; return (r == -ENOENT && proc_mounted() > 0) ? -ESRCH : r;
} }
int get_process_exe(pid_t pid, char **ret) { int get_process_exe(pid_t pid, char **ret) {
@ -1303,7 +1303,7 @@ int opinionated_personality(unsigned long *ret) {
if (current < 0) if (current < 0)
return current; return current;
if (((unsigned long) current & 0xffff) == PER_LINUX32) if (((unsigned long) current & OPINIONATED_PERSONALITY_MASK) == PER_LINUX32)
*ret = PER_LINUX32; *ret = PER_LINUX32;
else else
*ret = PER_LINUX; *ret = PER_LINUX;
@ -1468,7 +1468,7 @@ static int fork_flags_to_signal(ForkFlags flags) {
int safe_fork_full( int safe_fork_full(
const char *name, const char *name,
const int stdio_fds[3], const int stdio_fds[3],
const int except_fds[], int except_fds[],
size_t n_except_fds, size_t n_except_fds,
ForkFlags flags, ForkFlags flags,
pid_t *ret_pid) { pid_t *ret_pid) {
@ -1697,6 +1697,19 @@ int safe_fork_full(
} }
} }
if (flags & FORK_PACK_FDS) {
/* FORK_CLOSE_ALL_FDS ensures that except_fds are the only FDs >= 3 that are
* open, this is including the log. This is required by pack_fds, which will
* get stuck in an infinite loop of any FDs other than except_fds are open. */
assert(FLAGS_SET(flags, FORK_CLOSE_ALL_FDS));
r = pack_fds(except_fds, n_except_fds);
if (r < 0) {
log_full_errno(prio, r, "Failed to pack file descriptors: %m");
_exit(EXIT_FAILURE);
}
}
if (flags & FORK_CLOEXEC_OFF) { if (flags & FORK_CLOEXEC_OFF) {
r = fd_cloexec_many(except_fds, n_except_fds, false); r = fd_cloexec_many(except_fds, n_except_fds, false);
if (r < 0) { if (r < 0) {
@ -1736,7 +1749,7 @@ int safe_fork_full(
int pidref_safe_fork_full( int pidref_safe_fork_full(
const char *name, const char *name,
const int stdio_fds[3], const int stdio_fds[3],
const int except_fds[], int except_fds[],
size_t n_except_fds, size_t n_except_fds,
ForkFlags flags, ForkFlags flags,
PidRef *ret_pid) { PidRef *ret_pid) {
@ -1760,7 +1773,7 @@ int pidref_safe_fork_full(
int namespace_fork( int namespace_fork(
const char *outer_name, const char *outer_name,
const char *inner_name, const char *inner_name,
const int except_fds[], int except_fds[],
size_t n_except_fds, size_t n_except_fds,
ForkFlags flags, ForkFlags flags,
int pidns_fd, int pidns_fd,

View File

@ -101,12 +101,17 @@ bool is_main_thread(void);
bool oom_score_adjust_is_valid(int oa); bool oom_score_adjust_is_valid(int oa);
#ifndef PERSONALITY_INVALID #ifndef PERSONALITY_INVALID
/* personality(7) documents that 0xffffffffUL is used for querying the /* personality(2) documents that 0xFFFFFFFFUL is used for querying the
* current personality, hence let's use that here as error * current personality, hence let's use that here as error
* indicator. */ * indicator. */
#define PERSONALITY_INVALID 0xffffffffLU #define PERSONALITY_INVALID 0xFFFFFFFFUL
#endif #endif
/* The personality() syscall returns a 32-bit value where the top three bytes are reserved for flags that
* emulate historical or architectural quirks, and only the least significant byte reflects the actual
* personality we're interested in. */
#define OPINIONATED_PERSONALITY_MASK 0xFFUL
unsigned long personality_from_string(const char *p); unsigned long personality_from_string(const char *p);
const char *personality_to_string(unsigned long); const char *personality_to_string(unsigned long);
@ -180,12 +185,13 @@ typedef enum ForkFlags {
FORK_KEEP_NOTIFY_SOCKET = 1 << 17, /* Unless this specified, $NOTIFY_SOCKET will be unset. */ FORK_KEEP_NOTIFY_SOCKET = 1 << 17, /* Unless this specified, $NOTIFY_SOCKET will be unset. */
FORK_DETACH = 1 << 18, /* Double fork if needed to ensure PID1/subreaper is parent */ FORK_DETACH = 1 << 18, /* Double fork if needed to ensure PID1/subreaper is parent */
FORK_NEW_NETNS = 1 << 19, /* Run child in its own network namespace 💣 DO NOT USE IN THREADED PROGRAMS! 💣 */ FORK_NEW_NETNS = 1 << 19, /* Run child in its own network namespace 💣 DO NOT USE IN THREADED PROGRAMS! 💣 */
FORK_PACK_FDS = 1 << 20, /* Rearrange the passed FDs to be FD 3,4,5,etc. Updates the array in place (combine with FORK_CLOSE_ALL_FDS!) */
} ForkFlags; } ForkFlags;
int safe_fork_full( int safe_fork_full(
const char *name, const char *name,
const int stdio_fds[3], const int stdio_fds[3],
const int except_fds[], int except_fds[],
size_t n_except_fds, size_t n_except_fds,
ForkFlags flags, ForkFlags flags,
pid_t *ret_pid); pid_t *ret_pid);
@ -197,7 +203,7 @@ static inline int safe_fork(const char *name, ForkFlags flags, pid_t *ret_pid) {
int pidref_safe_fork_full( int pidref_safe_fork_full(
const char *name, const char *name,
const int stdio_fds[3], const int stdio_fds[3],
const int except_fds[], int except_fds[],
size_t n_except_fds, size_t n_except_fds,
ForkFlags flags, ForkFlags flags,
PidRef *ret_pid); PidRef *ret_pid);
@ -206,7 +212,18 @@ static inline int pidref_safe_fork(const char *name, ForkFlags flags, PidRef *re
return pidref_safe_fork_full(name, NULL, NULL, 0, flags, ret_pid); return pidref_safe_fork_full(name, NULL, NULL, 0, flags, ret_pid);
} }
int namespace_fork(const char *outer_name, const char *inner_name, const int except_fds[], size_t n_except_fds, ForkFlags flags, int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int root_fd, pid_t *ret_pid); int namespace_fork(
const char *outer_name,
const char *inner_name,
int except_fds[],
size_t n_except_fds,
ForkFlags flags,
int pidns_fd,
int mntns_fd,
int netns_fd,
int userns_fd,
int root_fd,
pid_t *ret_pid);
int set_oom_score_adjust(int value); int set_oom_score_adjust(int value);
int get_oom_score_adjust(int *ret); int get_oom_score_adjust(int *ret);

View File

@ -18,7 +18,7 @@ int reset_all_signal_handlers(void) {
.sa_handler = SIG_DFL, .sa_handler = SIG_DFL,
.sa_flags = SA_RESTART, .sa_flags = SA_RESTART,
}; };
int r = 0; int ret = 0, r;
for (int sig = 1; sig < _NSIG; sig++) { for (int sig = 1; sig < _NSIG; sig++) {
@ -26,14 +26,14 @@ int reset_all_signal_handlers(void) {
if (IN_SET(sig, SIGKILL, SIGSTOP)) if (IN_SET(sig, SIGKILL, SIGSTOP))
continue; continue;
/* On Linux the first two RT signals are reserved by /* On Linux the first two RT signals are reserved by glibc, and sigaction() will return
* glibc, and sigaction() will return EINVAL for them. */ * EINVAL for them. */
if (sigaction(sig, &sa, NULL) < 0) r = RET_NERRNO(sigaction(sig, &sa, NULL));
if (errno != EINVAL && r >= 0) if (r != -EINVAL)
r = -errno; RET_GATHER(ret, r);
} }
return r; return ret;
} }
int reset_signal_mask(void) { int reset_signal_mask(void) {
@ -57,10 +57,7 @@ int sigaction_many_internal(const struct sigaction *sa, ...) {
if (sig == 0) if (sig == 0)
continue; continue;
if (sigaction(sig, sa, NULL) < 0) { RET_GATHER(r, RET_NERRNO(sigaction(sig, sa, NULL)));
if (r >= 0)
r = -errno;
}
} }
va_end(ap); va_end(ap);
@ -87,7 +84,7 @@ static int sigset_add_many_ap(sigset_t *ss, va_list ap) {
return r; return r;
} }
int sigset_add_many(sigset_t *ss, ...) { int sigset_add_many_internal(sigset_t *ss, ...) {
va_list ap; va_list ap;
int r; int r;
@ -98,7 +95,7 @@ int sigset_add_many(sigset_t *ss, ...) {
return r; return r;
} }
int sigprocmask_many(int how, sigset_t *old, ...) { int sigprocmask_many_internal(int how, sigset_t *old, ...) {
va_list ap; va_list ap;
sigset_t ss; sigset_t ss;
int r; int r;
@ -113,10 +110,7 @@ int sigprocmask_many(int how, sigset_t *old, ...) {
if (r < 0) if (r < 0)
return r; return r;
if (sigprocmask(how, &ss, old) < 0) return RET_NERRNO(sigprocmask(how, &ss, old));
return -errno;
return 0;
} }
static const char *const static_signal_table[] = { static const char *const static_signal_table[] = {

View File

@ -31,8 +31,11 @@ int sigaction_many_internal(const struct sigaction *sa, ...);
#define sigaction_many(sa, ...) \ #define sigaction_many(sa, ...) \
sigaction_many_internal(sa, __VA_ARGS__, -1) sigaction_many_internal(sa, __VA_ARGS__, -1)
int sigset_add_many(sigset_t *ss, ...); int sigset_add_many_internal(sigset_t *ss, ...);
int sigprocmask_many(int how, sigset_t *old, ...); #define sigset_add_many(...) sigset_add_many_internal(__VA_ARGS__, -1)
int sigprocmask_many_internal(int how, sigset_t *old, ...);
#define sigprocmask_many(...) sigprocmask_many_internal(__VA_ARGS__, -1)
const char *signal_to_string(int i) _const_; const char *signal_to_string(int i) _const_;
int signal_from_string(const char *s) _pure_; int signal_from_string(const char *s) _pure_;
@ -46,7 +49,7 @@ static inline void block_signals_reset(sigset_t *ss) {
#define BLOCK_SIGNALS(...) \ #define BLOCK_SIGNALS(...) \
_cleanup_(block_signals_reset) _unused_ sigset_t _saved_sigset = ({ \ _cleanup_(block_signals_reset) _unused_ sigset_t _saved_sigset = ({ \
sigset_t _t; \ sigset_t _t; \
assert_se(sigprocmask_many(SIG_BLOCK, &_t, __VA_ARGS__, -1) >= 0); \ assert_se(sigprocmask_many(SIG_BLOCK, &_t, __VA_ARGS__) >= 0); \
_t; \ _t; \
}) })

View File

@ -25,43 +25,130 @@
#include "stat-util.h" #include "stat-util.h"
#include "string-util.h" #include "string-util.h"
int is_symlink(const char *path) { static int verify_stat_at(
struct stat info; int fd,
const char *path,
bool follow,
int (*verify_func)(const struct stat *st),
bool verify) {
assert(path);
if (lstat(path, &info) < 0)
return -errno;
return !!S_ISLNK(info.st_mode);
}
int is_dir_full(int atfd, const char* path, bool follow) {
struct stat st; struct stat st;
int r; int r;
assert(atfd >= 0 || atfd == AT_FDCWD); assert(fd >= 0 || fd == AT_FDCWD);
assert(atfd >= 0 || path); assert(!isempty(path) || !follow);
assert(verify_func);
if (path) if (fstatat(fd, strempty(path), &st,
r = fstatat(atfd, path, &st, follow ? 0 : AT_SYMLINK_NOFOLLOW); (isempty(path) ? AT_EMPTY_PATH : 0) | (follow ? 0 : AT_SYMLINK_NOFOLLOW)) < 0)
else
r = fstat(atfd, &st);
if (r < 0)
return -errno; return -errno;
return !!S_ISDIR(st.st_mode); r = verify_func(&st);
return verify ? r : r >= 0;
}
int stat_verify_regular(const struct stat *st) {
assert(st);
/* Checks whether the specified stat() structure refers to a regular file. If not returns an
* appropriate error code. */
if (S_ISDIR(st->st_mode))
return -EISDIR;
if (S_ISLNK(st->st_mode))
return -ELOOP;
if (!S_ISREG(st->st_mode))
return -EBADFD;
return 0;
}
int verify_regular_at(int fd, const char *path, bool follow) {
return verify_stat_at(fd, path, follow, stat_verify_regular, true);
}
int fd_verify_regular(int fd) {
assert(fd >= 0);
return verify_regular_at(fd, NULL, false);
}
int stat_verify_directory(const struct stat *st) {
assert(st);
if (S_ISLNK(st->st_mode))
return -ELOOP;
if (!S_ISDIR(st->st_mode))
return -ENOTDIR;
return 0;
}
int fd_verify_directory(int fd) {
assert(fd >= 0);
return verify_stat_at(fd, NULL, false, stat_verify_directory, true);
}
int is_dir_at(int fd, const char *path, bool follow) {
return verify_stat_at(fd, path, follow, stat_verify_directory, false);
}
int is_dir(const char *path, bool follow) {
assert(!isempty(path));
return is_dir_at(AT_FDCWD, path, follow);
}
int stat_verify_symlink(const struct stat *st) {
assert(st);
if (S_ISDIR(st->st_mode))
return -EISDIR;
if (!S_ISLNK(st->st_mode))
return -ENOLINK;
return 0;
}
int is_symlink(const char *path) {
assert(!isempty(path));
return verify_stat_at(AT_FDCWD, path, false, stat_verify_symlink, false);
}
int stat_verify_linked(const struct stat *st) {
assert(st);
if (st->st_nlink <= 0)
return -EIDRM; /* recognizable error. */
return 0;
}
int fd_verify_linked(int fd) {
assert(fd >= 0);
return verify_stat_at(fd, NULL, false, stat_verify_linked, true);
}
int stat_verify_device_node(const struct stat *st) {
assert(st);
if (S_ISLNK(st->st_mode))
return -ELOOP;
if (S_ISDIR(st->st_mode))
return -EISDIR;
if (!S_ISBLK(st->st_mode) && !S_ISCHR(st->st_mode))
return -ENOTTY;
return 0;
} }
int is_device_node(const char *path) { int is_device_node(const char *path) {
struct stat info; assert(!isempty(path));
return verify_stat_at(AT_FDCWD, path, false, stat_verify_device_node, false);
assert(path);
if (lstat(path, &info) < 0)
return -errno;
return !!(S_ISBLK(info.st_mode) || S_ISCHR(info.st_mode));
} }
int dir_is_empty_at(int dir_fd, const char *path, bool ignore_hidden_or_backup) { int dir_is_empty_at(int dir_fd, const char *path, bool ignore_hidden_or_backup) {
@ -260,70 +347,6 @@ int path_is_network_fs(const char *path) {
return is_network_fs(&s); return is_network_fs(&s);
} }
int stat_verify_regular(const struct stat *st) {
assert(st);
/* Checks whether the specified stat() structure refers to a regular file. If not returns an appropriate error
* code. */
if (S_ISDIR(st->st_mode))
return -EISDIR;
if (S_ISLNK(st->st_mode))
return -ELOOP;
if (!S_ISREG(st->st_mode))
return -EBADFD;
return 0;
}
int fd_verify_regular(int fd) {
struct stat st;
assert(fd >= 0);
if (fstat(fd, &st) < 0)
return -errno;
return stat_verify_regular(&st);
}
int verify_regular_at(int dir_fd, const char *path, bool follow) {
struct stat st;
assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
assert(path);
if (fstatat(dir_fd, path, &st, (isempty(path) ? AT_EMPTY_PATH : 0) | (follow ? 0 : AT_SYMLINK_NOFOLLOW)) < 0)
return -errno;
return stat_verify_regular(&st);
}
int stat_verify_directory(const struct stat *st) {
assert(st);
if (S_ISLNK(st->st_mode))
return -ELOOP;
if (!S_ISDIR(st->st_mode))
return -ENOTDIR;
return 0;
}
int fd_verify_directory(int fd) {
struct stat st;
assert(fd >= 0);
if (fstat(fd, &st) < 0)
return -errno;
return stat_verify_directory(&st);
}
int proc_mounted(void) { int proc_mounted(void) {
int r; int r;
@ -468,7 +491,7 @@ int xstatfsat(int dir_fd, const char *path, struct statfs *ret) {
assert(dir_fd >= 0 || dir_fd == AT_FDCWD); assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
assert(ret); assert(ret);
fd = xopenat(dir_fd, path, O_PATH|O_CLOEXEC|O_NOCTTY, /* xopen_flags = */ 0, /* mode = */ 0); fd = xopenat(dir_fd, path, O_PATH|O_CLOEXEC|O_NOCTTY);
if (fd < 0) if (fd < 0)
return fd; return fd;

View File

@ -14,14 +14,22 @@
#include "siphash24.h" #include "siphash24.h"
#include "time-util.h" #include "time-util.h"
int stat_verify_regular(const struct stat *st);
int verify_regular_at(int fd, const char *path, bool follow);
int fd_verify_regular(int fd);
int stat_verify_directory(const struct stat *st);
int fd_verify_directory(int fd);
int is_dir_at(int fd, const char *path, bool follow);
int is_dir(const char *path, bool follow);
int stat_verify_symlink(const struct stat *st);
int is_symlink(const char *path); int is_symlink(const char *path);
int is_dir_full(int atfd, const char *fname, bool follow);
static inline int is_dir(const char *path, bool follow) { int stat_verify_linked(const struct stat *st);
return is_dir_full(AT_FDCWD, path, follow); int fd_verify_linked(int fd);
}
static inline int is_dir_fd(int fd) { int stat_verify_device_node(const struct stat *st);
return is_dir_full(fd, NULL, false);
}
int is_device_node(const char *path); int is_device_node(const char *path);
int dir_is_empty_at(int dir_fd, const char *path, bool ignore_hidden_or_backup); int dir_is_empty_at(int dir_fd, const char *path, bool ignore_hidden_or_backup);
@ -72,13 +80,6 @@ int path_is_network_fs(const char *path);
*/ */
#define F_TYPE_EQUAL(a, b) (a == (typeof(a)) b) #define F_TYPE_EQUAL(a, b) (a == (typeof(a)) b)
int stat_verify_regular(const struct stat *st);
int fd_verify_regular(int fd);
int verify_regular_at(int dir_fd, const char *path, bool follow);
int stat_verify_directory(const struct stat *st);
int fd_verify_directory(int fd);
int proc_mounted(void); 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);

View File

@ -620,6 +620,9 @@ char *cellescape(char *buf, size_t len, const char *s) {
char* strshorten(char *s, size_t l) { char* strshorten(char *s, size_t l) {
assert(s); assert(s);
if (l >= SIZE_MAX-1) /* Would not change anything */
return s;
if (strnlen(s, l+1) > l) if (strnlen(s, l+1) > l)
s[l] = 0; s[l] = 0;

View File

@ -358,7 +358,7 @@ int strv_split_colon_pairs(char ***t, const char *s) {
const char *p = tuple; const char *p = tuple;
r = extract_many_words(&p, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, r = extract_many_words(&p, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS,
&first, &second, NULL); &first, &second);
if (r < 0) if (r < 0)
return r; return r;
if (r == 0) if (r == 0)

View File

@ -1429,7 +1429,7 @@ static int get_timezones_from_zone1970_tab(char ***ret) {
/* Line format is: /* Line format is:
* 'country codes' 'coordinates' 'timezone' 'comments' */ * 'country codes' 'coordinates' 'timezone' 'comments' */
r = extract_many_words(&p, NULL, 0, &cc, &co, &tz, NULL); r = extract_many_words(&p, NULL, 0, &cc, &co, &tz);
if (r < 0) if (r < 0)
continue; continue;
@ -1474,7 +1474,7 @@ static int get_timezones_from_tzdata_zi(char ***ret) {
* Link line format is: * Link line format is:
* 'Link' 'target' 'alias' * 'Link' 'target' 'alias'
* See 'man zic' for more detail. */ * See 'man zic' for more detail. */
r = extract_many_words(&p, NULL, 0, &type, &f1, &f2, NULL); r = extract_many_words(&p, NULL, 0, &type, &f1, &f2);
if (r < 0) if (r < 0)
continue; continue;
@ -1573,7 +1573,7 @@ int verify_timezone(const char *name, int log_level) {
r = fd_verify_regular(fd); r = fd_verify_regular(fd);
if (r < 0) if (r < 0)
return log_full_errno(log_level, r, "Timezone file '%s' is not a regular file: %m", t); return log_full_errno(log_level, r, "Timezone file '%s' is not a regular file: %m", t);
r = loop_read_exact(fd, buf, 4, false); r = loop_read_exact(fd, buf, 4, false);
if (r < 0) if (r < 0)

View File

@ -249,6 +249,30 @@
CONST_ISPOWEROF2(_x); \ CONST_ISPOWEROF2(_x); \
})) }))
#define ADD_SAFE(ret, a, b) (!__builtin_add_overflow(a, b, ret))
#define INC_SAFE(a, b) __INC_SAFE(UNIQ, a, b)
#define __INC_SAFE(q, a, b) \
({ \
const typeof(a) UNIQ_T(A, q) = (a); \
ADD_SAFE(UNIQ_T(A, q), *UNIQ_T(A, q), b); \
})
#define SUB_SAFE(ret, a, b) (!__builtin_sub_overflow(a, b, ret))
#define DEC_SAFE(a, b) __DEC_SAFE(UNIQ, a, b)
#define __DEC_SAFE(q, a, b) \
({ \
const typeof(a) UNIQ_T(A, q) = (a); \
SUB_SAFE(UNIQ_T(A, q), *UNIQ_T(A, q), b); \
})
#define MUL_SAFE(ret, a, b) (!__builtin_mul_overflow(a, b, ret))
#define MUL_ASSIGN_SAFE(a, b) __MUL_ASSIGN_SAFE(UNIQ, a, b)
#define __MUL_ASSIGN_SAFE(q, a, b) \
({ \
const typeof(a) UNIQ_T(A, q) = (a); \
MUL_SAFE(UNIQ_T(A, q), *UNIQ_T(A, q), b); \
})
#define LESS_BY(a, b) __LESS_BY(UNIQ, (a), UNIQ, (b)) #define LESS_BY(a, b) __LESS_BY(UNIQ, (a), UNIQ, (b))
#define __LESS_BY(aq, a, bq, b) \ #define __LESS_BY(aq, a, bq, b) \
({ \ ({ \
@ -298,7 +322,7 @@
const typeof(y) UNIQ_T(A, q) = (y); \ const typeof(y) UNIQ_T(A, q) = (y); \
const typeof(x) UNIQ_T(B, q) = DIV_ROUND_UP((x), UNIQ_T(A, q)); \ const typeof(x) UNIQ_T(B, q) = DIV_ROUND_UP((x), UNIQ_T(A, q)); \
typeof(x) UNIQ_T(C, q); \ typeof(x) UNIQ_T(C, q); \
__builtin_mul_overflow(UNIQ_T(B, q), UNIQ_T(A, q), &UNIQ_T(C, q)) ? (typeof(x)) -1 : UNIQ_T(C, q); \ MUL_SAFE(&UNIQ_T(C, q), UNIQ_T(B, q), UNIQ_T(A, q)) ? UNIQ_T(C, q) : (typeof(x)) -1; \
}) })
#define ROUND_UP(x, y) __ROUND_UP(UNIQ, (x), (y)) #define ROUND_UP(x, y) __ROUND_UP(UNIQ, (x), (y))

View File

@ -1,278 +0,0 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
/* Stolen from glibc and converted to our style. In glibc it comes with the following copyright blurb: */
/* Functions to compute SHA256 message digest of files or memory blocks.
according to the definition of SHA256 in FIPS 180-2.
Copyright (C) 2007-2022 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
#include <stdbool.h>
#if SD_BOOT
# include "efi-string.h"
#else
# include <string.h>
#endif
#include "macro-fundamental.h"
#include "sha256.h"
#include "unaligned-fundamental.h"
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
# define SWAP(n) \
__builtin_bswap32(n)
# define SWAP64(n) \
__builtin_bswap64(n)
#else
# define SWAP(n) (n)
# define SWAP64(n) (n)
#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. */
uint8_t *sha256_finish_ctx(struct sha256_ctx *ctx, uint8_t resbuf[static SHA256_DIGEST_SIZE]) {
/* 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)
unaligned_write_ne32(resbuf + i * sizeof(uint32_t), 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 (IS_ALIGNED32(buffer)) {
sha256_process_block(buffer, len & ~63, ctx);
buffer = (const char *) buffer + (len & ~63);
len &= 63;
} else
while (len > 64) {
memcpy(ctx->buffer, buffer, 64);
sha256_process_block(ctx->buffer, 64, ctx);
buffer = (const char *) buffer + 64;
len -= 64;
}
}
/* 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 = ASSERT_PTR(buffer);
size_t nwords = len / sizeof(uint32_t);
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;
}
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);
}

View File

@ -1,39 +0,0 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <stddef.h>
#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);
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);
static inline void sha256_process_bytes_and_size(const void *buffer, size_t len, struct sha256_ctx *ctx) {
sha256_process_bytes(&len, sizeof(len), ctx);
sha256_process_bytes(buffer, len, 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]) {})