diff options
author | Thomas Haller <thaller@redhat.com> | 2020-12-23 17:15:29 +0100 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2021-01-05 09:22:56 +0100 |
commit | d34d82399518ae07e0d476764123e47864670fd5 (patch) | |
tree | 0260f12f812588004a30cd93089c58967c90e972 | |
parent | 99b0a25fe001ff2e90a6eddcd59ace0e6ec6a644 (diff) | |
parent | 0d3f8ded9d97586238bbc1f98174158a3f30c391 (diff) | |
download | NetworkManager-d34d82399518ae07e0d476764123e47864670fd5.tar.gz |
systemd: merge branch systemd into master
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/714
149 files changed, 2355 insertions, 1968 deletions
diff --git a/Makefile.am b/Makefile.am index c60ade1bb8..e8bd7bdfc1 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1884,6 +1884,7 @@ shared_systemd_libnm_systemd_shared_la_SOURCES = \ shared/systemd/sd-adapt-shared/errno-list.h \ shared/systemd/sd-adapt-shared/glob-util.h \ shared/systemd/sd-adapt-shared/gunicode.h \ + shared/systemd/sd-adapt-shared/idn-util.h \ shared/systemd/sd-adapt-shared/ioprio.h \ shared/systemd/sd-adapt-shared/locale-util.h \ shared/systemd/sd-adapt-shared/memfd-util.h \ @@ -1962,6 +1963,8 @@ 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/ratelimit.c \ + shared/systemd/src/basic/ratelimit.h \ shared/systemd/src/basic/set.h \ shared/systemd/src/basic/signal-util.c \ shared/systemd/src/basic/signal-util.h \ @@ -1992,6 +1995,7 @@ shared_systemd_libnm_systemd_shared_la_SOURCES = \ shared/systemd/src/basic/util.h \ shared/systemd/src/shared/dns-domain.c \ shared/systemd/src/shared/dns-domain.h \ + shared/systemd/src/shared/log-link.h \ shared/systemd/src/shared/web-util.c \ shared/systemd/src/shared/web-util.h \ $(NULL) @@ -2031,6 +2035,7 @@ src_libnm_systemd_core_la_SOURCES = \ src/systemd/sd-adapt-core/conf-parser.h \ src/systemd/sd-adapt-core/device-util.h \ src/systemd/sd-adapt-core/khash.h \ + src/systemd/sd-adapt-core/network-util.h \ src/systemd/sd-adapt-core/nm-sd-adapt-core.c \ src/systemd/sd-adapt-core/nm-sd-adapt-core.h \ src/systemd/sd-adapt-core/sd-daemon.h \ diff --git a/shared/meson.build b/shared/meson.build index 0f46a00cbb..99500a2f8c 100644 --- a/shared/meson.build +++ b/shared/meson.build @@ -207,6 +207,7 @@ sources = files( 'systemd/src/basic/prioq.c', 'systemd/src/basic/process-util.c', 'systemd/src/basic/random-util.c', + 'systemd/src/basic/ratelimit.c', 'systemd/src/basic/signal-util.c', 'systemd/src/basic/socket-util.c', 'systemd/src/basic/stat-util.c', diff --git a/shared/nm-std-aux/unaligned.h b/shared/nm-std-aux/unaligned.h index e0bc1043b9..2a811aaa39 100644 --- a/shared/nm-std-aux/unaligned.h +++ b/shared/nm-std-aux/unaligned.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include <endian.h> diff --git a/shared/systemd/nm-sd-utils-shared.c b/shared/systemd/nm-sd-utils-shared.c index 83c91af786..bf0f8fc531 100644 --- a/shared/systemd/nm-sd-utils-shared.c +++ b/shared/systemd/nm-sd-utils-shared.c @@ -88,7 +88,9 @@ nm_sd_dns_name_is_valid(const char *s) gboolean nm_sd_hostname_is_valid(const char *s, bool allow_trailing_dot) { - return hostname_is_valid(s, allow_trailing_dot); + return hostname_is_valid(s, + allow_trailing_dot ? VALID_HOSTNAME_TRAILING_DOT + : (ValidHostnameFlags) 0); } /*****************************************************************************/ diff --git a/shared/systemd/sd-adapt-shared/idn-util.h b/shared/systemd/sd-adapt-shared/idn-util.h new file mode 100644 index 0000000000..637892c2d6 --- /dev/null +++ b/shared/systemd/sd-adapt-shared/idn-util.h @@ -0,0 +1,3 @@ +#pragma once + +/* dummy header */ diff --git a/shared/systemd/src/basic/alloc-util.c b/shared/systemd/src/basic/alloc-util.c index e355b60ff8..7f7eb43359 100644 --- a/shared/systemd/src/basic/alloc-util.c +++ b/shared/systemd/src/basic/alloc-util.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #include "nm-sd-adapt-shared.h" diff --git a/shared/systemd/src/basic/alloc-util.h b/shared/systemd/src/basic/alloc-util.h index 64d9e00315..f3e192ddaf 100644 --- a/shared/systemd/src/basic/alloc-util.h +++ b/shared/systemd/src/basic/alloc-util.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include <alloca.h> @@ -27,7 +27,7 @@ typedef void (*free_func_t)(void *p); size_t _n_ = n; \ assert(!size_multiply_overflow(sizeof(t), _n_)); \ assert(sizeof(t)*_n_ <= ALLOCA_MAX); \ - (t*) alloca(sizeof(t)*_n_); \ + (t*) alloca((sizeof(t)*_n_) ?: 1); \ }) #define newa0(t, n) \ @@ -35,14 +35,14 @@ typedef void (*free_func_t)(void *p); size_t _n_ = n; \ assert(!size_multiply_overflow(sizeof(t), _n_)); \ assert(sizeof(t)*_n_ <= ALLOCA_MAX); \ - (t*) alloca0(sizeof(t)*_n_); \ + (t*) alloca0((sizeof(t)*_n_) ?: 1); \ }) #define newdup(t, p, n) ((t*) memdup_multiply(p, sizeof(t), (n))) #define newdup_suffix0(t, p, n) ((t*) memdup_suffix0_multiply(p, sizeof(t), (n))) -#define malloc0(n) (calloc(1, (n))) +#define malloc0(n) (calloc(1, (n) ?: 1)) static inline void *mfree(void *memory) { free(memory); @@ -65,7 +65,7 @@ void* memdup_suffix0(const void *p, size_t l); /* We can't use _alloc_() here, s void *_q_; \ size_t _l_ = l; \ assert(_l_ <= ALLOCA_MAX); \ - _q_ = alloca(_l_); \ + _q_ = alloca(_l_ ?: 1); \ memcpy(_q_, p, _l_); \ }) @@ -135,7 +135,7 @@ void* greedy_realloc0(void **p, size_t *allocated, size_t need, size_t size); char *_new_; \ size_t _len_ = n; \ assert(_len_ <= ALLOCA_MAX); \ - _new_ = alloca(_len_); \ + _new_ = alloca(_len_ ?: 1); \ (void *) memset(_new_, 0, _len_); \ }) @@ -146,7 +146,7 @@ void* greedy_realloc0(void **p, size_t *allocated, size_t need, size_t size); size_t _mask_ = (align) - 1; \ size_t _size_ = size; \ assert(_size_ <= ALLOCA_MAX); \ - _ptr_ = alloca(_size_ + _mask_); \ + _ptr_ = alloca((_size_ + _mask_) ?: 1); \ (void*)(((uintptr_t)_ptr_ + _mask_) & ~_mask_); \ }) diff --git a/shared/systemd/src/basic/async.h b/shared/systemd/src/basic/async.h index 3160613184..e0bbaa5658 100644 --- a/shared/systemd/src/basic/async.h +++ b/shared/systemd/src/basic/async.h @@ -1,7 +1,13 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once +#include <sys/types.h> + +#include "macro.h" + int asynchronous_job(void* (*func)(void *p), void *arg); int asynchronous_sync(pid_t *ret_pid); int asynchronous_close(int fd); + +DEFINE_TRIVIAL_CLEANUP_FUNC(int, asynchronous_close); diff --git a/shared/systemd/src/basic/cgroup-util.h b/shared/systemd/src/basic/cgroup-util.h index 2b88571bc1..bdc0d0d086 100644 --- a/shared/systemd/src/basic/cgroup-util.h +++ b/shared/systemd/src/basic/cgroup-util.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include <dirent.h> @@ -208,6 +208,9 @@ static inline int cg_get_keyed_attribute_graceful( int cg_get_attribute_as_uint64(const char *controller, const char *path, const char *attribute, uint64_t *ret); +/* Does a parse_boolean() on the attribute contents and sets ret accordingly */ +int cg_get_attribute_as_bool(const char *controller, const char *path, const char *attribute, bool *ret); + int cg_set_access(const char *controller, const char *path, uid_t uid, gid_t gid); int cg_set_xattr(const char *controller, const char *path, const char *name, const void *value, size_t size, int flags); @@ -275,3 +278,13 @@ CGroupController cgroup_controller_from_string(const char *s) _pure_; bool is_cgroup_fs(const struct statfs *s); bool fd_is_cgroup_fs(int fd); + +typedef enum ManagedOOMMode { + MANAGED_OOM_AUTO, + MANAGED_OOM_KILL, + _MANAGED_OOM_MODE_MAX, + _MANAGED_OOM_MODE_INVALID = -1, +} ManagedOOMMode; + +const char* managed_oom_mode_to_string(ManagedOOMMode m) _const_; +ManagedOOMMode managed_oom_mode_from_string(const char *s) _pure_; diff --git a/shared/systemd/src/basic/env-file.c b/shared/systemd/src/basic/env-file.c index 1e93f18e34..568b742fcb 100644 --- a/shared/systemd/src/basic/env-file.c +++ b/shared/systemd/src/basic/env-file.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #include "nm-sd-adapt-shared.h" diff --git a/shared/systemd/src/basic/env-file.h b/shared/systemd/src/basic/env-file.h index e1ca195ff0..de475885ac 100644 --- a/shared/systemd/src/basic/env-file.h +++ b/shared/systemd/src/basic/env-file.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include <stdarg.h> diff --git a/shared/systemd/src/basic/env-util.c b/shared/systemd/src/basic/env-util.c index 11f4b29bab..a311ee0075 100644 --- a/shared/systemd/src/basic/env-util.c +++ b/shared/systemd/src/basic/env-util.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #include "nm-sd-adapt-shared.h" @@ -19,7 +19,8 @@ #include "utf8.h" #if 0 /* NM_IGNORED */ -#define VALID_CHARS_ENV_NAME \ +/* We follow bash for the character set. Different shells have different rules. */ +#define VALID_BASH_ENV_NAME_CHARS \ DIGITS LETTERS \ "_" @@ -44,17 +45,14 @@ static bool env_name_is_valid_n(const char *e, size_t n) { return false; for (p = e; p < e + n; p++) - if (!strchr(VALID_CHARS_ENV_NAME, *p)) + if (!strchr(VALID_BASH_ENV_NAME_CHARS, *p)) return false; return true; } bool env_name_is_valid(const char *e) { - if (!e) - return false; - - return env_name_is_valid_n(e, strlen(e)); + return env_name_is_valid_n(e, strlen_ptr(e)); } bool env_value_is_valid(const char *e) { @@ -549,7 +547,7 @@ char *replace_env_n(const char *format, size_t n, char **env, unsigned flags) { word = e+1; state = WORD; - } else if (flags & REPLACE_ENV_ALLOW_BRACELESS && strchr(VALID_CHARS_ENV_NAME, *e)) { + } else if (flags & REPLACE_ENV_ALLOW_BRACELESS && strchr(VALID_BASH_ENV_NAME_CHARS, *e)) { k = strnappend(r, word, e-word-1); if (!k) return NULL; @@ -639,7 +637,7 @@ char *replace_env_n(const char *format, size_t n, char **env, unsigned flags) { case VARIABLE_RAW: assert(flags & REPLACE_ENV_ALLOW_BRACELESS); - if (!strchr(VALID_CHARS_ENV_NAME, *e)) { + if (!strchr(VALID_BASH_ENV_NAME_CHARS, *e)) { const char *t; t = strv_env_get_n(env, word+1, e-word-1, flags); @@ -753,3 +751,17 @@ int getenv_bool_secure(const char *p) { return parse_boolean(e); } + +#if 0 /* NM_IGNORED */ +int set_unset_env(const char *name, const char *value, bool overwrite) { + int r; + + if (value) + r = setenv(name, value, overwrite); + else + r = unsetenv(name); + if (r < 0) + return -errno; + return 0; +} +#endif /* NM_IGNORED */ diff --git a/shared/systemd/src/basic/env-util.h b/shared/systemd/src/basic/env-util.h index 92802ed774..6684b3350f 100644 --- a/shared/systemd/src/basic/env-util.h +++ b/shared/systemd/src/basic/env-util.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include <stdbool.h> @@ -52,3 +52,6 @@ char *strv_env_get(char **x, const char *n) _pure_; int getenv_bool(const char *p); int getenv_bool_secure(const char *p); + +/* Like setenv, but calls unsetenv if value == NULL. */ +int set_unset_env(const char *name, const char *value, bool overwrite); diff --git a/shared/systemd/src/basic/errno-util.h b/shared/systemd/src/basic/errno-util.h index 0ca650f48f..5609820b88 100644 --- a/shared/systemd/src/basic/errno-util.h +++ b/shared/systemd/src/basic/errno-util.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include <stdlib.h> @@ -50,7 +50,10 @@ static inline int errno_or_else(int fallback) { /* 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 */ + * icmp_err_convert[] in net/ipv4/icmp.c in the kernel sources. + * + * Hint #3: When asynchronous connect() on TCP fails because the host never acknowledges a single packet, + * kernel tells us that with ETIMEDOUT, see tcp(7). */ static inline bool ERRNO_IS_DISCONNECT(int r) { return IN_SET(abs(r), ECONNABORTED, @@ -66,7 +69,8 @@ static inline bool ERRNO_IS_DISCONNECT(int r) { ENOTCONN, EPIPE, EPROTO, - ESHUTDOWN); + ESHUTDOWN, + ETIMEDOUT); } /* Transient errors we might get on accept() that we should ignore. As per error handling comment in diff --git a/shared/systemd/src/basic/escape.c b/shared/systemd/src/basic/escape.c index 1261fd4886..094b5c5ff0 100644 --- a/shared/systemd/src/basic/escape.c +++ b/shared/systemd/src/basic/escape.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #include "nm-sd-adapt-shared.h" diff --git a/shared/systemd/src/basic/escape.h b/shared/systemd/src/basic/escape.h index fa267813b3..691b6d802c 100644 --- a/shared/systemd/src/basic/escape.h +++ b/shared/systemd/src/basic/escape.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include <inttypes.h> @@ -16,7 +16,7 @@ /* Those that can be escaped or double-quoted. * - * Stricly speaking, ! does not need to be escaped, except in interactive + * Strictly speaking, ! does not need to be escaped, except in interactive * mode, but let's be extra nice to the user and quote ! in case this * output is ever used in interactive mode. */ #define SHELL_NEED_QUOTES SHELL_NEED_ESCAPE GLOB_CHARS "'()<>|&;!" diff --git a/shared/systemd/src/basic/ether-addr-util.c b/shared/systemd/src/basic/ether-addr-util.c index 4878a3d2ac..ae83eade9b 100644 --- a/shared/systemd/src/basic/ether-addr-util.c +++ b/shared/systemd/src/basic/ether-addr-util.c @@ -1,8 +1,9 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #include "nm-sd-adapt-shared.h" #include <errno.h> +#include <inttypes.h> #include <net/ethernet.h> #include <stdio.h> #include <sys/types.h> @@ -11,6 +12,20 @@ #include "macro.h" #include "string-util.h" +char* hw_addr_to_string(const hw_addr_data *addr, char buffer[HW_ADDR_TO_STRING_MAX]) { + assert(addr); + assert(buffer); + assert(addr->length <= HW_ADDR_MAX_SIZE); + + for (size_t i = 0; i < addr->length; i++) { + sprintf(&buffer[3*i], "%02"PRIx8, addr->addr.bytes[i]); + if (i < addr->length - 1) + buffer[3*i + 2] = ':'; + } + + return buffer; +} + char* ether_addr_to_string(const struct ether_addr *addr, char buffer[ETHER_ADDR_TO_STRING_MAX]) { assert(addr); assert(buffer); diff --git a/shared/systemd/src/basic/ether-addr-util.h b/shared/systemd/src/basic/ether-addr-util.h index 4e44b30be9..942ce55621 100644 --- a/shared/systemd/src/basic/ether-addr-util.h +++ b/shared/systemd/src/basic/ether-addr-util.h @@ -1,11 +1,35 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once +#include <linux/if_infiniband.h> #include <net/ethernet.h> #include <stdbool.h> #include "hash-funcs.h" +/* This is MAX_ADDR_LEN as defined in linux/netdevice.h, but net/if_arp.h + * defines a macro of the same name with a much lower size. */ +#define HW_ADDR_MAX_SIZE 32 + +union hw_addr_union { + struct ether_addr ether; + uint8_t infiniband[INFINIBAND_ALEN]; + uint8_t bytes[HW_ADDR_MAX_SIZE]; +}; + +typedef struct hw_addr_data { + union hw_addr_union addr; + size_t length; +} hw_addr_data; + +#define HW_ADDR_TO_STRING_MAX (3*HW_ADDR_MAX_SIZE) +char* hw_addr_to_string(const hw_addr_data *addr, char buffer[HW_ADDR_TO_STRING_MAX]); + +/* Use only as function argument, never stand-alone! */ +#define HW_ADDR_TO_STR(hw_addr) hw_addr_to_string((hw_addr), (char[HW_ADDR_TO_STRING_MAX]){}) + +#define HW_ADDR_NULL ((const hw_addr_data){}) + #define ETHER_ADDR_FORMAT_STR "%02X%02X%02X%02X%02X%02X" #define ETHER_ADDR_FORMAT_VAL(x) (x).ether_addr_octet[0], (x).ether_addr_octet[1], (x).ether_addr_octet[2], (x).ether_addr_octet[3], (x).ether_addr_octet[4], (x).ether_addr_octet[5] diff --git a/shared/systemd/src/basic/extract-word.c b/shared/systemd/src/basic/extract-word.c index e32b4c7f7f..1d86033f12 100644 --- a/shared/systemd/src/basic/extract-word.c +++ b/shared/systemd/src/basic/extract-word.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #include "nm-sd-adapt-shared.h" diff --git a/shared/systemd/src/basic/extract-word.h b/shared/systemd/src/basic/extract-word.h index f028577c40..d1de32e580 100644 --- a/shared/systemd/src/basic/extract-word.h +++ b/shared/systemd/src/basic/extract-word.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include "macro.h" diff --git a/shared/systemd/src/basic/fd-util.c b/shared/systemd/src/basic/fd-util.c index 525d38280e..e53cf18d14 100644 --- a/shared/systemd/src/basic/fd-util.c +++ b/shared/systemd/src/basic/fd-util.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #include "nm-sd-adapt-shared.h" @@ -23,6 +23,7 @@ #include "path-util.h" #include "process-util.h" #include "socket-util.h" +#include "sort-util.h" #include "stat-util.h" #include "stdio-util.h" #include "tmpfile-util.h" @@ -214,12 +215,97 @@ static int get_max_fd(void) { } int close_all_fds(const int except[], size_t n_except) { + static bool have_close_range = true; /* Assume we live in the future */ _cleanup_closedir_ DIR *d = NULL; struct dirent *de; int r = 0; assert(n_except == 0 || except); + if (have_close_range) { + /* In the best case we have close_range() to close all fds between a start and an end fd, + * which we can use on the "inverted" exception array, i.e. all intervals between all + * adjacent pairs from the sorted exception array. This changes loop complexity from O(n) + * where n is number of open fds to O(m⋅log(m)) where m is the number of fds to keep + * open. Given that we assume n ≫ m that's preferable to us. */ + + if (n_except == 0) { + /* Close everything. Yay! */ + + if (close_range(3, -1, 0) >= 0) + return 1; + + if (!ERRNO_IS_NOT_SUPPORTED(errno) && !ERRNO_IS_PRIVILEGE(errno)) + return -errno; + + have_close_range = false; + } else { + _cleanup_free_ int *sorted_malloc = NULL; + size_t n_sorted; + int *sorted; + + assert(n_except < SIZE_MAX); + n_sorted = n_except + 1; + + if (n_sorted > 64) /* Use heap for large numbers of fds, stack otherwise */ + sorted = sorted_malloc = new(int, n_sorted); + else + sorted = newa(int, n_sorted); + + if (sorted) { + int c = 0; + + memcpy(sorted, except, n_except * sizeof(int)); + + /* Let's add fd 2 to the list of fds, to simplify the loop below, as this + * allows us to cover the head of the array the same way as the body */ + sorted[n_sorted-1] = 2; + + typesafe_qsort(sorted, n_sorted, cmp_int); + + for (size_t i = 0; i < n_sorted-1; i++) { + int start, end; + + start = MAX(sorted[i], 2); /* The first three fds shall always remain open */ + end = MAX(sorted[i+1], 2); + + assert(end >= start); + + if (end - start <= 1) + continue; + + /* Close everything between the start and end fds (both of which shall stay open) */ + if (close_range(start + 1, end - 1, 0) < 0) { + if (!ERRNO_IS_NOT_SUPPORTED(errno) && !ERRNO_IS_PRIVILEGE(errno)) + return -errno; + + have_close_range = false; + break; + } + + c += end - start - 1; + } + + if (have_close_range) { + /* The loop succeeded. Let's now close everything beyond the end */ + + if (sorted[n_sorted-1] >= INT_MAX) /* Dont let the addition below overflow */ + return c; + + if (close_range(sorted[n_sorted-1] + 1, -1, 0) >= 0) + return c + 1; + + if (!ERRNO_IS_NOT_SUPPORTED(errno) && !ERRNO_IS_PRIVILEGE(errno)) + return -errno; + + have_close_range = false; + } + } + } + + /* Fallback on OOM or if close_range() is not supported */ + } + d = opendir("/proc/self/fd"); if (!d) { int fd, max_fd; diff --git a/shared/systemd/src/basic/fd-util.h b/shared/systemd/src/basic/fd-util.h index 93ce95cd03..2162537b80 100644 --- a/shared/systemd/src/basic/fd-util.h +++ b/shared/systemd/src/basic/fd-util.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include <dirent.h> diff --git a/shared/systemd/src/basic/fileio.c b/shared/systemd/src/basic/fileio.c index 664b894a2b..ea90614a05 100644 --- a/shared/systemd/src/basic/fileio.c +++ b/shared/systemd/src/basic/fileio.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #include "nm-sd-adapt-shared.h" @@ -120,7 +120,7 @@ int write_string_stream_ts( FILE *f, const char *line, WriteStringFileFlags flags, - struct timespec *ts) { + const struct timespec *ts) { bool needs_nl; int r, fd; @@ -164,7 +164,7 @@ int write_string_stream_ts( return r; if (ts) { - struct timespec twice[2] = {*ts, *ts}; + const struct timespec twice[2] = {*ts, *ts}; if (futimens(fd, twice) < 0) return -errno; @@ -177,7 +177,7 @@ static int write_string_file_atomic( const char *fn, const char *line, WriteStringFileFlags flags, - struct timespec *ts) { + const struct timespec *ts) { _cleanup_fclose_ FILE *f = NULL; _cleanup_free_ char *p = NULL; @@ -224,7 +224,7 @@ int write_string_file_ts( const char *fn, const char *line, WriteStringFileFlags flags, - struct timespec *ts) { + const struct timespec *ts) { _cleanup_fclose_ FILE *f = NULL; int q, r, fd; @@ -255,7 +255,8 @@ int write_string_file_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_WRONLY|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_CREATE) ? O_CREAT : 0) | + (FLAGS_SET(flags, WRITE_STRING_FILE_TRUNCATE) ? O_TRUNC : 0), (FLAGS_SET(flags, WRITE_STRING_FILE_MODE_0600) ? 0600 : 0666)); if (fd < 0) { r = -errno; @@ -475,12 +476,13 @@ int read_full_virtual_file(const char *filename, char **ret_contents, size_t *re int read_full_stream_full( FILE *f, const char *filename, + uint64_t offset, + size_t size, ReadFullFileFlags flags, char **ret_contents, size_t *ret_size) { _cleanup_free_ char *buf = NULL; - struct stat st; size_t n, n_next, l; int fd, r; @@ -488,32 +490,45 @@ int read_full_stream_full( assert(ret_contents); assert(!FLAGS_SET(flags, READ_FULL_FILE_UNBASE64 | READ_FULL_FILE_UNHEX)); - n_next = LINE_MAX; /* Start size */ + if (offset != UINT64_MAX && offset > LONG_MAX) + return -ERANGE; + + n_next = size != SIZE_MAX ? size : LINE_MAX; /* Start size */ fd = fileno(f); - if (fd >= 0) { /* If the FILE* object is backed by an fd (as opposed to memory or such, see fmemopen()), let's - * optimize our buffering */ + if (fd >= 0) { /* If the FILE* object is backed by an fd (as opposed to memory or such, see + * fmemopen()), let's optimize our buffering */ + struct stat st; if (fstat(fd, &st) < 0) return -errno; if (S_ISREG(st.st_mode)) { - - /* Safety check */ - if (st.st_size > READ_FULL_BYTES_MAX) - return -E2BIG; - - /* Start with the right file size. Note that we increase the size - * to read here by one, so that the first read attempt already - * makes us notice the EOF. */ - if (st.st_size > 0) - n_next = st.st_size + 1; + if (size == SIZE_MAX) { + uint64_t rsize = + LESS_BY((uint64_t) st.st_size, offset == UINT64_MAX ? 0 : offset); + + /* Safety check */ + if (rsize > READ_FULL_BYTES_MAX) + return -E2BIG; + + /* Start with the right file size. Note that we increase the size to read + * here by one, so that the first read attempt already makes us notice the + * EOF. If the reported size of the file is zero, we avoid this logic + * however, since quite likely it might be a virtual file in procfs that all + * report a zero file size. */ + if (st.st_size > 0) + n_next = rsize + 1; + } if (flags & READ_FULL_FILE_WARN_WORLD_READABLE) (void) warn_file_is_world_accessible(filename, &st, NULL, 0); } } + if (offset != UINT64_MAX && fseek(f, offset, SEEK_SET) < 0) + return -errno; + n = l = 0; for (;;) { char *t; @@ -550,6 +565,11 @@ int read_full_stream_full( if (feof(f)) break; + if (size != SIZE_MAX) { /* If we got asked to read some specific size, we already sized the buffer right, hence leave */ + assert(l == size); + break; + } + assert(k > 0); /* we can't have read zero bytes because that would have been EOF */ /* Safety check */ @@ -605,12 +625,21 @@ finalize: return r; } -int read_full_file_full(int dir_fd, const char *filename, ReadFullFileFlags flags, char **contents, size_t *size) { +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) { + _cleanup_fclose_ FILE *f = NULL; int r; assert(filename); - assert(contents); + assert(ret_contents); r = xfopenat(dir_fd, filename, "re", 0, &f); if (r < 0) { @@ -625,6 +654,10 @@ int read_full_file_full(int dir_fd, const char *filename, ReadFullFileFlags flag if (!FLAGS_SET(flags, READ_FULL_FILE_CONNECT_SOCKET)) return -ENXIO; + /* Seeking is not supported on AF_UNIX sockets */ + if (offset != UINT64_MAX) + return -ESPIPE; + if (dir_fd == AT_FDCWD) r = sockaddr_un_set_path(&sa.un, filename); else { @@ -648,6 +681,20 @@ int read_full_file_full(int dir_fd, const char *filename, ReadFullFileFlags flag if (sk < 0) return -errno; + if (bind_name) { + /* If the caller specified a socket name to bind to, do so before connecting. This is + * useful to communicate some minor, short meta-information token from the client to + * the server. */ + union sockaddr_union bsa; + + r = sockaddr_un_set_path(&bsa.un, bind_name); + if (r < 0) + return r; + + if (bind(sk, &bsa.sa, r) < 0) + return r; + } + if (connect(sk, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0) return errno == ENOTSOCK ? -ENXIO : -errno; /* propagate original error if this is * not a socket after all */ @@ -664,7 +711,7 @@ int read_full_file_full(int dir_fd, const char *filename, ReadFullFileFlags flag (void) __fsetlocking(f, FSETLOCKING_BYCALLER); - return read_full_stream_full(f, filename, flags, contents, size); + return read_full_stream_full(f, filename, offset, size, flags, ret_contents, ret_size); } #if 0 /* NM_IGNORED */ diff --git a/shared/systemd/src/basic/fileio.h b/shared/systemd/src/basic/fileio.h index 11a81a6d04..5a02856112 100644 --- a/shared/systemd/src/basic/fileio.h +++ b/shared/systemd/src/basic/fileio.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include <dirent.h> @@ -20,14 +20,15 @@ typedef enum { WRITE_STRING_FILE_CREATE = 1 << 0, - WRITE_STRING_FILE_ATOMIC = 1 << 1, - WRITE_STRING_FILE_AVOID_NEWLINE = 1 << 2, - WRITE_STRING_FILE_VERIFY_ON_FAILURE = 1 << 3, - WRITE_STRING_FILE_SYNC = 1 << 4, - WRITE_STRING_FILE_DISABLE_BUFFER = 1 << 5, - WRITE_STRING_FILE_NOFOLLOW = 1 << 6, - WRITE_STRING_FILE_MKDIR_0755 = 1 << 7, - WRITE_STRING_FILE_MODE_0600 = 1 << 8, + WRITE_STRING_FILE_TRUNCATE = 1 << 1, + WRITE_STRING_FILE_ATOMIC = 1 << 2, + WRITE_STRING_FILE_AVOID_NEWLINE = 1 << 3, + WRITE_STRING_FILE_VERIFY_ON_FAILURE = 1 << 4, + WRITE_STRING_FILE_SYNC = 1 << 5, + WRITE_STRING_FILE_DISABLE_BUFFER = 1 << 6, + WRITE_STRING_FILE_NOFOLLOW = 1 << 7, + WRITE_STRING_FILE_MKDIR_0755 = 1 << 8, + WRITE_STRING_FILE_MODE_0600 = 1 << 9, /* And before you wonder, why write_string_file_atomic_label_ts() is a separate function instead of just one more flag here: it's about linking: we don't want to pull -lselinux into all users of write_string_file() @@ -51,11 +52,11 @@ DIR* take_fdopendir(int *dfd); FILE* open_memstream_unlocked(char **ptr, size_t *sizeloc); FILE* fmemopen_unlocked(void *buf, size_t size, const char *mode); -int write_string_stream_ts(FILE *f, const char *line, WriteStringFileFlags flags, struct timespec *ts); +int write_string_stream_ts(FILE *f, const char *line, WriteStringFileFlags flags, const struct timespec *ts); 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, struct timespec *ts); +int write_string_file_ts(const char *fn, const char *line, WriteStringFileFlags flags, const struct timespec *ts); static inline int write_string_file(const char *fn, const char *line, WriteStringFileFlags flags) { return write_string_file_ts(fn, line, flags, NULL); } @@ -63,14 +64,14 @@ static inline int write_string_file(const char *fn, const char *line, WriteStrin int write_string_filef(const char *fn, WriteStringFileFlags flags, const char *format, ...) _printf_(3, 4); int read_one_line_file(const char *filename, char **line); -int read_full_file_full(int dir_fd, const char *filename, ReadFullFileFlags flags, char **contents, size_t *size); -static inline int read_full_file(const char *filename, char **contents, size_t *size) { - return read_full_file_full(AT_FDCWD, filename, 0, contents, size); +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(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); } int read_full_virtual_file(const char *filename, char **ret_contents, size_t *ret_size); -int read_full_stream_full(FILE *f, const char *filename, ReadFullFileFlags flags, char **contents, size_t *size); -static inline int read_full_stream(FILE *f, char **contents, size_t *size) { - return read_full_stream_full(f, NULL, 0, contents, size); +int read_full_stream_full(FILE *f, const char *filename, uint64_t offset, size_t size, ReadFullFileFlags flags, char **ret_contents, size_t *ret_size); +static inline int read_full_stream(FILE *f, char **ret_contents, size_t *ret_size) { + 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); diff --git a/shared/systemd/src/basic/format-util.c b/shared/systemd/src/basic/format-util.c index 62477f537e..42224b6f97 100644 --- a/shared/systemd/src/basic/format-util.c +++ b/shared/systemd/src/basic/format-util.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #include "nm-sd-adapt-shared.h" diff --git a/shared/systemd/src/basic/format-util.h b/shared/systemd/src/basic/format-util.h index c47fa76ea8..b7e18768e3 100644 --- a/shared/systemd/src/basic/format-util.h +++ b/shared/systemd/src/basic/format-util.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include <inttypes.h> @@ -72,11 +72,14 @@ typedef enum { FORMAT_BYTES_TRAILING_B = 1 << 2, } FormatBytesFlag; -#define FORMAT_BYTES_MAX 16 +#define FORMAT_BYTES_MAX 16U + char *format_bytes_full(char *buf, size_t l, uint64_t t, FormatBytesFlag flag); + static inline char *format_bytes(char *buf, size_t l, uint64_t t) { return format_bytes_full(buf, l, t, FORMAT_BYTES_USE_IEC | FORMAT_BYTES_BELOW_POINT | FORMAT_BYTES_TRAILING_B); } + static inline char *format_bytes_cgroup_protection(char *buf, size_t l, uint64_t t) { if (t == CGROUP_LIMIT_MAX) { (void) snprintf(buf, l, "%s", "infinity"); diff --git a/shared/systemd/src/basic/fs-util.c b/shared/systemd/src/basic/fs-util.c index e50252cb7f..094dd63ab5 100644 --- a/shared/systemd/src/basic/fs-util.c +++ b/shared/systemd/src/basic/fs-util.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #include "nm-sd-adapt-shared.h" @@ -821,7 +821,7 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags, * * 3. With CHASE_STEP: in this case only a single step of the normalization is executed, i.e. only the first * symlink or ".." component of the path is resolved, and the resulting path is returned. This is useful if - * a caller wants to trace the a path through the file system verbosely. Returns < 0 on error, > 0 if the + * a caller wants to trace the path through the file system verbosely. Returns < 0 on error, > 0 if the * path is fully normalized, and == 0 for each normalization step. This may be combined with * CHASE_NONEXISTENT, in which case 1 is returned when a component is not found. * @@ -1626,4 +1626,81 @@ int path_is_encrypted(const char *path) { return blockdev_is_encrypted(p, 10 /* safety net: maximum recursion depth */); } + +int conservative_rename( + int olddirfd, const char *oldpath, + int newdirfd, const char *newpath) { + + _cleanup_close_ int old_fd = -1, new_fd = -1; + struct stat old_stat, new_stat; + + /* Renames the old path to thew new path, much like renameat() — except if both are regular files and + * have the exact same contents and basic file attributes already. In that case remove the new file + * instead. This call is useful for reducing inotify wakeups on files that are updated but don't + * actually change. This function is written in a style that we rather rename too often than suppress + * too much. i.e. whenever we are in doubt we rather rename than fail. After all reducing inotify + * events is an optimization only, not more. */ + + old_fd = openat(olddirfd, oldpath, O_CLOEXEC|O_RDONLY|O_NOCTTY|O_NOFOLLOW); + if (old_fd < 0) + goto do_rename; + + new_fd = openat(newdirfd, newpath, O_CLOEXEC|O_RDONLY|O_NOCTTY|O_NOFOLLOW); + if (new_fd < 0) + goto do_rename; + + if (fstat(old_fd, &old_stat) < 0) + goto do_rename; + + if (!S_ISREG(old_stat.st_mode)) + goto do_rename; + + if (fstat(new_fd, &new_stat) < 0) + goto do_rename; + + if (new_stat.st_ino == old_stat.st_ino && + new_stat.st_dev == old_stat.st_dev) + goto is_same; + + if (old_stat.st_mode != new_stat.st_mode || + old_stat.st_size != new_stat.st_size || + old_stat.st_uid != new_stat.st_uid || + old_stat.st_gid != new_stat.st_gid) + goto do_rename; + + for (;;) { + char buf1[16*1024]; + char buf2[sizeof(buf1) + 1]; + ssize_t l1, l2; + + l1 = read(old_fd, buf1, sizeof(buf1)); + if (l1 < 0) + goto do_rename; + + l2 = read(new_fd, buf2, l1 + 1); + if (l1 != l2) + goto do_rename; + + if (l1 == 0) /* EOF on both! And everything's the same so far, yay! */ + break; + + if (memcmp(buf1, buf2, l1) != 0) + goto do_rename; + } + +is_same: + /* Everything matches? Then don't rename, instead remove the source file, and leave the existing + * destination in place */ + + if (unlinkat(olddirfd, oldpath, 0) < 0) + goto do_rename; + + return 0; + +do_rename: + if (renameat(olddirfd, oldpath, newdirfd, newpath) < 0) + return -errno; + + return 1; +} #endif /* NM_IGNORED */ diff --git a/shared/systemd/src/basic/fs-util.h b/shared/systemd/src/basic/fs-util.h index 241cc6ef62..9a39473567 100644 --- a/shared/systemd/src/basic/fs-util.h +++ b/shared/systemd/src/basic/fs-util.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include <dirent.h> @@ -132,3 +132,5 @@ int syncfs_path(int atfd, const char *path); int open_parent(const char *path, int flags, mode_t mode); int path_is_encrypted(const char *path); + +int conservative_rename(int olddirfd, const char *oldpath, int newdirfd, const char *newpath); diff --git a/shared/systemd/src/basic/hash-funcs.c b/shared/systemd/src/basic/hash-funcs.c index b1c19c9572..6f540b29a4 100644 --- a/shared/systemd/src/basic/hash-funcs.c +++ b/shared/systemd/src/basic/hash-funcs.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #include "nm-sd-adapt-shared.h" @@ -75,6 +75,19 @@ const struct hash_ops trivial_hash_ops = { .compare = trivial_compare_func, }; +const struct hash_ops trivial_hash_ops_free = { + .hash = trivial_hash_func, + .compare = trivial_compare_func, + .free_key = free, +}; + +const struct hash_ops trivial_hash_ops_free_free = { + .hash = trivial_hash_func, + .compare = trivial_compare_func, + .free_key = free, + .free_value = free, +}; + void uint64_hash_func(const uint64_t *p, struct siphash *state) { siphash24_compress(p, sizeof(uint64_t), state); } diff --git a/shared/systemd/src/basic/hash-funcs.h b/shared/systemd/src/basic/hash-funcs.h index 005d1b21d2..5672df1da4 100644 --- a/shared/systemd/src/basic/hash-funcs.h +++ b/shared/systemd/src/basic/hash-funcs.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include "alloc-util.h" @@ -88,6 +88,8 @@ extern const struct hash_ops path_hash_ops_free; void trivial_hash_func(const void *p, struct siphash *state); int trivial_compare_func(const void *a, const void *b) _const_; extern const struct hash_ops trivial_hash_ops; +extern const struct hash_ops trivial_hash_ops_free; +extern const struct hash_ops trivial_hash_ops_free_free; /* 32bit values we can always just embed in the pointer itself, but in order to support 32bit archs we need store 64bit * values indirectly, since they don't fit in a pointer. */ diff --git a/shared/systemd/src/basic/hashmap.c b/shared/systemd/src/basic/hashmap.c index b57814e699..0a5deabf2c 100644 --- a/shared/systemd/src/basic/hashmap.c +++ b/shared/systemd/src/basic/hashmap.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #include "nm-sd-adapt-shared.h" @@ -1797,10 +1797,10 @@ int set_consume(Set *s, void *value) { } #if 0 /* NM_IGNORED */ -int _hashmap_put_strdup(Hashmap **h, const char *k, const char *v HASHMAP_DEBUG_PARAMS) { +int _hashmap_put_strdup_full(Hashmap **h, const struct hash_ops *hash_ops, const char *k, const char *v HASHMAP_DEBUG_PARAMS) { int r; - r = _hashmap_ensure_allocated(h, &string_hash_ops_free_free HASHMAP_DEBUG_PASS_ARGS); + r = _hashmap_ensure_allocated(h, hash_ops HASHMAP_DEBUG_PASS_ARGS); if (r < 0) return r; @@ -1832,14 +1832,14 @@ int _hashmap_put_strdup(Hashmap **h, const char *k, const char *v HASHMAP_DEBUG } #endif /* NM_IGNORED */ -int _set_put_strdup(Set **s, const char *p HASHMAP_DEBUG_PARAMS) { +int _set_put_strdup_full(Set **s, const struct hash_ops *hash_ops, const char *p HASHMAP_DEBUG_PARAMS) { char *c; int r; assert(s); assert(p); - r = _set_ensure_allocated(s, &string_hash_ops_free HASHMAP_DEBUG_PASS_ARGS); + r = _set_ensure_allocated(s, hash_ops HASHMAP_DEBUG_PASS_ARGS); if (r < 0) return r; @@ -1853,14 +1853,14 @@ int _set_put_strdup(Set **s, const char *p HASHMAP_DEBUG_PARAMS) { return set_consume(*s, c); } -int _set_put_strdupv(Set **s, char **l HASHMAP_DEBUG_PARAMS) { +int _set_put_strdupv_full(Set **s, const struct hash_ops *hash_ops, char **l HASHMAP_DEBUG_PARAMS) { int n = 0, r; char **i; assert(s); STRV_FOREACH(i, l) { - r = _set_put_strdup(s, *i HASHMAP_DEBUG_PASS_ARGS); + r = _set_put_strdup_full(s, hash_ops, *i HASHMAP_DEBUG_PASS_ARGS); if (r < 0) return r; @@ -1980,3 +1980,53 @@ IteratedCache* iterated_cache_free(IteratedCache *cache) { return mfree(cache); } + +int set_strjoin(Set *s, const char *separator, bool wrap_with_separator, char **ret) { + size_t separator_len, allocated = 0, len = 0; + _cleanup_free_ char *str = NULL; + const char *value; + bool first; + + assert(ret); + + if (set_isempty(s)) { + *ret = NULL; + return 0; + } + + separator_len = strlen_ptr(separator); + + if (separator_len == 0) + wrap_with_separator = false; + + first = !wrap_with_separator; + + SET_FOREACH(value, s) { + size_t l = strlen_ptr(value); + + if (l == 0) + continue; + + if (!GREEDY_REALLOC(str, allocated, len + l + (first ? 0 : separator_len) + (wrap_with_separator ? separator_len : 0) + 1)) + return -ENOMEM; + + if (separator_len > 0 && !first) { + memcpy(str + len, separator, separator_len); + len += separator_len; + } + + memcpy(str + len, value, l); + len += l; + first = false; + } + + if (wrap_with_separator) { + memcpy(str + len, separator, separator_len); + len += separator_len; + } + + str[len] = '\0'; + + *ret = TAKE_PTR(str); + return 0; +} diff --git a/shared/systemd/src/basic/hashmap.h b/shared/systemd/src/basic/hashmap.h index 890f90a9d1..e99448375e 100644 --- a/shared/systemd/src/basic/hashmap.h +++ b/shared/systemd/src/basic/hashmap.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include <limits.h> @@ -153,8 +153,9 @@ static inline int ordered_hashmap_put(OrderedHashmap *h, const void *key, void * return hashmap_put(PLAIN_HASHMAP(h), key, value); } -int _hashmap_put_strdup(Hashmap **h, const char *k, const char *v HASHMAP_DEBUG_PARAMS); -#define hashmap_put_strdup(h, k, v) _hashmap_put_strdup(h, k, v HASHMAP_DEBUG_SRC_ARGS) +int _hashmap_put_strdup_full(Hashmap **h, const struct hash_ops *hash_ops, const char *k, const char *v HASHMAP_DEBUG_PARAMS); +#define hashmap_put_strdup_full(h, hash_ops, k, v) _hashmap_put_strdup_full(h, hash_ops, k, v HASHMAP_DEBUG_SRC_ARGS) +#define hashmap_put_strdup(h, k, v) hashmap_put_strdup_full(h, &string_hash_ops_free_free, k, v) int hashmap_update(Hashmap *h, const void *key, void *value); static inline int ordered_hashmap_update(OrderedHashmap *h, const void *key, void *value) { diff --git a/shared/systemd/src/basic/hexdecoct.c b/shared/systemd/src/basic/hexdecoct.c index 1fb52305cc..78930b3274 100644 --- a/shared/systemd/src/basic/hexdecoct.c +++ b/shared/systemd/src/basic/hexdecoct.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #include "nm-sd-adapt-shared.h" diff --git a/shared/systemd/src/basic/hexdecoct.h b/shared/systemd/src/basic/hexdecoct.h index dfdff1e9bb..7e2a6892c0 100644 --- a/shared/systemd/src/basic/hexdecoct.h +++ b/shared/systemd/src/basic/hexdecoct.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include <stdbool.h> diff --git a/shared/systemd/src/basic/hostname-util.c b/shared/systemd/src/basic/hostname-util.c index 82fc56dbd6..a3cdc62e3d 100644 --- a/shared/systemd/src/basic/hostname-util.c +++ b/shared/systemd/src/basic/hostname-util.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #include "nm-sd-adapt-shared.h" @@ -9,29 +9,11 @@ #include <unistd.h> #include "alloc-util.h" -#include "fd-util.h" -#include "fileio.h" #include "hostname-util.h" -#include "macro.h" #include "string-util.h" #include "strv.h" #if 0 /* NM_IGNORED */ -bool hostname_is_set(void) { - struct utsname u; - - assert_se(uname(&u) >= 0); - - if (isempty(u.nodename)) - return false; - - /* This is the built-in kernel default hostname */ - if (streq(u.nodename, "(none)")) - return false; - - return true; -} - char* gethostname_malloc(void) { struct utsname u; const char *s; @@ -93,6 +75,8 @@ int gethostname_strict(char **ret) { } bool valid_ldh_char(char c) { + /* "LDH" → "Letters, digits, hyphens", as per RFC 5890, Section 2.3.1 */ + return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || @@ -100,28 +84,24 @@ bool valid_ldh_char(char c) { c == '-'; } -/** - * Check if s looks like a valid hostname or FQDN. This does not do - * full DNS validation, but only checks if the name is composed of - * allowed characters and the length is not above the maximum allowed - * by Linux (c.f. dns_name_is_valid()). Trailing dot is allowed if - * allow_trailing_dot is true and at least two components are present - * in the name. Note that due to the restricted charset and length - * this call is substantially more conservative than - * dns_name_is_valid(). - */ -bool hostname_is_valid(const char *s, bool allow_trailing_dot) { +bool hostname_is_valid(const char *s, ValidHostnameFlags flags) { unsigned n_dots = 0; const char *p; bool dot, hyphen; + /* Check if s looks like a valid hostname or FQDN. This does not do full DNS validation, but only + * checks if the name is composed of allowed characters and the length is not above the maximum + * allowed by Linux (c.f. dns_name_is_valid()). A trailing dot is allowed if + * VALID_HOSTNAME_TRAILING_DOT flag is set and at least two components are present in the name. Note + * that due to the restricted charset and length this call is substantially more conservative than + * dns_name_is_valid(). Doesn't accept empty hostnames, hostnames with leading dots, and hostnames + * with multiple dots in a sequence. Doesn't allow hyphens at the beginning or end of label. */ + if (isempty(s)) return false; - /* Doesn't accept empty hostnames, hostnames with - * leading dots, and hostnames with multiple dots in a - * sequence. Also ensures that the length stays below - * HOST_NAME_MAX. */ + if (streq(s, ".host")) /* Used by the container logic to denote the "root container" */ + return FLAGS_SET(flags, VALID_HOSTNAME_DOT_HOST); for (p = s, dot = hyphen = true; *p; p++) if (*p == '.') { @@ -147,14 +127,13 @@ bool hostname_is_valid(const char *s, bool allow_trailing_dot) { hyphen = false; } - if (dot && (n_dots < 2 || !allow_trailing_dot)) + if (dot && (n_dots < 2 || !FLAGS_SET(flags, VALID_HOSTNAME_TRAILING_DOT))) return false; if (hyphen) return false; - if (p-s > HOST_NAME_MAX) /* Note that HOST_NAME_MAX is 64 on - * Linux, but DNS allows domain names - * up to 255 characters */ + if (p-s > HOST_NAME_MAX) /* Note that HOST_NAME_MAX is 64 on Linux, but DNS allows domain names up to + * 255 characters */ return false; return true; @@ -215,121 +194,3 @@ bool is_localhost(const char *hostname) { endswith_no_case(hostname, ".localhost.localdomain") || endswith_no_case(hostname, ".localhost.localdomain."); } - -#if 0 /* NM_IGNORED */ -bool is_gateway_hostname(const char *hostname) { - assert(hostname); - - /* This tries to identify the valid syntaxes for the our - * synthetic "gateway" host. */ - - return - strcaseeq(hostname, "_gateway") || strcaseeq(hostname, "_gateway.") -#if ENABLE_COMPAT_GATEWAY_HOSTNAME - || strcaseeq(hostname, "gateway") || strcaseeq(hostname, "gateway.") -#endif - ; -} - -int sethostname_idempotent(const char *s) { - char buf[HOST_NAME_MAX + 1] = {}; - - assert(s); - - if (gethostname(buf, sizeof(buf)) < 0) - return -errno; - - if (streq(buf, s)) - return 0; - - if (sethostname(s, strlen(s)) < 0) - return -errno; - - return 1; -} - -int shorten_overlong(const char *s, char **ret) { - char *h, *p; - - /* Shorten an overlong name to HOST_NAME_MAX or to the first dot, - * whatever comes earlier. */ - - assert(s); - - h = strdup(s); - if (!h) - return -ENOMEM; - - if (hostname_is_valid(h, false)) { - *ret = h; - return 0; - } - - p = strchr(h, '.'); - if (p) - *p = 0; - - strshorten(h, HOST_NAME_MAX); - - if (!hostname_is_valid(h, false)) { - free(h); - return -EDOM; - } - - *ret = h; - return 1; -} - -int read_etc_hostname_stream(FILE *f, char **ret) { - int r; - - assert(f); - assert(ret); - - for (;;) { - _cleanup_free_ char *line = NULL; - char *p; - - r = read_line(f, LONG_LINE_MAX, &line); - if (r < 0) - return r; - if (r == 0) /* EOF without any hostname? the file is empty, let's treat that exactly like no file at all: ENOENT */ - return -ENOENT; - - p = strstrip(line); - - /* File may have empty lines or comments, ignore them */ - if (!IN_SET(*p, '\0', '#')) { - char *copy; - - hostname_cleanup(p); /* normalize the hostname */ - - if (!hostname_is_valid(p, true)) /* check that the hostname we return is valid */ - return -EBADMSG; - - copy = strdup(p); - if (!copy) - return -ENOMEM; - - *ret = copy; - return 0; - } - } -} - -int read_etc_hostname(const char *path, char **ret) { - _cleanup_fclose_ FILE *f = NULL; - - assert(ret); - - if (!path) - path = "/etc/hostname"; - - f = fopen(path, "re"); - if (!f) - return -errno; - - return read_etc_hostname_stream(f, ret); - -} -#endif /* NM_IGNORED */ diff --git a/shared/systemd/src/basic/hostname-util.h b/shared/systemd/src/basic/hostname-util.h index cafd6f020b..6cff9c1d4c 100644 --- a/shared/systemd/src/basic/hostname-util.h +++ b/shared/systemd/src/basic/hostname-util.h @@ -1,29 +1,29 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include <stdbool.h> #include <stdio.h> #include "macro.h" - -bool hostname_is_set(void); +#include "strv.h" char* gethostname_malloc(void); char* gethostname_short_malloc(void); int gethostname_strict(char **ret); bool valid_ldh_char(char c) _const_; -bool hostname_is_valid(const char *s, bool allow_trailing_dot) _pure_; -char* hostname_cleanup(char *s); - -#define machine_name_is_valid(s) hostname_is_valid(s, false) -bool is_localhost(const char *hostname); -bool is_gateway_hostname(const char *hostname); +typedef enum ValidHostnameFlags { + VALID_HOSTNAME_TRAILING_DOT = 1 << 0, /* Accept trailing dot on multi-label names */ + VALID_HOSTNAME_DOT_HOST = 1 << 1, /* Accept ".host" as valid hostname */ +} ValidHostnameFlags; -int sethostname_idempotent(const char *s); +bool hostname_is_valid(const char *s, ValidHostnameFlags flags) _pure_; +char* hostname_cleanup(char *s); -int shorten_overlong(const char *s, char **ret); +bool is_localhost(const char *hostname); -int read_etc_hostname_stream(FILE *f, char **ret); -int read_etc_hostname(const char *path, char **ret); +static inline bool is_gateway_hostname(const char *hostname) { + /* This tries to identify the valid syntaxes for the our synthetic "gateway" host. */ + return STRCASE_IN_SET(hostname, "_gateway", "_gateway."); +} diff --git a/shared/systemd/src/basic/in-addr-util.c b/shared/systemd/src/basic/in-addr-util.c index 1ea3e7ff15..c315dcbb81 100644 --- a/shared/systemd/src/basic/in-addr-util.c +++ b/shared/systemd/src/basic/in-addr-util.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #include "nm-sd-adapt-shared.h" diff --git a/shared/systemd/src/basic/in-addr-util.h b/shared/systemd/src/basic/in-addr-util.h index 45c93a0056..24308b702e 100644 --- a/shared/systemd/src/basic/in-addr-util.h +++ b/shared/systemd/src/basic/in-addr-util.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include <netinet/in.h> diff --git a/shared/systemd/src/basic/io-util.c b/shared/systemd/src/basic/io-util.c index 8b0e354a48..f09c7fdd24 100644 --- a/shared/systemd/src/basic/io-util.c +++ b/shared/systemd/src/basic/io-util.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #include "nm-sd-adapt-shared.h" @@ -298,7 +298,7 @@ int iovw_put(struct iovec_wrapper *iovw, void *data, size_t len) { return -E2BIG; if (!GREEDY_REALLOC(iovw->iovec, iovw->size_bytes, iovw->count + 1)) - return log_oom(); + return -ENOMEM; iovw->iovec[iovw->count++] = IOVEC_MAKE(data, len); return 0; @@ -310,7 +310,7 @@ int iovw_put_string_field(struct iovec_wrapper *iovw, const char *field, const c x = strjoin(field, value); if (!x) - return log_oom(); + return -ENOMEM; r = iovw_put(iovw, x, strlen(x)); if (r >= 0) diff --git a/shared/systemd/src/basic/io-util.h b/shared/systemd/src/basic/io-util.h index 719e19e85d..d817714b05 100644 --- a/shared/systemd/src/basic/io-util.h +++ b/shared/systemd/src/basic/io-util.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include <stdbool.h> diff --git a/shared/systemd/src/basic/list.h b/shared/systemd/src/basic/list.h index b62c374985..256b7187c2 100644 --- a/shared/systemd/src/basic/list.h +++ b/shared/systemd/src/basic/list.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include "macro.h" diff --git a/shared/systemd/src/basic/log.h b/shared/systemd/src/basic/log.h index c2ffbb5d87..ee2e48392d 100644 --- a/shared/systemd/src/basic/log.h +++ b/shared/systemd/src/basic/log.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include <stdarg.h> @@ -44,10 +44,17 @@ typedef enum LogTarget{ #define ERRNO_VALUE(val) (abs(val) & 255) void log_set_target(LogTarget target); + void log_set_max_level_realm(LogRealm realm, int level); + #define log_set_max_level(level) \ log_set_max_level_realm(LOG_REALM, (level)) +static inline void log_set_max_level_all_realms(int level) { + for (LogRealm realm = 0; realm < _LOG_REALM_MAX; realm++) + log_set_max_level_realm(realm, level); +} + void log_set_facility(int facility); int log_set_target_from_string(const char *e); @@ -122,6 +129,31 @@ int log_internal_realm( #define log_internal(level, ...) \ log_internal_realm(LOG_REALM_PLUS_LEVEL(LOG_REALM, (level)), __VA_ARGS__) +#define log_object_internal(level, \ + error, \ + file, \ + line, \ + func, \ + object_field, \ + object, \ + extra_field, \ + extra, \ + format, \ + ...) \ + ({ \ + const char *const _object = (object); \ + \ + log_internal_realm((level), \ + (error), \ + file, \ + (line), \ + (func), \ + "%s%s" format, \ + _object ?: "", \ + _object ? ": " : "", \ + ##__VA_ARGS__); \ + }) + #if 0 /* NM_IGNORED */ int log_internalv_realm( int level, @@ -169,7 +201,7 @@ int log_struct_internal( const char *format, ...) _printf_(6,0) _sentinel_; int log_oom_internal( - LogRealm realm, + int level, const char *file, int line, const char *func); @@ -293,7 +325,8 @@ int log_emergency_level(void); log_dump_internal(LOG_REALM_PLUS_LEVEL(LOG_REALM, level), \ 0, PROJECT_FILE, __LINE__, __func__, buffer) -#define log_oom() log_oom_internal(LOG_REALM, PROJECT_FILE, __LINE__, __func__) +#define log_oom() log_oom_internal(LOG_REALM_PLUS_LEVEL(LOG_REALM, LOG_ERR), PROJECT_FILE, __LINE__, __func__) +#define log_oom_debug() log_oom_internal(LOG_REALM_PLUS_LEVEL(LOG_REALM, LOG_DEBUG), PROJECT_FILE, __LINE__, __func__) bool log_on_console(void) _pure_; diff --git a/shared/systemd/src/basic/macro.h b/shared/systemd/src/basic/macro.h index f872d41f05..34416b3daa 100644 --- a/shared/systemd/src/basic/macro.h +++ b/shared/systemd/src/basic/macro.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include <assert.h> @@ -94,6 +94,10 @@ #if (defined (__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))) || defined (__clang__) /* Temporarily disable some warnings */ +#define DISABLE_WARNING_DEPRECATED_DECLARATIONS \ + _Pragma("GCC diagnostic push"); \ + _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") + #define DISABLE_WARNING_FORMAT_NONLITERAL \ _Pragma("GCC diagnostic push"); \ _Pragma("GCC diagnostic ignored \"-Wformat-nonliteral\"") @@ -286,6 +290,12 @@ static inline size_t GREEDY_ALLOC_ROUND_UP(size_t l) { MAX(_c, z); \ }) +#define MAX4(x, y, z, a) \ + ({ \ + const typeof(x) _d = MAX3(x, y, z); \ + MAX(_d, a); \ + }) + #undef MIN #define MIN(a, b) __MIN(UNIQ, (a), UNIQ, (b)) #define __MIN(aq, a, bq, b) \ @@ -449,6 +459,9 @@ static inline int __coverity_check_and_return__(int condition) { #define PTR_TO_ULONG(p) ((unsigned long) ((uintptr_t) (p))) #define ULONG_TO_PTR(u) ((void *) ((uintptr_t) (u))) +#define PTR_TO_UINT8(p) ((uint8_t) ((uintptr_t) (p))) +#define UINT8_TO_PTR(u) ((void *) ((uintptr_t) (u))) + #define PTR_TO_INT32(p) ((int32_t) ((intptr_t) (p))) #define INT32_TO_PTR(u) ((void *) ((intptr_t) (u))) #define PTR_TO_UINT32(p) ((uint32_t) ((uintptr_t) (p))) @@ -550,10 +563,13 @@ static inline int __coverity_check_and_return__(int condition) { #define STRV_MAKE(...) ((char**) ((const char*[]) { __VA_ARGS__, NULL })) #define STRV_MAKE_EMPTY ((char*[1]) { NULL }) -/* Iterates through a specified list of pointers. Accepts NULL pointers, but uses (void*) -1 as internal marker for EOL. */ -#define FOREACH_POINTER(p, x, ...) \ - for (typeof(p) *_l = (typeof(p)[]) { ({ p = x; }), ##__VA_ARGS__, (void*) -1 }; \ - p != (typeof(p)) (void*) -1; \ +/* Pointers range from NULL to POINTER_MAX */ +#define POINTER_MAX ((void*) UINTPTR_MAX) + +/* Iterates through a specified list of pointers. Accepts NULL pointers, but uses POINTER_MAX as internal marker for EOL. */ +#define FOREACH_POINTER(p, x, ...) \ + for (typeof(p) *_l = (typeof(p)[]) { ({ p = x; }), ##__VA_ARGS__, POINTER_MAX }; \ + p != (typeof(p)) POINTER_MAX; \ p = *(++_l)) /* Define C11 thread_local attribute even on older gcc compiler @@ -643,4 +659,8 @@ static inline int __coverity_check_and_return__(int condition) { _copy; \ }) +static inline size_t size_add(size_t x, size_t y) { + return y >= SIZE_MAX - x ? SIZE_MAX : x + y; +} + #include "log.h" diff --git a/shared/systemd/src/basic/memory-util.c b/shared/systemd/src/basic/memory-util.c index bd1f5d737f..7ee7c94ed7 100644 --- a/shared/systemd/src/basic/memory-util.c +++ b/shared/systemd/src/basic/memory-util.c @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + #include "nm-sd-adapt-shared.h" #include <unistd.h> diff --git a/shared/systemd/src/basic/memory-util.h b/shared/systemd/src/basic/memory-util.h index 4f596cffb7..179edd247b 100644 --- a/shared/systemd/src/basic/memory-util.h +++ b/shared/systemd/src/basic/memory-util.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include <inttypes.h> diff --git a/shared/systemd/src/basic/mempool.c b/shared/systemd/src/basic/mempool.c index 8b8337dbbd..46c449142c 100644 --- a/shared/systemd/src/basic/mempool.c +++ b/shared/systemd/src/basic/mempool.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #include "nm-sd-adapt-shared.h" diff --git a/shared/systemd/src/basic/mempool.h b/shared/systemd/src/basic/mempool.h index 0eecca0f92..0fe2f2789c 100644 --- a/shared/systemd/src/basic/mempool.h +++ b/shared/systemd/src/basic/mempool.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include <stdbool.h> diff --git a/shared/systemd/src/basic/missing_fcntl.h b/shared/systemd/src/basic/missing_fcntl.h index 5d1c6352f4..00937d2af0 100644 --- a/shared/systemd/src/basic/missing_fcntl.h +++ b/shared/systemd/src/basic/missing_fcntl.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include <fcntl.h> diff --git a/shared/systemd/src/basic/missing_random.h b/shared/systemd/src/basic/missing_random.h index 17af87a3ae..443b913685 100644 --- a/shared/systemd/src/basic/missing_random.h +++ b/shared/systemd/src/basic/missing_random.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #if USE_SYS_RANDOM_H diff --git a/shared/systemd/src/basic/missing_socket.h b/shared/systemd/src/basic/missing_socket.h index fe4d35bd71..a4f6836fd4 100644 --- a/shared/systemd/src/basic/missing_socket.h +++ b/shared/systemd/src/basic/missing_socket.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include <sys/socket.h> @@ -69,6 +69,14 @@ struct sockaddr_vm { #define IPV6_FREEBIND 78 #endif +#ifndef IP_RECVFRAGSIZE +#define IP_RECVFRAGSIZE 25 +#endif + +#ifndef IPV6_RECVFRAGSIZE +#define IPV6_RECVFRAGSIZE 77 +#endif + /* linux/sockios.h */ #ifndef SIOCGSKNS #define SIOCGSKNS 0x894C diff --git a/shared/systemd/src/basic/missing_stat.h b/shared/systemd/src/basic/missing_stat.h index 5d59a21446..9c1df69822 100644 --- a/shared/systemd/src/basic/missing_stat.h +++ b/shared/systemd/src/basic/missing_stat.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include <linux/types.h> diff --git a/shared/systemd/src/basic/missing_syscall.h b/shared/systemd/src/basic/missing_syscall.h index d11a77d533..42d647535e 100644 --- a/shared/systemd/src/basic/missing_syscall.h +++ b/shared/systemd/src/basic/missing_syscall.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once /* Missing glibc definitions to access certain kernel APIs */ @@ -15,6 +15,26 @@ #include <asm/sgidefs.h> #endif +#if defined(__alpha__) +# define systemd_SC_arch_bias(x) (110 + (x)) +#elif defined(__ia64__) +# define systemd_SC_arch_bias(x) (1024 + (x)) +#elif defined(_MIPS_SIM) +# if _MIPS_SIM == _MIPS_SIM_ABI32 +# define systemd_SC_arch_bias(x) (4000 + (x)) +# elif _MIPS_SIM == _MIPS_SIM_NABI32 +# define systemd_SC_arch_bias(x) (6000 + (x)) +# elif _MIPS_SIM == _MIPS_SIM_ABI64 +# define systemd_SC_arch_bias(x) (5000 + (x)) +# else +# error "Unknown MIPS ABI" +# endif +#elif defined(__x86_64__) && defined(__ILP32__) +# define systemd_SC_arch_bias(x) ((x) | /* __X32_SYSCALL_BIT */ 0x40000000) +#else +# define systemd_SC_arch_bias(x) (x) +#endif + #include "missing_keyctl.h" #include "missing_stat.h" @@ -35,32 +55,38 @@ static inline int missing_pivot_root(const char *new_root, const char *put_old) /* ======================================================================= */ -#if defined __x86_64__ -# define systemd_NR_memfd_create 319 -#elif defined __arm__ -# define systemd_NR_memfd_create 385 -#elif defined __aarch64__ +#if defined(__aarch64__) # define systemd_NR_memfd_create 279 +#elif defined(__alpha__) +# define systemd_NR_memfd_create 512 +#elif defined(__arc__) || defined(__tilegx__) +# define systemd_NR_memfd_create 279 +#elif defined(__arm__) +# define systemd_NR_memfd_create 385 +#elif defined(__i386__) +# define systemd_NR_memfd_create 356 +#elif defined(__ia64__) +# define systemd_NR_memfd_create systemd_SC_arch_bias(316) +#elif defined(__m68k__) +# define systemd_NR_memfd_create 353 +#elif defined(_MIPS_SIM) +# if _MIPS_SIM == _MIPS_SIM_ABI32 +# define systemd_NR_memfd_create systemd_SC_arch_bias(354) +# elif _MIPS_SIM == _MIPS_SIM_NABI32 +# define systemd_NR_memfd_create systemd_SC_arch_bias(318) +# elif _MIPS_SIM == _MIPS_SIM_ABI64 +# define systemd_NR_memfd_create systemd_SC_arch_bias(314) +# endif #elif defined(__powerpc__) # define systemd_NR_memfd_create 360 -#elif defined __s390__ +#elif defined(__s390__) # define systemd_NR_memfd_create 350 -#elif defined _MIPS_SIM -# if _MIPS_SIM == _MIPS_SIM_ABI32 -# define systemd_NR_memfd_create 4354 -# endif -# if _MIPS_SIM == _MIPS_SIM_NABI32 -# define systemd_NR_memfd_create 6318 -# endif -# if _MIPS_SIM == _MIPS_SIM_ABI64 -# define systemd_NR_memfd_create 5314 -# endif -#elif defined __i386__ -# define systemd_NR_memfd_create 356 -#elif defined __arc__ -# define systemd_NR_memfd_create 279 +#elif defined(__sparc__) +# define systemd_NR_memfd_create 348 +#elif defined(__x86_64__) +# define systemd_NR_memfd_create systemd_SC_arch_bias(319) #else -# warning "memfd_create() syscall number unknown for your architecture" +# warning "memfd_create() syscall number is unknown for your architecture" #endif /* may be (invalid) negative number due to libseccomp, see PR 13319 */ @@ -92,36 +118,38 @@ static inline int missing_memfd_create(const char *name, unsigned int flags) { /* ======================================================================= */ -#if defined __x86_64__ -# define systemd_NR_getrandom 318 -#elif defined(__i386__) -# define systemd_NR_getrandom 355 +#if defined(__aarch64__) +# define systemd_NR_getrandom 278 +#elif defined(__alpha__) +# define systemd_NR_getrandom 511 +#elif defined(__arc__) || defined(__tilegx__) +# define systemd_NR_getrandom 278 #elif defined(__arm__) # define systemd_NR_getrandom 384 -#elif defined(__aarch64__) -# define systemd_NR_getrandom 278 +#elif defined(__i386__) +# define systemd_NR_getrandom 355 #elif defined(__ia64__) -# define systemd_NR_getrandom 1339 +# define systemd_NR_getrandom systemd_SC_arch_bias(318) #elif defined(__m68k__) # define systemd_NR_getrandom 352 -#elif defined(__s390x__) -# define systemd_NR_getrandom 349 -#elif defined(__powerpc__) -# define systemd_NR_getrandom 359 -#elif defined _MIPS_SIM +#elif defined(_MIPS_SIM) # if _MIPS_SIM == _MIPS_SIM_ABI32 -# define systemd_NR_getrandom 4353 -# endif -# if _MIPS_SIM == _MIPS_SIM_NABI32 -# define systemd_NR_getrandom 6317 +# define systemd_NR_getrandom systemd_SC_arch_bias(353) +# elif _MIPS_SIM == _MIPS_SIM_NABI32 +# define systemd_NR_getrandom systemd_SC_arch_bias(317) +# elif _MIPS_SIM == _MIPS_SIM_ABI64 +# define systemd_NR_getrandom systemd_SC_arch_bias(313) # endif -# if _MIPS_SIM == _MIPS_SIM_ABI64 -# define systemd_NR_getrandom 5313 -# endif -#elif defined(__arc__) -# define systemd_NR_getrandom 278 +#elif defined(__powerpc__) +# define systemd_NR_getrandom 359 +#elif defined(__s390__) +# define systemd_NR_getrandom 349 +#elif defined(__sparc__) +# define systemd_NR_getrandom 347 +#elif defined(__x86_64__) +# define systemd_NR_getrandom systemd_SC_arch_bias(318) #else -# warning "getrandom() syscall number unknown for your architecture" +# warning "getrandom() syscall number is unknown for your architecture" #endif /* may be (invalid) negative number due to libseccomp, see PR 13319 */ @@ -168,22 +196,38 @@ static inline pid_t missing_gettid(void) { /* ======================================================================= */ -#if defined(__x86_64__) -# define systemd_NR_name_to_handle_at 303 -#elif defined(__i386__) -# define systemd_NR_name_to_handle_at 341 +#if defined(__aarch64__) +# define systemd_NR_name_to_handle_at 264 +#elif defined(__alpha__) +# define systemd_NR_name_to_handle_at 497 +#elif defined(__arc__) || defined(__tilegx__) +# define systemd_NR_name_to_handle_at 264 #elif defined(__arm__) # define systemd_NR_name_to_handle_at 370 -#elif defined __aarch64__ -# define systemd_NR_name_to_handle_at 264 +#elif defined(__i386__) +# define systemd_NR_name_to_handle_at 341 +#elif defined(__ia64__) +# define systemd_NR_name_to_handle_at systemd_SC_arch_bias(302) +#elif defined(__m68k__) +# define systemd_NR_name_to_handle_at 340 +#elif defined(_MIPS_SIM) +# if _MIPS_SIM == _MIPS_SIM_ABI32 +# define systemd_NR_name_to_handle_at systemd_SC_arch_bias(339) +# elif _MIPS_SIM == _MIPS_SIM_NABI32 +# define systemd_NR_name_to_handle_at systemd_SC_arch_bias(303) +# elif _MIPS_SIM == _MIPS_SIM_ABI64 +# define systemd_NR_name_to_handle_at systemd_SC_arch_bias(298) +# endif #elif defined(__powerpc__) # define systemd_NR_name_to_handle_at 345 -#elif defined __s390__ || defined __s390x__ +#elif defined(__s390__) # define systemd_NR_name_to_handle_at 335 -#elif defined(__arc__) -# define systemd_NR_name_to_handle_at 264 +#elif defined(__sparc__) +# define systemd_NR_name_to_handle_at 332 +#elif defined(__x86_64__) +# define systemd_NR_name_to_handle_at systemd_SC_arch_bias(303) #else -# warning "name_to_handle_at number is not defined" +# warning "name_to_handle_at() syscall number is unknown for your architecture" #endif /* may be (invalid) negative number due to libseccomp, see PR 13319 */ @@ -221,22 +265,38 @@ static inline int missing_name_to_handle_at(int fd, const char *name, struct fil /* ======================================================================= */ -#if defined __aarch64__ +#if defined(__aarch64__) # define systemd_NR_setns 268 -#elif defined __arm__ +#elif defined(__alpha__) +# define systemd_NR_setns 501 +#elif defined(__arc__) || defined(__tilegx__) +# define systemd_NR_setns 268 +#elif defined(__arm__) # define systemd_NR_setns 375 -#elif defined(__x86_64__) -# define systemd_NR_setns 308 #elif defined(__i386__) # define systemd_NR_setns 346 +#elif defined(__ia64__) +# define systemd_NR_setns systemd_SC_arch_bias(306) +#elif defined(__m68k__) +# define systemd_NR_setns 344 +#elif defined(_MIPS_SIM) +# if _MIPS_SIM == _MIPS_SIM_ABI32 +# define systemd_NR_setns systemd_SC_arch_bias(344) +# elif _MIPS_SIM == _MIPS_SIM_NABI32 +# define systemd_NR_setns systemd_SC_arch_bias(308) +# elif _MIPS_SIM == _MIPS_SIM_ABI64 +# define systemd_NR_setns systemd_SC_arch_bias(303) +# endif #elif defined(__powerpc__) # define systemd_NR_setns 350 -#elif defined __s390__ || defined __s390x__ +#elif defined(__s390__) # define systemd_NR_setns 339 -#elif defined(__arc__) -# define systemd_NR_setns 268 +#elif defined(__sparc__) +# define systemd_NR_setns 337 +#elif defined(__x86_64__) +# define systemd_NR_setns systemd_SC_arch_bias(308) #else -# warning "setns() syscall number unknown for your architecture" +# warning "setns() syscall number is unknown for your architecture" #endif /* may be (invalid) negative number due to libseccomp, see PR 13319 */ @@ -278,32 +338,38 @@ static inline pid_t raw_getpid(void) { /* ======================================================================= */ -#if defined __x86_64__ -# define systemd_NR_renameat2 316 -#elif defined __arm__ -# define systemd_NR_renameat2 382 -#elif defined __aarch64__ +#if defined(__aarch64__) # define systemd_NR_renameat2 276 -#elif defined _MIPS_SIM +#elif defined(__alpha__) +# define systemd_NR_renameat2 510 +#elif defined(__arc__) || defined(__tilegx__) +# define systemd_NR_renameat2 276 +#elif defined(__arm__) +# define systemd_NR_renameat2 382 +#elif defined(__i386__) +# define systemd_NR_renameat2 353 +#elif defined(__ia64__) +# define systemd_NR_renameat2 systemd_SC_arch_bias(314) +#elif defined(__m68k__) +# define systemd_NR_renameat2 351 +#elif defined(_MIPS_SIM) # if _MIPS_SIM == _MIPS_SIM_ABI32 -# define systemd_NR_renameat2 4351 +# define systemd_NR_renameat2 systemd_SC_arch_bias(351) +# elif _MIPS_SIM == _MIPS_SIM_NABI32 +# define systemd_NR_renameat2 systemd_SC_arch_bias(315) +# elif _MIPS_SIM == _MIPS_SIM_ABI64 +# define systemd_NR_renameat2 systemd_SC_arch_bias(311) # endif -# if _MIPS_SIM == _MIPS_SIM_NABI32 -# define systemd_NR_renameat2 6315 -# endif -# if _MIPS_SIM == _MIPS_SIM_ABI64 -# define systemd_NR_renameat2 5311 -# endif -#elif defined __i386__ -# define systemd_NR_renameat2 353 -#elif defined __powerpc64__ +#elif defined(__powerpc__) # define systemd_NR_renameat2 357 -#elif defined __s390__ || defined __s390x__ +#elif defined(__s390__) # define systemd_NR_renameat2 347 -#elif defined __arc__ -# define systemd_NR_renameat2 276 +#elif defined(__sparc__) +# define systemd_NR_renameat2 345 +#elif defined(__x86_64__) +# define systemd_NR_renameat2 systemd_SC_arch_bias(316) #else -# warning "renameat2() syscall number unknown for your architecture" +# warning "renameat2() syscall number is unknown for your architecture" #endif /* may be (invalid) negative number due to libseccomp, see PR 13319 */ @@ -387,22 +453,38 @@ static inline key_serial_t missing_request_key(const char *type, const char *des /* ======================================================================= */ -#if defined(__x86_64__) -# define systemd_NR_copy_file_range 326 +#if defined(__aarch64__) +# define systemd_NR_copy_file_range 285 +#elif defined(__alpha__) +# define systemd_NR_copy_file_range 519 +#elif defined(__arc__) || defined(__tilegx__) +# define systemd_NR_copy_file_range 285 +#elif defined(__arm__) +# define systemd_NR_copy_file_range 391 #elif defined(__i386__) # define systemd_NR_copy_file_range 377 -#elif defined __s390__ -# define systemd_NR_copy_file_range 375 -#elif defined __arm__ -# define systemd_NR_copy_file_range 391 -#elif defined __aarch64__ -# define systemd_NR_copy_file_range 285 -#elif defined __powerpc__ +#elif defined(__ia64__) +# define systemd_NR_copy_file_range systemd_SC_arch_bias(323) +#elif defined(__m68k__) +# define systemd_NR_copy_file_range 376 +#elif defined(_MIPS_SIM) +# if _MIPS_SIM == _MIPS_SIM_ABI32 +# define systemd_NR_copy_file_range systemd_SC_arch_bias(360) +# elif _MIPS_SIM == _MIPS_SIM_NABI32 +# define systemd_NR_copy_file_range systemd_SC_arch_bias(324) +# elif _MIPS_SIM == _MIPS_SIM_ABI64 +# define systemd_NR_copy_file_range systemd_SC_arch_bias(320) +# endif +#elif defined(__powerpc__) # define systemd_NR_copy_file_range 379 -#elif defined __arc__ -# define systemd_NR_copy_file_range 285 +#elif defined(__s390__) +# define systemd_NR_copy_file_range 375 +#elif defined(__sparc__) +# define systemd_NR_copy_file_range 357 +#elif defined(__x86_64__) +# define systemd_NR_copy_file_range systemd_SC_arch_bias(326) #else -# warning "copy_file_range() syscall number unknown for your architecture" +# warning "copy_file_range() syscall number is unknown for your architecture" #endif /* may be (invalid) negative number due to libseccomp, see PR 13319 */ @@ -437,24 +519,38 @@ static inline ssize_t missing_copy_file_range(int fd_in, loff_t *off_in, /* ======================================================================= */ -#if defined __i386__ -# define systemd_NR_bpf 357 -#elif defined __x86_64__ -# define systemd_NR_bpf 321 -#elif defined __aarch64__ +#if defined(__aarch64__) +# define systemd_NR_bpf 280 +#elif defined(__alpha__) +# define systemd_NR_bpf 515 +#elif defined(__arc__) || defined(__tilegx__) # define systemd_NR_bpf 280 -#elif defined __arm__ +#elif defined(__arm__) # define systemd_NR_bpf 386 +#elif defined(__i386__) +# define systemd_NR_bpf 357 +#elif defined(__ia64__) +# define systemd_NR_bpf systemd_SC_arch_bias(317) +#elif defined(__m68k__) +# define systemd_NR_bpf 354 +#elif defined(_MIPS_SIM) +# if _MIPS_SIM == _MIPS_SIM_ABI32 +# define systemd_NR_bpf systemd_SC_arch_bias(355) +# elif _MIPS_SIM == _MIPS_SIM_NABI32 +# define systemd_NR_bpf systemd_SC_arch_bias(319) +# elif _MIPS_SIM == _MIPS_SIM_ABI64 +# define systemd_NR_bpf systemd_SC_arch_bias(315) +# endif #elif defined(__powerpc__) # define systemd_NR_bpf 361 -#elif defined __sparc__ -# define systemd_NR_bpf 349 -#elif defined __s390__ +#elif defined(__s390__) # define systemd_NR_bpf 351 -#elif defined __tilegx__ -# define systemd_NR_bpf 280 +#elif defined(__sparc__) +# define systemd_NR_bpf 349 +#elif defined(__x86_64__) +# define systemd_NR_bpf systemd_SC_arch_bias(321) #else -# warning "bpf() syscall number unknown for your architecture" +# warning "bpf() syscall number is unknown for your architecture" #endif /* may be (invalid) negative number due to libseccomp, see PR 13319 */ @@ -489,30 +585,38 @@ static inline int missing_bpf(int cmd, union bpf_attr *attr, size_t size) { /* ======================================================================= */ #ifndef __IGNORE_pkey_mprotect -# if defined __i386__ -# define systemd_NR_pkey_mprotect 380 -# elif defined __x86_64__ -# define systemd_NR_pkey_mprotect 329 -# elif defined __aarch64__ +# if defined(__aarch64__) # define systemd_NR_pkey_mprotect 288 -# elif defined __arm__ +# elif defined(__alpha__) +# define systemd_NR_pkey_mprotect 524 +# elif defined(__arc__) || defined(__tilegx__) +# define systemd_NR_pkey_mprotect 226 +# elif defined(__arm__) # define systemd_NR_pkey_mprotect 394 -# elif defined __powerpc__ -# define systemd_NR_pkey_mprotect 386 -# elif defined __s390__ -# define systemd_NR_pkey_mprotect 384 -# elif defined _MIPS_SIM +# elif defined(__i386__) +# define systemd_NR_pkey_mprotect 380 +# elif defined(__ia64__) +# define systemd_NR_pkey_mprotect systemd_SC_arch_bias(330) +# elif defined(__m68k__) +# define systemd_NR_pkey_mprotect 381 +# elif defined(_MIPS_SIM) # if _MIPS_SIM == _MIPS_SIM_ABI32 -# define systemd_NR_pkey_mprotect 4363 -# endif -# if _MIPS_SIM == _MIPS_SIM_NABI32 -# define systemd_NR_pkey_mprotect 6327 -# endif -# if _MIPS_SIM == _MIPS_SIM_ABI64 -# define systemd_NR_pkey_mprotect 5323 +# define systemd_NR_pkey_mprotect systemd_SC_arch_bias(363) +# elif _MIPS_SIM == _MIPS_SIM_NABI32 +# define systemd_NR_pkey_mprotect systemd_SC_arch_bias(327) +# elif _MIPS_SIM == _MIPS_SIM_ABI64 +# define systemd_NR_pkey_mprotect systemd_SC_arch_bias(323) # endif +# elif defined(__powerpc__) +# define systemd_NR_pkey_mprotect 386 +# elif defined(__s390__) +# define systemd_NR_pkey_mprotect 384 +# elif defined(__sparc__) +# define systemd_NR_pkey_mprotect 362 +# elif defined(__x86_64__) +# define systemd_NR_pkey_mprotect systemd_SC_arch_bias(329) # else -# warning "pkey_mprotect() syscall number unknown for your architecture" +# warning "pkey_mprotect() syscall number is unknown for your architecture" # endif /* may be (invalid) negative number due to libseccomp, see PR 13319 */ @@ -532,22 +636,38 @@ assert_cc(__NR_pkey_mprotect == systemd_NR_pkey_mprotect); /* ======================================================================= */ -#if defined __aarch64__ +#if defined(__aarch64__) # define systemd_NR_statx 291 -#elif defined __arm__ -# define systemd_NR_statx 397 -#elif defined __alpha__ +#elif defined(__alpha__) # define systemd_NR_statx 522 -#elif defined __i386__ || defined __powerpc64__ +#elif defined(__arc__) || defined(__tilegx__) +# define systemd_NR_statx 291 +#elif defined(__arm__) +# define systemd_NR_statx 397 +#elif defined(__i386__) +# define systemd_NR_statx 383 +#elif defined(__ia64__) +# define systemd_NR_statx systemd_SC_arch_bias(326) +#elif defined(__m68k__) +# define systemd_NR_statx 379 +#elif defined(_MIPS_SIM) +# if _MIPS_SIM == _MIPS_SIM_ABI32 +# define systemd_NR_statx systemd_SC_arch_bias(366) +# elif _MIPS_SIM == _MIPS_SIM_NABI32 +# define systemd_NR_statx systemd_SC_arch_bias(330) +# elif _MIPS_SIM == _MIPS_SIM_ABI64 +# define systemd_NR_statx systemd_SC_arch_bias(326) +# endif +#elif defined(__powerpc__) # define systemd_NR_statx 383 -#elif defined __s390__ || defined __s390x__ +#elif defined(__s390__) # define systemd_NR_statx 379 -#elif defined __sparc__ +#elif defined(__sparc__) # define systemd_NR_statx 360 -#elif defined __x86_64__ -# define systemd_NR_statx 332 +#elif defined(__x86_64__) +# define systemd_NR_statx systemd_SC_arch_bias(332) #else -# warning "statx() syscall number unknown for your architecture" +# warning "statx() syscall number is unknown for your architecture" #endif /* may be (invalid) negative number due to libseccomp, see PR 13319 */ @@ -632,23 +752,7 @@ static inline long missing_get_mempolicy(int *mode, unsigned long *nodemask, /* ======================================================================= */ /* should be always defined, see kernel 39036cd2727395c3369b1051005da74059a85317 */ -#if defined __alpha__ -# define systemd_NR_pidfd_send_signal 534 -#elif defined _MIPS_SIM -# if _MIPS_SIM == _MIPS_SIM_ABI32 /* o32 */ -# define systemd_NR_pidfd_send_signal (424 + 4000) -# endif -# if _MIPS_SIM == _MIPS_SIM_NABI32 /* n32 */ -# define systemd_NR_pidfd_send_signal (424 + 6000) -# endif -# if _MIPS_SIM == _MIPS_SIM_ABI64 /* n64 */ -# define systemd_NR_pidfd_send_signal (424 + 5000) -# endif -#elif defined __ia64__ -# define systemd_NR_pidfd_send_signal (424 + 1024) -#else -# define systemd_NR_pidfd_send_signal 424 -#endif +#define systemd_NR_pidfd_send_signal systemd_SC_arch_bias(424) /* may be (invalid) negative number due to libseccomp, see PR 13319 */ #if defined __NR_pidfd_send_signal && __NR_pidfd_send_signal >= 0 @@ -664,7 +768,7 @@ assert_cc(__NR_pidfd_send_signal == systemd_NR_pidfd_send_signal); #if !HAVE_PIDFD_SEND_SIGNAL static inline int missing_pidfd_send_signal(int fd, int sig, siginfo_t *info, unsigned flags) { -# ifdef __NR_pidfd_open +# ifdef __NR_pidfd_send_signal return syscall(__NR_pidfd_send_signal, fd, sig, info, flags); # else errno = ENOSYS; @@ -676,23 +780,7 @@ static inline int missing_pidfd_send_signal(int fd, int sig, siginfo_t *info, un #endif /* should be always defined, see kernel 7615d9e1780e26e0178c93c55b73309a5dc093d7 */ -#if defined __alpha__ -# define systemd_NR_pidfd_open 544 -#elif defined _MIPS_SIM -# if _MIPS_SIM == _MIPS_SIM_ABI32 /* o32 */ -# define systemd_NR_pidfd_open (434 + 4000) -# endif -# if _MIPS_SIM == _MIPS_SIM_NABI32 /* n32 */ -# define systemd_NR_pidfd_open (434 + 6000) -# endif -# if _MIPS_SIM == _MIPS_SIM_ABI64 /* n64 */ -# define systemd_NR_pidfd_open (434 + 5000) -# endif -#elif defined __ia64__ -# define systemd_NR_pidfd_open (434 + 1024) -#else -# define systemd_NR_pidfd_open 434 -#endif +#define systemd_NR_pidfd_open systemd_SC_arch_bias(434) /* may be (invalid) negative number due to libseccomp, see PR 13319 */ #if defined __NR_pidfd_open && __NR_pidfd_open >= 0 @@ -732,3 +820,70 @@ static inline int missing_rt_sigqueueinfo(pid_t tgid, int sig, siginfo_t *info) # define rt_sigqueueinfo missing_rt_sigqueueinfo #endif + +/* ======================================================================= */ + +#if 0 /* NM_IGNORED */ +#if !HAVE_EXECVEAT +static inline int missing_execveat(int dirfd, const char *pathname, + char *const argv[], char *const envp[], + int flags) { +# if defined __NR_execveat && __NR_execveat >= 0 + return syscall(__NR_execveat, dirfd, pathname, argv, envp, flags); +# else + errno = ENOSYS; + return -1; +# endif +} + +# undef AT_EMPTY_PATH +# define AT_EMPTY_PATH 0x1000 +# define execveat missing_execveat +#endif + +/* ======================================================================= */ + +#define systemd_NR_close_range systemd_SC_arch_bias(436) + +/* may be (invalid) negative number due to libseccomp, see PR 13319 */ +#if defined __NR_close_range && __NR_close_range >= 0 +# if defined systemd_NR_close_range +assert_cc(__NR_close_range == systemd_NR_close_range); +# endif +#else +# if defined __NR_close_range +# undef __NR_close_range +# endif +# if defined systemd_NR_close_range +# define __NR_close_range systemd_NR_close_range +# endif +#endif + +#if !HAVE_CLOSE_RANGE +static inline int missing_close_range(int first_fd, int end_fd, unsigned flags) { +# ifdef __NR_close_range + /* Kernel-side the syscall expects fds as unsigned integers (just like close() actually), while + * userspace exclusively uses signed integers for fds. We don't know just yet how glibc is going to + * wrap this syscall, but let's assume it's going to be similar to what they do for close(), + * i.e. make the same unsigned → signed type change from the raw kernel syscall compared to the + * userspace wrapper. There's only one caveat for this: unlike for close() there's the special + * UINT_MAX fd value for the 'end_fd' argument. Let's safely map that to -1 here. And let's refuse + * any other negative values. */ + if ((first_fd < 0) || (end_fd < 0 && end_fd != -1)) { + errno = -EBADF; + return -1; + } + + return syscall(__NR_close_range, + (unsigned) first_fd, + end_fd == -1 ? UINT_MAX : (unsigned) end_fd, /* Of course, the compiler should figure out that this is the identity mapping IRL */ + flags); +# else + errno = ENOSYS; + return -1; +# endif +} + +# define close_range missing_close_range +#endif +#endif /* NM_IGNORED */ diff --git a/shared/systemd/src/basic/missing_type.h b/shared/systemd/src/basic/missing_type.h index bf8a6caa1b..f6233090a9 100644 --- a/shared/systemd/src/basic/missing_type.h +++ b/shared/systemd/src/basic/missing_type.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include <uchar.h> diff --git a/shared/systemd/src/basic/parse-util.c b/shared/systemd/src/basic/parse-util.c index 6b47317a42..d53bf620af 100644 --- a/shared/systemd/src/basic/parse-util.c +++ b/shared/systemd/src/basic/parse-util.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #include "nm-sd-adapt-shared.h" @@ -867,4 +867,46 @@ int parse_oom_score_adjust(const char *s, int *ret) { *ret = v; return 0; } + +int store_loadavg_fixed_point(unsigned long i, unsigned long f, loadavg_t *ret) { + assert(ret); + + if (i >= (~0UL << FSHIFT)) + return -ERANGE; + + i = i << FSHIFT; + f = DIV_ROUND_UP((f << FSHIFT), 100); + + if (f >= FIXED_1) + return -ERANGE; + + *ret = i | f; + return 0; +} + +int parse_loadavg_fixed_point(const char *s, loadavg_t *ret) { + const char *d, *f_str, *i_str; + unsigned long i, f; + int r; + + assert(s); + assert(ret); + + d = strchr(s, '.'); + if (!d) + return -EINVAL; + + i_str = strndupa(s, d - s); + f_str = d + 1; + + r = safe_atolu_full(i_str, 10, &i); + if (r < 0) + return r; + + r = safe_atolu_full(f_str, 10, &f); + if (r < 0) + return r; + + return store_loadavg_fixed_point(i, f, ret); +} #endif /* NM_IGNORED */ diff --git a/shared/systemd/src/basic/parse-util.h b/shared/systemd/src/basic/parse-util.h index 2cee65c49a..ba4e727e3e 100644 --- a/shared/systemd/src/basic/parse-util.h +++ b/shared/systemd/src/basic/parse-util.h @@ -1,14 +1,19 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include <inttypes.h> #include <limits.h> +#if 0 /* NM_IGNORED */ +#include <linux/loadavg.h> +#endif /* NM_IGNORED */ #include <stddef.h> #include <stdint.h> #include <sys/types.h> #include "macro.h" +typedef unsigned long loadavg_t; + int parse_boolean(const char *v) _pure_; int parse_dev(const char *s, dev_t *ret); int parse_pid(const char *s, pid_t* ret_pid); @@ -88,18 +93,18 @@ static inline int safe_atoux64(const char *s, uint64_t *ret) { } #if LONG_MAX == INT_MAX -static inline int safe_atolu(const char *s, unsigned long *ret_u) { +static inline int safe_atolu_full(const char *s, unsigned base, long unsigned *ret_u) { assert_cc(sizeof(unsigned long) == sizeof(unsigned)); - return safe_atou(s, (unsigned*) ret_u); + return safe_atou_full(s, base, (unsigned*) ret_u); } static inline int safe_atoli(const char *s, long int *ret_u) { assert_cc(sizeof(long int) == sizeof(int)); return safe_atoi(s, (int*) ret_u); } #else -static inline int safe_atolu(const char *s, unsigned long *ret_u) { +static inline int safe_atolu_full(const char *s, unsigned base, unsigned long *ret_u) { assert_cc(sizeof(unsigned long) == sizeof(unsigned long long)); - return safe_atollu(s, (unsigned long long*) ret_u); + return safe_atollu_full(s, base, (unsigned long long*) ret_u); } static inline int safe_atoli(const char *s, long int *ret_u) { assert_cc(sizeof(long int) == sizeof(long long int)); @@ -107,6 +112,10 @@ static inline int safe_atoli(const char *s, long int *ret_u) { } #endif +static inline int safe_atolu(const char *s, unsigned long *ret_u) { + return safe_atolu_full(s, 0, ret_u); +} + #if SIZE_MAX == UINT_MAX static inline int safe_atozu(const char *s, size_t *ret_u) { assert_cc(sizeof(size_t) == sizeof(unsigned)); @@ -137,3 +146,8 @@ int parse_ip_port_range(const char *s, uint16_t *low, uint16_t *high); int parse_ip_prefix_length(const char *s, int *ret); int parse_oom_score_adjust(const char *s, int *ret); + +/* Given a Linux load average (e.g. decimal number 34.89 where 34 is passed as i and 89 is passed as f), convert it + * to a loadavg_t. */ +int store_loadavg_fixed_point(unsigned long i, unsigned long f, loadavg_t *ret); +int parse_loadavg_fixed_point(const char *s, loadavg_t *ret); diff --git a/shared/systemd/src/basic/path-util.c b/shared/systemd/src/basic/path-util.c index 644829b273..ea44c32bfc 100644 --- a/shared/systemd/src/basic/path-util.c +++ b/shared/systemd/src/basic/path-util.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #include "nm-sd-adapt-shared.h" @@ -558,7 +558,7 @@ char* path_join_internal(const char *first, ...) { sz = strlen_ptr(first); va_start(ap, first); - while ((p = va_arg(ap, char*)) != (const char*) -1) + while ((p = va_arg(ap, char*)) != POINTER_MAX) if (!isempty(p)) sz += 1 + strlen(p); va_end(ap); @@ -578,7 +578,7 @@ char* path_join_internal(const char *first, ...) { } va_start(ap, first); - while ((p = va_arg(ap, char*)) != (const char*) -1) { + while ((p = va_arg(ap, char*)) != POINTER_MAX) { if (isempty(p)) continue; @@ -594,22 +594,53 @@ char* path_join_internal(const char *first, ...) { } #if 0 /* NM_IGNORED */ -int find_executable_full(const char *name, bool use_path_envvar, char **ret) { +static int check_x_access(const char *path, int *ret_fd) { + if (ret_fd) { + _cleanup_close_ int fd = -1; + int r; + + /* We need to use O_PATH because there may be executables for which we have only exec + * permissions, but not read (usually suid executables). */ + fd = open(path, O_PATH|O_CLOEXEC); + if (fd < 0) + return -errno; + + r = access_fd(fd, X_OK); + if (r < 0) + return r; + + *ret_fd = TAKE_FD(fd); + } else { + /* Let's optimize things a bit by not opening the file if we don't need the fd. */ + if (access(path, X_OK) < 0) + return -errno; + } + + return 0; +} + +int find_executable_full(const char *name, bool use_path_envvar, char **ret_filename, int *ret_fd) { int last_error, r; const char *p = NULL; assert(name); if (is_path(name)) { - if (access(name, X_OK) < 0) - return -errno; + _cleanup_close_ int fd = -1; - if (ret) { - r = path_make_absolute_cwd(name, ret); + r = check_x_access(name, ret_fd ? &fd : NULL); + if (r < 0) + return r; + + if (ret_filename) { + r = path_make_absolute_cwd(name, ret_filename); if (r < 0) return r; } + if (ret_fd) + *ret_fd = TAKE_FD(fd); + return 0; } @@ -622,8 +653,10 @@ int find_executable_full(const char *name, bool use_path_envvar, char **ret) { last_error = -ENOENT; + /* Resolve a single-component name to a full path */ for (;;) { _cleanup_free_ char *j = NULL, *element = NULL; + _cleanup_close_ int fd = -1; r = extract_first_word(&p, &element, ":", EXTRACT_RELAX|EXTRACT_DONT_COALESCE_SEPARATORS); if (r < 0) @@ -638,7 +671,8 @@ int find_executable_full(const char *name, bool use_path_envvar, char **ret) { if (!j) return -ENOMEM; - if (access(j, X_OK) >= 0) { + r = check_x_access(j, ret_fd ? &fd : NULL); + if (r >= 0) { _cleanup_free_ char *with_dash; with_dash = strjoin(j, "/"); @@ -652,8 +686,10 @@ int find_executable_full(const char *name, bool use_path_envvar, char **ret) { /* We can't just `continue` inverting this case, since we need to update last_error. */ if (errno == ENOTDIR) { /* Found it! */ - if (ret) - *ret = path_simplify(TAKE_PTR(j), false); + if (ret_filename) + *ret_filename = path_simplify(TAKE_PTR(j), false); + if (ret_fd) + *ret_fd = TAKE_FD(fd); return 0; } diff --git a/shared/systemd/src/basic/path-util.h b/shared/systemd/src/basic/path-util.h index 6c26551911..988f058b5a 100644 --- a/shared/systemd/src/basic/path-util.h +++ b/shared/systemd/src/basic/path-util.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include <alloca.h> @@ -64,7 +64,7 @@ int path_compare(const char *a, const char *b) _pure_; bool path_equal(const char *a, const char *b) _pure_; bool path_equal_or_files_same(const char *a, const char *b, int flags); char* path_join_internal(const char *first, ...); -#define path_join(x, ...) path_join_internal(x, __VA_ARGS__, (const char*) -1) +#define path_join(x, ...) path_join_internal(x, __VA_ARGS__, POINTER_MAX) char* path_simplify(char *path, bool kill_dots); @@ -90,9 +90,9 @@ int path_strv_make_absolute_cwd(char **l); char** path_strv_resolve(char **l, const char *root); char** path_strv_resolve_uniq(char **l, const char *root); -int find_executable_full(const char *name, bool use_path_envvar, char **ret); -static inline int find_executable(const char *name, char **ret) { - return find_executable_full(name, true, ret); +int find_executable_full(const char *name, bool use_path_envvar, char **ret_filename, int *ret_fd); +static inline int find_executable(const char *name, char **ret_filename) { + return find_executable_full(name, true, ret_filename, NULL); } bool paths_check_timestamp(const char* const* paths, usec_t *paths_ts_usec, bool update); diff --git a/shared/systemd/src/basic/prioq.c b/shared/systemd/src/basic/prioq.c index dc048cc731..19a9bc57e8 100644 --- a/shared/systemd/src/basic/prioq.c +++ b/shared/systemd/src/basic/prioq.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Priority Queue diff --git a/shared/systemd/src/basic/prioq.h b/shared/systemd/src/basic/prioq.h index 1fb57bfa4c..951576c021 100644 --- a/shared/systemd/src/basic/prioq.h +++ b/shared/systemd/src/basic/prioq.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include <stdbool.h> diff --git a/shared/systemd/src/basic/process-util.c b/shared/systemd/src/basic/process-util.c index 03ca04e175..0e25b02001 100644 --- a/shared/systemd/src/basic/process-util.c +++ b/shared/systemd/src/basic/process-util.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #include "nm-sd-adapt-shared.h" diff --git a/shared/systemd/src/basic/process-util.h b/shared/systemd/src/basic/process-util.h index 314a8de17e..aab2c7a135 100644 --- a/shared/systemd/src/basic/process-util.h +++ b/shared/systemd/src/basic/process-util.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include <errno.h> diff --git a/shared/systemd/src/basic/random-util.c b/shared/systemd/src/basic/random-util.c index 9551e762fc..4f67d9af18 100644 --- a/shared/systemd/src/basic/random-util.c +++ b/shared/systemd/src/basic/random-util.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #include "nm-sd-adapt-shared.h" @@ -462,10 +462,21 @@ 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; int r; - assert(fd >= 0); - assert(seed && size > 0); + assert(seed || size == 0); + + if (size == 0) + return 0; + + if (fd < 0) { + opened_fd = open("/dev/urandom", O_WRONLY|O_CLOEXEC|O_NOCTTY); + if (opened_fd < 0) + return -errno; + + fd = opened_fd; + } if (credit) { _cleanup_free_ struct rand_pool_info *info = NULL; @@ -491,6 +502,6 @@ int random_write_entropy(int fd, const void *seed, size_t size, bool credit) { return r; } - return 0; + return 1; } #endif /* NM_IGNORED */ diff --git a/shared/systemd/src/basic/random-util.h b/shared/systemd/src/basic/random-util.h index 7824ffaceb..f661fc093a 100644 --- a/shared/systemd/src/basic/random-util.h +++ b/shared/systemd/src/basic/random-util.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include <stdbool.h> diff --git a/shared/systemd/src/basic/ratelimit.c b/shared/systemd/src/basic/ratelimit.c new file mode 100644 index 0000000000..12c8324db0 --- /dev/null +++ b/shared/systemd/src/basic/ratelimit.c @@ -0,0 +1,40 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include "nm-sd-adapt-shared.h" + +#include <sys/time.h> + +#include "macro.h" +#include "ratelimit.h" + +/* Modelled after Linux' lib/ratelimit.c by Dave Young + * <hidave.darkstar@gmail.com>, which is licensed GPLv2. */ + +bool ratelimit_below(RateLimit *r) { + usec_t ts; + + assert(r); + + if (!ratelimit_configured(r)) + return true; + + ts = now(CLOCK_MONOTONIC); + + if (r->begin <= 0 || + ts - r->begin > r->interval) { + r->begin = ts; + + /* Reset counter */ + r->num = 0; + goto good; + } + + if (r->num < r->burst) + goto good; + + return false; + +good: + r->num++; + return true; +} diff --git a/shared/systemd/src/basic/ratelimit.h b/shared/systemd/src/basic/ratelimit.h new file mode 100644 index 0000000000..ee1d17c0e7 --- /dev/null +++ b/shared/systemd/src/basic/ratelimit.h @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +#include <stdbool.h> + +#include "time-util.h" +#include "util.h" + +typedef struct RateLimit { + usec_t interval; /* Keep those two fields first so they can be initialized easily: */ + unsigned burst; /* RateLimit rl = { INTERVAL, BURST }; */ + unsigned num; + usec_t begin; +} RateLimit; + +static inline void ratelimit_reset(RateLimit *rl) { + rl->num = rl->begin = 0; +} + +static inline bool ratelimit_configured(RateLimit *rl) { + return rl->interval > 0 && rl->burst > 0; +} + +bool ratelimit_below(RateLimit *r); diff --git a/shared/systemd/src/basic/set.h b/shared/systemd/src/basic/set.h index 7170eea84c..57ff713039 100644 --- a/shared/systemd/src/basic/set.h +++ b/shared/systemd/src/basic/set.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include "extract-word.h" @@ -128,10 +128,12 @@ int _set_ensure_consume(Set **s, const struct hash_ops *hash_ops, void *key HAS int set_consume(Set *s, void *value); -int _set_put_strdup(Set **s, const char *p HASHMAP_DEBUG_PARAMS); -#define set_put_strdup(s, p) _set_put_strdup(s, p HASHMAP_DEBUG_SRC_ARGS) -int _set_put_strdupv(Set **s, char **l HASHMAP_DEBUG_PARAMS); -#define set_put_strdupv(s, l) _set_put_strdupv(s, l HASHMAP_DEBUG_SRC_ARGS) +int _set_put_strdup_full(Set **s, const struct hash_ops *hash_ops, const char *p HASHMAP_DEBUG_PARAMS); +#define set_put_strdup_full(s, hash_ops, p) _set_put_strdup_full(s, hash_ops, p HASHMAP_DEBUG_SRC_ARGS) +#define set_put_strdup(s, p) set_put_strdup_full(s, &string_hash_ops_free, p) +int _set_put_strdupv_full(Set **s, const struct hash_ops *hash_ops, char **l HASHMAP_DEBUG_PARAMS); +#define set_put_strdupv_full(s, hash_ops, l) _set_put_strdupv_full(s, hash_ops, l HASHMAP_DEBUG_SRC_ARGS) +#define set_put_strdupv(s, l) set_put_strdupv_full(s, &string_hash_ops_free, l) int set_put_strsplit(Set *s, const char *v, const char *separators, ExtractFlags flags); @@ -148,3 +150,5 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(Set*, set_free_free); #define _cleanup_set_free_ _cleanup_(set_freep) #define _cleanup_set_free_free_ _cleanup_(set_free_freep) + +int set_strjoin(Set *s, const char *separator, bool wrap_with_separator, char **ret); diff --git a/shared/systemd/src/basic/signal-util.c b/shared/systemd/src/basic/signal-util.c index a4b8163c0f..0c6f58184c 100644 --- a/shared/systemd/src/basic/signal-util.c +++ b/shared/systemd/src/basic/signal-util.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #include "nm-sd-adapt-shared.h" @@ -52,16 +52,7 @@ static int sigaction_many_ap(const struct sigaction *sa, int sig, va_list ap) { int r = 0; /* negative signal ends the list. 0 signal is skipped. */ - - if (sig < 0) - return 0; - - if (sig > 0) { - if (sigaction(sig, sa, NULL) < 0) - r = -errno; - } - - while ((sig = va_arg(ap, int)) >= 0) { + for (; sig >= 0; sig = va_arg(ap, int)) { if (sig == 0) continue; diff --git a/shared/systemd/src/basic/signal-util.h b/shared/systemd/src/basic/signal-util.h index 3909ee341d..bdd39d429d 100644 --- a/shared/systemd/src/basic/signal-util.h +++ b/shared/systemd/src/basic/signal-util.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include <signal.h> diff --git a/shared/systemd/src/basic/siphash24.h b/shared/systemd/src/basic/siphash24.h index 474d9c9d21..37a9c6c351 100644 --- a/shared/systemd/src/basic/siphash24.h +++ b/shared/systemd/src/basic/siphash24.h @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: CC0-1.0 */ + #pragma once #include <inttypes.h> diff --git a/shared/systemd/src/basic/socket-util.c b/shared/systemd/src/basic/socket-util.c index 4d889e5655..e224091dda 100644 --- a/shared/systemd/src/basic/socket-util.c +++ b/shared/systemd/src/basic/socket-util.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #include "nm-sd-adapt-shared.h" @@ -27,10 +27,7 @@ #include "format-util.h" #include "io-util.h" #include "log.h" -#include "macro.h" #include "memory-util.h" -#include "missing_socket.h" -#include "missing_network.h" #include "parse-util.h" #include "path-util.h" #include "process-util.h" @@ -325,7 +322,7 @@ bool socket_address_matches_fd(const SocketAddress *a, int fd) { } int sockaddr_port(const struct sockaddr *_sa, unsigned *ret_port) { - union sockaddr_union *sa = (union sockaddr_union*) _sa; + const union sockaddr_union *sa = (const union sockaddr_union*) _sa; /* Note, this returns the port as 'unsigned' rather than 'uint16_t', as AF_VSOCK knows larger ports */ @@ -350,6 +347,25 @@ int sockaddr_port(const struct sockaddr *_sa, unsigned *ret_port) { } } +const union in_addr_union *sockaddr_in_addr(const struct sockaddr *_sa) { + const union sockaddr_union *sa = (const union sockaddr_union*) _sa; + + if (!sa) + return NULL; + + switch (sa->sa.sa_family) { + + case AF_INET: + return (const union in_addr_union*) &sa->in.sin_addr; + + case AF_INET6: + return (const union in_addr_union*) &sa->in6.sin6_addr; + + default: + return NULL; + } +} + int sockaddr_pretty( const struct sockaddr *_sa, socklen_t salen, @@ -1251,71 +1267,8 @@ int socket_set_recvpktinfo(int fd, int af, bool b) { case AF_NETLINK: return setsockopt_int(fd, SOL_NETLINK, NETLINK_PKTINFO, b); - default: - return -EAFNOSUPPORT; - } -} - -int socket_set_recverr(int fd, int af, bool b) { - int r; - - if (af == AF_UNSPEC) { - r = socket_get_family(fd, &af); - if (r < 0) - return r; - } - - switch (af) { - - case AF_INET: - return setsockopt_int(fd, IPPROTO_IP, IP_RECVERR, b); - - case AF_INET6: - return setsockopt_int(fd, IPPROTO_IPV6, IPV6_RECVERR, b); - - default: - return -EAFNOSUPPORT; - } -} - -int socket_set_recvttl(int fd, int af, bool b) { - int r; - - if (af == AF_UNSPEC) { - r = socket_get_family(fd, &af); - if (r < 0) - return r; - } - - switch (af) { - - case AF_INET: - return setsockopt_int(fd, IPPROTO_IP, IP_RECVTTL, b); - - case AF_INET6: - return setsockopt_int(fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, b); - - default: - return -EAFNOSUPPORT; - } -} - -int socket_set_ttl(int fd, int af, int ttl) { - int r; - - if (af == AF_UNSPEC) { - r = socket_get_family(fd, &af); - if (r < 0) - return r; - } - - switch (af) { - - case AF_INET: - return setsockopt_int(fd, IPPROTO_IP, IP_TTL, ttl); - - case AF_INET6: - return setsockopt_int(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, ttl); + case AF_PACKET: + return setsockopt_int(fd, SOL_PACKET, PACKET_AUXDATA, b); default: return -EAFNOSUPPORT; @@ -1351,7 +1304,7 @@ int socket_set_unicast_if(int fd, int af, int ifi) { } } -int socket_set_freebind(int fd, int af, bool b) { +int socket_set_option(int fd, int af, int opt_ipv4, int opt_ipv6, int val) { int r; if (af == AF_UNSPEC) { @@ -1363,18 +1316,18 @@ int socket_set_freebind(int fd, int af, bool b) { switch (af) { case AF_INET: - return setsockopt_int(fd, IPPROTO_IP, IP_FREEBIND, b); + return setsockopt_int(fd, IPPROTO_IP, opt_ipv4, val); case AF_INET6: - return setsockopt_int(fd, IPPROTO_IPV6, IPV6_FREEBIND, b); + return setsockopt_int(fd, IPPROTO_IPV6, opt_ipv6, val); default: return -EAFNOSUPPORT; } } -int socket_set_transparent(int fd, int af, bool b) { - int r; +int socket_get_mtu(int fd, int af, size_t *ret) { + int mtu, r; if (af == AF_UNSPEC) { r = socket_get_family(fd, &af); @@ -1385,13 +1338,23 @@ int socket_set_transparent(int fd, int af, bool b) { switch (af) { case AF_INET: - return setsockopt_int(fd, IPPROTO_IP, IP_TRANSPARENT, b); + r = getsockopt_int(fd, IPPROTO_IP, IP_MTU, &mtu); + break; case AF_INET6: - return setsockopt_int(fd, IPPROTO_IPV6, IPV6_TRANSPARENT, b); + r = getsockopt_int(fd, IPPROTO_IPV6, IPV6_MTU, &mtu); + break; default: return -EAFNOSUPPORT; } + + if (r < 0) + return r; + if (mtu <= 0) + return -EINVAL; + + *ret = (size_t) mtu; + return 0; } #endif /* NM_IGNORED */ diff --git a/shared/systemd/src/basic/socket-util.h b/shared/systemd/src/basic/socket-util.h index 1ece911813..1de069476a 100644 --- a/shared/systemd/src/basic/socket-util.h +++ b/shared/systemd/src/basic/socket-util.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include <inttypes.h> @@ -15,6 +15,7 @@ #include <sys/un.h> #include "macro.h" +#include "missing_network.h" #include "missing_socket.h" #include "sparse-endian.h" @@ -104,6 +105,7 @@ const char* socket_address_get_path(const SocketAddress *a); bool socket_ipv6_is_supported(void); int sockaddr_port(const struct sockaddr *_sa, unsigned *port); +const union in_addr_union *sockaddr_in_addr(const struct sockaddr *sa); int sockaddr_pretty(const struct sockaddr *_sa, socklen_t salen, bool translate_ipv6, bool include_port, char **ret); int getpeername_pretty(int fd, bool include_port, char **ret); @@ -258,6 +260,19 @@ static inline int setsockopt_int(int fd, int level, int optname, int value) { return 0; } +static inline int getsockopt_int(int fd, int level, int optname, int *ret) { + int v; + socklen_t sl = sizeof(v); + + if (getsockopt(fd, level, optname, &v, &sl) < 0) + return -errno; + if (sl != sizeof(v)) + return -EIO; + + *ret = v; + return 0; +} + int socket_bind_to_ifname(int fd, const char *ifname); int socket_bind_to_ifindex(int fd, int ifindex); @@ -265,9 +280,28 @@ ssize_t recvmsg_safe(int sockfd, struct msghdr *msg, int flags); int socket_get_family(int fd, int *ret); int socket_set_recvpktinfo(int fd, int af, bool b); -int socket_set_recverr(int fd, int af, bool b); -int socket_set_recvttl(int fd, int af, bool b); -int socket_set_ttl(int fd, int af, int ttl); int socket_set_unicast_if(int fd, int af, int ifi); -int socket_set_freebind(int fd, int af, bool b); -int socket_set_transparent(int fd, int af, bool b); + +int socket_set_option(int fd, int af, int opt_ipv4, int opt_ipv6, int val); +#if 0 /* NM_IGNORED */ +static inline int socket_set_recverr(int fd, int af, bool b) { + return socket_set_option(fd, af, IP_RECVERR, IPV6_RECVERR, b); +} +static inline int socket_set_recvttl(int fd, int af, bool b) { + return socket_set_option(fd, af, IP_RECVTTL, IPV6_RECVHOPLIMIT, b); +} +static inline int socket_set_ttl(int fd, int af, int ttl) { + return socket_set_option(fd, af, IP_TTL, IPV6_UNICAST_HOPS, ttl); +} +static inline int socket_set_freebind(int fd, int af, bool b) { + return socket_set_option(fd, af, IP_FREEBIND, IPV6_FREEBIND, b); +} +static inline int socket_set_transparent(int fd, int af, bool b) { + return socket_set_option(fd, af, IP_TRANSPARENT, IPV6_TRANSPARENT, b); +} +static inline int socket_set_recvfragsize(int fd, int af, bool b) { + return socket_set_option(fd, af, IP_RECVFRAGSIZE, IPV6_RECVFRAGSIZE, b); +} +#endif /* NM_IGNORED */ + +int socket_get_mtu(int fd, int af, size_t *ret); diff --git a/shared/systemd/src/basic/sort-util.h b/shared/systemd/src/basic/sort-util.h index d1054f6235..a8984fc164 100644 --- a/shared/systemd/src/basic/sort-util.h +++ b/shared/systemd/src/basic/sort-util.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include <stdlib.h> @@ -70,3 +70,5 @@ static inline void qsort_r_safe(void *base, size_t nmemb, size_t size, __compar_ qsort_r_safe((p), (n), sizeof((p)[0]), (__compar_d_fn_t) _func_, userdata); \ }) #endif /* NM_IGNORED */ + +int cmp_int(const int *a, const int *b); diff --git a/shared/systemd/src/basic/stat-util.c b/shared/systemd/src/basic/stat-util.c index 6d393041ac..925f82b96f 100644 --- a/shared/systemd/src/basic/stat-util.c +++ b/shared/systemd/src/basic/stat-util.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #include "nm-sd-adapt-shared.h" @@ -415,7 +415,8 @@ bool stat_inode_unmodified(const struct stat *a, const struct stat *b) { return a && b && (a->st_mode & S_IFMT) != 0 && /* We use the check for .st_mode if the structure was ever initialized */ ((a->st_mode ^ b->st_mode) & S_IFMT) == 0 && /* same inode type */ - a->st_mtime == b->st_mtime && + a->st_mtim.tv_sec == b->st_mtim.tv_sec && + a->st_mtim.tv_nsec == b->st_mtim.tv_nsec && (!S_ISREG(a->st_mode) || a->st_size == b->st_size) && /* if regular file, compare file size */ a->st_dev == b->st_dev && a->st_ino == b->st_ino && diff --git a/shared/systemd/src/basic/stat-util.h b/shared/systemd/src/basic/stat-util.h index 26ecd635f1..a566114f7c 100644 --- a/shared/systemd/src/basic/stat-util.h +++ b/shared/systemd/src/basic/stat-util.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include <fcntl.h> diff --git a/shared/systemd/src/basic/stdio-util.h b/shared/systemd/src/basic/stdio-util.h index 02d8dc52f8..d45d3c1a62 100644 --- a/shared/systemd/src/basic/stdio-util.h +++ b/shared/systemd/src/basic/stdio-util.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #if 0 /* NM_IGNORED */ diff --git a/shared/systemd/src/basic/string-table.c b/shared/systemd/src/basic/string-table.c index 46014b180c..bd8047e6b9 100644 --- a/shared/systemd/src/basic/string-table.c +++ b/shared/systemd/src/basic/string-table.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #include "nm-sd-adapt-shared.h" diff --git a/shared/systemd/src/basic/string-table.h b/shared/systemd/src/basic/string-table.h index 96924778f5..ae4ea145d3 100644 --- a/shared/systemd/src/basic/string-table.h +++ b/shared/systemd/src/basic/string-table.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once @@ -28,13 +28,12 @@ ssize_t string_table_lookup(const char * const *table, size_t len, const char *k #define _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING_WITH_BOOLEAN(name,type,yes,scope) \ scope type name##_from_string(const char *s) { \ - int b; \ if (!s) \ return -1; \ - b = parse_boolean(s); \ + int b = parse_boolean(s); \ if (b == 0) \ return (type) 0; \ - else if (b > 0) \ + if (b > 0) \ return yes; \ return (type) string_table_lookup(name##_table, ELEMENTSOF(name##_table), s); \ } @@ -79,11 +78,13 @@ ssize_t string_table_lookup(const char * const *table, size_t len, const char *k _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING_WITH_BOOLEAN(name,type,yes,scope) #define DEFINE_STRING_TABLE_LOOKUP(name,type) _DEFINE_STRING_TABLE_LOOKUP(name,type,) +#define DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type) _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,) #define DEFINE_PRIVATE_STRING_TABLE_LOOKUP(name,type) _DEFINE_STRING_TABLE_LOOKUP(name,type,static) #define DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(name,type) _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,static) #define DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(name,type) _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING(name,type,static) #define DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(name,type,yes) _DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(name,type,yes,) +#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(name,type,yes) _DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(name,type,yes,static) /* For string conversions where numbers are also acceptable */ #define DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(name,type,max) \ diff --git a/shared/systemd/src/basic/string-util.c b/shared/systemd/src/basic/string-util.c index aea13dcb9d..9e7a027c0e 100644 --- a/shared/systemd/src/basic/string-util.c +++ b/shared/systemd/src/basic/string-util.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #include "nm-sd-adapt-shared.h" @@ -147,57 +147,32 @@ char *strnappend(const char *s, const char *suffix, size_t b) { char *strjoin_real(const char *x, ...) { va_list ap; - size_t l; + size_t l = 1; char *r, *p; va_start(ap, x); + for (const char *t = x; t; t = va_arg(ap, const char *)) { + size_t n; - if (x) { - l = strlen(x); - - for (;;) { - const char *t; - size_t n; - - t = va_arg(ap, const char *); - if (!t) - break; - - n = strlen(t); - if (n > ((size_t) -1) - l) { - va_end(ap); - return NULL; - } - - l += n; + n = strlen(t); + if (n > SIZE_MAX - l) { + va_end(ap); + return NULL; } - } else - l = 0; - + l += n; + } va_end(ap); - r = new(char, l+1); + p = r = new(char, l); if (!r) return NULL; - if (x) { - p = stpcpy(r, x); - - va_start(ap, x); - - for (;;) { - const char *t; - - t = va_arg(ap, const char *); - if (!t) - break; - - p = stpcpy(p, t); - } + va_start(ap, x); + for (const char *t = x; t; t = va_arg(ap, const char *)) + p = stpcpy(p, t); + va_end(ap); - va_end(ap); - } else - r[0] = 0; + *p = 0; return r; } diff --git a/shared/systemd/src/basic/string-util.h b/shared/systemd/src/basic/string-util.h index cefbda3577..fdd3ce7363 100644 --- a/shared/systemd/src/basic/string-util.h +++ b/shared/systemd/src/basic/string-util.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include <stdbool.h> @@ -33,6 +33,12 @@ static inline bool streq_ptr(const char *a, const char *b) { return strcmp_ptr(a, b) == 0; } +static inline char* strstr_ptr(const char *haystack, const char *needle) { + if (!haystack || !needle) + return NULL; + return strstr(haystack, needle); +} + static inline const char* strempty(const char *s) { return s ?: ""; } @@ -53,6 +59,10 @@ static inline const char* true_false(bool b) { return b ? "true" : "false"; } +static inline const char* plus_minus(bool b) { + return b ? "+" : "-"; +} + static inline const char* one_zero(bool b) { return b ? "1" : "0"; } diff --git a/shared/systemd/src/basic/strv.c b/shared/systemd/src/basic/strv.c index 30d3af460a..7d3e3fc7ca 100644 --- a/shared/systemd/src/basic/strv.c +++ b/shared/systemd/src/basic/strv.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #include "nm-sd-adapt-shared.h" @@ -125,7 +125,6 @@ size_t strv_length(char * const *l) { } char **strv_new_ap(const char *x, va_list ap) { - const char *s; _cleanup_strv_free_ char **a = NULL; size_t n = 0, i = 0; va_list aq; @@ -135,43 +134,28 @@ char **strv_new_ap(const char *x, va_list ap) { * STRV_IFNOTNULL() macro to include possibly NULL strings in * the string list. */ - if (x) { - n = x == STRV_IGNORE ? 0 : 1; - - va_copy(aq, ap); - while ((s = va_arg(aq, const char*))) { - if (s == STRV_IGNORE) - continue; - - n++; - } + va_copy(aq, ap); + for (const char *s = x; s; s = va_arg(aq, const char*)) { + if (s == STRV_IGNORE) + continue; - va_end(aq); + n++; } + va_end(aq); a = new(char*, n+1); if (!a) return NULL; - if (x) { - if (x != STRV_IGNORE) { - a[i] = strdup(x); - if (!a[i]) - return NULL; - i++; - } - - while ((s = va_arg(ap, const char*))) { - - if (s == STRV_IGNORE) - continue; + for (const char *s = x; s; s = va_arg(ap, const char*)) { + if (s == STRV_IGNORE) + continue; - a[i] = strdup(s); - if (!a[i]) - return NULL; + a[i] = strdup(s); + if (!a[i]) + return NULL; - i++; - } + i++; } a[i] = NULL; @@ -543,6 +527,19 @@ int strv_consume_prepend(char ***l, char *value) { return r; } +int strv_prepend(char ***l, const char *value) { + char *v; + + if (!value) + return 0; + + v = strdup(value); + if (!v) + return -ENOMEM; + + return strv_consume_prepend(l, v); +} + int strv_extend(char ***l, const char *value) { char *v; diff --git a/shared/systemd/src/basic/strv.h b/shared/systemd/src/basic/strv.h index 919fabf75a..6b3e8e7f86 100644 --- a/shared/systemd/src/basic/strv.h +++ b/shared/systemd/src/basic/strv.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include <fnmatch.h> @@ -34,6 +34,7 @@ size_t strv_length(char * const *l) _pure_; int strv_extend_strv(char ***a, char * const *b, bool filter_duplicates); int strv_extend_strv_concat(char ***a, char * const *b, const char *suffix); +int strv_prepend(char ***l, const char *value); int strv_extend(char ***l, const char *value); int strv_extendf(char ***l, const char *format, ...) _printf_(2,0); int strv_extend_front(char ***l, const char *value); @@ -62,7 +63,7 @@ char **strv_new_internal(const char *x, ...) _sentinel_; char **strv_new_ap(const char *x, va_list ap); #define strv_new(...) strv_new_internal(__VA_ARGS__, NULL) -#define STRV_IGNORE ((const char *) -1) +#define STRV_IGNORE ((const char *) POINTER_MAX) static inline const char* STRV_IFNOTNULL(const char *x) { return x ? x : STRV_IGNORE; diff --git a/shared/systemd/src/basic/strxcpyx.c b/shared/systemd/src/basic/strxcpyx.c index 301e6899c8..39aebb8897 100644 --- a/shared/systemd/src/basic/strxcpyx.c +++ b/shared/systemd/src/basic/strxcpyx.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Concatenates/copies strings. In any case, terminates in all cases diff --git a/shared/systemd/src/basic/strxcpyx.h b/shared/systemd/src/basic/strxcpyx.h index 9b66841246..cdef492db1 100644 --- a/shared/systemd/src/basic/strxcpyx.h +++ b/shared/systemd/src/basic/strxcpyx.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include <stddef.h> diff --git a/shared/systemd/src/basic/time-util.c b/shared/systemd/src/basic/time-util.c index 0fac79a72f..e5faa33425 100644 --- a/shared/systemd/src/basic/time-util.c +++ b/shared/systemd/src/basic/time-util.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #include "nm-sd-adapt-shared.h" @@ -1613,7 +1613,7 @@ TimestampStyle timestamp_style_from_string(const char *s) { return t; if (streq_ptr(s, "µs")) return TIMESTAMP_US; - if (streq_ptr(s, "µs+uts")) + if (streq_ptr(s, "µs+utc")) return TIMESTAMP_US_UTC; return t; } diff --git a/shared/systemd/src/basic/time-util.h b/shared/systemd/src/basic/time-util.h index cecd5efa60..89ee8b4a96 100644 --- a/shared/systemd/src/basic/time-util.h +++ b/shared/systemd/src/basic/time-util.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include <inttypes.h> @@ -63,10 +63,10 @@ typedef enum TimestampStyle { /* We assume a maximum timezone length of 6. TZNAME_MAX is not defined on Linux, but glibc internally initializes this * to 6. Let's rely on that. */ -#define FORMAT_TIMESTAMP_MAX (3+1+10+1+8+1+6+1+6+1) -#define FORMAT_TIMESTAMP_WIDTH 28 /* when outputting, assume this width */ -#define FORMAT_TIMESTAMP_RELATIVE_MAX 256 -#define FORMAT_TIMESPAN_MAX 64 +#define FORMAT_TIMESTAMP_MAX (3U+1U+10U+1U+8U+1U+6U+1U+6U+1U) +#define FORMAT_TIMESTAMP_WIDTH 28U /* when outputting, assume this width */ +#define FORMAT_TIMESTAMP_RELATIVE_MAX 256U +#define FORMAT_TIMESPAN_MAX 64U #define TIME_T_MAX (time_t)((UINTMAX_C(1) << ((sizeof(time_t) << 3) - 1)) - 1) diff --git a/shared/systemd/src/basic/tmpfile-util.c b/shared/systemd/src/basic/tmpfile-util.c index 9b3621bad9..bbd6a1ede9 100644 --- a/shared/systemd/src/basic/tmpfile-util.c +++ b/shared/systemd/src/basic/tmpfile-util.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #include "nm-sd-adapt-shared.h" diff --git a/shared/systemd/src/basic/tmpfile-util.h b/shared/systemd/src/basic/tmpfile-util.h index 802c85d6d9..45255fc062 100644 --- a/shared/systemd/src/basic/tmpfile-util.h +++ b/shared/systemd/src/basic/tmpfile-util.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include <stdio.h> diff --git a/shared/systemd/src/basic/umask-util.h b/shared/systemd/src/basic/umask-util.h index cad745170e..bd7c2bdb8c 100644 --- a/shared/systemd/src/basic/umask-util.h +++ b/shared/systemd/src/basic/umask-util.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include <stdbool.h> diff --git a/shared/systemd/src/basic/user-util.h b/shared/systemd/src/basic/user-util.h index 13e2c99e6c..20ff415e2e 100644 --- a/shared/systemd/src/basic/user-util.h +++ b/shared/systemd/src/basic/user-util.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include <grp.h> diff --git a/shared/systemd/src/basic/utf8.c b/shared/systemd/src/basic/utf8.c index 8159b18755..a7679bfa26 100644 --- a/shared/systemd/src/basic/utf8.c +++ b/shared/systemd/src/basic/utf8.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* Parts of this file are based on the GLIB utf8 validation functions. The * original license text follows. */ diff --git a/shared/systemd/src/basic/utf8.h b/shared/systemd/src/basic/utf8.h index f315ea0f1e..a6ea942c62 100644 --- a/shared/systemd/src/basic/utf8.h +++ b/shared/systemd/src/basic/utf8.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include <stdbool.h> diff --git a/shared/systemd/src/basic/util.c b/shared/systemd/src/basic/util.c index 8a3f95dc1e..10a5bcff98 100644 --- a/shared/systemd/src/basic/util.c +++ b/shared/systemd/src/basic/util.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #include "nm-sd-adapt-shared.h" @@ -168,7 +168,7 @@ int container_get_leader(const char *machine, pid_t *pid) { return 0; } - if (!machine_name_is_valid(machine)) + if (!hostname_is_valid(machine, 0)) return -EINVAL; p = strjoina("/run/systemd/machines/", machine); @@ -196,8 +196,8 @@ int container_get_leader(const char *machine, pid_t *pid) { } int version(void) { - puts("systemd " STRINGIFY(PROJECT_VERSION) " (" GIT_VERSION ")\n" - SYSTEMD_FEATURES); + printf("systemd " STRINGIFY(PROJECT_VERSION) " (" GIT_VERSION ")\n%s\n", + systemd_features); return 0; } diff --git a/shared/systemd/src/basic/util.h b/shared/systemd/src/basic/util.h index 6fc7480fcb..942d773ff1 100644 --- a/shared/systemd/src/basic/util.h +++ b/shared/systemd/src/basic/util.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include <stdint.h> diff --git a/shared/systemd/src/shared/dns-domain.c b/shared/systemd/src/shared/dns-domain.c index 6d60eb589d..dff7e83a19 100644 --- a/shared/systemd/src/shared/dns-domain.c +++ b/shared/systemd/src/shared/dns-domain.c @@ -1,16 +1,7 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #include "nm-sd-adapt-shared.h" -#if 0 /* NM_IGNORED */ -#if HAVE_LIBIDN2 -# include <idn2.h> -#elif HAVE_LIBIDN -# include <idna.h> -# include <stringprep.h> -#endif -#endif - #include <endian.h> #include <netinet/in.h> #include <stdio.h> @@ -21,6 +12,7 @@ #include "hashmap.h" #include "hexdecoct.h" #include "hostname-util.h" +#include "idn-util.h" #include "in-addr-util.h" #include "macro.h" #include "parse-util.h" @@ -319,12 +311,17 @@ int dns_label_apply_idna(const char *encoded, size_t encoded_size, char *decoded const char *p; bool contains_8bit = false; char buffer[DNS_LABEL_MAX+1]; + int r; assert(encoded); assert(decoded); /* Converts an U-label into an A-label */ + r = dlopen_idn(); + if (r < 0) + return r; + if (encoded_size <= 0) return -EINVAL; @@ -339,11 +336,11 @@ int dns_label_apply_idna(const char *encoded, size_t encoded_size, char *decoded return 0; } - input = stringprep_utf8_to_ucs4(encoded, encoded_size, &input_size); + input = sym_stringprep_utf8_to_ucs4(encoded, encoded_size, &input_size); if (!input) return -ENOMEM; - if (idna_to_ascii_4i(input, input_size, buffer, 0) != 0) + if (sym_idna_to_ascii_4i(input, input_size, buffer, 0) != 0) return -EINVAL; l = strlen(buffer); @@ -369,28 +366,33 @@ int dns_label_undo_idna(const char *encoded, size_t encoded_size, char *decoded, _cleanup_free_ char *result = NULL; uint32_t *output = NULL; size_t w; + int r; /* To be invoked after unescaping. Converts an A-label into an U-label. */ assert(encoded); assert(decoded); + r = dlopen_idn(); + if (r < 0) + return r; + if (encoded_size <= 0 || encoded_size > DNS_LABEL_MAX) return -EINVAL; if (!memory_startswith(encoded, encoded_size, IDNA_ACE_PREFIX)) return 0; - input = stringprep_utf8_to_ucs4(encoded, encoded_size, &input_size); + input = sym_stringprep_utf8_to_ucs4(encoded, encoded_size, &input_size); if (!input) return -ENOMEM; output_size = input_size; output = newa(uint32_t, output_size); - idna_to_unicode_44i(input, input_size, output, &output_size, 0); + sym_idna_to_unicode_44i(input, input_size, output, &output_size, 0); - result = stringprep_ucs4_to_utf8(output, output_size, NULL, &w); + result = sym_stringprep_ucs4_to_utf8(output, output_size, NULL, &w); if (!result) return -ENOMEM; if (w <= 0) @@ -748,12 +750,12 @@ int dns_name_reverse(int family, const union in_addr_union *a, char **ret) { return 0; } -int dns_name_address(const char *p, int *family, union in_addr_union *address) { +int dns_name_address(const char *p, int *ret_family, union in_addr_union *ret_address) { int r; assert(p); - assert(family); - assert(address); + assert(ret_family); + assert(ret_address); r = dns_name_endswith(p, "in-addr.arpa"); if (r < 0) @@ -782,11 +784,11 @@ int dns_name_address(const char *p, int *family, union in_addr_union *address) { if (r <= 0) return r; - *family = AF_INET; - address->in.s_addr = htobe32(((uint32_t) a[3] << 24) | - ((uint32_t) a[2] << 16) | - ((uint32_t) a[1] << 8) | - (uint32_t) a[0]); + *ret_family = AF_INET; + ret_address->in.s_addr = htobe32(((uint32_t) a[3] << 24) | + ((uint32_t) a[2] << 16) | + ((uint32_t) a[1] << 8) | + (uint32_t) a[0]); return 1; } @@ -827,11 +829,14 @@ int dns_name_address(const char *p, int *family, union in_addr_union *address) { if (r <= 0) return r; - *family = AF_INET6; - address->in6 = a; + *ret_family = AF_INET6; + ret_address->in6 = a; return 1; } + *ret_family = AF_UNSPEC; + *ret_address = IN_ADDR_NULL; + return 0; } #endif /* NM_IGNORED */ @@ -1277,47 +1282,67 @@ int dns_name_common_suffix(const char *a, const char *b, const char **ret) { } int dns_name_apply_idna(const char *name, char **ret) { + /* Return negative on error, 0 if not implemented, positive on success. */ -#if HAVE_LIBIDN2 +#if HAVE_LIBIDN2 || HAVE_LIBIDN2 int r; + + r = dlopen_idn(); + if (r == EOPNOTSUPP) { + *ret = NULL; + return 0; + } + if (r < 0) + return r; +#endif + +#if HAVE_LIBIDN2 _cleanup_free_ char *t = NULL; assert(name); assert(ret); - r = idn2_lookup_u8((uint8_t*) name, (uint8_t**) &t, - IDN2_NFC_INPUT | IDN2_NONTRANSITIONAL); + /* First, try non-transitional mode (i.e. IDN2008 rules) */ + r = sym_idn2_lookup_u8((uint8_t*) name, (uint8_t**) &t, + IDN2_NFC_INPUT | IDN2_NONTRANSITIONAL); + if (r == IDN2_DISALLOWED) /* If that failed, because of disallowed characters, try transitional mode. + * (i.e. IDN2003 rules which supports some unicode chars IDN2008 doesn't allow). */ + r = sym_idn2_lookup_u8((uint8_t*) name, (uint8_t**) &t, + IDN2_NFC_INPUT | IDN2_TRANSITIONAL); + log_debug("idn2_lookup_u8: %s → %s", name, t); if (r == IDN2_OK) { if (!startswith(name, "xn--")) { _cleanup_free_ char *s = NULL; - r = idn2_to_unicode_8z8z(t, &s, 0); + r = sym_idn2_to_unicode_8z8z(t, &s, 0); if (r != IDN2_OK) { log_debug("idn2_to_unicode_8z8z(\"%s\") failed: %d/%s", - t, r, idn2_strerror(r)); + t, r, sym_idn2_strerror(r)); + *ret = NULL; return 0; } if (!streq_ptr(name, s)) { log_debug("idn2 roundtrip failed: \"%s\" → \"%s\" → \"%s\", ignoring.", name, t, s); + *ret = NULL; return 0; } } *ret = TAKE_PTR(t); - return 1; /* *ret has been written */ } - log_debug("idn2_lookup_u8(\"%s\") failed: %d/%s", name, r, idn2_strerror(r)); + log_debug("idn2_lookup_u8(\"%s\") failed: %d/%s", name, r, sym_idn2_strerror(r)); if (r == IDN2_2HYPHEN) /* The name has two hyphens — forbidden by IDNA2008 in some cases */ return 0; if (IN_SET(r, IDN2_TOO_BIG_DOMAIN, IDN2_TOO_BIG_LABEL)) return -ENOSPC; + return -EINVAL; #elif HAVE_LIBIDN _cleanup_free_ char *buf = NULL; @@ -1369,6 +1394,7 @@ int dns_name_apply_idna(const char *name, char **ret) { return 1; #else + *ret = NULL; return 0; #endif } diff --git a/shared/systemd/src/shared/dns-domain.h b/shared/systemd/src/shared/dns-domain.h index e4e5b1b994..984f4840b6 100644 --- a/shared/systemd/src/shared/dns-domain.h +++ b/shared/systemd/src/shared/dns-domain.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include <errno.h> diff --git a/shared/systemd/src/shared/log-link.h b/shared/systemd/src/shared/log-link.h new file mode 100644 index 0000000000..3a4dcaa267 --- /dev/null +++ b/shared/systemd/src/shared/log-link.h @@ -0,0 +1,45 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +#include "log.h" + +#define log_interface_full_errno(ifname, level, error, ...) \ + ({ \ + const char *_ifname = (ifname); \ + _ifname ? log_object_internal(level, error, PROJECT_FILE, __LINE__, __func__, "INTERFACE=", _ifname, NULL, NULL, ##__VA_ARGS__) : \ + log_internal(level, error, PROJECT_FILE, __LINE__, __func__, ##__VA_ARGS__); \ + }) + +/* + * The following macros append INTERFACE= to the message. + * The macros require a struct named 'Link' which contains 'char *ifname': + * + * typedef struct Link { + * char *ifname; + * } Link; + * + * See, network/networkd-link.h for example. + */ + +#define log_link_full_errno(link, level, error, ...) \ + ({ \ + const Link *_l = (link); \ + log_interface_full_errno(_l ? _l->ifname : NULL, level, error, ##__VA_ARGS__); \ + }) + +#define log_link_full(link, level, ...) (void) log_link_full_errno(link, level, 0, __VA_ARGS__) + +#define log_link_debug(link, ...) log_link_full_errno(link, LOG_DEBUG, 0, __VA_ARGS__) +#define log_link_info(link, ...) log_link_full(link, LOG_INFO, __VA_ARGS__) +#define log_link_notice(link, ...) log_link_full(link, LOG_NOTICE, __VA_ARGS__) +#define log_link_warning(link, ...) log_link_full(link, LOG_WARNING, __VA_ARGS__) +#define log_link_error(link, ...) log_link_full(link, LOG_ERR, __VA_ARGS__) + +#define log_link_debug_errno(link, error, ...) log_link_full_errno(link, LOG_DEBUG, error, __VA_ARGS__) +#define log_link_info_errno(link, error, ...) log_link_full_errno(link, LOG_INFO, error, __VA_ARGS__) +#define log_link_notice_errno(link, error, ...) log_link_full_errno(link, LOG_NOTICE, error, __VA_ARGS__) +#define log_link_warning_errno(link, error, ...) log_link_full_errno(link, LOG_WARNING, error, __VA_ARGS__) +#define log_link_error_errno(link, error, ...) log_link_full_errno(link, LOG_ERR, error, __VA_ARGS__) + +#define LOG_LINK_MESSAGE(link, fmt, ...) "MESSAGE=%s: " fmt, (link)->ifname, ##__VA_ARGS__ +#define LOG_LINK_INTERFACE(link) "INTERFACE=%s", (link)->ifname diff --git a/shared/systemd/src/shared/web-util.c b/shared/systemd/src/shared/web-util.c index 4cff5e271d..35ba1a2e83 100644 --- a/shared/systemd/src/shared/web-util.c +++ b/shared/systemd/src/shared/web-util.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #include "nm-sd-adapt-shared.h" diff --git a/shared/systemd/src/shared/web-util.h b/shared/systemd/src/shared/web-util.h index c9e67e5c0a..ec54669f50 100644 --- a/shared/systemd/src/shared/web-util.h +++ b/shared/systemd/src/shared/web-util.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include <stdbool.h> diff --git a/src/dhcp/nm-dhcp-systemd.c b/src/dhcp/nm-dhcp-systemd.c index f929722377..3d46c2490e 100644 --- a/src/dhcp/nm-dhcp-systemd.c +++ b/src/dhcp/nm-dhcp-systemd.c @@ -568,6 +568,8 @@ dhcp_event_cb(sd_dhcp_client *client, int event, gpointer user_data) return -ENOMSG; } break; + case SD_DHCP_CLIENT_EVENT_TRANSIENT_FAILURE: + break; default: _LOGW("unhandled DHCP event %d", event); break; @@ -599,6 +601,9 @@ ip4_start(NMDhcpClient *client, const char * hostname; const char * mud_url; int r, i; + GBytes * bcast_hwaddr; + const uint8_t * bcast_hwaddr_arr; + gsize bcast_hwaddr_len; g_return_val_if_fail(!priv->client4, FALSE); g_return_val_if_fail(!priv->client6, FALSE); @@ -623,7 +628,19 @@ ip4_start(NMDhcpClient *client, nm_utils_error_set_literal(error, NM_UTILS_ERROR_UNKNOWN, "invalid MAC address"); return FALSE; } - r = sd_dhcp_client_set_mac(sd_client, hwaddr_arr, hwaddr_len, (guint16) arp_type); + + bcast_hwaddr_arr = NULL; + if ((bcast_hwaddr = nm_dhcp_client_get_broadcast_hw_addr(NM_DHCP_CLIENT(self)))) { + bcast_hwaddr_arr = g_bytes_get_data(bcast_hwaddr, &bcast_hwaddr_len); + if (bcast_hwaddr_len != hwaddr_len) + bcast_hwaddr_arr = NULL; + } + + r = sd_dhcp_client_set_mac(sd_client, + hwaddr_arr, + bcast_hwaddr_arr, + hwaddr_len, + (guint16) arp_type); if (r < 0) { nm_utils_error_set_errno(error, r, "failed to set MAC address: %s"); return FALSE; diff --git a/src/systemd/sd-adapt-core/network-util.h b/src/systemd/sd-adapt-core/network-util.h new file mode 100644 index 0000000000..637892c2d6 --- /dev/null +++ b/src/systemd/sd-adapt-core/network-util.h @@ -0,0 +1,3 @@ +#pragma once + +/* dummy header */ diff --git a/src/systemd/src/libsystemd-network/arp-util.c b/src/systemd/src/libsystemd-network/arp-util.c index b2ac2c9c48..1c777d8a7a 100644 --- a/src/systemd/src/libsystemd-network/arp-util.c +++ b/src/systemd/src/libsystemd-network/arp-util.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /*** Copyright © 2014 Axis Communications AB. All rights reserved. ***/ diff --git a/src/systemd/src/libsystemd-network/arp-util.h b/src/systemd/src/libsystemd-network/arp-util.h index 9a4427e831..2dac8cfbaa 100644 --- a/src/systemd/src/libsystemd-network/arp-util.h +++ b/src/systemd/src/libsystemd-network/arp-util.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once /*** diff --git a/src/systemd/src/libsystemd-network/dhcp-identifier.c b/src/systemd/src/libsystemd-network/dhcp-identifier.c index 026015a717..0720e38185 100644 --- a/src/systemd/src/libsystemd-network/dhcp-identifier.c +++ b/src/systemd/src/libsystemd-network/dhcp-identifier.c @@ -1,8 +1,9 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #include "nm-sd-adapt-core.h" #include <linux/if_infiniband.h> +#include <net/ethernet.h> #include <net/if_arp.h> #include "sd-device.h" @@ -10,7 +11,7 @@ #include "dhcp-identifier.h" #include "dhcp6-protocol.h" -#include "network-internal.h" +#include "network-util.h" #include "siphash24.h" #include "sparse-endian.h" #include "stdio-util.h" @@ -28,11 +29,10 @@ int dhcp_validate_duid_len(uint16_t duid_type, size_t duid_len, bool strict) { if (duid_len > MAX_DUID_LEN) return -EINVAL; - if (!strict) { + if (!strict) /* Strict validation is not requested. We only ensure that the * DUID is not too long. */ return 0; - } switch (duid_type) { case DUID_TYPE_LLT: diff --git a/src/systemd/src/libsystemd-network/dhcp-identifier.h b/src/systemd/src/libsystemd-network/dhcp-identifier.h index 76abd6583e..e9f2ea7e95 100644 --- a/src/systemd/src/libsystemd-network/dhcp-identifier.h +++ b/src/systemd/src/libsystemd-network/dhcp-identifier.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include "sd-id128.h" diff --git a/src/systemd/src/libsystemd-network/dhcp-internal.h b/src/systemd/src/libsystemd-network/dhcp-internal.h index 7e8149487a..40e6b1f26f 100644 --- a/src/systemd/src/libsystemd-network/dhcp-internal.h +++ b/src/systemd/src/libsystemd-network/dhcp-internal.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once /*** @@ -29,10 +29,10 @@ typedef struct DHCPServerData { extern const struct hash_ops dhcp_option_hash_ops; -int dhcp_network_bind_raw_socket(int ifindex, union sockaddr_union *link, - uint32_t xid, const uint8_t *mac_addr, - size_t mac_addr_len, uint16_t arp_type, - uint16_t port); +int dhcp_network_bind_raw_socket(int ifindex, union sockaddr_union *link, uint32_t xid, + const uint8_t *mac_addr, size_t mac_addr_len, + const uint8_t *bcast_addr, size_t bcast_addr_len, + uint16_t arp_type, uint16_t port); int dhcp_network_bind_udp_socket(int ifindex, be32_t address, uint16_t port, int ip_service_type); int dhcp_network_send_raw_socket(int s, const union sockaddr_union *link, const void *packet, size_t len); diff --git a/src/systemd/src/libsystemd-network/dhcp-lease-internal.h b/src/systemd/src/libsystemd-network/dhcp-lease-internal.h index 66222eaddb..49392d1bea 100644 --- a/src/systemd/src/libsystemd-network/dhcp-lease-internal.h +++ b/src/systemd/src/libsystemd-network/dhcp-lease-internal.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once /*** diff --git a/src/systemd/src/libsystemd-network/dhcp-network.c b/src/systemd/src/libsystemd-network/dhcp-network.c index 1f01ece14c..4477f46f2c 100644 --- a/src/systemd/src/libsystemd-network/dhcp-network.c +++ b/src/systemd/src/libsystemd-network/dhcp-network.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /*** Copyright © 2013 Intel Corporation. All rights reserved. ***/ @@ -21,9 +21,9 @@ #include "unaligned.h" static int _bind_raw_socket(int ifindex, union sockaddr_union *link, - uint32_t xid, const uint8_t *mac_addr, - size_t mac_addr_len, + uint32_t xid, const uint8_t *bcast_addr, + size_t bcast_addr_len, const struct ether_addr *eth_mac, uint16_t arp_type, uint8_t dhcp_hlen, uint16_t port) { @@ -106,9 +106,9 @@ static int _bind_raw_socket(int ifindex, union sockaddr_union *link, .sll_protocol = htobe16(ETH_P_IP), .sll_ifindex = ifindex, .sll_hatype = htobe16(arp_type), - .sll_halen = mac_addr_len, + .sll_halen = bcast_addr_len, }; - memcpy(link->ll.sll_addr, bcast_addr, mac_addr_len); + memcpy(link->ll.sll_addr, bcast_addr, bcast_addr_len); /* We may overflow link->ll. link->ll_buffer ensures we have enough space. */ r = bind(s, &link->sa, SOCKADDR_LL_LEN(link->ll)); if (r < 0) @@ -117,34 +117,44 @@ static int _bind_raw_socket(int ifindex, union sockaddr_union *link, return TAKE_FD(s); } -int dhcp_network_bind_raw_socket(int ifindex, union sockaddr_union *link, - uint32_t xid, const uint8_t *mac_addr, - size_t mac_addr_len, uint16_t arp_type, - uint16_t port) { +int dhcp_network_bind_raw_socket(int ifindex, union sockaddr_union *link, uint32_t xid, + const uint8_t *mac_addr, size_t mac_addr_len, + const uint8_t *bcast_addr, size_t bcast_addr_len, + uint16_t arp_type, uint16_t port) { static const uint8_t eth_bcast[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; /* Default broadcast address for IPoIB */ static const uint8_t ib_bcast[] = { 0x00, 0xff, 0xff, 0xff, 0xff, 0x12, 0x40, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff - }; + }; struct ether_addr eth_mac = { { 0, 0, 0, 0, 0, 0 } }; - const uint8_t *bcast_addr = NULL; + const uint8_t *default_bcast_addr; + size_t expected_bcast_addr_len; uint8_t dhcp_hlen = 0; if (arp_type == ARPHRD_ETHER) { assert_return(mac_addr_len == ETH_ALEN, -EINVAL); memcpy(ð_mac, mac_addr, ETH_ALEN); - bcast_addr = eth_bcast; dhcp_hlen = ETH_ALEN; + + default_bcast_addr = eth_bcast; + expected_bcast_addr_len = ETH_ALEN; } else if (arp_type == ARPHRD_INFINIBAND) { - assert_return(mac_addr_len == INFINIBAND_ALEN, -EINVAL); - bcast_addr = ib_bcast; + default_bcast_addr = ib_bcast; + expected_bcast_addr_len = INFINIBAND_ALEN; } else return -EINVAL; - return _bind_raw_socket(ifindex, link, xid, mac_addr, mac_addr_len, - bcast_addr, ð_mac, arp_type, dhcp_hlen, port); + if (bcast_addr && bcast_addr_len > 0) + assert_return(bcast_addr_len == expected_bcast_addr_len, -EINVAL); + else { + bcast_addr = default_bcast_addr; + bcast_addr_len = expected_bcast_addr_len; + } + + return _bind_raw_socket(ifindex, link, xid, bcast_addr, bcast_addr_len, + ð_mac, arp_type, dhcp_hlen, port); } int dhcp_network_bind_udp_socket(int ifindex, be32_t address, uint16_t port, int ip_service_type) { diff --git a/src/systemd/src/libsystemd-network/dhcp-option.c b/src/systemd/src/libsystemd-network/dhcp-option.c index 3a0f515574..2c15d85a97 100644 --- a/src/systemd/src/libsystemd-network/dhcp-option.c +++ b/src/systemd/src/libsystemd-network/dhcp-option.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /*** Copyright © 2013 Intel Corporation. All rights reserved. ***/ diff --git a/src/systemd/src/libsystemd-network/dhcp-packet.c b/src/systemd/src/libsystemd-network/dhcp-packet.c index 2062be91c8..eeadd5628b 100644 --- a/src/systemd/src/libsystemd-network/dhcp-packet.c +++ b/src/systemd/src/libsystemd-network/dhcp-packet.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /*** Copyright © 2013 Intel Corporation. All rights reserved. ***/ diff --git a/src/systemd/src/libsystemd-network/dhcp-protocol.h b/src/systemd/src/libsystemd-network/dhcp-protocol.h index f03663248a..11f4201ab2 100644 --- a/src/systemd/src/libsystemd-network/dhcp-protocol.h +++ b/src/systemd/src/libsystemd-network/dhcp-protocol.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once /*** diff --git a/src/systemd/src/libsystemd-network/dhcp6-internal.h b/src/systemd/src/libsystemd-network/dhcp6-internal.h index 9ce6dcd02c..24d8a314a4 100644 --- a/src/systemd/src/libsystemd-network/dhcp6-internal.h +++ b/src/systemd/src/libsystemd-network/dhcp6-internal.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once /*** diff --git a/src/systemd/src/libsystemd-network/dhcp6-lease-internal.h b/src/systemd/src/libsystemd-network/dhcp6-lease-internal.h index df6c95e0b3..e9e2362d6f 100644 --- a/src/systemd/src/libsystemd-network/dhcp6-lease-internal.h +++ b/src/systemd/src/libsystemd-network/dhcp6-lease-internal.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once /*** diff --git a/src/systemd/src/libsystemd-network/dhcp6-network.c b/src/systemd/src/libsystemd-network/dhcp6-network.c index 449ff6c4b0..b6816de404 100644 --- a/src/systemd/src/libsystemd-network/dhcp6-network.c +++ b/src/systemd/src/libsystemd-network/dhcp6-network.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /*** Copyright © 2014 Intel Corporation. All rights reserved. ***/ diff --git a/src/systemd/src/libsystemd-network/dhcp6-option.c b/src/systemd/src/libsystemd-network/dhcp6-option.c index 25da477d2c..21e2d3f02f 100644 --- a/src/systemd/src/libsystemd-network/dhcp6-option.c +++ b/src/systemd/src/libsystemd-network/dhcp6-option.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /*** Copyright © 2014-2015 Intel Corporation. All rights reserved. ***/ diff --git a/src/systemd/src/libsystemd-network/dhcp6-protocol.h b/src/systemd/src/libsystemd-network/dhcp6-protocol.h index f7a2702860..c700363803 100644 --- a/src/systemd/src/libsystemd-network/dhcp6-protocol.h +++ b/src/systemd/src/libsystemd-network/dhcp6-protocol.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once /*** diff --git a/src/systemd/src/libsystemd-network/lldp-internal.h b/src/systemd/src/libsystemd-network/lldp-internal.h index 9598438dba..f23695f974 100644 --- a/src/systemd/src/libsystemd-network/lldp-internal.h +++ b/src/systemd/src/libsystemd-network/lldp-internal.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include "sd-event.h" diff --git a/src/systemd/src/libsystemd-network/lldp-neighbor.c b/src/systemd/src/libsystemd-network/lldp-neighbor.c index 9baa8e8ca9..58ff0e0fbc 100644 --- a/src/systemd/src/libsystemd-network/lldp-neighbor.c +++ b/src/systemd/src/libsystemd-network/lldp-neighbor.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #include "nm-sd-adapt-core.h" diff --git a/src/systemd/src/libsystemd-network/lldp-neighbor.h b/src/systemd/src/libsystemd-network/lldp-neighbor.h index 74175edf54..a5718c8c31 100644 --- a/src/systemd/src/libsystemd-network/lldp-neighbor.h +++ b/src/systemd/src/libsystemd-network/lldp-neighbor.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include <inttypes.h> diff --git a/src/systemd/src/libsystemd-network/lldp-network.c b/src/systemd/src/libsystemd-network/lldp-network.c index 85d53e710d..75dce58c30 100644 --- a/src/systemd/src/libsystemd-network/lldp-network.c +++ b/src/systemd/src/libsystemd-network/lldp-network.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #include "nm-sd-adapt-core.h" diff --git a/src/systemd/src/libsystemd-network/lldp-network.h b/src/systemd/src/libsystemd-network/lldp-network.h index e4ed2898a5..bc69b324c2 100644 --- a/src/systemd/src/libsystemd-network/lldp-network.h +++ b/src/systemd/src/libsystemd-network/lldp-network.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include "sd-event.h" diff --git a/src/systemd/src/libsystemd-network/network-internal.c b/src/systemd/src/libsystemd-network/network-internal.c index 7a53565d40..3b1fea0bcf 100644 --- a/src/systemd/src/libsystemd-network/network-internal.c +++ b/src/systemd/src/libsystemd-network/network-internal.c @@ -1,664 +1,19 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #include "nm-sd-adapt-core.h" #include <arpa/inet.h> #include <linux/if.h> -#include "sd-id128.h" #include "sd-ndisc.h" #include "alloc-util.h" -#include "arphrd-list.h" -#include "condition.h" -#include "conf-parser.h" -#include "device-util.h" #include "dhcp-lease-internal.h" -#include "env-util.h" -#include "ether-addr-util.h" +#include "extract-word.h" #include "hexdecoct.h" #include "log.h" #include "network-internal.h" #include "parse-util.h" -#include "siphash24.h" -#include "socket-util.h" -#include "string-table.h" -#include "string-util.h" -#include "strv.h" -#include "utf8.h" -#include "util.h" - -#if 0 /* NM_IGNORED */ -const char *net_get_name_persistent(sd_device *device) { - const char *name, *field; - - assert(device); - - /* fetch some persistent data unique (on this machine) to this device */ - FOREACH_STRING(field, "ID_NET_NAME_ONBOARD", "ID_NET_NAME_SLOT", "ID_NET_NAME_PATH", "ID_NET_NAME_MAC") - if (sd_device_get_property_value(device, field, &name) >= 0) - return name; - - return NULL; -} - -#define HASH_KEY SD_ID128_MAKE(d3,1e,48,fa,90,fe,4b,4c,9d,af,d5,d7,a1,b1,2e,8a) - -int net_get_unique_predictable_data(sd_device *device, bool use_sysname, uint64_t *result) { - size_t l, sz = 0; - const char *name; - int r; - uint8_t *v; - - assert(device); - - /* net_get_name_persistent() will return one of the device names based on stable information about - * the device. If this is not available, we fall back to using the actual device name. */ - name = net_get_name_persistent(device); - if (!name && use_sysname) - (void) sd_device_get_sysname(device, &name); - if (!name) - return log_device_debug_errno(device, SYNTHETIC_ERRNO(ENODATA), - "No stable identifying information found"); - - log_device_debug(device, "Using \"%s\" as stable identifying information", name); - l = strlen(name); - sz = sizeof(sd_id128_t) + l; - v = newa(uint8_t, sz); - - /* Fetch some persistent data unique to this machine */ - r = sd_id128_get_machine((sd_id128_t*) v); - if (r < 0) - return r; - memcpy(v + sizeof(sd_id128_t), name, l); - - /* Let's hash the machine ID plus the device name. We use - * a fixed, but originally randomly created hash key here. */ - *result = htole64(siphash24(v, sz, HASH_KEY.bytes)); - return 0; -} - -static bool net_condition_test_strv(char * const *patterns, const char *string) { - char * const *p; - bool match = false, has_positive_rule = false; - - if (strv_isempty(patterns)) - return true; - - STRV_FOREACH(p, patterns) { - const char *q = *p; - bool invert; - - invert = *q == '!'; - q += invert; - - if (!invert) - has_positive_rule = true; - - if (string && fnmatch(q, string, 0) == 0) { - if (invert) - return false; - else - match = true; - } - } - - return has_positive_rule ? match : true; -} - -static bool net_condition_test_ifname(char * const *patterns, const char *ifname, char * const *alternative_names) { - if (net_condition_test_strv(patterns, ifname)) - return true; - - char * const *p; - STRV_FOREACH(p, alternative_names) - if (net_condition_test_strv(patterns, *p)) - return true; - - return false; -} - -static int net_condition_test_property(char * const *match_property, sd_device *device) { - char * const *p; - - if (strv_isempty(match_property)) - return true; - - STRV_FOREACH(p, match_property) { - _cleanup_free_ char *key = NULL; - const char *val, *dev_val; - bool invert, v; - - invert = **p == '!'; - - val = strchr(*p + invert, '='); - if (!val) - return -EINVAL; - - key = strndup(*p + invert, val - *p - invert); - if (!key) - return -ENOMEM; - - val++; - - v = device && - sd_device_get_property_value(device, key, &dev_val) >= 0 && - fnmatch(val, dev_val, 0) == 0; - - if (invert ? v : !v) - return false; - } - - return true; -} - -static const char *const wifi_iftype_table[NL80211_IFTYPE_MAX+1] = { - [NL80211_IFTYPE_ADHOC] = "ad-hoc", - [NL80211_IFTYPE_STATION] = "station", - [NL80211_IFTYPE_AP] = "ap", - [NL80211_IFTYPE_AP_VLAN] = "ap-vlan", - [NL80211_IFTYPE_WDS] = "wds", - [NL80211_IFTYPE_MONITOR] = "monitor", - [NL80211_IFTYPE_MESH_POINT] = "mesh-point", - [NL80211_IFTYPE_P2P_CLIENT] = "p2p-client", - [NL80211_IFTYPE_P2P_GO] = "p2p-go", - [NL80211_IFTYPE_P2P_DEVICE] = "p2p-device", - [NL80211_IFTYPE_OCB] = "ocb", - [NL80211_IFTYPE_NAN] = "nan", -}; - -DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(wifi_iftype, enum nl80211_iftype); - -char *link_get_type_string(unsigned short iftype, sd_device *device) { - const char *t, *devtype; - char *p; - - if (device && - sd_device_get_devtype(device, &devtype) >= 0 && - !isempty(devtype)) - return strdup(devtype); - - t = arphrd_to_name(iftype); - if (!t) - return NULL; - - p = strdup(t); - if (!p) - return NULL; - - ascii_strlower(p); - return p; -} - -bool net_match_config(Set *match_mac, - Set *match_permanent_mac, - char * const *match_paths, - char * const *match_drivers, - char * const *match_iftypes, - char * const *match_names, - char * const *match_property, - char * const *match_wifi_iftype, - char * const *match_ssid, - Set *match_bssid, - sd_device *device, - const struct ether_addr *dev_mac, - const struct ether_addr *dev_permanent_mac, - const char *dev_driver, - unsigned short dev_iftype, - const char *dev_name, - char * const *alternative_names, - enum nl80211_iftype dev_wifi_iftype, - const char *dev_ssid, - const struct ether_addr *dev_bssid) { - - _cleanup_free_ char *dev_iftype_str; - const char *dev_path = NULL; - - dev_iftype_str = link_get_type_string(dev_iftype, device); - - if (device) { - const char *mac_str; - - (void) sd_device_get_property_value(device, "ID_PATH", &dev_path); - if (!dev_driver) - (void) sd_device_get_property_value(device, "ID_NET_DRIVER", &dev_driver); - if (!dev_name) - (void) sd_device_get_sysname(device, &dev_name); - if (!dev_mac && - sd_device_get_sysattr_value(device, "address", &mac_str) >= 0) - dev_mac = ether_aton(mac_str); - } - - if (match_mac && (!dev_mac || !set_contains(match_mac, dev_mac))) - return false; - - if (match_permanent_mac && - (!dev_permanent_mac || - ether_addr_is_null(dev_permanent_mac) || - !set_contains(match_permanent_mac, dev_permanent_mac))) - return false; - - if (!net_condition_test_strv(match_paths, dev_path)) - return false; - - if (!net_condition_test_strv(match_drivers, dev_driver)) - return false; - - if (!net_condition_test_strv(match_iftypes, dev_iftype_str)) - return false; - - if (!net_condition_test_ifname(match_names, dev_name, alternative_names)) - return false; - - if (!net_condition_test_property(match_property, device)) - return false; - - if (!net_condition_test_strv(match_wifi_iftype, wifi_iftype_to_string(dev_wifi_iftype))) - return false; - - if (!net_condition_test_strv(match_ssid, dev_ssid)) - return false; - - if (match_bssid && (!dev_bssid || !set_contains(match_bssid, dev_bssid))) - return false; - - return true; -} - -int config_parse_net_condition(const char *unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - ConditionType cond = ltype; - Condition **list = data, *c; - bool negate; - - 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++; - - c = condition_new(cond, rvalue, false, negate); - if (!c) - return log_oom(); - - /* Drop previous assignment. */ - *list = condition_free_list_type(*list, cond); - - LIST_PREPEND(conditions, *list, c); - return 0; -} - -int config_parse_match_strv( - const char *unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - const char *p = rvalue; - char ***sv = data; - bool invert; - int r; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - if (isempty(rvalue)) { - *sv = strv_free(*sv); - return 0; - } - - invert = *p == '!'; - p += invert; - - for (;;) { - _cleanup_free_ char *word = NULL, *k = NULL; - - r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE); - if (r == 0) - return 0; - if (r == -ENOMEM) - return log_oom(); - if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, r, "Invalid syntax, ignoring: %s", rvalue); - return 0; - } - - if (invert) { - k = strjoin("!", word); - if (!k) - return log_oom(); - } else - k = TAKE_PTR(word); - - r = strv_consume(sv, TAKE_PTR(k)); - if (r < 0) - return log_oom(); - } -} - -int config_parse_match_ifnames( - const char *unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - const char *p = rvalue; - char ***sv = data; - bool invert; - int r; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - invert = *p == '!'; - p += invert; - - for (;;) { - _cleanup_free_ char *word = NULL, *k = NULL; - - r = extract_first_word(&p, &word, NULL, 0); - if (r == 0) - return 0; - if (r == -ENOMEM) - return log_oom(); - if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, 0, - "Failed to parse interface name list: %s", rvalue); - return 0; - } - - if (!ifname_valid_full(word, ltype)) { - log_syntax(unit, LOG_ERR, filename, line, 0, - "Interface name is not valid or too long, ignoring assignment: %s", word); - continue; - } - - if (invert) { - k = strjoin("!", word); - if (!k) - return log_oom(); - } else - k = TAKE_PTR(word); - - r = strv_consume(sv, TAKE_PTR(k)); - if (r < 0) - return log_oom(); - } -} - -int config_parse_match_property( - const char *unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - const char *p = rvalue; - char ***sv = data; - bool invert; - int r; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - invert = *p == '!'; - p += invert; - - for (;;) { - _cleanup_free_ char *word = NULL, *k = NULL; - - r = extract_first_word(&p, &word, NULL, EXTRACT_CUNESCAPE|EXTRACT_UNQUOTE); - if (r == 0) - return 0; - if (r == -ENOMEM) - return log_oom(); - if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, 0, - "Invalid syntax, ignoring: %s", rvalue); - return 0; - } - - if (!env_assignment_is_valid(word)) { - log_syntax(unit, LOG_ERR, filename, line, 0, - "Invalid property or value, ignoring assignment: %s", word); - continue; - } - - if (invert) { - k = strjoin("!", word); - if (!k) - return log_oom(); - } else - k = TAKE_PTR(word); - - r = strv_consume(sv, TAKE_PTR(k)); - if (r < 0) - return log_oom(); - } -} - -int config_parse_ifalias(const char *unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - char **s = data; - _cleanup_free_ char *n = NULL; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - n = strdup(rvalue); - if (!n) - return log_oom(); - - if (!ascii_is_valid(n) || strlen(n) >= IFALIASZ) { - log_syntax(unit, LOG_ERR, filename, line, 0, "Interface alias is not ASCII clean or is too long, ignoring assignment: %s", rvalue); - return 0; - } - - if (isempty(n)) - *s = mfree(*s); - else - free_and_replace(*s, n); - - return 0; -} - -int config_parse_hwaddr(const char *unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - _cleanup_free_ struct ether_addr *n = NULL; - struct ether_addr **hwaddr = data; - int r; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - n = new0(struct ether_addr, 1); - if (!n) - return log_oom(); - - r = ether_addr_from_string(rvalue, n); - if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, r, "Not a valid MAC address, ignoring assignment: %s", rvalue); - return 0; - } - - free_and_replace(*hwaddr, n); - - return 0; -} - -int config_parse_hwaddrs(const char *unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - _cleanup_set_free_free_ Set *s = NULL; - const char *p = rvalue; - Set **hwaddrs = data; - int r; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - if (isempty(rvalue)) { - /* Empty assignment resets the list */ - *hwaddrs = set_free_free(*hwaddrs); - return 0; - } - - s = set_new(ðer_addr_hash_ops); - if (!s) - return log_oom(); - - for (;;) { - _cleanup_free_ char *word = NULL; - _cleanup_free_ struct ether_addr *n = NULL; - - r = extract_first_word(&p, &word, NULL, 0); - if (r == 0) - break; - if (r == -ENOMEM) - return log_oom(); - if (r < 0) { - log_syntax(unit, LOG_WARNING, filename, line, r, "Invalid syntax, ignoring: %s", rvalue); - return 0; - } - - n = new(struct ether_addr, 1); - if (!n) - return log_oom(); - - r = ether_addr_from_string(word, n); - if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, 0, "Not a valid MAC address, ignoring: %s", word); - continue; - } - - r = set_put(s, n); - if (r < 0) - return log_oom(); - if (r > 0) - n = NULL; /* avoid cleanup */ - } - - r = set_ensure_allocated(hwaddrs, ðer_addr_hash_ops); - if (r < 0) - return log_oom(); - - r = set_move(*hwaddrs, s); - if (r < 0) - return log_oom(); - - return 0; -} - -int config_parse_bridge_port_priority( - const char *unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - uint16_t i; - int r; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - r = safe_atou16(rvalue, &i); - if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, r, - "Failed to parse bridge port priority, ignoring: %s", rvalue); - return 0; - } - - if (i > LINK_BRIDGE_PORT_PRIORITY_MAX) { - log_syntax(unit, LOG_ERR, filename, line, r, - "Bridge port priority is larger than maximum %u, ignoring: %s", LINK_BRIDGE_PORT_PRIORITY_MAX, rvalue); - return 0; - } - - *((uint16_t *)data) = i; - - return 0; -} -#endif /* NM_IGNORED */ size_t serialize_in_addrs(FILE *f, const struct in_addr *addresses, diff --git a/src/systemd/src/libsystemd-network/network-internal.h b/src/systemd/src/libsystemd-network/network-internal.h index 1959474ee2..e5b853c0cd 100644 --- a/src/systemd/src/libsystemd-network/network-internal.h +++ b/src/systemd/src/libsystemd-network/network-internal.h @@ -1,54 +1,11 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once -#include <linux/nl80211.h> #include <stdbool.h> +#include <stdio.h> -#include "sd-device.h" #include "sd-dhcp-lease.h" -#include "conf-parser.h" -#include "set.h" -#include "strv.h" - -#define LINK_BRIDGE_PORT_PRIORITY_INVALID 128 -#define LINK_BRIDGE_PORT_PRIORITY_MAX 63 - -#if 0 /* NM_IGNORED */ -bool net_match_config(Set *match_mac, - Set *match_permanent_mac, - char * const *match_paths, - char * const *match_drivers, - char * const *match_iftypes, - char * const *match_names, - char * const *match_property, - char * const *match_wifi_iftype, - char * const *match_ssid, - Set *match_bssid, - sd_device *device, - const struct ether_addr *dev_mac, - const struct ether_addr *dev_permanent_mac, - const char *dev_driver, - unsigned short dev_iftype, - const char *dev_name, - char * const *alternative_names, - enum nl80211_iftype dev_wifi_iftype, - const char *dev_ssid, - const struct ether_addr *dev_bssid); - -CONFIG_PARSER_PROTOTYPE(config_parse_net_condition); -CONFIG_PARSER_PROTOTYPE(config_parse_hwaddr); -CONFIG_PARSER_PROTOTYPE(config_parse_hwaddrs); -CONFIG_PARSER_PROTOTYPE(config_parse_match_strv); -CONFIG_PARSER_PROTOTYPE(config_parse_match_ifnames); -CONFIG_PARSER_PROTOTYPE(config_parse_match_property); -CONFIG_PARSER_PROTOTYPE(config_parse_ifalias); -CONFIG_PARSER_PROTOTYPE(config_parse_bridge_port_priority); - -int net_get_unique_predictable_data(sd_device *device, bool use_sysname, uint64_t *result); -const char *net_get_name_persistent(sd_device *device); -#endif /* NM_IGNORED */ - size_t serialize_in_addrs(FILE *f, const struct in_addr *addresses, size_t size, diff --git a/src/systemd/src/libsystemd-network/sd-dhcp-client.c b/src/systemd/src/libsystemd-network/sd-dhcp-client.c index 6849ed9e20..95703aafc2 100644 --- a/src/systemd/src/libsystemd-network/sd-dhcp-client.c +++ b/src/systemd/src/libsystemd-network/sd-dhcp-client.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /*** Copyright © 2013 Intel Corporation. All rights reserved. ***/ @@ -16,19 +16,22 @@ #include "sd-dhcp-client.h" #include "alloc-util.h" -#include "async.h" #include "dhcp-identifier.h" #include "dhcp-internal.h" #include "dhcp-lease-internal.h" #include "dhcp-protocol.h" #include "dns-domain.h" #include "event-util.h" +#include "fd-util.h" #include "hostname-util.h" #include "io-util.h" #include "memory-util.h" #include "random-util.h" +#include "set.h" +#include "sort-util.h" #include "string-util.h" #include "strv.h" +#include "time-util.h" #include "utf8.h" #include "web-util.h" @@ -38,6 +41,9 @@ #define RESTART_AFTER_NAK_MIN_USEC (1 * USEC_PER_SEC) #define RESTART_AFTER_NAK_MAX_USEC (30 * USEC_PER_MINUTE) +#define TRANSIENT_FAILURE_ATTEMPTS 3 /* Arbitrary limit: how many attempts are considered enough to report + * transient failure. */ + typedef struct sd_dhcp_client_id { uint8_t type; union { @@ -77,13 +83,13 @@ struct sd_dhcp_client { union sockaddr_union link; sd_event_source *receive_message; bool request_broadcast; - uint8_t *req_opts; - size_t req_opts_allocated; - size_t req_opts_size; + Set *req_opts; bool anonymize; be32_t last_addr; uint8_t mac_addr[MAX_MAC_ADDR_LEN]; size_t mac_addr_len; + uint8_t bcast_addr[MAX_MAC_ADDR_LEN]; + size_t bcast_addr_len; uint16_t arp_type; sd_dhcp_client_id client_id; size_t client_id_len; @@ -95,6 +101,9 @@ struct sd_dhcp_client { uint32_t fallback_lease_lifetime; uint32_t xid; usec_t start_time; + usec_t t1_time; + usec_t t2_time; + usec_t expire_time; uint64_t attempt; uint64_t max_attempts; OrderedHashmap *extra_options; @@ -232,8 +241,6 @@ int sd_dhcp_client_set_request_broadcast(sd_dhcp_client *client, int broadcast) } int sd_dhcp_client_set_request_option(sd_dhcp_client *client, uint8_t option) { - size_t i; - assert_return(client, -EINVAL); assert_return(IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED), -EBUSY); @@ -250,17 +257,7 @@ int sd_dhcp_client_set_request_option(sd_dhcp_client *client, uint8_t option) { break; } - for (i = 0; i < client->req_opts_size; i++) - if (client->req_opts[i] == option) - return -EEXIST; - - if (!GREEDY_REALLOC(client->req_opts, client->req_opts_allocated, - client->req_opts_size + 1)) - return -ENOMEM; - - client->req_opts[client->req_opts_size++] = option; - - return 0; + return set_ensure_put(&client->req_opts, NULL, UINT8_TO_PTR(option)); } int sd_dhcp_client_set_request_address( @@ -291,6 +288,7 @@ int sd_dhcp_client_set_ifindex(sd_dhcp_client *client, int ifindex) { int sd_dhcp_client_set_mac( sd_dhcp_client *client, const uint8_t *addr, + const uint8_t *bcast_addr, size_t addr_len, uint16_t arp_type) { @@ -311,7 +309,9 @@ int sd_dhcp_client_set_mac( return -EINVAL; if (client->mac_addr_len == addr_len && - memcmp(&client->mac_addr, addr, addr_len) == 0) + memcmp(&client->mac_addr, addr, addr_len) == 0 && + (client->bcast_addr_len > 0) == !!bcast_addr && + (!bcast_addr || memcmp(&client->bcast_addr, bcast_addr, addr_len) == 0)) return 0; if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) { @@ -323,6 +323,12 @@ int sd_dhcp_client_set_mac( memcpy(&client->mac_addr, addr, addr_len); client->mac_addr_len = addr_len; client->arp_type = arp_type; + client->bcast_addr_len = 0; + + if (bcast_addr) { + memcpy(&client->bcast_addr, bcast_addr, addr_len); + client->bcast_addr_len = addr_len; + } if (need_restart && client->state != DHCP_STATE_STOPPED) { r = sd_dhcp_client_start(client); @@ -543,7 +549,7 @@ int sd_dhcp_client_set_hostname( /* Make sure hostnames qualify as DNS and as Linux hostnames */ if (hostname && - !(hostname_is_valid(hostname, false) && dns_name_is_valid(hostname) > 0)) + !(hostname_is_valid(hostname, 0) && dns_name_is_valid(hostname) > 0)) return -EINVAL; return free_and_strdup(&client->hostname, hostname); @@ -698,7 +704,7 @@ static int client_initialize(sd_dhcp_client *client) { client->receive_message = sd_event_source_unref(client->receive_message); - client->fd = asynchronous_close(client->fd); + client->fd = safe_close(client->fd); (void) event_source_disable(client->timeout_resend); (void) event_source_disable(client->timeout_t1); @@ -730,6 +736,41 @@ static void client_stop(sd_dhcp_client *client, int error) { client_initialize(client); } +/* RFC2131 section 4.1: + * retransmission delays should include -1 to +1 sec of random 'fuzz'. */ +#define RFC2131_RANDOM_FUZZ \ + ((int64_t)(random_u64() % (2 * USEC_PER_SEC)) - (int64_t)USEC_PER_SEC) + +/* RFC2131 section 4.1: + * for retransmission delays, timeout should start at 4s then double + * each attempt with max of 64s, with -1 to +1 sec of random 'fuzz' added. + * This assumes the first call will be using attempt 1. */ +static usec_t client_compute_request_timeout(usec_t now, uint64_t attempt) { + usec_t timeout = (UINT64_C(1) << MIN(attempt + 1, UINT64_C(6))) * USEC_PER_SEC; + + return usec_sub_signed(usec_add(now, timeout), RFC2131_RANDOM_FUZZ); +} + +/* RFC2131 section 4.4.5: + * T1 defaults to (0.5 * duration_of_lease). + * T2 defaults to (0.875 * duration_of_lease). */ +#define T1_DEFAULT(lifetime) ((lifetime) / 2) +#define T2_DEFAULT(lifetime) (((lifetime) * 7) / 8) + +/* RFC2131 section 4.4.5: + * the client SHOULD wait one-half of the remaining time until T2 (in RENEWING state) + * and one-half of the remaining lease time (in REBINDING state), down to a minimum + * of 60 seconds. + * Note that while the default T1/T2 initial times do have random 'fuzz' applied, + * the RFC sec 4.4.5 does not mention adding any fuzz to retries. */ +static usec_t client_compute_reacquisition_timeout(usec_t now, usec_t expire) { + return now + MAX(usec_sub_unsigned(expire, now) / 2, 60 * USEC_PER_SEC); +} + +static int cmp_uint8(const uint8_t *a, const uint8_t *b) { + return CMP(*a, *b); +} + static int client_message_init( sd_dhcp_client *client, DHCPPacket **ret, @@ -840,10 +881,26 @@ static int client_message_init( MAY contain the Parameter Request List option. */ /* NOTE: in case that there would be an option to do not send * any PRL at all, the size should be checked before sending */ - if (client->req_opts_size > 0 && type != DHCP_RELEASE) { + if (!set_isempty(client->req_opts) && type != DHCP_RELEASE) { + _cleanup_free_ uint8_t *opts = NULL; + size_t n_opts, i = 0; + void *val; + + n_opts = set_size(client->req_opts); + opts = new(uint8_t, n_opts); + if (!opts) + return -ENOMEM; + + SET_FOREACH(val, client->req_opts) + opts[i++] = PTR_TO_UINT8(val); + assert(i == n_opts); + + /* For anonymizing the request, let's sort the options. */ + typesafe_qsort(opts, n_opts, cmp_uint8); + r = dhcp_option_append(&packet->dhcp, optlen, &optoffset, 0, SD_DHCP_OPTION_PARAMETER_REQUEST_LIST, - client->req_opts_size, client->req_opts); + n_opts, opts); if (r < 0) return r; } @@ -1173,9 +1230,8 @@ static int client_timeout_resend( sd_dhcp_client *client = userdata; DHCP_CLIENT_DONT_DESTROY(client); - usec_t next_timeout = 0; + usec_t next_timeout; uint64_t time_now; - uint32_t time_left; int r; assert(s); @@ -1189,22 +1245,11 @@ static int client_timeout_resend( switch (client->state) { case DHCP_STATE_RENEWING: - - time_left = (client->lease->t2 - client->lease->t1) / 2; - if (time_left < 60) - time_left = 60; - - next_timeout = time_now + time_left * USEC_PER_SEC; - + next_timeout = client_compute_reacquisition_timeout(time_now, client->t2_time); break; case DHCP_STATE_REBINDING: - - time_left = (client->lease->lifetime - client->lease->t2) / 2; - if (time_left < 60) - time_left = 60; - - next_timeout = time_now + time_left * USEC_PER_SEC; + next_timeout = client_compute_reacquisition_timeout(time_now, client->expire_time); break; case DHCP_STATE_REBOOTING: @@ -1216,33 +1261,28 @@ static int client_timeout_resend( r = client_start(client); if (r < 0) goto error; - else { - log_dhcp_client(client, "REBOOTED"); - return 0; - } + + log_dhcp_client(client, "REBOOTED"); + return 0; case DHCP_STATE_INIT: case DHCP_STATE_INIT_REBOOT: case DHCP_STATE_SELECTING: case DHCP_STATE_REQUESTING: case DHCP_STATE_BOUND: - - if (client->attempt < client->max_attempts) - client->attempt++; - else + if (client->attempt >= client->max_attempts) goto error; - next_timeout = time_now + ((UINT64_C(1) << MIN(client->attempt, (uint64_t) 6)) - 1) * USEC_PER_SEC; - + client->attempt++; + next_timeout = client_compute_request_timeout(time_now, client->attempt); break; case DHCP_STATE_STOPPED: + default: r = -EINVAL; goto error; } - next_timeout += (random_u32() & 0x1fffff); - r = event_reset_time(client->event, &client->timeout_resend, clock_boottime_or_monotonic(), next_timeout, 10 * USEC_PER_MSEC, @@ -1281,12 +1321,10 @@ static int client_timeout_resend( client->state = DHCP_STATE_REBOOTING; client->request_sent = time_now; - break; case DHCP_STATE_REBOOTING: case DHCP_STATE_BOUND: - break; case DHCP_STATE_STOPPED: @@ -1294,6 +1332,9 @@ static int client_timeout_resend( goto error; } + if (client->attempt >= TRANSIENT_FAILURE_ATTEMPTS) + client_notify(client, SD_DHCP_CLIENT_EVENT_TRANSIENT_FAILURE); + return 0; error: @@ -1378,9 +1419,10 @@ static int client_start_delayed(sd_dhcp_client *client) { client->xid = random_u32(); - r = dhcp_network_bind_raw_socket(client->ifindex, &client->link, - client->xid, client->mac_addr, - client->mac_addr_len, client->arp_type, client->port); + r = dhcp_network_bind_raw_socket(client->ifindex, &client->link, client->xid, + client->mac_addr, client->mac_addr_len, + client->bcast_addr, client->bcast_addr_len, + client->arp_type, client->port); if (r < 0) { client_stop(client, r); return r; @@ -1423,15 +1465,15 @@ static int client_timeout_t2(sd_event_source *s, uint64_t usec, void *userdata) assert(client); client->receive_message = sd_event_source_unref(client->receive_message); - client->fd = asynchronous_close(client->fd); + client->fd = safe_close(client->fd); client->state = DHCP_STATE_REBINDING; client->attempt = 0; - r = dhcp_network_bind_raw_socket(client->ifindex, &client->link, - client->xid, client->mac_addr, - client->mac_addr_len, client->arp_type, - client->port); + r = dhcp_network_bind_raw_socket(client->ifindex, &client->link, client->xid, + client->mac_addr, client->mac_addr_len, + client->bcast_addr, client->bcast_addr_len, + client->arp_type, client->port); if (r < 0) { client_stop(client, r); return 0; @@ -1606,25 +1648,8 @@ static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *ack, size_t le return r; } -static uint64_t client_compute_timeout(sd_dhcp_client *client, uint32_t lifetime, double factor) { - assert(client); - assert(client->request_sent); - assert(lifetime > 0); - - if (lifetime > 3) - lifetime -= 3; - else - lifetime = 0; - - return client->request_sent + (lifetime * USEC_PER_SEC * factor) + - + (random_u32() & 0x1fffff); -} - static int client_set_lease_timeouts(sd_dhcp_client *client) { usec_t time_now; - uint64_t lifetime_timeout; - uint64_t t2_timeout; - uint64_t t1_timeout; char time_string[FORMAT_TIMESPAN_MAX]; int r; @@ -1647,93 +1672,76 @@ static int client_set_lease_timeouts(sd_dhcp_client *client) { return r; assert(client->request_sent <= time_now); - /* convert the various timeouts from relative (secs) to absolute (usecs) */ - lifetime_timeout = client_compute_timeout(client, client->lease->lifetime, 1); - if (client->lease->t1 > 0 && client->lease->t2 > 0) { - /* both T1 and T2 are given */ - if (client->lease->t1 < client->lease->t2 && - client->lease->t2 < client->lease->lifetime) { - /* they are both valid */ - t2_timeout = client_compute_timeout(client, client->lease->t2, 1); - t1_timeout = client_compute_timeout(client, client->lease->t1, 1); - } else { - /* discard both */ - t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0); - client->lease->t2 = (client->lease->lifetime * 7) / 8; - t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5); - client->lease->t1 = client->lease->lifetime / 2; - } - } else if (client->lease->t2 > 0 && client->lease->t2 < client->lease->lifetime) { - /* only T2 is given, and it is valid */ - t2_timeout = client_compute_timeout(client, client->lease->t2, 1); - t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5); - client->lease->t1 = client->lease->lifetime / 2; - if (t2_timeout <= t1_timeout) { - /* the computed T1 would be invalid, so discard T2 */ - t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0); - client->lease->t2 = (client->lease->lifetime * 7) / 8; - } - } else if (client->lease->t1 > 0 && client->lease->t1 < client->lease->lifetime) { - /* only T1 is given, and it is valid */ - t1_timeout = client_compute_timeout(client, client->lease->t1, 1); - t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0); - client->lease->t2 = (client->lease->lifetime * 7) / 8; - if (t2_timeout <= t1_timeout) { - /* the computed T2 would be invalid, so discard T1 */ - t2_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5); - client->lease->t2 = client->lease->lifetime / 2; - } - } else { - /* fall back to the default timeouts */ - t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5); - client->lease->t1 = client->lease->lifetime / 2; - t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0); - client->lease->t2 = (client->lease->lifetime * 7) / 8; - } + /* verify that 0 < t2 < lifetime */ + if (client->lease->t2 == 0 || client->lease->t2 >= client->lease->lifetime) + client->lease->t2 = T2_DEFAULT(client->lease->lifetime); + /* verify that 0 < t1 < lifetime */ + if (client->lease->t1 == 0 || client->lease->t1 >= client->lease->t2) + client->lease->t1 = T1_DEFAULT(client->lease->lifetime); + /* now, if t1 >= t2, t1 *must* be T1_DEFAULT, since the previous check + * could not evalate to false if t1 >= t2; so setting t2 to T2_DEFAULT + * guarantees t1 < t2. */ + if (client->lease->t1 >= client->lease->t2) + client->lease->t2 = T2_DEFAULT(client->lease->lifetime); + + client->expire_time = client->request_sent + client->lease->lifetime * USEC_PER_SEC; + client->t1_time = client->request_sent + client->lease->t1 * USEC_PER_SEC; + client->t2_time = client->request_sent + client->lease->t2 * USEC_PER_SEC; + + /* RFC2131 section 4.4.5: + * Times T1 and T2 SHOULD be chosen with some random "fuzz". + * Since the RFC doesn't specify here the exact 'fuzz' to use, + * we use the range from section 4.1: -1 to +1 sec. */ + client->t1_time = usec_sub_signed(client->t1_time, RFC2131_RANDOM_FUZZ); + client->t2_time = usec_sub_signed(client->t2_time, RFC2131_RANDOM_FUZZ); + + /* after fuzzing, ensure t2 is still >= t1 */ + client->t2_time = MAX(client->t1_time, client->t2_time); /* arm lifetime timeout */ r = event_reset_time(client->event, &client->timeout_expire, clock_boottime_or_monotonic(), - lifetime_timeout, 10 * USEC_PER_MSEC, + client->expire_time, 10 * USEC_PER_MSEC, client_timeout_expire, client, client->event_priority, "dhcp4-lifetime", true); if (r < 0) return r; - log_dhcp_client(client, "lease expires in %s", - format_timespan(time_string, FORMAT_TIMESPAN_MAX, lifetime_timeout - time_now, USEC_PER_SEC)); - /* don't arm earlier timeouts if this has already expired */ - if (lifetime_timeout <= time_now) + if (client->expire_time <= time_now) return 0; + log_dhcp_client(client, "lease expires in %s", + format_timespan(time_string, FORMAT_TIMESPAN_MAX, client->expire_time - time_now, USEC_PER_SEC)); + /* arm T2 timeout */ r = event_reset_time(client->event, &client->timeout_t2, clock_boottime_or_monotonic(), - t2_timeout, 10 * USEC_PER_MSEC, + client->t2_time, 10 * USEC_PER_MSEC, client_timeout_t2, client, client->event_priority, "dhcp4-t2-timeout", true); if (r < 0) return r; - log_dhcp_client(client, "T2 expires in %s", - format_timespan(time_string, FORMAT_TIMESPAN_MAX, t2_timeout - time_now, USEC_PER_SEC)); - /* don't arm earlier timeout if this has already expired */ - if (t2_timeout <= time_now) + if (client->t2_time <= time_now) return 0; + log_dhcp_client(client, "T2 expires in %s", + format_timespan(time_string, FORMAT_TIMESPAN_MAX, client->t2_time - time_now, USEC_PER_SEC)); + /* arm T1 timeout */ r = event_reset_time(client->event, &client->timeout_t1, clock_boottime_or_monotonic(), - t1_timeout, 10 * USEC_PER_MSEC, + client->t1_time, 10 * USEC_PER_MSEC, client_timeout_t1, client, client->event_priority, "dhcp4-t1-timer", true); if (r < 0) return r; - log_dhcp_client(client, "T1 expires in %s", - format_timespan(time_string, FORMAT_TIMESPAN_MAX, t1_timeout - time_now, USEC_PER_SEC)); + if (client->t1_time > time_now) + log_dhcp_client(client, "T1 expires in %s", + format_timespan(time_string, FORMAT_TIMESPAN_MAX, client->t1_time - time_now, USEC_PER_SEC)); return 0; } @@ -1780,7 +1788,7 @@ static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message, i (void) event_source_disable(client->timeout_resend); client->receive_message = sd_event_source_unref(client->receive_message); - client->fd = asynchronous_close(client->fd); + client->fd = safe_close(client->fd); if (IN_SET(client->state, DHCP_STATE_REQUESTING, DHCP_STATE_REBOOTING)) @@ -1885,12 +1893,11 @@ static int client_receive_message_udp( assert(client); buflen = next_datagram_size_fd(fd); - if (buflen == -ENETDOWN) { + if (buflen == -ENETDOWN) /* the link is down. Don't return an error or the I/O event source will be disconnected and we won't be able to receive packets again when the link comes back. */ return 0; - } if (buflen < 0) return buflen; @@ -2133,9 +2140,10 @@ int sd_dhcp_client_send_decline(sd_dhcp_client *client) { } int sd_dhcp_client_stop(sd_dhcp_client *client) { - DHCP_CLIENT_DONT_DESTROY(client); + if (!client) + return 0; - assert_return(client, -EINVAL); + DHCP_CLIENT_DONT_DESTROY(client); client_stop(client, SD_DHCP_CLIENT_EVENT_STOP); client->state = DHCP_STATE_STOPPED; @@ -2193,7 +2201,7 @@ static sd_dhcp_client *dhcp_client_free(sd_dhcp_client *client) { sd_dhcp_lease_unref(client->lease); - free(client->req_opts); + set_free(client->req_opts); free(client->hostname); free(client->vendor_class_identifier); free(client->mudurl); @@ -2206,6 +2214,10 @@ static sd_dhcp_client *dhcp_client_free(sd_dhcp_client *client) { DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_dhcp_client, sd_dhcp_client, dhcp_client_free); int sd_dhcp_client_new(sd_dhcp_client **ret, int anonymize) { + const uint8_t *opts; + size_t n_opts; + int r; + assert_return(ret, -EINVAL); _cleanup_(sd_dhcp_client_unrefp) sd_dhcp_client *client = new(sd_dhcp_client, 1); @@ -2225,14 +2237,18 @@ int sd_dhcp_client_new(sd_dhcp_client **ret, int anonymize) { }; /* NOTE: this could be moved to a function. */ if (anonymize) { - client->req_opts_size = ELEMENTSOF(default_req_opts_anonymize); - client->req_opts = memdup(default_req_opts_anonymize, client->req_opts_size); + n_opts = ELEMENTSOF(default_req_opts_anonymize); + opts = default_req_opts_anonymize; } else { - client->req_opts_size = ELEMENTSOF(default_req_opts); - client->req_opts = memdup(default_req_opts, client->req_opts_size); + n_opts = ELEMENTSOF(default_req_opts); + opts = default_req_opts; + } + + for (size_t i = 0; i < n_opts; i++) { + r = sd_dhcp_client_set_request_option(client, opts[i]); + if (r < 0) + return r; } - if (!client->req_opts) - return -ENOMEM; *ret = TAKE_PTR(client); diff --git a/src/systemd/src/libsystemd-network/sd-dhcp-lease.c b/src/systemd/src/libsystemd-network/sd-dhcp-lease.c index c810877c7c..94b0d35c09 100644 --- a/src/systemd/src/libsystemd-network/sd-dhcp-lease.c +++ b/src/systemd/src/libsystemd-network/sd-dhcp-lease.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /*** Copyright © 2013 Intel Corporation. All rights reserved. ***/ @@ -1235,10 +1235,8 @@ int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) { if (!a) return -ENOMEM; - if (!strv_isempty(a)) { - lease->search_domains = a; - a = NULL; - } + if (!strv_isempty(a)) + lease->search_domains = TAKE_PTR(a); } if (routes) { diff --git a/src/systemd/src/libsystemd-network/sd-dhcp6-client.c b/src/systemd/src/libsystemd-network/sd-dhcp6-client.c index 42cde93b08..3fafd3c0e2 100644 --- a/src/systemd/src/libsystemd-network/sd-dhcp6-client.c +++ b/src/systemd/src/libsystemd-network/sd-dhcp6-client.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /*** Copyright © 2014-2015 Intel Corporation. All rights reserved. ***/ @@ -27,10 +27,10 @@ #include "hexdecoct.h" #include "hostname-util.h" #include "in-addr-util.h" -#include "network-internal.h" #include "random-util.h" #include "socket-util.h" #include "string-table.h" +#include "strv.h" #include "util.h" #include "web-util.h" @@ -194,8 +194,7 @@ int sd_dhcp6_client_set_mac( assert_return(client, -EINVAL); assert_return(addr, -EINVAL); - assert_return(addr_len > 0 && addr_len <= MAX_MAC_ADDR_LEN, -EINVAL); - assert_return(arp_type > 0, -EINVAL); + assert_return(addr_len <= MAX_MAC_ADDR_LEN, -EINVAL); assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY); @@ -203,8 +202,11 @@ int sd_dhcp6_client_set_mac( assert_return(addr_len == ETH_ALEN, -EINVAL); else if (arp_type == ARPHRD_INFINIBAND) assert_return(addr_len == INFINIBAND_ALEN, -EINVAL); - else - return -EINVAL; + else { + client->arp_type = ARPHRD_NONE; + client->mac_addr_len = 0; + return 0; + } if (client->mac_addr_len == addr_len && memcmp(&client->mac_addr, addr, addr_len) == 0) @@ -415,7 +417,7 @@ int sd_dhcp6_client_set_fqdn( /* Make sure FQDN qualifies as DNS and as Linux hostname */ if (fqdn && - !(hostname_is_valid(fqdn, false) && dns_name_is_valid(fqdn) > 0)) + !(hostname_is_valid(fqdn, 0) && dns_name_is_valid(fqdn) > 0)) return -EINVAL; return free_and_strdup(&client->fqdn, fqdn); @@ -1430,12 +1432,11 @@ static int client_receive_message( assert(client->event); buflen = next_datagram_size_fd(fd); - if (buflen == -ENETDOWN) { + if (buflen == -ENETDOWN) /* the link is down. Don't return an error or the I/O event source will be disconnected and we won't be able to receive packets again when the link comes back. */ return 0; - } if (buflen < 0) return buflen; @@ -1687,7 +1688,8 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state) { } int sd_dhcp6_client_stop(sd_dhcp6_client *client) { - assert_return(client, -EINVAL); + if (!client) + return 0; client_stop(client, SD_DHCP6_CLIENT_EVENT_STOP); @@ -1753,8 +1755,7 @@ int sd_dhcp6_client_start(sd_dhcp6_client *client) { } log_dhcp6_client(client, "Started in %s mode", - client->information_request? "Information request": - "Managed"); + client->information_request ? "Information request" : "Managed"); return client_start(client, state); } diff --git a/src/systemd/src/libsystemd-network/sd-dhcp6-lease.c b/src/systemd/src/libsystemd-network/sd-dhcp6-lease.c index 5f5a7fe616..5792f6882d 100644 --- a/src/systemd/src/libsystemd-network/sd-dhcp6-lease.c +++ b/src/systemd/src/libsystemd-network/sd-dhcp6-lease.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /*** Copyright © 2014-2015 Intel Corporation. All rights reserved. ***/ diff --git a/src/systemd/src/libsystemd-network/sd-ipv4acd.c b/src/systemd/src/libsystemd-network/sd-ipv4acd.c index b9e3dce38e..096afbd8ef 100644 --- a/src/systemd/src/libsystemd-network/sd-ipv4acd.c +++ b/src/systemd/src/libsystemd-network/sd-ipv4acd.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /*** Copyright © 2014 Axis Communications AB. All rights reserved. ***/ @@ -18,10 +18,12 @@ #include "ether-addr-util.h" #include "event-util.h" #include "fd-util.h" +#include "format-util.h" #include "in-addr-util.h" -#include "list.h" +#include "log-link.h" #include "random-util.h" #include "siphash24.h" +#include "string-table.h" #include "string-util.h" #include "time-util.h" @@ -56,6 +58,7 @@ struct sd_ipv4acd { int ifindex; int fd; + char ifname[IF_NAMESIZE + 1]; unsigned n_iteration; unsigned n_conflict; @@ -74,13 +77,30 @@ struct sd_ipv4acd { void* userdata; }; -#define log_ipv4acd_errno(acd, error, fmt, ...) log_internal(LOG_DEBUG, error, PROJECT_FILE, __LINE__, __func__, "IPV4ACD: " fmt, ##__VA_ARGS__) -#define log_ipv4acd(acd, fmt, ...) log_ipv4acd_errno(acd, 0, fmt, ##__VA_ARGS__) +#define log_ipv4acd_errno(acd, error, fmt, ...) \ + log_interface_full_errno(sd_ipv4acd_get_ifname(acd), LOG_DEBUG, error, "IPV4ACD: " fmt, ##__VA_ARGS__) +#define log_ipv4acd(acd, fmt, ...) \ + log_ipv4acd_errno(acd, 0, fmt, ##__VA_ARGS__) + +static const char * const ipv4acd_state_table[_IPV4ACD_STATE_MAX] = { + [IPV4ACD_STATE_INIT] = "init", + [IPV4ACD_STATE_STARTED] = "started", + [IPV4ACD_STATE_WAITING_PROBE] = "waiting-probe", + [IPV4ACD_STATE_PROBING] = "probing", + [IPV4ACD_STATE_WAITING_ANNOUNCE] = "waiting-announce", + [IPV4ACD_STATE_ANNOUNCING] = "announcing", + [IPV4ACD_STATE_RUNNING] = "running", +}; + +DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(ipv4acd_state, IPv4ACDState); static void ipv4acd_set_state(sd_ipv4acd *acd, IPv4ACDState st, bool reset_counter) { assert(acd); assert(st < _IPV4ACD_STATE_MAX); + if (st != acd->state) + log_ipv4acd(acd, "%s -> %s", ipv4acd_state_to_string(acd->state), ipv4acd_state_to_string(st)); + if (st == acd->state && !reset_counter) acd->n_iteration++; else { @@ -146,7 +166,8 @@ static void ipv4acd_client_notify(sd_ipv4acd *acd, int event) { int sd_ipv4acd_stop(sd_ipv4acd *acd) { IPv4ACDState old_state; - assert_return(acd, -EINVAL); + if (!acd) + return 0; old_state = acd->state; @@ -379,15 +400,35 @@ fail: } int sd_ipv4acd_set_ifindex(sd_ipv4acd *acd, int ifindex) { + char ifname[IF_NAMESIZE + 1]; + assert_return(acd, -EINVAL); assert_return(ifindex > 0, -EINVAL); assert_return(acd->state == IPV4ACD_STATE_INIT, -EBUSY); + if (!format_ifname(ifindex, ifname)) + return -ENODEV; + + strcpy(acd->ifname, ifname); acd->ifindex = ifindex; return 0; } +int sd_ipv4acd_get_ifindex(sd_ipv4acd *acd) { + if (!acd) + return -EINVAL; + + return acd->ifindex; +} + +const char *sd_ipv4acd_get_ifname(sd_ipv4acd *acd) { + if (!acd) + return NULL; + + return empty_to_null(acd->ifname); +} + int sd_ipv4acd_set_mac(sd_ipv4acd *acd, const struct ether_addr *addr) { assert_return(acd, -EINVAL); assert_return(addr, -EINVAL); diff --git a/src/systemd/src/libsystemd-network/sd-ipv4ll.c b/src/systemd/src/libsystemd-network/sd-ipv4ll.c index 0bfaf265a2..c5e7a91fe8 100644 --- a/src/systemd/src/libsystemd-network/sd-ipv4ll.c +++ b/src/systemd/src/libsystemd-network/sd-ipv4ll.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /*** Copyright © 2014 Axis Communications AB. All rights reserved. ***/ @@ -17,7 +17,7 @@ #include "alloc-util.h" #include "ether-addr-util.h" #include "in-addr-util.h" -#include "list.h" +#include "log-link.h" #include "random-util.h" #include "siphash24.h" #include "sparse-endian.h" @@ -51,8 +51,10 @@ struct sd_ipv4ll { void* userdata; }; -#define log_ipv4ll_errno(ll, error, fmt, ...) log_internal(LOG_DEBUG, error, PROJECT_FILE, __LINE__, __func__, "IPV4LL: " fmt, ##__VA_ARGS__) -#define log_ipv4ll(ll, fmt, ...) log_ipv4ll_errno(ll, 0, fmt, ##__VA_ARGS__) +#define log_ipv4ll_errno(ll, error, fmt, ...) \ + log_interface_full_errno(sd_ipv4ll_get_ifname(ll), LOG_DEBUG, error, "IPV4LL: " fmt, ##__VA_ARGS__) +#define log_ipv4ll(ll, fmt, ...) \ + log_ipv4ll_errno(ll, 0, fmt, ##__VA_ARGS__) static void ipv4ll_on_acd(sd_ipv4acd *ll, int event, void *userdata); @@ -91,7 +93,8 @@ int sd_ipv4ll_new(sd_ipv4ll **ret) { } int sd_ipv4ll_stop(sd_ipv4ll *ll) { - assert_return(ll, -EINVAL); + if (!ll) + return 0; return sd_ipv4acd_stop(ll->acd); } @@ -104,6 +107,20 @@ int sd_ipv4ll_set_ifindex(sd_ipv4ll *ll, int ifindex) { return sd_ipv4acd_set_ifindex(ll->acd, ifindex); } +int sd_ipv4ll_get_ifindex(sd_ipv4ll *ll) { + if (!ll) + return -EINVAL; + + return sd_ipv4acd_get_ifindex(ll->acd); +} + +const char *sd_ipv4ll_get_ifname(sd_ipv4ll *ll) { + if (!ll) + return NULL; + + return sd_ipv4acd_get_ifname(ll->acd); +} + int sd_ipv4ll_set_mac(sd_ipv4ll *ll, const struct ether_addr *addr) { int r; diff --git a/src/systemd/src/libsystemd-network/sd-lldp.c b/src/systemd/src/libsystemd-network/sd-lldp.c index 524b1bab0a..b12d8e27f2 100644 --- a/src/systemd/src/libsystemd-network/sd-lldp.c +++ b/src/systemd/src/libsystemd-network/sd-lldp.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #include "nm-sd-adapt-core.h" @@ -278,7 +278,8 @@ fail: } _public_ int sd_lldp_stop(sd_lldp *lldp) { - assert_return(lldp, -EINVAL); + if (!lldp) + return 0; if (lldp->fd < 0) return 0; diff --git a/src/systemd/src/libsystemd/sd-event/event-source.h b/src/systemd/src/libsystemd/sd-event/event-source.h index a8a30d825e..f0d2a1b9e6 100644 --- a/src/systemd/src/libsystemd/sd-event/event-source.h +++ b/src/systemd/src/libsystemd/sd-event/event-source.h @@ -1,5 +1,5 @@ #pragma once -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #include <sys/epoll.h> #include <sys/timerfd.h> @@ -11,6 +11,7 @@ #include "hashmap.h" #include "list.h" #include "prioq.h" +#include "ratelimit.h" typedef enum EventSourceType { SOURCE_IO, @@ -61,6 +62,7 @@ struct sd_event_source { bool dispatching:1; bool floating:1; bool exit_on_failure:1; + bool ratelimited:1; int64_t priority; unsigned pending_index; @@ -72,6 +74,13 @@ struct sd_event_source { LIST_FIELDS(sd_event_source, sources); + RateLimit rate_limit; + + /* These are primarily fields relevant for time event sources, but since any event source can + * effectively become one when rate-limited, this is part of the common fields. */ + unsigned earliest_index; + unsigned latest_index; + union { struct { sd_event_io_handler_t callback; @@ -84,8 +93,6 @@ struct sd_event_source { struct { sd_event_time_handler_t callback; usec_t next, accuracy; - unsigned earliest_index; - unsigned latest_index; } time; struct { sd_event_signal_handler_t callback; diff --git a/src/systemd/src/libsystemd/sd-event/event-util.c b/src/systemd/src/libsystemd/sd-event/event-util.c index e8384cfd6b..7cc55be101 100644 --- a/src/systemd/src/libsystemd/sd-event/event-util.c +++ b/src/systemd/src/libsystemd/sd-event/event-util.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #include "nm-sd-adapt-core.h" diff --git a/src/systemd/src/libsystemd/sd-event/event-util.h b/src/systemd/src/libsystemd/sd-event/event-util.h index 00180955f9..c8f97bc8d6 100644 --- a/src/systemd/src/libsystemd/sd-event/event-util.h +++ b/src/systemd/src/libsystemd/sd-event/event-util.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include <stdbool.h> diff --git a/src/systemd/src/libsystemd/sd-event/sd-event.c b/src/systemd/src/libsystemd/sd-event/sd-event.c index 60df499b01..dda4be00bf 100644 --- a/src/systemd/src/libsystemd/sd-event/sd-event.c +++ b/src/systemd/src/libsystemd/sd-event/sd-event.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #include "nm-sd-adapt-core.h" @@ -39,6 +39,16 @@ static bool EVENT_SOURCE_WATCH_PIDFD(sd_event_source *s) { s->child.options == WEXITED; } +static bool event_source_is_online(sd_event_source *s) { + assert(s); + return s->enabled != SD_EVENT_OFF && !s->ratelimited; +} + +static bool event_source_is_offline(sd_event_source *s) { + assert(s); + return s->enabled == SD_EVENT_OFF || s->ratelimited; +} + static const char* const event_source_type_table[_SOURCE_EVENT_SOURCE_TYPE_MAX] = { [SOURCE_IO] = "io", [SOURCE_TIME_REALTIME] = "realtime", @@ -57,7 +67,25 @@ static const char* const event_source_type_table[_SOURCE_EVENT_SOURCE_TYPE_MAX] DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(event_source_type, int); -#define EVENT_SOURCE_IS_TIME(t) IN_SET((t), SOURCE_TIME_REALTIME, SOURCE_TIME_BOOTTIME, SOURCE_TIME_MONOTONIC, SOURCE_TIME_REALTIME_ALARM, SOURCE_TIME_BOOTTIME_ALARM) +#define EVENT_SOURCE_IS_TIME(t) \ + IN_SET((t), \ + SOURCE_TIME_REALTIME, \ + SOURCE_TIME_BOOTTIME, \ + SOURCE_TIME_MONOTONIC, \ + SOURCE_TIME_REALTIME_ALARM, \ + SOURCE_TIME_BOOTTIME_ALARM) + +#define EVENT_SOURCE_CAN_RATE_LIMIT(t) \ + IN_SET((t), \ + SOURCE_IO, \ + SOURCE_TIME_REALTIME, \ + SOURCE_TIME_BOOTTIME, \ + SOURCE_TIME_MONOTONIC, \ + SOURCE_TIME_REALTIME_ALARM, \ + SOURCE_TIME_BOOTTIME_ALARM, \ + SOURCE_SIGNAL, \ + SOURCE_DEFER, \ + SOURCE_INOTIFY) struct sd_event { unsigned n_ref; @@ -83,7 +111,7 @@ struct sd_event { Hashmap *signal_data; /* indexed by priority */ Hashmap *child_sources; - unsigned n_enabled_child_sources; + unsigned n_online_child_sources; Set *post_sources; @@ -122,7 +150,7 @@ struct sd_event { LIST_HEAD(sd_event_source, sources); - usec_t last_run, last_log; + usec_t last_run_usec, last_log_usec; unsigned delays[sizeof(usec_t) * 8]; }; @@ -148,6 +176,11 @@ static int pending_prioq_compare(const void *a, const void *b) { if (x->enabled == SD_EVENT_OFF && y->enabled != SD_EVENT_OFF) return 1; + /* Non rate-limited ones first. */ + r = CMP(!!x->ratelimited, !!y->ratelimited); + if (r != 0) + return r; + /* Lower priority values first */ r = CMP(x->priority, y->priority); if (r != 0) @@ -170,6 +203,11 @@ static int prepare_prioq_compare(const void *a, const void *b) { if (x->enabled == SD_EVENT_OFF && y->enabled != SD_EVENT_OFF) return 1; + /* Non rate-limited ones first. */ + r = CMP(!!x->ratelimited, !!y->ratelimited); + if (r != 0) + return r; + /* Move most recently prepared ones last, so that we can stop * preparing as soon as we hit one that has already been * prepared in the current iteration */ @@ -181,12 +219,30 @@ static int prepare_prioq_compare(const void *a, const void *b) { return CMP(x->priority, y->priority); } +static usec_t time_event_source_next(const sd_event_source *s) { + assert(s); + + /* We have two kinds of event sources that have elapsation times associated with them: the actual + * time based ones and the ones for which a ratelimit can be in effect (where we want to be notified + * once the ratelimit time window ends). Let's return the next elapsing time depending on what we are + * looking at here. */ + + if (s->ratelimited) { /* If rate-limited the next elapsation is when the ratelimit time window ends */ + assert(s->rate_limit.begin != 0); + assert(s->rate_limit.interval != 0); + return usec_add(s->rate_limit.begin, s->rate_limit.interval); + } + + /* Otherwise this must be a time event source, if not ratelimited */ + if (EVENT_SOURCE_IS_TIME(s->type)) + return s->time.next; + + return USEC_INFINITY; +} + static int earliest_time_prioq_compare(const void *a, const void *b) { const sd_event_source *x = a, *y = b; - assert(EVENT_SOURCE_IS_TIME(x->type)); - assert(x->type == y->type); - /* Enabled ones first */ if (x->enabled != SD_EVENT_OFF && y->enabled == SD_EVENT_OFF) return -1; @@ -200,19 +256,30 @@ static int earliest_time_prioq_compare(const void *a, const void *b) { return 1; /* Order by time */ - return CMP(x->time.next, y->time.next); + return CMP(time_event_source_next(x), time_event_source_next(y)); } static usec_t time_event_source_latest(const sd_event_source *s) { - return usec_add(s->time.next, s->time.accuracy); + assert(s); + + if (s->ratelimited) { /* For ratelimited stuff the earliest and the latest time shall actually be the + * same, as we should avoid adding additional inaccuracy on an inaccuracy time + * window */ + assert(s->rate_limit.begin != 0); + assert(s->rate_limit.interval != 0); + return usec_add(s->rate_limit.begin, s->rate_limit.interval); + } + + /* Must be a time event source, if not ratelimited */ + if (EVENT_SOURCE_IS_TIME(s->type)) + return usec_add(s->time.next, s->time.accuracy); + + return USEC_INFINITY; } static int latest_time_prioq_compare(const void *a, const void *b) { const sd_event_source *x = a, *y = b; - assert(EVENT_SOURCE_IS_TIME(x->type)); - assert(x->type == y->type); - /* Enabled ones first */ if (x->enabled != SD_EVENT_OFF && y->enabled == SD_EVENT_OFF) return -1; @@ -382,7 +449,7 @@ static void source_io_unregister(sd_event_source *s) { return; if (epoll_ctl(s->event->epoll_fd, EPOLL_CTL_DEL, s->io.fd, NULL) < 0) - log_debug_errno(errno, "Failed to remove source %s (type %s) from epoll: %m", + log_debug_errno(errno, "Failed to remove source %s (type %s) from epoll, ignoring: %m", strna(s->description), event_source_type_to_string(s->type)); s->io.registered = false; @@ -401,13 +468,10 @@ static int source_io_register( .events = events | (enabled == SD_EVENT_ONESHOT ? EPOLLONESHOT : 0), .data.ptr = s, }; - int r; - r = epoll_ctl(s->event->epoll_fd, + if (epoll_ctl(s->event->epoll_fd, s->io.registered ? EPOLL_CTL_MOD : EPOLL_CTL_ADD, - s->io.fd, - &ev); - if (r < 0) + s->io.fd, &ev) < 0) return -errno; s->io.registered = true; @@ -427,15 +491,13 @@ static void source_child_pidfd_unregister(sd_event_source *s) { if (EVENT_SOURCE_WATCH_PIDFD(s)) if (epoll_ctl(s->event->epoll_fd, EPOLL_CTL_DEL, s->child.pidfd, NULL) < 0) - log_debug_errno(errno, "Failed to remove source %s (type %s) from epoll: %m", + log_debug_errno(errno, "Failed to remove source %s (type %s) from epoll, ignoring: %m", strna(s->description), event_source_type_to_string(s->type)); s->child.registered = false; } static int source_child_pidfd_register(sd_event_source *s, int enabled) { - int r; - assert(s); assert(s->type == SOURCE_CHILD); assert(enabled != SD_EVENT_OFF); @@ -446,11 +508,9 @@ static int source_child_pidfd_register(sd_event_source *s, int enabled) { .data.ptr = s, }; - if (s->child.registered) - r = epoll_ctl(s->event->epoll_fd, EPOLL_CTL_MOD, s->child.pidfd, &ev); - else - r = epoll_ctl(s->event->epoll_fd, EPOLL_CTL_ADD, s->child.pidfd, &ev); - if (r < 0) + if (epoll_ctl(s->event->epoll_fd, + s->child.registered ? EPOLL_CTL_MOD : EPOLL_CTL_ADD, + s->child.pidfd, &ev) < 0) return -errno; } @@ -618,8 +678,7 @@ static int event_make_signal_data( .data.ptr = d, }; - r = epoll_ctl(e->epoll_fd, EPOLL_CTL_ADD, d->fd, &ev); - if (r < 0) { + if (epoll_ctl(e->epoll_fd, EPOLL_CTL_ADD, d->fd, &ev) < 0) { r = -errno; goto fail; } @@ -671,12 +730,12 @@ static void event_gc_signal_data(sd_event *e, const int64_t *priority, int sig) * and possibly drop the signalfd for it. */ if (sig == SIGCHLD && - e->n_enabled_child_sources > 0) + e->n_online_child_sources > 0) return; if (e->signal_sources && e->signal_sources[sig] && - e->signal_sources[sig]->enabled != SD_EVENT_OFF) + event_source_is_online(e->signal_sources[sig])) return; /* @@ -706,6 +765,52 @@ static void event_gc_signal_data(sd_event *e, const int64_t *priority, int sig) event_unmask_signal_data(e, d, sig); } +static void event_source_pp_prioq_reshuffle(sd_event_source *s) { + assert(s); + + /* Reshuffles the pending + prepare prioqs. Called whenever the dispatch order changes, i.e. when + * they are enabled/disabled or marked pending and such. */ + + if (s->pending) + prioq_reshuffle(s->event->pending, s, &s->pending_index); + + if (s->prepare) + prioq_reshuffle(s->event->prepare, s, &s->prepare_index); +} + +static void event_source_time_prioq_reshuffle(sd_event_source *s) { + struct clock_data *d; + + assert(s); + + /* Called whenever the event source's timer ordering properties changed, i.e. time, accuracy, + * pending, enable state. Makes sure the two prioq's are ordered properly again. */ + + if (s->ratelimited) + d = &s->event->monotonic; + else { + assert(EVENT_SOURCE_IS_TIME(s->type)); + assert_se(d = event_get_clock_data(s->event, s->type)); + } + + prioq_reshuffle(d->earliest, s, &s->earliest_index); + prioq_reshuffle(d->latest, s, &s->latest_index); + d->needs_rearm = true; +} + +static void event_source_time_prioq_remove( + sd_event_source *s, + struct clock_data *d) { + + assert(s); + assert(d); + + prioq_remove(d->earliest, s, &s->earliest_index); + prioq_remove(d->latest, s, &s->latest_index); + s->earliest_index = s->latest_index = PRIOQ_IDX_NULL; + d->needs_rearm = true; +} + static void source_disconnect(sd_event_source *s) { sd_event *event; @@ -728,17 +833,18 @@ static void source_disconnect(sd_event_source *s) { case SOURCE_TIME_BOOTTIME: case SOURCE_TIME_MONOTONIC: case SOURCE_TIME_REALTIME_ALARM: - case SOURCE_TIME_BOOTTIME_ALARM: { - struct clock_data *d; + case SOURCE_TIME_BOOTTIME_ALARM: + /* Only remove this event source from the time event source here if it is not ratelimited. If + * it is ratelimited, we'll remove it below, separately. Why? Because the clock used might + * differ: ratelimiting always uses CLOCK_MONOTONIC, but timer events might use any clock */ - d = event_get_clock_data(s->event, s->type); - assert(d); + if (!s->ratelimited) { + struct clock_data *d; + assert_se(d = event_get_clock_data(s->event, s->type)); + event_source_time_prioq_remove(s, d); + } - prioq_remove(d->earliest, s, &s->time.earliest_index); - prioq_remove(d->latest, s, &s->time.latest_index); - d->needs_rearm = true; break; - } case SOURCE_SIGNAL: if (s->signal.sig > 0) { @@ -753,9 +859,9 @@ static void source_disconnect(sd_event_source *s) { case SOURCE_CHILD: if (s->child.pid > 0) { - if (s->enabled != SD_EVENT_OFF) { - assert(s->event->n_enabled_child_sources > 0); - s->event->n_enabled_child_sources--; + if (event_source_is_online(s)) { + assert(s->event->n_online_child_sources > 0); + s->event->n_online_child_sources--; } (void) hashmap_remove(s->event->child_sources, PID_TO_PTR(s->child.pid)); @@ -825,6 +931,9 @@ static void source_disconnect(sd_event_source *s) { if (s->prepare) prioq_remove(s->event->prepare, s, &s->prepare_index); + if (s->ratelimited) + event_source_time_prioq_remove(s, &s->event->monotonic); + event = TAKE_PTR(s->event); LIST_REMOVE(sources, event->sources, s); event->n_sources--; @@ -912,16 +1021,8 @@ static int source_set_pending(sd_event_source *s, bool b) { } else assert_se(prioq_remove(s->event->pending, s, &s->pending_index)); - if (EVENT_SOURCE_IS_TIME(s->type)) { - struct clock_data *d; - - d = event_get_clock_data(s->event, s->type); - assert(d); - - prioq_reshuffle(d->earliest, s, &s->time.earliest_index); - prioq_reshuffle(d->latest, s, &s->time.latest_index); - d->needs_rearm = true; - } + if (EVENT_SOURCE_IS_TIME(s->type)) + event_source_time_prioq_reshuffle(s); if (s->type == SOURCE_SIGNAL && !b) { struct signal_data *d; @@ -1054,7 +1155,6 @@ static int event_setup_timer_fd( return 0; _cleanup_close_ int fd = -1; - int r; fd = timerfd_create(clock, TFD_NONBLOCK|TFD_CLOEXEC); if (fd < 0) @@ -1067,8 +1167,7 @@ static int event_setup_timer_fd( .data.ptr = d, }; - r = epoll_ctl(e->epoll_fd, EPOLL_CTL_ADD, fd, &ev); - if (r < 0) + if (epoll_ctl(e->epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) return -errno; d->fd = TAKE_FD(fd); @@ -1081,6 +1180,52 @@ static int time_exit_callback(sd_event_source *s, uint64_t usec, void *userdata) return sd_event_exit(sd_event_source_get_event(s), PTR_TO_INT(userdata)); } +static int setup_clock_data(sd_event *e, struct clock_data *d, clockid_t clock) { + int r; + + assert(d); + + if (d->fd < 0) { + r = event_setup_timer_fd(e, d, clock); + if (r < 0) + return r; + } + + r = prioq_ensure_allocated(&d->earliest, earliest_time_prioq_compare); + if (r < 0) + return r; + + r = prioq_ensure_allocated(&d->latest, latest_time_prioq_compare); + if (r < 0) + return r; + + return 0; +} + +static int event_source_time_prioq_put( + sd_event_source *s, + struct clock_data *d) { + + int r; + + assert(s); + assert(d); + + r = prioq_put(d->earliest, s, &s->earliest_index); + if (r < 0) + return r; + + r = prioq_put(d->latest, s, &s->latest_index); + if (r < 0) { + assert_se(prioq_remove(d->earliest, s, &s->earliest_index) > 0); + s->earliest_index = PRIOQ_IDX_NULL; + return r; + } + + d->needs_rearm = true; + return 0; +} + _public_ int sd_event_add_time( sd_event *e, sd_event_source **ret, @@ -1111,23 +1256,12 @@ _public_ int sd_event_add_time( if (!callback) callback = time_exit_callback; - d = event_get_clock_data(e, type); - assert(d); - - r = prioq_ensure_allocated(&d->earliest, earliest_time_prioq_compare); - if (r < 0) - return r; + assert_se(d = event_get_clock_data(e, type)); - r = prioq_ensure_allocated(&d->latest, latest_time_prioq_compare); + r = setup_clock_data(e, d, clock); if (r < 0) return r; - if (d->fd < 0) { - r = event_setup_timer_fd(e, d, clock); - if (r < 0) - return r; - } - s = source_new(e, !ret, type); if (!s) return -ENOMEM; @@ -1135,17 +1269,11 @@ _public_ int sd_event_add_time( s->time.next = usec; s->time.accuracy = accuracy == 0 ? DEFAULT_ACCURACY_USEC : accuracy; s->time.callback = callback; - s->time.earliest_index = s->time.latest_index = PRIOQ_IDX_NULL; + s->earliest_index = s->latest_index = PRIOQ_IDX_NULL; s->userdata = userdata; s->enabled = SD_EVENT_ONESHOT; - d->needs_rearm = true; - - r = prioq_put(d->earliest, s, &s->time.earliest_index); - if (r < 0) - return r; - - r = prioq_put(d->latest, s, &s->time.latest_index); + r = event_source_time_prioq_put(s, d); if (r < 0) return r; @@ -1279,7 +1407,7 @@ _public_ int sd_event_add_child( if (!callback) callback = child_exit_callback; - if (e->n_enabled_child_sources == 0) { + if (e->n_online_child_sources == 0) { /* Caller must block SIGCHLD before using us to watch children, even if pidfd is available, * for compatibility with pre-pidfd and because we don't want the reap the child processes * ourselves, i.e. call waitid(), and don't want Linux' default internal logic for that to @@ -1329,31 +1457,25 @@ _public_ int sd_event_add_child( if (r < 0) return r; - e->n_enabled_child_sources++; - if (EVENT_SOURCE_WATCH_PIDFD(s)) { /* We have a pidfd and we only want to watch for exit */ - r = source_child_pidfd_register(s, s->enabled); - if (r < 0) { - e->n_enabled_child_sources--; + if (r < 0) return r; - } + } else { /* We have no pidfd or we shall wait for some other event than WEXITED */ - r = event_make_signal_data(e, SIGCHLD, NULL); - if (r < 0) { - e->n_enabled_child_sources--; + if (r < 0) return r; - } e->need_process_child = true; } + e->n_online_child_sources++; + if (ret) *ret = s; - TAKE_PTR(s); return 0; } @@ -1382,7 +1504,7 @@ _public_ int sd_event_add_child_pidfd( if (!callback) callback = child_exit_callback; - if (e->n_enabled_child_sources == 0) { + if (e->n_online_child_sources == 0) { r = signal_is_blocked(SIGCHLD); if (r < 0) return r; @@ -1418,31 +1540,24 @@ _public_ int sd_event_add_child_pidfd( if (r < 0) return r; - e->n_enabled_child_sources++; - if (EVENT_SOURCE_WATCH_PIDFD(s)) { /* We only want to watch for WEXITED */ - r = source_child_pidfd_register(s, s->enabled); - if (r < 0) { - e->n_enabled_child_sources--; + if (r < 0) return r; - } } else { /* We shall wait for some other event than WEXITED */ - r = event_make_signal_data(e, SIGCHLD, NULL); - if (r < 0) { - e->n_enabled_child_sources--; + if (r < 0) return r; - } e->need_process_child = true; } + e->n_online_child_sources++; + if (ret) *ret = s; - TAKE_PTR(s); return 0; } @@ -2026,7 +2141,7 @@ _public_ int sd_event_source_set_io_fd(sd_event_source *s, int fd) { if (s->io.fd == fd) return 0; - if (s->enabled == SD_EVENT_OFF) { + if (event_source_is_offline(s)) { s->io.fd = fd; s->io.registered = false; } else { @@ -2093,7 +2208,7 @@ _public_ int sd_event_source_set_io_events(sd_event_source *s, uint32_t events) if (r < 0) return r; - if (s->enabled != SD_EVENT_OFF) { + if (event_source_is_online(s)) { r = source_io_register(s, s->enabled, events); if (r < 0) return r; @@ -2196,7 +2311,7 @@ _public_ int sd_event_source_set_priority(sd_event_source *s, int64_t priority) event_gc_inode_data(s->event, old_inode_data); - } else if (s->type == SOURCE_SIGNAL && s->enabled != SD_EVENT_OFF) { + } else if (s->type == SOURCE_SIGNAL && event_source_is_online(s)) { struct signal_data *old, *d; /* Move us from the signalfd belonging to the old @@ -2216,11 +2331,7 @@ _public_ int sd_event_source_set_priority(sd_event_source *s, int64_t priority) } else s->priority = priority; - if (s->pending) - prioq_reshuffle(s->event->pending, s, &s->pending_index); - - if (s->prepare) - prioq_reshuffle(s->event->prepare, s, &s->prepare_index); + event_source_pp_prioq_reshuffle(s); if (s->type == SOURCE_EXIT) prioq_reshuffle(s->event->exit, s, &s->exit.prioq_index); @@ -2237,198 +2348,222 @@ fail: return r; } -_public_ int sd_event_source_get_enabled(sd_event_source *s, int *m) { +_public_ int sd_event_source_get_enabled(sd_event_source *s, int *ret) { assert_return(s, -EINVAL); assert_return(!event_pid_changed(s->event), -ECHILD); - if (m) - *m = s->enabled; + if (ret) + *ret = s->enabled; + return s->enabled != SD_EVENT_OFF; } -_public_ int sd_event_source_set_enabled(sd_event_source *s, int m) { +static int event_source_offline( + sd_event_source *s, + int enabled, + bool ratelimited) { + + bool was_offline; int r; - assert_return(s, -EINVAL); - assert_return(IN_SET(m, SD_EVENT_OFF, SD_EVENT_ON, SD_EVENT_ONESHOT), -EINVAL); - assert_return(!event_pid_changed(s->event), -ECHILD); + assert(s); + assert(enabled == SD_EVENT_OFF || ratelimited); - /* If we are dead anyway, we are fine with turning off - * sources, but everything else needs to fail. */ - if (s->event->state == SD_EVENT_FINISHED) - return m == SD_EVENT_OFF ? 0 : -ESTALE; + /* Unset the pending flag when this event source is disabled */ + if (s->enabled != SD_EVENT_OFF && + enabled == SD_EVENT_OFF && + !IN_SET(s->type, SOURCE_DEFER, SOURCE_EXIT)) { + r = source_set_pending(s, false); + if (r < 0) + return r; + } - if (s->enabled == m) - return 0; + was_offline = event_source_is_offline(s); + s->enabled = enabled; + s->ratelimited = ratelimited; - if (m == SD_EVENT_OFF) { + switch (s->type) { - /* Unset the pending flag when this event source is disabled */ - if (!IN_SET(s->type, SOURCE_DEFER, SOURCE_EXIT)) { - r = source_set_pending(s, false); - if (r < 0) - return r; - } + case SOURCE_IO: + source_io_unregister(s); + break; - switch (s->type) { + case SOURCE_TIME_REALTIME: + case SOURCE_TIME_BOOTTIME: + case SOURCE_TIME_MONOTONIC: + case SOURCE_TIME_REALTIME_ALARM: + case SOURCE_TIME_BOOTTIME_ALARM: + event_source_time_prioq_reshuffle(s); + break; - case SOURCE_IO: - source_io_unregister(s); - s->enabled = m; - break; + case SOURCE_SIGNAL: + event_gc_signal_data(s->event, &s->priority, s->signal.sig); + break; - case SOURCE_TIME_REALTIME: - case SOURCE_TIME_BOOTTIME: - case SOURCE_TIME_MONOTONIC: - case SOURCE_TIME_REALTIME_ALARM: - case SOURCE_TIME_BOOTTIME_ALARM: { - struct clock_data *d; + case SOURCE_CHILD: + if (!was_offline) { + assert(s->event->n_online_child_sources > 0); + s->event->n_online_child_sources--; + } - s->enabled = m; - d = event_get_clock_data(s->event, s->type); - assert(d); + if (EVENT_SOURCE_WATCH_PIDFD(s)) + source_child_pidfd_unregister(s); + else + event_gc_signal_data(s->event, &s->priority, SIGCHLD); + break; - prioq_reshuffle(d->earliest, s, &s->time.earliest_index); - prioq_reshuffle(d->latest, s, &s->time.latest_index); - d->needs_rearm = true; - break; - } + case SOURCE_EXIT: + prioq_reshuffle(s->event->exit, s, &s->exit.prioq_index); + break; - case SOURCE_SIGNAL: - s->enabled = m; + case SOURCE_DEFER: + case SOURCE_POST: + case SOURCE_INOTIFY: + break; - event_gc_signal_data(s->event, &s->priority, s->signal.sig); - break; + default: + assert_not_reached("Wut? I shouldn't exist."); + } - case SOURCE_CHILD: - s->enabled = m; + return 1; +} - assert(s->event->n_enabled_child_sources > 0); - s->event->n_enabled_child_sources--; +static int event_source_online( + sd_event_source *s, + int enabled, + bool ratelimited) { - if (EVENT_SOURCE_WATCH_PIDFD(s)) - source_child_pidfd_unregister(s); - else - event_gc_signal_data(s->event, &s->priority, SIGCHLD); + bool was_online; + int r; - break; + assert(s); + assert(enabled != SD_EVENT_OFF || !ratelimited); - case SOURCE_EXIT: - s->enabled = m; - prioq_reshuffle(s->event->exit, s, &s->exit.prioq_index); - break; + /* Unset the pending flag when this event source is enabled */ + if (s->enabled == SD_EVENT_OFF && + enabled != SD_EVENT_OFF && + !IN_SET(s->type, SOURCE_DEFER, SOURCE_EXIT)) { + r = source_set_pending(s, false); + if (r < 0) + return r; + } - case SOURCE_DEFER: - case SOURCE_POST: - case SOURCE_INOTIFY: - s->enabled = m; - break; + /* Are we really ready for onlining? */ + if (enabled == SD_EVENT_OFF || ratelimited) { + /* Nope, we are not ready for onlining, then just update the precise state and exit */ + s->enabled = enabled; + s->ratelimited = ratelimited; + return 0; + } - default: - assert_not_reached("Wut? I shouldn't exist."); - } + was_online = event_source_is_online(s); - } else { + switch (s->type) { + case SOURCE_IO: + r = source_io_register(s, enabled, s->io.events); + if (r < 0) + return r; + break; - /* Unset the pending flag when this event source is enabled */ - if (s->enabled == SD_EVENT_OFF && !IN_SET(s->type, SOURCE_DEFER, SOURCE_EXIT)) { - r = source_set_pending(s, false); - if (r < 0) - return r; + case SOURCE_SIGNAL: + r = event_make_signal_data(s->event, s->signal.sig, NULL); + if (r < 0) { + event_gc_signal_data(s->event, &s->priority, s->signal.sig); + return r; } - switch (s->type) { + break; + + case SOURCE_CHILD: + if (EVENT_SOURCE_WATCH_PIDFD(s)) { + /* yes, we have pidfd */ - case SOURCE_IO: - r = source_io_register(s, m, s->io.events); + r = source_child_pidfd_register(s, enabled); if (r < 0) return r; + } else { + /* no pidfd, or something other to watch for than WEXITED */ - s->enabled = m; - break; - - case SOURCE_TIME_REALTIME: - case SOURCE_TIME_BOOTTIME: - case SOURCE_TIME_MONOTONIC: - case SOURCE_TIME_REALTIME_ALARM: - case SOURCE_TIME_BOOTTIME_ALARM: { - struct clock_data *d; - - s->enabled = m; - d = event_get_clock_data(s->event, s->type); - assert(d); - - prioq_reshuffle(d->earliest, s, &s->time.earliest_index); - prioq_reshuffle(d->latest, s, &s->time.latest_index); - d->needs_rearm = true; - break; + r = event_make_signal_data(s->event, SIGCHLD, NULL); + if (r < 0) { + event_gc_signal_data(s->event, &s->priority, SIGCHLD); + return r; + } } - case SOURCE_SIGNAL: + if (!was_online) + s->event->n_online_child_sources++; + break; - s->enabled = m; + case SOURCE_TIME_REALTIME: + case SOURCE_TIME_BOOTTIME: + case SOURCE_TIME_MONOTONIC: + case SOURCE_TIME_REALTIME_ALARM: + case SOURCE_TIME_BOOTTIME_ALARM: + case SOURCE_EXIT: + case SOURCE_DEFER: + case SOURCE_POST: + case SOURCE_INOTIFY: + break; - r = event_make_signal_data(s->event, s->signal.sig, NULL); - if (r < 0) { - s->enabled = SD_EVENT_OFF; - event_gc_signal_data(s->event, &s->priority, s->signal.sig); - return r; - } + default: + assert_not_reached("Wut? I shouldn't exist."); + } - break; + s->enabled = enabled; + s->ratelimited = ratelimited; - case SOURCE_CHILD: + /* Non-failing operations below */ + switch (s->type) { + case SOURCE_TIME_REALTIME: + case SOURCE_TIME_BOOTTIME: + case SOURCE_TIME_MONOTONIC: + case SOURCE_TIME_REALTIME_ALARM: + case SOURCE_TIME_BOOTTIME_ALARM: + event_source_time_prioq_reshuffle(s); + break; - if (s->enabled == SD_EVENT_OFF) - s->event->n_enabled_child_sources++; + case SOURCE_EXIT: + prioq_reshuffle(s->event->exit, s, &s->exit.prioq_index); + break; - s->enabled = m; + default: + break; + } - if (EVENT_SOURCE_WATCH_PIDFD(s)) { - /* yes, we have pidfd */ + return 1; +} - r = source_child_pidfd_register(s, s->enabled); - if (r < 0) { - s->enabled = SD_EVENT_OFF; - s->event->n_enabled_child_sources--; - return r; - } - } else { - /* no pidfd, or something other to watch for than WEXITED */ +_public_ int sd_event_source_set_enabled(sd_event_source *s, int m) { + int r; - r = event_make_signal_data(s->event, SIGCHLD, NULL); - if (r < 0) { - s->enabled = SD_EVENT_OFF; - s->event->n_enabled_child_sources--; - event_gc_signal_data(s->event, &s->priority, SIGCHLD); - return r; - } - } + assert_return(s, -EINVAL); + assert_return(IN_SET(m, SD_EVENT_OFF, SD_EVENT_ON, SD_EVENT_ONESHOT), -EINVAL); + assert_return(!event_pid_changed(s->event), -ECHILD); - break; + /* If we are dead anyway, we are fine with turning off sources, but everything else needs to fail. */ + if (s->event->state == SD_EVENT_FINISHED) + return m == SD_EVENT_OFF ? 0 : -ESTALE; - case SOURCE_EXIT: - s->enabled = m; - prioq_reshuffle(s->event->exit, s, &s->exit.prioq_index); - break; + if (s->enabled == m) /* No change? */ + return 0; - case SOURCE_DEFER: - case SOURCE_POST: - case SOURCE_INOTIFY: + if (m == SD_EVENT_OFF) + r = event_source_offline(s, m, s->ratelimited); + else { + if (s->enabled != SD_EVENT_OFF) { + /* Switching from "on" to "oneshot" or back? If that's the case, we can take a shortcut, the + * event source is already enabled after all. */ s->enabled = m; - break; - - default: - assert_not_reached("Wut? I shouldn't exist."); + return 0; } - } - if (s->pending) - prioq_reshuffle(s->event->pending, s, &s->pending_index); - - if (s->prepare) - prioq_reshuffle(s->event->prepare, s, &s->prepare_index); + r = event_source_online(s, m, s->ratelimited); + } + if (r < 0) + return r; + event_source_pp_prioq_reshuffle(s); return 0; } @@ -2443,7 +2578,6 @@ _public_ int sd_event_source_get_time(sd_event_source *s, uint64_t *usec) { } _public_ int sd_event_source_set_time(sd_event_source *s, uint64_t usec) { - struct clock_data *d; int r; assert_return(s, -EINVAL); @@ -2457,13 +2591,7 @@ _public_ int sd_event_source_set_time(sd_event_source *s, uint64_t usec) { s->time.next = usec; - d = event_get_clock_data(s->event, s->type); - assert(d); - - prioq_reshuffle(d->earliest, s, &s->time.earliest_index); - prioq_reshuffle(d->latest, s, &s->time.latest_index); - d->needs_rearm = true; - + event_source_time_prioq_reshuffle(s); return 0; } @@ -2495,7 +2623,6 @@ _public_ int sd_event_source_get_time_accuracy(sd_event_source *s, uint64_t *use } _public_ int sd_event_source_set_time_accuracy(sd_event_source *s, uint64_t usec) { - struct clock_data *d; int r; assert_return(s, -EINVAL); @@ -2513,12 +2640,7 @@ _public_ int sd_event_source_set_time_accuracy(sd_event_source *s, uint64_t usec s->time.accuracy = usec; - d = event_get_clock_data(s->event, s->type); - assert(d); - - prioq_reshuffle(d->latest, s, &s->time.latest_index); - d->needs_rearm = true; - + event_source_time_prioq_reshuffle(s); return 0; } @@ -2693,6 +2815,96 @@ _public_ void *sd_event_source_set_userdata(sd_event_source *s, void *userdata) return ret; } +static int event_source_enter_ratelimited(sd_event_source *s) { + int r; + + assert(s); + + /* When an event source becomes ratelimited, we place it in the CLOCK_MONOTONIC priority queue, with + * the end of the rate limit time window, much as if it was a timer event source. */ + + if (s->ratelimited) + return 0; /* Already ratelimited, this is a NOP hence */ + + /* Make sure we can install a CLOCK_MONOTONIC event further down. */ + r = setup_clock_data(s->event, &s->event->monotonic, CLOCK_MONOTONIC); + if (r < 0) + return r; + + /* Timer event sources are already using the earliest/latest queues for the timer scheduling. Let's + * first remove them from the prioq appropriate for their own clock, so that we can use the prioq + * fields of the event source then for adding it to the CLOCK_MONOTONIC prioq instead. */ + if (EVENT_SOURCE_IS_TIME(s->type)) + event_source_time_prioq_remove(s, event_get_clock_data(s->event, s->type)); + + /* Now, let's add the event source to the monotonic clock instead */ + r = event_source_time_prioq_put(s, &s->event->monotonic); + if (r < 0) + goto fail; + + /* And let's take the event source officially offline */ + r = event_source_offline(s, s->enabled, /* ratelimited= */ true); + if (r < 0) { + event_source_time_prioq_remove(s, &s->event->monotonic); + goto fail; + } + + event_source_pp_prioq_reshuffle(s); + + log_debug("Event source %p (%s) entered rate limit state.", s, strna(s->description)); + return 0; + +fail: + /* Reinstall time event sources in the priority queue as before. This shouldn't fail, since the queue + * space for it should already be allocated. */ + if (EVENT_SOURCE_IS_TIME(s->type)) + assert_se(event_source_time_prioq_put(s, event_get_clock_data(s->event, s->type)) >= 0); + + return r; +} + +static int event_source_leave_ratelimit(sd_event_source *s) { + int r; + + assert(s); + + if (!s->ratelimited) + return 0; + + /* Let's take the event source out of the monotonic prioq first. */ + event_source_time_prioq_remove(s, &s->event->monotonic); + + /* Let's then add the event source to its native clock prioq again — if this is a timer event source */ + if (EVENT_SOURCE_IS_TIME(s->type)) { + r = event_source_time_prioq_put(s, event_get_clock_data(s->event, s->type)); + if (r < 0) + goto fail; + } + + /* Let's try to take it online again. */ + r = event_source_online(s, s->enabled, /* ratelimited= */ false); + if (r < 0) { + /* Do something roughly sensible when this failed: undo the two prioq ops above */ + if (EVENT_SOURCE_IS_TIME(s->type)) + event_source_time_prioq_remove(s, event_get_clock_data(s->event, s->type)); + + goto fail; + } + + event_source_pp_prioq_reshuffle(s); + ratelimit_reset(&s->rate_limit); + + log_debug("Event source %p (%s) left rate limit state.", s, strna(s->description)); + return 0; + +fail: + /* Do something somewhat reasonable when we cannot move an event sources out of ratelimited mode: + * simply put it back in it, maybe we can then process it more successfully next iteration. */ + assert_se(event_source_time_prioq_put(s, &s->event->monotonic) >= 0); + + return r; +} + static usec_t sleep_between(sd_event *e, usec_t a, usec_t b) { usec_t c; assert(e); @@ -2780,7 +2992,6 @@ static int event_arm_timer( struct itimerspec its = {}; sd_event_source *a, *b; usec_t t; - int r; assert(e); assert(d); @@ -2791,7 +3002,7 @@ static int event_arm_timer( d->needs_rearm = false; a = prioq_peek(d->earliest); - if (!a || a->enabled == SD_EVENT_OFF || a->time.next == USEC_INFINITY) { + if (!a || a->enabled == SD_EVENT_OFF || time_event_source_next(a) == USEC_INFINITY) { if (d->fd < 0) return 0; @@ -2800,9 +3011,8 @@ static int event_arm_timer( return 0; /* disarm */ - r = timerfd_settime(d->fd, TFD_TIMER_ABSTIME, &its, NULL); - if (r < 0) - return r; + if (timerfd_settime(d->fd, TFD_TIMER_ABSTIME, &its, NULL) < 0) + return -errno; d->next = USEC_INFINITY; return 0; @@ -2811,7 +3021,7 @@ static int event_arm_timer( b = prioq_peek(d->latest); assert_se(b && b->enabled != SD_EVENT_OFF); - t = sleep_between(e, a->time.next, time_event_source_latest(b)); + t = sleep_between(e, time_event_source_next(a), time_event_source_latest(b)); if (d->next == t) return 0; @@ -2824,8 +3034,7 @@ static int event_arm_timer( } else timespec_store(&its.it_value, t); - r = timerfd_settime(d->fd, TFD_TIMER_ABSTIME, &its, NULL); - if (r < 0) + if (timerfd_settime(d->fd, TFD_TIMER_ABSTIME, &its, NULL) < 0) return -errno; d->next = t; @@ -2890,19 +3099,29 @@ static int process_timer( for (;;) { s = prioq_peek(d->earliest); - if (!s || - s->time.next > n || - s->enabled == SD_EVENT_OFF || - s->pending) + if (!s || time_event_source_next(s) > n) + break; + + if (s->ratelimited) { + /* This is an event sources whose ratelimit window has ended. Let's turn it on + * again. */ + assert(s->ratelimited); + + r = event_source_leave_ratelimit(s); + if (r < 0) + return r; + + continue; + } + + if (s->enabled == SD_EVENT_OFF || s->pending) break; r = source_set_pending(s, true); if (r < 0) return r; - prioq_reshuffle(d->earliest, s, &s->time.earliest_index); - prioq_reshuffle(d->latest, s, &s->time.latest_index); - d->needs_rearm = true; + event_source_time_prioq_reshuffle(s); } return 0; @@ -2940,7 +3159,7 @@ static int process_child(sd_event *e) { if (s->pending) continue; - if (s->enabled == SD_EVENT_OFF) + if (event_source_is_offline(s)) continue; if (s->child.exited) @@ -2950,9 +3169,8 @@ static int process_child(sd_event *e) { continue; zero(s->child.siginfo); - r = waitid(P_PID, s->child.pid, &s->child.siginfo, - WNOHANG | (s->child.options & WEXITED ? WNOWAIT : 0) | s->child.options); - if (r < 0) + if (waitid(P_PID, s->child.pid, &s->child.siginfo, + WNOHANG | (s->child.options & WEXITED ? WNOWAIT : 0) | s->child.options) < 0) return -errno; if (s->child.siginfo.si_pid != 0) { @@ -2988,7 +3206,7 @@ static int process_pidfd(sd_event *e, sd_event_source *s, uint32_t revents) { if (s->pending) return 0; - if (s->enabled == SD_EVENT_OFF) + if (event_source_is_offline(s)) return 0; if (!EVENT_SOURCE_WATCH_PIDFD(s)) @@ -3148,7 +3366,7 @@ static int event_inotify_data_process(sd_event *e, struct inotify_data *d) { LIST_FOREACH(inotify.by_inode_data, s, inode_data->event_sources) { - if (s->enabled == SD_EVENT_OFF) + if (event_source_is_offline(s)) continue; r = source_set_pending(s, true); @@ -3184,7 +3402,7 @@ static int event_inotify_data_process(sd_event *e, struct inotify_data *d) { * sources if IN_IGNORED or IN_UNMOUNT is set. */ LIST_FOREACH(inotify.by_inode_data, s, inode_data->event_sources) { - if (s->enabled == SD_EVENT_OFF) + if (event_source_is_offline(s)) continue; if ((d->buffer.ev.mask & (IN_IGNORED|IN_UNMOUNT)) == 0 && @@ -3238,6 +3456,16 @@ static int source_dispatch(sd_event_source *s) { * callback might have invalidated/disconnected the event source. */ saved_event = sd_event_ref(s->event); + /* Check if we hit the ratelimit for this event source, if so, let's disable it. */ + assert(!s->ratelimited); + if (!ratelimit_below(&s->rate_limit)) { + r = event_source_enter_ratelimited(s); + if (r < 0) + return r; + + return 1; + } + if (!IN_SET(s->type, SOURCE_DEFER, SOURCE_EXIT)) { r = source_set_pending(s, false); if (r < 0) @@ -3251,7 +3479,7 @@ static int source_dispatch(sd_event_source *s) { * post sources as pending */ SET_FOREACH(z, s->event->post_sources) { - if (z->enabled == SD_EVENT_OFF) + if (event_source_is_offline(z)) continue; r = source_set_pending(z, true); @@ -3371,7 +3599,7 @@ static int event_prepare(sd_event *e) { sd_event_source *s; s = prioq_peek(e->prepare); - if (!s || s->prepare_iteration == e->iteration || s->enabled == SD_EVENT_OFF) + if (!s || s->prepare_iteration == e->iteration || event_source_is_offline(s)) break; s->prepare_iteration = e->iteration; @@ -3406,18 +3634,17 @@ static int event_prepare(sd_event *e) { static int dispatch_exit(sd_event *e) { sd_event_source *p; - _cleanup_(sd_event_unrefp) sd_event *ref = NULL; int r; assert(e); p = prioq_peek(e->exit); - if (!p || p->enabled == SD_EVENT_OFF) { + if (!p || event_source_is_offline(p)) { e->state = SD_EVENT_FINISHED; return 0; } - ref = sd_event_ref(e); + _unused_ _cleanup_(sd_event_unrefp) sd_event *ref = sd_event_ref(e); e->iteration++; e->state = SD_EVENT_EXITING; r = source_dispatch(p); @@ -3434,7 +3661,7 @@ static sd_event_source* event_next_pending(sd_event *e) { if (!p) return NULL; - if (p->enabled == SD_EVENT_OFF) + if (event_source_is_offline(p)) return NULL; return p; @@ -3443,7 +3670,6 @@ static sd_event_source* event_next_pending(sd_event *e) { static int arm_watchdog(sd_event *e) { struct itimerspec its = {}; usec_t t; - int r; assert(e); assert(e->watchdog_fd >= 0); @@ -3459,8 +3685,7 @@ static int arm_watchdog(sd_event *e) { if (its.it_value.tv_sec == 0 && its.it_value.tv_nsec == 0) its.it_value.tv_nsec = 1; - r = timerfd_settime(e->watchdog_fd, TFD_TIMER_ABSTIME, &its, NULL); - if (r < 0) + if (timerfd_settime(e->watchdog_fd, TFD_TIMER_ABSTIME, &its, NULL) < 0) return -errno; return 0; @@ -3515,6 +3740,9 @@ _public_ int sd_event_prepare(sd_event *e) { * syscalls */ assert_return(!e->default_event_ptr || e->tid == gettid(), -EREMOTEIO); + /* Make sure that none of the preparation callbacks ends up freeing the event source under our feet */ + _unused_ _cleanup_(sd_event_unrefp) sd_event *ref = sd_event_ref(e); + if (e->exit_requested) goto pending; @@ -3720,9 +3948,8 @@ _public_ int sd_event_dispatch(sd_event *e) { p = event_next_pending(e); if (p) { - _cleanup_(sd_event_unrefp) sd_event *ref = NULL; + _unused_ _cleanup_(sd_event_unrefp) sd_event *ref = sd_event_ref(e); - ref = sd_event_ref(e); e->state = SD_EVENT_RUNNING; r = source_dispatch(p); e->state = SD_EVENT_INITIAL; @@ -3756,29 +3983,32 @@ _public_ int sd_event_run(sd_event *e, uint64_t timeout) { assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); assert_return(e->state == SD_EVENT_INITIAL, -EBUSY); - if (e->profile_delays && e->last_run) { + if (e->profile_delays && e->last_run_usec != 0) { usec_t this_run; unsigned l; this_run = now(CLOCK_MONOTONIC); - l = u64log2(this_run - e->last_run); - assert(l < sizeof(e->delays)); + l = u64log2(this_run - e->last_run_usec); + assert(l < ELEMENTSOF(e->delays)); e->delays[l]++; - if (this_run - e->last_log >= 5*USEC_PER_SEC) { + if (this_run - e->last_log_usec >= 5*USEC_PER_SEC) { event_log_delays(e); - e->last_log = this_run; + e->last_log_usec = this_run; } } + /* Make sure that none of the preparation callbacks ends up freeing the event source under our feet */ + _unused_ _cleanup_(sd_event_unrefp) sd_event *ref = sd_event_ref(e); + r = sd_event_prepare(e); if (r == 0) /* There was nothing? Then wait... */ r = sd_event_wait(e, timeout); if (e->profile_delays) - e->last_run = now(CLOCK_MONOTONIC); + e->last_run_usec = now(CLOCK_MONOTONIC); if (r > 0) { /* There's something now, then let's dispatch it */ @@ -3793,7 +4023,6 @@ _public_ int sd_event_run(sd_event *e, uint64_t timeout) { } _public_ int sd_event_loop(sd_event *e) { - _cleanup_(sd_event_unrefp) sd_event *ref = NULL; int r; assert_return(e, -EINVAL); @@ -3801,7 +4030,7 @@ _public_ int sd_event_loop(sd_event *e) { assert_return(!event_pid_changed(e), -ECHILD); assert_return(e->state == SD_EVENT_INITIAL, -EBUSY); - ref = sd_event_ref(e); + _unused_ _cleanup_(sd_event_unrefp) sd_event *ref = NULL; while (e->state != SD_EVENT_FINISHED) { r = sd_event_run(e, (uint64_t) -1); @@ -3813,7 +4042,6 @@ _public_ int sd_event_loop(sd_event *e) { } _public_ int sd_event_get_fd(sd_event *e) { - assert_return(e, -EINVAL); assert_return(e = event_resolve(e), -ENOPKG); assert_return(!event_pid_changed(e), -ECHILD); @@ -3870,8 +4098,7 @@ _public_ int sd_event_now(sd_event *e, clockid_t clock, uint64_t *usec) { return -EOPNOTSUPP; if (!triple_timestamp_is_set(&e->timestamp)) { - /* Implicitly fall back to now() if we never ran - * before and thus have no cached time. */ + /* Implicitly fall back to now() if we never ran before and thus have no cached time. */ *usec = now(clock); return 1; } @@ -3951,8 +4178,7 @@ _public_ int sd_event_set_watchdog(sd_event *e, int b) { .data.ptr = INT_TO_PTR(SOURCE_WATCHDOG), }; - r = epoll_ctl(e->epoll_fd, EPOLL_CTL_ADD, e->watchdog_fd, &ev); - if (r < 0) { + if (epoll_ctl(e->epoll_fd, EPOLL_CTL_ADD, e->watchdog_fd, &ev) < 0) { r = -errno; goto fail; } @@ -4050,4 +4276,54 @@ _public_ int sd_event_source_set_exit_on_failure(sd_event_source *s, int b) { s->exit_on_failure = b; return 1; } + +_public_ int sd_event_source_set_ratelimit(sd_event_source *s, uint64_t interval, unsigned burst) { + int r; + + assert_return(s, -EINVAL); + + /* Turning on ratelimiting on event source types that don't support it, is a loggable offense. Doing + * so is a programming error. */ + assert_return(EVENT_SOURCE_CAN_RATE_LIMIT(s->type), -EDOM); + + /* When ratelimiting is configured we'll always reset the rate limit state first and start fresh, + * non-ratelimited. */ + r = event_source_leave_ratelimit(s); + if (r < 0) + return r; + + s->rate_limit = (RateLimit) { interval, burst }; + return 0; +} + +_public_ int sd_event_source_get_ratelimit(sd_event_source *s, uint64_t *ret_interval, unsigned *ret_burst) { + assert_return(s, -EINVAL); + + /* Querying whether an event source has ratelimiting configured is not a loggable offsense, hence + * don't use assert_return(). Unlike turning on ratelimiting it's not really a programming error */ + if (!EVENT_SOURCE_CAN_RATE_LIMIT(s->type)) + return -EDOM; + + if (!ratelimit_configured(&s->rate_limit)) + return -ENOEXEC; + + if (ret_interval) + *ret_interval = s->rate_limit.interval; + if (ret_burst) + *ret_burst = s->rate_limit.burst; + + return 0; +} + +_public_ int sd_event_source_is_ratelimited(sd_event_source *s) { + assert_return(s, -EINVAL); + + if (!EVENT_SOURCE_CAN_RATE_LIMIT(s->type)) + return false; + + if (!ratelimit_configured(&s->rate_limit)) + return false; + + return s->ratelimited; +} #endif /* NM_IGNORED */ diff --git a/src/systemd/src/libsystemd/sd-id128/id128-util.c b/src/systemd/src/libsystemd/sd-id128/id128-util.c index 3cb963786e..b61cfdb02c 100644 --- a/src/systemd/src/libsystemd/sd-id128/id128-util.c +++ b/src/systemd/src/libsystemd/sd-id128/id128-util.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #include "nm-sd-adapt-core.h" @@ -12,6 +12,7 @@ #include "id128-util.h" #include "io-util.h" #include "stdio-util.h" +#include "string-util.h" #if 0 /* NM_IGNORED */ char *id128_to_uuid_string(sd_id128_t id, char s[static ID128_UUID_STRING_MAX]) { @@ -101,6 +102,11 @@ 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 33: /* plain UUID with trailing newline */ if (buffer[32] != '\n') return -EINVAL; @@ -119,7 +125,7 @@ int id128_read_fd(int fd, Id128Format f, sd_id128_t *ret) { _fallthrough_; case 36: /* RFC UUID without trailing newline */ - if (f == ID128_PLAIN) + if (IN_SET(f, ID128_PLAIN, ID128_PLAIN_OR_UNINIT)) return -EINVAL; buffer[36] = 0; diff --git a/src/systemd/src/libsystemd/sd-id128/id128-util.h b/src/systemd/src/libsystemd/sd-id128/id128-util.h index 1901bf119f..6b09bcd96a 100644 --- a/src/systemd/src/libsystemd/sd-id128/id128-util.h +++ b/src/systemd/src/libsystemd/sd-id128/id128-util.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include <stdbool.h> @@ -17,6 +17,10 @@ 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; diff --git a/src/systemd/src/libsystemd/sd-id128/sd-id128.c b/src/systemd/src/libsystemd/sd-id128/sd-id128.c index d585ff2596..64b8c78728 100644 --- a/src/systemd/src/libsystemd/sd-id128/sd-id128.c +++ b/src/systemd/src/libsystemd/sd-id128/sd-id128.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #include "nm-sd-adapt-core.h" diff --git a/src/systemd/src/systemd/_sd-common.h b/src/systemd/src/systemd/_sd-common.h index 1055b00d07..e3de2ae562 100644 --- a/src/systemd/src/systemd/_sd-common.h +++ b/src/systemd/src/systemd/_sd-common.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #ifndef foosdcommonhfoo #define foosdcommonhfoo diff --git a/src/systemd/src/systemd/sd-dhcp-client.h b/src/systemd/src/systemd/sd-dhcp-client.h index ac3b5b369c..c35328a9a6 100644 --- a/src/systemd/src/systemd/sd-dhcp-client.h +++ b/src/systemd/src/systemd/sd-dhcp-client.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #ifndef foosddhcpclienthfoo #define foosddhcpclienthfoo @@ -40,6 +40,8 @@ enum { SD_DHCP_CLIENT_EVENT_EXPIRED = 3, SD_DHCP_CLIENT_EVENT_RENEW = 4, SD_DHCP_CLIENT_EVENT_SELECTING = 5, + SD_DHCP_CLIENT_EVENT_TRANSIENT_FAILURE = 6, /* Sent when we have not received a reply after the first few attempts. + * The client may want to start acquiring link-local addresses. */ }; enum { @@ -126,6 +128,7 @@ int sd_dhcp_client_set_ifindex( int sd_dhcp_client_set_mac( sd_dhcp_client *client, const uint8_t *addr, + const uint8_t *bcast_addr, size_t addr_len, uint16_t arp_type); int sd_dhcp_client_set_client_id( diff --git a/src/systemd/src/systemd/sd-dhcp-lease.h b/src/systemd/src/systemd/sd-dhcp-lease.h index 17bd491819..c255a1f912 100644 --- a/src/systemd/src/systemd/sd-dhcp-lease.h +++ b/src/systemd/src/systemd/sd-dhcp-lease.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #ifndef foosddhcpleasehfoo #define foosddhcpleasehfoo diff --git a/src/systemd/src/systemd/sd-dhcp-option.h b/src/systemd/src/systemd/sd-dhcp-option.h index 45dbd27985..71aa479b5e 100644 --- a/src/systemd/src/systemd/sd-dhcp-option.h +++ b/src/systemd/src/systemd/sd-dhcp-option.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #ifndef foosddhcpoptionhfoo #define foosddhcpoptionhfoo diff --git a/src/systemd/src/systemd/sd-dhcp6-client.h b/src/systemd/src/systemd/sd-dhcp6-client.h index 2b0d63a527..75ee27d68b 100644 --- a/src/systemd/src/systemd/sd-dhcp6-client.h +++ b/src/systemd/src/systemd/sd-dhcp6-client.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #ifndef foosddhcp6clienthfoo #define foosddhcp6clienthfoo diff --git a/src/systemd/src/systemd/sd-dhcp6-lease.h b/src/systemd/src/systemd/sd-dhcp6-lease.h index 240df74af8..f77b31acf9 100644 --- a/src/systemd/src/systemd/sd-dhcp6-lease.h +++ b/src/systemd/src/systemd/sd-dhcp6-lease.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #ifndef foosddhcp6leasehfoo #define foosddhcp6leasehfoo diff --git a/src/systemd/src/systemd/sd-dhcp6-option.h b/src/systemd/src/systemd/sd-dhcp6-option.h index 88a4986315..ddb2c7cecd 100644 --- a/src/systemd/src/systemd/sd-dhcp6-option.h +++ b/src/systemd/src/systemd/sd-dhcp6-option.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #ifndef foosddhcp6optionhfoo #define foosddhcp6optionhfoo diff --git a/src/systemd/src/systemd/sd-event.h b/src/systemd/src/systemd/sd-event.h index 3a53c3d27d..2ae2a0da48 100644 --- a/src/systemd/src/systemd/sd-event.h +++ b/src/systemd/src/systemd/sd-event.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #ifndef foosdeventhfoo #define foosdeventhfoo @@ -162,6 +162,9 @@ int sd_event_source_get_floating(sd_event_source *s); int sd_event_source_set_floating(sd_event_source *s, int b); int sd_event_source_get_exit_on_failure(sd_event_source *s); int sd_event_source_set_exit_on_failure(sd_event_source *s, int b); +int sd_event_source_set_ratelimit(sd_event_source *s, uint64_t interval_usec, unsigned burst); +int sd_event_source_get_ratelimit(sd_event_source *s, uint64_t *ret_interval_usec, unsigned *ret_burst); +int sd_event_source_is_ratelimited(sd_event_source *s); /* Define helpers so that __attribute__((cleanup(sd_event_unrefp))) and similar may be used. */ _SD_DEFINE_POINTER_CLEANUP_FUNC(sd_event, sd_event_unref); diff --git a/src/systemd/src/systemd/sd-id128.h b/src/systemd/src/systemd/sd-id128.h index 9b00b76ea6..02aa318a06 100644 --- a/src/systemd/src/systemd/sd-id128.h +++ b/src/systemd/src/systemd/sd-id128.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #ifndef foosdid128hfoo #define foosdid128hfoo diff --git a/src/systemd/src/systemd/sd-ipv4acd.h b/src/systemd/src/systemd/sd-ipv4acd.h index ebf723fc22..2809d8748b 100644 --- a/src/systemd/src/systemd/sd-ipv4acd.h +++ b/src/systemd/src/systemd/sd-ipv4acd.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #ifndef foosdipv4acdfoo #define foosdipv4acdfoo @@ -43,6 +43,8 @@ int sd_ipv4acd_get_address(sd_ipv4acd *acd, struct in_addr *address); int sd_ipv4acd_set_callback(sd_ipv4acd *acd, sd_ipv4acd_callback_t cb, void *userdata); int sd_ipv4acd_set_mac(sd_ipv4acd *acd, const struct ether_addr *addr); int sd_ipv4acd_set_ifindex(sd_ipv4acd *acd, int interface_index); +int sd_ipv4acd_get_ifindex(sd_ipv4acd *acd); +const char *sd_ipv4acd_get_ifname(sd_ipv4acd *acd); int sd_ipv4acd_set_address(sd_ipv4acd *acd, const struct in_addr *address); int sd_ipv4acd_is_running(sd_ipv4acd *acd); int sd_ipv4acd_start(sd_ipv4acd *acd, bool reset_conflicts); diff --git a/src/systemd/src/systemd/sd-ipv4ll.h b/src/systemd/src/systemd/sd-ipv4ll.h index 71bd4cfe48..aa4d174e4b 100644 --- a/src/systemd/src/systemd/sd-ipv4ll.h +++ b/src/systemd/src/systemd/sd-ipv4ll.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #ifndef foosdipv4llfoo #define foosdipv4llfoo @@ -43,6 +43,8 @@ int sd_ipv4ll_get_address(sd_ipv4ll *ll, struct in_addr *address); int sd_ipv4ll_set_callback(sd_ipv4ll *ll, sd_ipv4ll_callback_t cb, void *userdata); int sd_ipv4ll_set_mac(sd_ipv4ll *ll, const struct ether_addr *addr); int sd_ipv4ll_set_ifindex(sd_ipv4ll *ll, int interface_index); +int sd_ipv4ll_get_ifindex(sd_ipv4ll *ll); +const char *sd_ipv4ll_get_ifname(sd_ipv4ll *ll); int sd_ipv4ll_set_address(sd_ipv4ll *ll, const struct in_addr *address); int sd_ipv4ll_set_address_seed(sd_ipv4ll *ll, uint64_t seed); int sd_ipv4ll_is_running(sd_ipv4ll *ll); diff --git a/src/systemd/src/systemd/sd-lldp.h b/src/systemd/src/systemd/sd-lldp.h index c2abc20121..f551f6b4fa 100644 --- a/src/systemd/src/systemd/sd-lldp.h +++ b/src/systemd/src/systemd/sd-lldp.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #ifndef foosdlldphfoo #define foosdlldphfoo diff --git a/src/systemd/src/systemd/sd-ndisc.h b/src/systemd/src/systemd/sd-ndisc.h index 3ddfc8cb6d..c0e37899a7 100644 --- a/src/systemd/src/systemd/sd-ndisc.h +++ b/src/systemd/src/systemd/sd-ndisc.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #ifndef foosdndiscfoo #define foosdndiscfoo |