mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2026-02-03 14:50:30 +01:00
systemd: merge branch systemd into main
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/1529
This commit is contained in:
commit
5973e83160
99 changed files with 2216 additions and 1463 deletions
15
Makefile.am
15
Makefile.am
|
|
@ -399,6 +399,7 @@ src_libnm_std_aux_libnm_std_aux_la_SOURCES = \
|
|||
src/libnm-std-aux/nm-std-aux.h \
|
||||
src/libnm-std-aux/nm-std-utils.c \
|
||||
src/libnm-std-aux/nm-std-utils.h \
|
||||
src/libnm-std-aux/unaligned-fundamental.h \
|
||||
src/libnm-std-aux/unaligned.h \
|
||||
$(NULL)
|
||||
|
||||
|
|
@ -2302,12 +2303,12 @@ src_libnm_systemd_shared_libnm_systemd_shared_la_SOURCES = \
|
|||
src/libnm-systemd-shared/nm-sd-utils-shared.c \
|
||||
src/libnm-systemd-shared/nm-sd-utils-shared.h \
|
||||
src/libnm-systemd-shared/sd-adapt-shared/architecture.h \
|
||||
src/libnm-systemd-shared/sd-adapt-shared/argv-util.h \
|
||||
src/libnm-systemd-shared/sd-adapt-shared/arphrd-list.h \
|
||||
src/libnm-systemd-shared/sd-adapt-shared/blockdev-util.h \
|
||||
src/libnm-systemd-shared/sd-adapt-shared/build.h \
|
||||
src/libnm-systemd-shared/sd-adapt-shared/chase-symlinks.h \
|
||||
src/libnm-systemd-shared/sd-adapt-shared/copy.h \
|
||||
src/libnm-systemd-shared/sd-adapt-shared/def.h \
|
||||
src/libnm-systemd-shared/sd-adapt-shared/dhcp-server-internal.h \
|
||||
src/libnm-systemd-shared/sd-adapt-shared/dirent-util.h \
|
||||
src/libnm-systemd-shared/sd-adapt-shared/errno-list.h \
|
||||
|
|
@ -2327,6 +2328,7 @@ src_libnm_systemd_shared_libnm_systemd_shared_la_SOURCES = \
|
|||
src/libnm-systemd-shared/sd-adapt-shared/missing_syscall_def.h \
|
||||
src/libnm-systemd-shared/sd-adapt-shared/missing_timerfd.h \
|
||||
src/libnm-systemd-shared/sd-adapt-shared/mkdir.h \
|
||||
src/libnm-systemd-shared/sd-adapt-shared/mountpoint-util.h \
|
||||
src/libnm-systemd-shared/sd-adapt-shared/namespace-util.h \
|
||||
src/libnm-systemd-shared/sd-adapt-shared/netif-util.h \
|
||||
src/libnm-systemd-shared/sd-adapt-shared/nm-sd-adapt-shared.h \
|
||||
|
|
@ -2337,12 +2339,14 @@ src_libnm_systemd_shared_libnm_systemd_shared_la_SOURCES = \
|
|||
src/libnm-systemd-shared/sd-adapt-shared/sync-util.h \
|
||||
src/libnm-systemd-shared/sd-adapt-shared/sysctl-util.h \
|
||||
src/libnm-systemd-shared/sd-adapt-shared/terminal-util.h \
|
||||
src/libnm-systemd-shared/sd-adapt-shared/unaligned-fundamental.h \
|
||||
src/libnm-systemd-shared/sd-adapt-shared/unaligned.h \
|
||||
src/libnm-systemd-shared/sd-adapt-shared/virt.h \
|
||||
src/libnm-systemd-shared/src/basic/alloc-util.c \
|
||||
src/libnm-systemd-shared/src/basic/alloc-util.h \
|
||||
src/libnm-systemd-shared/src/basic/async.h \
|
||||
src/libnm-systemd-shared/src/basic/cgroup-util.h \
|
||||
src/libnm-systemd-shared/src/basic/constants.h \
|
||||
src/libnm-systemd-shared/src/basic/dns-def.h \
|
||||
src/libnm-systemd-shared/src/basic/env-file.c \
|
||||
src/libnm-systemd-shared/src/basic/env-file.h \
|
||||
|
|
@ -2383,6 +2387,7 @@ src_libnm_systemd_shared_libnm_systemd_shared_la_SOURCES = \
|
|||
src/libnm-systemd-shared/src/basic/locale-util.c \
|
||||
src/libnm-systemd-shared/src/basic/locale-util.h \
|
||||
src/libnm-systemd-shared/src/basic/log.h \
|
||||
src/libnm-systemd-shared/src/basic/logarithm.h \
|
||||
src/libnm-systemd-shared/src/basic/macro.h \
|
||||
src/libnm-systemd-shared/src/basic/memory-util.c \
|
||||
src/libnm-systemd-shared/src/basic/memory-util.h \
|
||||
|
|
@ -2435,9 +2440,8 @@ src_libnm_systemd_shared_libnm_systemd_shared_la_SOURCES = \
|
|||
src/libnm-systemd-shared/src/basic/user-util.h \
|
||||
src/libnm-systemd-shared/src/basic/utf8.c \
|
||||
src/libnm-systemd-shared/src/basic/utf8.h \
|
||||
src/libnm-systemd-shared/src/basic/util.c \
|
||||
src/libnm-systemd-shared/src/basic/util.h \
|
||||
src/libnm-systemd-shared/src/fundamental/macro-fundamental.h \
|
||||
src/libnm-systemd-shared/src/fundamental/memory-util-fundamental.h \
|
||||
src/libnm-systemd-shared/src/fundamental/sha256.c \
|
||||
src/libnm-systemd-shared/src/fundamental/sha256.h \
|
||||
src/libnm-systemd-shared/src/fundamental/string-util-fundamental.c \
|
||||
|
|
@ -2463,6 +2467,7 @@ src_libnm_systemd_core_libnm_systemd_core_la_cppflags = \
|
|||
-I$(srcdir)/src/libnm-systemd-core/sd-adapt-core \
|
||||
-I$(srcdir)/src/libnm-systemd-core/src/systemd \
|
||||
-I$(srcdir)/src/libnm-systemd-core/src/libsystemd-network \
|
||||
-I$(srcdir)/src/libnm-systemd-core/src/libsystemd/sd-device \
|
||||
-I$(srcdir)/src/libnm-systemd-core/src/libsystemd/sd-event \
|
||||
$(NULL)
|
||||
|
||||
|
|
@ -2477,13 +2482,11 @@ src_libnm_systemd_core_libnm_systemd_core_la_SOURCES = \
|
|||
src/libnm-systemd-core/nm-sd.h \
|
||||
src/libnm-systemd-core/sd-adapt-core/condition.h \
|
||||
src/libnm-systemd-core/sd-adapt-core/conf-parser.h \
|
||||
src/libnm-systemd-core/sd-adapt-core/device-util.h \
|
||||
src/libnm-systemd-core/sd-adapt-core/khash.h \
|
||||
src/libnm-systemd-core/sd-adapt-core/network-util.h \
|
||||
src/libnm-systemd-core/sd-adapt-core/nm-sd-adapt-core.c \
|
||||
src/libnm-systemd-core/sd-adapt-core/nm-sd-adapt-core.h \
|
||||
src/libnm-systemd-core/sd-adapt-core/sd-daemon.h \
|
||||
src/libnm-systemd-core/sd-adapt-core/sd-device.h \
|
||||
src/libnm-systemd-core/sd-adapt-core/udev-util.h \
|
||||
src/libnm-systemd-core/src/libsystemd-network/dhcp-identifier.c \
|
||||
src/libnm-systemd-core/src/libsystemd-network/dhcp-identifier.h \
|
||||
|
|
@ -2498,6 +2501,7 @@ src_libnm_systemd_core_libnm_systemd_core_la_SOURCES = \
|
|||
src/libnm-systemd-core/src/libsystemd-network/network-common.h \
|
||||
src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-client.c \
|
||||
src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-lease.c \
|
||||
src/libnm-systemd-core/src/libsystemd/sd-device/device-util.h \
|
||||
src/libnm-systemd-core/src/libsystemd/sd-event/event-source.h \
|
||||
src/libnm-systemd-core/src/libsystemd/sd-event/event-util.c \
|
||||
src/libnm-systemd-core/src/libsystemd/sd-event/event-util.h \
|
||||
|
|
@ -2506,6 +2510,7 @@ src_libnm_systemd_core_libnm_systemd_core_la_SOURCES = \
|
|||
src/libnm-systemd-core/src/libsystemd/sd-id128/id128-util.h \
|
||||
src/libnm-systemd-core/src/libsystemd/sd-id128/sd-id128.c \
|
||||
src/libnm-systemd-core/src/systemd/_sd-common.h \
|
||||
src/libnm-systemd-core/src/systemd/sd-device.h \
|
||||
src/libnm-systemd-core/src/systemd/sd-dhcp6-client.h \
|
||||
src/libnm-systemd-core/src/systemd/sd-dhcp6-lease.h \
|
||||
src/libnm-systemd-core/src/systemd/sd-dhcp6-option.h \
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ EXCLUDE_PATHS_TOPLEVEL=(
|
|||
"src/c-rbtree"
|
||||
"src/c-siphash"
|
||||
"src/c-stdaux"
|
||||
"src/libnm-std-aux/unaligned-fundamental.h"
|
||||
"src/libnm-std-aux/unaligned.h"
|
||||
"src/libnm-systemd-core/src"
|
||||
"src/libnm-systemd-shared/src"
|
||||
|
|
|
|||
40
src/libnm-std-aux/unaligned-fundamental.h
Normal file
40
src/libnm-std-aux/unaligned-fundamental.h
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
static inline uint16_t unaligned_read_ne16(const void *_u) {
|
||||
const struct __attribute__((__packed__, __may_alias__)) { uint16_t x; } *u = _u;
|
||||
|
||||
return u->x;
|
||||
}
|
||||
|
||||
static inline uint32_t unaligned_read_ne32(const void *_u) {
|
||||
const struct __attribute__((__packed__, __may_alias__)) { uint32_t x; } *u = _u;
|
||||
|
||||
return u->x;
|
||||
}
|
||||
|
||||
static inline uint64_t unaligned_read_ne64(const void *_u) {
|
||||
const struct __attribute__((__packed__, __may_alias__)) { uint64_t x; } *u = _u;
|
||||
|
||||
return u->x;
|
||||
}
|
||||
|
||||
static inline void unaligned_write_ne16(void *_u, uint16_t a) {
|
||||
struct __attribute__((__packed__, __may_alias__)) { uint16_t x; } *u = _u;
|
||||
|
||||
u->x = a;
|
||||
}
|
||||
|
||||
static inline void unaligned_write_ne32(void *_u, uint32_t a) {
|
||||
struct __attribute__((__packed__, __may_alias__)) { uint32_t x; } *u = _u;
|
||||
|
||||
u->x = a;
|
||||
}
|
||||
|
||||
static inline void unaligned_write_ne64(void *_u, uint64_t a) {
|
||||
struct __attribute__((__packed__, __may_alias__)) { uint64_t x; } *u = _u;
|
||||
|
||||
u->x = a;
|
||||
}
|
||||
|
|
@ -4,6 +4,8 @@
|
|||
#include <endian.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "unaligned-fundamental.h"
|
||||
|
||||
/* BE */
|
||||
|
||||
static inline uint16_t unaligned_read_be16(const void *_u) {
|
||||
|
|
@ -79,21 +81,3 @@ static inline void unaligned_write_le64(void *_u, uint64_t a) {
|
|||
|
||||
u->x = le64toh(a);
|
||||
}
|
||||
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
#define unaligned_read_ne16 unaligned_read_be16
|
||||
#define unaligned_read_ne32 unaligned_read_be32
|
||||
#define unaligned_read_ne64 unaligned_read_be64
|
||||
|
||||
#define unaligned_write_ne16 unaligned_write_be16
|
||||
#define unaligned_write_ne32 unaligned_write_be32
|
||||
#define unaligned_write_ne64 unaligned_write_be64
|
||||
#else
|
||||
#define unaligned_read_ne16 unaligned_read_le16
|
||||
#define unaligned_read_ne32 unaligned_read_le32
|
||||
#define unaligned_read_ne64 unaligned_read_le64
|
||||
|
||||
#define unaligned_write_ne16 unaligned_write_le16
|
||||
#define unaligned_write_ne32 unaligned_write_le32
|
||||
#define unaligned_write_ne64 unaligned_write_le64
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ libnm_systemd_core = static_library(
|
|||
include_directories(
|
||||
'sd-adapt-core',
|
||||
'src/libsystemd-network',
|
||||
'src/libsystemd/sd-device',
|
||||
'src/libsystemd/sd-event',
|
||||
'src/systemd',
|
||||
),
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
#include "nm-sd-adapt-core.h"
|
||||
|
||||
#include "fd-util.h"
|
||||
#include "sd-device.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
|
|
@ -19,3 +20,17 @@ asynchronous_close(int fd)
|
|||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
sd_device *
|
||||
sd_device_ref(sd_device *self)
|
||||
{
|
||||
g_return_val_if_fail(!self, self);
|
||||
return self;
|
||||
}
|
||||
|
||||
sd_device *
|
||||
sd_device_unref(sd_device *self)
|
||||
{
|
||||
g_return_val_if_fail(!self, self);
|
||||
return self;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,6 +40,8 @@
|
|||
#include <sys/syscall.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#define HAVE_EPOLL_PWAIT2 0
|
||||
|
||||
/* Missing in Linux 3.2.0, in Ubuntu 12.04 */
|
||||
#ifndef BPF_XOR
|
||||
#define BPF_XOR 0xa0
|
||||
|
|
@ -85,8 +87,14 @@ sd_notify(int unset_environment, const char *state)
|
|||
#include "sd-id128.h"
|
||||
#include "sparse-endian.h"
|
||||
#include "async.h"
|
||||
#include "util.h"
|
||||
|
||||
#endif /* (NETWORKMANAGER_COMPILATION) & NM_NETWORKMANAGER_COMPILATION_WITH_SYSTEMD */
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
struct sd_device;
|
||||
|
||||
struct sd_device *sd_device_ref(struct sd_device *self);
|
||||
struct sd_device *sd_device_unref(struct sd_device *self);
|
||||
|
||||
#endif /* __NM_SD_ADAPT_CORE_H__ */
|
||||
|
|
|
|||
|
|
@ -6,15 +6,11 @@
|
|||
#include <net/ethernet.h>
|
||||
#include <net/if_arp.h>
|
||||
|
||||
#include "sd-device.h"
|
||||
#include "sd-id128.h"
|
||||
|
||||
#include "dhcp-identifier.h"
|
||||
#include "netif-util.h"
|
||||
#include "siphash24.h"
|
||||
#include "sparse-endian.h"
|
||||
#include "string-table.h"
|
||||
#include "udev-util.h"
|
||||
|
||||
#define HASH_KEY SD_ID128_MAKE(80,11,8c,c2,fe,4a,03,ee,3e,d6,0c,6f,36,39,14,09)
|
||||
#define APPLICATION_ID SD_ID128_MAKE(a5,0a,d1,12,bf,60,45,77,a2,fb,74,1a,b1,95,5b,03)
|
||||
|
|
@ -213,49 +209,21 @@ int dhcp_identifier_set_duid(
|
|||
#endif /* NM_IGNORED */
|
||||
|
||||
int dhcp_identifier_set_iaid(
|
||||
int ifindex,
|
||||
sd_device *dev,
|
||||
const struct hw_addr_data *hw_addr,
|
||||
bool legacy_unstable_byteorder,
|
||||
bool use_mac,
|
||||
void *ret) {
|
||||
#if 0 /* NM_IGNORED */
|
||||
|
||||
/* name is a pointer to memory in the sd_device struct, so must
|
||||
* have the same scope */
|
||||
_cleanup_(sd_device_unrefp) sd_device *device = NULL;
|
||||
const char *name = NULL;
|
||||
uint32_t id32;
|
||||
uint64_t id;
|
||||
int r;
|
||||
|
||||
assert(ifindex > 0);
|
||||
assert(hw_addr);
|
||||
assert(ret);
|
||||
|
||||
if (udev_available() && !use_mac) {
|
||||
/* udev should be around */
|
||||
|
||||
r = sd_device_new_from_ifindex(&device, ifindex);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_device_get_is_initialized(device);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
/* not yet ready */
|
||||
return -EBUSY;
|
||||
|
||||
r = device_is_renaming(device);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r > 0)
|
||||
/* device is under renaming */
|
||||
return -EBUSY;
|
||||
|
||||
name = net_get_persistent_name(device);
|
||||
}
|
||||
|
||||
if (dev)
|
||||
name = net_get_persistent_name(dev);
|
||||
if (name)
|
||||
id = siphash24(name, strlen(name), HASH_KEY.bytes);
|
||||
else
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#include "sd-device.h"
|
||||
#include "sd-id128.h"
|
||||
|
||||
#include "ether-addr-util.h"
|
||||
|
|
@ -66,10 +67,9 @@ int dhcp_identifier_set_duid(
|
|||
struct duid *ret_duid,
|
||||
size_t *ret_len);
|
||||
int dhcp_identifier_set_iaid(
|
||||
int ifindex,
|
||||
sd_device *dev,
|
||||
const struct hw_addr_data *hw_addr,
|
||||
bool legacy_unstable_byteorder,
|
||||
bool use_mac,
|
||||
void *ret);
|
||||
|
||||
const char *duid_type_to_string(DUIDType t) _const_;
|
||||
|
|
|
|||
|
|
@ -48,6 +48,8 @@ struct sd_dhcp6_client {
|
|||
int event_priority;
|
||||
int fd;
|
||||
|
||||
sd_device *dev;
|
||||
|
||||
DHCP6State state;
|
||||
bool information_request;
|
||||
usec_t information_request_time_usec;
|
||||
|
|
@ -77,8 +79,9 @@ struct sd_dhcp6_client {
|
|||
|
||||
sd_dhcp6_client_callback_t callback;
|
||||
void *userdata;
|
||||
bool send_release;
|
||||
|
||||
/* Ignore ifindex when generating iaid. See dhcp_identifier_set_iaid(). */
|
||||
/* Ignore machine-ID when generating DUID. See dhcp_identifier_set_duid_en(). */
|
||||
bool test_mode;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ int dhcp6_network_bind_udp_socket(int ifindex, struct in6_addr *local_address) {
|
|||
.in6.sin6_port = htobe16(DHCP6_PORT_CLIENT),
|
||||
.in6.sin6_scope_id = ifindex,
|
||||
};
|
||||
_cleanup_close_ int s = -1;
|
||||
_cleanup_close_ int s = -EBADF;
|
||||
int r;
|
||||
|
||||
assert(ifindex > 0);
|
||||
|
|
|
|||
|
|
@ -497,13 +497,18 @@ int dhcp6_option_parse(
|
|||
}
|
||||
|
||||
int dhcp6_option_parse_status(const uint8_t *data, size_t data_len, char **ret_status_message) {
|
||||
DHCP6Status status;
|
||||
|
||||
assert(data || data_len == 0);
|
||||
|
||||
if (data_len < sizeof(uint16_t))
|
||||
return -EBADMSG;
|
||||
|
||||
status = unaligned_read_be16(data);
|
||||
|
||||
if (ret_status_message) {
|
||||
char *msg;
|
||||
_cleanup_free_ char *msg = NULL;
|
||||
const char *s;
|
||||
|
||||
/* The status message MUST NOT be null-terminated. See section 21.13 of RFC8415.
|
||||
* Let's escape unsafe characters for safety. */
|
||||
|
|
@ -511,10 +516,14 @@ int dhcp6_option_parse_status(const uint8_t *data, size_t data_len, char **ret_s
|
|||
if (!msg)
|
||||
return -ENOMEM;
|
||||
|
||||
*ret_status_message = msg;
|
||||
s = dhcp6_message_status_to_string(status);
|
||||
if (s && !strextend_with_separator(&msg, ": ", s))
|
||||
return -ENOMEM;
|
||||
|
||||
*ret_status_message = TAKE_PTR(msg);
|
||||
}
|
||||
|
||||
return unaligned_read_be16(data);
|
||||
return status;
|
||||
}
|
||||
|
||||
static int dhcp6_option_parse_ia_options(sd_dhcp6_client *client, const uint8_t *buf, size_t buflen) {
|
||||
|
|
@ -540,9 +549,8 @@ static int dhcp6_option_parse_ia_options(sd_dhcp6_client *client, const uint8_t
|
|||
return r;
|
||||
if (r > 0)
|
||||
return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL),
|
||||
"Received an IA address or PD prefix option with non-zero status: %s%s%s",
|
||||
strempty(msg), isempty(msg) ? "" : ": ",
|
||||
dhcp6_message_status_to_string(r));
|
||||
"Received an IA address or PD prefix option with non-zero status%s%s",
|
||||
isempty(msg) ? "." : ": ", strempty(msg));
|
||||
if (r < 0)
|
||||
/* Let's log but ignore the invalid status option. */
|
||||
log_dhcp6_client_errno(client, r,
|
||||
|
|
@ -748,9 +756,8 @@ int dhcp6_option_parse_ia(
|
|||
return r;
|
||||
if (r > 0)
|
||||
return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL),
|
||||
"Received an IA option with non-zero status: %s%s%s",
|
||||
strempty(msg), isempty(msg) ? "" : ": ",
|
||||
dhcp6_message_status_to_string(r));
|
||||
"Received an IA option with non-zero status%s%s",
|
||||
isempty(msg) ? "." : ": ", strempty(msg));
|
||||
if (r < 0)
|
||||
log_dhcp6_client_errno(client, r,
|
||||
"Received an IA option with an invalid status sub option, ignoring: %m");
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ static const char * const dhcp6_state_table[_DHCP6_STATE_MAX] = {
|
|||
[DHCP6_STATE_BOUND] = "bound",
|
||||
[DHCP6_STATE_RENEW] = "renew",
|
||||
[DHCP6_STATE_REBIND] = "rebind",
|
||||
[DHCP6_STATE_STOPPING] = "stopping",
|
||||
};
|
||||
|
||||
DEFINE_STRING_TABLE_LOOKUP_TO_STRING(dhcp6_state, DHCP6State);
|
||||
|
|
|
|||
|
|
@ -58,6 +58,7 @@ typedef enum DHCP6State {
|
|||
DHCP6_STATE_BOUND,
|
||||
DHCP6_STATE_RENEW,
|
||||
DHCP6_STATE_REBIND,
|
||||
DHCP6_STATE_STOPPING,
|
||||
_DHCP6_STATE_MAX,
|
||||
_DHCP6_STATE_INVALID = -EINVAL,
|
||||
} DHCP6State;
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
#include "sd-dhcp6-client.h"
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "device-util.h"
|
||||
#include "dhcp-identifier.h"
|
||||
#include "dhcp6-internal.h"
|
||||
#include "dhcp6-lease-internal.h"
|
||||
|
|
@ -309,9 +310,8 @@ static int client_ensure_iaid(sd_dhcp6_client *client) {
|
|||
if (client->iaid_set)
|
||||
return 0;
|
||||
|
||||
r = dhcp_identifier_set_iaid(client->ifindex, &client->hw_addr,
|
||||
r = dhcp_identifier_set_iaid(client->dev, &client->hw_addr,
|
||||
/* legacy_unstable_byteorder = */ true,
|
||||
/* use_mac = */ client->test_mode,
|
||||
&iaid);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
|
@ -508,6 +508,14 @@ int sd_dhcp6_client_set_rapid_commit(sd_dhcp6_client *client, int enable) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int sd_dhcp6_client_set_send_release(sd_dhcp6_client *client, int enable) {
|
||||
assert_return(client, -EINVAL);
|
||||
assert_return(!sd_dhcp6_client_is_running(client), -EBUSY);
|
||||
|
||||
client->send_release = enable;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_dhcp6_client_get_lease(sd_dhcp6_client *client, sd_dhcp6_lease **ret) {
|
||||
assert_return(client, -EINVAL);
|
||||
|
||||
|
|
@ -596,7 +604,8 @@ static int client_append_common_options_in_managed_mode(
|
|||
DHCP6_STATE_SOLICITATION,
|
||||
DHCP6_STATE_REQUEST,
|
||||
DHCP6_STATE_RENEW,
|
||||
DHCP6_STATE_REBIND));
|
||||
DHCP6_STATE_REBIND,
|
||||
DHCP6_STATE_STOPPING));
|
||||
assert(buf);
|
||||
assert(*buf);
|
||||
assert(offset);
|
||||
|
|
@ -613,9 +622,11 @@ static int client_append_common_options_in_managed_mode(
|
|||
return r;
|
||||
}
|
||||
|
||||
r = dhcp6_option_append_fqdn(buf, offset, client->fqdn);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (client->state != DHCP6_STATE_STOPPING) {
|
||||
r = dhcp6_option_append_fqdn(buf, offset, client->fqdn);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
r = dhcp6_option_append_user_class(buf, offset, client->user_class);
|
||||
if (r < 0)
|
||||
|
|
@ -646,6 +657,8 @@ static DHCP6MessageType client_message_type_from_state(sd_dhcp6_client *client)
|
|||
return DHCP6_MESSAGE_RENEW;
|
||||
case DHCP6_STATE_REBIND:
|
||||
return DHCP6_MESSAGE_REBIND;
|
||||
case DHCP6_STATE_STOPPING:
|
||||
return DHCP6_MESSAGE_RELEASE;
|
||||
default:
|
||||
assert_not_reached();
|
||||
}
|
||||
|
|
@ -689,6 +702,9 @@ static int client_append_oro(sd_dhcp6_client *client, uint8_t **buf, size_t *off
|
|||
req_opts = p;
|
||||
break;
|
||||
|
||||
case DHCP6_STATE_STOPPING:
|
||||
return 0;
|
||||
|
||||
default:
|
||||
n = client->n_req_opts;
|
||||
req_opts = client->req_opts;
|
||||
|
|
@ -700,6 +716,22 @@ static int client_append_oro(sd_dhcp6_client *client, uint8_t **buf, size_t *off
|
|||
return dhcp6_option_append(buf, offset, SD_DHCP6_OPTION_ORO, n * sizeof(be16_t), req_opts);
|
||||
}
|
||||
|
||||
static int client_append_mudurl(sd_dhcp6_client *client, uint8_t **buf, size_t *offset) {
|
||||
assert(client);
|
||||
assert(buf);
|
||||
assert(*buf);
|
||||
assert(offset);
|
||||
|
||||
if (!client->mudurl)
|
||||
return 0;
|
||||
|
||||
if (client->state == DHCP6_STATE_STOPPING)
|
||||
return 0;
|
||||
|
||||
return dhcp6_option_append(buf, offset, SD_DHCP6_OPTION_MUD_URL_V6,
|
||||
strlen(client->mudurl), client->mudurl);
|
||||
}
|
||||
|
||||
int dhcp6_client_send_message(sd_dhcp6_client *client) {
|
||||
_cleanup_free_ uint8_t *buf = NULL;
|
||||
struct in6_addr all_servers =
|
||||
|
|
@ -745,7 +777,7 @@ int dhcp6_client_send_message(sd_dhcp6_client *client) {
|
|||
|
||||
case DHCP6_STATE_REQUEST:
|
||||
case DHCP6_STATE_RENEW:
|
||||
|
||||
case DHCP6_STATE_STOPPING:
|
||||
r = dhcp6_option_append(&buf, &offset, SD_DHCP6_OPTION_SERVERID,
|
||||
client->lease->serverid_len,
|
||||
client->lease->serverid);
|
||||
|
|
@ -763,18 +795,15 @@ int dhcp6_client_send_message(sd_dhcp6_client *client) {
|
|||
return r;
|
||||
break;
|
||||
|
||||
case DHCP6_STATE_STOPPED:
|
||||
case DHCP6_STATE_BOUND:
|
||||
case DHCP6_STATE_STOPPED:
|
||||
default:
|
||||
assert_not_reached();
|
||||
}
|
||||
|
||||
if (client->mudurl) {
|
||||
r = dhcp6_option_append(&buf, &offset, SD_DHCP6_OPTION_MUD_URL_V6,
|
||||
strlen(client->mudurl), client->mudurl);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
r = client_append_mudurl(client, &buf, &offset);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = client_append_oro(client, &buf, &offset);
|
||||
if (r < 0)
|
||||
|
|
@ -866,6 +895,7 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec, void *userda
|
|||
break;
|
||||
|
||||
case DHCP6_STATE_STOPPED:
|
||||
case DHCP6_STATE_STOPPING:
|
||||
case DHCP6_STATE_BOUND:
|
||||
default:
|
||||
assert_not_reached();
|
||||
|
|
@ -921,6 +951,7 @@ static int client_start_transaction(sd_dhcp6_client *client, DHCP6State state) {
|
|||
assert(IN_SET(client->state, DHCP6_STATE_BOUND, DHCP6_STATE_RENEW));
|
||||
break;
|
||||
case DHCP6_STATE_STOPPED:
|
||||
case DHCP6_STATE_STOPPING:
|
||||
case DHCP6_STATE_BOUND:
|
||||
default:
|
||||
assert_not_reached();
|
||||
|
|
@ -1303,7 +1334,7 @@ static int client_receive_message(
|
|||
if (cmsg->cmsg_level == SOL_SOCKET &&
|
||||
cmsg->cmsg_type == SO_TIMESTAMP &&
|
||||
cmsg->cmsg_len == CMSG_LEN(sizeof(struct timeval)))
|
||||
triple_timestamp_from_realtime(&t, timeval_load((struct timeval*) (void *) CMSG_DATA(cmsg)));
|
||||
triple_timestamp_from_realtime(&t, timeval_load(CMSG_TYPED_DATA(cmsg, struct timeval)));
|
||||
}
|
||||
|
||||
if (client->transaction_id != (message->transaction_id & htobe32(0x00ffffff)))
|
||||
|
|
@ -1329,6 +1360,7 @@ static int client_receive_message(
|
|||
|
||||
case DHCP6_STATE_BOUND:
|
||||
case DHCP6_STATE_STOPPED:
|
||||
case DHCP6_STATE_STOPPING:
|
||||
default:
|
||||
assert_not_reached();
|
||||
}
|
||||
|
|
@ -1336,10 +1368,37 @@ static int client_receive_message(
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int client_send_release(sd_dhcp6_client *client) {
|
||||
sd_dhcp6_lease *lease;
|
||||
|
||||
assert(client);
|
||||
|
||||
if (!client->send_release)
|
||||
return 0;
|
||||
|
||||
if (sd_dhcp6_client_get_lease(client, &lease) < 0)
|
||||
return 0;
|
||||
|
||||
if (!lease->ia_na && !lease->ia_pd)
|
||||
return 0;
|
||||
|
||||
client_set_state(client, DHCP6_STATE_STOPPING);
|
||||
return dhcp6_client_send_message(client);
|
||||
}
|
||||
|
||||
int sd_dhcp6_client_stop(sd_dhcp6_client *client) {
|
||||
int r;
|
||||
|
||||
if (!client)
|
||||
return 0;
|
||||
|
||||
/* Intentionally ignoring failure to send DHCP6 release. The DHCPv6 client
|
||||
* engine is about to release its UDP socket unconditionally. */
|
||||
r = client_send_release(client);
|
||||
if (r < 0)
|
||||
log_dhcp6_client_errno(client, r,
|
||||
"Failed to send DHCP6 release message, ignoring: %m");
|
||||
|
||||
client_stop(client, SD_DHCP6_CLIENT_EVENT_STOP);
|
||||
|
||||
client->receive_message = sd_event_source_unref(client->receive_message);
|
||||
|
|
@ -1456,6 +1515,12 @@ sd_event *sd_dhcp6_client_get_event(sd_dhcp6_client *client) {
|
|||
return client->event;
|
||||
}
|
||||
|
||||
int sd_dhcp6_client_attach_device(sd_dhcp6_client *client, sd_device *dev) {
|
||||
assert_return(client, -EINVAL);
|
||||
|
||||
return device_unref_and_replace(client->dev, dev);
|
||||
}
|
||||
|
||||
static sd_dhcp6_client *dhcp6_client_free(sd_dhcp6_client *client) {
|
||||
if (!client)
|
||||
return NULL;
|
||||
|
|
@ -1471,6 +1536,8 @@ static sd_dhcp6_client *dhcp6_client_free(sd_dhcp6_client *client) {
|
|||
|
||||
client->fd = safe_close(client->fd);
|
||||
|
||||
sd_device_unref(client->dev);
|
||||
|
||||
free(client->req_opts);
|
||||
free(client->fqdn);
|
||||
free(client->mudurl);
|
||||
|
|
@ -1501,7 +1568,7 @@ int sd_dhcp6_client_new(sd_dhcp6_client **ret) {
|
|||
.ia_pd.type = SD_DHCP6_OPTION_IA_PD,
|
||||
.ifindex = -1,
|
||||
.request_ia = DHCP6_REQUEST_IA_NA | DHCP6_REQUEST_IA_PD,
|
||||
.fd = -1,
|
||||
.fd = -EBADF,
|
||||
.rapid_commit = true,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -512,13 +512,11 @@ static int dhcp6_lease_parse_message(
|
|||
r = dhcp6_option_parse_status(optval, optlen, &msg);
|
||||
if (r < 0)
|
||||
return log_dhcp6_client_errno(client, r, "Failed to parse status code: %m");
|
||||
|
||||
if (r > 0)
|
||||
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",
|
||||
dhcp6_message_type_to_string(message->type),
|
||||
strempty(msg), isempty(msg) ? "" : ": ",
|
||||
dhcp6_message_status_to_string(r));
|
||||
isempty(msg) ? "." : ": ", strempty(msg));
|
||||
break;
|
||||
}
|
||||
case SD_DHCP6_OPTION_IA_NA: {
|
||||
|
|
|
|||
103
src/libnm-systemd-core/src/libsystemd/sd-device/device-util.h
Normal file
103
src/libnm-systemd-core/src/libsystemd/sd-device/device-util.h
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "sd-device.h"
|
||||
|
||||
#include "log.h"
|
||||
#include "macro.h"
|
||||
|
||||
#define device_unref_and_replace(a, b) \
|
||||
unref_and_replace_full(a, b, sd_device_ref, sd_device_unref)
|
||||
|
||||
#define FOREACH_DEVICE_PROPERTY(device, key, value) \
|
||||
for (key = sd_device_get_property_first(device, &(value)); \
|
||||
key; \
|
||||
key = sd_device_get_property_next(device, &(value)))
|
||||
|
||||
#define FOREACH_DEVICE_TAG(device, tag) \
|
||||
for (tag = sd_device_get_tag_first(device); \
|
||||
tag; \
|
||||
tag = sd_device_get_tag_next(device))
|
||||
|
||||
#define FOREACH_DEVICE_CURRENT_TAG(device, tag) \
|
||||
for (tag = sd_device_get_current_tag_first(device); \
|
||||
tag; \
|
||||
tag = sd_device_get_current_tag_next(device))
|
||||
|
||||
#define FOREACH_DEVICE_SYSATTR(device, attr) \
|
||||
for (attr = sd_device_get_sysattr_first(device); \
|
||||
attr; \
|
||||
attr = sd_device_get_sysattr_next(device))
|
||||
|
||||
#define FOREACH_DEVICE_DEVLINK(device, devlink) \
|
||||
for (devlink = sd_device_get_devlink_first(device); \
|
||||
devlink; \
|
||||
devlink = sd_device_get_devlink_next(device))
|
||||
|
||||
#define _FOREACH_DEVICE_CHILD(device, child, suffix_ptr) \
|
||||
for (child = sd_device_get_child_first(device, suffix_ptr); \
|
||||
child; \
|
||||
child = sd_device_get_child_next(device, suffix_ptr))
|
||||
|
||||
#define FOREACH_DEVICE_CHILD(device, child) \
|
||||
_FOREACH_DEVICE_CHILD(device, child, NULL)
|
||||
|
||||
#define FOREACH_DEVICE_CHILD_WITH_SUFFIX(device, child, suffix) \
|
||||
_FOREACH_DEVICE_CHILD(device, child, &suffix)
|
||||
|
||||
#define FOREACH_DEVICE(enumerator, device) \
|
||||
for (device = sd_device_enumerator_get_device_first(enumerator); \
|
||||
device; \
|
||||
device = sd_device_enumerator_get_device_next(enumerator))
|
||||
|
||||
#define FOREACH_SUBSYSTEM(enumerator, device) \
|
||||
for (device = sd_device_enumerator_get_subsystem_first(enumerator); \
|
||||
device; \
|
||||
device = sd_device_enumerator_get_subsystem_next(enumerator))
|
||||
|
||||
#define log_device_full_errno_zerook(device, level, error, ...) \
|
||||
({ \
|
||||
const char *_sysname = NULL; \
|
||||
sd_device *_d = (device); \
|
||||
int _level = (level), _e = (error); \
|
||||
\
|
||||
if (_d && _unlikely_(log_get_max_level() >= LOG_PRI(_level))) \
|
||||
(void) sd_device_get_sysname(_d, &_sysname); \
|
||||
log_object_internal(_level, _e, PROJECT_FILE, __LINE__, __func__, \
|
||||
_sysname ? "DEVICE=" : NULL, _sysname, \
|
||||
NULL, NULL, __VA_ARGS__); \
|
||||
})
|
||||
|
||||
#define log_device_full_errno(device, level, error, ...) \
|
||||
({ \
|
||||
int _error = (error); \
|
||||
ASSERT_NON_ZERO(_error); \
|
||||
log_device_full_errno_zerook(device, level, _error, __VA_ARGS__); \
|
||||
})
|
||||
|
||||
#define log_device_full(device, level, ...) (void) log_device_full_errno_zerook(device, level, 0, __VA_ARGS__)
|
||||
|
||||
#define log_device_debug(device, ...) log_device_full(device, LOG_DEBUG, __VA_ARGS__)
|
||||
#define log_device_info(device, ...) log_device_full(device, LOG_INFO, __VA_ARGS__)
|
||||
#define log_device_notice(device, ...) log_device_full(device, LOG_NOTICE, __VA_ARGS__)
|
||||
#define log_device_warning(device, ...) log_device_full(device, LOG_WARNING, __VA_ARGS__)
|
||||
#define log_device_error(device, ...) log_device_full(device, LOG_ERR, __VA_ARGS__)
|
||||
|
||||
#define log_device_debug_errno(device, error, ...) log_device_full_errno(device, LOG_DEBUG, error, __VA_ARGS__)
|
||||
#define log_device_info_errno(device, error, ...) log_device_full_errno(device, LOG_INFO, error, __VA_ARGS__)
|
||||
#define log_device_notice_errno(device, error, ...) log_device_full_errno(device, LOG_NOTICE, error, __VA_ARGS__)
|
||||
#define log_device_warning_errno(device, error, ...) log_device_full_errno(device, LOG_WARNING, error, __VA_ARGS__)
|
||||
#define log_device_error_errno(device, error, ...) log_device_full_errno(device, LOG_ERR, error, __VA_ARGS__)
|
||||
|
||||
int devname_from_devnum(mode_t mode, dev_t devnum, char **ret);
|
||||
static inline int devname_from_stat_rdev(const struct stat *st, char **ret) {
|
||||
assert(st);
|
||||
return devname_from_devnum(st->st_mode, st->st_rdev, ret);
|
||||
}
|
||||
int device_open_from_devnum(mode_t mode, dev_t devnum, int flags, char **ret);
|
||||
|
||||
char** device_make_log_fields(sd_device *device);
|
||||
|
|
@ -114,7 +114,7 @@ int event_reset_time_relative(
|
|||
#if 0 /* NM_IGNORED */
|
||||
int event_add_time_change(sd_event *e, sd_event_source **ret, sd_event_io_handler_t callback, void *userdata) {
|
||||
_cleanup_(sd_event_source_unrefp) sd_event_source *s = NULL;
|
||||
_cleanup_close_ int fd = -1;
|
||||
_cleanup_close_ int fd = -EBADF;
|
||||
int r;
|
||||
|
||||
assert(e);
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
#include "glyph-util.h"
|
||||
#include "hashmap.h"
|
||||
#include "list.h"
|
||||
#include "logarithm.h"
|
||||
#include "macro.h"
|
||||
#include "memory-util.h"
|
||||
#include "missing_syscall.h"
|
||||
|
|
@ -379,22 +380,22 @@ _public_ int sd_event_new(sd_event** ret) {
|
|||
|
||||
*e = (sd_event) {
|
||||
.n_ref = 1,
|
||||
.epoll_fd = -1,
|
||||
.watchdog_fd = -1,
|
||||
.epoll_fd = -EBADF,
|
||||
.watchdog_fd = -EBADF,
|
||||
.realtime.wakeup = WAKEUP_CLOCK_DATA,
|
||||
.realtime.fd = -1,
|
||||
.realtime.fd = -EBADF,
|
||||
.realtime.next = USEC_INFINITY,
|
||||
.boottime.wakeup = WAKEUP_CLOCK_DATA,
|
||||
.boottime.fd = -1,
|
||||
.boottime.fd = -EBADF,
|
||||
.boottime.next = USEC_INFINITY,
|
||||
.monotonic.wakeup = WAKEUP_CLOCK_DATA,
|
||||
.monotonic.fd = -1,
|
||||
.monotonic.fd = -EBADF,
|
||||
.monotonic.next = USEC_INFINITY,
|
||||
.realtime_alarm.wakeup = WAKEUP_CLOCK_DATA,
|
||||
.realtime_alarm.fd = -1,
|
||||
.realtime_alarm.fd = -EBADF,
|
||||
.realtime_alarm.next = USEC_INFINITY,
|
||||
.boottime_alarm.wakeup = WAKEUP_CLOCK_DATA,
|
||||
.boottime_alarm.fd = -1,
|
||||
.boottime_alarm.fd = -EBADF,
|
||||
.boottime_alarm.next = USEC_INFINITY,
|
||||
.perturb = USEC_INFINITY,
|
||||
.original_pid = getpid_cached(),
|
||||
|
|
@ -644,7 +645,7 @@ static int event_make_signal_data(
|
|||
|
||||
*d = (struct signal_data) {
|
||||
.wakeup = WAKEUP_SIGNAL_DATA,
|
||||
.fd = -1,
|
||||
.fd = -EBADF,
|
||||
.priority = priority,
|
||||
};
|
||||
|
||||
|
|
@ -660,7 +661,9 @@ static int event_make_signal_data(
|
|||
ss_copy = d->sigset;
|
||||
assert_se(sigaddset(&ss_copy, sig) >= 0);
|
||||
|
||||
r = signalfd(d->fd, &ss_copy, SFD_NONBLOCK|SFD_CLOEXEC);
|
||||
r = signalfd(d->fd >= 0 ? d->fd : -1, /* the first arg must be -1 or a valid signalfd */
|
||||
&ss_copy,
|
||||
SFD_NONBLOCK|SFD_CLOEXEC);
|
||||
if (r < 0) {
|
||||
r = -errno;
|
||||
goto fail;
|
||||
|
|
@ -1179,7 +1182,7 @@ static int event_setup_timer_fd(
|
|||
if (_likely_(d->fd >= 0))
|
||||
return 0;
|
||||
|
||||
_cleanup_close_ int fd = -1;
|
||||
_cleanup_close_ int fd = -EBADF;
|
||||
|
||||
fd = timerfd_create(clock, TFD_NONBLOCK|TFD_CLOEXEC);
|
||||
if (fd < 0)
|
||||
|
|
@ -1516,7 +1519,7 @@ _public_ int sd_event_add_child(
|
|||
} else
|
||||
s->child.pidfd_owned = true; /* If we allocate the pidfd we own it by default */
|
||||
} else
|
||||
s->child.pidfd = -1;
|
||||
s->child.pidfd = -EBADF;
|
||||
|
||||
if (EVENT_SOURCE_WATCH_PIDFD(s)) {
|
||||
/* We have a pidfd and we only want to watch for exit */
|
||||
|
|
@ -1780,7 +1783,7 @@ static int event_make_inotify_data(
|
|||
int64_t priority,
|
||||
struct inotify_data **ret) {
|
||||
|
||||
_cleanup_close_ int fd = -1;
|
||||
_cleanup_close_ int fd = -EBADF;
|
||||
struct inotify_data *d;
|
||||
int r;
|
||||
|
||||
|
|
@ -1977,7 +1980,7 @@ static int event_make_inode_data(
|
|||
.dev = dev,
|
||||
.ino = ino,
|
||||
.wd = -1,
|
||||
.fd = -1,
|
||||
.fd = -EBADF,
|
||||
.inotify_data = inotify_data,
|
||||
};
|
||||
|
||||
|
|
@ -2073,7 +2076,7 @@ static int event_add_inotify_fd_internal(
|
|||
sd_event_inotify_handler_t callback,
|
||||
void *userdata) {
|
||||
|
||||
_cleanup_close_ int donated_fd = donate ? fd : -1;
|
||||
_cleanup_close_ int donated_fd = donate ? fd : -EBADF;
|
||||
_cleanup_(source_freep) sd_event_source *s = NULL;
|
||||
struct inotify_data *inotify_data = NULL;
|
||||
struct inode_data *inode_data = NULL;
|
||||
|
|
@ -2175,9 +2178,9 @@ _public_ int sd_event_add_inotify(
|
|||
|
||||
assert_return(path, -EINVAL);
|
||||
|
||||
fd = open(path, O_PATH|O_CLOEXEC|
|
||||
(mask & IN_ONLYDIR ? O_DIRECTORY : 0)|
|
||||
(mask & IN_DONT_FOLLOW ? O_NOFOLLOW : 0));
|
||||
fd = open(path, O_PATH | O_CLOEXEC |
|
||||
(mask & IN_ONLYDIR ? O_DIRECTORY : 0) |
|
||||
(mask & IN_DONT_FOLLOW ? O_NOFOLLOW : 0));
|
||||
if (fd < 0)
|
||||
return -errno;
|
||||
|
||||
|
|
@ -2727,6 +2730,9 @@ _public_ int sd_event_source_set_time_relative(sd_event_source *s, uint64_t usec
|
|||
assert_return(s, -EINVAL);
|
||||
assert_return(EVENT_SOURCE_IS_TIME(s->type), -EDOM);
|
||||
|
||||
if (usec == USEC_INFINITY)
|
||||
return sd_event_source_set_time(s, USEC_INFINITY);
|
||||
|
||||
r = sd_event_now(s->event, event_source_type_to_clock(s->type), &t);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
|
@ -3180,7 +3186,7 @@ static int event_arm_timer(
|
|||
assert_se(d->fd >= 0);
|
||||
|
||||
if (t == 0) {
|
||||
/* We don' want to disarm here, just mean some time looooong ago. */
|
||||
/* We don't want to disarm here, just mean some time looooong ago. */
|
||||
its.it_value.tv_sec = 0;
|
||||
its.it_value.tv_nsec = 1;
|
||||
} else
|
||||
|
|
@ -3777,12 +3783,9 @@ static int event_prepare(sd_event *e) {
|
|||
break;
|
||||
|
||||
s->prepare_iteration = e->iteration;
|
||||
r = prioq_reshuffle(e->prepare, s, &s->prepare_index);
|
||||
if (r < 0)
|
||||
return r;
|
||||
prioq_reshuffle(e->prepare, s, &s->prepare_index);
|
||||
|
||||
assert(s->prepare);
|
||||
|
||||
s->dispatching = true;
|
||||
r = s->prepare(s, s->userdata);
|
||||
s->dispatching = false;
|
||||
|
|
@ -3972,15 +3975,18 @@ static int epoll_wait_usec(
|
|||
usec_t timeout) {
|
||||
|
||||
int msec;
|
||||
#if 0
|
||||
/* A wrapper that uses epoll_pwait2() if available, and falls back to epoll_wait() if not. */
|
||||
|
||||
#if HAVE_EPOLL_PWAIT2
|
||||
static bool epoll_pwait2_absent = false;
|
||||
int r;
|
||||
|
||||
/* A wrapper that uses epoll_pwait2() if available, and falls back to epoll_wait() if not.
|
||||
*
|
||||
* FIXME: this is temporarily disabled until epoll_pwait2() becomes more widely available.
|
||||
* See https://github.com/systemd/systemd/pull/18973 and
|
||||
* https://github.com/systemd/systemd/issues/19052. */
|
||||
/* epoll_pwait2() was added to Linux 5.11 (2021-02-14) and to glibc in 2.35 (2022-02-03). In contrast
|
||||
* to other syscalls we don't bother with our own fallback syscall wrappers on old libcs, since this
|
||||
* is not that obvious to implement given the libc and kernel definitions differ in the last
|
||||
* argument. Moreover, the only reason to use it is the more accurate time-outs (which is not a
|
||||
* biggie), let's hence rely on glibc's definitions, and fallback to epoll_pwait() when that's
|
||||
* missing. */
|
||||
|
||||
if (!epoll_pwait2_absent && timeout != USEC_INFINITY) {
|
||||
r = epoll_pwait2(fd,
|
||||
|
|
|
|||
|
|
@ -16,60 +16,50 @@
|
|||
|
||||
#if 0 /* NM_IGNORED */
|
||||
bool id128_is_valid(const char *s) {
|
||||
size_t i, l;
|
||||
size_t l;
|
||||
|
||||
assert(s);
|
||||
|
||||
l = strlen(s);
|
||||
if (l == 32) {
|
||||
|
||||
if (l == SD_ID128_STRING_MAX - 1)
|
||||
/* Plain formatted 128bit hex string */
|
||||
return in_charset(s, HEXDIGITS);
|
||||
|
||||
for (i = 0; i < l; i++) {
|
||||
char c = s[i];
|
||||
|
||||
if (!ascii_isdigit(c) &&
|
||||
!(c >= 'a' && c <= 'f') &&
|
||||
!(c >= 'A' && c <= 'F'))
|
||||
return false;
|
||||
}
|
||||
|
||||
} else if (l == 36) {
|
||||
|
||||
if (l == SD_ID128_UUID_STRING_MAX - 1) {
|
||||
/* Formatted UUID */
|
||||
|
||||
for (i = 0; i < l; i++) {
|
||||
for (size_t i = 0; i < l; i++) {
|
||||
char c = s[i];
|
||||
|
||||
if (IN_SET(i, 8, 13, 18, 23)) {
|
||||
if (c != '-')
|
||||
return false;
|
||||
} else {
|
||||
if (!ascii_isdigit(c) &&
|
||||
!(c >= 'a' && c <= 'f') &&
|
||||
!(c >= 'A' && c <= 'F'))
|
||||
return false;
|
||||
}
|
||||
} else if (!ascii_ishex(c))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} else
|
||||
return false;
|
||||
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
#endif /* NM_IGNORED */
|
||||
|
||||
int id128_read_fd(int fd, Id128Format f, sd_id128_t *ret) {
|
||||
char buffer[36 + 2];
|
||||
int id128_read_fd(int fd, Id128FormatFlag f, sd_id128_t *ret) {
|
||||
char buffer[SD_ID128_UUID_STRING_MAX + 1]; /* +1 is for trailing newline */
|
||||
ssize_t l;
|
||||
int r;
|
||||
|
||||
assert(fd >= 0);
|
||||
assert(f < _ID128_FORMAT_MAX);
|
||||
|
||||
/* Reads an 128bit ID from a file, which may either be in plain format (32 hex digits), or in UUID format, both
|
||||
* optionally followed by a newline and nothing else. ID files should really be newline terminated, but if they
|
||||
* aren't that's OK too, following the rule of "Be conservative in what you send, be liberal in what you
|
||||
* accept". */
|
||||
* accept".
|
||||
*
|
||||
* This returns the following:
|
||||
* -ENOMEDIUM: an empty string,
|
||||
* -ENOPKG: "uninitialized" or "uninitialized\n",
|
||||
* -EUCLEAN: other invalid strings. */
|
||||
|
||||
l = loop_read(fd, buffer, sizeof(buffer), false); /* we expect a short read of either 32/33 or 36/37 chars */
|
||||
if (l < 0)
|
||||
|
|
@ -79,44 +69,44 @@ int id128_read_fd(int fd, Id128Format f, sd_id128_t *ret) {
|
|||
|
||||
switch (l) {
|
||||
|
||||
case 13:
|
||||
case 14:
|
||||
/* Treat an "uninitialized" id file like an empty one */
|
||||
return f == ID128_PLAIN_OR_UNINIT && strneq(buffer, "uninitialized\n", l) ? -ENOMEDIUM : -EINVAL;
|
||||
case STRLEN("uninitialized"):
|
||||
case STRLEN("uninitialized\n"):
|
||||
return strneq(buffer, "uninitialized\n", l) ? -ENOPKG : -EINVAL;
|
||||
|
||||
case 33: /* plain UUID with trailing newline */
|
||||
if (buffer[32] != '\n')
|
||||
return -EINVAL;
|
||||
case SD_ID128_STRING_MAX: /* plain UUID with trailing newline */
|
||||
if (buffer[SD_ID128_STRING_MAX-1] != '\n')
|
||||
return -EUCLEAN;
|
||||
|
||||
_fallthrough_;
|
||||
case 32: /* plain UUID without trailing newline */
|
||||
if (f == ID128_UUID)
|
||||
return -EINVAL;
|
||||
case SD_ID128_STRING_MAX-1: /* plain UUID without trailing newline */
|
||||
if (!FLAGS_SET(f, ID128_FORMAT_PLAIN))
|
||||
return -EUCLEAN;
|
||||
|
||||
buffer[32] = 0;
|
||||
buffer[SD_ID128_STRING_MAX-1] = 0;
|
||||
break;
|
||||
|
||||
case 37: /* RFC UUID with trailing newline */
|
||||
if (buffer[36] != '\n')
|
||||
return -EINVAL;
|
||||
case SD_ID128_UUID_STRING_MAX: /* RFC UUID with trailing newline */
|
||||
if (buffer[SD_ID128_UUID_STRING_MAX-1] != '\n')
|
||||
return -EUCLEAN;
|
||||
|
||||
_fallthrough_;
|
||||
case 36: /* RFC UUID without trailing newline */
|
||||
if (IN_SET(f, ID128_PLAIN, ID128_PLAIN_OR_UNINIT))
|
||||
return -EINVAL;
|
||||
case SD_ID128_UUID_STRING_MAX-1: /* RFC UUID without trailing newline */
|
||||
if (!FLAGS_SET(f, ID128_FORMAT_UUID))
|
||||
return -EUCLEAN;
|
||||
|
||||
buffer[36] = 0;
|
||||
buffer[SD_ID128_UUID_STRING_MAX-1] = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
return -EUCLEAN;
|
||||
}
|
||||
|
||||
return sd_id128_from_string(buffer, ret);
|
||||
r = sd_id128_from_string(buffer, ret);
|
||||
return r == -EINVAL ? -EUCLEAN : r;
|
||||
}
|
||||
|
||||
int id128_read(const char *p, Id128Format f, sd_id128_t *ret) {
|
||||
_cleanup_close_ int fd = -1;
|
||||
int id128_read(const char *p, Id128FormatFlag f, sd_id128_t *ret) {
|
||||
_cleanup_close_ int fd = -EBADF;
|
||||
|
||||
fd = open(p, O_RDONLY|O_CLOEXEC|O_NOCTTY);
|
||||
if (fd < 0)
|
||||
|
|
@ -126,29 +116,28 @@ int id128_read(const char *p, Id128Format f, sd_id128_t *ret) {
|
|||
}
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
int id128_write_fd(int fd, Id128Format f, sd_id128_t id, bool do_sync) {
|
||||
char buffer[36 + 2];
|
||||
int id128_write_fd(int fd, Id128FormatFlag f, sd_id128_t id) {
|
||||
char buffer[SD_ID128_UUID_STRING_MAX + 1]; /* +1 is for trailing newline */
|
||||
size_t sz;
|
||||
int r;
|
||||
|
||||
assert(fd >= 0);
|
||||
assert(f < _ID128_FORMAT_MAX);
|
||||
assert(IN_SET((f & ID128_FORMAT_ANY), ID128_FORMAT_PLAIN, ID128_FORMAT_UUID));
|
||||
|
||||
if (f != ID128_UUID) {
|
||||
if (FLAGS_SET(f, ID128_FORMAT_PLAIN)) {
|
||||
assert_se(sd_id128_to_string(id, buffer));
|
||||
buffer[SD_ID128_STRING_MAX - 1] = '\n';
|
||||
sz = SD_ID128_STRING_MAX;
|
||||
} else {
|
||||
assert_se(sd_id128_to_uuid_string(id, buffer));
|
||||
buffer[SD_ID128_UUID_STRING_MAX - 1] = '\n';
|
||||
sz = SD_ID128_UUID_STRING_MAX;
|
||||
}
|
||||
|
||||
buffer[sz - 1] = '\n';
|
||||
r = loop_write(fd, buffer, sz, false);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (do_sync) {
|
||||
if (FLAGS_SET(f, ID128_SYNC_ON_WRITE)) {
|
||||
r = fsync_full(fd);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
|
@ -157,14 +146,14 @@ int id128_write_fd(int fd, Id128Format f, sd_id128_t id, bool do_sync) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int id128_write(const char *p, Id128Format f, sd_id128_t id, bool do_sync) {
|
||||
_cleanup_close_ int fd = -1;
|
||||
int id128_write(const char *p, Id128FormatFlag f, sd_id128_t id) {
|
||||
_cleanup_close_ int fd = -EBADF;
|
||||
|
||||
fd = open(p, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY|O_TRUNC, 0444);
|
||||
if (fd < 0)
|
||||
return -errno;
|
||||
|
||||
return id128_write_fd(fd, f, id, do_sync);
|
||||
return id128_write_fd(fd, f, id);
|
||||
}
|
||||
|
||||
void id128_hash_func(const sd_id128_t *p, struct siphash *state) {
|
||||
|
|
@ -189,6 +178,7 @@ sd_id128_t id128_make_v4_uuid(sd_id128_t id) {
|
|||
}
|
||||
|
||||
DEFINE_HASH_OPS(id128_hash_ops, sd_id128_t, id128_hash_func, id128_compare_func);
|
||||
DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(id128_hash_ops_free, sd_id128_t, id128_hash_func, id128_compare_func, free);
|
||||
|
||||
int id128_get_product(sd_id128_t *ret) {
|
||||
sd_id128_t uuid;
|
||||
|
|
@ -199,9 +189,9 @@ int id128_get_product(sd_id128_t *ret) {
|
|||
/* Reads the systems product UUID from DMI or devicetree (where it is located on POWER). This is
|
||||
* particularly relevant in VM environments, where VM managers typically place a VM uuid there. */
|
||||
|
||||
r = id128_read("/sys/class/dmi/id/product_uuid", ID128_UUID, &uuid);
|
||||
r = id128_read("/sys/class/dmi/id/product_uuid", ID128_FORMAT_UUID, &uuid);
|
||||
if (r == -ENOENT)
|
||||
r = id128_read("/proc/device-tree/vm,uuid", ID128_UUID, &uuid);
|
||||
r = id128_read("/proc/device-tree/vm,uuid", ID128_FORMAT_UUID, &uuid);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
|
|
|||
|
|
@ -10,27 +10,32 @@
|
|||
|
||||
bool id128_is_valid(const char *s) _pure_;
|
||||
|
||||
typedef enum Id128Format {
|
||||
ID128_ANY,
|
||||
ID128_PLAIN, /* formatted as 32 hex chars as-is */
|
||||
ID128_PLAIN_OR_UNINIT, /* formatted as 32 hex chars as-is; allow special "uninitialized"
|
||||
* value when reading from file (id128_read() and id128_read_fd()).
|
||||
*
|
||||
* This format should be used when reading a machine-id file. */
|
||||
ID128_UUID, /* formatted as 36 character uuid string */
|
||||
_ID128_FORMAT_MAX,
|
||||
} Id128Format;
|
||||
typedef enum Id128FormatFlag {
|
||||
ID128_FORMAT_PLAIN = 1 << 0, /* formatted as 32 hex chars as-is */
|
||||
ID128_FORMAT_UUID = 1 << 1, /* formatted as 36 character uuid string */
|
||||
ID128_FORMAT_ANY = ID128_FORMAT_PLAIN | ID128_FORMAT_UUID,
|
||||
|
||||
int id128_read_fd(int fd, Id128Format f, sd_id128_t *ret);
|
||||
int id128_read(const char *p, Id128Format f, sd_id128_t *ret);
|
||||
ID128_SYNC_ON_WRITE = 1 << 2, /* Sync the file after write. Used only when writing an ID. */
|
||||
} Id128FormatFlag;
|
||||
|
||||
int id128_write_fd(int fd, Id128Format f, sd_id128_t id, bool do_sync);
|
||||
int id128_write(const char *p, Id128Format f, sd_id128_t id, bool do_sync);
|
||||
int id128_read_fd(int fd, Id128FormatFlag f, sd_id128_t *ret);
|
||||
int id128_read(const char *p, Id128FormatFlag f, sd_id128_t *ret);
|
||||
|
||||
int id128_write_fd(int fd, Id128FormatFlag f, sd_id128_t id);
|
||||
int id128_write(const char *p, Id128FormatFlag f, sd_id128_t id);
|
||||
|
||||
void id128_hash_func(const sd_id128_t *p, struct siphash *state);
|
||||
int id128_compare_func(const sd_id128_t *a, const sd_id128_t *b) _pure_;
|
||||
extern const struct hash_ops id128_hash_ops;
|
||||
extern const struct hash_ops id128_hash_ops_free;
|
||||
|
||||
sd_id128_t id128_make_v4_uuid(sd_id128_t id);
|
||||
|
||||
int id128_get_product(sd_id128_t *ret);
|
||||
|
||||
/* A helper to check for the three relevant cases of "machine ID not initialized" */
|
||||
#define ERRNO_IS_MACHINE_ID_UNSET(r) \
|
||||
IN_SET(abs(r), \
|
||||
ENOENT, \
|
||||
ENOMEDIUM, \
|
||||
ENOPKG)
|
||||
|
|
|
|||
|
|
@ -17,19 +17,22 @@
|
|||
#include "macro.h"
|
||||
#include "missing_syscall.h"
|
||||
#include "random-util.h"
|
||||
#include "stat-util.h"
|
||||
#include "user-util.h"
|
||||
#include "util.h"
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
_public_ char *sd_id128_to_string(sd_id128_t id, char s[_SD_ARRAY_STATIC SD_ID128_STRING_MAX]) {
|
||||
size_t k = 0;
|
||||
|
||||
assert_return(s, NULL);
|
||||
|
||||
for (size_t n = 0; n < 16; n++) {
|
||||
s[n*2] = hexchar(id.bytes[n] >> 4);
|
||||
s[n*2+1] = hexchar(id.bytes[n] & 0xF);
|
||||
for (size_t n = 0; n < sizeof(sd_id128_t); n++) {
|
||||
s[k++] = hexchar(id.bytes[n] >> 4);
|
||||
s[k++] = hexchar(id.bytes[n] & 0xF);
|
||||
}
|
||||
|
||||
s[SD_ID128_STRING_MAX-1] = 0;
|
||||
assert(k == SD_ID128_STRING_MAX - 1);
|
||||
s[k] = 0;
|
||||
|
||||
return s;
|
||||
}
|
||||
|
|
@ -41,7 +44,7 @@ _public_ char *sd_id128_to_uuid_string(sd_id128_t id, char s[_SD_ARRAY_STATIC SD
|
|||
|
||||
/* Similar to sd_id128_to_string() but formats the result as UUID instead of plain hex chars */
|
||||
|
||||
for (size_t n = 0; n < 16; n++) {
|
||||
for (size_t n = 0; n < sizeof(sd_id128_t); n++) {
|
||||
|
||||
if (IN_SET(n, 4, 6, 8, 10))
|
||||
s[k++] = '-';
|
||||
|
|
@ -57,14 +60,14 @@ _public_ char *sd_id128_to_uuid_string(sd_id128_t id, char s[_SD_ARRAY_STATIC SD
|
|||
}
|
||||
#endif /* NM_IGNORED */
|
||||
|
||||
_public_ int sd_id128_from_string(const char s[], sd_id128_t *ret) {
|
||||
unsigned n, i;
|
||||
_public_ int sd_id128_from_string(const char *s, sd_id128_t *ret) {
|
||||
size_t n, i;
|
||||
sd_id128_t t;
|
||||
bool is_guid = false;
|
||||
|
||||
assert_return(s, -EINVAL);
|
||||
|
||||
for (n = 0, i = 0; n < 16;) {
|
||||
for (n = 0, i = 0; n < sizeof(sd_id128_t);) {
|
||||
int a, b;
|
||||
|
||||
if (s[i] == '-') {
|
||||
|
|
@ -94,7 +97,7 @@ _public_ int sd_id128_from_string(const char s[], sd_id128_t *ret) {
|
|||
t.bytes[n++] = (a << 4) | b;
|
||||
}
|
||||
|
||||
if (i != (is_guid ? 36 : 32))
|
||||
if (i != (is_guid ? SD_ID128_UUID_STRING_MAX : SD_ID128_STRING_MAX) - 1)
|
||||
return -EINVAL;
|
||||
|
||||
if (s[i] != 0)
|
||||
|
|
@ -125,10 +128,8 @@ _public_ int sd_id128_get_machine(sd_id128_t *ret) {
|
|||
static thread_local sd_id128_t saved_machine_id = {};
|
||||
int r;
|
||||
|
||||
assert_return(ret, -EINVAL);
|
||||
|
||||
if (sd_id128_is_null(saved_machine_id)) {
|
||||
r = id128_read("/etc/machine-id", ID128_PLAIN, &saved_machine_id);
|
||||
r = id128_read("/etc/machine-id", ID128_FORMAT_PLAIN, &saved_machine_id);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
|
@ -136,7 +137,8 @@ _public_ int sd_id128_get_machine(sd_id128_t *ret) {
|
|||
return -ENOMEDIUM;
|
||||
}
|
||||
|
||||
*ret = saved_machine_id;
|
||||
if (ret)
|
||||
*ret = saved_machine_id;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -144,15 +146,19 @@ _public_ int sd_id128_get_boot(sd_id128_t *ret) {
|
|||
static thread_local sd_id128_t saved_boot_id = {};
|
||||
int r;
|
||||
|
||||
assert_return(ret, -EINVAL);
|
||||
|
||||
if (sd_id128_is_null(saved_boot_id)) {
|
||||
r = id128_read("/proc/sys/kernel/random/boot_id", ID128_UUID, &saved_boot_id);
|
||||
r = id128_read("/proc/sys/kernel/random/boot_id", ID128_FORMAT_UUID, &saved_boot_id);
|
||||
if (r == -ENOENT && proc_mounted() == 0)
|
||||
return -ENOSYS;
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (sd_id128_is_null(saved_boot_id))
|
||||
return -ENOMEDIUM;
|
||||
}
|
||||
|
||||
*ret = saved_boot_id;
|
||||
if (ret)
|
||||
*ret = saved_boot_id;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -203,22 +209,22 @@ static int get_invocation_from_keyring(sd_id128_t *ret) {
|
|||
/* Chop off the final description string */
|
||||
d = strrchr(description, ';');
|
||||
if (!d)
|
||||
return -EIO;
|
||||
return -EUCLEAN;
|
||||
*d = 0;
|
||||
|
||||
/* Look for the permissions */
|
||||
p = strrchr(description, ';');
|
||||
if (!p)
|
||||
return -EIO;
|
||||
return -EUCLEAN;
|
||||
|
||||
errno = 0;
|
||||
perms = strtoul(p + 1, &e, 16);
|
||||
if (errno > 0)
|
||||
return -errno;
|
||||
if (e == p + 1) /* Read at least one character */
|
||||
return -EIO;
|
||||
return -EUCLEAN;
|
||||
if (e != d) /* Must reached the end */
|
||||
return -EIO;
|
||||
return -EUCLEAN;
|
||||
|
||||
if ((perms & ~MAX_PERMS) != 0)
|
||||
return -EPERM;
|
||||
|
|
@ -228,7 +234,7 @@ static int get_invocation_from_keyring(sd_id128_t *ret) {
|
|||
/* Look for the group ID */
|
||||
g = strrchr(description, ';');
|
||||
if (!g)
|
||||
return -EIO;
|
||||
return -EUCLEAN;
|
||||
r = parse_gid(g + 1, &gid);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
|
@ -239,7 +245,7 @@ static int get_invocation_from_keyring(sd_id128_t *ret) {
|
|||
/* Look for the user ID */
|
||||
u = strrchr(description, ';');
|
||||
if (!u)
|
||||
return -EIO;
|
||||
return -EUCLEAN;
|
||||
r = parse_uid(u + 1, &uid);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
|
@ -250,13 +256,14 @@ static int get_invocation_from_keyring(sd_id128_t *ret) {
|
|||
if (c < 0)
|
||||
return -errno;
|
||||
if (c != sizeof(sd_id128_t))
|
||||
return -EIO;
|
||||
return -EUCLEAN;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_invocation_from_environment(sd_id128_t *ret) {
|
||||
const char *e;
|
||||
int r;
|
||||
|
||||
assert(ret);
|
||||
|
||||
|
|
@ -264,33 +271,31 @@ static int get_invocation_from_environment(sd_id128_t *ret) {
|
|||
if (!e)
|
||||
return -ENXIO;
|
||||
|
||||
return sd_id128_from_string(e, ret);
|
||||
r = sd_id128_from_string(e, ret);
|
||||
return r == -EINVAL ? -EUCLEAN : r;
|
||||
}
|
||||
|
||||
_public_ int sd_id128_get_invocation(sd_id128_t *ret) {
|
||||
static thread_local sd_id128_t saved_invocation_id = {};
|
||||
int r;
|
||||
|
||||
assert_return(ret, -EINVAL);
|
||||
|
||||
if (sd_id128_is_null(saved_invocation_id)) {
|
||||
/* We first check the environment. The environment variable is primarily relevant for user
|
||||
* services, and sufficiently safe as long as no privilege boundary is involved. */
|
||||
r = get_invocation_from_environment(&saved_invocation_id);
|
||||
if (r >= 0) {
|
||||
*ret = saved_invocation_id;
|
||||
return 0;
|
||||
} else if (r != -ENXIO)
|
||||
return r;
|
||||
|
||||
/* The kernel keyring is relevant for system services (as for user services we don't store
|
||||
* the invocation ID in the keyring, as there'd be no trust benefit in that). */
|
||||
r = get_invocation_from_keyring(&saved_invocation_id);
|
||||
if (r == -ENXIO)
|
||||
/* The kernel keyring is relevant for system services (as for user services we don't
|
||||
* store the invocation ID in the keyring, as there'd be no trust benefit in that). */
|
||||
r = get_invocation_from_keyring(&saved_invocation_id);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (sd_id128_is_null(saved_invocation_id))
|
||||
return -ENOMEDIUM;
|
||||
}
|
||||
|
||||
*ret = saved_invocation_id;
|
||||
if (ret)
|
||||
*ret = saved_invocation_id;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
167
src/libnm-systemd-core/src/systemd/sd-device.h
Normal file
167
src/libnm-systemd-core/src/systemd/sd-device.h
Normal file
|
|
@ -0,0 +1,167 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#ifndef foosddevicehfoo
|
||||
#define foosddevicehfoo
|
||||
|
||||
/***
|
||||
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
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd 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 systemd; If not, see <https://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <errno.h>
|
||||
#include <inttypes.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/sysmacros.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "sd-event.h"
|
||||
#include "sd-id128.h"
|
||||
|
||||
#include "_sd-common.h"
|
||||
|
||||
_SD_BEGIN_DECLARATIONS;
|
||||
|
||||
typedef struct sd_device sd_device;
|
||||
typedef struct sd_device_enumerator sd_device_enumerator;
|
||||
typedef struct sd_device_monitor sd_device_monitor;
|
||||
|
||||
__extension__ typedef enum sd_device_action_t {
|
||||
SD_DEVICE_ADD,
|
||||
SD_DEVICE_REMOVE,
|
||||
SD_DEVICE_CHANGE,
|
||||
SD_DEVICE_MOVE,
|
||||
SD_DEVICE_ONLINE,
|
||||
SD_DEVICE_OFFLINE,
|
||||
SD_DEVICE_BIND,
|
||||
SD_DEVICE_UNBIND,
|
||||
_SD_DEVICE_ACTION_MAX,
|
||||
_SD_DEVICE_ACTION_INVALID = -EINVAL,
|
||||
_SD_ENUM_FORCE_S64(DEVICE_ACTION)
|
||||
} sd_device_action_t;
|
||||
|
||||
/* callback */
|
||||
|
||||
typedef int (*sd_device_monitor_handler_t)(sd_device_monitor *m, sd_device *device, void *userdata);
|
||||
|
||||
/* device */
|
||||
|
||||
sd_device *sd_device_ref(sd_device *device);
|
||||
sd_device *sd_device_unref(sd_device *device);
|
||||
|
||||
int sd_device_new_from_syspath(sd_device **ret, const char *syspath);
|
||||
int sd_device_new_from_devnum(sd_device **ret, char type, dev_t devnum);
|
||||
int sd_device_new_from_subsystem_sysname(sd_device **ret, const char *subsystem, const char *sysname);
|
||||
int sd_device_new_from_device_id(sd_device **ret, const char *id);
|
||||
int sd_device_new_from_stat_rdev(sd_device **ret, const struct stat *st);
|
||||
int sd_device_new_from_devname(sd_device **ret, const char *devname);
|
||||
int sd_device_new_from_path(sd_device **ret, const char *path);
|
||||
int sd_device_new_from_ifname(sd_device **ret, const char *ifname);
|
||||
int sd_device_new_from_ifindex(sd_device **ret, int ifindex);
|
||||
|
||||
int sd_device_new_child(sd_device **ret, sd_device *device, const char *suffix);
|
||||
|
||||
int sd_device_get_parent(sd_device *child, sd_device **ret);
|
||||
int sd_device_get_parent_with_subsystem_devtype(sd_device *child, const char *subsystem, const char *devtype, sd_device **ret);
|
||||
|
||||
int sd_device_get_syspath(sd_device *device, const char **ret);
|
||||
int sd_device_get_subsystem(sd_device *device, const char **ret);
|
||||
int sd_device_get_devtype(sd_device *device, const char **ret);
|
||||
int sd_device_get_devnum(sd_device *device, dev_t *devnum);
|
||||
int sd_device_get_ifindex(sd_device *device, int *ifindex);
|
||||
int sd_device_get_driver(sd_device *device, const char **ret);
|
||||
int sd_device_get_devpath(sd_device *device, const char **ret);
|
||||
int sd_device_get_devname(sd_device *device, const char **ret);
|
||||
int sd_device_get_sysname(sd_device *device, const char **ret);
|
||||
int sd_device_get_sysnum(sd_device *device, const char **ret);
|
||||
int sd_device_get_action(sd_device *device, sd_device_action_t *ret);
|
||||
int sd_device_get_seqnum(sd_device *device, uint64_t *ret);
|
||||
int sd_device_get_diskseq(sd_device *device, uint64_t *ret);
|
||||
|
||||
int sd_device_get_is_initialized(sd_device *device);
|
||||
int sd_device_get_usec_initialized(sd_device *device, uint64_t *ret);
|
||||
int sd_device_get_usec_since_initialized(sd_device *device, uint64_t *ret);
|
||||
|
||||
const char *sd_device_get_tag_first(sd_device *device);
|
||||
const char *sd_device_get_tag_next(sd_device *device);
|
||||
const char *sd_device_get_current_tag_first(sd_device *device);
|
||||
const char *sd_device_get_current_tag_next(sd_device *device);
|
||||
const char *sd_device_get_devlink_first(sd_device *device);
|
||||
const char *sd_device_get_devlink_next(sd_device *device);
|
||||
const char *sd_device_get_property_first(sd_device *device, const char **value);
|
||||
const char *sd_device_get_property_next(sd_device *device, const char **value);
|
||||
const char *sd_device_get_sysattr_first(sd_device *device);
|
||||
const char *sd_device_get_sysattr_next(sd_device *device);
|
||||
sd_device *sd_device_get_child_first(sd_device *device, const char **ret_suffix);
|
||||
sd_device *sd_device_get_child_next(sd_device *device, const char **ret_suffix);
|
||||
|
||||
int sd_device_has_tag(sd_device *device, const char *tag);
|
||||
int sd_device_has_current_tag(sd_device *device, const char *tag);
|
||||
int sd_device_get_property_value(sd_device *device, const char *key, const char **value);
|
||||
int sd_device_get_trigger_uuid(sd_device *device, sd_id128_t *ret);
|
||||
int sd_device_get_sysattr_value(sd_device *device, const char *sysattr, const char **_value);
|
||||
|
||||
int sd_device_set_sysattr_value(sd_device *device, const char *sysattr, const char *value);
|
||||
int sd_device_set_sysattr_valuef(sd_device *device, const char *sysattr, const char *format, ...) _sd_printf_(3, 4);
|
||||
int sd_device_trigger(sd_device *device, sd_device_action_t action);
|
||||
int sd_device_trigger_with_uuid(sd_device *device, sd_device_action_t action, sd_id128_t *ret_uuid);
|
||||
int sd_device_open(sd_device *device, int flags);
|
||||
|
||||
/* device enumerator */
|
||||
|
||||
int sd_device_enumerator_new(sd_device_enumerator **ret);
|
||||
sd_device_enumerator *sd_device_enumerator_ref(sd_device_enumerator *enumerator);
|
||||
sd_device_enumerator *sd_device_enumerator_unref(sd_device_enumerator *enumerator);
|
||||
|
||||
sd_device *sd_device_enumerator_get_device_first(sd_device_enumerator *enumerator);
|
||||
sd_device *sd_device_enumerator_get_device_next(sd_device_enumerator *enumerator);
|
||||
sd_device *sd_device_enumerator_get_subsystem_first(sd_device_enumerator *enumerator);
|
||||
sd_device *sd_device_enumerator_get_subsystem_next(sd_device_enumerator *enumerator);
|
||||
|
||||
int sd_device_enumerator_add_match_subsystem(sd_device_enumerator *enumerator, const char *subsystem, int match);
|
||||
int sd_device_enumerator_add_match_sysattr(sd_device_enumerator *enumerator, const char *sysattr, const char *value, int match);
|
||||
int sd_device_enumerator_add_match_property(sd_device_enumerator *enumerator, const char *property, const char *value);
|
||||
int sd_device_enumerator_add_match_sysname(sd_device_enumerator *enumerator, const char *sysname);
|
||||
int sd_device_enumerator_add_nomatch_sysname(sd_device_enumerator *enumerator, const char *sysname);
|
||||
int sd_device_enumerator_add_match_tag(sd_device_enumerator *enumerator, const char *tag);
|
||||
int sd_device_enumerator_add_match_parent(sd_device_enumerator *enumerator, sd_device *parent);
|
||||
int sd_device_enumerator_allow_uninitialized(sd_device_enumerator *enumerator);
|
||||
|
||||
/* device monitor */
|
||||
|
||||
int sd_device_monitor_new(sd_device_monitor **ret);
|
||||
sd_device_monitor *sd_device_monitor_ref(sd_device_monitor *m);
|
||||
sd_device_monitor *sd_device_monitor_unref(sd_device_monitor *m);
|
||||
|
||||
int sd_device_monitor_set_receive_buffer_size(sd_device_monitor *m, size_t size);
|
||||
int sd_device_monitor_attach_event(sd_device_monitor *m, sd_event *event);
|
||||
int sd_device_monitor_detach_event(sd_device_monitor *m);
|
||||
sd_event *sd_device_monitor_get_event(sd_device_monitor *m);
|
||||
sd_event_source *sd_device_monitor_get_event_source(sd_device_monitor *m);
|
||||
int sd_device_monitor_set_description(sd_device_monitor *m, const char *description);
|
||||
int sd_device_monitor_get_description(sd_device_monitor *m, const char **ret);
|
||||
int sd_device_monitor_start(sd_device_monitor *m, sd_device_monitor_handler_t callback, void *userdata);
|
||||
int sd_device_monitor_stop(sd_device_monitor *m);
|
||||
|
||||
int sd_device_monitor_filter_add_match_subsystem_devtype(sd_device_monitor *m, const char *subsystem, const char *devtype);
|
||||
int sd_device_monitor_filter_add_match_tag(sd_device_monitor *m, const char *tag);
|
||||
int sd_device_monitor_filter_add_match_sysattr(sd_device_monitor *m, const char *sysattr, const char *value, int match);
|
||||
int sd_device_monitor_filter_add_match_parent(sd_device_monitor *m, sd_device *device, int match);
|
||||
int sd_device_monitor_filter_update(sd_device_monitor *m);
|
||||
int sd_device_monitor_filter_remove(sd_device_monitor *m);
|
||||
|
||||
_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_device, sd_device_unref);
|
||||
_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_device_enumerator, sd_device_enumerator_unref);
|
||||
_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_device_monitor, sd_device_monitor_unref);
|
||||
|
||||
_SD_END_DECLARATIONS;
|
||||
|
||||
#endif
|
||||
|
|
@ -23,6 +23,7 @@
|
|||
#include <net/ethernet.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "sd-device.h"
|
||||
#include "sd-dhcp6-lease.h"
|
||||
#include "sd-dhcp6-option.h"
|
||||
#include "sd-event.h"
|
||||
|
|
@ -263,6 +264,7 @@ int sd_dhcp6_client_set_address_request(sd_dhcp6_client *client,
|
|||
int sd_dhcp6_client_add_vendor_option(sd_dhcp6_client *client,
|
||||
sd_dhcp6_option *v);
|
||||
int sd_dhcp6_client_set_rapid_commit(sd_dhcp6_client *client, int enable);
|
||||
int sd_dhcp6_client_set_send_release(sd_dhcp6_client *client, int enable);
|
||||
|
||||
int sd_dhcp6_client_get_lease(
|
||||
sd_dhcp6_client *client,
|
||||
|
|
@ -279,6 +281,7 @@ int sd_dhcp6_client_attach_event(
|
|||
int64_t priority);
|
||||
int sd_dhcp6_client_detach_event(sd_dhcp6_client *client);
|
||||
sd_event *sd_dhcp6_client_get_event(sd_dhcp6_client *client);
|
||||
int sd_dhcp6_client_attach_device(sd_dhcp6_client *client, sd_device *dev);
|
||||
sd_dhcp6_client *sd_dhcp6_client_ref(sd_dhcp6_client *client);
|
||||
sd_dhcp6_client *sd_dhcp6_client_unref(sd_dhcp6_client *client);
|
||||
int sd_dhcp6_client_new(sd_dhcp6_client **ret);
|
||||
|
|
|
|||
|
|
@ -42,7 +42,6 @@ libnm_systemd_shared = static_library(
|
|||
'src/basic/time-util.c',
|
||||
'src/basic/tmpfile-util.c',
|
||||
'src/basic/utf8.c',
|
||||
'src/basic/util.c',
|
||||
'src/fundamental/sha256.c',
|
||||
'src/fundamental/string-util-fundamental.c',
|
||||
'src/shared/dns-domain.c',
|
||||
|
|
|
|||
|
|
@ -1,3 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
/* dummy header */
|
||||
|
|
@ -34,6 +34,10 @@
|
|||
|
||||
#define ENABLE_DEBUG_HASHMAP 0
|
||||
|
||||
#define SD_BOOT 0
|
||||
|
||||
#define HAVE_SPLIT_USR 0
|
||||
|
||||
/*****************************************************************************
|
||||
* The remainder of the header is only enabled when building the systemd code
|
||||
* itself.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
#pragma once
|
||||
|
||||
#include "libnm-std-aux/unaligned-fundamental.h"
|
||||
|
|
@ -104,3 +104,7 @@ void* greedy_realloc0(
|
|||
|
||||
return q;
|
||||
}
|
||||
|
||||
void *expand_to_usable(void *ptr, size_t newsize _unused_) {
|
||||
return ptr;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <alloca.h>
|
||||
#include <malloc.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
|
@ -184,17 +185,35 @@ void* greedy_realloc0(void **p, size_t need, size_t size);
|
|||
# define msan_unpoison(r, s)
|
||||
#endif
|
||||
|
||||
/* This returns the number of usable bytes in a malloc()ed region as per malloc_usable_size(), in a way that
|
||||
* is compatible with _FORTIFY_SOURCES. If _FORTIFY_SOURCES is used many memory operations will take the
|
||||
* object size as returned by __builtin_object_size() into account. Hence, let's return the smaller size of
|
||||
* malloc_usable_size() and __builtin_object_size() here, so that we definitely operate in safe territory by
|
||||
* both the compiler's and libc's standards. Note that __builtin_object_size() evaluates to SIZE_MAX if the
|
||||
* size cannot be determined, hence the MIN() expression should be safe with dynamically sized memory,
|
||||
* too. Moreover, when NULL is passed malloc_usable_size() is documented to return zero, and
|
||||
* __builtin_object_size() returns SIZE_MAX too, hence we also return a sensible value of 0 in this corner
|
||||
* case. */
|
||||
/* Dummy allocator to tell the compiler that the new size of p is newsize. The implementation returns the
|
||||
* pointer as is; the only reason for its existence is as a conduit for the _alloc_ attribute. This must not
|
||||
* be inlined (hence a non-static function with _noinline_ because LTO otherwise tries to inline it) because
|
||||
* gcc then loses the attributes on the function.
|
||||
* See: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96503 */
|
||||
void *expand_to_usable(void *p, size_t newsize) _alloc_(2) _returns_nonnull_ _noinline_;
|
||||
|
||||
static inline size_t malloc_sizeof_safe(void **xp) {
|
||||
if (_unlikely_(!xp || !*xp))
|
||||
return 0;
|
||||
|
||||
size_t sz = malloc_usable_size(*xp);
|
||||
*xp = expand_to_usable(*xp, sz);
|
||||
/* GCC doesn't see the _returns_nonnull_ when built with ubsan, so yet another hint to make it doubly
|
||||
* clear that expand_to_usable won't return NULL.
|
||||
* See: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=79265 */
|
||||
if (!*xp)
|
||||
assert_not_reached();
|
||||
return sz;
|
||||
}
|
||||
|
||||
/* This returns the number of usable bytes in a malloc()ed region as per malloc_usable_size(), which may
|
||||
* return a value larger than the size that was actually allocated. Access to that additional memory is
|
||||
* discouraged because it violates the C standard; a compiler cannot see that this as valid. To help the
|
||||
* compiler out, the MALLOC_SIZEOF_SAFE macro 'allocates' the usable size using a dummy allocator function
|
||||
* expand_to_usable. There is a possibility of malloc_usable_size() returning different values during the
|
||||
* lifetime of an object, which may cause problems, but the glibc allocator does not do that at the moment. */
|
||||
#define MALLOC_SIZEOF_SAFE(x) \
|
||||
MIN(malloc_usable_size(x), __builtin_object_size(x, 0))
|
||||
malloc_sizeof_safe((void**) &__builtin_choose_expr(__builtin_constant_p(x), (void*) { NULL }, (x)))
|
||||
|
||||
/* Inspired by ELEMENTSOF() but operates on malloc()'ed memory areas: typesafely returns the number of items
|
||||
* that fit into the specified memory block */
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
#include <sys/statfs.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "def.h"
|
||||
#include "constants.h"
|
||||
#include "set.h"
|
||||
|
||||
#define SYSTEMD_CGROUP_CONTROLLER_LEGACY "name=systemd"
|
||||
|
|
|
|||
111
src/libnm-systemd-shared/src/basic/constants.h
Normal file
111
src/libnm-systemd-shared/src/basic/constants.h
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#if !defined(HAS_FEATURE_MEMORY_SANITIZER)
|
||||
# if defined(__has_feature)
|
||||
# if __has_feature(memory_sanitizer)
|
||||
# define HAS_FEATURE_MEMORY_SANITIZER 1
|
||||
# endif
|
||||
# endif
|
||||
# if !defined(HAS_FEATURE_MEMORY_SANITIZER)
|
||||
# define HAS_FEATURE_MEMORY_SANITIZER 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if !defined(HAS_FEATURE_ADDRESS_SANITIZER)
|
||||
# ifdef __SANITIZE_ADDRESS__
|
||||
# define HAS_FEATURE_ADDRESS_SANITIZER 1
|
||||
# elif defined(__has_feature)
|
||||
# if __has_feature(address_sanitizer)
|
||||
# define HAS_FEATURE_ADDRESS_SANITIZER 1
|
||||
# endif
|
||||
# endif
|
||||
# if !defined(HAS_FEATURE_ADDRESS_SANITIZER)
|
||||
# define HAS_FEATURE_ADDRESS_SANITIZER 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#define DEFAULT_RESTART_USEC (100*USEC_PER_MSEC)
|
||||
|
||||
/* Many different things, but also system unit start/stop */
|
||||
#define DEFAULT_TIMEOUT_USEC (DEFAULT_TIMEOUT_SEC*USEC_PER_SEC)
|
||||
/* User unit start/stop */
|
||||
#define DEFAULT_USER_TIMEOUT_USEC (DEFAULT_USER_TIMEOUT_SEC*USEC_PER_SEC)
|
||||
/* Timeout for user confirmation on the console */
|
||||
#define DEFAULT_CONFIRM_USEC (30*USEC_PER_SEC)
|
||||
|
||||
/* We use an extra-long timeout for the reload. This is because a reload or reexec means generators are rerun
|
||||
* which are timed out after DEFAULT_TIMEOUT_USEC. Let's use twice that time here, so that the generators can
|
||||
* have their timeout, and for everything else there's the same time budget in place. */
|
||||
#define DAEMON_RELOAD_TIMEOUT_SEC (DEFAULT_TIMEOUT_USEC * 2)
|
||||
|
||||
#define DEFAULT_START_LIMIT_INTERVAL (10*USEC_PER_SEC)
|
||||
#define DEFAULT_START_LIMIT_BURST 5
|
||||
|
||||
/* The default time after which exit-on-idle services exit. This
|
||||
* should be kept lower than the watchdog timeout, because otherwise
|
||||
* the watchdog pings will keep the loop busy. */
|
||||
#define DEFAULT_EXIT_USEC (30*USEC_PER_SEC)
|
||||
|
||||
/* The default value for the net.unix.max_dgram_qlen sysctl */
|
||||
#define DEFAULT_UNIX_MAX_DGRAM_QLEN 512
|
||||
|
||||
#define SIGNALS_CRASH_HANDLER SIGSEGV,SIGILL,SIGFPE,SIGBUS,SIGQUIT,SIGABRT
|
||||
#define SIGNALS_IGNORE SIGPIPE
|
||||
|
||||
#define NOTIFY_FD_MAX 768
|
||||
#define NOTIFY_BUFFER_MAX PIPE_BUF
|
||||
|
||||
#if HAVE_SPLIT_USR
|
||||
# define _CONF_PATHS_SPLIT_USR_NULSTR(n) "/lib/" n "\0"
|
||||
# define _CONF_PATHS_SPLIT_USR(n) , "/lib/" n
|
||||
#else
|
||||
# define _CONF_PATHS_SPLIT_USR_NULSTR(n)
|
||||
# define _CONF_PATHS_SPLIT_USR(n)
|
||||
#endif
|
||||
|
||||
/* Return a nulstr for a standard cascade of configuration paths,
|
||||
* suitable to pass to conf_files_list_nulstr() or config_parse_many_nulstr()
|
||||
* to implement drop-in directories for extending configuration
|
||||
* files. */
|
||||
#define CONF_PATHS_NULSTR(n) \
|
||||
"/etc/" n "\0" \
|
||||
"/run/" n "\0" \
|
||||
"/usr/local/lib/" n "\0" \
|
||||
"/usr/lib/" n "\0" \
|
||||
_CONF_PATHS_SPLIT_USR_NULSTR(n)
|
||||
|
||||
#define CONF_PATHS_USR(n) \
|
||||
"/etc/" n, \
|
||||
"/run/" n, \
|
||||
"/usr/local/lib/" n, \
|
||||
"/usr/lib/" n
|
||||
|
||||
#define CONF_PATHS(n) \
|
||||
CONF_PATHS_USR(n) \
|
||||
_CONF_PATHS_SPLIT_USR(n)
|
||||
|
||||
#define CONF_PATHS_USR_STRV(n) \
|
||||
STRV_MAKE(CONF_PATHS_USR(n))
|
||||
|
||||
#define CONF_PATHS_STRV(n) \
|
||||
STRV_MAKE(CONF_PATHS(n))
|
||||
|
||||
/* The limit for PID 1 itself (which is not inherited to children) */
|
||||
#define HIGH_RLIMIT_MEMLOCK (1024ULL*1024ULL*64ULL)
|
||||
|
||||
/* Since kernel 5.16 the kernel default limit was raised to 8M. Let's adjust things on old kernels too, and
|
||||
* in containers so that our children inherit that. */
|
||||
#define DEFAULT_RLIMIT_MEMLOCK (1024ULL*1024ULL*8ULL)
|
||||
|
||||
#define PLYMOUTH_SOCKET { \
|
||||
.un.sun_family = AF_UNIX, \
|
||||
.un.sun_path = "\0/org/freedesktop/plymouthd", \
|
||||
}
|
||||
|
||||
/* Path where PID1 listens for varlink subscriptions from systemd-oomd to notify of changes in ManagedOOM settings. */
|
||||
#define VARLINK_ADDR_PATH_MANAGED_OOM_SYSTEM "/run/systemd/io.system.ManagedOOM"
|
||||
/* Path where systemd-oomd listens for varlink connections from user managers to report changes in ManagedOOM settings. */
|
||||
#define VARLINK_ADDR_PATH_MANAGED_OOM_USER "/run/systemd/oom/io.system.ManagedOOM"
|
||||
|
||||
#define KERNEL_BASELINE_VERSION "4.15"
|
||||
|
|
@ -14,11 +14,17 @@
|
|||
#include "tmpfile-util.h"
|
||||
#include "utf8.h"
|
||||
|
||||
typedef int (*push_env_func_t)(
|
||||
const char *filename,
|
||||
unsigned line,
|
||||
const char *key,
|
||||
char *value,
|
||||
void *userdata);
|
||||
|
||||
static int parse_env_file_internal(
|
||||
FILE *f,
|
||||
const char *fname,
|
||||
int (*push) (const char *filename, unsigned line,
|
||||
const char *key, char *value, void *userdata),
|
||||
push_env_func_t push,
|
||||
void *userdata) {
|
||||
|
||||
size_t n_key = 0, n_value = 0, last_value_whitespace = SIZE_MAX, last_key_whitespace = SIZE_MAX;
|
||||
|
|
@ -39,6 +45,9 @@ static int parse_env_file_internal(
|
|||
COMMENT_ESCAPE
|
||||
} state = PRE_KEY;
|
||||
|
||||
assert(f || fname);
|
||||
assert(push);
|
||||
|
||||
if (f)
|
||||
r = read_full_stream(f, &contents, NULL);
|
||||
else
|
||||
|
|
@ -276,6 +285,8 @@ static int check_utf8ness_and_warn(
|
|||
const char *filename, unsigned line,
|
||||
const char *key, char *value) {
|
||||
|
||||
assert(key);
|
||||
|
||||
if (!utf8_is_valid(key)) {
|
||||
_cleanup_free_ char *p = NULL;
|
||||
|
||||
|
|
@ -306,6 +317,8 @@ static int parse_env_file_push(
|
|||
va_list aq, *ap = userdata;
|
||||
int r;
|
||||
|
||||
assert(key);
|
||||
|
||||
r = check_utf8ness_and_warn(filename, line, key, value);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
|
@ -340,6 +353,8 @@ int parse_env_filev(
|
|||
int r;
|
||||
va_list aq;
|
||||
|
||||
assert(f || fname);
|
||||
|
||||
va_copy(aq, ap);
|
||||
r = parse_env_file_internal(f, fname, parse_env_file_push, &aq);
|
||||
va_end(aq);
|
||||
|
|
@ -354,6 +369,8 @@ int parse_env_file_sentinel(
|
|||
va_list ap;
|
||||
int r;
|
||||
|
||||
assert(f || fname);
|
||||
|
||||
va_start(ap, fname);
|
||||
r = parse_env_filev(f, fname, ap);
|
||||
va_end(ap);
|
||||
|
|
@ -362,14 +379,46 @@ int parse_env_file_sentinel(
|
|||
}
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
int parse_env_file_fd_sentinel(
|
||||
int fd,
|
||||
const char *fname, /* only used for logging */
|
||||
...) {
|
||||
|
||||
_cleanup_close_ int fd_ro = -EBADF;
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
va_list ap;
|
||||
int r;
|
||||
|
||||
assert(fd >= 0);
|
||||
|
||||
fd_ro = fd_reopen(fd, O_CLOEXEC | O_RDONLY);
|
||||
if (fd_ro < 0)
|
||||
return fd_ro;
|
||||
|
||||
f = fdopen(fd_ro, "re");
|
||||
if (!f)
|
||||
return -errno;
|
||||
|
||||
TAKE_FD(fd_ro);
|
||||
|
||||
va_start(ap, fname);
|
||||
r = parse_env_filev(f, fname, ap);
|
||||
va_end(ap);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int load_env_file_push(
|
||||
const char *filename, unsigned line,
|
||||
const char *key, char *value,
|
||||
void *userdata) {
|
||||
|
||||
char ***m = userdata;
|
||||
char *p;
|
||||
int r;
|
||||
|
||||
assert(key);
|
||||
|
||||
r = check_utf8ness_and_warn(filename, line, key, value);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
|
@ -386,15 +435,18 @@ static int load_env_file_push(
|
|||
return 0;
|
||||
}
|
||||
|
||||
int load_env_file(FILE *f, const char *fname, char ***rl) {
|
||||
int load_env_file(FILE *f, const char *fname, char ***ret) {
|
||||
_cleanup_strv_free_ char **m = NULL;
|
||||
int r;
|
||||
|
||||
assert(f || fname);
|
||||
assert(ret);
|
||||
|
||||
r = parse_env_file_internal(f, fname, load_env_file_push, &m);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
*rl = TAKE_PTR(m);
|
||||
*ret = TAKE_PTR(m);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -406,6 +458,8 @@ static int load_env_file_push_pairs(
|
|||
char ***m = ASSERT_PTR(userdata);
|
||||
int r;
|
||||
|
||||
assert(key);
|
||||
|
||||
r = check_utf8ness_and_warn(filename, line, key, value);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
|
@ -429,15 +483,17 @@ static int load_env_file_push_pairs(
|
|||
return strv_extend(m, "");
|
||||
}
|
||||
|
||||
int load_env_file_pairs(FILE *f, const char *fname, char ***rl) {
|
||||
int load_env_file_pairs(FILE *f, const char *fname, char ***ret) {
|
||||
_cleanup_strv_free_ char **m = NULL;
|
||||
int r;
|
||||
|
||||
assert(f || fname);
|
||||
|
||||
r = parse_env_file_internal(f, fname, load_env_file_push_pairs, &m);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
*rl = TAKE_PTR(m);
|
||||
*ret = TAKE_PTR(m);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -449,6 +505,8 @@ static int merge_env_file_push(
|
|||
char ***env = ASSERT_PTR(userdata);
|
||||
char *expanded_value;
|
||||
|
||||
assert(key);
|
||||
|
||||
if (!value) {
|
||||
log_error("%s:%u: invalid syntax (around \"%s\"), ignoring.", strna(filename), line, key);
|
||||
return 0;
|
||||
|
|
@ -479,6 +537,9 @@ int merge_env_file(
|
|||
FILE *f,
|
||||
const char *fname) {
|
||||
|
||||
assert(env);
|
||||
assert(f || fname);
|
||||
|
||||
/* NOTE: this function supports braceful and braceless variable expansions,
|
||||
* plus "extended" substitutions, unlike other exported parsing functions.
|
||||
*/
|
||||
|
|
@ -489,6 +550,9 @@ int merge_env_file(
|
|||
static void write_env_var(FILE *f, const char *v) {
|
||||
const char *p;
|
||||
|
||||
assert(f);
|
||||
assert(v);
|
||||
|
||||
p = strchr(v, '=');
|
||||
if (!p) {
|
||||
/* Fallback */
|
||||
|
|
|
|||
|
|
@ -9,8 +9,10 @@
|
|||
int parse_env_filev(FILE *f, const char *fname, va_list ap);
|
||||
int parse_env_file_sentinel(FILE *f, const char *fname, ...) _sentinel_;
|
||||
#define parse_env_file(f, fname, ...) parse_env_file_sentinel(f, fname, __VA_ARGS__, NULL)
|
||||
int load_env_file(FILE *f, const char *fname, char ***l);
|
||||
int load_env_file_pairs(FILE *f, const char *fname, char ***l);
|
||||
int parse_env_file_fd_sentinel(int fd, const char *fname, ...) _sentinel_;
|
||||
#define parse_env_file_fd(fd, fname, ...) parse_env_file_fd_sentinel(fd, fname, __VA_ARGS__, NULL)
|
||||
int load_env_file(FILE *f, const char *fname, char ***ret);
|
||||
int load_env_file_pairs(FILE *f, const char *fname, char ***ret);
|
||||
|
||||
int merge_env_file(char ***env, FILE *f, const char *fname);
|
||||
|
||||
|
|
|
|||
|
|
@ -448,31 +448,30 @@ char* escape_non_printable_full(const char *str, size_t console_width, XEscapeFl
|
|||
}
|
||||
|
||||
char* octescape(const char *s, size_t len) {
|
||||
char *r, *t;
|
||||
const char *f;
|
||||
char *buf, *t;
|
||||
|
||||
/* Escapes all chars in bad, in addition to \ and " chars,
|
||||
* in \nnn style escaping. */
|
||||
/* Escapes all chars in bad, in addition to \ and " chars, in \nnn style escaping. */
|
||||
|
||||
r = new(char, len * 4 + 1);
|
||||
if (!r)
|
||||
assert(s || len == 0);
|
||||
|
||||
t = buf = new(char, len * 4 + 1);
|
||||
if (!buf)
|
||||
return NULL;
|
||||
|
||||
for (f = s, t = r; f < s + len; f++) {
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
uint8_t u = (uint8_t) s[i];
|
||||
|
||||
if (*f < ' ' || *f >= 127 || IN_SET(*f, '\\', '"')) {
|
||||
if (u < ' ' || u >= 127 || IN_SET(u, '\\', '"')) {
|
||||
*(t++) = '\\';
|
||||
*(t++) = '0' + (*f >> 6);
|
||||
*(t++) = '0' + ((*f >> 3) & 8);
|
||||
*(t++) = '0' + (*f & 8);
|
||||
*(t++) = '0' + (u >> 6);
|
||||
*(t++) = '0' + ((u >> 3) & 7);
|
||||
*(t++) = '0' + (u & 7);
|
||||
} else
|
||||
*(t++) = *f;
|
||||
*(t++) = u;
|
||||
}
|
||||
|
||||
*t = 0;
|
||||
|
||||
return r;
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
static char* strcpy_backslash_escaped(char *t, const char *s, const char *bad) {
|
||||
|
|
|
|||
|
|
@ -31,7 +31,6 @@
|
|||
#include "stat-util.h"
|
||||
#include "stdio-util.h"
|
||||
#include "tmpfile-util.h"
|
||||
#include "util.h"
|
||||
|
||||
/* The maximum number of iterations in the loop to close descriptors in the fallback case
|
||||
* when /proc/self/fd/ is inaccessible. */
|
||||
|
|
@ -59,11 +58,9 @@ int close_nointr(int fd) {
|
|||
}
|
||||
|
||||
int safe_close(int fd) {
|
||||
|
||||
/*
|
||||
* Like close_nointr() but cannot fail. Guarantees errno is
|
||||
* unchanged. Is a NOP with negative fds passed, and returns
|
||||
* -1, so that it can be used in this syntax:
|
||||
* Like close_nointr() but cannot fail. Guarantees errno is unchanged. Is a noop for negative fds,
|
||||
* and returns -EBADF, so that it can be used in this syntax:
|
||||
*
|
||||
* fd = safe_close(fd);
|
||||
*/
|
||||
|
|
@ -79,7 +76,7 @@ int safe_close(int fd) {
|
|||
assert_se(close_nointr(fd) != -EBADF);
|
||||
}
|
||||
|
||||
return -1;
|
||||
return -EBADF;
|
||||
}
|
||||
|
||||
void safe_close_pair(int p[static 2]) {
|
||||
|
|
@ -177,12 +174,35 @@ int fd_cloexec(int fd, bool cloexec) {
|
|||
}
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
int fd_cloexec_many(const int fds[], size_t n_fds, bool cloexec) {
|
||||
int ret = 0, r;
|
||||
|
||||
assert(n_fds == 0 || fds);
|
||||
|
||||
for (size_t i = 0; i < n_fds; i++) {
|
||||
if (fds[i] < 0) /* Skip gracefully over already invalidated fds */
|
||||
continue;
|
||||
|
||||
r = fd_cloexec(fds[i], cloexec);
|
||||
if (r < 0 && ret >= 0) /* Continue going, but return first error */
|
||||
ret = r;
|
||||
else
|
||||
ret = 1; /* report if we did anything */
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
_pure_ static bool fd_in_set(int fd, const int fdset[], size_t n_fdset) {
|
||||
assert(n_fdset == 0 || fdset);
|
||||
|
||||
for (size_t i = 0; i < n_fdset; i++)
|
||||
for (size_t i = 0; i < n_fdset; i++) {
|
||||
if (fdset[i] < 0)
|
||||
continue;
|
||||
|
||||
if (fdset[i] == fd)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
@ -229,7 +249,7 @@ static int close_all_fds_frugal(const int except[], size_t n_except) {
|
|||
"Refusing to loop over %d potential fds.",
|
||||
max_fd);
|
||||
|
||||
for (int fd = 3; fd >= 0; fd = fd < max_fd ? fd + 1 : -1) {
|
||||
for (int fd = 3; fd >= 0; fd = fd < max_fd ? fd + 1 : -EBADF) {
|
||||
int q;
|
||||
|
||||
if (fd_in_set(fd, except, n_except))
|
||||
|
|
@ -255,6 +275,10 @@ static int close_all_fds_special_case(const int except[], size_t n_except) {
|
|||
if (!have_close_range)
|
||||
return 0;
|
||||
|
||||
if (n_except == 1 && except[0] < 0) /* Minor optimization: if we only got one fd, and it's invalid,
|
||||
* we got none */
|
||||
n_except = 0;
|
||||
|
||||
switch (n_except) {
|
||||
|
||||
case 0:
|
||||
|
|
@ -389,7 +413,7 @@ int close_all_fds(const int except[], size_t n_except) {
|
|||
return close_all_fds_frugal(except, n_except); /* ultimate fallback if /proc/ is not available */
|
||||
|
||||
FOREACH_DIRENT(de, d, return -errno) {
|
||||
int fd = -1, q;
|
||||
int fd = -EBADF, q;
|
||||
|
||||
if (!IN_SET(de->d_type, DT_LNK, DT_UNKNOWN))
|
||||
continue;
|
||||
|
|
@ -479,7 +503,8 @@ void cmsg_close_all(struct msghdr *mh) {
|
|||
|
||||
CMSG_FOREACH(cmsg, mh)
|
||||
if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS)
|
||||
close_many((int*) ((void*) CMSG_DATA(cmsg)), (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int));
|
||||
close_many(CMSG_TYPED_DATA(cmsg, int),
|
||||
(cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int));
|
||||
}
|
||||
|
||||
bool fdname_is_valid(const char *s) {
|
||||
|
|
@ -611,25 +636,23 @@ int fd_move_above_stdio(int fd) {
|
|||
|
||||
#if 0 /* NM_IGNORED */
|
||||
int rearrange_stdio(int original_input_fd, int original_output_fd, int original_error_fd) {
|
||||
|
||||
int fd[3] = { /* Put together an array of fds we work on */
|
||||
original_input_fd,
|
||||
original_output_fd,
|
||||
original_error_fd
|
||||
};
|
||||
|
||||
int r, i,
|
||||
null_fd = -1, /* if we open /dev/null, we store the fd to it here */
|
||||
copy_fd[3] = { -1, -1, -1 }; /* This contains all fds we duplicate here temporarily, and hence need to close at the end */
|
||||
int fd[3] = { original_input_fd, /* Put together an array of fds we work on */
|
||||
original_output_fd,
|
||||
original_error_fd },
|
||||
null_fd = -EBADF, /* If we open /dev/null, we store the fd to it here */
|
||||
copy_fd[3] = { -EBADF, -EBADF, -EBADF }, /* This contains all fds we duplicate here
|
||||
* temporarily, and hence need to close at the end. */
|
||||
r;
|
||||
bool null_readable, null_writable;
|
||||
|
||||
/* Sets up stdin, stdout, stderr with the three file descriptors passed in. If any of the descriptors is
|
||||
* specified as -1 it will be connected with /dev/null instead. If any of the file descriptors is passed as
|
||||
* itself (e.g. stdin as STDIN_FILENO) it is left unmodified, but the O_CLOEXEC bit is turned off should it be
|
||||
* on.
|
||||
/* Sets up stdin, stdout, stderr with the three file descriptors passed in. If any of the descriptors
|
||||
* is specified as -EBADF it will be connected with /dev/null instead. If any of the file descriptors
|
||||
* is passed as itself (e.g. stdin as STDIN_FILENO) it is left unmodified, but the O_CLOEXEC bit is
|
||||
* turned off should it be on.
|
||||
*
|
||||
* Note that if any of the passed file descriptors are > 2 they will be closed — both on success and on
|
||||
* failure! Thus, callers should assume that when this function returns the input fds are invalidated.
|
||||
* Note that if any of the passed file descriptors are > 2 they will be closed — both on success and
|
||||
* on failure! Thus, callers should assume that when this function returns the input fds are
|
||||
* invalidated.
|
||||
*
|
||||
* Note that when this function fails stdin/stdout/stderr might remain half set up!
|
||||
*
|
||||
|
|
@ -665,7 +688,7 @@ int rearrange_stdio(int original_input_fd, int original_output_fd, int original_
|
|||
}
|
||||
|
||||
/* Let's assemble fd[] with the fds to install in place of stdin/stdout/stderr */
|
||||
for (i = 0; i < 3; i++) {
|
||||
for (int i = 0; i < 3; i++) {
|
||||
|
||||
if (fd[i] < 0)
|
||||
fd[i] = null_fd; /* A negative parameter means: connect this one to /dev/null */
|
||||
|
|
@ -681,10 +704,10 @@ int rearrange_stdio(int original_input_fd, int original_output_fd, int original_
|
|||
}
|
||||
}
|
||||
|
||||
/* At this point we now have the fds to use in fd[], and they are all above the stdio range, so that we
|
||||
* have freedom to move them around. If the fds already were at the right places then the specific fds are
|
||||
* -1. Let's now move them to the right places. This is the point of no return. */
|
||||
for (i = 0; i < 3; i++) {
|
||||
/* At this point we now have the fds to use in fd[], and they are all above the stdio range, so that
|
||||
* we have freedom to move them around. If the fds already were at the right places then the specific
|
||||
* fds are -EBADF. Let's now move them to the right places. This is the point of no return. */
|
||||
for (int i = 0; i < 3; i++) {
|
||||
|
||||
if (fd[i] == i) {
|
||||
|
||||
|
|
@ -715,7 +738,7 @@ finish:
|
|||
safe_close_above_stdio(original_error_fd);
|
||||
|
||||
/* Close the copies we moved > 2 */
|
||||
for (i = 0; i < 3; i++)
|
||||
for (int i = 0; i < 3; i++)
|
||||
safe_close(copy_fd[i]);
|
||||
|
||||
/* Close our null fd, if it's > 2 */
|
||||
|
|
@ -761,6 +784,37 @@ int fd_reopen(int fd, int flags) {
|
|||
return new_fd;
|
||||
}
|
||||
|
||||
int fd_reopen_condition(
|
||||
int fd,
|
||||
int flags,
|
||||
int mask,
|
||||
int *ret_new_fd) {
|
||||
|
||||
int r, new_fd;
|
||||
|
||||
assert(fd >= 0);
|
||||
|
||||
/* Invokes fd_reopen(fd, flags), but only if the existing F_GETFL flags don't match the specified
|
||||
* flags (masked by the specified mask). This is useful for converting O_PATH fds into real fds if
|
||||
* needed, but only then. */
|
||||
|
||||
r = fcntl(fd, F_GETFL);
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
|
||||
if ((r & mask) == (flags & mask)) {
|
||||
*ret_new_fd = -EBADF;
|
||||
return fd;
|
||||
}
|
||||
|
||||
new_fd = fd_reopen(fd, flags);
|
||||
if (new_fd < 0)
|
||||
return new_fd;
|
||||
|
||||
*ret_new_fd = new_fd;
|
||||
return new_fd;
|
||||
}
|
||||
|
||||
int read_nr_open(void) {
|
||||
_cleanup_free_ char *nr_open = NULL;
|
||||
int r;
|
||||
|
|
|
|||
|
|
@ -15,14 +15,15 @@
|
|||
/* Make sure we can distinguish fd 0 and NULL */
|
||||
#define FD_TO_PTR(fd) INT_TO_PTR((fd)+1)
|
||||
#define PTR_TO_FD(p) (PTR_TO_INT(p)-1)
|
||||
#define PIPE_EBADF { -EBADF, -EBADF }
|
||||
|
||||
int close_nointr(int fd);
|
||||
int safe_close(int fd);
|
||||
void safe_close_pair(int p[static 2]);
|
||||
|
||||
static inline int safe_close_above_stdio(int fd) {
|
||||
if (fd < 3) /* Don't close stdin/stdout/stderr, but still invalidate the fd by returning -1 */
|
||||
return -1;
|
||||
if (fd < 3) /* Don't close stdin/stdout/stderr, but still invalidate the fd by returning -EBADF. */
|
||||
return -EBADF;
|
||||
|
||||
return safe_close(fd);
|
||||
}
|
||||
|
|
@ -56,6 +57,7 @@ DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(DIR*, closedir, NULL);
|
|||
|
||||
int fd_nonblock(int fd, bool nonblock);
|
||||
int fd_cloexec(int fd, bool cloexec);
|
||||
int fd_cloexec_many(const int fds[], size_t n_fds, bool cloexec);
|
||||
|
||||
int get_max_fd(void);
|
||||
|
||||
|
|
@ -85,17 +87,11 @@ int fd_move_above_stdio(int fd);
|
|||
int rearrange_stdio(int original_input_fd, int original_output_fd, int original_error_fd);
|
||||
|
||||
static inline int make_null_stdio(void) {
|
||||
return rearrange_stdio(-1, -1, -1);
|
||||
return rearrange_stdio(-EBADF, -EBADF, -EBADF);
|
||||
}
|
||||
|
||||
/* Like TAKE_PTR() but for file descriptors, resetting them to -1 */
|
||||
#define TAKE_FD(fd) \
|
||||
({ \
|
||||
int *_fd_ = &(fd); \
|
||||
int _ret_ = *_fd_; \
|
||||
*_fd_ = -1; \
|
||||
_ret_; \
|
||||
})
|
||||
/* Like TAKE_PTR() but for file descriptors, resetting them to -EBADF */
|
||||
#define TAKE_FD(fd) TAKE_GENERIC(fd, int, -EBADF)
|
||||
|
||||
/* Like free_and_replace(), but for file descriptors */
|
||||
#define close_and_replace(a, b) \
|
||||
|
|
@ -107,6 +103,7 @@ static inline int make_null_stdio(void) {
|
|||
})
|
||||
|
||||
int fd_reopen(int fd, int flags);
|
||||
int fd_reopen_condition(int fd, int flags, int mask, int *ret_new_fd);
|
||||
int read_nr_open(void);
|
||||
int fd_get_diskseq(int fd, uint64_t *ret);
|
||||
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@
|
|||
#include "log.h"
|
||||
#include "macro.h"
|
||||
#include "mkdir.h"
|
||||
#include "nulstr-util.h"
|
||||
#include "parse-util.h"
|
||||
#include "path-util.h"
|
||||
#include "socket-util.h"
|
||||
|
|
@ -45,18 +46,21 @@
|
|||
* can detect EOFs. */
|
||||
#define READ_VIRTUAL_BYTES_MAX (4U*1024U*1024U - 2U)
|
||||
|
||||
int fopen_unlocked(const char *path, const char *options, FILE **ret) {
|
||||
#if 0 /* NM_IGNORED */
|
||||
int fopen_unlocked_at(int dir_fd, const char *path, const char *options, int flags, FILE **ret) {
|
||||
int r;
|
||||
|
||||
assert(ret);
|
||||
|
||||
FILE *f = fopen(path, options);
|
||||
if (!f)
|
||||
return -errno;
|
||||
r = xfopenat(dir_fd, path, options, flags, ret);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
(void) __fsetlocking(f, FSETLOCKING_BYCALLER);
|
||||
(void) __fsetlocking(*ret, FSETLOCKING_BYCALLER);
|
||||
|
||||
*ret = f;
|
||||
return 0;
|
||||
}
|
||||
#endif /* NM_IGNORED */
|
||||
|
||||
int fdopen_unlocked(int fd, const char *options, FILE **ret) {
|
||||
assert(ret);
|
||||
|
|
@ -80,7 +84,7 @@ int take_fdopen_unlocked(int *fd, const char *options, FILE **ret) {
|
|||
if (r < 0)
|
||||
return r;
|
||||
|
||||
*fd = -1;
|
||||
*fd = -EBADF;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -92,7 +96,7 @@ FILE* take_fdopen(int *fd, const char *options) {
|
|||
if (!f)
|
||||
return NULL;
|
||||
|
||||
*fd = -1;
|
||||
*fd = -EBADF;
|
||||
|
||||
return f;
|
||||
}
|
||||
|
|
@ -104,7 +108,7 @@ DIR* take_fdopendir(int *dfd) {
|
|||
if (!d)
|
||||
return NULL;
|
||||
|
||||
*dfd = -1;
|
||||
*dfd = -EBADF;
|
||||
|
||||
return d;
|
||||
}
|
||||
|
|
@ -137,7 +141,7 @@ int write_string_stream_ts(
|
|||
const struct timespec *ts) {
|
||||
|
||||
bool needs_nl;
|
||||
int r, fd = -1;
|
||||
int r, fd = -EBADF;
|
||||
|
||||
assert(f);
|
||||
assert(line);
|
||||
|
|
@ -212,7 +216,8 @@ int write_string_stream_ts(
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int write_string_file_atomic(
|
||||
static int write_string_file_atomic_at(
|
||||
int dir_fd,
|
||||
const char *fn,
|
||||
const char *line,
|
||||
WriteStringFileFlags flags,
|
||||
|
|
@ -228,7 +233,7 @@ static int write_string_file_atomic(
|
|||
/* Note that we'd really like to use O_TMPFILE here, but can't really, since we want replacement
|
||||
* semantics here, and O_TMPFILE can't offer that. i.e. rename() replaces but linkat() doesn't. */
|
||||
|
||||
r = fopen_temporary(fn, &f, &p);
|
||||
r = fopen_temporary_at(dir_fd, fn, &f, &p);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
|
@ -240,7 +245,7 @@ static int write_string_file_atomic(
|
|||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
if (rename(p, fn) < 0) {
|
||||
if (renameat(dir_fd, p, dir_fd, fn) < 0) {
|
||||
r = -errno;
|
||||
goto fail;
|
||||
}
|
||||
|
|
@ -255,11 +260,12 @@ static int write_string_file_atomic(
|
|||
return 0;
|
||||
|
||||
fail:
|
||||
(void) unlink(p);
|
||||
(void) unlinkat(dir_fd, p, 0);
|
||||
return r;
|
||||
}
|
||||
|
||||
int write_string_file_ts(
|
||||
int write_string_file_ts_at(
|
||||
int dir_fd,
|
||||
const char *fn,
|
||||
const char *line,
|
||||
WriteStringFileFlags flags,
|
||||
|
|
@ -275,7 +281,7 @@ int write_string_file_ts(
|
|||
assert(!((flags & WRITE_STRING_FILE_VERIFY_ON_FAILURE) && (flags & WRITE_STRING_FILE_SYNC)));
|
||||
|
||||
if (flags & WRITE_STRING_FILE_MKDIR_0755) {
|
||||
r = mkdir_parents(fn, 0755);
|
||||
r = mkdirat_parents(dir_fd, fn, 0755);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
|
@ -283,7 +289,7 @@ int write_string_file_ts(
|
|||
if (flags & WRITE_STRING_FILE_ATOMIC) {
|
||||
assert(flags & WRITE_STRING_FILE_CREATE);
|
||||
|
||||
r = write_string_file_atomic(fn, line, flags, ts);
|
||||
r = write_string_file_atomic_at(dir_fd, fn, line, flags, ts);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
|
|
@ -292,12 +298,12 @@ int write_string_file_ts(
|
|||
assert(!ts);
|
||||
|
||||
/* We manually build our own version of fopen(..., "we") that works without O_CREAT and with O_NOFOLLOW if needed. */
|
||||
fd = open(fn, O_CLOEXEC|O_NOCTTY |
|
||||
(FLAGS_SET(flags, WRITE_STRING_FILE_NOFOLLOW) ? O_NOFOLLOW : 0) |
|
||||
(FLAGS_SET(flags, WRITE_STRING_FILE_CREATE) ? O_CREAT : 0) |
|
||||
(FLAGS_SET(flags, WRITE_STRING_FILE_TRUNCATE) ? O_TRUNC : 0) |
|
||||
(FLAGS_SET(flags, WRITE_STRING_FILE_SUPPRESS_REDUNDANT_VIRTUAL) ? O_RDWR : O_WRONLY),
|
||||
(FLAGS_SET(flags, WRITE_STRING_FILE_MODE_0600) ? 0600 : 0666));
|
||||
fd = openat(dir_fd, fn, O_CLOEXEC|O_NOCTTY |
|
||||
(FLAGS_SET(flags, WRITE_STRING_FILE_NOFOLLOW) ? O_NOFOLLOW : 0) |
|
||||
(FLAGS_SET(flags, WRITE_STRING_FILE_CREATE) ? O_CREAT : 0) |
|
||||
(FLAGS_SET(flags, WRITE_STRING_FILE_TRUNCATE) ? O_TRUNC : 0) |
|
||||
(FLAGS_SET(flags, WRITE_STRING_FILE_SUPPRESS_REDUNDANT_VIRTUAL) ? O_RDWR : O_WRONLY),
|
||||
(FLAGS_SET(flags, WRITE_STRING_FILE_MODE_0600) ? 0600 : 0666));
|
||||
if (fd < 0) {
|
||||
r = -errno;
|
||||
goto fail;
|
||||
|
|
@ -367,7 +373,7 @@ int read_one_line_file(const char *fn, char **line) {
|
|||
return read_line(f, LONG_LINE_MAX, line);
|
||||
}
|
||||
|
||||
int verify_file(const char *fn, const char *blob, bool accept_extra_nl) {
|
||||
int verify_file_at(int dir_fd, const char *fn, const char *blob, bool accept_extra_nl) {
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
_cleanup_free_ char *buf = NULL;
|
||||
size_t l, k;
|
||||
|
|
@ -385,7 +391,7 @@ int verify_file(const char *fn, const char *blob, bool accept_extra_nl) {
|
|||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
r = fopen_unlocked(fn, "re", &f);
|
||||
r = fopen_unlocked_at(dir_fd, fn, "re", 0, &f);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
|
@ -558,7 +564,7 @@ int read_virtual_file_at(
|
|||
char **ret_contents,
|
||||
size_t *ret_size) {
|
||||
|
||||
_cleanup_close_ int fd = -1;
|
||||
_cleanup_close_ int fd = -EBADF;
|
||||
|
||||
assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
|
||||
|
||||
|
|
@ -767,7 +773,7 @@ int read_full_file_full(
|
|||
|
||||
r = xfopenat(dir_fd, filename, "re", 0, &f);
|
||||
if (r < 0) {
|
||||
_cleanup_close_ int sk = -1;
|
||||
_cleanup_close_ int sk = -EBADF;
|
||||
|
||||
/* ENXIO is what Linux returns if we open a node that is an AF_UNIX socket */
|
||||
if (r != -ENXIO)
|
||||
|
|
@ -851,7 +857,6 @@ int executable_is_script(const char *path, char **interpreter) {
|
|||
*interpreter = ans;
|
||||
return 1;
|
||||
}
|
||||
#endif /* NM_IGNORED */
|
||||
|
||||
/**
|
||||
* Retrieve one field from a file like /proc/self/status. pattern
|
||||
|
|
@ -864,7 +869,6 @@ int executable_is_script(const char *path, char **interpreter) {
|
|||
int get_proc_field(const char *filename, const char *pattern, const char *terminator, char **field) {
|
||||
_cleanup_free_ char *status = NULL;
|
||||
char *t, *f;
|
||||
size_t len;
|
||||
int r;
|
||||
|
||||
assert(terminator);
|
||||
|
|
@ -916,9 +920,7 @@ int get_proc_field(const char *filename, const char *pattern, const char *termin
|
|||
t--;
|
||||
}
|
||||
|
||||
len = strcspn(t, terminator);
|
||||
|
||||
f = strndup(t, len);
|
||||
f = strdupcspn(t, terminator);
|
||||
if (!f)
|
||||
return -ENOMEM;
|
||||
|
||||
|
|
@ -947,6 +949,7 @@ DIR *xopendirat(int fd, const char *name, int flags) {
|
|||
|
||||
return d;
|
||||
}
|
||||
#endif /* NM_IGNORED */
|
||||
|
||||
int fopen_mode_to_flags(const char *mode) {
|
||||
const char *p;
|
||||
|
|
@ -1256,7 +1259,7 @@ typedef enum EndOfLineMarker {
|
|||
|
||||
static EndOfLineMarker categorize_eol(char c, ReadLineFlags flags) {
|
||||
|
||||
if (!IN_SET(flags, READ_LINE_ONLY_NUL)) {
|
||||
if (!FLAGS_SET(flags, READ_LINE_ONLY_NUL)) {
|
||||
if (c == '\n')
|
||||
return EOL_TEN;
|
||||
if (c == '\r')
|
||||
|
|
|
|||
|
|
@ -43,7 +43,10 @@ typedef enum {
|
|||
READ_FULL_FILE_FAIL_WHEN_LARGER = 1 << 5, /* fail loading if file is larger than specified size */
|
||||
} ReadFullFileFlags;
|
||||
|
||||
int fopen_unlocked(const char *path, const char *options, FILE **ret);
|
||||
int fopen_unlocked_at(int dir_fd, const char *path, const char *options, int flags, FILE **ret);
|
||||
static inline int fopen_unlocked(const char *path, const char *options, FILE **ret) {
|
||||
return fopen_unlocked_at(AT_FDCWD, path, options, 0, ret);
|
||||
}
|
||||
int fdopen_unlocked(int fd, const char *options, FILE **ret);
|
||||
int take_fdopen_unlocked(int *fd, const char *options, FILE **ret);
|
||||
FILE* take_fdopen(int *fd, const char *options);
|
||||
|
|
@ -55,7 +58,13 @@ int write_string_stream_ts(FILE *f, const char *line, WriteStringFileFlags flags
|
|||
static inline int write_string_stream(FILE *f, const char *line, WriteStringFileFlags flags) {
|
||||
return write_string_stream_ts(f, line, flags, NULL);
|
||||
}
|
||||
int write_string_file_ts(const char *fn, const char *line, WriteStringFileFlags flags, const struct timespec *ts);
|
||||
int write_string_file_ts_at(int dir_fd, const char *fn, const char *line, WriteStringFileFlags flags, const struct timespec *ts);
|
||||
static inline int write_string_file_ts(const char *fn, const char *line, WriteStringFileFlags flags, const struct timespec *ts) {
|
||||
return write_string_file_ts_at(AT_FDCWD, fn, line, flags, ts);
|
||||
}
|
||||
static inline int write_string_file_at(int dir_fd, const char *fn, const char *line, WriteStringFileFlags flags) {
|
||||
return write_string_file_ts_at(dir_fd, fn, line, flags, NULL);
|
||||
}
|
||||
static inline int write_string_file(const char *fn, const char *line, WriteStringFileFlags flags) {
|
||||
return write_string_file_ts(fn, line, flags, NULL);
|
||||
}
|
||||
|
|
@ -64,6 +73,9 @@ int write_string_filef(const char *fn, WriteStringFileFlags flags, const char *f
|
|||
|
||||
int read_one_line_file(const char *filename, char **line);
|
||||
int read_full_file_full(int dir_fd, const char *filename, uint64_t offset, size_t size, ReadFullFileFlags flags, const char *bind_name, char **ret_contents, size_t *ret_size);
|
||||
static inline int read_full_file_at(int dir_fd, const char *filename, char **ret_contents, size_t *ret_size) {
|
||||
return read_full_file_full(dir_fd, filename, UINT64_MAX, SIZE_MAX, 0, NULL, ret_contents, ret_size);
|
||||
}
|
||||
static inline int read_full_file(const char *filename, char **ret_contents, size_t *ret_size) {
|
||||
return read_full_file_full(AT_FDCWD, filename, UINT64_MAX, SIZE_MAX, 0, NULL, ret_contents, ret_size);
|
||||
}
|
||||
|
|
@ -82,7 +94,10 @@ static inline int read_full_stream(FILE *f, char **ret_contents, size_t *ret_siz
|
|||
return read_full_stream_full(f, NULL, UINT64_MAX, SIZE_MAX, 0, ret_contents, ret_size);
|
||||
}
|
||||
|
||||
int verify_file(const char *fn, const char *blob, bool accept_extra_nl);
|
||||
int verify_file_at(int dir_fd, const char *fn, const char *blob, bool accept_extra_nl);
|
||||
static inline int verify_file(const char *fn, const char *blob, bool accept_extra_nl) {
|
||||
return verify_file_at(AT_FDCWD, fn, blob, accept_extra_nl);
|
||||
}
|
||||
|
||||
int executable_is_script(const char *path, char **interpreter);
|
||||
|
||||
|
|
|
|||
|
|
@ -34,7 +34,6 @@
|
|||
#include "tmpfile-util.h"
|
||||
#include "umask-util.h"
|
||||
#include "user-util.h"
|
||||
#include "util.h"
|
||||
|
||||
int unlink_noerrno(const char *path) {
|
||||
PROTECT_ERRNO;
|
||||
|
|
@ -180,37 +179,41 @@ int readlink_value(const char *p, char **ret) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int readlink_and_make_absolute(const char *p, char **r) {
|
||||
int readlink_and_make_absolute(const char *p, char **ret) {
|
||||
_cleanup_free_ char *target = NULL;
|
||||
char *k;
|
||||
int j;
|
||||
int r;
|
||||
|
||||
assert(p);
|
||||
assert(r);
|
||||
assert(ret);
|
||||
|
||||
j = readlink_malloc(p, &target);
|
||||
if (j < 0)
|
||||
return j;
|
||||
r = readlink_malloc(p, &target);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
k = file_in_same_dir(p, target);
|
||||
if (!k)
|
||||
return -ENOMEM;
|
||||
|
||||
*r = k;
|
||||
return 0;
|
||||
return file_in_same_dir(p, target, ret);
|
||||
}
|
||||
|
||||
int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid) {
|
||||
_cleanup_close_ int fd = -1;
|
||||
int chmod_and_chown_at(int dir_fd, const char *path, mode_t mode, uid_t uid, gid_t gid) {
|
||||
_cleanup_close_ int fd = -EBADF;
|
||||
|
||||
assert(path);
|
||||
assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
|
||||
|
||||
fd = open(path, O_PATH|O_CLOEXEC|O_NOFOLLOW); /* Let's acquire an O_PATH fd, as precaution to change
|
||||
* mode/owner on the same file */
|
||||
if (fd < 0)
|
||||
return -errno;
|
||||
if (path) {
|
||||
/* Let's acquire an O_PATH fd, as precaution to change mode/owner on the same file */
|
||||
fd = openat(dir_fd, path, O_PATH|O_CLOEXEC|O_NOFOLLOW);
|
||||
if (fd < 0)
|
||||
return -errno;
|
||||
dir_fd = fd;
|
||||
|
||||
return fchmod_and_chown(fd, mode, uid, gid);
|
||||
} else if (dir_fd == AT_FDCWD) {
|
||||
/* Let's acquire an O_PATH fd of the current directory */
|
||||
fd = openat(dir_fd, ".", O_PATH|O_CLOEXEC|O_NOFOLLOW|O_DIRECTORY);
|
||||
if (fd < 0)
|
||||
return -errno;
|
||||
dir_fd = fd;
|
||||
}
|
||||
|
||||
return fchmod_and_chown(dir_fd, mode, uid, gid);
|
||||
}
|
||||
|
||||
int fchmod_and_chown_with_fallback(int fd, const char *path, mode_t mode, uid_t uid, gid_t gid) {
|
||||
|
|
@ -356,7 +359,7 @@ int fd_warn_permissions(const char *path, int fd) {
|
|||
}
|
||||
|
||||
int touch_file(const char *path, bool parents, usec_t stamp, uid_t uid, gid_t gid, mode_t mode) {
|
||||
_cleanup_close_ int fd = -1;
|
||||
_cleanup_close_ int fd = -EBADF;
|
||||
int r, ret;
|
||||
|
||||
assert(path);
|
||||
|
|
@ -684,7 +687,7 @@ void unlink_tempfilep(char (*p)[]) {
|
|||
}
|
||||
|
||||
int unlinkat_deallocate(int fd, const char *name, UnlinkDeallocateFlags flags) {
|
||||
_cleanup_close_ int truncate_fd = -1;
|
||||
_cleanup_close_ int truncate_fd = -EBADF;
|
||||
struct stat st;
|
||||
off_t l, bs;
|
||||
|
||||
|
|
@ -816,7 +819,7 @@ int conservative_renameat(
|
|||
int olddirfd, const char *oldpath,
|
||||
int newdirfd, const char *newpath) {
|
||||
|
||||
_cleanup_close_ int old_fd = -1, new_fd = -1;
|
||||
_cleanup_close_ int old_fd = -EBADF, new_fd = -EBADF;
|
||||
struct stat old_stat, new_stat;
|
||||
|
||||
/* Renames the old path to thew new path, much like renameat() — except if both are regular files and
|
||||
|
|
@ -912,7 +915,7 @@ int posix_fallocate_loop(int fd, uint64_t offset, uint64_t size) {
|
|||
|
||||
/* On EINTR try a couple of times more, but protect against busy looping
|
||||
* (not more than 16 times per 10s) */
|
||||
rl = (RateLimit) { 10 * USEC_PER_SEC, 16 };
|
||||
rl = (const RateLimit) { 10 * USEC_PER_SEC, 16 };
|
||||
while (ratelimit_below(&rl)) {
|
||||
r = posix_fallocate(fd, offset, size);
|
||||
if (r != EINTR)
|
||||
|
|
@ -998,7 +1001,7 @@ int parse_cifs_service(
|
|||
}
|
||||
|
||||
int open_mkdir_at(int dirfd, const char *path, int flags, mode_t mode) {
|
||||
_cleanup_close_ int fd = -1, parent_fd = -1;
|
||||
_cleanup_close_ int fd = -EBADF, parent_fd = -EBADF;
|
||||
_cleanup_free_ char *fname = NULL;
|
||||
bool made;
|
||||
int r;
|
||||
|
|
|
|||
|
|
@ -33,7 +33,10 @@ int readlink_malloc(const char *p, char **r);
|
|||
int readlink_value(const char *p, char **ret);
|
||||
int readlink_and_make_absolute(const char *p, char **r);
|
||||
|
||||
int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid);
|
||||
int chmod_and_chown_at(int dir_fd, const char *path, mode_t mode, uid_t uid, gid_t gid);
|
||||
static inline int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid) {
|
||||
return chmod_and_chown_at(AT_FDCWD, path, mode, uid, gid);
|
||||
}
|
||||
int fchmod_and_chown_with_fallback(int fd, const char *path, mode_t mode, uid_t uid, gid_t gid);
|
||||
static inline int fchmod_and_chown(int fd, mode_t mode, uid_t uid, gid_t gid) {
|
||||
return fchmod_and_chown_with_fallback(fd, NULL, mode, uid, gid); /* no fallback */
|
||||
|
|
|
|||
|
|
@ -11,15 +11,15 @@ bool emoji_enabled(void) {
|
|||
static int cached_emoji_enabled = -1;
|
||||
|
||||
if (cached_emoji_enabled < 0) {
|
||||
int val;
|
||||
int val = getenv_bool("SYSTEMD_EMOJI");
|
||||
if (val >= 0)
|
||||
return (cached_emoji_enabled = val);
|
||||
|
||||
val = getenv_bool("SYSTEMD_EMOJI");
|
||||
if (val < 0)
|
||||
cached_emoji_enabled =
|
||||
is_locale_utf8() &&
|
||||
!STRPTR_IN_SET(getenv("TERM"), "dumb", "linux");
|
||||
else
|
||||
cached_emoji_enabled = val;
|
||||
const char *term = getenv("TERM");
|
||||
if (!term || STR_IN_SET(term, "dumb", "linux"))
|
||||
return (cached_emoji_enabled = false);
|
||||
|
||||
cached_emoji_enabled = is_locale_utf8();
|
||||
}
|
||||
|
||||
return cached_emoji_enabled;
|
||||
|
|
@ -73,6 +73,7 @@ const char *special_glyph(SpecialGlyph code) {
|
|||
[SPECIAL_GLYPH_RECYCLING] = "~",
|
||||
[SPECIAL_GLYPH_DOWNLOAD] = "\\",
|
||||
[SPECIAL_GLYPH_SPARKLES] = "*",
|
||||
[SPECIAL_GLYPH_WARNING_SIGN] = "!",
|
||||
},
|
||||
|
||||
/* UTF-8 */
|
||||
|
|
@ -126,10 +127,11 @@ const char *special_glyph(SpecialGlyph code) {
|
|||
/* This emoji is a single character cell glyph in Unicode, and two in ASCII */
|
||||
[SPECIAL_GLYPH_TOUCH] = u8"👆", /* actually called: BACKHAND INDEX POINTING UP */
|
||||
|
||||
/* These three emojis are single character cell glyphs in Unicode and also in ASCII. */
|
||||
/* These four emojis are single character cell glyphs in Unicode and also in ASCII. */
|
||||
[SPECIAL_GLYPH_RECYCLING] = u8"♻️", /* actually called: UNIVERSAL RECYCLNG SYMBOL */
|
||||
[SPECIAL_GLYPH_DOWNLOAD] = u8"⤵️", /* actually called: RIGHT ARROW CURVING DOWN */
|
||||
[SPECIAL_GLYPH_SPARKLES] = u8"✨",
|
||||
[SPECIAL_GLYPH_WARNING_SIGN] = u8"⚠️",
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ typedef enum SpecialGlyph {
|
|||
SPECIAL_GLYPH_RECYCLING,
|
||||
SPECIAL_GLYPH_DOWNLOAD,
|
||||
SPECIAL_GLYPH_SPARKLES,
|
||||
SPECIAL_GLYPH_WARNING_SIGN,
|
||||
_SPECIAL_GLYPH_MAX,
|
||||
_SPECIAL_GLYPH_INVALID = -EINVAL,
|
||||
} SpecialGlyph;
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#include "alloc-util.h"
|
||||
#include "fileio.h"
|
||||
#include "hashmap.h"
|
||||
#include "logarithm.h"
|
||||
#include "macro.h"
|
||||
#include "memory-util.h"
|
||||
#include "mempool.h"
|
||||
|
|
@ -374,8 +375,9 @@ static void get_hash_key(uint8_t hash_key[HASH_KEY_SIZE], bool reuse_is_ok) {
|
|||
}
|
||||
|
||||
static struct hashmap_base_entry* bucket_at(HashmapBase *h, unsigned idx) {
|
||||
return (struct hashmap_base_entry*) (void *)
|
||||
((uint8_t*) storage_ptr(h) + idx * hashmap_type_info[h->type].entry_size);
|
||||
return CAST_ALIGN_PTR(
|
||||
struct hashmap_base_entry,
|
||||
(uint8_t *) storage_ptr(h) + idx * hashmap_type_info[h->type].entry_size);
|
||||
}
|
||||
|
||||
static struct plain_hashmap_entry* plain_bucket_at(Hashmap *h, unsigned idx) {
|
||||
|
|
@ -774,7 +776,7 @@ static struct HashmapBase* hashmap_base_new(const struct hash_ops *hash_ops, enu
|
|||
HashmapBase *h;
|
||||
const struct hashmap_type_info *hi = &hashmap_type_info[type];
|
||||
|
||||
bool use_pool = mempool_enabled && mempool_enabled();
|
||||
bool use_pool = mempool_enabled && mempool_enabled(); /* mempool_enabled is a weak symbol */
|
||||
|
||||
h = use_pool ? mempool_alloc0_tile(hi->mempool) : malloc0(hi->head_size);
|
||||
if (!h)
|
||||
|
|
@ -1753,7 +1755,7 @@ HashmapBase* _hashmap_copy(HashmapBase *h HASHMAP_DEBUG_PARAMS) {
|
|||
}
|
||||
|
||||
if (r < 0)
|
||||
return _hashmap_free(copy, false, false);
|
||||
return _hashmap_free(copy, NULL, NULL);
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@
|
|||
|
||||
#include "hash-funcs.h"
|
||||
#include "macro.h"
|
||||
#include "util.h"
|
||||
|
||||
/*
|
||||
* A hash table implementation. As a minor optimization a NULL hashmap object
|
||||
|
|
|
|||
|
|
@ -61,11 +61,13 @@ char *hexmem(const void *p, size_t l) {
|
|||
const uint8_t *x;
|
||||
char *r, *z;
|
||||
|
||||
assert(p || l == 0);
|
||||
|
||||
z = r = new(char, l * 2 + 1);
|
||||
if (!r)
|
||||
return NULL;
|
||||
|
||||
for (x = p; x < (const uint8_t*) p + l; x++) {
|
||||
for (x = p; x && x < (const uint8_t*) p + l; x++) {
|
||||
*(z++) = hexchar(*x >> 4);
|
||||
*(z++) = hexchar(*x & 15);
|
||||
}
|
||||
|
|
@ -110,12 +112,17 @@ static int unhex_next(const char **p, size_t *l) {
|
|||
return r;
|
||||
}
|
||||
|
||||
int unhexmem_full(const char *p, size_t l, bool secure, void **ret, size_t *ret_len) {
|
||||
int unhexmem_full(
|
||||
const char *p,
|
||||
size_t l,
|
||||
bool secure,
|
||||
void **ret,
|
||||
size_t *ret_len) {
|
||||
|
||||
_cleanup_free_ uint8_t *buf = NULL;
|
||||
size_t buf_size;
|
||||
const char *x;
|
||||
uint8_t *z;
|
||||
int r;
|
||||
|
||||
assert(p || l == 0);
|
||||
|
||||
|
|
@ -128,22 +135,20 @@ int unhexmem_full(const char *p, size_t l, bool secure, void **ret, size_t *ret_
|
|||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
CLEANUP_ERASE_PTR(secure ? &buf : NULL, buf_size);
|
||||
|
||||
for (x = p, z = buf;;) {
|
||||
int a, b;
|
||||
|
||||
a = unhex_next(&x, &l);
|
||||
if (a == -EPIPE) /* End of string */
|
||||
break;
|
||||
if (a < 0) {
|
||||
r = a;
|
||||
goto on_failure;
|
||||
}
|
||||
if (a < 0)
|
||||
return a;
|
||||
|
||||
b = unhex_next(&x, &l);
|
||||
if (b < 0) {
|
||||
r = b;
|
||||
goto on_failure;
|
||||
}
|
||||
if (b < 0)
|
||||
return b;
|
||||
|
||||
*(z++) = (uint8_t) a << 4 | (uint8_t) b;
|
||||
}
|
||||
|
|
@ -156,12 +161,6 @@ int unhexmem_full(const char *p, size_t l, bool secure, void **ret, size_t *ret_
|
|||
*ret = TAKE_PTR(buf);
|
||||
|
||||
return 0;
|
||||
|
||||
on_failure:
|
||||
if (secure)
|
||||
explicit_bzero_safe(buf, buf_size);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
|
|
@ -591,121 +590,136 @@ ssize_t base64mem_full(
|
|||
const void *p,
|
||||
size_t l,
|
||||
size_t line_break,
|
||||
char **out) {
|
||||
char **ret) {
|
||||
|
||||
const uint8_t *x;
|
||||
char *r, *z;
|
||||
char *b, *z;
|
||||
size_t m;
|
||||
|
||||
assert(p || l == 0);
|
||||
assert(out);
|
||||
assert(line_break > 0);
|
||||
assert(ret);
|
||||
|
||||
/* three input bytes makes four output bytes, padding is added so we must round up */
|
||||
m = 4 * (l + 2) / 3 + 1;
|
||||
|
||||
if (line_break != SIZE_MAX)
|
||||
m += m / line_break;
|
||||
|
||||
z = r = malloc(m);
|
||||
if (!r)
|
||||
z = b = malloc(m);
|
||||
if (!b)
|
||||
return -ENOMEM;
|
||||
|
||||
for (x = p; x < (const uint8_t*) p + (l / 3) * 3; x += 3) {
|
||||
for (x = p; x && x < (const uint8_t*) p + (l / 3) * 3; x += 3) {
|
||||
/* x[0] == XXXXXXXX; x[1] == YYYYYYYY; x[2] == ZZZZZZZZ */
|
||||
maybe_line_break(&z, r, line_break);
|
||||
maybe_line_break(&z, b, line_break);
|
||||
*(z++) = base64char(x[0] >> 2); /* 00XXXXXX */
|
||||
maybe_line_break(&z, r, line_break);
|
||||
maybe_line_break(&z, b, line_break);
|
||||
*(z++) = base64char((x[0] & 3) << 4 | x[1] >> 4); /* 00XXYYYY */
|
||||
maybe_line_break(&z, r, line_break);
|
||||
maybe_line_break(&z, b, line_break);
|
||||
*(z++) = base64char((x[1] & 15) << 2 | x[2] >> 6); /* 00YYYYZZ */
|
||||
maybe_line_break(&z, r, line_break);
|
||||
maybe_line_break(&z, b, line_break);
|
||||
*(z++) = base64char(x[2] & 63); /* 00ZZZZZZ */
|
||||
}
|
||||
|
||||
switch (l % 3) {
|
||||
case 2:
|
||||
maybe_line_break(&z, r, line_break);
|
||||
maybe_line_break(&z, b, line_break);
|
||||
*(z++) = base64char(x[0] >> 2); /* 00XXXXXX */
|
||||
maybe_line_break(&z, r, line_break);
|
||||
maybe_line_break(&z, b, line_break);
|
||||
*(z++) = base64char((x[0] & 3) << 4 | x[1] >> 4); /* 00XXYYYY */
|
||||
maybe_line_break(&z, r, line_break);
|
||||
maybe_line_break(&z, b, line_break);
|
||||
*(z++) = base64char((x[1] & 15) << 2); /* 00YYYY00 */
|
||||
maybe_line_break(&z, r, line_break);
|
||||
maybe_line_break(&z, b, line_break);
|
||||
*(z++) = '=';
|
||||
|
||||
break;
|
||||
case 1:
|
||||
maybe_line_break(&z, r, line_break);
|
||||
*(z++) = base64char(x[0] >> 2); /* 00XXXXXX */
|
||||
maybe_line_break(&z, r, line_break);
|
||||
*(z++) = base64char((x[0] & 3) << 4); /* 00XX0000 */
|
||||
maybe_line_break(&z, r, line_break);
|
||||
*(z++) = '=';
|
||||
maybe_line_break(&z, r, line_break);
|
||||
*(z++) = '=';
|
||||
|
||||
case 1:
|
||||
maybe_line_break(&z, b, line_break);
|
||||
*(z++) = base64char(x[0] >> 2); /* 00XXXXXX */
|
||||
maybe_line_break(&z, b, line_break);
|
||||
*(z++) = base64char((x[0] & 3) << 4); /* 00XX0000 */
|
||||
maybe_line_break(&z, b, line_break);
|
||||
*(z++) = '=';
|
||||
maybe_line_break(&z, b, line_break);
|
||||
*(z++) = '=';
|
||||
break;
|
||||
}
|
||||
|
||||
*z = 0;
|
||||
*out = r;
|
||||
assert(z >= r); /* Let static analyzers know that the answer is non-negative. */
|
||||
return z - r;
|
||||
*ret = b;
|
||||
|
||||
assert(z >= b); /* Let static analyzers know that the answer is non-negative. */
|
||||
return z - b;
|
||||
}
|
||||
|
||||
static int base64_append_width(
|
||||
char **prefix, int plen,
|
||||
char sep, int indent,
|
||||
const void *p, size_t l,
|
||||
int width) {
|
||||
static ssize_t base64_append_width(
|
||||
char **prefix,
|
||||
size_t plen,
|
||||
char sep,
|
||||
size_t indent,
|
||||
const void *p,
|
||||
size_t l,
|
||||
size_t width) {
|
||||
|
||||
_cleanup_free_ char *x = NULL;
|
||||
char *t, *s;
|
||||
ssize_t len, avail, line, lines;
|
||||
size_t lines;
|
||||
ssize_t len;
|
||||
|
||||
assert(prefix);
|
||||
assert(*prefix || plen == 0);
|
||||
assert(p || l == 0);
|
||||
|
||||
len = base64mem(p, l, &x);
|
||||
if (len <= 0)
|
||||
if (len < 0)
|
||||
return len;
|
||||
if (len == 0)
|
||||
return plen;
|
||||
|
||||
lines = DIV_ROUND_UP(len, width);
|
||||
|
||||
if ((size_t) plen >= SSIZE_MAX - 1 - 1 ||
|
||||
if (plen >= SSIZE_MAX - 1 - 1 ||
|
||||
lines > (SSIZE_MAX - plen - 1 - 1) / (indent + width + 1))
|
||||
return -ENOMEM;
|
||||
|
||||
t = realloc(*prefix, (ssize_t) plen + 1 + 1 + (indent + width + 1) * lines);
|
||||
t = realloc(*prefix, plen + 1 + 1 + (indent + width + 1) * lines);
|
||||
if (!t)
|
||||
return -ENOMEM;
|
||||
|
||||
t[plen] = sep;
|
||||
s = t + plen;
|
||||
for (size_t line = 0; line < lines; line++) {
|
||||
size_t act = MIN(width, (size_t) len);
|
||||
|
||||
for (line = 0, s = t + plen + 1, avail = len; line < lines; line++) {
|
||||
int act = MIN(width, avail);
|
||||
if (line > 0)
|
||||
sep = '\n';
|
||||
|
||||
if (line > 0 || sep == '\n') {
|
||||
memset(s, ' ', indent);
|
||||
s += indent;
|
||||
if (s > t) {
|
||||
*s++ = sep;
|
||||
if (sep == '\n')
|
||||
s = mempset(s, ' ', indent);
|
||||
}
|
||||
|
||||
s = mempcpy(s, x + width * line, act);
|
||||
*(s++) = line < lines - 1 ? '\n' : '\0';
|
||||
avail -= act;
|
||||
len -= act;
|
||||
}
|
||||
assert(avail == 0);
|
||||
assert(len == 0);
|
||||
|
||||
*s = '\0';
|
||||
*prefix = t;
|
||||
return 0;
|
||||
return s - t;
|
||||
}
|
||||
|
||||
int base64_append(
|
||||
char **prefix, int plen,
|
||||
const void *p, size_t l,
|
||||
int indent, int width) {
|
||||
ssize_t base64_append(
|
||||
char **prefix,
|
||||
size_t plen,
|
||||
const void *p,
|
||||
size_t l,
|
||||
size_t indent,
|
||||
size_t width) {
|
||||
|
||||
if (plen > width / 2 || plen + indent > width)
|
||||
/* leave indent on the left, keep last column free */
|
||||
return base64_append_width(prefix, plen, '\n', indent, p, l, width - indent - 1);
|
||||
return base64_append_width(prefix, plen, '\n', indent, p, l, width - indent);
|
||||
else
|
||||
/* leave plen on the left, keep last column free */
|
||||
return base64_append_width(prefix, plen, ' ', plen + 1, p, l, width - plen - 1);
|
||||
|
|
@ -754,12 +768,17 @@ static int unbase64_next(const char **p, size_t *l) {
|
|||
return ret;
|
||||
}
|
||||
|
||||
int unbase64mem_full(const char *p, size_t l, bool secure, void **ret, size_t *ret_size) {
|
||||
int unbase64mem_full(
|
||||
const char *p,
|
||||
size_t l,
|
||||
bool secure,
|
||||
void **ret,
|
||||
size_t *ret_size) {
|
||||
|
||||
_cleanup_free_ uint8_t *buf = NULL;
|
||||
const char *x;
|
||||
uint8_t *z;
|
||||
size_t len;
|
||||
int r;
|
||||
|
||||
assert(p || l == 0);
|
||||
|
||||
|
|
@ -774,60 +793,44 @@ int unbase64mem_full(const char *p, size_t l, bool secure, void **ret, size_t *r
|
|||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
CLEANUP_ERASE_PTR(secure ? &buf : NULL, len);
|
||||
|
||||
for (x = p, z = buf;;) {
|
||||
int a, b, c, d; /* a == 00XXXXXX; b == 00YYYYYY; c == 00ZZZZZZ; d == 00WWWWWW */
|
||||
|
||||
a = unbase64_next(&x, &l);
|
||||
if (a == -EPIPE) /* End of string */
|
||||
break;
|
||||
if (a < 0) {
|
||||
r = a;
|
||||
goto on_failure;
|
||||
}
|
||||
if (a == INT_MAX) { /* Padding is not allowed at the beginning of a 4ch block */
|
||||
r = -EINVAL;
|
||||
goto on_failure;
|
||||
}
|
||||
if (a < 0)
|
||||
return a;
|
||||
if (a == INT_MAX) /* Padding is not allowed at the beginning of a 4ch block */
|
||||
return -EINVAL;
|
||||
|
||||
b = unbase64_next(&x, &l);
|
||||
if (b < 0) {
|
||||
r = b;
|
||||
goto on_failure;
|
||||
}
|
||||
if (b == INT_MAX) { /* Padding is not allowed at the second character of a 4ch block either */
|
||||
r = -EINVAL;
|
||||
goto on_failure;
|
||||
}
|
||||
if (b < 0)
|
||||
return b;
|
||||
if (b == INT_MAX) /* Padding is not allowed at the second character of a 4ch block either */
|
||||
return -EINVAL;
|
||||
|
||||
c = unbase64_next(&x, &l);
|
||||
if (c < 0) {
|
||||
r = c;
|
||||
goto on_failure;
|
||||
}
|
||||
if (c < 0)
|
||||
return c;
|
||||
|
||||
d = unbase64_next(&x, &l);
|
||||
if (d < 0) {
|
||||
r = d;
|
||||
goto on_failure;
|
||||
}
|
||||
if (d < 0)
|
||||
return d;
|
||||
|
||||
if (c == INT_MAX) { /* Padding at the third character */
|
||||
|
||||
if (d != INT_MAX) { /* If the third character is padding, the fourth must be too */
|
||||
r = -EINVAL;
|
||||
goto on_failure;
|
||||
}
|
||||
if (d != INT_MAX) /* If the third character is padding, the fourth must be too */
|
||||
return -EINVAL;
|
||||
|
||||
/* b == 00YY0000 */
|
||||
if (b & 15) {
|
||||
r = -EINVAL;
|
||||
goto on_failure;
|
||||
}
|
||||
if (b & 15)
|
||||
return -EINVAL;
|
||||
|
||||
if (l > 0) { /* Trailing rubbish? */
|
||||
r = -ENAMETOOLONG;
|
||||
goto on_failure;
|
||||
}
|
||||
if (l > 0) /* Trailing rubbish? */
|
||||
return -ENAMETOOLONG;
|
||||
|
||||
*(z++) = (uint8_t) a << 2 | (uint8_t) (b >> 4); /* XXXXXXYY */
|
||||
break;
|
||||
|
|
@ -835,15 +838,11 @@ int unbase64mem_full(const char *p, size_t l, bool secure, void **ret, size_t *r
|
|||
|
||||
if (d == INT_MAX) {
|
||||
/* c == 00ZZZZ00 */
|
||||
if (c & 3) {
|
||||
r = -EINVAL;
|
||||
goto on_failure;
|
||||
}
|
||||
if (c & 3)
|
||||
return -EINVAL;
|
||||
|
||||
if (l > 0) { /* Trailing rubbish? */
|
||||
r = -ENAMETOOLONG;
|
||||
goto on_failure;
|
||||
}
|
||||
if (l > 0) /* Trailing rubbish? */
|
||||
return -ENAMETOOLONG;
|
||||
|
||||
*(z++) = (uint8_t) a << 2 | (uint8_t) b >> 4; /* XXXXXXYY */
|
||||
*(z++) = (uint8_t) b << 4 | (uint8_t) c >> 2; /* YYYYZZZZ */
|
||||
|
|
@ -857,18 +856,14 @@ int unbase64mem_full(const char *p, size_t l, bool secure, void **ret, size_t *r
|
|||
|
||||
*z = 0;
|
||||
|
||||
assert((size_t) (z - buf) <= len);
|
||||
|
||||
if (ret_size)
|
||||
*ret_size = (size_t) (z - buf);
|
||||
if (ret)
|
||||
*ret = TAKE_PTR(buf);
|
||||
|
||||
return 0;
|
||||
|
||||
on_failure:
|
||||
if (secure)
|
||||
explicit_bzero_safe(buf, len);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
|
|
|
|||
|
|
@ -38,9 +38,13 @@ static inline ssize_t base64mem(const void *p, size_t l, char **ret) {
|
|||
return base64mem_full(p, l, SIZE_MAX, ret);
|
||||
}
|
||||
|
||||
int base64_append(char **prefix, int plen,
|
||||
const void *p, size_t l,
|
||||
int margin, int width);
|
||||
ssize_t base64_append(
|
||||
char **prefix,
|
||||
size_t plen,
|
||||
const void *p,
|
||||
size_t l,
|
||||
size_t margin,
|
||||
size_t width);
|
||||
int unbase64mem_full(const char *p, size_t l, bool secure, void **mem, size_t *len);
|
||||
static inline int unbase64mem(const char *p, size_t l, void **mem, size_t *len) {
|
||||
return unbase64mem_full(p, l, false, mem, len);
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ int gethostname_full(GetHostnameFlags flags, char **ret) {
|
|||
}
|
||||
|
||||
if (FLAGS_SET(flags, GET_HOSTNAME_SHORT))
|
||||
buf = strndup(s, strcspn(s, "."));
|
||||
buf = strdupcspn(s, ".");
|
||||
else
|
||||
buf = strdup(s);
|
||||
if (!buf)
|
||||
|
|
|
|||
|
|
@ -60,4 +60,12 @@ static inline bool is_outbound_hostname(const char *hostname) {
|
|||
return STRCASE_IN_SET(hostname, "_outbound", "_outbound.");
|
||||
}
|
||||
|
||||
static inline bool is_dns_stub_hostname(const char *hostname) {
|
||||
return STRCASE_IN_SET(hostname, "_localdnsstub", "_localdnsstub.");
|
||||
}
|
||||
|
||||
static inline bool is_dns_proxy_stub_hostname(const char *hostname) {
|
||||
return STRCASE_IN_SET(hostname, "_localdnsproxy", "_localdnsproxy.");
|
||||
}
|
||||
|
||||
int get_pretty_hostname(char **ret);
|
||||
|
|
|
|||
|
|
@ -13,13 +13,13 @@
|
|||
#include "alloc-util.h"
|
||||
#include "errno-util.h"
|
||||
#include "in-addr-util.h"
|
||||
#include "logarithm.h"
|
||||
#include "macro.h"
|
||||
#include "parse-util.h"
|
||||
#include "random-util.h"
|
||||
#include "stdio-util.h"
|
||||
#include "string-util.h"
|
||||
#include "strxcpyx.h"
|
||||
#include "util.h"
|
||||
|
||||
bool in4_addr_is_null(const struct in_addr *a) {
|
||||
assert(a);
|
||||
|
|
@ -907,14 +907,6 @@ int in_addr_prefix_from_string_auto_internal(
|
|||
break;
|
||||
case PREFIXLEN_REFUSE:
|
||||
return -ENOANO; /* To distinguish this error from others. */
|
||||
case PREFIXLEN_LEGACY:
|
||||
if (family == AF_INET) {
|
||||
r = in4_addr_default_prefixlen(&buffer.in, &k);
|
||||
if (r < 0)
|
||||
return r;
|
||||
} else
|
||||
k = 0;
|
||||
break;
|
||||
default:
|
||||
assert_not_reached();
|
||||
}
|
||||
|
|
@ -930,7 +922,7 @@ int in_addr_prefix_from_string_auto_internal(
|
|||
|
||||
}
|
||||
|
||||
static void in_addr_data_hash_func(const struct in_addr_data *a, struct siphash *state) {
|
||||
void in_addr_data_hash_func(const struct in_addr_data *a, struct siphash *state) {
|
||||
assert(a);
|
||||
assert(state);
|
||||
|
||||
|
|
@ -938,7 +930,7 @@ static void in_addr_data_hash_func(const struct in_addr_data *a, struct siphash
|
|||
siphash24_compress(&a->address, FAMILY_ADDRESS_SIZE(a->family), state);
|
||||
}
|
||||
|
||||
static int in_addr_data_compare_func(const struct in_addr_data *x, const struct in_addr_data *y) {
|
||||
int in_addr_data_compare_func(const struct in_addr_data *x, const struct in_addr_data *y) {
|
||||
int r;
|
||||
|
||||
assert(x);
|
||||
|
|
@ -951,7 +943,18 @@ static int in_addr_data_compare_func(const struct in_addr_data *x, const struct
|
|||
return memcmp(&x->address, &y->address, FAMILY_ADDRESS_SIZE(x->family));
|
||||
}
|
||||
|
||||
DEFINE_HASH_OPS(in_addr_data_hash_ops, struct in_addr_data, in_addr_data_hash_func, in_addr_data_compare_func);
|
||||
DEFINE_HASH_OPS(
|
||||
in_addr_data_hash_ops,
|
||||
struct in_addr_data,
|
||||
in_addr_data_hash_func,
|
||||
in_addr_data_compare_func);
|
||||
|
||||
DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(
|
||||
in_addr_data_hash_ops_free,
|
||||
struct in_addr_data,
|
||||
in_addr_data_hash_func,
|
||||
in_addr_data_compare_func,
|
||||
free);
|
||||
|
||||
void in6_addr_hash_func(const struct in6_addr *addr, struct siphash *state) {
|
||||
assert(addr);
|
||||
|
|
@ -967,7 +970,12 @@ int in6_addr_compare_func(const struct in6_addr *a, const struct in6_addr *b) {
|
|||
return memcmp(a, b, sizeof(*a));
|
||||
}
|
||||
|
||||
DEFINE_HASH_OPS(in6_addr_hash_ops, struct in6_addr, in6_addr_hash_func, in6_addr_compare_func);
|
||||
DEFINE_HASH_OPS(
|
||||
in6_addr_hash_ops,
|
||||
struct in6_addr,
|
||||
in6_addr_hash_func,
|
||||
in6_addr_compare_func);
|
||||
|
||||
DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(
|
||||
in6_addr_hash_ops_free,
|
||||
struct in6_addr,
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@
|
|||
|
||||
#include "hash-funcs.h"
|
||||
#include "macro.h"
|
||||
#include "util.h"
|
||||
|
||||
union in_addr_union {
|
||||
struct in_addr in;
|
||||
|
|
@ -154,7 +153,6 @@ int in_addr_prefix_from_string(const char *p, int family, union in_addr_union *r
|
|||
typedef enum InAddrPrefixLenMode {
|
||||
PREFIXLEN_FULL, /* Default to prefixlen of address size, 32 for IPv4 or 128 for IPv6, if not specified. */
|
||||
PREFIXLEN_REFUSE, /* Fail with -ENOANO if prefixlen is not specified. */
|
||||
PREFIXLEN_LEGACY, /* Default to legacy default prefixlen calculation from address if not specified. */
|
||||
} InAddrPrefixLenMode;
|
||||
|
||||
int in_addr_prefix_from_string_auto_internal(const char *p, InAddrPrefixLenMode mode, int *ret_family, union in_addr_union *ret_prefix, unsigned char *ret_prefixlen);
|
||||
|
|
@ -178,10 +176,13 @@ static inline size_t FAMILY_ADDRESS_SIZE(int family) {
|
|||
* See also oss-fuzz#11344. */
|
||||
#define IN_ADDR_NULL ((union in_addr_union) { .in6 = {} })
|
||||
|
||||
void in_addr_data_hash_func(const struct in_addr_data *a, struct siphash *state);
|
||||
int in_addr_data_compare_func(const struct in_addr_data *x, const struct in_addr_data *y);
|
||||
void in6_addr_hash_func(const struct in6_addr *addr, struct siphash *state);
|
||||
int in6_addr_compare_func(const struct in6_addr *a, const struct in6_addr *b);
|
||||
|
||||
extern const struct hash_ops in_addr_data_hash_ops;
|
||||
extern const struct hash_ops in_addr_data_hash_ops_free;
|
||||
extern const struct hash_ops in6_addr_hash_ops;
|
||||
extern const struct hash_ops in6_addr_hash_ops_free;
|
||||
|
||||
|
|
|
|||
|
|
@ -167,6 +167,21 @@ int ppoll_usec(struct pollfd *fds, size_t nfds, usec_t timeout) {
|
|||
|
||||
assert(fds || nfds == 0);
|
||||
|
||||
/* This is a wrapper around ppoll() that does primarily two things:
|
||||
*
|
||||
* ✅ Takes a usec_t instead of a struct timespec
|
||||
*
|
||||
* ✅ Guarantees that if an invalid fd is specified we return EBADF (i.e. converts POLLNVAL to
|
||||
* EBADF). This is done because EBADF is a programming error usually, and hence should bubble up
|
||||
* as error, and not be eaten up as non-error POLLNVAL event.
|
||||
*
|
||||
* ⚠️ ⚠️ ⚠️ Note that this function does not add any special handling for EINTR. Don't forget
|
||||
* poll()/ppoll() will return with EINTR on any received signal always, there is no automatic
|
||||
* restarting via SA_RESTART available. Thus, typically you want to handle EINTR not as an error,
|
||||
* but just as reason to restart things, under the assumption you use a more appropriate mechanism
|
||||
* to handle signals, such as signalfd() or signal handlers. ⚠️ ⚠️ ⚠️
|
||||
*/
|
||||
|
||||
if (nfds == 0)
|
||||
return 0;
|
||||
|
||||
|
|
@ -194,6 +209,9 @@ int fd_wait_for_event(int fd, int event, usec_t timeout) {
|
|||
};
|
||||
int r;
|
||||
|
||||
/* ⚠️ ⚠️ ⚠️ Keep in mind you almost certainly want to handle -EINTR gracefully in the caller, see
|
||||
* ppoll_usec() above! ⚠️ ⚠️ ⚠️ */
|
||||
|
||||
r = ppoll_usec(&pollfd, 1, timeout);
|
||||
if (r <= 0)
|
||||
return r;
|
||||
|
|
|
|||
|
|
@ -91,7 +91,16 @@ struct iovec_wrapper *iovw_new(void);
|
|||
struct iovec_wrapper *iovw_free(struct iovec_wrapper *iovw);
|
||||
struct iovec_wrapper *iovw_free_free(struct iovec_wrapper *iovw);
|
||||
void iovw_free_contents(struct iovec_wrapper *iovw, bool free_vectors);
|
||||
|
||||
int iovw_put(struct iovec_wrapper *iovw, void *data, size_t len);
|
||||
static inline int iovw_consume(struct iovec_wrapper *iovw, void *data, size_t len) {
|
||||
/* Move data into iovw or free on error */
|
||||
int r = iovw_put(iovw, data, len);
|
||||
if (r < 0)
|
||||
free(data);
|
||||
return r;
|
||||
}
|
||||
|
||||
int iovw_put_string_field(struct iovec_wrapper *iovw, const char *field, const char *value);
|
||||
int iovw_put_string_field_free(struct iovec_wrapper *iovw, const char *field, char *value);
|
||||
void iovw_rebase(struct iovec_wrapper *iovw, char *old, char *new);
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#include "macro.h"
|
||||
|
||||
/* The head of the linked list. Use this in the structure that shall
|
||||
* contain the head of the linked list */
|
||||
#define LIST_HEAD(t,name) \
|
||||
|
|
@ -28,26 +26,27 @@
|
|||
|
||||
/* Prepend an item to the list */
|
||||
#define LIST_PREPEND(name,head,item) \
|
||||
do { \
|
||||
({ \
|
||||
typeof(*(head)) **_head = &(head), *_item = (item); \
|
||||
assert(_item); \
|
||||
if ((_item->name##_next = *_head)) \
|
||||
_item->name##_next->name##_prev = _item; \
|
||||
_item->name##_prev = NULL; \
|
||||
*_head = _item; \
|
||||
} while (false)
|
||||
_item; \
|
||||
})
|
||||
|
||||
/* Append an item to the list */
|
||||
#define LIST_APPEND(name,head,item) \
|
||||
do { \
|
||||
({ \
|
||||
typeof(*(head)) **_hhead = &(head), *_tail; \
|
||||
LIST_FIND_TAIL(name, *_hhead, _tail); \
|
||||
_tail = LIST_FIND_TAIL(name, *_hhead); \
|
||||
LIST_INSERT_AFTER(name, *_hhead, _tail, item); \
|
||||
} while (false)
|
||||
})
|
||||
|
||||
/* Remove an item from the list */
|
||||
#define LIST_REMOVE(name,head,item) \
|
||||
do { \
|
||||
({ \
|
||||
typeof(*(head)) **_head = &(head), *_item = (item); \
|
||||
assert(_item); \
|
||||
if (_item->name##_next) \
|
||||
|
|
@ -59,37 +58,30 @@
|
|||
*_head = _item->name##_next; \
|
||||
} \
|
||||
_item->name##_next = _item->name##_prev = NULL; \
|
||||
} while (false)
|
||||
_item; \
|
||||
})
|
||||
|
||||
/* Find the head of the list */
|
||||
#define LIST_FIND_HEAD(name,item,head) \
|
||||
do { \
|
||||
#define LIST_FIND_HEAD(name,item) \
|
||||
({ \
|
||||
typeof(*(item)) *_item = (item); \
|
||||
if (!_item) \
|
||||
(head) = NULL; \
|
||||
else { \
|
||||
while (_item->name##_prev) \
|
||||
_item = _item->name##_prev; \
|
||||
(head) = _item; \
|
||||
} \
|
||||
} while (false)
|
||||
while (_item && _item->name##_prev) \
|
||||
_item = _item->name##_prev; \
|
||||
_item; \
|
||||
})
|
||||
|
||||
/* Find the tail of the list */
|
||||
#define LIST_FIND_TAIL(name,item,tail) \
|
||||
do { \
|
||||
#define LIST_FIND_TAIL(name,item) \
|
||||
({ \
|
||||
typeof(*(item)) *_item = (item); \
|
||||
if (!_item) \
|
||||
(tail) = NULL; \
|
||||
else { \
|
||||
while (_item->name##_next) \
|
||||
_item = _item->name##_next; \
|
||||
(tail) = _item; \
|
||||
} \
|
||||
} while (false)
|
||||
while (_item && _item->name##_next) \
|
||||
_item = _item->name##_next; \
|
||||
_item; \
|
||||
})
|
||||
|
||||
/* Insert an item after another one (a = where, b = what) */
|
||||
#define LIST_INSERT_AFTER(name,head,a,b) \
|
||||
do { \
|
||||
({ \
|
||||
typeof(*(head)) **_head = &(head), *_a = (a), *_b = (b); \
|
||||
assert(_b); \
|
||||
if (!_a) { \
|
||||
|
|
@ -103,11 +95,12 @@
|
|||
_b->name##_prev = _a; \
|
||||
_a->name##_next = _b; \
|
||||
} \
|
||||
} while (false)
|
||||
_b; \
|
||||
})
|
||||
|
||||
/* Insert an item before another one (a = where, b = what) */
|
||||
#define LIST_INSERT_BEFORE(name,head,a,b) \
|
||||
do { \
|
||||
({ \
|
||||
typeof(*(head)) **_head = &(head), *_a = (a), *_b = (b); \
|
||||
assert(_b); \
|
||||
if (!_a) { \
|
||||
|
|
@ -131,7 +124,8 @@
|
|||
_b->name##_next = _a; \
|
||||
_a->name##_prev = _b; \
|
||||
} \
|
||||
} while (false)
|
||||
_b; \
|
||||
})
|
||||
|
||||
#define LIST_JUST_US(name,item) \
|
||||
(!(item)->name##_prev && !(item)->name##_next)
|
||||
|
|
@ -172,18 +166,19 @@
|
|||
|
||||
/* Join two lists tail to head: a->b, c->d to a->b->c->d and de-initialise second list */
|
||||
#define LIST_JOIN(name,a,b) \
|
||||
do { \
|
||||
({ \
|
||||
assert(b); \
|
||||
if (!(a)) \
|
||||
(a) = (b); \
|
||||
else { \
|
||||
typeof(*(a)) *_head = (b), *_tail; \
|
||||
LIST_FIND_TAIL(name, (a), _tail); \
|
||||
_tail = LIST_FIND_TAIL(name, (a)); \
|
||||
_tail->name##_next = _head; \
|
||||
_head->name##_prev = _tail; \
|
||||
} \
|
||||
(b) = NULL; \
|
||||
} while (false)
|
||||
a; \
|
||||
})
|
||||
|
||||
#define LIST_POP(name, a) \
|
||||
({ \
|
||||
|
|
@ -193,3 +188,7 @@
|
|||
LIST_REMOVE(name, *_a, _p); \
|
||||
_p; \
|
||||
})
|
||||
|
||||
/* Now include "macro.h", because we want our definition of assert() which the macros above use. We include
|
||||
* it down here instead of up top, since macro.h pulls in log.h which in turn needs our own definitions. */
|
||||
#include "macro.h"
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "def.h"
|
||||
#include "constants.h"
|
||||
#include "dirent-util.h"
|
||||
#include "env-util.h"
|
||||
#include "fd-util.h"
|
||||
|
|
@ -98,7 +98,7 @@ static int add_locales_from_archive(Set *locales) {
|
|||
const struct locarhead *h;
|
||||
const struct namehashent *e;
|
||||
const void *p = MAP_FAILED;
|
||||
_cleanup_close_ int fd = -1;
|
||||
_cleanup_close_ int fd = -EBADF;
|
||||
size_t sz = 0;
|
||||
struct stat st;
|
||||
int r;
|
||||
|
|
@ -290,8 +290,9 @@ void init_gettext(void) {
|
|||
#endif /* NM_IGNORED */
|
||||
|
||||
bool is_locale_utf8(void) {
|
||||
const char *set;
|
||||
static int cached_answer = -1;
|
||||
const char *set;
|
||||
int r;
|
||||
|
||||
/* Note that we default to 'true' here, since today UTF8 is
|
||||
* pretty much supported everywhere. */
|
||||
|
|
@ -299,6 +300,13 @@ bool is_locale_utf8(void) {
|
|||
if (cached_answer >= 0)
|
||||
goto out;
|
||||
|
||||
r = getenv_bool_secure("SYSTEMD_UTF8");
|
||||
if (r >= 0) {
|
||||
cached_answer = r;
|
||||
goto out;
|
||||
} else if (r != -ENXIO)
|
||||
log_debug_errno(r, "Failed to parse $SYSTEMD_UTF8, ignoring: %m");
|
||||
|
||||
if (!setlocale(LC_ALL, "")) {
|
||||
cached_answer = true;
|
||||
goto out;
|
||||
|
|
|
|||
|
|
@ -7,8 +7,10 @@
|
|||
#include <string.h>
|
||||
#include <syslog.h>
|
||||
|
||||
#include "list.h"
|
||||
#include "macro.h"
|
||||
#include "ratelimit.h"
|
||||
#include "stdio-util.h"
|
||||
|
||||
/* Some structures we reference but don't want to pull in headers for */
|
||||
struct iovec;
|
||||
|
|
@ -432,6 +434,7 @@ int log_emergency_level(void);
|
|||
|
||||
#define log_oom() log_oom_internal(LOG_ERR, PROJECT_FILE, __LINE__, __func__)
|
||||
#define log_oom_debug() log_oom_internal(LOG_DEBUG, PROJECT_FILE, __LINE__, __func__)
|
||||
#define log_oom_warning() log_oom_internal(LOG_WARNING, PROJECT_FILE, __LINE__, __func__)
|
||||
|
||||
bool log_on_console(void) _pure_;
|
||||
|
||||
|
|
@ -516,15 +519,12 @@ typedef struct LogRateLimit {
|
|||
RateLimit ratelimit;
|
||||
} LogRateLimit;
|
||||
|
||||
#define log_ratelimit_internal(_level, _error, _format, _file, _line, _func, ...) \
|
||||
#define log_ratelimit_internal(_level, _error, _ratelimit, _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, \
|
||||
}, \
|
||||
.ratelimit = (_ratelimit), \
|
||||
}; \
|
||||
unsigned _num_dropped_errors = ratelimit_num_dropped(&_log_ratelimit.ratelimit); \
|
||||
if (_log_ratelimit_error != _log_ratelimit.error || _log_ratelimit_level != _log_ratelimit.level) { \
|
||||
|
|
@ -532,18 +532,115 @@ typedef struct LogRateLimit {
|
|||
_log_ratelimit.error = _log_ratelimit_error; \
|
||||
_log_ratelimit.level = _log_ratelimit_level; \
|
||||
} \
|
||||
if (ratelimit_below(&_log_ratelimit.ratelimit)) \
|
||||
if (log_get_max_level() == LOG_DEBUG || 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_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, ...) \
|
||||
#define log_ratelimit_full_errno(level, error, _ratelimit, 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__) \
|
||||
? log_ratelimit_internal(_level, _e, _ratelimit, format, PROJECT_FILE, __LINE__, __func__, ##__VA_ARGS__) \
|
||||
: -ERRNO_VALUE(_e); \
|
||||
_e < 0 ? _e : -ESTRPIPE; \
|
||||
})
|
||||
|
||||
#define log_ratelimit_full(level, _ratelimit, format, ...) \
|
||||
log_ratelimit_full_errno(level, 0, _ratelimit, format, ##__VA_ARGS__)
|
||||
|
||||
/* Normal logging */
|
||||
#define log_ratelimit_info(...) log_ratelimit_full(LOG_INFO, __VA_ARGS__)
|
||||
#define log_ratelimit_notice(...) log_ratelimit_full(LOG_NOTICE, __VA_ARGS__)
|
||||
#define log_ratelimit_warning(...) log_ratelimit_full(LOG_WARNING, __VA_ARGS__)
|
||||
#define log_ratelimit_error(...) log_ratelimit_full(LOG_ERR, __VA_ARGS__)
|
||||
#define log_ratelimit_emergency(...) log_ratelimit_full(log_emergency_level(), __VA_ARGS__)
|
||||
|
||||
/* Logging triggered by an errno-like error */
|
||||
#define log_ratelimit_info_errno(error, ...) log_ratelimit_full_errno(LOG_INFO, error, __VA_ARGS__)
|
||||
#define log_ratelimit_notice_errno(error, ...) log_ratelimit_full_errno(LOG_NOTICE, error, __VA_ARGS__)
|
||||
#define log_ratelimit_warning_errno(error, ...) log_ratelimit_full_errno(LOG_WARNING, error, __VA_ARGS__)
|
||||
#define log_ratelimit_error_errno(error, ...) log_ratelimit_full_errno(LOG_ERR, error, __VA_ARGS__)
|
||||
#define log_ratelimit_emergency_errno(error, ...) log_ratelimit_full_errno(log_emergency_level(), error, __VA_ARGS__)
|
||||
|
||||
/*
|
||||
* The log context allows attaching extra metadata to log messages written to the journal via log.h. We keep
|
||||
* track of a thread local log context onto which we can push extra metadata fields that should be logged.
|
||||
*
|
||||
* LOG_CONTEXT_PUSH() will add the provided field to the log context and will remove it again when the
|
||||
* current block ends. LOG_CONTEXT_PUSH_STRV() will do the same but for all fields in the given strv.
|
||||
* LOG_CONTEXT_PUSHF() is like LOG_CONTEXT_PUSH() but takes a format string and arguments.
|
||||
*
|
||||
* Using the macros is as simple as putting them anywhere inside a block to add a field to all following log
|
||||
* messages logged from inside that block.
|
||||
*
|
||||
* void myfunction(...) {
|
||||
* ...
|
||||
*
|
||||
* LOG_CONTEXT_PUSHF("MYMETADATA=%s", "abc");
|
||||
*
|
||||
* // Every journal message logged will now have the MYMETADATA=abc
|
||||
* // field included.
|
||||
* }
|
||||
*
|
||||
* One special case to note is async code, where we use callbacks that are invoked to continue processing
|
||||
* when some event occurs. For async code, there's usually an associated "userdata" struct containing all the
|
||||
* information associated with the async operation. In this "userdata" struct, we can store a log context
|
||||
* allocated with log_context_new() and freed with log_context_free(). We can then add and remove fields to
|
||||
* the `fields` member of the log context object and all those fields will be logged along with each log
|
||||
* message.
|
||||
*/
|
||||
|
||||
typedef struct LogContext LogContext;
|
||||
|
||||
bool log_context_enabled(void);
|
||||
|
||||
LogContext* log_context_attach(LogContext *c);
|
||||
LogContext* log_context_detach(LogContext *c);
|
||||
|
||||
LogContext* log_context_new(char **fields, bool owned);
|
||||
LogContext* log_context_free(LogContext *c);
|
||||
|
||||
/* Same as log_context_new(), but frees the given fields strv on failure. */
|
||||
LogContext* log_context_new_consume(char **fields);
|
||||
|
||||
/* Returns the number of attached log context objects. */
|
||||
size_t log_context_num_contexts(void);
|
||||
/* Returns the number of fields in all attached log contexts. */
|
||||
size_t log_context_num_fields(void);
|
||||
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(LogContext*, log_context_detach);
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(LogContext*, log_context_free);
|
||||
|
||||
#define LOG_CONTEXT_PUSH(...) \
|
||||
LOG_CONTEXT_PUSH_STRV(STRV_MAKE(__VA_ARGS__))
|
||||
|
||||
#define LOG_CONTEXT_PUSHF(...) \
|
||||
LOG_CONTEXT_PUSH(snprintf_ok((char[LINE_MAX]) {}, LINE_MAX, __VA_ARGS__))
|
||||
|
||||
#define _LOG_CONTEXT_PUSH_STRV(strv, c) \
|
||||
_unused_ _cleanup_(log_context_freep) LogContext *c = log_context_new(strv, /*owned=*/ false);
|
||||
|
||||
#define LOG_CONTEXT_PUSH_STRV(strv) \
|
||||
_LOG_CONTEXT_PUSH_STRV(strv, UNIQ_T(c, UNIQ))
|
||||
|
||||
/* LOG_CONTEXT_CONSUME_STR()/LOG_CONTEXT_CONSUME_STRV() are identical to
|
||||
* LOG_CONTEXT_PUSH_STR()/LOG_CONTEXT_PUSH_STRV() except they take ownership of the given str/strv argument.
|
||||
*/
|
||||
|
||||
#define _LOG_CONTEXT_CONSUME_STR(s, c, strv) \
|
||||
_unused_ _cleanup_strv_free_ strv = strv_new(s); \
|
||||
if (!strv) \
|
||||
free(s); \
|
||||
_unused_ _cleanup_(log_context_freep) LogContext *c = log_context_new_consume(TAKE_PTR(strv))
|
||||
|
||||
#define LOG_CONTEXT_CONSUME_STR(s) \
|
||||
_LOG_CONTEXT_CONSUME_STR(s, UNIQ_T(c, UNIQ), UNIQ_T(sv, UNIQ))
|
||||
|
||||
#define _LOG_CONTEXT_CONSUME_STRV(strv, c) \
|
||||
_unused_ _cleanup_(log_context_freep) LogContext *c = log_context_new_consume(strv);
|
||||
|
||||
#define LOG_CONTEXT_CONSUME_STRV(strv) \
|
||||
_LOG_CONTEXT_CONSUME_STRV(strv, UNIQ_T(c, UNIQ))
|
||||
|
|
|
|||
|
|
@ -5,27 +5,6 @@
|
|||
|
||||
#include "macro.h"
|
||||
|
||||
extern int saved_argc;
|
||||
extern char **saved_argv;
|
||||
|
||||
static inline void save_argc_argv(int argc, char **argv) {
|
||||
|
||||
/* Protect against CVE-2021-4034 style attacks */
|
||||
assert_se(argc > 0);
|
||||
assert_se(argv);
|
||||
assert_se(argv[0]);
|
||||
|
||||
saved_argc = argc;
|
||||
saved_argv = argv;
|
||||
}
|
||||
|
||||
bool kexec_loaded(void);
|
||||
|
||||
int prot_from_flags(int flags) _const_;
|
||||
|
||||
bool in_initrd(void);
|
||||
void in_initrd_force(bool value);
|
||||
|
||||
/* Note: log2(0) == log2(1) == 0 here and below. */
|
||||
|
||||
#define CONST_LOG2ULL(x) ((x) > 1 ? (unsigned) __builtin_clzll(x) ^ 63U : 0)
|
||||
|
|
@ -80,9 +59,3 @@ static inline unsigned log2u_round_up(unsigned x) {
|
|||
|
||||
return log2u(x - 1) + 1;
|
||||
}
|
||||
|
||||
int container_get_leader(const char *machine, pid_t *pid);
|
||||
|
||||
int version(void);
|
||||
|
||||
void disable_coredumps(void);
|
||||
|
|
@ -9,32 +9,9 @@
|
|||
#include <sys/sysmacros.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "constants.h"
|
||||
#include "macro-fundamental.h"
|
||||
|
||||
#if !defined(HAS_FEATURE_MEMORY_SANITIZER)
|
||||
# if defined(__has_feature)
|
||||
# if __has_feature(memory_sanitizer)
|
||||
# define HAS_FEATURE_MEMORY_SANITIZER 1
|
||||
# endif
|
||||
# endif
|
||||
# if !defined(HAS_FEATURE_MEMORY_SANITIZER)
|
||||
# define HAS_FEATURE_MEMORY_SANITIZER 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if !defined(HAS_FEATURE_ADDRESS_SANITIZER)
|
||||
# ifdef __SANITIZE_ADDRESS__
|
||||
# define HAS_FEATURE_ADDRESS_SANITIZER 1
|
||||
# elif defined(__has_feature)
|
||||
# if __has_feature(address_sanitizer)
|
||||
# define HAS_FEATURE_ADDRESS_SANITIZER 1
|
||||
# endif
|
||||
# endif
|
||||
# if !defined(HAS_FEATURE_ADDRESS_SANITIZER)
|
||||
# define HAS_FEATURE_ADDRESS_SANITIZER 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Note: on GCC "no_sanitize_address" is a function attribute only, on llvm it may also be applied to global
|
||||
* variables. We define a specific macro which knows this. Note that on GCC we don't need this decorator so much, since
|
||||
* our primary usecase for this attribute is registration structures placed in named ELF sections which shall not be
|
||||
|
|
@ -88,10 +65,14 @@
|
|||
_Pragma("GCC diagnostic push")
|
||||
#endif
|
||||
|
||||
#define DISABLE_WARNING_TYPE_LIMITS \
|
||||
#define DISABLE_WARNING_TYPE_LIMITS \
|
||||
_Pragma("GCC diagnostic push"); \
|
||||
_Pragma("GCC diagnostic ignored \"-Wtype-limits\"")
|
||||
|
||||
#define DISABLE_WARNING_ADDRESS \
|
||||
_Pragma("GCC diagnostic push"); \
|
||||
_Pragma("GCC diagnostic ignored \"-Waddress\"")
|
||||
|
||||
#define REENABLE_WARNING \
|
||||
_Pragma("GCC diagnostic pop")
|
||||
#else
|
||||
|
|
@ -203,12 +184,12 @@ static inline int __coverity_check_and_return__(int condition) {
|
|||
#define assert_message_se(expr, message) \
|
||||
do { \
|
||||
if (_unlikely_(!(expr))) \
|
||||
log_assert_failed(message, PROJECT_FILE, __LINE__, __PRETTY_FUNCTION__); \
|
||||
log_assert_failed(message, PROJECT_FILE, __LINE__, __func__); \
|
||||
} while (false)
|
||||
|
||||
#define assert_log(expr, message) ((_likely_(expr)) \
|
||||
? (true) \
|
||||
: (log_assert_failed_return(message, PROJECT_FILE, __LINE__, __PRETTY_FUNCTION__), false))
|
||||
: (log_assert_failed_return(message, PROJECT_FILE, __LINE__, __func__), false))
|
||||
|
||||
#endif /* __COVERITY__ */
|
||||
|
||||
|
|
@ -223,7 +204,7 @@ static inline int __coverity_check_and_return__(int condition) {
|
|||
#endif
|
||||
|
||||
#define assert_not_reached() \
|
||||
log_assert_failed_unreachable(PROJECT_FILE, __LINE__, __PRETTY_FUNCTION__)
|
||||
log_assert_failed_unreachable(PROJECT_FILE, __LINE__, __func__)
|
||||
|
||||
#define assert_return(expr, r) \
|
||||
do { \
|
||||
|
|
@ -350,10 +331,14 @@ static inline int __coverity_check_and_return__(int condition) {
|
|||
*p = func(*p); \
|
||||
}
|
||||
|
||||
/* When func() doesn't return the appropriate type, set variable to empty afterwards */
|
||||
/* When func() doesn't return the appropriate type, set variable to empty afterwards.
|
||||
* The func() may be provided by a dynamically loaded shared library, hence add an assertion. */
|
||||
#define DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(type, func, empty) \
|
||||
static inline void func##p(type *p) { \
|
||||
if (*p != (empty)) { \
|
||||
DISABLE_WARNING_ADDRESS; \
|
||||
assert(func); \
|
||||
REENABLE_WARNING; \
|
||||
func(*p); \
|
||||
*p = (empty); \
|
||||
} \
|
||||
|
|
|
|||
|
|
@ -40,21 +40,3 @@ bool memeqbyte(uint8_t byte, const void *data, size_t length) {
|
|||
/* Now we know first 16 bytes match, memcmp() with self. */
|
||||
return memcmp(data, p + 16, length) == 0;
|
||||
}
|
||||
|
||||
#if !HAVE_EXPLICIT_BZERO
|
||||
/*
|
||||
* The pointer to memset() is volatile so that compiler must de-reference the pointer and can't assume that
|
||||
* it points to any function in particular (such as memset(), which it then might further "optimize"). This
|
||||
* approach is inspired by openssl's crypto/mem_clr.c.
|
||||
*/
|
||||
typedef void *(*memset_t)(void *,int,size_t);
|
||||
|
||||
static volatile memset_t memset_func = memset;
|
||||
|
||||
void* explicit_bzero_safe(void *p, size_t l) {
|
||||
if (l > 0)
|
||||
memset_func(p, '\0', l);
|
||||
|
||||
return p;
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
#include "alloc-util.h"
|
||||
#include "macro.h"
|
||||
#include "memory-util-fundamental.h"
|
||||
|
||||
size_t page_size(void) _pure_;
|
||||
#define PAGE_ALIGN(l) ALIGN_TO((l), page_size())
|
||||
|
|
@ -91,17 +92,6 @@ static inline void *mempmem_safe(const void *haystack, size_t haystacklen, const
|
|||
return (uint8_t*) p + needlelen;
|
||||
}
|
||||
|
||||
#if HAVE_EXPLICIT_BZERO
|
||||
static inline void* explicit_bzero_safe(void *p, size_t l) {
|
||||
if (l > 0)
|
||||
explicit_bzero(p, l);
|
||||
|
||||
return p;
|
||||
}
|
||||
#else
|
||||
void *explicit_bzero_safe(void *p, size_t l);
|
||||
#endif
|
||||
|
||||
static inline void* erase_and_free(void *p) {
|
||||
size_t l;
|
||||
|
||||
|
|
|
|||
|
|
@ -370,6 +370,20 @@ static inline int missing_rt_sigqueueinfo(pid_t tgid, int sig, siginfo_t *info)
|
|||
/* ======================================================================= */
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
#if !HAVE_RT_TGSIGQUEUEINFO
|
||||
static inline int missing_rt_tgsigqueueinfo(pid_t tgid, pid_t tid, int sig, siginfo_t *info) {
|
||||
# if defined __NR_rt_tgsigqueueinfo && __NR_rt_tgsigqueueinfo >= 0
|
||||
return syscall(__NR_rt_tgsigqueueinfo, tgid, tid, sig, info);
|
||||
# else
|
||||
# error "__NR_rt_tgsigqueueinfo not defined"
|
||||
# endif
|
||||
}
|
||||
|
||||
# define rt_tgsigqueueinfo missing_rt_tgsigqueueinfo
|
||||
#endif
|
||||
|
||||
/* ======================================================================= */
|
||||
|
||||
#if !HAVE_EXECVEAT
|
||||
static inline int missing_execveat(int dirfd, const char *pathname,
|
||||
char *const argv[], char *const envp[],
|
||||
|
|
@ -419,44 +433,6 @@ static inline int missing_close_range(int first_fd, int end_fd, unsigned flags)
|
|||
|
||||
/* ======================================================================= */
|
||||
|
||||
#if !HAVE_EPOLL_PWAIT2
|
||||
|
||||
/* Defined to be equivalent to the kernel's _NSIG_WORDS, i.e. the size of the array of longs that is
|
||||
* encapsulated by sigset_t. */
|
||||
#define KERNEL_NSIG_WORDS (64 / (sizeof(long) * 8))
|
||||
#define KERNEL_NSIG_BYTES (KERNEL_NSIG_WORDS * sizeof(long))
|
||||
|
||||
struct epoll_event;
|
||||
|
||||
static inline int missing_epoll_pwait2(
|
||||
int fd,
|
||||
struct epoll_event *events,
|
||||
int maxevents,
|
||||
const struct timespec *timeout,
|
||||
const sigset_t *sigset) {
|
||||
|
||||
# if defined(__NR_epoll_pwait2) && HAVE_LINUX_TIME_TYPES_H
|
||||
if (timeout) {
|
||||
/* Convert from userspace timespec to kernel timespec */
|
||||
struct __kernel_timespec ts = {
|
||||
.tv_sec = timeout->tv_sec,
|
||||
.tv_nsec = timeout->tv_nsec,
|
||||
};
|
||||
|
||||
return syscall(__NR_epoll_pwait2, fd, events, maxevents, &ts, sigset, sigset ? KERNEL_NSIG_BYTES : 0);
|
||||
} else
|
||||
return syscall(__NR_epoll_pwait2, fd, events, maxevents, NULL, sigset, sigset ? KERNEL_NSIG_BYTES : 0);
|
||||
# else
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
# endif
|
||||
}
|
||||
|
||||
# define epoll_pwait2 missing_epoll_pwait2
|
||||
#endif
|
||||
|
||||
/* ======================================================================= */
|
||||
|
||||
#if !HAVE_MOUNT_SETATTR
|
||||
|
||||
#if !HAVE_STRUCT_MOUNT_ATTR
|
||||
|
|
@ -600,6 +576,46 @@ static inline int missing_move_mount(
|
|||
|
||||
/* ======================================================================= */
|
||||
|
||||
#if !HAVE_FSOPEN
|
||||
|
||||
#ifndef FSOPEN_CLOEXEC
|
||||
#define FSOPEN_CLOEXEC 0x00000001
|
||||
#endif
|
||||
|
||||
static inline int missing_fsopen(const char *fsname, unsigned flags) {
|
||||
# if defined __NR_fsopen && __NR_fsopen >= 0
|
||||
return syscall(__NR_fsopen, fsname, flags);
|
||||
# else
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
# endif
|
||||
}
|
||||
|
||||
# define fsopen missing_fsopen
|
||||
#endif
|
||||
|
||||
/* ======================================================================= */
|
||||
|
||||
#if !HAVE_FSCONFIG
|
||||
|
||||
#ifndef FSCONFIG_SET_STRING
|
||||
#define FSCONFIG_SET_STRING 1 /* Set parameter, supplying a string value */
|
||||
#endif
|
||||
|
||||
static inline int missing_fsconfig(int fd, unsigned cmd, const char *key, const void *value, int aux) {
|
||||
# if defined __NR_fsconfig && __NR_fsconfig >= 0
|
||||
return syscall(__NR_fsconfig, fd, cmd, key, value, aux);
|
||||
# else
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
# endif
|
||||
}
|
||||
|
||||
# define fsconfig missing_fsconfig
|
||||
#endif
|
||||
|
||||
/* ======================================================================= */
|
||||
|
||||
#if !HAVE_GETDENTS64
|
||||
|
||||
static inline ssize_t missing_getdents64(int fd, void *buffer, size_t length) {
|
||||
|
|
|
|||
|
|
@ -261,6 +261,26 @@ int parse_size(const char *t, uint64_t base, uint64_t *size) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int parse_sector_size(const char *t, uint64_t *ret) {
|
||||
int r;
|
||||
|
||||
assert(t);
|
||||
assert(ret);
|
||||
|
||||
uint64_t ss;
|
||||
|
||||
r = safe_atou64(t, &ss);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to parse sector size parameter %s", t);
|
||||
if (ss < 512 || ss > 4096) /* Allow up to 4K due to dm-crypt support and 4K alignment by the homed LUKS backend */
|
||||
return log_error_errno(SYNTHETIC_ERRNO(ERANGE), "Sector size not between 512 and 4096: %s", t);
|
||||
if (!ISPOWEROF2(ss))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Sector size not power of 2: %s", t);
|
||||
|
||||
*ret = ss;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int parse_range(const char *t, unsigned *lower, unsigned *upper) {
|
||||
_cleanup_free_ char *word = NULL;
|
||||
unsigned l, u;
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ int parse_ifindex(const char *s);
|
|||
int parse_mtu(int family, const char *s, uint32_t *ret);
|
||||
|
||||
int parse_size(const char *t, uint64_t base, uint64_t *size);
|
||||
int parse_sector_size(const char *t, uint64_t *ret);
|
||||
int parse_range(const char *t, unsigned *lower, unsigned *upper);
|
||||
int parse_errno(const char *t);
|
||||
|
||||
|
|
|
|||
|
|
@ -523,17 +523,17 @@ char* path_extend_internal(char **x, ...) {
|
|||
va_list ap;
|
||||
bool slash;
|
||||
|
||||
/* Joins all listed strings until the sentinel and places a "/" between them unless the strings end/begin
|
||||
* already with one so that it is unnecessary. Note that slashes which are already duplicate won't be
|
||||
* removed. The string returned is hence always equal to or longer than the sum of the lengths of each
|
||||
* individual string.
|
||||
/* Joins all listed strings until the sentinel and places a "/" between them unless the strings
|
||||
* end/begin already with one so that it is unnecessary. Note that slashes which are already
|
||||
* duplicate won't be removed. The string returned is hence always equal to or longer than the sum of
|
||||
* the lengths of the individual strings.
|
||||
*
|
||||
* The first argument may be an already allocated string that is extended via realloc() if
|
||||
* non-NULL. path_extend() and path_join() are macro wrappers around this function, making use of the
|
||||
* first parameter to distinguish the two operations.
|
||||
*
|
||||
* Note: any listed empty string is simply skipped. This can be useful for concatenating strings of which some
|
||||
* are optional.
|
||||
* Note: any listed empty string is simply skipped. This can be useful for concatenating strings of
|
||||
* which some are optional.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
|
|
@ -592,7 +592,7 @@ char* path_extend_internal(char **x, ...) {
|
|||
|
||||
#if 0 /* NM_IGNORED */
|
||||
static int check_x_access(const char *path, int *ret_fd) {
|
||||
_cleanup_close_ int fd = -1;
|
||||
_cleanup_close_ int fd = -EBADF;
|
||||
int r;
|
||||
|
||||
/* We need to use O_PATH because there may be executables for which we have only exec
|
||||
|
|
@ -620,7 +620,7 @@ static int check_x_access(const char *path, int *ret_fd) {
|
|||
}
|
||||
|
||||
static int find_executable_impl(const char *name, const char *root, char **ret_filename, int *ret_fd) {
|
||||
_cleanup_close_ int fd = -1;
|
||||
_cleanup_close_ int fd = -EBADF;
|
||||
_cleanup_free_ char *path_name = NULL;
|
||||
int r;
|
||||
|
||||
|
|
@ -1171,31 +1171,35 @@ bool path_is_normalized(const char *p) {
|
|||
}
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
char *file_in_same_dir(const char *path, const char *filename) {
|
||||
char *e, *ret;
|
||||
size_t k;
|
||||
int file_in_same_dir(const char *path, const char *filename, char **ret) {
|
||||
_cleanup_free_ char *b = NULL;
|
||||
int r;
|
||||
|
||||
assert(path);
|
||||
assert(filename);
|
||||
assert(ret);
|
||||
|
||||
/* This removes the last component of path and appends
|
||||
* filename, unless the latter is absolute anyway or the
|
||||
* former isn't */
|
||||
/* This removes the last component of path and appends filename, unless the latter is absolute anyway
|
||||
* or the former isn't */
|
||||
|
||||
if (path_is_absolute(filename))
|
||||
return strdup(filename);
|
||||
b = strdup(filename);
|
||||
else {
|
||||
_cleanup_free_ char *dn = NULL;
|
||||
|
||||
e = strrchr(path, '/');
|
||||
if (!e)
|
||||
return strdup(filename);
|
||||
r = path_extract_directory(path, &dn);
|
||||
if (r == -EDESTADDRREQ) /* no path prefix */
|
||||
b = strdup(filename);
|
||||
else if (r < 0)
|
||||
return r;
|
||||
else
|
||||
b = path_join(dn, filename);
|
||||
}
|
||||
if (!b)
|
||||
return -ENOMEM;
|
||||
|
||||
k = strlen(filename);
|
||||
ret = new(char, (e + 1 - path) + k + 1);
|
||||
if (!ret)
|
||||
return NULL;
|
||||
|
||||
memcpy(mempcpy(ret, path, e + 1 - path), filename, k + 1);
|
||||
return ret;
|
||||
*ret = TAKE_PTR(b);
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool hidden_or_backup_file(const char *filename) {
|
||||
|
|
|
|||
|
|
@ -132,6 +132,7 @@ int fsck_exists_for_fstype(const char *fstype);
|
|||
|
||||
/* Similar to path_join(), but only works for two components, and only the first one may be NULL and returns
|
||||
* an alloca() buffer, or possibly a const pointer into the path parameter. */
|
||||
/* DEPRECATED: use path_join() instead */
|
||||
#define prefix_roota(root, path) \
|
||||
({ \
|
||||
const char* _path = (path), *_root = (root), *_ret; \
|
||||
|
|
@ -171,7 +172,7 @@ static inline bool path_is_safe(const char *p) {
|
|||
}
|
||||
bool path_is_normalized(const char *p) _pure_;
|
||||
|
||||
char *file_in_same_dir(const char *path, const char *filename);
|
||||
int file_in_same_dir(const char *path, const char *filename, char **ret);
|
||||
|
||||
bool hidden_or_backup_file(const char *filename) _pure_;
|
||||
|
||||
|
|
|
|||
|
|
@ -255,7 +255,7 @@ int prioq_remove(Prioq *q, void *data, unsigned *idx) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
int prioq_reshuffle(Prioq *q, void *data, unsigned *idx) {
|
||||
void prioq_reshuffle(Prioq *q, void *data, unsigned *idx) {
|
||||
struct prioq_item *i;
|
||||
unsigned k;
|
||||
|
||||
|
|
@ -263,12 +263,11 @@ int prioq_reshuffle(Prioq *q, void *data, unsigned *idx) {
|
|||
|
||||
i = find_item(q, data, idx);
|
||||
if (!i)
|
||||
return 0;
|
||||
return;
|
||||
|
||||
k = i - q->items;
|
||||
k = shuffle_down(q, k);
|
||||
shuffle_up(q, k);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void *prioq_peek_by_index(Prioq *q, unsigned idx) {
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ int prioq_ensure_allocated(Prioq **q, compare_func_t compare_func);
|
|||
int prioq_put(Prioq *q, void *data, unsigned *idx);
|
||||
int prioq_ensure_put(Prioq **q, compare_func_t compare_func, void *data, unsigned *idx);
|
||||
int prioq_remove(Prioq *q, void *data, unsigned *idx);
|
||||
int prioq_reshuffle(Prioq *q, void *data, unsigned *idx);
|
||||
void prioq_reshuffle(Prioq *q, void *data, unsigned *idx);
|
||||
|
||||
void *prioq_peek_by_index(Prioq *q, unsigned idx) _pure_;
|
||||
static inline void *prioq_peek(Prioq *q) {
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@
|
|||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/personality.h>
|
||||
#include <sys/prctl.h>
|
||||
|
|
@ -26,19 +25,25 @@
|
|||
|
||||
#include "alloc-util.h"
|
||||
#include "architecture.h"
|
||||
#include "argv-util.h"
|
||||
#include "env-file.h"
|
||||
#include "env-util.h"
|
||||
#include "errno-util.h"
|
||||
#include "escape.h"
|
||||
#include "fd-util.h"
|
||||
#include "fileio.h"
|
||||
#include "fs-util.h"
|
||||
#include "hostname-util.h"
|
||||
#include "locale-util.h"
|
||||
#include "log.h"
|
||||
#include "macro.h"
|
||||
#include "memory-util.h"
|
||||
#include "missing_sched.h"
|
||||
#include "missing_syscall.h"
|
||||
#include "mountpoint-util.h"
|
||||
#include "namespace-util.h"
|
||||
#include "nulstr-util.h"
|
||||
#include "parse-util.h"
|
||||
#include "path-util.h"
|
||||
#include "process-util.h"
|
||||
#include "raw-clone.h"
|
||||
|
|
@ -259,151 +264,47 @@ int get_process_cmdline(pid_t pid, size_t max_columns, ProcessCmdlineFlags flags
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int update_argv(const char name[], size_t l) {
|
||||
static int can_do = -1;
|
||||
|
||||
if (can_do == 0)
|
||||
return 0;
|
||||
can_do = false; /* We'll set it to true only if the whole process works */
|
||||
|
||||
/* Let's not bother with this if we don't have euid == 0. Strictly speaking we should check for the
|
||||
* CAP_SYS_RESOURCE capability which is independent of the euid. In our own code the capability generally is
|
||||
* present only for euid == 0, hence let's use this as quick bypass check, to avoid calling mmap() if
|
||||
* PR_SET_MM_ARG_{START,END} fails with EPERM later on anyway. After all geteuid() is dead cheap to call, but
|
||||
* mmap() is not. */
|
||||
if (geteuid() != 0)
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EPERM),
|
||||
"Skipping PR_SET_MM, as we don't have privileges.");
|
||||
|
||||
static size_t mm_size = 0;
|
||||
static char *mm = NULL;
|
||||
int container_get_leader(const char *machine, pid_t *pid) {
|
||||
_cleanup_free_ char *s = NULL, *class = NULL;
|
||||
const char *p;
|
||||
pid_t leader;
|
||||
int r;
|
||||
|
||||
if (mm_size < l+1) {
|
||||
size_t nn_size;
|
||||
char *nn;
|
||||
assert(machine);
|
||||
assert(pid);
|
||||
|
||||
nn_size = PAGE_ALIGN(l+1);
|
||||
nn = mmap(NULL, nn_size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
|
||||
if (nn == MAP_FAILED)
|
||||
return log_debug_errno(errno, "mmap() failed: %m");
|
||||
|
||||
strncpy(nn, name, nn_size);
|
||||
|
||||
/* Now, let's tell the kernel about this new memory */
|
||||
if (prctl(PR_SET_MM, PR_SET_MM_ARG_START, (unsigned long) nn, 0, 0) < 0) {
|
||||
if (ERRNO_IS_PRIVILEGE(errno))
|
||||
return log_debug_errno(errno, "PR_SET_MM_ARG_START failed: %m");
|
||||
|
||||
/* HACK: prctl() API is kind of dumb on this point. The existing end address may already be
|
||||
* below the desired start address, in which case the kernel may have kicked this back due
|
||||
* to a range-check failure (see linux/kernel/sys.c:validate_prctl_map() to see this in
|
||||
* action). The proper solution would be to have a prctl() API that could set both start+end
|
||||
* simultaneously, or at least let us query the existing address to anticipate this condition
|
||||
* and respond accordingly. For now, we can only guess at the cause of this failure and try
|
||||
* a workaround--which will briefly expand the arg space to something potentially huge before
|
||||
* resizing it to what we want. */
|
||||
log_debug_errno(errno, "PR_SET_MM_ARG_START failed, attempting PR_SET_MM_ARG_END hack: %m");
|
||||
|
||||
if (prctl(PR_SET_MM, PR_SET_MM_ARG_END, (unsigned long) nn + l + 1, 0, 0) < 0) {
|
||||
r = log_debug_errno(errno, "PR_SET_MM_ARG_END hack failed, proceeding without: %m");
|
||||
(void) munmap(nn, nn_size);
|
||||
return r;
|
||||
}
|
||||
|
||||
if (prctl(PR_SET_MM, PR_SET_MM_ARG_START, (unsigned long) nn, 0, 0) < 0)
|
||||
return log_debug_errno(errno, "PR_SET_MM_ARG_START still failed, proceeding without: %m");
|
||||
} else {
|
||||
/* And update the end pointer to the new end, too. If this fails, we don't really know what
|
||||
* to do, it's pretty unlikely that we can rollback, hence we'll just accept the failure,
|
||||
* and continue. */
|
||||
if (prctl(PR_SET_MM, PR_SET_MM_ARG_END, (unsigned long) nn + l + 1, 0, 0) < 0)
|
||||
log_debug_errno(errno, "PR_SET_MM_ARG_END failed, proceeding without: %m");
|
||||
}
|
||||
|
||||
if (mm)
|
||||
(void) munmap(mm, mm_size);
|
||||
|
||||
mm = nn;
|
||||
mm_size = nn_size;
|
||||
} else {
|
||||
strncpy(mm, name, mm_size);
|
||||
|
||||
/* Update the end pointer, continuing regardless of any failure. */
|
||||
if (prctl(PR_SET_MM, PR_SET_MM_ARG_END, (unsigned long) mm + l + 1, 0, 0) < 0)
|
||||
log_debug_errno(errno, "PR_SET_MM_ARG_END failed, proceeding without: %m");
|
||||
if (streq(machine, ".host")) {
|
||||
*pid = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
can_do = true;
|
||||
if (!hostname_is_valid(machine, 0))
|
||||
return -EINVAL;
|
||||
|
||||
p = strjoina("/run/systemd/machines/", machine);
|
||||
r = parse_env_file(NULL, p,
|
||||
"LEADER", &s,
|
||||
"CLASS", &class);
|
||||
if (r == -ENOENT)
|
||||
return -EHOSTDOWN;
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (!s)
|
||||
return -EIO;
|
||||
|
||||
if (!streq_ptr(class, "container"))
|
||||
return -EIO;
|
||||
|
||||
r = parse_pid(s, &leader);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (leader <= 1)
|
||||
return -EIO;
|
||||
|
||||
*pid = leader;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rename_process(const char name[]) {
|
||||
bool truncated = false;
|
||||
|
||||
/* This is a like a poor man's setproctitle(). It changes the comm field, argv[0], and also the glibc's
|
||||
* internally used name of the process. For the first one a limit of 16 chars applies; to the second one in
|
||||
* many cases one of 10 (i.e. length of "/sbin/init") — however if we have CAP_SYS_RESOURCES it is unbounded;
|
||||
* to the third one 7 (i.e. the length of "systemd". If you pass a longer string it will likely be
|
||||
* truncated.
|
||||
*
|
||||
* Returns 0 if a name was set but truncated, > 0 if it was set but not truncated. */
|
||||
|
||||
if (isempty(name))
|
||||
return -EINVAL; /* let's not confuse users unnecessarily with an empty name */
|
||||
|
||||
if (!is_main_thread())
|
||||
return -EPERM; /* Let's not allow setting the process name from other threads than the main one, as we
|
||||
* cache things without locking, and we make assumptions that PR_SET_NAME sets the
|
||||
* process name that isn't correct on any other threads */
|
||||
|
||||
size_t l = strlen(name);
|
||||
|
||||
/* First step, change the comm field. The main thread's comm is identical to the process comm. This means we
|
||||
* can use PR_SET_NAME, which sets the thread name for the calling thread. */
|
||||
if (prctl(PR_SET_NAME, name) < 0)
|
||||
log_debug_errno(errno, "PR_SET_NAME failed: %m");
|
||||
if (l >= TASK_COMM_LEN) /* Linux userspace process names can be 15 chars at max */
|
||||
truncated = true;
|
||||
|
||||
/* Second step, change glibc's ID of the process name. */
|
||||
if (program_invocation_name) {
|
||||
size_t k;
|
||||
|
||||
k = strlen(program_invocation_name);
|
||||
strncpy(program_invocation_name, name, k);
|
||||
if (l > k)
|
||||
truncated = true;
|
||||
}
|
||||
|
||||
/* Third step, completely replace the argv[] array the kernel maintains for us. This requires privileges, but
|
||||
* has the advantage that the argv[] array is exactly what we want it to be, and not filled up with zeros at
|
||||
* the end. This is the best option for changing /proc/self/cmdline. */
|
||||
(void) update_argv(name, l);
|
||||
|
||||
/* Fourth step: in all cases we'll also update the original argv[], so that our own code gets it right too if
|
||||
* it still looks here */
|
||||
if (saved_argc > 0) {
|
||||
if (saved_argv[0]) {
|
||||
size_t k;
|
||||
|
||||
k = strlen(saved_argv[0]);
|
||||
strncpy(saved_argv[0], name, k);
|
||||
if (l > k)
|
||||
truncated = true;
|
||||
}
|
||||
|
||||
for (int i = 1; i < saved_argc; i++) {
|
||||
if (!saved_argv[i])
|
||||
break;
|
||||
|
||||
memzero(saved_argv[i], strlen(saved_argv[i]));
|
||||
}
|
||||
}
|
||||
|
||||
return !truncated;
|
||||
}
|
||||
|
||||
int is_kernel_thread(pid_t pid) {
|
||||
_cleanup_free_ char *line = NULL;
|
||||
unsigned long long flags;
|
||||
|
|
@ -870,6 +771,23 @@ void sigterm_wait(pid_t pid) {
|
|||
(void) wait_for_terminate(pid, NULL);
|
||||
}
|
||||
|
||||
void sigkill_nowait(pid_t pid) {
|
||||
assert(pid > 1);
|
||||
|
||||
(void) kill(pid, SIGKILL);
|
||||
}
|
||||
|
||||
void sigkill_nowaitp(pid_t *pid) {
|
||||
PROTECT_ERRNO;
|
||||
|
||||
if (!pid)
|
||||
return;
|
||||
if (*pid <= 1)
|
||||
return;
|
||||
|
||||
sigkill_nowait(*pid);
|
||||
}
|
||||
|
||||
int kill_and_sigcont(pid_t pid, int sig) {
|
||||
int r;
|
||||
|
||||
|
|
@ -1362,15 +1280,26 @@ int safe_fork_full(
|
|||
}
|
||||
|
||||
if (FLAGS_SET(flags, FORK_NEW_MOUNTNS | FORK_MOUNTNS_SLAVE)) {
|
||||
|
||||
/* Optionally, make sure we never propagate mounts to the host. */
|
||||
|
||||
if (mount(NULL, "/", NULL, MS_SLAVE | MS_REC, NULL) < 0) {
|
||||
log_full_errno(prio, errno, "Failed to remount root directory as MS_SLAVE: %m");
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
if (FLAGS_SET(flags, FORK_PRIVATE_TMP)) {
|
||||
assert(FLAGS_SET(flags, FORK_NEW_MOUNTNS));
|
||||
|
||||
/* Optionally, overmount new tmpfs instance on /tmp/. */
|
||||
r = mount_nofollow("tmpfs", "/tmp", "tmpfs",
|
||||
MS_NOSUID|MS_NODEV,
|
||||
"mode=01777" TMPFS_LIMITS_RUN);
|
||||
if (r < 0) {
|
||||
log_full_errno(prio, r, "Failed to overmount /tmp/: %m");
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & FORK_CLOSE_ALL_FDS) {
|
||||
/* Close the logs here in case it got reopened above, as close_all_fds() would close them for us */
|
||||
log_close();
|
||||
|
|
@ -1382,6 +1311,14 @@ int safe_fork_full(
|
|||
}
|
||||
}
|
||||
|
||||
if (flags & FORK_CLOEXEC_OFF) {
|
||||
r = fd_cloexec_many(except_fds, n_except_fds, false);
|
||||
if (r < 0) {
|
||||
log_full_errno(prio, r, "Failed to turn off O_CLOEXEC on file descriptors: %m");
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
/* When we were asked to reopen the logs, do so again now */
|
||||
if (flags & FORK_REOPEN_LOG) {
|
||||
log_open();
|
||||
|
|
@ -1529,6 +1466,20 @@ int pidfd_get_pid(int fd, pid_t *ret) {
|
|||
return parse_pid(p, ret);
|
||||
}
|
||||
|
||||
int pidfd_verify_pid(int pidfd, pid_t pid) {
|
||||
pid_t current_pid;
|
||||
int r;
|
||||
|
||||
assert(pidfd >= 0);
|
||||
assert(pid > 0);
|
||||
|
||||
r = pidfd_get_pid(pidfd, ¤t_pid);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return current_pid != pid ? -ESRCH : 0;
|
||||
}
|
||||
|
||||
static int rlimit_to_nice(rlim_t limit) {
|
||||
if (limit <= 1)
|
||||
return PRIO_MAX-1; /* i.e. 19 */
|
||||
|
|
@ -1585,40 +1536,6 @@ int setpriority_closest(int priority) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
bool invoked_as(char *argv[], const char *token) {
|
||||
if (!argv || isempty(argv[0]))
|
||||
return false;
|
||||
|
||||
if (isempty(token))
|
||||
return false;
|
||||
|
||||
return strstr(last_path_component(argv[0]), token);
|
||||
}
|
||||
|
||||
bool invoked_by_systemd(void) {
|
||||
int r;
|
||||
|
||||
/* If the process is directly executed by PID1 (e.g. ExecStart= or generator), systemd-importd,
|
||||
* or systemd-homed, then $SYSTEMD_EXEC_PID= is set, and read the command line. */
|
||||
const char *e = getenv("SYSTEMD_EXEC_PID");
|
||||
if (!e)
|
||||
return false;
|
||||
|
||||
if (streq(e, "*"))
|
||||
/* For testing. */
|
||||
return true;
|
||||
|
||||
pid_t p;
|
||||
r = parse_pid(e, &p);
|
||||
if (r < 0) {
|
||||
/* We know that systemd sets the variable correctly. Something else must have set it. */
|
||||
log_debug_errno(r, "Failed to parse \"SYSTEMD_EXEC_PID=%s\", ignoring: %m", e);
|
||||
return false;
|
||||
}
|
||||
|
||||
return getpid_cached() == p;
|
||||
}
|
||||
|
||||
_noreturn_ void freeze(void) {
|
||||
log_close();
|
||||
|
||||
|
|
@ -1640,31 +1557,6 @@ _noreturn_ void freeze(void) {
|
|||
pause();
|
||||
}
|
||||
|
||||
bool argv_looks_like_help(int argc, char **argv) {
|
||||
char **l;
|
||||
|
||||
/* Scans the command line for indications the user asks for help. This is supposed to be called by
|
||||
* tools that do not implement getopt() style command line parsing because they are not primarily
|
||||
* user-facing. Detects four ways of asking for help:
|
||||
*
|
||||
* 1. Passing zero arguments
|
||||
* 2. Passing "help" as first argument
|
||||
* 3. Passing --help as any argument
|
||||
* 4. Passing -h as any argument
|
||||
*/
|
||||
|
||||
if (argc <= 1)
|
||||
return true;
|
||||
|
||||
if (streq_ptr(argv[1], "help"))
|
||||
return true;
|
||||
|
||||
l = strv_skip(argv, 1);
|
||||
|
||||
return strv_contains(l, "--help") ||
|
||||
strv_contains(l, "-h");
|
||||
}
|
||||
|
||||
static const char *const sigchld_code_table[] = {
|
||||
[CLD_EXITED] = "exited",
|
||||
[CLD_KILLED] = "killed",
|
||||
|
|
|
|||
|
|
@ -50,6 +50,8 @@ int get_process_environ(pid_t pid, char **ret);
|
|||
int get_process_ppid(pid_t pid, pid_t *ret);
|
||||
int get_process_umask(pid_t pid, mode_t *ret);
|
||||
|
||||
int container_get_leader(const char *machine, pid_t *pid);
|
||||
|
||||
int wait_for_terminate(pid_t pid, siginfo_t *status);
|
||||
|
||||
typedef enum WaitFlags {
|
||||
|
|
@ -66,10 +68,11 @@ int wait_for_terminate_with_timeout(pid_t pid, usec_t timeout);
|
|||
void sigkill_wait(pid_t pid);
|
||||
void sigkill_waitp(pid_t *pid);
|
||||
void sigterm_wait(pid_t pid);
|
||||
void sigkill_nowait(pid_t pid);
|
||||
void sigkill_nowaitp(pid_t *pid);
|
||||
|
||||
int kill_and_sigcont(pid_t pid, int sig);
|
||||
|
||||
int rename_process(const char name[]);
|
||||
int is_kernel_thread(pid_t pid);
|
||||
|
||||
int getenv_for_pid(pid_t pid, const char *field, char **_value);
|
||||
|
|
@ -148,10 +151,12 @@ typedef enum ForkFlags {
|
|||
FORK_WAIT = 1 << 7, /* Wait until child exited */
|
||||
FORK_NEW_MOUNTNS = 1 << 8, /* Run child in its own mount namespace */
|
||||
FORK_MOUNTNS_SLAVE = 1 << 9, /* Make child's mount namespace MS_SLAVE */
|
||||
FORK_RLIMIT_NOFILE_SAFE = 1 << 10, /* Set RLIMIT_NOFILE soft limit to 1K for select() compat */
|
||||
FORK_STDOUT_TO_STDERR = 1 << 11, /* Make stdout a copy of stderr */
|
||||
FORK_FLUSH_STDIO = 1 << 12, /* fflush() stdout (and stderr) before forking */
|
||||
FORK_NEW_USERNS = 1 << 13, /* Run child in its own user namespace */
|
||||
FORK_PRIVATE_TMP = 1 << 10, /* Mount new /tmp/ in the child (combine with FORK_NEW_MOUNTNS!) */
|
||||
FORK_RLIMIT_NOFILE_SAFE = 1 << 11, /* Set RLIMIT_NOFILE soft limit to 1K for select() compat */
|
||||
FORK_STDOUT_TO_STDERR = 1 << 12, /* Make stdout a copy of stderr */
|
||||
FORK_FLUSH_STDIO = 1 << 13, /* fflush() stdout (and stderr) before forking */
|
||||
FORK_NEW_USERNS = 1 << 14, /* Run child in its own user namespace */
|
||||
FORK_CLOEXEC_OFF = 1 << 15, /* In the child: turn off O_CLOEXEC on all fds in except_fds[] */
|
||||
} ForkFlags;
|
||||
|
||||
int safe_fork_full(const char *name, const int except_fds[], size_t n_except_fds, ForkFlags flags, pid_t *ret_pid);
|
||||
|
|
@ -177,23 +182,12 @@ int get_oom_score_adjust(int *ret);
|
|||
|
||||
assert_cc(TASKS_MAX <= (unsigned long) PID_T_MAX);
|
||||
|
||||
/* Like TAKE_PTR() but for child PIDs, resetting them to 0 */
|
||||
#define TAKE_PID(pid) \
|
||||
({ \
|
||||
pid_t *_ppid_ = &(pid); \
|
||||
pid_t _pid_ = *_ppid_; \
|
||||
*_ppid_ = 0; \
|
||||
_pid_; \
|
||||
})
|
||||
/* Like TAKE_PTR() but for pid_t, resetting them to 0 */
|
||||
#define TAKE_PID(pid) TAKE_GENERIC(pid, pid_t, 0)
|
||||
|
||||
int pidfd_get_pid(int fd, pid_t *ret);
|
||||
int pidfd_verify_pid(int pidfd, pid_t pid);
|
||||
|
||||
int setpriority_closest(int priority);
|
||||
|
||||
bool invoked_as(char *argv[], const char *token);
|
||||
|
||||
bool invoked_by_systemd(void);
|
||||
|
||||
_noreturn_ void freeze(void);
|
||||
|
||||
bool argv_looks_like_help(int argc, char **argv);
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ static void fallback_random_bytes(void *p, size_t n) {
|
|||
|
||||
void random_bytes(void *p, size_t n) {
|
||||
static bool have_getrandom = true, have_grndinsecure = true;
|
||||
_cleanup_close_ int fd = -1;
|
||||
_cleanup_close_ int fd = -EBADF;
|
||||
|
||||
if (n == 0)
|
||||
return;
|
||||
|
|
@ -119,7 +119,7 @@ void random_bytes(void *p, size_t n) {
|
|||
|
||||
int crypto_random_bytes(void *p, size_t n) {
|
||||
static bool have_getrandom = true, seen_initialized = false;
|
||||
_cleanup_close_ int fd = -1;
|
||||
_cleanup_close_ int fd = -EBADF;
|
||||
|
||||
if (n == 0)
|
||||
return 0;
|
||||
|
|
@ -147,7 +147,7 @@ int crypto_random_bytes(void *p, size_t n) {
|
|||
}
|
||||
|
||||
if (!seen_initialized) {
|
||||
_cleanup_close_ int ready_fd = -1;
|
||||
_cleanup_close_ int ready_fd = -EBADF;
|
||||
int r;
|
||||
|
||||
ready_fd = open("/dev/random", O_RDONLY|O_CLOEXEC|O_NOCTTY);
|
||||
|
|
@ -190,7 +190,7 @@ size_t random_pool_size(void) {
|
|||
}
|
||||
|
||||
int random_write_entropy(int fd, const void *seed, size_t size, bool credit) {
|
||||
_cleanup_close_ int opened_fd = -1;
|
||||
_cleanup_close_ int opened_fd = -EBADF;
|
||||
int r;
|
||||
|
||||
assert(seed || size == 0);
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ static inline uint32_t random_u32(void) {
|
|||
/* Some limits on the pool sizes when we deal with the kernel random pool */
|
||||
#define RANDOM_POOL_SIZE_MIN 32U
|
||||
#define RANDOM_POOL_SIZE_MAX (10U*1024U*1024U)
|
||||
#define RANDOM_EFI_SEED_SIZE 32U
|
||||
|
||||
size_t random_pool_size(void);
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
bool ratelimit_below(RateLimit *r) {
|
||||
usec_t ts;
|
||||
bool good = false;
|
||||
|
||||
assert(r);
|
||||
|
||||
|
|
@ -26,18 +27,12 @@ bool ratelimit_below(RateLimit *r) {
|
|||
|
||||
/* Reset counter */
|
||||
r->num = 0;
|
||||
goto good;
|
||||
}
|
||||
|
||||
if (r->num < r->burst)
|
||||
goto good;
|
||||
good = true;
|
||||
} else if (r->num < r->burst)
|
||||
good = true;
|
||||
|
||||
r->num++;
|
||||
return false;
|
||||
|
||||
good:
|
||||
r->num++;
|
||||
return true;
|
||||
return good;
|
||||
}
|
||||
|
||||
unsigned ratelimit_num_dropped(RateLimit *r) {
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
#include "errno-util.h"
|
||||
#include "macro.h"
|
||||
#include "missing_syscall.h"
|
||||
#include "parse-util.h"
|
||||
#include "signal-util.h"
|
||||
#include "stdio-util.h"
|
||||
|
|
@ -285,4 +286,21 @@ int pop_pending_signal_internal(int sig, ...) {
|
|||
|
||||
return r; /* Returns the signal popped */
|
||||
}
|
||||
|
||||
void propagate_signal(int sig, siginfo_t *siginfo) {
|
||||
pid_t p;
|
||||
|
||||
/* To be called from a signal handler. Will raise the same signal again, in our process + in our threads.
|
||||
*
|
||||
* Note that we use raw_getpid() instead of getpid_cached(). We might have forked with raw_clone()
|
||||
* earlier (see PID 1), and hence let's go to the raw syscall here. In particular as this is not
|
||||
* performance sensitive code.
|
||||
*
|
||||
* Note that we use kill() rather than raise() as fallback, for similar reasons. */
|
||||
|
||||
p = raw_getpid();
|
||||
|
||||
if (rt_tgsigqueueinfo(p, gettid(), sig, siginfo) < 0)
|
||||
assert_se(kill(p, sig) >= 0);
|
||||
}
|
||||
#endif /* NM_IGNORED */
|
||||
|
|
|
|||
|
|
@ -65,3 +65,5 @@ int signal_is_blocked(int sig);
|
|||
|
||||
int pop_pending_signal_internal(int sig, ...);
|
||||
#define pop_pending_signal(...) pop_pending_signal_internal(__VA_ARGS__, -1)
|
||||
|
||||
void propagate_signal(int sig, siginfo_t *siginfo);
|
||||
|
|
|
|||
|
|
@ -1056,7 +1056,7 @@ ssize_t receive_one_fd_iov(
|
|||
if (found)
|
||||
*ret_fd = *(int*) CMSG_DATA(found);
|
||||
else
|
||||
*ret_fd = -1;
|
||||
*ret_fd = -EBADF;
|
||||
|
||||
return k;
|
||||
}
|
||||
|
|
@ -1440,7 +1440,7 @@ int socket_get_mtu(int fd, int af, size_t *ret) {
|
|||
#endif /* NM_IGNORED */
|
||||
|
||||
int connect_unix_path(int fd, int dir_fd, const char *path) {
|
||||
_cleanup_close_ int inode_fd = -1;
|
||||
_cleanup_close_ int inode_fd = -EBADF;
|
||||
union sockaddr_union sa = {
|
||||
.un.sun_family = AF_UNIX,
|
||||
};
|
||||
|
|
@ -1486,3 +1486,73 @@ int connect_unix_path(int fd, int dir_fd, const char *path) {
|
|||
|
||||
return RET_NERRNO(connect(fd, &sa.sa, salen));
|
||||
}
|
||||
|
||||
int socket_address_parse_unix(SocketAddress *ret_address, const char *s) {
|
||||
struct sockaddr_un un;
|
||||
int r;
|
||||
|
||||
assert(ret_address);
|
||||
assert(s);
|
||||
|
||||
if (!IN_SET(*s, '/', '@'))
|
||||
return -EPROTO;
|
||||
|
||||
r = sockaddr_un_set_path(&un, s);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
*ret_address = (SocketAddress) {
|
||||
.sockaddr.un = un,
|
||||
.size = r,
|
||||
};
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
int socket_address_parse_vsock(SocketAddress *ret_address, const char *s) {
|
||||
/* AF_VSOCK socket in vsock:cid:port notation */
|
||||
_cleanup_free_ char *n = NULL;
|
||||
char *e, *cid_start;
|
||||
unsigned port, cid;
|
||||
int r;
|
||||
|
||||
assert(ret_address);
|
||||
assert(s);
|
||||
|
||||
cid_start = startswith(s, "vsock:");
|
||||
if (!cid_start)
|
||||
return -EPROTO;
|
||||
|
||||
e = strchr(cid_start, ':');
|
||||
if (!e)
|
||||
return -EINVAL;
|
||||
|
||||
r = safe_atou(e+1, &port);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
n = strndup(cid_start, e - cid_start);
|
||||
if (!n)
|
||||
return -ENOMEM;
|
||||
|
||||
if (isempty(n))
|
||||
cid = VMADDR_CID_ANY;
|
||||
else {
|
||||
r = safe_atou(n, &cid);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
*ret_address = (SocketAddress) {
|
||||
.sockaddr.vm = {
|
||||
.svm_cid = cid,
|
||||
.svm_family = AF_VSOCK,
|
||||
.svm_port = port,
|
||||
},
|
||||
.size = sizeof(struct sockaddr_vm),
|
||||
};
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* NM_IGNORED */
|
||||
|
|
|
|||
|
|
@ -177,15 +177,17 @@ int flush_accept(int fd);
|
|||
#define CMSG_FOREACH(cmsg, mh) \
|
||||
for ((cmsg) = CMSG_FIRSTHDR(mh); (cmsg); (cmsg) = CMSG_NXTHDR((mh), (cmsg)))
|
||||
|
||||
#define CMSG_TYPED_DATA(cmsg, type) \
|
||||
({ \
|
||||
struct cmsghdr *_cmsg = cmsg; \
|
||||
_cmsg ? CAST_ALIGN_PTR(type, CMSG_DATA(_cmsg)) : (type*) NULL; \
|
||||
})
|
||||
|
||||
struct cmsghdr* cmsg_find(struct msghdr *mh, int level, int type, socklen_t length);
|
||||
|
||||
/* Type-safe, dereferencing version of cmsg_find() */
|
||||
#define CMSG_FIND_DATA(mh, level, type, ctype) \
|
||||
({ \
|
||||
struct cmsghdr *_found; \
|
||||
_found = cmsg_find(mh, level, type, CMSG_LEN(sizeof(ctype))); \
|
||||
(ctype*) (_found ? CMSG_DATA(_found) : NULL); \
|
||||
})
|
||||
#define CMSG_FIND_DATA(mh, level, type, ctype) \
|
||||
CMSG_TYPED_DATA(cmsg_find(mh, level, type, CMSG_LEN(sizeof(ctype))), ctype)
|
||||
|
||||
/* Resolves to a type that can carry cmsghdr structures. Make sure things are properly aligned, i.e. the type
|
||||
* itself is placed properly in memory and the size is also aligned to what's appropriate for "cmsghdr"
|
||||
|
|
@ -338,3 +340,9 @@ int socket_get_mtu(int fd, int af, size_t *ret);
|
|||
#define UCRED_INVALID { .pid = 0, .uid = UID_INVALID, .gid = GID_INVALID }
|
||||
|
||||
int connect_unix_path(int fd, int dir_fd, const char *path);
|
||||
|
||||
/* Parses AF_UNIX and AF_VSOCK addresses. AF_INET[6] require some netlink calls, so it cannot be in
|
||||
* src/basic/ and is done from 'socket_local_address from src/shared/. Return -EPROTO in case of
|
||||
* protocol mismatch. */
|
||||
int socket_address_parse_unix(SocketAddress *ret_address, const char *s);
|
||||
int socket_address_parse_vsock(SocketAddress *ret_address, const char *s);
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
#include "fileio.h"
|
||||
#include "filesystems.h"
|
||||
#include "fs-util.h"
|
||||
#include "hash-funcs.h"
|
||||
#include "macro.h"
|
||||
#include "missing_fs.h"
|
||||
#include "missing_magic.h"
|
||||
|
|
@ -69,7 +70,7 @@ int is_device_node(const char *path) {
|
|||
}
|
||||
|
||||
int dir_is_empty_at(int dir_fd, const char *path, bool ignore_hidden_or_backup) {
|
||||
_cleanup_close_ int fd = -1;
|
||||
_cleanup_close_ int fd = -EBADF;
|
||||
struct dirent *buf;
|
||||
size_t m;
|
||||
|
||||
|
|
@ -167,25 +168,36 @@ int null_or_empty_fd(int fd) {
|
|||
return null_or_empty(&st);
|
||||
}
|
||||
|
||||
int path_is_read_only_fs(const char *path) {
|
||||
static int fd_is_read_only_fs(int fd) {
|
||||
struct statvfs st;
|
||||
|
||||
assert(path);
|
||||
assert(fd >= 0);
|
||||
|
||||
if (statvfs(path, &st) < 0)
|
||||
if (fstatvfs(fd, &st) < 0)
|
||||
return -errno;
|
||||
|
||||
if (st.f_flag & ST_RDONLY)
|
||||
return true;
|
||||
|
||||
/* On NFS, statvfs() might not reflect whether we can actually
|
||||
* write to the remote share. Let's try again with
|
||||
* access(W_OK) which is more reliable, at least sometimes. */
|
||||
if (access(path, W_OK) < 0 && errno == EROFS)
|
||||
/* On NFS, fstatvfs() might not reflect whether we can actually write to the remote share. Let's try
|
||||
* again with access(W_OK) which is more reliable, at least sometimes. */
|
||||
if (access_fd(fd, W_OK) == -EROFS)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int path_is_read_only_fs(const char *path) {
|
||||
_cleanup_close_ int fd = -EBADF;
|
||||
|
||||
assert(path);
|
||||
|
||||
fd = open(path, O_CLOEXEC | O_PATH);
|
||||
if (fd < 0)
|
||||
return -errno;
|
||||
|
||||
return fd_is_read_only_fs(fd);
|
||||
}
|
||||
#endif /* NM_IGNORED */
|
||||
|
||||
int files_same(const char *filea, const char *fileb, int flags) {
|
||||
|
|
@ -454,4 +466,21 @@ int statx_fallback(int dfd, const char *path, int flags, unsigned mask, struct s
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void inode_hash_func(const struct stat *q, struct siphash *state) {
|
||||
siphash24_compress(&q->st_dev, sizeof(q->st_dev), state);
|
||||
siphash24_compress(&q->st_ino, sizeof(q->st_ino), state);
|
||||
}
|
||||
|
||||
int inode_compare_func(const struct stat *a, const struct stat *b) {
|
||||
int r;
|
||||
|
||||
r = CMP(a->st_dev, b->st_dev);
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
return CMP(a->st_ino, b->st_ino);
|
||||
}
|
||||
|
||||
DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(inode_hash_ops, struct stat, inode_hash_func, inode_compare_func, free);
|
||||
#endif /* NM_IGNORED */
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
#include "macro.h"
|
||||
#include "missing_stat.h"
|
||||
#include "siphash24.h"
|
||||
|
||||
int is_symlink(const char *path);
|
||||
int is_dir_full(int atfd, const char *fname, bool follow);
|
||||
|
|
@ -96,3 +97,7 @@ int statx_fallback(int dfd, const char *path, int flags, unsigned mask, struct s
|
|||
struct new_statx nsx; \
|
||||
} var
|
||||
#endif
|
||||
|
||||
void inode_hash_func(const struct stat *q, struct siphash *state);
|
||||
int inode_compare_func(const struct stat *a, const struct stat *b);
|
||||
extern const struct hash_ops inode_hash_ops;
|
||||
|
|
|
|||
|
|
@ -9,15 +9,20 @@
|
|||
#include <sys/types.h>
|
||||
|
||||
#include "macro.h"
|
||||
#include "memory-util.h"
|
||||
|
||||
#define snprintf_ok(buf, len, fmt, ...) \
|
||||
({ \
|
||||
char *_buf = (buf); \
|
||||
size_t _len = (len); \
|
||||
int _snpf = snprintf(_buf, _len, (fmt), ##__VA_ARGS__); \
|
||||
_snpf >= 0 && (size_t) _snpf < _len ? _buf : NULL; \
|
||||
})
|
||||
_printf_(3, 4)
|
||||
static inline char *snprintf_ok(char *buf, size_t len, const char *format, ...) {
|
||||
va_list ap;
|
||||
int r;
|
||||
|
||||
va_start(ap, format);
|
||||
DISABLE_WARNING_FORMAT_NONLITERAL;
|
||||
r = vsnprintf(buf, len, format, ap);
|
||||
REENABLE_WARNING;
|
||||
va_end(ap);
|
||||
|
||||
return r >= 0 && (size_t) r < len ? buf : NULL;
|
||||
}
|
||||
|
||||
#define xsprintf(buf, fmt, ...) \
|
||||
assert_message_se(snprintf_ok(buf, ELEMENTSOF(buf), fmt, ##__VA_ARGS__), "xsprintf: " #buf "[] must be big enough")
|
||||
|
|
@ -28,7 +33,7 @@ do { \
|
|||
size_t _i, _k; \
|
||||
/* See https://github.com/google/sanitizers/issues/992 */ \
|
||||
if (HAS_FEATURE_MEMORY_SANITIZER) \
|
||||
zero(_argtypes); \
|
||||
memset(_argtypes, 0, sizeof(_argtypes)); \
|
||||
_k = parse_printf_format((format), ELEMENTSOF(_argtypes), _argtypes); \
|
||||
assert(_k < ELEMENTSOF(_argtypes)); \
|
||||
for (_i = 0; _i < _k; _i++) { \
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@
|
|||
#include "strv.h"
|
||||
#include "terminal-util.h"
|
||||
#include "utf8.h"
|
||||
#include "util.h"
|
||||
|
||||
char* first_word(const char *s, const char *word) {
|
||||
size_t sl, wl;
|
||||
|
|
@ -739,6 +738,7 @@ char *strip_tab_ansi(char **ibuf, size_t *_isz, size_t highlight[2]) {
|
|||
|
||||
return *ibuf;
|
||||
}
|
||||
#endif /* NM_IGNORED */
|
||||
|
||||
char *strextend_with_separator_internal(char **x, const char *separator, ...) {
|
||||
size_t f, l, l_separator;
|
||||
|
|
@ -809,7 +809,6 @@ char *strextend_with_separator_internal(char **x, const char *separator, ...) {
|
|||
|
||||
return p;
|
||||
}
|
||||
#endif /* NM_IGNORED */
|
||||
|
||||
int strextendf_with_separator(char **x, const char *separator, const char *format, ...) {
|
||||
size_t m, a, l_separator;
|
||||
|
|
@ -1197,6 +1196,49 @@ char *string_replace_char(char *str, char old_char, char new_char) {
|
|||
return str;
|
||||
}
|
||||
|
||||
int make_cstring(const char *s, size_t n, MakeCStringMode mode, char **ret) {
|
||||
char *b;
|
||||
|
||||
assert(s || n == 0);
|
||||
assert(mode >= 0);
|
||||
assert(mode < _MAKE_CSTRING_MODE_MAX);
|
||||
|
||||
/* Converts a sized character buffer into a NUL-terminated NUL string, refusing if there are embedded
|
||||
* NUL bytes. Whether to expect a trailing NUL byte can be specified via 'mode' */
|
||||
|
||||
if (n == 0) {
|
||||
if (mode == MAKE_CSTRING_REQUIRE_TRAILING_NUL)
|
||||
return -EINVAL;
|
||||
|
||||
if (!ret)
|
||||
return 0;
|
||||
|
||||
b = new0(char, 1);
|
||||
} else {
|
||||
const char *nul;
|
||||
|
||||
nul = memchr(s, 0, n);
|
||||
if (nul) {
|
||||
if (nul < s + n - 1 || /* embedded NUL? */
|
||||
mode == MAKE_CSTRING_REFUSE_TRAILING_NUL)
|
||||
return -EINVAL;
|
||||
|
||||
n--;
|
||||
} else if (mode == MAKE_CSTRING_REQUIRE_TRAILING_NUL)
|
||||
return -EINVAL;
|
||||
|
||||
if (!ret)
|
||||
return 0;
|
||||
|
||||
b = memdup_suffix0(s, n);
|
||||
}
|
||||
if (!b)
|
||||
return -ENOMEM;
|
||||
|
||||
*ret = b;
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t strspn_from_end(const char *str, const char *accept) {
|
||||
size_t n = 0;
|
||||
|
||||
|
|
@ -1211,4 +1253,20 @@ size_t strspn_from_end(const char *str, const char *accept) {
|
|||
|
||||
return n;
|
||||
}
|
||||
|
||||
char *strdupspn(const char *a, const char *accept) {
|
||||
if (isempty(a) || isempty(accept))
|
||||
return strdup("");
|
||||
|
||||
return strndup(a, strspn(a, accept));
|
||||
}
|
||||
|
||||
char *strdupcspn(const char *a, const char *reject) {
|
||||
if (isempty(a))
|
||||
return strdup("");
|
||||
if (isempty(reject))
|
||||
return strdup(a);
|
||||
|
||||
return strndup(a, strcspn(a, reject));
|
||||
}
|
||||
#endif /* NM_IGNORED */
|
||||
|
|
|
|||
|
|
@ -53,9 +53,13 @@ static inline const char* enable_disable(bool b) {
|
|||
return b ? "enable" : "disable";
|
||||
}
|
||||
|
||||
static inline const char *empty_to_null(const char *p) {
|
||||
return isempty(p) ? NULL : p;
|
||||
}
|
||||
/* This macro's return pointer will have the "const" qualifier set or unset the same way as the input
|
||||
* pointer. */
|
||||
#define empty_to_null(p) \
|
||||
({ \
|
||||
const char *_p = (p); \
|
||||
(typeof(p)) (isempty(_p) ? NULL : _p); \
|
||||
})
|
||||
|
||||
static inline const char *empty_to_na(const char *p) {
|
||||
return isempty(p) ? "n/a" : p;
|
||||
|
|
@ -74,6 +78,11 @@ static inline bool empty_or_dash(const char *str) {
|
|||
static inline const char *empty_or_dash_to_null(const char *p) {
|
||||
return empty_or_dash(p) ? NULL : p;
|
||||
}
|
||||
#define empty_or_dash_to_null(p) \
|
||||
({ \
|
||||
const char *_p = (p); \
|
||||
(typeof(p)) (empty_or_dash(_p) ? NULL : _p); \
|
||||
})
|
||||
|
||||
char *first_word(const char *s, const char *word) _pure_;
|
||||
|
||||
|
|
@ -230,4 +239,17 @@ bool streq_skip_trailing_chars(const char *s1, const char *s2, const char *ok);
|
|||
|
||||
char *string_replace_char(char *str, char old_char, char new_char);
|
||||
|
||||
typedef enum MakeCStringMode {
|
||||
MAKE_CSTRING_REFUSE_TRAILING_NUL,
|
||||
MAKE_CSTRING_ALLOW_TRAILING_NUL,
|
||||
MAKE_CSTRING_REQUIRE_TRAILING_NUL,
|
||||
_MAKE_CSTRING_MODE_MAX,
|
||||
_MAKE_CSTRING_MODE_INVALID = -1,
|
||||
} MakeCStringMode;
|
||||
|
||||
int make_cstring(const char *s, size_t n, MakeCStringMode mode, char **ret);
|
||||
|
||||
size_t strspn_from_end(const char *str, const char *accept);
|
||||
|
||||
char *strdupspn(const char *a, const char *accept);
|
||||
char *strdupcspn(const char *a, const char *reject);
|
||||
|
|
|
|||
|
|
@ -629,123 +629,6 @@ char** strv_remove(char **l, const char *s) {
|
|||
return l;
|
||||
}
|
||||
|
||||
char** strv_parse_nulstr(const char *s, size_t l) {
|
||||
/* l is the length of the input data, which will be split at NULs into
|
||||
* elements of the resulting strv. Hence, the number of items in the resulting strv
|
||||
* will be equal to one plus the number of NUL bytes in the l bytes starting at s,
|
||||
* unless s[l-1] is NUL, in which case the final empty string is not stored in
|
||||
* the resulting strv, and length is equal to the number of NUL bytes.
|
||||
*
|
||||
* Note that contrary to a normal nulstr which cannot contain empty strings, because
|
||||
* the input data is terminated by any two consequent NUL bytes, this parser accepts
|
||||
* empty strings in s.
|
||||
*/
|
||||
|
||||
size_t c = 0, i = 0;
|
||||
char **v;
|
||||
|
||||
assert(s || l <= 0);
|
||||
|
||||
if (l <= 0)
|
||||
return new0(char*, 1);
|
||||
|
||||
for (const char *p = s; p < s + l; p++)
|
||||
if (*p == 0)
|
||||
c++;
|
||||
|
||||
if (s[l-1] != 0)
|
||||
c++;
|
||||
|
||||
v = new0(char*, c+1);
|
||||
if (!v)
|
||||
return NULL;
|
||||
|
||||
for (const char *p = s; p < s + l; ) {
|
||||
const char *e;
|
||||
|
||||
e = memchr(p, 0, s + l - p);
|
||||
|
||||
v[i] = strndup(p, e ? e - p : s + l - p);
|
||||
if (!v[i]) {
|
||||
strv_free(v);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
i++;
|
||||
|
||||
if (!e)
|
||||
break;
|
||||
|
||||
p = e + 1;
|
||||
}
|
||||
|
||||
assert(i == c);
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
char** strv_split_nulstr(const char *s) {
|
||||
const char *i;
|
||||
char **r = NULL;
|
||||
|
||||
NULSTR_FOREACH(i, s)
|
||||
if (strv_extend(&r, i) < 0) {
|
||||
strv_free(r);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!r)
|
||||
return strv_new(NULL);
|
||||
|
||||
return r;
|
||||
}
|
||||
#endif /* NM_IGNORED */
|
||||
|
||||
int strv_make_nulstr(char * const *l, char **ret, size_t *ret_size) {
|
||||
/* A valid nulstr with two NULs at the end will be created, but
|
||||
* q will be the length without the two trailing NULs. Thus the output
|
||||
* string is a valid nulstr and can be iterated over using NULSTR_FOREACH,
|
||||
* and can also be parsed by strv_parse_nulstr as long as the length
|
||||
* is provided separately.
|
||||
*/
|
||||
|
||||
_cleanup_free_ char *m = NULL;
|
||||
size_t n = 0;
|
||||
|
||||
assert(ret);
|
||||
assert(ret_size);
|
||||
|
||||
STRV_FOREACH(i, l) {
|
||||
size_t z;
|
||||
|
||||
z = strlen(*i);
|
||||
|
||||
if (!GREEDY_REALLOC(m, n + z + 2))
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy(m + n, *i, z + 1);
|
||||
n += z + 1;
|
||||
}
|
||||
|
||||
if (!m) {
|
||||
m = new0(char, 1);
|
||||
if (!m)
|
||||
return -ENOMEM;
|
||||
n = 1;
|
||||
} else
|
||||
/* make sure there is a second extra NUL at the end of resulting nulstr */
|
||||
m[n] = '\0';
|
||||
|
||||
assert(n > 0);
|
||||
*ret = m;
|
||||
*ret_size = n - 1;
|
||||
|
||||
m = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool strv_overlap(char * const *a, char * const *b) {
|
||||
STRV_FOREACH(i, a)
|
||||
if (strv_contains(b, *i))
|
||||
|
|
@ -916,6 +799,22 @@ rollback:
|
|||
return -ENOMEM;
|
||||
}
|
||||
|
||||
int strv_extend_assignment(char ***l, const char *lhs, const char *rhs) {
|
||||
char *j;
|
||||
|
||||
assert(l);
|
||||
assert(lhs);
|
||||
|
||||
if (!rhs) /* value is optional, in which case we suppress the field */
|
||||
return 0;
|
||||
|
||||
j = strjoin(lhs, "=", rhs);
|
||||
if (!j)
|
||||
return -ENOMEM;
|
||||
|
||||
return strv_consume(l, j);
|
||||
}
|
||||
|
||||
int fputstrv(FILE *f, char * const *l, const char *separator, bool *space) {
|
||||
bool b = false;
|
||||
int r;
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ static inline int strv_extend(char ***l, const char *value) {
|
|||
return strv_extend_with_size(l, NULL, value);
|
||||
}
|
||||
|
||||
int strv_extendf(char ***l, const char *format, ...) _printf_(2,0);
|
||||
int strv_extendf(char ***l, const char *format, ...) _printf_(2,3);
|
||||
int strv_extend_front(char ***l, const char *value);
|
||||
|
||||
int strv_push_with_size(char ***l, size_t *n, char *value);
|
||||
|
|
@ -124,20 +124,6 @@ static inline char *strv_join(char * const *l, const char *separator) {
|
|||
return strv_join_full(l, separator, NULL, false);
|
||||
}
|
||||
|
||||
char** strv_parse_nulstr(const char *s, size_t l);
|
||||
char** strv_split_nulstr(const char *s);
|
||||
int strv_make_nulstr(char * const *l, char **p, size_t *n);
|
||||
|
||||
static inline int strv_from_nulstr(char ***a, const char *nulstr) {
|
||||
char **t;
|
||||
|
||||
t = strv_split_nulstr(nulstr);
|
||||
if (!t)
|
||||
return -ENOMEM;
|
||||
*a = t;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool strv_overlap(char * const *a, char * const *b) _pure_;
|
||||
|
||||
#define _STRV_FOREACH_BACKWARDS(s, l, h, i) \
|
||||
|
|
@ -255,6 +241,8 @@ char** strv_skip(char **l, size_t n);
|
|||
|
||||
int strv_extend_n(char ***l, const char *value, size_t n);
|
||||
|
||||
int strv_extend_assignment(char ***l, const char *lhs, const char *rhs);
|
||||
|
||||
int fputstrv(FILE *f, char * const *l, const char *separator, bool *space);
|
||||
|
||||
#define strv_free_and_replace(a, b) \
|
||||
|
|
|
|||
|
|
@ -311,54 +311,48 @@ char *format_timestamp_style(
|
|||
};
|
||||
|
||||
struct tm tm;
|
||||
bool utc, us;
|
||||
time_t sec;
|
||||
size_t n;
|
||||
bool utc = false, us = false;
|
||||
int r;
|
||||
|
||||
assert(buf);
|
||||
assert(style >= 0);
|
||||
assert(style < _TIMESTAMP_STYLE_MAX);
|
||||
|
||||
switch (style) {
|
||||
case TIMESTAMP_PRETTY:
|
||||
case TIMESTAMP_UNIX:
|
||||
break;
|
||||
case TIMESTAMP_US:
|
||||
us = true;
|
||||
break;
|
||||
case TIMESTAMP_UTC:
|
||||
utc = true;
|
||||
break;
|
||||
case TIMESTAMP_US_UTC:
|
||||
us = true;
|
||||
utc = true;
|
||||
break;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (l < (size_t) (3 + /* week day */
|
||||
1 + 10 + /* space and date */
|
||||
1 + 8 + /* space and time */
|
||||
(us ? 1 + 6 : 0) + /* "." and microsecond part */
|
||||
1 + 1 + /* space and shortest possible zone */
|
||||
1))
|
||||
return NULL; /* Not enough space even for the shortest form. */
|
||||
if (!timestamp_is_set(t))
|
||||
return NULL; /* Timestamp is unset */
|
||||
|
||||
if (style == TIMESTAMP_UNIX) {
|
||||
r = snprintf(buf, l, "@" USEC_FMT, t / USEC_PER_SEC); /* round down µs → s */
|
||||
if (r < 0 || (size_t) r >= l)
|
||||
return NULL; /* Doesn't fit */
|
||||
if (l < (size_t) (1 + 1 + 1))
|
||||
return NULL; /* not enough space for even the shortest of forms */
|
||||
|
||||
return buf;
|
||||
return snprintf_ok(buf, l, "@" USEC_FMT, t / USEC_PER_SEC); /* round down µs → s */
|
||||
}
|
||||
|
||||
utc = IN_SET(style, TIMESTAMP_UTC, TIMESTAMP_US_UTC, TIMESTAMP_DATE);
|
||||
us = IN_SET(style, TIMESTAMP_US, TIMESTAMP_US_UTC);
|
||||
|
||||
if (l < (size_t) (3 + /* week day */
|
||||
1 + 10 + /* space and date */
|
||||
style == TIMESTAMP_DATE ? 0 :
|
||||
(1 + 8 + /* space and time */
|
||||
(us ? 1 + 6 : 0) + /* "." and microsecond part */
|
||||
1 + (utc ? 3 : 1)) + /* space and shortest possible zone */
|
||||
1))
|
||||
return NULL; /* Not enough space even for the shortest form. */
|
||||
|
||||
/* Let's not format times with years > 9999 */
|
||||
if (t > USEC_TIMESTAMP_FORMATTABLE_MAX) {
|
||||
assert(l >= STRLEN("--- XXXX-XX-XX XX:XX:XX") + 1);
|
||||
strcpy(buf, "--- XXXX-XX-XX XX:XX:XX");
|
||||
return buf;
|
||||
static const char* const xxx[_TIMESTAMP_STYLE_MAX] = {
|
||||
[TIMESTAMP_PRETTY] = "--- XXXX-XX-XX XX:XX:XX",
|
||||
[TIMESTAMP_US] = "--- XXXX-XX-XX XX:XX:XX.XXXXXX",
|
||||
[TIMESTAMP_UTC] = "--- XXXX-XX-XX XX:XX:XX UTC",
|
||||
[TIMESTAMP_US_UTC] = "--- XXXX-XX-XX XX:XX:XX.XXXXXX UTC",
|
||||
[TIMESTAMP_DATE] = "--- XXXX-XX-XX",
|
||||
};
|
||||
|
||||
assert(l >= strlen(xxx[style]) + 1);
|
||||
return strcpy(buf, xxx[style]);
|
||||
}
|
||||
|
||||
sec = (time_t) (t / USEC_PER_SEC); /* Round down */
|
||||
|
|
@ -370,6 +364,14 @@ char *format_timestamp_style(
|
|||
assert((size_t) tm.tm_wday < ELEMENTSOF(weekdays));
|
||||
memcpy(buf, weekdays[tm.tm_wday], 4);
|
||||
|
||||
if (style == TIMESTAMP_DATE) {
|
||||
/* Special format string if only date should be shown. */
|
||||
if (strftime(buf + 3, l - 3, " %Y-%m-%d", &tm) <= 0)
|
||||
return NULL; /* Doesn't fit */
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
/* Add the main components */
|
||||
if (strftime(buf + 3, l - 3, " %Y-%m-%d %H:%M:%S", &tm) <= 0)
|
||||
return NULL; /* Doesn't fit */
|
||||
|
|
@ -1401,7 +1403,7 @@ int get_timezones(char ***ret) {
|
|||
int verify_timezone(const char *name, int log_level) {
|
||||
bool slash = false;
|
||||
const char *p, *t;
|
||||
_cleanup_close_ int fd = -1;
|
||||
_cleanup_close_ int fd = -EBADF;
|
||||
char buf[4];
|
||||
int r;
|
||||
|
||||
|
|
@ -1575,7 +1577,7 @@ int time_change_fd(void) {
|
|||
.it_value.tv_sec = TIME_T_MAX,
|
||||
};
|
||||
|
||||
_cleanup_close_ int fd = -1;
|
||||
_cleanup_close_ int fd = -EBADF;
|
||||
|
||||
assert_cc(sizeof(time_t) == sizeof(TIME_T_MAX));
|
||||
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ typedef enum TimestampStyle {
|
|||
TIMESTAMP_UTC,
|
||||
TIMESTAMP_US_UTC,
|
||||
TIMESTAMP_UNIX,
|
||||
TIMESTAMP_DATE,
|
||||
_TIMESTAMP_STYLE_MAX,
|
||||
_TIMESTAMP_STYLE_INVALID = -EINVAL,
|
||||
} TimestampStyle;
|
||||
|
|
|
|||
|
|
@ -21,29 +21,15 @@
|
|||
#include "tmpfile-util.h"
|
||||
#include "umask-util.h"
|
||||
|
||||
int fopen_temporary(const char *path, FILE **ret_f, char **ret_temp_path) {
|
||||
static int fopen_temporary_internal(int dir_fd, const char *path, FILE **ret_file) {
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
_cleanup_free_ char *t = NULL;
|
||||
_cleanup_close_ int fd = -1;
|
||||
_cleanup_close_ int fd = -EBADF;
|
||||
int r;
|
||||
|
||||
if (path) {
|
||||
r = tempfn_xxxxxx(path, NULL, &t);
|
||||
if (r < 0)
|
||||
return r;
|
||||
} else {
|
||||
const char *d;
|
||||
assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
|
||||
assert(path);
|
||||
|
||||
r = tmp_dir(&d);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
t = path_join(d, "XXXXXX");
|
||||
if (!t)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
fd = mkostemp_safe(t);
|
||||
fd = openat(dir_fd, path, O_CLOEXEC|O_NOCTTY|O_RDWR|O_CREAT|O_EXCL, 0600);
|
||||
if (fd < 0)
|
||||
return -errno;
|
||||
|
||||
|
|
@ -52,15 +38,59 @@ int fopen_temporary(const char *path, FILE **ret_f, char **ret_temp_path) {
|
|||
|
||||
r = take_fdopen_unlocked(&fd, "w", &f);
|
||||
if (r < 0) {
|
||||
(void) unlink(t);
|
||||
(void) unlinkat(dir_fd, path, 0);
|
||||
return r;
|
||||
}
|
||||
|
||||
if (ret_f)
|
||||
*ret_f = TAKE_PTR(f);
|
||||
if (ret_file)
|
||||
*ret_file = TAKE_PTR(f);
|
||||
|
||||
if (ret_temp_path)
|
||||
*ret_temp_path = TAKE_PTR(t);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fopen_temporary_at(int dir_fd, const char *path, FILE **ret_file, char **ret_path) {
|
||||
_cleanup_free_ char *t = NULL;
|
||||
int r;
|
||||
|
||||
assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
|
||||
assert(path);
|
||||
|
||||
r = tempfn_random(path, NULL, &t);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = fopen_temporary_internal(dir_fd, t, ret_file);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (ret_path)
|
||||
*ret_path = TAKE_PTR(t);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fopen_temporary_child_at(int dir_fd, const char *path, FILE **ret_file, char **ret_path) {
|
||||
_cleanup_free_ char *t = NULL;
|
||||
int r;
|
||||
|
||||
assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
|
||||
|
||||
if (!path) {
|
||||
r = tmp_dir(&path);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
r = tempfn_random_child(path, NULL, &t);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = fopen_temporary_internal(dir_fd, t, ret_file);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (ret_path)
|
||||
*ret_path = TAKE_PTR(t);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -74,7 +104,7 @@ int mkostemp_safe(char *pattern) {
|
|||
|
||||
#if 0 /* NM_IGNORED */
|
||||
int fmkostemp_safe(char *pattern, const char *mode, FILE **ret_f) {
|
||||
_cleanup_close_ int fd = -1;
|
||||
_cleanup_close_ int fd = -EBADF;
|
||||
FILE *f;
|
||||
|
||||
fd = mkostemp_safe(pattern);
|
||||
|
|
@ -171,7 +201,6 @@ int tempfn_xxxxxx(const char *p, const char *extra, char **ret) {
|
|||
return tempfn_build(p, extra, "XXXXXX", /* child = */ false, ret);
|
||||
}
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
int tempfn_random(const char *p, const char *extra, char **ret) {
|
||||
_cleanup_free_ char *s = NULL;
|
||||
|
||||
|
|
@ -216,6 +245,7 @@ int tempfn_random_child(const char *p, const char *extra, char **ret) {
|
|||
return tempfn_build(p, extra, s, /* child = */ true, ret);
|
||||
}
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
int open_tmpfile_unlinkable(const char *directory, int flags) {
|
||||
char *p;
|
||||
int fd, r;
|
||||
|
|
@ -284,7 +314,7 @@ int open_tmpfile_linkable(const char *target, int flags, char **ret_path) {
|
|||
int fopen_tmpfile_linkable(const char *target, int flags, char **ret_path, FILE **ret_file) {
|
||||
_cleanup_free_ char *path = NULL;
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
_cleanup_close_ int fd = -1;
|
||||
_cleanup_close_ int fd = -EBADF;
|
||||
|
||||
assert(target);
|
||||
assert(ret_file);
|
||||
|
|
@ -363,4 +393,24 @@ int mkdtemp_malloc(const char *template, char **ret) {
|
|||
*ret = TAKE_PTR(p);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mkdtemp_open(const char *template, int flags, char **ret) {
|
||||
_cleanup_free_ char *p = NULL;
|
||||
int fd, r;
|
||||
|
||||
r = mkdtemp_malloc(template, &p);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
fd = RET_NERRNO(open(p, O_DIRECTORY|O_CLOEXEC|flags));
|
||||
if (fd < 0) {
|
||||
(void) rmdir(p);
|
||||
return fd;
|
||||
}
|
||||
|
||||
if (ret)
|
||||
*ret = TAKE_PTR(p);
|
||||
|
||||
return fd;
|
||||
}
|
||||
#endif /* NM_IGNORED */
|
||||
|
|
|
|||
|
|
@ -1,9 +1,19 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int fopen_temporary(const char *path, FILE **_f, char **_temp_path);
|
||||
int fopen_temporary_at(int dir_fd, const char *path, FILE **ret_file, char **ret_path);
|
||||
static inline int fopen_temporary(const char *path, FILE **ret_file, char **ret_path) {
|
||||
return fopen_temporary_at(AT_FDCWD, path, ret_file, ret_path);
|
||||
}
|
||||
|
||||
int fopen_temporary_child_at(int dir_fd, const char *path, FILE **ret_file, char **ret_path);
|
||||
static inline int fopen_temporary_child(const char *path, FILE **ret_file, char **ret_path) {
|
||||
return fopen_temporary_child_at(AT_FDCWD, path, ret_file, ret_path);
|
||||
}
|
||||
|
||||
int mkostemp_safe(char *pattern);
|
||||
int fmkostemp_safe(char *pattern, const char *mode, FILE**_f);
|
||||
|
||||
|
|
@ -19,3 +29,4 @@ int link_tmpfile(int fd, const char *path, const char *target);
|
|||
int flink_tmpfile(FILE *f, const char *path, const char *target);
|
||||
|
||||
int mkdtemp_malloc(const char *template, char **ret);
|
||||
int mkdtemp_open(const char *template, int flags, char **ret);
|
||||
|
|
|
|||
|
|
@ -15,12 +15,12 @@ static inline void umaskp(mode_t *u) {
|
|||
|
||||
/* We make use of the fact here that the umask() concept is using only the lower 9 bits of mode_t, although
|
||||
* mode_t has space for the file type in the bits further up. We simply OR in the file type mask S_IFMT to
|
||||
* distinguish the first and the second iteration of the RUN_WITH_UMASK() loop, so that we can run the first
|
||||
* one, and exit on the second. */
|
||||
* distinguish the first and the second iteration of the WITH_UMASK() loop, so that we can run the first one,
|
||||
* and exit on the second. */
|
||||
|
||||
assert_cc((S_IFMT & 0777) == 0);
|
||||
|
||||
#define RUN_WITH_UMASK(mask) \
|
||||
#define WITH_UMASK(mask) \
|
||||
for (_cleanup_umask_ mode_t _saved_umask_ = umask(mask) | S_IFMT; \
|
||||
FLAGS_SET(_saved_umask_, S_IFMT); \
|
||||
_saved_umask_ &= 0777)
|
||||
|
|
|
|||
|
|
@ -1,178 +0,0 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include "nm-sd-adapt-shared.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "build.h"
|
||||
#include "env-file.h"
|
||||
#include "env-util.h"
|
||||
#include "fd-util.h"
|
||||
#include "fileio.h"
|
||||
#include "hostname-util.h"
|
||||
#include "log.h"
|
||||
#include "macro.h"
|
||||
#include "parse-util.h"
|
||||
#include "stat-util.h"
|
||||
#include "string-util.h"
|
||||
#include "util.h"
|
||||
#include "virt.h"
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
int saved_argc = 0;
|
||||
char **saved_argv = NULL;
|
||||
static int saved_in_initrd = -1;
|
||||
|
||||
bool kexec_loaded(void) {
|
||||
_cleanup_free_ char *s = NULL;
|
||||
|
||||
if (read_one_line_file("/sys/kernel/kexec_loaded", &s) < 0)
|
||||
return false;
|
||||
|
||||
return s[0] == '1';
|
||||
}
|
||||
|
||||
int prot_from_flags(int flags) {
|
||||
|
||||
switch (flags & O_ACCMODE) {
|
||||
|
||||
case O_RDONLY:
|
||||
return PROT_READ;
|
||||
|
||||
case O_WRONLY:
|
||||
return PROT_WRITE;
|
||||
|
||||
case O_RDWR:
|
||||
return PROT_READ|PROT_WRITE;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
bool in_initrd(void) {
|
||||
int r;
|
||||
const char *e;
|
||||
bool lenient = false;
|
||||
|
||||
if (saved_in_initrd >= 0)
|
||||
return saved_in_initrd;
|
||||
|
||||
/* We have two checks here:
|
||||
*
|
||||
* 1. the flag file /etc/initrd-release must exist
|
||||
* 2. the root file system must be a memory file system
|
||||
*
|
||||
* The second check is extra paranoia, since misdetecting an
|
||||
* initrd can have bad consequences due the initrd
|
||||
* emptying when transititioning to the main systemd.
|
||||
*
|
||||
* If env var $SYSTEMD_IN_INITRD is not set or set to "auto",
|
||||
* both checks are used. If it's set to "lenient", only check
|
||||
* 1 is used. If set to a boolean value, then the boolean
|
||||
* value is returned.
|
||||
*/
|
||||
|
||||
e = secure_getenv("SYSTEMD_IN_INITRD");
|
||||
if (e) {
|
||||
if (streq(e, "lenient"))
|
||||
lenient = true;
|
||||
else if (!streq(e, "auto")) {
|
||||
r = parse_boolean(e);
|
||||
if (r >= 0) {
|
||||
saved_in_initrd = r > 0;
|
||||
return saved_in_initrd;
|
||||
}
|
||||
log_debug_errno(r, "Failed to parse $SYSTEMD_IN_INITRD, ignoring: %m");
|
||||
}
|
||||
}
|
||||
|
||||
if (!lenient) {
|
||||
r = path_is_temporary_fs("/");
|
||||
if (r < 0)
|
||||
log_debug_errno(r, "Couldn't determine if / is a temporary file system: %m");
|
||||
|
||||
saved_in_initrd = r > 0;
|
||||
}
|
||||
|
||||
r = access("/etc/initrd-release", F_OK);
|
||||
if (r >= 0) {
|
||||
if (saved_in_initrd == 0)
|
||||
log_debug("/etc/initrd-release exists, but it's not an initrd.");
|
||||
else
|
||||
saved_in_initrd = 1;
|
||||
} else {
|
||||
if (errno != ENOENT)
|
||||
log_debug_errno(errno, "Failed to test if /etc/initrd-release exists: %m");
|
||||
saved_in_initrd = 0;
|
||||
}
|
||||
|
||||
return saved_in_initrd;
|
||||
}
|
||||
|
||||
void in_initrd_force(bool value) {
|
||||
saved_in_initrd = value;
|
||||
}
|
||||
|
||||
int container_get_leader(const char *machine, pid_t *pid) {
|
||||
_cleanup_free_ char *s = NULL, *class = NULL;
|
||||
const char *p;
|
||||
pid_t leader;
|
||||
int r;
|
||||
|
||||
assert(machine);
|
||||
assert(pid);
|
||||
|
||||
if (streq(machine, ".host")) {
|
||||
*pid = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!hostname_is_valid(machine, 0))
|
||||
return -EINVAL;
|
||||
|
||||
p = strjoina("/run/systemd/machines/", machine);
|
||||
r = parse_env_file(NULL, p,
|
||||
"LEADER", &s,
|
||||
"CLASS", &class);
|
||||
if (r == -ENOENT)
|
||||
return -EHOSTDOWN;
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (!s)
|
||||
return -EIO;
|
||||
|
||||
if (!streq_ptr(class, "container"))
|
||||
return -EIO;
|
||||
|
||||
r = parse_pid(s, &leader);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (leader <= 1)
|
||||
return -EIO;
|
||||
|
||||
*pid = leader;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int version(void) {
|
||||
printf("systemd " STRINGIFY(PROJECT_VERSION) " (" GIT_VERSION ")\n%s\n",
|
||||
systemd_features);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Turn off core dumps but only if we're running outside of a container. */
|
||||
void disable_coredumps(void) {
|
||||
int r;
|
||||
|
||||
if (detect_container() > 0)
|
||||
return;
|
||||
|
||||
r = write_string_file("/proc/sys/kernel/core_pattern", "|/bin/false", WRITE_STRING_FILE_DISABLE_BUFFER);
|
||||
if (r < 0)
|
||||
log_debug_errno(r, "Failed to turn off coredumps, ignoring: %m");
|
||||
}
|
||||
#endif /* NM_IGNORED */
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#ifndef SD_BOOT
|
||||
#if !SD_BOOT
|
||||
# include <assert.h>
|
||||
#endif
|
||||
|
||||
|
|
@ -20,6 +20,7 @@
|
|||
#define _hidden_ __attribute__((__visibility__("hidden")))
|
||||
#define _likely_(x) (__builtin_expect(!!(x), 1))
|
||||
#define _malloc_ __attribute__((__malloc__))
|
||||
#define _noinline_ __attribute__((noinline))
|
||||
#define _noreturn_ _Noreturn
|
||||
#define _packed_ __attribute__((__packed__))
|
||||
#define _printf_(a, b) __attribute__((__format__(printf, a, b)))
|
||||
|
|
@ -36,6 +37,13 @@
|
|||
#define _weak_ __attribute__((__weak__))
|
||||
#define _weakref_(x) __attribute__((__weakref__(#x)))
|
||||
|
||||
/* !NM_IGNORED */
|
||||
#if __GNUC__ <= 4
|
||||
#undef _returns_nonnull_
|
||||
#define _returns_nonnull_
|
||||
#endif
|
||||
/* !NM_IGNORED */
|
||||
|
||||
#ifdef __clang__
|
||||
# define _alloc_(...)
|
||||
#else
|
||||
|
|
@ -66,18 +74,18 @@
|
|||
#define XCONCATENATE(x, y) x ## y
|
||||
#define CONCATENATE(x, y) XCONCATENATE(x, y)
|
||||
|
||||
#ifdef SD_BOOT
|
||||
#if SD_BOOT
|
||||
_noreturn_ void efi_assert(const char *expr, const char *file, unsigned line, const char *function);
|
||||
|
||||
#ifdef NDEBUG
|
||||
#define assert(expr)
|
||||
#define assert_not_reached() __builtin_unreachable()
|
||||
#else
|
||||
#define assert(expr) ({ _likely_(expr) ? VOID_0 : efi_assert(#expr, __FILE__, __LINE__, __PRETTY_FUNCTION__); })
|
||||
#define assert_not_reached() efi_assert("Code should not be reached", __FILE__, __LINE__, __PRETTY_FUNCTION__)
|
||||
#define assert(expr) ({ _likely_(expr) ? VOID_0 : efi_assert(#expr, __FILE__, __LINE__, __func__); })
|
||||
#define assert_not_reached() efi_assert("Code should not be reached", __FILE__, __LINE__, __func__)
|
||||
#endif
|
||||
#define static_assert _Static_assert
|
||||
#define assert_se(expr) ({ _likely_(expr) ? VOID_0 : efi_assert(#expr, __FILE__, __LINE__, __PRETTY_FUNCTION__); })
|
||||
#define assert_se(expr) ({ _likely_(expr) ? VOID_0 : efi_assert(#expr, __FILE__, __LINE__, __func__); })
|
||||
#endif
|
||||
|
||||
/* This passes the argument through after (if asserts are enabled) checking that it is not null. */
|
||||
|
|
@ -259,47 +267,44 @@
|
|||
(UNIQ_T(X, xq) / UNIQ_T(Y, yq) + !!(UNIQ_T(X, xq) % UNIQ_T(Y, yq))); \
|
||||
})
|
||||
|
||||
#define CASE_F(X) case X:
|
||||
#define CASE_F_1(CASE, X) CASE_F(X)
|
||||
#define CASE_F_2(CASE, X, ...) CASE(X) CASE_F_1(CASE, __VA_ARGS__)
|
||||
#define CASE_F_3(CASE, X, ...) CASE(X) CASE_F_2(CASE, __VA_ARGS__)
|
||||
#define CASE_F_4(CASE, X, ...) CASE(X) CASE_F_3(CASE, __VA_ARGS__)
|
||||
#define CASE_F_5(CASE, X, ...) CASE(X) CASE_F_4(CASE, __VA_ARGS__)
|
||||
#define CASE_F_6(CASE, X, ...) CASE(X) CASE_F_5(CASE, __VA_ARGS__)
|
||||
#define CASE_F_7(CASE, X, ...) CASE(X) CASE_F_6(CASE, __VA_ARGS__)
|
||||
#define CASE_F_8(CASE, X, ...) CASE(X) CASE_F_7(CASE, __VA_ARGS__)
|
||||
#define CASE_F_9(CASE, X, ...) CASE(X) CASE_F_8(CASE, __VA_ARGS__)
|
||||
#define CASE_F_10(CASE, X, ...) CASE(X) CASE_F_9(CASE, __VA_ARGS__)
|
||||
#define CASE_F_11(CASE, X, ...) CASE(X) CASE_F_10(CASE, __VA_ARGS__)
|
||||
#define CASE_F_12(CASE, X, ...) CASE(X) CASE_F_11(CASE, __VA_ARGS__)
|
||||
#define CASE_F_13(CASE, X, ...) CASE(X) CASE_F_12(CASE, __VA_ARGS__)
|
||||
#define CASE_F_14(CASE, X, ...) CASE(X) CASE_F_13(CASE, __VA_ARGS__)
|
||||
#define CASE_F_15(CASE, X, ...) CASE(X) CASE_F_14(CASE, __VA_ARGS__)
|
||||
#define CASE_F_16(CASE, X, ...) CASE(X) CASE_F_15(CASE, __VA_ARGS__)
|
||||
#define CASE_F_17(CASE, X, ...) CASE(X) CASE_F_16(CASE, __VA_ARGS__)
|
||||
#define CASE_F_18(CASE, X, ...) CASE(X) CASE_F_17(CASE, __VA_ARGS__)
|
||||
#define CASE_F_19(CASE, X, ...) CASE(X) CASE_F_18(CASE, __VA_ARGS__)
|
||||
#define CASE_F_20(CASE, X, ...) CASE(X) CASE_F_19(CASE, __VA_ARGS__)
|
||||
#define CASE_F_1(X) case X:
|
||||
#define CASE_F_2(X, ...) case X: CASE_F_1( __VA_ARGS__)
|
||||
#define CASE_F_3(X, ...) case X: CASE_F_2( __VA_ARGS__)
|
||||
#define CASE_F_4(X, ...) case X: CASE_F_3( __VA_ARGS__)
|
||||
#define CASE_F_5(X, ...) case X: CASE_F_4( __VA_ARGS__)
|
||||
#define CASE_F_6(X, ...) case X: CASE_F_5( __VA_ARGS__)
|
||||
#define CASE_F_7(X, ...) case X: CASE_F_6( __VA_ARGS__)
|
||||
#define CASE_F_8(X, ...) case X: CASE_F_7( __VA_ARGS__)
|
||||
#define CASE_F_9(X, ...) case X: CASE_F_8( __VA_ARGS__)
|
||||
#define CASE_F_10(X, ...) case X: CASE_F_9( __VA_ARGS__)
|
||||
#define CASE_F_11(X, ...) case X: CASE_F_10( __VA_ARGS__)
|
||||
#define CASE_F_12(X, ...) case X: CASE_F_11( __VA_ARGS__)
|
||||
#define CASE_F_13(X, ...) case X: CASE_F_12( __VA_ARGS__)
|
||||
#define CASE_F_14(X, ...) case X: CASE_F_13( __VA_ARGS__)
|
||||
#define CASE_F_15(X, ...) case X: CASE_F_14( __VA_ARGS__)
|
||||
#define CASE_F_16(X, ...) case X: CASE_F_15( __VA_ARGS__)
|
||||
#define CASE_F_17(X, ...) case X: CASE_F_16( __VA_ARGS__)
|
||||
#define CASE_F_18(X, ...) case X: CASE_F_17( __VA_ARGS__)
|
||||
#define CASE_F_19(X, ...) case X: CASE_F_18( __VA_ARGS__)
|
||||
#define CASE_F_20(X, ...) case X: CASE_F_19( __VA_ARGS__)
|
||||
|
||||
#define GET_CASE_F(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,NAME,...) NAME
|
||||
#define FOR_EACH_MAKE_CASE(...) \
|
||||
GET_CASE_F(__VA_ARGS__,CASE_F_20,CASE_F_19,CASE_F_18,CASE_F_17,CASE_F_16,CASE_F_15,CASE_F_14,CASE_F_13,CASE_F_12,CASE_F_11, \
|
||||
CASE_F_10,CASE_F_9,CASE_F_8,CASE_F_7,CASE_F_6,CASE_F_5,CASE_F_4,CASE_F_3,CASE_F_2,CASE_F_1) \
|
||||
(CASE_F,__VA_ARGS__)
|
||||
(__VA_ARGS__)
|
||||
|
||||
#define IN_SET(x, ...) \
|
||||
#define IN_SET(x, first, ...) \
|
||||
({ \
|
||||
bool _found = false; \
|
||||
/* If the build breaks in the line below, you need to extend the case macros. (We use "long double" as \
|
||||
* type for the array, in the hope that checkers such as ubsan don't complain that the initializers for \
|
||||
* the array are not representable by the base type. Ideally we'd use typeof(x) as base type, but that \
|
||||
* doesn't work, as we want to use this on bitfields and gcc refuses typeof() on bitfields.) */ \
|
||||
static const long double __assert_in_set[] _unused_ = { __VA_ARGS__ }; \
|
||||
/* If the build breaks in the line below, you need to extend the case macros. We use typeof(+x) \
|
||||
* here to widen the type of x if it is a bit-field as this would otherwise be illegal. */ \
|
||||
static const typeof(+x) __assert_in_set[] _unused_ = { first, __VA_ARGS__ }; \
|
||||
assert_cc(ELEMENTSOF(__assert_in_set) <= 20); \
|
||||
switch (x) { \
|
||||
FOR_EACH_MAKE_CASE(__VA_ARGS__) \
|
||||
FOR_EACH_MAKE_CASE(first, __VA_ARGS__) \
|
||||
_found = true; \
|
||||
break; \
|
||||
break; \
|
||||
default: \
|
||||
break; \
|
||||
} \
|
||||
|
|
@ -308,13 +313,18 @@
|
|||
|
||||
/* Takes inspiration from Rust's Option::take() method: reads and returns a pointer, but at the same time
|
||||
* resets it to NULL. See: https://doc.rust-lang.org/std/option/enum.Option.html#method.take */
|
||||
#define TAKE_PTR(ptr) \
|
||||
({ \
|
||||
typeof(ptr) *_pptr_ = &(ptr); \
|
||||
typeof(ptr) _ptr_ = *_pptr_; \
|
||||
*_pptr_ = NULL; \
|
||||
_ptr_; \
|
||||
#define TAKE_GENERIC(var, type, nullvalue) \
|
||||
({ \
|
||||
type *_pvar_ = &(var); \
|
||||
type _var_ = *_pvar_; \
|
||||
type _nullvalue_ = nullvalue; \
|
||||
*_pvar_ = _nullvalue_; \
|
||||
_var_; \
|
||||
})
|
||||
#define TAKE_PTR_TYPE(ptr, type) TAKE_GENERIC(ptr, type, NULL)
|
||||
#define TAKE_PTR(ptr) TAKE_PTR_TYPE(ptr, typeof(ptr))
|
||||
#define TAKE_STRUCT_TYPE(s, type) TAKE_GENERIC(s, type, {})
|
||||
#define TAKE_STRUCT(s) TAKE_STRUCT_TYPE(s, typeof(s))
|
||||
|
||||
/*
|
||||
* STRLEN - return the length of a string literal, minus the trailing NUL byte.
|
||||
|
|
@ -338,14 +348,23 @@ static inline size_t ALIGN_TO(size_t l, size_t ali) {
|
|||
return ((l + ali - 1) & ~(ali - 1));
|
||||
}
|
||||
|
||||
#define ALIGN2(l) ALIGN_TO(l, 2)
|
||||
#define ALIGN4(l) ALIGN_TO(l, 4)
|
||||
#define ALIGN8(l) ALIGN_TO(l, 8)
|
||||
#ifndef SD_BOOT
|
||||
#define ALIGN2_PTR(p) ((void*) ALIGN2((uintptr_t) p))
|
||||
#define ALIGN4_PTR(p) ((void*) ALIGN4((uintptr_t) p))
|
||||
#define ALIGN8_PTR(p) ((void*) ALIGN8((uintptr_t) p))
|
||||
#if !SD_BOOT
|
||||
/* libefi also provides ALIGN, and we do not use them in sd-boot explicitly. */
|
||||
#define ALIGN(l) ALIGN_TO(l, sizeof(void*))
|
||||
#define ALIGN_PTR(p) ((void*) ALIGN((uintptr_t) (p)))
|
||||
#endif
|
||||
|
||||
/* Checks if the specified pointer is aligned as appropriate for the specific type */
|
||||
#define IS_ALIGNED16(p) (((uintptr_t) p) % __alignof__(uint16_t) == 0)
|
||||
#define IS_ALIGNED32(p) (((uintptr_t) p) % __alignof__(uint32_t) == 0)
|
||||
#define IS_ALIGNED64(p) (((uintptr_t) p) % __alignof__(uint64_t) == 0)
|
||||
|
||||
/* Same as ALIGN_TO but callable in constant contexts. */
|
||||
#define CONST_ALIGN_TO(l, ali) \
|
||||
__builtin_choose_expr( \
|
||||
|
|
@ -356,9 +375,31 @@ static inline size_t ALIGN_TO(size_t l, size_t ali) {
|
|||
((l) + (ali) - 1) & ~((ali) - 1), \
|
||||
VOID_0)
|
||||
|
||||
/* Similar to ((t *) (void *) (p)) to cast a pointer. The macro asserts that the pointer has a suitable
|
||||
* alignment for type "t". This exists for places where otherwise "-Wcast-align=strict" would issue a
|
||||
* warning or if you want to assert that the cast gives a pointer of suitable alignment. */
|
||||
#define CAST_ALIGN_PTR(t, p) \
|
||||
({ \
|
||||
const void *_p = (p); \
|
||||
assert(((uintptr_t) _p) % __alignof__(t) == 0); \
|
||||
(t *) _p; \
|
||||
})
|
||||
|
||||
#define UPDATE_FLAG(orig, flag, b) \
|
||||
((b) ? ((orig) | (flag)) : ((orig) & ~(flag)))
|
||||
#define SET_FLAG(v, flag, b) \
|
||||
(v) = UPDATE_FLAG(v, flag, b)
|
||||
#define FLAGS_SET(v, flags) \
|
||||
((~(v) & (flags)) == 0)
|
||||
|
||||
/* Declare a flexible array usable in a union.
|
||||
* This is essentially a work-around for a pointless constraint in C99
|
||||
* and might go away in some future version of the standard.
|
||||
*
|
||||
* See https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=3080ea5553cc909b000d1f1d964a9041962f2c5b
|
||||
*/
|
||||
#define DECLARE_FLEX_ARRAY(type, name) \
|
||||
struct { \
|
||||
dummy_t __empty__ ## name; \
|
||||
type name[]; \
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,66 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#if SD_BOOT
|
||||
# include "efi-string.h"
|
||||
#else
|
||||
# include <string.h>
|
||||
#endif
|
||||
|
||||
#include "macro-fundamental.h"
|
||||
|
||||
#if !SD_BOOT && HAVE_EXPLICIT_BZERO
|
||||
static inline void *explicit_bzero_safe(void *p, size_t l) {
|
||||
if (p && l > 0)
|
||||
explicit_bzero(p, l);
|
||||
|
||||
return p;
|
||||
}
|
||||
#else
|
||||
static inline void *explicit_bzero_safe(void *p, size_t l) {
|
||||
if (p && l > 0) {
|
||||
memset(p, 0, l);
|
||||
__asm__ __volatile__("" : : "r"(p) : "memory");
|
||||
}
|
||||
return p;
|
||||
}
|
||||
#endif
|
||||
|
||||
struct VarEraser {
|
||||
/* NB: This is a pointer to memory to erase in case of CLEANUP_ERASE(). Pointer to pointer to memory
|
||||
* to erase in case of CLEANUP_ERASE_PTR() */
|
||||
void *p;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
static inline void erase_var(struct VarEraser *e) {
|
||||
explicit_bzero_safe(e->p, e->size);
|
||||
}
|
||||
|
||||
/* Mark var to be erased when leaving scope. */
|
||||
#define CLEANUP_ERASE(var) \
|
||||
_cleanup_(erase_var) _unused_ struct VarEraser CONCATENATE(_eraser_, UNIQ) = { \
|
||||
.p = &(var), \
|
||||
.size = sizeof(var), \
|
||||
}
|
||||
|
||||
static inline void erase_varp(struct VarEraser *e) {
|
||||
|
||||
/* Very similar to erase_var(), but assumes `p` is a pointer to a pointer whose memory shall be destructed. */
|
||||
if (!e->p)
|
||||
return;
|
||||
|
||||
explicit_bzero_safe(*(void**) e->p, e->size);
|
||||
}
|
||||
|
||||
/* Mark pointer so that memory pointed to is erased when leaving scope. Note: this takes a pointer to the
|
||||
* specified pointer, instead of just a copy of it. This is to allow callers to invalidate the pointer after
|
||||
* use, if they like, disabling our automatic erasure (for example because they succeeded with whatever they
|
||||
* wanted to do and now intend to return the allocated buffer to their caller without it being erased). */
|
||||
#define CLEANUP_ERASE_PTR(ptr, sz) \
|
||||
_cleanup_(erase_varp) _unused_ struct VarEraser CONCATENATE(_eraser_, UNIQ) = { \
|
||||
.p = (ptr), \
|
||||
.size = (sz), \
|
||||
}
|
||||
|
|
@ -24,7 +24,7 @@
|
|||
<https://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <stdbool.h>
|
||||
#ifdef SD_BOOT
|
||||
#if SD_BOOT
|
||||
# include "efi-string.h"
|
||||
#else
|
||||
# include <string.h>
|
||||
|
|
@ -32,6 +32,7 @@
|
|||
|
||||
#include "macro-fundamental.h"
|
||||
#include "sha256.h"
|
||||
#include "unaligned-fundamental.h"
|
||||
|
||||
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||
# define SWAP(n) \
|
||||
|
|
@ -50,14 +51,6 @@
|
|||
# define SWAP64(n) (n)
|
||||
#endif
|
||||
|
||||
/* The condition below is from glibc's string/string-inline.c.
|
||||
* See definition of _STRING_INLINE_unaligned. */
|
||||
#if !defined(__mc68020__) && !defined(__s390__) && !defined(__i386__)
|
||||
# define UNALIGNED_P(p) (((uintptr_t) p) % __alignof__(uint32_t) != 0)
|
||||
#else
|
||||
# define UNALIGNED_P(p) false
|
||||
#endif
|
||||
|
||||
/* This array contains the bytes used to pad the buffer to the next
|
||||
64-byte boundary. (FIPS 180-2:5.1.1) */
|
||||
static const uint8_t fillbuf[64] = {
|
||||
|
|
@ -130,11 +123,7 @@ uint8_t *sha256_finish_ctx(struct sha256_ctx *ctx, uint8_t resbuf[static SHA256_
|
|||
|
||||
/* Put result from CTX in first 32 bytes following RESBUF. */
|
||||
for (size_t i = 0; i < 8; ++i)
|
||||
if (UNALIGNED_P(resbuf))
|
||||
memcpy(resbuf + i * sizeof(uint32_t), (uint32_t[]) { SWAP(ctx->H[i]) }, sizeof(uint32_t));
|
||||
else
|
||||
((uint32_t *) (void *) resbuf)[i] = SWAP(ctx->H[i]);
|
||||
|
||||
unaligned_write_ne32(resbuf + i * sizeof(uint32_t), SWAP(ctx->H[i]));
|
||||
return resbuf;
|
||||
}
|
||||
|
||||
|
|
@ -167,18 +156,17 @@ void sha256_process_bytes(const void *buffer, size_t len, struct sha256_ctx *ctx
|
|||
|
||||
/* Process available complete blocks. */
|
||||
if (len >= 64) {
|
||||
if (UNALIGNED_P(buffer))
|
||||
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;
|
||||
}
|
||||
else {
|
||||
sha256_process_block(buffer, len & ~63, ctx);
|
||||
buffer = (const char *) buffer + (len & ~63);
|
||||
len &= 63;
|
||||
}
|
||||
}
|
||||
|
||||
/* Move remaining bytes into internal buffer. */
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#include "stdint.h"
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define SHA256_DIGEST_SIZE 32
|
||||
|
||||
|
|
@ -28,6 +29,11 @@ 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]) {})
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
#include "nm-sd-adapt-shared.h"
|
||||
|
||||
#ifndef SD_BOOT
|
||||
#if !SD_BOOT
|
||||
# include <ctype.h>
|
||||
#endif
|
||||
|
||||
|
|
@ -22,7 +22,7 @@ sd_char *startswith(const sd_char *s, const sd_char *prefix) {
|
|||
return (sd_char*) s + l;
|
||||
}
|
||||
|
||||
#ifndef SD_BOOT
|
||||
#if !SD_BOOT
|
||||
sd_char *startswith_no_case(const sd_char *s, const sd_char *prefix) {
|
||||
size_t l;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#ifdef SD_BOOT
|
||||
#if SD_BOOT
|
||||
# include <efi.h>
|
||||
# include <efilib.h>
|
||||
# include "efi-string.h"
|
||||
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
#include "macro-fundamental.h"
|
||||
|
||||
#ifdef SD_BOOT
|
||||
#if SD_BOOT
|
||||
# define strlen strlen16
|
||||
# define strcmp strcmp16
|
||||
# define strncmp strncmp16
|
||||
|
|
@ -59,7 +59,7 @@ static inline size_t strlen_ptr(const sd_char *s) {
|
|||
}
|
||||
|
||||
sd_char *startswith(const sd_char *s, const sd_char *prefix) _pure_;
|
||||
#ifndef SD_BOOT
|
||||
#if !SD_BOOT
|
||||
sd_char *startswith_no_case(const sd_char *s, const sd_char *prefix) _pure_;
|
||||
#endif
|
||||
sd_char *endswith(const sd_char *s, const sd_char *postfix) _pure_;
|
||||
|
|
@ -110,6 +110,10 @@ static inline bool ascii_isdigit(sd_char a) {
|
|||
return a >= '0' && a <= '9';
|
||||
}
|
||||
|
||||
static inline bool ascii_ishex(sd_char a) {
|
||||
return ascii_isdigit(a) || (a >= 'a' && a <= 'f') || (a >= 'A' && a <= 'F');
|
||||
}
|
||||
|
||||
static inline bool ascii_isalpha(sd_char a) {
|
||||
/* A pure ASCII, locale independent version of isalpha() */
|
||||
return (a >= 'a' && a <= 'z') || (a >= 'A' && a <= 'Z');
|
||||
|
|
|
|||
|
|
@ -302,7 +302,6 @@ int dns_label_escape_new(const char *p, size_t l, char **ret) {
|
|||
int dns_label_apply_idna(const char *encoded, size_t encoded_size, char *decoded, size_t decoded_max) {
|
||||
_cleanup_free_ uint32_t *input = NULL;
|
||||
size_t input_size, l;
|
||||
const char *p;
|
||||
bool contains_8bit = false;
|
||||
char buffer[DNS_LABEL_MAX+1];
|
||||
int r;
|
||||
|
|
@ -319,7 +318,7 @@ int dns_label_apply_idna(const char *encoded, size_t encoded_size, char *decoded
|
|||
if (encoded_size <= 0)
|
||||
return -EINVAL;
|
||||
|
||||
for (p = encoded; p < encoded + encoded_size; p++)
|
||||
for (const char *p = encoded; p < encoded + encoded_size; p++)
|
||||
if ((uint8_t) *p > 127)
|
||||
contains_8bit = true;
|
||||
|
||||
|
|
@ -534,7 +533,18 @@ int dns_name_compare_func(const char *a, const char *b) {
|
|||
}
|
||||
}
|
||||
|
||||
DEFINE_HASH_OPS(dns_name_hash_ops, char, dns_name_hash_func, dns_name_compare_func);
|
||||
DEFINE_HASH_OPS(
|
||||
dns_name_hash_ops,
|
||||
char,
|
||||
dns_name_hash_func,
|
||||
dns_name_compare_func);
|
||||
|
||||
DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(
|
||||
dns_name_hash_ops_free,
|
||||
char,
|
||||
dns_name_hash_func,
|
||||
dns_name_compare_func,
|
||||
free);
|
||||
|
||||
int dns_name_equal(const char *x, const char *y) {
|
||||
int r, q;
|
||||
|
|
@ -752,9 +762,8 @@ int dns_name_address(const char *p, int *ret_family, union in_addr_union *ret_ad
|
|||
return r;
|
||||
if (r > 0) {
|
||||
uint8_t a[4];
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < ELEMENTSOF(a); i++) {
|
||||
for (size_t i = 0; i < ELEMENTSOF(a); i++) {
|
||||
char label[DNS_LABEL_MAX+1];
|
||||
|
||||
r = dns_label_unescape(&p, label, sizeof label, 0);
|
||||
|
|
@ -788,9 +797,8 @@ int dns_name_address(const char *p, int *ret_family, union in_addr_union *ret_ad
|
|||
return r;
|
||||
if (r > 0) {
|
||||
struct in6_addr a;
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < ELEMENTSOF(a.s6_addr); i++) {
|
||||
for (size_t i = 0; i < ELEMENTSOF(a.s6_addr); i++) {
|
||||
char label[DNS_LABEL_MAX+1];
|
||||
int x, y;
|
||||
|
||||
|
|
@ -832,7 +840,6 @@ int dns_name_address(const char *p, int *ret_family, union in_addr_union *ret_ad
|
|||
#endif /* NM_IGNORED */
|
||||
|
||||
bool dns_name_is_root(const char *name) {
|
||||
|
||||
assert(name);
|
||||
|
||||
/* There are exactly two ways to encode the root domain name:
|
||||
|
|
@ -904,8 +911,6 @@ int dns_name_to_wire_format(const char *domain, uint8_t *buffer, size_t len, boo
|
|||
|
||||
#if 0 /* NM_IGNORED */
|
||||
static bool srv_type_label_is_valid(const char *label, size_t n) {
|
||||
size_t k;
|
||||
|
||||
assert(label);
|
||||
|
||||
if (n < 2) /* Label needs to be at least 2 chars long */
|
||||
|
|
@ -919,12 +924,11 @@ static bool srv_type_label_is_valid(const char *label, size_t n) {
|
|||
return false;
|
||||
|
||||
/* Third and further chars must be alphanumeric or a hyphen */
|
||||
for (k = 2; k < n; k++) {
|
||||
for (size_t k = 2; k < n; k++)
|
||||
if (!ascii_isalpha(label[k]) &&
|
||||
!ascii_isdigit(label[k]) &&
|
||||
label[k] != '-')
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -1120,14 +1124,12 @@ finish:
|
|||
}
|
||||
|
||||
static int dns_name_build_suffix_table(const char *name, const char *table[]) {
|
||||
const char *p;
|
||||
const char *p = ASSERT_PTR(name);
|
||||
unsigned n = 0;
|
||||
int r;
|
||||
|
||||
assert(name);
|
||||
assert(table);
|
||||
|
||||
p = name;
|
||||
for (;;) {
|
||||
if (n > DNS_N_LABELS_MAX)
|
||||
return -EINVAL;
|
||||
|
|
|
|||
|
|
@ -62,13 +62,10 @@ static inline int dns_name_is_valid_ldh(const char *s) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
static inline bool dns_name_is_empty(const char *s) {
|
||||
return isempty(s) || streq(s, ".");
|
||||
}
|
||||
|
||||
void dns_name_hash_func(const char *s, struct siphash *state);
|
||||
int dns_name_compare_func(const char *a, const char *b);
|
||||
extern const struct hash_ops dns_name_hash_ops;
|
||||
extern const struct hash_ops dns_name_hash_ops_free;
|
||||
|
||||
int dns_name_between(const char *a, const char *b, const char *c);
|
||||
int dns_name_equal(const char *x, const char *y);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue