systemd: merge branch systemd into master

This commit is contained in:
Thomas Haller 2019-04-04 09:49:37 +02:00
commit 917cd3eb03
62 changed files with 927 additions and 905 deletions

View file

@ -1587,15 +1587,17 @@ shared_systemd_libnm_systemd_shared_la_SOURCES = \
shared/systemd/sd-adapt-shared/locale-util.h \
shared/systemd/sd-adapt-shared/memfd-util.h \
shared/systemd/sd-adapt-shared/missing.h \
shared/systemd/sd-adapt-shared/missing_socket.h \
shared/systemd/sd-adapt-shared/missing_syscall.h \
shared/systemd/sd-adapt-shared/missing_timerfd.h \
shared/systemd/sd-adapt-shared/mkdir.h \
shared/systemd/sd-adapt-shared/namespace-util.h \
shared/systemd/sd-adapt-shared/nm-sd-adapt-shared.h \
shared/systemd/sd-adapt-shared/nm-sd-adapt-shared.h \
shared/systemd/sd-adapt-shared/nulstr-util.h \
shared/systemd/sd-adapt-shared/procfs-util.h \
shared/systemd/sd-adapt-shared/raw-clone.h \
shared/systemd/sd-adapt-shared/rlimit-util.h \
shared/systemd/sd-adapt-shared/strxcpyx.h \
shared/systemd/sd-adapt-shared/terminal-util.h \
shared/systemd/sd-adapt-shared/unaligned.h \
shared/systemd/sd-adapt-shared/user-util.h \
@ -1607,6 +1609,7 @@ shared_systemd_libnm_systemd_shared_la_SOURCES = \
shared/systemd/src/basic/env-file.h \
shared/systemd/src/basic/env-util.c \
shared/systemd/src/basic/env-util.h \
shared/systemd/src/basic/errno-util.h \
shared/systemd/src/basic/escape.c \
shared/systemd/src/basic/escape.h \
shared/systemd/src/basic/ether-addr-util.c \
@ -1634,9 +1637,13 @@ shared_systemd_libnm_systemd_shared_la_SOURCES = \
shared/systemd/src/basic/list.h \
shared/systemd/src/basic/log.h \
shared/systemd/src/basic/macro.h \
shared/systemd/src/basic/memory-util.c \
shared/systemd/src/basic/memory-util.h \
shared/systemd/src/basic/mempool.c \
shared/systemd/src/basic/mempool.h \
shared/systemd/src/basic/missing_fcntl.h \
shared/systemd/src/basic/missing_socket.h \
shared/systemd/src/basic/missing_stat.h \
shared/systemd/src/basic/missing_type.h \
shared/systemd/src/basic/parse-util.c \
shared/systemd/src/basic/parse-util.h \
@ -1648,12 +1655,12 @@ shared_systemd_libnm_systemd_shared_la_SOURCES = \
shared/systemd/src/basic/process-util.h \
shared/systemd/src/basic/random-util.c \
shared/systemd/src/basic/random-util.h \
shared/systemd/src/basic/refcnt.h \
shared/systemd/src/basic/set.h \
shared/systemd/src/basic/signal-util.h \
shared/systemd/src/basic/siphash24.h \
shared/systemd/src/basic/socket-util.c \
shared/systemd/src/basic/socket-util.h \
shared/systemd/src/basic/sort-util.h \
shared/systemd/src/basic/sparse-endian.h \
shared/systemd/src/basic/stat-util.c \
shared/systemd/src/basic/stat-util.h \
@ -1711,7 +1718,7 @@ src_libnm_systemd_core_la_SOURCES = \
src/systemd/sd-adapt-core/nm-sd-adapt-core.h \
src/systemd/sd-adapt-core/sd-daemon.h \
src/systemd/sd-adapt-core/sd-device.h \
src/systemd/sd-adapt-core/stat-util.h \
src/systemd/sd-adapt-core/udev-util.h \
src/systemd/src/libsystemd-network/arp-util.c \
src/systemd/src/libsystemd-network/arp-util.h \
src/systemd/src/libsystemd-network/dhcp-identifier.c \

View file

@ -187,6 +187,7 @@ libnm_systemd_shared = static_library(
'systemd/src/basic/hostname-util.c',
'systemd/src/basic/in-addr-util.c',
'systemd/src/basic/io-util.c',
'systemd/src/basic/memory-util.c',
'systemd/src/basic/mempool.c',
'systemd/src/basic/parse-util.c',
'systemd/src/basic/path-util.c',

View file

@ -3,4 +3,6 @@
/* dummy header */
#include "missing_fcntl.h"
#include "missing_socket.h"
#include "missing_stat.h"
#include "missing_type.h"

View file

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

View file

@ -2,12 +2,13 @@
#include "nm-sd-adapt-shared.h"
#include <malloc.h>
#include <stdint.h>
#include <string.h>
#include "alloc-util.h"
#include "macro.h"
#include "util.h"
#include "memory-util.h"
void* memdup(const void *p, size_t l) {
void *ret;
@ -29,6 +30,9 @@ void* memdup_suffix0(const void *p, size_t l) {
/* The same as memdup() but place a safety NUL byte after the allocated memory */
if (_unlikely_(l == SIZE_MAX)) /* prevent overflow */
return NULL;
ret = malloc(l + 1);
if (!ret)
return NULL;
@ -47,19 +51,23 @@ void* greedy_realloc(void **p, size_t *allocated, size_t need, size_t size) {
if (*allocated >= need)
return *p;
newalloc = MAX(need * 2, 64u / size);
a = newalloc * size;
/* check for overflows */
if (a < size * need)
if (_unlikely_(need > SIZE_MAX/2)) /* Overflow check */
return NULL;
newalloc = need * 2;
if (size_multiply_overflow(newalloc, size))
return NULL;
a = newalloc * size;
if (a < 64) /* Allocate at least 64 bytes */
a = 64;
q = realloc(*p, a);
if (!q)
return NULL;
*p = q;
*allocated = newalloc;
*allocated = _unlikely_(size == 0) ? newalloc : malloc_usable_size(q) / size;
return q;
}

View file

@ -8,6 +8,10 @@
#include "macro.h"
#if HAS_FEATURE_MEMORY_SANITIZER
# include <sanitizer/msan_interface.h>
#endif
typedef void (*free_func_t)(void *p);
/* If for some reason more than 4M are allocated on the stack, let's abort immediately. It's better than
@ -152,11 +156,17 @@ void* greedy_realloc0(void **p, size_t *allocated, size_t need, size_t size);
(void*)memset(_new_, 0, _xsize_); \
})
/* Takes inspiration from Rusts'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 */
/* 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) _ptr_ = (ptr); \
(ptr) = NULL; \
_ptr_; \
})
#if HAS_FEATURE_MEMORY_SANITIZER
# define msan_unpoison(r, s) __msan_unpoison(r, s)
#else
# define msan_unpoison(r, s)
#endif

View file

@ -562,7 +562,7 @@ int write_env_file(const char *fname, char **l) {
r = -errno;
}
unlink(p);
(void) unlink(p);
return r;
}
#endif /* NM_IGNORED */

View file

@ -0,0 +1,43 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
#include "macro.h"
static inline void _reset_errno_(int *saved_errno) {
if (*saved_errno < 0) /* Invalidated by UNPROTECT_ERRNO? */
return;
errno = *saved_errno;
}
#define PROTECT_ERRNO \
_cleanup_(_reset_errno_) _unused_ int _saved_errno_ = errno
#define UNPROTECT_ERRNO \
do { \
errno = _saved_errno_; \
_saved_errno_ = -1; \
} while (false)
static inline int negative_errno(void) {
/* This helper should be used to shut up gcc if you know 'errno' is
* negative. Instead of "return -errno;", use "return negative_errno();"
* It will suppress bogus gcc warnings in case it assumes 'errno' might
* be 0 and thus the caller's error-handling might not be triggered. */
assert_return(errno > 0, -EINVAL);
return -errno;
}
/* Hint #1: ENETUNREACH happens if we try to connect to "non-existing" special IP addresses, such as ::5.
*
* Hint #2: The kernel sends e.g., EHOSTUNREACH or ENONET to userspace in some ICMP error cases. See the
* icmp_err_convert[] in net/ipv4/icmp.c in the kernel sources */
#define ERRNO_IS_DISCONNECT(r) \
IN_SET(abs(r), \
ENOTCONN, ECONNRESET, ECONNREFUSED, ECONNABORTED, EPIPE, \
ENETUNREACH, EHOSTUNREACH, ENOPROTOOPT, EHOSTDOWN, \
ENONET, ESHUTDOWN)
/* Resource exhaustion, could be our fault or general system trouble */
#define ERRNO_IS_RESOURCE(r) \
IN_SET(abs(r), ENOMEM, EMFILE, ENFILE)

View file

@ -27,6 +27,10 @@
#include "util.h"
#include "tmpfile-util.h"
/* The maximum number of iterations in the loop to close descriptors in the fallback case
* when /proc/self/fd/ is inaccessible. */
#define MAX_FD_LOOP_LIMIT (1024*1024)
int close_nointr(int fd) {
assert(fd >= 0);
@ -231,6 +235,13 @@ int close_all_fds(const int except[], size_t n_except) {
if (max_fd < 0)
return max_fd;
/* Refuse to do the loop over more too many elements. It's better to fail immediately than to
* spin the CPU for a long time. */
if (max_fd > MAX_FD_LOOP_LIMIT)
return log_debug_errno(SYNTHETIC_ERRNO(EPERM),
"/proc/self/fd is inaccessible. Refusing to loop over %d potential fds.",
max_fd);
for (fd = 3; fd >= 0; fd = fd < max_fd ? fd + 1 : -1) {
int q;

View file

@ -77,18 +77,6 @@ int acquire_data_fd(const void *data, size_t size, unsigned flags);
int fd_duplicate_data_fd(int fd);
/* Hint: ENETUNREACH happens if we try to connect to "non-existing" special IP addresses, such as ::5 */
/* The kernel sends e.g., EHOSTUNREACH or ENONET to userspace in some ICMP error cases.
* See the icmp_err_convert[] in net/ipv4/icmp.c in the kernel sources */
#define ERRNO_IS_DISCONNECT(r) \
IN_SET(r, \
ENOTCONN, ECONNRESET, ECONNREFUSED, ECONNABORTED, EPIPE, \
ENETUNREACH, EHOSTUNREACH, ENOPROTOOPT, EHOSTDOWN, ENONET)
/* Resource exhaustion, could be our fault or general system trouble */
#define ERRNO_IS_RESOURCE(r) \
IN_SET(r, ENOMEM, EMFILE, ENFILE)
int fd_move_above_stdio(int fd);
int rearrange_stdio(int original_input_fd, int original_output_fd, int original_error_fd);

View file

@ -8,6 +8,7 @@
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <linux/falloc.h>
#include <linux/magic.h>
#include <time.h>
#include <unistd.h>
@ -219,64 +220,109 @@ 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) {
char fd_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int) + 1];
_cleanup_close_ int fd = -1;
bool st_valid = false;
struct stat st;
int r;
assert(path);
/* Under the assumption that we are running privileged we first change the access mode and only then hand out
* ownership to avoid a window where access is too open. */
/* Under the assumption that we are running privileged we first change the access mode and only then
* hand out ownership to avoid a window where access is too open. */
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 */
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;
xsprintf(fd_path, "/proc/self/fd/%i", fd);
if (mode != MODE_INVALID) {
if ((mode & S_IFMT) != 0) {
struct stat st;
if (stat(fd_path, &st) < 0)
return -errno;
if ((mode & S_IFMT) != (st.st_mode & S_IFMT))
return -EINVAL;
st_valid = true;
}
if (chmod(fd_path, mode & 07777) < 0)
return -errno;
if (chmod(fd_path, mode & 07777) < 0) {
r = -errno;
if (!st_valid && stat(fd_path, &st) < 0)
return -errno;
if ((mode & 07777) != (st.st_mode & 07777))
return r;
st_valid = true;
}
}
if (uid != UID_INVALID || gid != GID_INVALID)
if (chown(fd_path, uid, gid) < 0)
return -errno;
if (uid != UID_INVALID || gid != GID_INVALID) {
if (chown(fd_path, uid, gid) < 0) {
r = -errno;
if (!st_valid && stat(fd_path, &st) < 0)
return -errno;
if (uid != UID_INVALID && st.st_uid != uid)
return r;
if (gid != GID_INVALID && st.st_gid != gid)
return r;
}
}
return 0;
}
int fchmod_and_chown(int fd, mode_t mode, uid_t uid, gid_t gid) {
bool st_valid = false;
struct stat st;
int r;
/* Under the assumption that we are running privileged we first change the access mode and only then hand out
* ownership to avoid a window where access is too open. */
if (mode != MODE_INVALID) {
if ((mode & S_IFMT) != 0) {
struct stat st;
if (fstat(fd, &st) < 0)
return -errno;
if ((mode & S_IFMT) != (st.st_mode & S_IFMT))
return -EINVAL;
st_valid = true;
}
if (fchmod(fd, mode & 0777) < 0)
return -errno;
if (fchmod(fd, mode & 07777) < 0) {
r = -errno;
if (!st_valid && fstat(fd, &st) < 0)
return -errno;
if ((mode & 07777) != (st.st_mode & 07777))
return r;
st_valid = true;
}
}
if (uid != UID_INVALID || gid != GID_INVALID)
if (fchown(fd, uid, gid) < 0)
return -errno;
if (fchown(fd, uid, gid) < 0) {
r = -errno;
if (!st_valid && fstat(fd, &st) < 0)
return -errno;
if (uid != UID_INVALID && st.st_uid != uid)
return r;
if (gid != GID_INVALID && st.st_gid != gid)
return r;
}
return 0;
}
@ -314,6 +360,10 @@ int fd_warn_permissions(const char *path, int fd) {
if (fstat(fd, &st) < 0)
return -errno;
/* Don't complain if we are reading something that is not a file, for example /dev/null */
if (!S_ISREG(st.st_mode))
return 0;
if (st.st_mode & 0111)
log_warning("Configuration file %s is marked executable. Please remove executable permission bits. Proceeding anyway.", path);
@ -934,6 +984,7 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags,
if (fstat(child, &st) < 0)
return -errno;
if ((flags & CHASE_SAFE) &&
(empty_or_root(root) || (size_t)(todo - buffer) > strlen(root)) &&
unsafe_transition(&previous_stat, &st))
return log_unsafe_transition(fd, child, path, flags);
@ -1338,6 +1389,21 @@ int fsync_path_at(int at_fd, const char *path) {
return 0;
}
int syncfs_path(int atfd, const char *path) {
_cleanup_close_ int fd = -1;
assert(path);
fd = openat(atfd, path, O_CLOEXEC|O_RDONLY|O_NONBLOCK);
if (fd < 0)
return -errno;
if (syncfs(fd) < 0)
return -errno;
return 0;
}
int open_parent(const char *path, int flags, mode_t mode) {
_cleanup_free_ char *parent = NULL;
int fd;
@ -1354,9 +1420,9 @@ int open_parent(const char *path, int flags, mode_t mode) {
/* Let's insist on O_DIRECTORY since the parent of a file or directory is a directory. Except if we open an
* O_TMPFILE file, because in that case we are actually create a regular file below the parent directory. */
if ((flags & O_PATH) == O_PATH)
if (FLAGS_SET(flags, O_PATH))
flags |= O_DIRECTORY;
else if ((flags & O_TMPFILE) != O_TMPFILE)
else if (!FLAGS_SET(flags, O_TMPFILE))
flags |= O_DIRECTORY|O_RDONLY;
fd = open(parent, flags, mode);

View file

@ -10,8 +10,8 @@
#include <sys/types.h>
#include <unistd.h>
#include "errno-util.h"
#include "time-util.h"
#include "util.h"
int unlink_noerrno(const char *path);
@ -108,4 +108,6 @@ int unlinkat_deallocate(int fd, const char *name, int flags);
int fsync_directory_of_file(int fd);
int fsync_path_at(int at_fd, const char *path);
int syncfs_path(int atfd, const char *path);
int open_parent(const char *path, int flags, mode_t mode);

View file

@ -11,6 +11,7 @@
#include "fileio.h"
#include "hashmap.h"
#include "macro.h"
#include "memory-util.h"
#include "mempool.h"
#include "process-util.h"
#include "random-util.h"
@ -18,7 +19,6 @@
#include "siphash24.h"
#include "string-util.h"
#include "strv.h"
#include "util.h"
#if ENABLE_DEBUG_HASHMAP
#include <pthread.h>
@ -1538,7 +1538,6 @@ void *internal_hashmap_first_key_and_value(HashmapBase *h, bool remove, void **r
}
unsigned internal_hashmap_size(HashmapBase *h) {
if (!h)
return 0;
@ -1546,7 +1545,6 @@ unsigned internal_hashmap_size(HashmapBase *h) {
}
unsigned internal_hashmap_buckets(HashmapBase *h) {
if (!h)
return 0;
@ -1906,8 +1904,7 @@ IteratedCache *iterated_cache_free(IteratedCache *cache) {
if (cache) {
free(cache->keys.ptr);
free(cache->values.ptr);
free(cache);
}
return NULL;
return mfree(cache);
}

View file

@ -412,9 +412,11 @@ static inline char **ordered_hashmap_get_strv(OrderedHashmap *h) {
DEFINE_TRIVIAL_CLEANUP_FUNC(Hashmap*, hashmap_free);
DEFINE_TRIVIAL_CLEANUP_FUNC(Hashmap*, hashmap_free_free);
DEFINE_TRIVIAL_CLEANUP_FUNC(Hashmap*, hashmap_free_free_key);
DEFINE_TRIVIAL_CLEANUP_FUNC(Hashmap*, hashmap_free_free_free);
DEFINE_TRIVIAL_CLEANUP_FUNC(OrderedHashmap*, ordered_hashmap_free);
DEFINE_TRIVIAL_CLEANUP_FUNC(OrderedHashmap*, ordered_hashmap_free_free);
DEFINE_TRIVIAL_CLEANUP_FUNC(OrderedHashmap*, ordered_hashmap_free_free_key);
DEFINE_TRIVIAL_CLEANUP_FUNC(OrderedHashmap*, ordered_hashmap_free_free_free);
#define _cleanup_hashmap_free_ _cleanup_(hashmap_freep)

View file

@ -10,8 +10,8 @@
#include "alloc-util.h"
#include "hexdecoct.h"
#include "macro.h"
#include "memory-util.h"
#include "string-util.h"
#include "util.h"
char octchar(int x) {
return '0' + (x & 7);

View file

@ -7,12 +7,15 @@
#include <errno.h>
#include <net/if.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include "alloc-util.h"
#include "in-addr-util.h"
#include "macro.h"
#include "parse-util.h"
#include "random-util.h"
#include "strxcpyx.h"
#include "util.h"
bool in4_addr_is_null(const struct in_addr *a) {
@ -107,6 +110,7 @@ int in_addr_equal(int family, const union in_addr_union *a, const union in_addr_
return -EAFNOSUPPORT;
}
#if 0 /* NM_IGNORED */
int in_addr_prefix_intersect(
int family,
const union in_addr_union *a,
@ -217,8 +221,86 @@ int in_addr_prefix_next(int family, union in_addr_union *u, unsigned prefixlen)
return -EAFNOSUPPORT;
}
int in_addr_random_prefix(
int family,
union in_addr_union *u,
unsigned prefixlen_fixed_part,
unsigned prefixlen) {
assert(u);
/* Random network part of an address by one. */
if (prefixlen <= 0)
return 0;
if (family == AF_INET) {
uint32_t c, n;
if (prefixlen_fixed_part > 32)
prefixlen_fixed_part = 32;
if (prefixlen > 32)
prefixlen = 32;
if (prefixlen_fixed_part >= prefixlen)
return -EINVAL;
c = be32toh(u->in.s_addr);
c &= ((UINT32_C(1) << prefixlen_fixed_part) - 1) << (32 - prefixlen_fixed_part);
random_bytes(&n, sizeof(n));
n &= ((UINT32_C(1) << (prefixlen - prefixlen_fixed_part)) - 1) << (32 - prefixlen);
u->in.s_addr = htobe32(n | c);
return 1;
}
if (family == AF_INET6) {
struct in6_addr n;
unsigned i, j;
if (prefixlen_fixed_part > 128)
prefixlen_fixed_part = 128;
if (prefixlen > 128)
prefixlen = 128;
if (prefixlen_fixed_part >= prefixlen)
return -EINVAL;
random_bytes(&n, sizeof(n));
for (i = 0; i < 16; i++) {
uint8_t mask_fixed_part = 0, mask = 0;
if (i < (prefixlen_fixed_part + 7) / 8) {
if (i < prefixlen_fixed_part / 8)
mask_fixed_part = 0xffu;
else {
j = prefixlen_fixed_part % 8;
mask_fixed_part = ((UINT8_C(1) << (j + 1)) - 1) << (8 - j);
}
}
if (i < (prefixlen + 7) / 8) {
if (i < prefixlen / 8)
mask = 0xffu ^ mask_fixed_part;
else {
j = prefixlen % 8;
mask = (((UINT8_C(1) << (j + 1)) - 1) << (8 - j)) ^ mask_fixed_part;
}
}
u->in6.s6_addr[i] &= mask_fixed_part;
u->in6.s6_addr[i] |= n.s6_addr[i] & mask;
}
return 1;
}
return -EAFNOSUPPORT;
}
#endif /* NM_IGNORED */
int in_addr_to_string(int family, const union in_addr_union *u, char **ret) {
char *x;
_cleanup_free_ char *x = NULL;
size_t l;
assert(u);
@ -236,18 +318,52 @@ int in_addr_to_string(int family, const union in_addr_union *u, char **ret) {
return -ENOMEM;
errno = 0;
if (!inet_ntop(family, u, x, l)) {
free(x);
if (!inet_ntop(family, u, x, l))
return errno > 0 ? -errno : -EINVAL;
}
*ret = x;
*ret = TAKE_PTR(x);
return 0;
}
int in_addr_ifindex_to_string(int family, const union in_addr_union *u, int ifindex, char **ret) {
#if 0 /* NM_IGNORED */
int in_addr_prefix_to_string(int family, const union in_addr_union *u, unsigned prefixlen, char **ret) {
_cleanup_free_ char *x = NULL;
char *p;
size_t l;
assert(u);
assert(ret);
if (family == AF_INET)
l = INET_ADDRSTRLEN + 3;
else if (family == AF_INET6)
l = INET6_ADDRSTRLEN + 4;
else
return -EAFNOSUPPORT;
if (prefixlen > FAMILY_ADDRESS_SIZE(family) * 8)
return -EINVAL;
x = new(char, l);
if (!x)
return -ENOMEM;
errno = 0;
if (!inet_ntop(family, u, x, l))
return errno > 0 ? -errno : -EINVAL;
p = x + strlen(x);
l -= strlen(x);
(void) strpcpyf(&p, l, "/%u", prefixlen);
*ret = TAKE_PTR(x);
return 0;
}
#endif /* NM_IGNORED */
int in_addr_ifindex_to_string(int family, const union in_addr_union *u, int ifindex, char **ret) {
_cleanup_free_ char *x = NULL;
size_t l;
char *x;
int r;
assert(u);
@ -273,14 +389,12 @@ int in_addr_ifindex_to_string(int family, const union in_addr_union *u, int ifin
return -ENOMEM;
errno = 0;
if (!inet_ntop(family, u, x, l)) {
free(x);
if (!inet_ntop(family, u, x, l))
return errno > 0 ? -errno : -EINVAL;
}
sprintf(strchr(x, 0), "%%%i", ifindex);
*ret = x;
*ret = TAKE_PTR(x);
return 0;
fallback:

View file

@ -35,7 +35,9 @@ bool in4_addr_is_non_local(const struct in_addr *a);
int in_addr_equal(int family, const union in_addr_union *a, const union in_addr_union *b);
int in_addr_prefix_intersect(int family, const union in_addr_union *a, unsigned aprefixlen, const union in_addr_union *b, unsigned bprefixlen);
int in_addr_prefix_next(int family, union in_addr_union *u, unsigned prefixlen);
int in_addr_random_prefix(int family, union in_addr_union *u, unsigned prefixlen_fixed_part, unsigned prefixlen);
int in_addr_to_string(int family, const union in_addr_union *u, char **ret);
int in_addr_prefix_to_string(int family, const union in_addr_union *u, unsigned prefixlen, char **ret);
int in_addr_ifindex_to_string(int family, const union in_addr_union *u, int ifindex, char **ret);
int in_addr_from_string(int family, const char *s, union in_addr_union *ret);
int in_addr_from_string_auto(const char *s, int *ret_family, union in_addr_union *ret);

View file

@ -120,6 +120,19 @@ int log_internalv_realm(
log_internalv_realm(LOG_REALM_PLUS_LEVEL(LOG_REALM, (level)), __VA_ARGS__)
/* Realm is fixed to LOG_REALM_SYSTEMD for those */
int log_object_internalv(
int level,
int error,
const char *file,
int line,
const char *func,
const char *object_field,
const char *object,
const char *extra_field,
const char *extra,
const char *format,
va_list ap) _printf_(10,0);
int log_object_internal(
int level,
int error,
@ -145,7 +158,12 @@ int log_oom_internal(
const char *file,
int line,
const char *func);
#endif /* NM_IGNORED */
#define log_oom_internal(realm, file, line, func) \
log_internal_realm (LOG_REALM_PLUS_LEVEL (realm, LOG_ERR), \
ENOMEM, file, line, func, "Out of memory.")
#if 0 /* NM_IGNORED */
int log_format_iovec(
struct iovec *iovec,
size_t iovec_len,
@ -315,7 +333,7 @@ int log_syntax_invalid_utf8_internal(
int _level = (level), _e = (error); \
(log_get_max_level() >= LOG_PRI(_level)) \
? log_syntax_internal(unit, _level, config_file, config_line, _e, __FILE__, __LINE__, __func__, __VA_ARGS__) \
: -abs(_e); \
: -ERRNO_VALUE(_e); \
})
#define log_syntax_invalid_utf8(unit, level, config_file, config_line, rvalue) \

View file

@ -0,0 +1,59 @@
#include "nm-sd-adapt-shared.h"
#include <unistd.h>
#include "memory-util.h"
size_t page_size(void) {
static thread_local size_t pgsz = 0;
long r;
if (_likely_(pgsz > 0))
return pgsz;
r = sysconf(_SC_PAGESIZE);
assert(r > 0);
pgsz = (size_t) r;
return pgsz;
}
bool memeqzero(const void *data, size_t length) {
/* Does the buffer consist entirely of NULs?
* Copied from https://github.com/systemd/casync/, copied in turn from
* https://github.com/rustyrussell/ccan/blob/master/ccan/mem/mem.c#L92,
* which is licensed CC-0.
*/
const uint8_t *p = data;
size_t i;
/* Check first 16 bytes manually */
for (i = 0; i < 16; i++, length--) {
if (length == 0)
return true;
if (p[i])
return false;
}
/* Now we know first 16 bytes are NUL, memcmp with self. */
return memcmp(data, p + i, 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

View file

@ -0,0 +1,84 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
#include <inttypes.h>
#include <stdbool.h>
#include <string.h>
#include <sys/types.h>
#include "macro.h"
size_t page_size(void) _pure_;
#define PAGE_ALIGN(l) ALIGN_TO((l), page_size())
/* Normal memcpy requires src to be nonnull. We do nothing if n is 0. */
static inline void memcpy_safe(void *dst, const void *src, size_t n) {
if (n == 0)
return;
assert(src);
memcpy(dst, src, n);
}
/* Normal memcmp requires s1 and s2 to be nonnull. We do nothing if n is 0. */
static inline int memcmp_safe(const void *s1, const void *s2, size_t n) {
if (n == 0)
return 0;
assert(s1);
assert(s2);
return memcmp(s1, s2, n);
}
/* Compare s1 (length n1) with s2 (length n2) in lexicographic order. */
static inline int memcmp_nn(const void *s1, size_t n1, const void *s2, size_t n2) {
return memcmp_safe(s1, s2, MIN(n1, n2))
?: CMP(n1, n2);
}
#define memzero(x,l) \
({ \
size_t _l_ = (l); \
void *_x_ = (x); \
_l_ == 0 ? _x_ : memset(_x_, 0, _l_); \
})
#define zero(x) (memzero(&(x), sizeof(x)))
bool memeqzero(const void *data, size_t length);
#define eqzero(x) memeqzero(x, sizeof(x))
static inline void *mempset(void *s, int c, size_t n) {
memset(s, c, n);
return (uint8_t*)s + n;
}
/* Normal memmem() requires haystack to be nonnull, which is annoying for zero-length buffers */
static inline void *memmem_safe(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen) {
if (needlelen <= 0)
return (void*) haystack;
if (haystacklen < needlelen)
return NULL;
assert(haystack);
assert(needle);
return memmem(haystack, haystacklen, needle, 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
/* Use with _cleanup_ to erase a single 'char' when leaving scope */
static inline void erase_char(char *p) {
explicit_bzero_safe(p, sizeof(char));
}

View file

@ -7,6 +7,7 @@
#include "env-util.h"
#include "macro.h"
#include "memory-util.h"
#include "mempool.h"
#include "process-util.h"
#include "util.h"

View file

@ -0,0 +1,66 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
#include <sys/socket.h>
#if 0 /* NM_IGNORED */
#if HAVE_LINUX_VM_SOCKETS_H
#include <linux/vm_sockets.h>
#else
#define VMADDR_CID_ANY -1U
struct sockaddr_vm {
unsigned short svm_family;
unsigned short svm_reserved1;
unsigned int svm_port;
unsigned int svm_cid;
unsigned char svm_zero[sizeof(struct sockaddr) -
sizeof(unsigned short) -
sizeof(unsigned short) -
sizeof(unsigned int) -
sizeof(unsigned int)];
};
#endif /* !HAVE_LINUX_VM_SOCKETS_H */
#endif /* NM_IGNORED */
#ifndef AF_VSOCK
#define AF_VSOCK 40
#endif
#ifndef SO_REUSEPORT
#define SO_REUSEPORT 15
#endif
#ifndef SO_PEERGROUPS
#define SO_PEERGROUPS 59
#endif
#ifndef SO_BINDTOIFINDEX
#define SO_BINDTOIFINDEX 62
#endif
#ifndef SOL_NETLINK
#define SOL_NETLINK 270
#endif
#ifndef SOL_ALG
#define SOL_ALG 279
#endif
/* Not exposed yet. Defined in include/linux/socket.h. */
#ifndef SOL_SCTP
#define SOL_SCTP 132
#endif
/* Not exposed yet. Defined in include/linux/socket.h */
#ifndef SCM_SECURITY
#define SCM_SECURITY 0x03
#endif
/* netinet/in.h */
#ifndef IP_FREEBIND
#define IP_FREEBIND 15
#endif
#ifndef IP_TRANSPARENT
#define IP_TRANSPARENT 19
#endif

View file

@ -0,0 +1,53 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
#include <linux/types.h>
#include <sys/stat.h>
#if 0 /* NM_IGNORED */
#if WANT_LINUX_STAT_H
#include <linux/stat.h>
#endif
/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */
#if !HAVE_STRUCT_STATX
struct statx_timestamp {
__s64 tv_sec;
__u32 tv_nsec;
__s32 __reserved;
};
struct statx {
__u32 stx_mask;
__u32 stx_blksize;
__u64 stx_attributes;
__u32 stx_nlink;
__u32 stx_uid;
__u32 stx_gid;
__u16 stx_mode;
__u16 __spare0[1];
__u64 stx_ino;
__u64 stx_size;
__u64 stx_blocks;
__u64 stx_attributes_mask;
struct statx_timestamp stx_atime;
struct statx_timestamp stx_btime;
struct statx_timestamp stx_ctime;
struct statx_timestamp stx_mtime;
__u32 stx_rdev_major;
__u32 stx_rdev_minor;
__u32 stx_dev_major;
__u32 stx_dev_minor;
__u64 __spare2[14];
};
#endif
#endif /* NM_IGNORED */
/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */
#ifndef STATX_BTIME
#define STATX_BTIME 0x00000800U
#endif
/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */
#ifndef AT_STATX_DONT_SYNC
#define AT_STATX_DONT_SYNC 0x4000
#endif

View file

@ -23,6 +23,7 @@
#include "log.h"
#include "macro.h"
#include "missing.h"
#include "nulstr-util.h"
#include "parse-util.h"
#include "path-util.h"
#include "stat-util.h"
@ -1112,48 +1113,40 @@ int path_simplify_and_warn(
unsigned line,
const char *lvalue) {
bool absolute, fatal = flag & PATH_CHECK_FATAL;
bool fatal = flag & PATH_CHECK_FATAL;
assert(!FLAGS_SET(flag, PATH_CHECK_ABSOLUTE | PATH_CHECK_RELATIVE));
if (!utf8_is_valid(path)) {
log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, path);
return -EINVAL;
}
if (!utf8_is_valid(path))
return log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, path);
if (flag & (PATH_CHECK_ABSOLUTE | PATH_CHECK_RELATIVE)) {
bool absolute;
absolute = path_is_absolute(path);
if (!absolute && (flag & PATH_CHECK_ABSOLUTE)) {
log_syntax(unit, LOG_ERR, filename, line, 0,
"%s= path is not absolute%s: %s",
lvalue, fatal ? "" : ", ignoring", path);
return -EINVAL;
}
if (!absolute && (flag & PATH_CHECK_ABSOLUTE))
return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL),
"%s= path is not absolute%s: %s",
lvalue, fatal ? "" : ", ignoring", path);
if (absolute && (flag & PATH_CHECK_RELATIVE)) {
log_syntax(unit, LOG_ERR, filename, line, 0,
"%s= path is absolute%s: %s",
lvalue, fatal ? "" : ", ignoring", path);
return -EINVAL;
}
if (absolute && (flag & PATH_CHECK_RELATIVE))
return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL),
"%s= path is absolute%s: %s",
lvalue, fatal ? "" : ", ignoring", path);
}
path_simplify(path, true);
if (!path_is_normalized(path)) {
log_syntax(unit, LOG_ERR, filename, line, 0,
"%s= path is not normalized%s: %s",
lvalue, fatal ? "" : ", ignoring", path);
return -EINVAL;
}
if (!path_is_valid(path))
return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL),
"%s= path has invalid length (%zu bytes)%s.",
lvalue, strlen(path), fatal ? "" : ", ignoring");
if (!path_is_valid(path)) {
log_syntax(unit, LOG_ERR, filename, line, 0,
"%s= path has invalid length (%zu bytes)%s.",
lvalue, strlen(path), fatal ? "" : ", ignoring");
return -EINVAL;
}
if (!path_is_normalized(path))
return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL),
"%s= path is not normalized%s: %s",
lvalue, fatal ? "" : ", ignoring", path);
return 0;
}

View file

@ -36,7 +36,9 @@
#include "ioprio.h"
#include "log.h"
#include "macro.h"
#include "memory-util.h"
#include "missing.h"
#include "namespace-util.h"
#include "process-util.h"
#include "raw-clone.h"
#include "rlimit-util.h"
@ -46,7 +48,6 @@
#include "string-util.h"
#include "terminal-util.h"
#include "user-util.h"
#include "util.h"
#if 0 /* NM_IGNORED */
int get_process_state(pid_t pid) {
@ -938,6 +939,20 @@ int getenv_for_pid(pid_t pid, const char *field, char **ret) {
return 0;
}
int pid_is_my_child(pid_t pid) {
pid_t ppid;
int r;
if (pid <= 1)
return false;
r = get_process_ppid(pid, &ppid);
if (r < 0)
return r;
return ppid == getpid_cached();
}
bool pid_is_unwaited(pid_t pid) {
/* Checks whether a PID is still valid at all, including a zombie */
@ -1007,7 +1022,7 @@ _noreturn_ void freeze(void) {
log_close();
/* Make sure nobody waits for us on a socket anymore */
close_all_fds(NULL, 0);
(void) close_all_fds(NULL, 0);
sync();
@ -1543,6 +1558,40 @@ int set_oom_score_adjust(int value) {
WRITE_STRING_FILE_VERIFY_ON_FAILURE|WRITE_STRING_FILE_DISABLE_BUFFER);
}
int cpus_in_affinity_mask(void) {
size_t n = 16;
int r;
for (;;) {
cpu_set_t *c;
c = CPU_ALLOC(n);
if (!c)
return -ENOMEM;
if (sched_getaffinity(0, CPU_ALLOC_SIZE(n), c) >= 0) {
int k;
k = CPU_COUNT_S(CPU_ALLOC_SIZE(n), c);
CPU_FREE(c);
if (k <= 0)
return -EINVAL;
return k;
}
r = -errno;
CPU_FREE(c);
if (r != -EINVAL)
return r;
if (n > SIZE_MAX/2)
return -ENOMEM;
n *= 2;
}
}
static const char *const ioprio_class_table[] = {
[IOPRIO_CLASS_NONE] = "none",
[IOPRIO_CLASS_RT] = "realtime",

View file

@ -12,6 +12,7 @@
#include <sys/resource.h>
#include <sys/types.h>
#include "alloc-util.h"
#include "format-util.h"
#include "ioprio.h"
#include "macro.h"
@ -68,6 +69,7 @@ int getenv_for_pid(pid_t pid, const char *field, char **_value);
bool pid_is_alive(pid_t pid);
bool pid_is_unwaited(pid_t pid);
int pid_is_my_child(pid_t pid);
int pid_from_same_root_fs(pid_t pid);
bool is_main_thread(void);
@ -194,3 +196,5 @@ assert_cc(TASKS_MAX <= (unsigned long) PID_T_MAX)
(pid) = 0; \
_pid_; \
})
int cpus_in_affinity_mask(void);

View file

@ -25,16 +25,13 @@
# include <linux/random.h>
#endif
#include "alloc-util.h"
#include "fd-util.h"
#include "io-util.h"
#include "missing.h"
#include "random-util.h"
#include "time-util.h"
#if HAS_FEATURE_MEMORY_SANITIZER
#include <sanitizer/msan_interface.h>
#endif
int rdrand(unsigned long *ret) {
#if defined(__i386__) || defined(__x86_64__)
@ -60,11 +57,7 @@ int rdrand(unsigned long *ret) {
"setc %1"
: "=r" (*ret),
"=qm" (err));
#if HAS_FEATURE_MEMORY_SANITIZER
__msan_unpoison(&err, sizeof(err));
#endif
msan_unpoison(&err, sizeof(err));
if (!err)
return -EAGAIN;

View file

@ -1,54 +0,0 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
/* A type-safe atomic refcounter.
*
* DO NOT USE THIS UNLESS YOU ACTUALLY CARE ABOUT THREAD SAFETY! */
typedef struct {
volatile unsigned _value;
} RefCount;
#define REFCNT_GET(r) ((r)._value)
#define REFCNT_INC(r) (__sync_add_and_fetch(&(r)._value, 1))
#define REFCNT_DEC(r) (__sync_sub_and_fetch(&(r)._value, 1))
#define REFCNT_INIT ((RefCount) { ._value = 1 })
#define _DEFINE_ATOMIC_REF_FUNC(type, name, scope) \
scope type *name##_ref(type *p) { \
if (!p) \
return NULL; \
\
assert_se(REFCNT_INC(p->n_ref) >= 2); \
return p; \
}
#define _DEFINE_ATOMIC_UNREF_FUNC(type, name, free_func, scope) \
scope type *name##_unref(type *p) { \
if (!p) \
return NULL; \
\
if (REFCNT_DEC(p->n_ref) > 0) \
return NULL; \
\
return free_func(p); \
}
#define DEFINE_ATOMIC_REF_FUNC(type, name) \
_DEFINE_ATOMIC_REF_FUNC(type, name,)
#define DEFINE_PUBLIC_ATOMIC_REF_FUNC(type, name) \
_DEFINE_ATOMIC_REF_FUNC(type, name, _public_)
#define DEFINE_ATOMIC_UNREF_FUNC(type, name, free_func) \
_DEFINE_ATOMIC_UNREF_FUNC(type, name, free_func,)
#define DEFINE_PUBLIC_ATOMIC_UNREF_FUNC(type, name, free_func) \
_DEFINE_ATOMIC_UNREF_FUNC(type, name, free_func, _public_)
#define DEFINE_ATOMIC_REF_UNREF_FUNC(type, name, free_func) \
DEFINE_ATOMIC_REF_FUNC(type, name); \
DEFINE_ATOMIC_UNREF_FUNC(type, name, free_func);
#define DEFINE_PUBLIC_ATOMIC_REF_UNREF_FUNC(type, name, free_func) \
DEFINE_PUBLIC_ATOMIC_REF_FUNC(type, name); \
DEFINE_PUBLIC_ATOMIC_UNREF_FUNC(type, name, free_func);

View file

@ -23,6 +23,7 @@
#include "format-util.h"
#include "log.h"
#include "macro.h"
#include "memory-util.h"
#include "missing.h"
#include "parse-util.h"
#include "path-util.h"
@ -33,7 +34,6 @@
#include "strv.h"
#include "user-util.h"
#include "utf8.h"
#include "util.h"
#if 0 /* NM_IGNORED */
#if ENABLE_IDN
@ -238,23 +238,32 @@ int socket_address_parse_and_warn(SocketAddress *a, const char *s) {
}
int socket_address_parse_netlink(SocketAddress *a, const char *s) {
int family;
_cleanup_free_ char *word = NULL;
unsigned group = 0;
_cleanup_free_ char *sfamily = NULL;
int family, r;
assert(a);
assert(s);
zero(*a);
a->type = SOCK_RAW;
errno = 0;
if (sscanf(s, "%ms %u", &sfamily, &group) < 1)
return errno > 0 ? -errno : -EINVAL;
r = extract_first_word(&s, &word, NULL, 0);
if (r < 0)
return r;
if (r == 0)
return -EINVAL;
family = netlink_family_from_string(sfamily);
family = netlink_family_from_string(word);
if (family < 0)
return -EINVAL;
if (!isempty(s)) {
r = safe_atou(s, &group);
if (r < 0)
return r;
}
a->sockaddr.nl.nl_family = AF_NETLINK;
a->sockaddr.nl.nl_groups = group;
@ -1351,3 +1360,39 @@ int sockaddr_un_set_path(struct sockaddr_un *ret, const char *path) {
}
}
#endif /* NM_IGNORED */
int socket_bind_to_ifname(int fd, const char *ifname) {
assert(fd >= 0);
/* Call with NULL to drop binding */
if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, ifname, strlen_ptr(ifname)) < 0)
return -errno;
return 0;
}
int socket_bind_to_ifindex(int fd, int ifindex) {
char ifname[IFNAMSIZ] = "";
assert(fd >= 0);
if (ifindex <= 0) {
/* Drop binding */
if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, NULL, 0) < 0)
return -errno;
return 0;
}
if (setsockopt(fd, SOL_SOCKET, SO_BINDTOIFINDEX, &ifindex, sizeof(ifindex)) >= 0)
return 0;
if (errno != ENOPROTOOPT)
return -errno;
/* Fall back to SO_BINDTODEVICE on kernels < 5.0 which didn't have SO_BINDTOIFINDEX */
if (!if_indextoname(ifindex, ifname))
return -errno;
return socket_bind_to_ifname(fd, ifname);
}

View file

@ -200,3 +200,6 @@ static inline int setsockopt_int(int fd, int level, int optname, int value) {
return 0;
}
int socket_bind_to_ifname(int fd, const char *ifname);
int socket_bind_to_ifindex(int fd, int ifindex);

View file

@ -0,0 +1,70 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
#include <stdlib.h>
#include "macro.h"
void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size,
__compar_d_fn_t compar, void *arg);
#define typesafe_bsearch_r(k, b, n, func, userdata) \
({ \
const typeof(b[0]) *_k = k; \
int (*_func_)(const typeof(b[0])*, const typeof(b[0])*, typeof(userdata)) = func; \
xbsearch_r((const void*) _k, (b), (n), sizeof((b)[0]), (__compar_d_fn_t) _func_, userdata); \
})
/**
* Normal bsearch requires base to be nonnull. Here were require
* that only if nmemb > 0.
*/
static inline void* bsearch_safe(const void *key, const void *base,
size_t nmemb, size_t size, __compar_fn_t compar) {
if (nmemb <= 0)
return NULL;
assert(base);
return bsearch(key, base, nmemb, size, compar);
}
#define typesafe_bsearch(k, b, n, func) \
({ \
const typeof(b[0]) *_k = k; \
int (*_func_)(const typeof(b[0])*, const typeof(b[0])*) = func; \
bsearch_safe((const void*) _k, (b), (n), sizeof((b)[0]), (__compar_fn_t) _func_); \
})
/**
* Normal qsort requires base to be nonnull. Here were require
* that only if nmemb > 0.
*/
static inline void qsort_safe(void *base, size_t nmemb, size_t size, __compar_fn_t compar) {
if (nmemb <= 1)
return;
assert(base);
qsort(base, nmemb, size, compar);
}
/* A wrapper around the above, but that adds typesafety: the element size is automatically derived from the type and so
* is the prototype for the comparison function */
#define typesafe_qsort(p, n, func) \
({ \
int (*_func_)(const typeof(p[0])*, const typeof(p[0])*) = func; \
qsort_safe((p), (n), sizeof((p)[0]), (__compar_fn_t) _func_); \
})
static inline void qsort_r_safe(void *base, size_t nmemb, size_t size, __compar_d_fn_t compar, void *userdata) {
if (nmemb <= 1)
return;
assert(base);
qsort_r(base, nmemb, size, compar, userdata);
}
#define typesafe_qsort_r(p, n, func, userdata) \
({ \
int (*_func_)(const typeof(p[0])*, const typeof(p[0])*, typeof(userdata)) = func; \
qsort_r_safe((p), (n), sizeof((p)[0]), (__compar_d_fn_t) _func_, userdata); \
})

View file

@ -226,52 +226,6 @@ int fd_is_network_fs(int fd) {
return is_network_fs(&s);
}
int fd_is_network_ns(int fd) {
struct statfs s;
int r;
/* Checks whether the specified file descriptor refers to a network namespace. On old kernels there's no nice
* way to detect that, hence on those we'll return a recognizable error (EUCLEAN), so that callers can handle
* this somewhat nicely.
*
* This function returns > 0 if the fd definitely refers to a network namespace, 0 if it definitely does not
* refer to a network namespace, -EUCLEAN if we can't determine, and other negative error codes on error. */
if (fstatfs(fd, &s) < 0)
return -errno;
if (!is_fs_type(&s, NSFS_MAGIC)) {
/* On really old kernels, there was no "nsfs", and network namespace sockets belonged to procfs
* instead. Handle that in a somewhat smart way. */
if (is_fs_type(&s, PROC_SUPER_MAGIC)) {
struct statfs t;
/* OK, so it is procfs. Let's see if our own network namespace is procfs, too. If so, then the
* passed fd might refer to a network namespace, but we can't know for sure. In that case,
* return a recognizable error. */
if (statfs("/proc/self/ns/net", &t) < 0)
return -errno;
if (s.f_type == t.f_type)
return -EUCLEAN; /* It's possible, we simply don't know */
}
return 0; /* No! */
}
r = ioctl(fd, NS_GET_NSTYPE);
if (r < 0) {
if (errno == ENOTTY) /* Old kernels didn't know this ioctl, let's also return a recognizable error in that case */
return -EUCLEAN;
return -errno;
}
return r == CLONE_NEWNET;
}
int path_is_temporary_fs(const char *path) {
_cleanup_close_ int fd = -1;

View file

@ -1,6 +1,7 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
#include <fcntl.h>
#include <stdbool.h>
#include <stddef.h>
#include <sys/stat.h>
@ -50,8 +51,6 @@ bool is_network_fs(const struct statfs *s) _pure_;
int fd_is_temporary_fs(int fd);
int fd_is_network_fs(int fd);
int fd_is_network_ns(int fd);
int path_is_temporary_fs(const char *path);
/* Because statfs.t_type can be int on some architectures, we have to cast

View file

@ -7,7 +7,7 @@
#include <sys/types.h>
#include "macro.h"
#include "util.h"
#include "memory-util.h"
#define snprintf_ok(buf, len, fmt, ...) \
((size_t) snprintf(buf, len, fmt, __VA_ARGS__) < (len))

View file

@ -59,13 +59,13 @@ ssize_t string_table_lookup(const char * const *table, size_t len, const char *k
#define _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING_FALLBACK(name,type,max,scope) \
scope type name##_from_string(const char *s) { \
type i; \
unsigned u = 0; \
type i; \
if (!s) \
return (type) -1; \
for (i = 0; i < (type) ELEMENTSOF(name##_table); i++) \
if (streq_ptr(name##_table[i], s)) \
return i; \
i = (type) string_table_lookup(name##_table, ELEMENTSOF(name##_table), s); \
if (i >= 0) \
return i; \
if (safe_atou(s, &u) >= 0 && u <= max) \
return (type) u; \
return (type) -1; \

View file

@ -12,14 +12,15 @@
#include "alloc-util.h"
#include "escape.h"
#include "fileio.h"
#include "gunicode.h"
#include "locale-util.h"
#include "macro.h"
#include "memory-util.h"
#include "string-util.h"
#include "terminal-util.h"
#include "utf8.h"
#include "util.h"
#include "fileio.h"
int strcmp_ptr(const char *a, const char *b) {
@ -681,19 +682,6 @@ char *cellescape(char *buf, size_t len, const char *s) {
}
#endif /* NM_IGNORED */
bool nulstr_contains(const char *nulstr, const char *needle) {
const char *i;
if (!nulstr)
return false;
NULSTR_FOREACH(i, nulstr)
if (streq(i, needle))
return true;
return false;
}
char* strshorten(char *s, size_t l) {
assert(s);
@ -1056,25 +1044,6 @@ int free_and_strndup(char **p, const char *s, size_t l) {
return 1;
}
#if !HAVE_EXPLICIT_BZERO
/*
* 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
char* string_erase(char *x) {
if (!x)
return NULL;

View file

@ -165,8 +165,6 @@ char *cellescape(char *buf, size_t len, const char *s);
/* This limit is arbitrary, enough to give some idea what the string contains */
#define CELLESCAPE_DEFAULT_LENGTH 64
bool nulstr_contains(const char *nulstr, const char *needle);
char* strshorten(char *s, size_t l);
char *strreplace(const char *text, const char *old_string, const char *new_string);
@ -182,34 +180,13 @@ char *strrep(const char *s, unsigned n);
int split_pair(const char *s, const char *sep, char **l, char **r);
int free_and_strdup(char **p, const char *s);
static inline int free_and_strdup_warn(char **p, const char *s) {
if (free_and_strdup(p, s) < 0)
return log_oom();
return 0;
}
int free_and_strndup(char **p, const char *s, size_t l);
/* Normal memmem() requires haystack to be nonnull, which is annoying for zero-length buffers */
static inline void *memmem_safe(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen) {
if (needlelen <= 0)
return (void*) haystack;
if (haystacklen < needlelen)
return NULL;
assert(haystack);
assert(needle);
return memmem(haystack, haystacklen, needle, 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
char *string_erase(char *x);
char *string_free_erase(char *s);

View file

@ -13,9 +13,10 @@
#include "escape.h"
#include "extract-word.h"
#include "fileio.h"
#include "nulstr-util.h"
#include "sort-util.h"
#include "string-util.h"
#include "strv.h"
#include "util.h"
char *strv_find(char **l, const char *name) {
char **i;
@ -651,6 +652,7 @@ char **strv_parse_nulstr(const char *s, size_t l) {
return v;
}
#if 0 /* NM_IGNORED */
char **strv_split_nulstr(const char *s) {
const char *i;
char **r = NULL;
@ -666,6 +668,7 @@ char **strv_split_nulstr(const char *s) {
return r;
}
#endif /* NM_IGNORED */
int strv_make_nulstr(char **l, char **p, size_t *q) {
/* A valid nulstr with two NULs at the end will be created, but
@ -722,6 +725,7 @@ bool strv_overlap(char **a, char **b) {
return false;
}
#if 0 /* NM_IGNORED */
static int str_compare(char * const *a, char * const *b) {
return strcmp(*a, *b);
}
@ -730,6 +734,7 @@ char **strv_sort(char **l) {
typesafe_qsort(l, strv_length(l), str_compare);
return l;
}
#endif /* NM_IGNORED */
bool strv_equal(char **a, char **b) {

View file

@ -5,12 +5,12 @@
#include <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include "alloc-util.h"
#include "extract-word.h"
#include "macro.h"
#include "string-util.h"
#include "util.h"
char *strv_find(char **l, const char *name) _pure_;
char *strv_find_prefix(char **l, const char *name) _pure_;

View file

@ -1219,7 +1219,7 @@ int get_timezones(char ***ret) {
n_allocated = 2;
n_zones = 1;
f = fopen("/usr/share/zoneinfo/zone.tab", "re");
f = fopen("/usr/share/zoneinfo/zone1970.tab", "re");
if (f) {
for (;;) {
_cleanup_free_ char *line = NULL;

View file

@ -65,12 +65,7 @@ static bool unichar_is_control(char32_t ch) {
#endif /* NM_IGNORED */
/* count of characters used to encode one unicode char */
static size_t utf8_encoded_expected_len(const char *str) {
uint8_t c;
assert(str);
c = (uint8_t) str[0];
static size_t utf8_encoded_expected_len(uint8_t c) {
if (c < 0x80)
return 1;
if ((c & 0xe0) == 0xc0)
@ -94,7 +89,7 @@ int utf8_encoded_to_unichar(const char *str, char32_t *ret_unichar) {
assert(str);
len = utf8_encoded_expected_len(str);
len = utf8_encoded_expected_len(str[0]);
switch (len) {
case 1:
@ -138,14 +133,14 @@ bool utf8_is_printable_newline(const char* str, size_t length, bool newline) {
assert(str);
for (p = str; length;) {
for (p = str; length > 0;) {
int encoded_len, r;
char32_t val;
encoded_len = utf8_encoded_valid_unichar(p);
if (encoded_len < 0 ||
(size_t) encoded_len > length)
encoded_len = utf8_encoded_valid_unichar(p, length);
if (encoded_len < 0)
return false;
assert(encoded_len > 0 && (size_t) encoded_len <= length);
r = utf8_encoded_to_unichar(p, &val);
if (r < 0 ||
@ -170,7 +165,7 @@ char *utf8_is_valid(const char *str) {
while (*p) {
int len;
len = utf8_encoded_valid_unichar(p);
len = utf8_encoded_valid_unichar(p, (size_t) -1);
if (len < 0)
return NULL;
@ -192,7 +187,7 @@ char *utf8_escape_invalid(const char *str) {
while (*str) {
int len;
len = utf8_encoded_valid_unichar(str);
len = utf8_encoded_valid_unichar(str, (size_t) -1);
if (len > 0) {
s = mempcpy(s, str, len);
str += len;
@ -220,7 +215,7 @@ char *utf8_escape_non_printable(const char *str) {
while (*str) {
int len;
len = utf8_encoded_valid_unichar(str);
len = utf8_encoded_valid_unichar(str, (size_t) -1);
if (len > 0) {
if (utf8_is_printable(str, len)) {
s = mempcpy(s, str, len);
@ -416,7 +411,7 @@ char16_t *utf8_to_utf16(const char *s, size_t length) {
char32_t unichar;
size_t e;
e = utf8_encoded_expected_len(s + i);
e = utf8_encoded_expected_len(s[i]);
if (e <= 1) /* Invalid and single byte characters are copied as they are */
goto copy;
@ -469,17 +464,24 @@ static int utf8_unichar_to_encoded_len(char32_t unichar) {
}
/* validate one encoded unicode char and return its length */
int utf8_encoded_valid_unichar(const char *str) {
int utf8_encoded_valid_unichar(const char *str, size_t length /* bytes */) {
char32_t unichar;
size_t len, i;
int r;
assert(str);
assert(length > 0);
len = utf8_encoded_expected_len(str);
/* We read until NUL, at most length bytes. (size_t) -1 may be used to disable the length check. */
len = utf8_encoded_expected_len(str[0]);
if (len == 0)
return -EINVAL;
/* Do we have a truncated multi-byte character? */
if (len > length)
return -EINVAL;
/* ascii is valid */
if (len == 1)
return 1;
@ -513,7 +515,7 @@ size_t utf8_n_codepoints(const char *str) {
while (*str != 0) {
int k;
k = utf8_encoded_valid_unichar(str);
k = utf8_encoded_valid_unichar(str, (size_t) -1);
if (k < 0)
return (size_t) -1;

View file

@ -32,7 +32,7 @@ char16_t *utf8_to_utf16(const char *s, size_t length);
size_t char16_strlen(const char16_t *s); /* returns the number of 16bit words in the string (not bytes!) */
int utf8_encoded_valid_unichar(const char *str);
int utf8_encoded_valid_unichar(const char *str, size_t length);
int utf8_encoded_to_unichar(const char *str, char32_t *ret_unichar);
static inline bool utf16_is_surrogate(char16_t c) {

View file

@ -21,7 +21,6 @@
#include "alloc-util.h"
#include "btrfs-util.h"
#include "build.h"
#include "cgroup-util.h"
#include "def.h"
#include "device-nodes.h"
#include "dirent-util.h"
@ -54,35 +53,6 @@
int saved_argc = 0;
char **saved_argv = NULL;
static int saved_in_initrd = -1;
#endif /* NM_IGNORED */
size_t page_size(void) {
static thread_local size_t pgsz = 0;
long r;
if (_likely_(pgsz > 0))
return pgsz;
r = sysconf(_SC_PAGESIZE);
assert(r > 0);
pgsz = (size_t) r;
return pgsz;
}
#if 0 /* NM_IGNORED */
bool plymouth_running(void) {
return access("/run/plymouth/pid", F_OK) >= 0;
}
bool display_is_local(const char *display) {
assert(display);
return
display[0] == ':' &&
display[1] >= '0' &&
display[1] <= '9';
}
bool kexec_loaded(void) {
_cleanup_free_ char *s = NULL;
@ -146,53 +116,6 @@ void in_initrd_force(bool value) {
saved_in_initrd = value;
}
/* hey glibc, APIs with callbacks without a user pointer are so useless */
void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size,
__compar_d_fn_t compar, void *arg) {
size_t l, u, idx;
const void *p;
int comparison;
assert(!size_multiply_overflow(nmemb, size));
l = 0;
u = nmemb;
while (l < u) {
idx = (l + u) / 2;
p = (const uint8_t*) base + idx * size;
comparison = compar(key, p, arg);
if (comparison < 0)
u = idx;
else if (comparison > 0)
l = idx + 1;
else
return (void *)p;
}
return NULL;
}
bool memeqzero(const void *data, size_t length) {
/* Does the buffer consist entirely of NULs?
* Copied from https://github.com/systemd/casync/, copied in turn from
* https://github.com/rustyrussell/ccan/blob/master/ccan/mem/mem.c#L92,
* which is licensed CC-0.
*/
const uint8_t *p = data;
size_t i;
/* Check first 16 bytes manually */
for (i = 0; i < 16; i++, length--) {
if (length == 0)
return true;
if (p[i])
return false;
}
/* Now we know first 16 bytes are NUL, memcmp with self. */
return memcmp(data, p + i, length) == 0;
}
int on_ac_power(void) {
bool found_offline = false, found_online = false;
_cleanup_closedir_ DIR *d = NULL;
@ -299,268 +222,6 @@ int container_get_leader(const char *machine, pid_t *pid) {
return 0;
}
int namespace_open(pid_t pid, int *pidns_fd, int *mntns_fd, int *netns_fd, int *userns_fd, int *root_fd) {
_cleanup_close_ int pidnsfd = -1, mntnsfd = -1, netnsfd = -1, usernsfd = -1;
int rfd = -1;
assert(pid >= 0);
if (mntns_fd) {
const char *mntns;
mntns = procfs_file_alloca(pid, "ns/mnt");
mntnsfd = open(mntns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
if (mntnsfd < 0)
return -errno;
}
if (pidns_fd) {
const char *pidns;
pidns = procfs_file_alloca(pid, "ns/pid");
pidnsfd = open(pidns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
if (pidnsfd < 0)
return -errno;
}
if (netns_fd) {
const char *netns;
netns = procfs_file_alloca(pid, "ns/net");
netnsfd = open(netns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
if (netnsfd < 0)
return -errno;
}
if (userns_fd) {
const char *userns;
userns = procfs_file_alloca(pid, "ns/user");
usernsfd = open(userns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
if (usernsfd < 0 && errno != ENOENT)
return -errno;
}
if (root_fd) {
const char *root;
root = procfs_file_alloca(pid, "root");
rfd = open(root, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
if (rfd < 0)
return -errno;
}
if (pidns_fd)
*pidns_fd = pidnsfd;
if (mntns_fd)
*mntns_fd = mntnsfd;
if (netns_fd)
*netns_fd = netnsfd;
if (userns_fd)
*userns_fd = usernsfd;
if (root_fd)
*root_fd = rfd;
pidnsfd = mntnsfd = netnsfd = usernsfd = -1;
return 0;
}
int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int root_fd) {
if (userns_fd >= 0) {
/* Can't setns to your own userns, since then you could
* escalate from non-root to root in your own namespace, so
* check if namespaces equal before attempting to enter. */
_cleanup_free_ char *userns_fd_path = NULL;
int r;
if (asprintf(&userns_fd_path, "/proc/self/fd/%d", userns_fd) < 0)
return -ENOMEM;
r = files_same(userns_fd_path, "/proc/self/ns/user", 0);
if (r < 0)
return r;
if (r)
userns_fd = -1;
}
if (pidns_fd >= 0)
if (setns(pidns_fd, CLONE_NEWPID) < 0)
return -errno;
if (mntns_fd >= 0)
if (setns(mntns_fd, CLONE_NEWNS) < 0)
return -errno;
if (netns_fd >= 0)
if (setns(netns_fd, CLONE_NEWNET) < 0)
return -errno;
if (userns_fd >= 0)
if (setns(userns_fd, CLONE_NEWUSER) < 0)
return -errno;
if (root_fd >= 0) {
if (fchdir(root_fd) < 0)
return -errno;
if (chroot(".") < 0)
return -errno;
}
return reset_uid_gid();
}
uint64_t physical_memory(void) {
_cleanup_free_ char *root = NULL, *value = NULL;
uint64_t mem, lim;
size_t ps;
long sc;
int r;
/* We return this as uint64_t in case we are running as 32bit process on a 64bit kernel with huge amounts of
* memory.
*
* In order to support containers nicely that have a configured memory limit we'll take the minimum of the
* physically reported amount of memory and the limit configured for the root cgroup, if there is any. */
sc = sysconf(_SC_PHYS_PAGES);
assert(sc > 0);
ps = page_size();
mem = (uint64_t) sc * (uint64_t) ps;
r = cg_get_root_path(&root);
if (r < 0) {
log_debug_errno(r, "Failed to determine root cgroup, ignoring cgroup memory limit: %m");
return mem;
}
r = cg_all_unified();
if (r < 0) {
log_debug_errno(r, "Failed to determine root unified mode, ignoring cgroup memory limit: %m");
return mem;
}
if (r > 0) {
r = cg_get_attribute("memory", root, "memory.max", &value);
if (r < 0) {
log_debug_errno(r, "Failed to read memory.max cgroup attribute, ignoring cgroup memory limit: %m");
return mem;
}
if (streq(value, "max"))
return mem;
} else {
r = cg_get_attribute("memory", root, "memory.limit_in_bytes", &value);
if (r < 0) {
log_debug_errno(r, "Failed to read memory.limit_in_bytes cgroup attribute, ignoring cgroup memory limit: %m");
return mem;
}
}
r = safe_atou64(value, &lim);
if (r < 0) {
log_debug_errno(r, "Failed to parse cgroup memory limit '%s', ignoring: %m", value);
return mem;
}
if (lim == UINT64_MAX)
return mem;
/* Make sure the limit is a multiple of our own page size */
lim /= ps;
lim *= ps;
return MIN(mem, lim);
}
uint64_t physical_memory_scale(uint64_t v, uint64_t max) {
uint64_t p, m, ps, r;
assert(max > 0);
/* Returns the physical memory size, multiplied by v divided by max. Returns UINT64_MAX on overflow. On success
* the result is a multiple of the page size (rounds down). */
ps = page_size();
assert(ps > 0);
p = physical_memory() / ps;
assert(p > 0);
m = p * v;
if (m / p != v)
return UINT64_MAX;
m /= max;
r = m * ps;
if (r / ps != m)
return UINT64_MAX;
return r;
}
uint64_t system_tasks_max(void) {
uint64_t a = TASKS_MAX, b = TASKS_MAX;
_cleanup_free_ char *root = NULL;
int r;
/* Determine the maximum number of tasks that may run on this system. We check three sources to determine this
* limit:
*
* a) the maximum tasks value the kernel allows on this architecture
* b) the cgroups pids_max attribute for the system
* c) the kernel's configured maximum PID value
*
* And then pick the smallest of the three */
r = procfs_tasks_get_limit(&a);
if (r < 0)
log_debug_errno(r, "Failed to read maximum number of tasks from /proc, ignoring: %m");
r = cg_get_root_path(&root);
if (r < 0)
log_debug_errno(r, "Failed to determine cgroup root path, ignoring: %m");
else {
_cleanup_free_ char *value = NULL;
r = cg_get_attribute("pids", root, "pids.max", &value);
if (r < 0)
log_debug_errno(r, "Failed to read pids.max attribute of cgroup root, ignoring: %m");
else if (!streq(value, "max")) {
r = safe_atou64(value, &b);
if (r < 0)
log_debug_errno(r, "Failed to parse pids.max attribute of cgroup root, ignoring: %m");
}
}
return MIN3(TASKS_MAX,
a <= 0 ? TASKS_MAX : a,
b <= 0 ? TASKS_MAX : b);
}
uint64_t system_tasks_max_scale(uint64_t v, uint64_t max) {
uint64_t t, m;
assert(max > 0);
/* Multiply the system's task value by the fraction v/max. Hence, if max==100 this calculates percentages
* relative to the system's maximum number of tasks. Returns UINT64_MAX on overflow. */
t = system_tasks_max();
assert(t > 0);
m = t * v;
if (m / t != v) /* overflow? */
return UINT64_MAX;
return m / max;
}
int version(void) {
puts("systemd " STRINGIFY(PROJECT_VERSION) " (" GIT_VERSION ")\n"
SYSTEMD_FEATURES);

View file

@ -1,34 +1,9 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
#include <alloca.h>
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
#include <limits.h>
#include <locale.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/inotify.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/statfs.h>
#include <sys/sysmacros.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
#include "format-util.h"
#include "macro.h"
#include "time-util.h"
size_t page_size(void) _pure_;
#define PAGE_ALIGN(l) ALIGN_TO((l), page_size())
static inline const char* yes_no(bool b) {
return b ? "yes" : "no";
@ -46,19 +21,14 @@ static inline const char* enable_disable(bool b) {
return b ? "enable" : "disable";
}
bool plymouth_running(void);
bool display_is_local(const char *display) _pure_;
#define NULSTR_FOREACH(i, l) \
for ((i) = (l); (i) && *(i); (i) = strchr((i), 0)+1)
#define NULSTR_FOREACH_PAIR(i, j, l) \
for ((i) = (l), (j) = strchr((i), 0)+1; (i) && *(i); (i) = strchr((j), 0)+1, (j) = *(i) ? strchr((i), 0)+1 : (i))
extern int saved_argc;
extern char **saved_argv;
static inline void save_argc_argv(int argc, char **argv) {
saved_argc = argc;
saved_argv = argv;
}
bool kexec_loaded(void);
int prot_from_flags(int flags) _const_;
@ -66,138 +36,8 @@ int prot_from_flags(int flags) _const_;
bool in_initrd(void);
void in_initrd_force(bool value);
void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size,
__compar_d_fn_t compar, void *arg);
#define typesafe_bsearch_r(k, b, n, func, userdata) \
({ \
const typeof(b[0]) *_k = k; \
int (*_func_)(const typeof(b[0])*, const typeof(b[0])*, typeof(userdata)) = func; \
xbsearch_r((const void*) _k, (b), (n), sizeof((b)[0]), (__compar_d_fn_t) _func_, userdata); \
})
/**
* Normal bsearch requires base to be nonnull. Here were require
* that only if nmemb > 0.
*/
static inline void* bsearch_safe(const void *key, const void *base,
size_t nmemb, size_t size, __compar_fn_t compar) {
if (nmemb <= 0)
return NULL;
assert(base);
return bsearch(key, base, nmemb, size, compar);
}
#define typesafe_bsearch(k, b, n, func) \
({ \
const typeof(b[0]) *_k = k; \
int (*_func_)(const typeof(b[0])*, const typeof(b[0])*) = func; \
bsearch_safe((const void*) _k, (b), (n), sizeof((b)[0]), (__compar_fn_t) _func_); \
})
/**
* Normal qsort requires base to be nonnull. Here were require
* that only if nmemb > 0.
*/
static inline void qsort_safe(void *base, size_t nmemb, size_t size, __compar_fn_t compar) {
if (nmemb <= 1)
return;
assert(base);
qsort(base, nmemb, size, compar);
}
/* A wrapper around the above, but that adds typesafety: the element size is automatically derived from the type and so
* is the prototype for the comparison function */
#define typesafe_qsort(p, n, func) \
({ \
int (*_func_)(const typeof(p[0])*, const typeof(p[0])*) = func; \
qsort_safe((p), (n), sizeof((p)[0]), (__compar_fn_t) _func_); \
})
static inline void qsort_r_safe(void *base, size_t nmemb, size_t size, __compar_d_fn_t compar, void *userdata) {
if (nmemb <= 1)
return;
assert(base);
qsort_r(base, nmemb, size, compar, userdata);
}
#define typesafe_qsort_r(p, n, func, userdata) \
({ \
int (*_func_)(const typeof(p[0])*, const typeof(p[0])*, typeof(userdata)) = func; \
qsort_r_safe((p), (n), sizeof((p)[0]), (__compar_d_fn_t) _func_, userdata); \
})
/* Normal memcpy requires src to be nonnull. We do nothing if n is 0. */
static inline void memcpy_safe(void *dst, const void *src, size_t n) {
if (n == 0)
return;
assert(src);
memcpy(dst, src, n);
}
/* Normal memcmp requires s1 and s2 to be nonnull. We do nothing if n is 0. */
static inline int memcmp_safe(const void *s1, const void *s2, size_t n) {
if (n == 0)
return 0;
assert(s1);
assert(s2);
return memcmp(s1, s2, n);
}
/* Compare s1 (length n1) with s2 (length n2) in lexicographic order. */
static inline int memcmp_nn(const void *s1, size_t n1, const void *s2, size_t n2) {
return memcmp_safe(s1, s2, MIN(n1, n2))
?: CMP(n1, n2);
}
int on_ac_power(void);
#define memzero(x,l) \
({ \
size_t _l_ = (l); \
void *_x_ = (x); \
_l_ == 0 ? _x_ : memset(_x_, 0, _l_); \
})
#define zero(x) (memzero(&(x), sizeof(x)))
bool memeqzero(const void *data, size_t length);
#define eqzero(x) memeqzero(x, sizeof(x))
static inline void *mempset(void *s, int c, size_t n) {
memset(s, c, n);
return (uint8_t*)s + n;
}
static inline void _reset_errno_(int *saved_errno) {
if (*saved_errno < 0) /* Invalidated by UNPROTECT_ERRNO? */
return;
errno = *saved_errno;
}
#define PROTECT_ERRNO \
_cleanup_(_reset_errno_) _unused_ int _saved_errno_ = errno
#define UNPROTECT_ERRNO \
do { \
errno = _saved_errno_; \
_saved_errno_ = -1; \
} while (false)
static inline int negative_errno(void) {
/* This helper should be used to shut up gcc if you know 'errno' is
* negative. Instead of "return -errno;", use "return negative_errno();"
* It will suppress bogus gcc warnings in case it assumes 'errno' might
* be 0 and thus the caller's error-handling might not be triggered. */
assert_return(errno > 0, -EINVAL);
return -errno;
}
static inline unsigned u64log2(uint64_t n) {
#if __SIZEOF_LONG_LONG__ == 8
return (n > 1) ? (unsigned) __builtin_clzll(n) ^ 63U : 0;
@ -237,15 +77,6 @@ static inline unsigned log2u_round_up(unsigned x) {
int container_get_leader(const char *machine, pid_t *pid);
int namespace_open(pid_t pid, int *pidns_fd, int *mntns_fd, int *netns_fd, int *userns_fd, int *root_fd);
int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int root_fd);
uint64_t physical_memory(void);
uint64_t physical_memory_scale(uint64_t v, uint64_t max);
uint64_t system_tasks_max(void);
uint64_t system_tasks_max_scale(uint64_t v, uint64_t max);
int version(void);
int str_verscmp(const char *s1, const char *s2);

View file

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

View file

@ -14,6 +14,7 @@
#include "siphash24.h"
#include "sparse-endian.h"
#include "stdio-util.h"
#include "udev-util.h"
#include "virt.h"
#define SYSTEMD_PEN 43793
@ -189,6 +190,13 @@ int dhcp_identifier_set_iaid(
/* 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_name(device);
}
}

View file

@ -154,7 +154,6 @@ int dhcp_network_bind_udp_socket(int ifindex, be32_t address, uint16_t port) {
.in.sin_addr.s_addr = address,
};
_cleanup_close_ int s = -1;
char ifname[IF_NAMESIZE] = "";
int r;
s = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
@ -170,12 +169,9 @@ int dhcp_network_bind_udp_socket(int ifindex, be32_t address, uint16_t port) {
return r;
if (ifindex > 0) {
if (if_indextoname(ifindex, ifname) == 0)
return -errno;
r = setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE, ifname, strlen(ifname));
r = socket_bind_to_ifindex(s, ifindex);
if (r < 0)
return -errno;
return r;
}
if (address == INADDR_ANY) {

View file

@ -10,10 +10,10 @@
#include <string.h>
#include "alloc-util.h"
#include "utf8.h"
#include "strv.h"
#include "dhcp-internal.h"
#include "memory-util.h"
#include "strv.h"
#include "utf8.h"
static int option_append(uint8_t options[], size_t size, size_t *offset,
uint8_t code, size_t optlen, const void *optval) {

View file

@ -15,10 +15,10 @@
#include "dhcp6-lease-internal.h"
#include "dhcp6-protocol.h"
#include "dns-domain.h"
#include "memory-util.h"
#include "sparse-endian.h"
#include "strv.h"
#include "unaligned.h"
#include "util.h"
typedef struct DHCP6StatusOption {
struct DHCP6Option option;

View file

@ -9,9 +9,9 @@
#include "in-addr-util.h"
#include "lldp-internal.h"
#include "lldp-neighbor.h"
#include "memory-util.h"
#include "missing.h"
#include "unaligned.h"
#include "util.h"
static void lldp_neighbor_id_hash_func(const LLDPNeighborID *id, struct siphash *state) {
siphash24_compress(id->chassis_id, id->chassis_id_size, state);

View file

@ -103,32 +103,12 @@ bool net_match_config(Set *match_mac,
char * const *match_drivers,
char * const *match_types,
char * const *match_names,
Condition *match_host,
Condition *match_virt,
Condition *match_kernel_cmdline,
Condition *match_kernel_version,
Condition *match_arch,
const struct ether_addr *dev_mac,
const char *dev_path,
const char *dev_driver,
const char *dev_type,
const char *dev_name) {
if (match_host && condition_test(match_host) <= 0)
return false;
if (match_virt && condition_test(match_virt) <= 0)
return false;
if (match_kernel_cmdline && condition_test(match_kernel_cmdline) <= 0)
return false;
if (match_kernel_version && condition_test(match_kernel_version) <= 0)
return false;
if (match_arch && condition_test(match_arch) <= 0)
return false;
if (match_mac && (!dev_mac || !set_contains(match_mac, dev_mac)))
return false;
@ -159,32 +139,31 @@ int config_parse_net_condition(const char *unit,
void *userdata) {
ConditionType cond = ltype;
Condition **ret = data;
Condition **list = data, *c;
bool negate;
Condition *c;
_cleanup_free_ char *s = NULL;
assert(filename);
assert(lvalue);
assert(rvalue);
assert(data);
if (isempty(rvalue)) {
*list = condition_free_list_type(*list, cond);
return 0;
}
negate = rvalue[0] == '!';
if (negate)
rvalue++;
s = strdup(rvalue);
if (!s)
return log_oom();
c = condition_new(cond, s, false, negate);
c = condition_new(cond, rvalue, false, negate);
if (!c)
return log_oom();
if (*ret)
condition_free(*ret);
/* Drop previous assignment. */
*list = condition_free_list_type(*list, cond);
*ret = c;
LIST_PREPEND(conditions, *list, c);
return 0;
}

View file

@ -6,7 +6,6 @@
#include "sd-device.h"
#include "sd-dhcp-lease.h"
#include "condition.h"
#include "conf-parser.h"
#include "def.h"
#include "set.h"
@ -20,11 +19,6 @@ bool net_match_config(Set *match_mac,
char * const *match_driver,
char * const *match_type,
char * const *match_name,
Condition *match_host,
Condition *match_virt,
Condition *match_kernel_cmdline,
Condition *match_kernel_version,
Condition *match_arch,
const struct ether_addr *dev_mac,
const char *dev_path,
const char *dev_driver,

View file

@ -25,10 +25,10 @@
#include "event-util.h"
#include "hostname-util.h"
#include "io-util.h"
#include "memory-util.h"
#include "random-util.h"
#include "string-util.h"
#include "strv.h"
#include "util.h"
#define MAX_CLIENT_ID_LEN (sizeof(uint32_t) + MAX_DUID_LEN) /* Arbitrary limit */
#define MAX_MAC_ADDR_LEN CONST_MAX(INFINIBAND_ALEN, ETH_ALEN)

View file

@ -10,6 +10,9 @@
#include <stdio_ext.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include "sd-dhcp-lease.h"

View file

@ -22,7 +22,7 @@
#include "random-util.h"
#include "siphash24.h"
#include "string-util.h"
#include "util.h"
#include "time-util.h"
/* Constants from the RFC */
#define PROBE_WAIT_USEC (1U * USEC_PER_SEC)

View file

@ -219,28 +219,21 @@ static int ipv4ll_pick_address(sd_ipv4ll *ll) {
return sd_ipv4ll_set_address(ll, &(struct in_addr) { addr });
}
int sd_ipv4ll_restart(sd_ipv4ll *ll) {
ll->address = 0;
return sd_ipv4ll_start(ll);
}
#define MAC_HASH_KEY SD_ID128_MAKE(df,04,22,98,3f,ad,14,52,f9,87,2e,d1,9c,70,e2,f2)
int sd_ipv4ll_start(sd_ipv4ll *ll) {
static int ipv4ll_start_internal(sd_ipv4ll *ll, bool reset_generation) {
int r;
bool picked_address = false;
assert_return(ll, -EINVAL);
assert_return(!ether_addr_is_null(&ll->mac), -EINVAL);
assert_return(sd_ipv4ll_is_running(ll) == 0, -EBUSY);
/* If no random seed is set, generate some from the MAC address */
if (!ll->seed_set)
ll->seed.value = htole64(siphash24(ll->mac.ether_addr_octet, ETH_ALEN, MAC_HASH_KEY.bytes));
/* Restart the generation counter. */
ll->seed.generation = 0;
if (reset_generation)
ll->seed.generation = 0;
if (ll->address == 0) {
r = ipv4ll_pick_address(ll);
@ -264,6 +257,19 @@ int sd_ipv4ll_start(sd_ipv4ll *ll) {
return 0;
}
int sd_ipv4ll_start(sd_ipv4ll *ll) {
assert_return(ll, -EINVAL);
assert_return(sd_ipv4ll_is_running(ll) == 0, -EBUSY);
return ipv4ll_start_internal(ll, true);
}
int sd_ipv4ll_restart(sd_ipv4ll *ll) {
ll->address = 0;
return ipv4ll_start_internal(ll, false);
}
static void ipv4ll_client_notify(sd_ipv4ll *ll, int event) {
assert(ll);
@ -299,11 +305,7 @@ void ipv4ll_on_acd(sd_ipv4acd *acd, int event, void *userdata) {
ll->claimed_address = 0;
} else {
r = ipv4ll_pick_address(ll);
if (r < 0)
goto error;
r = sd_ipv4acd_start(ll->acd);
r = sd_ipv4ll_restart(ll);
if (r < 0)
goto error;
}

View file

@ -15,7 +15,9 @@
#include "lldp-internal.h"
#include "lldp-neighbor.h"
#include "lldp-network.h"
#include "memory-util.h"
#include "socket-util.h"
#include "sort-util.h"
#include "string-table.h"
#define LLDP_DEFAULT_NEIGHBORS_MAX 128U

View file

@ -17,6 +17,7 @@
#include "hashmap.h"
#include "list.h"
#include "macro.h"
#include "memory-util.h"
#include "missing.h"
#include "prioq.h"
#include "process-util.h"
@ -25,7 +26,6 @@
#include "string-table.h"
#include "string-util.h"
#include "time-util.h"
#include "util.h"
#define DEFAULT_ACCURACY_USEC (250 * USEC_PER_MSEC)
@ -3120,7 +3120,7 @@ _public_ int sd_event_wait(sd_event *e, uint64_t timeout) {
timeout = 0;
m = epoll_wait(e->epoll_fd, ev_queue, ev_queue_max,
timeout == (uint64_t) -1 ? -1 : (int) ((timeout + USEC_PER_MSEC - 1) / USEC_PER_MSEC));
timeout == (uint64_t) -1 ? -1 : (int) DIV_ROUND_UP(timeout, USEC_PER_MSEC));
if (m < 0) {
if (errno == EINTR) {
e->state = SD_EVENT_PENDING;

View file

@ -121,7 +121,6 @@ _public_ int sd_id128_get_boot(sd_id128_t *ret) {
#if 0 /* NM_IGNORED */
static int get_invocation_from_keyring(sd_id128_t *ret) {
_cleanup_free_ char *description = NULL;
char *d, *p, *g, *u, *e;
unsigned long perms;
@ -140,7 +139,7 @@ static int get_invocation_from_keyring(sd_id128_t *ret) {
if (key == -1) {
/* Keyring support not available? No invocation key stored? */
if (IN_SET(errno, ENOSYS, ENOKEY))
return 0;
return -ENXIO;
return -errno;
}
@ -216,7 +215,19 @@ static int get_invocation_from_keyring(sd_id128_t *ret) {
if (c != sizeof(sd_id128_t))
return -EIO;
return 1;
return 0;
}
static int get_invocation_from_environment(sd_id128_t *ret) {
const char *e;
assert(ret);
e = secure_getenv("INVOCATION_ID");
if (!e)
return -ENXIO;
return sd_id128_from_string(e, ret);
}
_public_ int sd_id128_get_invocation(sd_id128_t *ret) {
@ -226,31 +237,17 @@ _public_ int sd_id128_get_invocation(sd_id128_t *ret) {
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 && r != -ENXIO)
return r;
/* We first try to read the invocation ID from the kernel keyring. This has the benefit that it is not
* fakeable by unprivileged code. If the information is not available in the keyring, we use
* $INVOCATION_ID but ignore the data if our process was called by less privileged code
* (i.e. secure_getenv() instead of getenv()).
*
* The kernel keyring is only 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). The environment variable is
* primarily relevant for user services, and sufficiently safe as no privilege boundary is involved. */
/* 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 (r == 0) {
const char *e;
e = secure_getenv("INVOCATION_ID");
if (!e)
return -ENXIO;
r = sd_id128_from_string(e, &saved_invocation_id);
if (r < 0)
return r;
}
}
*ret = saved_invocation_id;

View file

@ -71,7 +71,7 @@ typedef int (*sd_event_handler_t)(sd_event_source *s, void *userdata);
typedef int (*sd_event_io_handler_t)(sd_event_source *s, int fd, uint32_t revents, void *userdata);
typedef int (*sd_event_time_handler_t)(sd_event_source *s, uint64_t usec, void *userdata);
typedef int (*sd_event_signal_handler_t)(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata);
#if defined _GNU_SOURCE || _POSIX_C_SOURCE >= 199309L
#if defined _GNU_SOURCE || (defined _POSIX_C_SOURCE && _POSIX_C_SOURCE >= 199309L)
typedef int (*sd_event_child_handler_t)(sd_event_source *s, const siginfo_t *si, void *userdata);
#else
typedef void* sd_event_child_handler_t;